惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

C
Check Point Blog
奇客Solidot–传递最新科技情报
奇客Solidot–传递最新科技情报
GbyAI
GbyAI
WordPress大学
WordPress大学
月光博客
月光博客
V
Visual Studio Blog
freeCodeCamp Programming Tutorials: Python, JavaScript, Git & More
Google DeepMind News
Google DeepMind News
H
Help Net Security
MongoDB | Blog
MongoDB | Blog
P
Proofpoint News Feed
博客园 - 司徒正美
S
SegmentFault 最新的问题
Apple Machine Learning Research
Apple Machine Learning Research
Blog — PlanetScale
Blog — PlanetScale
B
Blog
Cyber Security Advisories - MS-ISAC
Cyber Security Advisories - MS-ISAC
H
Hackread – Cybersecurity News, Data Breaches, AI and More
Microsoft Azure Blog
Microsoft Azure Blog
V
V2EX
L
LangChain Blog
腾讯CDC
T
The Blog of Author Tim Ferriss
量子位

博客园 - sunwaywei

被MM当成电脑白痴了 用Delphi编写的一个上网助手 Excel 2007的日期格式设置 使用C++绘制算法弥补.net图形绘制缺陷 使用UpdatePanel控件要注意的一个问题 Chuck Jazdzewski 对新手程序员的建议 打赢了一场效率仗 一个极有可能引发ExecutionEngineException的情况 竟然是灰鸽子? They're Back!!! Turbo系列产品的回归! 不小心染上了Bloodhound.NsAnti 第三届虚拟现实峰会 忙碌的这几天 ASP.NET 2.0 中使用自定义缓存依赖 在 .net 2.0 中使用自定义事务操作 郁闷的端午节 奇怪的C++问题 为了一个 const 折腾了半天 CAD二次开发中遇到一个无法解决的问题
.net 2.0 的 Bug?--与 COM 交互时发生奇怪的 InvalidCastExc...
sunwaywei · 2006-07-09 · via 博客园 - sunwaywei

最近在开发中发现一个奇怪的现象,百思不得其解。程序是用 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。 

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