








最近在开发中发现一个奇怪的现象,百思不得其解。程序是用 VS 2005 写的,其中使用了 ParallelGraphics 公司的 Cortona VRML Viewer 控件,以提供 3D 场景浏览的功能。其中,我希望当场景里发现某些事件的时候,程序能够作出一定的反应,为此,需要实现一个事件回调。相关的代码是这样的:
1
public class TestSyncCallback : VRMLAutomation.IVRMLEventCallback
2
{
3
IVRMLEventCallback Members
11
}
这里的 IVRMLEventCallback 是在类型库里引入的,其原型定义如下:
1
[
2
uuid(6BEF46D1-FD35-11d2-812F-00A0C94C695A),
3
helpstring("IVRMLEventCallback Interface"),
4
pointer_default(unique)
5
]
6
interface IVRMLEventCallback : IUnknown
7
{
8
HRESULT OnEvent([in] LPFIELDOBJECT Value,
9
[in] VARIANT* Hint,
10
[in] double TimeStamp);
11
};
这是引入类型库后反射得到的 metadata:
1
[InterfaceType(1)]
2
[Guid("6BEF46D1-FD35-11D2-812F-00A0C94C695A")]
3
public interface IVRMLEventCallback
4
{
5
void OnEvent(VRMLField value, ref object Hint, double TimeStamp);
6
}
继续往下,实现了回调接口后,需要把该 Callback 向一个 VRMLField 注册,相关代码如下:
1
void RegisterEventCallback()
2
{
3
try
4
{
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 函数的原型定义是:
1
HRESULT Advise([in] LPDISPATCH Listener,
2
[in] VARIANT* Hint);
引入后反射为:
1
void Advise(object Listener, ref object Hint);
关于这个函数的正确使用方法,ParallelGraphics 公司提供的 C++ Demo 里是这样使用的:
1
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。
(暂发首页,希望有解决过或是遇过类似问题的朋友指点)
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。