[WLAN-BRINGUP]
[reactos.git] / base / system / regsvr32 / regsvr32.c
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 #define WIN32_LEAN_AND_MEAN
13
14 // Both UNICODE and _UNICODE must be either defined or undefined
15 // because some headers use UNICODE and others use _UNICODE
16 #ifdef UNICODE
17 #ifndef _UNICODE
18 #define _UNICODE
19 #endif
20 #else
21 #ifdef _UNICODE
22 #define UNICODE
23 #endif
24 #endif
25
26 #include <windows.h>
27 #include <ole2.h>
28 #include <stdio.h>
29 #include <string.h>
30 #include <malloc.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
56
57 #include "resource.h"
58
59 LPCTSTR ModuleTitle = _T("RegSvr32");
60
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];
69
70
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.
77 #ifdef UNICODE
78 #define CommandLineToArgv CommandLineToArgvW
79 #include <shellapi.h>
80 #else
81 #define CommandLineToArgv CommandLineToArgvT
82
83 LPTSTR *WINAPI CommandLineToArgvT(LPCTSTR lpCmdLine, int *lpArgc)
84 {
85 HGLOBAL hargv;
86 LPTSTR *argv, lpSrc, lpDest, lpArg;
87 int argc, nBSlash;
88 BOOL bInQuotes;
89
90 // If null was passed in for lpCmdLine, there are no arguments
91 if (!lpCmdLine) {
92 if (lpArgc)
93 *lpArgc = 0;
94 return 0;
95 }
96
97 lpSrc = (LPTSTR)lpCmdLine;
98 // Skip spaces at beginning
99 while (*lpSrc == _T(' ') || *lpSrc == _T('\t'))
100 lpSrc++;
101
102 // If command-line starts with null, there are no arguments
103 if (*lpSrc == 0) {
104 if (lpArgc)
105 *lpArgc = 0;
106 return 0;
107 }
108
109 lpArg = lpSrc;
110 argc = 0;
111 nBSlash = 0;
112 bInQuotes = FALSE;
113
114 // Count the number of arguments
115 while (1) {
116 if (*lpSrc == 0 || ((*lpSrc == _T(' ') || *lpSrc == _T('\t')) && !bInQuotes)) {
117 // Whitespace not enclosed in quotes signals the start of another argument
118 argc++;
119
120 // Skip whitespace between arguments
121 while (*lpSrc == _T(' ') || *lpSrc == _T('\t'))
122 lpSrc++;
123 if (*lpSrc == 0)
124 break;
125 nBSlash = 0;
126 continue;
127 }
128 else if (*lpSrc == _T('\\')) {
129 // Count consecutive backslashes
130 nBSlash++;
131 }
132 else if (*lpSrc == _T('\"') && !(nBSlash & 1)) {
133 // Open or close quotes
134 bInQuotes = !bInQuotes;
135 nBSlash = 0;
136 }
137 else {
138 // Some other character
139 nBSlash = 0;
140 }
141 lpSrc++;
142 }
143
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);
147
148 if (!argv) {
149 // Memory allocation failed
150 if (lpArgc)
151 *lpArgc = 0;
152 return 0;
153 }
154
155 lpSrc = lpArg;
156 lpDest = lpArg = (LPTSTR)(argv + argc);
157 argc = 0;
158 nBSlash = 0;
159 bInQuotes = FALSE;
160
161 // Fill the argument array
162 while (1) {
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
166 *lpDest++ = 0;
167 argv[argc++] = lpArg;
168
169 // Skip whitespace between arguments
170 while (*lpSrc == _T(' ') || *lpSrc == _T('\t'))
171 lpSrc++;
172 if (*lpSrc == 0)
173 break;
174 lpArg = lpDest;
175 nBSlash = 0;
176 continue;
177 }
178 else if (*lpSrc == _T('\\')) {
179 *lpDest++ = _T('\\');
180 lpSrc++;
181
182 // Count consecutive backslashes
183 nBSlash++;
184 }
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;
191 }
192 else {
193 // If an odd number of backslashes are before the quotes,
194 // output a quote
195 lpDest -= (nBSlash + 1) / 2;
196 *lpDest++ = _T('\"');
197 }
198 lpSrc++;
199 nBSlash = 0;
200 }
201 else {
202 // Copy other characters
203 *lpDest++ = *lpSrc++;
204 nBSlash = 0;
205 }
206 }
207
208 if (lpArgc)
209 *lpArgc = argc;
210 return argv;
211 }
212
213 #endif
214
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.
221 #ifdef UNICODE
222 #define ConvertToWideChar(lptString) (lptString)
223 #define FreeConvertedWideChar(lpwString) ((void) 0)
224 #else
225
226 LPWSTR ConvertToWideChar(LPCSTR lpString)
227 {
228 LPWSTR lpwString;
229 size_t nStrLen;
230
231 nStrLen = strlen(lpString) + 1;
232
233 lpwString = (LPWSTR)malloc(nStrLen * sizeof(WCHAR));
234 MultiByteToWideChar(0,0,lpString,nStrLen,lpwString,nStrLen);
235
236 return lpwString;
237 }
238
239 #define FreeConvertedWideChar(lpwString) free(lpwString)
240 #endif
241
242 void DisplayMessage(BOOL bConsole, BOOL bSilent, LPCTSTR lpMessage, LPCTSTR lpTitle, UINT uType)
243 {
244 if (!bSilent)
245 MessageBox(0,lpMessage,lpTitle,uType);
246 if (bConsole)
247 _tprintf(_T("%s: %s\n\n"),lpTitle,lpMessage);
248 }
249
250 int WINAPI _tWinMain(
251 HINSTANCE hInstance,
252 HINSTANCE hPrevInstance,
253 LPTSTR lpCmdLine,
254 int nCmdShow
255 )
256 {
257 int argc;
258 LPTSTR *argv;
259 LPTSTR lptDllName,lptDllCmdLine,lptMsgBuffer;
260 LPCTSTR lptFuncName;
261 LPCSTR lpFuncName;
262 LPWSTR lpwDllCmdLine;
263 BOOL bUnregister,bSilent,bConsole,bInstall,bNoRegister;
264 UINT nDllCount;
265 HMODULE hDll;
266 DLLREGISTER fnDllRegister;
267 DLLINSTALL fnDllInstall;
268 HRESULT hResult;
269 DWORD dwErr;
270 int nRetValue,i;
271
272 // Get Langues msg
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);
277
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);
282
283 // Get command-line in argc-argv format
284 argv = CommandLineToArgv(GetCommandLine(),&argc);
285
286 // Initialize variables
287 lptFuncName = 0;
288 lptDllCmdLine = 0;
289 nDllCount = 0;
290 bUnregister = FALSE;
291 bSilent = FALSE;
292 bConsole = FALSE;
293 bInstall = FALSE;
294 bNoRegister = FALSE;
295
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]) {
300 case _T('u'):
301 case _T('U'):
302 bUnregister = TRUE;
303 break;
304 case _T('s'):
305 case _T('S'):
306 bSilent = TRUE;
307 break;
308 case _T('c'):
309 case _T('C'):
310 bConsole = TRUE;
311 break;
312 case _T('i'):
313 case _T('I'):
314 bInstall = TRUE;
315 lptDllCmdLine = argv[i];
316 while (*lptDllCmdLine != 0 && *lptDllCmdLine != _T(':'))
317 lptDllCmdLine++;
318 if (*lptDllCmdLine == _T(':'))
319 lptDllCmdLine++;
320 break;
321 case _T('n'):
322 case _T('N'):
323 bNoRegister = TRUE;
324 break;
325 default:
326 if (!lptFuncName)
327 lptFuncName = argv[i];
328 }
329 }
330 else {
331 nDllCount++;
332 }
333 }
334
335 // An unrecognized flag was used, display a message and show available options
336
337 if (lptFuncName) {
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);
342 free(lptMsgBuffer);
343 GlobalFree(argv);
344 return EXITCODE_PARAMERROR;
345 }
346
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);
352 free(lptMsgBuffer);
353 GlobalFree(argv);
354 return EXITCODE_PARAMERROR;
355 }
356
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);
362 free(lptMsgBuffer);
363 GlobalFree(argv);
364 return EXITCODE_PARAMERROR;
365 }
366
367 nRetValue = EXITCODE_SUCCESS;
368 if (!bUnregister) {
369 lpFuncName = szDllRegister;
370 lptFuncName = tszDllRegister;
371 }
372 else {
373 lpFuncName = szDllUnregister;
374 lptFuncName = tszDllUnregister;
375 }
376
377 if (lptDllCmdLine)
378 lpwDllCmdLine = ConvertToWideChar(lptDllCmdLine);
379 else
380 lpwDllCmdLine = 0;
381
382 // Initialize OLE32 before attempting to register the
383 // dll. Some dll's require this to register properly
384 OleInitialize(0);
385
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];
391
392 // Everything is all setup, so load the dll now
393 hDll = LoadLibraryEx(lptDllName,0,LOAD_WITH_ALTERED_SEARCH_PATH);
394 if (hDll) {
395 if (!bNoRegister) {
396 // Get the address of DllRegisterServer or DllUnregisterServer
397 fnDllRegister = (DLLREGISTER)GetProcAddress(hDll,lpFuncName);
398 if (fnDllRegister) {
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);
406 }
407 else {
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);
412 }
413 free(lptMsgBuffer);
414 if (hResult != S_OK)
415 nRetValue = EXITCODE_FAILURE;
416 }
417 else {
418 FreeLibrary(hDll);
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);
423 free(lptMsgBuffer);
424 nRetValue = EXITCODE_NOENTRY;
425 }
426 }
427
428 if (bInstall && nRetValue == EXITCODE_SUCCESS) {
429 // Get the address of DllInstall
430 fnDllInstall = (DLLINSTALL)GetProcAddress(hDll,szDllInstall);
431 if (fnDllInstall) {
432 // If the function exists, call it
433 if (!bUnregister)
434 hResult = fnDllInstall(1,lpwDllCmdLine);
435 else
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);
442 }
443 else {
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);
448 }
449 free(lptMsgBuffer);
450 if (hResult != S_OK)
451 nRetValue = EXITCODE_FAILURE;
452 }
453 else {
454 FreeLibrary(hDll);
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);
459 free(lptMsgBuffer);
460 nRetValue = EXITCODE_NOENTRY;
461 }
462 }
463
464 // The dll function has finished executing, so unload it
465 FreeLibrary(hDll);
466 }
467 else {
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);
473 free(lptMsgBuffer);
474 nRetValue = EXITCODE_LOADERROR;
475 }
476 }
477 }
478
479 if (lpwDllCmdLine)
480 FreeConvertedWideChar(lpwDllCmdLine);
481 GlobalFree(argv);
482 OleUninitialize();
483 return nRetValue;
484 }
485