/****************************************************************************** * Removes the registry key with all subkeys. Parses full key name. * * Parameters: * reg_key_name - full name of registry branch to delete. Ignored if is NULL, * empty, points to register key class, does not exist. */ void delete_registry_key(WCHAR *reg_key_name) { WCHAR *key_name = NULL; HKEY key_class; if (!reg_key_name || !reg_key_name[0]) return; if (!parseKeyName(reg_key_name, &key_class, &key_name)) { char* reg_key_nameA = GetMultiByteString(reg_key_name); fprintf(stderr,"%s: Incorrect registry class specification in '%s'\n", getAppName(), reg_key_nameA); HeapFree(GetProcessHeap(), 0, reg_key_nameA); exit(1); } if (!*key_name) { char* reg_key_nameA = GetMultiByteString(reg_key_name); fprintf(stderr,"%s: Can't delete registry class '%s'\n", getAppName(), reg_key_nameA); HeapFree(GetProcessHeap(), 0, reg_key_nameA); exit(1); } RegDeleteTreeW(key_class, key_name); }
/****************************************************************************** * A helper function for processRegEntry() that opens the current key. * That key must be closed by calling closeKey(). */ static LONG openKeyW(WCHAR* stdInput) { HKEY keyClass; WCHAR* keyPath; DWORD dwDisp; LONG res; /* Sanity checks */ if (stdInput == NULL) return ERROR_INVALID_PARAMETER; /* Get the registry class */ if (!parseKeyName(stdInput, &keyClass, &keyPath)) return ERROR_INVALID_PARAMETER; res = RegCreateKeyExW( keyClass, /* Class */ keyPath, /* Sub Key */ 0, /* MUST BE 0 */ NULL, /* object type */ REG_OPTION_NON_VOLATILE, /* option, REG_OPTION_NON_VOLATILE ... */ KEY_ALL_ACCESS, /* access mask, KEY_ALL_ACCESS */ NULL, /* security attribute */ ¤tKeyHandle, /* result */ &dwDisp); /* disposition, REG_CREATED_NEW_KEY or REG_OPENED_EXISTING_KEY */ if (res == ERROR_SUCCESS) currentKeyName = GetMultiByteString(stdInput); else currentKeyHandle = NULL; return res; }
/****************************************************************************** * Converts a hex comma separated values list into a binary string. */ static BYTE* convertHexCSVToHex(WCHAR *str, DWORD *size) { WCHAR *s; BYTE *d, *data; /* The worst case is 1 digit + 1 comma per byte */ *size=(lstrlenW(str)+1)/2; data=HeapAlloc(GetProcessHeap(), 0, *size); CHECK_ENOUGH_MEMORY(data); s = str; d = data; *size=0; while (*s != '\0') { UINT wc; WCHAR *end; wc = strtoulW(s,&end,16); if (end == s || wc > 0xff || (*end && *end != ',')) { char* strA = GetMultiByteString(s); fprintf(stderr,"%s: ERROR converting CSV hex stream. Invalid value at '%s'\n", getAppName(), strA); HeapFree(GetProcessHeap(), 0, data); HeapFree(GetProcessHeap(), 0, strA); return NULL; } *d++ =(BYTE)wc; (*size)++; if (*end) end++; s = end; } return data; }
/****************************************************************************** * Open file in binary mode for export. */ static FILE *REGPROC_open_export_file(WCHAR *file_name, BOOL unicode) { FILE *file; WCHAR dash = '-'; if (strncmpW(file_name,&dash,1)==0) { file=stdout; _setmode(_fileno(file), _O_BINARY); } else { CHAR* file_nameA = GetMultiByteString(file_name); file = fopen(file_nameA, "wb"); if (!file) { perror(""); fprintf(stderr,"%s: Can't open file \"%s\"\n", getAppName(), file_nameA); HeapFree(GetProcessHeap(), 0, file_nameA); exit(1); } HeapFree(GetProcessHeap(), 0, file_nameA); } if(unicode) { const BYTE unicode_seq[] = {0xff,0xfe}; const WCHAR header[] = {'W','i','n','d','o','w','s',' ','R','e','g','i','s','t','r','y',' ','E','d','i','t','o','r',' ','V','e','r','s','i','o','n',' ','5','.','0','0','\r','\n'}; fwrite(unicode_seq, sizeof(BYTE), sizeof(unicode_seq)/sizeof(unicode_seq[0]), file); fwrite(header, sizeof(WCHAR), sizeof(header)/sizeof(header[0]), file); } else { fputs("REGEDIT4\r\n", file); } return file; }
/****************************************************************************** * Writes the given line to a file, in multi-byte or wide characters */ static void REGPROC_write_line(FILE *file, const WCHAR* str, BOOL unicode) { if(unicode) { fwrite(str, sizeof(WCHAR), lstrlenW(str), file); } else { char* strA = GetMultiByteString(str); fputs(strA, file); HeapFree(GetProcessHeap(), 0, strA); } }
BOOL ExportRegistryFile(HWND hWnd) { OPENFILENAME ofn; TCHAR ExportKeyPath[_MAX_PATH]; TCHAR Caption[128]; HKEY hKeyRoot; LPCTSTR pszKeyPath; /* Figure out which key path we are exporting */ pszKeyPath = GetItemPath(g_pChildWnd->hTreeWnd, 0, &hKeyRoot); GetKeyName(ExportKeyPath, COUNT_OF(ExportKeyPath), hKeyRoot, pszKeyPath); InitOpenFileName(hWnd, &ofn); LoadString(hInst, IDS_EXPORT_REG_FILE, Caption, sizeof(Caption)/sizeof(TCHAR)); ofn.lpstrTitle = Caption; /* Only set the path if a key (not the root node) is selected */ if (hKeyRoot != 0) { ofn.lCustData = (LPARAM) ExportKeyPath; } ofn.Flags = OFN_ENABLETEMPLATE | OFN_EXPLORER | OFN_ENABLEHOOK | OFN_OVERWRITEPROMPT; ofn.lpfnHook = ExportRegistryFile_OFNHookProc; ofn.lpTemplateName = MAKEINTRESOURCE(IDD_EXPORTRANGE); if (GetSaveFileName(&ofn)) { BOOL result; DWORD format; if (ofn.nFilterIndex == 1) format = REG_FORMAT_5; else format = REG_FORMAT_4; result = export_registry_key(ofn.lpstrFile, ExportKeyPath, format); if (!result) { LPSTR p = GetMultiByteString(ofn.lpstrFile); fprintf(stderr, "Can't open file \"%s\"\n", p); HeapFree(GetProcessHeap(), 0, p); return FALSE; } } else { CheckCommDlgError(hWnd); } return TRUE; }
/****************************************************************************** * This function receives the currently read entry and performs the * corresponding action. * isUnicode affects parsing of REG_MULTI_SZ values */ static void processRegEntry(WCHAR* stdInput, BOOL isUnicode) { /* * We encountered the end of the file, make sure we * close the opened key and exit */ if (stdInput == NULL) { closeKey(); return; } if ( stdInput[0] == '[') /* We are reading a new key */ { WCHAR* keyEnd; closeKey(); /* Close the previous key */ /* Get rid of the square brackets */ stdInput++; keyEnd = strrchrW(stdInput, ']'); if (keyEnd) *keyEnd='\0'; /* delete the key if we encounter '-' at the start of reg key */ if ( stdInput[0] == '-') { delete_registry_key(stdInput + 1); } else if ( openKeyW(stdInput) != ERROR_SUCCESS ) { char* stdInputA = GetMultiByteString(stdInput); fprintf(stderr,"%s: setValue failed to open key %s\n", getAppName(), stdInputA); HeapFree(GetProcessHeap(), 0, stdInputA); } } else if( currentKeyHandle && (( stdInput[0] == '@') || /* reading a default @=data pair */ ( stdInput[0] == '\"'))) /* reading a new value=data pair */ { processSetValue(stdInput, isUnicode); } else { /* Since we are assuming that the file format is valid we must be * reading a blank line which indicates the end of this key processing */ closeKey(); } }
static BOOL ImportRegistryFile(HWND hWnd) { OPENFILENAME ofn; TCHAR Caption[128], szTitle[256], szText[256]; LPCTSTR pszKeyPath; HKEY hRootKey; InitOpenFileName(hWnd, &ofn); LoadString(hInst, IDS_IMPORT_REG_FILE, Caption, COUNT_OF(Caption)); ofn.lpstrTitle = Caption; ofn.Flags |= OFN_ENABLESIZING; /* ofn.lCustData = ;*/ if (GetOpenFileName(&ofn)) { FILE *fp = _wfopen(ofn.lpstrFile, L"r"); if (fp == NULL || !import_registry_file(fp)) { LPSTR p = GetMultiByteString(ofn.lpstrFile); fprintf(stderr, "Can't open file \"%s\"\n", p); HeapFree(GetProcessHeap(), 0, p); if (fp != NULL) fclose(fp); return FALSE; } LoadString(hInst, IDS_APP_TITLE, szTitle, sizeof(szTitle)); LoadString(hInst, IDS_IMPORTED_OK, szText, sizeof(szTitle)); /* show successful import */ MessageBox(NULL, szText, szTitle, MB_OK); fclose(fp); } else { CheckCommDlgError(hWnd); } RefreshTreeView(g_pChildWnd->hTreeWnd); pszKeyPath = GetItemPath(g_pChildWnd->hTreeWnd, 0, &hRootKey); RefreshListView(g_pChildWnd->hListWnd, hRootKey, pszKeyPath); return TRUE; }
/****************************************************************************** * This function is a wrapper for the setValue function. It prepares the * land and cleans the area once completed. * Note: this function modifies the line parameter. * * line - registry file unwrapped line. Should have the registry value name and * complete registry value data. */ static void processSetValue(WCHAR* line, BOOL is_unicode) { WCHAR* val_name; /* registry value name */ WCHAR* val_data; /* registry value data */ int line_idx = 0; /* current character under analysis */ LONG res; /* get value name */ while ( isspaceW(line[line_idx]) ) line_idx++; if (line[line_idx] == '@' && line[line_idx + 1] == '=') { line[line_idx] = '\0'; val_name = line; line_idx++; } else if (line[line_idx] == '\"') { line_idx++; val_name = line + line_idx; while (line[line_idx]) { if (line[line_idx] == '\\') /* skip escaped character */ { line_idx += 2; } else { if (line[line_idx] == '\"') { line[line_idx] = '\0'; line_idx++; break; } else { line_idx++; } } } while ( isspaceW(line[line_idx]) ) line_idx++; if (!line[line_idx]) { fprintf(stderr, "%s: warning: unexpected EOL\n", getAppName()); return; } if (line[line_idx] != '=') { char* lineA; line[line_idx] = '\"'; lineA = GetMultiByteString(line); fprintf(stderr,"%s: warning: unrecognized line: '%s'\n", getAppName(), lineA); HeapFree(GetProcessHeap(), 0, lineA); return; } } else { char* lineA = GetMultiByteString(line); fprintf(stderr,"%s: warning: unrecognized line: '%s'\n", getAppName(), lineA); HeapFree(GetProcessHeap(), 0, lineA); return; } line_idx++; /* skip the '=' character */ while ( isspaceW(line[line_idx]) ) line_idx++; val_data = line + line_idx; /* trim trailing blanks */ line_idx = strlenW(val_data); while (line_idx > 0 && isspaceW(val_data[line_idx-1])) line_idx--; val_data[line_idx] = '\0'; REGPROC_unescape_string(val_name); res = setValue(val_name, val_data, is_unicode); if ( res != ERROR_SUCCESS ) { char* val_nameA = GetMultiByteString(val_name); char* val_dataA = GetMultiByteString(val_data); fprintf(stderr,"%s: ERROR Key %s not created. Value: %s, Data: %s\n", getAppName(), currentKeyName, val_nameA, val_dataA); HeapFree(GetProcessHeap(), 0, val_nameA); HeapFree(GetProcessHeap(), 0, val_dataA); } }
/****************************************************************************** * Writes contents of the registry key to the specified file stream. * * Parameters: * file_name - name of a file to export registry branch to. * reg_key_name - registry branch to export. The whole registry is exported if * reg_key_name is NULL or contains an empty string. */ BOOL export_registry_key(WCHAR *file_name, WCHAR *reg_key_name, DWORD format) { WCHAR *reg_key_name_buf; WCHAR *val_name_buf; BYTE *val_buf; WCHAR *line_buf; DWORD reg_key_name_size = KEY_MAX_LEN; DWORD val_name_size = KEY_MAX_LEN; DWORD val_size = REG_VAL_BUF_SIZE; DWORD line_buf_size = KEY_MAX_LEN + REG_VAL_BUF_SIZE; FILE *file = NULL; BOOL unicode = (format == REG_FORMAT_5); reg_key_name_buf = HeapAlloc(GetProcessHeap(), 0, reg_key_name_size * sizeof(*reg_key_name_buf)); val_name_buf = HeapAlloc(GetProcessHeap(), 0, val_name_size * sizeof(*val_name_buf)); val_buf = HeapAlloc(GetProcessHeap(), 0, val_size); line_buf = HeapAlloc(GetProcessHeap(), 0, line_buf_size * sizeof(*line_buf)); CHECK_ENOUGH_MEMORY(reg_key_name_buf && val_name_buf && val_buf && line_buf); if (reg_key_name && reg_key_name[0]) { HKEY reg_key_class; WCHAR *branch_name = NULL; HKEY key; REGPROC_resize_char_buffer(®_key_name_buf, ®_key_name_size, lstrlenW(reg_key_name)); lstrcpyW(reg_key_name_buf, reg_key_name); /* open the specified key */ if (!parseKeyName(reg_key_name, ®_key_class, &branch_name)) { CHAR* key_nameA = GetMultiByteString(reg_key_name); fprintf(stderr,"%s: Incorrect registry class specification in '%s'\n", getAppName(), key_nameA); HeapFree(GetProcessHeap(), 0, key_nameA); exit(1); } if (!branch_name[0]) { /* no branch - registry class is specified */ file = REGPROC_open_export_file(file_name, unicode); export_hkey(file, reg_key_class, ®_key_name_buf, ®_key_name_size, &val_name_buf, &val_name_size, &val_buf, &val_size, &line_buf, &line_buf_size, unicode); } else if (RegOpenKeyW(reg_key_class, branch_name, &key) == ERROR_SUCCESS) { file = REGPROC_open_export_file(file_name, unicode); export_hkey(file, key, ®_key_name_buf, ®_key_name_size, &val_name_buf, &val_name_size, &val_buf, &val_size, &line_buf, &line_buf_size, unicode); RegCloseKey(key); } else { CHAR* key_nameA = GetMultiByteString(reg_key_name); fprintf(stderr,"%s: Can't export. Registry key '%s' does not exist!\n", getAppName(), key_nameA); HeapFree(GetProcessHeap(), 0, key_nameA); REGPROC_print_error(); } } else { unsigned int i; /* export all registry classes */ file = REGPROC_open_export_file(file_name, unicode); for (i = 0; i < REG_CLASS_NUMBER; i++) { /* do not export HKEY_CLASSES_ROOT */ if (reg_class_keys[i] != HKEY_CLASSES_ROOT && reg_class_keys[i] != HKEY_CURRENT_USER && reg_class_keys[i] != HKEY_CURRENT_CONFIG && reg_class_keys[i] != HKEY_DYN_DATA) { lstrcpyW(reg_key_name_buf, reg_class_namesW[i]); export_hkey(file, reg_class_keys[i], ®_key_name_buf, ®_key_name_size, &val_name_buf, &val_name_size, &val_buf, &val_size, &line_buf, &line_buf_size, unicode); } } } if (file) { fclose(file); } HeapFree(GetProcessHeap(), 0, reg_key_name); HeapFree(GetProcessHeap(), 0, val_name_buf); HeapFree(GetProcessHeap(), 0, val_buf); HeapFree(GetProcessHeap(), 0, line_buf); return TRUE; }
/****************************************************************************** * Writes contents of the registry key to the specified file stream. * * Parameters: * file - writable file stream to export registry branch to. * key - registry branch to export. * reg_key_name_buf - name of the key with registry class. * Is resized if necessary. * reg_key_name_size - length of the buffer for the registry class in characters. * val_name_buf - buffer for storing value name. * Is resized if necessary. * val_name_size - length of the buffer for storing value names in characters. * val_buf - buffer for storing values while extracting. * Is resized if necessary. * val_size - size of the buffer for storing values in bytes. */ static void export_hkey(FILE *file, HKEY key, WCHAR **reg_key_name_buf, DWORD *reg_key_name_size, WCHAR **val_name_buf, DWORD *val_name_size, BYTE **val_buf, DWORD *val_size, WCHAR **line_buf, DWORD *line_buf_size, BOOL unicode) { DWORD max_sub_key_len; DWORD max_val_name_len; DWORD max_val_size; DWORD curr_len; DWORD i; BOOL more_data; LONG ret; WCHAR key_format[] = {'\r','\n','[','%','s',']','\r','\n',0}; /* get size information and resize the buffers if necessary */ if (RegQueryInfoKeyW(key, NULL, NULL, NULL, NULL, &max_sub_key_len, NULL, NULL, &max_val_name_len, &max_val_size, NULL, NULL ) != ERROR_SUCCESS) { REGPROC_print_error(); } curr_len = strlenW(*reg_key_name_buf); REGPROC_resize_char_buffer(reg_key_name_buf, reg_key_name_size, max_sub_key_len + curr_len + 1); REGPROC_resize_char_buffer(val_name_buf, val_name_size, max_val_name_len); REGPROC_resize_binary_buffer(val_buf, val_size, max_val_size); REGPROC_resize_char_buffer(line_buf, line_buf_size, lstrlenW(*reg_key_name_buf) + 4); /* output data for the current key */ sprintfW(*line_buf, key_format, *reg_key_name_buf); REGPROC_write_line(file, *line_buf, unicode); /* print all the values */ i = 0; more_data = TRUE; while(more_data) { DWORD value_type; DWORD val_name_size1 = *val_name_size; DWORD val_size1 = *val_size; ret = RegEnumValueW(key, i, *val_name_buf, &val_name_size1, NULL, &value_type, *val_buf, &val_size1); if (ret == ERROR_MORE_DATA) { /* Increase the size of the buffers and retry */ REGPROC_resize_char_buffer(val_name_buf, val_name_size, val_name_size1); REGPROC_resize_binary_buffer(val_buf, val_size, val_size1); } else if (ret != ERROR_SUCCESS) { more_data = FALSE; if (ret != ERROR_NO_MORE_ITEMS) { REGPROC_print_error(); } } else { DWORD line_len; i++; if ((*val_name_buf)[0]) { const WCHAR val_start[] = {'"','%','s','"','=',0}; line_len = 0; REGPROC_export_string(line_buf, line_buf_size, &line_len, *val_name_buf, lstrlenW(*val_name_buf)); REGPROC_resize_char_buffer(val_name_buf, val_name_size, lstrlenW(*line_buf) + 1); lstrcpyW(*val_name_buf, *line_buf); line_len = 3 + lstrlenW(*val_name_buf); REGPROC_resize_char_buffer(line_buf, line_buf_size, line_len); sprintfW(*line_buf, val_start, *val_name_buf); } else { const WCHAR std_val[] = {'@','=',0}; line_len = 2; REGPROC_resize_char_buffer(line_buf, line_buf_size, line_len); lstrcpyW(*line_buf, std_val); } switch (value_type) { case REG_SZ: { WCHAR* wstr = (WCHAR*)*val_buf; if (val_size1 < sizeof(WCHAR) || val_size1 % sizeof(WCHAR) || wstr[val_size1 / sizeof(WCHAR) - 1]) { REGPROC_export_binary(line_buf, line_buf_size, &line_len, value_type, *val_buf, val_size1, unicode); } else { const WCHAR start[] = {'"',0}; const WCHAR end[] = {'"','\r','\n',0}; DWORD len; len = lstrlenW(start); REGPROC_resize_char_buffer(line_buf, line_buf_size, line_len + len); lstrcpyW(*line_buf + line_len, start); line_len += len; /* At this point we know wstr is '\0'-terminated * so we can subtract 1 from the size */ REGPROC_export_string(line_buf, line_buf_size, &line_len, wstr, val_size1 / sizeof(WCHAR) - 1); REGPROC_resize_char_buffer(line_buf, line_buf_size, line_len + lstrlenW(end)); lstrcpyW(*line_buf + line_len, end); } break; } case REG_DWORD: { WCHAR format[] = {'d','w','o','r','d',':','%','0','8','x','\r','\n',0}; REGPROC_resize_char_buffer(line_buf, line_buf_size, line_len + 15); sprintfW(*line_buf + line_len, format, *((DWORD *)*val_buf)); break; } default: { char* key_nameA = GetMultiByteString(*reg_key_name_buf); char* value_nameA = GetMultiByteString(*val_name_buf); fprintf(stderr,"%s: warning - unsupported registry format '%d', " "treat as binary\n", getAppName(), value_type); fprintf(stderr,"key name: \"%s\"\n", key_nameA); fprintf(stderr,"value name:\"%s\"\n\n", value_nameA); HeapFree(GetProcessHeap(), 0, key_nameA); HeapFree(GetProcessHeap(), 0, value_nameA); } /* falls through */ case REG_EXPAND_SZ: case REG_MULTI_SZ: /* falls through */ case REG_BINARY: REGPROC_export_binary(line_buf, line_buf_size, &line_len, value_type, *val_buf, val_size1, unicode); } REGPROC_write_line(file, *line_buf, unicode); } } i = 0; more_data = TRUE; (*reg_key_name_buf)[curr_len] = '\\'; while(more_data) { DWORD buf_size = *reg_key_name_size - curr_len - 1; ret = RegEnumKeyExW(key, i, *reg_key_name_buf + curr_len + 1, &buf_size, NULL, NULL, NULL, NULL); if (ret == ERROR_MORE_DATA) { /* Increase the size of the buffer and retry */ REGPROC_resize_char_buffer(reg_key_name_buf, reg_key_name_size, curr_len + 1 + buf_size); } else if (ret != ERROR_SUCCESS) { more_data = FALSE; if (ret != ERROR_NO_MORE_ITEMS) { REGPROC_print_error(); } } else { HKEY subkey; i++; if (RegOpenKeyW(key, *reg_key_name_buf + curr_len + 1, &subkey) == ERROR_SUCCESS) { export_hkey(file, subkey, reg_key_name_buf, reg_key_name_size, val_name_buf, val_name_size, val_buf, val_size, line_buf, line_buf_size, unicode); RegCloseKey(subkey); } else { REGPROC_print_error(); } } } (*reg_key_name_buf)[curr_len] = '\0'; }
BOOL ModifyValue(HWND hwnd, HKEY hKeyRoot, LPCWSTR keyPath, LPCWSTR valueName) { BOOL result = FALSE; DWORD type; LONG lRet; HKEY hKey; LONG len; lRet = RegOpenKeyExW(hKeyRoot, keyPath, 0, KEY_READ | KEY_SET_VALUE, &hKey); if (lRet != ERROR_SUCCESS) { error_code_messagebox(hwnd, lRet); return FALSE; } editValueName = valueName ? valueName : g_pszDefaultValueName; if(!(stringValueData = read_value(hwnd, hKey, valueName, &type, &len))) goto done; if ( (type == REG_SZ) || (type == REG_EXPAND_SZ) ) { if (DialogBoxW(0, MAKEINTRESOURCEW(IDD_EDIT_STRING), hwnd, modify_dlgproc) == IDOK) { lRet = RegSetValueExW(hKey, valueName, 0, type, (LPBYTE)stringValueData, (lstrlenW(stringValueData) + 1) * sizeof(WCHAR)); if (lRet == ERROR_SUCCESS) result = TRUE; else error_code_messagebox(hwnd, lRet); } } else if ( type == REG_DWORD ) { const WCHAR u[] = {'%','u',0}; const WCHAR x[] = {'%','x',0}; wsprintfW(stringValueData, isDecimal ? u : x, *((DWORD*)stringValueData)); if (DialogBoxW(0, MAKEINTRESOURCEW(IDD_EDIT_DWORD), hwnd, modify_dlgproc) == IDOK) { DWORD val; CHAR* valueA = GetMultiByteString(stringValueData); if (sscanf(valueA, isDecimal ? "%u" : "%x", &val)) { lRet = RegSetValueExW(hKey, valueName, 0, type, (BYTE*)&val, sizeof(val)); if (lRet == ERROR_SUCCESS) result = TRUE; else error_code_messagebox(hwnd, lRet); } HeapFree(GetProcessHeap(), 0, valueA); } } else if ( type == REG_BINARY ) { struct edit_params params; params.hKey = hKey; params.lpszValueName = valueName; params.pData = stringValueData; params.cbData = len; result = DialogBoxParamW(NULL, MAKEINTRESOURCEW(IDD_EDIT_BINARY), hwnd, bin_modify_dlgproc, (LPARAM)¶ms); } else if ( type == REG_MULTI_SZ ) { WCHAR char1 = '\r', char2 = '\n'; WCHAR *tmpValueData = NULL; INT i, j, count; for ( i = 0, count = 0; i < len - 1; i++) if ( !stringValueData[i] && stringValueData[i + 1] ) count++; tmpValueData = HeapAlloc( GetProcessHeap(), 0, ( len + count ) * sizeof(WCHAR)); if ( !tmpValueData ) goto done; for ( i = 0, j = 0; i < len - 1; i++) { if ( !stringValueData[i] && stringValueData[i + 1]) { tmpValueData[j++] = char1; tmpValueData[j++] = char2; } else tmpValueData[j++] = stringValueData[i]; } tmpValueData[j] = stringValueData[i]; HeapFree( GetProcessHeap(), 0, stringValueData); stringValueData = tmpValueData; tmpValueData = NULL; if (DialogBoxW(0, MAKEINTRESOURCEW(IDD_EDIT_MULTI_STRING), hwnd, modify_dlgproc) == IDOK) { len = lstrlenW( stringValueData ); tmpValueData = HeapAlloc( GetProcessHeap(), 0, (len + 2) * sizeof(WCHAR)); if ( !tmpValueData ) goto done; for ( i = 0, j = 0; i < len - 1; i++) { if ( stringValueData[i] == char1 && stringValueData[i + 1] == char2) { if ( tmpValueData[j - 1] != 0) tmpValueData[j++] = 0; i++; } else tmpValueData[j++] = stringValueData[i]; } tmpValueData[j++] = stringValueData[i]; tmpValueData[j++] = 0; tmpValueData[j++] = 0; HeapFree( GetProcessHeap(), 0, stringValueData); stringValueData = tmpValueData; lRet = RegSetValueExW(hKey, valueName, 0, type, (LPBYTE)stringValueData, j * sizeof(WCHAR)); if (lRet == ERROR_SUCCESS) result = TRUE; else error_code_messagebox(hwnd, lRet); } } else { error(hwnd, IDS_UNSUPPORTED_TYPE, type); } done: HeapFree(GetProcessHeap(), 0, stringValueData); stringValueData = NULL; RegCloseKey(hKey); return result; }