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.

560 lines
12 KiB

  1. #include "priv.h"
  2. const TCHAR c_szAppName[] = TEXT("reginst");
  3. const TCHAR c_szDllReg[] = TEXT("DllRegisterServer");
  4. const TCHAR c_szDllUnreg[] = TEXT("DllUnregisterServer");
  5. typedef HRESULT (CALLBACK* DLLREGPROC)(void);
  6. typedef HRESULT (CALLBACK* DLLINSTALLPROC)(BOOL bInstall, LPCWSTR pszCmdLine);
  7. HINSTANCE g_hinst;
  8. #define RIF_QUIET 0x00000001
  9. #define RIF_UNINSTALL 0x00000002
  10. #define RIF_INSTALLONLY 0x00000004
  11. #define RIF_REGONLY 0x00000008
  12. #define RIF_HELP 0x00000010
  13. // Don't link to shlwapi.dll so this is a stand-alone tool
  14. /*----------------------------------------------------------
  15. Purpose: If a path is contained in quotes then remove them.
  16. Returns: --
  17. Cond: --
  18. */
  19. void
  20. PathUnquoteSpaces(
  21. LPTSTR lpsz)
  22. {
  23. int cch;
  24. cch = lstrlen(lpsz);
  25. // Are the first and last chars quotes?
  26. if (lpsz[0] == TEXT('"') && lpsz[cch-1] == TEXT('"'))
  27. {
  28. // Yep, remove them.
  29. lpsz[cch-1] = TEXT('\0');
  30. hmemcpy(lpsz, lpsz+1, (cch-1) * SIZEOF(TCHAR));
  31. }
  32. }
  33. // returns a pointer to the arguments in a cmd type path or pointer to
  34. // NULL if no args exist
  35. //
  36. // "foo.exe bar.txt" -> "bar.txt"
  37. // "foo.exe" -> ""
  38. //
  39. // Spaces in filenames must be quoted.
  40. // " "A long name.txt" bar.txt " -> "bar.txt"
  41. LPTSTR
  42. PathGetArgs(
  43. LPCTSTR pszPath)
  44. {
  45. BOOL fInQuotes = FALSE;
  46. if (!pszPath)
  47. return NULL;
  48. while (*pszPath)
  49. {
  50. if (*pszPath == TEXT('"'))
  51. fInQuotes = !fInQuotes;
  52. else if (!fInQuotes && *pszPath == TEXT(' '))
  53. return (LPTSTR)pszPath+1;
  54. pszPath = CharNext(pszPath);
  55. }
  56. return (LPTSTR)pszPath;
  57. }
  58. __inline BOOL ChrCmpA_inline(WORD w1, WORD wMatch)
  59. {
  60. /* Most of the time this won't match, so test it first for speed.
  61. */
  62. if (LOBYTE(w1) == LOBYTE(wMatch))
  63. {
  64. if (IsDBCSLeadByte(LOBYTE(w1)))
  65. {
  66. return(w1 != wMatch);
  67. }
  68. return FALSE;
  69. }
  70. return TRUE;
  71. }
  72. LPSTR FAR PASCAL StrChrA(LPCSTR lpStart, WORD wMatch)
  73. {
  74. for ( ; *lpStart; lpStart = AnsiNext(lpStart))
  75. {
  76. if (!ChrCmpA_inline(*(UNALIGNED WORD FAR *)lpStart, wMatch))
  77. return((LPSTR)lpStart);
  78. }
  79. return (NULL);
  80. }
  81. BOOL
  82. StrTrim(
  83. IN OUT LPSTR pszTrimMe,
  84. IN LPCSTR pszTrimChars)
  85. {
  86. BOOL bRet = FALSE;
  87. LPSTR psz;
  88. LPSTR pszStartMeat;
  89. LPSTR pszMark = NULL;
  90. ASSERT(IS_VALID_STRING_PTRA(pszTrimMe, -1));
  91. ASSERT(IS_VALID_STRING_PTRA(pszTrimChars, -1));
  92. if (pszTrimMe)
  93. {
  94. /* Trim leading characters. */
  95. psz = pszTrimMe;
  96. while (*psz && StrChrA(pszTrimChars, *psz))
  97. psz = CharNextA(psz);
  98. pszStartMeat = psz;
  99. /* Trim trailing characters. */
  100. // (The old algorithm used to start from the end and go
  101. // backwards, but that is piggy because DBCS version of
  102. // CharPrev iterates from the beginning of the string
  103. // on every call.)
  104. while (*psz)
  105. {
  106. if (StrChrA(pszTrimChars, *psz))
  107. {
  108. pszMark = psz;
  109. }
  110. else
  111. {
  112. pszMark = NULL;
  113. }
  114. psz = CharNextA(psz);
  115. }
  116. // Any trailing characters to clip?
  117. if (pszMark)
  118. {
  119. // Yes
  120. *pszMark = '\0';
  121. bRet = TRUE;
  122. }
  123. /* Relocate stripped string. */
  124. if (pszStartMeat > pszTrimMe)
  125. {
  126. /* (+ 1) for null terminator. */
  127. MoveMemory(pszTrimMe, pszStartMeat, CbFromCchA(lstrlenA(pszStartMeat) + 1));
  128. bRet = TRUE;
  129. }
  130. else
  131. ASSERT(pszStartMeat == pszTrimMe);
  132. ASSERT(IS_VALID_STRING_PTRA(pszTrimMe, -1));
  133. }
  134. return bRet;
  135. }
  136. HRESULT ParseOption(LPCTSTR * ppsz, LPDWORD pdwFlags)
  137. {
  138. HRESULT hres = S_FALSE;
  139. LPCTSTR psz = *ppsz;
  140. // Skip any leading whitespace
  141. while (*psz && (' ' == *psz || '\t' == *psz))
  142. psz++;
  143. if ('/' == *psz || '-' == *psz)
  144. {
  145. hres = S_OK;
  146. psz++;
  147. switch (*psz)
  148. {
  149. case '?':
  150. *pdwFlags |= RIF_HELP;
  151. break;
  152. case 'q':
  153. *pdwFlags |= RIF_QUIET;
  154. break;
  155. case 'u':
  156. *pdwFlags |= RIF_UNINSTALL;
  157. break;
  158. case 'i':
  159. *pdwFlags |= RIF_INSTALLONLY;
  160. break;
  161. case 'r':
  162. *pdwFlags |= RIF_REGONLY;
  163. break;
  164. default:
  165. hres = E_FAIL;
  166. break;
  167. }
  168. // Return the new position in the string
  169. *ppsz = psz+1;
  170. }
  171. else
  172. {
  173. *ppsz = psz;
  174. }
  175. return hres;
  176. }
  177. HRESULT CallInstall(UINT * pids, DLLREGPROC pfnRegSvr, DLLINSTALLPROC pfnInstall, BOOL bInstall, LPCWSTR psz)
  178. {
  179. HRESULT hres = S_OK;
  180. ASSERT(NULL == pfnRegSvr || IS_VALID_CODE_PTR(pfnRegSvr, DLLREGPROC));
  181. ASSERT(NULL == pfnInstall || IS_VALID_CODE_PTR(pfnInstall, DLLINSTALLPROC));
  182. ASSERT(IS_VALID_STRING_PTRW(psz, -1));
  183. _try
  184. {
  185. if (pfnRegSvr)
  186. {
  187. hres = pfnRegSvr();
  188. if (FAILED(hres))
  189. *pids = IDS_INSTALLFAILED;
  190. else
  191. *pids = IDS_REGSUCCESS;
  192. }
  193. if (SUCCEEDED(hres) && pfnInstall)
  194. {
  195. hres = pfnInstall(bInstall, psz);
  196. if (FAILED(hres))
  197. *pids = IDS_INSTALLFAILED;
  198. else
  199. *pids = IDS_INSTALLSUCCESS;
  200. }
  201. }
  202. _except (EXCEPTION_EXECUTE_HANDLER)
  203. {
  204. hres = E_UNEXPECTED;
  205. *pids = IDS_UNEXPECTED;
  206. }
  207. return hres;
  208. }
  209. /*----------------------------------------------------------
  210. Purpose: Worker function to do the work
  211. reginst /q /u /i /r foo.dll <cmdline>
  212. /q Quiet
  213. /u Uninstall
  214. Calls both DllInstall and DllRegisterServer unless:
  215. /i Call DllInstall only
  216. /r Call DllRegisterServer/DllUnregisterServer only
  217. <cmdline> is passed to DllInstall if it exists.
  218. */
  219. HRESULT
  220. DoWork(HWND hwnd, LPCTSTR pszCmdLine)
  221. {
  222. TCHAR szDll[MAX_PATH];
  223. WCHAR wszArgs[MAX_PATH];
  224. LPCTSTR psz;
  225. LPCTSTR pszArgs;
  226. DWORD dwFlags = 0;
  227. HRESULT hres;
  228. UINT ids = 0;
  229. LPCTSTR pszFnError = NULL;
  230. // Options come first
  231. psz = PathGetArgs(pszCmdLine);
  232. while (S_OK == (hres = ParseOption(&psz, &dwFlags)))
  233. ; // Loop thru options
  234. if (dwFlags & RIF_HELP)
  235. {
  236. ids = IDS_HELP;
  237. hres = S_OK;
  238. }
  239. else
  240. {
  241. // Now psz should point at DLL or null terminator
  242. lstrcpyn(szDll, psz, SIZECHARS(szDll));
  243. // Strip off args from the dll name
  244. LPTSTR pszT = PathGetArgs(szDll);
  245. if (*pszT)
  246. *pszT = 0;
  247. StrTrim(szDll, " \t");
  248. PathUnquoteSpaces(szDll);
  249. // Get args to pass to DllInstall
  250. pszArgs = PathGetArgs(psz);
  251. MultiByteToWideChar(CP_ACP, 0, pszArgs, -1, wszArgs, SIZECHARS(wszArgs));
  252. HINSTANCE hinst = LoadLibrary(szDll);
  253. if (hinst)
  254. {
  255. DLLREGPROC pfnRegSvr = NULL;
  256. DLLINSTALLPROC pfnInstall = NULL;
  257. hres = S_OK;
  258. if (IsFlagClear(dwFlags, RIF_INSTALLONLY))
  259. {
  260. if (dwFlags & RIF_UNINSTALL)
  261. {
  262. pfnRegSvr = (DLLREGPROC)GetProcAddress(hinst, "DllUnregisterServer");
  263. pszFnError = c_szDllUnreg;
  264. }
  265. else
  266. {
  267. pfnRegSvr = (DLLREGPROC)GetProcAddress(hinst, "DllRegisterServer");
  268. pszFnError = c_szDllReg;
  269. }
  270. }
  271. if (IsFlagClear(dwFlags, RIF_REGONLY))
  272. {
  273. pfnInstall = (DLLINSTALLPROC)GetProcAddress(hinst, "DllInstall");
  274. pszFnError = TEXT("DllInstall");
  275. }
  276. if (NULL == pfnInstall && NULL == pfnRegSvr)
  277. {
  278. ids = IDS_FAILED;
  279. hres = E_FAIL;
  280. }
  281. else
  282. {
  283. hres = CallInstall(&ids, pfnRegSvr, pfnInstall, IsFlagClear(dwFlags, RIF_UNINSTALL), wszArgs);
  284. if (SUCCEEDED(hres))
  285. {
  286. if (pfnRegSvr && pfnInstall)
  287. ids = IDS_FULLSUCCESS;
  288. if (IsFlagSet(dwFlags, RIF_UNINSTALL))
  289. {
  290. // refer to "uninstall" msgs instead
  291. ids += (IDS_UNREGSUCCESS - IDS_REGSUCCESS);
  292. }
  293. }
  294. }
  295. FreeLibrary(hinst);
  296. }
  297. else
  298. {
  299. ids = IDS_LOADFAILED;
  300. hres = E_FAIL;
  301. }
  302. }
  303. if (0 != ids && IsFlagClear(dwFlags, RIF_QUIET))
  304. {
  305. TCHAR szFmt[512];
  306. TCHAR szMsg[1024];
  307. TCHAR szT[32];
  308. LPCTSTR rgpsz[2];
  309. UINT uFlags = MB_OK;
  310. rgpsz[0] = szDll;
  311. rgpsz[1] = pszFnError;
  312. LoadString(g_hinst, IDS_TITLE, szT, SIZECHARS(szT));
  313. LoadString(g_hinst, ids, szFmt, SIZECHARS(szFmt));
  314. FormatMessage(FORMAT_MESSAGE_FROM_STRING | FORMAT_MESSAGE_ARGUMENT_ARRAY,
  315. szFmt, 0, 0, szMsg, SIZECHARS(szMsg), (va_list *)rgpsz);
  316. switch (ids)
  317. {
  318. case IDS_UNEXPECTED:
  319. uFlags |= MB_ICONERROR;
  320. break;
  321. case IDS_FAILED:
  322. case IDS_LOADFAILED:
  323. case IDS_INSTALLFAILED:
  324. uFlags |= MB_ICONWARNING;
  325. break;
  326. default:
  327. uFlags |= MB_ICONINFORMATION;
  328. break;
  329. }
  330. MessageBox(hwnd, szMsg, szT, uFlags);
  331. }
  332. return hres;
  333. }
  334. // stolen from the CRT, used to shrink our code
  335. int
  336. _stdcall
  337. ModuleEntry(void)
  338. {
  339. int i;
  340. STARTUPINFO si;
  341. LPTSTR pszCmdLine = GetCommandLine();
  342. si.dwFlags = 0;
  343. GetStartupInfoA(&si);
  344. i = WinMain(GetModuleHandle(NULL),
  345. NULL,
  346. pszCmdLine,
  347. (si.dwFlags & STARTF_USESHOWWINDOW) ? si.wShowWindow : SW_SHOWDEFAULT);
  348. ExitProcess(i);
  349. return i; // We never come here
  350. }
  351. /*----------------------------------------------------------
  352. Purpose: Stub window proc
  353. Returns:
  354. Cond: --
  355. */
  356. LRESULT
  357. CALLBACK
  358. WndProc(
  359. HWND hWnd,
  360. UINT iMessage,
  361. WPARAM wParam,
  362. LPARAM lParam)
  363. {
  364. switch(iMessage)
  365. {
  366. case WM_CREATE:
  367. break;
  368. case WM_DESTROY:
  369. break;
  370. default:
  371. return DefWindowProc(hWnd, iMessage, wParam, lParam);
  372. break;
  373. }
  374. return 0L;
  375. }
  376. /*----------------------------------------------------------
  377. Purpose: Initialize a stub window
  378. Returns:
  379. Cond: --
  380. */
  381. BOOL
  382. InitStubWindow(
  383. IN HINSTANCE hInst,
  384. IN HINSTANCE hPrevInstance,
  385. OUT HWND * phwnd)
  386. {
  387. WNDCLASS wndclass;
  388. if (!hPrevInstance)
  389. {
  390. wndclass.style = 0 ;
  391. wndclass.lpfnWndProc = WndProc ;
  392. wndclass.cbClsExtra = 0 ;
  393. wndclass.cbWndExtra = 0 ;
  394. wndclass.hInstance = hInst ;
  395. wndclass.hIcon = NULL;
  396. wndclass.hCursor = LoadCursor (NULL, IDC_ARROW);
  397. wndclass.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
  398. wndclass.lpszMenuName = NULL ;
  399. wndclass.lpszClassName = c_szAppName;
  400. if (!RegisterClass(&wndclass))
  401. {
  402. return(FALSE);
  403. }
  404. }
  405. *phwnd = CreateWindowEx(WS_EX_TOOLWINDOW,
  406. c_szAppName,
  407. TEXT(""),
  408. WS_OVERLAPPED,
  409. CW_USEDEFAULT, CW_USEDEFAULT, 0, 0,
  410. NULL, NULL, hInst, NULL);
  411. return (NULL != *phwnd);
  412. }
  413. /*----------------------------------------------------------
  414. Purpose: WinMain
  415. Returns:
  416. Cond: --
  417. */
  418. int
  419. WinMain(
  420. HINSTANCE hInstance,
  421. HINSTANCE hPrevInstance,
  422. LPTSTR pszCmdLine,
  423. int nCmdShow)
  424. {
  425. HWND hwndStub;
  426. int nRet = 0;
  427. g_hinst = hInstance;
  428. #ifdef DEBUG
  429. CcshellGetDebugFlags();
  430. if (IsFlagSet(g_dwBreakFlags, BF_ONOPEN))
  431. DebugBreak();
  432. #endif
  433. // turn off critical error stuff
  434. SetErrorMode(SEM_NOOPENFILEERRORBOX | SEM_FAILCRITICALERRORS);
  435. if (InitStubWindow(hInstance, hPrevInstance, &hwndStub))
  436. {
  437. // Do work here
  438. nRet = DoWork(hwndStub, pszCmdLine);
  439. DestroyWindow(hwndStub);
  440. }
  441. return nRet;
  442. }