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

如何在C++中通过OLE Automation获取Word中ActiveX控件的名称

C++ 遍历Word文档中ActiveX控件并获取名称的解决方案

在C#中通过OLE Automation实现该需求十分直接,但C++里OLEFormat.Object属于抽象的IDispatch类型,无法直接访问name属性,需要借助COM的IDispatch机制或类型转换来解决,以下是具体实现方案:

前置准备

  • 引入Word类型库(通常为MSWORD.OLB)和Microsoft Forms 2.0类型库(MSFORMS.TLB)到C++项目,确保能调用对应的接口定义。
  • 初始化COM环境:调用CoInitialize(NULL)或CoInitializeEx(NULL, COINIT_MULTITHREADED)。

实现思路

Word中的ActiveX控件(如ComboBox、TextBox等)均属于Microsoft Forms控件范畴,它们都实现了MSForms::IControl接口,该接口内置Name属性。我们可以将OLEFormat.Object返回的IDispatch*转换为MSForms::IControl*直接获取名称;若转换失败,再通过IDispatch的GetIDsOfNames和Invoke方法动态读取属性值。

代码示例

#include <iostream>
#include <atlbase.h>
// 需根据Office版本和系统位数调整类型库路径
#import "C:\Program Files\Microsoft Office\root\Office16\MSWORD.OLB" rename("ExitWindows", "WordExitWindows")
#import "C:\Windows\SysWOW64\MSFORMS.TLB" rename("TabIndex", "FormsTabIndex") rename("Timer", "FormsTimer")

using namespace Word;
using namespace MSForms;

