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.

585 lines
19 KiB

  1. // regsvr.cpp : Program to invoke OLE self-registration on a DLL.
  2. //
  3. // This is a part of the Microsoft Foundation Classes C++ library.
  4. // Copyright (C) 1992-1995 Microsoft Corporation
  5. // All rights reserved.
  6. //
  7. // This source code is only intended as a supplement to the
  8. // Microsoft Foundation Classes Reference and related
  9. // electronic documentation provided with the library.
  10. // See these sources for detailed information regarding the
  11. // Microsoft Foundation Classes product.
  12. #include <windows.h>
  13. #include <ole2.h>
  14. #include <tchar.h>
  15. #include <stdio.h>
  16. #include "resource.h"
  17. #define FAIL_ARGS 1
  18. #define FAIL_OLE 2
  19. #define FAIL_LOAD 3
  20. #define FAIL_ENTRY 4
  21. #define FAIL_REG 5
  22. const TCHAR _szAppName[] = _T("RegSvr32");
  23. const char _szDllInstall[] = "DllInstall";
  24. const TCHAR _tszDllInstall[] = TEXT("DllInstall");
  25. TCHAR _szDllPath[_MAX_PATH];
  26. // Leave room for "Ex" to be tacked onto end
  27. char _szDllRegSvr[32] = "DllRegisterServer";
  28. TCHAR _tszDllRegSvr[32] = TEXT("DllRegisterServer");
  29. char _szDllUnregSvr[32] = "DllUnregisterServer";
  30. TCHAR _tszDllUnregSvr[32] = TEXT("DllUnregisterServer");
  31. char _szRegContext[_MAX_PATH];
  32. HINSTANCE _hInstance;
  33. BOOL _bSilent;
  34. void
  35. FormatString3(
  36. LPTSTR lpszOut,
  37. LPCTSTR lpszFormat,
  38. LPCTSTR lpsz1,
  39. LPCTSTR lpsz2,
  40. LPCTSTR lpsz3
  41. )
  42. {
  43. LPCTSTR pchSrc = lpszFormat;
  44. LPTSTR pchDest = lpszOut;
  45. LPCTSTR pchTmp;
  46. while (*pchSrc != '\0') {
  47. if (pchSrc[0] == '%' && (pchSrc[1] >= '1' && pchSrc[1] <= '3')) {
  48. if (pchSrc[1] == '1')
  49. pchTmp = lpsz1;
  50. else if (pchSrc[1] == '2')
  51. pchTmp = lpsz2;
  52. else
  53. pchTmp = lpsz3;
  54. lstrcpy(pchDest, pchTmp);
  55. pchDest += lstrlen(pchDest);
  56. pchSrc += 2;
  57. } else {
  58. if (_istlead(*pchSrc))
  59. *pchDest++ = *pchSrc++; // copy first of 2 bytes
  60. *pchDest++ = *pchSrc++;
  61. }
  62. }
  63. *pchDest = '\0';
  64. }
  65. #define MAX_STRING 1024
  66. void
  67. DisplayMessage(
  68. UINT ids,
  69. LPCTSTR pszArg1 = NULL,
  70. LPCTSTR pszArg2 = NULL,
  71. LPCTSTR pszArg3 = NULL,
  72. BOOL bUsage = FALSE,
  73. BOOL bInfo = FALSE
  74. )
  75. {
  76. if (_bSilent)
  77. return;
  78. TCHAR szFmt[MAX_STRING];
  79. LoadString(_hInstance, ids, szFmt, MAX_STRING);
  80. TCHAR szText[MAX_STRING];
  81. FormatString3(szText, szFmt, pszArg1, pszArg2, pszArg3);
  82. if (bUsage) {
  83. int cch = _tcslen(szText);
  84. LoadString(_hInstance, IDS_USAGE, szText + cch, MAX_STRING - cch);
  85. }
  86. if (! _bSilent)
  87. MessageBox(NULL, szText, _szAppName,
  88. MB_TASKMODAL | (bInfo ? MB_ICONINFORMATION : MB_ICONEXCLAMATION));
  89. }
  90. inline void
  91. Usage(
  92. UINT ids,
  93. LPCTSTR pszArg1 = NULL,
  94. LPCTSTR pszArg2 = NULL
  95. )
  96. {
  97. DisplayMessage(ids, pszArg1, pszArg2, NULL, TRUE);
  98. }
  99. inline void
  100. Info(
  101. UINT ids,
  102. LPCTSTR pszArg1 = NULL,
  103. LPCTSTR pszArg2 = NULL
  104. )
  105. {
  106. DisplayMessage(ids, pszArg1, pszArg2, NULL, FALSE, TRUE);
  107. }
  108. #define MAX_APPID 256
  109. BOOL IsContextRegFileType(LPCTSTR *ppszDllName)
  110. {
  111. HKEY hk1, hk2;
  112. LONG lRet;
  113. LONG cch;
  114. TCHAR szExt[_MAX_EXT];
  115. TCHAR szAppID[MAX_APPID];
  116. _tsplitpath(*ppszDllName, NULL, NULL, NULL, szExt);
  117. // Find [HKEY_CLASSES_ROOT\.foo]
  118. if (ERROR_SUCCESS != RegOpenKeyEx(HKEY_CLASSES_ROOT, szExt, 0, KEY_QUERY_VALUE, &hk1))
  119. return FALSE;
  120. // Read [HKEY_CLASSES_ROOT\.foo\"foo_auto_file"]
  121. cch = sizeof(szAppID);
  122. lRet = RegQueryValue(hk1, NULL, szAppID, &cch);
  123. RegCloseKey(hk1);
  124. if (ERROR_SUCCESS != lRet)
  125. return FALSE;
  126. // Find [HKEY_CLASSES_ROOT\foo_auto_file]
  127. if (ERROR_SUCCESS != RegOpenKeyEx(HKEY_CLASSES_ROOT, szAppID, 0, KEY_QUERY_VALUE, &hk1))
  128. return FALSE;
  129. // Find [HKEY_CLASSES_ROOT\foo_auto_file\AutoRegister]
  130. if (ERROR_SUCCESS != RegOpenKeyEx(hk1, TEXT("AutoRegister"), 0, KEY_QUERY_VALUE, &hk2))
  131. {
  132. RegCloseKey(hk1);
  133. return FALSE;
  134. }
  135. // Read [HKEY_CLASSES_ROOT\foo_auto_file\AutoRegister\"d:\...\fooreg.dll"]
  136. cch = MAX_PATH;
  137. lRet = RegQueryValue(hk2, NULL, _szDllPath, &cch);
  138. RegCloseKey(hk1);
  139. RegCloseKey(hk2);
  140. if (ERROR_SUCCESS != lRet)
  141. return FALSE;
  142. _szDllPath[cch] = TEXT('\0');
  143. *ppszDllName = _szDllPath;
  144. return TRUE;
  145. }
  146. int PASCAL
  147. _tWinMain(
  148. HINSTANCE hInstance,
  149. HINSTANCE,
  150. LPSTR,
  151. int
  152. )
  153. {
  154. int iReturn = 0;
  155. HRESULT (STDAPICALLTYPE * lpDllEntryPointReg)(void);
  156. HRESULT (STDAPICALLTYPE * lpDllEntryPointRegEx)(LPCSTR);
  157. HRESULT (STDAPICALLTYPE * lpDllEntryPointRegExW)(LPCWSTR);
  158. HRESULT (STDAPICALLTYPE * lpDllEntryPointInstall)(BOOL, LPWSTR);
  159. HRESULT rc;
  160. BOOL bVisualC = FALSE;
  161. BOOL bUnregister = FALSE;
  162. BOOL bCallDllInstall = FALSE;
  163. BOOL bCallDllRegisterServer = TRUE;
  164. BOOL bErrorsOnly = FALSE;
  165. BOOL bContextReg = FALSE;
  166. BOOL bUnicodeContextReg = FALSE;
  167. LPSTR pszDllEntryPoint = _szDllRegSvr;
  168. LPTSTR ptszDllEntryPoint = _tszDllRegSvr;
  169. LPTSTR pszTok;
  170. LPCTSTR pszDllName;
  171. LPSTR pszContext;
  172. LPCTSTR pszContextW;
  173. TCHAR pszDllInstallCmdLine[MAX_PATH];
  174. #ifdef UNICODE
  175. PWCHAR pwszDllInstallCmdLine = pszDllInstallCmdLine;
  176. #else
  177. WCHAR pwszDllInstallCmdLine[MAX_PATH];
  178. #endif
  179. int iNumDllsToRegister = 0;
  180. int iCount;
  181. LPCTSTR ppszDllNames[255];
  182. TCHAR szError[1024];
  183. _hInstance = hInstance;
  184. // Parse command line arguments.
  185. int iTok;
  186. for (iTok = 1; iTok < __argc; iTok++) {
  187. pszTok = __targv[iTok];
  188. if ((pszTok[0] == TEXT('-')) || (pszTok[0] == TEXT('/'))) {
  189. switch (pszTok[1]) {
  190. case TEXT('e'):
  191. case TEXT('E'):
  192. bErrorsOnly = TRUE;
  193. break;
  194. case TEXT('i'):
  195. case TEXT('I'):
  196. bCallDllInstall = TRUE;
  197. if (pszTok[2] == TEXT(':'))
  198. {
  199. if (pszTok[3] == TEXT('"')) {
  200. // handle quoted InstallCmdLine (
  201. // (e.g. /i:"c:\my dll dir\mydll.dll")
  202. LPTSTR pszEndQuote = &pszTok[4];
  203. int iLength = lstrlen(pszEndQuote);
  204. if ((iLength > 0) && pszEndQuote[iLength - 1] == TEXT('"')) {
  205. // they quoted the string but it wasent really necessary
  206. // (e.g. /i:"shell32.dll")
  207. pszEndQuote[iLength - 1] = TEXT('\0');
  208. lstrcpy(pszDllInstallCmdLine, pszEndQuote);
  209. } else {
  210. // we have a quoted string that spans multiple tokens
  211. lstrcpy(pszDllInstallCmdLine, pszEndQuote);
  212. for (iTok++; iTok < __argc; iTok++) {
  213. // grab the next token
  214. pszEndQuote = __targv[iTok];
  215. iLength = lstrlen(pszEndQuote);
  216. if ((iLength > 0) && (pszEndQuote[iLength - 1] == '"')) {
  217. pszEndQuote[iLength - 1] = TEXT('\0');
  218. lstrcat(pszDllInstallCmdLine, TEXT(" "));
  219. lstrcat(pszDllInstallCmdLine, pszEndQuote);
  220. break;
  221. }
  222. lstrcat(pszDllInstallCmdLine, TEXT(" "));
  223. lstrcat(pszDllInstallCmdLine, pszEndQuote);
  224. }
  225. }
  226. } else {
  227. // cmd line is NOT quoted
  228. lstrcpy(pszDllInstallCmdLine, &pszTok[3]);
  229. }
  230. #ifndef UNICODE
  231. if (!MultiByteToWideChar(CP_ACP,
  232. 0,
  233. (LPCTSTR)pszDllInstallCmdLine,
  234. -1,
  235. pwszDllInstallCmdLine,
  236. MAX_PATH))
  237. {
  238. Usage(IDS_UNRECOGNIZEDFLAG, pszTok);
  239. return FAIL_ARGS;
  240. }
  241. #endif
  242. }
  243. else
  244. {
  245. lstrcpyW((LPWSTR)pwszDllInstallCmdLine, L"");
  246. }
  247. break;
  248. case TEXT('n'):
  249. case TEXT('N'):
  250. bCallDllRegisterServer = FALSE;
  251. break;
  252. case TEXT('s'):
  253. case TEXT('S'):
  254. _bSilent = TRUE;
  255. break;
  256. case TEXT('u'):
  257. case TEXT('U'):
  258. bUnregister = TRUE;
  259. pszDllEntryPoint = _szDllUnregSvr;
  260. ptszDllEntryPoint = _tszDllUnregSvr;
  261. break;
  262. case TEXT('v'):
  263. case TEXT('V'):
  264. bVisualC = TRUE;
  265. break;
  266. case TEXT('c'):
  267. case TEXT('C'):
  268. // Ignore this
  269. break;
  270. default:
  271. Usage(IDS_UNRECOGNIZEDFLAG, pszTok);
  272. return FAIL_ARGS;
  273. }
  274. } else {
  275. if (pszTok[0] == TEXT('"')) {
  276. // handle quoted DllName
  277. TCHAR szTemp[MAX_PATH];
  278. LPTSTR pszQuotedDllName;
  279. int iLength;
  280. lstrcpy(szTemp, &pszTok[1]);
  281. iLength = lstrlen(szTemp);
  282. if ((iLength > 0) && szTemp[iLength - 1] != TEXT('"')) {
  283. // handle quoted dll name that spans multiple tokens
  284. for (iTok++; iTok < __argc; iTok++) {
  285. lstrcat(szTemp, TEXT(" "));
  286. lstrcat(szTemp, __targv[iTok]);
  287. iLength = lstrlen(__targv[iTok]);
  288. if ((iLength > 0) && __targv[iTok][iLength - 1] == TEXT('"')) {
  289. // this token has the end quote, so stop here
  290. break;
  291. }
  292. }
  293. }
  294. iLength = lstrlen(szTemp);
  295. // remove the trailing " if one exists
  296. if ( (iLength > 0) && (szTemp[iLength - 1] == TEXT('"')) ) {
  297. szTemp[iLength - 1] = TEXT('\0');
  298. }
  299. pszQuotedDllName = (LPTSTR) LocalAlloc(LPTR, (iLength + 1) * sizeof(TCHAR));
  300. if (pszQuotedDllName)
  301. {
  302. lstrcpy(pszQuotedDllName, szTemp);
  303. ppszDllNames[iNumDllsToRegister] = pszQuotedDllName;
  304. iNumDllsToRegister++;
  305. }
  306. } else {
  307. // no leading " so assume that this token is one of the dll names
  308. ppszDllNames[iNumDllsToRegister] = pszTok;
  309. iNumDllsToRegister++;
  310. }
  311. }
  312. }
  313. // check to see if we were passed a '-n' but no '-i'
  314. if (!bCallDllRegisterServer && !bCallDllInstall) {
  315. Usage(IDS_UNRECOGNIZEDFLAG, TEXT("/n must be used with the /i switch"));
  316. return FAIL_ARGS;
  317. }
  318. if (iNumDllsToRegister == 0) {
  319. if (bVisualC)
  320. DisplayMessage(IDS_NOPROJECT);
  321. else
  322. Usage(IDS_NODLLNAME);
  323. return FAIL_ARGS;
  324. }
  325. // Initialize OLE.
  326. __try {
  327. rc = OleInitialize(NULL);
  328. } __except (EXCEPTION_EXECUTE_HANDLER) {
  329. rc = (HRESULT) GetExceptionCode();
  330. }
  331. if (FAILED(rc)) {
  332. DisplayMessage(IDS_OLEINITFAILED);
  333. return FAIL_OLE;
  334. }
  335. if (_bSilent) {
  336. SetErrorMode(SEM_FAILCRITICALERRORS); // Make sure LoadLib fail in silent mode (no popups).
  337. }
  338. for (iCount = 0; iCount < iNumDllsToRegister; iCount++) {
  339. pszDllName = ppszDllNames[iCount];
  340. /*
  341. * See if this is a non-executable file that requires special handling. If so,
  342. * bContextReg will be set to TRUE and pszDllName (which original pointed to
  343. * the path to the special file) will be set to the path to the executable that
  344. * is responsible for doing the actual registration. The path to the special
  345. * file will be passed in as context info in the call Dll[Un]RegisterServerEx.
  346. */
  347. pszContextW = pszDllName;
  348. pszContext = (LPSTR)pszContextW;
  349. bContextReg = IsContextRegFileType(&pszDllName);
  350. if (TRUE == bContextReg) {
  351. lstrcatA(pszDllEntryPoint, "Ex");
  352. lstrcat(ptszDllEntryPoint, TEXT("Ex"));
  353. // Convert pszContext to a real char *
  354. #ifdef UNICODE
  355. if (!WideCharToMultiByte(CP_ACP,
  356. 0,
  357. (LPCWSTR)pszContext,
  358. lstrlenW((LPCWSTR)pszContext),
  359. _szRegContext,
  360. sizeof(_szRegContext),
  361. 0,
  362. NULL))
  363. {
  364. Usage(IDS_UNRECOGNIZEDFLAG, pszTok);
  365. return FAIL_ARGS;
  366. } else {
  367. pszContext = _szRegContext;
  368. }
  369. #endif
  370. }
  371. // Load the library -- fail silently if problems
  372. UINT errMode = SetErrorMode(SEM_FAILCRITICALERRORS);
  373. HINSTANCE hLib = LoadLibraryEx(pszDllName, NULL, LOAD_WITH_ALTERED_SEARCH_PATH);
  374. SetErrorMode(errMode);
  375. if (hLib < (HINSTANCE)HINSTANCE_ERROR) {
  376. DWORD dwErr = GetLastError();
  377. if (ERROR_BAD_EXE_FORMAT == dwErr) {
  378. DisplayMessage(IDS_NOTEXEORHELPER, pszDllName);
  379. } else {
  380. if (FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM, NULL,
  381. dwErr, 0, szError, sizeof(szError), NULL)) {
  382. DisplayMessage(IDS_LOADLIBFAILED, pszDllName, szError);
  383. }
  384. }
  385. iReturn = FAIL_LOAD;
  386. goto CleanupOle;
  387. }
  388. // during unregister we need to call DllInstall first, and then DllUnregisterServer
  389. if (bUnregister)
  390. goto DllInstall;
  391. DllRegisterServer:
  392. // Call the entry point for DllRegisterServer/DllUnregisterServer
  393. if (bCallDllRegisterServer) {
  394. if (bContextReg) {
  395. (FARPROC&)lpDllEntryPointRegEx = GetProcAddress(hLib, "DllRegisterServerExW");
  396. if (lpDllEntryPointRegEx) {
  397. (FARPROC&)lpDllEntryPointRegExW = (FARPROC&)lpDllEntryPointRegEx;
  398. bUnicodeContextReg = TRUE;
  399. } else {
  400. (FARPROC&)lpDllEntryPointRegEx = GetProcAddress(hLib, "DllRegisterServerEx");
  401. }
  402. (FARPROC&)lpDllEntryPointReg = (FARPROC&)lpDllEntryPointRegEx;
  403. } else {
  404. (FARPROC&)lpDllEntryPointReg = (FARPROC&)lpDllEntryPointRegEx = GetProcAddress(hLib, pszDllEntryPoint);
  405. }
  406. if (lpDllEntryPointReg == NULL) {
  407. TCHAR szExt[_MAX_EXT];
  408. _tsplitpath(pszDllName, NULL, NULL, NULL, szExt);
  409. if (FALSE == bContextReg && (lstrcmp(szExt, TEXT(".dll")) != 0) && (lstrcmp(szExt, TEXT(".ocx")) != 0))
  410. DisplayMessage(IDS_NOTDLLOROCX, pszDllName, ptszDllEntryPoint);
  411. else
  412. DisplayMessage(IDS_NOENTRYPOINT, pszDllName, ptszDllEntryPoint);
  413. iReturn = FAIL_ENTRY;
  414. goto CleanupLibrary;
  415. }
  416. // try calling DllRegisterServer[Ex]() / DllUnregisterServer[Ex]()
  417. __try {
  418. if (bUnicodeContextReg) {
  419. rc = (*lpDllEntryPointRegExW)(pszContextW);
  420. } else {
  421. if (bContextReg) {
  422. rc = (*lpDllEntryPointRegEx)(pszContext);
  423. } else {
  424. rc = (*lpDllEntryPointReg)();
  425. }
  426. }
  427. } __except(EXCEPTION_EXECUTE_HANDLER) {
  428. rc = (HRESULT) GetExceptionCode();
  429. }
  430. if (FAILED(rc)) {
  431. wsprintf(szError, _T("0x%08lx"), rc);
  432. DisplayMessage(IDS_CALLFAILED, ptszDllEntryPoint, pszDllName, szError);
  433. iReturn = FAIL_REG;
  434. goto CleanupLibrary;
  435. }
  436. }
  437. // during unregister we need to call DllInstall first, then DllRegisterServer,
  438. // since we already called DllInstall and then jumped back up to DllRegisterServer:
  439. // skip over it and goto CheckErrors:
  440. if (bUnregister)
  441. goto CheckErrors;
  442. DllInstall:
  443. // Call the entry point for DllInstall
  444. if (bCallDllInstall) {
  445. (FARPROC&)lpDllEntryPointInstall = GetProcAddress(hLib, _szDllInstall);
  446. if (lpDllEntryPointInstall == NULL) {
  447. TCHAR szExt[_MAX_EXT];
  448. _tsplitpath(pszDllName, NULL, NULL, NULL, szExt);
  449. if ((lstrcmp(szExt, TEXT(".dll")) != 0) && (lstrcmp(szExt, TEXT(".ocx")) != 0))
  450. DisplayMessage(IDS_NOTDLLOROCX, pszDllName, _tszDllInstall);
  451. else
  452. DisplayMessage(IDS_NOENTRYPOINT, pszDllName, _tszDllInstall);
  453. iReturn = FAIL_ENTRY;
  454. goto CleanupLibrary;
  455. }
  456. // try calling DllInstall(BOOL bRegister, LPWSTR lpwszCmdLine) here...
  457. // NOTE: the lpwszCmdLine string must be UNICODE!
  458. __try {
  459. rc = (*lpDllEntryPointInstall)(!bUnregister, pwszDllInstallCmdLine);
  460. } __except(EXCEPTION_EXECUTE_HANDLER) {
  461. rc = (HRESULT) GetExceptionCode();
  462. }
  463. if (FAILED(rc)) {
  464. wsprintf(szError, _T("0x%08lx"), rc);
  465. DisplayMessage(IDS_CALLFAILED, _tszDllInstall, pszDllName, szError);
  466. iReturn = FAIL_REG;
  467. goto CleanupLibrary;
  468. }
  469. }
  470. // during unregister we now need to call DllUnregisterServer
  471. if (bUnregister)
  472. goto DllRegisterServer;
  473. CheckErrors:
  474. if (!bErrorsOnly) {
  475. TCHAR szMessage[MAX_PATH];
  476. // set up the success message text
  477. if (bCallDllRegisterServer)
  478. {
  479. lstrcpy(szMessage, ptszDllEntryPoint);
  480. if (bCallDllInstall)
  481. {
  482. lstrcat(szMessage, TEXT(" and "));
  483. lstrcat(szMessage, _tszDllInstall);
  484. }
  485. }
  486. else if (bCallDllInstall)
  487. {
  488. lstrcpy(szMessage, _tszDllInstall);
  489. }
  490. Info(IDS_CALLSUCCEEDED, szMessage, pszDllName);
  491. }
  492. CleanupLibrary:
  493. FreeLibrary(hLib);
  494. }
  495. CleanupOle:
  496. __try {
  497. OleUninitialize();
  498. } __except (EXCEPTION_EXECUTE_HANDLER) {
  499. DisplayMessage(IDS_OLEUNINITFAILED);
  500. }
  501. return iReturn;
  502. }