最近在开发中发现一个奇怪的现象,百思不得其解。程序是用 VS 2005 写的,其中使用了 ParallelGraphics 公司的 Cortona VRML Viewer 控件,以提供 3D 场景浏览的功能。其中,我希望当场景里发现某些事件的时候,程序能够作出一定的反应,为此,需要实现一个事件回调。相关的代码是这样的:
public class TestSyncCallback : VRMLAutomation.IVRMLEventCallback2
{3
IVRMLEventCallback Members11
}
这里的 IVRMLEventCallback 是在类型库里引入的,其原型定义如下:
[2
uuid(6BEF46D1-FD35-11d2-812F-00A0C94C695A),3
helpstring("IVRMLEventCallback Interface"),4
pointer_default(unique)5
]6
interface IVRMLEventCallback : IUnknown7
{8
HRESULT OnEvent([in] LPFIELDOBJECT Value,9
[in] VARIANT* Hint,10
[in] double TimeStamp);11
};这是引入类型库后反射得到的 metadata:
[InterfaceType(1)]2
[Guid("6BEF46D1-FD35-11D2-812F-00A0C94C695A")]3
public interface IVRMLEventCallback4
{5
void OnEvent(VRMLField value, ref object Hint, double TimeStamp);6
}继续往下,实现了回调接口后,需要把该 Callback 向一个 VRMLField 注册,相关代码如下:
void RegisterEventCallback()2
{3
try4
{5
VRMLField field;6
TestSyncCallback callback;7
object hint = "hint";8
// 相关设置略9
field.Advise(callback, ref hint);10
}11
catch (COMException e)12
{13
MessageBox.Show(e.ToString());14
}15
catch (Exception e)16
{17
MessageBox.Show(e.ToString());18
}19
}这里,第 9 行的 Advise 函数的原型定义是:
HRESULT Advise([in] LPDISPATCH Listener,2
[in] VARIANT* Hint);引入后反射为:
void Advise(object Listener, ref object Hint);关于这个函数的正确使用方法,ParallelGraphics 公司提供的 C++ Demo 里是这样使用的:
VrmlEventCallback* pVrmlEventCallback = new VrmlEventCallback();2
pField->Advise(reinterpret_cast<LPDISPATCH>(pVrmlEventCallback), &Hint);这个函数的用法,Listener 参数是一个实现了 IVRMLEventCallback 接口的对象,在本例中将 TestSyncCallback 的一个实例传递进去。这个用法是绝对正确的。编译通过也完全没有问题,但是这段代码在运行的时候,Advise 函数执行会抛出一个异常:Specified cast is not valid。
请注意,这个异常不是一个 COMException,而是一个 InvalidCastException。那么到底是哪里转换失败了?奇怪之余,我自己写了一个 IVRMLEventCallback 的 C# Wrapper,结果仍然不行。再然后改用 VB.NET,使用 Wizard 自动产生了接口函数,然而这个 Specified cast is not valid 依然如故。看来不是 C# 的问题,而是 .net 2.0 或是 VS2005 的问题了。
实在通不过运行。无奈之下用 VS 2003 一试,结果同样的代码在 VS 2003 里一点错误都没有,运行十分正常。
再然后,将在 VS 2003 下执行通过的工程 Upgrade 到 VS 2005,意外地发现,居然一切 OK 了!即使是 Rebuild 之后,也仍然是可以运行的!可是我调出原先无法通过的工程,一试之下却仍然不行!仔细核对两个项目之间的差别,从 Properties 到 References,再使用 ILDASM 检查生成的运行代码,实在是无法看出任何的差异!
极其奇怪。是不是 .net 2.0 或是 VS 2005 在与 COM 交互的局部细节作了一些调整?可是就算是调整也应当有一些提示什么的啊。难不成,这是一个 Bug?
Such a strange exception。
(暂发首页,希望有解决过或是遇过类似问题的朋友指点)



浙公网安备 33010602011771号