5

我试着在 SO 上看这个,但所有试图回答的问题都没有提供完整的答案。

我实际上想将一个属性添加到现有文件的详细信息选项卡中。文件的扩展名为 sldprt。属性/值必须在 Windows 资源管理器中可见。

不确定如何使用 Windows API Code Pack Shell 或 DSOFile 完成此操作?任何其他解决方案也可以。

我在 Windows 10 上使用 VS、C#。

如果有人可以提供详细的解决方案,我将非常感激。

完美的解决方案是:

  • 通过 dsofile、ADS 或任何可能的方式将属性添加到文件中。
  • 编辑到 Windows 注册表或负责在文件属性的详细信息选项卡和 Windows 资源管理器中显示新属性的任何 Windows 部分
  • 显示如何编辑属性的值。

此问题的此答案不会将属性添加到详细信息选项卡或 Windows 资源管理器详细视图。

我认为这是可能的,因为 SOLIDWORKS(3d 包)向所有 SOLIDWORKS 文件添加了一个名为sw last saved with的属性。详细信息窗口中还有大量其他属性。

如果您没有正确的解决方案,请不要回答。非常感谢你。

我不确定这个问题是否与Add new metadata properties to a file重复。

预览:

在此处输入图像描述 在此处输入图像描述

编辑:

sldprt 扩展注册(仅供参考):

在此处输入图像描述

4

2 回答 2

7

属性窗口中的详细信息选项卡填充了元数据属性处理程序。元数据属性系统是 Microsoft 在 Windows Vista 中引入的东西,它是开放和可扩展的,使独立开发人员(如 Solidworks)能够实现和支持他们自己的文件属性。非常粗略地,执行流程是这样的:

User clicks file properties
Look up property handler for the file format
If found property handler:
    Query property handler for properties
    Populate file details with queried properties
Else:
    Populate file details with generic file info

属性处理程序是 COM 对象。COM(组件对象模型)是微软对独立于语言的面向对象框架的尝试,其起源可以追溯到九十年代,但为了解释的目的,只要说 COM 对象是一个 C++ 类,它实现了IUnknown界面。属性处理程序必须在此IPropertyStore之上实现接口:

struct IPropertyStore : public IUnknown
{
public:
    virtual HRESULT GetCount( 
        DWORD *cProps) = 0;

    virtual HRESULT GetAt( 
        DWORD iProp,
        PROPERTYKEY *pkey) = 0;

    virtual HRESULT GetValue( 
        REFPROPERTYKEY key,
        PROPVARIANT *pv) = 0;

    virtual HRESULT SetValue( 
        REFPROPERTYKEY key,
        REFPROPVARIANT propvar) = 0;

    virtual HRESULT Commit( void) = 0;
};

为开发人员提供了此接口的便利实现,CLSID_InMemoryPropertyStore以简化他们自己的IPropertyStore. 这里有趣的方法是GetValueSetValue。属性被分配一个唯一的 GUID,PROPERTYKEY传递给这些函数的结构包含该 GUID 以识别属性。GetValue和的实现细节SetValue留给开发人员,因此由开发人员决定如何以及在何处存储每个属性的值——这些值可以存储在另一个文件、备用文件流或注册表中以列举几个选项——但出于可传输性的原因,建议将值存储在文件本身中。这样,如果文件被压缩并通过电子邮件发送,例如,属性就会随之而来。

属性处理程序 COM 对象被编译成 DLL 并使用regsvr32. 这允许 Windows 知道去哪里寻找特定文件格式的属性。注册后,可以通过多种方式获取属性处理程序,其中一种是便捷函数SHGetPropertyStoreFromParsingName

HRESULT GetPropertyStore(PCWSTR pszFilename, GETPROPERTYSTOREFLAGS gpsFlags, IPropertyStore** ppps)
{
    WCHAR szExpanded[MAX_PATH];
    HRESULT hr = ExpandEnvironmentStrings(pszFilename, szExpanded, ARRAYSIZE(szExpanded)) ? S_OK : HRESULT_FROM_WIN32(GetLastError());
    if (SUCCEEDED(hr))
    {
        WCHAR szAbsPath[MAX_PATH];
        hr = _wfullpath(szAbsPath, szExpanded, ARRAYSIZE(szAbsPath)) ? S_OK : E_FAIL;
        if (SUCCEEDED(hr))
        {
            hr = SHGetPropertyStoreFromParsingName(szAbsPath, NULL, gpsFlags, IID_PPV_ARGS(ppps));
        }
    }
    return hr;
}

