четверг, 23 августа 2012 г.

VerQueryValue Access Violation

Столкнулся с интересным багом при получении информации о версии из ресурсов (Visual Studio 10, C++).


Access Violation возникает при выполнении VerQueryValue (см. картинку).
Причем, ошибка возникает только если используется Multi-Byte Character Set. А если выставить в свойствах проекта Use Unicode Character Set, то ошибка пропадает. Из этого можно сделать вывод, что баг именно в VerQueryValueA, а в VerQueryValueW его нет.
Что ж, решение проблемы заключается в переписывании функции чтения информации о версии таким образом, чтобы всегда использовалась функция VerQueryValueW. Ниже приведен листинг готовой функции.

UPD 30.01.2014. Спустя полтора года выяснилось, что и с использованием VerQueryValueW возможен Access Violation. Что же, лучше поздно чем никогда. Дело в том, что эта функция рассчитана на то, чтобы быть использованной совместно GetFileVersionInfo. Возможно, VerQueryValue может в каких-то случаях модифицировать ресурс. В общем, фикс заключается в том, что нужно выделить участок памяти (например, с помощью LocalAlloc), скопировать в него информацию о версии из ресурса (CopyMemory), и использовать его при вызове VerQueryValue. Реализация приведена ниже.

  1. void ReadVersion(_TCHAR * szVer, int cbVer, const _TCHAR * szEntry)
  2. {
  3.     _tcscpy(szVer, _T("\n"));
  4.     HRSRC hVersion = FindResource(
  5.         NULL,
  6.         MAKEINTRESOURCE(VS_VERSION_INFO),
  7.         RT_VERSION);
  8.     if (hVersion)  
  9.     {
  10.         DWORD dwSize = SizeofResource(NULL, hVersion);
  11.         HGLOBAL hGlobal = LoadResource(NULL, hVersion);
  12.         if (hGlobal != NULL)  
  13.         {
  14.             LPVOID versionInfoGlobal  = LockResource(hGlobal);
  15.             if (versionInfoGlobal != NULL)
  16.             {
  17.                 LPVOID versionInfoLocal = LocalAlloc(LMEM_FIXED, dwSize);
  18.                 CopyMemory(versionInfoLocal, versionInfoGlobal, dwSize);
  19.  
  20.                 DWORD vLen, langD;
  21.                 BOOL retVal;
  22.  
  23.                 LPVOID retbuf = NULL;
  24.  
  25. #ifdef _UNICODE
  26.                 const _TCHAR * entry = szEntry;
  27. #else                    
  28.                 WCHAR entry[64]; //I assume here that length of szEntry string is less than 64
  29.                 MultiByteToWideChar(CP_ACP, 0, szEntry, -1, entry, 64);
  30. #endif
  31.  
  32.                 WCHAR fileEntry[1024];
  33.  
  34.                 _swprintf(fileEntry, L"\\VarFileInfo\\Translation");
  35.                 retVal = VerQueryValueW(versionInfoLocal, fileEntry, &retbuf, (UINT*)&vLen);
  36.                 if (retVal && vLen == 4)
  37.                 {
  38.                     memcpy(&langD, retbuf, 4);            
  39.                     _swprintf(fileEntry, L"\\StringFileInfo\\%02X%02X%02X%02X\\%s",
  40.                             (langD & 0xff00)>>8,langD & 0xff,(langD & 0xff000000)>>24,
  41.                             (langD & 0xff0000)>>16, entry);            
  42.                 }
  43.                 else
  44.                     _swprintf(fileEntry, L"\\StringFileInfo\\%04X04B0\\%s",
  45.                     GetUserDefaultLangID(), entry);
  46.  
  47.                 retVal = VerQueryValueW(versionInfoLocal, fileEntry, &retbuf, (UINT*)&vLen);
  48.                 if (retVal)
  49.                 {
  50. #ifdef _UNICODE
  51.                     _sntprintf(szVer, cbVer-1, _T(" %s\n"), (_TCHAR*)retbuf);
  52.                     szVer[cbVer-1] = '\0';
  53. #else
  54.                     szVer[0] = '\0';
  55.                     int n = WideCharToMultiByte(CP_ACP, 0, (LPWSTR)retbuf, -1, szVer+1, cbVer-2, NULL, NULL);
  56.                     if (n > 0)
  57.                     {
  58.                         szVer[0] = ' ';
  59.                         szVer[n] = '\n';
  60.                         szVer[n+1] = '\0';
  61.                     }
  62. #endif
  63.                 }
  64.  
  65.                 LocalFree(versionInfoLocal);
  66.             }
  67.             FreeResource(hGlobal);
  68.         }
  69.     }
  70. }

===
Перепечатка материалов блога разрешается с обязательной ссылкой на blog.coolsoftware.ru

Комментариев нет:

Отправить комментарий