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.

608 lines
17 KiB

  1. #include "rundll.h"
  2. #include <strsafe.h>
  3. #define ARRAYSIZE(a) (sizeof(a)/sizeof(a[0]))
  4. #define IsPathSep(ch) ((ch) == TEXT('\\') || (ch) == TEXT('/'))
  5. #define Reference(x) ((x)=(x))
  6. #define BLOCK
  7. void WINAPI RunDllErrMsg(HWND hwnd, UINT idStr, LPCTSTR pszTitle, LPCTSTR psz1, LPCTSTR psz2);
  8. int PASCAL WinMainT(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPTSTR lpszCmdLine, int nCmdShow);
  9. TCHAR const g_szAppName [] = TEXT("RunDLL");
  10. TCHAR const c_szNULL[] = TEXT("");
  11. TCHAR const c_szLocalizeMe[] = TEXT("RUNDLL");
  12. HANDLE g_hActCtx = INVALID_HANDLE_VALUE;
  13. ULONG_PTR g_dwActCtx = 0;
  14. BOOL g_fCatchExceptions = TRUE;
  15. HINSTANCE g_hinst;
  16. HICON g_hIcon;
  17. HINSTANCE g_hModule;
  18. HWND g_hwndStub;
  19. BOOL g_fUseCCV6 = FALSE;
  20. #ifdef WX86
  21. #include <wx86dll.h>
  22. WX86LOADX86DLL_ROUTINE pWx86LoadX86Dll = NULL;
  23. WX86THUNKPROC_ROUTINE pWx86ThunkProc = NULL;
  24. HMODULE g_hWx86Dll = NULL;
  25. #endif
  26. RUNDLLPROC g_lpfnCommand;
  27. BOOL g_fCmdIsANSI; // TRUE if g_lpfnCommand() expects ANSI strings
  28. LPTSTR PASCAL StringChr(LPCTSTR lpStart, TCHAR ch)
  29. {
  30. for (; *lpStart; lpStart = CharNext(lpStart))
  31. {
  32. if (*lpStart == ch)
  33. return (LPTSTR)lpStart;
  34. }
  35. return NULL;
  36. }
  37. LPTSTR PASCAL StringHasPathChar(LPCTSTR lpStart)
  38. {
  39. for (; *lpStart; lpStart = CharNext(lpStart))
  40. {
  41. if (IsPathSep(*lpStart))
  42. return (LPTSTR)lpStart;
  43. }
  44. return NULL;
  45. }
  46. // stolen from the CRT, used to shirink our code
  47. int _stdcall ModuleEntry(void)
  48. {
  49. int i;
  50. STARTUPINFO si;
  51. LPTSTR pszCmdLine = GetCommandLine();
  52. if ( *pszCmdLine == TEXT('\"') )
  53. {
  54. /*
  55. * Scan, and skip over, subsequent characters until
  56. * another double-quote or a null is encountered.
  57. */
  58. while ( *++pszCmdLine && (*pszCmdLine
  59. != TEXT('\"')) );
  60. /*
  61. * If we stopped on a double-quote (usual case), skip
  62. * over it.
  63. */
  64. if ( *pszCmdLine == TEXT('\"') )
  65. pszCmdLine++;
  66. }
  67. else
  68. {
  69. while (*pszCmdLine > TEXT(' '))
  70. pszCmdLine++;
  71. }
  72. /*
  73. * Skip past any white space preceeding the second token.
  74. */
  75. while (*pszCmdLine && (*pszCmdLine <= TEXT(' ')))
  76. {
  77. pszCmdLine++;
  78. }
  79. si.dwFlags = 0;
  80. GetStartupInfo(&si);
  81. i = WinMainT(GetModuleHandle(NULL), NULL, pszCmdLine,
  82. si.dwFlags & STARTF_USESHOWWINDOW ? si.wShowWindow : SW_SHOWDEFAULT);
  83. ExitProcess(i);
  84. return i; // We never comes here.
  85. }
  86. BOOL PASCAL ParseCommand(LPTSTR lpszCmdLine, UINT cchCmdLine, int nCmdShow)
  87. {
  88. LPTSTR lpStart, lpEnd, lpFunction;
  89. ACTCTX act;
  90. TCHAR szManifest[MAX_PATH];
  91. LPTSTR pszFullPath;
  92. TCHAR szPath[MAX_PATH];
  93. TCHAR kszManifest[] = TEXT(".manifest");
  94. LPTSTR pszName;
  95. BOOL bManifest = FALSE;
  96. #ifdef DEBUG
  97. OutputDebugString(TEXT("RUNDLL: Command: "));
  98. OutputDebugString(lpszCmdLine);
  99. OutputDebugString(TEXT("\r\n"));
  100. #endif
  101. for (lpStart = lpszCmdLine; ; )
  102. {
  103. // Skip leading blanks
  104. while (*lpStart == TEXT(' '))
  105. {
  106. ++lpStart;
  107. }
  108. // Check if there are any switches
  109. if (*lpStart != TEXT('/'))
  110. {
  111. break;
  112. }
  113. // Look at all the switches; ignore unknown ones
  114. for (++lpStart; ; ++lpStart)
  115. {
  116. switch (*lpStart)
  117. {
  118. case TEXT(' '):
  119. case TEXT('\0'):
  120. goto EndSwitches;
  121. break;
  122. // Put any switches we care about here
  123. case TEXT('d'):
  124. case TEXT('D'):
  125. // Disable exception catching.
  126. g_fCatchExceptions = FALSE;
  127. break;
  128. default:
  129. break;
  130. }
  131. }
  132. EndSwitches:
  133. ;
  134. }
  135. // If the path is double-quoted, search for the next
  136. // quote, otherwise, look for a space
  137. lpEnd = lpStart;
  138. if ( *lpStart == TEXT('\"') )
  139. {
  140. // Skip opening quote
  141. lpStart++;
  142. // Scan, and skip over, subsequent characters until
  143. // another double-quote or a null is encountered.
  144. while ( *++lpEnd && (*lpEnd != TEXT('\"')) )
  145. NULL;
  146. if (!*lpEnd)
  147. return FALSE;
  148. *lpEnd++ = TEXT('\0');
  149. }
  150. else
  151. {
  152. // No quotes, so run until a space or a comma
  153. while ( *lpEnd && (*lpEnd != TEXT(' ')) && (*lpEnd != TEXT(',')))
  154. lpEnd++;
  155. if (!*lpEnd)
  156. return FALSE;
  157. *lpEnd++ = TEXT('\0');
  158. }
  159. // At this point we're just past the terminated dll path. We
  160. // then skip spaces and commas, which should take us to the start of the
  161. // entry point (lpFunction)
  162. while ( *lpEnd && ((*lpEnd == TEXT(' ')) || (*lpEnd == TEXT(','))))
  163. lpEnd++;
  164. if (!*lpEnd)
  165. return FALSE;
  166. lpFunction = lpEnd;
  167. // If there's a space after the function name, we need to terminate
  168. // the function name and move the end pointer, because that's where
  169. // the arguments to the function live.
  170. lpEnd = StringChr(lpFunction, TEXT(' '));
  171. if (lpEnd)
  172. *lpEnd++ = TEXT('\0');
  173. // If there is a path component in the function name, bail out.
  174. if (StringHasPathChar(lpFunction))
  175. return FALSE;
  176. // Load the library and get the procedure address
  177. // Note that we try to get a module handle first, so we don't need
  178. // to pass full file names around
  179. //
  180. // Get the full name of the DLL
  181. pszFullPath = lpStart;
  182. // If the path is not specified, find it
  183. if (GetFileAttributes(lpStart) == -1)
  184. {
  185. if (SearchPath(NULL, lpStart, NULL, ARRAYSIZE(szPath), szPath, &pszName) > 0)
  186. {
  187. pszFullPath = szPath;
  188. }
  189. }
  190. // First see if there is an blah.dll.manifest
  191. act.cbSize = sizeof(act);
  192. act.dwFlags = 0;
  193. if (SUCCEEDED(StringCchCopy(szManifest, ARRAYSIZE(szManifest), pszFullPath)) &&
  194. SUCCEEDED(StringCchCat(szManifest, ARRAYSIZE(szManifest), kszManifest)))
  195. {
  196. bManifest = TRUE;
  197. }
  198. if (bManifest && GetFileAttributes(szManifest) != -1)
  199. {
  200. act.lpSource = szManifest;
  201. g_hActCtx = CreateActCtx(&act);
  202. }
  203. else
  204. {
  205. // No? See if there is one in the binary.
  206. act.dwFlags = ACTCTX_FLAG_RESOURCE_NAME_VALID;
  207. act.lpSource = pszFullPath;
  208. act.lpResourceName = MAKEINTRESOURCE(123);
  209. g_hActCtx = CreateActCtx(&act);
  210. }
  211. if (g_hActCtx != INVALID_HANDLE_VALUE)
  212. ActivateActCtx(g_hActCtx, &g_dwActCtx);
  213. g_hModule = LoadLibrary(lpStart);
  214. #ifdef WX86
  215. //
  216. // If the load fails try it thru wx86, since it might be an
  217. // x86 on risc binary
  218. //
  219. if (g_hModule==NULL)
  220. {
  221. g_hWx86Dll = LoadLibrary(TEXT("wx86.dll"));
  222. if (g_hWx86Dll)
  223. {
  224. pWx86LoadX86Dll = (PVOID)GetProcAddress(g_hWx86Dll, "Wx86LoadX86Dll");
  225. pWx86ThunkProc = (PVOID)GetProcAddress(g_hWx86Dll, "Wx86ThunkProc");
  226. if (pWx86LoadX86Dll && pWx86ThunkProc)
  227. {
  228. g_hModule = pWx86LoadX86Dll(lpStart, 0);
  229. }
  230. }
  231. if (!g_hModule)
  232. {
  233. if (g_hWx86Dll)
  234. {
  235. FreeLibrary(g_hWx86Dll);
  236. g_hWx86Dll = NULL;
  237. }
  238. }
  239. }
  240. #endif
  241. if (g_hModule==NULL)
  242. {
  243. TCHAR szSysErrMsg[MAX_PATH];
  244. BOOL fSuccess = FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
  245. NULL, GetLastError(), 0, szSysErrMsg, ARRAYSIZE(szSysErrMsg), NULL);
  246. if (fSuccess)
  247. {
  248. RunDllErrMsg(NULL, IDS_CANTLOADDLL, c_szLocalizeMe, lpStart, szSysErrMsg);
  249. }
  250. return FALSE;
  251. }
  252. BLOCK
  253. {
  254. //
  255. // Check whether we need to run as a different windows version
  256. //
  257. // Stolen from ntos\mm\procsup.c
  258. //
  259. //
  260. PPEB Peb = NtCurrentPeb();
  261. PIMAGE_DOS_HEADER pDosHeader = (PIMAGE_DOS_HEADER)g_hModule;
  262. PIMAGE_NT_HEADERS pHeader = (PIMAGE_NT_HEADERS)((DWORD_PTR)g_hModule + pDosHeader->e_lfanew);
  263. PIMAGE_LOAD_CONFIG_DIRECTORY ImageConfigData;
  264. ULONG ReturnedSize;
  265. if (pHeader->FileHeader.SizeOfOptionalHeader != 0 &&
  266. pHeader->OptionalHeader.Win32VersionValue != 0)
  267. {
  268. Peb->OSMajorVersion = pHeader->OptionalHeader.Win32VersionValue & 0xFF;
  269. Peb->OSMinorVersion = (pHeader->OptionalHeader.Win32VersionValue >> 8) & 0xFF;
  270. Peb->OSBuildNumber = (USHORT)((pHeader->OptionalHeader.Win32VersionValue >> 16) & 0x3FFF);
  271. Peb->OSPlatformId = (pHeader->OptionalHeader.Win32VersionValue >> 30) ^ 0x2;
  272. }
  273. ImageConfigData = ImageDirectoryEntryToData( Peb->ImageBaseAddress,
  274. TRUE,
  275. IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG,
  276. &ReturnedSize
  277. );
  278. if (ImageConfigData != NULL && ImageConfigData->CSDVersion != 0)
  279. {
  280. Peb->OSCSDVersion = ImageConfigData->CSDVersion;
  281. }
  282. }
  283. // Special case: load function by ordinal
  284. // '#' was used by GetProcAddress in the Win16 days
  285. if (lpFunction[0] == TEXT('#') && lpFunction[1] != TEXT('\0'))
  286. {
  287. g_lpfnCommand = (RUNDLLPROC)GetProcAddress(g_hModule, MAKEINTRESOURCEA(_wtoi(lpFunction + 1)));
  288. // Support Unicode exports only
  289. g_fCmdIsANSI = FALSE;
  290. }
  291. else
  292. {
  293. /*
  294. * Look for a 'W' tagged Unicode function.
  295. * If it is not there, then look for the 'A' tagged ANSI function
  296. * if we cant find that one either, then look for an un-tagged function
  297. */
  298. LPSTR lpstrFunctionName;
  299. UINT cchLength;
  300. cchLength = lstrlen(lpFunction)+1;
  301. g_fCmdIsANSI = FALSE;
  302. lpstrFunctionName = (LPSTR)LocalAlloc(LMEM_FIXED, (cchLength+1)*2); // +1 for "W", *2 for DBCS
  303. if (lpstrFunctionName && (WideCharToMultiByte (CP_ACP, 0, lpFunction, cchLength,
  304. lpstrFunctionName, cchLength*2, NULL, NULL)))
  305. {
  306. cchLength = lstrlenA(lpstrFunctionName);
  307. lpstrFunctionName[cchLength] = 'W'; // convert name to Wide version
  308. lpstrFunctionName[cchLength+1] = '\0';
  309. g_lpfnCommand = (RUNDLLPROC)GetProcAddress(g_hModule, lpstrFunctionName);
  310. if (g_lpfnCommand == NULL)
  311. {
  312. // No UNICODE version, try for ANSI
  313. lpstrFunctionName[cchLength] = 'A'; // convert name to ANSI version
  314. g_fCmdIsANSI = TRUE;
  315. g_lpfnCommand = (RUNDLLPROC)GetProcAddress(g_hModule, lpstrFunctionName);
  316. if (g_lpfnCommand == NULL)
  317. {
  318. // No ANSI version either, try for non-tagged
  319. lpstrFunctionName[cchLength] = '\0'; // convert name to ANSI version
  320. g_lpfnCommand = (RUNDLLPROC)GetProcAddress(g_hModule, lpstrFunctionName);
  321. }
  322. }
  323. }
  324. if (lpstrFunctionName)
  325. {
  326. LocalFree((LPVOID)lpstrFunctionName);
  327. }
  328. }
  329. #ifdef WX86
  330. if (g_lpfnCommand && g_hWx86Dll)
  331. {
  332. g_lpfnCommand = pWx86ThunkProc(g_lpfnCommand, (PVOID)4, TRUE);
  333. }
  334. #endif
  335. if (!g_lpfnCommand)
  336. {
  337. RunDllErrMsg(NULL, IDS_GETPROCADRERR, c_szLocalizeMe, lpStart, lpFunction);
  338. FreeLibrary(g_hModule);
  339. return(FALSE);
  340. }
  341. // Copy the rest of the command parameters down
  342. //
  343. if (lpEnd)
  344. {
  345. return SUCCEEDED(StringCchCopy(lpszCmdLine, cchCmdLine, lpEnd));
  346. }
  347. else
  348. {
  349. *lpszCmdLine = TEXT('\0');
  350. }
  351. return(TRUE);
  352. }
  353. LRESULT PASCAL StubNotify(HWND hWnd, WPARAM wParam, RUNDLL_NOTIFY FAR *lpn)
  354. {
  355. switch (lpn->hdr.code)
  356. {
  357. case RDN_TASKINFO:
  358. // don't need to set title too
  359. // SetWindowText(hWnd, lpn->lpszTitle ? lpn->lpszTitle : c_szNULL);
  360. g_hIcon = lpn->hIcon ? lpn->hIcon :
  361. LoadIcon(g_hinst, MAKEINTRESOURCE(IDI_DEFAULT));
  362. SetClassLongPtr(hWnd, GCLP_HICON, (DWORD_PTR)g_hIcon);
  363. return 0L;
  364. default:
  365. return(DefWindowProc(hWnd, WM_NOTIFY, wParam, (LPARAM)lpn));
  366. }
  367. }
  368. LRESULT CALLBACK WndProc(HWND hWnd, UINT iMessage, WPARAM wParam, LPARAM lParam)
  369. {
  370. switch(iMessage)
  371. {
  372. case WM_CREATE:
  373. g_hIcon = LoadIcon(g_hinst, MAKEINTRESOURCE(IDI_DEFAULT));
  374. break;
  375. case WM_DESTROY:
  376. break;
  377. case WM_NOTIFY:
  378. return(StubNotify(hWnd, wParam, (RUNDLL_NOTIFY *)lParam));
  379. #ifdef COOLICON
  380. case WM_QUERYDRAGICON:
  381. return(MAKELRESULT(g_hIcon, 0));
  382. #endif
  383. default:
  384. return DefWindowProc(hWnd, iMessage, wParam, lParam);
  385. }
  386. return 0L;
  387. }
  388. BOOL PASCAL InitStubWindow(HINSTANCE hInst, HINSTANCE hPrevInstance)
  389. {
  390. WNDCLASS wndclass;
  391. if (!hPrevInstance)
  392. {
  393. wndclass.style = 0;
  394. wndclass.lpfnWndProc = WndProc;
  395. wndclass.cbClsExtra = 0;
  396. wndclass.cbWndExtra = 0;
  397. wndclass.hInstance = hInst;
  398. #ifdef COOLICON
  399. wndclass.hIcon = NULL;
  400. #else
  401. wndclass.hIcon = LoadIcon(hInst, MAKEINTRESOURCE(IDI_DEFAULT));
  402. #endif
  403. wndclass.hCursor = LoadCursor (NULL, IDC_ARROW);
  404. wndclass.hbrBackground = GetStockObject (WHITE_BRUSH);
  405. wndclass.lpszMenuName = NULL;
  406. wndclass.lpszClassName = g_szAppName;
  407. if (!RegisterClass(&wndclass))
  408. {
  409. return(FALSE);
  410. }
  411. }
  412. g_hwndStub = CreateWindowEx(WS_EX_TOOLWINDOW,
  413. g_szAppName, c_szNULL, WS_OVERLAPPED, CW_USEDEFAULT, CW_USEDEFAULT, 0, 0, NULL, NULL, hInst, NULL);
  414. return(g_hwndStub != NULL);
  415. }
  416. void PASCAL CleanUp(void)
  417. {
  418. DestroyWindow(g_hwndStub);
  419. FreeLibrary(g_hModule);
  420. }
  421. int PASCAL WinMainT (HINSTANCE hInstance, HINSTANCE hPrevInstance, LPTSTR lpszCmdLine, int nCmdShow)
  422. {
  423. LPTSTR lpszCmdLineCopy;
  424. HANDLE hFusionManifest;
  425. LPVOID pchCmdLine;
  426. UINT cchCmdLine = lstrlen(lpszCmdLine) + 1;
  427. g_hinst = hInstance;
  428. // make a copy of lpCmdLine, since ParseCommand modifies the string
  429. lpszCmdLineCopy = LocalAlloc(LPTR, cchCmdLine * sizeof(TCHAR));
  430. if (!lpszCmdLineCopy)
  431. {
  432. goto Error0;
  433. }
  434. if (FAILED(StringCchCopy(lpszCmdLineCopy, cchCmdLine, lpszCmdLine)) ||
  435. !ParseCommand(lpszCmdLineCopy, cchCmdLine, nCmdShow))
  436. {
  437. goto Error1;
  438. }
  439. // turn off critical error message box
  440. SetErrorMode(g_fCatchExceptions ? (SEM_NOOPENFILEERRORBOX | SEM_FAILCRITICALERRORS) : SEM_NOOPENFILEERRORBOX);
  441. if (!InitStubWindow(hInstance, hPrevInstance))
  442. {
  443. goto Error2;
  444. }
  445. pchCmdLine = lpszCmdLineCopy;
  446. if (g_fCmdIsANSI)
  447. {
  448. int cchCmdLineW = lstrlen(lpszCmdLineCopy) + 1;
  449. int cbCmdLineA;
  450. cbCmdLineA = WideCharToMultiByte(CP_ACP, 0, lpszCmdLineCopy, cchCmdLineW, NULL, 0, NULL, NULL);
  451. pchCmdLine = LocalAlloc( LMEM_FIXED, cbCmdLineA );
  452. if (pchCmdLine == NULL)
  453. {
  454. RunDllErrMsg(NULL, IDS_LOADERR+00, c_szLocalizeMe, lpszCmdLineCopy, NULL);
  455. goto Error3;
  456. }
  457. WideCharToMultiByte(CP_ACP, 0, lpszCmdLineCopy, cchCmdLineW, pchCmdLine, cbCmdLineA, NULL, NULL);
  458. }
  459. if (g_fCatchExceptions)
  460. {
  461. try
  462. {
  463. g_lpfnCommand(g_hwndStub, hInstance, pchCmdLine, nCmdShow);
  464. }
  465. _except (EXCEPTION_EXECUTE_HANDLER)
  466. {
  467. RunDllErrMsg(NULL, IDS_LOADERR+17, c_szLocalizeMe, lpszCmdLine, NULL);
  468. }
  469. }
  470. else
  471. {
  472. g_lpfnCommand(g_hwndStub, hInstance, pchCmdLine, nCmdShow);
  473. }
  474. Error3:
  475. if (g_fCmdIsANSI)
  476. {
  477. LocalFree(pchCmdLine);
  478. }
  479. Error2:
  480. CleanUp();
  481. Error1:
  482. LocalFree(lpszCmdLineCopy);
  483. Error0:
  484. if (g_hActCtx != INVALID_HANDLE_VALUE)
  485. {
  486. DeactivateActCtx(0, g_dwActCtx);
  487. ReleaseActCtx(g_hActCtx);
  488. g_hActCtx = NULL;
  489. }
  490. return(FALSE);
  491. }
  492. void WINAPI RunDllErrMsg(HWND hwnd, UINT idStr, LPCTSTR pszTitle, LPCTSTR psz1, LPCTSTR psz2)
  493. {
  494. TCHAR szTmp[200];
  495. TCHAR szMsg[200 + MAX_PATH];
  496. if (LoadString(g_hinst, idStr, szTmp, ARRAYSIZE(szTmp)))
  497. {
  498. StringCchPrintf(szMsg, ARRAYSIZE(szMsg), szTmp, psz1, psz2);
  499. MessageBox(hwnd, szMsg, pszTitle, MB_OK|MB_ICONHAND);
  500. }
  501. }