com – 错误0x800706F7“存根接收到错误数据”在Windows XP SP3
在我的VB6应用程序中,我多次调用我的团队从Ada项目创建的COM服务器(使用GNATCOM). COM服务器上基本上有两种方法可用.他们在VB中的原型是:
Sub PutParam(Param As Parameter_Type,Value) Function GetParam(Param As Parameter_Type) 其中Parameter_Type是一个枚举类型,它区分了我可以放入/获取COM服务器的许多参数,’Value’是Variant类型变量. PutParam()接收变量,GetParam()返回变量. (我真的不知道为什么在VB6对象浏览器中没有引用COM服务器接口上的Variant类型…). 这个项目的产品已经连续多年使用,在Windows XP SP2的计算机上没有任何问题.在使用WinXP SP3的计算机上,当尝试将参数设置为“Long”类型时,我们得到错误0x800706F7“存根接收到错误数据”. 有没有人知道可能导致这种情况的原因? COM服务器仍在SP2系统中构建.在使用SP3的系统上构建它应该有什么区别吗? (就像我们在X64系统中为X64构建时). 导致问题的一个调用是(更改了一些var名称): Dim StructData As StructData_Type StructData.FirstLong = 1234567 StructData.SecondLong = 8901234 StructData.Status = True ComServer.PutParam(StructDataParamType,StructData) StructData_Type的定义是: Type StructData_Type FirstLong As Long SecondLong As Long Status As Boolean End Type (首次发布问题后添加了以下内容) IDL中COM服务器接口上的原语调用定义如下: // Service to receive data HRESULT PutParam([in] Parameter_Type Param,[in] VARIANT *Value); //Service to send requested data HRESULT GetParam([in] Parameter_Type Param,[out,retval] VARIANT *Value); 我试图传递的结构的定义是: struct StructData_Type { int FirstLong; int SecondLong; VARIANT_BOOL Status; } StructData_Type; 我觉得奇怪的是,这里的定义是使用’int’作为FirstLong和SeconLong的类型,当我检查VB6对象资源管理器时,它们被输入’Long’.顺便说一句,当我从COM服务器(使用特定实用程序)中提取IDL时,这些参数被定义为Long. 更新: 我已经使用为Windows 7编译的COM服务器版本测试了相同的代码(不同版本的GNAT,相同的GNATCOM版本),它的工作原理!我真的不知道这里发生了什么.我将继续尝试在WinXP SP3上识别问题,但很高兴知道它适用于Win7.如果您遇到类似的问题,尝试迁移到Win7可能会很好. 解决方法
我将专注于解释错误的含义,问题中的提示太少,无法提供简单的答案.
在跨执行边界进行调用时,在COM中使用“存根”.在问题中没有明确说明,但您的Ada程序可能是一个EXE并实现了一个进程外的COM服务器.由于它们的强大隔离,跨越Windows中进程之间的界限很困难.这是在Windows中通过RPC,远程过程调用,一种跨越这些边界进行调用的协议来完成的,网络是典型的情况. 要进行RPC调用,必须将函数的参数序列化为网络数据包. COM不知道如何执行此操作,因为它不了解函数的实际参数,它需要代理的帮助.一段知道参数类型的代码.在接收端是一段非常相似的代码,与代理的功能完全相反.它反序列化参数并进行内部调用.这是存根. 这种方法可能失败的一种方法是当存根接收网络数据包并且它包含的数据多于或少于函数参数值所需的数据.显然,它不知道如何处理该数据包,没有明智的方法将其转换为StructData_Type值,并且它将失败并显示“存根收到错误数据”错误. 因此,要考虑此错误的第一个解释是DLL Hell问题.代理和存根之间不匹配.如果这个应用程序已经稳定了很长时间,那么这不是一个快乐的解释. 您的代码片段的另一个方面可能会导致此问题.结构是软件中非常麻烦的野兽,它们的成员与它们的自然存储边界对齐,并且对齐规则需要由各自的编译器解释.对于您引用的结构,情况肯定如此.它需要10个字节来存储字段,4 4 2并且它们自然对齐.但结构实际上是12个字节长.最后填充两个字节,以确保在结构存储在数组中时,整数仍然对齐.它也使COM的工作非常困难,因为COM隐藏了实现细节,结构对齐是一个巨大的细节.复制结构需要帮助,这是IRecordInfo接口的工作.当存根找不到该接口的实现时,该存根也将失败. 我将谈谈代理,存根和IRecordInfo.生成代理/存根对有两种基本方法.一种方法是使用名为IDL,接口描述语言的语言描述接口,并使用MIDL进行编译.该编译器能够自动生成代理/存根代码,因为它知道函数参数类型.您将获得需要在客户端和服务器上注册的DLL.您的服务器可能正在使用它,我不知道. 第二种方式是VB6使用的方式,它利用了Windows内置的通用代理.称为FactoryBuffer,其CLSID为{00000320-0000-0000-C000-000000000046}.它的工作原理是使用类型库.类型库是COM服务器中函数的机器可读描述,足以让FactoryBuffer弄清楚如何序列化函数参数.此类型库也是提供IRecordInfo需要确定结构成员如何对齐的信息的库.我不知道它是如何在服务器端完成的,以前从未听说过GNATCOM. 因此,对此问题的一个强有力的解释是您遇到了类型库的问题.在VB6中特别棘手,因为你不能直接控制它使用的guid.当您进行微不足道的更改时,它喜欢生成新的,唯一的方法是通过选择二进制兼容性选项来避免它.它使用类型库的旧副本并尝试使新的副本尽可能兼容.如果你没有启用该选项,那么确实会遇到麻烦,特别是对于结构的指导. Kaboom如果它改变了,另一端仍然使用旧的guid. 只是一些关于从哪里开始寻找的提示.不要认为这是由SP3引起的问题,这个COM基础设施很长一段时间没有改变.但是,由于安装了新的操作系统版本并且不得不重新注册所有内容,因此肯定会出现这种问题. SysInternals的ProcMon是一个很好的实用程序,可以看到程序使用注册表来查找代理,存根和类型库.你肯定会得到COM Spy实用程序的帮助,尽管这些日子很难找到它们. (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |