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 // Both UNICODE and _UNICODE must be either defined or undefined
13 // because some headers use UNICODE and others use _UNICODE
24 #define WIN32_NO_STATUS
26 #define COM_NO_WINDOWS_H
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
57 LPCTSTR ModuleTitle
= _T("RegSvr32");
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
];
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.
75 #define CommandLineToArgv CommandLineToArgvW
78 #define CommandLineToArgv CommandLineToArgvT
80 LPTSTR
*WINAPI
CommandLineToArgvT(LPCTSTR lpCmdLine
, int *lpArgc
)
83 LPTSTR
*argv
, lpSrc
, lpDest
, lpArg
;
87 // If null was passed in for lpCmdLine, there are no arguments
94 lpSrc
= (LPTSTR
)lpCmdLine
;
95 // Skip spaces at beginning
96 while (*lpSrc
== _T(' ') || *lpSrc
== _T('\t'))
99 // If command-line starts with null, there are no arguments
111 // Count the number of arguments
113 if (*lpSrc
== 0 || ((*lpSrc
== _T(' ') || *lpSrc
== _T('\t')) && !bInQuotes
)) {
114 // Whitespace not enclosed in quotes signals the start of another argument
117 // Skip whitespace between arguments
118 while (*lpSrc
== _T(' ') || *lpSrc
== _T('\t'))
125 else if (*lpSrc
== _T('\\')) {
126 // Count consecutive backslashes
129 else if (*lpSrc
== _T('\"') && !(nBSlash
& 1)) {
130 // Open or close quotes
131 bInQuotes
= !bInQuotes
;
135 // Some other character
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
);
146 // Memory allocation failed
153 lpDest
= lpArg
= (LPTSTR
)(argv
+ argc
);
158 // Fill the argument array
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
164 argv
[argc
++] = lpArg
;
166 // Skip whitespace between arguments
167 while (*lpSrc
== _T(' ') || *lpSrc
== _T('\t'))
175 else if (*lpSrc
== _T('\\')) {
176 *lpDest
++ = _T('\\');
179 // Count consecutive backslashes
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
;
190 // If an odd number of backslashes are before the quotes,
192 lpDest
-= (nBSlash
+ 1) / 2;
193 *lpDest
++ = _T('\"');
199 // Copy other characters
200 *lpDest
++ = *lpSrc
++;
212 // The macro ConvertToWideChar takes a tstring parameter and returns
213 // a pointer to a unicode string. A conversion is performed if
214 // neccessary. 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.
219 #define ConvertToWideChar(lptString) (lptString)
220 #define FreeConvertedWideChar(lpwString) ((void) 0)
223 LPWSTR
ConvertToWideChar(LPCSTR lpString
)
228 nStrLen
= strlen(lpString
) + 1;
230 lpwString
= (LPWSTR
)malloc(nStrLen
* sizeof(WCHAR
));
231 MultiByteToWideChar(0,0,lpString
,nStrLen
,lpwString
,nStrLen
);
236 #define FreeConvertedWideChar(lpwString) free(lpwString)
239 void DisplayMessage(BOOL bConsole
, BOOL bSilent
, LPCTSTR lpMessage
, LPCTSTR lpTitle
, UINT uType
)
242 MessageBox(0,lpMessage
,lpTitle
,uType
);
244 _tprintf(_T("%s: %s\n\n"),lpTitle
,lpMessage
);
247 int WINAPI
_tWinMain(
249 HINSTANCE hPrevInstance
,
256 LPTSTR lptDllName
,lptDllCmdLine
,lptMsgBuffer
;
259 LPWSTR lpwDllCmdLine
;
260 BOOL bUnregister
,bSilent
,bConsole
,bInstall
,bNoRegister
;
263 DLLREGISTER fnDllRegister
;
264 DLLINSTALL fnDllInstall
;
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
);
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
);
280 // Get command-line in argc-argv format
281 argv
= CommandLineToArgv(GetCommandLine(),&argc
);
283 // Initialize variables
293 // Find all arguments starting with a slash (/)
294 for (i
= 1; i
< argc
; i
++) {
295 if (*argv
[i
] == _T('/')) {
296 switch (argv
[i
][1]) {
312 lptDllCmdLine
= argv
[i
];
313 while (*lptDllCmdLine
!= 0 && *lptDllCmdLine
!= _T(':'))
315 if (*lptDllCmdLine
== _T(':'))
324 lptFuncName
= argv
[i
];
332 // An unrecognized flag was used, display a message and show available options
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
);
341 return EXITCODE_PARAMERROR
;
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
);
351 return EXITCODE_PARAMERROR
;
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
);
361 return EXITCODE_PARAMERROR
;
364 nRetValue
= EXITCODE_SUCCESS
;
366 lpFuncName
= szDllRegister
;
367 lptFuncName
= tszDllRegister
;
370 lpFuncName
= szDllUnregister
;
371 lptFuncName
= tszDllUnregister
;
375 lpwDllCmdLine
= ConvertToWideChar(lptDllCmdLine
);
379 // Initialize OLE32 before attempting to register the
380 // dll. Some dll's require this to register properly
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
];
389 // Everything is all setup, so load the dll now
390 hDll
= LoadLibraryEx(lptDllName
,0,LOAD_WITH_ALTERED_SEARCH_PATH
);
393 // Get the address of DllRegisterServer or DllUnregisterServer
394 fnDllRegister
= (DLLREGISTER
)GetProcAddress(hDll
,lpFuncName
);
396 // If the function exists, call it
397 hResult
= fnDllRegister();
398 if (hResult
== S_OK
) {
399 // (Un)register succeeded, display a message
400 lptMsgBuffer
= (LPTSTR
)malloc((_tcslen(SuccessMessage
) - 4 + _tcslen(lptFuncName
) + _tcslen(lptDllName
) + 1) * sizeof(TCHAR
));
401 _stprintf(lptMsgBuffer
,SuccessMessage
,lptFuncName
,lptDllName
);
402 DisplayMessage(bConsole
,bSilent
,lptMsgBuffer
,ModuleTitle
,MB_ICONINFORMATION
);
405 // (Un)register failed, display a message
406 lptMsgBuffer
= (LPTSTR
)malloc((_tcslen(FailureMessage
) + _tcslen(lptFuncName
) + _tcslen(lptDllName
) + 1) * sizeof(TCHAR
));
407 _stprintf(lptMsgBuffer
,FailureMessage
,lptFuncName
,lptDllName
,hResult
);
408 DisplayMessage(bConsole
,bSilent
,lptMsgBuffer
,ModuleTitle
,MB_ICONEXCLAMATION
);
412 nRetValue
= EXITCODE_FAILURE
;
416 // Dll(Un)register was not found, display an error message
417 lptMsgBuffer
= (LPTSTR
)malloc((_tcslen(MissingEntry
) - 8 + _tcslen(lptFuncName
) * 2 + _tcslen(lptDllName
) * 2 + 1) * sizeof(TCHAR
));
418 _stprintf(lptMsgBuffer
,MissingEntry
,lptDllName
,lptFuncName
,lptFuncName
,lptDllName
);
419 DisplayMessage(bConsole
,bSilent
,lptMsgBuffer
,ModuleTitle
,MB_ICONEXCLAMATION
);
421 nRetValue
= EXITCODE_NOENTRY
;
425 if (bInstall
&& nRetValue
== EXITCODE_SUCCESS
) {
426 // Get the address of DllInstall
427 fnDllInstall
= (DLLINSTALL
)GetProcAddress(hDll
,szDllInstall
);
429 // If the function exists, call it
431 hResult
= fnDllInstall(1,lpwDllCmdLine
);
433 hResult
= fnDllInstall(0,lpwDllCmdLine
);
434 if (hResult
== S_OK
) {
435 // (Un)install succeeded, display a message
436 lptMsgBuffer
= (LPTSTR
)malloc((_tcslen(SuccessMessage
) - 4 + _tcslen(tszDllInstall
) + _tcslen(lptDllName
) + 1) * sizeof(TCHAR
));
437 _stprintf(lptMsgBuffer
,SuccessMessage
,tszDllInstall
,lptDllName
);
438 DisplayMessage(bConsole
,bSilent
,lptMsgBuffer
,ModuleTitle
,MB_ICONINFORMATION
);
441 // (Un)install failed, display a message
442 lptMsgBuffer
= (LPTSTR
)malloc((_tcslen(FailureMessage
) + _tcslen(tszDllInstall
) + _tcslen(lptDllName
) + 1) * sizeof(TCHAR
));
443 _stprintf(lptMsgBuffer
,FailureMessage
,tszDllInstall
,lptDllName
,hResult
);
444 DisplayMessage(bConsole
,bSilent
,lptMsgBuffer
,ModuleTitle
,MB_ICONEXCLAMATION
);
448 nRetValue
= EXITCODE_FAILURE
;
452 // DllInstall was not found, display an error message
453 lptMsgBuffer
= (LPTSTR
)malloc((_tcslen(MissingEntry
) - 8 + _tcslen(tszDllInstall
) * 2 + _tcslen(lptDllName
) * 2 + 1) * sizeof(TCHAR
));
454 _stprintf(lptMsgBuffer
,MissingEntry
,lptDllName
,tszDllInstall
,tszDllInstall
,lptDllName
);
455 DisplayMessage(bConsole
,bSilent
,lptMsgBuffer
,ModuleTitle
,MB_ICONEXCLAMATION
);
457 nRetValue
= EXITCODE_NOENTRY
;
461 // The dll function has finished executing, so unload it
465 // The dll could not be loaded; display an error message
466 dwErr
= GetLastError();
467 lptMsgBuffer
= (LPTSTR
)malloc((_tcslen(DllNotLoaded
) + 2 + _tcslen(lptDllName
) + 1) * sizeof(TCHAR
));
468 _stprintf(lptMsgBuffer
,DllNotLoaded
,lptDllName
,dwErr
);
469 DisplayMessage(bConsole
,bSilent
,lptMsgBuffer
,ModuleTitle
,MB_ICONEXCLAMATION
);
471 nRetValue
= EXITCODE_LOADERROR
;
477 FreeConvertedWideChar(lpwDllCmdLine
);