Почитал форумы, вижу, что люди, как и я, маются с бякой экспорта ключей из реестра в формате *.REG. Посему решил отметиться следующей функцией:
ExportRegistryData.
Естественно, что глупо ожидать от нее совершенства — собственно, ради того, чтобы выловились все баги, я и запостил сюда ее.
Кода порядком, но уж звиняйте, писалось в 3 часа ночи, а уж тут красивостей не жди

Вроде постарался учесть самое основное. Как обычно — замечания, исправления и все, что по делу — велкам. Пустые придирки — идут лесом
З.Ы. Блин, как форматирование из-за табуляций бьется

Правда, сам виноват — где пробелы, а где табуляция...
Пример использования
// экспорт всех подключей и значений...
ExportRegistryData(HKEY_CURRENT_USER,"Software\\Microsoft",
NULL,TRUE,"C:\\test.txt",TRUE);
// Экспорт одного значения
ExportRegistryData(HKEY_CURRENT_USER,"Software\\Microsoft",
"ValueName",FALSE,"C:\\test.txt",TRUE);
Хидер
//---------------------------------------------------------------------------
#ifndef RegExportH
#define RegExportH
//---------------------------------------------------------------------------
#include <windows.h>
//---------------------------------------------------------------------------
/*
ExportRegistryData - exports registry data to file.
Parameters
hKey
Handle to a currently open key or any of the following predefined
reserved handle values:
HKEY_CLASSES_ROOT
HKEY_CURRENT_CONFIG
HKEY_CURRENT_USER
HKEY_LOCAL_MACHINE
HKEY_USERS
Windows NT: HKEY_PERFORMANCE_DATA
Windows 95 and Windows 98: HKEY_DYN_DATA
lpSubKey
Pointer to a null-terminated string containing the name of the subkey to export.
lpValueName
Pointer to a null-terminated string containing the name of the value to export.
If lpValueName parameter is NULL, ExportRegistryData exports all values
of key, specified in lpSubKey parameter, otherwise ExportRegistryData
exports only value data, pointed to lpValueName.
bSaveSubtree
Specifies how this operation is to proceed a subkeys. If this parameter
is TRUE, function exports all subkeys and values of key, specified in
lpSubKey parameter, otherwise only values of lpSubKey are exported.
NOTE:
This parameter CANNOT be TRUE if lpValueName not NULL.
lpFileName
Pointer to a null-terminated string containing the name of the file in
which the specified key and subkeys are saved.
NOTE:
This parameter CANNOT be NULL.
bWriteHeader
Specifies if file header will be written to file.
SUPPORTED registry value types:
REG_SZ
REG_EXPAND_SZ
REG_BINARY
REG_DWORD, REG_DWORD_LITTLE_ENDIAN
REG_MULTI_SZ
*/
BOOL WINAPI ExportRegistryData(HKEY hKey,LPCTSTR lpSubKey,LPCTSTR lpValueName,
BOOL bSaveSubtree, LPCTSTR lpFileName, BOOL bWriteHeader);
//---------------------------------------------------------------------------
#endif
Сырец
//---------------------------------------------------------------------------
#include "RegExport.h"
//---------------------------------------------------------------------------
#define OVERHEAD_LEN 50
#define CRLF_LEN 2
#define CRLF "\r\n"
#define NEXT_LINE "\\\r\n "
#define MAX_LINE_LEN 80
#define BYTES_PER_LINE 25
#define FILE_HEADER "REGEDIT4\r\n\r\n"
//---------------------------------------------------------------------------
const char* key_names[] = {
"HKEY_CLASSES_ROOT\\",
"HKEY_CURRENT_USER\\",
"HKEY_LOCAL_MACHINE\\",
"HKEY_USERS\\",
"HKEY_PERFORMANCE_DATA\\",
"HKEY_CURRENT_CONFIG\\",
"HKEY_DYN_DATA\\"
};
const int NEXT_LINE_LEN = lstrlen(NEXT_LINE);
//---------------------------------------------------------------------------
BOOL WINAPI WriteData(HANDLE hFile,LPCTSTR lpData, DWORD dwDataLen)
{
DWORD dwWritten;
if(!WriteFile(hFile,(LPCVOID) lpData,dwDataLen,&dwWritten,NULL) ||
dwWritten != dwDataLen)
return FALSE;
return TRUE;
}
//---------------------------------------------------------------------------
DWORD WINAPI FormatBuffer(LPBYTE bWorkBuffer,LPCTSTR lpValueName,
DWORD dwValueNameLen, LPCBYTE bData,DWORD dwDataLen,DWORD dwType)
{
LPBYTE lpByte = bWorkBuffer;
static char hexdata[3] = {0};
DWORD dwTemp;
if(!dwValueNameLen)
{
CopyMemory((PVOID)lpByte,(CONST VOID*)"@=",2);
lpByte += 2;
} // if(!dwValueNameLen)
else
{
*lpByte++ = '"';
for(DWORD i=0;i<dwValueNameLen;i++)
{
if(lpValueName[i] == '\\' || lpValueName[i] == '"')
*lpByte++ = '\\';
*lpByte++ = lpValueName[i];
} // for
*lpByte++ = '"';
*lpByte++ = '=';
} // else
switch(dwType)
{
case REG_DWORD:
{
CopyMemory((PVOID)lpByte,(CONST VOID*)"dword:",6);
lpByte += 6;
for(int i=3;i>=0;i--)
{
dwTemp = (BYTE) *(bData+i);
wsprintf(hexdata,"%02x",dwTemp);
CopyMemory((PVOID)lpByte,(CONST VOID*)hexdata,2);
lpByte+=2;
} // for
CopyMemory((PVOID)lpByte,(CONST VOID*)CRLF,CRLF_LEN);
lpByte += CRLF_LEN;
} // case REG_DWORD:
return (lpByte - bWorkBuffer);
case REG_BINARY:
case REG_EXPAND_SZ:
case REG_MULTI_SZ:
{
CopyMemory((PVOID)lpByte,(CONST VOID*)"hex",3);
lpByte += 3;
if(dwType != REG_BINARY)
{
*lpByte++ = '(';
char cType = (dwType == REG_MULTI_SZ ? '7' : '2');
*lpByte++ = cType;
*lpByte++ = ')';
} // if(dwType != REG_BINARY)
*lpByte++ = ':';
for(DWORD i=0;i<dwDataLen;i++)
{
dwTemp = (BYTE) bData[i];
wsprintf(hexdata,"%02x",dwTemp);
CopyMemory((PVOID)lpByte,(CONST VOID*)hexdata,2);
lpByte+=2;
if((i+1) < dwDataLen)
*lpByte++ = ',';
if( i>0 && ((i+1) < dwDataLen) && !(i%(BYTES_PER_LINE-1)))
{
CopyMemory((PVOID)lpByte,(CONST VOID*)NEXT_LINE,NEXT_LINE_LEN);
lpByte += NEXT_LINE_LEN;
} // if(!(i%BYTES_PER_LINE))
} // for(DWORD i=0;i<dwDataLen;i++)
CopyMemory((PVOID)lpByte,(CONST VOID*)CRLF,CRLF_LEN);
lpByte += CRLF_LEN;
}
return (lpByte - bWorkBuffer);
case REG_SZ:
{
*lpByte++ = '"';
for(DWORD i=0;i<dwDataLen && bData[i];i++)
{
if(bData[i] == '\\' || bData[i] == '"')
*lpByte++ = '\\';
*lpByte++ = bData[i];
} // for
*lpByte++ = '"';
CopyMemory((PVOID)lpByte,(CONST VOID*)CRLF,CRLF_LEN);
lpByte += CRLF_LEN;
}
return (lpByte - bWorkBuffer);
} // switch(dwType)
return 0;
}
//---------------------------------------------------------------------------
DWORD WINAPI ValGetBufferLength(DWORD dwValueNameLength,
DWORD dwDataLength, DWORD dwDataType)
{
DWORD dwResult = dwValueNameLength + OVERHEAD_LEN + CRLF_LEN;
switch(dwDataType)
{
case REG_NONE:
return 0;
case REG_BINARY:
case REG_EXPAND_SZ:
case REG_MULTI_SZ:
{
DWORD dwNLines = (dwDataLength/BYTES_PER_LINE) + (dwDataLength%BYTES_PER_LINE);
dwResult += MAX_LINE_LEN*dwNLines * (dwDataType !=REG_BINARY ? 2 : 1 );
}
break;
case REG_DWORD:
dwResult += sizeof(DWORD);
break;
case REG_SZ:
dwResult += dwDataLength + CRLF_LEN*2;
break;
} // switch(dwDataType)
return dwResult;
}
//---------------------------------------------------------------------------
BOOL WINAPI ExportKey(HANDLE hFile,HKEY hKey,LPCTSTR lpSubKey, BOOL bSaveSubtree)
{
BOOL result = FALSE;
char nameBuffer[MAX_PATH] = {0};
DWORD dwNameBufferLen = MAX_PATH, dwValueBufferLen = MAX_PATH;
LONG lResult;
DWORD dwIndex = 0;
HKEY hOpenedKey;
DWORD dwType;
lResult = RegOpenKeyEx( hKey
, lpSubKey
, 0
, KEY_QUERY_VALUE | KEY_ENUMERATE_SUB_KEYS
, &hOpenedKey
);
if(ERROR_ACCESS_DENIED == lResult)
return TRUE;
if(ERROR_SUCCESS != lResult)
return result;
lResult = RegEnumValue(hOpenedKey,dwIndex,nameBuffer,&dwNameBufferLen,NULL,
&dwType,NULL,&dwValueBufferLen);
if(ERROR_SUCCESS != lResult)
{
result = (lResult == ERROR_NO_MORE_ITEMS);
}
else
result = TRUE;
if(!result)
{
RegCloseKey(hOpenedKey);
return FALSE;
}
if(!WriteData(hFile,"[",1) ||
!WriteData(hFile,key_names[(int)hKey],lstrlen(key_names[(int)hKey])) ||
!WriteData(hFile,lpSubKey,lstrlen(lpSubKey)) ||
!WriteData(hFile,"]\r\n",3))
{
RegCloseKey(hOpenedKey);
return FALSE;
}
do
{
BYTE* bData = new BYTE[dwValueBufferLen];
if(bData)
{
lResult = RegQueryValueEx( hOpenedKey
, nameBuffer
, NULL
, &dwType
, bData
, &dwValueBufferLen
);
if(ERROR_SUCCESS == lResult)
{
//compute length of buffer
DWORD dwBufLen = ValGetBufferLength(dwNameBufferLen,dwValueBufferLen,dwType);
if(dwBufLen)
{
BYTE* bWorkBuffer = new BYTE[dwBufLen];
if(bWorkBuffer)
{
DWORD dwToWrite = FormatBuffer(bWorkBuffer,nameBuffer,dwNameBufferLen,
bData,dwValueBufferLen,dwType);
if(dwToWrite)
{
if(WriteData(hFile,bWorkBuffer,dwToWrite))
result = TRUE;
} // if(dwToWrite)
} // if(bWorkBuffer)
delete [] bWorkBuffer;
} // if(dwBufLen)
} // if(ERROR_SUCCESS == lResult)
} // if(bData)
delete [] bData;
if(!result)
break;
dwNameBufferLen = dwValueBufferLen = MAX_PATH;
dwIndex++;
} while(ERROR_NO_MORE_ITEMS != RegEnumValue(hOpenedKey,dwIndex,
nameBuffer,&dwNameBufferLen,NULL,
NULL,NULL,&dwValueBufferLen));
if(!result || !WriteData(hFile,CRLF,CRLF_LEN))
{
RegCloseKey(hOpenedKey);
return FALSE;
}
if(bSaveSubtree)
{
char pathBuffer[MAX_PATH] = {0};
dwIndex = 0;
dwNameBufferLen = MAX_PATH;
lResult = RegEnumKey(hOpenedKey,dwIndex,nameBuffer,dwNameBufferLen);
if(ERROR_SUCCESS != lResult)
{
RegCloseKey(hOpenedKey);
return (lResult == ERROR_NO_MORE_ITEMS);
} // if(ERROR_SUCCESS != lResult)
int len = lstrlen(lpSubKey);
do
{
lstrcpy(pathBuffer,lpSubKey);
if(pathBuffer[len-1] != '\\')
lstrcat(pathBuffer,"\\");
lstrcat(pathBuffer,nameBuffer);
result = result && ExportKey(hFile,hKey,pathBuffer, bSaveSubtree);
if(!result)
break;
dwIndex++;
} while(ERROR_NO_MORE_ITEMS !=
RegEnumKey(hOpenedKey,dwIndex,nameBuffer,dwNameBufferLen));
} // if(bSaveSubtree)
RegCloseKey(hOpenedKey);
return result;
}
//---------------------------------------------------------------------------
BOOL WINAPI ExportRegistryData( HKEY hKey
, LPCTSTR lpSubKey
, LPCTSTR lpValueName
, BOOL bSaveSubtree
, LPCTSTR lpFileName
, BOOL bWriteHeader
)
{
BOOL result = FALSE;
// check parameters
if(!lpFileName || (bSaveSubtree && lpValueName) )
return result;
HANDLE hFile = CreateFile( lpFileName
, GENERIC_WRITE
, FILE_SHARE_WRITE
, NULL
, CREATE_ALWAYS
, FILE_ATTRIBUTE_NORMAL
, NULL
);
if(INVALID_HANDLE_VALUE == hFile)
return result;
HKEY hOpenedKey;
LONG lResult = RegOpenKeyEx( hKey
, lpSubKey
, 0
, KEY_QUERY_VALUE | KEY_ENUMERATE_SUB_KEYS
, &hOpenedKey
);
if(ERROR_SUCCESS != lResult)
{
CloseHandle(hFile);
::DeleteFile(lpFileName);
return result;
}
// save one value?
if(lpValueName)
{
DWORD dwType;
DWORD dwDataLen;
lResult = RegQueryValueEx( hOpenedKey
, lpValueName
, NULL
, &dwType
, NULL
, &dwDataLen
);
if(ERROR_SUCCESS == lResult)
{
BYTE* bData = new BYTE[dwDataLen];
if(bData)
{
// query for value
lResult = RegQueryValueEx( hOpenedKey
, lpValueName
, NULL
, NULL
, bData
, &dwDataLen
);
if(ERROR_SUCCESS == lResult)
{
//compute length of buffer
DWORD dwValueNameLen = lstrlen(lpValueName);
DWORD dwBufLen = ValGetBufferLength(dwValueNameLen,dwDataLen,dwType);
if(dwBufLen)
{
BYTE* bWorkBuffer = new BYTE[dwBufLen];
if(bWorkBuffer)
{
DWORD dwToWrite = FormatBuffer(bWorkBuffer,lpValueName,
dwValueNameLen,bData,dwDataLen,dwType);
if(dwToWrite)
{
if( ( bWriteHeader ? WriteData(hFile,FILE_HEADER,
lstrlen(FILE_HEADER)) : TRUE ) &&
WriteData(hFile,"[",1) &&
WriteData(hFile,key_names[(int)hKey],
lstrlen(key_names[(int)hKey])) &&
WriteData(hFile,lpSubKey,lstrlen(lpSubKey)) &&
WriteData(hFile,"]\r\n",3) &&
WriteData(hFile,bWorkBuffer,dwToWrite) &&
WriteData(hFile,CRLF,CRLF_LEN))
result = TRUE;
} // if(dwToWrite)
} // if(bWorkBuffer)
delete [] bWorkBuffer;
} // if(dwBufLen)
} // if(ERROR_SUCCESS == lResult)
} // if(bData)
delete [] bData;
} // if(ERROR_SUCCESS == lResult)
} // if(lpValueName)
else
{
// export tree...
if( ( bWriteHeader ? WriteData(hFile,FILE_HEADER,lstrlen(FILE_HEADER)) : TRUE ) )
result = ExportKey(hFile,hKey,lpSubKey,bSaveSubtree);
} // else
RegCloseKey(hOpenedKey);
CloseHandle(hFile);
if(!result)
::DeleteFile(lpFileName);
return result;
}
//---------------------------------------------------------------------------
Здравствуйте, CAMAD, Вы писали:
[]
F>>Дык формат файла совместим с Regedit. Т.е. Regedit.exe импортирует полученный файл вполне нормально.
CAM>Хм, тогда какой смысл вообще писать свою функцию для экспорта ? Regedit.exe и экспортирует ключики вполне нормально.
Дело в том, что Regedit от Win2000 и XP экспортирует немножко по другому, нежели Regedit от Win98. Т.е. файл, сэкспортированный из Win2000, Win98 просто не поймет. А у меня — совместимый формат REGEDIT4. В принципе, если немножко подкрутить, то будет вообще шоколадно
Далее: RegSaveKey — это вообще отдельная песня

