当我的程序打开时,在我的任何代码实际运行之前,它将自动尝试加载其导入的函数的各种DLL。它查看应用程序所在的文件夹,然后查看\ Windows和\ Windows \ System32等几个特定位置。
如果我想使用一些自定义DLL,但我不想用它们混乱应用程序的文件夹,有没有办法将它们安装到子文件夹然后把东西放到EXE中,告诉它在哪里看?
答案 0 :(得分:3)
您必须更改PATH
环境变量。尝试使用SetDllDirectory()
功能。否则,您必须dynamically load your DLLs。
另请参阅this问题,以避免出现更多可能出现的问题。
答案 1 :(得分:3)
这是everything you need to know about DLL search order。请注意不要引入安全问题。如果您搜索不安全的位置,攻击者可以在其中放置恶意DLL并让您的程序加载并执行它。
答案 2 :(得分:1)
我实际上喜欢动态加载的DLLS,并且只有一个包装单元,所以我可以像调用它们一样调用DLL函数。
我通过让每个包装器函数调用我的本地LoadDLLLibrary来避免加载/卸载的性能损失,如下所示:
function LoadDLLLibrary: Boolean;
begin
if MyDLLLib = 0 then
MyDLLLib := LoadLibrary('path to my dll'); // Only load it once.
Result := MyDLLLib <> 0;
end;
每个包装器调用LoadDLLLibrary(实际上只执行一次),然后调用GetProcAddress。就像这样:
procedure DoSomeDLLStuff;
var
DLLProc: TExecuteDoSomeDLLStuffProc;
begin
LoadDLLLibrary;
try
if MyDLLLib <> 0 then
begin
DLLProc := GetProcAddress(MyDLLLib , PROC_SomeDLLSTuff);
DLLProc; // run it
end;
finally
// No need to unload, it'll get unloaded in finalization.
end;
end;
然后在底部......
initialization
MyDLLLib := 0;
finalization
UnLoadDLLLibrary; // Final unload, as we let it stick around instead of freeing it all the time.
end.
所以最终结果是我只加载DLL一次,然后卸载一次。对于动态加载但执行很多的DLL非常方便。
答案 3 :(得分:1)
正如我在对该问题的评论中所说,如果您依赖于静态依赖关系并因此通过Windows加载,那么您将无法使用Windows搜索dll的标准方法。如果您不想永久更改Windows路径,可以尝试从bat / cmd文件运行应用程序,并在启动应用程序之前更改路径。应该限制路径更改的AFAIK(cmd实例的持续时间)开始执行bat / cmd文件。
如果您能够更改为使用动态依赖项(从所需列表中删除bpls?),则可以获得更大的灵活性。与LoadLibrary一样,编译为使用运行时包的bpls也可以动态加载。这是大多数基于delphi bpl的插件系统所依赖的。
(Un)使用(Un)LoadPackage动态加载bpls。 LoadPackage加载由Name参数指定的包(使用SafeLoadLibrary),检查重复单元,并调用包中包含的所有单元的初始化块。
为了确保调用动态加载的bpl中的所有Register过程,您需要使用提供回调函数的GetPackageInfo调用来枚举单元。
BTW:代码示例摘自2001年大会期间Mark Miller(CodeRush的开发人员/架构师)在动态应用程序研讨会期间开发的插件系统。代码曾经在线,但我再也找不到了......var
localModuleHandle: HModule;
begin
try
localModuleHandle := LoadPackage(packageName);
//GetPackageInfo accesses the given package's info table and enumerates
// all the contained units and required packages
Flags := ufAllUnits;
GetPackageInfo(localModuleHandle, Pointer(localModuleHandle), Flags, PackageIsLoadingProc);
except
on e: Exception do
Application.MessageBox(PChar(e.Message), PChar(sError), MB_OK + MB_ICONWARNING);
end;
end;
procedure PackageIsLoadingProc(const Name: string; NameType: TNameType;
Flags: Byte; Param: Pointer);
type
TRegisterProc = procedure;
var
RegisterProc: TRegisterProc;
localName: String;
begin
// Flags:
// ufMainUnit = $01;
// ufPackageUnit = $02;
// ufWeakUnit = $04;
// ufOrgWeakUnit = $08;
// ufImplicitUnit = $10;
// ufWeakPackageUnit = ufPackageUnit or ufWeakUnit;
if NameType = ntContainsUnit then
begin
localName := LowerCase(Name);
if Length(localName) > 0 then
localName[1] := UpCase(localName[1]);
@RegisterProc := GetProcAddress(HModule(Param),
PChar('@' + localName + '@Register$qqrv'));
if @RegisterProc <> nil then
RegisterProc;
end;
end;