1 /* 2 * ReactOS regsvr32 3 * Copyright (C) 2004-2006 ReactOS Team 4 * 5 * COPYRIGHT: See COPYING in the top level directory 6 * PROJECT: ReactOS regsvr32.exe 7 * FILE: base/system/regsvr32/regsvr32.c 8 * PURPOSE: Register a COM component in the registry 9 * PROGRAMMER: ShadowFlare (blakflare@hotmail.com) 10 */ 11 12 // Both UNICODE and _UNICODE must be either defined or undefined 13 // because some headers use UNICODE and others use _UNICODE 14 #ifdef UNICODE 15 #ifndef _UNICODE 16 #define _UNICODE 17 #endif 18 #else 19 #ifdef _UNICODE 20 #define UNICODE 21 #endif 22 #endif 23 24 #define WIN32_NO_STATUS 25 #define _INC_WINDOWS 26 #define COM_NO_WINDOWS_H 27 #include <stdarg.h> 28 #include <windef.h> 29 #include <winbase.h> 30 #include <ole2.h> 31 #include <tchar.h> 32 33 typedef HRESULT (WINAPI *DLLREGISTER)(void); 34 typedef HRESULT (WINAPI *DLLINSTALL)(BOOL bInstall, LPWSTR lpwCmdLine); 35 36 #define EXITCODE_SUCCESS 0 37 #define EXITCODE_PARAMERROR 1 38 #define EXITCODE_LOADERROR 3 39 #define EXITCODE_NOENTRY 4 40 #define EXITCODE_FAILURE 5 41 42 LPCSTR szDllRegister = "DllRegisterServer"; 43 LPCSTR szDllUnregister = "DllUnregisterServer"; 44 LPCSTR szDllInstall = "DllInstall"; 45 #ifdef UNICODE 46 LPCWSTR tszDllRegister = L"DllRegisterServer"; 47 LPCWSTR tszDllUnregister = L"DllUnregisterServer"; 48 LPCWSTR tszDllInstall = L"DllInstall"; 49 #else 50 #define tszDllRegister szDllRegister 51 #define tszDllUnregister szDllUnregister 52 #define tszDllInstall szDllInstall 53 #endif 54 55 #include "resource.h" 56 57 LPCTSTR ModuleTitle = _T("RegSvr32"); 58 59 TCHAR UsageMessage[RC_STRING_MAX_SIZE]; 60 TCHAR NoDllSpecified[RC_STRING_MAX_SIZE]; 61 TCHAR InvalidFlag[RC_STRING_MAX_SIZE]; 62 TCHAR SwitchN_NoI[RC_STRING_MAX_SIZE]; 63 TCHAR DllNotLoaded[RC_STRING_MAX_SIZE]; 64 TCHAR MissingEntry[RC_STRING_MAX_SIZE]; 65 TCHAR FailureMessage[RC_STRING_MAX_SIZE]; 66 TCHAR SuccessMessage[RC_STRING_MAX_SIZE]; 67 68 // The macro CommandLineToArgv maps to a function that converts 69 // a command-line string to argc and argv similar to the ones 70 // in the standard main function. If this code is compiled for 71 // unicode, the build-in Windows API function is used, otherwise 72 // a non-unicode non-API version is used for compatibility with 73 // Windows versions that have no unicode support. 74 #ifdef UNICODE 75 #define CommandLineToArgv CommandLineToArgvW 76 #include <shellapi.h> 77 #else 78 #define CommandLineToArgv CommandLineToArgvT 79 80 LPTSTR *WINAPI CommandLineToArgvT(LPCTSTR lpCmdLine, int *lpArgc) 81 { 82 HGLOBAL hargv; 83 LPTSTR *argv, lpSrc, lpDest, lpArg; 84 int argc, nBSlash; 85 BOOL bInQuotes; 86 87 // If null was passed in for lpCmdLine, there are no arguments 88 if (!lpCmdLine) { 89 if (lpArgc) 90 *lpArgc = 0; 91 return 0; 92 } 93 94 lpSrc = (LPTSTR)lpCmdLine; 95 // Skip spaces at beginning 96 while (*lpSrc == _T(' ') || *lpSrc == _T('\t')) 97 lpSrc++; 98 99 // If command-line starts with null, there are no arguments 100 if (*lpSrc == 0) { 101 if (lpArgc) 102 *lpArgc = 0; 103 return 0; 104 } 105 106 lpArg = lpSrc; 107 argc = 0; 108 nBSlash = 0; 109 bInQuotes = FALSE; 110 111 // Count the number of arguments 112 while (1) { 113 if (*lpSrc == 0 || ((*lpSrc == _T(' ') || *lpSrc == _T('\t')) && !bInQuotes)) { 114 // Whitespace not enclosed in quotes signals the start of another argument 115 argc++; 116 117 // Skip whitespace between arguments 118 while (*lpSrc == _T(' ') || *lpSrc == _T('\t')) 119 lpSrc++; 120 if (*lpSrc == 0) 121 break; 122 nBSlash = 0; 123 continue; 124 } 125 else if (*lpSrc == _T('\\')) { 126 // Count consecutive backslashes 127 nBSlash++; 128 } 129 else if (*lpSrc == _T('\"') && !(nBSlash & 1)) { 130 // Open or close quotes 131 bInQuotes = !bInQuotes; 132 nBSlash = 0; 133 } 134 else { 135 // Some other character 136 nBSlash = 0; 137 } 138 lpSrc++; 139 } 140 141 // Allocate space the same way as CommandLineToArgvW for compatibility 142 hargv = GlobalAlloc(0, argc * sizeof(LPTSTR) + (_tcslen(lpArg) + 1) * sizeof(TCHAR)); 143 argv = (LPTSTR *)GlobalLock(hargv); 144 145 if (!argv) { 146 // Memory allocation failed 147 if (lpArgc) 148 *lpArgc = 0; 149 return 0; 150 } 151 152 lpSrc = lpArg; 153 lpDest = lpArg = (LPTSTR)(argv + argc); 154 argc = 0; 155 nBSlash = 0; 156 bInQuotes = FALSE; 157 158 // Fill the argument array 159 while (1) { 160 if (*lpSrc == 0 || ((*lpSrc == _T(' ') || *lpSrc == _T('\t')) && !bInQuotes)) { 161 // Whitespace not enclosed in quotes signals the start of another argument 162 // Null-terminate argument 163 *lpDest++ = 0; 164 argv[argc++] = lpArg; 165 166 // Skip whitespace between arguments 167 while (*lpSrc == _T(' ') || *lpSrc == _T('\t')) 168 lpSrc++; 169 if (*lpSrc == 0) 170 break; 171 lpArg = lpDest; 172 nBSlash = 0; 173 continue; 174 } 175 else if (*lpSrc == _T('\\')) { 176 *lpDest++ = _T('\\'); 177 lpSrc++; 178 179 // Count consecutive backslashes 180 nBSlash++; 181 } 182 else if (*lpSrc == _T('\"')) { 183 if (!(nBSlash & 1)) { 184 // If an even number of backslashes are before the quotes, 185 // the quotes don't go in the output 186 lpDest -= nBSlash / 2; 187 bInQuotes = !bInQuotes; 188 } 189 else { 190 // If an odd number of backslashes are before the quotes, 191 // output a quote 192 lpDest -= (nBSlash + 1) / 2; 193 *lpDest++ = _T('\"'); 194 } 195 lpSrc++; 196 nBSlash = 0; 197 } 198 else { 199 // Copy other characters 200 *lpDest++ = *lpSrc++; 201 nBSlash = 0; 202 } 203 } 204 205 if (lpArgc) 206 *lpArgc = argc; 207 return argv; 208 } 209 210 #endif 211 212 // The macro ConvertToWideChar takes a tstring parameter and returns 213 // a pointer to a unicode string. A conversion is performed if 214 // necessary. FreeConvertedWideChar string should be used on the 215 // return value of ConvertToWideChar when the string is no longer 216 // needed. The original string or the string that is returned 217 // should not be modified until FreeConvertedWideChar has been called. 218 #ifdef UNICODE 219 #define ConvertToWideChar(lptString) (lptString) 220 #define FreeConvertedWideChar(lpwString) ((void) 0) 221 #else 222 223 LPWSTR ConvertToWideChar(LPCSTR lpString) 224 { 225 LPWSTR lpwString; 226 size_t nStrLen; 227 228 nStrLen = strlen(lpString) + 1; 229 230 lpwString = (LPWSTR)malloc(nStrLen * sizeof(WCHAR)); 231 MultiByteToWideChar(0,0,lpString,nStrLen,lpwString,nStrLen); 232 233 return lpwString; 234 } 235 236 #define FreeConvertedWideChar(lpwString) free(lpwString) 237 #endif 238 239 void DisplayMessage(BOOL bConsole, BOOL bSilent, LPCTSTR lpMessage, LPCTSTR lpTitle, UINT uType) 240 { 241 if (!bSilent) 242 MessageBox(0,lpMessage,lpTitle,uType); 243 if (bConsole) 244 _tprintf(_T("%s: %s\n\n"),lpTitle,lpMessage); 245 } 246 247 int WINAPI _tWinMain( 248 HINSTANCE hInstance, 249 HINSTANCE hPrevInstance, 250 LPTSTR lpCmdLine, 251 int nCmdShow 252 ) 253 { 254 int argc; 255 LPTSTR *argv; 256 LPTSTR lptDllName,lptDllCmdLine,lptMsgBuffer; 257 LPCTSTR lptFuncName; 258 LPCSTR lpFuncName; 259 LPWSTR lpwDllCmdLine; 260 BOOL bUnregister,bSilent,bConsole,bInstall,bNoRegister; 261 UINT nDllCount, fuOldErrorMode; 262 HMODULE hDll; 263 DLLREGISTER fnDllRegister; 264 DLLINSTALL fnDllInstall; 265 HRESULT hResult; 266 DWORD dwErr; 267 int nRetValue,i; 268 269 // Get Langues msg 270 LoadString( GetModuleHandle(NULL), IDS_UsageMessage, (LPTSTR) UsageMessage,RC_STRING_MAX_SIZE); 271 LoadString( GetModuleHandle(NULL), IDS_NoDllSpecified, (LPTSTR) NoDllSpecified,RC_STRING_MAX_SIZE); 272 LoadString( GetModuleHandle(NULL), IDS_InvalidFlag, (LPTSTR) InvalidFlag,RC_STRING_MAX_SIZE); 273 LoadString( GetModuleHandle(NULL), IDS_SwitchN_NoI, (LPTSTR) SwitchN_NoI,RC_STRING_MAX_SIZE); 274 275 LoadString( GetModuleHandle(NULL), IDS_DllNotLoaded, (LPTSTR) DllNotLoaded,RC_STRING_MAX_SIZE); 276 LoadString( GetModuleHandle(NULL), IDS_MissingEntry, (LPTSTR) MissingEntry,RC_STRING_MAX_SIZE); 277 LoadString( GetModuleHandle(NULL), IDS_FailureMessage, (LPTSTR) FailureMessage,RC_STRING_MAX_SIZE); 278 LoadString( GetModuleHandle(NULL), IDS_SuccessMessage, (LPTSTR) SuccessMessage,RC_STRING_MAX_SIZE); 279 280 // Get command-line in argc-argv format 281 argv = CommandLineToArgv(GetCommandLine(),&argc); 282 283 // Initialize variables 284 lptFuncName = 0; 285 lptDllCmdLine = 0; 286 nDllCount = 0; 287 bUnregister = FALSE; 288 bSilent = FALSE; 289 bConsole = FALSE; 290 bInstall = FALSE; 291 bNoRegister = FALSE; 292 293 // Find all arguments starting with a slash (/) 294 for (i = 1; i < argc; i++) { 295 if (*argv[i] == _T('/') || *argv[i] == '-') { 296 switch (argv[i][1]) { 297 case _T('u'): 298 case _T('U'): 299 bUnregister = TRUE; 300 break; 301 case _T('s'): 302 case _T('S'): 303 bSilent = TRUE; 304 break; 305 case _T('c'): 306 case _T('C'): 307 bConsole = TRUE; 308 break; 309 case _T('i'): 310 case _T('I'): 311 bInstall = TRUE; 312 lptDllCmdLine = argv[i]; 313 while (*lptDllCmdLine != 0 && *lptDllCmdLine != _T(':')) 314 lptDllCmdLine++; 315 if (*lptDllCmdLine == _T(':')) 316 lptDllCmdLine++; 317 break; 318 case _T('n'): 319 case _T('N'): 320 bNoRegister = TRUE; 321 break; 322 default: 323 if (!lptFuncName) 324 lptFuncName = argv[i]; 325 } 326 } 327 else { 328 nDllCount++; 329 } 330 } 331 332 // An unrecognized flag was used, display a message and show available options 333 334 if (lptFuncName) { 335 lptMsgBuffer = (LPTSTR)malloc((_tcslen(UsageMessage) - 2 + _tcslen(InvalidFlag) - 2 + _tcslen(lptFuncName) + 1) * sizeof(TCHAR)); 336 _stprintf(lptMsgBuffer + (_tcslen(UsageMessage) - 2),InvalidFlag,lptFuncName); 337 _stprintf(lptMsgBuffer,UsageMessage,lptMsgBuffer + (_tcslen(UsageMessage) - 2)); 338 DisplayMessage(bConsole,bSilent,lptMsgBuffer,ModuleTitle,MB_ICONEXCLAMATION); 339 free(lptMsgBuffer); 340 GlobalFree(argv); 341 return EXITCODE_PARAMERROR; 342 } 343 344 // /n was used without /i, display a message and show available options 345 if (bNoRegister && (!bInstall)) { 346 lptMsgBuffer = (LPTSTR)malloc((_tcslen(UsageMessage) - 2 + _tcslen(SwitchN_NoI) + 1) * sizeof(TCHAR)); 347 _stprintf(lptMsgBuffer,UsageMessage,SwitchN_NoI); 348 DisplayMessage(bConsole,bSilent,lptMsgBuffer,ModuleTitle,MB_ICONEXCLAMATION); 349 free(lptMsgBuffer); 350 GlobalFree(argv); 351 return EXITCODE_PARAMERROR; 352 } 353 354 // No dll was specified, display a message and show available options 355 if (nDllCount == 0) { 356 lptMsgBuffer = (LPTSTR)malloc((_tcslen(UsageMessage) - 2 + _tcslen(NoDllSpecified) + 1) * sizeof(TCHAR)); 357 _stprintf(lptMsgBuffer,UsageMessage,NoDllSpecified); 358 DisplayMessage(bConsole,bSilent,lptMsgBuffer,ModuleTitle,MB_ICONEXCLAMATION); 359 free(lptMsgBuffer); 360 GlobalFree(argv); 361 return EXITCODE_PARAMERROR; 362 } 363 364 nRetValue = EXITCODE_SUCCESS; 365 if (!bUnregister) { 366 lpFuncName = szDllRegister; 367 lptFuncName = tszDllRegister; 368 } 369 else { 370 lpFuncName = szDllUnregister; 371 lptFuncName = tszDllUnregister; 372 } 373 374 if (lptDllCmdLine) 375 lpwDllCmdLine = ConvertToWideChar(lptDllCmdLine); 376 else 377 lpwDllCmdLine = 0; 378 379 // Initialize OLE32 before attempting to register the 380 // dll. Some dll's require this to register properly 381 OleInitialize(0); 382 383 // (Un)register every dll whose filename was passed in the command-line string 384 for (i = 1; i < argc && nRetValue == EXITCODE_SUCCESS; i++) { 385 // Arguments that do not start with a slash (/) are filenames 386 if (*argv[i] != _T('/')) { 387 lptDllName = argv[i]; 388 389 fuOldErrorMode = SetErrorMode(SEM_FAILCRITICALERRORS); 390 // Everything is all setup, so load the dll now 391 hDll = LoadLibraryEx(lptDllName,0,LOAD_WITH_ALTERED_SEARCH_PATH); 392 if (hDll) { 393 SetErrorMode(fuOldErrorMode); 394 if (!bNoRegister) { 395 // Get the address of DllRegisterServer or DllUnregisterServer 396 fnDllRegister = (DLLREGISTER)GetProcAddress(hDll,lpFuncName); 397 if (fnDllRegister) { 398 // If the function exists, call it 399 hResult = fnDllRegister(); 400 if (hResult == S_OK) { 401 // (Un)register succeeded, display a message 402 lptMsgBuffer = (LPTSTR)malloc((_tcslen(SuccessMessage) - 4 + _tcslen(lptFuncName) + _tcslen(lptDllName) + 1) * sizeof(TCHAR)); 403 _stprintf(lptMsgBuffer,SuccessMessage,lptFuncName,lptDllName); 404 DisplayMessage(bConsole,bSilent,lptMsgBuffer,ModuleTitle,MB_ICONINFORMATION); 405 } 406 else { 407 // (Un)register failed, display a message 408 lptMsgBuffer = (LPTSTR)malloc((_tcslen(FailureMessage) + _tcslen(lptFuncName) + _tcslen(lptDllName) + 1) * sizeof(TCHAR)); 409 _stprintf(lptMsgBuffer,FailureMessage,lptFuncName,lptDllName,hResult); 410 DisplayMessage(bConsole,bSilent,lptMsgBuffer,ModuleTitle,MB_ICONEXCLAMATION); 411 } 412 free(lptMsgBuffer); 413 if (hResult != S_OK) 414 nRetValue = EXITCODE_FAILURE; 415 } 416 else { 417 FreeLibrary(hDll); 418 // Dll(Un)register was not found, display an error message 419 lptMsgBuffer = (LPTSTR)malloc((_tcslen(MissingEntry) - 8 + _tcslen(lptFuncName) * 2 + _tcslen(lptDllName) * 2 + 1) * sizeof(TCHAR)); 420 _stprintf(lptMsgBuffer,MissingEntry,lptDllName,lptFuncName,lptFuncName,lptDllName); 421 DisplayMessage(bConsole,bSilent,lptMsgBuffer,ModuleTitle,MB_ICONEXCLAMATION); 422 free(lptMsgBuffer); 423 nRetValue = EXITCODE_NOENTRY; 424 } 425 } 426 427 if (bInstall && nRetValue == EXITCODE_SUCCESS) { 428 // Get the address of DllInstall 429 fnDllInstall = (DLLINSTALL)GetProcAddress(hDll,szDllInstall); 430 if (fnDllInstall) { 431 // If the function exists, call it 432 if (!bUnregister) 433 hResult = fnDllInstall(1,lpwDllCmdLine); 434 else 435 hResult = fnDllInstall(0,lpwDllCmdLine); 436 if (hResult == S_OK) { 437 // (Un)install succeeded, display a message 438 lptMsgBuffer = (LPTSTR)malloc((_tcslen(SuccessMessage) - 4 + _tcslen(tszDllInstall) + _tcslen(lptDllName) + 1) * sizeof(TCHAR)); 439 _stprintf(lptMsgBuffer,SuccessMessage,tszDllInstall,lptDllName); 440 DisplayMessage(bConsole,bSilent,lptMsgBuffer,ModuleTitle,MB_ICONINFORMATION); 441 } 442 else { 443 // (Un)install failed, display a message 444 lptMsgBuffer = (LPTSTR)malloc((_tcslen(FailureMessage) + _tcslen(tszDllInstall) + _tcslen(lptDllName) + 1) * sizeof(TCHAR)); 445 _stprintf(lptMsgBuffer,FailureMessage,tszDllInstall,lptDllName,hResult); 446 DisplayMessage(bConsole,bSilent,lptMsgBuffer,ModuleTitle,MB_ICONEXCLAMATION); 447 } 448 free(lptMsgBuffer); 449 if (hResult != S_OK) 450 nRetValue = EXITCODE_FAILURE; 451 } 452 else { 453 // DllInstall was not found, display an error message 454 lptMsgBuffer = (LPTSTR)malloc((_tcslen(MissingEntry) - 8 + _tcslen(tszDllInstall) * 2 + _tcslen(lptDllName) * 2 + 1) * sizeof(TCHAR)); 455 _stprintf(lptMsgBuffer,MissingEntry,lptDllName,tszDllInstall,tszDllInstall,lptDllName); 456 DisplayMessage(bConsole,bSilent,lptMsgBuffer,ModuleTitle,MB_ICONEXCLAMATION); 457 free(lptMsgBuffer); 458 nRetValue = EXITCODE_NOENTRY; 459 } 460 } 461 462 // The dll function has finished executing, so unload it 463 FreeLibrary(hDll); 464 } 465 else { 466 // The dll could not be loaded; display an error message 467 dwErr = GetLastError(); 468 SetErrorMode(fuOldErrorMode); 469 lptMsgBuffer = (LPTSTR)malloc((_tcslen(DllNotLoaded) + 2 + _tcslen(lptDllName) + 1) * sizeof(TCHAR)); 470 _stprintf(lptMsgBuffer,DllNotLoaded,lptDllName,dwErr); 471 DisplayMessage(bConsole,bSilent,lptMsgBuffer,ModuleTitle,MB_ICONEXCLAMATION); 472 free(lptMsgBuffer); 473 nRetValue = EXITCODE_LOADERROR; 474 } 475 } 476 } 477 478 if (lpwDllCmdLine) 479 FreeConvertedWideChar(lpwDllCmdLine); 480 GlobalFree(argv); 481 OleUninitialize(); 482 return nRetValue; 483 } 484