regsvr32.c 8.99 KB
Newer Older
1
/*
2
 * PURPOSE: Register OLE components in the registry
3 4 5 6
 *
 * Copyright 2001 ReactOS project
 * Copyright 2001 Jurgen Van Gael [jurgen.vangael@student.kuleuven.ac.be]
 * Copyright 2002 Andriy Palamarchuk
7
 * Copyright 2014, 2015 Hugh McMaster
8 9 10 11 12 13 14 15 16 17 18 19 20
 *
 * 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
21
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
22 23
 */

24 25
#define WIN32_LEAN_AND_MEAN

26 27 28
#include "config.h"
#include "wine/port.h"

29
#include <windows.h>
30
#include <ole2.h>
31
#include "regsvr32.h"
32
#include "wine/unicode.h"
33 34 35
#include "wine/debug.h"

WINE_DEFAULT_DEBUG_CHANNEL(regsvr32);
36

37 38 39
typedef HRESULT (WINAPI *DLLREGISTER)   (void);
typedef HRESULT (WINAPI *DLLUNREGISTER) (void);
typedef HRESULT (WINAPI *DLLINSTALL)    (BOOL,LPCWSTR);
40

41
static BOOL Silent = FALSE;
42

43
static void __cdecl output_write(UINT id, ...)
44
{
45
    WCHAR fmt[1024];
46
    __ms_va_list va_args;
47
    WCHAR *str;
48 49
    DWORD len, nOut, ret;

50 51
    if (Silent) return;

52
    if (!LoadStringW(GetModuleHandleW(NULL), id, fmt, sizeof(fmt)/sizeof(fmt[0])))
53 54 55 56 57 58 59
    {
        WINE_FIXME("LoadString failed with %d\n", GetLastError());
        return;
    }

    __ms_va_start(va_args, id);
    SetLastError(NO_ERROR);
60 61
    len = FormatMessageW(FORMAT_MESSAGE_FROM_STRING|FORMAT_MESSAGE_ALLOCATE_BUFFER,
                         fmt, 0, 0, (LPWSTR)&str, 0, &va_args);
62 63 64
    __ms_va_end(va_args);
    if (len == 0 && GetLastError() != NO_ERROR)
    {
65
        WINE_FIXME("Could not format string: le=%u, fmt=%s\n", GetLastError(), wine_dbgstr_w(fmt));
66 67 68
        return;
    }

69
    ret = WriteConsoleW(GetStdHandle(STD_OUTPUT_HANDLE), str, len, &nOut, NULL);
70

71 72 73
    /* WriteConsole fails if its output is redirected to a file.
     * If this occurs, we should use an OEM codepage and call WriteFile.
     */
74
    if (!ret)
75 76 77 78 79 80 81 82 83 84 85 86 87
    {
        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);
        }
    }
88
    LocalFree(str);
89 90 91 92 93 94 95
}

/**
 * Loads procedure.
 *
 * Parameters:
 * strDll - name of the dll.
96 97
 * procName - name of the procedure to load from the dll.
 * DllHandle - a variable that receives the handle of the loaded dll.
98
 */
99
static VOID *LoadProc(const WCHAR* strDll, const char* procName, HMODULE* DllHandle)
100 101 102
{
    VOID* (*proc)(void);

103
    *DllHandle = LoadLibraryExW(strDll, 0, LOAD_WITH_ALTERED_SEARCH_PATH);
104 105
    if(!*DllHandle)
    {
106
        output_write(STRING_DLL_LOAD_FAILED, strDll);
107
        ExitProcess(LOADLIBRARY_FAILED);
108 109 110 111
    }
    proc = (VOID *) GetProcAddress(*DllHandle, procName);
    if(!proc)
    {
112
        output_write(STRING_PROC_NOT_IMPLEMENTED, procName, strDll);
113
        FreeLibrary(*DllHandle);
114
        return NULL;
115 116 117 118
    }
    return proc;
}

119
static int RegisterDll(const WCHAR* strDll)
120 121 122 123 124 125
{
    HRESULT hr;
    DLLREGISTER pfRegister;
    HMODULE DllHandle = NULL;

    pfRegister = LoadProc(strDll, "DllRegisterServer", &DllHandle);
126
    if (!pfRegister)
127
        return GETPROCADDRESS_FAILED;
128 129 130 131

    hr = pfRegister();
    if(FAILED(hr))
    {
132
        output_write(STRING_REGISTER_FAILED, strDll);
133
        return DLLSERVER_FAILED;
134
    }
135
    output_write(STRING_REGISTER_SUCCESSFUL, strDll);
136 137 138 139 140 141

    if(DllHandle)
        FreeLibrary(DllHandle);
    return 0;
}