Поищите по форумам, если интересно. Много нового узнаете о проблемах совместимости
Зачем это было нужно мне: юзер выбирает, какие ключики удалять из реестра. Перед удалением делается бэкап-файл, который юзер может _сам_, если захочет, импортировать в реестр. С помощью Regedit, ессно
Здравствуйте, Блудов Павел, Вы писали:
БП>Здравствуйте, Flamer, Вы писали:
F>>Дело в том, что Regedit от Win2000 и XP экспортирует немножко по другому, нежели Regedit от Win98. Т.е. файл, сэкспортированный из Win2000, Win98 просто не поймет. А у меня — совместимый формат REGEDIT4. В принципе, если немножко подкрутить, то будет вообще шоколадно
БП>Там вибиралка есть — в каком формате сохранять. По умолчанию REGEDIT5 (уникод). Но REGEDIT4 там тоже имеется.
Выбиралка пущай будет. А теперь вопрос: как из программы указать выбиралку? Чего указать в ShellExecute? Как понять, что ключ экспортировался? Вдруг нету Regedit.exe на машине (есть и такое, причем не так уж редко)? Вдруг доступ к Regedit.exe запрещен злобным админом? А хочется немного поэкспортировать...
З.Ы. В общем, я понял: опять я изобрел велосипед

