Changed default timeout to 15 seconds (from 100 seconds). Returns now if CreateProcess fails. Now closes handles if unable to allocate memory.

git-svn-id: https://svn.code.sf.net/p/nsis/code/NSIS/trunk@1258 212acab6-be3b-0410-9dea-997c60f758d6
This commit is contained in:
rainwater 2002-10-01 22:09:53 +00:00
parent 65bc61f40f
commit c9b3214463
3 changed files with 224 additions and 206 deletions

View file

@ -3,6 +3,7 @@ nsExec
nsExec will execute command-line based programs and capture the output nsExec will execute command-line based programs and capture the output
without opening a dos box. without opening a dos box.
Usage Usage
----- -----
nsExec::Exec [/TIMEOUT=x] path nsExec::Exec [/TIMEOUT=x] path
@ -15,13 +16,18 @@ Both functions are the same except ExecToLog will print the output
to the logwindow. to the logwindow.
The timeout value is optional and is used to set the time in The timeout value is optional and is used to set the time in
milliseconds for the dll to wait for the process to return milliseconds for the plugin to wait for the process to return
before it quits. before it quits.
Return Value Return Value
------------ ------------
If nsExec is unable to execute the process, it will return "error" If nsExec is unable to execute the process, it will return "error"
on the top of the stack, else it returns "success". on the top of the stack, else it returns the return code from the
executed process.
Copyright (c) 2002 Robert Rainwater Copyright Info
--------------
Copyright (c) 2002 Robert Rainwater
Thanks to Justin Frankel and Amir Szekely

View file