一旦获得,GetValueSetValue可以在IPropertyStore对象上调用以获取、更改或设置属性的新值。如果使用SetValue,请确保也调用Commit


Microsoft 提供了一个名为 的实用程序,PropertyEdit用于获取和设置文件的元数据属性,作为其 Windows 经典示例的一部分。很遗憾,他们没有在帮助页面的任何地方提及它。由于您已经安装了 Solidworks,您感兴趣的文件格式的属性处理程序应该已经在系统上注册,并且应该是编译PropertyEdit和使用它来获取和设置处理程序支持的元数据属性的问题。这是一个简单的命令行实用程序。

如果您需要或想要支持您自己的文件格式的自定义元数据,还有一个完整的示例属性处理程序:RecipePropertyHandler.

作为参考,通过其规范名称设置属性:

HRESULT GetPropertyStore(PCWSTR pszFilename, GETPROPERTYSTOREFLAGS gpsFlags, IPropertyStore** ppps)
{
    WCHAR szExpanded[MAX_PATH];
    HRESULT hr = ExpandEnvironmentStrings(pszFilename, szExpanded, ARRAYSIZE(szExpanded)) ? S_OK : HRESULT_FROM_WIN32(GetLastError());
    if (SUCCEEDED(hr))
    {
        WCHAR szAbsPath[MAX_PATH];
        hr = _wfullpath(szAbsPath, szExpanded, ARRAYSIZE(szAbsPath)) ? S_OK : E_FAIL;
        if (SUCCEEDED(hr))
        {
            hr = SHGetPropertyStoreFromParsingName(szAbsPath, NULL, gpsFlags, IID_PPV_ARGS(ppps));
        }
    }
    return hr;
}

HRESULT SetPropertyValue(PCWSTR pszFilename, PCWSTR pszCanonicalName, PCWSTR pszValue)
{
    // Convert the Canonical name of the property to PROPERTYKEY
    PROPERTYKEY key;
    HRESULT hr = PSGetPropertyKeyFromName(pszCanonicalName, &key);
    if (SUCCEEDED(hr))
    {
        IPropertyStore* pps = NULL;

        // Call the helper to get the property store for the
        // initialized item
        hr = GetPropertyStore(pszFilename, GPS_READWRITE, &pps);
        if (SUCCEEDED(hr))
        {
            PROPVARIANT propvarValue = {0};
            hr = InitPropVariantFromString(pszValue, &propvarValue);
            if (SUCCEEDED(hr))
            {
                hr = PSCoerceToCanonicalValue(key, &propvarValue);
                if (SUCCEEDED(hr))
                {
                    // Set the value to the property store of the item.
                    hr = pps->SetValue(key, propvarValue);
                    if (SUCCEEDED(hr))
                    {
                        // Commit does the actual writing back to the file stream.
                        hr = pps->Commit();
                        if (SUCCEEDED(hr))
                        {
                            wprintf(L"Property %s value %s written successfully \n", pszCanonicalName, pszValue);
                        }
                        else
                        {
                            wprintf(L"Error %x: Commit to the propertystore failed.\n", hr);
                        }
                    }
                    else
                    {
                        wprintf(L"Error %x: Set value to the propertystore failed.\n", hr);
                    }
                }
                PropVariantClear(&propvarValue);
            }
            pps->Release();
        }
        else
        {
            wprintf(L"Error %x: getting the propertystore for the item.\n", hr);
        }
    }
     else
    {
        wprintf(L"Invalid property specified: %s\n", pszCanonicalName);
    }
    return hr;
}
于 2018-06-07T21:39:50.063 回答
2

在 Windows 7 SDK 示例包中有两个完整的示例项目演示了如何执行此操作:RecipePropertyHandlerPlaylistPropertyHandler

主要思想是实现IPropertyStore接口,它有点像集合/迭代器:

Commit    Saves a property change.
GetAt     Gets a property key from an item's array of properties.
GetCount  Gets the number of properties attached to the file.
GetValue  Gets data for a specific property.
SetValue  Sets a new property value, or replaces or removes an existing value.

您的代码需要通过实现IInitializeWithStream接口来初始化处理程序。然后它需要响应GetCount,GetAtGetValue调用以提供属性名称和值。

我喜欢做所有这些的示例项目,并附带有关如何注册属性处理程序的说明。

PS mnistic 的回答主要讨论了一种将属性(和值)添加到某些文件系统中存在的单个文件的方法。这个答案提供了将属性添加到特定文件类型的通用解决方案。

于 2018-06-08T01:38:08.573 回答