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. Реализация приведена ниже.

void ReadVersion(_TCHAR * szVer, int cbVer, const _TCHAR * szEntry)
{
_tcscpy(szVer, _T("\n"));
HRSRC hVersion = FindResource(
NULL,
MAKEINTRESOURCE(VS_VERSION_INFO),
RT_VERSION);
if (hVersion)
{
DWORD dwSize = SizeofResource(NULL, hVersion);
HGLOBAL hGlobal = LoadResource(NULL, hVersion);
if (hGlobal != NULL)
{
LPVOID versionInfoGlobal = LockResource(hGlobal);
if (versionInfoGlobal != NULL)
{
LPVOID versionInfoLocal = LocalAlloc(LMEM_FIXED, dwSize);
CopyMemory(versionInfoLocal, versionInfoGlobal, dwSize);

DWORD vLen, langD;
BOOL retVal;

LPVOID retbuf = NULL;

#ifdef _UNICODE
const _TCHAR * entry = szEntry;
#else
WCHAR entry[64]; //I assume here that length of szEntry string is less than 64
MultiByteToWideChar(CP_ACP, 0, szEntry, -1, entry, 64);
#endif

WCHAR fileEntry[1024];

_swprintf(fileEntry, L"\\VarFileInfo\\Translation");
retVal = VerQueryValueW(versionInfoLocal, fileEntry, &retbuf, (UINT*)&vLen);
if (retVal && vLen == 4)
{
memcpy(&langD, retbuf, 4);
_swprintf(fileEntry, L"\\StringFileInfo\\%02X%02X%02X%02X\\%s",
(langD & 0xff00)>>8,langD & 0xff,(langD & 0xff000000)>>24,
(langD & 0xff0000)>>16, entry);
}
else
_swprintf(fileEntry, L"\\StringFileInfo\\%04X04B0\\%s",
GetUserDefaultLangID(), entry);

retVal = VerQueryValueW(versionInfoLocal, fileEntry, &retbuf, (UINT*)&vLen);
if (retVal)
{
#ifdef _UNICODE
_sntprintf(szVer, cbVer-1, _T(" %s\n"), (_TCHAR*)retbuf);
szVer[cbVer-1] = '\0';
#else
szVer[0] = '\0';
int n = WideCharToMultiByte(CP_ACP, 0, (LPWSTR)retbuf, -1, szVer+1, cbVer-2, NULL, NULL);
if (n > 0)
{
szVer[0] = ' ';
szVer[n] = '\n';
szVer[n+1] = '\0';
}
#endif
}

LocalFree(versionInfoLocal);
}
FreeResource(hGlobal);
}
}
}

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