我需要将一组符号从一个DLL转发到另一个(以支持某些版本控制方案PEP 384,如果您想知道的话)。它对功能正常工作;我写了一个模块定义文件,说
LIBRARY "python3"
EXPORTS
PyArg_Parse=python32.PyArg_Parse
PyArg_ParseTuple=python32.PyArg_ParseTuple
PyArg_ParseTupleAndKeywords=python32.PyArg_ParseTupleAndKeywords
[...]
但是,它对数据失败。如果我说
PyBaseObject_Type=python32.PyBaseObject_Type
则链接器会提示PyBaseObject_Type是无法解析的符号,即使它实际上是从python32.dll导出的也是如此。在查看导入库时,我注意到,对于数据,只有
_imp__
符号,因此我尝试了PyBaseObject_Type=python32._imp__PyBaseObject_Type
链接器现在实际上确实创建了一个DLL,但是,在该DLL中,转发转到
_imp__
符号,该符号随后在运行时无法解析。我还尝试将DATA放入行中(带或不带_imp__
);这没有什么区别。IIUC,转发数据应该可以正常工作,因为对于任何DLL导入程序,该数据都声明为
__declspec(dllimport)
,因此编译器应正确解释引用。因此:如何生成进行数据转发的DLL?
最佳答案
在我看来,从主DLL(保存数据的DLL)导出数据期间,使用DATA的解决方案是而不是。
要重现我的意思,您可以创建一个具有DllDataForward.c的项目:
#include <Windows.h>
EXTERN_C __declspec(dllexport) int myData = 5;
#ifndef _DEBUG
EXTERN_C BOOL WINAPI _DllMainCRTStartup (HINSTANCE hinstDLL, DWORD fdwReason,
LPVOID lpvReserved)
#else
BOOL WINAPI DllMain (HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
#endif
{
if (fdwReason == DLL_PROCESS_ATTACH)
DisableThreadLibraryCalls(hinstDLL);
return TRUE;
UNREFERENCED_PARAMETER (lpvReserved);
}
EXTERN_C __declspec(dllexport) BOOL WINAPI MyFunc()
{
return TRUE;
}
和DllDataForward.def:
LIBRARY "DllDataForward"
EXPORTS
myData
MyFunc
通常,将使用“myData DATA”而不是“myData”。
然后,您可以创建一个ForwardingDll.c:
#include <Windows.h>
#ifndef _DEBUG
EXTERN_C BOOL WINAPI _DllMainCRTStartup (HINSTANCE hinstDLL, DWORD fdwReason,
LPVOID lpvReserved)
#else
BOOL WINAPI DllMain (HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
#endif
{
if (fdwReason == DLL_PROCESS_ATTACH)
DisableThreadLibraryCalls(hinstDLL);
return TRUE;
UNREFERENCED_PARAMETER (lpvReserved);
}
使用ForwardingDll.def:
LIBRARY "ForwardingDll"
EXPORTS
myNewData=DllDataForward.myData DATA
MyNewFunc=DllDataForward.MyFunc
您应该包括在编译DllDataForward时创建的导入库DllDataForward.lib,作为在ForwardingDll.dll构建过程中链接器的输入。这样的导入库可以成功使用,您将收到ForwardingDll.dll。
dumpbin.exe ForwardingDll.dll /EXPORTS
产生作为输出
...
ordinal hint RVA name
1 0 MyNewFunc (forwarded to DllDataForward.MyFunc)
2 1 myNewData (forwarded to DllDataForward.myData)
...
使用DllDataForward.lib的简单测试应用程序构建仅具有源test.c:
#include <Windows.h>
#include <stdio.h>
#include <tchar.h>
EXTERN_C __declspec(dllimport) int myNewData;
EXTERN_C __declspec(dllimport) BOOL WINAPI MyNewFunc();
int main()
{
BOOL isSuccess = MyNewFunc();
int i=myNewData;
_tprintf (TEXT("i=%d\nisSuccess=%s\n"),
i, isSuccess? TEXT("TRUE"): TEXT("FALSE"));
}
产生作为输出
i=5
isSuccess=TRUE
更新了:我想添加一些更多信息为什么使用DEF文件中的“myData DATA”而不是“myData”起到了作用,以及如何使用建议使用现有的DLL 这样的技巧python32.dll 在python32.dll中没有任何更改,也没有重新编译它。我将显示原始python32.lib缺少所有数据变量(如
PyBaseObject_Type
)的导出。我将展示如何创建一个额外的python32.lib ,它确实带有我们需要的数据符号。首先,我想清除在DEF文件中从“myData DATA”更改为“myData”之后在导入库中进行的更改。首先,让我们使用包含“myData DATA”的DEF文件编译DllDataForward.dll,然后在导入库DllDataForward.LIB的内部进行查看:
dumpbin.exe DllDataForward.lib /all >%TEMP%\DllDataForward-lib.txt
notepad %TEMP%\DllDataForward-lib.txt
我们将看到该库具有 6个公共(public)符号:
224 __IMPORT_DESCRIPTOR_DllDataForward
46A __NULL_IMPORT_DESCRIPTOR
5A8 DllDataForward_NULL_THUNK_DATA
776 __imp__myData
708 _MyFunc@0
708 __imp__MyFunc@0
接下来,将DEF文件从“myData DATA”更改为“myData”,创建dll和导入库,并在其中再查找一次。我们将看到,现在导入库具有 7 (!!!)而不是6个公共(public)符号:
23A __IMPORT_DESCRIPTOR_DllDataForward
480 __NULL_IMPORT_DESCRIPTOR
5BE DllDataForward_NULL_THUNK_DATA
78C __imp__myData
78C _myData
71E _MyFunc@0
71E __imp__MyFunc@0
因此,对于具有“myData DATA”的DEF文件的使用存在问题,因为创建的导入库不包含公共(public)符号
_myData
。我们可以使用具有“myData DATA”的正确DLL,并创建和另一个第二个导入库,该库手动导出
_myData
。我们不会在DllDataForward.dll中进行任何更改,只需手动进行更改和其他lib。为此,我们根据
dumpbin.exe DllDataForward.dll /exports
转储DllDataForward.dll的导出。我们会看到:...
ordinal hint RVA name
1 0 00001020 MyFunc = _MyFunc@0
2 1 00003000 myData = _myData
...
现在,我们仅根据
dumpbin.exe DllDataForward.dll /exports
的输出在另一个目录中创建新的DllDataForward.def 文件:LIBRARY "DllDataForward"
EXPORTS
myData = _myData
接下来使用命令
lib.exe /DEF:DllDataForward.def /OUT:DllDataForward.lib /MACHINE:X86
我们创建第二个
DllDataForward.lib
(在另一个目录中,原始DllDataForward.lib
)。现在,我们可以使用两个 DllDataForward.lib
编译ForwardingDll.dll ,并接收所需的DLL。 Test.exe将显示该批处理工作。与检查当前版本3.2a3中的python32.lib完全相同:
dumpbin.exe "C:\Program Files\Python32\libs\python32.lib" /all >python32-lib.txt
notepad python32-lib.txt
我们将找出以下几行(大约在文件开头)
1957 public symbols
…
1BCCC _PyArg_Parse
1BCCC __imp__PyArg_Parse
…
1BFF6 __imp__PyBaseObject_Type
…
我们也可以用
dumpbin C:\Windows\system32\python32.dll /exports >%TEMP%\python32-exports.txt
notepad %TEMP%\python32-exports.txt
符号
PyBaseObject_Type
将被导出为 14 D 001DD5D0 PyBaseObject_Type
因此,我们可以从python32.def文件中创建其他python32.lib
LIBRARY "python32"
EXPORTS
PyBaseObject_Type
使用
lib /DEF:python32.def /OUT:python32.lib /MACHINE:X86
现在您可以定义DLL的DEF
LIBRARY "python3"
EXPORTS
PyArg_Parse=python32.PyArg_Parse
PyArg_ParseTuple=python32.PyArg_ParseTuple
PyArg_ParseTupleAndKeywords=python32.PyArg_ParseTupleAndKeywords
PyBaseObject_Type=python32.PyBaseObject_Type DATA
就像您最初想要的一样,但是我们将同时使用和“C:\Program Files\Python32\libs\python32.lib”和我们在链接期间创建的第二个小python32.lib。
我自己不使用python,也不知道
PyBaseObject_Type
的大小,但是如果我将其声明为int
,EXTERN_C __declspec(dllimport) int PyBaseObject_Type;
我可以验证
PyBaseObject_Type
的第一部分是否为1。它可以正常工作!抱歉,冗长的答案,并感谢所有阅读我所有的答案直到这个地方的人。
关于dll - 在DLL中转发数据,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/4060143/