我需要将一组符号从一个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/

10-12 17:59