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
25 #define REG_VAL_BUF_SIZE 4096
27 /* Delimiters used to parse the "value" to query queryValue*/
28 #define QUERY_VALUE_MAX_ARGS 1
30 /* maximal number of characters in hexadecimal data line,
31 not including '\' character */
32 #define REG_FILE_HEX_LINE_LEN 76
34 /* Globals used by the api setValue, queryValue */
35 static LPSTR currentKeyName
= NULL
;
36 static HKEY currentKeyClass
= 0;
37 static HKEY currentKeyHandle
= 0;
38 static BOOL bTheKeyIsOpen
= FALSE
;
40 static const CHAR
*app_name
= "UNKNOWN";
42 static const CHAR
*reg_class_names
[] = {
43 "HKEY_LOCAL_MACHINE", "HKEY_USERS", "HKEY_CLASSES_ROOT",
44 "HKEY_CURRENT_CONFIG", "HKEY_CURRENT_USER", "HKEY_DYN_DATA"
47 #define REG_CLASS_NUMBER (sizeof(reg_class_names) / sizeof(reg_class_names[0]))
49 static HKEY reg_class_keys
[REG_CLASS_NUMBER
] = {
50 HKEY_LOCAL_MACHINE
, HKEY_USERS
, HKEY_CLASSES_ROOT
,
51 HKEY_CURRENT_CONFIG
, HKEY_CURRENT_USER
, HKEY_DYN_DATA
55 #define NOT_ENOUGH_MEMORY 1
58 /* processing macros */
60 /* common check of memory allocation results */
61 #define CHECK_ENOUGH_MEMORY(p) \
64 fprintf(stderr,"%s: file %s, line %d: Not enough memory", \
65 getAppName(), __FILE__, __LINE__); \
66 exit(NOT_ENOUGH_MEMORY); \
69 /******************************************************************************
70 * This is a replacement for strsep which is not portable (missing on Solaris).
74 char* getToken(char** str
, const char* delims
)
85 if (strchr(delims
,**str
)!=NULL
) {
92 /* There is no other token */
98 /******************************************************************************
99 * Copies file name from command line string to the buffer.
100 * Rewinds the command line string pointer to the next non-space character
101 * after the file name.
102 * Buffer contains an empty string if no filename was found;
105 * command_line - command line current position pointer
106 * where *s[0] is the first symbol of the file name.
107 * file_name - buffer to write the file name to.
109 void get_file_name(CHAR
**command_line
, CHAR
*file_name
)
111 CHAR
*s
= *command_line
;
112 int pos
= 0; /* position of pointer "s" in *command_line */
124 fprintf(stderr
,"%s: Unexpected end of file name!\n",
132 while(s
[0] && !isspace(s
[0])) {
137 memcpy(file_name
, *command_line
, pos
* sizeof((*command_line
)[0]));
138 /* remove the last backslash */
139 if (file_name
[pos
- 1] == '\\') {
140 file_name
[pos
- 1] = '\0';
142 file_name
[pos
] = '\0';
149 while(s
[0] && isspace(s
[0])) {
153 (*command_line
) += pos
;
157 /******************************************************************************
158 * Converts a hex representation of a DWORD into a DWORD.
160 DWORD
convertHexToDWord(char *str
, BYTE
*buf
)
167 sscanf(xbuf
,"%08lx",&dw
);
168 memcpy(buf
,&dw
,sizeof(DWORD
));
169 return sizeof(DWORD
);
172 /******************************************************************************
173 * Converts a hex buffer into a hex comma separated values
175 char* convertHexToHexCSV(BYTE
*buf
, ULONG bufLen
)
183 str
= HeapAlloc(GetProcessHeap(), 0, (bufLen
+1)*2);
184 memset(str
, 0, (bufLen
+1)*2);
185 ptrStr
= str
; /* Pointer to result */
186 ptrBuf
= buf
; /* Pointer to current */
188 while (current
< bufLen
) {
189 BYTE bCur
= ptrBuf
[current
++];
192 sprintf(res
, "%02x", (unsigned int)*&bCur
);
197 /* Get rid of the last comma */
198 str
[strlen(str
)-1] = '\0';
202 /******************************************************************************
203 * Converts a hex buffer into a DWORD string
205 char* convertHexToDWORDStr(BYTE
*buf
, ULONG bufLen
)
210 if ( bufLen
!= sizeof(DWORD
) ) return NULL
;
212 str
= HeapAlloc(GetProcessHeap(), 0, (bufLen
*2)+1);
214 memcpy(&dw
,buf
,sizeof(DWORD
));
215 sprintf(str
, "%08lx", dw
);
217 /* Get rid of the last comma */
221 /******************************************************************************
222 * Converts a hex comma separated values list into a hex list.
223 * The Hex input string must be in exactly the correct form.
225 DWORD
convertHexCSVToHex(char *str
, BYTE
*buf
, ULONG bufLen
)
227 char *s
= str
; /* Pointer to current */
228 char *b
= (char*) buf
; /* Pointer to result */
230 size_t strLen
= strlen(str
);
234 memset(buf
, 0, bufLen
);
237 * warn the user if we are here with a string longer than 2 bytes that does
238 * not contains ",". It is more likely because the data is invalid.
240 if ( ( strLen
> 2) && ( strchr(str
, ',') == NULL
) )
241 fprintf(stderr
,"%s: WARNING converting CSV hex stream with no comma, "
242 "input data seems invalid.\n", getAppName());
243 if (strLen
> 3*bufLen
)
244 fprintf(stderr
,"%s: ERROR converting CSV hex stream. Too long\n",
247 while (strPos
< strLen
) {
251 memcpy(xbuf
,s
,2); xbuf
[2]='\0';
252 sscanf(xbuf
,"%02x",&wc
);
253 if (byteCount
< bufLen
)
254 *b
++ =(unsigned char)wc
;
264 /******************************************************************************
265 * This function returns the HKEY associated with the data type encoded in the
266 * value. It modifies the input parameter (key value) in order to skip this
267 * "now useless" data type information.
269 * Note: Updated based on the algorithm used in 'server/registry.c'
271 DWORD
getDataType(LPSTR
*lpValue
, DWORD
* parse_type
)
273 struct data_type
{ const char *tag
; int len
; int type
; int parse_type
; };
275 static const struct data_type data_types
[] = { /* actual type */ /* type to assume for parsing */
276 { "\"", 1, REG_SZ
, REG_SZ
},
277 { "str:\"", 5, REG_SZ
, REG_SZ
},
278 { "str(2):\"", 8, REG_EXPAND_SZ
, REG_SZ
},
279 { "hex:", 4, REG_BINARY
, REG_BINARY
},
280 { "dword:", 6, REG_DWORD
, REG_DWORD
},
281 { "hex(", 4, -1, REG_BINARY
},
285 const struct data_type
*ptr
;
288 for (ptr
= data_types
; ptr
->tag
; ptr
++) {
289 if (memcmp( ptr
->tag
, *lpValue
, ptr
->len
))
293 *parse_type
= ptr
->parse_type
;
298 /* "hex(xx):" is special */
299 type
= (int)strtoul( *lpValue
, &end
, 16 );
300 if (**lpValue
=='\0' || *end
!=')' || *(end
+1)!=':') {
308 return (**lpValue
=='\0'?REG_SZ
:REG_NONE
);
311 /******************************************************************************
312 * Returns an allocated buffer with a cleaned copy (removed the surrounding
313 * dbl quotes) of the passed value.
315 LPSTR
getArg( LPSTR arg
)
324 * Get rid of surrounding quotes
328 if( arg
[len
-1] == '\"' ) arg
[len
-1] = '\0';
329 if( arg
[0] == '\"' ) arg
++;
331 tmp
= HeapAlloc(GetProcessHeap(), 0, strlen(arg
)+1);
337 /******************************************************************************
338 * Replaces escape sequences with the characters.
340 static void REGPROC_unescape_string(LPSTR str
)
342 size_t str_idx
= 0; /* current character under analysis */
343 size_t val_idx
= 0; /* the last character of the unescaped string */
344 size_t len
= strlen(str
);
345 for (str_idx
= 0; str_idx
< len
; str_idx
++, val_idx
++) {
346 if (str
[str_idx
] == '\\') {
348 switch (str
[str_idx
]) {
354 str
[val_idx
] = str
[str_idx
];
357 fprintf(stderr
,"Warning! Unrecognized escape sequence: \\%c'\n",
359 str
[val_idx
] = str
[str_idx
];
363 str
[val_idx
] = str
[str_idx
];
369 /******************************************************************************
370 * Sets the value with name val_name to the data in val_data for the currently
374 * val_name - name of the registry value
375 * val_data - registry value data
377 HRESULT
setValue(LPSTR val_name
, LPSTR val_data
)
380 DWORD dwDataType
, dwParseType
= REG_BINARY
;
382 BYTE convert
[KEY_MAX_LEN
];
383 BYTE
*bBigBuffer
= 0;
386 if ( (val_name
== NULL
) || (val_data
== NULL
) )
387 return ERROR_INVALID_PARAMETER
;
389 /* Get the data type stored into the value field */
390 dwDataType
= getDataType(&val_data
, &dwParseType
);
392 if ( dwParseType
== REG_SZ
) /* no conversion for string */
394 dwLen
= (DWORD
) strlen(val_data
);
395 if (dwLen
>0 && val_data
[dwLen
-1]=='"')
398 val_data
[dwLen
]='\0';
401 REGPROC_unescape_string(val_data
);
402 lpbData
= (LPBYTE
)val_data
;
403 } else if (dwParseType
== REG_DWORD
) /* Convert the dword types */
405 dwLen
= convertHexToDWord(val_data
, convert
);
407 } else /* Convert the hexadecimal types */
409 size_t b_len
= strlen (val_data
)+2/3;
410 if (b_len
> KEY_MAX_LEN
) {
411 bBigBuffer
= HeapAlloc (GetProcessHeap(), 0, b_len
);
412 CHECK_ENOUGH_MEMORY(bBigBuffer
);
413 dwLen
= convertHexCSVToHex(val_data
, bBigBuffer
, (ULONG
) b_len
);
414 lpbData
= bBigBuffer
;
416 dwLen
= convertHexCSVToHex(val_data
, convert
, KEY_MAX_LEN
);
421 hRes
= RegSetValueExA(
430 HeapFree (GetProcessHeap(), 0, bBigBuffer
);
435 /******************************************************************************
438 HRESULT
openKey( LPSTR stdInput
)
444 if (stdInput
== NULL
)
445 return ERROR_INVALID_PARAMETER
;
447 /* Get the registry class */
448 currentKeyClass
= getRegClass(stdInput
); /* Sets global variable */
449 if (currentKeyClass
== (HKEY
)ERROR_INVALID_PARAMETER
)
450 return (HRESULT
)ERROR_INVALID_PARAMETER
;
452 /* Get the key name */
453 currentKeyName
= getRegKeyName(stdInput
); /* Sets global variable */
454 if (currentKeyName
== NULL
)
455 return ERROR_INVALID_PARAMETER
;
457 hRes
= RegCreateKeyExA(
458 currentKeyClass
, /* Class */
459 currentKeyName
, /* Sub Key */
461 NULL
, /* object type */
462 REG_OPTION_NON_VOLATILE
, /* option, REG_OPTION_NON_VOLATILE ... */
463 KEY_ALL_ACCESS
, /* access mask, KEY_ALL_ACCESS */
464 NULL
, /* security attribute */
465 ¤tKeyHandle
, /* result */
466 &dwDisp
); /* disposition, REG_CREATED_NEW_KEY or
467 REG_OPENED_EXISTING_KEY */
469 if (hRes
== ERROR_SUCCESS
)
470 bTheKeyIsOpen
= TRUE
;
476 /******************************************************************************
477 * Extracts from [HKEY\some\key\path] or HKEY\some\key\path types of line
478 * the key name (what starts after the first '\')
480 LPSTR
getRegKeyName(LPSTR lpLine
)
483 char lpLineCopy
[KEY_MAX_LEN
];
488 strcpy(lpLineCopy
, lpLine
);
490 keyNameBeg
= strchr(lpLineCopy
, '\\'); /* The key name start by '\' */
494 keyNameBeg
++; /* is not part of the name */
495 keyNameEnd
= strchr(lpLineCopy
, ']');
497 *keyNameEnd
= '\0'; /* remove ']' from the key name */
500 keyNameBeg
= lpLineCopy
+ strlen(lpLineCopy
); /* branch - empty string */
502 currentKeyName
= HeapAlloc(GetProcessHeap(), 0, strlen(keyNameBeg
) + 1);
503 CHECK_ENOUGH_MEMORY(currentKeyName
);
504 strcpy(currentKeyName
, keyNameBeg
);
505 return currentKeyName
;
508 /******************************************************************************
509 * Extracts from [HKEY\some\key\path] or HKEY\some\key\path types of line
510 * the key class (what ends before the first '\')
512 HKEY
getRegClass(LPSTR lpClass
)
518 char lpClassCopy
[KEY_MAX_LEN
];
521 return (HKEY
)ERROR_INVALID_PARAMETER
;
523 lstrcpynA(lpClassCopy
, lpClass
, KEY_MAX_LEN
);
525 classNameEnd
= strchr(lpClassCopy
, '\\'); /* The class name ends by '\' */
526 if (!classNameEnd
) /* or the whole string */
528 classNameEnd
= lpClassCopy
+ strlen(lpClassCopy
);
529 if (classNameEnd
[-1] == ']')
534 *classNameEnd
= '\0'; /* Isolate the class name */
535 if (lpClassCopy
[0] == '[') {
536 classNameBeg
= lpClassCopy
+ 1;
538 classNameBeg
= lpClassCopy
;
541 for (i
= 0; i
< REG_CLASS_NUMBER
; i
++) {
542 if (!strcmp(classNameBeg
, reg_class_names
[i
])) {
543 return reg_class_keys
[i
];
546 return (HKEY
)ERROR_INVALID_PARAMETER
;
549 /******************************************************************************
550 * Close the currently opened key.
554 RegCloseKey(currentKeyHandle
);
556 HeapFree(GetProcessHeap(), 0, currentKeyName
); /* Allocated by getKeyName */
558 bTheKeyIsOpen
= FALSE
;
560 currentKeyName
= NULL
;
562 currentKeyHandle
= 0;
565 /******************************************************************************
566 * This function is the main entry point to the setValue type of action. It
567 * receives the currently read line and dispatch the work depending on the
570 void doSetValue(LPSTR stdInput
)
573 * We encountered the end of the file, make sure we
574 * close the opened key and exit
576 if (stdInput
== NULL
) {
577 if (bTheKeyIsOpen
!= FALSE
)
583 if ( stdInput
[0] == '[') /* We are reading a new key */
585 if ( bTheKeyIsOpen
!= FALSE
)
586 closeKey(); /* Close the previous key before */
588 if ( openKey(stdInput
) != ERROR_SUCCESS
)
589 fprintf(stderr
,"%s: setValue failed to open key %s\n",
590 getAppName(), stdInput
);
591 } else if( ( bTheKeyIsOpen
) &&
592 (( stdInput
[0] == '@') || /* reading a default @=data pair */
593 ( stdInput
[0] == '\"'))) /* reading a new value=data pair */
595 processSetValue(stdInput
);
596 } else /* since we are assuming that the */
597 { /* file format is valid we must */
598 if ( bTheKeyIsOpen
) /* be reading a blank line which */
599 closeKey(); /* indicate end of this key processing */
603 /******************************************************************************
604 * This function is the main entry point to the queryValue type of action. It
605 * receives the currently read line and dispatch the work depending on the
608 void doQueryValue(LPSTR stdInput
)
611 * We encountered the end of the file, make sure we
612 * close the opened key and exit
614 if (stdInput
== NULL
) {
615 if (bTheKeyIsOpen
!= FALSE
)
621 if ( stdInput
[0] == '[') /* We are reading a new key */
623 if ( bTheKeyIsOpen
!= FALSE
)
624 closeKey(); /* Close the previous key before */
626 if ( openKey(stdInput
) != ERROR_SUCCESS
)
627 fprintf(stderr
,"%s: queryValue failed to open key %s\n",
628 getAppName(), stdInput
);
629 } else if( ( bTheKeyIsOpen
) &&
630 (( stdInput
[0] == '@') || /* reading a default @=data pair */
631 ( stdInput
[0] == '\"'))) /* reading a new value=data pair */
633 processQueryValue(stdInput
);
634 } else /* since we are assuming that the */
635 { /* file format is valid we must */
636 if ( bTheKeyIsOpen
) /* be reading a blank line which */
637 closeKey(); /* indicate end of this key processing */
641 /******************************************************************************
642 * This function is the main entry point to the deleteValue type of action. It
643 * receives the currently read line and dispatch the work depending on the
646 void doDeleteValue(LPSTR line
)
648 UNREFERENCED_PARAMETER(line
);
649 fprintf(stderr
,"%s: deleteValue not yet implemented\n", getAppName());
652 /******************************************************************************
653 * This function is the main entry point to the deleteKey type of action. It
654 * receives the currently read line and dispatch the work depending on the
657 void doDeleteKey(LPSTR line
)
659 UNREFERENCED_PARAMETER(line
);
660 fprintf(stderr
,"%s: deleteKey not yet implemented\n", getAppName());
663 /******************************************************************************
664 * This function is the main entry point to the createKey type of action. It
665 * receives the currently read line and dispatch the work depending on the
668 void doCreateKey(LPSTR line
)
670 UNREFERENCED_PARAMETER(line
);
671 fprintf(stderr
,"%s: createKey not yet implemented\n", getAppName());
674 /******************************************************************************
675 * This function is a wrapper for the setValue function. It prepares the
676 * land and clean the area once completed.
677 * Note: this function modifies the line parameter.
679 * line - registry file unwrapped line. Should have the registry value name and
680 * complete registry value data.
682 void processSetValue(LPSTR line
)
684 LPSTR val_name
; /* registry value name */
685 LPSTR val_data
; /* registry value data */
687 int line_idx
= 0; /* current character under analysis */
691 if (line
[line_idx
] == '@' && line
[line_idx
+ 1] == '=') {
692 line
[line_idx
] = '\0';
695 } else if (line
[line_idx
] == '\"') {
697 val_name
= line
+ line_idx
;
699 /* check if the line is unterminated (otherwise it may loop forever!) */
700 if (line
[line_idx
] == '\0') {
701 fprintf(stderr
,"Warning! unrecognized line:\n%s\n", line
);
704 if (line
[line_idx
] == '\\') /* skip escaped character */
708 if (line
[line_idx
] == '\"') {
709 line
[line_idx
] = '\0';
717 if (line
[line_idx
] != '=') {
718 line
[line_idx
] = '\"';
719 fprintf(stderr
,"Warning! unrecognized line:\n%s\n", line
);
724 fprintf(stderr
,"Warning! unrecognized line:\n%s\n", line
);
727 line_idx
++; /* skip the '=' character */
728 val_data
= line
+ line_idx
;
730 REGPROC_unescape_string(val_name
);
731 hRes
= setValue(val_name
, val_data
);
732 if ( hRes
!= ERROR_SUCCESS
)
733 fprintf(stderr
,"%s: ERROR Key %s not created. Value: %s, Data: %s\n",
740 /******************************************************************************
741 * This function is a wrapper for the queryValue function. It prepares the
742 * land and clean the area once completed.
744 void processQueryValue(LPSTR cmdline
)
746 UNREFERENCED_PARAMETER(cmdline
);
747 fprintf(stderr
,"ERROR!!! - temporary disabled");
750 LPSTR argv
[QUERY_VALUE_MAX_ARGS
];/* args storage */
751 LPSTR token
= NULL
; /* current token analyzed */
752 ULONG argCounter
= 0; /* counter of args */
755 LPSTR keyValue
= NULL
;
759 * Init storage and parse the line
761 for (counter
=0; counter
<QUERY_VALUE_MAX_ARGS
; counter
++)
764 while( (token
= getToken(&cmdline
, queryValueDelim
[argCounter
])) != NULL
) {
765 argv
[argCounter
++] = getArg(token
);
767 if (argCounter
== QUERY_VALUE_MAX_ARGS
)
768 break; /* Stop processing args no matter what */
771 /* The value we look for is the first token on the line */
772 if ( argv
[0] == NULL
)
773 return; /* SHOULD NOT HAPPEN */
777 if( (keyValue
[0] == '@') && (strlen(keyValue
) == 1) ) {
778 LONG lLen
= KEY_MAX_LEN
;
779 CHAR
* lpsData
=HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY
,KEY_MAX_LEN
);
781 * We need to query the key default value
783 hRes
= RegQueryValue(
789 if (hRes
==ERROR_MORE_DATA
) {
790 lpsData
=HeapReAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY
,lpsData
,lLen
);
791 hRes
= RegQueryValue(currentKeyHandle
,currentKeyName
,(LPBYTE
)lpsData
,&lLen
);
794 if (hRes
== ERROR_SUCCESS
) {
795 lpsRes
= HeapAlloc( GetProcessHeap(), 0, lLen
);
796 lstrcpynA(lpsRes
, lpsData
, lLen
);
799 DWORD dwLen
= KEY_MAX_LEN
;
800 BYTE
* lpbData
=HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY
,KEY_MAX_LEN
);
803 * We need to query a specific value for the key
805 hRes
= RegQueryValueEx(
813 if (hRes
==ERROR_MORE_DATA
) {
814 lpbData
=HeapReAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY
,lpbData
,dwLen
);
815 hRes
= RegQueryValueEx(currentKeyHandle
,keyValue
,NULL
,&dwType
,(LPBYTE
)lpbData
,&dwLen
);
818 if (hRes
== ERROR_SUCCESS
) {
820 * Convert the returned data to a displayable format
824 case REG_EXPAND_SZ
: {
825 lpsRes
= HeapAlloc( GetProcessHeap(), 0, dwLen
);
826 lstrcpynA(lpsRes
, lpbData
, dwLen
);
830 lpsRes
= convertHexToDWORDStr(lpbData
, dwLen
);
834 lpsRes
= convertHexToHexCSV(lpbData
, dwLen
);
840 HeapFree(GetProcessHeap(), 0, lpbData
);
844 if ( hRes
== ERROR_SUCCESS
)
846 "%s: Value \"%s\" = \"%s\" in key [%s]\n",
853 fprintf(stderr
,"%s: ERROR Value \"%s\" not found for key \"%s\".\n",
861 for (counter
=0; counter
<argCounter
; counter
++)
862 if (argv
[counter
] != NULL
)
863 HeapFree(GetProcessHeap(), 0, argv
[counter
]);
866 HeapFree(GetProcessHeap(), 0, lpsRes
);
870 /******************************************************************************
871 * Calls command for each line of a registry file.
872 * Correctly processes comments (in # form), line continuation.
875 * in - input stream to read from
876 * command - command to be called for each line
878 void processRegLines(FILE *in
, CommandAPI command
)
880 LPSTR line
= NULL
; /* line read from input stream */
881 size_t lineSize
= REG_VAL_BUF_SIZE
;
883 line
= HeapAlloc(GetProcessHeap(), 0, lineSize
);
884 CHECK_ENOUGH_MEMORY(line
);
887 LPSTR s
; /* The pointer into line for where the current fgets should read */
890 size_t size_remaining
;
892 char *s_eol
; /* various local uses */
894 /* Do we need to expand the buffer ? */
895 assert (s
>= line
&& s
<= line
+ lineSize
);
896 size_remaining
= lineSize
- (s
-line
);
897 if (size_remaining
< 2) /* room for 1 character and the \0 */
900 size_t new_size
= lineSize
+ REG_VAL_BUF_SIZE
;
901 if (new_size
> lineSize
) /* no arithmetic overflow */
902 new_buffer
= HeapReAlloc (GetProcessHeap(), 0, line
, new_size
);
905 CHECK_ENOUGH_MEMORY(new_buffer
);
907 s
= line
+ lineSize
- size_remaining
;
909 size_remaining
= lineSize
- (s
-line
);
912 /* Get as much as possible into the buffer, terminated either by
913 * eof, error, eol or getting the maximum amount. Abort on error.
915 size_to_get
= (int) (size_remaining
> INT_MAX
? INT_MAX
: size_remaining
);
916 if (NULL
== fgets (s
, size_to_get
, in
)) {
918 perror ("While reading input");
923 /* It is not clear to me from the definition that the
924 * contents of the buffer are well defined on detecting
925 * an eof without managing to read anything.
930 /* If we didn't read the eol nor the eof go around for the rest */
931 s_eol
= strchr (s
, '\n');
932 if (!feof (in
) && !s_eol
) {
933 s
= strchr (s
, '\0');
934 /* It should be s + size_to_get - 1 but this is safer */
938 /* If it is a comment line then discard it and go around again */
939 if (line
[0] == '#') {
944 /* Remove any line feed. Leave s_eol on the \0 */
947 if (s_eol
> line
&& *(s_eol
-1) == '\r')
950 s_eol
= strchr (s
, '\0');
952 /* If there is a concatenating \\ then go around again */
953 if (s_eol
> line
&& *(s_eol
-1) == '\\') {
956 /* The following error protection could be made more self-
957 * correcting but I thought it not worth trying.
959 if ((c
= fgetc (in
)) == EOF
|| c
!= ' ' ||
960 (c
= fgetc (in
)) == EOF
|| c
!= ' ')
961 fprintf(stderr
,"%s: ERROR - invalid continuation.\n",
966 break; /* That is the full virtual line */
973 HeapFree(GetProcessHeap(), 0, line
);
976 /******************************************************************************
977 * This function is the main entry point to the registerDLL action. It
978 * receives the currently read line, then loads and registers the requested DLLs
980 void doRegisterDLL(LPSTR stdInput
)
985 /* Check for valid input */
986 if (stdInput
== NULL
)
989 /* Load and register the library, then free it */
990 theLib
= LoadLibraryA(stdInput
);
992 FARPROC lpfnDLLRegProc
= GetProcAddress(theLib
, "DllRegisterServer");
994 retVal
= (*lpfnDLLRegProc
)();
996 fprintf(stderr
,"%s: Couldn't find DllRegisterServer proc in '%s'.\n",
997 getAppName(), stdInput
);
1000 fprintf(stderr
,"%s: DLLRegisterServer error 0x%x in '%s'.\n",
1001 getAppName(), retVal
, stdInput
);
1003 FreeLibrary(theLib
);
1005 fprintf(stderr
,"%s: Could not load DLL '%s'.\n", getAppName(), stdInput
);
1009 /******************************************************************************
1010 * This function is the main entry point to the unregisterDLL action. It
1011 * receives the currently read line, then loads and unregisters the requested DLLs
1013 void doUnregisterDLL(LPSTR stdInput
)
1018 /* Check for valid input */
1019 if (stdInput
== NULL
)
1022 /* Load and unregister the library, then free it */
1023 theLib
= LoadLibraryA(stdInput
);
1025 FARPROC lpfnDLLRegProc
= GetProcAddress(theLib
, "DllUnregisterServer");
1027 retVal
= (*lpfnDLLRegProc
)();
1029 fprintf(stderr
,"%s: Couldn't find DllUnregisterServer proc in '%s'.\n",
1030 getAppName(), stdInput
);
1033 fprintf(stderr
,"%s: DLLUnregisterServer error 0x%x in '%s'.\n",
1034 getAppName(), retVal
, stdInput
);
1036 FreeLibrary(theLib
);
1038 fprintf(stderr
,"%s: Could not load DLL '%s'.\n", getAppName(), stdInput
);
1042 /****************************************************************************
1043 * REGPROC_print_error
1045 * Print the message for GetLastError
1048 static void REGPROC_print_error(void)
1054 error_code
= GetLastError ();
1055 status
= FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER
| FORMAT_MESSAGE_FROM_SYSTEM
,
1056 NULL
, error_code
, 0, (LPTSTR
) &lpMsgBuf
, 0, NULL
);
1058 fprintf(stderr
,"%s: Cannot display message for error %ld, status %ld\n",
1059 getAppName(), error_code
, GetLastError());
1063 LocalFree((HLOCAL
)lpMsgBuf
);
1067 /******************************************************************************
1068 * Checks whether the buffer has enough room for the string or required size.
1069 * Resizes the buffer if necessary.
1072 * buffer - pointer to a buffer for string
1073 * len - current length of the buffer in characters.
1074 * required_len - length of the string to place to the buffer in characters.
1075 * The length does not include the terminating null character.
1077 static void REGPROC_resize_char_buffer(CHAR
**buffer
, DWORD
*len
, DWORD required_len
)
1080 if (required_len
> *len
) {
1081 *len
= required_len
;
1083 *buffer
= HeapAlloc(GetProcessHeap(), 0, *len
* sizeof(**buffer
));
1085 *buffer
= HeapReAlloc(GetProcessHeap(), 0, *buffer
, *len
* sizeof(**buffer
));
1086 CHECK_ENOUGH_MEMORY(*buffer
);
1090 /******************************************************************************
1091 * Prints string str to file
1093 static void REGPROC_export_string(FILE *file
, CHAR
*str
)
1095 size_t len
= strlen(str
);
1098 /* escaping characters */
1099 for (i
= 0; i
< len
; i
++) {
1103 fputs("\\\\", file
);
1106 fputs("\\\"", file
);
1109 fputs("\\\n", file
);
1118 /******************************************************************************
1119 * Writes contents of the registry key to the specified file stream.
1122 * file - writable file stream to export registry branch to.
1123 * key - registry branch to export.
1124 * reg_key_name_buf - name of the key with registry class.
1125 * Is resized if necessary.
1126 * reg_key_name_len - length of the buffer for the registry class in characters.
1127 * val_name_buf - buffer for storing value name.
1128 * Is resized if necessary.
1129 * val_name_len - length of the buffer for storing value names in characters.
1130 * val_buf - buffer for storing values while extracting.
1131 * Is resized if necessary.
1132 * val_size - size of the buffer for storing values in bytes.
1134 static void export_hkey(FILE *file
, HKEY key
,
1135 CHAR
**reg_key_name_buf
, DWORD
*reg_key_name_len
,
1136 CHAR
**val_name_buf
, DWORD
*val_name_len
,
1137 BYTE
**val_buf
, DWORD
*val_size
)
1139 DWORD max_sub_key_len
;
1140 DWORD max_val_name_len
;
1147 /* get size information and resize the buffers if necessary */
1148 if (RegQueryInfoKey(key
, NULL
, NULL
, NULL
, NULL
,
1149 &max_sub_key_len
, NULL
,
1150 NULL
, &max_val_name_len
, &max_val_size
, NULL
, NULL
1151 ) != ERROR_SUCCESS
) {
1152 REGPROC_print_error();
1154 curr_len
= (DWORD
) strlen(*reg_key_name_buf
);
1155 REGPROC_resize_char_buffer(reg_key_name_buf
, reg_key_name_len
,
1156 max_sub_key_len
+ curr_len
+ 1);
1157 REGPROC_resize_char_buffer(val_name_buf
, val_name_len
,
1159 if (max_val_size
> *val_size
) {
1160 *val_size
= max_val_size
;
1161 if (!*val_buf
) *val_buf
= HeapAlloc(GetProcessHeap(), 0, *val_size
);
1162 else *val_buf
= HeapReAlloc(GetProcessHeap(), 0, *val_buf
, *val_size
);
1163 CHECK_ENOUGH_MEMORY(val_buf
);
1166 /* output data for the current key */
1168 fputs(*reg_key_name_buf
, file
);
1170 /* print all the values */
1175 DWORD val_name_len1
= *val_name_len
;
1176 DWORD val_size1
= *val_size
;
1177 ret
= RegEnumValueA(key
, i
, *val_name_buf
, &val_name_len1
, NULL
,
1178 &value_type
, *val_buf
, &val_size1
);
1179 if (ret
!= ERROR_SUCCESS
) {
1181 if (ret
!= ERROR_NO_MORE_ITEMS
) {
1182 REGPROC_print_error();
1187 if ((*val_name_buf
)[0]) {
1189 REGPROC_export_string(file
, *val_name_buf
);
1195 switch (value_type
) {
1199 REGPROC_export_string(file
, (char*) *val_buf
);
1200 fputs("\"\n", file
);
1204 fprintf(file
, "dword:%08lx\n", *((DWORD
*)*val_buf
));
1208 fprintf(stderr
,"%s: warning - unsupported registry format '%ld', "
1209 "treat as binary\n",
1210 getAppName(), value_type
);
1211 fprintf(stderr
,"key name: \"%s\"\n", *reg_key_name_buf
);
1212 fprintf(stderr
,"value name:\"%s\"\n\n", *val_name_buf
);
1218 const CHAR
*hex_prefix
;
1222 if (value_type
== REG_BINARY
) {
1223 hex_prefix
= "hex:";
1226 sprintf(buf
, "hex(%ld):", value_type
);
1229 /* position of where the next character will be printed */
1230 /* NOTE: yes, strlen("hex:") is used even for hex(x): */
1231 cur_pos
= (int) (strlen("\"\"=") + strlen("hex:") +
1232 strlen(*val_name_buf
));
1234 fputs(hex_prefix
, file
);
1235 for (i1
= 0; i1
< val_size1
; i1
++) {
1236 fprintf(file
, "%02x", (unsigned int)(*val_buf
)[i1
]);
1237 if (i1
+ 1 < val_size1
) {
1243 if (cur_pos
> REG_FILE_HEX_LINE_LEN
) {
1244 fputs("\\\n ", file
);
1257 (*reg_key_name_buf
)[curr_len
] = '\\';
1259 DWORD buf_len
= *reg_key_name_len
- curr_len
;
1261 ret
= RegEnumKeyExA(key
, i
, *reg_key_name_buf
+ curr_len
+ 1, &buf_len
,
1262 NULL
, NULL
, NULL
, NULL
);
1263 if (ret
!= ERROR_SUCCESS
&& ret
!= ERROR_MORE_DATA
) {
1265 if (ret
!= ERROR_NO_MORE_ITEMS
) {
1266 REGPROC_print_error();
1272 if (RegOpenKeyA(key
, *reg_key_name_buf
+ curr_len
+ 1,
1273 &subkey
) == ERROR_SUCCESS
) {
1274 export_hkey(file
, subkey
, reg_key_name_buf
, reg_key_name_len
,
1275 val_name_buf
, val_name_len
, val_buf
, val_size
);
1276 RegCloseKey(subkey
);
1278 REGPROC_print_error();
1282 (*reg_key_name_buf
)[curr_len
] = '\0';
1285 /******************************************************************************
1286 * Open file for export.
1288 static FILE *REGPROC_open_export_file(const TCHAR
*file_name
)
1290 FILE *file
= _tfopen(file_name
, _T("w"));
1293 /* fprintf(stderr,"%s: Can't open file \"%s\"\n", getAppName(), file_name);*/
1296 fputs("REGEDIT4\n", file
);
1300 /******************************************************************************
1301 * Writes contents of the registry key to the specified file stream.
1304 * file_name - name of a file to export registry branch to.
1305 * reg_key_name - registry branch to export. The whole registry is exported if
1306 * reg_key_name is NULL or contains an empty string.
1308 BOOL
export_registry_key(const TCHAR
*file_name
, CHAR
*reg_key_name
)
1312 CHAR
*reg_key_name_buf
;
1315 DWORD reg_key_name_len
= KEY_MAX_LEN
;
1316 DWORD val_name_len
= KEY_MAX_LEN
;
1317 DWORD val_size
= REG_VAL_BUF_SIZE
;
1320 reg_key_name_buf
= HeapAlloc(GetProcessHeap(), 0,
1321 reg_key_name_len
* sizeof(*reg_key_name_buf
));
1322 val_name_buf
= HeapAlloc(GetProcessHeap(), 0,
1323 val_name_len
* sizeof(*val_name_buf
));
1324 val_buf
= HeapAlloc(GetProcessHeap(), 0, val_size
);
1325 CHECK_ENOUGH_MEMORY(reg_key_name_buf
&& val_name_buf
&& val_buf
);
1327 if (reg_key_name
&& reg_key_name
[0]) {
1331 REGPROC_resize_char_buffer(®_key_name_buf
, ®_key_name_len
,
1332 (DWORD
) strlen(reg_key_name
));
1333 strcpy(reg_key_name_buf
, reg_key_name
);
1335 /* open the specified key */
1336 reg_key_class
= getRegClass(reg_key_name
);
1337 if (reg_key_class
== (HKEY
)ERROR_INVALID_PARAMETER
) {
1338 fprintf(stderr
,"%s: Incorrect registry class specification in '%s'\n",
1339 getAppName(), reg_key_name
);
1342 branch_name
= getRegKeyName(reg_key_name
);
1343 CHECK_ENOUGH_MEMORY(branch_name
);
1344 if (!branch_name
[0]) {
1345 /* no branch - registry class is specified */
1346 file
= REGPROC_open_export_file(file_name
);
1347 export_hkey(file
, reg_key_class
,
1348 ®_key_name_buf
, ®_key_name_len
,
1349 &val_name_buf
, &val_name_len
,
1350 &val_buf
, &val_size
);
1351 } else if (RegOpenKeyA(reg_key_class
, branch_name
, &key
) == ERROR_SUCCESS
) {
1352 file
= REGPROC_open_export_file(file_name
);
1353 export_hkey(file
, key
,
1354 ®_key_name_buf
, ®_key_name_len
,
1355 &val_name_buf
, &val_name_len
,
1356 &val_buf
, &val_size
);
1359 fprintf(stderr
,"%s: Can't export. Registry key '%s' does not exist!\n",
1360 getAppName(), reg_key_name
);
1361 REGPROC_print_error();
1363 HeapFree(GetProcessHeap(), 0, branch_name
);
1367 /* export all registry classes */
1368 file
= REGPROC_open_export_file(file_name
);
1369 for (i
= 0; i
< REG_CLASS_NUMBER
; i
++) {
1370 /* do not export HKEY_CLASSES_ROOT */
1371 if (reg_class_keys
[i
] != HKEY_CLASSES_ROOT
&&
1372 reg_class_keys
[i
] != HKEY_CURRENT_USER
&&
1373 reg_class_keys
[i
] != HKEY_CURRENT_CONFIG
&&
1374 reg_class_keys
[i
] != HKEY_DYN_DATA
) {
1375 strcpy(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
);
1387 HeapFree(GetProcessHeap(), 0, val_buf
);
1391 /******************************************************************************
1392 * Reads contents of the specified file into the registry.
1394 BOOL
import_registry_file(LPTSTR filename
)
1396 FILE* reg_file
= _tfopen(filename
, _T("r"));
1399 unsigned char ch1
= fgetc(reg_file
);
1400 unsigned char ch2
= fgetc(reg_file
);
1402 /* detect UTF-16.LE or UTF-16.BE format */
1403 if ((ch1
== 0xff && ch2
== 0xfe) ||
1404 (ch1
== 0xfe && ch2
== 0xff)) {
1405 /* TODO: implement support for UNICODE files! */
1407 /* restore read point to the first line */
1408 fseek(reg_file
, 0L, SEEK_SET
);
1409 processRegLines(reg_file
, doSetValue
);
1417 /******************************************************************************
1418 * Recursive function which removes the registry key with all subkeys.
1420 static void delete_branch(HKEY key
,
1421 CHAR
**reg_key_name_buf
, DWORD
*reg_key_name_len
)
1424 DWORD max_sub_key_len
;
1430 if (RegOpenKeyA(key
, *reg_key_name_buf
, &branch_key
) != ERROR_SUCCESS
) {
1431 REGPROC_print_error();
1434 /* get size information and resize the buffers if necessary */
1435 if (RegQueryInfoKey(branch_key
, NULL
, NULL
, NULL
,
1436 &subkeys
, &max_sub_key_len
,
1437 NULL
, NULL
, NULL
, NULL
, NULL
, NULL
1438 ) != ERROR_SUCCESS
) {
1439 REGPROC_print_error();
1441 curr_len
= (DWORD
) strlen(*reg_key_name_buf
);
1442 REGPROC_resize_char_buffer(reg_key_name_buf
, reg_key_name_len
,
1443 max_sub_key_len
+ curr_len
+ 1);
1445 (*reg_key_name_buf
)[curr_len
] = '\\';
1446 for (i
= subkeys
- 1; i
>= 0; i
--) {
1447 DWORD buf_len
= *reg_key_name_len
- curr_len
;
1449 ret
= RegEnumKeyExA(branch_key
, i
, *reg_key_name_buf
+ curr_len
+ 1,
1450 &buf_len
, NULL
, NULL
, NULL
, NULL
);
1451 if (ret
!= ERROR_SUCCESS
&&
1452 ret
!= ERROR_MORE_DATA
&&
1453 ret
!= ERROR_NO_MORE_ITEMS
) {
1454 REGPROC_print_error();
1456 delete_branch(key
, reg_key_name_buf
, reg_key_name_len
);
1459 (*reg_key_name_buf
)[curr_len
] = '\0';
1460 RegCloseKey(branch_key
);
1461 RegDeleteKeyA(key
, *reg_key_name_buf
);
1464 /******************************************************************************
1465 * Removes the registry key with all subkeys. Parses full key name.
1468 * reg_key_name - full name of registry branch to delete. Ignored if is NULL,
1469 * empty, points to register key class, does not exist.
1471 void delete_registry_key(CHAR
*reg_key_name
)
1474 DWORD branch_name_len
;
1478 if (!reg_key_name
|| !reg_key_name
[0])
1480 /* open the specified key */
1481 reg_key_class
= getRegClass(reg_key_name
);
1482 if (reg_key_class
== (HKEY
)ERROR_INVALID_PARAMETER
) {
1483 fprintf(stderr
,"%s: Incorrect registry class specification in '%s'\n",
1484 getAppName(), reg_key_name
);
1487 branch_name
= getRegKeyName(reg_key_name
);
1488 CHECK_ENOUGH_MEMORY(branch_name
);
1489 branch_name_len
= (DWORD
) strlen(branch_name
);
1490 if (!branch_name
[0]) {
1491 fprintf(stderr
,"%s: Can't delete registry class '%s'\n",
1492 getAppName(), reg_key_name
);
1495 if (RegOpenKeyA(reg_key_class
, branch_name
, &branch_key
) == ERROR_SUCCESS
) {
1496 /* check whether the key exists */
1497 RegCloseKey(branch_key
);
1498 delete_branch(reg_key_class
, &branch_name
, &branch_name_len
);
1500 HeapFree(GetProcessHeap(), 0, branch_name
);
1503 /******************************************************************************
1504 * Sets the application name. Then application name is used in the error
1507 void setAppName(const CHAR
*name
)
1512 const CHAR
*getAppName(void)
1517 LONG
RegCopyKey(HKEY hDestKey
, LPCTSTR lpDestSubKey
, HKEY hSrcKey
, LPCTSTR lpSrcSubKey
)
1520 DWORD dwDisposition
;
1521 HKEY hDestSubKey
= NULL
;
1522 HKEY hSrcSubKey
= NULL
;
1523 DWORD dwIndex
, dwType
, cbName
, cbData
;
1524 TCHAR szSubKey
[256];
1525 TCHAR szValueName
[256];
1526 BYTE szValueData
[512];
1530 /* open the source subkey, if specified */
1533 lResult
= RegOpenKeyEx(hSrcKey
, lpSrcSubKey
, 0, KEY_ALL_ACCESS
, &hSrcSubKey
);
1536 hSrcKey
= hSrcSubKey
;
1539 /* create the destination subkey */
1540 lResult
= RegCreateKeyEx(hDestKey
, lpDestSubKey
, 0, NULL
, 0, KEY_WRITE
, NULL
,
1541 &hDestSubKey
, &dwDisposition
);
1545 /* copy all subkeys */
1549 cbName
= sizeof(szSubKey
) / sizeof(szSubKey
[0]);
1550 lResult
= RegEnumKeyEx(hSrcKey
, dwIndex
++, szSubKey
, &cbName
, NULL
, NULL
, NULL
, &ft
);
1551 if (lResult
== ERROR_SUCCESS
)
1553 lResult
= RegCopyKey(hDestSubKey
, szSubKey
, hSrcKey
, szSubKey
);
1558 while(lResult
== ERROR_SUCCESS
);
1560 /* copy all subvalues */
1564 cbName
= sizeof(szValueName
) / sizeof(szValueName
[0]);
1565 cbData
= sizeof(szValueData
) / sizeof(szValueData
[0]);
1566 lResult
= RegEnumValue(hSrcKey
, dwIndex
++, szValueName
, &cbName
, NULL
, &dwType
, szValueData
, &cbData
);
1567 if (lResult
== ERROR_SUCCESS
)
1569 lResult
= RegSetValueEx(hDestSubKey
, szValueName
, 0, dwType
, szValueData
, cbData
);
1574 while(lResult
== ERROR_SUCCESS
);
1576 lResult
= ERROR_SUCCESS
;
1580 RegCloseKey(hSrcSubKey
);
1582 RegCloseKey(hDestSubKey
);
1583 if (lResult
!= ERROR_SUCCESS
)
1584 SHDeleteKey(hDestKey
, lpDestSubKey
);
1589 LONG
RegMoveKey(HKEY hDestKey
, LPCTSTR lpDestSubKey
, HKEY hSrcKey
, LPCTSTR lpSrcSubKey
)
1594 return ERROR_INVALID_FUNCTION
;
1596 lResult
= RegCopyKey(hDestKey
, lpDestSubKey
, hSrcKey
, lpSrcSubKey
);
1597 if (lResult
== ERROR_SUCCESS
)
1598 SHDeleteKey(hSrcKey
, lpSrcSubKey
);
1603 LONG
RegRenameKey(HKEY hKey
, LPCTSTR lpSubKey
, LPCTSTR lpNewName
)
1606 LPTSTR lpNewSubKey
= NULL
;
1612 s
= _tcsrchr(lpSubKey
, _T('\\'));
1616 lpNewSubKey
= (LPTSTR
) HeapAlloc(GetProcessHeap(), 0, (s
- lpSubKey
+ _tcslen(lpNewName
) + 1) * sizeof(TCHAR
));
1617 if (lpNewSubKey
!= NULL
)
1619 memcpy(lpNewSubKey
, lpSubKey
, (s
- lpSubKey
) * sizeof(TCHAR
));
1620 _tcscpy(lpNewSubKey
+ (s
- lpSubKey
), lpNewName
);
1621 lpNewName
= lpNewSubKey
;
1624 return ERROR_NOT_ENOUGH_MEMORY
;
1627 Ret
= RegMoveKey(hKey
, lpNewName
, hKey
, lpSubKey
);
1631 HeapFree(GetProcessHeap(), 0, lpNewSubKey
);
1636 LONG
RegRenameValue(HKEY hKey
, LPCTSTR lpSubKey
, LPCTSTR lpDestValue
, LPCTSTR lpSrcValue
)
1639 HKEY hSubKey
= NULL
;
1640 DWORD dwType
, cbData
;
1645 lResult
= RegOpenKey(hKey
, lpSubKey
, &hSubKey
);
1646 if (lResult
!= ERROR_SUCCESS
)
1651 cbData
= sizeof(data
);
1652 lResult
= RegQueryValueEx(hKey
, lpSrcValue
, NULL
, &dwType
, data
, &cbData
);
1653 if (lResult
!= ERROR_SUCCESS
)
1656 lResult
= RegSetValueEx(hKey
, lpDestValue
, 0, dwType
, data
, cbData
);
1657 if (lResult
!= ERROR_SUCCESS
)
1660 RegDeleteValue(hKey
, lpSrcValue
);
1664 RegCloseKey(hSubKey
);
1668 LONG
RegQueryStringValue(HKEY hKey
, LPCTSTR lpSubKey
, LPCTSTR lpValueName
, LPTSTR pszBuffer
, DWORD dwBufferLen
)
1671 HKEY hSubKey
= NULL
;
1672 DWORD cbData
, dwType
;
1676 lResult
= RegOpenKey(hKey
, lpSubKey
, &hSubKey
);
1677 if (lResult
!= ERROR_SUCCESS
)
1682 cbData
= (dwBufferLen
- 1) * sizeof(*pszBuffer
);
1683 lResult
= RegQueryValueEx(hKey
, lpValueName
, NULL
, &dwType
, (LPBYTE
) pszBuffer
, &cbData
);
1684 if (lResult
!= ERROR_SUCCESS
)
1686 if (dwType
!= REG_SZ
)
1692 pszBuffer
[cbData
/ sizeof(*pszBuffer
)] = '\0';
1695 if (lResult
!= ERROR_SUCCESS
)
1696 pszBuffer
[0] = '\0';
1698 RegCloseKey(hSubKey
);
1702 /******************************************************************************
1706 static LONG
RegNextKey(HKEY hKey
, LPTSTR lpSubKey
, size_t iSubKeyLength
)
1710 LPCTSTR pszOriginalKey
;
1711 TCHAR szKeyName
[256];
1712 HKEY hSubKey
, hBaseKey
;
1716 BOOL bFoundKey
= FALSE
;
1718 /* Try accessing a subkey */
1719 if (RegOpenKeyEx(hKey
, lpSubKey
, 0, KEY_ALL_ACCESS
, &hSubKey
) == ERROR_SUCCESS
)
1721 cbName
= (DWORD
) iSubKeyLength
- _tcslen(lpSubKey
) - 1;
1722 lResult
= RegEnumKeyEx(hSubKey
, 0, lpSubKey
+ _tcslen(lpSubKey
) + 1,
1723 &cbName
, NULL
, NULL
, NULL
, &ft
);
1724 RegCloseKey(hSubKey
);
1726 if (lResult
== ERROR_SUCCESS
)
1728 lpSubKey
[_tcslen(lpSubKey
)] = '\\';
1735 /* Go up and find the next sibling key */
1738 s
= _tcsrchr(lpSubKey
, TEXT('\\'));
1742 pszOriginalKey
= s
+ 1;
1745 RegOpenKeyEx(hKey
, lpSubKey
, 0, KEY_ALL_ACCESS
, &hBaseKey
);
1749 pszOriginalKey
= lpSubKey
;
1758 lResult
= RegEnumKey(hBaseKey
, dwIndex
++, szKeyName
, sizeof(szKeyName
) / sizeof(szKeyName
[0]));
1760 while((lResult
== ERROR_SUCCESS
) && _tcscmp(szKeyName
, pszOriginalKey
));
1762 if (lResult
== ERROR_SUCCESS
)
1764 lResult
= RegEnumKey(hBaseKey
, dwIndex
++, szKeyName
, sizeof(szKeyName
) / sizeof(szKeyName
[0]));
1765 if (lResult
== ERROR_SUCCESS
)
1768 _sntprintf(lpSubKey
+ _tcslen(lpSubKey
), iSubKeyLength
- _tcslen(lpSubKey
), _T("\\%s"), szKeyName
);
1771 RegCloseKey(hBaseKey
);
1776 return bFoundKey
? ERROR_SUCCESS
: ERROR_NO_MORE_ITEMS
;
1779 static BOOL
RegSearchCompare(LPCTSTR s1
, LPCTSTR s2
, DWORD dwSearchFlags
)
1782 if (dwSearchFlags
& RSF_WHOLESTRING
)
1784 if (dwSearchFlags
& RSF_MATCHCASE
)
1785 bResult
= !_tcscmp(s1
, s2
);
1787 bResult
= !_tcsicmp(s1
, s2
);
1791 if (dwSearchFlags
& RSF_MATCHCASE
)
1792 bResult
= (_tcsstr(s1
, s2
) != NULL
);
1795 /* My kingdom for _tcsistr() */
1799 if (!_tcsnicmp(s1
, s2
, _tcslen(s2
)))
1811 LONG
RegSearch(HKEY hKey
, LPTSTR lpSubKey
, size_t iSubKeyLength
,
1812 LPCTSTR pszSearchString
, DWORD dwValueIndex
,
1813 DWORD dwSearchFlags
, BOOL (*pfnCallback
)(LPVOID
), LPVOID lpParam
)
1818 UNREFERENCED_PARAMETER(dwValueIndex
);
1820 if (dwSearchFlags
& (RSF_LOOKATVALUES
| RSF_LOOKATDATA
))
1821 return ERROR_CALL_NOT_IMPLEMENTED
; /* NYI */
1827 if (pfnCallback(lpParam
))
1828 return ERROR_OPERATION_ABORTED
;
1831 lResult
= RegNextKey(hKey
, lpSubKey
, iSubKeyLength
);
1832 if (lResult
!= ERROR_SUCCESS
)
1835 s
= _tcsrchr(lpSubKey
, TEXT('\\'));
1836 s
= s
? s
+ 1 : lpSubKey
;
1838 while(!(dwSearchFlags
& RSF_LOOKATKEYS
) || !RegSearchCompare(s
, pszSearchString
, dwSearchFlags
));
1840 return ERROR_SUCCESS
;
1843 /******************************************************************************
1844 * Key naming and parsing
1847 BOOL
RegKeyGetName(LPTSTR pszDest
, size_t iDestLength
, HKEY hRootKey
, LPCTSTR lpSubKey
)
1851 if (hRootKey
== HKEY_CLASSES_ROOT
)
1852 pszRootKey
= TEXT("HKEY_CLASSES_ROOT");
1853 else if (hRootKey
== HKEY_CURRENT_USER
)
1854 pszRootKey
= TEXT("HKEY_CURRENT_USER");
1855 else if (hRootKey
== HKEY_LOCAL_MACHINE
)
1856 pszRootKey
= TEXT("HKEY_LOCAL_MACHINE");
1857 else if (hRootKey
== HKEY_USERS
)
1858 pszRootKey
= TEXT("HKEY_USERS");
1859 else if (hRootKey
== HKEY_CURRENT_CONFIG
)
1860 pszRootKey
= TEXT("HKEY_CURRENT_CONFIG");
1861 else if (hRootKey
== HKEY_DYN_DATA
)
1862 pszRootKey
= TEXT("HKEY_DYN_DATA");
1867 _sntprintf(pszDest
, iDestLength
, TEXT("%s\\%s"), pszRootKey
, lpSubKey
);
1869 _sntprintf(pszDest
, iDestLength
, TEXT("%s"), pszRootKey
);