#c #debugging #winapi #registry #release
#c #отладка #winapi #реестр #выпуск
Вопрос:
Это сводит меня с ума. Я компилирую свой проект в Visual Studio 2012. Я хочу прочитать REG_BINARY
запись в реестре, используя вызовы RegOpenKeyEx
и RegQueryValueEx
. В режиме отладки (многопоточная отладка) все работает идеально. Однако в режиме выпуска (многопоточный) RegQueryValueEx
очень часто происходит сбой с кодом ошибки ERROR_MORE_DATA
. Вот код, который я использую:
HKEY keyHandle;
TCHAR lpData[1024];
DWORD lpcbData;
if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, L"SOFTWARE\Microsoft\Windows NT\CurrentVersion", 0, KEY_QUERY_VALUE | KEY_WOW64_64KEY, amp;keyHandle) != ERROR_SUCCESS){
MessageBox(NULL, L"fail", L"title", MB_OK);
return NULL;
} else if (RegQueryValueEx(keyHandle, L"DigitalProductId", NULL, NULL, (LPBYTE)lpData, amp;lpcbData) != ERROR_SUCCESS){
MessageBox(NULL, L"fail!", L"title", MB_OK);
return NULL;
}
MessageBox(NULL, L"success", L"title", MB_OK);
Ответ №1:
По определению RegQueryValueEx, lpcbData является как входным, так и исходящим параметром. То есть RegQueryValueEx одновременно считывает его и записывает в него. Он жалуется, потому что вы передаете его, не инициализируя его сначала размером буфера, который в вашем случае равен 1024 (также я рекомендую вам изменить TCHAR на BYTE, как того требует API; позже вы можете преобразовать его в строку Unicode).
Попробуйте установить его равным 1024 перед вызовом функции. Если затем произойдет сбой с ERROR_MORE_DATA, то ваш буфер недостаточно велик — другими словами, строка раздела реестра слишком длинная — вы можете либо определить, чтобы она содержала больше символов, либо, что еще лучше, сначала вызвать функцию с параметром NULL вместо buffer, и вы получите обратно в lpcbData требуемый размер буфера. Затем вы можете выделить необходимый буфер в куче. Надеюсь, это поможет!
Комментарии:
1. @Mints97 Чтобы ответить на вопрос, который сводит вас с ума: похоже, это работает в отладочных сборках, поскольку отладочные сборки инициализируют память битовым шаблоном (0xcccccccccc), чтобы легче обнаруживать неинициализированную память. Это значение достаточно велико, чтобы прочитать данные вашего реестра за один раз. Это также больше, чем ваш фактический размер буфера. В сборках выпуска неинициализированная память содержит все, что оставила там предыдущая операция записи. Память, в которую ранее не было записано значение 0. Передача 0 в качестве
lpcbData
аргумента с ненулевым значениемlpData
неизбежно приводит кERROR_MORE_DATA
.
Ответ №2:
Вы не выполняете инициализацию lpcbData
перед вызовом RegQueryValueEx()
. Вы должны указать ему, насколько велик lpData
, в байтах, чтобы он знал, сколько байтов он может восстановить.
DWORD lpcbData = sizeof(lpData);
Прочитайте документацию:
lpcbData [ввод, вывод, необязательно]
Указатель на переменную, которая определяет размер буфера, на который указывает параметр lpData, в байтах. Когда функция возвращается, эта переменная содержит размер данных, скопированных в lpData.
Лучший вариант — спросить реестр, насколько велики данные, а затем (повторно) выделить буфер по мере необходимости. Пример в документации показывает, как это сделать.
Комментарии:
1. Большое вам спасибо, я попробую перераспределить размер буфера!
Ответ №3:
Вы должны установить lpcbData
размер вашего буфера, прежде чем передавать его в RegQueryValueEx()
.
Пример кода:
HKEY keyHandle;
TCHAR lpData[1024];
DWORD lpcbData= sizeof(lpData); //set size.
if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, L"SOFTWARE\Microsoft\Windows NT\CurrentVersion", 0, KEY_QUERY_VALUE | KEY_WOW64_64KEY, amp;keyHandle) != ERROR_SUCCESS){
MessageBox(NULL, L"fail", L"title", MB_OK);
return NULL;
} else if (RegQueryValueEx(keyHandle, L"DigitalProductId", NULL, NULL, (LPBYTE)lpData, amp;lpcbData) != ERROR_SUCCESS){
MessageBox(NULL, L"fail!", L"title", MB_OK);
return NULL;
}
Он работает случайно, так что lpcData
содержит некоторое случайное значение, которое превышает фактический размер данных. И, вероятно, ваши данные не превышают 1024.
Более того, если вы получите ERROR_MORE_DATA
ошибку, lpcData
будет указано, какой размер требуется для чтения данных. Поэтому вам следует соответствующим образом обновить свой буфер и повторить попытку.