|
|
#include "shellprv.h"
#pragma hdrstop
#include <regstr.h>
TCHAR const c_szRunDll[] = TEXT("rundll32.exe");
//
// Emulate multi-threads with multi-processes.
//
STDAPI_(BOOL) SHRunDLLProcess(HWND hwnd, LPCTSTR pszCmdLine, int nCmdShow, UINT idStr, BOOL fRunAsNewUser) { BOOL bRet; HKEY hkey; SHELLEXECUTEINFO ExecInfo = {0}; TCHAR szPath[MAX_PATH];
// I hate network install. The windows directory is not the windows
// directory
szPath[0] = TEXT('\0'); if (RegOpenKey(HKEY_LOCAL_MACHINE, REGSTR_PATH_SETUP TEXT("\\Setup"), &hkey) == ERROR_SUCCESS) { DWORD dwType; DWORD cbData = SIZEOF(szPath);; if (SHQueryValueEx(hkey, TEXT("SharedDir"), NULL, &dwType, (LPBYTE)szPath, &cbData) != ERROR_SUCCESS) szPath[0] = TEXT('\0'); RegCloseKey(hkey); } PathCombine(szPath, szPath, c_szRunDll);
DebugMsg(DM_TRACE, TEXT("sh TR - RunDLLProcess (%s)"), pszCmdLine); FillExecInfo(ExecInfo, hwnd, NULL, szPath, pszCmdLine, szNULL, nCmdShow);
// if we want to launch this cpl as a new user, set the verb to be "runas"
if (fRunAsNewUser) { ExecInfo.lpVerb = TEXT("runas"); } else { // normal execute so no ui, we do our own error messages
ExecInfo.fMask = SEE_MASK_FLAG_NO_UI; }
//
// We need to put an appropriate message box.
//
bRet = ShellExecuteEx(&ExecInfo);
if (!bRet && !fRunAsNewUser) { // If we failed and we werent passing fRunAsNewUser, then we put up our own error UI,
// else, if we were running this as a new user, then we didnt pass SEE_MASK_FLAG_NO_UI
// so the error is already taken care of for us by shellexec.
TCHAR szTitle[64]; DWORD dwErr = GetLastError(); // LoadString can stomp on this (on failure)
LoadString(HINST_THISDLL, idStr, szTitle, ARRAYSIZE(szTitle)); ExecInfo.fMask = 0; _ShellExecuteError(&ExecInfo, szTitle, dwErr); }
return bRet; }
LRESULT CALLBACK WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) { switch(uMsg) { case STUBM_SETICONTITLE: if (lParam) SetWindowText(hWnd, (LPCTSTR)lParam); if (wParam) SendMessage(hWnd, WM_SETICON, ICON_BIG, wParam); break;
case STUBM_SETDATA: SetWindowLongPtr(hWnd, 0, wParam); break; case STUBM_GETDATA: return GetWindowLong(hWnd, 0); default: return DefWindowProc(hWnd, uMsg, wParam, lParam) ; } return 0; }
HWND _CreateStubWindow(POINT * ppt, HWND hwndParent) { WNDCLASS wc; int cx, cy; // If the stub window is parented, then we want it to be a tool window. This prevents activation
// problems when this is used in multimon for positioning.
DWORD dwExStyle = hwndParent? WS_EX_TOOLWINDOW : WS_EX_APPWINDOW; if (!GetClassInfo(HINST_THISDLL, c_szStubWindowClass, &wc)) { wc.style = 0; wc.lpfnWndProc = WndProc; wc.cbClsExtra = 0; wc.cbWndExtra = SIZEOF(DWORD) * 2; wc.hInstance = HINST_THISDLL; wc.hIcon = NULL; wc.hCursor = LoadCursor (NULL, IDC_ARROW); wc.hbrBackground = GetStockObject (WHITE_BRUSH); wc.lpszMenuName = NULL; wc.lpszClassName = c_szStubWindowClass;
RegisterClass(&wc); }
cx = cy = CW_USEDEFAULT; if (ppt) { cx = (int)ppt->x; cy = (int)ppt->y; }
if (IS_BIDI_LOCALIZED_SYSTEM()) { dwExStyle |= dwExStyleRTLMirrorWnd; } // WS_EX_APPWINDOW makes this show up in ALT+TAB, but not the tray.
return CreateWindowEx(dwExStyle, c_szStubWindowClass, c_szNULL, hwndParent? WS_POPUP : WS_OVERLAPPED, cx, cy, 0, 0, hwndParent, NULL, HINST_THISDLL, NULL); }
typedef struct // dlle
{ HINSTANCE hinst; RUNDLLPROC lpfn; BOOL fCmdIsANSI; } DLLENTRY;
BOOL _InitializeDLLEntry(LPTSTR lpszCmdLine, DLLENTRY * pdlle) { LPTSTR lpStart, lpEnd, lpFunction;
DebugMsg(DM_TRACE, TEXT("sh TR - RunDLLThread (%s)"), lpszCmdLine);
for (lpStart=lpszCmdLine; ; ) { // Skip leading blanks
//
while (*lpStart == TEXT(' ')) { ++lpStart; }
// Check if there are any switches
//
if (*lpStart != TEXT('/')) { break; }
// Look at all the switches; ignore unknown ones
//
for (++lpStart; ; ++lpStart) { switch (*lpStart) { case TEXT(' '): case TEXT('\0'): goto EndSwitches; break;
// Put any switches we care about here
//
default: break; } } EndSwitches: ; }
// We have found the DLL,FN parameter
//
lpEnd = StrChr(lpStart, TEXT(' ')); if (lpEnd) { *lpEnd++ = TEXT('\0'); }
// There must be a DLL name and a function name
//
lpFunction = StrChr(lpStart, TEXT(',')); if (!lpFunction) { return(FALSE); } *lpFunction++ = TEXT('\0');
// Load the library and get the procedure address
// Note that we try to get a module handle first, so we don't need
// to pass full file names around
//
pdlle->hinst = GetModuleHandle(lpStart); if (pdlle->hinst) { TCHAR szName[MAXPATHLEN];
GetModuleFileName(pdlle->hinst, szName, ARRAYSIZE(szName)); LoadLibrary(szName); } else { pdlle->hinst = LoadLibrary(lpStart); if (!ISVALIDHINSTANCE(pdlle->hinst)) { return(FALSE); } }
#ifdef UNICODE
{ /*
* Look for a 'W' tagged Unicode function. * If it is not there, then look for the 'A' tagged ANSI function * if we cant find that one either, then look for an un-tagged function */ LPSTR pszFunctionName; UINT cchLength;
cchLength = lstrlen(lpFunction)+1; pdlle->fCmdIsANSI = FALSE;
pszFunctionName = (LPSTR)LocalAlloc(LMEM_FIXED, (cchLength+1)*2); // +1 for "W", *2 for DBCS
if (pszFunctionName && (WideCharToMultiByte (CP_ACP, 0, lpFunction, cchLength, pszFunctionName, cchLength*2, NULL, NULL))) {
cchLength = lstrlenA(pszFunctionName); pszFunctionName[cchLength] = 'W'; // convert name to Wide version
pszFunctionName[cchLength+1] = '\0';
pdlle->lpfn = (RUNDLLPROC)GetProcAddress(pdlle->hinst, pszFunctionName);
if (pdlle->lpfn == NULL) { // No UNICODE version, try for ANSI
pszFunctionName[cchLength] = 'A'; // convert name to ANSI version
pdlle->fCmdIsANSI = TRUE;
pdlle->lpfn = (RUNDLLPROC)GetProcAddress(pdlle->hinst, pszFunctionName);
if (pdlle->lpfn == NULL) { // No ANSI version either, try for non-tagged
pszFunctionName[cchLength] = '\0'; // convert name to ANSI version
pdlle->lpfn = (RUNDLLPROC)GetProcAddress(pdlle->hinst, pszFunctionName); } } } if (pszFunctionName) { LocalFree((LPVOID)pszFunctionName); } } #else
{ /*
* Look for 'A' tagged ANSI version. * If it is not there, then look for a non-tagged function. */ LPSTR pszFunction; int cchFunction;
pdlle->lpfn = NULL;
cchFunction = lstrlen(lpFunction);
pszFunction = LocalAlloc(LMEM_FIXED, cchFunction + sizeof(CHAR) * 2); // string + 'A' + '\0'
if (pszFunction != NULL) { CopyMemory(pszFunction, lpFunction, cchFunction);
pszFunction[cchFunction++] = 'A'; pszFunction[cchFunction] = '\0';
pdlle->lpfn = (RUNDLLPROC)GetProcAddress(pdlle->hinst, pszFunction);
LocalFree(pszFunction); } }
#endif
if (!pdlle->lpfn) { FreeLibrary(pdlle->hinst); return(FALSE); }
// Copy the rest of the command parameters down
//
if (lpEnd) { lstrcpy(lpszCmdLine, lpEnd); } else { *lpszCmdLine = TEXT('\0'); }
return(TRUE); }
typedef struct tagRunThreadParam { int nCmdShow; TCHAR szCmdLine[1]; } RUNTHREADPARAM;
DWORD WINAPI _ThreadInitDLL(LPVOID pv) { RUNTHREADPARAM * prtp = (RUNTHREADPARAM*)pv; LPTSTR pszCmdLine = (LPTSTR)&prtp->szCmdLine; DLLENTRY dlle;
if (_InitializeDLLEntry(pszCmdLine, &dlle)) { HWND hwndStub=_CreateStubWindow(NULL, NULL); if (hwndStub) { ULONG cchCmdLine = 0; SetForegroundWindow(hwndStub); #ifdef UNICODE
if (dlle.fCmdIsANSI) { //
// If the function is an ANSI version
// Change the command line parameter strings to ANSI before we call the function
//
int cchCmdLine = lstrlen(pszCmdLine);
LPVOID pszCommand = LocalAlloc(LMEM_FIXED, sizeof(char) * (cchCmdLine + 1)); if (pszCommand) { WideCharToMultiByte(CP_ACP, 0, pszCmdLine, -1, pszCommand, cchCmdLine, NULL, NULL); } dlle.lpfn(hwndStub, g_hinst, pszCommand, prtp->nCmdShow);
} else #endif
{ dlle.lpfn(hwndStub, g_hinst, pszCmdLine, prtp->nCmdShow); } DestroyWindow(hwndStub); } FreeLibrary(dlle.hinst); }
LocalFree((HLOCAL)prtp);
return 0; }
BOOL WINAPI SHRunDLLThread(HWND hwnd, LPCTSTR pszCmdLine, int nCmdShow) { BOOL fSuccess = FALSE; // assume error
// don't need +1 on lstrlen since szCmdLine is already of size 1 (for NULL)
RUNTHREADPARAM * prtp = LocalAlloc(LPTR, sizeof(RUNTHREADPARAM) + (lstrlen(pszCmdLine) * sizeof(TCHAR)));
if (prtp) { DWORD idThread; HANDLE hthread;
lstrcpy(prtp->szCmdLine, pszCmdLine);
hthread = CreateThread(NULL, 0, _ThreadInitDLL, prtp, 0, &idThread); if (hthread) { // We don't need to communicate with this thread any more.
// Close the handle and let it run and terminate itself.
//
// Notes: In this case, prtp will be freed by the thread.
//
CloseHandle(hthread); fSuccess = TRUE; } else { // Thread creation failed, we should free the buffer.
LocalFree((HLOCAL)prtp); } }
return fSuccess; }
|