2016-11-28 50 views
-1

我已使用VS2012 C++項目從Win8移至Win10。我沒有問題,而在Win8中使用VerQueryValue功能,但現在我調試過程中有錯誤:Windows10中的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; 
} 

可能是什麼問題?

+2

做一些調試。代碼中寫入的特定內存會導致異常。一邊。你爲什麼決定讓'fileEntry'靜態?你知道這意味着你的函數不是線程安全的嗎?通過使其變爲靜態可能會獲得什麼? 'VerQueryValue'中的 –

+0

異常?或者在'CString csEntry'中使用'%s'時可能在'sprintf'中? – RbMm

+0

顯示調用堆棧。顯示你如何調用'GetVersionInfo'。顯示[mcve]。 –

回答

3

您是直接訪問版本資源數據而不是使用GetFileVersionInfo()。因此,您不能使用VerQueryValue()來查詢本地化值,您可以查詢只有VS_FIXEDFILEINFO結構,沒有別的。即使如此,您也無法使用該訪問的返回值LockResource()。您必須先將將資源數據複製到您自己的讀取/寫入內存緩衝區,然後再訪問該結構。

原因是因爲GetFileVersionInfo()執行數據查找和內存使用的內存塊分配VerQueryValue()。雷蒙德陳解釋說這在他的博客:

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

的文件說,到VerQueryValue的第一個參數必須由GetFileVersionInfo函數的一個原因返回的緩衝區。 GetFileVersionInfo返回的緩衝區是一個特殊格式的不透明數據塊,以便VerQueryValue可以工作。你不應該看看緩衝區,你當然不能試圖「以其他方式獲取數據」。因爲如果你這樣做,VerQueryValue會在緩衝區中尋找某些未按照函數預期的方式格式化的東西

這就是爲什麼你會崩潰 - VerQueryValue()正試圖訪問尚未正確設置的內存。

如果您要直接訪問版本資源,那麼您需要手動解析其數據,完全不使用VerQueryValue()。你是幸運你的代碼之前從未崩潰。您正在經營未定義的行爲領土!你的運氣已經用完了。你需要重新編寫代碼來做正確的事情。