【问题标题】:How to get FileDescription with VerQueryValue (getting the example to work)?如何使用 VerQueryValue 获取 FileDescription(让示例工作)?
【发布时间】:2020-08-22 19:34:17
【问题描述】:

我正在尝试使用 WinAPI 函数 VerQueryValue 获取文件的各种属性,如其“详细信息”选项卡中所示。我已成功使用此函数通过VS_FIXEDFILEINFO 获取非字符串版本信息,但无法使函数文档底部显示的example 正常工作。

该示例实际上并不完整,因为它省略了其他相关函数的使用以及使用该函数所需的一些缓冲区的构造,因此我已尽我所能填补空白并更改了一些使用 C++ SL 的中间步骤,因为这最终是我需要使用的语言:

#include <iostream>
#include <iomanip>
#include "sstream"
#include "Windows.h"
#pragma comment(lib, "Version.lib")

int ReadOutFileDescriptions(std::wstring filename)
{
    LPBYTE lpBuffer = NULL;
    DWORD  verHandle, verSize = GetFileVersionInfoSize(filename.c_str(), &verHandle);

    if (verSize != NULL)
    {
        LPSTR verData = new char[verSize];

        if (GetFileVersionInfo(filename.c_str(), verHandle, verSize, verData))
        {
            UINT cbTranslate;

            // Structure used to store enumerated languages and code pages.
            struct LANGANDCODEPAGE {
                WORD wLanguage;
                WORD wCodePage;
            } *lpTranslate;

            // Read the list of languages and code pages.
            VerQueryValue(verData, TEXT("\\VarFileInfo\\Translation"), (LPVOID*)&lpTranslate, &cbTranslate);

            // Read the file description for each language and code page.
            for (ULONGLONG i = 0; i < (cbTranslate / sizeof(struct LANGANDCODEPAGE)); i++)
            {
                std::wostringstream ss; ss << std::setfill(L'0') << std::hex;
                ss << std::setw(4) << lpTranslate[i].wLanguage;
                std::wstring langS = ss.str();
                ss.str(std::wstring());
                ss << std::setw(4) << lpTranslate[i].wCodePage;
                std::wstring codeS = ss.str();
                std::wstring subBlock = L"\\StringFileInfo\\" + langS + codeS + L"\\FileDescription";

                // Retrieve file description for language and code page "i".
                WCHAR descBuffer[50];
                LPVOID lpBuffer = &descBuffer;
                UINT bufferSize;
                VerQueryValue(verData, subBlock.c_str(), &lpBuffer, &bufferSize);
                
                std::cout << bufferSize << '\n' << descBuffer; 
            }
        }

        delete[] verData;
    }

    return 0;
}

int main(int argc, char* argv[])
{
    ReadOutFileDescriptions(L"MyFile.exe");
    return 0;
}

我只对 WinAPI 及其 typedef 有一点经验,而且我的 C 有点生疏,所以我确定我只是设置/使用不正确的缓冲区等。

打印的缓冲区大小是正确的(MyFile.exe 的描述长度 + 1 表示空字符)所以我知道函数正在获取正确的值,但实际打印的值只是一系列十六进制字符,很可能是地址。

我做错了什么?

编辑(答案): 感谢@dxiv,我意识到我并不完全理解如何在内部和函数返回后使用 VerQueryValue 的“结果”参数 (lplpBuffer)。

将循环的结尾更改为以下即可达到我想要的结果:

//WCHAR descBuffer[50] Not required, the function doesn't utilize a user made buffer
LPVOID lpBuffer;
UINT bufferSize;

VerQueryValue(verData, subBlock.c_str(), &lpBuffer, &bufferSize); // lpBuffer is reassigned here
std::wstring fileDescription((const TCHAR*)lpBuffer); // Create std::string from C style string (char*) that lpBuffer now points to
std::wcout << bufferSize << '\n' << fileDescription;

【问题讨论】:

  • std::cout 不知道有关 WCHAR[] 的 bean,请使用 std::wcout。支持调试器。
  • lpBuffer null 终止了吗?
  • @Mayur 是的,虽然在调用返回之前字符串的长度也被放入“puLen”(此处为bufferSize)缓冲区参数中
  • 文档中没有提到它,但实际上它是空终止的,至少在我的带有 SDK 10.0.18362 的 Windows 10 机器上(证明:i.imgur.com/Lznaziv.png)。虽然通常您不应该依赖于一种实现,但对这种行为进行更改无疑会破坏许多应用程序,并且非常重要,我怀疑它会被更改。如果您仍然希望安全,在 C++ 中您可以使用构造函数 std::wstring((const TCHAR*)lpBuffer, *puLen) 来指定 str 长度,或者在 C 中您可以分配一个 *puLen+1 的缓冲区, strcpy lpBuffer 进去,然后做 buffer[*puLen+1] = '\0'
  • @Mayur 不是 stackoverflow 最正式的事情,但我意识到我在上次回复时忘记联系你了。

标签: c++ c winapi


【解决方案1】:
VerQueryValue(verData, subBlock.c_str(), &lpBuffer, &bufferSize);

std::cout << bufferSize << '\n' << descBuffer; 

一旦VerQueryValue 返回,lpBuffer 不再指向descBuffer,而是指向调用内部分配的不同缓冲区。此时返回的字符串位于(const TCHAR *)lpBuffer

【讨论】:

  • 现在我明白为什么这个论点是无效的了**。我已经习惯了这些函数让你为“输出”提供一个指向你自己的缓冲区的指针,但在这种情况下,它在内部构造结果并更改你提供的指针,以便它最终指向结果的开头,因为它是一个 C 风格的字符串。我将更新问题以使用您的更正。
  • @oblivioncth 是的,void ** 是一个死的赠品。另一个自然的问题是谁拥有该指针以及如何处理它。对此的回答来自docs:“包含指向所请求版本信息的指针的地址 在 pBlock 指向的缓冲区中 . 当相关的pBlock内存被释放时,lplpBuffer指向的内存被释放。”。因此,在返回时,lpBuffer 实际上指向大 verData 块内的某个位置。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2023-03-26
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-07-29
  • 2015-03-16
相关资源
最近更新 更多