2 * Registry processing routines. Routines, common for registry
3 * processing frontends.
5 * Copyright 1999 Sylvain St-Germain
6 * Copyright 2002 Andriy Palamarchuk
8 * This library is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public
10 * License as published by the Free Software Foundation; either
11 * version 2.1 of the License, or (at your option) any later version.
13 * This library is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Lesser General Public License for more details.
18 * You should have received a copy of the GNU Lesser General Public
19 * License along with this library; if not, write to the Free Software
20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
39 #define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers
59 #define REG_VAL_BUF_SIZE 4096
61 /* Delimiters used to parse the "value" to query queryValue*/
62 #define QUERY_VALUE_MAX_ARGS 1
64 /* maximal number of characters in hexadecimal data line,
65 not including '\' character */
66 #define REG_FILE_HEX_LINE_LEN 76
68 /* Globals used by the api setValue, queryValue */
69 static LPTSTR currentKeyName = NULL;
70 static HKEY currentKeyClass = 0;
71 static HKEY currentKeyHandle = 0;
72 static BOOL bTheKeyIsOpen = FALSE;
74 static TCHAR *reg_class_names[] = {
75 _T("HKEY_LOCAL_MACHINE"),
77 _T("HKEY_CLASSES_ROOT"),
78 _T("HKEY_CURRENT_CONFIG"),
79 _T("HKEY_CURRENT_USER")
82 #define REG_CLASS_NUMBER (sizeof(reg_class_names) / sizeof(reg_class_names[0]))
84 static HKEY reg_class_keys[REG_CLASS_NUMBER] = {
85 HKEY_LOCAL_MACHINE, HKEY_USERS, HKEY_CLASSES_ROOT,
86 HKEY_CURRENT_CONFIG, HKEY_CURRENT_USER
90 #define NOT_ENOUGH_MEMORY 1
93 /* processing macros */
95 /* common check of memory allocation results */
97 #define CHECK_ENOUGH_MEMORY(p) \
100 _tprintf(_T("file %S, line %d: Not enough memory"), __FILE__, __LINE__); \
102 exit(NOT_ENOUGH_MEMORY); \
105 #define CHECK_ENOUGH_MEMORY(p) \
108 _tprintf(_T("file %s, line %d: Not enough memory"), __FILE__, __LINE__); \
110 exit(NOT_ENOUGH_MEMORY); \
120 /******************************************************************************
121 * This is a replacement for strsep which is not portable (missing on Solaris).
125 char* getToken(char** str, const char* delims)
135 while (**str!='\0') {
136 if (strchr(delims,**str)!=NULL) {
143 /* There is no other token */
149 /******************************************************************************
150 * Copies file name from command line string to the buffer.
151 * Rewinds the command line string pointer to the next non-spece character
152 * after the file name.
153 * Buffer contains an empty string if no filename was found;
156 * command_line - command line current position pointer
157 * where *s[0] is the first symbol of the file name.
158 * file_name - buffer to write the file name to.
160 void get_file_nameA(CHAR **command_line, CHAR *file_name, int max_filename)
162 CHAR *s = *command_line;
163 int pos = 0; /* position of pointer "s" in *command_line */
172 while (s[0] != '"') {
174 _tprintf(_T("Unexpected end of file name!\n"));
182 while (s[0] && !isspace(s[0])) {
187 memcpy(file_name, *command_line, pos * sizeof((*command_line)[0]));
188 /* remove the last backslash */
189 if (file_name[pos - 1] == '\\') {
190 file_name[pos - 1] = '\0';
192 file_name[pos] = '\0';
198 while (s[0] && isspace(s[0])) {
202 (*command_line) += pos;
205 void get_file_nameW(CHAR** command_line, WCHAR* filename, int max_filename)
207 CHAR filenameA[_MAX_PATH];
210 get_file_nameA(command_line, filenameA, _MAX_PATH);
211 len = strlen(filenameA);
212 OemToCharBuffW(filenameA, filename, max_filename);
213 filename[len] = _T('\0');
215 UNICODE_STRING UnicodeString;
216 ANSI_STRING AnsiString;
217 CHAR filenameA[_MAX_PATH];
219 get_file_nameA(command_line, filenameA, _MAX_PATH);
221 //RtlInitAnsiString(&AnsiString, filenameA);
222 UnicodeString.Buffer = filename;
223 UnicodeString.MaximumLength = max_filename;//MAX_PATH;
224 RtlAnsiStringToUnicodeString(&UnicodeString, &AnsiString, FALSE);
228 /******************************************************************************
229 * Converts a hex representation of a DWORD into a DWORD.
231 DWORD convertHexToDWord(TCHAR* str, BYTE* buf)
236 memcpy(xbuf, str, 8 * sizeof(TCHAR));
237 xbuf[88 * sizeof(TCHAR)] = '\0';
238 _stscanf(xbuf, _T("%08lx"), &dw);
239 memcpy(buf, &dw, sizeof(DWORD));
240 return sizeof(DWORD);
243 /******************************************************************************
244 * Converts a hex buffer into a hex comma separated values
246 TCHAR* convertHexToHexCSV(BYTE* buf, ULONG bufLen)
253 str = HeapAlloc(GetProcessHeap(), 0, (bufLen+1)*2*sizeof(TCHAR));
254 memset(str, 0, (bufLen+1)*2);
255 ptrStr = str; /* Pointer to result */
256 ptrBuf = buf; /* Pointer to current */
257 while (current < bufLen) {
258 BYTE bCur = ptrBuf[current++];
260 _stprintf(res, _T("%02x"), (unsigned int)*&bCur);
262 _tcscat(str, _T(","));
264 /* Get rid of the last comma */
265 str[_tcslen(str)-1] = _T('\0');
269 /******************************************************************************
270 * Converts a hex buffer into a DWORD string
272 TCHAR* convertHexToDWORDStr(BYTE* buf, ULONG bufLen)
277 if (bufLen != sizeof(DWORD)) return NULL;
278 str = HeapAlloc(GetProcessHeap(), 0, ((bufLen*2)+1)*sizeof(TCHAR));
279 memcpy(&dw, buf, sizeof(DWORD));
280 _stprintf(str, _T("%08lx"), dw);
281 /* Get rid of the last comma */
285 /******************************************************************************
286 * Converts a hex comma separated values list into a hex list.
287 * The Hex input string must be in exactly the correct form.
289 DWORD convertHexCSVToHex(TCHAR* str, BYTE* buf, ULONG bufLen)
291 TCHAR* s = str; /* Pointer to current */
292 CHAR* b = buf; /* Pointer to result */
293 ULONG strLen = _tcslen(str);
297 memset(buf, 0, bufLen);
299 * warn the user if we are here with a string longer than 2 bytes that does
300 * not contains ",". It is more likely because the data is invalid.
302 if ((strLen > 2) && (_tcschr(str, _T(',')) == NULL)) {
303 _tprintf(_T("WARNING converting CSV hex stream with no comma, ") \
304 _T("input data seems invalid.\n"));
306 if (strLen > 3*bufLen) {
307 _tprintf(_T("ERROR converting CSV hex stream. Too long\n"));
309 while (strPos < strLen) {
314 _stscanf(xbuf, _T("%02x"), (UINT*)&wc);
315 if (byteCount < bufLen)
316 *b++ = (unsigned char)wc;
324 /******************************************************************************
325 * This function returns the HKEY associated with the data type encoded in the
326 * value. It modifies the input parameter (key value) in order to skip this
327 * "now useless" data type information.
329 * Note: Updated based on the algorithm used in 'server/registry.c'
331 DWORD getDataType(LPTSTR* lpValue, DWORD* parse_type)
333 struct data_type { const TCHAR *tag; int len; int type; int parse_type; };
335 static const struct data_type data_types[] =
336 { /* actual type */ /* type to assume for parsing */
337 { _T("\""), 1, REG_SZ, REG_SZ },
338 { _T("str:\""), 5, REG_SZ, REG_SZ },
339 // { _T("str(2):\""), 8, REG_EXPAND_SZ, REG_SZ },
340 { _T("expand:\""), 8, REG_EXPAND_SZ, REG_EXPAND_SZ },
341 { _T("hex:"), 4, REG_BINARY, REG_BINARY },
342 { _T("dword:"), 6, REG_DWORD, REG_DWORD },
343 { _T("hex("), 4, -1, REG_BINARY },
347 const struct data_type *ptr;
350 for (ptr = data_types; ptr->tag; ptr++) {
351 if (memcmp(ptr->tag, *lpValue, ptr->len))
355 *parse_type = ptr->parse_type;
357 *lpValue += ptr->len;
360 /* "hex(xx):" is special */
361 type = (int)_tcstoul(*lpValue , &end, 16);
362 if (**lpValue == _T('\0') || *end != _T(')') || *(end+1) != _T(':')) {
370 return (**lpValue == _T('\0') ? REG_SZ : REG_NONE);
373 /******************************************************************************
374 * Returns an allocated buffer with a cleaned copy (removed the surrounding
375 * dbl quotes) of the passed value.
377 LPTSTR getArg(LPTSTR arg)
382 if (arg == NULL) return NULL;
384 // Get rid of surrounding quotes
386 if (arg[len-1] == _T('\"')) arg[len-1] = _T('\0');
387 if (arg[0] == _T('\"')) arg++;
388 tmp = HeapAlloc(GetProcessHeap(), 0, (_tcslen(arg)+1) * sizeof(TCHAR));
393 /******************************************************************************
394 * Replaces escape sequences with the characters.
396 void REGPROC_unescape_string(LPTSTR str)
398 int str_idx = 0; /* current character under analysis */
399 int val_idx = 0; /* the last character of the unescaped string */
400 int len = _tcslen(str);
401 for (str_idx = 0; str_idx < len; str_idx++, val_idx++) {
402 if (str[str_idx] == _T('\\')) {
404 switch (str[str_idx]) {
406 str[val_idx] = _T('\n');
410 str[val_idx] = str[str_idx];
413 _tprintf(_T("Warning! Unrecognized escape sequence: \\%c'\n"), str[str_idx]);
414 str[val_idx] = str[str_idx];
418 str[val_idx] = str[str_idx];
421 str[val_idx] = _T('\0');
424 /******************************************************************************
425 * Sets the value with name val_name to the data in val_data for the currently
429 * val_name - name of the registry value
430 * val_data - registry value data
432 HRESULT setValue(LPTSTR val_name, LPTSTR val_data)
435 DWORD dwDataType, dwParseType;
437 BYTE convert[KEY_MAX_LEN];
438 BYTE *bBigBuffer = 0;
441 if ((val_name == NULL) || (val_data == NULL))
442 return ERROR_INVALID_PARAMETER;
444 /* Get the data type stored into the value field */
445 dwDataType = getDataType(&val_data, &dwParseType);
447 // if (dwParseType == REG_EXPAND_SZ) {
449 // if (dwParseType == REG_SZ || dwParseType == REG_EXPAND_SZ) { /* no conversion for string */
451 if (dwParseType == REG_SZ) { /* no conversion for string */
452 dwLen = _tcslen(val_data);
453 if (dwLen > 0 && val_data[dwLen-1] == _T('"')) {
455 val_data[dwLen] = _T('\0');
458 dwLen *= sizeof(TCHAR);
459 REGPROC_unescape_string(val_data);
461 } else if (dwParseType == REG_DWORD) { /* Convert the dword types */
462 dwLen = convertHexToDWord(val_data, convert);
464 } else { /* Convert the hexadecimal types */
465 int b_len = _tcslen(val_data)+2/3;
466 if (b_len > KEY_MAX_LEN) {
467 bBigBuffer = HeapAlloc (GetProcessHeap(), 0, b_len * sizeof(TCHAR));
468 if (bBigBuffer == NULL) {
469 return ERROR_REGISTRY_IO_FAILED;
471 CHECK_ENOUGH_MEMORY(bBigBuffer);
472 dwLen = convertHexCSVToHex(val_data, bBigBuffer, b_len);
473 lpbData = bBigBuffer;
475 dwLen = convertHexCSVToHex(val_data, convert, KEY_MAX_LEN);
479 hRes = RegSetValueEx(currentKeyHandle, val_name,
480 0, /* Reserved */dwDataType, lpbData, dwLen);
482 _tprintf(_T(" Value: %s, Data: %s\n"), val_name, lpbData);
486 HeapFree(GetProcessHeap(), 0, bBigBuffer);
491 /******************************************************************************
494 HRESULT openKey(LPTSTR stdInput)
500 if (stdInput == NULL)
501 return ERROR_INVALID_PARAMETER;
503 /* Get the registry class */
504 currentKeyClass = getRegClass(stdInput); /* Sets global variable */
505 if (currentKeyClass == (HKEY)ERROR_INVALID_PARAMETER)
506 return (HRESULT)ERROR_INVALID_PARAMETER;
508 /* Get the key name */
509 currentKeyName = getRegKeyName(stdInput); /* Sets global variable */
510 if (currentKeyName == NULL)
511 return ERROR_INVALID_PARAMETER;
513 hRes = RegCreateKeyEx(
514 currentKeyClass, /* Class */
515 currentKeyName, /* Sub Key */
517 NULL, /* object type */
518 REG_OPTION_NON_VOLATILE, /* option, REG_OPTION_NON_VOLATILE ... */
519 KEY_ALL_ACCESS, /* access mask, KEY_ALL_ACCESS */
520 NULL, /* security attribute */
521 ¤tKeyHandle, /* result */
522 &dwDisp); /* disposition, REG_CREATED_NEW_KEY or
523 REG_OPENED_EXISTING_KEY */
525 if (hRes == ERROR_SUCCESS)
526 bTheKeyIsOpen = TRUE;
532 /******************************************************************************
533 * Extracts from [HKEY\some\key\path] or HKEY\some\key\path types of line
534 * the key name (what starts after the first '\')
536 LPTSTR getRegKeyName(LPTSTR lpLine)
539 TCHAR lpLineCopy[KEY_MAX_LEN];
544 _tcscpy(lpLineCopy, lpLine);
545 keyNameBeg = _tcschr(lpLineCopy, _T('\\')); /* The key name start by '\' */
549 keyNameBeg++; /* is not part of the name */
550 keyNameEnd = _tcschr(lpLineCopy, _T(']'));
552 *keyNameEnd = _T('\0'); /* remove ']' from the key name */
555 keyNameBeg = lpLineCopy + _tcslen(lpLineCopy); /* branch - empty string */
557 currentKeyName = HeapAlloc(GetProcessHeap(), 0, (_tcslen(keyNameBeg)+1)*sizeof(TCHAR));
558 CHECK_ENOUGH_MEMORY(currentKeyName);
559 _tcscpy(currentKeyName, keyNameBeg);
560 return currentKeyName;
563 /******************************************************************************
564 * Extracts from [HKEY\some\key\path] or HKEY\some\key\path types of line
565 * the key class (what ends before the first '\')
567 HKEY getRegClass(LPTSTR lpClass)
573 TCHAR lpClassCopy[KEY_MAX_LEN];
576 return (HKEY)ERROR_INVALID_PARAMETER;
578 _tcsncpy(lpClassCopy, lpClass, KEY_MAX_LEN);
580 classNameEnd = _tcschr(lpClassCopy, _T('\\')); /* The class name ends by '\' */
581 if (!classNameEnd) { /* or the whole string */
582 classNameEnd = lpClassCopy + _tcslen(lpClassCopy);
583 if (classNameEnd[-1] == _T(']')) {
587 *classNameEnd = _T('\0'); /* Isolate the class name */
588 if (lpClassCopy[0] == _T('[')) {
589 classNameBeg = lpClassCopy + 1;
591 classNameBeg = lpClassCopy;
593 for (i = 0; i < REG_CLASS_NUMBER; i++) {
594 if (!_tcscmp(classNameBeg, reg_class_names[i])) {
595 return reg_class_keys[i];
598 return (HKEY)ERROR_INVALID_PARAMETER;
601 /******************************************************************************
602 * Close the currently opened key.
606 RegCloseKey(currentKeyHandle);
607 HeapFree(GetProcessHeap(), 0, currentKeyName); /* Allocated by getKeyName */
608 bTheKeyIsOpen = FALSE;
609 currentKeyName = NULL;
611 currentKeyHandle = 0;
614 /******************************************************************************
615 * This function is the main entry point to the setValue type of action. It
616 * receives the currently read line and dispatch the work depending on the
619 void doSetValue(LPTSTR stdInput)
622 * We encountered the end of the file, make sure we
623 * close the opened key and exit
625 if (stdInput == NULL) {
626 if (bTheKeyIsOpen != FALSE)
631 if (stdInput[0] == _T('[')) { /* We are reading a new key */
632 if (bTheKeyIsOpen != FALSE) {
633 closeKey(); /* Close the previous key before */
635 if (openKey(stdInput) != ERROR_SUCCESS) {
636 _tprintf(_T("doSetValue failed to open key %s\n"), stdInput);
638 } else if ((bTheKeyIsOpen) &&
639 ((stdInput[0] == _T('@')) || /* reading a default @=data pair */
640 (stdInput[0] == _T('\"')))) { /* reading a new value=data pair */
641 processSetValue(stdInput);
642 } else { /* since we are assuming that the file format is */
643 if (bTheKeyIsOpen) /* valid we must be reading a blank line which */
644 closeKey(); /* indicate end of this key processing */
648 /******************************************************************************
649 * This funtion is the main entry point to the queryValue type of action. It
650 * receives the currently read line and dispatch the work depending on the
653 void doQueryValue(LPTSTR stdInput) {
655 * We encoutered the end of the file, make sure we
656 * close the opened key and exit
658 if (stdInput == NULL) {
659 if (bTheKeyIsOpen != FALSE)
664 if (stdInput[0] == _T('[')) { /* We are reading a new key */
665 if (bTheKeyIsOpen != FALSE)
666 closeKey(); /* Close the previous key before */
667 if (openKey(stdInput) != ERROR_SUCCESS ) {
668 _tprintf(_T("doQueryValue failed to open key %s\n"), stdInput);
671 else if( (bTheKeyIsOpen) &&
672 ((stdInput[0] == _T('@')) || /* reading a default @=data pair */
673 (stdInput[0] == _T('\"')))) { /* reading a new value=data pair */
674 processQueryValue(stdInput);
675 } else { /* since we are assuming that the file format is */
676 if (bTheKeyIsOpen) /* valid we must be reading a blank line which */
677 closeKey(); /* indicate end of this key processing */
681 /******************************************************************************
682 * This funtion is the main entry point to the deletetValue type of action. It
683 * receives the currently read line and dispatch the work depending on the
686 void doDeleteValue(LPTSTR line) {
687 _tprintf(_T("deleteValue not yet implemented\n"));
690 /******************************************************************************
691 * This funtion is the main entry point to the deleteKey type of action. It
692 * receives the currently read line and dispatch the work depending on the
695 void doDeleteKey(LPTSTR line) {
696 _tprintf(_T("deleteKey not yet implemented\n"));
699 /******************************************************************************
700 * This funtion is the main entry point to the createKey type of action. It
701 * receives the currently read line and dispatch the work depending on the
704 void doCreateKey(LPTSTR line) {
705 _tprintf(_T("createKey not yet implemented\n"));
708 /******************************************************************************
709 * This function is a wrapper for the setValue function. It prepares the
710 * land and clean the area once completed.
711 * Note: this function modifies the line parameter.
713 * line - registry file unwrapped line. Should have the registry value name and
714 * complete registry value data.
716 void processSetValue(LPTSTR line)
718 LPTSTR val_name; /* registry value name */
719 LPTSTR val_data; /* registry value data */
721 int line_idx = 0; /* current character under analysis */
725 if (line[line_idx] == _T('@') && line[line_idx + 1] == _T('=')) {
726 line[line_idx] = _T('\0');
729 } else if (line[line_idx] == _T('\"')) {
731 val_name = line + line_idx;
733 if (line[line_idx] == _T('\\')) { /* skip escaped character */
736 if (line[line_idx] == _T('\"')) {
737 line[line_idx] = _T('\0');
745 if (line[line_idx] != _T('=')) {
746 line[line_idx] = _T('\"');
747 _tprintf(_T("Warning! uncrecognized line:\n%s\n"), line);
751 _tprintf(_T("Warning! unrecognized line:\n%s\n"), line);
754 line_idx++; /* skip the '=' character */
755 val_data = line + line_idx;
756 REGPROC_unescape_string(val_name);
758 _tprintf(_T("Key: %s, Value: %s, Data: %s\n"), currentKeyName, val_name, val_data);
760 hRes = setValue(val_name, val_data);
761 if (hRes != ERROR_SUCCESS) {
762 _tprintf(_T("ERROR Key %s not created. Value: %s, Data: %s\n"), currentKeyName, val_name, val_data);
766 /******************************************************************************
767 * This function is a wrapper for the queryValue function. It prepares the
768 * land and clean the area once completed.
770 void processQueryValue(LPTSTR cmdline)
772 _tprintf(_T("ERROR!!! - temporary disabled"));
776 LPSTR argv[QUERY_VALUE_MAX_ARGS];/* args storage */
777 LPSTR token = NULL; /* current token analized */
778 ULONG argCounter = 0; /* counter of args */
781 LPSTR keyValue = NULL;
785 * Init storage and parse the line
787 for (counter = 0; counter < QUERY_VALUE_MAX_ARGS; counter++)
788 argv[counter] = NULL;
790 while ((token = getToken(&cmdline, queryValueDelim[argCounter])) != NULL) {
791 argv[argCounter++] = getArg(token);
792 if (argCounter == QUERY_VALUE_MAX_ARGS)
793 break; /* Stop processing args no matter what */
796 /* The value we look for is the first token on the line */
798 return; /* SHOULD NOT HAPPEN */
802 if ((keyValue[0] == '@') && (_tcslen(keyValue) == 1)) {
803 LONG lLen = KEY_MAX_LEN;
804 TCHAR* lpsData = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,KEY_MAX_LEN);
806 * We need to query the key default value
808 hRes = RegQueryValue(currentKeyHandle, currentKeyName, (LPBYTE)lpsData, &lLen);
809 if (hRes == ERROR_MORE_DATA) {
810 lpsData = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, lpsData, lLen);
811 hRes = RegQueryValue(currentKeyHandle, currentKeyName, (LPBYTE)lpsData, &lLen);
813 if (hRes == ERROR_SUCCESS) {
814 lpsRes = HeapAlloc(GetProcessHeap(), 0, lLen);
815 strncpy(lpsRes, lpsData, lLen);
819 DWORD dwLen = KEY_MAX_LEN;
820 BYTE* lpbData = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, KEY_MAX_LEN);
823 * We need to query a specific value for the key
825 hRes = RegQueryValueEx(
833 if (hRes == ERROR_MORE_DATA) {
834 lpbData = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, lpbData, dwLen * sizeof(TCHAR));
835 hRes = RegQueryValueEx(currentKeyHandle, keyValue, NULL, &dwType, (LPBYTE)lpbData, &dwLen);
838 if (hRes == ERROR_SUCCESS) {
840 * Convert the returned data to a displayable format
845 lpsRes = HeapAlloc(GetProcessHeap(), 0, dwLen * sizeof(TCHAR));
846 strncpy(lpsRes, lpbData, dwLen);
847 lpsRes[dwLen-1] = '\0';
850 lpsRes = convertHexToDWORDStr(lpbData, dwLen);
853 lpsRes = convertHexToHexCSV(lpbData, dwLen);
858 HeapFree(GetProcessHeap(), 0, lpbData);
860 if (hRes == ERROR_SUCCESS) {
861 _tprintf(_T("Value \"%s\" = \"%s\" in key [%s]\n"), keyValue, lpsRes, currentKeyName);
864 _tprintf(_T("ERROR Value \"%s\" not found. for key \"%s\"\n"), keyValue, currentKeyName);
870 for (counter=0; counter<argCounter; counter++)
871 if (argv[counter] != NULL)
872 HeapFree(GetProcessHeap(), 0, argv[counter]);
875 HeapFree(GetProcessHeap(), 0, lpsRes);
879 /******************************************************************************
880 * Calls command for each line of a registry file.
881 * Correctly processes comments (in # form), line continuation.
884 * in - input stream to read from
885 * command - command to be called for each line
887 void processRegLines(FILE *in, CommandAPI command)
889 LPTSTR line = NULL; /* line read from input stream */
890 ULONG lineSize = REG_VAL_BUF_SIZE;
892 line = HeapAlloc(GetProcessHeap(), 0, lineSize * sizeof(TCHAR));
893 CHECK_ENOUGH_MEMORY(line);
896 LPTSTR s; /* The pointer into line for where the current fgets should read */
899 size_t size_remaining;
901 TCHAR *s_eol; /* various local uses */
903 /* Do we need to expand the buffer ? */
904 assert (s >= line && s <= line + lineSize);
905 size_remaining = lineSize - (s-line);
906 if (size_remaining < 2) { /* room for 1 character and the \0 */
908 size_t new_size = lineSize + REG_VAL_BUF_SIZE;
909 if (new_size > lineSize) /* no arithmetic overflow */
910 new_buffer = HeapReAlloc (GetProcessHeap(), 0, line, new_size * sizeof(TCHAR));
913 CHECK_ENOUGH_MEMORY(new_buffer);
915 s = line + lineSize - size_remaining;
917 size_remaining = lineSize - (s-line);
920 /* Get as much as possible into the buffer, terminated either by
921 * eof, error, eol or getting the maximum amount. Abort on error.
924 // This line is surely foobar, don't want to read INT_MAX in buffer at s, it's never going to be that big...
925 // size_to_get = (size_remaining > INT_MAX ? INT_MAX : size_remaining);
927 // Looks as if 'lineSize' contains the number of characters of buffer size
929 size_to_get = (size_remaining > lineSize ? lineSize : size_remaining);
931 if (NULL == _fgetts(s, size_to_get, in)) {
933 //_tperror(_T("While reading input"));
934 perror ("While reading input");
940 /* It is not clear to me from the definition that the
941 * contents of the buffer are well defined on detecting
942 * an eof without managing to read anything.
947 /* If we didn't read the eol nor the eof go around for the rest */
948 s_eol = _tcschr (s, _T('\n'));
949 if (!feof (in) && !s_eol) {
950 s = _tcschr (s, _T('\0'));
951 /* It should be s + size_to_get - 1 but this is safer */
955 /* If it is a comment line then discard it and go around again */
956 if (line [0] == _T('#')) {
961 /* Remove any line feed. Leave s_eol on the \0 */
964 if (s_eol > line && *(s_eol-1) == _T('\r'))
967 s_eol = _tcschr (s, _T('\0'));
969 /* If there is a concatenating \\ then go around again */
970 if (s_eol > line && *(s_eol-1) == _T('\\')) {
973 /* The following error protection could be made more self-
974 * correcting but I thought it not worth trying.
977 if ((c = _fgettc(in)) == _TEOF || c != _T(' ') ||
978 (c = _fgettc(in)) == _TEOF || c != _T(' '))
979 _tprintf(_T("ERROR - invalid continuation.\n"));
982 break; /* That is the full virtual line */
987 HeapFree(GetProcessHeap(), 0, line);
990 /******************************************************************************
991 * This funtion is the main entry point to the registerDLL action. It
992 * receives the currently read line, then loads and registers the requested DLLs
994 void doRegisterDLL(LPTSTR stdInput)
999 /* Check for valid input */
1000 if (stdInput == NULL) return;
1002 /* Load and register the library, then free it */
1003 theLib = LoadLibrary(stdInput);
1005 FARPROC lpfnDLLRegProc = GetProcAddress(theLib, "DllRegisterServer");
1006 if (lpfnDLLRegProc) {
1007 retVal = (*lpfnDLLRegProc)();
1009 _tprintf(_T("Couldn't find DllRegisterServer proc in '%s'.\n"), stdInput);
1011 if (retVal != S_OK) {
1012 _tprintf(_T("Couldn't find DllRegisterServer proc in '%s'.\n"), stdInput);
1014 FreeLibrary(theLib);
1016 _tprintf(_T("Could not load DLL '%s'.\n"), stdInput);
1020 /******************************************************************************
1021 * This funtion is the main entry point to the unregisterDLL action. It
1022 * receives the currently read line, then loads and unregisters the requested DLLs
1024 void doUnregisterDLL(LPTSTR stdInput)
1029 /* Check for valid input */
1030 if (stdInput == NULL) return;
1032 /* Load and unregister the library, then free it */
1033 theLib = LoadLibrary(stdInput);
1035 FARPROC lpfnDLLRegProc = GetProcAddress(theLib, "DllUnregisterServer");
1036 if (lpfnDLLRegProc) {
1037 retVal = (*lpfnDLLRegProc)();
1039 _tprintf(_T("Couldn't find DllUnregisterServer proc in '%s'.\n"), stdInput);
1041 if (retVal != S_OK) {
1042 _tprintf(_T("DLLUnregisterServer error 0x%x in '%s'.\n"), retVal, stdInput);
1044 FreeLibrary(theLib);
1046 _tprintf(_T("Could not load DLL '%s'.\n"), stdInput);
1050 /****************************************************************************
1051 * REGPROC_print_error
1053 * Print the message for GetLastError
1056 void REGPROC_print_error(VOID)
1062 error_code = GetLastError ();
1063 status = FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
1064 NULL, error_code, 0, (LPTSTR) &lpMsgBuf, 0, NULL);
1066 _tprintf(_T("Cannot display message for error %ld, status %ld\n"), error_code, GetLastError());
1068 _tprintf(_T("REGPROC_print_error() - "));
1070 LocalFree((HLOCAL)lpMsgBuf);
1075 /******************************************************************************
1076 * Checks whether the buffer has enough room for the string or required size.
1077 * Resizes the buffer if necessary.
1080 * buffer - pointer to a buffer for string
1081 * len - current length of the buffer in characters.
1082 * required_len - length of the string to place to the buffer in characters.
1083 * The length does not include the terminating null character.
1085 void REGPROC_resize_char_buffer(TCHAR **buffer, DWORD *len, DWORD required_len)
1088 if (required_len > *len) {
1089 *len = required_len;
1090 *buffer = HeapReAlloc(GetProcessHeap(), 0, *buffer, *len * sizeof(**buffer));
1091 CHECK_ENOUGH_MEMORY(*buffer);
1095 /******************************************************************************
1096 * Prints string str to file
1098 void REGPROC_export_string(FILE *file, TCHAR *str)
1100 size_t len = _tcslen(str);
1103 /* escaping characters */
1104 for (i = 0; i < len; i++) {
1107 //case _T('\\'): _fputts(_T("\\\\"), file); break;
1108 case _T('\"'): _fputts(_T("\\\""), file); break;
1109 case _T('\n'): _fputts(_T("\\\n"), file); break;
1110 default: _fputtc(c, file); break;
1115 /******************************************************************************
1116 * Writes contents of the registry key to the specified file stream.
1119 * file - writable file stream to export registry branch to.
1120 * key - registry branch to export.
1121 * reg_key_name_buf - name of the key with registry class.
1122 * Is resized if necessary.
1123 * reg_key_name_len - length of the buffer for the registry class in characters.
1124 * val_name_buf - buffer for storing value name.
1125 * Is resized if necessary.
1126 * val_name_len - length of the buffer for storing value names in characters.
1127 * val_buf - buffer for storing values while extracting.
1128 * Is resized if necessary.
1129 * val_size - size of the buffer for storing values in bytes.
1131 void export_hkey(FILE *file, HKEY key,
1132 TCHAR **reg_key_name_buf, DWORD *reg_key_name_len,
1133 TCHAR **val_name_buf, DWORD *val_name_len,
1134 BYTE **val_buf, DWORD *val_size)
1136 DWORD max_sub_key_len;
1137 DWORD max_val_name_len;
1144 /* get size information and resize the buffers if necessary */
1145 if (RegQueryInfoKey(key, NULL, NULL, NULL, NULL, &max_sub_key_len, NULL,
1146 NULL, &max_val_name_len, &max_val_size, NULL, NULL) != ERROR_SUCCESS) {
1147 REGPROC_print_error();
1149 curr_len = _tcslen(*reg_key_name_buf);
1150 REGPROC_resize_char_buffer(reg_key_name_buf, reg_key_name_len, max_sub_key_len + curr_len + 1);
1151 REGPROC_resize_char_buffer(val_name_buf, val_name_len, max_val_name_len);
1152 if (max_val_size > *val_size) {
1153 *val_size = max_val_size;
1154 *val_buf = HeapReAlloc(GetProcessHeap(), 0, *val_buf, *val_size * sizeof(TCHAR));
1155 CHECK_ENOUGH_MEMORY(val_buf);
1157 /* output data for the current key */
1158 _fputts(_T("\n["), file);
1159 _fputts(*reg_key_name_buf, file);
1160 _fputts(_T("]\n"), file);
1161 /* print all the values */
1166 DWORD val_name_len1 = *val_name_len;
1167 DWORD val_size1 = *val_size;
1168 ret = RegEnumValue(key, i, *val_name_buf, &val_name_len1, NULL, &value_type, *val_buf, &val_size1);
1169 if (ret != ERROR_SUCCESS) {
1171 if (ret != ERROR_NO_MORE_ITEMS) {
1172 REGPROC_print_error();
1176 if ((*val_name_buf)[0]) {
1177 _fputts(_T("\""), file);
1178 REGPROC_export_string(file, *val_name_buf);
1179 _fputts(_T("\"="), file);
1181 _fputts(_T("@="), file);
1183 switch (value_type) {
1185 _fputts(_T("expand:"), file);
1187 _fputts(_T("\""), file);
1188 REGPROC_export_string(file, *val_buf);
1189 _fputts(_T("\"\n"), file);
1192 _ftprintf(file, _T("dword:%08lx\n"), *((DWORD *)*val_buf));
1196 _tprintf(_T("warning - unsupported registry format '%ld', ") \
1197 _T("treating as binary\n"), value_type);
1198 _tprintf(_T("key name: \"%s\"\n"), *reg_key_name_buf);
1199 _tprintf(_T("value name:\"%s\"\n\n"), *val_name_buf);
1211 if (value_type == REG_BINARY) {
1212 hex_prefix = _T("hex:");
1215 _stprintf(buf, _T("hex(%ld):"), value_type);
1217 /* position of where the next character will be printed */
1218 /* NOTE: yes, _tcslen("hex:") is used even for hex(x): */
1219 cur_pos = _tcslen(_T("\"\"=")) + _tcslen(_T("hex:")) +
1220 _tcslen(*val_name_buf);
1221 _fputts(hex_prefix, file);
1222 for (i1 = 0; i1 < val_size1; i1++) {
1223 _ftprintf(file, _T("%02x"), (unsigned int)(*val_buf)[i1]);
1224 if (i1 + 1 < val_size1) {
1225 _fputts(_T(","), file);
1229 if (cur_pos > REG_FILE_HEX_LINE_LEN) {
1230 _fputts(_T("\\\n "), file);
1234 _fputts(_T("\n"), file);
1242 (*reg_key_name_buf)[curr_len] = _T('\\');
1244 DWORD buf_len = *reg_key_name_len - curr_len;
1245 ret = RegEnumKeyEx(key, i, *reg_key_name_buf + curr_len + 1, &buf_len, NULL, NULL, NULL, NULL);
1246 if (ret != ERROR_SUCCESS && ret != ERROR_MORE_DATA) {
1248 if (ret != ERROR_NO_MORE_ITEMS) {
1249 REGPROC_print_error();
1255 if (RegOpenKey(key, *reg_key_name_buf + curr_len + 1, &subkey) == ERROR_SUCCESS) {
1256 export_hkey(file, subkey, reg_key_name_buf, reg_key_name_len, val_name_buf, val_name_len, val_buf, val_size);
1257 RegCloseKey(subkey);
1259 REGPROC_print_error();
1263 (*reg_key_name_buf)[curr_len] = _T('\0');
1266 #define REG_NONE ( 0 ) // No value type
1267 #define REG_SZ ( 1 ) // Unicode nul terminated string
1268 #define REG_EXPAND_SZ ( 2 ) // Unicode nul terminated string
1269 // (with environment variable references)
1270 #define REG_BINARY ( 3 ) // Free form binary
1271 #define REG_DWORD ( 4 ) // 32-bit number
1272 #define REG_DWORD_LITTLE_ENDIAN ( 4 ) // 32-bit number (same as REG_DWORD)
1273 #define REG_DWORD_BIG_ENDIAN ( 5 ) // 32-bit number
1274 #define REG_LINK ( 6 ) // Symbolic Link (unicode)
1275 #define REG_MULTI_SZ ( 7 ) // Multiple Unicode strings
1276 #define REG_RESOURCE_LIST ( 8 ) // Resource list in the resource map
1277 #define REG_FULL_RESOURCE_DESCRIPTOR ( 9 ) // Resource list in the hardware description
1278 #define REG_RESOURCE_REQUIREMENTS_LIST ( 10 )
1281 /******************************************************************************
1282 * Open file for export.
1284 FILE *REGPROC_open_export_file(TCHAR *file_name)
1286 //_CRTIMP FILE * __cdecl _wfopen(const wchar_t *, const wchar_t *);
1288 //FILE* fopen (const char* szFileName, const char* szMode);
1289 //FILE* _wfopen(const wchar_t *file, const wchar_t *mode);
1291 FILE *file = _tfopen(file_name, _T("w"));
1294 _tprintf(_T("REGPROC_open_export_file(%s) - Can't open file.\n"), file_name);
1298 _fputts(_T("REGEDIT4\n"), file);
1302 /******************************************************************************
1303 * Writes contents of the registry key to the specified file stream.
1306 * file_name - name of a file to export registry branch to.
1307 * reg_key_name - registry branch to export. The whole registry is exported if
1308 * reg_key_name is NULL or contains an empty string.
1310 BOOL export_registry_key(TCHAR* file_name, TCHAR* reg_key_name)
1314 TCHAR *reg_key_name_buf;
1315 TCHAR *val_name_buf;
1317 DWORD reg_key_name_len = KEY_MAX_LEN;
1318 DWORD val_name_len = KEY_MAX_LEN;
1319 DWORD val_size = REG_VAL_BUF_SIZE;
1322 //_tprintf(_T("export_registry_key(%s, %s)\n"), reg_key_name, file_name);
1324 reg_key_name_buf = HeapAlloc(GetProcessHeap(), 0, reg_key_name_len * sizeof(*reg_key_name_buf));
1325 val_name_buf = HeapAlloc(GetProcessHeap(), 0, val_name_len * sizeof(*val_name_buf));
1326 val_buf = HeapAlloc(GetProcessHeap(), 0, val_size);
1327 CHECK_ENOUGH_MEMORY(reg_key_name_buf && val_name_buf && val_buf);
1329 if (reg_key_name && reg_key_name[0]) {
1333 REGPROC_resize_char_buffer(®_key_name_buf, ®_key_name_len,
1334 _tcslen(reg_key_name));
1335 _tcscpy(reg_key_name_buf, reg_key_name);
1337 /* open the specified key */
1338 reg_key_class = getRegClass(reg_key_name);
1339 if (reg_key_class == (HKEY)ERROR_INVALID_PARAMETER) {
1340 _tprintf(_T("Incorrect registry class specification in '%s\n"), reg_key_name);
1344 branch_name = getRegKeyName(reg_key_name);
1345 CHECK_ENOUGH_MEMORY(branch_name);
1346 if (!branch_name[0]) {
1347 /* no branch - registry class is specified */
1348 file = REGPROC_open_export_file(file_name);
1349 export_hkey(file, reg_key_class,
1350 ®_key_name_buf, ®_key_name_len,
1351 &val_name_buf, &val_name_len,
1352 &val_buf, &val_size);
1353 } else if (RegOpenKey(reg_key_class, branch_name, &key) == ERROR_SUCCESS) {
1354 file = REGPROC_open_export_file(file_name);
1355 export_hkey(file, key,
1356 ®_key_name_buf, ®_key_name_len,
1357 &val_name_buf, &val_name_len,
1358 &val_buf, &val_size);
1361 _tprintf(_T("Can't export. Registry key '%s does not exist!\n"), reg_key_name);
1362 REGPROC_print_error();
1364 HeapFree(GetProcessHeap(), 0, branch_name);
1368 /* export all registry classes */
1369 file = REGPROC_open_export_file(file_name);
1370 for (i = 0; i < REG_CLASS_NUMBER; i++) {
1371 /* do not export HKEY_CLASSES_ROOT */
1372 if (reg_class_keys[i] != HKEY_CLASSES_ROOT &&
1373 reg_class_keys[i] != HKEY_CURRENT_USER &&
1374 reg_class_keys[i] != HKEY_CURRENT_CONFIG) {
1375 _tcscpy(reg_key_name_buf, reg_class_names[i]);
1376 export_hkey(file, reg_class_keys[i],
1377 ®_key_name_buf, ®_key_name_len,
1378 &val_name_buf, &val_name_len,
1379 &val_buf, &val_size);
1386 // HeapFree(GetProcessHeap(), 0, reg_key_name);
1387 HeapFree(GetProcessHeap(), 0, val_buf);
1388 HeapFree(GetProcessHeap(), 0, val_name_buf);
1389 HeapFree(GetProcessHeap(), 0, reg_key_name_buf);
1393 /******************************************************************************
1394 * Reads contents of the specified file into the registry.
1396 BOOL import_registry_file(LPTSTR filename)
1398 FILE* reg_file = _tfopen(filename, _T("r"));
1401 processRegLines(reg_file, doSetValue);
1407 /******************************************************************************
1408 * Recursive function which removes the registry key with all subkeys.
1410 BOOL delete_branch(HKEY key, TCHAR** reg_key_name_buf, DWORD* reg_key_name_len)
1413 DWORD max_sub_key_len;
1419 if (RegOpenKey(key, *reg_key_name_buf, &branch_key) != ERROR_SUCCESS) {
1420 REGPROC_print_error();
1424 /* get size information and resize the buffers if necessary */
1425 if (RegQueryInfoKey(branch_key, NULL, NULL, NULL, &subkeys, &max_sub_key_len,
1426 NULL, NULL, NULL, NULL, NULL, NULL) != ERROR_SUCCESS) {
1427 REGPROC_print_error();
1428 RegCloseKey(branch_key);
1431 curr_len = _tcslen(*reg_key_name_buf);
1432 REGPROC_resize_char_buffer(reg_key_name_buf, reg_key_name_len, max_sub_key_len + curr_len + 1);
1434 (*reg_key_name_buf)[curr_len] = '\\';
1435 for (i = subkeys - 1; i >= 0; i--) {
1436 DWORD buf_len = *reg_key_name_len - curr_len;
1437 ret = RegEnumKeyEx(branch_key, i, *reg_key_name_buf + curr_len + 1, &buf_len, NULL, NULL, NULL, NULL);
1438 if (ret != ERROR_SUCCESS && ret != ERROR_MORE_DATA && ret != ERROR_NO_MORE_ITEMS) {
1439 REGPROC_print_error();
1440 RegCloseKey(branch_key);
1443 delete_branch(key, reg_key_name_buf, reg_key_name_len);
1446 (*reg_key_name_buf)[curr_len] = '\0';
1447 RegCloseKey(branch_key);
1448 RegDeleteKey(key, *reg_key_name_buf);
1452 /******************************************************************************
1453 * Removes the registry key with all subkeys. Parses full key name.
1456 * reg_key_name - full name of registry branch to delete. Ignored if is NULL,
1457 * empty, points to register key class, does not exist.
1459 void delete_registry_key(TCHAR* reg_key_name)
1462 DWORD branch_name_len;
1466 if (!reg_key_name || !reg_key_name[0]) {
1469 /* open the specified key */
1470 reg_key_class = getRegClass(reg_key_name);
1471 if (reg_key_class == (HKEY)ERROR_INVALID_PARAMETER) {
1472 _tprintf(_T("Incorrect registry class specification in '%s'\n"), reg_key_name);
1476 branch_name = getRegKeyName(reg_key_name);
1477 CHECK_ENOUGH_MEMORY(branch_name);
1478 branch_name_len = _tcslen(branch_name);
1479 if (!branch_name[0]) {
1480 _tprintf(_T("Can't delete registry class '%s'\n"), reg_key_name);
1484 if (RegOpenKey(reg_key_class, branch_name, &branch_key) == ERROR_SUCCESS) {
1485 /* check whether the key exists */
1486 RegCloseKey(branch_key);
1487 delete_branch(reg_key_class, &branch_name, &branch_name_len);
1489 HeapFree(GetProcessHeap(), 0, branch_name);