Windows10中的VerQueryValue

时间:2016-11-28 08:55:15

标签: c++ winapi visual-studio-2012

我已使用Win8项目从Win10移至VS2012 C++。我在Win8中使用VerQueryValue函数时没有问题,但现在我在调试时遇到错误:

Unhandled exception at 0x77C88F11 (ntdll.dll) in MyApp.exe: 0xC0000005: Access violation writing location 0x00AAC2DC.

我使用MSDN中的示例代码:

CString GetVersionInfo(HMODULE hLib, CString csEntry)
{
    CString csRet;

    if (hLib == NULL)
        hLib = AfxGetResourceHandle();

    HRSRC hVersion = FindResource( hLib, 
        MAKEINTRESOURCE(VS_VERSION_INFO), RT_VERSION );
    if (hVersion != NULL)
    {
        HGLOBAL hGlobal = LoadResource( hLib, hVersion ); 
        if ( hGlobal != NULL)  
        {  

            LPVOID versionInfo  = LockResource(hGlobal);  
            if (versionInfo != NULL)
            {
                DWORD vLen,langD;
                BOOL retVal;    

                LPVOID retbuf=NULL;

                static char fileEntry[256];

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

                if (VerQueryValue(versionInfo,fileEntry,&retbuf,(UINT *)&vLen)) 
                    csRet = (char*)retbuf;
            }
        }

        UnlockResource( hGlobal );  
        FreeResource( hGlobal );  
    }

    return csRet;
}

可能有什么问题?

1 个答案:

答案 0 :(得分:4)

直接访问版本资源数据,而不是使用GetFileVersionInfo()。因此,您无法使用VerQueryValue()来查询本地化值,您只能查询 VS_FIXEDFILEINFO结构,而不能查询任何其他内容。即便如此,您也无法使用LockResource()的返回值进行访问。在访问结构之前,必须将资源数据复制到您自己的读/写内存缓冲区中。

原因是GetFileVersionInfo()执行VerQueryValue()内部使用的数据查找和内存块分配。 Raymond Chen在他的博客上解释了这一点:

The first parameter to VerQueryValue really must be a buffer you obtained from GetFileVersionInfo

  

文档说明,VerQueryValue的第一个参数必须是GetFileVersionInfo函数返回的缓冲区。 GetFileVersionInfo返回的缓冲区是一个专门格式化的不透明数据块,以便VerQueryValue可以工作。你不应该查看那个缓冲区,你当然不能尝试“以其他方式获取数据”。因为如果你这样做,VerQueryValue将在缓冲区中查找未按函数预期的方式格式化的内容

这就是您遇到崩溃的原因 - VerQueryValue()正在尝试访问尚未正确设置的内存。

如果要直接访问版本资源,则需要手动解析其数据,根本不要使用VerQueryValue()。您幸运以前您的代码从未崩溃过。您在未定义的行为区域内操作!你的运气已经用光了。你需要重新编写代码来做正确的事情。