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
);