На главную
ПРАВИЛА FAQ Помощь Участники Календарь Избранное RSS
msm.ru
Модераторы: Qraizer, Hsilgos
  
> Маленькая программка с ShellExecute из командной строки, Посмотреть ошибки и скомпилировать
Добрый день!

Возникла разовая задача: нужна программа, без интерфейса, с функцией ShellExecute внутри.
Получает в командной строке параметр и выполняет его ShellExecute'ом. Всё 8-)

Я на VBA пишу, там exe файлов нет :)
Надо писать на чём-то, что в конечном результате даст исполняемый файл.
Первый раздел на форуме это С++ и по нему есть много инфы, можно быстро нагуглить вопрос. Поэтому решил делать на нём.
Вот что получилось:
ExpandedWrap disabled
    #include <iostream>
    #include <cstdlib>
    #include <ShellAPI.h>
     
    int main(int argc, char *argv[])
    {
        if (argc == 1)
        {
            ShellExecute(0, NULL, argv[1], NULL, NULL, SW_SHOWNORMAL);      
        }
        exit(1);
    }

Это мой первый С++ код за последние лет так 15 :blush:
Предполагаю, что он содержит ошибки.
У меня не установлена среда разработки, код написан в редакторе сообщений форума.
Конечно можно скачать и установить, но задача разовая, пока не вижу смысла.

В итоге один вопрос и одна просьба:
Есть ошибки в коде?
Если нет, сделайте, пожалуйста, exe файл! :rolleyes:
Лучше день потерять, но потом за 5 минут долететь
  • К ShellAPI.h всё равно нужен windows.h.
  • argc указывает количество строк в argv, поэтому сравнивать надо с 2, если ожидаешь там параметры; в argv[0] лежит имя собственно самой запущенной программы.
exit() там не нужен, достаточно return, т.к. это конец main(). Нормальное завершение программы "по соглашению сторон" означает 0 как результат, а не 1. При этом return 0; писать в конце main() не обязательно, по дефолту именно это и предполагается.
Ты не указал, под какую систему тебе нужен бинарник. 64-битный не запустится под 32-битной ОСью.
Одни с годами умнеют, другие становятся старше.
Qraizer большое спасибо!

64bit

поправил, по списку замечаний:
ExpandedWrap disabled
    #include <iostream>
    #include <windows.h>
    #include <ShellAPI.h>
     
    int main(int argc, char *argv[])
    {
        if (argc == 2)
        {
            ShellExecute(0, NULL, argv[1], NULL, NULL, SW_SHOWNORMAL);      
        }
    }


З.Ы. Вот это не совсем понял:
argv[0] - имя собственно самой запущенной программы
argv[1] - переданный параметр
откуда 2 ?
Лучше день потерять, но потом за 5 минут долететь
Цитата SV() @
argv[0] - имя собственно самой запущенной программы
argv[1] - переданный параметр
откуда 2 ?
Длина массива argv[], два элемента.
Прикреплённый файлПрикреплённый файлshellExec.zip (44,72 Кбайт, скачиваний: 5)
Собрал VS2017. На всякий случай со статическими либами, бо не факт, что .dll-ки у тебя инсталлированы.

Добавлено
P.S. Если твой argv[1] нужно запускать с параметрами, что имеет смысл, то программка слишком проста. Нужно доработать на сбор последующих argv[] в строку и передавать вместе с argv[1] в начале.
Одни с годами умнеют, другие становятся старше.
Есть пара непредвиденных проблем:
1. Вместо SW_SHOWNORMAL видимо надо SW_RESTORE.
(если argv[1] это "С:\text.docx" и Word уже запущен, то в текущей конфигурации text.docx откроется, тут всё ок, но Word при этом не становится активным окном - это уже не ок)
2. При запуске на долю секунды на экране появляется чёрное окно.
Погуглил - кто-то пишет что надо добавить
ExpandedWrap disabled
    ShowWindow(NULL,HIDE_WINDOW);

другое мнение - настроить компилятор, чтобы окна вообще не было:
Цитата
Чтобы консольное окно скрыть, не надо его вообще создавать, для компилятора g++ опция
-mwindows
Тут я научил людей как сие делать:MessageBox
Читай с сообщения номер 11, можешь также использовать FreeConsole, если поможет.

можно как-то убрать окно?

Цитата Qraizer @
P.S. Если твой argv[1] нужно запускать с параметрами, что имеет смысл, то программка слишком проста. Нужно доработать на сбор последующих argv[] в строку и передавать вместе с argv[1] в начале.
Да, так конечно будет правильней. Но этот функционал 99,9999% не будет востребован.

З.Ы. Не думал, что вылезет столько нюансов. Чую всё таки придётся ставить студию. Что качать?
Лучше день потерять, но потом за 5 минут долететь
Цитата SV() @
можно как-то убрать окно?

Надо создать приложение не как консольное, а как GUI.
Но при этом окна не создавать.
Т.е. вместо
ExpandedWrap disabled
    int main(int argc, char *argv[])
    {
    // ...
    }

Надо делать:
ExpandedWrap disabled
    int WINAPI _tWinMain (HINSTANCE hThisInst,HINSTANCE hPrevInst,TCHAR* lpszArgs,int nWinMode)
    {
    // ...
    }


Кроме того, вариант
ExpandedWrap disabled
       if (argc == 2)
        {
            ShellExecute(0, NULL, argv[1], NULL, NULL, SW_SHOWNORMAL);      
        }

