gpt4 book ai didi

C++ 转换 Windows IAction

转载 作者:行者123 更新时间:2023-11-28 04:32:28 25 4
gpt4 key购买 nike

我正在努力从 Windows 任务计划程序中检索一些信息。 MSDN表示有几种类型的 Action 。我想分别处理它们。我试过:

IAction* pAction = NULL;
pActionCollection->get_Item(_variant_t(i), &pAction);
if (IExecAction* pExecAction = dynamic_cast<IExecAction*>(pAction)) { /*my work...*/ }
if (IComHandlerAction* pComHandlerAction = dynamic_cast<IComHandlerAction*>(pAction)) { /*my work...*/ }
if (IEmailAction* pEmailAction = dynamic_cast<IEmailAction*>(pAction)) { /*my work...*/ }
if (IShowMessageAction* pShowMessageAction = dynamic_cast<IShowMessageAction*>(pAction)) { /*my work...*/ }

但是这个程序在第一个dynamic_cast 抛出异常。

Exception thrown at 0x00007FFB516365A5 (vcruntime140d.dll) in myProgram.exe: 0xC0000005: Access violation reading location 0x00000130BAFEDB04.

taskschd.h 中的定义显示IExecActionIAction 的派生类。

这很好用:

if (IExecAction* pExecAction = ((IExecAction*)pAction)) { /*my work...*/ }

但是如果我想做一些类型检查怎么办?如何正确使用它?

最佳答案

要从同一对象上的另一个 com 接口(interface)获取 com 接口(interface)的指针,我们只需要使用 QueryInterface 方法,它总是由任何接口(interface)实现。所以你的情况下的代码需要是下一个:

    IAction* pAction;
IExecAction* pExecAction;
IEmailAction* pEmailAction;

HRESULT hr;

if (SUCCEEDED(hr = pAction->QueryInterface(IID_PPV_ARGS(&pExecAction))))
{
// use pExecAction
pExecAction->Release();
}

if (SUCCEEDED(hr = pAction->QueryInterface(IID_PPV_ARGS(&pEmailAction))))
{
// use pExecAction
pEmailAction->Release();
}

即使一个接口(interface)继承自另一个接口(interface),使用 C/C++ 转换也总是错误的。例如

    pExecAction = static_cast<IExecAction*>(pAction);
pEmailAction = static_cast<IEmailAction*>(pAction);

此代码从 C++ 语法来看是正确的,因为 IExecAction : IActionIEmailAction : IAction继承自 IAction .并且此转换(如果考虑到这 3 个接口(interface)的布局)为 pExecAction 提供相等的二进制值和 pEmailAction .但是pExecAction不能具有与 pEmailAction 相同的二进制值.必须是

assert((void*)pEmailAction != (void*)pExecAction);

为什么?因为有 pEmailActionpExecActionvtable 的相同位置有不同的虚函数。例如在 IExecAction 表中的第 10 个位置必须是指向 get_Path 的指针方法。从另一边看 IEmailAction 表中的第 10 个位置必须是指向 get_Server 的指针方法。如果(void*)pEmailAction == (void*)pExecAction - 它们将具有相同的 vtable 指针。但指向哪个函数的指针 - get_Path get_Server 会排在第 10 位吗?结果指向这 2 个接口(interface)的指针不能相同(指向同一内存)。那么最少一个static_cast这里(可能和两者)给出错误的结果。了解如何 QueryInterface工作以及为什么指向pExecActionpEmailAction会有所不同——我们需要寻求实现。接口(interface)的实现 - 这是一些类,它(通常)继承自所有这些接口(interface)并像这样实现它:

class CAction : IExecAction, IEmailAction
{
virtual ULONG STDMETHODCALLTYPE AddRef( );

virtual HRESULT STDMETHODCALLTYPE QueryInterface( REFIID riid, void **ppvObject)
{
PVOID pvObject;

if (riid == __uuidof(IAction))
{
pvObject = static_cast<IExecAction*>(this);
// or can be
pvObject = static_cast<IEmailAction*>(this);
}
else if (riid == __uuidof(IExecAction))
{
pvObject = static_cast<IExecAction*>(this);
}
else if (riid == __uuidof(IEmailAction))
{
pvObject = static_cast<IExecAction*>(this);
}
else
{
*ppvObject = 0;
return E_NOINTERFACE;
}

*ppvObject = pvObject;
AddRef();
return S_OK;
}
};

static_cast<IExecAction*>(this);总是会给出另一个二进制值比较 static_cast<IEmailAction*>(this); - CAction将包含 2 个不同的 vtables - 一个用于 IExecAction和一个 IEmailAction .他们有共同的初始部分(9 个条目)但随后不同。和 static_cast<IExecAction*>(this);static_cast<IEmailAction*>(this);返回 2 个不同的(总是)指向这 2 个不同的 vtables 的指针。什么时候 IAction*我们选择返回或第一个或第二个 vtable 指针。两者都是正确的。什么指针返回实现 - 我们不知道(实现 IExecAction 的实际类的布局,IEmailAction 对我们来说是未知的)

关于C++ 转换 Windows IAction,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/52495658/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com