通过QueryInterface接口查询和使用IDispatch 接口进行操作的对比。

本文对比了使用QueryInterface和IDispatch接口进行网页表单自动化提交的方法。QueryInterface方式适用于已知网页设计的情况,虽然实现过程较为繁琐,但效率较高;而IDispatch方式则更加简单,尽管执行速度稍慢。
写一个提交网页表单的程序。比较了一下QueryInterface接口查询和使用IDispatch 接口进行操作

通过 QueryInterface 接口查询,然后再进行条件判断显然是比较烦琐的,但是效率比较高。适合特定的已知网页设计内容的程序。
例如自动进入126邮箱的程序。

直接使用 IDispatch 接口进行操作的,这个方式执行起来稍微慢一些,但程序比较简单。

找一个这个资料IShellWindows。
修改完宏定义(_WINDOWS;_WIN32_WINNT=0x0A00;WINVER=0x0A00;%(PreprocessorDefinitions))之后,清理然后重新生成,结果输出: 重新生成开始于 15:41... 1>------ 已启动全部重新生成: 项目: MFCApplication9, 配置: Debug x64 ------ 1>pch.cpp 1>CMyColorButton.cpp 1>Unicode 已启用 1>MFCApplication9.cpp 1>C:\Users\Li\source\repos\MFCApplication9\CMyColorButton.cpp(18,16): error C2065: “ODS_HOT”: 未声明的标识符 1>(编译源文件“/CMyColorButton.cpp”) 1>C:\Users\Li\source\repos\MFCApplication9\CMyColorButton.cpp(124,17): error C2065: “ODS_HOT”: 未声明的标识符 1>(编译源文件“/CMyColorButton.cpp”) 1>C:\Users\Li\source\repos\MFCApplication9\CMyColorButton.cpp(145,5): error C2872: “Font”: 不明确的符号 1>(编译源文件“/CMyColorButton.cpp”) 1> C:\Program Files\Microsoft Visual Studio\2022\Community\VC\Tools\MSVC\14.44.35207\include\comdef.h(489,12): 1> 可能是“Font” 1> C:\Program Files (x86)\Windows Kits\10\Include\10.0.26100.0\um\GdiplusHeaders.h(256,7): 1> 或 “Gdiplus::Font” 1>C:\Users\Li\source\repos\MFCApplication9\CMyColorButton.cpp(145,10): error C2259: “Font”: 无法实例化抽象类 1>(编译源文件“/CMyColorButton.cpp”) 1> C:\Program Files\Microsoft Visual Studio\2022\Community\VC\Tools\MSVC\14.44.35207\include\comdef.h(489,12): 1> 参见“Font”的声明 1> C:\Users\Li\source\repos\MFCApplication9\CMyColorButton.cpp(145,10): 1> 由于下列成员: 1> C:\Users\Li\source\repos\MFCApplication9\CMyColorButton.cpp(145,10): 1> “HRESULT IUnknown::QueryInterface(const IID &,void **)”: 是抽象的 1> C:\Program Files (x86)\Windows Kits\10\Include\10.0.26100.0\um\unknwnbase.h(121,47): 1> 参见“IUnknown::QueryInterface”的声明 1> C:\Users\Li\source\repos\MFCApplication9\CMyColorButton.cpp(145,10): 1> “ULONG IUnknown::AddRef(void)”: 是抽象的 1> C:\Program Files (x86)\Windows Kits\10\Include\10.0.26100.0\um\unknwnbase.h(125,45): 1> 参见“IUnknown::AddRef”的声明 1> C:\Users\Li\source\repos\MFCApplication9\CMyColorButton.cpp(145,10): 1> “ULONG IUnknown::Release(void)”: 是抽象的 1> C:\Program Files (x86)\Windows Kits\10\Include\10.0.26100.0\um\unknwnbase.h(127,45): 1> 参见“IUnknown::Release”的声明 1> C:\Users\Li\source\repos\MFCApplication9\CMyColorButton.cpp(145,10): 1> “HRESULT IDispatch::GetTypeInfoCount(UINT *)”: 是抽象的 1> C:\Program Files (x86)\Windows Kits\10\Include\10.0.26100.0\um\oaidl.h(2309,43): 1> 参见“IDispatch::GetTypeInfoCount”的声明 1> C:\Users\Li\source\repos\MFCApplication9\CMyColorButton.cpp(145,10): 1> “HRESULT IDispatch::GetTypeInfo(UINT,LCID,ITypeInfo **)”: 是抽象的 1> C:\Program Files (x86)\Windows Kits\10\Include\10.0.26100.0\um\oaidl.h(2312,43): 1> 参见“IDispatch::GetTypeInfo”的声明 1> C:\Users\Li\source\repos\MFCApplication9\CMyColorButton.cpp(145,10): 1> “HRESULT IDispatch::GetIDsOfNames(const IID &,LPOLESTR *,UINT,LCID,DISPID *)”: 是抽象的 1> C:\Program Files (x86)\Windows Kits\10\Include\10.0.26100.0\um\oaidl.h(2317,43): 1> 参见“IDispatch::GetIDsOfNames”的声明 1> C:\Users\Li\source\repos\MFCApplication9\CMyColorButton.cpp(145,10): 1> “HRESULT IDispatch::Invoke(DISPID,const IID &,LCID,WORD,DISPPARAMS *,VARIANT *,EXCEPINFO *,UINT *)”: 是抽象的 1> C:\Program Files (x86)\Windows Kits\10\Include\10.0.26100.0\um\oaidl.h(2324,57): 1> 参见“IDispatch::Invoke”的声明 1>C:\Users\Li\source\repos\MFCApplication9\CMyColorButton.cpp(145,14): error C2259: “Font”: 无法实例化抽象类 1>(编译源文件“/CMyColorButton.cpp”) 1> C:\Program Files\Microsoft Visual Studio\2022\Community\VC\Tools\MSVC\14.44.35207\include\comdef.h(489,12): 1> 参见“Font”的声明 1> C:\Users\Li\source\repos\MFCApplication9\CMyColorButton.cpp(145,14): 1> 由于下列成员: 1> C:\Users\Li\source\repos\MFCApplication9\CMyColorButton.cpp(145,14): 1> “HRESULT IUnknown::QueryInterface(const IID &,void **)”: 是抽象的 1> C:\Program Files (x86)\Windows Kits\10\Include\10.0.26100.0\um\unknwnbase.h(121,47): 1> 参见“IUnknown::QueryInterface”的声明 1> C:\Users\Li\source\repos\MFCApplication9\CMyColorButton.cpp(145,14): 1> “ULONG IUnknown::AddRef(void)”: 是抽象的 1> C:\Program Files (x86)\Windows Kits\10\Include\10.0.26100.0\um\unknwnbase.h(125,45): 1> 参见“IUnknown::AddRef”的声明 1> C:\Users\Li\source\repos\MFCApplication9\CMyColorButton.cpp(145,14): 1> “ULONG IUnknown::Release(void)”: 是抽象的 1> C:\Program Files (x86)\Windows Kits\10\Include\10.0.26100.0\um\unknwnbase.h(127,45): 1> 参见“IUnknown::Release”的声明 1> C:\Users\Li\source\repos\MFCApplication9\CMyColorButton.cpp(145,14): 1> “HRESULT IDispatch::GetTypeInfoCount(UINT *)”: 是抽象的 1> C:\Program Files (x86)\Windows Kits\10\Include\10.0.26100.0\um\oaidl.h(2309,43): 1> 参见“IDispatch::GetTypeInfoCount”的声明 1> C:\Users\Li\source\repos\MFCApplication9\CMyColorButton.cpp(145,14): 1> “HRESULT IDispatch::GetTypeInfo(UINT,LCID,ITypeInfo **)”: 是抽象的 1> C:\Program Files (x86)\Windows Kits\10\Include\10.0.26100.0\um\oaidl.h(2312,43): 1> 参见“IDispatch::GetTypeInfo”的声明 1> C:\Users\Li\source\repos\MFCApplication9\CMyColorButton.cpp(145,14): 1> “HRESULT IDispatch::GetIDsOfNames(const IID &,LPOLESTR *,UINT,LCID,DISPID *)”: 是抽象的 1> C:\Program Files (x86)\Windows Kits\10\Include\10.0.26100.0\um\oaidl.h(2317,43): 1> 参见“IDispatch::GetIDsOfNames”的声明 1> C:\Users\Li\source\repos\MFCApplication9\CMyColorButton.cpp(145,14): 1> “HRESULT IDispatch::Invoke(DISPID,const IID &,LCID,WORD,DISPPARAMS *,VARIANT *,EXCEPINFO *,UINT *)”: 是抽象的 1> C:\Program Files (x86)\Windows Kits\10\Include\10.0.26100.0\um\oaidl.h(2324,57): 1> 参见“IDispatch::Invoke”的声明 1>C:\Users\Li\source\repos\MFCApplication9\CMyColorButton.cpp(145,14): error C2661: “Font::Font”: 没有重载函数接受 2 个参数 1>(编译源文件“/CMyColorButton.cpp”) 1> C:\Users\Li\source\repos\MFCApplication9\CMyColorButton.cpp(145,14): 1> 尝试匹配参数列表“(HDC, CFont *)”时 1>C:\Users\Li\source\repos\MFCApplication9\CMyColorButton.cpp(146,68): warning C4244: “参数”: 从“int”转换到“Gdiplus::REAL”,可能丢失数据 1>(编译源文件“/CMyColorButton.cpp”) 1>C:\Users\Li\source\repos\MFCApplication9\CMyColorButton.cpp(146,53): warning C4244: “参数”: 从“int”转换到“Gdiplus::REAL”,可能丢失数据 1>(编译源文件“/CMyColorButton.cpp”) 1>C:\Users\Li\source\repos\MFCApplication9\CMyColorButton.cpp(146,37): warning C4244: “参数”: 从“LONG”转换到“Gdiplus::REAL”,可能丢失数据 1>(编译源文件“/CMyColorButton.cpp”) 1>C:\Users\Li\source\repos\MFCApplication9\CMyColorButton.cpp(146,26): warning C4244: “参数”: 从“LONG”转换到“Gdiplus::REAL”,可能丢失数据 1>(编译源文件“/CMyColorButton.cpp”) 1>C:\Users\Li\source\repos\MFCApplication9\CMyColorButton.cpp(152,14): error C2665: “Gdiplus::Graphics::DrawString”: 没有重载函数可以转换所有参数类型 1>(编译源文件“/CMyColorButton.cpp”) 1> C:\Program Files (x86)\Windows Kits\10\Include\10.0.26100.0\um\GdiplusGraphics.h(1247,5): 1> 可能是“Gdiplus::Status Gdiplus::Graphics::DrawString(const WCHAR *,INT,const Gdiplus::Font *,const Gdiplus::PointF &,const Gdiplus::StringFormat *,const Gdiplus::Brush *)” 1> C:\Users\Li\source\repos\MFCApplication9\CMyColorButton.cpp(152,14): 1> “Gdiplus::Status Gdiplus::Graphics::DrawString(const WCHAR *,INT,const Gdiplus::Font *,const Gdiplus::PointF &,const Gdiplus::StringFormat *,const Gdiplus::Brush *)”: 无法将参数 3 从“Font *”转换为“const Gdiplus::Font *” 1> C:\Users\Li\source\repos\MFCApplication9\CMyColorButton.cpp(152,35): 1> 指向的类型不相关; 转换需要 reinterpret_cast、C 样式强制转换或带圆括号的函数样式强制转换 1> C:\Program Files (x86)\Windows Kits\10\Include\10.0.26100.0\um\GdiplusGraphics.h(1204,5): 1> 或 “Gdiplus::Status Gdiplus::Graphics::DrawString(const WCHAR *,INT,const Gdiplus::Font *,const Gdiplus::RectF &,const Gdiplus::StringFormat *,const Gdiplus::Brush *)” 1> C:\Users\Li\source\repos\MFCApplication9\CMyColorButton.cpp(152,14): 1> “Gdiplus::Status Gdiplus::Graphics::DrawString(const WCHAR *,INT,const Gdiplus::Font *,const Gdiplus::RectF &,const Gdiplus::StringFormat *,const Gdiplus::Brush *)”: 无法将参数 3 从“Font *”转换为“const Gdiplus::Font *” 1> C:\Users\Li\source\repos\MFCApplication9\CMyColorButton.cpp(152,35): 1> 指向的类型不相关; 转换需要 reinterpret_cast、C 样式强制转换或带圆括号的函数样式强制转换 1> C:\Users\Li\source\repos\MFCApplication9\CMyColorButton.cpp(152,14): 1> 尝试匹配参数列表“(CString, int, Font *, Gdiplus::RectF, Gdiplus::StringFormat *, Gdiplus::SolidBrush *)”时 1>C:\Users\Li\source\repos\MFCApplication9\MFCApplication9.cpp(76,12): warning C4101: “g_gdiplusToken”: 未引用的局部变量 1>(编译源文件“/MFCApplication9.cpp”) 1>MFCApplication9Dlg.cpp 1>正在生成代码... 1>已完成生成项目“MFCApplication9.vcxproj”的操作 - 失败。 ========== 全部重新生成: 0 成功,1 失败,0 已跳过 ========== ========== 重新生成 于 15:42 完成,耗时 02.674 秒 ==========
07-05
<think>首先,用户的问题是:"我想查找IUnknownIDispatch接口的实现方法 请问IUnknownIDispatch接口的实现方式"。这基于COM (Component Object Model) 技术。 回顾系统级指令: - 必须使用中文回答。 - 行内数学表达式用$...$格式。 - 独立公式用$$...$$格式。 - 语法正确。 - 生成相关问题。 - 引用的段落末尾添加引用标识,如[^1]。 用户提供的引用: - [^1]: 关于IDispatch接口的动态调用机制:GetIDsOfNamesInvoke。 - [^2]: IUnknown接口的基础:QueryInterface, AddRef, Release。 - [^3]: IDispatch接口的示例代码片段。 - [^4]: 使用智能指针调用IDispatch。 - [^5]: 类工厂的实现示例。 用户的问题是关于IUnknownIDispatch接口的实现方法。我需要基于这些引用构建回答。 核心内容: - IUnknown是COM的基础接口,所有COM接口必须继承自它。它有三个方法: - QueryInterface: 用于查询其他接口。 - AddRef: 增加引用计数。 - Release: 减少引用计数,当计数为0时销毁对象。 - IDispatch接口继承自IUnknown,用于支持动态调用(如脚本语言)。它添加了GetIDsOfNamesInvoke方法: - GetIDsOfNames: 将方法名映射到DISPID。 - Invoke: 通过DISPID调用方法。 实现方式: - 在C++中,COM对象实现特定的接口。 - 对象必须实现IUnknown的三个方法。 - 如果支持IDispatch,还要实现它的两个方法。 - 引用[^3][^5]提供了代码示例。 回答结构: 1. 介绍IUnknown接口的实现。 2. 介绍IDispatch接口的实现。 3. 基于引用提供代码片段。 4. 确保回答清晰、逐步解决问题。 5. 末尾添加相关问题。 6. 在引用的段落末尾添加引用标识。 生成相关问题: - 例如:如何实现COM对象的生命周期管理?IDispatch接口在自动化中的作用? 确保中文回答。 大纲: 1. IUnknown接口的实现: - 必须实现QueryInterface, AddRef, Release。 - 引用[^2][^5]有例子。 2. IDispatch接口的实现: - 继承自IUnknown。 - 实现GetIDsOfNamesInvoke。 - 引用[^1], [^3], [^4]有相关信息。 3. 代码示例:从引用中提取并解释简短代码。 4. 总结关键点。 5. 相关问题答案生成。 最后,添加相关问题部分。 </think>### IUnknown IDispatch 接口的实现方法 在 COM (Component Object Model) 技术中,`IUnknown` `IDispatch` 是核心接口。`IUnknown` 是所有 COM 接口的基类,而 `IDispatch` 继承自 `IUnknown`,用于支持动态调用(如脚本语言)。下面我将逐步解释它们的实现方式,并基于您提供的引用提供可靠的代码示例。 #### 1. **IUnknown 接口的实现** `IUnknown` 定义了 COM 对象的基本生命周期接口查询机制。它包含三个必须实现的方法: - **QueryInterface**: 查询对象是否支持其他接口。 - **AddRef**: 增加对象的引用计数。 - **Release**: 减少引用计数,当计数为0时销毁对象。 所有 COM 组件必须实现 `IUnknown`,且其方法顺序不可改变[^2]。 实现步骤如下: - **引用计数管理**: 在对象内部维护一个计数器(例如 `m_dwRef`)。 - **QueryInterface 实现**: 检查请求的接口 ID (IID),如果支持则返回指针并调用 `AddRef`。 - **AddRef Release 实现**: 更新计数器,并在计数归零时删除对象。 **代码示例**(基于引用[^5]的类工厂实现): ```cpp STDMETHODIMP MathClassFactory::QueryInterface(REFIID riid, void** ppv) { *ppv = NULL; if (riid == IID_IUnknown || riid == IID_IClassFactory) { *ppv = this; } if (*ppv) { ((LPUNKNOWN)*ppv)->AddRef(); // 增加引用计数 return S_OK; } return E_NOINTERFACE; // 不支持请求的接口 } STDMETHODIMP_(ULONG) MathClassFactory::AddRef() { return ++m_dwRef; // 递增引用计数 } STDMETHODIMP_(ULONG) MathClassFactory::Release() { if (--m_dwRef == 0) { // 递减计数,若为0则销毁对象 delete this; return 0; } return m_dwRef; } ``` 此代码展示了如何管理对象生命周期接口查询。关键点包括: - 使用 `REFIID` 检查接口 ID。 - `AddRef` `Release` 确保线程安全的资源管理。 - 当 `Release` 使计数归零时,对象自动销毁[^2][^5]。 #### 2. **IDispatch 接口的实现** `IDispatch` 继承自 `IUnknown`,用于支持动态调用(如自动化)。它添加了两个核心方法: - **GetIDsOfNames**: 将方法名或属性名映射为数字标识符 (DISPID)。 - **Invoke**: 通过 DISPID 动态调用方法或访问属性。 实现 `IDispatch` 的对象称为“双重接口”(dual interface),既可静态调用也可动态调用[^1][^3]。 实现步骤如下: - **定义接口方法**: 在 IDL(接口定义语言)中声明方法,并分配 DISPID(例如 `[id(1)]`)。 - **GetIDsOfNames 实现**: 解析名称字符串,返回对应的 DISPID。 - **Invoke 实现**: 根据 DISPID 调用实际方法,处理参数返回值。 **代码示例**(基于引用[^3]的接口定义引用[^4]的调用逻辑): ```cpp // 接口定义(IDL 示例) [uuid(21B794E2-4857-4576-8FC2-CDAB2A486600), dual] interface IMyCar : IDispatch { [id(1)] HRESULT Run(); // DISPID=1 [id(2)] HRESULT AddGas([in] LONG add, [out] LONG* total); // DISPID=2 [propget, id(3)] HRESULT Gas([out, retval] LONG* pVal); // DISPID=3 }; // Invoke 的简化实现(以 AddGas 方法为例) HRESULT Invoke(DISPID dispId, REFIID riid, LCID lcid, WORD flags, DISPPARAMS* pDispParams, VARIANT* pVarResult) { switch (dispId) { case 1: // DISPID for Run Run(); return S_OK; case 2: // DISPID for AddGas if (pDispParams->cArgs != 1) return DISP_E_BADPARAMCOUNT; LONG add = pDispParams->rgvarg[0].lVal; LONG total; AddGas(add, &total); // 调用实际方法 if (pVarResult) pVarResult->lVal = total; return S_OK; default: return DISP_E_MEMBERNOTFOUND; } } ``` 关键点包括: - `GetIDsOfNames` 映射名称到 DISPID(例如 `L"Add"` 对应 DISPID=2)。 - `Invoke` 使用 `DISPID` 分派调用,并处理参数传递(如 `DISPPARAMS` 结构)。 - 动态调用时,客户端通过 `GetIDsOfNames` 获取 DISPID,然后调用 `Invoke`[^1][^3][^4]。 #### 3. **完整实现注意事项** - **继承关系**: `IDispatch` 必须继承 `IUnknown`,确保双重接口兼容性。 - **错误处理**: 所有方法返回 `HRESULT` 表示状态(如 `S_OK` 或 `E_NOINTERFACE`)。 - **线程安全**: 在 `AddRef` `Release` 中使用原子操作。 - **客户端调用**: 如引用[^4]所示,使用 `CComDispatchDriver` 等智能指针简化 `Invoke` 调用。 实现这两个接口是 COM 组件开发的基础,确保对象可被多种语言(如 C++、VB、脚本)访问[^1][^2][^4]。 ### 相关问题 1. **如何在 COM 中管理对象的生命周期?** (答案:通过 `AddRef` `Release` 实现引用计数,当计数归零时自动销毁对象[^2][^5]。) 2. **IDispatch 接口在自动化开发中有哪些应用场景?** (答案:用于支持脚本语言(如 VBScript)动态调用 COM 对象,常见于 Office 自动化或浏览器控件[^1][^4]。) 3. **如何优化 IDispatch 的性能?** (答案:缓存 DISPID 减少 `GetIDsOfNames` 调用,或使用类型库(type library)预编译接口定义[^3][^4]。)
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值