int main()
{
    HRESULT hr = CoInitialize(NULL);
    if (FAILED(hr))
    {
        std::cerr << "COM初始化失败" << std::endl;
        return -1;
    }

    CComPtr<_Application> wordApp;
    hr = wordApp.CoCreateInstance(__uuidof(Application));
    if (FAILED(hr))
    {
        std::cerr << "创建Word应用实例失败" << std::endl;
        CoUninitialize();
        return -1;
    }

    wordApp->Visible = VARIANT_TRUE;

    CComPtr<Document> doc;
    hr = wordApp->Documents->Open(CComVariant(L"sample.docm"), NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, &doc);
    if (FAILED(hr))
    {
        std::cerr << "打开文档失败" << std::endl;
        wordApp->Quit(&variantFalse, &variantFalse, &variantFalse);
        CoUninitialize();
        return -1;
    }

    // 遍历Shapes中的ActiveX控件
    CComPtr<Shapes> shapes;
    hr = doc->get_Shapes(&shapes);
    if (SUCCEEDED(hr))
    {
        long count = 0;
        shapes->get_Count(&count);
        for (long i = 1; i <= count; ++i)
        {
            CComPtr<Shape> shape;
            hr = shapes->Item(CComVariant(i), &shape);
            if (SUCCEEDED(hr))
            {
                MsoShapeType type;
                shape->get_Type(&type);
                // 仅处理OLE控件类型
                if (type == msoOLEControlObject)
                {
                    CComPtr<OLEFormat> oleFormat;
                    hr = shape->get_OLEFormat(&oleFormat);
                    if (SUCCEEDED(hr))
                    {
                        CComPtr<IDispatch> dispObj;
                        hr = oleFormat->get_Object(&dispObj);
                        if (SUCCEEDED(hr))
                        {
                            // 优先转换为MSForms::IControl强类型访问
                            CComPtr<IControl> control;
                            hr = dispObj->QueryInterface(__uuidof(IControl), (void**)&control);
                            if (SUCCEEDED(hr))
                            {
                                CComBSTR name;
                                hr = control->get_Name(&name);
                                if (SUCCEEDED(hr))
                                {
                                    std::wcout << L"控件名称:" << name.m_str << std::endl;
                                }
                            }
                            else
                            {
                                // 强类型转换失败时,通过IDispatch动态获取属性
                                DISPID dispid;
                                LPOLESTR propName = L"Name";
                                hr = dispObj->GetIDsOfNames(IID_NULL, &propName, 1, LOCALE_USER_DEFAULT, &dispid);
                                if (SUCCEEDED(hr))
                                {
                                    VARIANT result;
                                    VariantInit(&result);
                                    DISPPARAMS dp = { NULL, NULL, 0, 0 };
                                    hr = dispObj->Invoke(dispid, IID_NULL, LOCALE_USER_DEFAULT, DISPATCH_PROPERTYGET, &dp, &result, NULL, NULL);
                                    if (SUCCEEDED(hr) && result.vt == BSTR)
                                    {
                                        std::wcout << L"控件名称:" << result.bstrVal << std::endl;
                                    }
                                    VariantClear(&result);
                                }
                            }
                        }
                    }
                }
            }
        }
    }

    // 处理InlineShapes中的嵌入式控件(逻辑与Shapes一致)
    CComPtr<InlineShapes> inlineShapes;
    hr = doc->get_InlineShapes(&inlineShapes);
    if (SUCCEEDED(hr))
    {
        long count = 0;
        inlineShapes->get_Count(&count);
        for (long i = 1; i <= count; ++i)
        {
            CComPtr<InlineShape> inlineShape;
            hr = inlineShapes->Item(CComVariant(i), &inlineShape);
            if (SUCCEEDED(hr))
            {
                MsoShapeType type;
                inlineShape->get_Type(&type);
                if (type == msoOLEControlObject)
                {
                    CComPtr<OLEFormat> oleFormat;
                    hr = inlineShape->get_OLEFormat(&oleFormat);
                    if (SUCCEEDED(hr))
                    {
                        CComPtr<IDispatch> dispObj;
                        hr = oleFormat->get_Object(&dispObj);
                        if (SUCCEEDED(hr))
                        {
                            CComPtr<IControl> control;
                            hr = dispObj->QueryInterface(__uuidof(IControl), (void**)&control);
                            if (SUCCEEDED(hr))
                            {
                                CComBSTR name;
                                hr = control->get_Name(&name);
                                if (SUCCEEDED(hr))
                                {
                                    std::wcout << L"嵌入式控件名称:" << name.m_str << std::endl;
                                }
                            }
                            else
                            {
                                DISPID dispid;
                                LPOLESTR propName = L"Name";
                                hr = dispObj->GetIDsOfNames(IID_NULL, &propName, 1, LOCALE_USER_DEFAULT, &dispid);
                                if (SUCCEEDED(hr))
                                {
                                    VARIANT result;
                                    VariantInit(&result);
                                    DISPPARAMS dp = { NULL, NULL, 0, 0 };
                                    hr = dispObj->Invoke(dispid, IID_NULL, LOCALE_USER_DEFAULT, DISPATCH_PROPERTYGET, &dp, &result, NULL, NULL);
                                    if (SUCCEEDED(hr) && result.vt == BSTR)
                                    {
                                        std::wcout << L"嵌入式控件名称:" << result.bstrVal << std::endl;
                                    }
                                    VariantClear(&result);
                                }
                            }
                        }
                    }
                }
            }
        }
    }

    // 清理资源
    doc->Close(&variantFalse, &variantFalse, &variantFalse);
    wordApp->Quit(&variantFalse, &variantFalse, &variantFalse);
    CoUninitialize();
    return 0;
}

关键说明

  • 优先使用QueryInterface转换到MSForms::IControl,强类型访问效率更高、可靠性更强。
  • 针对非Microsoft Forms的特殊ActiveX控件,需通过IDispatch动态调用方式读取Name属性。
  • 使用CComPtr管理COM对象,可自动释放接口,避免内存泄漏。
  • 代码中的类型库路径需根据Office版本(如Office16对应Office 2016及以上)和系统位数(32位系统用C:\Windows\System32\MSFORMS.TLB)调整。

内容的提问来源于stack exchange,提问作者Achim Schön

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.26 01:27:14