scroll mode for very long start menus
[reactos.git] / reactos / apps / utils / regsvr32 / regsvr32.c
1 /*
2 * ReactOS regsvr32
3 * Copyright (C) 2004 ReactOS Team
4 *
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)
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 LPCTSTR ModuleTitle = _T("RegSvr32");
56 LPCTSTR UsageMessage =
57 _T("%s\n\n")
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.");
77
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.
84 #ifdef UNICODE
85 #define CommandLineToArgv CommandLineToArgvW
86 #include <shellapi.h>
87 #else
88 #define CommandLineToArgv CommandLineToArgvT
89
90 LPTSTR *WINAPI CommandLineToArgvT(LPCTSTR lpCmdLine, int *lpArgc)
91 {
92 HGLOBAL hargv;
93 LPTSTR *argv, lpSrc, lpDest, lpArg;
94 int argc, nBSlash;
95 BOOL bInQuotes;
96
97 // If null was passed in for lpCmdLine, there are no arguments
98 if (!lpCmdLine) {
99 if (lpArgc)
100 *lpArgc = 0;
101 return 0;
102 }
103
104 lpSrc = (LPTSTR)lpCmdLine;
105 // Skip spaces at beginning
106 while (*lpSrc == _T(' ') || *lpSrc == _T('\t'))
107 lpSrc++;
108
109 // If command-line starts with null, there are no arguments
110 if (*lpSrc == 0) {
111 if (lpArgc)
112 *lpArgc = 0;
113 return 0;
114 }
115
116 lpArg = lpSrc;
117 argc = 0;
118 nBSlash = 0;
119 bInQuotes = FALSE;
120
121 // Count the number of arguments
122 while (1) {
123 if (*lpSrc == 0 || ((*lpSrc == _T(' ') || *lpSrc == _T('\t')) && !bInQuotes)) {
124 // Whitespace not enclosed in quotes signals the start of another argument
125 argc++;
126
127 // Skip whitespace between arguments
128 while (*lpSrc == _T(' ') || *lpSrc == _T('\t'))
129 lpSrc++;
130 if (*lpSrc == 0)
131 break;
132 nBSlash = 0;
133 continue;
134 }
135 else if (*lpSrc == _T('\\')) {
136 // Count consecutive backslashes
137 nBSlash++;
138 }
139 else if (*lpSrc == _T('\"') && !(nBSlash & 1)) {
140 // Open or close quotes
141 bInQuotes = !bInQuotes;
142 nBSlash = 0;
143 }
144 else {
145 // Some other character
146 nBSlash = 0;
147 }
148 lpSrc++;
149 }
150
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);
154
155 if (!argv) {
156 // Memory allocation failed
157 if (lpArgc)
158 *lpArgc = 0;
159 return 0;
160 }
161
162 lpSrc = lpArg;
163 lpDest = lpArg = (LPTSTR)(argv + argc);
164 argc = 0;
165 nBSlash = 0;
166 bInQuotes = FALSE;
167
168 // Fill the argument array
169 while (1) {
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
173 *lpDest++ = 0;
174 argv[argc++] = lpArg;
175
176 // Skip whitespace between arguments
177 while (*lpSrc == _T(' ') || *lpSrc == _T('\t'))
178 lpSrc++;
179 if (*lpSrc == 0)
180 break;
181 lpArg = lpDest;
182 nBSlash = 0;
183 continue;
184 }
185 else if (*lpSrc == _T('\\')) {
186 *lpDest++ = _T('\\');
187 lpSrc++;
188
189 // Count consecutive backslashes
190 nBSlash++;
191 }
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;
198 }
199 else {
200 // If an odd number of backslashes are before the quotes,
201 // output a quote
202 lpDest -= (nBSlash + 1) / 2;
203 *lpDest++ = _T('\"');
204 }
205 lpSrc++;
206 nBSlash = 0;
207 }
208 else {
209 // Copy other characters
210 *lpDest++ = *lpSrc++;
211 nBSlash = 0;
212 }
213 }
214
215 if (lpArgc)
216 *lpArgc = argc;
217 return argv;
218 }
219
220 #endif
221
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.
228 #ifdef UNICODE
229 #define ConvertToWideChar(lptString) (lptString)
230 #define FreeConvertedWideChar(lpwString)
231 #else
232
233 LPWSTR ConvertToWideChar(LPCSTR lpString)
234 {
235 LPWSTR lpwString;
236 size_t nStrLen;
237
238 nStrLen = strlen(lpString) + 1;
239
240 lpwString = (LPWSTR)malloc(nStrLen * sizeof(WCHAR));
241 MultiByteToWideChar(0,0,lpString,nStrLen,lpwString,nStrLen);
242
243 return lpwString;
244 }
245
246 #define FreeConvertedWideChar(lpwString) free(lpwString)
247 #endif
248
249 void DisplayMessage(BOOL bConsole, BOOL bSilent, LPCTSTR lpMessage, LPCTSTR lpTitle, UINT uType)
250 {
251 if (!bSilent)
252 MessageBox(0,lpMessage,lpTitle,uType);
253 if (bConsole)
254 _tprintf(_T("%s: %s\n\n"),lpTitle,lpMessage);
255 }
256
257 int WINAPI WinMain(
258 HINSTANCE hInstance,
259 HINSTANCE hPrevInstance,
260 LPSTR lpCmdLineA,
261 int nCmdShow
262 )
263 {
264 int argc;
265 LPTSTR *argv;
266 LPTSTR lptDllName,lptDllCmdLine,lptMsgBuffer;
267 LPCTSTR lptFuncName;
268 LPCSTR lpFuncName;
269 LPWSTR lpwDllCmdLine;
270 BOOL bUnregister,bSilent,bConsole,bInstall,bNoRegister;
271 UINT nDllCount;
272 HMODULE hDll;
273 DLLREGISTER fnDllRegister;
274 DLLINSTALL fnDllInstall;
275 HRESULT hResult;
276 DWORD dwErr;
277 int nRetValue,i;
278
279 // Get command-line in argc-argv format
280 argv = CommandLineToArgv(GetCommandLine(),&argc);
281
282 // Initialize variables
283 lptFuncName = 0;
284 lptDllCmdLine = 0;
285 nDllCount = 0;
286 bUnregister = FALSE;
287 bSilent = FALSE;
288 bConsole = FALSE;
289 bInstall = FALSE;
290 bNoRegister = FALSE;
291
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]) {
296 case _T('u'):
297 case _T('U'):
298 bUnregister = TRUE;
299 break;
300 case _T('s'):
301 case _T('S'):
302 bSilent = TRUE;
303 break;
304 case _T('c'):
305 case _T('C'):
306 bConsole = TRUE;
307 break;
308 case _T('i'):
309 case _T('I'):
310 bInstall = TRUE;
311 lptDllCmdLine = argv[i];
312 while (*lptDllCmdLine != 0 && *lptDllCmdLine != _T(':'))
313 lptDllCmdLine++;
314 if (*lptDllCmdLine == _T(':'))
315 lptDllCmdLine++;
316 break;
317 case _T('n'):
318 case _T('N'):
319 bNoRegister = TRUE;
320 break;
321 default:
322 if (!lptFuncName)
323 lptFuncName = argv[i];
324 }
325 }
326 else {
327 nDllCount++;
328 }
329 }
330
331 // An unrecognized flag was used, display a message and show available options
332 if (lptFuncName) {
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);
337 free(lptMsgBuffer);
338 GlobalFree(argv);
339 return EXITCODE_PARAMERROR;
340 }
341
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);
347 free(lptMsgBuffer);
348 GlobalFree(argv);
349 return EXITCODE_PARAMERROR;
350 }
351
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);
357 free(lptMsgBuffer);
358 GlobalFree(argv);
359 return EXITCODE_PARAMERROR;
360 }
361
362 nRetValue = EXITCODE_SUCCESS;
363 if (!bUnregister) {
364 lpFuncName = szDllRegister;
365 lptFuncName = tszDllRegister;
366 }
367 else {
368 lpFuncName = szDllUnregister;
369 lptFuncName = tszDllUnregister;
370 }
371
372 if (lptDllCmdLine)
373 lpwDllCmdLine = ConvertToWideChar(lptDllCmdLine);
374 else
375 lpwDllCmdLine = 0;
376
377 // Initialize OLE32 before attempting to register the
378 // dll. Some dll's require this to register properly
379 OleInitialize(0);
380
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];
386
387 // Everything is all setup, so load the dll now
388 hDll = LoadLibraryEx(lptDllName,0,LOAD_WITH_ALTERED_SEARCH_PATH);
389 if (hDll) {
390 if (!bNoRegister) {
391 // Get the address of DllRegisterServer or DllUnregisterServer
392 fnDllRegister = (DLLREGISTER)GetProcAddress(hDll,lpFuncName);
393 if (fnDllRegister) {
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);
401 }
402 else {
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);
407 }
408 free(lptMsgBuffer);
409 if (hResult != S_OK)
410 nRetValue = EXITCODE_FAILURE;
411 }
412 else {
413 FreeLibrary(hDll);
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);
418 free(lptMsgBuffer);
419 nRetValue = EXITCODE_NOENTRY;
420 }
421 }
422
423 if (bInstall) {
424 // Get the address of DllInstall
425 fnDllInstall = (DLLINSTALL)GetProcAddress(hDll,szDllInstall);
426 if (fnDllInstall) {
427 // If the function exists, call it
428 if (!bUnregister)
429 hResult = fnDllInstall(1,lpwDllCmdLine);
430 else
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);
437 }
438 else {
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);
443 }
444 free(lptMsgBuffer);
445 if (hResult != S_OK)
446 nRetValue = EXITCODE_FAILURE;
447 }
448 else {
449 FreeLibrary(hDll);
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);
454 free(lptMsgBuffer);
455 nRetValue = EXITCODE_NOENTRY;
456 }
457 }
458
459 // The dll function has finished executing, so unload it
460 FreeLibrary(hDll);
461 }
462 else {
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);
468 free(lptMsgBuffer);
469 nRetValue = EXITCODE_LOADERROR;
470 }
471 }
472 }
473
474 if (lpwDllCmdLine)
475 FreeConvertedWideChar(lpwDllCmdLine);
476 GlobalFree(argv);
477 OleUninitialize();
478 return nRetValue;
479 }
480