4

基本上,当我尝试使用 VB6 调用 upnp.dll 中的函数时出现此错误,其中 upnp.dll 返回的数据类型不受 VB6 支持。以前,同样的错误发生在不同的函数/变量上,解决方法是在 oleview.exe 中打开 upnp.dll(查看类型库信息)并将所有出现的“Unsigned Long”替换为“Long”然后编译一个删除了“Unsigned”关键字的新TypeLib,这解决了那个senario的问题。

现在,我需要解决相同的问题,但需要使用不同的函数/变量,但问题是,当我在 oleview 的 upnp.dll 的 TypeLib 视图中时,我不知道需要更改或删除哪个变量数据类型。

为了完整起见,我会让你知道这个错误发生在哪里,然后我会向你展示我在修改时遇到问题的 oleview/TypeLib 视图的相关部分。(供您参考,upnp.dll 包含在 windows\system32 中,并且 oleview.exe 随 Windows SDK 工具包一起提供,如果您的计算机上还没有它)。

我正在调用函数.InvokeAction sActionName, aryIns, aryOuts,其中 aryIns 和 aryOuts 是这样声明的变体:Dim aryIns As Variant, aryIns As Variant- 基本上,我通常声明它,将我需要的任何输入数据放入 aryIns 中,我将获得带有 InvokeAction 调用结果的 aryOuts。好消息是,InvokeAction 将我的一般 Variant 转换为一个适当尺寸的数组,反映为我正在使用的 ActionName 返回的输出项的数量。

关于我收到错误的重点,我在“WAN 连接设备”下的“WanIPConnection”上使用(对于 sActionName)“GetStatusInfo”。我不需要为 aryIns 定义任何项目,因为此调用不需要或不需要任何输入参数,但它提供(返回)3 个项目(结果)并将它们放入 aryOuts。所以 aryOuts 最终成为一个数组,其中包含从索引 0 到 2 的项目(总共 3 个项目)......当我遍历这个 aryOuts 数组时,项目 0 和 1 被打印出来并完美地查看(没有问题)但在第 3 次item (aryOuts(2)) 我得到了上述异常。

基本上,前 2 个参数只是简单的字符串(访问这些没有问题),但 UPnP 人员将第三个参数定义为Unsigned 4 Byte Integer(这就是问题所在),VB6 无法解释此数据类型并且不允许我访问此数组项 (aryOuts(2)),但我无法弄清楚我需要修改 TypeLib 的哪一部分,因为 InvokeAction aryOuts 的定义只是在 TypeLib 中声明为 VARIANT*,这是相关部分TypeLib 供您查看(我已经包含了我认为相关的区域,如果您想发布其他区域,请告诉我,我可以这样做):

[
  odl,
  uuid(A295019C-DC65-47DD-90DC-7FE918A1AB44),
  helpstring("IUPnPService Interface"),
  dual,
  nonextensible,
  oleautomation
]
interface IUPnPService : IDispatch {
    [id(0x600209c5), helpstring("method QueryStateVariable")]
    HRESULT QueryStateVariable(
                    [in] BSTR bstrVariableName, 
                    [out, retval] VARIANT* pValue);
    [id(0x600209c6), helpstring("method InvokeAction")]
    HRESULT InvokeAction(
                    [in] BSTR bstrActionName, 
                    [in] VARIANT vInActionArgs, 
                    [in, out] VARIANT* pvOutActionArgs, 
                    [out, retval] VARIANT* pvRetVal);
    [id(0x600209c7), propget, helpstring("property ServiceTypeIdentifier")]
    HRESULT ServiceTypeIdentifier([out, retval] BSTR* pVal);
    [id(0x600209c8), helpstring("method AddStateChangeCallback")]
    HRESULT AddCallback([in] IUnknown* pUnkCallback);
    [id(0x600209c9), propget, helpstring("property Id")]
    HRESULT Id([out, retval] BSTR* pbstrId);
    [id(0x600209ca), propget, helpstring("property LastTransportStatus")]
    HRESULT LastTransportStatus([out, retval] long* plValue);
};

我之前谈到的 aryOuts() 数组是由声明中的[in, out] VARIANT* pvOutActionArgs行定义的InvokeAction(在上面的 TypeLib 中)。基本上,整个数组被定义为一个 VARIANT* (这很好),但我无法访问pvOutActionArgs上面定义的数组的第三个元素(索引项号 2),如何围绕这个问题修改 TypeLib?

作为参考,以及那些感兴趣的人,Hans Passant (@HansPassant) 通过要求我从 oleview.exe 暴露的 upnp.dll TypeLib 中删除 Text 的 Unsigned 部分来帮助我解决类似的情况 - 他帮助我做到了这(以及在以下帖子中生成和编译新 TypeLib (upnp.tbl) 所需的其余步骤: 标记为受限的函数或接口,或函数使用 Visual Basic 中不支持的自动化类型

4

1 回答 1

6

尝试分配aryOuts(2)Long变量 ( lStatusBits = aryOuts(2))。访问 VB6 中的变体应该没有问题VT_UI4,除非它阻塞For Each vElem ...循环(vElem作为变体)或变体分配的变体。您无法在 typelib 中执行任何操作来解决此问题。如果没有其他方法,您可以使用Call CopyMemory(aryOuts(2), VT_I4, 2)where VT_I4= 3手动更改变体类型

COM 变体是一种数据结构,它以一个名为 vartype 的 int16 成员开头,它定义了存储在变量中的数据的类型(aryOuts(2)在您的情况下)。

VarTypeVT_UI4用于无符号 int32 值。VB6Long被转换为有符号的VT_I4 = 3变体。

VarTypeVT_UI2用于无符号 int16 值。VB6Integer被转换为有符号的VT_I2 = 2变体。

除非您知道自己在做什么,否则修改变量的变体类型可能非常危险。在这种情况下,您可以非常安全地将无符号类型转换为有符号类型,而不会泄漏内存或任何其他副作用。

于 2012-08-31T08:52:04.643 回答