include/mscvpdb.h: Use flexible array members for the rest of structures.
[wine.git] / programs / regsvr32 / regsvr32.c
blob18c664f436a5b520ea4f10494a22bab2fcbb826a
1 /*
2 * PURPOSE: Register OLE components in the registry
4 * Copyright 2001 ReactOS project
5 * Copyright 2001 Jurgen Van Gael [jurgen.vangael@student.kuleuven.ac.be]
6 * Copyright 2002 Andriy Palamarchuk
7 * Copyright 2014, 2015 Hugh McMaster
9 * This library is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU Lesser General Public
11 * License as published by the Free Software Foundation; either
12 * version 2.1 of the License, or (at your option) any later version.
14 * This library is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 * Lesser General Public License for more details.
19 * You should have received a copy of the GNU Lesser General Public
20 * 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
24 #define WIN32_LEAN_AND_MEAN
25 #include <windows.h>
26 #include <winternl.h>
27 #include <winnls.h>
28 #include <ole2.h>
29 #include "regsvr32.h"
30 #include "wine/debug.h"
32 WINE_DEFAULT_DEBUG_CHANNEL(regsvr32);
34 typedef HRESULT (WINAPI *DLLREGISTER) (void);
35 typedef HRESULT (WINAPI *DLLUNREGISTER) (void);
36 typedef HRESULT (WINAPI *DLLINSTALL) (BOOL,LPCWSTR);
38 static BOOL Silent;
40 static void WINAPIV output_write(BOOL with_usage, UINT id, ...)
42 WCHAR buffer[4096];
43 WCHAR fmt[1024];
44 va_list va_args;
45 DWORD len;
46 LCID current_lcid;
48 current_lcid = GetThreadLocale();
49 if (Silent) /* force en-US not to have localized strings */
50 SetThreadLocale(MAKELCID(MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), SORT_DEFAULT));
52 if (!LoadStringW(GetModuleHandleW(NULL), id, fmt, ARRAY_SIZE(fmt)))
54 WINE_FIXME("LoadString failed with %ld\n", GetLastError());
55 SetThreadLocale(current_lcid);
56 return;
59 va_start(va_args, id);
60 len = FormatMessageW(FORMAT_MESSAGE_FROM_STRING,
61 fmt, 0, 0, buffer, ARRAY_SIZE(buffer), &va_args);
62 va_end(va_args);
63 if (len == 0 && GetLastError() != ERROR_NO_WORK_DONE)
65 WINE_FIXME("Could not format string: le=%lu, fmt=%s\n", GetLastError(), wine_dbgstr_w(fmt));
66 SetThreadLocale(current_lcid);
67 return;
69 if (with_usage &&
70 !LoadStringW(GetModuleHandleW(NULL), STRING_USAGE,
71 &buffer[wcslen(buffer)], ARRAY_SIZE(buffer) - wcslen(buffer)))
73 WINE_FIXME("LoadString failed with %ld\n", GetLastError());
74 SetThreadLocale(current_lcid);
75 return;
77 if (Silent)
78 MESSAGE("%ls", buffer);
79 else
80 MessageBoxW(NULL, buffer, L"RegSvr32", MB_OK);
81 SetThreadLocale(current_lcid);
84 static LPCWSTR find_arg_start(LPCWSTR cmdline)
86 LPCWSTR s;
87 BOOL in_quotes;
88 int bcount;
90 bcount=0;
91 in_quotes=FALSE;
92 s=cmdline;
93 while (1) {
94 if (*s==0 || ((*s=='\t' || *s==' ') && !in_quotes)) {
95 /* end of this command line argument */
96 break;
97 } else if (*s=='\\') {
98 /* '\', count them */
99 bcount++;
100 } else if ((*s=='"') && ((bcount & 1)==0)) {
101 /* unescaped '"' */
102 in_quotes=!in_quotes;
103 bcount=0;
104 } else {
105 /* a regular character */
106 bcount=0;
108 s++;
110 return s;
113 static void reexec_self( WORD machine )
115 SYSTEM_SUPPORTED_PROCESSOR_ARCHITECTURES_INFORMATION machines[8];
116 WCHAR app[MAX_PATH];
117 LPCWSTR args;
118 WCHAR *cmdline;
119 HANDLE process = 0;
120 STARTUPINFOW si = {0};
121 PROCESS_INFORMATION pi;
122 void *cookie;
123 ULONG i;
125 NtQuerySystemInformationEx( SystemSupportedProcessorArchitectures, &process, sizeof(process),
126 machines, sizeof(machines), NULL );
127 for (i = 0; machines[i].Machine; i++) if (machines[i].Machine == machine) break;
128 if (!machines[i].Machine) return;
129 if (machines[i].Native) machine = IMAGE_FILE_MACHINE_TARGET_HOST;
130 if (!GetSystemWow64Directory2W( app, MAX_PATH, machine )) return;
131 wcscat( app, L"\\regsvr32.exe" );
133 TRACE( "restarting as %s\n", debugstr_w(app) );
135 args = find_arg_start(GetCommandLineW());
137 cmdline = HeapAlloc(GetProcessHeap(), 0,
138 (wcslen(app)+wcslen(args)+1)*sizeof(WCHAR));
140 wcscpy(cmdline, app);
141 wcscat(cmdline, args);
143 si.cb = sizeof(si);
145 Wow64DisableWow64FsRedirection(&cookie);
146 if (CreateProcessW(app, cmdline, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi))
148 DWORD exit_code;
149 WaitForSingleObject(pi.hProcess, INFINITE);
150 GetExitCodeProcess(pi.hProcess, &exit_code);
151 ExitProcess(exit_code);
153 else
155 WINE_TRACE("failed to restart, err=%ld\n", GetLastError());
157 Wow64RevertWow64FsRedirection(cookie);
158 HeapFree(GetProcessHeap(), 0, cmdline);
162 * Loads procedure.
164 * Parameters:
165 * strDll - name of the dll.
166 * procName - name of the procedure to load from the dll.
167 * DllHandle - a variable that receives the handle of the loaded dll.
168 * firstDll - true if this is the first dll in the command line.
170 static VOID *LoadProc(const WCHAR* strDll, const char* procName, HMODULE* DllHandle, BOOL firstDll)
172 VOID* (*proc)(void);
174 *DllHandle = LoadLibraryExW(strDll, 0, LOAD_WITH_ALTERED_SEARCH_PATH);
175 if(!*DllHandle)
177 HMODULE module;
178 if (firstDll && GetLastError() == ERROR_BAD_EXE_FORMAT &&
179 (module = LoadLibraryExW(strDll, 0, LOAD_LIBRARY_AS_IMAGE_RESOURCE)))
181 IMAGE_NT_HEADERS *nt = RtlImageNtHeader( (HMODULE)((ULONG_PTR)module & ~3) );
182 reexec_self( nt->FileHeader.Machine );
184 output_write(FALSE, STRING_DLL_LOAD_FAILED, strDll);
185 ExitProcess(LOADLIBRARY_FAILED);
187 proc = (VOID *) GetProcAddress(*DllHandle, procName);
188 if(!proc)
190 output_write(FALSE, STRING_PROC_NOT_IMPLEMENTED, procName, strDll);
191 FreeLibrary(*DllHandle);
192 return NULL;
194 return proc;
197 static int RegisterDll(const WCHAR* strDll, BOOL firstDll)
199 HRESULT hr;
200 DLLREGISTER pfRegister;
201 HMODULE DllHandle = NULL;
203 pfRegister = LoadProc(strDll, "DllRegisterServer", &DllHandle, firstDll);
204 if (!pfRegister)
205 return GETPROCADDRESS_FAILED;
207 hr = pfRegister();
208 if(FAILED(hr))
210 output_write(FALSE, STRING_REGISTER_FAILED, strDll);
211 return DLLSERVER_FAILED;
213 output_write(FALSE, STRING_REGISTER_SUCCESSFUL, strDll);
215 if(DllHandle)
216 FreeLibrary(DllHandle);
217 return 0;
220 static int UnregisterDll(const WCHAR* strDll, BOOL firstDll)
222 HRESULT hr;
223 DLLUNREGISTER pfUnregister;
224 HMODULE DllHandle = NULL;
226 pfUnregister = LoadProc(strDll, "DllUnregisterServer", &DllHandle, firstDll);
227 if (!pfUnregister)
228 return GETPROCADDRESS_FAILED;
230 hr = pfUnregister();
231 if(FAILED(hr))
233 output_write(FALSE, STRING_UNREGISTER_FAILED, strDll);
234 return DLLSERVER_FAILED;
236 output_write(FALSE, STRING_UNREGISTER_SUCCESSFUL, strDll);
238 if(DllHandle)
239 FreeLibrary(DllHandle);
240 return 0;
243 static int InstallDll(BOOL install, const WCHAR *strDll, const WCHAR *command_line, BOOL firstDll)
245 HRESULT hr;
246 DLLINSTALL pfInstall;
247 HMODULE DllHandle = NULL;
249 pfInstall = LoadProc(strDll, "DllInstall", &DllHandle, firstDll);
250 if (!pfInstall)
251 return GETPROCADDRESS_FAILED;
253 hr = pfInstall(install, command_line);
254 if(FAILED(hr))
256 if (install)
257 output_write(FALSE, STRING_INSTALL_FAILED, strDll);
258 else
259 output_write(FALSE, STRING_UNINSTALL_FAILED, strDll);
260 return DLLSERVER_FAILED;
262 if (install)
263 output_write(FALSE, STRING_INSTALL_SUCCESSFUL, strDll);
264 else
265 output_write(FALSE, STRING_UNINSTALL_SUCCESSFUL, strDll);
267 if(DllHandle)
268 FreeLibrary(DllHandle);
269 return 0;
272 static WCHAR *parse_command_line(WCHAR *command_line)
274 if (command_line[0] == ':' && command_line[1])
276 int len = lstrlenW(command_line);
278 command_line++;
279 len--;
280 /* remove double quotes */
281 if (command_line[0] == '"')
283 command_line++;
284 len--;
285 if (command_line[0])
287 len--;
288 command_line[len] = 0;
291 if (command_line[0])
292 return command_line;
294 return NULL;
297 int __cdecl wmain(int argc, WCHAR* argv[])
299 int i, res, ret = 0;
300 BOOL CallRegister = TRUE;
301 BOOL CallInstall = FALSE;
302 BOOL Unregister = FALSE;
303 BOOL DllFound = FALSE;
304 WCHAR* wsCommandLine = NULL;
305 WCHAR EmptyLine[] = L"";
307 OleInitialize(NULL);
309 /* We mirror the Microsoft version by processing all of the flags before
310 * the files (e.g. regsvr32 file1 /s file2 is silent even for file1).
312 * Note the complication that this version may be passed Unix format filenames
313 * which could be mistaken for flags. The Windows version conveniently
314 * requires each flag to be separate (e.g. no /su), so we will simply
315 * assume that anything longer than /. is a filename.
317 for(i = 1; i < argc; i++)
319 if (argv[i][0] == '/' || argv[i][0] == '-')
321 if (!argv[i][1])
322 return INVALID_ARG;
324 if (argv[i][2] && argv[i][2] != ':')
325 continue;
327 switch (towlower(argv[i][1]))
329 case 'u':
330 Unregister = TRUE;
331 break;
332 case 's':
333 Silent = TRUE;
334 break;
335 case 'i':
336 CallInstall = TRUE;
337 wsCommandLine = parse_command_line(argv[i] + 2); /* argv[i] + strlen("/i") */
338 if (!wsCommandLine)
339 wsCommandLine = EmptyLine;
340 break;
341 case 'n':
342 CallRegister = FALSE;
343 break;
344 default:
345 output_write(TRUE, STRING_UNRECOGNIZED_SWITCH, argv[i]);
346 return INVALID_ARG;
348 argv[i] = NULL;
352 if (!CallInstall && !CallRegister) /* flags: /n or /u /n */
353 return INVALID_ARG;
355 for (i = 1; i < argc; i++)
357 if (argv[i])
359 WCHAR *DllName = argv[i];
360 BOOL firstDll = !DllFound;
361 res = 0;
363 DllFound = TRUE;
364 if (CallInstall && Unregister)
365 res = InstallDll(!Unregister, DllName, wsCommandLine, firstDll);
367 /* The Windows version stops processing the current file on the first error. */
368 if (res)
370 ret = res;
371 continue;
374 if (!CallInstall || CallRegister)
376 if(Unregister)
377 res = UnregisterDll(DllName, firstDll);
378 else
379 res = RegisterDll(DllName, firstDll);
382 if (res)
384 ret = res;
385 continue;
388 if (CallInstall && !Unregister)
389 res = InstallDll(!Unregister, DllName, wsCommandLine, firstDll);
391 if (res)
393 ret = res;
394 continue;
399 if (!DllFound)
401 output_write(TRUE, STRING_HEADER);
402 return INVALID_ARG;
405 OleUninitialize();
407 /* return the most recent error code, even if later DLLs succeed */
408 return ret;