// regsvr.cpp : Program to invoke OLE self-registration on a DLL. // // This is a part of the Microsoft Foundation Classes C++ library. // Copyright (C) 1992-1995 Microsoft Corporation // All rights reserved. // // This source code is only intended as a supplement to the // Microsoft Foundation Classes Reference and related // electronic documentation provided with the library. // See these sources for detailed information regarding the // Microsoft Foundation Classes product. #include #include #include #include #include "resource.h" #define FAIL_ARGS 1 #define FAIL_OLE 2 #define FAIL_LOAD 3 #define FAIL_ENTRY 4 #define FAIL_REG 5 const TCHAR _szAppName[] = _T("RegSvr32"); const char _szDllInstall[] = "DllInstall"; const TCHAR _tszDllInstall[] = TEXT("DllInstall"); TCHAR _szDllPath[_MAX_PATH]; // Leave room for "Ex" to be tacked onto end char _szDllRegSvr[32] = "DllRegisterServer"; TCHAR _tszDllRegSvr[32] = TEXT("DllRegisterServer"); char _szDllUnregSvr[32] = "DllUnregisterServer"; TCHAR _tszDllUnregSvr[32] = TEXT("DllUnregisterServer"); char _szRegContext[_MAX_PATH]; HINSTANCE _hInstance; BOOL _bSilent; void FormatString3( LPTSTR lpszOut, LPCTSTR lpszFormat, LPCTSTR lpsz1, LPCTSTR lpsz2, LPCTSTR lpsz3 ) { LPCTSTR pchSrc = lpszFormat; LPTSTR pchDest = lpszOut; LPCTSTR pchTmp; while (*pchSrc != '\0') { if (pchSrc[0] == '%' && (pchSrc[1] >= '1' && pchSrc[1] <= '3')) { if (pchSrc[1] == '1') pchTmp = lpsz1; else if (pchSrc[1] == '2') pchTmp = lpsz2; else pchTmp = lpsz3; lstrcpy(pchDest, pchTmp); pchDest += lstrlen(pchDest); pchSrc += 2; } else { if (_istlead(*pchSrc)) *pchDest++ = *pchSrc++; // copy first of 2 bytes *pchDest++ = *pchSrc++; } } *pchDest = '\0'; } #define MAX_STRING 1024 void DisplayMessage( UINT ids, LPCTSTR pszArg1 = NULL, LPCTSTR pszArg2 = NULL, LPCTSTR pszArg3 = NULL, BOOL bUsage = FALSE, BOOL bInfo = FALSE ) { if (_bSilent) return; TCHAR szFmt[MAX_STRING]; LoadString(_hInstance, ids, szFmt, MAX_STRING); TCHAR szText[MAX_STRING]; FormatString3(szText, szFmt, pszArg1, pszArg2, pszArg3); if (bUsage) { int cch = _tcslen(szText); LoadString(_hInstance, IDS_USAGE, szText + cch, MAX_STRING - cch); } if (! _bSilent) MessageBox(NULL, szText, _szAppName, MB_TASKMODAL | (bInfo ? MB_ICONINFORMATION : MB_ICONEXCLAMATION)); } inline void Usage( UINT ids, LPCTSTR pszArg1 = NULL, LPCTSTR pszArg2 = NULL ) { DisplayMessage(ids, pszArg1, pszArg2, NULL, TRUE); } inline void Info( UINT ids, LPCTSTR pszArg1 = NULL, LPCTSTR pszArg2 = NULL ) { DisplayMessage(ids, pszArg1, pszArg2, NULL, FALSE, TRUE); } #define MAX_APPID 256 BOOL IsContextRegFileType(LPCTSTR *ppszDllName) { HKEY hk1, hk2; LONG lRet; LONG cch; TCHAR szExt[_MAX_EXT]; TCHAR szAppID[MAX_APPID]; _tsplitpath(*ppszDllName, NULL, NULL, NULL, szExt); // Find [HKEY_CLASSES_ROOT\.foo] if (ERROR_SUCCESS != RegOpenKeyEx(HKEY_CLASSES_ROOT, szExt, 0, KEY_QUERY_VALUE, &hk1)) return FALSE; // Read [HKEY_CLASSES_ROOT\.foo\"foo_auto_file"] cch = sizeof(szAppID); lRet = RegQueryValue(hk1, NULL, szAppID, &cch); RegCloseKey(hk1); if (ERROR_SUCCESS != lRet) return FALSE; // Find [HKEY_CLASSES_ROOT\foo_auto_file] if (ERROR_SUCCESS != RegOpenKeyEx(HKEY_CLASSES_ROOT, szAppID, 0, KEY_QUERY_VALUE, &hk1)) return FALSE; // Find [HKEY_CLASSES_ROOT\foo_auto_file\AutoRegister] if (ERROR_SUCCESS != RegOpenKeyEx(hk1, TEXT("AutoRegister"), 0, KEY_QUERY_VALUE, &hk2)) { RegCloseKey(hk1); return FALSE; } // Read [HKEY_CLASSES_ROOT\foo_auto_file\AutoRegister\"d:\...\fooreg.dll"] cch = MAX_PATH; lRet = RegQueryValue(hk2, NULL, _szDllPath, &cch); RegCloseKey(hk1); RegCloseKey(hk2); if (ERROR_SUCCESS != lRet) return FALSE; _szDllPath[cch] = TEXT('\0'); *ppszDllName = _szDllPath; return TRUE; } int PASCAL _tWinMain( HINSTANCE hInstance, HINSTANCE, LPSTR, int ) { int iReturn = 0; HRESULT (STDAPICALLTYPE * lpDllEntryPointReg)(void); HRESULT (STDAPICALLTYPE * lpDllEntryPointRegEx)(LPCSTR); HRESULT (STDAPICALLTYPE * lpDllEntryPointRegExW)(LPCWSTR); HRESULT (STDAPICALLTYPE * lpDllEntryPointInstall)(BOOL, LPWSTR); HRESULT rc; BOOL bVisualC = FALSE; BOOL bUnregister = FALSE; BOOL bCallDllInstall = FALSE; BOOL bCallDllRegisterServer = TRUE; BOOL bErrorsOnly = FALSE; BOOL bContextReg = FALSE; BOOL bUnicodeContextReg = FALSE; LPSTR pszDllEntryPoint = _szDllRegSvr; LPTSTR ptszDllEntryPoint = _tszDllRegSvr; LPTSTR pszTok; LPCTSTR pszDllName; LPSTR pszContext; LPCTSTR pszContextW; TCHAR pszDllInstallCmdLine[MAX_PATH]; #ifdef UNICODE PWCHAR pwszDllInstallCmdLine = pszDllInstallCmdLine; #else WCHAR pwszDllInstallCmdLine[MAX_PATH]; #endif int iNumDllsToRegister = 0; int iCount; LPCTSTR ppszDllNames[255]; TCHAR szError[1024]; _hInstance = hInstance; // Parse command line arguments. int iTok; for (iTok = 1; iTok < __argc; iTok++) { pszTok = __targv[iTok]; if ((pszTok[0] == TEXT('-')) || (pszTok[0] == TEXT('/'))) { switch (pszTok[1]) { case TEXT('e'): case TEXT('E'): bErrorsOnly = TRUE; break; case TEXT('i'): case TEXT('I'): bCallDllInstall = TRUE; if (pszTok[2] == TEXT(':')) { if (pszTok[3] == TEXT('"')) { // handle quoted InstallCmdLine ( // (e.g. /i:"c:\my dll dir\mydll.dll") LPTSTR pszEndQuote = &pszTok[4]; int iLength = lstrlen(pszEndQuote); if ((iLength > 0) && pszEndQuote[iLength - 1] == TEXT('"')) { // they quoted the string but it wasent really necessary // (e.g. /i:"shell32.dll") pszEndQuote[iLength - 1] = TEXT('\0'); lstrcpy(pszDllInstallCmdLine, pszEndQuote); } else { // we have a quoted string that spans multiple tokens lstrcpy(pszDllInstallCmdLine, pszEndQuote); for (iTok++; iTok < __argc; iTok++) { // grab the next token pszEndQuote = __targv[iTok]; iLength = lstrlen(pszEndQuote); if ((iLength > 0) && (pszEndQuote[iLength - 1] == '"')) { pszEndQuote[iLength - 1] = TEXT('\0'); lstrcat(pszDllInstallCmdLine, TEXT(" ")); lstrcat(pszDllInstallCmdLine, pszEndQuote); break; } lstrcat(pszDllInstallCmdLine, TEXT(" ")); lstrcat(pszDllInstallCmdLine, pszEndQuote); } } } else { // cmd line is NOT quoted lstrcpy(pszDllInstallCmdLine, &pszTok[3]); } #ifndef UNICODE if (!MultiByteToWideChar(CP_ACP, 0, (LPCTSTR)pszDllInstallCmdLine, -1, pwszDllInstallCmdLine, MAX_PATH)) { Usage(IDS_UNRECOGNIZEDFLAG, pszTok); return FAIL_ARGS; } #endif } else { lstrcpyW((LPWSTR)pwszDllInstallCmdLine, L""); } break; case TEXT('n'): case TEXT('N'): bCallDllRegisterServer = FALSE; break; case TEXT('s'): case TEXT('S'): _bSilent = TRUE; break; case TEXT('u'): case TEXT('U'): bUnregister = TRUE; pszDllEntryPoint = _szDllUnregSvr; ptszDllEntryPoint = _tszDllUnregSvr; break; case TEXT('v'): case TEXT('V'): bVisualC = TRUE; break; case TEXT('c'): case TEXT('C'): // Ignore this break; default: Usage(IDS_UNRECOGNIZEDFLAG, pszTok); return FAIL_ARGS; } } else { if (pszTok[0] == TEXT('"')) { // handle quoted DllName TCHAR szTemp[MAX_PATH]; LPTSTR pszQuotedDllName; int iLength; lstrcpy(szTemp, &pszTok[1]); iLength = lstrlen(szTemp); if ((iLength > 0) && szTemp[iLength - 1] != TEXT('"')) { // handle quoted dll name that spans multiple tokens for (iTok++; iTok < __argc; iTok++) { lstrcat(szTemp, TEXT(" ")); lstrcat(szTemp, __targv[iTok]); iLength = lstrlen(__targv[iTok]); if ((iLength > 0) && __targv[iTok][iLength - 1] == TEXT('"')) { // this token has the end quote, so stop here break; } } } iLength = lstrlen(szTemp); // remove the trailing " if one exists if ( (iLength > 0) && (szTemp[iLength - 1] == TEXT('"')) ) { szTemp[iLength - 1] = TEXT('\0'); } pszQuotedDllName = (LPTSTR) LocalAlloc(LPTR, (iLength + 1) * sizeof(TCHAR)); if (pszQuotedDllName) { lstrcpy(pszQuotedDllName, szTemp); ppszDllNames[iNumDllsToRegister] = pszQuotedDllName; iNumDllsToRegister++; } } else { // no leading " so assume that this token is one of the dll names ppszDllNames[iNumDllsToRegister] = pszTok; iNumDllsToRegister++; } } } // check to see if we were passed a '-n' but no '-i' if (!bCallDllRegisterServer && !bCallDllInstall) { Usage(IDS_UNRECOGNIZEDFLAG, TEXT("/n must be used with the /i switch")); return FAIL_ARGS; } if (iNumDllsToRegister == 0) { if (bVisualC) DisplayMessage(IDS_NOPROJECT); else Usage(IDS_NODLLNAME); return FAIL_ARGS; } // Initialize OLE. __try { rc = OleInitialize(NULL); } __except (EXCEPTION_EXECUTE_HANDLER) { rc = (HRESULT) GetExceptionCode(); } if (FAILED(rc)) { DisplayMessage(IDS_OLEINITFAILED); return FAIL_OLE; } if (_bSilent) { SetErrorMode(SEM_FAILCRITICALERRORS); // Make sure LoadLib fail in silent mode (no popups). } for (iCount = 0; iCount < iNumDllsToRegister; iCount++) { pszDllName = ppszDllNames[iCount]; /* * See if this is a non-executable file that requires special handling. If so, * bContextReg will be set to TRUE and pszDllName (which original pointed to * the path to the special file) will be set to the path to the executable that * is responsible for doing the actual registration. The path to the special * file will be passed in as context info in the call Dll[Un]RegisterServerEx. */ pszContextW = pszDllName; pszContext = (LPSTR)pszContextW; bContextReg = IsContextRegFileType(&pszDllName); if (TRUE == bContextReg) { lstrcatA(pszDllEntryPoint, "Ex"); lstrcat(ptszDllEntryPoint, TEXT("Ex")); // Convert pszContext to a real char * #ifdef UNICODE if (!WideCharToMultiByte(CP_ACP, 0, (LPCWSTR)pszContext, lstrlenW((LPCWSTR)pszContext), _szRegContext, sizeof(_szRegContext), 0, NULL)) { Usage(IDS_UNRECOGNIZEDFLAG, pszTok); return FAIL_ARGS; } else { pszContext = _szRegContext; } #endif } // Load the library -- fail silently if problems UINT errMode = SetErrorMode(SEM_FAILCRITICALERRORS); HINSTANCE hLib = LoadLibraryEx(pszDllName, NULL, LOAD_WITH_ALTERED_SEARCH_PATH); SetErrorMode(errMode); if (hLib < (HINSTANCE)HINSTANCE_ERROR) { DWORD dwErr = GetLastError(); if (ERROR_BAD_EXE_FORMAT == dwErr) { DisplayMessage(IDS_NOTEXEORHELPER, pszDllName); } else { if (FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM, NULL, dwErr, 0, szError, sizeof(szError), NULL)) { DisplayMessage(IDS_LOADLIBFAILED, pszDllName, szError); } } iReturn = FAIL_LOAD; goto CleanupOle; } // during unregister we need to call DllInstall first, and then DllUnregisterServer if (bUnregister) goto DllInstall; DllRegisterServer: // Call the entry point for DllRegisterServer/DllUnregisterServer if (bCallDllRegisterServer) { if (bContextReg) { (FARPROC&)lpDllEntryPointRegEx = GetProcAddress(hLib, "DllRegisterServerExW"); if (lpDllEntryPointRegEx) { (FARPROC&)lpDllEntryPointRegExW = (FARPROC&)lpDllEntryPointRegEx; bUnicodeContextReg = TRUE; } else { (FARPROC&)lpDllEntryPointRegEx = GetProcAddress(hLib, "DllRegisterServerEx"); } (FARPROC&)lpDllEntryPointReg = (FARPROC&)lpDllEntryPointRegEx; } else { (FARPROC&)lpDllEntryPointReg = (FARPROC&)lpDllEntryPointRegEx = GetProcAddress(hLib, pszDllEntryPoint); } if (lpDllEntryPointReg == NULL) { TCHAR szExt[_MAX_EXT]; _tsplitpath(pszDllName, NULL, NULL, NULL, szExt); if (FALSE == bContextReg && (lstrcmp(szExt, TEXT(".dll")) != 0) && (lstrcmp(szExt, TEXT(".ocx")) != 0)) DisplayMessage(IDS_NOTDLLOROCX, pszDllName, ptszDllEntryPoint); else DisplayMessage(IDS_NOENTRYPOINT, pszDllName, ptszDllEntryPoint); iReturn = FAIL_ENTRY; goto CleanupLibrary; } // try calling DllRegisterServer[Ex]() / DllUnregisterServer[Ex]() __try { if (bUnicodeContextReg) { rc = (*lpDllEntryPointRegExW)(pszContextW); } else { if (bContextReg) { rc = (*lpDllEntryPointRegEx)(pszContext); } else { rc = (*lpDllEntryPointReg)(); } } } __except(EXCEPTION_EXECUTE_HANDLER) { rc = (HRESULT) GetExceptionCode(); } if (FAILED(rc)) { wsprintf(szError, _T("0x%08lx"), rc); DisplayMessage(IDS_CALLFAILED, ptszDllEntryPoint, pszDllName, szError); iReturn = FAIL_REG; goto CleanupLibrary; } } // during unregister we need to call DllInstall first, then DllRegisterServer, // since we already called DllInstall and then jumped back up to DllRegisterServer: // skip over it and goto CheckErrors: if (bUnregister) goto CheckErrors; DllInstall: // Call the entry point for DllInstall if (bCallDllInstall) { (FARPROC&)lpDllEntryPointInstall = GetProcAddress(hLib, _szDllInstall); if (lpDllEntryPointInstall == NULL) { TCHAR szExt[_MAX_EXT]; _tsplitpath(pszDllName, NULL, NULL, NULL, szExt); if ((lstrcmp(szExt, TEXT(".dll")) != 0) && (lstrcmp(szExt, TEXT(".ocx")) != 0)) DisplayMessage(IDS_NOTDLLOROCX, pszDllName, _tszDllInstall); else DisplayMessage(IDS_NOENTRYPOINT, pszDllName, _tszDllInstall); iReturn = FAIL_ENTRY; goto CleanupLibrary; } // try calling DllInstall(BOOL bRegister, LPWSTR lpwszCmdLine) here... // NOTE: the lpwszCmdLine string must be UNICODE! __try { rc = (*lpDllEntryPointInstall)(!bUnregister, pwszDllInstallCmdLine); } __except(EXCEPTION_EXECUTE_HANDLER) { rc = (HRESULT) GetExceptionCode(); } if (FAILED(rc)) { wsprintf(szError, _T("0x%08lx"), rc); DisplayMessage(IDS_CALLFAILED, _tszDllInstall, pszDllName, szError); iReturn = FAIL_REG; goto CleanupLibrary; } } // during unregister we now need to call DllUnregisterServer if (bUnregister) goto DllRegisterServer; CheckErrors: if (!bErrorsOnly) { TCHAR szMessage[MAX_PATH]; // set up the success message text if (bCallDllRegisterServer) { lstrcpy(szMessage, ptszDllEntryPoint); if (bCallDllInstall) { lstrcat(szMessage, TEXT(" and ")); lstrcat(szMessage, _tszDllInstall); } } else if (bCallDllInstall) { lstrcpy(szMessage, _tszDllInstall); } Info(IDS_CALLSUCCEEDED, szMessage, pszDllName); } CleanupLibrary: FreeLibrary(hLib); } CleanupOle: __try { OleUninitialize(); } __except (EXCEPTION_EXECUTE_HANDLER) { DisplayMessage(IDS_OLEUNINITFAILED); } return iReturn; }