@ -1,3 +1,23 @@
/*
Copyright (c) 2002 Robert Rainwater <rrainwater@yahoo.com>
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
#include <windows.h> #include <windows.h>
#include <commctrl.h> #include <commctrl.h>
#include "../exdll/exdll.h" #include "../exdll/exdll.h"
@ -8,245 +28,237 @@
#ifndef false #ifndef false
#define false FALSE #define false FALSE
#endif #endif
#define TIMEOUT 100000 #define TIMEOUT 15000
#define LOOPTIMEOUT 100 #define LOOPTIMEOUT 100
HINSTANCE g_hInstance; HINSTANCE g_hInstance;
HWND g_hwndParent; HWND g_hwndParent;
HWND g_hwndList; HWND g_hwndList;
HWND g_hwndDlg; HWND g_hwndDlg;
char * g_exec; char * g_exec;
char * g_szto; char * g_szto;
BOOL g_foundto; BOOL g_foundto;
int g_to; int g_to;
void ExecScript(BOOL log); void ExecScript(BOOL log);
void LogMessages(const char *pStr);
void LogMessage(const char *pStr); void LogMessage(const char *pStr);
char *my_strstr(const char *string, const char *strCharSet); char *my_strstr(const char *string, const char *strCharSet);
int my_atoi(char *s); int my_atoi(char *s);
void __declspec(dllexport) Exec(HWND hwndParent, int string_size, char *variables, stack_t **stacktop) { void __declspec(dllexport) Exec(HWND hwndParent, int string_size, char *variables, stack_t **stacktop) {
g_hwndParent=hwndParent; g_hwndParent=hwndParent;
EXDLL_INIT(); EXDLL_INIT();
{ {
ExecScript(false); ExecScript(false);
} }
} }
void __declspec(dllexport) ExecToLog(HWND hwndParent, int string_size, char *variables, stack_t **stacktop) { void __declspec(dllexport) ExecToLog(HWND hwndParent, int string_size, char *variables, stack_t **stacktop) {
g_hwndParent=hwndParent; g_hwndParent=hwndParent;
EXDLL_INIT(); EXDLL_INIT();
{ {
ExecScript(true); ExecScript(true);
} }
} }
BOOL WINAPI _DllMainCRTStartup(HANDLE hInst, ULONG ul_reason_for_call, LPVOID lpReserved) { BOOL WINAPI _DllMainCRTStartup(HANDLE hInst, ULONG ul_reason_for_call, LPVOID lpReserved) {
g_hInstance=hInst; g_hInstance=hInst;
return TRUE; return TRUE;
} }
void ExecScript(BOOL log) { void ExecScript(BOOL log) {
g_to = TIMEOUT; g_to = TIMEOUT;
g_foundto = FALSE; g_foundto = FALSE;
g_hwndDlg = FindWindowEx(g_hwndParent,NULL,"#32770",NULL); g_hwndDlg = FindWindowEx(g_hwndParent,NULL,"#32770",NULL);
g_hwndList = FindWindowEx(g_hwndDlg,NULL,"SysListView32",NULL); g_hwndList = FindWindowEx(g_hwndDlg,NULL,"SysListView32",NULL);
g_exec = (char *)GlobalAlloc(GPTR, sizeof(char)*g_stringsize+1); g_exec = (char *)GlobalAlloc(GPTR, sizeof(char)*g_stringsize+1);
g_szto = (char *)GlobalAlloc(GPTR, sizeof(char)*g_stringsize+1); g_szto = (char *)GlobalAlloc(GPTR, sizeof(char)*g_stringsize+1);
if (!popstring(g_szto)) { if (!popstring(g_szto)) {
if (my_strstr(g_szto,"/TIMEOUT=")) { if (my_strstr(g_szto,"/TIMEOUT=")) {
g_szto += 9; g_szto += 9;
g_to = my_atoi(g_szto); g_to = my_atoi(g_szto);
if (g_to<0) g_to = TIMEOUT; if (g_to<0) g_to = TIMEOUT;
g_foundto = TRUE; g_foundto = TRUE;
}
} }
} if (g_foundto) {
if (g_foundto) { if (popstring(g_exec)) {
if (popstring(g_exec)) { pushstring("error");
pushstring("error"); return;
return; }
} }
} else {
else { lstrcpy(g_exec,g_szto);
lstrcpy(g_exec,g_szto); }
} {
{ STARTUPINFO si={sizeof(si),};
STARTUPINFO si={sizeof(si),}; SECURITY_ATTRIBUTES sa={sizeof(sa),};
SECURITY_ATTRIBUTES sa={sizeof(sa),}; SECURITY_DESCRIPTOR sd={0,};
SECURITY_DESCRIPTOR sd={0,}; PROCESS_INFORMATION pi={0,};
PROCESS_INFORMATION pi={0,}; OSVERSIONINFO osv={sizeof(osv)};
OSVERSIONINFO osv={sizeof(osv)}; HANDLE newstdout=0,read_stdout=0;
HANDLE newstdout=0,read_stdout=0; DWORD dwRead = 1;
DWORD dwRead = 1; DWORD dwExit = !STILL_ACTIVE;
DWORD dwExit = !STILL_ACTIVE; static char szBuf[1024];
static char szBuf[1024]; static char szRet[128];
static char szRet[128]; HGLOBAL hUnusedBuf;
static char *szUnusedBuf;
HGLOBAL hUnusedBuf;
static char *szUnusedBuf;
if (log) {
hUnusedBuf = GlobalAlloc(GHND, sizeof(szBuf)*4);
if (!hUnusedBuf) {
pushstring("error");
return;
}
szUnusedBuf = (char *)GlobalLock(hUnusedBuf);
}
GetVersionEx(&osv);
if (osv.dwPlatformId == VER_PLATFORM_WIN32_NT) {
InitializeSecurityDescriptor(&sd,SECURITY_DESCRIPTOR_REVISION);
SetSecurityDescriptorDacl(&sd,true,NULL,false);
sa.lpSecurityDescriptor = &sd;
}
else sa.lpSecurityDescriptor = NULL;
sa.bInheritHandle = true;
if (!CreatePipe(&read_stdout,&newstdout,&sa,0)) {
pushstring("error");
return;
}
GetStartupInfo(&si);
si.dwFlags = STARTF_USESTDHANDLES|STARTF_USESHOWWINDOW;
si.wShowWindow = SW_HIDE;
si.hStdOutput = newstdout;
si.hStdError = newstdout;
if (!CreateProcess(NULL,g_exec,NULL,NULL,TRUE,CREATE_NEW_CONSOLE,NULL,NULL,&si,&pi)) {
CloseHandle(newstdout);
CloseHandle(read_stdout);
pushstring("error");
}
while (dwExit == STILL_ACTIVE || dwRead) {
PeekNamedPipe(read_stdout, 0, 0, 0, &dwRead, NULL);
if (dwRead) {
ReadFile(read_stdout, szBuf, sizeof(szBuf)-1, &dwRead, NULL);
szBuf[dwRead] = 0;
if (log) { if (log) {
char *p, *lineBreak; hUnusedBuf = GlobalAlloc(GHND, sizeof(szBuf)*4);
SIZE_T iReqLen = lstrlen(szBuf) + lstrlen(szUnusedBuf);
if (GlobalSize(hUnusedBuf) < iReqLen) {
GlobalUnlock(hUnusedBuf);
hUnusedBuf = GlobalReAlloc(hUnusedBuf, iReqLen+sizeof(szBuf), GHND);
if (!hUnusedBuf) { if (!hUnusedBuf) {
pushstring("error"); pushstring("error");
return; return;
} }
szUnusedBuf = (char *)GlobalLock(hUnusedBuf); szUnusedBuf = (char *)GlobalLock(hUnusedBuf);
}
p = szUnusedBuf; // get the old left overs
lstrcat(p, szBuf);
while (lineBreak = my_strstr(p, "\r\n")) {
*lineBreak = 0;
LogMessage(p);
p = lineBreak + 2;
}
// If data was taken out from the unused buffer, move p contents to the start of szUnusedBuf
if (p != szUnusedBuf) {
char *p2 = szUnusedBuf;
while (*p)
*p2++ = *p++;
*p2 = 0;
}
} }
}
else Sleep(LOOPTIMEOUT); GetVersionEx(&osv);
GetExitCodeProcess(pi.hProcess, &dwExit); if (osv.dwPlatformId == VER_PLATFORM_WIN32_NT) {
if (dwExit != STILL_ACTIVE) { InitializeSecurityDescriptor(&sd,SECURITY_DESCRIPTOR_REVISION);
PeekNamedPipe(read_stdout, 0, 0, 0, &dwRead, NULL); SetSecurityDescriptorDacl(&sd,true,NULL,false);
} sa.lpSecurityDescriptor = &sd;
}
else sa.lpSecurityDescriptor = NULL;
sa.bInheritHandle = true;
if (!CreatePipe(&read_stdout,&newstdout,&sa,0)) {
pushstring("error");
return;
}
GetStartupInfo(&si);
si.dwFlags = STARTF_USESTDHANDLES|STARTF_USESHOWWINDOW;
si.wShowWindow = SW_HIDE;
si.hStdOutput = newstdout;
si.hStdError = newstdout;
if (!CreateProcess(NULL,g_exec,NULL,NULL,TRUE,CREATE_NEW_CONSOLE,NULL,NULL,&si,&pi)) {
CloseHandle(newstdout);
CloseHandle(read_stdout);
pushstring("error");
return;
}
while (dwExit == STILL_ACTIVE || dwRead) {
PeekNamedPipe(read_stdout, 0, 0, 0, &dwRead, NULL);
if (dwRead) {
ReadFile(read_stdout, szBuf, sizeof(szBuf)-1, &dwRead, NULL);
szBuf[dwRead] = 0;
if (log) {
char *p, *lineBreak;
SIZE_T iReqLen = lstrlen(szBuf) + lstrlen(szUnusedBuf);
if (GlobalSize(hUnusedBuf) < iReqLen) {
GlobalUnlock(hUnusedBuf);
hUnusedBuf = GlobalReAlloc(hUnusedBuf, iReqLen+sizeof(szBuf), GHND);
if (!hUnusedBuf) {
pushstring("error");
CloseHandle(pi.hThread);
CloseHandle(pi.hProcess);
CloseHandle(newstdout);
CloseHandle(read_stdout);
return;
}
szUnusedBuf = (char *)GlobalLock(hUnusedBuf);
}
p = szUnusedBuf; // get the old left overs
lstrcat(p, szBuf);
while (lineBreak = my_strstr(p, "\r\n")) {
*lineBreak = 0;
LogMessage(p);
p = lineBreak + 2;
}
// If data was taken out from the unused buffer, move p contents to the start of szUnusedBuf
if (p != szUnusedBuf) {
char *p2 = szUnusedBuf;
while (*p) *p2++ = *p++;
*p2 = 0;
}
}
}
else Sleep(LOOPTIMEOUT);
GetExitCodeProcess(pi.hProcess, &dwExit);
if (dwExit != STILL_ACTIVE) {
PeekNamedPipe(read_stdout, 0, 0, 0, &dwRead, NULL);
}
}
if (*szUnusedBuf) LogMessage(szUnusedBuf);
wsprintf(szRet,"%d",dwExit);
pushstring(szRet);
CloseHandle(pi.hThread);
CloseHandle(pi.hProcess);
CloseHandle(newstdout);
CloseHandle(read_stdout);
if (log) GlobalUnlock(hUnusedBuf);
} }
if (*szUnusedBuf) LogMessage(szUnusedBuf);
wsprintf(szRet,"%d",dwExit);
pushstring(szRet);
CloseHandle(pi.hThread);
CloseHandle(pi.hProcess);
CloseHandle(newstdout);
CloseHandle(read_stdout);
if (log) GlobalUnlock(hUnusedBuf);
}
} }
// code I stole (err borrowed) from Tim Kosse // Tim Kosse's LogMessage
// all credits/problems are his
void LogMessage(const char *pStr) { void LogMessage(const char *pStr) {
LVITEM item={0}; LVITEM item={0};
int nItemCount; int nItemCount;
if (!g_hwndList) return; if (!g_hwndList) return;
if (!lstrlen(pStr)) return; if (!lstrlen(pStr)) return;
nItemCount=SendMessage(g_hwndList, LVM_GETITEMCOUNT, 0, 0); nItemCount=SendMessage(g_hwndList, LVM_GETITEMCOUNT, 0, 0);
item.mask=LVIF_TEXT; item.mask=LVIF_TEXT;
item.pszText=(char *)pStr; item.pszText=(char *)pStr;
item.cchTextMax=0; item.cchTextMax=0;
item.iItem=nItemCount; item.iItem=nItemCount;
ListView_InsertItem(g_hwndList, &item); ListView_InsertItem(g_hwndList, &item);
ListView_EnsureVisible(g_hwndList, item.iItem, 0); ListView_EnsureVisible(g_hwndList, item.iItem, 0);
} }
char *my_strstr(const char *string, const char *strCharSet) { char *my_strstr(const char *string, const char *strCharSet) {
char *s1, *s2; char *s1, *s2;
size_t chklen; size_t chklen;
size_t i; size_t i;
if (lstrlen(string) < lstrlen(strCharSet)) return 0; if (lstrlen(string) < lstrlen(strCharSet)) return 0;
if (!*strCharSet) return (char*)string; if (!*strCharSet) return (char*)string;
chklen=lstrlen(string)-lstrlen(strCharSet); chklen=lstrlen(string)-lstrlen(strCharSet);
for (i = 0; i <= chklen; i++) { for (i = 0; i <= chklen; i++) {
s1=&((char*)string)[i]; s1=&((char*)string)[i];
s2=(char*)strCharSet; s2=(char*)strCharSet;
while (*s1++ == *s2++) while (*s1++ == *s2++)
if (!*s2) if (!*s2) return &((char*)string)[i];
return &((char*)string)[i]; }
} return 0;
return 0;
} }
int my_atoi(char *s) int my_atoi(char *s) {
{ unsigned int v=0;
unsigned int v=0; if (*s == '0' && (s[1] == 'x' || s[1] == 'X')) {
if (*s == '0' && (s[1] == 'x' || s[1] == 'X')) s+=2;
{ for (;;) {
s+=2; int c=*s++;
for (;;) if (c >= '0' && c <= '9') c-='0';
{ else if (c >= 'a' && c <= 'f') c-='a'-10;
int c=*s++; else if (c >= 'A' && c <= 'F') c-='A'-10;
if (c >= '0' && c <= '9') c-='0'; else break;
else if (c >= 'a' && c <= 'f') c-='a'-10; v<<=4;
else if (c >= 'A' && c <= 'F') c-='A'-10; v+=c;
else break; }
v<<=4; }
v+=c; else if (*s == '0' && s[1] <= '7' && s[1] >= '0') {
} s++;
} for (;;) {
else if (*s == '0' && s[1] <= '7' && s[1] >= '0') int c=*s++;
{ if (c >= '0' && c <= '7') c-='0';
s++; else break;
for (;;) v<<=3;
{ v+=c;
int c=*s++; }
if (c >= '0' && c <= '7') c-='0'; }
else break; else {
v<<=3; int sign=0;
v+=c; if (*s == '-') { s++; sign++; }
} for (;;) {
} int c=*s++ - '0';
else if (c < 0 || c > 9) break;
{ v*=10;
int sign=0; v+=c;
if (*s == '-') { s++; sign++; } }
for (;;) if (sign) return -(int) v;
{ }
int c=*s++ - '0'; return (int)v;
if (c < 0 || c > 9) break;
v*=10;
v+=c;
}
if (sign) return -(int) v;
}
return (int)v;
} }

Binary file not shown.