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