Home | Info | Community | Development | myReactOS | Contact Us
ReactOS Development > Doxygenrundll32.c
Go to the documentation of this file.
00001 /* 00002 * ReactOS rundll32 00003 * Copyright (C) 2003-2004 ReactOS Team 00004 * 00005 * COPYRIGHT: See COPYING in the top level directory 00006 * PROJECT: ReactOS rundll32.exe 00007 * FILE: base/system/rundll32/rundll32.c 00008 * PURPOSE: Run a DLL as a program 00009 * PROGRAMMER: ShadowFlare (blakflare@hotmail.com) 00010 */ 00011 00012 #define WIN32_LEAN_AND_MEAN 00013 00014 // Both UNICODE and _UNICODE must be either defined or undefined 00015 // because some headers use UNICODE and others use _UNICODE 00016 #ifdef UNICODE 00017 #ifndef _UNICODE 00018 #define _UNICODE 00019 #endif 00020 #else 00021 #ifdef _UNICODE 00022 #define UNICODE 00023 #endif 00024 #endif 00025 00026 #include <windows.h> 00027 #include <stdio.h> 00028 #include <string.h> 00029 #include <malloc.h> 00030 #include <tchar.h> 00031 #include "resource.h" 00032 00033 typedef int (WINAPI *DllWinMainW)( 00034 HWND hWnd, 00035 HINSTANCE hInstance, 00036 LPWSTR lpwCmdLine, 00037 int nCmdShow 00038 ); 00039 typedef int (WINAPI *DllWinMainA)( 00040 HWND hWnd, 00041 HINSTANCE hInstance, 00042 LPSTR lpCmdLine, 00043 int nCmdShow 00044 ); 00045 00046 /* 00047 LPCTSTR DllNotLoaded = _T("LoadLibrary failed to load \"%s\""); 00048 LPCTSTR MissingEntry = _T("Missing entry point:%s\nIn %s"); 00049 */ 00050 LPCTSTR rundll32_wtitle = _T("rundll32"); 00051 LPCTSTR rundll32_wclass = _T("rundll32_window"); 00052 00053 TCHAR ModuleFileName[MAX_PATH+1]; 00054 LPTSTR ModuleTitle; 00055 00056 00057 // CommandLineToArgv converts a command-line string to argc and 00058 // argv similar to the ones in the standard main function. 00059 // This is a specialized version coded specifically for rundll32 00060 // and is not intended to be used in any other program. 00061 LPTSTR *WINAPI CommandLineToArgv(LPCTSTR lpCmdLine, int *lpArgc) 00062 { 00063 LPTSTR *argv, lpSrc, lpDest, lpArg; 00064 int argc, nBSlash, nNames; 00065 BOOL bInQuotes, bFirstChar; 00066 00067 // If null was passed in for lpCmdLine, there are no arguments 00068 if (!lpCmdLine) { 00069 if (lpArgc) 00070 *lpArgc = 0; 00071 return 0; 00072 } 00073 00074 lpSrc = (LPTSTR)lpCmdLine; 00075 // Skip spaces at beginning 00076 while (*lpSrc == _T(' ') || *lpSrc == _T('\t')) 00077 lpSrc++; 00078 00079 // If command-line starts with null, there are no arguments 00080 if (*lpSrc == 0) { 00081 if (lpArgc) 00082 *lpArgc = 0; 00083 return 0; 00084 } 00085 00086 lpArg = lpSrc; 00087 argc = 0; 00088 nBSlash = 0; 00089 bInQuotes = FALSE; 00090 bFirstChar = TRUE; 00091 nNames = 0; 00092 00093 // Count the number of arguments 00094 while (nNames < 4) { 00095 if (*lpSrc == 0 || (*lpSrc == _T(',') && nNames == 2) || ((*lpSrc == _T(' ') || *lpSrc == _T('\t')) && !bInQuotes)) { 00096 // Whitespace not enclosed in quotes signals the start of another argument 00097 argc++; 00098 00099 // Skip whitespace between arguments 00100 while (*lpSrc == _T(' ') || *lpSrc == _T('\t') || (*lpSrc == _T(',') && nNames == 2)) 00101 lpSrc++; 00102 if (*lpSrc == 0) 00103 break; 00104 if (nNames >= 3) { 00105 // Increment the count for the last argument 00106 argc++; 00107 break; 00108 } 00109 nBSlash = 0; 00110 bFirstChar = TRUE; 00111 continue; 00112 } 00113 else if (*lpSrc == _T('\\')) { 00114 // Count consecutive backslashes 00115 nBSlash++; 00116 bFirstChar = FALSE; 00117 } 00118 else if (*lpSrc == _T('\"') && !(nBSlash & 1)) { 00119 // Open or close quotes 00120 bInQuotes = !bInQuotes; 00121 nBSlash = 0; 00122 } 00123 else { 00124 // Some other character 00125 nBSlash = 0; 00126 if (bFirstChar && ((*lpSrc != _T('/') && nNames <= 1) || nNames > 1)) 00127 nNames++; 00128 bFirstChar = FALSE; 00129 } 00130 lpSrc++; 00131 } 00132 00133 // Allocate space for the pointers in argv and the strings in one block 00134 argv = (LPTSTR *)malloc(argc * sizeof(LPTSTR) + (_tcslen(lpArg) + 1) * sizeof(TCHAR)); 00135 00136 if (!argv) { 00137 // Memory allocation failed 00138 if (lpArgc) 00139 *lpArgc = 0; 00140 return 0; 00141 } 00142 00143 lpSrc = lpArg; 00144 lpDest = lpArg = (LPTSTR)(argv + argc); 00145 argc = 0; 00146 nBSlash = 0; 00147 bInQuotes = FALSE; 00148 bFirstChar = TRUE; 00149 nNames = 0; 00150 00151 // Fill the argument array 00152 while (nNames < 4) { 00153 if (*lpSrc == 0 || (*lpSrc == _T(',') && nNames == 2) || ((*lpSrc == _T(' ') || *lpSrc == _T('\t')) && !bInQuotes)) { 00154 // Whitespace not enclosed in quotes signals the start of another argument 00155 // Null-terminate argument 00156 *lpDest++ = 0; 00157 argv[argc++] = lpArg; 00158 00159 // Skip whitespace between arguments 00160 while (*lpSrc == _T(' ') || *lpSrc == _T('\t') || (*lpSrc == _T(',') && nNames == 2)) 00161 lpSrc++; 00162 if (*lpSrc == 0) 00163 break; 00164 lpArg = lpDest; 00165 if (nNames >= 3) { 00166 // Copy the rest of the command-line to the last argument 00167 argv[argc++] = lpArg; 00168 _tcscpy(lpArg,lpSrc); 00169 break; 00170 } 00171 nBSlash = 0; 00172 bFirstChar = TRUE; 00173 continue; 00174 } 00175 else if (*lpSrc == _T('\\')) { 00176 *lpDest++ = _T('\\'); 00177 lpSrc++; 00178 00179 // Count consecutive backslashes 00180 nBSlash++; 00181 bFirstChar = FALSE; 00182 } 00183 else if (*lpSrc == _T('\"')) { 00184 if (!(nBSlash & 1)) { 00185 // If an even number of backslashes are before the quotes, 00186 // the quotes don't go in the output 00187 lpDest -= nBSlash / 2; 00188 bInQuotes = !bInQuotes; 00189 } 00190 else { 00191 // If an odd number of backslashes are before the quotes, 00192 // output a quote 00193 lpDest -= (nBSlash + 1) / 2; 00194 *lpDest++ = _T('\"'); 00195 bFirstChar = FALSE; 00196 } 00197 lpSrc++; 00198 nBSlash = 0; 00199 } 00200 else { 00201 // Copy other characters 00202 if (bFirstChar && ((*lpSrc != _T('/') && nNames <= 1) || nNames > 1)) 00203 nNames++; 00204 *lpDest++ = *lpSrc++; 00205 nBSlash = 0; 00206 bFirstChar = FALSE; 00207 } 00208 } 00209 00210 if (lpArgc) 00211 *lpArgc = argc; 00212 return argv; 00213 } 00214 00215 void GetModuleTitle(void) 00216 { 00217 LPTSTR lpStr; 00218 00219 GetModuleFileName(0,ModuleFileName,MAX_PATH); 00220 ModuleTitle = ModuleFileName; 00221 00222 for (lpStr = ModuleFileName;*lpStr;lpStr++) { 00223 if (*lpStr == _T('\\')) 00224 ModuleTitle = lpStr+1; 00225 } 00226 00227 for (lpStr = ModuleTitle;*lpStr;lpStr++) { 00228 if (_tcsicmp(lpStr,_T(".exe"))==0) 00229 break; 00230 } 00231 00232 *lpStr = 0; 00233 } 00234 00235 // The macro ConvertToWideChar takes a tstring parameter and returns 00236 // a pointer to a unicode string. A conversion is performed if 00237 // neccessary. FreeConvertedWideChar string should be used on the 00238 // return value of ConvertToWideChar when the string is no longer 00239 // needed. The original string or the string that is returned 00240 // should not be modified until FreeConvertedWideChar has been called. 00241 #ifdef UNICODE 00242 #define ConvertToWideChar(lptString) (lptString) 00243 #define FreeConvertedWideChar(lpwString) 00244 #else 00245 00246 LPWSTR ConvertToWideChar(LPCSTR lpString) 00247 { 00248 LPWSTR lpwString; 00249 size_t nStrLen; 00250 00251 nStrLen = strlen(lpString) + 1; 00252 00253 lpwString = (LPWSTR)malloc(nStrLen * sizeof(WCHAR)); 00254 MultiByteToWideChar(0,0,lpString,nStrLen,lpwString,nStrLen); 00255 00256 return lpwString; 00257 } 00258 00259 #define FreeConvertedWideChar(lpwString) free(lpwString) 00260 #endif 00261 00262 // The macro ConvertToMultiByte takes a tstring parameter and returns 00263 // a pointer to an ansi string. A conversion is performed if 00264 // neccessary. FreeConvertedMultiByte string should be used on the 00265 // return value of ConvertToMultiByte when the string is no longer 00266 // needed. The original string or the string that is returned 00267 // should not be modified until FreeConvertedMultiByte has been called. 00268 #ifdef UNICODE 00269 #define ConvertToMultiByte(lptString) DuplicateToMultiByte(lptString,0) 00270 #define FreeConvertedMultiByte(lpaString) free(lpaString) 00271 #else 00272 #define ConvertToMultiByte(lptString) (lptString) 00273 #define FreeConvertedMultiByte(lpaString) 00274 #endif 00275 00276 // DuplicateToMultiByte takes a tstring parameter and always returns 00277 // a pointer to a duplicate ansi string. If nBufferSize is zero, 00278 // the buffer length is the exact size of the string plus the 00279 // terminating null. If nBufferSize is nonzero, the buffer length 00280 // is equal to nBufferSize. As with strdup, free should be called 00281 // for the returned string when it is no longer needed. 00282 LPSTR DuplicateToMultiByte(LPCTSTR lptString, size_t nBufferSize) 00283 { 00284 LPSTR lpString; 00285 size_t nStrLen; 00286 00287 nStrLen = _tcslen(lptString) + 1; 00288 if (nBufferSize == 0) nBufferSize = nStrLen; 00289 00290 lpString = (LPSTR)malloc(nBufferSize); 00291 #ifdef UNICODE 00292 WideCharToMultiByte(0,0,lptString,nStrLen,lpString,nBufferSize,0,0); 00293 #else 00294 strncpy(lpString,lptString,nBufferSize); 00295 #endif 00296 00297 return lpString; 00298 } 00299 00300 LRESULT CALLBACK EmptyWindowProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) 00301 { 00302 return DefWindowProc(hWnd, uMsg, wParam, lParam); 00303 } 00304 00305 // Registers a minimal window class for passing to the dll function 00306 BOOL RegisterBlankClass(HINSTANCE hInstance, HINSTANCE hPrevInstance) 00307 { 00308 WNDCLASSEX wcex; 00309 00310 wcex.cbSize = sizeof(WNDCLASSEX); 00311 wcex.style = 0; 00312 wcex.lpfnWndProc = EmptyWindowProc; 00313 wcex.cbClsExtra = 0; 00314 wcex.cbWndExtra = 0; 00315 wcex.hInstance = hInstance; 00316 wcex.hIcon = 0; 00317 wcex.hCursor = 0; 00318 wcex.hbrBackground = 0; 00319 wcex.lpszMenuName = 0; 00320 wcex.lpszClassName = rundll32_wclass; 00321 wcex.hIconSm = 0; 00322 00323 return (RegisterClassEx(&wcex) != (ATOM)0); 00324 } 00325 00326 int WINAPI _tWinMain( 00327 HINSTANCE hInstance, 00328 HINSTANCE hPrevInstance, 00329 LPTSTR lpCmdLine, 00330 int nCmdShow 00331 ) 00332 { 00333 int argc; 00334 TCHAR szMsg[RC_STRING_MAX_SIZE]; 00335 00336 LPTSTR *argv; 00337 LPTSTR lptCmdLine,lptDllName,lptFuncName,lptMsgBuffer; 00338 LPSTR lpFuncName,lpaCmdLine; 00339 LPWSTR lpwCmdLine; 00340 HMODULE hDll; 00341 DllWinMainW fnDllWinMainW; 00342 DllWinMainA fnDllWinMainA; 00343 HWND hWindow; 00344 int nRetVal,i; 00345 size_t nStrLen; 00346 00347 // Get command-line in argc-argv format 00348 argv = CommandLineToArgv(GetCommandLine(),&argc); 00349 00350 // Skip all beginning arguments starting with a slash (/) 00351 for (i = 1; i < argc; i++) 00352 if (*argv[i] != _T('/')) break; 00353 00354 // If no dll was specified, there is nothing to do 00355 if (i >= argc) { 00356 if (argv) free(argv); 00357 return 0; 00358 } 00359 00360 lptDllName = argv[i++]; 00361 00362 // The next argument, which specifies the name of the dll function, 00363 // can either have a comma between it and the dll filename or a space. 00364 // Using a comma here is the preferred method 00365 if (i < argc) 00366 lptFuncName = argv[i++]; 00367 else 00368 lptFuncName = _T(""); 00369 00370 // If no function name was specified, nothing needs to be done 00371 if (!*lptFuncName) { 00372 if (argv) free(argv); 00373 return 0; 00374 } 00375 00376 // The rest of the arguments will be passed to dll function 00377 if (i < argc) 00378 lptCmdLine = argv[i]; 00379 else 00380 lptCmdLine = _T(""); 00381 00382 nRetVal = 0; 00383 00384 // Everything is all setup, so load the dll now 00385 hDll = LoadLibrary(lptDllName); 00386 if (hDll) { 00387 nStrLen = _tcslen(lptFuncName); 00388 // Make a non-unicode version of the function name, 00389 // since that is all GetProcAddress accepts 00390 lpFuncName = DuplicateToMultiByte(lptFuncName,nStrLen + 2); 00391 00392 #ifdef UNICODE 00393 lpFuncName[nStrLen] = 'W'; 00394 lpFuncName[nStrLen+1] = 0; 00395 // Get address of unicode version of the dll function if it exists 00396 fnDllWinMainW = (DllWinMainW)GetProcAddress(hDll,lpFuncName); 00397 fnDllWinMainA = 0; 00398 if (!fnDllWinMainW) { 00399 // If no unicode function was found, get the address of the non-unicode function 00400 lpFuncName[nStrLen] = 'A'; 00401 fnDllWinMainA = (DllWinMainA)GetProcAddress(hDll,lpFuncName); 00402 if (!fnDllWinMainA) { 00403 // If first non-unicode function was not found, get the address 00404 // of the other non-unicode function 00405 lpFuncName[nStrLen] = 0; 00406 fnDllWinMainA = (DllWinMainA)GetProcAddress(hDll,lpFuncName); 00407 } 00408 } 00409 #else 00410 // Get address of non-unicode version of the dll function if it exists 00411 fnDllWinMainA = (DllWinMainA)GetProcAddress(hDll,lpFuncName); 00412 fnDllWinMainW = 0; 00413 if (!fnDllWinMainA) { 00414 // If first non-unicode function was not found, get the address 00415 // of the other non-unicode function 00416 lpFuncName[nStrLen] = 'A'; 00417 lpFuncName[nStrLen+1] = 0; 00418 fnDllWinMainA = (DllWinMainA)GetProcAddress(hDll,lpFuncName); 00419 if (!fnDllWinMainA) { 00420 // If non-unicode function was not found, get the address of the unicode function 00421 lpFuncName[nStrLen] = 'W'; 00422 fnDllWinMainW = (DllWinMainW)GetProcAddress(hDll,lpFuncName); 00423 } 00424 } 00425 #endif 00426 00427 free(lpFuncName); 00428 00429 if (!RegisterBlankClass(hInstance, hPrevInstance)) 00430 { 00431 return 0; 00432 } 00433 // Create a window so we can pass a window handle to 00434 // the dll function; this is required 00435 hWindow = CreateWindowEx(0,rundll32_wclass,rundll32_wtitle,0,CW_USEDEFAULT,0,CW_USEDEFAULT,0,0,0,hInstance,0); 00436 00437 if (fnDllWinMainW) { 00438 // Convert the command-line string to unicode and call the dll function 00439 lpwCmdLine = ConvertToWideChar(lptCmdLine); 00440 nRetVal = fnDllWinMainW(hWindow,hInstance,lpwCmdLine,nCmdShow); 00441 FreeConvertedWideChar(lpwCmdLine); 00442 } 00443 else if (fnDllWinMainA) { 00444 // Convert the command-line string to ansi and call the dll function 00445 lpaCmdLine = ConvertToMultiByte(lptCmdLine); 00446 nRetVal = fnDllWinMainA(hWindow,hInstance,lpaCmdLine,nCmdShow); 00447 FreeConvertedMultiByte(lpaCmdLine); 00448 } 00449 else { 00450 // The specified dll function was not found; display an error message 00451 GetModuleTitle(); 00452 LoadString( GetModuleHandle(NULL), IDS_MissingEntry, (LPTSTR) szMsg,RC_STRING_MAX_SIZE); 00453 00454 lptMsgBuffer = (LPTSTR)malloc((_tcslen(szMsg) - 4 + _tcslen(lptFuncName) + _tcslen(lptDllName) + 1) * sizeof(TCHAR)); 00455 _stprintf(lptMsgBuffer,szMsg,lptFuncName,lptDllName); 00456 MessageBox(0,lptMsgBuffer,ModuleTitle,MB_ICONERROR); 00457 free(lptMsgBuffer); 00458 } 00459 00460 DestroyWindow(hWindow); 00461 UnregisterClass(rundll32_wclass,hInstance); 00462 00463 // The dll function has finished executing, so unload it 00464 FreeLibrary(hDll); 00465 } 00466 else { 00467 // The dll could not be loaded; display an error message 00468 GetModuleTitle(); 00469 LoadString( GetModuleHandle(NULL), IDS_DllNotLoaded, (LPTSTR) szMsg,RC_STRING_MAX_SIZE); 00470 00471 lptMsgBuffer = (LPTSTR)malloc((_tcslen(szMsg) - 2 + _tcslen(lptDllName) + 1) * sizeof(TCHAR)); 00472 _stprintf(lptMsgBuffer,szMsg,lptDllName); 00473 00474 MessageBox(0,lptMsgBuffer,ModuleTitle,MB_ICONERROR); 00475 free(lptMsgBuffer); 00476 } 00477 00478 if (argv) free(argv); 00479 return nRetVal; 00480 } 00481 Generated on Sat May 26 2012 04:17:41 for ReactOS by
1.7.6.1
|