qdi*_*dii 4 c++ dll linker visual-studio
我的一个朋友在创建DLL时会遇到一堆错误.Visual Studio抱怨未解析的外部符号.我主要是一个Unix用户,所以我可能会在那里弄错.在Unix上,当您创建静态库(存档)时,它不会将不同的目标文件连接到存档文件中.我希望动态对象以相同的方式创建,但显然会发生额外的链接阶段.
第一个问题:为什么dll存在链接阶段?
在这种情况下,DLL indeeds包含未定义的符号,因为我们希望DLL在EXE文件中找到这些符号.这与典型的DLL行为完全相反,其中EXE使用DLL中定义的符号.为了清楚起见,我希望在DLL加载到内存中时能够找到这些符号.
第二个问题:如何使DLL使用EXE文件中定义的符号?
编辑: 我重新提出了问题,因为我认为我没有明确说明问题.
Ole*_*leg 11
您将问题的根源描述为:"我希望DLL从exe文件中导入一些符号"在评论中输入Luchian Grigore的答案.您在问题的文本中另外写了"DLL要在EXE文件中找到这些符号.我们希望DLL在EXE文件中找到这些符号."
大多数是设计问题是否从exe导出函数或数据.通常只能从DLL创建导出.如果EXE需要向DLL提供一些信息,它会通过参数提供信息.例如,您在EXE中调用了一些MyFunc在DLL中实现和导出的函数.作为附加参数MyFunc你得到的context指针可以直接或间接获得所需的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
Run Code Online (Sandbox Code Playgroud)
我可以解释一下如何在没有长时间讨论的情况下实现场景,何时以及是否真的应该这样做.
首先,LIB文件包含OBJ文件,其另一种格式为Program Executable(PE).在编译期间,不同的公共部分将放在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中的一些信息的方式.
我制作了演示项目,演示了这种方式.如果您想从项目中删除所有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
}
Run Code Online (Sandbox Code Playgroud)
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);
}
Run Code Online (Sandbox Code Playgroud)
为了能够在第一时间成功创建项目,我们必须解决问题:"谁是第一个:鸡还是鸡蛋?" 因为EXE项目依赖于MyDll.lib而DLL项目依赖于ExportFromExe.lib.对于EXE的第一次编译,我们可以$(OutDir)MyDll.lib从EXE项目的链接器设置中删除temoprary 并定义CREATE_IMPORT_LIBRARY_ONLY.结果我们将创造ExportFromExe.exe和ExportFromExe.lib.在更大的项目中,可以使用Undefined Symbol Only (/FORCE:UNRESOLVED)链接器选项.然后我们可以建立MyDll创建MyDll.dll和的项目MyDll.lib.现在您可以CREATE_IMPORT_LIBRARY_ONLY从EXE中删除并包含$(OutDir)MyDll.lib为链接器设置("输入"部分设置中的"附加深度").EXE项目的下一个版本将产生最终解决方案.
我使用了一些小技巧来删除C-Runtime并将EXE和DLL的大小减小到2,5或3 KB.因此,您可以使用/allswitch DumpBin.exe来检查EXE和DLL包含RAW二进制数据的完整信息.
因为EXE返回结果为ERRORLEVEL,所以您可以在推荐提示中测试应用程序:
echo %ERRORLEVEL%
0
ExportFromExe.exe
echo %ERRORLEVEL%
18
Run Code Online (Sandbox Code Playgroud)