1 /* 2 * Registry processing routines. Routines, common for registry 3 * processing frontends. 4 * 5 * Copyright 1999 Sylvain St-Germain 6 * Copyright 2002 Andriy Palamarchuk 7 * 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. 12 * 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. 17 * 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 21 */ 22 23 #ifdef WIN32_REGDBG 24 #include <windows.h> 25 #include <tchar.h> 26 #ifndef __GNUC__ 27 #include <ntsecapi.h> 28 #else 29 #include <ctype.h> 30 #endif 31 #include <limits.h> 32 #include <stdlib.h> 33 #include <stdio.h> 34 #include <assert.h> 35 //#include <winreg.h> 36 #include "regdump.h" 37 #else 38 39 #define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers 40 #include <windows.h> 41 #include <commctrl.h> 42 #include <stdlib.h> 43 #include <tchar.h> 44 #include <process.h> 45 #include <stdio.h> 46 #include <wchar.h> 47 48 #include <ctype.h> 49 #include <limits.h> 50 #include <winnt.h> 51 #include <winreg.h> 52 #include <assert.h> 53 54 #endif 55 56 #include "regproc.h" 57 58 59 #define REG_VAL_BUF_SIZE 4096 60 61 /* Delimiters used to parse the "value" to query queryValue*/ 62 #define QUERY_VALUE_MAX_ARGS 1 63 64 /* maximal number of characters in hexadecimal data line, 65 not including '\' character */ 66 #define REG_FILE_HEX_LINE_LEN 76 67 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; 73 74 static TCHAR *reg_class_names[] = { 75 _T("HKEY_LOCAL_MACHINE"), 76 _T("HKEY_USERS"), 77 _T("HKEY_CLASSES_ROOT"), 78 _T("HKEY_CURRENT_CONFIG"), 79 _T("HKEY_CURRENT_USER") 80 }; 81 82 #define REG_CLASS_NUMBER (sizeof(reg_class_names) / sizeof(reg_class_names[0])) 83 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 87 }; 88 89 /* return values */ 90 #define NOT_ENOUGH_MEMORY 1 91 #define IO_ERROR 2 92 93 /* processing macros */ 94 95 /* common check of memory allocation results */ 96 #ifdef UNICODE 97 #define CHECK_ENOUGH_MEMORY(p) \ 98 if (!(p)) \ 99 { \ 100 _tprintf(_T("file %S, line %d: Not enough memory"), __FILE__, __LINE__); \ 101 assert(0);\ 102 exit(NOT_ENOUGH_MEMORY); \ 103 } 104 #else 105 #define CHECK_ENOUGH_MEMORY(p) \ 106 if (!(p)) \ 107 { \ 108 _tprintf(_T("file %s, line %d: Not enough memory"), __FILE__, __LINE__); \ 109 assert(0);\ 110 exit(NOT_ENOUGH_MEMORY); \ 111 } 112 #endif 113 114 #ifdef UNICODE 115 #define _TEOF WEOF 116 #else 117 #define _TEOF EOF 118 #endif 119 120 /****************************************************************************** 121 * This is a replacement for strsep which is not portable (missing on Solaris). 122 */ 123 #if 0 124 /* DISABLED */ 125 char* getToken(char** str, const char* delims) 126 { 127 char* token; 128 129 if (*str==NULL) { 130 /* No more tokens */ 131 return NULL; 132 } 133 134 token=*str; 135 while (**str!='\0') { 136 if (strchr(delims,**str)!=NULL) { 137 **str='\0'; 138 (*str)++; 139 return token; 140 } 141 (*str)++; 142 } 143 /* There is no other token */ 144 *str=NULL; 145 return token; 146 } 147 #endif 148 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; 154 * 155 * params: 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. 159 */ 160 void get_file_nameA(CHAR **command_line, CHAR *file_name, int max_filename) 161 { 162 CHAR *s = *command_line; 163 int pos = 0; /* position of pointer "s" in *command_line */ 164 file_name[0] = 0; 165 166 if (!s[0]) { 167 return; 168 } 169 if (s[0] == '"') { 170 s++; 171 (*command_line)++; 172 while (s[0] != '"') { 173 if (!s[0]) { 174 _tprintf(_T("Unexpected end of file name!\n")); 175 assert(0); 176 //exit(1); 177 } 178 s++; 179 pos++; 180 } 181 } else { 182 while (s[0] && !isspace(s[0])) { 183 s++; 184 pos++; 185 } 186 } 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'; 191 } else { 192 file_name[pos] = '\0'; 193 } 194 if (s[0]) { 195 s++; 196 pos++; 197 } 198 while (s[0] && isspace(s[0])) { 199 s++; 200 pos++; 201 } 202 (*command_line) += pos; 203 } 204 205 void get_file_nameW(CHAR** command_line, WCHAR* filename, int max_filename) 206 { 207 CHAR filenameA[_MAX_PATH]; 208 int len; 209 210 get_file_nameA(command_line, filenameA, _MAX_PATH); 211 len = strlen(filenameA); 212 OemToCharBuffW(filenameA, filename, max_filename); 213 filename[len] = _T('\0'); 214 /* 215 UNICODE_STRING UnicodeString; 216 ANSI_STRING AnsiString; 217 CHAR filenameA[_MAX_PATH]; 218 219 get_file_nameA(command_line, filenameA, _MAX_PATH); 220 221 //RtlInitAnsiString(&AnsiString, filenameA); 222 UnicodeString.Buffer = filename; 223 UnicodeString.MaximumLength = max_filename;//MAX_PATH; 224 RtlAnsiStringToUnicodeString(&UnicodeString, &AnsiString, FALSE); 225 */ 226 } 227 228 /****************************************************************************** 229 * Converts a hex representation of a DWORD into a DWORD. 230 */ 231 DWORD convertHexToDWord(TCHAR* str, BYTE* buf) 232 { 233 DWORD dw; 234 TCHAR xbuf[9]; 235 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); 241 } 242 243 /****************************************************************************** 244 * Converts a hex buffer into a hex comma separated values 245 */ 246 TCHAR* convertHexToHexCSV(BYTE* buf, ULONG bufLen) 247 { 248 TCHAR* str; 249 TCHAR* ptrStr; 250 BYTE* ptrBuf; 251 252 ULONG current = 0; 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++]; 259 TCHAR res[3]; 260 _stprintf(res, _T("%02x"), (unsigned int)*&bCur); 261 _tcscat(str, res); 262 _tcscat(str, _T(",")); 263 } 264 /* Get rid of the last comma */ 265 str[_tcslen(str)-1] = _T('\0'); 266 return str; 267 } 268 269 /****************************************************************************** 270 * Converts a hex buffer into a DWORD string 271 */ 272 TCHAR* convertHexToDWORDStr(BYTE* buf, ULONG bufLen) 273 { 274 TCHAR* str; 275 DWORD dw; 276 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 */ 282 return str; 283 } 284 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. 288 */ 289 DWORD convertHexCSVToHex(TCHAR* str, BYTE* buf, ULONG bufLen) 290 { 291 TCHAR* s = str; /* Pointer to current */ 292 CHAR* b = buf; /* Pointer to result */ 293 ULONG strLen = _tcslen(str); 294 ULONG strPos = 0; 295 DWORD byteCount = 0; 296 297 memset(buf, 0, bufLen); 298 /* 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. 301 */ 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")); 305 } 306 if (strLen > 3*bufLen) { 307 _tprintf(_T("ERROR converting CSV hex stream. Too long\n")); 308 } 309 while (strPos < strLen) { 310 TCHAR xbuf[3]; 311 TCHAR wc; 312 memcpy(xbuf, s, 2); 313 xbuf[2] = _T('\0'); 314 _stscanf(xbuf, _T("%02x"), (UINT*)&wc); 315 if (byteCount < bufLen) 316 *b++ = (unsigned char)wc; 317 s += 3; 318 strPos += 3; 319 ++byteCount; 320 } 321 return byteCount; 322 } 323 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. 328 * 329 * Note: Updated based on the algorithm used in 'server/registry.c' 330 */ 331 DWORD getDataType(LPTSTR* lpValue, DWORD* parse_type) 332 { 333 struct data_type { const TCHAR *tag; int len; int type; int parse_type; }; 334 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 }, 344 { NULL, 0, 0, 0 } 345 }; 346 347 const struct data_type *ptr; 348 int type; 349 350 for (ptr = data_types; ptr->tag; ptr++) { 351 if (memcmp(ptr->tag, *lpValue, ptr->len)) 352 continue; 353 354 /* Found! */ 355 *parse_type = ptr->parse_type; 356 type = ptr->type; 357 *lpValue += ptr->len; 358 if (type == -1) { 359 TCHAR* end; 360 /* "hex(xx):" is special */ 361 type = (int)_tcstoul(*lpValue , &end, 16); 362 if (**lpValue == _T('\0') || *end != _T(')') || *(end+1) != _T(':')) { 363 type = REG_NONE; 364 } else { 365 *lpValue = end + 2; 366 } 367 } 368 return type; 369 } 370 return (**lpValue == _T('\0') ? REG_SZ : REG_NONE); 371 } 372 373 /****************************************************************************** 374 * Returns an allocated buffer with a cleaned copy (removed the surrounding 375 * dbl quotes) of the passed value. 376 */ 377 LPTSTR getArg(LPTSTR arg) 378 { 379 LPTSTR tmp = NULL; 380 ULONG len; 381 382 if (arg == NULL) return NULL; 383 384 // Get rid of surrounding quotes 385 len = _tcslen(arg); 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)); 389 _tcscpy(tmp, arg); 390 return tmp; 391 } 392 393 /****************************************************************************** 394 * Replaces escape sequences with the characters. 395 */ 396 void REGPROC_unescape_string(LPTSTR str) 397 { 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('\\')) { 403 str_idx++; 404 switch (str[str_idx]) { 405 case _T('n'): 406 str[val_idx] = _T('\n'); 407 break; 408 case _T('\\'): 409 case _T('"'): 410 str[val_idx] = str[str_idx]; 411 break; 412 default: 413 _tprintf(_T("Warning! Unrecognized escape sequence: \\%c'\n"), str[str_idx]); 414 str[val_idx] = str[str_idx]; 415 break; 416 } 417 } else { 418 str[val_idx] = str[str_idx]; 419 } 420 } 421 str[val_idx] = _T('\0'); 422 } 423 424 /****************************************************************************** 425 * Sets the value with name val_name to the data in val_data for the currently 426 * opened key. 427 * 428 * Parameters: 429 * val_name - name of the registry value 430 * val_data - registry value data 431 */ 432 HRESULT setValue(LPTSTR val_name, LPTSTR val_data) 433 { 434 HRESULT hRes; 435 DWORD dwDataType, dwParseType; 436 LPBYTE lpbData; 437 BYTE convert[KEY_MAX_LEN]; 438 BYTE *bBigBuffer = 0; 439 DWORD dwLen; 440 441 if ((val_name == NULL) || (val_data == NULL)) 442 return ERROR_INVALID_PARAMETER; 443 444 /* Get the data type stored into the value field */ 445 dwDataType = getDataType(&val_data, &dwParseType); 446 447 // if (dwParseType == REG_EXPAND_SZ) { 448 // } 449 // if (dwParseType == REG_SZ || dwParseType == REG_EXPAND_SZ) { /* no conversion for string */ 450 451 if (dwParseType == REG_SZ) { /* no conversion for string */ 452 dwLen = _tcslen(val_data); 453 if (dwLen > 0 && val_data[dwLen-1] == _T('"')) { 454 dwLen--; 455 val_data[dwLen] = _T('\0'); 456 } 457 dwLen++; 458 dwLen *= sizeof(TCHAR); 459 REGPROC_unescape_string(val_data); 460 lpbData = val_data; 461 } else if (dwParseType == REG_DWORD) { /* Convert the dword types */ 462 dwLen = convertHexToDWord(val_data, convert); 463 lpbData = 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; 470 } 471 CHECK_ENOUGH_MEMORY(bBigBuffer); 472 dwLen = convertHexCSVToHex(val_data, bBigBuffer, b_len); 473 lpbData = bBigBuffer; 474 } else { 475 dwLen = convertHexCSVToHex(val_data, convert, KEY_MAX_LEN); 476 lpbData = convert; 477 } 478 } 479 hRes = RegSetValueEx(currentKeyHandle, val_name, 480 0, /* Reserved */dwDataType, lpbData, dwLen); 481 482 _tprintf(_T(" Value: %s, Data: %s\n"), val_name, lpbData); 483 484 485 if (bBigBuffer) 486 HeapFree(GetProcessHeap(), 0, bBigBuffer); 487 return hRes; 488 } 489 490 491 /****************************************************************************** 492 * Open the key 493 */ 494 HRESULT openKey(LPTSTR stdInput) 495 { 496 DWORD dwDisp; 497 HRESULT hRes; 498 499 /* Sanity checks */ 500 if (stdInput == NULL) 501 return ERROR_INVALID_PARAMETER; 502 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; 507 508 /* Get the key name */ 509 currentKeyName = getRegKeyName(stdInput); /* Sets global variable */ 510 if (currentKeyName == NULL) 511 return ERROR_INVALID_PARAMETER; 512 513 hRes = RegCreateKeyEx( 514 currentKeyClass, /* Class */ 515 currentKeyName, /* Sub Key */ 516 0, /* MUST BE 0 */ 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 */ 524 525 if (hRes == ERROR_SUCCESS) 526 bTheKeyIsOpen = TRUE; 527 528 return hRes; 529 530 } 531 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 '\') 535 */ 536 LPTSTR getRegKeyName(LPTSTR lpLine) 537 { 538 LPTSTR keyNameBeg; 539 TCHAR lpLineCopy[KEY_MAX_LEN]; 540 541 if (lpLine == NULL) 542 return NULL; 543 544 _tcscpy(lpLineCopy, lpLine); 545 keyNameBeg = _tcschr(lpLineCopy, _T('\\')); /* The key name start by '\' */ 546 if (keyNameBeg) { 547 LPTSTR keyNameEnd; 548 549 keyNameBeg++; /* is not part of the name */ 550 keyNameEnd = _tcschr(lpLineCopy, _T(']')); 551 if (keyNameEnd) { 552 *keyNameEnd = _T('\0'); /* remove ']' from the key name */ 553 } 554 } else { 555 keyNameBeg = lpLineCopy + _tcslen(lpLineCopy); /* branch - empty string */ 556 } 557 currentKeyName = HeapAlloc(GetProcessHeap(), 0, (_tcslen(keyNameBeg)+1)*sizeof(TCHAR)); 558 CHECK_ENOUGH_MEMORY(currentKeyName); 559 _tcscpy(currentKeyName, keyNameBeg); 560 return currentKeyName; 561 } 562 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 '\') 566 */ 567 HKEY getRegClass(LPTSTR lpClass) 568 { 569 LPTSTR classNameEnd; 570 LPTSTR classNameBeg; 571 int i; 572 573 TCHAR lpClassCopy[KEY_MAX_LEN]; 574 575 if (lpClass == NULL) 576 return (HKEY)ERROR_INVALID_PARAMETER; 577 578 _tcsncpy(lpClassCopy, lpClass, KEY_MAX_LEN); 579 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(']')) { 584 classNameEnd--; 585 } 586 } 587 *classNameEnd = _T('\0'); /* Isolate the class name */ 588 if (lpClassCopy[0] == _T('[')) { 589 classNameBeg = lpClassCopy + 1; 590 } else { 591 classNameBeg = lpClassCopy; 592 } 593 for (i = 0; i < REG_CLASS_NUMBER; i++) { 594 if (!_tcscmp(classNameBeg, reg_class_names[i])) { 595 return reg_class_keys[i]; 596 } 597 } 598 return (HKEY)ERROR_INVALID_PARAMETER; 599 } 600 601 /****************************************************************************** 602 * Close the currently opened key. 603 */ 604 void closeKey(VOID) 605 { 606 RegCloseKey(currentKeyHandle); 607 HeapFree(GetProcessHeap(), 0, currentKeyName); /* Allocated by getKeyName */ 608 bTheKeyIsOpen = FALSE; 609 currentKeyName = NULL; 610 currentKeyClass = 0; 611 currentKeyHandle = 0; 612 } 613 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 617 * context. 618 */ 619 void doSetValue(LPTSTR stdInput) 620 { 621 /* 622 * We encountered the end of the file, make sure we 623 * close the opened key and exit 624 */ 625 if (stdInput == NULL) { 626 if (bTheKeyIsOpen != FALSE) 627 closeKey(); 628 return; 629 } 630 631 if (stdInput[0] == _T('[')) { /* We are reading a new key */ 632 if (bTheKeyIsOpen != FALSE) { 633 closeKey(); /* Close the previous key before */ 634 } 635 if (openKey(stdInput) != ERROR_SUCCESS) { 636 _tprintf(_T("doSetValue failed to open key %s\n"), stdInput); 637 } 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 */ 645 } 646 } 647 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 651 * context. 652 */ 653 void doQueryValue(LPTSTR stdInput) { 654 /* 655 * We encoutered the end of the file, make sure we 656 * close the opened key and exit 657 */ 658 if (stdInput == NULL) { 659 if (bTheKeyIsOpen != FALSE) 660 closeKey(); 661 return; 662 } 663 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); 669 } 670 } 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 */ 678 } 679 } 680 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 684 * context. 685 */ 686 void doDeleteValue(LPTSTR line) { 687 _tprintf(_T("deleteValue not yet implemented\n")); 688 } 689 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 693 * context. 694 */ 695 void doDeleteKey(LPTSTR line) { 696 _tprintf(_T("deleteKey not yet implemented\n")); 697 } 698 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 702 * context. 703 */ 704 void doCreateKey(LPTSTR line) { 705 _tprintf(_T("createKey not yet implemented\n")); 706 } 707 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. 712 * 713 * line - registry file unwrapped line. Should have the registry value name and 714 * complete registry value data. 715 */ 716 void processSetValue(LPTSTR line) 717 { 718 LPTSTR val_name; /* registry value name */ 719 LPTSTR val_data; /* registry value data */ 720 721 int line_idx = 0; /* current character under analysis */ 722 HRESULT hRes = 0; 723 724 /* get value name */ 725 if (line[line_idx] == _T('@') && line[line_idx + 1] == _T('=')) { 726 line[line_idx] = _T('\0'); 727 val_name = line; 728 line_idx++; 729 } else if (line[line_idx] == _T('\"')) { 730 line_idx++; 731 val_name = line + line_idx; 732 while (TRUE) { 733 if (line[line_idx] == _T('\\')) { /* skip escaped character */ 734 line_idx += 2; 735 } else { 736 if (line[line_idx] == _T('\"')) { 737 line[line_idx] = _T('\0'); 738 line_idx++; 739 break; 740 } else { 741 line_idx++; 742 } 743 } 744 } 745 if (line[line_idx] != _T('=')) { 746 line[line_idx] = _T('\"'); 747 _tprintf(_T("Warning! uncrecognized line:\n%s\n"), line); 748 return; 749 } 750 } else { 751 _tprintf(_T("Warning! unrecognized line:\n%s\n"), line); 752 return; 753 } 754 line_idx++; /* skip the '=' character */ 755 val_data = line + line_idx; 756 REGPROC_unescape_string(val_name); 757 758 _tprintf(_T("Key: %s, Value: %s, Data: %s\n"), currentKeyName, val_name, val_data); 759 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); 763 } 764 } 765 766 /****************************************************************************** 767 * This function is a wrapper for the queryValue function. It prepares the 768 * land and clean the area once completed. 769 */ 770 void processQueryValue(LPTSTR cmdline) 771 { 772 _tprintf(_T("ERROR!!! - temporary disabled")); 773 //exit(1); 774 return; 775 #if 0 776 LPSTR argv[QUERY_VALUE_MAX_ARGS];/* args storage */ 777 LPSTR token = NULL; /* current token analized */ 778 ULONG argCounter = 0; /* counter of args */ 779 INT counter; 780 HRESULT hRes = 0; 781 LPSTR keyValue = NULL; 782 LPSTR lpsRes = NULL; 783 784 /* 785 * Init storage and parse the line 786 */ 787 for (counter = 0; counter < QUERY_VALUE_MAX_ARGS; counter++) 788 argv[counter] = NULL; 789 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 */ 794 } 795 796 /* The value we look for is the first token on the line */ 797 if (argv[0] == NULL) 798 return; /* SHOULD NOT HAPPEN */ 799 else 800 keyValue = argv[0]; 801 802 if ((keyValue[0] == '@') && (_tcslen(keyValue) == 1)) { 803 LONG lLen = KEY_MAX_LEN; 804 TCHAR* lpsData = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,KEY_MAX_LEN); 805 /* 806 * We need to query the key default value 807 */ 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); 812 } 813 if (hRes == ERROR_SUCCESS) { 814 lpsRes = HeapAlloc(GetProcessHeap(), 0, lLen); 815 strncpy(lpsRes, lpsData, lLen); 816 lpsRes[lLen-1]='\0'; 817 } 818 } else { 819 DWORD dwLen = KEY_MAX_LEN; 820 BYTE* lpbData = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, KEY_MAX_LEN); 821 DWORD dwType; 822 /* 823 * We need to query a specific value for the key 824 */ 825 hRes = RegQueryValueEx( 826 currentKeyHandle, 827 keyValue, 828 0, 829 &dwType, 830 (LPBYTE)lpbData, 831 &dwLen); 832 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); 836 } 837 838 if (hRes == ERROR_SUCCESS) { 839 /* 840 * Convert the returned data to a displayable format 841 */ 842 switch (dwType) { 843 case REG_SZ: 844 case REG_EXPAND_SZ: 845 lpsRes = HeapAlloc(GetProcessHeap(), 0, dwLen * sizeof(TCHAR)); 846 strncpy(lpsRes, lpbData, dwLen); 847 lpsRes[dwLen-1] = '\0'; 848 break; 849 case REG_DWORD: 850 lpsRes = convertHexToDWORDStr(lpbData, dwLen); 851 break; 852 default: 853 lpsRes = convertHexToHexCSV(lpbData, dwLen); 854 break; 855 } 856 } 857 858 HeapFree(GetProcessHeap(), 0, lpbData); 859 } 860 if (hRes == ERROR_SUCCESS) { 861 _tprintf(_T("Value \"%s\" = \"%s\" in key [%s]\n"), keyValue, lpsRes, currentKeyName); 862 863 } else { 864 _tprintf(_T("ERROR Value \"%s\" not found. for key \"%s\"\n"), keyValue, currentKeyName); 865 } 866 867 /* 868 * Do some cleanup 869 */ 870 for (counter=0; counter<argCounter; counter++) 871 if (argv[counter] != NULL) 872 HeapFree(GetProcessHeap(), 0, argv[counter]); 873 874 if (lpsRes != NULL) 875 HeapFree(GetProcessHeap(), 0, lpsRes); 876 #endif 877 } 878 879 /****************************************************************************** 880 * Calls command for each line of a registry file. 881 * Correctly processes comments (in # form), line continuation. 882 * 883 * Parameters: 884 * in - input stream to read from 885 * command - command to be called for each line 886 */ 887 void processRegLines(FILE *in, CommandAPI command) 888 { 889 LPTSTR line = NULL; /* line read from input stream */ 890 ULONG lineSize = REG_VAL_BUF_SIZE; 891 892 line = HeapAlloc(GetProcessHeap(), 0, lineSize * sizeof(TCHAR)); 893 CHECK_ENOUGH_MEMORY(line); 894 895 while (!feof(in)) { 896 LPTSTR s; /* The pointer into line for where the current fgets should read */ 897 s = line; 898 for (;;) { 899 size_t size_remaining; 900 int size_to_get; 901 TCHAR *s_eol; /* various local uses */ 902 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 */ 907 TCHAR *new_buffer; 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)); 911 else 912 new_buffer = NULL; 913 CHECK_ENOUGH_MEMORY(new_buffer); 914 line = new_buffer; 915 s = line + lineSize - size_remaining; 916 lineSize = new_size; 917 size_remaining = lineSize - (s-line); 918 } 919 920 /* Get as much as possible into the buffer, terminated either by 921 * eof, error, eol or getting the maximum amount. Abort on error. 922 */ 923 // 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); 926 // 927 // Looks as if 'lineSize' contains the number of characters of buffer size 928 // 929 size_to_get = (size_remaining > lineSize ? lineSize : size_remaining); 930 931 if (NULL == _fgetts(s, size_to_get, in)) { 932 if (ferror(in)) { 933 //_tperror(_T("While reading input")); 934 perror ("While reading input"); 935 //exit(IO_ERROR); 936 return; 937 } else { 938 assert (feof(in)); 939 *s = _T('\0'); 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. 943 */ 944 } 945 } 946 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 */ 952 continue; 953 } 954 955 /* If it is a comment line then discard it and go around again */ 956 if (line [0] == _T('#')) { 957 s = line; 958 continue; 959 } 960 961 /* Remove any line feed. Leave s_eol on the \0 */ 962 if (s_eol) { 963 *s_eol = _T('\0'); 964 if (s_eol > line && *(s_eol-1) == _T('\r')) 965 *--s_eol = _T('\0'); 966 } else { 967 s_eol = _tcschr (s, _T('\0')); 968 } 969 /* If there is a concatenating \\ then go around again */ 970 if (s_eol > line && *(s_eol-1) == _T('\\')) { 971 int c; 972 s = s_eol-1; 973 /* The following error protection could be made more self- 974 * correcting but I thought it not worth trying. 975 */ 976 977 if ((c = _fgettc(in)) == _TEOF || c != _T(' ') || 978 (c = _fgettc(in)) == _TEOF || c != _T(' ')) 979 _tprintf(_T("ERROR - invalid continuation.\n")); 980 continue; 981 } 982 break; /* That is the full virtual line */ 983 } 984 command(line); 985 } 986 command(NULL); 987 HeapFree(GetProcessHeap(), 0, line); 988 } 989 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 993 */ 994 void doRegisterDLL(LPTSTR stdInput) 995 { 996 HMODULE theLib = 0; 997 UINT retVal = 0; 998 999 /* Check for valid input */ 1000 if (stdInput == NULL) return; 1001 1002 /* Load and register the library, then free it */ 1003 theLib = LoadLibrary(stdInput); 1004 if (theLib) { 1005 FARPROC lpfnDLLRegProc = GetProcAddress(theLib, "DllRegisterServer"); 1006 if (lpfnDLLRegProc) { 1007 retVal = (*lpfnDLLRegProc)(); 1008 } else { 1009 _tprintf(_T("Couldn't find DllRegisterServer proc in '%s'.\n"), stdInput); 1010 } 1011 if (retVal != S_OK) { 1012 _tprintf(_T("Couldn't find DllRegisterServer proc in '%s'.\n"), stdInput); 1013 } 1014 FreeLibrary(theLib); 1015 } else { 1016 _tprintf(_T("Could not load DLL '%s'.\n"), stdInput); 1017 } 1018 } 1019 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 1023 */ 1024 void doUnregisterDLL(LPTSTR stdInput) 1025 { 1026 HMODULE theLib = 0; 1027 UINT retVal = 0; 1028 1029 /* Check for valid input */ 1030 if (stdInput == NULL) return; 1031 1032 /* Load and unregister the library, then free it */ 1033 theLib = LoadLibrary(stdInput); 1034 if (theLib) { 1035 FARPROC lpfnDLLRegProc = GetProcAddress(theLib, "DllUnregisterServer"); 1036 if (lpfnDLLRegProc) { 1037 retVal = (*lpfnDLLRegProc)(); 1038 } else { 1039 _tprintf(_T("Couldn't find DllUnregisterServer proc in '%s'.\n"), stdInput); 1040 } 1041 if (retVal != S_OK) { 1042 _tprintf(_T("DLLUnregisterServer error 0x%x in '%s'.\n"), retVal, stdInput); 1043 } 1044 FreeLibrary(theLib); 1045 } else { 1046 _tprintf(_T("Could not load DLL '%s'.\n"), stdInput); 1047 } 1048 } 1049 1050 /**************************************************************************** 1051 * REGPROC_print_error 1052 * 1053 * Print the message for GetLastError 1054 */ 1055 1056 void REGPROC_print_error(VOID) 1057 { 1058 LPVOID lpMsgBuf; 1059 DWORD error_code; 1060 int status; 1061 1062 error_code = GetLastError (); 1063 status = FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM, 1064 NULL, error_code, 0, (LPTSTR) &lpMsgBuf, 0, NULL); 1065 if (!status) { 1066 _tprintf(_T("Cannot display message for error %ld, status %ld\n"), error_code, GetLastError()); 1067 } else { 1068 _tprintf(_T("REGPROC_print_error() - ")); 1069 puts(lpMsgBuf); 1070 LocalFree((HLOCAL)lpMsgBuf); 1071 } 1072 //exit(1); 1073 } 1074 1075 /****************************************************************************** 1076 * Checks whether the buffer has enough room for the string or required size. 1077 * Resizes the buffer if necessary. 1078 * 1079 * Parameters: 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. 1084 */ 1085 void REGPROC_resize_char_buffer(TCHAR **buffer, DWORD *len, DWORD required_len) 1086 { 1087 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); 1092 } 1093 } 1094 1095 /****************************************************************************** 1096 * Prints string str to file 1097 */ 1098 void REGPROC_export_string(FILE *file, TCHAR *str) 1099 { 1100 size_t len = _tcslen(str); 1101 size_t i; 1102 1103 /* escaping characters */ 1104 for (i = 0; i < len; i++) { 1105 TCHAR c = str[i]; 1106 switch (c) { 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; 1111 } 1112 } 1113 } 1114 1115 /****************************************************************************** 1116 * Writes contents of the registry key to the specified file stream. 1117 * 1118 * Parameters: 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. 1130 */ 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) 1135 { 1136 DWORD max_sub_key_len; 1137 DWORD max_val_name_len; 1138 DWORD max_val_size; 1139 DWORD curr_len; 1140 DWORD i; 1141 BOOL more_data; 1142 LONG ret; 1143 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(); 1148 } 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); 1156 } 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 */ 1162 i = 0; 1163 more_data = TRUE; 1164 while (more_data) { 1165 DWORD value_type; 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) { 1170 more_data = FALSE; 1171 if (ret != ERROR_NO_MORE_ITEMS) { 1172 REGPROC_print_error(); 1173 } 1174 } else { 1175 i++; 1176 if ((*val_name_buf)[0]) { 1177 _fputts(_T("\""), file); 1178 REGPROC_export_string(file, *val_name_buf); 1179 _fputts(_T("\"="), file); 1180 } else { 1181 _fputts(_T("@="), file); 1182 } 1183 switch (value_type) { 1184 case REG_EXPAND_SZ: 1185 _fputts(_T("expand:"), file); 1186 case REG_SZ: 1187 _fputts(_T("\""), file); 1188 REGPROC_export_string(file, *val_buf); 1189 _fputts(_T("\"\n"), file); 1190 break; 1191 case REG_DWORD: 1192 _ftprintf(file, _T("dword:%08lx\n"), *((DWORD *)*val_buf)); 1193 break; 1194 default: 1195 /* 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); 1200 */ 1201 /* falls through */ 1202 case REG_MULTI_SZ: 1203 /* falls through */ 1204 case REG_BINARY: 1205 { 1206 DWORD i1; 1207 TCHAR *hex_prefix; 1208 TCHAR buf[20]; 1209 int cur_pos; 1210 1211 if (value_type == REG_BINARY) { 1212 hex_prefix = _T("hex:"); 1213 } else { 1214 hex_prefix = buf; 1215 _stprintf(buf, _T("hex(%ld):"), value_type); 1216 } 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); 1226 } 1227 cur_pos += 3; 1228 /* wrap the line */ 1229 if (cur_pos > REG_FILE_HEX_LINE_LEN) { 1230 _fputts(_T("\\\n "), file); 1231 cur_pos = 2; 1232 } 1233 } 1234 _fputts(_T("\n"), file); 1235 break; 1236 } 1237 } 1238 } 1239 } 1240 i = 0; 1241 more_data = TRUE; 1242 (*reg_key_name_buf)[curr_len] = _T('\\'); 1243 while (more_data) { 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) { 1247 more_data = FALSE; 1248 if (ret != ERROR_NO_MORE_ITEMS) { 1249 REGPROC_print_error(); 1250 } 1251 } else { 1252 HKEY subkey; 1253 1254 i++; 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); 1258 } else { 1259 REGPROC_print_error(); 1260 } 1261 } 1262 } 1263 (*reg_key_name_buf)[curr_len] = _T('\0'); 1264 } 1265 /* 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 ) 1279 1280 */ 1281 /****************************************************************************** 1282 * Open file for export. 1283 */ 1284 FILE *REGPROC_open_export_file(TCHAR *file_name) 1285 { 1286 //_CRTIMP FILE * __cdecl _wfopen(const wchar_t *, const wchar_t *); 1287 1288 //FILE* fopen (const char* szFileName, const char* szMode); 1289 //FILE* _wfopen(const wchar_t *file, const wchar_t *mode); 1290 1291 FILE *file = _tfopen(file_name, _T("w")); 1292 if (!file) { 1293 perror(""); 1294 _tprintf(_T("REGPROC_open_export_file(%s) - Can't open file.\n"), file_name); 1295 //exit(1); 1296 return NULL; 1297 } 1298 _fputts(_T("REGEDIT4\n"), file); 1299 return file; 1300 } 1301 1302 /****************************************************************************** 1303 * Writes contents of the registry key to the specified file stream. 1304 * 1305 * Parameters: 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. 1309 */ 1310 BOOL export_registry_key(TCHAR* file_name, TCHAR* reg_key_name) 1311 { 1312 HKEY reg_key_class; 1313 1314 TCHAR *reg_key_name_buf; 1315 TCHAR *val_name_buf; 1316 BYTE *val_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; 1320 FILE *file = NULL; 1321 1322 //_tprintf(_T("export_registry_key(%s, %s)\n"), reg_key_name, file_name); 1323 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); 1328 1329 if (reg_key_name && reg_key_name[0]) { 1330 TCHAR *branch_name; 1331 HKEY key; 1332 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); 1336 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); 1341 //exit(1); 1342 return FALSE; 1343 } 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); 1359 RegCloseKey(key); 1360 } else { 1361 _tprintf(_T("Can't export. Registry key '%s does not exist!\n"), reg_key_name); 1362 REGPROC_print_error(); 1363 } 1364 HeapFree(GetProcessHeap(), 0, branch_name); 1365 } else { 1366 int i; 1367 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); 1380 } 1381 } 1382 } 1383 if (file) { 1384 fclose(file); 1385 } 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); 1390 return TRUE; 1391 } 1392 1393 /****************************************************************************** 1394 * Reads contents of the specified file into the registry. 1395 */ 1396 BOOL import_registry_file(LPTSTR filename) 1397 { 1398 FILE* reg_file = _tfopen(filename, _T("r")); 1399 1400 if (reg_file) { 1401 processRegLines(reg_file, doSetValue); 1402 return TRUE; 1403 } 1404 return FALSE; 1405 } 1406 1407 /****************************************************************************** 1408 * Recursive function which removes the registry key with all subkeys. 1409 */ 1410 BOOL delete_branch(HKEY key, TCHAR** reg_key_name_buf, DWORD* reg_key_name_len) 1411 { 1412 HKEY branch_key; 1413 DWORD max_sub_key_len; 1414 DWORD subkeys; 1415 DWORD curr_len; 1416 LONG ret; 1417 long int i; 1418 1419 if (RegOpenKey(key, *reg_key_name_buf, &branch_key) != ERROR_SUCCESS) { 1420 REGPROC_print_error(); 1421 return FALSE; 1422 } 1423 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); 1429 return FALSE; 1430 } 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); 1433 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); 1441 return FALSE; 1442 } else { 1443 delete_branch(key, reg_key_name_buf, reg_key_name_len); 1444 } 1445 } 1446 (*reg_key_name_buf)[curr_len] = '\0'; 1447 RegCloseKey(branch_key); 1448 RegDeleteKey(key, *reg_key_name_buf); 1449 return TRUE; 1450 } 1451 1452 /****************************************************************************** 1453 * Removes the registry key with all subkeys. Parses full key name. 1454 * 1455 * Parameters: 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. 1458 */ 1459 void delete_registry_key(TCHAR* reg_key_name) 1460 { 1461 TCHAR* branch_name; 1462 DWORD branch_name_len; 1463 HKEY reg_key_class; 1464 HKEY branch_key; 1465 1466 if (!reg_key_name || !reg_key_name[0]) { 1467 return; 1468 } 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); 1473 //exit(1); 1474 return; 1475 } 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); 1481 //exit(1); 1482 return; 1483 } 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); 1488 } 1489 HeapFree(GetProcessHeap(), 0, branch_name); 1490 } 1491 1492