| /* |
| * 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; |
| } |