From 024e01a71ed00beca612260131642d97c33f676b Mon Sep 17 00:00:00 2001 From: anders_k Date: Tue, 21 Mar 2017 22:04:40 +0000 Subject: [PATCH] Added ExecShellWait git-svn-id: https://svn.code.sf.net/p/nsis/code/NSIS/trunk@6839 212acab6-be3b-0410-9dea-997c60f758d6 --- Docs/src/basic.but | 11 +++++++++-- Docs/src/history.but | 2 ++ Source/exehead/exec.c | 31 +++++++++++++++++-------------- Source/exehead/fileform.h | 4 ++-- Source/exehead/util.c | 10 ++++++++++ Source/exehead/util.h | 4 +++- Source/script.cpp | 25 ++++++++++++++----------- Source/tokens.cpp | 3 ++- Source/tokens.h | 1 + 9 files changed, 60 insertions(+), 31 deletions(-) diff --git a/Docs/src/basic.but b/Docs/src/basic.but index 0e96ae41..e3462150 100644 --- a/Docs/src/basic.but +++ b/Docs/src/basic.but @@ -27,13 +27,20 @@ Execute the specified program and continue immediately. Note that the file speci \S2{execshell} ExecShell -\c action command [parameters] [SW_SHOWDEFAULT | SW_SHOWNORMAL | SW_SHOWMAXIMIZED | SW_SHOWMINIMIZED | SW_HIDE] +\c [/INVOKEIDLIST] action command [parameters] [SW_SHOWDEFAULT | SW_SHOWNORMAL | SW_SHOWMAXIMIZED | SW_SHOWMINIMIZED | SW_HIDE] -Execute the specified program using ShellExecute. Note that action is usually "open", "print", etc, but can be an empty string to use the default action. Parameters and the show type are optional. $OUTDIR is used as the working directory. The error flag is set if the process could not be launched. +Execute the specified program using ShellExecuteEx. Note that action is usually "open", "print", etc, but can be an empty string to use the default action. Parameters and the show type are optional. $OUTDIR is used as the working directory. The error flag is set if the process could not be launched. \c ExecShell "open" "http://nsis.sf.net/" \c ExecShell "open" "$INSTDIR\readme.txt" \c ExecShell "print" "$INSTDIR\readme.txt" +\c ExecShell /INVOKEIDLIST "properties" "$TEMP" + +\S2{execshellwait} ExecShellWait + +\c [/INVOKEIDLIST] action command [parameters] [SW_SHOWDEFAULT | SW_SHOWNORMAL | SW_SHOWMAXIMIZED | SW_SHOWMINIMIZED | SW_HIDE] + +Execute the specified program using ExecShell and wait for executed process to quit. It will only wait for executable files and not other file types nor URLs. \S2{execwait} ExecWait diff --git a/Docs/src/history.but b/Docs/src/history.but index b48d6fef..6bb9d115 100644 --- a/Docs/src/history.but +++ b/Docs/src/history.but @@ -8,6 +8,8 @@ Released on ? ?th, 2017 \S2{} Major Changes +\b Added \R{execshellwait}{ExecShellWait} + \b Added \R{writeregmultistr}{WriteRegMultiStr} (\W{http://sf.net/p/nsis/feature-requests/382}{RFE #382}, \W{http://sf.net/p/nsis/patches/219}{patch #219}) \S2{} Minor Changes diff --git a/Source/exehead/exec.c b/Source/exehead/exec.c index 78066e80..cba43871 100644 --- a/Source/exehead/exec.c +++ b/Source/exehead/exec.c @@ -876,20 +876,29 @@ static int NSISCALL ExecuteEntry(entry *entry_) #ifdef NSIS_SUPPORT_SHELLEXECUTE case EW_SHELLEXEC: // this uses improvements of Andras Varga { - int x; - TCHAR *buf0=GetStringFromParm(0x00); - TCHAR *buf3=GetStringFromParm(0x31); - TCHAR *buf2=GetStringFromParm(0x22); + SHELLEXECUTEINFO sei; + TCHAR *buf0=GetStringFromParm(0x00); // Verb + TCHAR *buf3=GetStringFromParm(0x31); // File + TCHAR *buf2=GetStringFromParm(0x22); // Parameters GetStringFromParm(0x15); // For update_status_text_buf1 update_status_text_buf1(LANG_EXECSHELL); - x=(int)(INT_PTR)ShellExecute(g_hwnd,buf0[0]?buf0:NULL,buf3,buf2[0]?buf2:NULL,state_output_directory,parm3); - if (x < 33) + sei.cbSize=sizeof(SHELLEXECUTEINFO); + sei.fMask=parm4; + sei.hwnd=g_hwnd, sei.nShow=parm3; + sei.lpVerb=buf0[0]?buf0:NULL, sei.lpFile=buf3, sei.lpParameters=buf2[0]?buf2:NULL, sei.lpDirectory=state_output_directory; + sei.lpIDList=NULL; // Must set this because SEE_MASK_INVOKEIDLIST might be set + if (!ShellExecuteEx(&sei)) { log_printf5(_T("ExecShell: warning: error (\"%s\": file:\"%s\" params:\"%s\")=%d"),buf0,buf3,buf2,x); exec_error++; } else { + if (SEE_MASK_NOCLOSEPROCESS & sei.fMask) + { + WaitForProcess(sei.hProcess); + CloseHandle(sei.hProcess); + } log_printf4(_T("ExecShell: success (\"%s\": file:\"%s\" params:\"%s\")"),buf0,buf3,buf2); } } @@ -910,17 +919,11 @@ static int NSISCALL ExecuteEntry(entry *entry_) log_printf2(_T("Exec: success (\"%s\")"),buf0); if (parm2) { - DWORD lExitCode; - while (WaitForSingleObject(hProc,100) == WAIT_TIMEOUT) - { - MessageLoop(WM_PAINT); - } - GetExitCodeProcess(hProc, &lExitCode); - + DWORD lExitCode=WaitForProcess(hProc); if (parm1>=0) myitoa(var1,lExitCode); else if (lExitCode) exec_error++; } - CloseHandle( hProc ); + CloseHandle(hProc); } else { diff --git a/Source/exehead/fileform.h b/Source/exehead/fileform.h index 597a6ece..5bf0f716 100644 --- a/Source/exehead/fileform.h +++ b/Source/exehead/fileform.h @@ -50,7 +50,7 @@ enum { EW_INVALID_OPCODE, // zero is invalid. useful for catching errors. (otherwise an all zeroes instruction - // does nothing, which is easily ignored but means something is wrong. + // does nothing, which is easily ignored but means something is wrong) EW_RET, // return from function call EW_NOP, // Nop/Jump, do nothing: 1, [?new address+1:advance one] EW_ABORT, // Abort: 1 [status] @@ -118,7 +118,7 @@ enum #endif #ifdef NSIS_SUPPORT_SHELLEXECUTE - EW_SHELLEXEC, // ShellExecute program: 4, [shell action, complete commandline, parameters, showwindow] + EW_SHELLEXEC, // ShellExecute program: 5, [SEE_MASK_FLAG_*, verb, file, parameters, showwindow] (Will wait if SEE_MASK_NOCLOSEPROCESS is set) #endif #ifdef NSIS_SUPPORT_EXECUTE diff --git a/Source/exehead/util.c b/Source/exehead/util.c index 6131bf2f..48aa5936 100644 --- a/Source/exehead/util.c +++ b/Source/exehead/util.c @@ -1192,3 +1192,13 @@ void * NSISCALL NSISGetProcAddress(HANDLE dllHandle, TCHAR* funcName) return GetProcAddress(dllHandle, funcName); #endif } + +DWORD NSISCALL WaitForProcess(HANDLE hProcess) +{ + DWORD excod; + while (WaitForSingleObject(hProcess, 100) == WAIT_TIMEOUT) + MessageLoop(WM_PAINT); + + GetExitCodeProcess(hProcess, &excod); + return excod; +} diff --git a/Source/exehead/util.h b/Source/exehead/util.h index a5081d0f..8280e7b0 100644 --- a/Source/exehead/util.h +++ b/Source/exehead/util.h @@ -157,7 +157,9 @@ void NSISCALL MessageLoop(UINT uCheckedMsg); * @param funcName The name of the function to get the address of. * @return The pointer to the function. Null if failure. */ -void * NSISCALL NSISGetProcAddress(HANDLE dllHandle, TCHAR* funcName); +void* NSISCALL NSISGetProcAddress(HANDLE dllHandle, TCHAR* funcName); + +DWORD NSISCALL WaitForProcess(HANDLE hProcess); // Turn a pair of chars into a word // Turn four chars into a dword diff --git a/Source/script.cpp b/Source/script.cpp index 4e88d5a2..74429df7 100644 --- a/Source/script.cpp +++ b/Source/script.cpp @@ -4135,25 +4135,28 @@ int CEXEBuild::doCommand(int which_token, LineParser &line) ERROR_MSG(_T("Error: %") NPRIs _T(" specified, NSIS_SUPPORT_EXECUTE not defined.\n"), line.gettoken_str(0)); return PS_ERROR; #endif//!NSIS_SUPPORT_EXECUTE - case TOK_EXECSHELL: // this uses improvements of Andras Varga + case TOK_EXECSHELL: + case TOK_EXECSHELLWAIT: #ifdef NSIS_SUPPORT_SHELLEXECUTE { - const TCHAR *verb=line.gettoken_str(1), *file=line.gettoken_str(2), *params=line.gettoken_str(3); + UINT to=0, xflags=0; + static const TCHAR*fn=_T("/INVOKEIDLIST\0/CONNECTNETDRV\0/DOENVSUBST\0/NOIDLIST\0/NOCONSOLE\0/NOZONECHECKS\0/WAITFORINPUTIDLE\0/LOGUSAGE\0/ASYNCOK\0"); + static const UINT fv[]={ 0x0000000C, 0x00000080, 0x00000200, 0x00001000,0x00008000, 0x00800000, 0x02000000, 0x04000000,0x00100000 }; + for (int k;;) if ((k = line.gettoken_enum(to+1,fn)) < 0) { if (line.gettoken_str(to+1)[0]=='/') PRINTHELP(); break; } else xflags|=fv[k], to++; + const TCHAR *verb=line.gettoken_str(to+1), *file=line.gettoken_str(to+2), *params=line.gettoken_str(to+3), *cnam=get_commandtoken_name(which_token); ent.which=EW_SHELLEXEC; - ent.offsets[0]=add_string(verb); - ent.offsets[1]=add_string(file); - ent.offsets[2]=add_string(params); - ent.offsets[3]=SW_SHOWNORMAL; - if (line.getnumtokens() > 4) + ent.offsets[0]=add_string(verb), ent.offsets[1]=add_string(file); + ent.offsets[2]=add_string(params), ent.offsets[3]=SW_SHOWNORMAL; + ent.offsets[4]=SEE_MASK_FLAG_NO_UI|SEE_MASK_FLAG_DDEWAIT|xflags|(which_token==TOK_EXECSHELLWAIT ? SEE_MASK_NOCLOSEPROCESS : 0); + if (line.getnumtokens()-to > 4) { int tab[8]={SW_SHOWDEFAULT,SW_SHOWNORMAL,SW_SHOWMAXIMIZED,SW_SHOWMINIMIZED,SW_HIDE,SW_SHOW,SW_SHOWNA,SW_SHOWMINNOACTIVE}; - int a=line.gettoken_enum(4,_T("SW_SHOWDEFAULT\0SW_SHOWNORMAL\0SW_SHOWMAXIMIZED\0SW_SHOWMINIMIZED\0SW_HIDE\0SW_SHOW\0SW_SHOWNA\0SW_SHOWMINNOACTIVE\0")); - if (a < 0) PRINTHELP() - ent.offsets[3]=tab[a]; + int a=line.gettoken_enum(to+4,_T("SW_SHOWDEFAULT\0SW_SHOWNORMAL\0SW_SHOWMAXIMIZED\0SW_SHOWMINIMIZED\0SW_HIDE\0SW_SHOW\0SW_SHOWNA\0SW_SHOWMINNOACTIVE\0")); + if (a >= 0) ent.offsets[3]=tab[a]; else PRINTHELP() } tstring detail=tstring(verb)+(_T(" ")+!*verb)+tstring(file); ent.offsets[5]=add_string(detail.c_str()); - SCRIPT_MSG(_T("ExecShell: %") NPRIs _T(": \"%") NPRIs _T("\" \"%") NPRIs _T("\" %") NPRIs _T("\n"),verb,file,params,line.gettoken_str(4)); + SCRIPT_MSG(_T("%") NPRIs _T(": %") NPRIs _T(": \"%") NPRIs _T("\" \"%") NPRIs _T("\" %") NPRIs _T("\n"),cnam,verb,file,params,line.gettoken_str(to+4)); DefineInnerLangString(NLF_EXEC_SHELL); } return add_entry(&ent); diff --git a/Source/tokens.cpp b/Source/tokens.cpp index cf6f9689..fb3a8ecc 100644 --- a/Source/tokens.cpp +++ b/Source/tokens.cpp @@ -80,7 +80,8 @@ static tokenType tokenlist[TOK__LAST] = {TOK_EXCH,_T("Exch"),0,1,_T("[$(user_var)] | [stack_item_index]"),TP_CODE}, {TOK_EXEC,_T("Exec"),1,0,_T("command_line"),TP_CODE}, {TOK_EXECWAIT,_T("ExecWait"),1,1,_T("command_line [$(user_var: return value)]"),TP_CODE}, -{TOK_EXECSHELL,_T("ExecShell"),2,2,_T("(open|print|etc) command_line [parameters [showmode]]\n showmode=(SW_SHOWNORMAL|SW_SHOWMAXIMIZED|SW_SHOWMINIMIZED|SW_HIDE|SW_SHOW)"),TP_CODE}, +{TOK_EXECSHELL,_T("ExecShell"),2,11,_T("[flags] verb command_line [parameters [showmode]]\n verb=(open|print)\n showmode=(SW_SHOWNORMAL|SW_SHOWMAXIMIZED|SW_SHOWMINIMIZED|SW_HIDE|SW_SHOW)"),TP_CODE}, +{TOK_EXECSHELLWAIT,_T("ExecShellWait"),2,11,_T("[flags] verb command_line [parameters [showmode]]"),TP_CODE}, {TOK_EXPANDENVSTRS,_T("ExpandEnvStrings"),2,0,_T("$(user_var: output) string"),TP_CODE}, {TOK_FINDWINDOW,_T("FindWindow"),2,3,_T("$(user_var: handle output) WindowClass [WindowTitle] [Window_Parent] [Child_After]"),TP_CODE}, {TOK_FINDCLOSE,_T("FindClose"),1,0,_T("$(user_var: handle input)"),TP_CODE}, diff --git a/Source/tokens.h b/Source/tokens.h index 09e97a80..e454d322 100644 --- a/Source/tokens.h +++ b/Source/tokens.h @@ -176,6 +176,7 @@ enum TOK_EXEC, TOK_EXECWAIT, TOK_EXECSHELL, + TOK_EXECSHELLWAIT, TOK_CALLINSTDLL, TOK_REGDLL, TOK_UNREGDLL,