Сам себе ищу проблемы

Хотя, что странно, пользуюсь своими решениями этих проблем.. Может, пора завязывать? Трава, правда, хороша
Здравствуйте, Блудов Павел, Вы писали:
БП>Здравствуйте, Flamer, Вы писали:
F>>А теперь вопрос: как из программы указать выбиралку? Чего указать в ShellExecute?
БП>regedit.exe /e <filename> <KEY PATH> для REGEDIT5
БП>regedit.exe /a <filename> <KEY PATH> для REGEDIT4
БП>regedit.exe /ea <filename> <KEY PATH> для REGEDIT5 под XP и REGEDIT4 под 98
F>> Как понять, что ключ экспортировался?
БП>По наличию файла
F>> Вдруг нету Regedit.exe на машине (есть и такое, причем не так уж редко)? Вдруг доступ к Regedit.exe запрещен злобным админом? А хочется немного поэкспортировать...
БП>Тода да. Но тогда где импорт? Нужно еще и доморощенный импорт — для полноты картины.
БП>Павел.
---------------------------
Класная тема.
Мне как раз понадобилось сохранить на дискету ключ и поднять на другой машине.
БП>regedit.exe /a <filename> <KEY PATH> для REGEDIT4
работает прекрасно, а вот при поднятии выскакивает диалог
---------------------------
Registry Editor
---------------------------
Are you sure you want to add the information in xxxxx.reg to the registry?
---------------------------
Yes No
---------------------------
Какой опцией можно это подавить?
И где посмотреть список ключей командной строки для regedit.exe?