我需要将一组符号从一个DLL转发到另一个DLL(如果你想知道的话,支持一些版本控制方案,PEP 384).它适用于各种功能; 我写了一个模块定义文件,说
LIBRARY "python3"
EXPORTS
PyArg_Parse=python32.PyArg_Parse
PyArg_ParseTuple=python32.PyArg_ParseTuple
PyArg_ParseTupleAndKeywords=python32.PyArg_ParseTupleAndKeywords
[...]
Run Code Online (Sandbox Code Playgroud)
但是,数据失败了.如果我说
PyBaseObject_Type=python32.PyBaseObject_Type
Run Code Online (Sandbox Code Playgroud)
然后链接器抱怨PyBaseObject_Type是一个未解析的符号,即使它实际上是从python32.dll导出的.看一下导入库,我注意到,对于数据,只有_imp__符号,所以我试过了
PyBaseObject_Type=python32._imp__PyBaseObject_Type
Run Code Online (Sandbox Code Playgroud)
链接器现在实际上创建了一个DLL,但是,在此DLL中,转发转到_imp__符号,然后在运行时无法解析.我也尝试将DATA放入线路(有或没有_imp__); 这没有什么区别.
IIUC,转发数据应该可以正常工作,因为数据是__declspec(dllimport)针对DLL的任何导入器声明的,因此编译器应该正确解释引用.
那么:我如何生成一个执行数据转发的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;
}
Run Code Online (Sandbox Code Playgroud)
和DllDataForward.def:
LIBRARY "DllDataForward"
EXPORTS
myData
MyFunc
Run Code Online (Sandbox Code Playgroud)
通常一个将使用"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);
}
Run Code Online (Sandbox Code Playgroud)
与ForwardingDll.def:
LIBRARY "ForwardingDll"
EXPORTS
myNewData=DllDataForward.myData DATA
MyNewFunc=DllDataForward.MyFunc
Run Code Online (Sandbox Code Playgroud)
您应该在构建ForwardingDll.dll期间包含在编译DllDataForward期间创建的导入库DllDataForward.lib作为链接器的输入.这样的导入库可以成功使用,您将收到ForwardingDll.dll.
dumpbin.exe ForwardingDll.dll /EXPORTS
Run Code Online (Sandbox Code Playgroud)
产生作为输出
...
ordinal hint RVA name
1 0 MyNewFunc (forwarded to DllDataForward.MyFunc)
2 1 myNewData (forwarded to DllDataForward.myData)
...
Run Code Online (Sandbox Code Playgroud)
使用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"));
}
Run Code Online (Sandbox Code Playgroud)
产生作为输出
i=5
isSuccess=TRUE
Run Code Online (Sandbox Code Playgroud)
更新:我想添加更多信息为什么在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
Run Code Online (Sandbox Code Playgroud)
我们将看到lib有6个公共符号:
224 __IMPORT_DESCRIPTOR_DllDataForward
46A __NULL_IMPORT_DESCRIPTOR
5A8 DllDataForward_NULL_THUNK_DATA
776 __imp__myData
708 _MyFunc@0
708 __imp__MyFunc@0
Run Code Online (Sandbox Code Playgroud)
接下来将DEF文件从"myData DATA"更改为"myData",创建dll和导入库并再次查看其内部.我们将看到导入库现在有7个(!!!)而不是6个公共符号:
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
Run Code Online (Sandbox Code Playgroud)
因此,我们在使用具有"myData DATA"的DEF文件时遇到问题,因为创建的导入库不包含公共符号_myData.
我们可以使用具有"myData DATA" 的正确 DLL,并创建另一个_myData手动导出的第二个导入库.我们不会对DllDataForward.dll进行任何更改,只需手动创建和使用其他库.
为此,我们转储DllDataForward.dll的导出dumpbin.exe DllDataForward.dll /exports.我们会看到:
...
ordinal hint RVA name
1 0 00001020 MyFunc = _MyFunc@0
2 1 00003000 myData = _myData
...
Run Code Online (Sandbox Code Playgroud)
现在我们创建一个新的DllDataForward.def在其他目录下的文件仅在输出基础的dumpbin.exe DllDataForward.dll /exports:
LIBRARY "DllDataForward"
EXPORTS
myData = _myData
Run Code Online (Sandbox Code Playgroud)
接下来使用命令
lib.exe /DEF:DllDataForward.def /OUT:DllDataForward.lib /MACHINE:X86
Run Code Online (Sandbox Code Playgroud)
我们创建了第二个DllDataForward.lib(在另一个目录中创建了原始文件DllDataForward.lib).现在我们可以使用两个 编译ForwardingDll.dll DllDataForward.lib并接收我们需要的DLL.Test.exe将显示批准工作.
完全以同样的方式检查当前版本3.2a3中的python32.lib:
dumpbin.exe "C:\Program Files\Python32\libs\python32.lib" /all >python32-lib.txt
notepad python32-lib.txt
Run Code Online (Sandbox Code Playgroud)
我们将找到以下行(约在文件的开头)
1957 public symbols
…
1BCCC _PyArg_Parse
1BCCC __imp__PyArg_Parse
…
1BFF6 __imp__PyBaseObject_Type
…
Run Code Online (Sandbox Code Playgroud)
我们也可以验证
dumpbin C:\Windows\system32\python32.dll /exports >%TEMP%\python32-exports.txt
notepad %TEMP%\python32-exports.txt
Run Code Online (Sandbox Code Playgroud)
符号PyBaseObject_Type将导出为
14 D 001DD5D0 PyBaseObject_Type
Run Code Online (Sandbox Code Playgroud)
所以我们可以从python32.def文件创建额外的python32.lib
LIBRARY "python32"
EXPORTS
PyBaseObject_Type
Run Code Online (Sandbox Code Playgroud)
运用
lib /DEF:python32.def /OUT:python32.lib /MACHINE:X86
Run Code Online (Sandbox Code Playgroud)
现在您可以定义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
Run Code Online (Sandbox Code Playgroud)
就像你想要的,可是我们将使用两个 "C:\ Program Files文件\ Python32 \库\ python32.lib",而我们在连接过程中产生的小秒针python32.lib.
我自己不使用python而且不知道它的大小PyBaseObject_Type,但如果我将其声明为int
EXTERN_C __declspec(dllimport) int PyBaseObject_Type;
Run Code Online (Sandbox Code Playgroud)
我可以验证第一部分PyBaseObject_Type是1.它有效!
对于那些读完所有答案直到这个地方的所有人,我们很抱歉.
| 归档时间: |
|
| 查看次数: |
2771 次 |
| 最近记录: |