C ++ для чтения и записи реестра Windows правильно - PullRequest
0 голосов
/ 05 августа 2010

Так что я застрял на этом некоторое время ... думал, что заставил его работать, но иногда он ломается, и я не уверен в точных причинах ...

Я не уверен, имеет ли это значение, но я пишу это в Browser Helper Object (BHO) ... Всегда ли IE 32-битный процесс, независимо от того, работает ли он на 64 и 32-битной ОС?

так что я хочу иметь возможность читать из реестра ключ, который мне может понадобиться ...

Я использую эту функцию:

if (RegCreateKeyEx(HKEY_CURRENT_USER, L"Software\\ProductName", 0, NULL,
                   REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS | KEY_WOW64_32KEY,
                   NULL, &hk, NULL) == ERROR_SUCCESS)

тогда я проверяю, существует ли ключ с этим:

TCHAR ext_id[20];
DWORD toolbarIdLength;

if(RegQueryValueEx(hk, L"ext_id", NULL, NULL,
                   (LPBYTE)ext_id, &extIdLength) == ERROR_SUCCESS)

в случае успеха, я проверяю, завершено ли оно нулем:

ext_id[extIdLength] = 0;

иначе я использую wininet lib для отправки информации на мой сервер, назначая новый ext_id и записываю в реестр это значение ... используя эту функцию:

RegSetValueEx(hk, L"ext_id", 0, REG_SZ, (const BYTE *)ext_id, _tcslen(ext_id)*2 + 1);

по какой-то странной причине он писал только половину материала, который я передавал, поэтому я удвоил _tcslen (ext_id) и добавил 1 для безопасности? Большинство примеров, которые я нашел в Интернете, не имеют этой длины, умноженной на 2, она работает для меня так, поэтому я оставил ее в покое ...

кажется все это работало правильно:

и это сработало для моего dev_machine: Windows 7 64bit.

протестировано на 32-битной Windows 7 ...

Проблема возникла в Windows XP IE 6, она не работала, но кажется, что если я снова вызову функцию RegQueryValueEx, она вернет правильное значение, поэтому я заметил в следующем запросе ...

Я также заметил, что в зависимости от того, какую другую строку я отправляю на сервер, она будет работать по-разному, это может быть связано с тем, что я относительно новичок в C ++ (на самом деле, только пару недель) и я уверен, что я делаю что-то действительно неправильно.

О, я прочитал в msdn, что мне нужно использовать KEY_WOW64_32KEY или KEY_WOW64_64KEY в флагах для открытия ключа реестра в зависимости от ситуации ... но действительно ли это необходимо в моей ситуации (BHO для браузеров 6.0 - 8.0)

1 Ответ

0 голосов
/ 05 августа 2010

Вы упали из-за того, как Windows обрабатывает Unicode. Dev Studio имеет удобный переключатель, который позволяет вам переключаться между сборками Unicode и Multibyte для приложений, и вы собираете для Unicode.

Расположение: «Свойства проекта» - «Свойства конфигурации» - «Общие» - «Набор символов». Использовать набор символов «Юникод».

Буква L перед всеми вашими строковыми литералами означает, что строковый литерал является массивом wchar_t's: L "Software \ ProductName".

TCHAR - это макрос, который означает wchar_t при сборке для Unicode и `char1 при сборке приложения с многобайтовым набором символов.

_tcslen также является MACRO, который msv c-runtine определяет как strlen или wcslen в зависимости от выбранного набора символов проектов.

В любом случае, суть проблемы заключается в следующем: wcslen возвращает количество wchar_t в строке, а функции реестра ожидают количество байтов данных.

Это был бы правильный способ записи RegSetValueEx, такой, чтобы набор переключателей символов работал:

DWORD cch=0;
StrCchLength(ext_id,1024,&cch);
RegSetValueEx(hk, TEXT("ext_id"), 0, REG_SZ, (const BYTE *)ext_id, ( cch + 1) * sizeof(TCHAR));

Обратите внимание, что я использовал API StrCchLength из StrSafe.h вместо strlen, wcslen, lstrlen или связанных API. StrCchLength и связанные с ним API имеют функции, помогающие писать более безопасный код - в этом случае вместо выполнения неограниченной записи в реестр ext_id «обрезается» до 1024 символов.

Примечание: Вы должны быть здесь очень осторожны. Некоторые из API-интерфейсов реестра задокументированы как требующие, чтобы количество байтов ИСКЛЮЧАЛО завершающий ноль, RegSetValueEx требует, чтобы число байтов включало нулевой терминатор. Поэтому я добавляю +1 к количеству символов в строке ТО, умножаем на размер TCHAR, чтобы получить количество типов.


При чтении значений - причина, по которой вам нужно выполнить двойной запрос, заключается в том, что RegQueryValueEx использует указатель lpcbData для двух целей - в качестве входного значения он определяет размер буфера и в качестве выходного значения, где он возвращает количество фактически записанных байтов в буфер (в случае успеха) ИЛИ, если код возврата - ERROR_MORE_DATA, тогда буфер НЕ записывается, но * lpcbData установлено на необходимое количество байтов.

TCHAR ext_id[20];
DWORD extIdLength = sizeof (ext_id); // you need to initialize this
LONG err = RegQueryValueEx(hk, TEXT("ext_id"), NULL, NULL, (LPBYTE)ext_id, &extIdLength) ;
if(err == ERROR_MORE_DATA) {
  // you can try again here, using extIdLength to create a new buffer that IS big enough
}
if(err == ERROR_SUCCESS){
  ...
...