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.

672 lines
19 KiB

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