Bug 816

Summary: Нельзя через команду wine запустить *.bat и *.msi
Product: WINE@Etersoft Reporter: Анатолий Лютин <vostok>
Component: ОбщееAssignee: BUGS@Etersoft <bugs>
Status: CLOSED FIXED QA Contact:
Severity: enhancement    
Priority: P5 CC: kondratyuk, lav
Version: 1.0.9   
Target Milestone: выпуск 1.0.9   
Hardware: PC   
OS: Linux   
Whiteboard:
Заявки RT: Связано с:
Дата напоминания:
Bug Depends on:    
Bug Blocks: 3962, 4774, 8987    

Description Анатолий Лютин 2007-10-25 10:57:49 MSD
В винде можно из cmd всё это запустить, а в вайн говорит, что это BAD EXE FORMAT.
Comment 1 Константин Кондратюк 2007-10-25 13:01:46 MSD
wine start example.bat
Comment 2 Анатолий Лютин 2007-10-25 13:02:50 MSD
Вопрос в том, что нельзя в консоли сделать wine example.msi, а в винде в cmd можно.
Comment 3 Vitaly Lipatov 2008-04-09 18:19:02 MSD
В виндовом cmd (и наверняка через CreateProcess тоже?) можно запустить напрямую файлы с расширением bat, cmd, msi:
C> test.msi

В вайне так не работает и приходится запускать через start (то есть ShellExec используется для вызова обработчика файла).
Comment 4 Анатолий Лютин 2008-04-09 18:34:36 MSD
Вообще в wine есть код, который проверяет расширение у файла и если это .exe, .com  , то идёт одна обработка, а все другие отваливаются. 

Наверное проще всего будет сделать хак, который при получении .bat и .msi перезапускал этот код, но с программой start, посылая ей на вход имя пакета.
Comment 5 Vitaly Lipatov 2008-04-09 18:43:22 MSD
Возможно в Windows обработка bat/cmd/msi сделана на той же основе, что и com/exe, поэтому надо сделать аналогично, и это будет не хаком.
Проверяется просто - в винде эти файлы должны исполняться с использованием cmd.exe (или указанным в COMSPEC интерпретатором?), вне зависимости от ассоциации расширения с программой (используемого в ShellExec).
Comment 6 Виталий Перов 2008-04-25 18:16:43 MSD
Как я понял из msdn, напрямую из CreateProcess() незная тип файла всё-таки запускать нельзя.
Чтобы через CreateProcess() запустить .bat файл нужно в lpApplicationName передать  cmd.exe, а в lpCommandLine передать /с плюс имя файла

