Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

400 lines
11 KiB

  1. #include "shellprv.h"
  2. #pragma hdrstop
  3. #include <regstr.h>
  4. TCHAR const c_szRunDll[] = TEXT("rundll32.exe");
  5. //
  6. // Emulate multi-threads with multi-processes.
  7. //
  8. STDAPI_(BOOL) SHRunDLLProcess(HWND hwnd, LPCTSTR pszCmdLine, int nCmdShow, UINT idStr, BOOL fRunAsNewUser)
  9. {
  10. BOOL bRet;
  11. HKEY hkey;
  12. SHELLEXECUTEINFO ExecInfo = {0};
  13. TCHAR szPath[MAX_PATH];
  14. // I hate network install. The windows directory is not the windows
  15. // directory
  16. szPath[0] = TEXT('\0');
  17. if (RegOpenKey(HKEY_LOCAL_MACHINE, REGSTR_PATH_SETUP TEXT("\\Setup"), &hkey) == ERROR_SUCCESS)
  18. {
  19. DWORD dwType;
  20. DWORD cbData = SIZEOF(szPath);;
  21. if (SHQueryValueEx(hkey, TEXT("SharedDir"), NULL, &dwType, (LPBYTE)szPath, &cbData) != ERROR_SUCCESS)
  22. szPath[0] = TEXT('\0');
  23. RegCloseKey(hkey);
  24. }
  25. PathCombine(szPath, szPath, c_szRunDll);
  26. DebugMsg(DM_TRACE, TEXT("sh TR - RunDLLProcess (%s)"), pszCmdLine);
  27. FillExecInfo(ExecInfo, hwnd, NULL, szPath, pszCmdLine, szNULL, nCmdShow);
  28. // if we want to launch this cpl as a new user, set the verb to be "runas"
  29. if (fRunAsNewUser)
  30. {
  31. ExecInfo.lpVerb = TEXT("runas");
  32. }
  33. else
  34. {
  35. // normal execute so no ui, we do our own error messages
  36. ExecInfo.fMask = SEE_MASK_FLAG_NO_UI;
  37. }
  38. //
  39. // We need to put an appropriate message box.
  40. //
  41. bRet = ShellExecuteEx(&ExecInfo);
  42. if (!bRet && !fRunAsNewUser)
  43. {
  44. // If we failed and we werent passing fRunAsNewUser, then we put up our own error UI,
  45. // else, if we were running this as a new user, then we didnt pass SEE_MASK_FLAG_NO_UI
  46. // so the error is already taken care of for us by shellexec.
  47. TCHAR szTitle[64];
  48. DWORD dwErr = GetLastError(); // LoadString can stomp on this (on failure)
  49. LoadString(HINST_THISDLL, idStr, szTitle, ARRAYSIZE(szTitle));
  50. ExecInfo.fMask = 0;
  51. _ShellExecuteError(&ExecInfo, szTitle, dwErr);
  52. }
  53. return bRet;
  54. }
  55. LRESULT CALLBACK WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
  56. {
  57. switch(uMsg)
  58. {
  59. case STUBM_SETICONTITLE:
  60. if (lParam)
  61. SetWindowText(hWnd, (LPCTSTR)lParam);
  62. if (wParam)
  63. SendMessage(hWnd, WM_SETICON, ICON_BIG, wParam);
  64. break;
  65. case STUBM_SETDATA:
  66. SetWindowLongPtr(hWnd, 0, wParam);
  67. break;
  68. case STUBM_GETDATA:
  69. return GetWindowLong(hWnd, 0);
  70. default:
  71. return DefWindowProc(hWnd, uMsg, wParam, lParam) ;
  72. }
  73. return 0;
  74. }
  75. HWND _CreateStubWindow(POINT * ppt, HWND hwndParent)
  76. {
  77. WNDCLASS wc;
  78. int cx, cy;
  79. // If the stub window is parented, then we want it to be a tool window. This prevents activation
  80. // problems when this is used in multimon for positioning.
  81. DWORD dwExStyle = hwndParent? WS_EX_TOOLWINDOW : WS_EX_APPWINDOW;
  82. if (!GetClassInfo(HINST_THISDLL, c_szStubWindowClass, &wc))
  83. {
  84. wc.style = 0;
  85. wc.lpfnWndProc = WndProc;
  86. wc.cbClsExtra = 0;
  87. wc.cbWndExtra = SIZEOF(DWORD) * 2;
  88. wc.hInstance = HINST_THISDLL;
  89. wc.hIcon = NULL;
  90. wc.hCursor = LoadCursor (NULL, IDC_ARROW);
  91. wc.hbrBackground = GetStockObject (WHITE_BRUSH);
  92. wc.lpszMenuName = NULL;
  93. wc.lpszClassName = c_szStubWindowClass;
  94. RegisterClass(&wc);
  95. }
  96. cx = cy = CW_USEDEFAULT;
  97. if (ppt)
  98. {
  99. cx = (int)ppt->x;
  100. cy = (int)ppt->y;
  101. }
  102. if (IS_BIDI_LOCALIZED_SYSTEM())
  103. {
  104. dwExStyle |= dwExStyleRTLMirrorWnd;
  105. }
  106. // WS_EX_APPWINDOW makes this show up in ALT+TAB, but not the tray.
  107. return CreateWindowEx(dwExStyle, c_szStubWindowClass, c_szNULL, hwndParent? WS_POPUP : WS_OVERLAPPED, cx, cy, 0, 0, hwndParent, NULL, HINST_THISDLL, NULL);
  108. }
  109. typedef struct // dlle
  110. {
  111. HINSTANCE hinst;
  112. RUNDLLPROC lpfn;
  113. BOOL fCmdIsANSI;
  114. } DLLENTRY;
  115. BOOL _InitializeDLLEntry(LPTSTR lpszCmdLine, DLLENTRY * pdlle)
  116. {
  117. LPTSTR lpStart, lpEnd, lpFunction;
  118. DebugMsg(DM_TRACE, TEXT("sh TR - RunDLLThread (%s)"), lpszCmdLine);
  119. for (lpStart=lpszCmdLine; ; )
  120. {
  121. // Skip leading blanks
  122. //
  123. while (*lpStart == TEXT(' '))
  124. {
  125. ++lpStart;
  126. }
  127. // Check if there are any switches
  128. //
  129. if (*lpStart != TEXT('/'))
  130. {
  131. break;
  132. }
  133. // Look at all the switches; ignore unknown ones
  134. //
  135. for (++lpStart; ; ++lpStart)
  136. {
  137. switch (*lpStart)
  138. {
  139. case TEXT(' '):
  140. case TEXT('\0'):
  141. goto EndSwitches;
  142. break;
  143. // Put any switches we care about here
  144. //
  145. default:
  146. break;
  147. }
  148. }
  149. EndSwitches:
  150. ;
  151. }
  152. // We have found the DLL,FN parameter
  153. //
  154. lpEnd = StrChr(lpStart, TEXT(' '));
  155. if (lpEnd)
  156. {
  157. *lpEnd++ = TEXT('\0');
  158. }
  159. // There must be a DLL name and a function name
  160. //
  161. lpFunction = StrChr(lpStart, TEXT(','));
  162. if (!lpFunction)
  163. {
  164. return(FALSE);
  165. }
  166. *lpFunction++ = TEXT('\0');
  167. // Load the library and get the procedure address
  168. // Note that we try to get a module handle first, so we don't need
  169. // to pass full file names around
  170. //
  171. pdlle->hinst = GetModuleHandle(lpStart);
  172. if (pdlle->hinst)
  173. {
  174. TCHAR szName[MAXPATHLEN];
  175. GetModuleFileName(pdlle->hinst, szName, ARRAYSIZE(szName));
  176. LoadLibrary(szName);
  177. }
  178. else
  179. {
  180. pdlle->hinst = LoadLibrary(lpStart);
  181. if (!ISVALIDHINSTANCE(pdlle->hinst))
  182. {
  183. return(FALSE);
  184. }
  185. }
  186. #ifdef UNICODE
  187. {
  188. /*
  189. * Look for a 'W' tagged Unicode function.
  190. * If it is not there, then look for the 'A' tagged ANSI function
  191. * if we cant find that one either, then look for an un-tagged function
  192. */
  193. LPSTR pszFunctionName;
  194. UINT cchLength;
  195. cchLength = lstrlen(lpFunction)+1;
  196. pdlle->fCmdIsANSI = FALSE;
  197. pszFunctionName = (LPSTR)LocalAlloc(LMEM_FIXED, (cchLength+1)*2); // +1 for "W", *2 for DBCS
  198. if (pszFunctionName && (WideCharToMultiByte (CP_ACP, 0, lpFunction, cchLength,
  199. pszFunctionName, cchLength*2, NULL, NULL))) {
  200. cchLength = lstrlenA(pszFunctionName);
  201. pszFunctionName[cchLength] = 'W'; // convert name to Wide version
  202. pszFunctionName[cchLength+1] = '\0';
  203. pdlle->lpfn = (RUNDLLPROC)GetProcAddress(pdlle->hinst, pszFunctionName);
  204. if (pdlle->lpfn == NULL) {
  205. // No UNICODE version, try for ANSI
  206. pszFunctionName[cchLength] = 'A'; // convert name to ANSI version
  207. pdlle->fCmdIsANSI = TRUE;
  208. pdlle->lpfn = (RUNDLLPROC)GetProcAddress(pdlle->hinst, pszFunctionName);
  209. if (pdlle->lpfn == NULL) {
  210. // No ANSI version either, try for non-tagged
  211. pszFunctionName[cchLength] = '\0'; // convert name to ANSI version
  212. pdlle->lpfn = (RUNDLLPROC)GetProcAddress(pdlle->hinst, pszFunctionName);
  213. }
  214. }
  215. }
  216. if (pszFunctionName) {
  217. LocalFree((LPVOID)pszFunctionName);
  218. }
  219. }
  220. #else
  221. {
  222. /*
  223. * Look for 'A' tagged ANSI version.
  224. * If it is not there, then look for a non-tagged function.
  225. */
  226. LPSTR pszFunction;
  227. int cchFunction;
  228. pdlle->lpfn = NULL;
  229. cchFunction = lstrlen(lpFunction);
  230. pszFunction = LocalAlloc(LMEM_FIXED, cchFunction + sizeof(CHAR) * 2); // string + 'A' + '\0'
  231. if (pszFunction != NULL)
  232. {
  233. CopyMemory(pszFunction, lpFunction, cchFunction);
  234. pszFunction[cchFunction++] = 'A';
  235. pszFunction[cchFunction] = '\0';
  236. pdlle->lpfn = (RUNDLLPROC)GetProcAddress(pdlle->hinst, pszFunction);
  237. LocalFree(pszFunction);
  238. }
  239. }
  240. #endif
  241. if (!pdlle->lpfn)
  242. {
  243. FreeLibrary(pdlle->hinst);
  244. return(FALSE);
  245. }
  246. // Copy the rest of the command parameters down
  247. //
  248. if (lpEnd)
  249. {
  250. lstrcpy(lpszCmdLine, lpEnd);
  251. }
  252. else
  253. {
  254. *lpszCmdLine = TEXT('\0');
  255. }
  256. return(TRUE);
  257. }
  258. typedef struct tagRunThreadParam {
  259. int nCmdShow;
  260. TCHAR szCmdLine[1];
  261. } RUNTHREADPARAM;
  262. DWORD WINAPI _ThreadInitDLL(LPVOID pv)
  263. {
  264. RUNTHREADPARAM * prtp = (RUNTHREADPARAM*)pv;
  265. LPTSTR pszCmdLine = (LPTSTR)&prtp->szCmdLine;
  266. DLLENTRY dlle;
  267. if (_InitializeDLLEntry(pszCmdLine, &dlle))
  268. {
  269. HWND hwndStub=_CreateStubWindow(NULL, NULL);
  270. if (hwndStub)
  271. {
  272. ULONG cchCmdLine = 0;
  273. SetForegroundWindow(hwndStub);
  274. #ifdef UNICODE
  275. if (dlle.fCmdIsANSI)
  276. {
  277. //
  278. // If the function is an ANSI version
  279. // Change the command line parameter strings to ANSI before we call the function
  280. //
  281. int cchCmdLine = lstrlen(pszCmdLine);
  282. LPVOID pszCommand = LocalAlloc(LMEM_FIXED, sizeof(char) * (cchCmdLine + 1));
  283. if (pszCommand)
  284. {
  285. WideCharToMultiByte(CP_ACP, 0, pszCmdLine, -1, pszCommand, cchCmdLine, NULL, NULL);
  286. }
  287. dlle.lpfn(hwndStub, g_hinst, pszCommand, prtp->nCmdShow);
  288. }
  289. else
  290. #endif
  291. {
  292. dlle.lpfn(hwndStub, g_hinst, pszCmdLine, prtp->nCmdShow);
  293. }
  294. DestroyWindow(hwndStub);
  295. }
  296. FreeLibrary(dlle.hinst);
  297. }
  298. LocalFree((HLOCAL)prtp);
  299. return 0;
  300. }
  301. BOOL WINAPI SHRunDLLThread(HWND hwnd, LPCTSTR pszCmdLine, int nCmdShow)
  302. {
  303. BOOL fSuccess = FALSE; // assume error
  304. // don't need +1 on lstrlen since szCmdLine is already of size 1 (for NULL)
  305. RUNTHREADPARAM * prtp = LocalAlloc(LPTR, sizeof(RUNTHREADPARAM) + (lstrlen(pszCmdLine) * sizeof(TCHAR)));
  306. if (prtp)
  307. {
  308. DWORD idThread;
  309. HANDLE hthread;
  310. lstrcpy(prtp->szCmdLine, pszCmdLine);
  311. hthread = CreateThread(NULL, 0, _ThreadInitDLL, prtp, 0, &idThread);
  312. if (hthread)
  313. {
  314. // We don't need to communicate with this thread any more.
  315. // Close the handle and let it run and terminate itself.
  316. //
  317. // Notes: In this case, prtp will be freed by the thread.
  318. //
  319. CloseHandle(hthread);
  320. fSuccess = TRUE;
  321. }
  322. else
  323. {
  324. // Thread creation failed, we should free the buffer.
  325. LocalFree((HLOCAL)prtp);
  326. }
  327. }
  328. return fSuccess;
  329. }