Yes you can use bat file, system is called "microsoft application". Use the same way than for shortcut file.
But take care, your bat file NEED to wait for the application close to exit.
To try run your bat file, if the cmd application close (or return to prompt) before the application you are lanching is closed, it's not good.
To fix some prb in some application I use this autoit script, if it can help you. It works for lnk file, but can work for bat too with some modifications.
;Parsing
Local $count = StringInStr($CmdLineRaw, ".exe", 0 , 1, 1)
local $app = StringLeft ( $CmdLineRaw, $count + 4 )
local $command = StringTrimLeft( $CmdLineRaw, $count + 4 )
if not $command then exit 0
;Get more info
$count = StringInStr($command, '"', 0 , 1, 1)
local $link = StringTrimLeft ( $command, $count )
$link = StringTrimRight ( $link, 1 )
Local $aDetails = FileGetShortcut($link)
If @error Then exit
local $tmp = StringSplit($aDetails[0], "\")
local $apptorun = $tmp[$tmp[0]]
;run command
;Run ('"' & $app & '" ' & $command)
ShellExecute('"' & $link & '"')
;wait for application launched with protection loop
;wait for 5 s and exit if no application found
local $protloop = 10
While not(ProcessExists($apptorun))
$protloop = $protloop - 1
if ($protloop < 0) then exit 0
sleep(500)
WEnd
;try to put in front
local $PID = GetProcessPID($apptorun)
local $WinName = ProcessGetWindow($PID)
WinSetState($WinName,"",@SW_SHOW)
WinSetState($WinName,"",@SW_ENABLE)
;wait for close
While (ProcessExists($apptorun) or (ProcessExists("cmd.exe")))
sleep(500)
WEnd
;To resolve bug in taito Xom Tetris gran master
local $list = ProcessList("game.exe")
if $list[0][0] > 0 Then
local $PID = $list[1][1]
ProcessWaitClose($PID)
endif
Exit 0
;*********************************************************
;functions
;*********************************************************
Func GetProcessPID($name)
Local $list = ProcessList($name)
For $i = 1 To $list[0][0]
If $list[$i][0] <> "" then
Return $list[$i][1]
Endif
Next
return 0
endFunc
Func ProcessGetWindow($PId)
If IsNumber($PId) = 0 then
SetError(1)
Else
Local $WinList = WinList()
For $i = 1 To $WinList[0][0]
If WinGetProcess($WinList[$i][0], "") = $PId Then
return $WinList[$i][0]
EndIf
Next
Return 0
EndIf
EndFunc
;~
;~ Func _WinWaitActivePID($iPid)
;~ While 1
;~ Local $list = WinList()
;~ For $i = 1 To $list[0][0]
;~ If $list[$i][0] <> "" And IsVisible($list[$i][1]) Then
;~ If WinGetProcess($list[$i][1]) = $iPid AND WinActive($list[$i][1]) Then Return $list[$i][0]
;~ EndIf
;~ Next
;~ WEnd
;~ EndFunc
;~
;~ Func IsVisible($handle)
;~ If BitAND(WinGetState($handle), 2) Then
;~ Return 1
;~ Else
;~ Return 0
;~ EndIf
;~ EndFunc