142
static int UnregisterDll(const WCHAR* strDll)
143 144 145 146 147 148
{
    HRESULT hr;
    DLLUNREGISTER pfUnregister;
    HMODULE DllHandle = NULL;

    pfUnregister = LoadProc(strDll, "DllUnregisterServer", &DllHandle);
149
    if (!pfUnregister)
150
        return GETPROCADDRESS_FAILED;
151

152 153 154
    hr = pfUnregister();
    if(FAILED(hr))
    {
155
        output_write(STRING_UNREGISTER_FAILED, strDll);
156
        return DLLSERVER_FAILED;
157
    }
158
    output_write(STRING_UNREGISTER_SUCCESSFUL, strDll);
159 160 161 162 163 164

    if(DllHandle)
        FreeLibrary(DllHandle);
    return 0;
}

165
static int InstallDll(BOOL install, const WCHAR *strDll, const WCHAR *command_line)
166 167 168 169 170 171
{
    HRESULT hr;
    DLLINSTALL pfInstall;
    HMODULE DllHandle = NULL;

    pfInstall = LoadProc(strDll, "DllInstall", &DllHandle);
172
    if (!pfInstall)
173
        return GETPROCADDRESS_FAILED;
174

175 176
    hr = pfInstall(install, command_line);
    if(FAILED(hr))
177 178
    {
        if (install)
179
            output_write(STRING_INSTALL_FAILED, strDll);
180
        else
181
            output_write(STRING_UNINSTALL_FAILED, strDll);
182
        return DLLSERVER_FAILED;
183
    }
184 185 186 187
    if (install)
        output_write(STRING_INSTALL_SUCCESSFUL, strDll);
    else
        output_write(STRING_UNINSTALL_SUCCESSFUL, strDll);
188 189 190 191 192 193

    if(DllHandle)
        FreeLibrary(DllHandle);
    return 0;
}

194
static WCHAR *parse_command_line(WCHAR *command_line)
195 196 197
{
    if (command_line[0] == ':' && command_line[1])
    {
198
        int len = strlenW(command_line);
199 200 201 202 203 204 205 206 207 208 209 210 211 212 213

        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])
214
            return command_line;
215
    }
216
    return NULL;
217 218
}

219
int wmain(int argc, WCHAR* argv[])
220
{
221
    int             i, res, ret = 0;
222 223 224 225 226 227
    BOOL            CallRegister = TRUE;
    BOOL            CallInstall = FALSE;
    BOOL            Unregister = FALSE;
    BOOL            DllFound = FALSE;
    WCHAR*          wsCommandLine = NULL;
    WCHAR           EmptyLine[1] = {0};
228

229
    OleInitialize(NULL);
230

231
    /* We mirror the Microsoft version by processing all of the flags before
232
     * the files (e.g. regsvr32 file1 /s file2 is silent even for file1).
233 234 235 236 237
     *
     * 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.
238
     */
239 240
    for(i = 1; i < argc; i++)
    {
241
        if (argv[i][0] == '/' || argv[i][0] == '-')
242
        {
243 244 245 246 247 248
            if (!argv[i][1])
                return INVALID_ARG;

            if (argv[i][2] && argv[i][2] != ':')
                continue;

249
            switch (tolowerW(argv[i][1]))
250 251
            {
            case 'u':
252
                Unregister = TRUE;
253 254
                break;
            case 's':
255
                Silent = TRUE;
256 257 258
                break;
            case 'i':
                CallInstall = TRUE;
259
                wsCommandLine = parse_command_line(argv[i] + 2); /* argv[i] + strlen("/i") */
260 261 262 263 264 265 266 267 268 269 270 271
                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);
272
                return INVALID_ARG;
273
            }
274
            argv[i] = NULL;
275
        }
276 277
    }

278
    if (!CallInstall && !CallRegister) /* flags: /n or /u /n */
279
        return INVALID_ARG;
280

281 282 283
    for (i = 1; i < argc; i++)
    {
        if (argv[i])
284
        {
285
            WCHAR *DllName = argv[i];
286
            res = 0;
287 288

            DllFound = TRUE;
289 290 291
            if (CallInstall && Unregister)
                res = InstallDll(!Unregister, DllName, wsCommandLine);

292
            /* The Windows version stops processing the current file on the first error. */
293
            if (res)
294 295
            {
                ret = res;
296
                continue;
297
            }
298

299
            if (!CallInstall || CallRegister)
300 301 302 303 304 305
            {
                if(Unregister)
                    res = UnregisterDll(DllName);
                else
                    res = RegisterDll(DllName);
            }
306

307
            if (res)
308 309
            {
                ret = res;
310
                continue;
311
            }
312

313
            if (CallInstall && !Unregister)
314
                res = InstallDll(!Unregister, DllName, wsCommandLine);
315

316
            if (res)
317 318
            {
                ret = res;
319
		continue;
320
            }
321 322 323 324 325
        }
    }

    if (!DllFound)
    {
326 327
        output_write(STRING_HEADER);
        output_write(STRING_USAGE);
328
        return INVALID_ARG;
329 330
    }

331 332
    OleUninitialize();

333 334
    /* return the most recent error code, even if later DLLs succeed */
    return ret;
335
}