【问题标题】:How to extract file description of executables using WINAPI and C++?如何使用 WINAPI 和 C++ 提取可执行文件的文件描述?
【发布时间】:2019-01-27 12:43:42
【问题描述】:

我正在尝试提取可执行文件的文件描述。文件描述是当您右键单击文件时看到的,选择属性,它位于常规选项卡中。

我已尝试使用此处找到的算法:https://docs.microsoft.com/en-us/windows/desktop/api/winver/nf-winver-verqueryvaluea,但对于某些文件,返回的文件描述为空,尽管我可以在“属性”窗口中看到它。例如,如果我创建一个可执行文件,返回的文件描述将为空,但在“属性”窗口中,它的文件描述与其名称相同。如何提取“常规”选项卡中包含的每个可执行文件的文件描述并且不获取空字符串?

我按以下顺序使用函数:

GetFileVersionInfoSize

获取文件版本信息

VerQueryValue

StringCchPrintfW

VerQueryValue

StringCchCopyNW

有时它会在 VerQueryValue 处失败,有时它会在 GetFileVersionInfo 处失败。我还注意到 Microsoft.Photos.exe 失败了

【问题讨论】:

  • 请显示您正在使用的代码,并准确解释观察到的行为与预期行为的偏差。
  • 我使用的代码是 VerQueryValue 的 msdn 页面上的示例。
  • 也许你会,也许你不会。我们不知道,因为我们看不到代码。一旦链接变得无法访问,这个问题就没有多大价值了。请提供minimal reproducible example。还要确保阅读How to Ask
  • 另请注意,Microsoft.Photos.exe 是一个 UWP 应用程序。您在 Properties 对话框中看到的信息很可能是从嵌入式应用程序清单资源中提取的,而不是从版本信息资源中提取的。我不知道,但您可能需要调查一下。
  • 文件描述包含在版本信息中。如果可用,属性窗口显然会显示该描述,如果不可用,则显示可执行文件名称。在你的代码中做同样的事情。

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


【解决方案1】:

如果您想模仿 shell 的行为,请使用 shell API,特别是它的 property system

属性对话框中显示的大部分数据都可以使用一组预定义的常量进行查询,这些常量在“Propkey.h”中定义。在这种情况下,我们需要System.FileDescription property。要查询它,我们需要它的 PKEY,即PKEY_FileDescription

查询属性的最简单方法之一是IShellItem2::GetString() 方法。 out 参数ppsz 返回一个指向字符串的指针,必须使用CoTaskMemFree() 释放该字符串。参考文献中没有提到这一点,但这是释放 shell 分配给您的内存的常用方法。

要从文件系统路径获取 IShellItem2 接口,我们可以使用SHCreateItemFromParsingName()

在以下示例中,我将可重用代码封装在函数 GetShellPropStringFromPath() 中。

示例 C++ 控制台应用程序:

#include <Windows.h>
#include <ShlObj.h>    // Shell API
#include <Propkey.h>   // PKEY_* constants
#include <atlbase.h>   // CComPtr, CComHeapPtr
#include <iostream>
#include <io.h>
#include <fcntl.h>
#include <string>
#include <system_error>

// Wrapper for SHCreateItemFromParsingName(), IShellItem2::GetString()
// Throws std::system_error in case of any error.
std::wstring GetShellPropStringFromPath( LPCWSTR pPath, PROPERTYKEY const& key )
{
    // Use CComPtr to automatically release the IShellItem2 interface when the function returns
    // or an exception is thrown.
    CComPtr<IShellItem2> pItem;
    HRESULT hr = SHCreateItemFromParsingName( pPath, nullptr, IID_PPV_ARGS( &pItem ) );
    if( FAILED( hr ) )
        throw std::system_error( hr, std::system_category(), "SHCreateItemFromParsingName() failed" );
    
    // Use CComHeapPtr to automatically release the string allocated by the shell when the function returns
    // or an exception is thrown (calls CoTaskMemFree).
    CComHeapPtr<WCHAR> pValue;
    hr = pItem->GetString( key, &pValue );
    if( FAILED( hr ) )
        throw std::system_error( hr, std::system_category(), "IShellItem2::GetString() failed" );

    // Copy to wstring for convenience
    return std::wstring( pValue );
}

int main()
{
    CoInitialize( nullptr );   // TODO: error handling
    _setmode( _fileno( stdout ), _O_U16TEXT );  // for proper UTF-16 console output

    try
    {
        // Show some properties of Microsoft.Photos.exe (adjust path if necessary)
        LPCWSTR path = LR"(C:\Program Files\WindowsApps\Microsoft.Windows.Photos_2018.18061.17410.0_x64__8wekyb3d8bbwe\Microsoft.Photos.exe)";
        std::wcout << L"PKEY_FileDescription:      " 
                   << GetShellPropStringFromPath( path, PKEY_FileDescription ) << std::endl;
        std::wcout << L"PKEY_Software_ProductName: " 
                   << GetShellPropStringFromPath( path, PKEY_Software_ProductName ) << std::endl;
    }
    catch( std::system_error const& e )
    {
        std::cout << "ERROR: " << e.what() << "\nError code: " << e.code() << std::endl;
    }

    CoUninitialize();
}

输出:

PKEY_FileDescription:      Microsoft.Photos.exe
PKEY_Software_ProductName: Microsoft Photos

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-02-05
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多