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
wine start example.bat Вопрос в том, что нельзя в консоли сделать wine example.msi, а в винде в cmd можно. В виндовом cmd (и наверняка через CreateProcess тоже?) можно запустить напрямую файлы с расширением bat, cmd, msi: C> test.msi В вайне так не работает и приходится запускать через start (то есть ShellExec используется для вызова обработчика файла). Вообще в wine есть код, который проверяет расширение у файла и если это .exe, .com , то идёт одна обработка, а все другие отваливаются. Наверное проще всего будет сделать хак, который при получении .bat и .msi перезапускал этот код, но с программой start, посылая ей на вход имя пакета. Возможно в Windows обработка bat/cmd/msi сделана на той же основе, что и com/exe, поэтому надо сделать аналогично, и это будет не хаком. Проверяется просто - в винде эти файлы должны исполняться с использованием cmd.exe (или указанным в COMSPEC интерпретатором?), вне зависимости от ассоциации расширения с программой (используемого в ShellExec). Как я понял из msdn, напрямую из CreateProcess() незная тип файла всё-таки запускать нельзя. Чтобы через CreateProcess() запустить .bat файл нужно в lpApplicationName передать cmd.exe, а в lpCommandLine передать /с плюс имя файла т.е по сути мы вызываем комманду cmd.exe x.bat Проблема в том, что в Wine в cmd.exe не работает передача параметров через коммандную строку. Т.е при выхове "wine cmd.exe x.bat" просто открывается сmd, но имя файла в качестве параметра ему не передаётся (In reply to comment #6) > Как я понял из msdn, напрямую из CreateProcess() > незная тип файла всё-таки запускать нельзя. > Чтобы через CreateProcess() запустить .bat файл > нужно в lpApplicationName передать cmd.exe, а в lpCommandLine > передать /с плюс имя файла > > т.е по сути мы вызываем комманду cmd.exe x.bat > Возможно стоит посмотреть SHELL_FindExecutable(..), а так же как и где она используется. Это может помочь. (In reply to comment #7) > Т.е при выхове "wine cmd.exe x.bat" просто > открывается сmd, но имя файла в качестве > параметра ему не передаётся Только что проверил под Windows - там тоже откроется только cmd, а батник запускаться не будет. Думаю, что не надо для таких целей использовать cmd. Надо использовать минимум start. А start из панели "выполнить" не работает. Зато если зайти в cmd и там сказать start 1.bat, то откроется ещё одно окно с cmd и выполниться там батник. Работает, только там есть ещё опция /с. Если набираешь "сmd c:/test.bat", то не работает, а если "сmd /c c:/test.bat" то уже работает. (In reply to comment #11) > Работает, только там есть ещё опция /с. > Если набираешь "сmd c:/test.bat", то не работает, а > если "сmd /c c:/test.bat" то уже работает. > Гм, а ключ /c в Wine-ском cmd реализован? :) В wine из коммандной строки тоже работает! Надо ещё проверить через CreateProcess() CreateProcess() работает наполовину. Т.е если передавать как написано в MSDN: lpApplicationName = "cmd.exe"; lpCommandLine = "/с x.bat", то не работает. С помощью GetLastError можно можно отловить ошибку: файл не найден. если же передавать lpApplicationName = NULL; pCommandLine = "cmd.exe /с x.bat", то всё прекрасно работает. Проверил в 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. А на деле получается совсем другое (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. > А на деле получается совсем другое > Так часто бывает. Можно написать тест и в комментарии к тесту указать, что этот тест показывает отличие реализации от того, что заявлено в документации. 1. Ну что вы говорите, у cmd должен быть специальный параметр (вроде /P), который говорит что надо запустить батник. 2. Существует переменная окружения COMSPEC, задающая действующий командный интерпретатор. 3. Безусловно, все bat- и cmd-файлы выполняются через cmd.exe, поскольку это его назначение. Что-то я стормозил с комментарием, но тем не менее: в нормально документации написано, что передавать надо lpApplicationName = "cmd.exe"; lpCommandLine = "cmd.exe /с x.bat" (командная строка должна включать в себя и название команды) А ApplicationName - так, для справки. (In reply to comment #18) > Что-то я стормозил с комментарием, но тем не > менее: > в нормально документации написано, что > передавать надо > lpApplicationName = "cmd.exe"; lpCommandLine = "cmd.exe /с x.bat" > > (командная строка должна включать в себя и > название команды) > А ApplicationName - так, для справки. > Т.е получается что проблема с .bat-файлами только в MSDN документации, а в wine всё работает как и должно работать. Осталось только проверить работает ли CreateProcess() с *.msi wine cmd /c web.msi Результат: Bad format (In reply to comment #20) > wine cmd /c web.msi > Результат: > Bad format Что логично. Никаким боком cmd не имеет отношения к исполнению msi-сценариев. Этим занимается msiexec (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 работает При вызове: CreateProcessA(NULL, "cmd /c web.msi", NULL.... Тоже Bad format проверил в WinXp. тест для CreateProcess() нормально запускает *.msi Можно создать тест и отправить его в Wine? для теста нужен тестовый *.msi. Взять готовый в данном случае не получится. Придётся создавать свой. При этом не должно быть графического интерфейса. Желательно чтобы он только распаковывал 1 файл в текущую или определённую директорию. Насколько это реально пока не знаю. Нашёл специальную программу "Advanced Installer" она не позволяет создать *.msi без оконного интерфейса. Думаю другие программы тоже этого не позволяют. Думаю, можно создавать процесс, смотреть что возвращает CreateProcessA(), а потом сразу его убивать, пока окно не успело прорисоваться. Только такой тест точно не понравится в официальной ветке 1. Давай с другой стороны - как можно сделать, чтобы у нас msi обрабатывался как надо? 2. Не обязательно создавать полноценный msi для тестирования - достаточно, думаю, сделать пустышку с нужной сигнатурой в начале. Не знаю правда как проверять что он запустился - возможно коды возврата у CreateProcess будут разные? (In reply to comment #28) > 1. Давай с другой стороны - как можно > сделать, > чтобы у нас msi обрабатывался как надо? В CreateProcessA() уже есть похожий код, отлавливающий вызов *.bat Думаю не так сложно дописать обработку *.msi. При этом будет вызываться msiexec -i х.msi > 2. Не обязательно создавать полноценный msi > для тестирования - достаточно, думаю, > сделать пустышку с нужной сигнатурой в > начале. Не знаю правда как проверять что он > запустился - возможно коды возврата у > CreateProcess будут разные? > Да, нужно проверить. CreateProcessA() при этом должнен запустить msiexec в новом потоке, а сам завершится успешно. Если возникает ошибка, то она возникает уже в другом потоке. Если *.msi будет содержать только сигнатуру, то вряд ли msi будет считать его корректным. Если передавать просто пустой файл, то думаю разницы никакой не будет. В Wine существует 2 способа выполнения .bat файлов через CreateProcess. В качестве имени можно передавать: 1) "cmd /c х.bat" при этом cmd вызывается напрямую 2) "x.bat" при этом внутри функции идёт определение типа по расширению, и в конечном итоге вызывается "cmd /c х.bat" Получается, что для реализации *.msi недостаточно просто дописать CreateProcess, а нужно ещё дописывать cmd.exe При запуске msi через CreateProcess ( комманда "cmd /c х.msi"): 1)При использовании реальных *.msi завершается успешно, но пишет "Bad format" Здесь CreateProcess всегда завершается успешно. Получается, что тестировать надо cmd.exe 2)При использовании пустого *.msi cmd распознаёт его как нормальный Реализовал поддержку *.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 будет намного удобнее. Реализовывать надо через ShellExecute При этом программа-обработчик должна братся из реестра. Для начала, думаю, надо добится работы: $wine start x.msi или $wine start x.html Ошибся: $wine start x.html работает! $wine start x.msi тоже работает Добавил в скрипт запуска 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 "$@" |