/* * PURPOSE: Register OLE components in the registry * * Copyright 2001 ReactOS project * Copyright 2001 Jurgen Van Gael [jurgen.vangael@student.kuleuven.ac.be] * Copyright 2002 Andriy Palamarchuk * Copyright 2014, 2015 Hugh McMaster * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA */ #define WIN32_LEAN_AND_MEAN #include "config.h" #include "wine/port.h" #include <windows.h> #include <ole2.h> #include "regsvr32.h" #include "wine/unicode.h" #include "wine/debug.h" WINE_DEFAULT_DEBUG_CHANNEL(regsvr32); typedef HRESULT (WINAPI *DLLREGISTER) (void); typedef HRESULT (WINAPI *DLLUNREGISTER) (void); typedef HRESULT (WINAPI *DLLINSTALL) (BOOL,LPCWSTR); static BOOL Silent = FALSE; static void __cdecl output_write(UINT id, ...) { WCHAR fmt[1024]; __ms_va_list va_args; WCHAR *str; DWORD len, nOut, ret; if (Silent) return; if (!LoadStringW(GetModuleHandleW(NULL), id, fmt, sizeof(fmt)/sizeof(fmt[0]))) { WINE_FIXME("LoadString failed with %d\n", GetLastError()); return; } __ms_va_start(va_args, id); SetLastError(NO_ERROR); len = FormatMessageW(FORMAT_MESSAGE_FROM_STRING|FORMAT_MESSAGE_ALLOCATE_BUFFER, fmt, 0, 0, (LPWSTR)&str, 0, &va_args); __ms_va_end(va_args); if (len == 0 && GetLastError() != NO_ERROR) { WINE_FIXME("Could not format string: le=%u, fmt=%s\n", GetLastError(), wine_dbgstr_w(fmt)); return; } ret = WriteConsoleW(GetStdHandle(STD_OUTPUT_HANDLE), str, len, &nOut, NULL); /* WriteConsole fails if its output is redirected to a file. * If this occurs, we should use an OEM codepage and call WriteFile. */ if (!ret) { DWORD lenA; char *strA; lenA = WideCharToMultiByte(GetConsoleOutputCP(), 0, str, len, NULL, 0, NULL, NULL); strA = HeapAlloc(GetProcessHeap(), 0, lenA); if (strA) { WideCharToMultiByte(GetConsoleOutputCP(), 0, str, len, strA, lenA, NULL, NULL); WriteFile(GetStdHandle(STD_OUTPUT_HANDLE), strA, lenA, &nOut, FALSE); HeapFree(GetProcessHeap(), 0, strA); } } LocalFree(str); } /** * Loads procedure. * * Parameters: * strDll - name of the dll. * procName - name of the procedure to load from the dll. * DllHandle - a variable that receives the handle of the loaded dll. */ static VOID *LoadProc(const WCHAR* strDll, const char* procName, HMODULE* DllHandle) { VOID* (*proc)(void); *DllHandle = LoadLibraryExW(strDll, 0, LOAD_WITH_ALTERED_SEARCH_PATH); if(!*DllHandle) { output_write(STRING_DLL_LOAD_FAILED, strDll); ExitProcess(LOADLIBRARY_FAILED); } proc = (VOID *) GetProcAddress(*DllHandle, procName); if(!proc) { output_write(STRING_PROC_NOT_IMPLEMENTED, procName, strDll); FreeLibrary(*DllHandle); return NULL; } return proc; } static int RegisterDll(const WCHAR* strDll) { HRESULT hr; DLLREGISTER pfRegister; HMODULE DllHandle = NULL; pfRegister = LoadProc(strDll, "DllRegisterServer", &DllHandle); if (!pfRegister) return GETPROCADDRESS_FAILED; hr = pfRegister(); if(FAILED(hr)) { output_write(STRING_REGISTER_FAILED, strDll); return DLLSERVER_FAILED; } output_write(STRING_REGISTER_SUCCESSFUL, strDll); if(DllHandle) FreeLibrary(DllHandle); return 0; } static int UnregisterDll(const WCHAR* strDll) { HRESULT hr; DLLUNREGISTER pfUnregister; HMODULE DllHandle = NULL; pfUnregister = LoadProc(strDll, "DllUnregisterServer", &DllHandle); if (!pfUnregister) return GETPROCADDRESS_FAILED; hr = pfUnregister(); if(FAILED(hr)) { output_write(STRING_UNREGISTER_FAILED, strDll); return DLLSERVER_FAILED; } output_write(STRING_UNREGISTER_SUCCESSFUL, strDll); if(DllHandle) FreeLibrary(DllHandle); return 0; } static int InstallDll(BOOL install, const WCHAR *strDll, const WCHAR *command_line) { HRESULT hr; DLLINSTALL pfInstall; HMODULE DllHandle = NULL; pfInstall = LoadProc(strDll, "DllInstall", &DllHandle); if (!pfInstall) return GETPROCADDRESS_FAILED; hr = pfInstall(install, command_line); if(FAILED(hr)) { if (install) output_write(STRING_INSTALL_FAILED, strDll); else output_write(STRING_UNINSTALL_FAILED, strDll); return DLLSERVER_FAILED; } if (install) output_write(STRING_INSTALL_SUCCESSFUL, strDll); else output_write(STRING_UNINSTALL_SUCCESSFUL, strDll); if(DllHandle) FreeLibrary(DllHandle); return 0; } static WCHAR *parse_command_line(WCHAR *command_line) { if (command_line[0] == ':' && command_line[1]) { int len = strlenW(command_line); command_line++; len--; /* remove double quotes */ if (command_line[0] == '"') { command_line++; len--; if (command_line[0]) { len--; command_line[len] = 0; } } if (command_line[0]) return command_line; } return NULL; } int wmain(int argc, WCHAR* argv[]) { int i, res, ret = 0; BOOL CallRegister = TRUE; BOOL CallInstall = FALSE; BOOL Unregister = FALSE; BOOL DllFound = FALSE; WCHAR* wsCommandLine = NULL; WCHAR EmptyLine[1] = {0}; OleInitialize(NULL); /* We mirror the Microsoft version by processing all of the flags before * the files (e.g. regsvr32 file1 /s file2 is silent even for file1). * * Note the complication that this version may be passed Unix format filenames * which could be mistaken for flags. The Windows version conveniently * requires each flag to be separate (e.g. no /su), so we will simply * assume that anything longer than /. is a filename. */ for(i = 1; i < argc; i++) { if (argv[i][0] == '/' || argv[i][0] == '-') { if (!argv[i][1]) return INVALID_ARG; if (argv[i][2] && argv[i][2] != ':') continue; switch (tolowerW(argv[i][1])) { case 'u': Unregister = TRUE; break; case 's': Silent = TRUE; break; case 'i': CallInstall = TRUE; wsCommandLine = parse_command_line(argv[i] + 2); /* argv[i] + strlen("/i") */ if (!wsCommandLine) wsCommandLine = EmptyLine; break; case 'n': CallRegister = FALSE; break; case 'c': /* console output */; break; default: output_write(STRING_UNRECOGNIZED_SWITCH, argv[i]); output_write(STRING_USAGE); return INVALID_ARG; } argv[i] = NULL; } } if (!CallInstall && !CallRegister) /* flags: /n or /u /n */ return INVALID_ARG; for (i = 1; i < argc; i++) { if (argv[i]) { WCHAR *DllName = argv[i]; res = 0; DllFound = TRUE; if (CallInstall && Unregister) res = InstallDll(!Unregister, DllName, wsCommandLine); /* The Windows version stops processing the current file on the first error. */ if (res) { ret = res; continue; } if (!CallInstall || CallRegister) { if(Unregister) res = UnregisterDll(DllName); else res = RegisterDll(DllName); } if (res) { ret = res; continue; } if (CallInstall && !Unregister) res = InstallDll(!Unregister, DllName, wsCommandLine); if (res) { ret = res; continue; } } } if (!DllFound) { output_write(STRING_HEADER); output_write(STRING_USAGE); return INVALID_ARG; } OleUninitialize(); /* return the most recent error code, even if later DLLs succeed */ return ret; }