2 * Windows regedit.exe registry editor implementation.
4 * Copyright 2002 Andriy Palamarchuk
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.
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.
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
27 #include "wine/debug.h"
33 WINE_DEFAULT_DEBUG_CHANNEL(regedit
);
35 static void output_writeconsole(const WCHAR
*str
, DWORD wlen
)
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 MessageBoxW(NULL
, str
, NULL
, MB_ICONERROR
);
44 if (!WriteConsoleW(GetStdHandle(STD_OUTPUT_HANDLE
), str
, wlen
, &count
, NULL
))
49 /* WriteConsole() fails on Windows if its output is redirected. If this occurs,
50 * we should call WriteFile() with OEM code page.
52 len
= WideCharToMultiByte(GetOEMCP(), 0, str
, wlen
, NULL
, 0, NULL
, NULL
);
56 WideCharToMultiByte(GetOEMCP(), 0, str
, wlen
, msgA
, len
, NULL
, NULL
);
57 WriteFile(GetStdHandle(STD_OUTPUT_HANDLE
), msgA
, len
, &count
, FALSE
);
63 static void output_formatstring(const WCHAR
*fmt
, va_list va_args
)
69 SetLastError(NO_ERROR
);
71 len
= FormatMessageW(FORMAT_MESSAGE_FROM_STRING
|FORMAT_MESSAGE_ALLOCATE_BUFFER
,
72 fmt
, 0, 0, (WCHAR
*)&str
, 0, &va_args
);
74 if (len
== 0 && GetLastError() != NO_ERROR
)
76 if (len
== 0 && GetLastError() != ERROR_NO_WORK_DONE
)
79 WINE_FIXME("Could not format string: le=%lu, fmt=%s\n", GetLastError(), wine_dbgstr_w(fmt
));
82 output_writeconsole(str
, len
);
86 void WINAPIV
output_message(unsigned int id
, ...)
91 if (!LoadStringW(GetModuleHandleW(NULL
), id
, fmt
, ARRAY_SIZE(fmt
)))
93 WINE_FIXME("LoadString failed with %ld\n", GetLastError());
96 va_start(va_args
, id
);
97 output_formatstring(fmt
, va_args
);
101 void WINAPIV
error_exit(unsigned int id
, ...)
106 if (!LoadStringW(GetModuleHandleW(NULL
), id
, fmt
, ARRAY_SIZE(fmt
)))
109 WINE_FIXME("LoadString failed with %lu\n", GetLastError());
113 va_start(va_args
, id
);
114 output_formatstring(fmt
, va_args
);
117 exit(0); /* regedit.exe always terminates with error code zero */
121 ACTION_ADD
, ACTION_EXPORT
, ACTION_DELETE
125 static void PerformRegAction(REGEDIT_ACTION action
, WCHAR
**argv
, int *i
, BOOL silent
)
127 static void PerformRegAction(REGEDIT_ACTION action
, WCHAR
**argv
, int *i
)
132 WCHAR
*filename
= argv
[*i
];
133 WCHAR
*realname
= NULL
;
137 /* Request import confirmation */
142 UINT mbType
= MB_YESNO
;
144 LoadStringW(hInst
, IDS_IMPORT_PROMPT
, szText
, ARRAY_SIZE(szText
));
146 if (argv
[*i
+ 1] != NULL
)
148 /* Enable three buttons if there's another file coming */
149 mbType
= MB_YESNOCANCEL
;
152 choice
= InfoMessageBox(NULL
, mbType
| MB_ICONQUESTION
, szTitle
, szText
, filename
);
158 /* The cancel case is useful if the user is importing more than one registry file
159 * at a time, and wants to back out anytime during the import process. This way, the
160 * user doesn't have to resort to ending the regedit process abruptly just to cancel
162 * To achieve this, we skip all further command line arguments.
171 if (!lstrcmpW(filename
, L
"-"))
177 size
= SearchPathW(NULL
, filename
, NULL
, 0, NULL
, NULL
);
180 realname
= malloc(size
* sizeof(WCHAR
));
181 size
= SearchPathW(NULL
, filename
, NULL
, size
, realname
, NULL
);
185 output_message(STRING_FILE_NOT_FOUND
, filename
);
189 reg_file
= _wfopen(realname
, L
"rb");
190 if (reg_file
== NULL
)
192 _wperror(L
"regedit");
193 output_message(STRING_CANNOT_OPEN_FILE
, filename
);
198 import_registry_file(reg_file
);
207 delete_registry_key(argv
[*i
]);
209 case ACTION_EXPORT
: {
210 WCHAR
*filename
= argv
[*i
];
211 WCHAR
*key_name
= argv
[++(*i
)];
213 if (key_name
&& *key_name
)
214 export_registry_key(filename
, key_name
, REG_FORMAT_5
);
216 export_registry_key(filename
, NULL
, REG_FORMAT_5
);
221 output_message(STRING_UNHANDLED_ACTION
);
223 error_exit(STRING_UNHANDLED_ACTION
);
229 BOOL
ProcessCmdLine(WCHAR
*cmdline
)
233 REGEDIT_ACTION action
= ACTION_ADD
;
238 argv
= CommandLineToArgvW(cmdline
, &argc
);
249 for (i
= 1; i
< argc
; i
++)
251 if (argv
[i
][0] != '/' && argv
[i
][0] != '-')
252 break; /* No flags specified. */
254 if (!argv
[i
][1] && argv
[i
][0] == '-')
255 break; /* '-' is a filename. It indicates we should use stdin. */
257 if (argv
[i
][1] && argv
[i
][2] && argv
[i
][2] != ':')
258 break; /* This is a file path beginning with '/'. */
260 switch (towupper(argv
[i
][1]))
263 error_exit(STRING_USAGE
);
266 action
= ACTION_DELETE
;
269 action
= ACTION_EXPORT
;
286 output_message(STRING_INVALID_SWITCH
, argv
[i
]);
287 error_exit(STRING_HELP
);
297 output_message(STRING_NO_FILENAME
);
300 output_message(STRING_NO_REG_KEY
);
303 error_exit(STRING_HELP
);
306 for (; i
< argc
; i
++)
308 PerformRegAction(action
, argv
, &i
, silent
);
310 PerformRegAction(action
, argv
, &i
);