【发布时间】:2012-08-31 05:42:08
【问题描述】:
基本上,当我尝试使用 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 中,我将得到 aryOuts 的结果InvokeAction 调用。好消息是,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 无法解释这一点datatype 并且不允许我访问此数组项 (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() 数组是由 InvokeAction 声明中的 [in, out] VARIANT* pvOutActionArgs 行定义的(在上面的 TypeLib 中)。基本上,整个数组被定义为一个 VARIANT* (这很好),但我无法访问上面定义的 pvOutActionArgs 数组的第三个元素(索引项号 2),如何围绕这个问题修改 TypeLib?
作为参考,以及那些感兴趣的人,Hans Passant (@HansPassant) 帮助我解决了类似的情况,要求我从 oleview 公开的 upnp.dll TypeLib 中删除 Text 的 Unsigned 部分。 exe - 他帮助我做到了这一点(以及在以下帖子中生成和编译新 TypeLib (upnp.tbl) 所需的其余步骤: Function or interface marked as restricted, or the function uses an Automation type not supported in Visual Basic
【问题讨论】:
-
让我直截了当地说:1)你试图在“upnp.dll”中调用一个函数,2)你试图从 VB6 中执行此操作,3)你得到当您尝试在 VB6 调试器中运行 VB6 程序时,返回给您的“运行时错误 458”。正确的?问:你能发布产生错误的 VB 代码吗? Q:这是Windows自带的标准“upnp.dll”系统.dll吗?问:您运行的是哪个版本的 Windows?
-
这是Windows自带的标准upnp.dll(我用的是Win7),其他UPnP功能都可以正常使用,upnp.dll和VB6没有大的兼容性问题,在之前的一篇在场景中,我已经修改了 TypeLib,以便 VB6 理解 upnp.dll 返回的类型,这只是需要修改的另一种情况,但我不确定如何在未明确声明数组项时进行此修改(并且整个数组只是声明为 VARIANT*),我问是否有人知道我需要如何修改 TypeLib 中的数组声明以使其与 VB6 兼容。
-
通过 VB6 兼容,我的意思是,如果有人知道如何修改数组声明 (pvOutActionArgs),以便当此数组中的特定项目是无符号 4 字节整数(或任何无符号,因为 VB6 没有支持未签名的任何东西)它由 VB6 可读/可访问。目前,它抛出 458 错误。我只需要修改 [in, out] VARIANT* pvOutActionArgs 行来说明 pvOutActionArgs 应该变成一个数组(同时确保数组中的所有项目都是 String 数据类型),这(我认为)可以工作,因为 VB6 可以读取包含 String 数据类型项的数组。
-
尝试将
aryOuts(2)分配给Long变量(lStatusBits = aryOuts(2))。在 VB6 中访问VT_UI4变体应该没有问题,除非它被For Each vElem ...循环(vElem是一个变体)或变体分配给变体阻塞。您无法在 typelib 中执行任何操作来解决此问题。如果没有其他方法,您可以使用Call CopyMemory(aryOuts(2), VT_I4, 2)whereVT_I4 = 3手动更改变体类型 -
@wqw 你是个传奇!您的 CopyMemory 想法奏效了!我刚刚运行 CopyMemory aryOuts(2), 3, 2 (不带括号,将其作为子例程运行,而不是函数),然后在使用 aryOuts(2) 运行 CopyMemory 之后,我尝试访问 aryOuts(2) 以打印出来价值,它奏效了! Print aryOuts(2) 工作完美。如果没有 CopyMemory,尝试将其单独分配给 Long 是行不通的,但是在通过 CopyMemory 运行它之后,我能够将它分配给任何东西并毫无问题地从中读取。随意复制/粘贴您的评论作为答案,因为我很乐意投票并接受它作为答案。
标签: visual-studio vb6 com-interop