3 * Copyright (C) 2004 ReactOS Team
5 * COPYRIGHT: See COPYING in the top level directory
6 * PROJECT: ReactOS regsvr32.exe
7 * FILE: apps/utils/regsvr32/regsvr32.c
8 * PURPOSE: Register a COM component in the registry
9 * PROGRAMMER: ShadowFlare (blakflare@hotmail.com)
12 #define WIN32_LEAN_AND_MEAN
14 // Both UNICODE and _UNICODE must be either defined or undefined
15 // because some headers use UNICODE and others use _UNICODE
33 typedef HRESULT (WINAPI
*DLLREGISTER
)(void);
34 typedef HRESULT (WINAPI
*DLLINSTALL
)(BOOL bInstall
, LPWSTR lpwCmdLine
);
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
42 LPCSTR szDllRegister
= "DllRegisterServer";
43 LPCSTR szDllUnregister
= "DllUnregisterServer";
44 LPCSTR szDllInstall
= "DllInstall";
46 LPCWSTR tszDllRegister
= L
"DllRegisterServer";
47 LPCWSTR tszDllUnregister
= L
"DllUnregisterServer";
48 LPCWSTR tszDllInstall
= L
"DllInstall";
50 #define tszDllRegister szDllRegister
51 #define tszDllUnregister szDllUnregister
52 #define tszDllInstall szDllInstall
55 LPCTSTR ModuleTitle
= _T("RegSvr32");
56 LPCTSTR UsageMessage
=
58 _T("Usage: regsvr32 [/u] [/s] [/c] [/n] [/i[:cmdline]] dllname\n")
59 _T("/u - Unregister server\n")
60 _T("/s - Silent; display no message boxes\n")
61 _T("/c - Console output\n")
62 _T("/i - Call DllInstall passing it an optional [cmdline]; when used with /u calls dll uninstall\n")
63 _T("/n - Do not call DllRegisterServer; this option must be used with /i");
64 LPCTSTR NoDllSpecified
= _T("No DLL name specified.");
65 LPCTSTR InvalidFlag
= _T("Unrecognized flag: %s");
66 LPCTSTR SwitchN_NoI
= _T("Unrecognized flag: /n must be used with the /i switch");
67 LPCTSTR DllNotLoaded
=
68 _T("LoadLibrary(\"%s\") failed.\n")
69 _T("GetLastError returns 0x%08x.");
70 LPCTSTR MissingEntry
=
71 _T("%s was loaded, but the %s entry point was not found.\n\n")
72 _T("%s may not be exported, or a corrupt version of %s may be in memory. Consider using PView to detect and remove it.");
73 LPCTSTR FailureMessage
=
74 _T("%s in %s failed.\n")
75 _T("Return code was: 0x%08x");
76 LPCTSTR SuccessMessage
= _T("%s in %s succeeded.");
78 // The macro CommandLineToArgv maps to a function that converts
79 // a command-line string to argc and argv similar to the ones
80 // in the standard main function. If this code is compiled for
81 // unicode, the build-in Windows API function is used, otherwise
82 // a non-unicode non-API version is used for compatibility with
83 // Windows versions that have no unicode support.
85 #define CommandLineToArgv CommandLineToArgvW
88 #define CommandLineToArgv CommandLineToArgvT
90 LPTSTR
*WINAPI
CommandLineToArgvT(LPCTSTR lpCmdLine
, int *lpArgc
)
93 LPTSTR
*argv
, lpSrc
, lpDest
, lpArg
;
97 // If null was passed in for lpCmdLine, there are no arguments
104 lpSrc
= (LPTSTR
)lpCmdLine
;
105 // Skip spaces at beginning
106 while (*lpSrc
== _T(' ') || *lpSrc
== _T('\t'))
109 // If command-line starts with null, there are no arguments
121 // Count the number of arguments
123 if (*lpSrc
== 0 || ((*lpSrc
== _T(' ') || *lpSrc
== _T('\t')) && !bInQuotes
)) {
124 // Whitespace not enclosed in quotes signals the start of another argument
127 // Skip whitespace between arguments
128 while (*lpSrc
== _T(' ') || *lpSrc
== _T('\t'))
135 else if (*lpSrc
== _T('\\')) {
136 // Count consecutive backslashes
139 else if (*lpSrc
== _T('\"') && !(nBSlash
& 1)) {
140 // Open or close quotes
141 bInQuotes
= !bInQuotes
;
145 // Some other character
151 // Allocate space the same way as CommandLineToArgvW for compatibility
152 hargv
= GlobalAlloc(0, argc
* sizeof(LPTSTR
) + (_tcslen(lpArg
) + 1) * sizeof(TCHAR
));
153 argv
= (LPTSTR
*)GlobalLock(hargv
);
156 // Memory allocation failed
163 lpDest
= lpArg
= (LPTSTR
)(argv
+ argc
);
168 // Fill the argument array
170 if (*lpSrc
== 0 || ((*lpSrc
== _T(' ') || *lpSrc
== _T('\t')) && !bInQuotes
)) {
171 // Whitespace not enclosed in quotes signals the start of another argument
172 // Null-terminate argument
174 argv
[argc
++] = lpArg
;
176 // Skip whitespace between arguments
177 while (*lpSrc
== _T(' ') || *lpSrc
== _T('\t'))
185 else if (*lpSrc
== _T('\\')) {
186 *lpDest
++ = _T('\\');
189 // Count consecutive backslashes
192 else if (*lpSrc
== _T('\"')) {
193 if (!(nBSlash
& 1)) {
194 // If an even number of backslashes are before the quotes,
195 // the quotes don't go in the output
196 lpDest
-= nBSlash
/ 2;
197 bInQuotes
= !bInQuotes
;
200 // If an odd number of backslashes are before the quotes,
202 lpDest
-= (nBSlash
+ 1) / 2;
203 *lpDest
++ = _T('\"');
209 // Copy other characters
210 *lpDest
++ = *lpSrc
++;
222 // The macro ConvertToWideChar takes a tstring parameter and returns
223 // a pointer to a unicode string. A conversion is performed if
224 // neccessary. FreeConvertedWideChar string should be used on the
225 // return value of ConvertToWideChar when the string is no longer
226 // needed. The original string or the string that is returned
227 // should not be modified until FreeConvertedWideChar has been called.
229 #define ConvertToWideChar(lptString) (lptString)
230 #define FreeConvertedWideChar(lpwString)
233 LPWSTR
ConvertToWideChar(LPCSTR lpString
)
238 nStrLen
= strlen(lpString
) + 1;
240 lpwString
= (LPWSTR
)malloc(nStrLen
* sizeof(WCHAR
));
241 MultiByteToWideChar(0,0,lpString
,nStrLen
,lpwString
,nStrLen
);
246 #define FreeConvertedWideChar(lpwString) free(lpwString)
249 void DisplayMessage(BOOL bConsole
, BOOL bSilent
, LPCTSTR lpMessage
, LPCTSTR lpTitle
, UINT uType
)
252 MessageBox(0,lpMessage
,lpTitle
,uType
);
254 _tprintf(_T("%s: %s\n\n"),lpTitle
,lpMessage
);
259 HINSTANCE hPrevInstance
,
266 LPTSTR lptDllName
,lptDllCmdLine
,lptMsgBuffer
;
269 LPWSTR lpwDllCmdLine
;
270 BOOL bUnregister
,bSilent
,bConsole
,bInstall
,bNoRegister
;
273 DLLREGISTER fnDllRegister
;
274 DLLINSTALL fnDllInstall
;
279 // Get command-line in argc-argv format
280 argv
= CommandLineToArgv(GetCommandLine(),&argc
);
282 // Initialize variables
292 // Find all arguments starting with a slash (/)
293 for (i
= 1; i
< argc
; i
++) {
294 if (*argv
[i
] == _T('/')) {
295 switch (argv
[i
][1]) {
311 lptDllCmdLine
= argv
[i
];
312 while (*lptDllCmdLine
!= 0 && *lptDllCmdLine
!= _T(':'))
314 if (*lptDllCmdLine
== _T(':'))
323 lptFuncName
= argv
[i
];
331 // An unrecognized flag was used, display a message and show available options
333 lptMsgBuffer
= (LPTSTR
)malloc((_tcslen(UsageMessage
) - 2 + _tcslen(InvalidFlag
) - 2 + _tcslen(lptFuncName
) + 1) * sizeof(TCHAR
));
334 _stprintf(lptMsgBuffer
+ (_tcslen(UsageMessage
) - 2),InvalidFlag
,lptFuncName
);
335 _stprintf(lptMsgBuffer
,UsageMessage
,lptMsgBuffer
+ (_tcslen(UsageMessage
) - 2));
336 DisplayMessage(bConsole
,bSilent
,lptMsgBuffer
,ModuleTitle
,MB_ICONEXCLAMATION
);
339 return EXITCODE_PARAMERROR
;
342 // /n was used without /i, display a message and show available options
343 if (bNoRegister
&& (!bInstall
)) {
344 lptMsgBuffer
= (LPTSTR
)malloc((_tcslen(UsageMessage
) - 2 + _tcslen(SwitchN_NoI
) + 1) * sizeof(TCHAR
));
345 _stprintf(lptMsgBuffer
,UsageMessage
,SwitchN_NoI
);
346 DisplayMessage(bConsole
,bSilent
,lptMsgBuffer
,ModuleTitle
,MB_ICONEXCLAMATION
);
349 return EXITCODE_PARAMERROR
;
352 // No dll was specified, display a message and show available options
353 if (nDllCount
== 0) {
354 lptMsgBuffer
= (LPTSTR
)malloc((_tcslen(UsageMessage
) - 2 + _tcslen(NoDllSpecified
) + 1) * sizeof(TCHAR
));
355 _stprintf(lptMsgBuffer
,UsageMessage
,NoDllSpecified
);
356 DisplayMessage(bConsole
,bSilent
,lptMsgBuffer
,ModuleTitle
,MB_ICONEXCLAMATION
);
359 return EXITCODE_PARAMERROR
;
362 nRetValue
= EXITCODE_SUCCESS
;
364 lpFuncName
= szDllRegister
;
365 lptFuncName
= tszDllRegister
;
368 lpFuncName
= szDllUnregister
;
369 lptFuncName
= tszDllUnregister
;
373 lpwDllCmdLine
= ConvertToWideChar(lptDllCmdLine
);
377 // Initialize OLE32 before attempting to register the
378 // dll. Some dll's require this to register properly
381 // (Un)register every dll whose filename was passed in the command-line string
382 for (i
= 1; i
< argc
; i
++) {
383 // Arguments that do not start with a slash (/) are filenames
384 if (*argv
[i
] != _T('/')) {
385 lptDllName
= argv
[i
];
387 // Everything is all setup, so load the dll now
388 hDll
= LoadLibraryEx(lptDllName
,0,LOAD_WITH_ALTERED_SEARCH_PATH
);
391 // Get the address of DllRegisterServer or DllUnregisterServer
392 fnDllRegister
= (DLLREGISTER
)GetProcAddress(hDll
,lpFuncName
);
394 // If the function exists, call it
395 hResult
= fnDllRegister();
396 if (hResult
== S_OK
) {
397 // (Un)register succeeded, display a message
398 lptMsgBuffer
= (LPTSTR
)malloc((_tcslen(SuccessMessage
) - 4 + _tcslen(lptFuncName
) + _tcslen(lptDllName
) + 1) * sizeof(TCHAR
));
399 _stprintf(lptMsgBuffer
,SuccessMessage
,lptFuncName
,lptDllName
);
400 DisplayMessage(bConsole
,bSilent
,lptMsgBuffer
,ModuleTitle
,MB_ICONINFORMATION
);
403 // (Un)register failed, display a message
404 lptMsgBuffer
= (LPTSTR
)malloc((_tcslen(FailureMessage
) + _tcslen(lptFuncName
) + _tcslen(lptDllName
) + 1) * sizeof(TCHAR
));
405 _stprintf(lptMsgBuffer
,FailureMessage
,lptFuncName
,lptDllName
,hResult
);
406 DisplayMessage(bConsole
,bSilent
,lptMsgBuffer
,ModuleTitle
,MB_ICONEXCLAMATION
);
410 nRetValue
= EXITCODE_FAILURE
;
414 // Dll(Un)register was not found, display an error message
415 lptMsgBuffer
= (LPTSTR
)malloc((_tcslen(MissingEntry
) - 8 + _tcslen(lptFuncName
) * 2 + _tcslen(lptDllName
) * 2 + 1) * sizeof(TCHAR
));
416 _stprintf(lptMsgBuffer
,MissingEntry
,lptDllName
,lptFuncName
,lptFuncName
,lptDllName
);
417 DisplayMessage(bConsole
,bSilent
,lptMsgBuffer
,ModuleTitle
,MB_ICONEXCLAMATION
);
419 nRetValue
= EXITCODE_NOENTRY
;
424 // Get the address of DllInstall
425 fnDllInstall
= (DLLINSTALL
)GetProcAddress(hDll
,szDllInstall
);
427 // If the function exists, call it
429 hResult
= fnDllInstall(1,lpwDllCmdLine
);
431 hResult
= fnDllInstall(0,lpwDllCmdLine
);
432 if (hResult
== S_OK
) {
433 // (Un)install succeeded, display a message
434 lptMsgBuffer
= (LPTSTR
)malloc((_tcslen(SuccessMessage
) - 4 + _tcslen(tszDllInstall
) + _tcslen(lptDllName
) + 1) * sizeof(TCHAR
));
435 _stprintf(lptMsgBuffer
,SuccessMessage
,tszDllInstall
,lptDllName
);
436 DisplayMessage(bConsole
,bSilent
,lptMsgBuffer
,ModuleTitle
,MB_ICONINFORMATION
);
439 // (Un)install failed, display a message
440 lptMsgBuffer
= (LPTSTR
)malloc((_tcslen(FailureMessage
) + _tcslen(tszDllInstall
) + _tcslen(lptDllName
) + 1) * sizeof(TCHAR
));
441 _stprintf(lptMsgBuffer
,FailureMessage
,tszDllInstall
,lptDllName
,hResult
);
442 DisplayMessage(bConsole
,bSilent
,lptMsgBuffer
,ModuleTitle
,MB_ICONEXCLAMATION
);
446 nRetValue
= EXITCODE_FAILURE
;
450 // DllInstall was not found, display an error message
451 lptMsgBuffer
= (LPTSTR
)malloc((_tcslen(MissingEntry
) - 8 + _tcslen(tszDllInstall
) * 2 + _tcslen(lptDllName
) * 2 + 1) * sizeof(TCHAR
));
452 _stprintf(lptMsgBuffer
,MissingEntry
,lptDllName
,tszDllInstall
,tszDllInstall
,lptDllName
);
453 DisplayMessage(bConsole
,bSilent
,lptMsgBuffer
,ModuleTitle
,MB_ICONEXCLAMATION
);
455 nRetValue
= EXITCODE_NOENTRY
;
459 // The dll function has finished executing, so unload it
463 // The dll could not be loaded; display an error message
464 dwErr
= GetLastError();
465 lptMsgBuffer
= (LPTSTR
)malloc((_tcslen(DllNotLoaded
) + 2 + _tcslen(lptDllName
) + 1) * sizeof(TCHAR
));
466 _stprintf(lptMsgBuffer
,DllNotLoaded
,lptDllName
,dwErr
);
467 DisplayMessage(bConsole
,bSilent
,lptMsgBuffer
,ModuleTitle
,MB_ICONEXCLAMATION
);
469 nRetValue
= EXITCODE_LOADERROR
;
475 FreeConvertedWideChar(lpwDllCmdLine
);