regsvr32.c 12 KB

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