这应该很简单.ID2D1LinearGradientBrush使用有效的vtable从ID2D1Brush派生.我意识到QueryInterface可以在这里工作,但我的问题与dynamic_cast有关.
[definition from d2d1.h]
interface DX_DECLARE_INTERFACE("2cd906ab-12e2-11dc-9fed-001143a055f9")
ID2D1LinearGradientBrush : public ID2D1Brush
{
// ....
}
Run Code Online (Sandbox Code Playgroud)
但是,鉴于过度简化的示例函数......
bool ClampToItem(ID2D1Brush *brush, SizeF itemSize)
{
// As expected, works when a linear gradient brush is the parameter.
ID2D1LinearGradientBrush *linearGradientBrush = static_cast<ID2D1LinearGradientBrush *>(brush);
linearGradientBrush->SetStartPoint(D2D1_POINT_2F{ itemSize.Width, 0.0f });
linearGradientBrush->SetEndPoint(D2D1_POINT_2F{ itemSize.Width, itemSize.Height });
return true;
}
bool ClampToItem2(ID2D1Brush *brush, SizeF itemSize)
{
// this dynamic cast FAILS EVERY TIME with an access violation
ID2D1LinearGradientBrush *linearGradientBrush = dynamic_cast<ID2D1LinearGradientBrush *>(brush);
if (!linearGradientBrush) // <-- never gets here
return false;
linearGradientBrush->SetStartPoint(D2D1_POINT_2F{ itemSize.Width, 0.0f });
linearGradientBrush->SetEndPoint(D2D1_POINT_2F{ itemSize.Width, itemSize.Height });
return true;
}
Run Code Online (Sandbox Code Playgroud)
由于我不确定将ID2D1LinearGradientBrush作为参数提供,我想使用dynamic_cast.我一定很遗憾.这些COM对象不包含RTTI信息吗?谢谢您的帮助.
// For clarification, this works as expected
bool ClampToItem3(ID2D1Brush *brush, SizeF itemSize)
{
ID2D1LinearGradientBrush *linearGradientBrush;
HRESULT hr = brush->QueryInterface(__uuidof(ID2D1LinearGradientBrush), (void **)&linearGradientBrush);
if (hr == S_OK)
{
linearGradientBrush->SetStartPoint(D2D1_POINT_2F{ itemSize.Width, 0.0f });
linearGradientBrush->SetEndPoint(D2D1_POINT_2F{ itemSize.Width, itemSize.Height });
linearGradientBrush->Release();
linearGradientBrush = nullptr;
}
return true;
}
Run Code Online (Sandbox Code Playgroud)
编辑:
跟踪动态转换(进入rtti.cpp):
extern "C" PVOID __CLRCALL_OR_CDECL __RTDynamicCast(
PVOID inptr, // Pointer to polymorphic object
LONG VfDelta, // Offset of vfptr in object
PVOID SrcType, // Static type of object pointed to by inptr
PVOID TargetType, // Desired result of cast
BOOL isReference) // TRUE if input is reference, FALSE if input is ptr
throw(...)
Run Code Online (Sandbox Code Playgroud)
调用,inptr有效,vfDelta为0,SrcType和TargetType看起来很棒,isRef表示false.进一步跟踪,此处发生内存访问冲突:
// Ptr to CompleteObjectLocator should be stored at vfptr[-1]
_RTTICompleteObjectLocator *pCompleteLocator =
(_RTTICompleteObjectLocator *) ((*((void***)inptr))[-1]);
char *pCompleteObject = (char *)inptr - COL_OFFSET(*pCompleteLocator);
Run Code Online (Sandbox Code Playgroud)
因为*pCompleteLocator已移至无效位置.
Microsoft的标准COM接口__declspec(novtable)用作其定义的一部分; 如果你看一下你的定义,DX_DECLARE_INTERFACE你会看到这就是这种情况.这意味着基接口类没有vtable,只有具体实现有一个.RTTI没有dynamic_cast正常工作所需的信息.
对于COM接口,您应始终使用QueryInterface动态转换.