【问题标题】:"standard" dll created in vb6 gives access violation when called in python在 vb6 中创建的“标准”dll 在 python 中调用时会出现访问冲突
【发布时间】:2012-03-07 10:54:34
【问题描述】:

我通过以下 hack 使用 vb6 创建了一个“标准”dll:http://windowsdevcenter.com/pub/a/windows/2005/04/26/create_dll.html?page=3。我们称之为 myVB6dll。

myVB6dll 中的一个函数(称为 myVB6dllFunc())从 hid.dll 调用 HidD_GetHidGuid() 并返回 GUID 的一个字节(用于测试目的)。当我从 vb6 中的测试程序调用 myVB6dllFunc() 时,它返回正确的值。但是,当从 python2.7 测试程序调用时,它会抛出“访问冲突写入 0x00000009c”。

用 C++ 编写的类似 dll 在从 VB6 或 Python2.7 调用时都可以工作。

那么,VB6 dll 真的不是标准 dll,而且 hack 并不能真正起作用(但它确实适用于 Python 调用的来自 vb6 dll 的简单测试用例,例如如果我返回两个整数的总和)?有没有办法让它在 Python 中工作?这两个dll有什么区别?

【问题讨论】:

    标签: c++ python dll vb6


    【解决方案1】:

    从 VB6 dll 导出函数的最简单方法是使用 vbAdvance add-in,它现在是免费软件。

    您面临的问题是您需要在调用导出的线程上初始化 VB6 运行时。这也包括初始化 COM 单元 (STA)。最简单的方法是从您的 python 代码创建一个 VB6 类的实例。

    在导出函数中“手动”初始化 VB6 运行时要困难得多,并且需要使用自定义类型库来调用 API 函数(在初始化运行时之前不能使用声明或内置 VB6 函数)。

    这是我正在使用的一个函数

    Private Function pvInitVbRuntime() As Boolean
    '    Const FUNC_NAME     As String = "pvInitVbRuntime" '
        Const PROGID_DUMMY  As String = LIB_NAME & ".cDummy"
        Dim lIdx            As Long
    
        lIdx = GetModuleHandle("MSVBVM60.DLL")
        lIdx = GetProcAddress(lIdx, "__vbaSetSystemError")
        Call RtlMoveMemory(lIdx, ByVal lIdx + 9, 4)
        Call RtlMoveMemory(lIdx, ByVal lIdx, 4)
        If TlsGetValue(lIdx) <> 0 Then
            Call CoCreateInstance(CLSIDFromProgID(PROGID_DUMMY), Nothing, CLSCTX_INPROC_SERVER, VBGUIDFromString("{00000000-0000-0000-C000-000000000046}"), Nothing)
            pvInitVbRuntime = True
        Else
    '        Call APIOutputDebugString(GetCurrentThreadId() & ": not a VB thread [" & LIB_NAME & "." & MODULE_NAME & "." & FUNC_NAME & "]" & vbCrLf) '
        End If
    End Function
    

    所有 API 函数(GetModuleHandleGetProcAddressRtlMoveMemoryTlsGetValueCoCreateInstanceCLSIDFromProgIDVBGUIDFromStringAPIOutputDebugString)都在自定义类型库中声明。基本上它在线程上创建了一个虚拟的 VB6 类(称为cDummy)。如果公寓尚未初始化(未调用CoInitialize),则该函数将失败。

    【讨论】:

    • 谢谢wqw。我正在消化你的回复。
    • @tosa:VB6 对全局变量使用 TLS(线程本地存储),因此 VB6 全局变量每个线程都有“副本”。 __vbaSetSystemError 的技巧是找出运行时应该在当前进程中使用的 TLS 插槽/索引。如果未设置具有此索引的 TLS 插槽,则运行时尚未初始化(因此没有全局变量,也没有可用的错误处理)。请注意,MSVBVM60.DLL 已经加载,因为您的 VB6 dll 在其导入部分中指定了它,因此GetModuleHandle 永远不会失败。
    猜你喜欢
    • 2023-03-22
    • 2011-05-25
    • 1970-01-01
    • 2012-09-12
    • 1970-01-01
    • 1970-01-01
    • 2014-03-19
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多