千里之行,始于足下

酌贪泉而觉爽,处涸辙而犹欢

  博客园 :: 首页 :: 博问 :: 闪存 :: 新随笔 :: 联系 :: 订阅 订阅 :: 管理 ::

最近在开发中发现一个奇怪的现象,百思不得其解。程序是用 VS 2005 写的,其中使用了 ParallelGraphics 公司的 Cortona VRML Viewer 控件,以提供 3D 场景浏览的功能。其中,我希望当场景里发现某些事件的时候,程序能够作出一定的反应,为此,需要实现一个事件回调。相关的代码是这样的:

 1public 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]
 6interface IVRMLEventCallback : IUnknown
 7{
 8  HRESULT OnEvent([in] LPFIELDOBJECT Value,
 9                  [in] VARIANT* Hint,
10                  [indouble TimeStamp);
11}
;

这是引入类型库后反射得到的 metadata:

1[InterfaceType(1)]
2[Guid("6BEF46D1-FD35-11D2-812F-00A0C94C695A")]
3public interface IVRMLEventCallback
4{
5    void OnEvent(VRMLField value, ref object Hint, double TimeStamp);
6}

继续往下,实现了回调接口后,需要把该 Callback 向一个 VRMLField 注册,相关代码如下:

 1void 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 函数的原型定义是:

1HRESULT Advise([in] LPDISPATCH Listener,
2               [in] VARIANT* Hint);

引入后反射为:

1void Advise(object Listener, ref object Hint);

关于这个函数的正确使用方法,ParallelGraphics 公司提供的 C++ Demo 里是这样使用的:

1VrmlEventCallback* pVrmlEventCallback = new VrmlEventCallback();
2pField->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。 

(暂发首页,希望有解决过或是遇过类似问题的朋友指点)

posted on 2006-07-09 18:50  sunwaywei  阅读(1688)  评论(6编辑  收藏  举报