【问题标题】:VB - Linking a DLL in implicit wayVB - 以隐式方式链接 DLL
【发布时间】:2011-03-04 15:19:40
【问题描述】:

我正在开发一个 VB6 图形界面,我需要创建一个到 DLL 的隐式链接。

这样做的动机来自我的previous question。有问题的 DLL 使用静态 TLS,__declspec(thread),当然,当使用 LoadLibray 显式链接 DLL 时,这会严重失败。

我真的很想避免修改 DLL,那么有谁知道如何欺骗 VB6 可执行文件以隐式链接到特定的 DLL?

【问题讨论】:

  • 我已经编辑了问题和标签。我希望你批准。我这样做是为了提高您获得好答案的机会!我不知道如何做到这一点的细节,或者即使它会起作用,但我的直觉告诉我它应该起作用。
  • @David,是的,我注意到了,我说谢谢!现在更清楚了,下次我会尝试按照你的模型。

标签: windows multithreading visual-c++ dll vb6


【解决方案1】:

为您的 DLL 创建一个 IDL 文件,在 moduleclause 中描述您导出的函数。

使用 MIDL 编译器进行编译并从您的 VB6 项目(项目 - 参考)中引用生成的 tlb 文件。
并删除所有Declare Functions。

tlb 文件仅用于编译(在这种情况下),您不必将其包含在设置中。

【讨论】:

  • 这是个好主意,但我认为 VB6 仍然会动态加载库。
  • @GSerg 我不熟悉 IDL 文件和 MIDL 编译器,所以我需要一些时间来完成它(现在我正在学习 IDL 文件是什么)。当我完成后,我会给你一个反馈。非常感谢。
  • @Beppe 我专门学习了 IDL 来完成这个技巧。当您专注于您需要的领域时,这很容易。 MSDN文章末尾的IDL示例基本上就是你需要的所有IDL代码。
  • @GSerg 我试过了,但是一删除Declare Functions,编译器就说这些函数没有定义。
  • @Beppe String 在 VB 中。在 IDL 中我使用了LPSTR,本质上是char*
【解决方案2】:

这是一个从标准操作系统 dll 导入函数的示例 IDL

[
  uuid(YOURTYPE-LIBG-UIDH-ERE0-000000000000),
  version(1.0),
  helpstring ("My Type Library 1.0")
]
library MyTypeLib
{
    importlib("stdole2.tlb");

    typedef struct {
        long    Data1;
        short   Data2;
        short   Data3;
        BYTE    Data4[8];
    } VBGUID;

    typedef VBGUID CLSID;

    [dllname("OLEAUT32")]
    module OleAut32
    {
        [entry("SysAllocString")]
        BSTR SysAllocString([in] long lpStr);
        ...
    };

    [dllname("USER32")]
    module User32
    {
        [entry("RegisterClipboardFormatA")]
        UINT RegisterClipboardFormat([in] LPSTR lpszFormat);
        [entry("FillRect")]
        DWORD FillRect([in] DWORD hDC, [in] int lpRect, [in] DWORD hBrush);
        ...
    };

    [dllname("BOGUS")]
    module Strings
    {
        const LPSTR CLSID_DsQuery = "{8A23E65E-31C2-11D0-891C-00A024AB2DBB}";
        const LPSTR CLSID_DsFindObjects = "{83EE3FE1-57D9-11D0-B932-00A024AB2DBB}";
        ...
    }
}

【讨论】:

  • 感谢您的回复!我只是对具有我定义的类型的变量有问题,例如:int myFunct([in] myStruct data); 编译器说:syntax error: expecting a type specification near "myStruct"。你知道如何解决这个问题吗?谢谢
  • 您必须在 IDL 中包含该结构(示例已更新),或者您可以将其声明为 long myFunct([in] long data) 并在 VB6 中使用 myFunct VarPtr(uData) 调用它。
  • 你能在 IDL 文件中发布一个包含结构的例子吗?谢谢
【解决方案3】:

在 GSerg 和 David Heffernan 的帮助下,我终于解决了这个问题。

这里是用于生成 .tlb 的 IDL

[
    uuid(12345678-1234-1234-1234-123456789ABC),
    version(1.0)
] 

    library myTypeLib
    {
        [dllname("myLib.dll")]

        module myLib
        { 

            [entry("myFunc")]
            int __stdcall myFunc( LPSTR  filename_in,  LPSTR   filename_out, LPSTR  ErrMsg);
        };
    };

要编译它,请在 Visual Studio 命令提示符中使用命令“midl”。

生成的 .tlb 文件应与 DLL 一起放在 VB6 项目的同一目录中。

在 Project->References 下的 VB6 项目中,可以添加 .tlb 文件。

如果一切顺利,按F2,可能会注意到可用库列表中的“myTypeLib”。

现在可以在 VB6 项目中调用“myFunc”了!

但是有两个问题需要指出:

1) 一些变量类型在 VB6 和 C 之间不兼容。这个问题的一个例子是 char 数组。虽然在 VB6 中它们被声明为 Dim myStr as String,但在 C 中它们通常被声明为 char myStr[MAX_DIM];。为了使VB6和C之间的转换成为可能,无需修改DLL,可以在VB6端将字符串声明为Dim myStr as String * 256,而在IDL文件中,对应的字符串应作为LPSTR myStr传递给函数。

2)VB6 在创建 .exe 之前不会链接 DLL。但是如果一个 DLL 没有被链接,那么它的功能是不可见的。由于这个原因,必须在 VB6 项目中使用的隐式链接 DLL 的所有功能都必须包含在 IDL 文件中。

此外,出于同样的原因,即使所有功能都包含在 IDL 文件中,也无法从 IDE 运行程序(它会崩溃)来调试它。运行应用程序的唯一方法是创建 .exe。

【讨论】:

  • 这很奇怪,一切都应该在不创建 exe 的情况下运行,并且您也应该能够调试。无法调试的唯一情况是在 tlb 中使用不同的调用约定,例如 __cdecl。我建议你下载著名的Win32.tlb 并使用它——你会发现一切正常。要从 tlb 中提取 IDL 源,您可以使用任何适当的工具,例如 PE Browse
  • 虽然我能发现的唯一区别是 __stdcall_stdcall
  • @GSerg 我试图修复您发现的差异,但它仍然在 IDE 中崩溃。关于 Windows API tlb,你知道它是否包含任何使用__declspec(thread) 变量的函数吗?
  • 啊。我想这也算作不同的调用约定。混蛋。
猜你喜欢
  • 1970-01-01
  • 2011-06-15
  • 1970-01-01
  • 2015-12-05
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多