mirror of
https://github.com/reactos/reactos.git
synced 2024-09-10 12:54:51 +00:00
484 lines
14 KiB
C
484 lines
14 KiB
C
/*
|
|
* ReactOS regsvr32
|
|
* Copyright (C) 2004-2006 ReactOS Team
|
|
*
|
|
* COPYRIGHT: See COPYING in the top level directory
|
|
* PROJECT: ReactOS regsvr32.exe
|
|
* FILE: base/system/regsvr32/regsvr32.c
|
|
* PURPOSE: Register a COM component in the registry
|
|
* PROGRAMMER: ShadowFlare (blakflare@hotmail.com)
|
|
*/
|
|
|
|
// 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
|
|
|
|
#define WIN32_NO_STATUS
|
|
#define _INC_WINDOWS
|
|
#define COM_NO_WINDOWS_H
|
|
#include <stdarg.h>
|
|
#include <windef.h>
|
|
#include <winbase.h>
|
|
#include <ole2.h>
|
|
#include <tchar.h>
|
|
|
|
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
|
|
|
|
#include "resource.h"
|
|
|
|
LPCTSTR ModuleTitle = _T("RegSvr32");
|
|
|
|
TCHAR UsageMessage[RC_STRING_MAX_SIZE];
|
|
TCHAR NoDllSpecified[RC_STRING_MAX_SIZE];
|
|
TCHAR InvalidFlag[RC_STRING_MAX_SIZE];
|
|
TCHAR SwitchN_NoI[RC_STRING_MAX_SIZE];
|
|
TCHAR DllNotLoaded[RC_STRING_MAX_SIZE];
|
|
TCHAR MissingEntry[RC_STRING_MAX_SIZE];
|
|
TCHAR FailureMessage[RC_STRING_MAX_SIZE];
|
|
TCHAR SuccessMessage[RC_STRING_MAX_SIZE];
|
|
|
|
// 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 <shellapi.h>
|
|
#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
|
|
// necessary. 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) ((void) 0)
|
|
#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 _tWinMain(
|
|
HINSTANCE hInstance,
|
|
HINSTANCE hPrevInstance,
|
|
LPTSTR lpCmdLine,
|
|
int nCmdShow
|
|
)
|
|
{
|
|
int argc;
|
|
LPTSTR *argv;
|
|
LPTSTR lptDllName,lptDllCmdLine,lptMsgBuffer;
|
|
LPCTSTR lptFuncName;
|
|
LPCSTR lpFuncName;
|
|
LPWSTR lpwDllCmdLine;
|
|
BOOL bUnregister,bSilent,bConsole,bInstall,bNoRegister;
|
|
UINT nDllCount, fuOldErrorMode;
|
|
HMODULE hDll;
|
|
DLLREGISTER fnDllRegister;
|
|
DLLINSTALL fnDllInstall;
|
|
HRESULT hResult;
|
|
DWORD dwErr;
|
|
int nRetValue,i;
|
|
|
|
// Get Langues msg
|
|
LoadString( GetModuleHandle(NULL), IDS_UsageMessage, (LPTSTR) UsageMessage,RC_STRING_MAX_SIZE);
|
|
LoadString( GetModuleHandle(NULL), IDS_NoDllSpecified, (LPTSTR) NoDllSpecified,RC_STRING_MAX_SIZE);
|
|
LoadString( GetModuleHandle(NULL), IDS_InvalidFlag, (LPTSTR) InvalidFlag,RC_STRING_MAX_SIZE);
|
|
LoadString( GetModuleHandle(NULL), IDS_SwitchN_NoI, (LPTSTR) SwitchN_NoI,RC_STRING_MAX_SIZE);
|
|
|
|
LoadString( GetModuleHandle(NULL), IDS_DllNotLoaded, (LPTSTR) DllNotLoaded,RC_STRING_MAX_SIZE);
|
|
LoadString( GetModuleHandle(NULL), IDS_MissingEntry, (LPTSTR) MissingEntry,RC_STRING_MAX_SIZE);
|
|
LoadString( GetModuleHandle(NULL), IDS_FailureMessage, (LPTSTR) FailureMessage,RC_STRING_MAX_SIZE);
|
|
LoadString( GetModuleHandle(NULL), IDS_SuccessMessage, (LPTSTR) SuccessMessage,RC_STRING_MAX_SIZE);
|
|
|
|
// 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('/') || *argv[i] == '-') {
|
|
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 && nRetValue == EXITCODE_SUCCESS; i++) {
|
|
// Arguments that do not start with a slash (/) are filenames
|
|
if (*argv[i] != _T('/')) {
|
|
lptDllName = argv[i];
|
|
|
|
fuOldErrorMode = SetErrorMode(SEM_FAILCRITICALERRORS);
|
|
// Everything is all setup, so load the dll now
|
|
hDll = LoadLibraryEx(lptDllName,0,LOAD_WITH_ALTERED_SEARCH_PATH);
|
|
if (hDll) {
|
|
SetErrorMode(fuOldErrorMode);
|
|
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 && nRetValue == EXITCODE_SUCCESS) {
|
|
// 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 {
|
|
// 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();
|
|
SetErrorMode(fuOldErrorMode);
|
|
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;
|
|
}
|