diff --git a/reactos/apps/utils/regsvr32/regsvr32.c b/reactos/apps/utils/regsvr32/regsvr32.c index 4bb958e1958..cb6889c2268 100644 --- a/reactos/apps/utils/regsvr32/regsvr32.c +++ b/reactos/apps/utils/regsvr32/regsvr32.c @@ -1,487 +1,480 @@ -/* - * ReactOS regsvr32 - * Copyright (C) 2004 ReactOS Team - * - * COPYRIGHT: See COPYING in the top level directory - * PROJECT: ReactOS regsvr32.exe - * FILE: apps/utils/regsvr32/regsvr32.c - * PURPOSE: Register a COM component in the registry - * PROGRAMMER: ShadowFlare (blakflare@hotmail.com) - */ - -#define WIN32_LEAN_AND_MEAN - -// Both UNICODE and _UNICODE must be either defined or undefined -// because some headers use UNICODE and others use _UNICODE -#ifdef UNICODE -#ifndef _UNICODE -#define _UNICODE -#endif -#else -#ifdef _UNICODE -#define UNICODE -#endif -#endif - -#include -#include -#include -#include -#include -#include - -typedef HRESULT (WINAPI *DLLREGISTER)(void); -typedef HRESULT (WINAPI *DLLINSTALL)(BOOL bInstall, LPWSTR lpwCmdLine); - -#define EXITCODE_SUCCESS 0 -#define EXITCODE_PARAMERROR 1 -#define EXITCODE_LOADERROR 3 -#define EXITCODE_NOENTRY 4 -#define EXITCODE_FAILURE 5 - -LPCSTR szDllRegister = "DllRegisterServer"; -LPCSTR szDllUnregister = "DllUnregisterServer"; -LPCSTR szDllInstall = "DllInstall"; -#ifdef UNICODE -LPCWSTR tszDllRegister = L"DllRegisterServer"; -LPCWSTR tszDllUnregister = L"DllUnregisterServer"; -LPCWSTR tszDllInstall = L"DllInstall"; -#else -#define tszDllRegister szDllRegister -#define tszDllUnregister szDllUnregister -#define tszDllInstall szDllInstall -#endif - -LPCTSTR ModuleTitle = _T("RegSvr32"); -LPCTSTR UsageMessage = - _T("%s\n\n") - _T("Usage: regsvr32 [/u] [/s] [/c] [/n] [/i[:cmdline]] dllname\n") - _T("/u - Unregister server\n") - _T("/s - Silent; display no message boxes\n") - _T("/c - Console output\n") - _T("/i - Call DllInstall passing it an optional [cmdline]; when used with /u calls dll uninstall\n") - _T("/n - Do not call DllRegisterServer; this option must be used with /i"); -LPCTSTR NoDllSpecified = _T("No DLL name specified."); -LPCTSTR InvalidFlag = _T("Unrecognized flag: %s"); -LPCTSTR SwitchN_NoI = _T("Unrecognized flag: /n must be used with the /i switch"); -LPCTSTR DllNotLoaded = - _T("LoadLibrary(\"%s\") failed.\n") - _T("GetLastError returns 0x%08x."); -LPCTSTR MissingEntry = - _T("%s was loaded, but the %s entry point was not found.\n\n") - _T("%s may not be exported, or a corrupt version of %s may be in memory. Consider using PView to detect and remove it."); -LPCTSTR FailureMessage = - _T("%s in %s failed.\n") - _T("Return code was: 0x%08x"); -LPCTSTR SuccessMessage = _T("%s in %s succeeded."); - -// The macro CommandLineToArgv maps to a function that converts -// a command-line string to argc and argv similar to the ones -// in the standard main function. If this code is compiled for -// unicode, the build-in Windows API function is used, otherwise -// a non-unicode non-API version is used for compatibility with -// Windows versions that have no unicode support. -#ifdef UNICODE -#define CommandLineToArgv CommandLineToArgvW -#include -#else -#define CommandLineToArgv CommandLineToArgvT - -LPTSTR *WINAPI CommandLineToArgvT(LPCTSTR lpCmdLine, int *lpArgc) -{ - HGLOBAL hargv; - LPTSTR *argv, lpSrc, lpDest, lpArg; - int argc, nBSlash; - BOOL bInQuotes; - - // If null was passed in for lpCmdLine, there are no arguments - if (!lpCmdLine) { - if (lpArgc) - *lpArgc = 0; - return 0; - } - - lpSrc = (LPTSTR)lpCmdLine; - // Skip spaces at beginning - while (*lpSrc == _T(' ') || *lpSrc == _T('\t')) - lpSrc++; - - // If command-line starts with null, there are no arguments - if (*lpSrc == 0) { - if (lpArgc) - *lpArgc = 0; - return 0; - } - - lpArg = lpSrc; - argc = 0; - nBSlash = 0; - bInQuotes = FALSE; - - // Count the number of arguments - while (1) { - if (*lpSrc == 0 || ((*lpSrc == _T(' ') || *lpSrc == _T('\t')) && !bInQuotes)) { - // Whitespace not enclosed in quotes signals the start of another argument - argc++; - - // Skip whitespace between arguments - while (*lpSrc == _T(' ') || *lpSrc == _T('\t')) - lpSrc++; - if (*lpSrc == 0) - break; - nBSlash = 0; - continue; - } - else if (*lpSrc == _T('\\')) { - // Count consecutive backslashes - nBSlash++; - } - else if (*lpSrc == _T('\"') && !(nBSlash & 1)) { - // Open or close quotes - bInQuotes = !bInQuotes; - nBSlash = 0; - } - else { - // Some other character - nBSlash = 0; - } - lpSrc++; - } - - // Allocate space the same way as CommandLineToArgvW for compatibility - hargv = GlobalAlloc(0, argc * sizeof(LPTSTR) + (_tcslen(lpArg) + 1) * sizeof(TCHAR)); - argv = (LPTSTR *)GlobalLock(hargv); - - if (!argv) { - // Memory allocation failed - if (lpArgc) - *lpArgc = 0; - return 0; - } - - lpSrc = lpArg; - lpDest = lpArg = (LPTSTR)(argv + argc); - argc = 0; - nBSlash = 0; - bInQuotes = FALSE; - - // Fill the argument array - while (1) { - if (*lpSrc == 0 || ((*lpSrc == _T(' ') || *lpSrc == _T('\t')) && !bInQuotes)) { - // Whitespace not enclosed in quotes signals the start of another argument - // Null-terminate argument - *lpDest++ = 0; - argv[argc++] = lpArg; - - // Skip whitespace between arguments - while (*lpSrc == _T(' ') || *lpSrc == _T('\t')) - lpSrc++; - if (*lpSrc == 0) - break; - lpArg = lpDest; - nBSlash = 0; - continue; - } - else if (*lpSrc == _T('\\')) { - *lpDest++ = _T('\\'); - lpSrc++; - - // Count consecutive backslashes - nBSlash++; - } - else if (*lpSrc == _T('\"')) { - if (!(nBSlash & 1)) { - // If an even number of backslashes are before the quotes, - // the quotes don't go in the output - lpDest -= nBSlash / 2; - bInQuotes = !bInQuotes; - } - else { - // If an odd number of backslashes are before the quotes, - // output a quote - lpDest -= (nBSlash + 1) / 2; - *lpDest++ = _T('\"'); - } - lpSrc++; - nBSlash = 0; - } - else { - // Copy other characters - *lpDest++ = *lpSrc++; - nBSlash = 0; - } - } - - if (lpArgc) - *lpArgc = argc; - return argv; -} - -#endif - -// The macro ConvertToWideChar takes a tstring parameter and returns -// a pointer to a unicode string. A conversion is performed if -// neccessary. FreeConvertedWideChar string should be used on the -// return value of ConvertToWideChar when the string is no longer -// needed. The original string or the string that is returned -// should not be modified until FreeConvertedWideChar has been called. -#ifdef UNICODE -#define ConvertToWideChar(lptString) (lptString) -#define FreeConvertedWideChar(lpwString) -#else - -LPWSTR ConvertToWideChar(LPCSTR lpString) -{ - LPWSTR lpwString; - size_t nStrLen; - - nStrLen = strlen(lpString) + 1; - - lpwString = (LPWSTR)malloc(nStrLen * sizeof(WCHAR)); - MultiByteToWideChar(0,0,lpString,nStrLen,lpwString,nStrLen); - - return lpwString; -} - -#define FreeConvertedWideChar(lpwString) free(lpwString) -#endif - -int WINAPI WinMain( - HINSTANCE hInstance, - HINSTANCE hPrevInstance, - LPSTR lpCmdLineA, - int nCmdShow -) -{ - int argc; - LPTSTR *argv; - LPTSTR lptDllName,lptDllCmdLine,lptMsgBuffer; - LPCTSTR lptFuncName; - LPCSTR lpFuncName; - LPWSTR lpwDllCmdLine; - BOOL bUnregister,bSilent,bConsole,bInstall,bNoRegister; - UINT nDllCount; - HMODULE hDll; - DLLREGISTER fnDllRegister; - DLLINSTALL fnDllInstall; - HRESULT hResult; - DWORD dwErr; - int nRetValue,i; - - // Get command-line in argc-argv format - argv = CommandLineToArgv(GetCommandLine(),&argc); - - // Initialize variables - lptFuncName = 0; - lptDllCmdLine = 0; - nDllCount = 0; - bUnregister = FALSE; - bSilent = FALSE; - bConsole = FALSE; - bInstall = FALSE; - bNoRegister = FALSE; - - // Find all arguments starting with a slash (/) - for (i = 1; i < argc; i++) { - if (*argv[i] == _T('/')) { - switch (argv[i][1]) { - case _T('u'): - case _T('U'): - bUnregister = TRUE; - break; - case _T('s'): - case _T('S'): - bSilent = TRUE; - break; - case _T('c'): - case _T('C'): - bConsole = TRUE; - break; - case _T('i'): - case _T('I'): - bInstall = TRUE; - if (argv[i][2] == _T(':')) - lptDllCmdLine = argv[i]+3; - else - lptDllCmdLine = _T(""); - break; - case _T('n'): - case _T('N'): - bNoRegister = TRUE; - break; - default: - if (!lptFuncName) - lptFuncName = argv[i]; - } - } - else { - nDllCount++; - } - } - - // An unrecognized flag was used, display a message and show available options - if (lptFuncName) { - if (!bSilent) { - lptMsgBuffer = (LPTSTR)malloc((_tcslen(UsageMessage) - 2 + _tcslen(InvalidFlag) - 2 + _tcslen(lptFuncName) + 1) * sizeof(TCHAR)); - _stprintf(lptMsgBuffer + (_tcslen(UsageMessage) - 2),InvalidFlag,lptFuncName); - _stprintf(lptMsgBuffer,UsageMessage,lptMsgBuffer + (_tcslen(UsageMessage) - 2)); - MessageBox(0,lptMsgBuffer,ModuleTitle,MB_ICONEXCLAMATION); - free(lptMsgBuffer); - } - GlobalFree(argv); - return EXITCODE_PARAMERROR; - } - - // /n was used without /i, display a message and show available options - if (bNoRegister && (!bInstall)) { - if (!bSilent) { - lptMsgBuffer = (LPTSTR)malloc((_tcslen(UsageMessage) - 2 + _tcslen(SwitchN_NoI) + 1) * sizeof(TCHAR)); - _stprintf(lptMsgBuffer,UsageMessage,SwitchN_NoI); - MessageBox(0,lptMsgBuffer,ModuleTitle,MB_ICONEXCLAMATION); - free(lptMsgBuffer); - } - GlobalFree(argv); - return EXITCODE_PARAMERROR; - } - - // No dll was specified, display a message and show available options - if (nDllCount == 0) { - if (!bSilent) { - lptMsgBuffer = (LPTSTR)malloc((_tcslen(UsageMessage) - 2 + _tcslen(NoDllSpecified) + 1) * sizeof(TCHAR)); - _stprintf(lptMsgBuffer,UsageMessage,NoDllSpecified); - MessageBox(0,lptMsgBuffer,ModuleTitle,MB_ICONEXCLAMATION); - free(lptMsgBuffer); - } - GlobalFree(argv); - return EXITCODE_PARAMERROR; - } - - nRetValue = EXITCODE_SUCCESS; - if (!bUnregister) { - lpFuncName = szDllRegister; - lptFuncName = tszDllRegister; - } - else { - lpFuncName = szDllUnregister; - lptFuncName = tszDllUnregister; - } - - if (lptDllCmdLine) - lpwDllCmdLine = ConvertToWideChar(lptDllCmdLine); - else - lpwDllCmdLine = 0; - - // Initialize OLE32 before attempting to register the - // dll. Some dll's require this to register properly - OleInitialize(0); - - // (Un)register every dll whose filename was passed in the command-line string - for (i = 1; i < argc; i++) { - // Arguments that do not start with a slash (/) are filenames - if (*argv[i] != _T('/')) { - lptDllName = argv[i]; - - // Everything is all setup, so load the dll now - hDll = LoadLibrary(lptDllName); - if (hDll) { - if (!bNoRegister) { - // Get the address of DllRegisterServer or DllUnregisterServer - fnDllRegister = (DLLREGISTER)GetProcAddress(hDll,lpFuncName); - if (fnDllRegister) { - // If the function exists, call it - hResult = fnDllRegister(); - if (!bSilent) { - if (hResult == S_OK) { - // (Un)register succeeded, display a message - lptMsgBuffer = (LPTSTR)malloc((_tcslen(SuccessMessage) - 4 + _tcslen(lptFuncName) + _tcslen(lptDllName) + 1) * sizeof(TCHAR)); - _stprintf(lptMsgBuffer,SuccessMessage,lptFuncName,lptDllName); - MessageBox(0,lptMsgBuffer,ModuleTitle,MB_ICONINFORMATION); - } - else { - // (Un)register failed, display a message - lptMsgBuffer = (LPTSTR)malloc((_tcslen(FailureMessage) + _tcslen(lptFuncName) + _tcslen(lptDllName) + 1) * sizeof(TCHAR)); - _stprintf(lptMsgBuffer,FailureMessage,lptFuncName,lptDllName,hResult); - MessageBox(0,lptMsgBuffer,ModuleTitle,MB_ICONEXCLAMATION); - } - free(lptMsgBuffer); - } - if (hResult != S_OK) - nRetValue = EXITCODE_FAILURE; - } - else { - FreeLibrary(hDll); - if (!bSilent) { - // Dll(Un)register was not found, display an error message - lptMsgBuffer = (LPTSTR)malloc((_tcslen(MissingEntry) - 8 + _tcslen(lptFuncName) * 2 + _tcslen(lptDllName) * 2 + 1) * sizeof(TCHAR)); - _stprintf(lptMsgBuffer,MissingEntry,lptDllName,lptFuncName,lptFuncName,lptDllName); - MessageBox(0,lptMsgBuffer,ModuleTitle,MB_ICONEXCLAMATION); - free(lptMsgBuffer); - } - nRetValue = EXITCODE_NOENTRY; - } - } - - if (bInstall) { - // Get the address of DllInstall - fnDllInstall = (DLLINSTALL)GetProcAddress(hDll,szDllInstall); - if (fnDllInstall) { - // If the function exists, call it - if (!bUnregister) - hResult = fnDllInstall(1,lpwDllCmdLine); - else - hResult = fnDllInstall(0,lpwDllCmdLine); - if (!bSilent) { - if (hResult == S_OK) { - // (Un)install succeeded, display a message - lptMsgBuffer = (LPTSTR)malloc((_tcslen(SuccessMessage) - 4 + _tcslen(tszDllInstall) + _tcslen(lptDllName) + 1) * sizeof(TCHAR)); - _stprintf(lptMsgBuffer,SuccessMessage,tszDllInstall,lptDllName); - MessageBox(0,lptMsgBuffer,ModuleTitle,MB_ICONINFORMATION); - } - else { - // (Un)install failed, display a message - lptMsgBuffer = (LPTSTR)malloc((_tcslen(FailureMessage) + _tcslen(tszDllInstall) + _tcslen(lptDllName) + 1) * sizeof(TCHAR)); - _stprintf(lptMsgBuffer,FailureMessage,tszDllInstall,lptDllName,hResult); - MessageBox(0,lptMsgBuffer,ModuleTitle,MB_ICONEXCLAMATION); - } - free(lptMsgBuffer); - } - if (hResult != S_OK) - nRetValue = EXITCODE_FAILURE; - } - else { - FreeLibrary(hDll); - if (!bSilent) { - // DllInstall was not found, display an error message - lptMsgBuffer = (LPTSTR)malloc((_tcslen(MissingEntry) - 8 + _tcslen(tszDllInstall) * 2 + _tcslen(lptDllName) * 2 + 1) * sizeof(TCHAR)); - _stprintf(lptMsgBuffer,MissingEntry,lptDllName,tszDllInstall,tszDllInstall,lptDllName); - MessageBox(0,lptMsgBuffer,ModuleTitle,MB_ICONEXCLAMATION); - free(lptMsgBuffer); - } - nRetValue = EXITCODE_NOENTRY; - } - } - - // The dll function has finished executing, so unload it - FreeLibrary(hDll); - } - else { - if (!bSilent) { - // The dll could not be loaded; display an error message - dwErr = GetLastError(); - lptMsgBuffer = (LPTSTR)malloc((_tcslen(DllNotLoaded) + 2 + _tcslen(lptDllName) + 1) * sizeof(TCHAR)); - _stprintf(lptMsgBuffer,DllNotLoaded,lptDllName,dwErr); - MessageBox(0,lptMsgBuffer,ModuleTitle,MB_ICONEXCLAMATION); - free(lptMsgBuffer); - } - nRetValue = EXITCODE_LOADERROR; - } - } - } - - if (lpwDllCmdLine) - FreeConvertedWideChar(lpwDllCmdLine); - GlobalFree(argv); - OleUninitialize(); - return nRetValue; -} - +/* + * ReactOS regsvr32 + * Copyright (C) 2004 ReactOS Team + * + * COPYRIGHT: See COPYING in the top level directory + * PROJECT: ReactOS regsvr32.exe + * FILE: apps/utils/regsvr32/regsvr32.c + * PURPOSE: Register a COM component in the registry + * PROGRAMMER: ShadowFlare (blakflare@hotmail.com) + */ + +#define WIN32_LEAN_AND_MEAN + +// Both UNICODE and _UNICODE must be either defined or undefined +// because some headers use UNICODE and others use _UNICODE +#ifdef UNICODE +#ifndef _UNICODE +#define _UNICODE +#endif +#else +#ifdef _UNICODE +#define UNICODE +#endif +#endif + +#include +#include +#include +#include +#include +#include + +typedef HRESULT (WINAPI *DLLREGISTER)(void); +typedef HRESULT (WINAPI *DLLINSTALL)(BOOL bInstall, LPWSTR lpwCmdLine); + +#define EXITCODE_SUCCESS 0 +#define EXITCODE_PARAMERROR 1 +#define EXITCODE_LOADERROR 3 +#define EXITCODE_NOENTRY 4 +#define EXITCODE_FAILURE 5 + +LPCSTR szDllRegister = "DllRegisterServer"; +LPCSTR szDllUnregister = "DllUnregisterServer"; +LPCSTR szDllInstall = "DllInstall"; +#ifdef UNICODE +LPCWSTR tszDllRegister = L"DllRegisterServer"; +LPCWSTR tszDllUnregister = L"DllUnregisterServer"; +LPCWSTR tszDllInstall = L"DllInstall"; +#else +#define tszDllRegister szDllRegister +#define tszDllUnregister szDllUnregister +#define tszDllInstall szDllInstall +#endif + +LPCTSTR ModuleTitle = _T("RegSvr32"); +LPCTSTR UsageMessage = + _T("%s\n\n") + _T("Usage: regsvr32 [/u] [/s] [/c] [/n] [/i[:cmdline]] dllname\n") + _T("/u - Unregister server\n") + _T("/s - Silent; display no message boxes\n") + _T("/c - Console output\n") + _T("/i - Call DllInstall passing it an optional [cmdline]; when used with /u calls dll uninstall\n") + _T("/n - Do not call DllRegisterServer; this option must be used with /i"); +LPCTSTR NoDllSpecified = _T("No DLL name specified."); +LPCTSTR InvalidFlag = _T("Unrecognized flag: %s"); +LPCTSTR SwitchN_NoI = _T("Unrecognized flag: /n must be used with the /i switch"); +LPCTSTR DllNotLoaded = + _T("LoadLibrary(\"%s\") failed.\n") + _T("GetLastError returns 0x%08x."); +LPCTSTR MissingEntry = + _T("%s was loaded, but the %s entry point was not found.\n\n") + _T("%s may not be exported, or a corrupt version of %s may be in memory. Consider using PView to detect and remove it."); +LPCTSTR FailureMessage = + _T("%s in %s failed.\n") + _T("Return code was: 0x%08x"); +LPCTSTR SuccessMessage = _T("%s in %s succeeded."); + +// The macro CommandLineToArgv maps to a function that converts +// a command-line string to argc and argv similar to the ones +// in the standard main function. If this code is compiled for +// unicode, the build-in Windows API function is used, otherwise +// a non-unicode non-API version is used for compatibility with +// Windows versions that have no unicode support. +#ifdef UNICODE +#define CommandLineToArgv CommandLineToArgvW +#include +#else +#define CommandLineToArgv CommandLineToArgvT + +LPTSTR *WINAPI CommandLineToArgvT(LPCTSTR lpCmdLine, int *lpArgc) +{ + HGLOBAL hargv; + LPTSTR *argv, lpSrc, lpDest, lpArg; + int argc, nBSlash; + BOOL bInQuotes; + + // If null was passed in for lpCmdLine, there are no arguments + if (!lpCmdLine) { + if (lpArgc) + *lpArgc = 0; + return 0; + } + + lpSrc = (LPTSTR)lpCmdLine; + // Skip spaces at beginning + while (*lpSrc == _T(' ') || *lpSrc == _T('\t')) + lpSrc++; + + // If command-line starts with null, there are no arguments + if (*lpSrc == 0) { + if (lpArgc) + *lpArgc = 0; + return 0; + } + + lpArg = lpSrc; + argc = 0; + nBSlash = 0; + bInQuotes = FALSE; + + // Count the number of arguments + while (1) { + if (*lpSrc == 0 || ((*lpSrc == _T(' ') || *lpSrc == _T('\t')) && !bInQuotes)) { + // Whitespace not enclosed in quotes signals the start of another argument + argc++; + + // Skip whitespace between arguments + while (*lpSrc == _T(' ') || *lpSrc == _T('\t')) + lpSrc++; + if (*lpSrc == 0) + break; + nBSlash = 0; + continue; + } + else if (*lpSrc == _T('\\')) { + // Count consecutive backslashes + nBSlash++; + } + else if (*lpSrc == _T('\"') && !(nBSlash & 1)) { + // Open or close quotes + bInQuotes = !bInQuotes; + nBSlash = 0; + } + else { + // Some other character + nBSlash = 0; + } + lpSrc++; + } + + // Allocate space the same way as CommandLineToArgvW for compatibility + hargv = GlobalAlloc(0, argc * sizeof(LPTSTR) + (_tcslen(lpArg) + 1) * sizeof(TCHAR)); + argv = (LPTSTR *)GlobalLock(hargv); + + if (!argv) { + // Memory allocation failed + if (lpArgc) + *lpArgc = 0; + return 0; + } + + lpSrc = lpArg; + lpDest = lpArg = (LPTSTR)(argv + argc); + argc = 0; + nBSlash = 0; + bInQuotes = FALSE; + + // Fill the argument array + while (1) { + if (*lpSrc == 0 || ((*lpSrc == _T(' ') || *lpSrc == _T('\t')) && !bInQuotes)) { + // Whitespace not enclosed in quotes signals the start of another argument + // Null-terminate argument + *lpDest++ = 0; + argv[argc++] = lpArg; + + // Skip whitespace between arguments + while (*lpSrc == _T(' ') || *lpSrc == _T('\t')) + lpSrc++; + if (*lpSrc == 0) + break; + lpArg = lpDest; + nBSlash = 0; + continue; + } + else if (*lpSrc == _T('\\')) { + *lpDest++ = _T('\\'); + lpSrc++; + + // Count consecutive backslashes + nBSlash++; + } + else if (*lpSrc == _T('\"')) { + if (!(nBSlash & 1)) { + // If an even number of backslashes are before the quotes, + // the quotes don't go in the output + lpDest -= nBSlash / 2; + bInQuotes = !bInQuotes; + } + else { + // If an odd number of backslashes are before the quotes, + // output a quote + lpDest -= (nBSlash + 1) / 2; + *lpDest++ = _T('\"'); + } + lpSrc++; + nBSlash = 0; + } + else { + // Copy other characters + *lpDest++ = *lpSrc++; + nBSlash = 0; + } + } + + if (lpArgc) + *lpArgc = argc; + return argv; +} + +#endif + +// The macro ConvertToWideChar takes a tstring parameter and returns +// a pointer to a unicode string. A conversion is performed if +// neccessary. FreeConvertedWideChar string should be used on the +// return value of ConvertToWideChar when the string is no longer +// needed. The original string or the string that is returned +// should not be modified until FreeConvertedWideChar has been called. +#ifdef UNICODE +#define ConvertToWideChar(lptString) (lptString) +#define FreeConvertedWideChar(lpwString) +#else + +LPWSTR ConvertToWideChar(LPCSTR lpString) +{ + LPWSTR lpwString; + size_t nStrLen; + + nStrLen = strlen(lpString) + 1; + + lpwString = (LPWSTR)malloc(nStrLen * sizeof(WCHAR)); + MultiByteToWideChar(0,0,lpString,nStrLen,lpwString,nStrLen); + + return lpwString; +} + +#define FreeConvertedWideChar(lpwString) free(lpwString) +#endif + +void DisplayMessage(BOOL bConsole, BOOL bSilent, LPCTSTR lpMessage, LPCTSTR lpTitle, UINT uType) +{ + if (!bSilent) + MessageBox(0,lpMessage,lpTitle,uType); + if (bConsole) + _tprintf(_T("%s: %s\n\n"),lpTitle,lpMessage); +} + +int WINAPI WinMain( + HINSTANCE hInstance, + HINSTANCE hPrevInstance, + LPSTR lpCmdLineA, + int nCmdShow +) +{ + int argc; + LPTSTR *argv; + LPTSTR lptDllName,lptDllCmdLine,lptMsgBuffer; + LPCTSTR lptFuncName; + LPCSTR lpFuncName; + LPWSTR lpwDllCmdLine; + BOOL bUnregister,bSilent,bConsole,bInstall,bNoRegister; + UINT nDllCount; + HMODULE hDll; + DLLREGISTER fnDllRegister; + DLLINSTALL fnDllInstall; + HRESULT hResult; + DWORD dwErr; + int nRetValue,i; + + // Get command-line in argc-argv format + argv = CommandLineToArgv(GetCommandLine(),&argc); + + // Initialize variables + lptFuncName = 0; + lptDllCmdLine = 0; + nDllCount = 0; + bUnregister = FALSE; + bSilent = FALSE; + bConsole = FALSE; + bInstall = FALSE; + bNoRegister = FALSE; + + // Find all arguments starting with a slash (/) + for (i = 1; i < argc; i++) { + if (*argv[i] == _T('/')) { + switch (argv[i][1]) { + case _T('u'): + case _T('U'): + bUnregister = TRUE; + break; + case _T('s'): + case _T('S'): + bSilent = TRUE; + break; + case _T('c'): + case _T('C'): + bConsole = TRUE; + break; + case _T('i'): + case _T('I'): + bInstall = TRUE; + lptDllCmdLine = argv[i]; + while (*lptDllCmdLine != 0 && *lptDllCmdLine != _T(':')) + lptDllCmdLine++; + if (*lptDllCmdLine == _T(':')) + lptDllCmdLine++; + break; + case _T('n'): + case _T('N'): + bNoRegister = TRUE; + break; + default: + if (!lptFuncName) + lptFuncName = argv[i]; + } + } + else { + nDllCount++; + } + } + + // An unrecognized flag was used, display a message and show available options + if (lptFuncName) { + lptMsgBuffer = (LPTSTR)malloc((_tcslen(UsageMessage) - 2 + _tcslen(InvalidFlag) - 2 + _tcslen(lptFuncName) + 1) * sizeof(TCHAR)); + _stprintf(lptMsgBuffer + (_tcslen(UsageMessage) - 2),InvalidFlag,lptFuncName); + _stprintf(lptMsgBuffer,UsageMessage,lptMsgBuffer + (_tcslen(UsageMessage) - 2)); + DisplayMessage(bConsole,bSilent,lptMsgBuffer,ModuleTitle,MB_ICONEXCLAMATION); + free(lptMsgBuffer); + GlobalFree(argv); + return EXITCODE_PARAMERROR; + } + + // /n was used without /i, display a message and show available options + if (bNoRegister && (!bInstall)) { + lptMsgBuffer = (LPTSTR)malloc((_tcslen(UsageMessage) - 2 + _tcslen(SwitchN_NoI) + 1) * sizeof(TCHAR)); + _stprintf(lptMsgBuffer,UsageMessage,SwitchN_NoI); + DisplayMessage(bConsole,bSilent,lptMsgBuffer,ModuleTitle,MB_ICONEXCLAMATION); + free(lptMsgBuffer); + GlobalFree(argv); + return EXITCODE_PARAMERROR; + } + + // No dll was specified, display a message and show available options + if (nDllCount == 0) { + lptMsgBuffer = (LPTSTR)malloc((_tcslen(UsageMessage) - 2 + _tcslen(NoDllSpecified) + 1) * sizeof(TCHAR)); + _stprintf(lptMsgBuffer,UsageMessage,NoDllSpecified); + DisplayMessage(bConsole,bSilent,lptMsgBuffer,ModuleTitle,MB_ICONEXCLAMATION); + free(lptMsgBuffer); + GlobalFree(argv); + return EXITCODE_PARAMERROR; + } + + nRetValue = EXITCODE_SUCCESS; + if (!bUnregister) { + lpFuncName = szDllRegister; + lptFuncName = tszDllRegister; + } + else { + lpFuncName = szDllUnregister; + lptFuncName = tszDllUnregister; + } + + if (lptDllCmdLine) + lpwDllCmdLine = ConvertToWideChar(lptDllCmdLine); + else + lpwDllCmdLine = 0; + + // Initialize OLE32 before attempting to register the + // dll. Some dll's require this to register properly + OleInitialize(0); + + // (Un)register every dll whose filename was passed in the command-line string + for (i = 1; i < argc; i++) { + // Arguments that do not start with a slash (/) are filenames + if (*argv[i] != _T('/')) { + lptDllName = argv[i]; + + // Everything is all setup, so load the dll now + hDll = LoadLibraryEx(lptDllName,0,LOAD_WITH_ALTERED_SEARCH_PATH); + if (hDll) { + if (!bNoRegister) { + // Get the address of DllRegisterServer or DllUnregisterServer + fnDllRegister = (DLLREGISTER)GetProcAddress(hDll,lpFuncName); + if (fnDllRegister) { + // If the function exists, call it + hResult = fnDllRegister(); + if (hResult == S_OK) { + // (Un)register succeeded, display a message + lptMsgBuffer = (LPTSTR)malloc((_tcslen(SuccessMessage) - 4 + _tcslen(lptFuncName) + _tcslen(lptDllName) + 1) * sizeof(TCHAR)); + _stprintf(lptMsgBuffer,SuccessMessage,lptFuncName,lptDllName); + DisplayMessage(bConsole,bSilent,lptMsgBuffer,ModuleTitle,MB_ICONINFORMATION); + } + else { + // (Un)register failed, display a message + lptMsgBuffer = (LPTSTR)malloc((_tcslen(FailureMessage) + _tcslen(lptFuncName) + _tcslen(lptDllName) + 1) * sizeof(TCHAR)); + _stprintf(lptMsgBuffer,FailureMessage,lptFuncName,lptDllName,hResult); + DisplayMessage(bConsole,bSilent,lptMsgBuffer,ModuleTitle,MB_ICONEXCLAMATION); + } + free(lptMsgBuffer); + if (hResult != S_OK) + nRetValue = EXITCODE_FAILURE; + } + else { + FreeLibrary(hDll); + // Dll(Un)register was not found, display an error message + lptMsgBuffer = (LPTSTR)malloc((_tcslen(MissingEntry) - 8 + _tcslen(lptFuncName) * 2 + _tcslen(lptDllName) * 2 + 1) * sizeof(TCHAR)); + _stprintf(lptMsgBuffer,MissingEntry,lptDllName,lptFuncName,lptFuncName,lptDllName); + DisplayMessage(bConsole,bSilent,lptMsgBuffer,ModuleTitle,MB_ICONEXCLAMATION); + free(lptMsgBuffer); + nRetValue = EXITCODE_NOENTRY; + } + } + + if (bInstall) { + // Get the address of DllInstall + fnDllInstall = (DLLINSTALL)GetProcAddress(hDll,szDllInstall); + if (fnDllInstall) { + // If the function exists, call it + if (!bUnregister) + hResult = fnDllInstall(1,lpwDllCmdLine); + else + hResult = fnDllInstall(0,lpwDllCmdLine); + if (hResult == S_OK) { + // (Un)install succeeded, display a message + lptMsgBuffer = (LPTSTR)malloc((_tcslen(SuccessMessage) - 4 + _tcslen(tszDllInstall) + _tcslen(lptDllName) + 1) * sizeof(TCHAR)); + _stprintf(lptMsgBuffer,SuccessMessage,tszDllInstall,lptDllName); + DisplayMessage(bConsole,bSilent,lptMsgBuffer,ModuleTitle,MB_ICONINFORMATION); + } + else { + // (Un)install failed, display a message + lptMsgBuffer = (LPTSTR)malloc((_tcslen(FailureMessage) + _tcslen(tszDllInstall) + _tcslen(lptDllName) + 1) * sizeof(TCHAR)); + _stprintf(lptMsgBuffer,FailureMessage,tszDllInstall,lptDllName,hResult); + DisplayMessage(bConsole,bSilent,lptMsgBuffer,ModuleTitle,MB_ICONEXCLAMATION); + } + free(lptMsgBuffer); + if (hResult != S_OK) + nRetValue = EXITCODE_FAILURE; + } + else { + FreeLibrary(hDll); + // DllInstall was not found, display an error message + lptMsgBuffer = (LPTSTR)malloc((_tcslen(MissingEntry) - 8 + _tcslen(tszDllInstall) * 2 + _tcslen(lptDllName) * 2 + 1) * sizeof(TCHAR)); + _stprintf(lptMsgBuffer,MissingEntry,lptDllName,tszDllInstall,tszDllInstall,lptDllName); + DisplayMessage(bConsole,bSilent,lptMsgBuffer,ModuleTitle,MB_ICONEXCLAMATION); + free(lptMsgBuffer); + nRetValue = EXITCODE_NOENTRY; + } + } + + // The dll function has finished executing, so unload it + FreeLibrary(hDll); + } + else { + // The dll could not be loaded; display an error message + dwErr = GetLastError(); + lptMsgBuffer = (LPTSTR)malloc((_tcslen(DllNotLoaded) + 2 + _tcslen(lptDllName) + 1) * sizeof(TCHAR)); + _stprintf(lptMsgBuffer,DllNotLoaded,lptDllName,dwErr); + DisplayMessage(bConsole,bSilent,lptMsgBuffer,ModuleTitle,MB_ICONEXCLAMATION); + free(lptMsgBuffer); + nRetValue = EXITCODE_LOADERROR; + } + } + } + + if (lpwDllCmdLine) + FreeConvertedWideChar(lpwDllCmdLine); + GlobalFree(argv); + OleUninitialize(); + return nRetValue; +} + diff --git a/reactos/apps/utils/rundll32/rundll32.c b/reactos/apps/utils/rundll32/rundll32.c index cf7f99edf87..560e60b30d4 100644 --- a/reactos/apps/utils/rundll32/rundll32.c +++ b/reactos/apps/utils/rundll32/rundll32.c @@ -1,467 +1,467 @@ -/* - * ReactOS rundll32 - * Copyright (C) 2003-2004 ReactOS Team - * - * COPYRIGHT: See COPYING in the top level directory - * PROJECT: ReactOS rundll32.exe - * FILE: apps/utils/rundll32/rundll32.c - * PURPOSE: Run a DLL as a program - * PROGRAMMER: ShadowFlare (blakflare@hotmail.com) - */ - -#define WIN32_LEAN_AND_MEAN - -// Both UNICODE and _UNICODE must be either defined or undefined -// because some headers use UNICODE and others use _UNICODE -#ifdef UNICODE -#ifndef _UNICODE -#define _UNICODE -#endif -#else -#ifdef _UNICODE -#define UNICODE -#endif -#endif - -#include -#include -#include -#include -#include - -typedef int (WINAPI *DllWinMainW)( - HWND hWnd, - HINSTANCE hInstance, - LPWSTR lpwCmdLine, - int nCmdShow -); -typedef int (WINAPI *DllWinMainA)( - HWND hWnd, - HINSTANCE hInstance, - LPSTR lpCmdLine, - int nCmdShow -); - -LPCTSTR DllNotLoaded = _T("LoadLibrary failed to load \"%s\""); -LPCTSTR MissingEntry = _T("Missing entry point:%s\nIn %s"); -LPCTSTR rundll32_wtitle = _T("rundll32"); -LPCTSTR rundll32_wclass = _T("rundll32_window"); -TCHAR ModuleFileName[MAX_PATH+1]; -LPTSTR ModuleTitle; - -// CommandLineToArgv converts a command-line string to argc and -// argv similar to the ones in the standard main function. -// This is a specialized version coded specifically for rundll32 -// and is not intended to be used in any other program. -LPTSTR *WINAPI CommandLineToArgv(LPCTSTR lpCmdLine, int *lpArgc) -{ - LPTSTR *argv, lpSrc, lpDest, lpArg; - int argc, nBSlash, nNames; - BOOL bInQuotes, bFirstChar; - - // If null was passed in for lpCmdLine, there are no arguments - if (!lpCmdLine) { - if (lpArgc) - *lpArgc = 0; - return 0; - } - - lpSrc = (LPTSTR)lpCmdLine; - // Skip spaces at beginning - while (*lpSrc == _T(' ') || *lpSrc == _T('\t')) - lpSrc++; - - // If command-line starts with null, there are no arguments - if (*lpSrc == 0) { - if (lpArgc) - *lpArgc = 0; - return 0; - } - - lpArg = lpSrc; - argc = 0; - nBSlash = 0; - bInQuotes = FALSE; - bFirstChar = TRUE; - nNames = 0; - - // Count the number of arguments - while (nNames < 4) { - if (*lpSrc == 0 || (*lpSrc == _T(',') && nNames == 2) || ((*lpSrc == _T(' ') || *lpSrc == _T('\t')) && !bInQuotes)) { - // Whitespace not enclosed in quotes signals the start of another argument - argc++; - - // Skip whitespace between arguments - while (*lpSrc == _T(' ') || *lpSrc == _T('\t') || (*lpSrc == _T(',') && nNames == 2)) - lpSrc++; - if (*lpSrc == 0) - break; - if (nNames >= 3) { - // Increment the count for the last argument - argc++; - break; - } - nBSlash = 0; - bFirstChar = TRUE; - continue; - } - else if (*lpSrc == _T('\\')) { - // Count consecutive backslashes - nBSlash++; - bFirstChar = FALSE; - } - else if (*lpSrc == _T('\"') && !(nBSlash & 1)) { - // Open or close quotes - bInQuotes = !bInQuotes; - nBSlash = 0; - } - else { - // Some other character - nBSlash = 0; - if (bFirstChar && ((*lpSrc != _T('/') && nNames <= 1) || nNames > 1)) - nNames++; - bFirstChar = FALSE; - } - lpSrc++; - } - - // Allocate space for the pointers in argv and the strings in one block - argv = (LPTSTR *)malloc(argc * sizeof(LPTSTR) + (_tcslen(lpArg) + 1) * sizeof(TCHAR)); - - if (!argv) { - // Memory allocation failed - if (lpArgc) - *lpArgc = 0; - return 0; - } - - lpSrc = lpArg; - lpDest = lpArg = (LPTSTR)(argv + argc); - argc = 0; - nBSlash = 0; - bInQuotes = FALSE; - bFirstChar = TRUE; - nNames = 0; - - // Fill the argument array - while (nNames < 4) { - if (*lpSrc == 0 || (*lpSrc == _T(',') && nNames == 2) || ((*lpSrc == _T(' ') || *lpSrc == _T('\t')) && !bInQuotes)) { - // Whitespace not enclosed in quotes signals the start of another argument - // Null-terminate argument - *lpDest++ = 0; - argv[argc++] = lpArg; - - // Skip whitespace between arguments - while (*lpSrc == _T(' ') || *lpSrc == _T('\t') || (*lpSrc == _T(',') && nNames == 2)) - lpSrc++; - if (*lpSrc == 0) - break; - lpArg = lpDest; - if (nNames >= 3) { - // Copy the rest of the command-line to the last argument - argv[argc++] = lpArg; - _tcscpy(lpArg,lpSrc); - break; - } - nBSlash = 0; - bFirstChar = TRUE; - continue; - } - else if (*lpSrc == _T('\\')) { - *lpDest++ = _T('\\'); - lpSrc++; - - // Count consecutive backslashes - nBSlash++; - bFirstChar = FALSE; - } - else if (*lpSrc == _T('\"')) { - if (!(nBSlash & 1)) { - // If an even number of backslashes are before the quotes, - // the quotes don't go in the output - lpDest -= nBSlash / 2; - bInQuotes = !bInQuotes; - } - else { - // If an odd number of backslashes are before the quotes, - // output a quote - lpDest -= (nBSlash + 1) / 2; - *lpDest++ = _T('\"'); - bFirstChar = FALSE; - } - lpSrc++; - nBSlash = 0; - } - else { - // Copy other characters - if (bFirstChar && ((*lpSrc != _T('/') && nNames <= 1) || nNames > 1)) - nNames++; - *lpDest++ = *lpSrc++; - nBSlash = 0; - bFirstChar = FALSE; - } - } - - if (lpArgc) - *lpArgc = argc; - return argv; -} - -void GetModuleTitle(void) -{ - LPTSTR lpStr; - - GetModuleFileName(0,ModuleFileName,MAX_PATH); - ModuleTitle = ModuleFileName; - - for (lpStr = ModuleFileName;*lpStr;lpStr++) { - if (*lpStr == _T('\\')) - ModuleTitle = lpStr+1; - } - - for (lpStr = ModuleTitle;*lpStr;lpStr++) { - if (_tcsicmp(lpStr,_T(".exe"))==0) - break; - } - - *lpStr = 0; -} - -// The macro ConvertToWideChar takes a tstring parameter and returns -// a pointer to a unicode string. A conversion is performed if -// neccessary. FreeConvertedWideChar string should be used on the -// return value of ConvertToWideChar when the string is no longer -// needed. The original string or the string that is returned -// should not be modified until FreeConvertedWideChar has been called. -#ifdef UNICODE -#define ConvertToWideChar(lptString) (lptString) -#define FreeConvertedWideChar(lpwString) -#else - -LPWSTR ConvertToWideChar(LPCSTR lpString) -{ - LPWSTR lpwString; - size_t nStrLen; - - nStrLen = strlen(lpString) + 1; - - lpwString = (LPWSTR)malloc(nStrLen * sizeof(WCHAR)); - MultiByteToWideChar(0,0,lpString,nStrLen,lpwString,nStrLen); - - return lpwString; -} - -#define FreeConvertedWideChar(lpwString) free(lpwString) -#endif - -// The macro ConvertToMultiByte takes a tstring parameter and returns -// a pointer to an ansi string. A conversion is performed if -// neccessary. FreeConvertedMultiByte string should be used on the -// return value of ConvertToMultiByte when the string is no longer -// needed. The original string or the string that is returned -// should not be modified until FreeConvertedMultiByte has been called. -#ifdef UNICODE -#define ConvertToMultiByte(lptString) DuplicateToMultiByte(lptString,0) -#define FreeConvertedMultiByte(lpaString) free(lpaString) -#else -#define ConvertToMultiByte(lptString) (lptString) -#define FreeConvertedMultiByte(lpaString) -#endif - -// DuplicateToMultiByte takes a tstring parameter and always returns -// a pointer to a duplicate ansi string. If nBufferSize is zero, -// the buffer length is the exact size of the string plus the -// terminating null. If nBufferSize is nonzero, the buffer length -// is equal to nBufferSize. As with strdup, free should be called -// for the returned string when it is no longer needed. -LPSTR DuplicateToMultiByte(LPCTSTR lptString, size_t nBufferSize) -{ - LPSTR lpString; - size_t nStrLen; - - nStrLen = _tcslen(lptString) + 1; - if (nBufferSize == 0) nBufferSize = nStrLen; - - lpString = (LPSTR)malloc(nBufferSize); -#ifdef UNICODE - WideCharToMultiByte(0,0,lptString,nStrLen,lpString,nBufferSize,0,0); -#else - strncpy(lpString,lptString,nBufferSize); -#endif - - return lpString; -} - -LRESULT CALLBACK EmptyWindowProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) -{ - return DefWindowProc(hWnd, uMsg, wParam, lParam); -} - -// Registers a minimal window class for passing to the dll function -ATOM RegisterBlankClass(HINSTANCE hInstance) -{ - WNDCLASSEX wcex; - - wcex.cbSize = sizeof(WNDCLASSEX); - - wcex.style = 0; - wcex.lpfnWndProc = EmptyWindowProc; - wcex.cbClsExtra = 0; - wcex.cbWndExtra = 0; - wcex.hInstance = hInstance; - wcex.hIcon = 0; - wcex.hCursor = 0; - wcex.hbrBackground = 0; - wcex.lpszMenuName = 0; - wcex.lpszClassName = rundll32_wclass; - wcex.hIconSm = 0; - - return RegisterClassEx(&wcex); -} - -int WINAPI WinMain( - HINSTANCE hInstance, - HINSTANCE hPrevInstance, - LPSTR lpCmdLineA, - int nCmdShow -) -{ - int argc; - LPTSTR *argv; - LPTSTR lptCmdLine,lptDllName,lptFuncName,lptMsgBuffer; - LPSTR lpFuncName,lpaCmdLine; - LPWSTR lpwCmdLine; - HMODULE hDll; - DllWinMainW fnDllWinMainW; - DllWinMainA fnDllWinMainA; - HWND hWindow; - int nRetVal,i; - size_t nStrLen; - - // Get command-line in argc-argv format - argv = CommandLineToArgv(GetCommandLine(),&argc); - - // Skip all beginning arguments starting with a slash (/) - for (i = 1; i < argc; i++) - if (*argv[i] != _T('/')) break; - - // If no dll was specified, there is nothing to do - if (i >= argc) { - if (argv) free(argv); - return 0; - } - - lptDllName = argv[i++]; - - // The next argument, which specifies the name of the dll function, - // can either have a comma between it and the dll filename or a space. - // Using a comma here is the preferred method - if (i < argc) - lptFuncName = argv[i++]; - else - lptFuncName = _T(""); - - // If no function name was specified, nothing needs to be done - if (!*lptFuncName) { - if (argv) free(argv); - return 0; - } - - // The rest of the arguments will be passed to dll function - if (i < argc) - lptCmdLine = argv[i]; - else - lptCmdLine = _T(""); - - nRetVal = 0; - - // Everything is all setup, so load the dll now - hDll = LoadLibrary(lptDllName); - if (hDll) { - nStrLen = _tcslen(lptFuncName); - // Make a non-unicode version of the function name, - // since that is all GetProcAddress accepts - lpFuncName = DuplicateToMultiByte(lptFuncName,nStrLen + 2); - -#ifdef UNICODE - lpFuncName[nStrLen] = 'W'; - lpFuncName[nStrLen+1] = 0; - // Get address of unicode version of the dll function if it exists - fnDllWinMainW = (DllWinMainW)GetProcAddress(hDll,lpFuncName); - fnDllWinMainA = 0; - if (!fnDllWinMainW) { - // If no unicode function was found, get the address of the non-unicode function - lpFuncName[nStrLen] = 'A'; - fnDllWinMainA = (DllWinMainA)GetProcAddress(hDll,lpFuncName); - if (!fnDllWinMainA) { - // If first non-unicode function was not found, get the address - // of the other non-unicode function - lpFuncName[nStrLen] = 0; - fnDllWinMainA = (DllWinMainA)GetProcAddress(hDll,lpFuncName); - } - } -#else - // Get address of non-unicode version of the dll function if it exists - fnDllWinMainA = (DllWinMainA)GetProcAddress(hDll,lpFuncName); - fnDllWinMainW = 0; - if (!fnDllWinMainA) { - // If first non-unicode function was not found, get the address - // of the other non-unicode function - lpFuncName[nStrLen] = 'A'; - lpFuncName[nStrLen+1] = 0; - fnDllWinMainA = (DllWinMainA)GetProcAddress(hDll,lpFuncName); - if (!fnDllWinMainA) { - // If non-unicode function was not found, get the address of the unicode function - lpFuncName[nStrLen] = 'W'; - fnDllWinMainW = (DllWinMainW)GetProcAddress(hDll,lpFuncName); - } - } -#endif - - free(lpFuncName); - - RegisterBlankClass(hInstance); - // Create a window so we can pass a window handle to - // the dll function; this is required - hWindow = CreateWindowEx(0,rundll32_wclass,rundll32_wtitle,0,CW_USEDEFAULT,0,CW_USEDEFAULT,0,0,0,hInstance,0); - - if (fnDllWinMainW) { - // Convert the command-line string to unicode and call the dll function - lpwCmdLine = ConvertToWideChar(lptCmdLine); - nRetVal = fnDllWinMainW(hWindow,hInstance,lpwCmdLine,nCmdShow); - FreeConvertedWideChar(lpwCmdLine); - } - else if (fnDllWinMainA) { - // Convert the command-line string to ansi and call the dll function - lpaCmdLine = ConvertToMultiByte(lptCmdLine); - nRetVal = fnDllWinMainA(hWindow,hInstance,lpaCmdLine,nCmdShow); - FreeConvertedMultiByte(lpaCmdLine); - } - else { - // The specified dll function was not found; display an error message - GetModuleTitle(); - lptMsgBuffer = (LPTSTR)malloc((_tcslen(MissingEntry) - 4 + _tcslen(lptFuncName) + _tcslen(lptDllName) + 1) * sizeof(TCHAR)); - _stprintf(lptMsgBuffer,MissingEntry,lptFuncName,lptDllName); - MessageBox(0,lptMsgBuffer,ModuleTitle,MB_ICONERROR); - free(lptMsgBuffer); - } - - DestroyWindow(hWindow); - UnregisterClass(rundll32_wclass,hInstance); - - // The dll function has finished executing, so unload it - FreeLibrary(hDll); - } - else { - // The dll could not be loaded; display an error message - GetModuleTitle(); - lptMsgBuffer = (LPTSTR)malloc((_tcslen(DllNotLoaded) - 2 + _tcslen(lptDllName) + 1) * sizeof(TCHAR)); - _stprintf(lptMsgBuffer,DllNotLoaded,lptDllName); - MessageBox(0,lptMsgBuffer,ModuleTitle,MB_ICONERROR); - free(lptMsgBuffer); - } - - if (argv) free(argv); - return nRetVal; -} - +/* + * ReactOS rundll32 + * Copyright (C) 2003-2004 ReactOS Team + * + * COPYRIGHT: See COPYING in the top level directory + * PROJECT: ReactOS rundll32.exe + * FILE: apps/utils/rundll32/rundll32.c + * PURPOSE: Run a DLL as a program + * PROGRAMMER: ShadowFlare (blakflare@hotmail.com) + */ + +#define WIN32_LEAN_AND_MEAN + +// Both UNICODE and _UNICODE must be either defined or undefined +// because some headers use UNICODE and others use _UNICODE +#ifdef UNICODE +#ifndef _UNICODE +#define _UNICODE +#endif +#else +#ifdef _UNICODE +#define UNICODE +#endif +#endif + +#include +#include +#include +#include +#include + +typedef int (WINAPI *DllWinMainW)( + HWND hWnd, + HINSTANCE hInstance, + LPWSTR lpwCmdLine, + int nCmdShow +); +typedef int (WINAPI *DllWinMainA)( + HWND hWnd, + HINSTANCE hInstance, + LPSTR lpCmdLine, + int nCmdShow +); + +LPCTSTR DllNotLoaded = _T("LoadLibrary failed to load \"%s\""); +LPCTSTR MissingEntry = _T("Missing entry point:%s\nIn %s"); +LPCTSTR rundll32_wtitle = _T("rundll32"); +LPCTSTR rundll32_wclass = _T("rundll32_window"); +TCHAR ModuleFileName[MAX_PATH+1]; +LPTSTR ModuleTitle; + +// CommandLineToArgv converts a command-line string to argc and +// argv similar to the ones in the standard main function. +// This is a specialized version coded specifically for rundll32 +// and is not intended to be used in any other program. +LPTSTR *WINAPI CommandLineToArgv(LPCTSTR lpCmdLine, int *lpArgc) +{ + LPTSTR *argv, lpSrc, lpDest, lpArg; + int argc, nBSlash, nNames; + BOOL bInQuotes, bFirstChar; + + // If null was passed in for lpCmdLine, there are no arguments + if (!lpCmdLine) { + if (lpArgc) + *lpArgc = 0; + return 0; + } + + lpSrc = (LPTSTR)lpCmdLine; + // Skip spaces at beginning + while (*lpSrc == _T(' ') || *lpSrc == _T('\t')) + lpSrc++; + + // If command-line starts with null, there are no arguments + if (*lpSrc == 0) { + if (lpArgc) + *lpArgc = 0; + return 0; + } + + lpArg = lpSrc; + argc = 0; + nBSlash = 0; + bInQuotes = FALSE; + bFirstChar = TRUE; + nNames = 0; + + // Count the number of arguments + while (nNames < 4) { + if (*lpSrc == 0 || (*lpSrc == _T(',') && nNames == 2) || ((*lpSrc == _T(' ') || *lpSrc == _T('\t')) && !bInQuotes)) { + // Whitespace not enclosed in quotes signals the start of another argument + argc++; + + // Skip whitespace between arguments + while (*lpSrc == _T(' ') || *lpSrc == _T('\t') || (*lpSrc == _T(',') && nNames == 2)) + lpSrc++; + if (*lpSrc == 0) + break; + if (nNames >= 3) { + // Increment the count for the last argument + argc++; + break; + } + nBSlash = 0; + bFirstChar = TRUE; + continue; + } + else if (*lpSrc == _T('\\')) { + // Count consecutive backslashes + nBSlash++; + bFirstChar = FALSE; + } + else if (*lpSrc == _T('\"') && !(nBSlash & 1)) { + // Open or close quotes + bInQuotes = !bInQuotes; + nBSlash = 0; + } + else { + // Some other character + nBSlash = 0; + if (bFirstChar && ((*lpSrc != _T('/') && nNames <= 1) || nNames > 1)) + nNames++; + bFirstChar = FALSE; + } + lpSrc++; + } + + // Allocate space for the pointers in argv and the strings in one block + argv = (LPTSTR *)malloc(argc * sizeof(LPTSTR) + (_tcslen(lpArg) + 1) * sizeof(TCHAR)); + + if (!argv) { + // Memory allocation failed + if (lpArgc) + *lpArgc = 0; + return 0; + } + + lpSrc = lpArg; + lpDest = lpArg = (LPTSTR)(argv + argc); + argc = 0; + nBSlash = 0; + bInQuotes = FALSE; + bFirstChar = TRUE; + nNames = 0; + + // Fill the argument array + while (nNames < 4) { + if (*lpSrc == 0 || (*lpSrc == _T(',') && nNames == 2) || ((*lpSrc == _T(' ') || *lpSrc == _T('\t')) && !bInQuotes)) { + // Whitespace not enclosed in quotes signals the start of another argument + // Null-terminate argument + *lpDest++ = 0; + argv[argc++] = lpArg; + + // Skip whitespace between arguments + while (*lpSrc == _T(' ') || *lpSrc == _T('\t') || (*lpSrc == _T(',') && nNames == 2)) + lpSrc++; + if (*lpSrc == 0) + break; + lpArg = lpDest; + if (nNames >= 3) { + // Copy the rest of the command-line to the last argument + argv[argc++] = lpArg; + _tcscpy(lpArg,lpSrc); + break; + } + nBSlash = 0; + bFirstChar = TRUE; + continue; + } + else if (*lpSrc == _T('\\')) { + *lpDest++ = _T('\\'); + lpSrc++; + + // Count consecutive backslashes + nBSlash++; + bFirstChar = FALSE; + } + else if (*lpSrc == _T('\"')) { + if (!(nBSlash & 1)) { + // If an even number of backslashes are before the quotes, + // the quotes don't go in the output + lpDest -= nBSlash / 2; + bInQuotes = !bInQuotes; + } + else { + // If an odd number of backslashes are before the quotes, + // output a quote + lpDest -= (nBSlash + 1) / 2; + *lpDest++ = _T('\"'); + bFirstChar = FALSE; + } + lpSrc++; + nBSlash = 0; + } + else { + // Copy other characters + if (bFirstChar && ((*lpSrc != _T('/') && nNames <= 1) || nNames > 1)) + nNames++; + *lpDest++ = *lpSrc++; + nBSlash = 0; + bFirstChar = FALSE; + } + } + + if (lpArgc) + *lpArgc = argc; + return argv; +} + +void GetModuleTitle(void) +{ + LPTSTR lpStr; + + GetModuleFileName(0,ModuleFileName,MAX_PATH); + ModuleTitle = ModuleFileName; + + for (lpStr = ModuleFileName;*lpStr;lpStr++) { + if (*lpStr == _T('\\')) + ModuleTitle = lpStr+1; + } + + for (lpStr = ModuleTitle;*lpStr;lpStr++) { + if (_tcsicmp(lpStr,_T(".exe"))==0) + break; + } + + *lpStr = 0; +} + +// The macro ConvertToWideChar takes a tstring parameter and returns +// a pointer to a unicode string. A conversion is performed if +// neccessary. FreeConvertedWideChar string should be used on the +// return value of ConvertToWideChar when the string is no longer +// needed. The original string or the string that is returned +// should not be modified until FreeConvertedWideChar has been called. +#ifdef UNICODE +#define ConvertToWideChar(lptString) (lptString) +#define FreeConvertedWideChar(lpwString) +#else + +LPWSTR ConvertToWideChar(LPCSTR lpString) +{ + LPWSTR lpwString; + size_t nStrLen; + + nStrLen = strlen(lpString) + 1; + + lpwString = (LPWSTR)malloc(nStrLen * sizeof(WCHAR)); + MultiByteToWideChar(0,0,lpString,nStrLen,lpwString,nStrLen); + + return lpwString; +} + +#define FreeConvertedWideChar(lpwString) free(lpwString) +#endif + +// The macro ConvertToMultiByte takes a tstring parameter and returns +// a pointer to an ansi string. A conversion is performed if +// neccessary. FreeConvertedMultiByte string should be used on the +// return value of ConvertToMultiByte when the string is no longer +// needed. The original string or the string that is returned +// should not be modified until FreeConvertedMultiByte has been called. +#ifdef UNICODE +#define ConvertToMultiByte(lptString) DuplicateToMultiByte(lptString,0) +#define FreeConvertedMultiByte(lpaString) free(lpaString) +#else +#define ConvertToMultiByte(lptString) (lptString) +#define FreeConvertedMultiByte(lpaString) +#endif + +// DuplicateToMultiByte takes a tstring parameter and always returns +// a pointer to a duplicate ansi string. If nBufferSize is zero, +// the buffer length is the exact size of the string plus the +// terminating null. If nBufferSize is nonzero, the buffer length +// is equal to nBufferSize. As with strdup, free should be called +// for the returned string when it is no longer needed. +LPSTR DuplicateToMultiByte(LPCTSTR lptString, size_t nBufferSize) +{ + LPSTR lpString; + size_t nStrLen; + + nStrLen = _tcslen(lptString) + 1; + if (nBufferSize == 0) nBufferSize = nStrLen; + + lpString = (LPSTR)malloc(nBufferSize); +#ifdef UNICODE + WideCharToMultiByte(0,0,lptString,nStrLen,lpString,nBufferSize,0,0); +#else + strncpy(lpString,lptString,nBufferSize); +#endif + + return lpString; +} + +LRESULT CALLBACK EmptyWindowProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) +{ + return DefWindowProc(hWnd, uMsg, wParam, lParam); +} + +// Registers a minimal window class for passing to the dll function +ATOM RegisterBlankClass(HINSTANCE hInstance) +{ + WNDCLASSEX wcex; + + wcex.cbSize = sizeof(WNDCLASSEX); + + wcex.style = 0; + wcex.lpfnWndProc = EmptyWindowProc; + wcex.cbClsExtra = 0; + wcex.cbWndExtra = 0; + wcex.hInstance = hInstance; + wcex.hIcon = 0; + wcex.hCursor = 0; + wcex.hbrBackground = 0; + wcex.lpszMenuName = 0; + wcex.lpszClassName = rundll32_wclass; + wcex.hIconSm = 0; + + return RegisterClassEx(&wcex); +} + +int WINAPI WinMain( + HINSTANCE hInstance, + HINSTANCE hPrevInstance, + LPSTR lpCmdLineA, + int nCmdShow +) +{ + int argc; + LPTSTR *argv; + LPTSTR lptCmdLine,lptDllName,lptFuncName,lptMsgBuffer; + LPSTR lpFuncName,lpaCmdLine; + LPWSTR lpwCmdLine; + HMODULE hDll; + DllWinMainW fnDllWinMainW; + DllWinMainA fnDllWinMainA; + HWND hWindow; + int nRetVal,i; + size_t nStrLen; + + // Get command-line in argc-argv format + argv = CommandLineToArgv(GetCommandLine(),&argc); + + // Skip all beginning arguments starting with a slash (/) + for (i = 1; i < argc; i++) + if (*argv[i] != _T('/')) break; + + // If no dll was specified, there is nothing to do + if (i >= argc) { + if (argv) free(argv); + return 0; + } + + lptDllName = argv[i++]; + + // The next argument, which specifies the name of the dll function, + // can either have a comma between it and the dll filename or a space. + // Using a comma here is the preferred method + if (i < argc) + lptFuncName = argv[i++]; + else + lptFuncName = _T(""); + + // If no function name was specified, nothing needs to be done + if (!*lptFuncName) { + if (argv) free(argv); + return 0; + } + + // The rest of the arguments will be passed to dll function + if (i < argc) + lptCmdLine = argv[i]; + else + lptCmdLine = _T(""); + + nRetVal = 0; + + // Everything is all setup, so load the dll now + hDll = LoadLibrary(lptDllName); + if (hDll) { + nStrLen = _tcslen(lptFuncName); + // Make a non-unicode version of the function name, + // since that is all GetProcAddress accepts + lpFuncName = DuplicateToMultiByte(lptFuncName,nStrLen + 2); + +#ifdef UNICODE + lpFuncName[nStrLen] = 'W'; + lpFuncName[nStrLen+1] = 0; + // Get address of unicode version of the dll function if it exists + fnDllWinMainW = (DllWinMainW)GetProcAddress(hDll,lpFuncName); + fnDllWinMainA = 0; + if (!fnDllWinMainW) { + // If no unicode function was found, get the address of the non-unicode function + lpFuncName[nStrLen] = 'A'; + fnDllWinMainA = (DllWinMainA)GetProcAddress(hDll,lpFuncName); + if (!fnDllWinMainA) { + // If first non-unicode function was not found, get the address + // of the other non-unicode function + lpFuncName[nStrLen] = 0; + fnDllWinMainA = (DllWinMainA)GetProcAddress(hDll,lpFuncName); + } + } +#else + // Get address of non-unicode version of the dll function if it exists + fnDllWinMainA = (DllWinMainA)GetProcAddress(hDll,lpFuncName); + fnDllWinMainW = 0; + if (!fnDllWinMainA) { + // If first non-unicode function was not found, get the address + // of the other non-unicode function + lpFuncName[nStrLen] = 'A'; + lpFuncName[nStrLen+1] = 0; + fnDllWinMainA = (DllWinMainA)GetProcAddress(hDll,lpFuncName); + if (!fnDllWinMainA) { + // If non-unicode function was not found, get the address of the unicode function + lpFuncName[nStrLen] = 'W'; + fnDllWinMainW = (DllWinMainW)GetProcAddress(hDll,lpFuncName); + } + } +#endif + + free(lpFuncName); + + RegisterBlankClass(hInstance); + // Create a window so we can pass a window handle to + // the dll function; this is required + hWindow = CreateWindowEx(0,rundll32_wclass,rundll32_wtitle,0,CW_USEDEFAULT,0,CW_USEDEFAULT,0,0,0,hInstance,0); + + if (fnDllWinMainW) { + // Convert the command-line string to unicode and call the dll function + lpwCmdLine = ConvertToWideChar(lptCmdLine); + nRetVal = fnDllWinMainW(hWindow,hInstance,lpwCmdLine,nCmdShow); + FreeConvertedWideChar(lpwCmdLine); + } + else if (fnDllWinMainA) { + // Convert the command-line string to ansi and call the dll function + lpaCmdLine = ConvertToMultiByte(lptCmdLine); + nRetVal = fnDllWinMainA(hWindow,hInstance,lpaCmdLine,nCmdShow); + FreeConvertedMultiByte(lpaCmdLine); + } + else { + // The specified dll function was not found; display an error message + GetModuleTitle(); + lptMsgBuffer = (LPTSTR)malloc((_tcslen(MissingEntry) - 4 + _tcslen(lptFuncName) + _tcslen(lptDllName) + 1) * sizeof(TCHAR)); + _stprintf(lptMsgBuffer,MissingEntry,lptFuncName,lptDllName); + MessageBox(0,lptMsgBuffer,ModuleTitle,MB_ICONERROR); + free(lptMsgBuffer); + } + + DestroyWindow(hWindow); + UnregisterClass(rundll32_wclass,hInstance); + + // The dll function has finished executing, so unload it + FreeLibrary(hDll); + } + else { + // The dll could not be loaded; display an error message + GetModuleTitle(); + lptMsgBuffer = (LPTSTR)malloc((_tcslen(DllNotLoaded) - 2 + _tcslen(lptDllName) + 1) * sizeof(TCHAR)); + _stprintf(lptMsgBuffer,DllNotLoaded,lptDllName); + MessageBox(0,lptMsgBuffer,ModuleTitle,MB_ICONERROR); + free(lptMsgBuffer); + } + + if (argv) free(argv); + return nRetVal; +} +