C++ 转换 Windows IAction
C++ casting Windows IAction
我正在努力从 windows 任务计划程序中检索一些信息。
MSDN表示有几种类型的动作。我想分别处理它们。我试过了:
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
中的定义表明 IExecAction
是 IAction
的派生 class。
效果很好:
if (IExecAction* pExecAction = ((IExecAction*)pAction)) { /*my work...*/ }
但是如果我想做一些类型检查怎么办?
我该如何正确使用它?
为了从同一对象上的另一个 com 接口获取 com 接口的指针,我们只需要使用 QueryInterface
方法,该方法始终由任何接口实现。所以你的代码需要在下一个:
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();
}
即使一个接口继承自另一个接口,使用 c/c++ 转换总是错误的。例如
pExecAction = static_cast<IExecAction*>(pAction);
pEmailAction = static_cast<IEmailAction*>(pAction);
此代码从 c++ 语法来看是正确的,因为 IExecAction : IAction
和 IEmailAction : IAction
都继承自 IAction
。并且此转换(如果考虑到这 3 个接口的布局)为 pExecAction
和 pEmailAction
提供相等的二进制值。但是 pExecAction
不能有与 pEmailAction
相同的二进制值。必须
assert((void*)pEmailAction != (void*)pExecAction);
为什么?因为 have pEmailAction
和 pExecAction
在 vtable 的同一位置有不同的虚函数。例如在 IExecAction
must be pointer to get_Path
method. from another side on the 10-th position in the table of IEmailAction
must be pointer to get_Server
method. if (void*)pEmailAction == (void*)pExecAction
- they will be have the same pointers to vtable. but pointer to which function - get_Path
or get_Server
的 table 中的第 10 个位置将在第 10 个位置?结果指向这 2 个接口的指针不能相同(指向同一内存)。那么这里的最小值 static_cast
(可能是,两者都是)如何给出错误的结果。为了理解 QueryInterface
是如何工作的以及为什么指向 pExecAction
和 pEmailAction
的指针会不同 - 我们需要寻找实现。接口的实现 - 这是一些 class,它(通常)继承所有这些接口并像这样实现它:
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);
return 2 个不同的(总是)指向这 2 个不同的 vtable 的指针。当 IAction*
我们 select return 或第一个或第二个 vtable 指针。两者都是正确的。什么指针 return 实现 - 我们不知道(实现 IExecAction
、IEmailAction
的实际 class 的布局对我们来说是未知的)
我正在努力从 windows 任务计划程序中检索一些信息。 MSDN表示有几种类型的动作。我想分别处理它们。我试过了:
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
中的定义表明 IExecAction
是 IAction
的派生 class。
效果很好:
if (IExecAction* pExecAction = ((IExecAction*)pAction)) { /*my work...*/ }
但是如果我想做一些类型检查怎么办? 我该如何正确使用它?
为了从同一对象上的另一个 com 接口获取 com 接口的指针,我们只需要使用 QueryInterface
方法,该方法始终由任何接口实现。所以你的代码需要在下一个:
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();
}
即使一个接口继承自另一个接口,使用 c/c++ 转换总是错误的。例如
pExecAction = static_cast<IExecAction*>(pAction);
pEmailAction = static_cast<IEmailAction*>(pAction);
此代码从 c++ 语法来看是正确的,因为 IExecAction : IAction
和 IEmailAction : IAction
都继承自 IAction
。并且此转换(如果考虑到这 3 个接口的布局)为 pExecAction
和 pEmailAction
提供相等的二进制值。但是 pExecAction
不能有与 pEmailAction
相同的二进制值。必须
assert((void*)pEmailAction != (void*)pExecAction);
为什么?因为 have pEmailAction
和 pExecAction
在 vtable 的同一位置有不同的虚函数。例如在 IExecAction
must be pointer to get_Path
method. from another side on the 10-th position in the table of IEmailAction
must be pointer to get_Server
method. if (void*)pEmailAction == (void*)pExecAction
- they will be have the same pointers to vtable. but pointer to which function - get_Path
or get_Server
的 table 中的第 10 个位置将在第 10 个位置?结果指向这 2 个接口的指针不能相同(指向同一内存)。那么这里的最小值 static_cast
(可能是,两者都是)如何给出错误的结果。为了理解 QueryInterface
是如何工作的以及为什么指向 pExecAction
和 pEmailAction
的指针会不同 - 我们需要寻找实现。接口的实现 - 这是一些 class,它(通常)继承所有这些接口并像这样实现它:
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);
return 2 个不同的(总是)指向这 2 个不同的 vtable 的指针。当 IAction*
我们 select return 或第一个或第二个 vtable 指针。两者都是正确的。什么指针 return 实现 - 我们不知道(实现 IExecAction
、IEmailAction
的实际 class 的布局对我们来说是未知的)