3 * Copyright (C) 2004-2006 ReactOS Team
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)
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
59 LPCTSTR ModuleTitle
= _T("RegSvr32");
61 TCHAR UsageMessage
[RC_STRING_MAX_SIZE
];
62 TCHAR NoDllSpecified
[RC_STRING_MAX_SIZE
];
63 TCHAR InvalidFlag
[RC_STRING_MAX_SIZE
];
64 TCHAR SwitchN_NoI
[RC_STRING_MAX_SIZE
];
65 TCHAR DllNotLoaded
[RC_STRING_MAX_SIZE
];
66 TCHAR MissingEntry
[RC_STRING_MAX_SIZE
];
67 TCHAR FailureMessage
[RC_STRING_MAX_SIZE
];
68 TCHAR SuccessMessage
[RC_STRING_MAX_SIZE
];
71 // The macro CommandLineToArgv maps to a function that converts
72 // a command-line string to argc and argv similar to the ones
73 // in the standard main function. If this code is compiled for
74 // unicode, the build-in Windows API function is used, otherwise
75 // a non-unicode non-API version is used for compatibility with
76 // Windows versions that have no unicode support.
78 #define CommandLineToArgv CommandLineToArgvW
81 #define CommandLineToArgv CommandLineToArgvT
83 LPTSTR
*WINAPI
CommandLineToArgvT(LPCTSTR lpCmdLine
, int *lpArgc
)
86 LPTSTR
*argv
, lpSrc
, lpDest
, lpArg
;
90 // If null was passed in for lpCmdLine, there are no arguments
97 lpSrc
= (LPTSTR
)lpCmdLine
;
98 // Skip spaces at beginning
99 while (*lpSrc
== _T(' ') || *lpSrc
== _T('\t'))
102 // If command-line starts with null, there are no arguments
114 // Count the number of arguments
116 if (*lpSrc
== 0 || ((*lpSrc
== _T(' ') || *lpSrc
== _T('\t')) && !bInQuotes
)) {
117 // Whitespace not enclosed in quotes signals the start of another argument
120 // Skip whitespace between arguments
121 while (*lpSrc
== _T(' ') || *lpSrc
== _T('\t'))
128 else if (*lpSrc
== _T('\\')) {
129 // Count consecutive backslashes
132 else if (*lpSrc
== _T('\"') && !(nBSlash
& 1)) {
133 // Open or close quotes
134 bInQuotes
= !bInQuotes
;
138 // Some other character
144 // Allocate space the same way as CommandLineToArgvW for compatibility
145 hargv
= GlobalAlloc(0, argc
* sizeof(LPTSTR
) + (_tcslen(lpArg
) + 1) * sizeof(TCHAR
));
146 argv
= (LPTSTR
*)GlobalLock(hargv
);
149 // Memory allocation failed
156 lpDest
= lpArg
= (LPTSTR
)(argv
+ argc
);
161 // Fill the argument array
163 if (*lpSrc
== 0 || ((*lpSrc
== _T(' ') || *lpSrc
== _T('\t')) && !bInQuotes
)) {
164 // Whitespace not enclosed in quotes signals the start of another argument
165 // Null-terminate argument
167 argv
[argc
++] = lpArg
;
169 // Skip whitespace between arguments
170 while (*lpSrc
== _T(' ') || *lpSrc
== _T('\t'))
178 else if (*lpSrc
== _T('\\')) {
179 *lpDest
++ = _T('\\');
182 // Count consecutive backslashes
185 else if (*lpSrc
== _T('\"')) {
186 if (!(nBSlash
& 1)) {
187 // If an even number of backslashes are before the quotes,
188 // the quotes don't go in the output
189 lpDest
-= nBSlash
/ 2;
190 bInQuotes
= !bInQuotes
;
193 // If an odd number of backslashes are before the quotes,
195 lpDest
-= (nBSlash
+ 1) / 2;
196 *lpDest
++ = _T('\"');
202 // Copy other characters
203 *lpDest
++ = *lpSrc
++;
215 // The macro ConvertToWideChar takes a tstring parameter and returns
216 // a pointer to a unicode string. A conversion is performed if
217 // neccessary. FreeConvertedWideChar string should be used on the
218 // return value of ConvertToWideChar when the string is no longer
219 // needed. The original string or the string that is returned
220 // should not be modified until FreeConvertedWideChar has been called.
222 #define ConvertToWideChar(lptString) (lptString)
223 #define FreeConvertedWideChar(lpwString) ((void) 0)
226 LPWSTR
ConvertToWideChar(LPCSTR lpString
)
231 nStrLen
= strlen(lpString
) + 1;
233 lpwString
= (LPWSTR
)malloc(nStrLen
* sizeof(WCHAR
));
234 MultiByteToWideChar(0,0,lpString
,nStrLen
,lpwString
,nStrLen
);
239 #define FreeConvertedWideChar(lpwString) free(lpwString)
242 void DisplayMessage(BOOL bConsole
, BOOL bSilent
, LPCTSTR lpMessage
, LPCTSTR lpTitle
, UINT uType
)
245 MessageBox(0,lpMessage
,lpTitle
,uType
);
247 _tprintf(_T("%s: %s\n\n"),lpTitle
,lpMessage
);
250 int WINAPI
_tWinMain(
252 HINSTANCE hPrevInstance
,
259 LPTSTR lptDllName
,lptDllCmdLine
,lptMsgBuffer
;
262 LPWSTR lpwDllCmdLine
;
263 BOOL bUnregister
,bSilent
,bConsole
,bInstall
,bNoRegister
;
266 DLLREGISTER fnDllRegister
;
267 DLLINSTALL fnDllInstall
;
273 LoadString( GetModuleHandle(NULL
), IDS_UsageMessage
, (LPTSTR
) UsageMessage
,RC_STRING_MAX_SIZE
);
274 LoadString( GetModuleHandle(NULL
), IDS_NoDllSpecified
, (LPTSTR
) NoDllSpecified
,RC_STRING_MAX_SIZE
);
275 LoadString( GetModuleHandle(NULL
), IDS_InvalidFlag
, (LPTSTR
) InvalidFlag
,RC_STRING_MAX_SIZE
);
276 LoadString( GetModuleHandle(NULL
), IDS_SwitchN_NoI
, (LPTSTR
) SwitchN_NoI
,RC_STRING_MAX_SIZE
);
278 LoadString( GetModuleHandle(NULL
), IDS_DllNotLoaded
, (LPTSTR
) DllNotLoaded
,RC_STRING_MAX_SIZE
);
279 LoadString( GetModuleHandle(NULL
), IDS_MissingEntry
, (LPTSTR
) MissingEntry
,RC_STRING_MAX_SIZE
);
280 LoadString( GetModuleHandle(NULL
), IDS_FailureMessage
, (LPTSTR
) FailureMessage
,RC_STRING_MAX_SIZE
);
281 LoadString( GetModuleHandle(NULL
), IDS_SuccessMessage
, (LPTSTR
) SuccessMessage
,RC_STRING_MAX_SIZE
);
283 // Get command-line in argc-argv format
284 argv
= CommandLineToArgv(GetCommandLine(),&argc
);
286 // Initialize variables
296 // Find all arguments starting with a slash (/)
297 for (i
= 1; i
< argc
; i
++) {
298 if (*argv
[i
] == _T('/')) {
299 switch (argv
[i
][1]) {
315 lptDllCmdLine
= argv
[i
];
316 while (*lptDllCmdLine
!= 0 && *lptDllCmdLine
!= _T(':'))
318 if (*lptDllCmdLine
== _T(':'))
327 lptFuncName
= argv
[i
];
335 // An unrecognized flag was used, display a message and show available options
338 lptMsgBuffer
= (LPTSTR
)malloc((_tcslen(UsageMessage
) - 2 + _tcslen(InvalidFlag
) - 2 + _tcslen(lptFuncName
) + 1) * sizeof(TCHAR
));
339 _stprintf(lptMsgBuffer
+ (_tcslen(UsageMessage
) - 2),InvalidFlag
,lptFuncName
);
340 _stprintf(lptMsgBuffer
,UsageMessage
,lptMsgBuffer
+ (_tcslen(UsageMessage
) - 2));
341 DisplayMessage(bConsole
,bSilent
,lptMsgBuffer
,ModuleTitle
,MB_ICONEXCLAMATION
);
344 return EXITCODE_PARAMERROR
;
347 // /n was used without /i, display a message and show available options
348 if (bNoRegister
&& (!bInstall
)) {
349 lptMsgBuffer
= (LPTSTR
)malloc((_tcslen(UsageMessage
) - 2 + _tcslen(SwitchN_NoI
) + 1) * sizeof(TCHAR
));
350 _stprintf(lptMsgBuffer
,UsageMessage
,SwitchN_NoI
);
351 DisplayMessage(bConsole
,bSilent
,lptMsgBuffer
,ModuleTitle
,MB_ICONEXCLAMATION
);
354 return EXITCODE_PARAMERROR
;
357 // No dll was specified, display a message and show available options
358 if (nDllCount
== 0) {
359 lptMsgBuffer
= (LPTSTR
)malloc((_tcslen(UsageMessage
) - 2 + _tcslen(NoDllSpecified
) + 1) * sizeof(TCHAR
));
360 _stprintf(lptMsgBuffer
,UsageMessage
,NoDllSpecified
);
361 DisplayMessage(bConsole
,bSilent
,lptMsgBuffer
,ModuleTitle
,MB_ICONEXCLAMATION
);
364 return EXITCODE_PARAMERROR
;
367 nRetValue
= EXITCODE_SUCCESS
;
369 lpFuncName
= szDllRegister
;
370 lptFuncName
= tszDllRegister
;
373 lpFuncName
= szDllUnregister
;
374 lptFuncName
= tszDllUnregister
;
378 lpwDllCmdLine
= ConvertToWideChar(lptDllCmdLine
);
382 // Initialize OLE32 before attempting to register the
383 // dll. Some dll's require this to register properly
386 // (Un)register every dll whose filename was passed in the command-line string
387 for (i
= 1; i
< argc
&& nRetValue
== EXITCODE_SUCCESS
; i
++) {
388 // Arguments that do not start with a slash (/) are filenames
389 if (*argv
[i
] != _T('/')) {
390 lptDllName
= argv
[i
];
392 // Everything is all setup, so load the dll now
393 hDll
= LoadLibraryEx(lptDllName
,0,LOAD_WITH_ALTERED_SEARCH_PATH
);
396 // Get the address of DllRegisterServer or DllUnregisterServer
397 fnDllRegister
= (DLLREGISTER
)GetProcAddress(hDll
,lpFuncName
);
399 // If the function exists, call it
400 hResult
= fnDllRegister();
401 if (hResult
== S_OK
) {
402 // (Un)register succeeded, display a message
403 lptMsgBuffer
= (LPTSTR
)malloc((_tcslen(SuccessMessage
) - 4 + _tcslen(lptFuncName
) + _tcslen(lptDllName
) + 1) * sizeof(TCHAR
));
404 _stprintf(lptMsgBuffer
,SuccessMessage
,lptFuncName
,lptDllName
);
405 DisplayMessage(bConsole
,bSilent
,lptMsgBuffer
,ModuleTitle
,MB_ICONINFORMATION
);
408 // (Un)register failed, display a message
409 lptMsgBuffer
= (LPTSTR
)malloc((_tcslen(FailureMessage
) + _tcslen(lptFuncName
) + _tcslen(lptDllName
) + 1) * sizeof(TCHAR
));
410 _stprintf(lptMsgBuffer
,FailureMessage
,lptFuncName
,lptDllName
,hResult
);
411 DisplayMessage(bConsole
,bSilent
,lptMsgBuffer
,ModuleTitle
,MB_ICONEXCLAMATION
);
415 nRetValue
= EXITCODE_FAILURE
;
419 // Dll(Un)register was not found, display an error message
420 lptMsgBuffer
= (LPTSTR
)malloc((_tcslen(MissingEntry
) - 8 + _tcslen(lptFuncName
) * 2 + _tcslen(lptDllName
) * 2 + 1) * sizeof(TCHAR
));
421 _stprintf(lptMsgBuffer
,MissingEntry
,lptDllName
,lptFuncName
,lptFuncName
,lptDllName
);
422 DisplayMessage(bConsole
,bSilent
,lptMsgBuffer
,ModuleTitle
,MB_ICONEXCLAMATION
);
424 nRetValue
= EXITCODE_NOENTRY
;
428 if (bInstall
&& nRetValue
== EXITCODE_SUCCESS
) {
429 // Get the address of DllInstall
430 fnDllInstall
= (DLLINSTALL
)GetProcAddress(hDll
,szDllInstall
);
432 // If the function exists, call it
434 hResult
= fnDllInstall(1,lpwDllCmdLine
);
436 hResult
= fnDllInstall(0,lpwDllCmdLine
);
437 if (hResult
== S_OK
) {
438 // (Un)install succeeded, display a message
439 lptMsgBuffer
= (LPTSTR
)malloc((_tcslen(SuccessMessage
) - 4 + _tcslen(tszDllInstall
) + _tcslen(lptDllName
) + 1) * sizeof(TCHAR
));
440 _stprintf(lptMsgBuffer
,SuccessMessage
,tszDllInstall
,lptDllName
);
441 DisplayMessage(bConsole
,bSilent
,lptMsgBuffer
,ModuleTitle
,MB_ICONINFORMATION
);
444 // (Un)install failed, display a message
445 lptMsgBuffer
= (LPTSTR
)malloc((_tcslen(FailureMessage
) + _tcslen(tszDllInstall
) + _tcslen(lptDllName
) + 1) * sizeof(TCHAR
));
446 _stprintf(lptMsgBuffer
,FailureMessage
,tszDllInstall
,lptDllName
,hResult
);
447 DisplayMessage(bConsole
,bSilent
,lptMsgBuffer
,ModuleTitle
,MB_ICONEXCLAMATION
);
451 nRetValue
= EXITCODE_FAILURE
;
455 // DllInstall was not found, display an error message
456 lptMsgBuffer
= (LPTSTR
)malloc((_tcslen(MissingEntry
) - 8 + _tcslen(tszDllInstall
) * 2 + _tcslen(lptDllName
) * 2 + 1) * sizeof(TCHAR
));
457 _stprintf(lptMsgBuffer
,MissingEntry
,lptDllName
,tszDllInstall
,tszDllInstall
,lptDllName
);
458 DisplayMessage(bConsole
,bSilent
,lptMsgBuffer
,ModuleTitle
,MB_ICONEXCLAMATION
);
460 nRetValue
= EXITCODE_NOENTRY
;
464 // The dll function has finished executing, so unload it
468 // The dll could not be loaded; display an error message
469 dwErr
= GetLastError();
470 lptMsgBuffer
= (LPTSTR
)malloc((_tcslen(DllNotLoaded
) + 2 + _tcslen(lptDllName
) + 1) * sizeof(TCHAR
));
471 _stprintf(lptMsgBuffer
,DllNotLoaded
,lptDllName
,dwErr
);
472 DisplayMessage(bConsole
,bSilent
,lptMsgBuffer
,ModuleTitle
,MB_ICONEXCLAMATION
);
474 nRetValue
= EXITCODE_LOADERROR
;
480 FreeConvertedWideChar(lpwDllCmdLine
);