我正在使用VB6图形界面,我需要隐式链接到DLL。
这样做的动机来自我previous question。有问题的DLL使用静态TLS,__declspec(thread)
,当使用LoadLibray明确链接DLL时,这当然会失败。
我真的想避免修改DLL,所以有人知道如何欺骗VB6可执行文件隐式链接到特定的DLL吗?
答案 0 :(得分:5)
为您的DLL创建一个IDL文件,用于在module
子句中描述导出的函数。
使用MIDL编译器编译并从VB6项目中引用生成的tlb文件(项目 - 参考)。
并删除所有Declare Function
。
tlb文件仅用于编译(在本例中为 ),您不必将其包含在设置中。
答案 1 :(得分:2)
以下是从标准OS 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}";
...
}
}
答案 2 :(得分:0)
最后,由于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文件中,应将相应的字符串作为{{1}传递给函数。 }。
2)VB6在创建.exe之前不会链接DLL。但是如果DLL没有链接,那么它的功能是不可见的。出于这个原因,必须在IDL文件中包含必须在VB6项目中使用的隐式链接DLL的所有功能。
此外,出于同样的原因,即使在IDL文件中包含所有功能之后,也无法从IDE运行程序(它将崩溃)以进行调试。运行应用程序的唯一方法是创建.exe。