т.е по сути мы вызываем комманду cmd.exe x.bat
Comment 7 Виталий Перов 2008-04-25 18:19:26 MSD
Проблема в том, что в Wine в cmd.exe не работает передача параметров через коммандную строку.
Т.е при выхове "wine cmd.exe x.bat" просто открывается сmd, но имя файла в качестве параметра ему не передаётся
Comment 8 Анатолий Лютин 2008-04-25 18:22:50 MSD
(In reply to comment #6)
> Как я понял из msdn, напрямую из CreateProcess()
> незная тип файла всё-таки запускать нельзя.
> Чтобы через CreateProcess() запустить .bat файл
> нужно в lpApplicationName передать  cmd.exe, а в lpCommandLine
> передать /с плюс имя файла
> 
> т.е по сути мы вызываем комманду cmd.exe x.bat
> 

Возможно стоит посмотреть SHELL_FindExecutable(..), а так же как и где она используется. Это может помочь.
Comment 9 Анатолий Лютин 2008-04-25 18:29:34 MSD
(In reply to comment #7)

> Т.е при выхове "wine cmd.exe x.bat" просто
> открывается сmd, но имя файла в качестве
> параметра ему не передаётся
Только что проверил под Windows - там тоже откроется только cmd, а батник запускаться не будет.

Думаю, что не надо для таких целей использовать cmd. Надо использовать минимум start. 

Comment 10 Анатолий Лютин 2008-04-25 18:31:21 MSD
А start из панели "выполнить" не работает. Зато если зайти в cmd и там сказать start 1.bat, то откроется ещё одно окно с cmd и выполниться там батник.
Comment 11 Виталий Перов 2008-04-25 19:01:47 MSD
Работает, только там есть ещё опция /с.
Если набираешь "сmd c:/test.bat", то не работает, а если "сmd /c c:/test.bat" то уже работает. 
Comment 12 Анатолий Лютин 2008-04-25 19:12:10 MSD
(In reply to comment #11)
> Работает, только там есть ещё опция /с.
> Если набираешь "сmd c:/test.bat", то не работает, а
> если "сmd /c c:/test.bat" то уже работает. 
> 

Гм, а ключ /c в Wine-ском cmd реализован? :)
Comment 13 Виталий Перов 2008-04-25 19:19:40 MSD
В wine из коммандной строки тоже работает!
Надо ещё проверить через CreateProcess()
Comment 14 Виталий Перов 2008-04-25 20:50:49 MSD
CreateProcess() работает наполовину.

Т.е если передавать как написано в MSDN: lpApplicationName = "cmd.exe"; lpCommandLine = "/с x.bat", то не работает. С помощью GetLastError можно можно отловить ошибку: файл не найден.

если же передавать lpApplicationName = NULL; pCommandLine = "cmd.exe /с x.bat", то всё прекрасно работает.
Comment 15 Виталий Перов 2008-04-25 21:21:55 MSD
Проверил в WinXp
Странно, но всё работает также.
Видимо ошибка в MSDN.
Написано одно:
To run a batch file, you must start the command interpreter; set lpApplicationName to cmd.exe and set lpCommandLine to the following arguments: /c plus the name of the batch file.
А на деле получается совсем другое
Comment 16 Анатолий Лютин 2008-04-25 21:24:26 MSD
(In reply to comment #15)
> Проверил в WinXp
> Странно, но всё работает также.
> Видимо ошибка в MSDN.
> Написано одно:
> To run a batch file, you must start the command interpreter; set
> lpApplicationName to cmd.exe and set lpCommandLine to the following arguments:
> /c plus the name of the batch file.
> А на деле получается совсем другое
> 
Так часто бывает. Можно написать тест и в комментарии к тесту указать, что этот тест показывает отличие реализации от того, что заявлено в документации.
Comment 17 Vitaly Lipatov 2008-04-25 22:41:11 MSD
1. Ну что вы говорите, у cmd должен быть специальный параметр (вроде /P), который говорит что надо запустить батник.
2. Существует переменная окружения COMSPEC, задающая действующий командный интерпретатор.
3. Безусловно, все bat- и cmd-файлы выполняются через cmd.exe, поскольку это его назначение.
Comment 18 Vitaly Lipatov 2008-04-26 01:05:41 MSD
Что-то я стормозил с комментарием, но тем не менее:
в нормально документации написано, что передавать надо
lpApplicationName = "cmd.exe"; lpCommandLine = "cmd.exe /с x.bat"

(командная строка должна включать в себя и название команды)
А ApplicationName - так, для справки.
Comment 19 Виталий Перов 2008-04-26 13:59:02 MSD
(In reply to comment #18)
> Что-то я стормозил с комментарием, но тем не
> менее:
> в нормально документации написано, что
> передавать надо
> lpApplicationName = "cmd.exe"; lpCommandLine = "cmd.exe /с x.bat"
> 
> (командная строка должна включать в себя и
> название команды)
> А ApplicationName - так, для справки.
> 

Т.е получается что проблема с .bat-файлами только в MSDN документации, а в wine всё работает как и должно работать.

Осталось только проверить работает ли CreateProcess() с *.msi
Comment 20 Виталий Перов 2008-04-29 17:13:05 MSD
wine cmd /c web.msi
Результат:
Bad format
Comment 21 Vitaly Lipatov 2008-04-29 17:17:38 MSD
(In reply to comment #20)
> wine cmd /c web.msi
> Результат:
> Bad format
Что логично. Никаким боком cmd не имеет отношения к исполнению msi-сценариев. Этим занимается msiexec 

Comment 22 Виталий Перов 2008-04-29 17:26:05 MSD
(In reply to comment #21)
> (In reply to comment #20)
> > wine cmd /c web.msi
> > Результат:
> > Bad format
> Что логично. Никаким боком cmd не имеет
> отношения к исполнению msi-сценариев. Этим
> занимается msiexec 
> 

в WinXP cmd /c web.msi работает
Comment 23 Виталий Перов 2008-04-29 17:27:40 MSD
При вызове:
CreateProcessA(NULL, "cmd /c web.msi", NULL....
Тоже Bad format
Comment 24 Виталий Перов 2008-04-29 17:34:19 MSD
проверил в WinXp. тест для CreateProcess() нормально запускает *.msi
Comment 25 Vitaly Lipatov 2008-04-29 19:51:05 MSD
Можно создать тест и отправить его в Wine?
Comment 26 Виталий Перов 2008-05-05 17:43:53 MSD
для теста нужен тестовый *.msi.
Взять готовый в данном случае не получится. Придётся создавать свой.
При этом не должно быть графического интерфейса.
Желательно чтобы он только распаковывал 1 файл в текущую или определённую директорию.
Насколько это реально пока не знаю.
Comment 27 Виталий Перов 2008-05-05 20:53:38 MSD
Нашёл специальную программу "Advanced Installer" она не позволяет создать *.msi без оконного интерфейса. Думаю другие программы тоже этого не позволяют.

Думаю, можно создавать процесс, смотреть что возвращает CreateProcessA(), а потом сразу его убивать, пока окно не успело прорисоваться.
Только такой тест точно не понравится в официальной ветке
Comment 28 Vitaly Lipatov 2008-05-06 00:34:58 MSD
1. Давай с другой стороны - как можно сделать,
чтобы у нас msi обрабатывался как надо?
2. Не обязательно создавать полноценный msi для тестирования - достаточно, думаю, сделать пустышку с нужной сигнатурой в начале. Не знаю правда как проверять что он запустился - возможно коды возврата у CreateProcess будут разные?
Comment 29 Виталий Перов 2008-05-06 14:16:52 MSD
(In reply to comment #28)
> 1. Давай с другой стороны - как можно
> сделать,
> чтобы у нас msi обрабатывался как надо?
В CreateProcessA() уже есть похожий код, отлавливающий вызов *.bat
Думаю не так сложно дописать обработку *.msi. При этом будет вызываться msiexec -i  х.msi

> 2. Не обязательно создавать полноценный msi
> для тестирования - достаточно, думаю,
> сделать пустышку с нужной сигнатурой в
> начале. Не знаю правда как проверять что он
> запустился - возможно коды возврата у
> CreateProcess будут разные?
> 
Да, нужно проверить. CreateProcessA() при этом должнен запустить msiexec в новом потоке, а сам завершится успешно. Если возникает ошибка, то она возникает уже в другом потоке.
Если *.msi будет содержать только сигнатуру, то вряд ли msi будет считать его корректным. Если передавать просто пустой файл, то думаю разницы никакой не будет.
Comment 30 Виталий Перов 2008-05-06 16:46:28 MSD
В Wine существует 2 способа выполнения .bat файлов через CreateProcess.
В качестве имени можно передавать:
1) "cmd /c х.bat" при этом cmd вызывается напрямую
2) "x.bat" при этом внутри функции идёт определение типа по расширению, и в конечном итоге вызывается "cmd /c х.bat"

Получается, что для реализации *.msi недостаточно просто дописать CreateProcess, а нужно ещё дописывать cmd.exe
Comment 31 Виталий Перов 2008-05-06 17:01:37 MSD
При запуске msi через CreateProcess ( комманда "cmd /c х.msi"):

1)При использовании реальных *.msi завершается успешно, но пишет "Bad format"
Здесь CreateProcess всегда завершается успешно. Получается, что тестировать надо cmd.exe 

2)При использовании пустого *.msi cmd распознаёт его как нормальный
Comment 32 Виталий Перов 2008-05-08 18:51:13 MSD
Реализовал поддержку *.msi через cmd

работает:
$ wine cmd.exe /c x.msi
CreateProcessA(NULL,"wine cmd.exe /c x.msi", ...

пока не работает:
CreateProcessA(NULL,"x.msi", ...

ещё возможно:
$ wine x.bat
$ wine x.msi
Но это уже сложнее, лучше оставить на потом.

Послал патч в официальную ветку. Там возникли большие сомнения по поводу того реализовано ли в Windows это внутри cmd, или скорее как-то через реестр.

Как это работает в Windows - информации не нашёл. Если нет возражений я бы оставил так. Только осталось дописать поддержку CreateProcessA(NULL,"x.msi", ...
В итоге в официальную ветку скорее всего не примут, зато в нашей версии работа с *.msi будет намного удобнее.
Comment 33 Виталий Перов 2008-05-12 20:45:22 MSD
Реализовывать надо через ShellExecute
При этом программа-обработчик должна братся из реестра.

Для начала, думаю, надо добится работы:

$wine start x.msi
или
$wine start x.html
Comment 34 Виталий Перов 2008-05-12 20:47:24 MSD
Ошибся:
$wine start x.html работает!
Comment 35 Виталий Перов 2008-05-12 21:03:56 MSD
$wine start x.msi тоже работает
Comment 36 Vitaly Lipatov 2009-05-23 13:58:32 MSD
Добавил в скрипт запуска wine проверку, и теперь реально существующие файлы,
не имеющие расширения .EXE, будут запускаться через wine start FILE

+# if file is exist in Unix or Wine notation
+if [ -n "$1" ] && [ -f $(winepath "$1") ] ; then
+       TRNAME=$(echo "$1" | tr [a-z] [A-Z])
+       # if file is not executable, run it with start
+       if [ $(basename "$TRNAME" .EXE) = $(basename "$TRNAME") ] ; then
+               run_wine start "$@"
+       fi
+fi
+
 run_wine "$@"