案例:我正在创建一个应该能够获取某个文件夹中的所有DLL并加载它们的应用程序。这些DLL充当模块,应该能够执行在主应用程序中可能发生或可能不发生的某些任务。
为了允许从我的DLL访问主应用程序,我已将主应用程序的文件夹添加到DLL的其他包含目录中。这可以达到我可以在主应用程序的头文件上调用#include
并使用它的类和函数的程度。
问题:主应用程序头文件中的包含似乎会导致DLL尝试从这些包中访问函数时出现问题。例如:我的主应用程序中有一个“目标”类。这个班有1个包括:
#ifndef D3DX9_INCLUDED
#define D3DX9_INCLUDED
#include <d3dx9.h> // Direct3D 9
#endif
如果我在我的DLL中包含Target.h,我会得到4个相同的错误:
Error 2 error C3861: 'sqrtf': identifier not found c:\program files (x86)\microsoft directx sdk (june 2010)\include\d3dx9math.inl 1585 1 WW
Error 3 error C3861: 'sqrtf': identifier not found c:\program files (x86)\microsoft directx sdk (june 2010)\include\d3dx9math.inl 1717 1 WW
Error 4 error C3861: 'sqrtf': identifier not found c:\program files (x86)\microsoft directx sdk (june 2010)\include\d3dx9math.inl 1862 1 WW
Error 5 error C3861: 'sqrtf': identifier not found c:\program files (x86)\microsoft directx sdk (june 2010)\include\d3dx9math.inl 2032 1 WW
如果我从Target类中删除原始包含,则不再存在错误。 我可以在我的DLL中包含d3dx9而没有问题,但只有当它没有包含在Target类中时。将d3dx9.h直接包含在我的DLL中会产生与上面完全相同的错误。显然这没有用,因为我需要包含Target类和DLL中的某些类和函数。
我是在寻找不同类型的文件而不是模块的DLL吗?在处理DLL时,有什么我应该记住的吗?
如果我忘记添加任何信息,请告诉我,我会尽我所能。 任何帮助将不胜感激。
更新:只使用math.h将DLL拆解到最低限度,并且d3dx9.h包含仍然给我相同的错误。
// dllmain.cpp : Defines the entry point for the DLL application.
#include "stdafx.h"
#include <math.h>
#include <d3dx9.h> // Direct3D 9
BOOL APIENTRY DllMain( HMODULE hModule,
DWORD ul_reason_for_call,
LPVOID lpReserved
)
{
switch (ul_reason_for_call)
{
case DLL_PROCESS_ATTACH:
case DLL_THREAD_ATTACH:
case DLL_THREAD_DETACH:
case DLL_PROCESS_DETACH:
break;
}
return TRUE;
}
答案 0 :(得分:0)
我无法说明您使用行为不当的头文件的原因,尽管从一个没有预编译头的最小示例开始,只包括<windows.h>
,<math.h>
和{ {1}}应该帮助您解决问题。
对于如何允许插件DLL重用主应用程序的功能的更大问题,基本上有三种方法,它们的复杂性和耦合性不同。您可能不希望要求所有未来的插件都使用完全相同的编译器构建,您(或者无法将主应用程序移动到新的编译器,直到所有插件也准备好同时移动)。
<d3dx9.h>
也在EXE中运行。需要对构建选项进行一些调整,以告知链接器创建导入库。所有这些案例都受益于COM程序员熟悉的解耦技术。基本上,API应该只包含三种类型:
关于这些的关键是它们在不同的编译器版本,不同的供应商甚至不同的语言中具有一致的内存布局。有时您需要__declspec(dllexport)
来获得最终的布局控制级别。
我们从COM中学到的另一件事是拥有工厂并让对象通过#pragma pack
虚拟成员函数释放自己的内存。为了支持类似shared_ptr的引用计数,COM使用Release()
和AddRef()
对。这里重要的是,当销毁对象的代码是对象的一部分时,它会自动在与工厂相同的模块中使用内存分配器。
COM不需要的一件事是工厂界面。大多数情况下,简单的工厂功能都足够好。