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 21 #ifndef __REACTOS__ 22 #include <stdlib.h> 23 #include <windows.h> 24 #include <commctrl.h> 25 #include <shellapi.h> 26 27 #include "wine/debug.h" 28 #include "main.h" 29 #else 30 #include "regedit.h" 31 #endif 32 33 WINE_DEFAULT_DEBUG_CHANNEL(regedit); 34 35 static void output_writeconsole(const WCHAR *str, DWORD wlen) 36 { 37 #ifdef __REACTOS__ 38 /* This is win32gui application, don't ever try writing to console. 39 * For the console version we have a separate reg.exe application. */ 40 WCHAR AppStr[255]; 41 LoadStringW(hInst, IDS_APP_TITLE, AppStr, ARRAY_SIZE(AppStr)); 42 MessageBoxW(NULL, str, AppStr, MB_OK | MB_ICONINFORMATION); 43 #else 44 DWORD count; 45 46 if (!WriteConsoleW(GetStdHandle(STD_OUTPUT_HANDLE), str, wlen, &count, NULL)) 47 { 48 DWORD len; 49 char *msgA; 50 51 /* WriteConsole() fails on Windows if its output is redirected. If this occurs, 52 * we should call WriteFile() with OEM code page. 53 */ 54 len = WideCharToMultiByte(GetOEMCP(), 0, str, wlen, NULL, 0, NULL, NULL); 55 msgA = malloc(len); 56 if (!msgA) return; 57 58 WideCharToMultiByte(GetOEMCP(), 0, str, wlen, msgA, len, NULL, NULL); 59 WriteFile(GetStdHandle(STD_OUTPUT_HANDLE), msgA, len, &count, FALSE); 60 free(msgA); 61 } 62 #endif 63 } 64 65 static void output_formatstring(const WCHAR *fmt, va_list va_args) 66 { 67 WCHAR *str; 68 DWORD len; 69 70 #ifdef __REACTOS__ 71 SetLastError(NO_ERROR); 72 #endif 73 len = FormatMessageW(FORMAT_MESSAGE_FROM_STRING|FORMAT_MESSAGE_ALLOCATE_BUFFER, 74 fmt, 0, 0, (WCHAR *)&str, 0, &va_args); 75 #ifdef __REACTOS__ 76 if (len == 0 && GetLastError() != NO_ERROR) 77 #else 78 if (len == 0 && GetLastError() != ERROR_NO_WORK_DONE) 79 #endif 80 { 81 WINE_FIXME("Could not format string: le=%lu, fmt=%s\n", GetLastError(), wine_dbgstr_w(fmt)); 82 return; 83 } 84 output_writeconsole(str, len); 85 LocalFree(str); 86 } 87 88 void WINAPIV output_message(unsigned int id, ...) 89 { 90 WCHAR fmt[1536]; 91 va_list va_args; 92 93 if (!LoadStringW(GetModuleHandleW(NULL), id, fmt, ARRAY_SIZE(fmt))) 94 { 95 WINE_FIXME("LoadString failed with %ld\n", GetLastError()); 96 return; 97 } 98 va_start(va_args, id); 99 output_formatstring(fmt, va_args); 100 va_end(va_args); 101 } 102 103 void WINAPIV error_exit(unsigned int id, ...) 104 { 105 WCHAR fmt[1536]; 106 va_list va_args; 107 108 if (!LoadStringW(GetModuleHandleW(NULL), id, fmt, ARRAY_SIZE(fmt))) 109 { 110 #ifndef __REACTOS__ 111 WINE_FIXME("LoadString failed with %lu\n", GetLastError()); 112 #endif 113 return; 114 } 115 va_start(va_args, id); 116 output_formatstring(fmt, va_args); 117 va_end(va_args); 118 119 exit(0); /* regedit.exe always terminates with error code zero */ 120 } 121 122 typedef enum { 123 ACTION_ADD, ACTION_EXPORT, ACTION_DELETE 124 } REGEDIT_ACTION; 125 126 static void PerformRegAction(REGEDIT_ACTION action, WCHAR **argv, int *i) 127 { 128 switch (action) { 129 case ACTION_ADD: { 130 WCHAR *filename = argv[*i]; 131 WCHAR *realname = NULL; 132 FILE *reg_file; 133 134 if (!lstrcmpW(filename, L"-")) 135 reg_file = stdin; 136 else 137 { 138 int size; 139 140 size = SearchPathW(NULL, filename, NULL, 0, NULL, NULL); 141 if (size > 0) 142 { 143 realname = malloc(size * sizeof(WCHAR)); 144 size = SearchPathW(NULL, filename, NULL, size, realname, NULL); 145 } 146 if (size == 0) 147 { 148 output_message(STRING_FILE_NOT_FOUND, filename); 149 free(realname); 150 return; 151 } 152 reg_file = _wfopen(realname, L"rb"); 153 if (reg_file == NULL) 154 { 155 _wperror(L"regedit"); 156 output_message(STRING_CANNOT_OPEN_FILE, filename); 157 free(realname); 158 return; 159 } 160 } 161 import_registry_file(reg_file); 162 if (realname) 163 { 164 free(realname); 165 fclose(reg_file); 166 } 167 break; 168 } 169 case ACTION_DELETE: 170 delete_registry_key(argv[*i]); 171 break; 172 case ACTION_EXPORT: { 173 WCHAR *filename = argv[*i]; 174 WCHAR *key_name = argv[++(*i)]; 175 176 if (key_name && *key_name) 177 export_registry_key(filename, key_name, REG_FORMAT_5); 178 else 179 export_registry_key(filename, NULL, REG_FORMAT_5); 180 break; 181 } 182 default: 183 error_exit(STRING_UNHANDLED_ACTION); 184 break; 185 } 186 } 187 188 BOOL ProcessCmdLine(WCHAR *cmdline) 189 { 190 WCHAR **argv; 191 int argc, i; 192 REGEDIT_ACTION action = ACTION_ADD; 193 194 argv = CommandLineToArgvW(cmdline, &argc); 195 196 if (!argv) 197 return FALSE; 198 199 if (argc == 1) 200 { 201 LocalFree(argv); 202 return FALSE; 203 } 204 205 for (i = 1; i < argc; i++) 206 { 207 if (argv[i][0] != '/' && argv[i][0] != '-') 208 break; /* No flags specified. */ 209 210 if (!argv[i][1] && argv[i][0] == '-') 211 break; /* '-' is a filename. It indicates we should use stdin. */ 212 213 if (argv[i][1] && argv[i][2] && argv[i][2] != ':') 214 break; /* This is a file path beginning with '/'. */ 215 216 switch (towupper(argv[i][1])) 217 { 218 case '?': 219 error_exit(STRING_USAGE); 220 break; 221 case 'D': 222 action = ACTION_DELETE; 223 break; 224 case 'E': 225 action = ACTION_EXPORT; 226 break; 227 case 'C': 228 case 'L': 229 case 'M': 230 case 'R': 231 /* unhandled */; 232 break; 233 case 'S': 234 case 'V': 235 /* ignored */; 236 break; 237 default: 238 output_message(STRING_INVALID_SWITCH, argv[i]); 239 error_exit(STRING_HELP); 240 } 241 } 242 243 if (i == argc) 244 { 245 switch (action) 246 { 247 case ACTION_ADD: 248 case ACTION_EXPORT: 249 output_message(STRING_NO_FILENAME); 250 break; 251 case ACTION_DELETE: 252 output_message(STRING_NO_REG_KEY); 253 break; 254 } 255 error_exit(STRING_HELP); 256 } 257 258 for (; i < argc; i++) 259 PerformRegAction(action, argv, &i); 260 261 LocalFree(argv); 262 263 return TRUE; 264 } 265