昨晚在写一段OLE自动化代码时,遇到一个莫名其妙的错误:当我的程序调用使用了VARIANT类型参数的自动化接口时出现严重错误,一晚上没有查出来。晚上回家仔细想了想,今早一来几下就解决了,原来是VC的一个BUG。说是BUG,可能也不是它的BUG。闲话少说,我们进入正题。
如果你需要重现这种错误,那很简单:在VC7.1中新建一个MFC单文档程序,选择支持自动化,并使用CHtmlView。新工程建立后,向导自动为我们的View建立了自动化接口,我们只需要向这个接口添加一个使用了VARIANT参数的方法就行了(在Class View窗口中选中接口,右键,然后选择Add\Add Method...)。如:
[id(1), helpstring("上传一个文件到服务器,并返回相应文件在服务器中的整数标识")] VARIANT_BOOL UploadFile(BSTR file, BSTR comment, VARIANT fileId);
在接下来,我们写一个HTML页面用于调用这个接口:
<HTML>
<HEAD>
</HEAD>
<script language='jscript'>
function Upload()
{
window.external.UploadFile('345', 'asd', 234);
alert ('ok');
}
</script>
<BODY>
<Button onclick='Upload()'>试一下</Button>
</BODY>
</HTML>
接下来修改你的View的实现,在其OnInitialUpdate()中加入
Navigate2(_T("file://html file path/html file name "),NULL,NULL);
现在编译并执行这个程序,你会发现当你点了“试一下”按钮后,程序会提示在oledisp1.cpp的 690 行出错。仔细跟踪进去,你会发现出错原因是参数类型不配置造成的。
可是看看向导为我们生成的代码:
// 接口映射
BEGIN_DISPATCH_MAP(CJILClientView, CHtmlView)
DISP_FUNCTION_ID(CJILClientView, "UploadFile", dispidUploadFile, UploadFile, VT_BOOL, VTS_BSTR VTS_BSTR VTS_VARIANT)
END_DISPATCH_MAP()
// ... 省略其它代码
// 接口函数
VARIANT_BOOL CJILClientView::UploadFile(LPCTSTR file, LPCTSTR comment, VARIANT fileId)
{
AFX_MANAGE_STATE(AfxGetAppModuleState());
// TODO: ...
return VARIANT_TRUE;
}
怎么样,好象一点错也没有吧,类型完全配置,那我们的问题到底是什么原因呢?其实仔细想一下就不难想出,JScript等语言都是传VARIANT变量的引用,而不是象C++那样传值。因此,我们应该将上面代码中接口映射处的 VTS_VARIANT 改为 VTS_PVARIANT,而函数中相应的参数改为引用类型的。 改完后的代码如下
// 接口映射
BEGIN_DISPATCH_MAP(CJILClientView, CHtmlView)
DISP_FUNCTION_ID(CJILClientView, "UploadFile", dispidUploadFile, UploadFile, VT_BOOL, VTS_BSTR VTS_BSTR VTS_PVARIANT)
END_DISPATCH_MAP()
// 接口函数
VARIANT_BOOL CJILClientView::UploadFile(LPCTSTR file, LPCTSTR comment, VARIANT & fileId)
{
AFX_MANAGE_STATE(AfxGetAppModuleState());
// TODO: ...
return VARIANT_TRUE;
}
现在再编译执行我们的程序,怎么样,没有问题了吧。看来是微软的老兄们想当然地把所有类型都按ULONG等简单类型处理了。
结论:VC7.1中MFC的OLE自动化向导有严重BUG。当然,我没有试过这样改了后,从VB等程序调用这个接口会不会正常工作。有兴趣的朋友们可以自己试一下啦。试完后别忘了告诉我结果啊。^_^
本文地址:http://com.8s8s.com/it/it727.htm