[SHELL-EXPERIMENTS]
[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 // 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 // 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.
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;
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('/')) {
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 // Everything is all setup, so load the dll now
390 hDll = LoadLibraryEx(lptDllName,0,LOAD_WITH_ALTERED_SEARCH_PATH);
391 if (hDll) {
392 if (!bNoRegister) {
393 // Get the address of DllRegisterServer or DllUnregisterServer
394 fnDllRegister = (DLLREGISTER)GetProcAddress(hDll,lpFuncName);
395 if (fnDllRegister) {
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);
403 }
404 else {
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);
409 }
410 free(lptMsgBuffer);
411 if (hResult != S_OK)
412 nRetValue = EXITCODE_FAILURE;
413 }
414 else {
415 FreeLibrary(hDll);
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);
420 free(lptMsgBuffer);
421 nRetValue = EXITCODE_NOENTRY;
422 }
423 }
424
425 if (bInstall && nRetValue == EXITCODE_SUCCESS) {
426 // Get the address of DllInstall
427 fnDllInstall = (DLLINSTALL)GetProcAddress(hDll,szDllInstall);
428 if (fnDllInstall) {
429 // If the function exists, call it
430 if (!bUnregister)
431 hResult = fnDllInstall(1,lpwDllCmdLine);
432 else
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);
439 }
440 else {
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);
445 }
446 free(lptMsgBuffer);
447 if (hResult != S_OK)
448 nRetValue = EXITCODE_FAILURE;
449 }
450 else {
451 FreeLibrary(hDll);
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);
456 free(lptMsgBuffer);
457 nRetValue = EXITCODE_NOENTRY;
458 }
459 }
460
461 // The dll function has finished executing, so unload it
462 FreeLibrary(hDll);
463 }
464 else {
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);
470 free(lptMsgBuffer);
471 nRetValue = EXITCODE_LOADERROR;
472 }
473 }
474 }
475
476 if (lpwDllCmdLine)
477 FreeConvertedWideChar(lpwDllCmdLine);
478 GlobalFree(argv);
479 OleUninitialize();
480 return nRetValue;
481 }