You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何正确使用Windows API中的抽象类与接口?

正确使用Windows COM接口(如IPropertyStorage)

你的代码存在两个核心问题:

  1. PropertyStorage ips();是C++典型的"最令人头疼的解析"场景——这不是创建对象,而是声明了一个返回PropertyStorage类型的函数。
  2. 更关键的是:Windows API中以I开头的这类接口是COM接口,不需要你自己子类化并重写方法。COM接口的实现由系统或第三方组件提供,你只需要通过COM标准机制获取实例并调用方法即可。

核心使用流程

COM接口的使用遵循固定步骤:

  • 初始化COM库:程序启动时调用CoInitializeEx,退出时调用CoUninitialize。
  • 通过专用API获取接口实例:比如从复合文件获取IStorage,再通过QueryInterface或专用方法获取IPropertyStorage。
  • 调用接口方法完成操作,最后调用Release()释放接口(遵循COM引用计数规则)。

示例代码

#include <iostream>
#include <propidl.h>
#include <objidl.h>
#include <propkey.h>

int main(int argc, char* argv[]) {
    // 初始化COM库,指定Apartment线程模型
    HRESULT hr = CoInitializeEx(nullptr, COINIT_APARTMENTTHREADED);
    if (FAILED(hr)) {
        std::cout << "COM初始化失败,错误码: " << hr << std::endl;
        return 1;
    }

    IStorage* pStorage = nullptr;
    // 创建或打开复合文件,获取IStorage接口实例
    hr = StgCreateDocfile(L"test_prop_store", 
                          STGM_CREATE | STGM_READWRITE | STGM_SHARE_EXCLUSIVE, 
                          0, &pStorage);
    if (FAILED(hr)) {
        std::cout << "创建复合文件失败,错误码: " << hr << std::endl;
        CoUninitialize();
        return 1;
    }

    IPropertyStorage* pPropStorage = nullptr;
    // 从IStorage创建并获取IPropertyStorage接口
    hr = pStorage->CreatePropertySet(FMTID_UserDefinedProperties, 
                                     nullptr, PROPSETFLAG_DEFAULT,
                                     STGM_CREATE | STGM_READWRITE | STGM_SHARE_EXCLUSIVE, 
                                     &pPropStorage);
    if (FAILED(hr)) {
        std::cout << "创建属性集失败,错误码: " << hr << std::endl;
        pStorage->Release();
        CoUninitialize();
        return 1;
    }

    // 示例:写入属性
    PROPVARIANT propVar;
    PropVariantInit(&propVar);
    propVar.vt = VT_LPWSTR;
    propVar.pwszVal = const_cast<LPWSTR>(L"测试内容");
    
    hr = pPropStorage->WriteMultiple(1, &PKEY_Title, &propVar, PID_FIRST_USABLE);
    if (SUCCEEDED(hr)) {
        std::cout << "属性写入成功" << std::endl;
    } else {
        std::cout << "属性写入失败,错误码: " << hr << std::endl;
    }
    PropVariantClear(&propVar);

    // 按逆序释放接口:先释放子接口,再释放父接口
    pPropStorage->Release();
    pStorage->Release();

    // 关闭COM库
    CoUninitialize();
    return 0;
}

关键注意事项

  • 引用计数规则:所有COM接口都实现了AddRef()和Release(),每次获取接口时计数+1,调用Release()时计数-1,计数为0时对象自动销毁。必须确保所有获取的接口都被正确释放,避免内存泄漏。
  • 不要自行子类化COM接口:这些接口的具体实现由系统提供,你不需要重写任何方法,直接调用接口暴露的方法即可。
  • 错误处理:COM函数返回HRESULT类型,务必用SUCCEEDED()或FAILED()宏判断执行结果,及时处理错误。

内容的提问来源于stack exchange,提问作者Eliazar

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.14 19:25:17