我正在一个VB6graphics界面,我需要隐式链接到一个DLL。
这个动机来自我以前的问题 。 有问题的DLL使用静态TLS, __declspec(thread)
,当然这当使用LoadLibray明确地链接DLL时会失败。
我真的想避免修改DLL,所以没有人知道如何欺骗VB6可执行文件隐式链接到特定的DLL?
为您的DLL创建一个IDL文件,描述您在module
子句中导出的函数。
使用MIDL编译器编译并从VB6项目(Project – References)中引用生成的tlb文件。
并删除所有的Declare Function
。
tlb文件仅用于编译( 在这种情况下 ),您不必将其包含在设置中。
这里是一个从标准操作系统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}"; ... } }
最后,由于GSerg和David Heffernan的帮助,我能够解决这个问题。
这里用IDL来生成.tlb
[ 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项目的同一目录中。
在项目 – >引用下的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不链接DLL,直到.exe被创建。 但是,如果一个DLL没有链接,那么它的功能是不可见的。 由于这个原因,必须在VB6项目中使用的隐式链接DLL的所有功能都必须包含在IDL文件中。
而且,出于同样的原因,即使所有的功能都包含在IDL文件中后,也不可能从IDE运行程序(它会崩溃)以便进行调试。 运行该应用程序的唯一方法是创建.exe。