regedit.c 6.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247
  1. /*
  2. * Windows regedit.exe registry editor implementation.
  3. *
  4. * Copyright 2002 Andriy Palamarchuk
  5. *
  6. * This library is free software; you can redistribute it and/or
  7. * modify it under the terms of the GNU Lesser General Public
  8. * License as published by the Free Software Foundation; either
  9. * version 2.1 of the License, or (at your option) any later version.
  10. *
  11. * This library is distributed in the hope that it will be useful,
  12. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  14. * Lesser General Public License for more details.
  15. *
  16. * You should have received a copy of the GNU Lesser General Public
  17. * License along with this library; if not, write to the Free Software
  18. * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
  19. */
  20. #include <stdlib.h>
  21. #include <windows.h>
  22. #include <commctrl.h>
  23. #include <shellapi.h>
  24. #include "wine/debug.h"
  25. #include "wine/heap.h"
  26. #include "main.h"
  27. WINE_DEFAULT_DEBUG_CHANNEL(regedit);
  28. static void output_writeconsole(const WCHAR *str, DWORD wlen)
  29. {
  30. DWORD count, ret;
  31. ret = WriteConsoleW(GetStdHandle(STD_OUTPUT_HANDLE), str, wlen, &count, NULL);
  32. if (!ret)
  33. {
  34. DWORD len;
  35. char *msgA;
  36. /* WriteConsole() fails on Windows if its output is redirected. If this occurs,
  37. * we should call WriteFile() and assume the console encoding is still correct.
  38. */
  39. len = WideCharToMultiByte(GetConsoleOutputCP(), 0, str, wlen, NULL, 0, NULL, NULL);
  40. msgA = heap_xalloc(len);
  41. WideCharToMultiByte(GetConsoleOutputCP(), 0, str, wlen, msgA, len, NULL, NULL);
  42. WriteFile(GetStdHandle(STD_OUTPUT_HANDLE), msgA, len, &count, FALSE);
  43. heap_free(msgA);
  44. }
  45. }
  46. static void output_formatstring(const WCHAR *fmt, __ms_va_list va_args)
  47. {
  48. WCHAR *str;
  49. DWORD len;
  50. len = FormatMessageW(FORMAT_MESSAGE_FROM_STRING|FORMAT_MESSAGE_ALLOCATE_BUFFER,
  51. fmt, 0, 0, (WCHAR *)&str, 0, &va_args);
  52. if (len == 0 && GetLastError() != ERROR_NO_WORK_DONE)
  53. {
  54. WINE_FIXME("Could not format string: le=%u, fmt=%s\n", GetLastError(), wine_dbgstr_w(fmt));
  55. return;
  56. }
  57. output_writeconsole(str, len);
  58. LocalFree(str);
  59. }
  60. void WINAPIV output_message(unsigned int id, ...)
  61. {
  62. WCHAR fmt[1536];
  63. __ms_va_list va_args;
  64. if (!LoadStringW(GetModuleHandleW(NULL), id, fmt, ARRAY_SIZE(fmt)))
  65. {
  66. WINE_FIXME("LoadString failed with %d\n", GetLastError());
  67. return;
  68. }
  69. __ms_va_start(va_args, id);
  70. output_formatstring(fmt, va_args);
  71. __ms_va_end(va_args);
  72. }
  73. void WINAPIV error_exit(unsigned int id, ...)
  74. {
  75. WCHAR fmt[1536];
  76. __ms_va_list va_args;
  77. if (!LoadStringW(GetModuleHandleW(NULL), id, fmt, ARRAY_SIZE(fmt)))
  78. {
  79. WINE_FIXME("LoadString failed with %u\n", GetLastError());
  80. return;
  81. }
  82. __ms_va_start(va_args, id);
  83. output_formatstring(fmt, va_args);
  84. __ms_va_end(va_args);
  85. exit(0); /* regedit.exe always terminates with error code zero */
  86. }
  87. typedef enum {
  88. ACTION_ADD, ACTION_EXPORT, ACTION_DELETE
  89. } REGEDIT_ACTION;
  90. static void PerformRegAction(REGEDIT_ACTION action, WCHAR **argv, int *i)
  91. {
  92. switch (action) {
  93. case ACTION_ADD: {
  94. WCHAR *filename = argv[*i];
  95. WCHAR hyphen[] = {'-',0};
  96. WCHAR *realname = NULL;
  97. FILE *reg_file;
  98. if (!lstrcmpW(filename, hyphen))
  99. reg_file = stdin;
  100. else
  101. {
  102. int size;
  103. WCHAR rb_mode[] = {'r','b',0};
  104. size = SearchPathW(NULL, filename, NULL, 0, NULL, NULL);
  105. if (size > 0)
  106. {
  107. realname = heap_xalloc(size * sizeof(WCHAR));
  108. size = SearchPathW(NULL, filename, NULL, size, realname, NULL);
  109. }
  110. if (size == 0)
  111. {
  112. output_message(STRING_FILE_NOT_FOUND, filename);
  113. heap_free(realname);
  114. return;
  115. }
  116. reg_file = _wfopen(realname, rb_mode);
  117. if (reg_file == NULL)
  118. {
  119. WCHAR regedit[] = {'r','e','g','e','d','i','t',0};
  120. _wperror(regedit);
  121. output_message(STRING_CANNOT_OPEN_FILE, filename);
  122. heap_free(realname);
  123. return;
  124. }
  125. }
  126. import_registry_file(reg_file);
  127. if (realname)
  128. {
  129. heap_free(realname);
  130. fclose(reg_file);
  131. }
  132. break;
  133. }
  134. case ACTION_DELETE:
  135. delete_registry_key(argv[*i]);
  136. break;
  137. case ACTION_EXPORT: {
  138. WCHAR *filename = argv[*i];
  139. WCHAR *key_name = argv[++(*i)];
  140. if (key_name && *key_name)
  141. export_registry_key(filename, key_name, REG_FORMAT_5);
  142. else
  143. export_registry_key(filename, NULL, REG_FORMAT_5);
  144. break;
  145. }
  146. default:
  147. error_exit(STRING_UNHANDLED_ACTION);
  148. break;
  149. }
  150. }
  151. BOOL ProcessCmdLine(WCHAR *cmdline)
  152. {
  153. WCHAR **argv;
  154. int argc, i;
  155. REGEDIT_ACTION action = ACTION_ADD;
  156. argv = CommandLineToArgvW(cmdline, &argc);
  157. if (!argv)
  158. return FALSE;
  159. if (argc == 1)
  160. {
  161. LocalFree(argv);
  162. return FALSE;
  163. }
  164. for (i = 1; i < argc; i++)
  165. {
  166. if (argv[i][0] != '/' && argv[i][0] != '-')
  167. break; /* No flags specified. */
  168. if (!argv[i][1] && argv[i][0] == '-')
  169. break; /* '-' is a filename. It indicates we should use stdin. */
  170. if (argv[i][1] && argv[i][2] && argv[i][2] != ':')
  171. break; /* This is a file path beginning with '/'. */
  172. switch (towupper(argv[i][1]))
  173. {
  174. case '?':
  175. error_exit(STRING_USAGE);
  176. break;
  177. case 'D':
  178. action = ACTION_DELETE;
  179. break;
  180. case 'E':
  181. action = ACTION_EXPORT;
  182. break;
  183. case 'C':
  184. case 'L':
  185. case 'M':
  186. case 'R':
  187. /* unhandled */;
  188. break;
  189. case 'S':
  190. case 'V':
  191. /* ignored */;
  192. break;
  193. default:
  194. output_message(STRING_INVALID_SWITCH, argv[i]);
  195. error_exit(STRING_HELP);
  196. }
  197. }
  198. if (i == argc)
  199. {
  200. switch (action)
  201. {
  202. case ACTION_ADD:
  203. case ACTION_EXPORT:
  204. output_message(STRING_NO_FILENAME);
  205. break;
  206. case ACTION_DELETE:
  207. output_message(STRING_NO_REG_KEY);
  208. break;
  209. }
  210. error_exit(STRING_HELP);
  211. }
  212. for (; i < argc; i++)
  213. PerformRegAction(action, argv, &i);
  214. LocalFree(argv);
  215. return TRUE;
  216. }