As I said in my comments to the question, if you are relying on static dependencies and thus loading by Windows, then you are stuck with using the standard ways in which Windows searches for dlls. And if you do not want to change the windows' path permanently, you could try running your app from a bat/cmd file and change the path just before starting your app. AFAIK that should limit the change of the path to the (duration of the) cmd instance started to execute the bat/cmd file.
More flexibility can be obtained though if you are able to change to using dynamic dependencies (remove your bpls from the required list?). As with LoadLibrary, bpls compiled to use runtime packages can be loaded dynamically as well. It is what most delphi bpl based plugin systems rely on.
(Un)Loading bpls dynamically is done using (Un)LoadPackage. LoadPackage loads the package specified by the Name parameter (using SafeLoadLibrary), checks for duplicate units, and calls the initialization blocks of all units contained in the package.
To make sure all Register procedures in a dynamically loaded bpl are called, you need to enumerate the units using a GetPackageInfo call providing a call back function.
BTW: Code samples are excerpts from a plugin system developed during a dynamic applications workshop by Mark Miller (CodeRush's developer/architect) during a 2001 conference. The code used to be online, but I can no longer find it there...
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;