使用 GetFileVersionInformation 获取访问冲突错误

Getting Access Violation Error using GetFileVersionInfo

本文关键字:错误 访问冲突 获取 GetFileVersionInformation 使用      更新时间:2023-10-16
    DWORD dwHandle;
    DWORD dwSize = GetFileVersionInfoSizeEx( FILE_VER_GET_NEUTRAL , strFilePath.c_str() , &dwHandle );
    if( dwSize == 0 )
        break;
    pVersionInfo = new BYTE[ dwSize ];
    bRetVal = GetFileVersionInfoEx( FILE_VER_GET_NEUTRAL , strFilePath.c_str() ,dwHandle , dwSize , &pVersionInfo );
    if( bRetVal == false )
        break;
    UINT uLen;
    VS_FIXEDFILEINFO *pFileInfo;
    bRetVal = VerQueryValue( &pVersionInfo , L"\" , (LPVOID *)&pFileInfo , &uLen );
    if( bRetVal == false )
        break;
    DWORD dwFileVersionMS = pFileInfo->dwFileVersionMS;
    DWORD dwFileVersionLS = pFileInfo->dwFileVersionLS;
    DWORD dwLeftMost     = HIWORD(dwFileVersionMS);
    DWORD dwSecondLeft   = LOWORD(dwFileVersionMS);
    DWORD dwSecondRight  = HIWORD(dwFileVersionLS);
    DWORD dwRightMost    = LOWORD(dwFileVersionLS);
    strVersion.sprintf( L"%u.%u.%u.%u", dwLeftMost , dwSecondLeft , dwSecondRight , dwRightMost );
}while(0);
if( pVersionInfo )
    delete []pVersionInfo;
return bRetVal;

在调试此代码时,我在删除语句中收到访问冲突错误......谁能说出我做错了什么。

错误是您将指向已分配数据块的指针作为VerQueryValue的第一个参数传递,这会导致您将错误的地址传递给函数。这会导致未定义的行为,因为VerQueryValue从内存中不应读取/写入数据的某个位置读取数据并将数据写入内存中的某个位置。

解决方案是不要在此处使用地址运算符。


更新:您对GetFileVersionInfoEx函数调用执行相同的操作。不要将地址运算符用于pVersionInfo

错误在行中

bRetVal = GetFileVersionInfoEx( FILE_VER_GET_NEUTRAL , strFilePath.c_str() ,dwHandle , dwSize , &pVersionInfo );

正确的调用应该是

bRetVal = GetFileVersionInfoEx( FILE_VER_GET_NEUTRAL , strFilePath.c_str() ,dwHandle , dwSize , pVersionInfo );

从 msdn:

BOOL WINAPI GetFileVersionInfoEx(
  _In_        DWORD dwFlags,
  _In_        LPCTSTR lptstrFilename,
  _Reserved_  DWORD dwHandle,
  _In_        DWORD dwLen,
  _Out_       LPVOID lpData
);

函数GetFileVersionInfoEx()将使用版本信息填充 lpData(或者在上面更正的示例中为 pVersionInfo)指向的缓冲区。 在您的代码中,它将更改指针的值,使其指向内存中的其他位置。

当您调用 delete[] 时,它会给您异常,因为指针的值已更改,并且它不再是 new [] 运算符设置的值。 换句话说,您正在尝试释放未动态分配的内存。

这是您在

另一个线程中具有完整代码示例的问题的解决方案,但正如所指出的,问题是您将指向信息的缓冲区的指针传递错误的方式,不需要address of操作器。

这是一个截图,您的代码已固定为正常工作:

#include <Windows.h>
#include <cstdio>
#pragma comment(lib, "version.lib")
void main(int argc, char** argv)
{
    const wchar_t* strFilePath = L"C:\Windows\System32\kernel32.dll";
    DWORD dwHandle;
    BOOL bRetVal;
    DWORD dwSize = GetFileVersionInfoSizeEx( FILE_VER_GET_NEUTRAL , strFilePath , &dwHandle );
    if( dwSize == 0 )
        return;
    BYTE* pVersionInfo = new BYTE[dwSize];
    bRetVal = GetFileVersionInfoEx( FILE_VER_GET_NEUTRAL , strFilePath , dwHandle , dwSize , pVersionInfo );
    if( bRetVal == false )
        return;
    UINT uLen;
    VS_FIXEDFILEINFO *pFileInfo = NULL;
    bRetVal = VerQueryValue( pVersionInfo , L"\" , (LPVOID *)&pFileInfo , &uLen );
    if( bRetVal == false )
        return;
    DWORD dwFileVersionMS = pFileInfo->dwFileVersionMS;
    DWORD dwFileVersionLS = pFileInfo->dwFileVersionLS;
    DWORD dwLeftMost     = HIWORD(dwFileVersionMS);
    DWORD dwSecondLeft   = LOWORD(dwFileVersionMS);
    DWORD dwSecondRight  = HIWORD(dwFileVersionLS);
    DWORD dwRightMost    = LOWORD(dwFileVersionLS);
    char pVersion[1024];
    sprintf(pVersion, "%u.%u.%u.%u", dwLeftMost , dwSecondLeft , dwSecondRight , dwRightMost );
    if( pVersionInfo )
        delete []pVersionInfo;
}