Не удачен.
Лучше приблизительно так:
ExpandedWrap disabled
       if (argc > 1)
        {
            TCHAR* pCommandStr = ::GetCommandString();
            ShellExecute(0, NULL, pCommandStr, NULL, NULL, SW_SHOWNORMAL);      
        }
Сообщение отредактировано: ЫукпШ -
Подпись была выключена в связи с наложенным заземлением.
SV(), я и не сомневался, что не всё учтено. 2-3 итерации – это норма. Пересоберу, не вопрос.
"Окончательное" ТЗ подытожишь?
Одни с годами умнеют, другие становятся старше.
Ничего не поменялось, всё как в моем предыдущем сообщении:
- если argv[1] это "С:\text.docx" и Word уже запущен, то в результате Word с открытым "С:\text.docx" должен стать активным окном.
Предполагаю, что для этого надо заменить SW_SHOWNORMAL на SW_RESTORE.
- сама программа должна быть невидимкой. Её окно не должно мелькать на экране.
ЫукпШ предлагал варианты, я добавил их в код, но это уже выше моего уровня, совсем не уверен в том, что получилось.
Собрал все правки вот так:
ExpandedWrap disabled
    #include <iostream>
    #include <windows.h>
    #include <ShellAPI.h>
    #include <TCHAR.H>
     
    int WINAPI _tWinMain (HINSTANCE hThisInst,HINSTANCE hPrevInst,TCHAR* lpszArgs,int nWinMode)
    {
        TCHAR* pCommandStr = ::GetCommandString();
        ShellExecute(0, NULL, pCommandStr, NULL, NULL, SW_RESTORE);  
    }
:blush:

Qraizer, очень извиняюсь, я уже чувствую, что перехожу рамки, и это превращается в работу...
Лучше день потерять, но потом за 5 минут долететь
Цитата SV() @
ЫукпШ предлагал варианты, я добавил их в код, но это уже выше моего уровня, совсем не уверен в том, что получилось.

Увы.
Виноват, ошибся.
1. Не "GetCommandString", а "GetCommandLine".
2. Так
ExpandedWrap disabled
       TCHAR* pCommandStr = ::GetCommandString();
        ShellExecute(0, NULL, pCommandStr, NULL, NULL, SW_RESTORE);

Работать не будет.
Придётся разбирать командную строку.
Либо самому, либо используя "CommandLineToArgvW"
Тут есть пример.
Сообщение отредактировано: ЫукпШ -
Подпись была выключена в связи с наложенным заземлением.
Вообще-то GetCommandString() возвращает всю строку, включая имя программы. Т.е. туда будут входить все argv[], начиная с нулевого. Коли мы делам ГУЙный стартер, тогда уж лучше брать третий параметр WinMain(): который lpszArgs. Ну и iostream тебе не нужен, в консоль ничего не выдаётся. Он и раньше не был нужен, но у меня был вопрос, который я хотел задать, на предмет обработки ошибок: нормально ли, что при ошибках ничего никому никуда не выдаётся?
Вот текст:
ExpandedWrap disabled
    #include <windows.h>
    #include <ShellAPI.h>
    #include <TCHAR.H>
     
    int WINAPI _tWinMain (HINSTANCE hThisInst,HINSTANCE hPrevInst,TCHAR* lpszArgs,int nWinMode)
    {
      ShellExecute(0, NULL, lpszArgs, NULL, NULL, SW_RESTORE);  
    }
Собрал под UNICODE.
Прикреплённый файлПрикреплённый файлshellExec.zip (40,25 Кбайт, скачиваний: 5)
Если есть желание, можно вообще избавиться от стартового кода, но тогда придётся всё-таки GetCommandString() и отрезать от него первый параметр руками. Зато .exeшичек будет совсем маленький.
Одни с годами умнеют, другие становятся старше.
Цитата Qraizer @
нормально ли, что при ошибках ничего никому никуда не выдаётся?
да :yes:
Тут всё так просто, что если ничего не произошло - без всяких сообщений понятно, что накосячил с параметрами в командной строке.

Размер exe-шника честно говоря не важен. 84kb в современном мире это фактически ноль. Если будет работать быстрее - есть смысл. Но на первый взгляд она и так шустрая.

Протестил - всё работает как надо: окно не мелькает, выполняется без задержки.
Проблема
Цитата SV() @
если argv[1] это "С:\text.docx" и Word уже запущен, то в результате Word с открытым "С:\text.docx" должен стать активным окном.
не решена.
Но эти все SW_SHOWNORMAL, SW_RESTORE и т.д. никогда на моей памяти вменяемо не работали.
Я наколхозил так: создал ярлык и передаю его проге. Т.е. argv[1] это "С:\text.docx — ярлык.lnk"

Сейчас внедрю прогу, создам все ярлычки, посмотрим, как себя покажет в реальной работе.
Лучше день потерять, но потом за 5 минут долететь
У меня консольная утилитка, юзаю это, как ведет за пределами консоли не скажу:
https://docs.microsoft.com/ru-ru/cpp/c-runt...ue&view=vs-2019
MS Visual Studio 2019 (C++)
Visual Prolog 9.x
1 пользователей читают эту тему (1 гостей и 0 скрытых пользователей)
0 пользователей:


Рейтинг@Mail.ru
[ Script Execution time: 0,1369 ]   [ 24 queries used ]   [ Generated: 29.09.20, 07:20 GMT ]