regsvr32.c 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414
  1. /*
  2. * PURPOSE: Register OLE components in the registry
  3. *
  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
  8. *
  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.
  13. *
  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.
  18. *
  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
  22. */
  23. #define WIN32_LEAN_AND_MEAN
  24. #include <windows.h>
  25. #include <winternl.h>
  26. #include <ole2.h>
  27. #include "regsvr32.h"
  28. #include "wine/debug.h"
  29. WINE_DEFAULT_DEBUG_CHANNEL(regsvr32);
  30. typedef HRESULT (WINAPI *DLLREGISTER) (void);
  31. typedef HRESULT (WINAPI *DLLUNREGISTER) (void);
  32. typedef HRESULT (WINAPI *DLLINSTALL) (BOOL,LPCWSTR);
  33. static BOOL Silent = FALSE;
  34. static void WINAPIV output_write(UINT id, ...)
  35. {
  36. WCHAR fmt[1024];
  37. va_list va_args;
  38. WCHAR *str;
  39. DWORD len, nOut;
  40. if (Silent) return;
  41. if (!LoadStringW(GetModuleHandleW(NULL), id, fmt, ARRAY_SIZE(fmt)))
  42. {
  43. WINE_FIXME("LoadString failed with %ld\n", GetLastError());
  44. return;
  45. }
  46. va_start(va_args, id);
  47. len = FormatMessageW(FORMAT_MESSAGE_FROM_STRING|FORMAT_MESSAGE_ALLOCATE_BUFFER,
  48. fmt, 0, 0, (LPWSTR)&str, 0, &va_args);
  49. va_end(va_args);
  50. if (len == 0 && GetLastError() != ERROR_NO_WORK_DONE)
  51. {
  52. WINE_FIXME("Could not format string: le=%lu, fmt=%s\n", GetLastError(), wine_dbgstr_w(fmt));
  53. return;
  54. }
  55. /* WriteConsole fails if its output is redirected to a file.
  56. * If this occurs, we should use an OEM codepage and call WriteFile.
  57. */
  58. if (!WriteConsoleW(GetStdHandle(STD_OUTPUT_HANDLE), str, len, &nOut, NULL))
  59. {
  60. DWORD lenA;
  61. char *strA;
  62. lenA = WideCharToMultiByte(GetOEMCP(), 0, str, len, NULL, 0, NULL, NULL);
  63. strA = HeapAlloc(GetProcessHeap(), 0, lenA);
  64. if (strA)
  65. {
  66. WideCharToMultiByte(GetOEMCP(), 0, str, len, strA, lenA, NULL, NULL);
  67. WriteFile(GetStdHandle(STD_OUTPUT_HANDLE), strA, lenA, &nOut, FALSE);
  68. HeapFree(GetProcessHeap(), 0, strA);
  69. }
  70. }
  71. LocalFree(str);
  72. }
  73. static LPCWSTR find_arg_start(LPCWSTR cmdline)
  74. {
  75. LPCWSTR s;
  76. BOOL in_quotes;
  77. int bcount;
  78. bcount=0;
  79. in_quotes=FALSE;
  80. s=cmdline;
  81. while (1) {
  82. if (*s==0 || ((*s=='\t' || *s==' ') && !in_quotes)) {
  83. /* end of this command line argument */
  84. break;
  85. } else if (*s=='\\') {
  86. /* '\', count them */
  87. bcount++;
  88. } else if ((*s=='"') && ((bcount & 1)==0)) {
  89. /* unescaped '"' */
  90. in_quotes=!in_quotes;
  91. bcount=0;
  92. } else {
  93. /* a regular character */
  94. bcount=0;
  95. }
  96. s++;
  97. }
  98. return s;
  99. }
  100. static void reexec_self( WORD machine )
  101. {
  102. WCHAR app[MAX_PATH];
  103. LPCWSTR args;
  104. WCHAR *cmdline;
  105. ULONG i, machines[8];
  106. HANDLE process = 0;
  107. STARTUPINFOW si = {0};
  108. PROCESS_INFORMATION pi;
  109. void *cookie;
  110. NtQuerySystemInformationEx( SystemSupportedProcessorArchitectures, &process, sizeof(process),
  111. machines, sizeof(machines), NULL );
  112. for (i = 0; machines[i]; i++) if (LOWORD(machines[i]) == machine) break;
  113. if (!machines[i]) return;
  114. if (HIWORD(machines[i]) & 4 /* native machine */) machine = IMAGE_FILE_MACHINE_TARGET_HOST;
  115. if (!GetSystemWow64Directory2W( app, MAX_PATH, machine )) return;
  116. wcscat( app, L"\\regsvr32.exe" );
  117. TRACE( "restarting as %s\n", debugstr_w(app) );
  118. args = find_arg_start(GetCommandLineW());
  119. cmdline = HeapAlloc(GetProcessHeap(), 0,
  120. (wcslen(app)+wcslen(args)+1)*sizeof(WCHAR));
  121. wcscpy(cmdline, app);
  122. wcscat(cmdline, args);
  123. si.cb = sizeof(si);
  124. Wow64DisableWow64FsRedirection(&cookie);
  125. if (CreateProcessW(app, cmdline, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi))
  126. {
  127. DWORD exit_code;
  128. WaitForSingleObject(pi.hProcess, INFINITE);
  129. GetExitCodeProcess(pi.hProcess, &exit_code);
  130. ExitProcess(exit_code);
  131. }
  132. else
  133. {
  134. WINE_TRACE("failed to restart, err=%ld\n", GetLastError());
  135. }
  136. Wow64RevertWow64FsRedirection(cookie);
  137. HeapFree(GetProcessHeap(), 0, cmdline);
  138. }
  139. /**
  140. * Loads procedure.
  141. *
  142. * Parameters:
  143. * strDll - name of the dll.
  144. * procName - name of the procedure to load from the dll.
  145. * DllHandle - a variable that receives the handle of the loaded dll.
  146. * firstDll - true if this is the first dll in the command line.
  147. */
  148. static VOID *LoadProc(const WCHAR* strDll, const char* procName, HMODULE* DllHandle, BOOL firstDll)
  149. {
  150. VOID* (*proc)(void);
  151. *DllHandle = LoadLibraryExW(strDll, 0, LOAD_WITH_ALTERED_SEARCH_PATH);
  152. if(!*DllHandle)
  153. {
  154. HMODULE module;
  155. if (firstDll && GetLastError() == ERROR_BAD_EXE_FORMAT &&
  156. (module = LoadLibraryExW(strDll, 0, LOAD_LIBRARY_AS_IMAGE_RESOURCE)))
  157. {
  158. IMAGE_NT_HEADERS *nt = RtlImageNtHeader( (HMODULE)((ULONG_PTR)module & ~3) );
  159. reexec_self( nt->FileHeader.Machine );
  160. }
  161. output_write(STRING_DLL_LOAD_FAILED, strDll);
  162. ExitProcess(LOADLIBRARY_FAILED);
  163. }
  164. proc = (VOID *) GetProcAddress(*DllHandle, procName);
  165. if(!proc)
  166. {
  167. output_write(STRING_PROC_NOT_IMPLEMENTED, procName, strDll);
  168. FreeLibrary(*DllHandle);
  169. return NULL;
  170. }
  171. return proc;
  172. }
  173. static int RegisterDll(const WCHAR* strDll, BOOL firstDll)
  174. {
  175. HRESULT hr;
  176. DLLREGISTER pfRegister;
  177. HMODULE DllHandle = NULL;
  178. pfRegister = LoadProc(strDll, "DllRegisterServer", &DllHandle, firstDll);
  179. if (!pfRegister)
  180. return GETPROCADDRESS_FAILED;
  181. hr = pfRegister();
  182. if(FAILED(hr))
  183. {
  184. output_write(STRING_REGISTER_FAILED, strDll);
  185. return DLLSERVER_FAILED;
  186. }
  187. output_write(STRING_REGISTER_SUCCESSFUL, strDll);
  188. if(DllHandle)
  189. FreeLibrary(DllHandle);
  190. return 0;
  191. }
  192. static int UnregisterDll(const WCHAR* strDll, BOOL firstDll)
  193. {
  194. HRESULT hr;
  195. DLLUNREGISTER pfUnregister;
  196. HMODULE DllHandle = NULL;
  197. pfUnregister = LoadProc(strDll, "DllUnregisterServer", &DllHandle, firstDll);
  198. if (!pfUnregister)
  199. return GETPROCADDRESS_FAILED;
  200. hr = pfUnregister();
  201. if(FAILED(hr))
  202. {
  203. output_write(STRING_UNREGISTER_FAILED, strDll);
  204. return DLLSERVER_FAILED;
  205. }
  206. output_write(STRING_UNREGISTER_SUCCESSFUL, strDll);
  207. if(DllHandle)
  208. FreeLibrary(DllHandle);
  209. return 0;
  210. }
  211. static int InstallDll(BOOL install, const WCHAR *strDll, const WCHAR *command_line, BOOL firstDll)
  212. {
  213. HRESULT hr;
  214. DLLINSTALL pfInstall;
  215. HMODULE DllHandle = NULL;
  216. pfInstall = LoadProc(strDll, "DllInstall", &DllHandle, firstDll);
  217. if (!pfInstall)
  218. return GETPROCADDRESS_FAILED;
  219. hr = pfInstall(install, command_line);
  220. if(FAILED(hr))
  221. {
  222. if (install)
  223. output_write(STRING_INSTALL_FAILED, strDll);
  224. else
  225. output_write(STRING_UNINSTALL_FAILED, strDll);
  226. return DLLSERVER_FAILED;
  227. }
  228. if (install)
  229. output_write(STRING_INSTALL_SUCCESSFUL, strDll);
  230. else
  231. output_write(STRING_UNINSTALL_SUCCESSFUL, strDll);
  232. if(DllHandle)
  233. FreeLibrary(DllHandle);
  234. return 0;
  235. }
  236. static WCHAR *parse_command_line(WCHAR *command_line)
  237. {
  238. if (command_line[0] == ':' && command_line[1])
  239. {
  240. int len = lstrlenW(command_line);
  241. command_line++;
  242. len--;
  243. /* remove double quotes */
  244. if (command_line[0] == '"')
  245. {
  246. command_line++;
  247. len--;
  248. if (command_line[0])
  249. {
  250. len--;
  251. command_line[len] = 0;
  252. }
  253. }
  254. if (command_line[0])
  255. return command_line;
  256. }
  257. return NULL;
  258. }
  259. int __cdecl wmain(int argc, WCHAR* argv[])
  260. {
  261. int i, res, ret = 0;
  262. BOOL CallRegister = TRUE;
  263. BOOL CallInstall = FALSE;
  264. BOOL Unregister = FALSE;
  265. BOOL DllFound = FALSE;
  266. WCHAR* wsCommandLine = NULL;
  267. WCHAR EmptyLine[] = L"";
  268. OleInitialize(NULL);
  269. /* We mirror the Microsoft version by processing all of the flags before
  270. * the files (e.g. regsvr32 file1 /s file2 is silent even for file1).
  271. *
  272. * Note the complication that this version may be passed Unix format filenames
  273. * which could be mistaken for flags. The Windows version conveniently
  274. * requires each flag to be separate (e.g. no /su), so we will simply
  275. * assume that anything longer than /. is a filename.
  276. */
  277. for(i = 1; i < argc; i++)
  278. {
  279. if (argv[i][0] == '/' || argv[i][0] == '-')
  280. {
  281. if (!argv[i][1])
  282. return INVALID_ARG;
  283. if (argv[i][2] && argv[i][2] != ':')
  284. continue;
  285. switch (towlower(argv[i][1]))
  286. {
  287. case 'u':
  288. Unregister = TRUE;
  289. break;
  290. case 's':
  291. Silent = TRUE;
  292. break;
  293. case 'i':
  294. CallInstall = TRUE;
  295. wsCommandLine = parse_command_line(argv[i] + 2); /* argv[i] + strlen("/i") */
  296. if (!wsCommandLine)
  297. wsCommandLine = EmptyLine;
  298. break;
  299. case 'n':
  300. CallRegister = FALSE;
  301. break;
  302. case 'c':
  303. /* console output */;
  304. break;
  305. default:
  306. output_write(STRING_UNRECOGNIZED_SWITCH, argv[i]);
  307. output_write(STRING_USAGE);
  308. return INVALID_ARG;
  309. }
  310. argv[i] = NULL;
  311. }
  312. }
  313. if (!CallInstall && !CallRegister) /* flags: /n or /u /n */
  314. return INVALID_ARG;
  315. for (i = 1; i < argc; i++)
  316. {
  317. if (argv[i])
  318. {
  319. WCHAR *DllName = argv[i];
  320. BOOL firstDll = !DllFound;
  321. res = 0;
  322. DllFound = TRUE;
  323. if (CallInstall && Unregister)
  324. res = InstallDll(!Unregister, DllName, wsCommandLine, firstDll);
  325. /* The Windows version stops processing the current file on the first error. */
  326. if (res)
  327. {
  328. ret = res;
  329. continue;
  330. }
  331. if (!CallInstall || CallRegister)
  332. {
  333. if(Unregister)
  334. res = UnregisterDll(DllName, firstDll);
  335. else
  336. res = RegisterDll(DllName, firstDll);
  337. }
  338. if (res)
  339. {
  340. ret = res;
  341. continue;
  342. }
  343. if (CallInstall && !Unregister)
  344. res = InstallDll(!Unregister, DllName, wsCommandLine, firstDll);
  345. if (res)
  346. {
  347. ret = res;
  348. continue;
  349. }
  350. }
  351. }
  352. if (!DllFound)
  353. {
  354. output_write(STRING_HEADER);
  355. output_write(STRING_USAGE);
  356. return INVALID_ARG;
  357. }
  358. OleUninitialize();
  359. /* return the most recent error code, even if later DLLs succeed */
  360. return ret;
  361. }