Win32应用程序插件如何将其DLL加载到自己的目录中 < >我的代码是一个特定应用程序的插件,用Visual Studio 8用C++编写。它使用来自外部提供程序的两个DLL。不幸的是,我的插件无法启动,因为没有找到DLL(我将它们放在与插件本身相同的目录中)
当我手动将DLL移动或复制到主机应用程序目录时,插件可以正常加载。这种移动对于最终用户来说是不可接受的麻烦,我正在寻找一种方法让我的插件透明地加载DLL。我能做什么 有关详情:Win32应用程序插件如何将其DLL加载到自己的目录中 < >我的代码是一个特定应用程序的插件,用Visual Studio 8用C++编写。它使用来自外部提供程序的两个DLL。不幸的是,我的插件无法启动,因为没有找到DLL(我将它们放在与插件本身相同的目录中),dll,winapi,plugins,search-path,Dll,Winapi,Plugins,Search Path,当我手动将DLL移动或复制到主机应用程序目录时,插件可以正常加载。这种移动对于最终用户来说是不可接受的麻烦,我正在寻找一种方法让我的插件透明地加载DLL。我能做什么 有关详情: 主机应用程序插件位于主机应用程序指定的目录中。该目录不在DLL搜索路径中,我无法控制它 插件本身打包为插件目录的子目录,包含插件代码本身,以及与插件相关的任何资源(例如图像、配置文件…)。我控制子目录(称为“bundle”)中的内容,但不控制它的位置 该应用程序的常见插件安装习惯用法是最终用户将插件包复制到插件目录
- 主机应用程序插件位于主机应用程序指定的目录中。该目录不在DLL搜索路径中,我无法控制它
- 插件本身打包为插件目录的子目录,包含插件代码本身,以及与插件相关的任何资源(例如图像、配置文件…)。我控制子目录(称为“bundle”)中的内容,但不控制它的位置
- 该应用程序的常见插件安装习惯用法是最终用户将插件包复制到插件目录
然后使用()将该路径添加到dll搜索路径。您没有要求非常基本的内容。Windows根本不支持您想要的东西 您有一些解决此问题的选项:
- 创建两个DLL。您的插件实现dll,它静态链接到您需要的任何其他dll。和一个简单的“facade”dll,由托管应用程序加载。facade dll先调用SetDllDirectory,然后调用LoadLibrary,以加载具有所需搜索路径的实现dll,然后,对于每个插件导出的函数,它实现一个存根函数,该存根函数使用GetProcAddress直接将调用传递给实现dll
- 放弃并仅使用LoadLibrary(具有显式路径)和GetProcAddress访问附属dll中的功能。痛苦
- 最后一个选项是文档记录最少、windows程序员理解最差的选项。基本上,我们使用windows版本的技术来支持.NET:并行程序集。不要害怕。“并排程序集”只是一个普通的旧dll,但附带一个.manifest文件,该文件提供了一些关于它的额外信息
假设本机代码和您可以使用(而不是任何形式的隐式链接),请使用和查找dll的运行位置
HMODULE hModule = GetModuleHandleW(L"RunningDll.dll");
WCHAR path[MAX_PATH];
GetModuleFileNameW(hModule, path, MAX_PATH);
然后将dll的基本名称替换为要加载的plugin.dll的名称
CString plugin(path);
int pos = plugin.Find(L"RunningDll.dll");
plugin = plugin.Left(pos);
plugin += L"pluginName.dll";
调用生成的字符串。在这种情况下是您的朋友。不久前,我遇到了完全相同的问题,其实很简单。指定链接器(/DELAYLOAD
标志)哪些模块是延迟加载的,基本上它们没有在PE头中作为显式导入列出,因此加载程序在找不到所述模块时不会抱怨,并且来自这些模块的所有函数调用都封装在存根中,以确保加载模块并找到函数
因此,假设您希望延迟加载XmlLite库。首先,在链接器标志中指定
/DELAYLOAD:XmlLite.dll
。然后在模块的初始化函数(最好是DllMain
)中,将XmlLite DLL解包到一个临时文件夹中,然后对其调用LoadLibrary
。从那时起,对XmlLite.dll导出的任何函数的每次调用都将自动解决。这没有多大帮助,因为他不能更改宿主应用程序的代码。据我所知,他可以更改插件dll。他无法更改插件加载的第三方dll。但是由于问题是从他的插件dll加载那些dll,他可以在代码中对此做些什么。你的建议不可行,因为我的代码从来没有启动过。不要从DllMain调用LoadLibrary。From“入口点函数应仅执行简单的初始化或终止任务。它不得调用LoadLibrary或LoadLibraryEx函数(或调用这些函数的函数),因为这可能会在DL中创建依赖项循环
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
<file name="firstrequireddll.dll"/>
<file name="2ndrequireddll.dll"/>
</assembly>
#if _MSC_VER >= 1400 // VS2005 added this directive
#pragma comment(linker, \
"\"/manifestdependency:type='Win32' "\
"name='Company.Product.Subsystem' "\
"version='6.0.0.0' "\
"processorArchitecture='*' "\
"language='*'\"")
#endif
HMODULE hModule = GetModuleHandleW(L"RunningDll.dll");
WCHAR path[MAX_PATH];
GetModuleFileNameW(hModule, path, MAX_PATH);
CString plugin(path);
int pos = plugin.Find(L"RunningDll.dll");
plugin = plugin.Left(pos);
plugin += L"pluginName.dll";