65.9K
CodeProject 正在变化。 阅读更多。
Home

使用 COleDispatchDriver 的 MFC COM 包装代码生成器

starIconstarIconstarIconstarIconstarIcon

5.00/5 (7投票s)

2022年6月19日

CPOL

3分钟阅读

viewsIcon

6843

downloadIcon

317

IDispatch C++ 代码生成得当

引言

随着 REST 接口接管世界,微软对其原生代码工具的关注越来越少。最新的 COleDispatchDriver 代码生成器简直是一场灾难,生成的代码甚至无法编译。幸运的是,我已经编写了自己的生成器来解决历史遗留问题,这也是我完成 2018 年开始的开源版本的最后动力。

背景

这个代码生成器的目标是

  • 完美解析从 OLE Viewer 生成的 IDL
  • 自动使用库名称作为 namespace
  • helpstring 作为库的注释输出
  • 生成 enum 声明
  • 在函数上输出 enum 名称(而不是 long
  • 当它无法识别类型时输出 VARIANT,而不是一条说明该函数无法支持的注释
  • 为所有内容输出实际类型,而不是 IDispatch
  • 支持 COM 事件代码生成

Using the Code

首先,您需要访问 oleview.exe。您可以在 Windows SDK 中找到它。例如,在我的机器上,EXE 文件位于 C:\Program Files (x86)\Windows Kits\10\bin\10.0.20348.0\\x64\oleview.exe。请注意,您可能需要使用命令 regsvr32 iviewers.dll 以管理员身份注册 iviewers.dll

现在在 OLE Viewer 中选择一个接口(例如,Microsoft XML)并查看 IDL

使用 Ctrl-A 选择所有代码,然后将其粘贴到文本文件中并保存,扩展名为 .idl

对通过 IDL 中的 importlib 命令导入的任何类型库递归重复此过程(在本例中为 stdole2.tlb)。

您现在可以在 .idl 文件上运行 idl2cpp.exe

例如

idl2cpp XML.idl

如果这样运行,没有任何开关,您应该只会收到一条消息,说明文件已成功解析。要输出一些代码,您可以选择

  • /enums
  • /events_h
  • /events_cpp
  • /fwd_decls
  • /h
  • /cpp

请注意,这些开关是互斥的。

最好先将 enums 和前向声明输出到两个单独的文件中,然后创建头文件并 #include 这两个文件。

例如

idl2cpp XML.idl /enums > msxml2_enums.h

idl2cpp XML.idl /fwd_decls > msxml2_fwd_decls.h

idl2cpp XML.idl /h > msxml2.h

最后,您可以输出 cpp 文件

idl2cpp XML.idl /cpp > msxml2.cpp

输出

以下是您可能期望的输出示例

msxml2_enums.h
#pragma once

// GENERATED CODE by idl2cpp 2022-06-19 13:26:24
namespace MSXML2
{
// Schema Object Model Content Types
enum class _SCHEMACONTENTTYPE
{
        SCHEMACONTENTTYPE_EMPTY = 0,
        SCHEMACONTENTTYPE_TEXTONLY = 1,
        SCHEMACONTENTTYPE_ELEMENTONLY = 2,
        SCHEMACONTENTTYPE_MIXED = 3
};

...
msxml2_fwd_decls.h
#pragma once

// GENERATED CODE by idl2cpp 2022-06-19 13:27:25
namespace MSXML2
{
        struct IXMLDOMNode;
        struct IXMLDOMNodeList;
        struct IXMLDOMNamedNodeMap;

...
msxml2.h
#pragma once

// GENERATED CODE by idl2cpp 2022-06-19 13:29:27

// http://support.microsoft.com/kb/134980
#pragma warning(push)
#pragma warning(disable:4275)

// Microsoft XML, v6.0
namespace MSXML2
{
using DOMNodeType = tagDOMNodeType;
using SCHEMACONTENTTYPE = _SCHEMACONTENTTYPE;
using SCHEMADERIVATIONMETHOD = _SCHEMADERIVATIONMETHOD;
using SCHEMAPROCESSCONTENTS = _SCHEMAPROCESSCONTENTS;
using SCHEMATYPEVARIETY = _SCHEMATYPEVARIETY;
using SCHEMAUSE = _SCHEMAUSE;
using SCHEMAWHITESPACE = _SCHEMAWHITESPACE;
using SERVERXMLHTTP_OPTION = _SERVERXMLHTTP_OPTION;
using SOMITEMTYPE = _SOMITEMTYPE;
using SXH_PROXY_SETTING = _SXH_PROXY_SETTING;
using SXH_SERVER_CERT_OPTION = _SXH_SERVER_CERT_OPTION;
using XHR_PROPERTY = _XHR_PROPERTY;

// Core DOM node interface
struct AFX_EXT_CLASS IXMLDOMNode : COleDispatchDriver
{
        IXMLDOMNode() {}
        IXMLDOMNode(LPDISPATCH pDispatch) :
                COleDispatchDriver(pDispatch) {}
        IXMLDOMNode(const IXMLDOMNode& dispatchSrc) :
                COleDispatchDriver(dispatchSrc) {}

        CString GetnodeName();
        VARIANT GetnodeValue();
        void SetnodeValue(const VARIANT& newValue);

...
msxml2.cpp
// GENERATED CODE by idl2cpp 2022-06-19 13:30:45
namespace MSXML2
{
CString IXMLDOMNode::GetnodeName()
{
        CString result{};

        InvokeHelper(0x2, DISPATCH_PROPERTYGET, VT_BSTR, &result, nullptr);
        return result;
}

VARIANT IXMLDOMNode::GetnodeValue()
{
        VARIANT result{};

        InvokeHelper(0x3, DISPATCH_PROPERTYGET, VT_VARIANT, &result, nullptr);
        return result;
}

...

请注意,自动生成的头文件包含 #includes 语句,用于 msxml2_enums.h 和 msxml2_fwd.h。

生成的源文件还将自动包含 #include 语句,用于 msxml2.h。

目前,/events_cpp 的生成器要求手动添加对应头文件的 #include

历史

  • 2022年6月19日:创建
  • 2022年6月19日:将缺失的文件添加到 zip 文件中
  • 2022年6月19日:停止将 int 转换为 long 作为返回值
  • 2022年6月19日:添加了开关 /events_h/events_cpp
  • 2022年6月19日:输出 nullptr 而不是 0 作为指针的默认值
  • 2022年6月24日:各种错误修复
  • 2022年7月2日:添加了对函数 helpstring 的支持
  • 2022年7月2日:一致地处理 CURRENCYVARIANT。仅在仅为 in 参数时才使用 const
  • 2022年7月4日:int64uint64 不应创建注释
  • 2022年7月4日:将可选参数默认为 0/nullptr,如果没有指定值
  • 2022年10月19日:修复了 output_header.cpp 中的断开链接
  • 2023年1月21日:更新为使用最新的 parsertl
  • 2023年1月31日:更新为使用最新的 parsertl
  • 2023年9月11日:更新了 lexertlparsertlMakefile。修复了一些 g++ 警告
  • 2023年12月2日:现在尽可能输出实际类型,而不是一直使用 IDispatch*
  • 2023年12月5日:将运算符 LPDISPATCH 设置为 delete 并自动输出 #includes
  • 2023年12月10日:改进了事件源代码生成的注释。还进行了 SonarLint 建议的更改
  • 2023年12月22日:添加了 /name 开关,以便可以输出单个接口
  • 2023年12月26日:向 events_template.cpp 添加了缺失的换行符
  • 2024年2月15日:更新为使用 lexertl17 和 parsertl17
  • 2024年4月6日:添加了更多解释。
  • 2024年4月7日:现在正确处理 coclass 参数。
© . All rights reserved.