您在对 Luchian Grigore 的回答的评论中将问题的根源描述为:“我希望 DLL 从 exe 文件中导入一些符号”。您在问题文本中还写道,您希望“DLL 在 EXE 文件中找到这些符号。我们希望 DLL 在 EXE 文件中找到这些符号。”
是否从 exe 中导出函数或数据主要是设计问题。通常,仅从 DLL 创建导出。如果EXE 需要向DLL 提供一些信息,它通过参数 提供信息。例如,您在 EXE 中调用某个函数 MyFunc 在 DLL 中实现和导出。作为MyFunc的附加参数,你会得到context指针,它可以直接或间接获取DLL所需的所有EXE信息。
在极少数情况下,您可以从 EXE 中导出数据或函数。例如,您使用DumpBin.exe 实用程序(只需启动“Visual Studio 命令提示符(2010)”即可使用它)来验证 Outlook.exe 是否导出
DumpBin.exe /exports "C:\Program Files\Microsoft Office\Office14\OUTLOOK.EXE"
File Type: EXECUTABLE IMAGE
Section contains the following exports for outlook.exe
00000000 characteristics
4E79B6C8 time date stamp Wed Sep 21 12:04:56 2011
0.00 version
1 ordinal base
66 number of functions
66 number of names
ordinal hint RVA name
1 0 00B58A88 CleanupAddressComponents
2 1 00B58A88 CleanupNameComponents
3 2 00228DC4 DllCanUnloadNow
4 3 004848F8 DllGetClassObject
...
65 40 0038EF30 UpdateContactTracker
66 41 00902788 dwIsLoggingEnabled
我可以解释你如何在没有长时间讨论的情况下实现这个场景,你何时以及是否真的应该这样做。
首先,LIB 文件包含另一种格式为Program Executable (PE) 的OBJ 文件。在编译期间,不同的公共部分将被放置在 OBJ 文件中。非常重要的是,可执行程序(EXE 或 DLL)不仅包含来自代码,而且在 PE 的标头部分中还有许多附加信息。最重要的是
- 导出目录
- 导入目录
- 导入地址表目录
- 基本重定位目录
- 资源目录
您可以使用DumpBin.exe 实用程序(只需启动“Visual Studio 命令提示符(2010)”即可轻松使用它)。要查看有关标头的信息,您可以使用DumpBin.exe /headers my.exe。要查看导出目录的包含,您可以使用DumpBin.exe /exports my.exe 等。
如果您编译导出某些函数或数据的 DLL,则会另外创建 LIB 文件。它是如此命名的导入库。如果您在 EXE 项目中使用 LIB,它使用 DLL 中的某些函数或数据,则链接器将解析外部引用并放置在 EXE 的导入目录中有关应在加载时解析的函数的信息时间。
所以导入库只包含EXE中填写导入目录和导入地址表目录的模板。
一般来说,可以通过同样的方式从EXE中导出函数的一些数据,创建LIB,在DLL项目中使用LIB,并以同样的方式实现从EXE中导入DLL中的一些信息。
我制作了the demo project,它演示了方法。 如果您想从项目中删除所有 LIB 并自行创建,请仔细阅读我回答末尾的编译说明。 ExportFromExe.c的代码(EXE):
//#define CREATE_IMPORT_LIBRARY_ONLY
#include <Windows.h>
EXTERN_C __declspec(dllexport) int someData = 0;
EXTERN_C __declspec(dllexport) int __stdcall myFunc (int x);
EXTERN_C __declspec(dllexport) int __stdcall MyFunc();
int __stdcall myFunc (int x)
{
return x + 10;
}
#ifndef _DEBUG
int mainCRTStartup()
#else
int main()
#endif
{
someData = 5;
#ifndef CREATE_IMPORT_LIBRARY_ONLY
return MyFunc();
#endif
}
MyDll.c(DLL)的代码:
#include <Windows.h>
EXTERN_C __declspec(dllexport) int myData = 3;
EXTERN_C __declspec(dllimport) int someData;
EXTERN_C __declspec(dllimport) int __stdcall myFunc (int x);
#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) int WINAPI MyFunc()
{
return someData + myFunc(myData);
}
为了能够在第一时间成功创建项目,我们必须解决以下问题:“谁先做:先有鸡还是先有蛋?”因为 EXE 项目依赖于 MyDll.lib 而 DLL 项目依赖于 ExportFromExe.lib。对于 EXE 的第一次编译,我们可以从 EXE 项目的链接器设置中临时删除 $(OutDir)MyDll.lib 并定义 CREATE_IMPORT_LIBRARY_ONLY。结果,我们将创建ExportFromExe.exe 和ExportFromExe.lib。在更大的项目中,可以改用链接器的Undefined Symbol Only (/FORCE:UNRESOLVED) 选项。然后我们可以构建MyDll 项目,该项目创建MyDll.dll 和MyDll.lib。现在您可以从 EXE 中删除 CREATE_IMPORT_LIBRARY_ONLY 并将 $(OutDir)MyDll.lib 作为链接器设置(设置的“输入”部分中的“附加依赖项”)。 EXE项目的下一个构建产生最终的解决方案。
我使用了一些小技巧来删除 C-Runtime 并将 EXE 和 DLL 的大小减少到 2.5 或 3 KB。因此,您可以使用DumpBin.exe 的/all 开关来检查来自EXE 和DLL 包括RAW 二进制数据的完整信息。
因为 EXE 返回结果为 ERRORLEVEL,所以您可以在推荐提示符下测试应用程序:
echo %ERRORLEVEL%
0
ExportFromExe.exe
echo %ERRORLEVEL%
18