![]() |
Packages in anderem Verzeichnis
Hallo zusammen,
ich habe eine „einfache“ Frage und komme nicht so recht weiter mit all dem, was ich bisher dazu gefunden habe: Mein Programm verwendet Packages, eingebunden über die Programmoptionen. Gibt es eine Möglichkeit, beim Programmstart Code auszuführen - vermutlich in der dpr-Datei - bevor versucht wird, diese Packages (bpl) zu laden? Wo muss der Code dann hin? Hintergrund meiner Frage: Ich möchte mein Programmverzeichnis gerne „sauber“ halten, also nicht viele libraries/packages dort unterbringen. dort sollten sich nur die paar Dateien befinden, die ausschließlich zum Progamm gehören (also .exe, .ini, .db zum Beispiel). Dazu möchte ich gerne die bpl-Dateien in ein Unterverzeichnis packen und vor deren Laden den Windows-Pfad entsprechend anpassen - und beim Entladen wieder zuück. Habe dazu eine interessante dll gefunden ![]() Wo packe ich also den Code zum Anpassen der Path-Variablen hin?
Delphi-Quellcode:
hier irgendwo?
begin
Application.Initialize; Application.MainFormOnTaskbar := True; Application.CreateForm(TformMain, formMain); Application.Run; end. Oder in das initialization einer eigenen unit, die ich dann als erstes einbinde? Leider weiß ich zu wenig, wie ein Programmstart intern abläuft, um das richtig zu verstehen. Für jeden Hinweis dankbar Harald |
AW: Packages in anderem Verzeichnis
Hi, very interesting problem !
I spent almost two hours testing different approaches and ... Zitat:
One approach i tested is to add a DLL that will change set the PATH variable with SetEnvironmentVariable, the DLL worked fine right after loading by the OS, but ... it seems the OS loads few DLLs in bulk then after that start to call them, if it hit missed one it will stop and unload the loaded ones, so that DLL was loaded but no called, i mean DllMain not called. Also patched the binary to make sure it is the first to be in the Import Table, and yes the OS tried and loaded it first but didn't call DllMain, even it loaded few more DLL, non being executed, so this was not a solution. Zitat:
There is few ways to do this, but all are ugly !! 1) Use batch file to execute your EXE, with : Zitat:
![]() Also here i am not sure if the the same PATH value will work, i mean passing this "YOUR_PACKAGE_PATH;%PATH%" to SetEnvironmentVariable, so to be on the safe side i would read PATH value first with GetEnvironmentVariable, then append the path then call SetEnvironmentVariable, this before CreateProcess (or any other executing calls that works) 3) Move your EXE to the same package directory, and leave a shortcut !! :duck: Hope that helps, or may be someone else might have ideas to entertain. |
AW: Packages in anderem Verzeichnis
Eine weitere Möglichkeit wäre kleines Vorschalt-Programm, das das eigentliche Programm aufruft. Dieses eigentliche Programm liegt dann im gleichen Ordner wie die BPLs. Also quasi dasselbe wie eine Verknüpfung, wie Kas Ob es vorgeschlagen hat, aber flexibler.
Wir benutzen sowas intern, um aus Unterordnern jeweils die neueste Version eines Programms aufzurufen:
Code:
Hintergrund: So kann man eine neue Programmversion releasen, wenn die alte noch irgendwo in Benutzung ist und deshalb nicht ersetzt werden kann.
Pfad\zum\Programm\
Version_1.0.0\ Version_1.0.1\ Version_1.2.0\ Version_1.3.5\ Vorschaltprogramm.exe |
AW: Packages in anderem Verzeichnis
Liste der Anhänge anzeigen (Anzahl: 1)
Still lingering in my head and i think i found more elegant solution :cheer:
This involve utilizing Windows Application Registration ![]() In short the steps are: 1) add a key in the registry with your EXE name to this path Zitat:
Code:
and at last add the PATH value
(default) REG_SZ D:\Projects Delphi\DelphiRuntime\Win32\Debug\DelphiRuntimeTest.exe
Code:
and that is it !!
PATH REG_SZ D:\Projects Delphi\DelphiRuntime\Win32\Debug;D:\Program Files (x86)\Embarcadero\Studio\16.0\bin
I tested it and it worked perfectly, thoughts on this: 1) For some reason, yet i don't understand it works fine with HKEY_LOCAL_MACHINE but didn't work with HKEY_CURRENT_USER on my OS, yet again my OS is %$#%$ the least, i heavily tweaked many things about paths and users, specially my user, so it might work for you with HKEY_CURRENT_USER. 2) Here how the registry entries look like Anhang 57141 3) Not sure about adding the current directory in my case above "D:\Projects Delphi\DelphiRuntime\Win32\Debug", most likely it is not needed. Hope that helps. |
AW: Packages in anderem Verzeichnis
OK, with the registry trick above, it works only with ShellExecute, with the debugger executing the application with CreateProcess will not work.
If you run the exe using Windows Explorer then it is fine and the DLL will be found and loaded, but other executing method might not work ! |
AW: Packages in anderem Verzeichnis
![]() Side-by-Side Manifest (SxS) : <PackageDependency> in <Dependencies> bekannte Libraries : HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Session Manager\KnownDLLs oder, was eben über die Standard-Suchpfade zu finden ist, welches diese Unterverzeichnisse nunmal nicht beinhaltet. und ![]() ![]() gehen halt erst zur Laufzeit und demnach nur beim dynamischen Laden |
AW: Packages in anderem Verzeichnis
erst einmal Euch allen ein dickes Danke! Es ist wirklich großartig, hier solche engagierte und kompetente Hilfe zu erhalten :-)
Nun, die Überlegungen von Kas Ob. sind sehr interessant und haben mir ein wenig Einblick in die Funktionsweise einer exe und Windows gegeben. Ich fürchte, dass ich das aber nicht tun kann, weil ich die Zielsysteme nicht so weit manipulieren möchte. Mein Programm soll eigentlich kaum einen Hinweis auf sich im System, in der Registry hinterlassen - und da ist das Ändern der Path-Variablen schon mehr als eigentlich gewollt. Danke dennoch für die interessanten Ideen, die ich sicherlich für mich weiterverfolgen werde. Spannend finde ich den Vorschlag von Herrn Müller (dummzeuch), der auch noch andere Vorteile hätte, wie er schreibt. Das werde ich mir genauer ansehen. Einziger Wermutstropfen ist, dass meine Programmstruktur noch komplizierter wird. Aber da das mit den bpl-Dateien und manchen eigenen dll-Dateien eh schon nicht einfach ist, macht das wohl auch nicht mehr viel aus. Rein verständnishalber würde mich noch die Idee mit dem
Code:
interessieren. Wenn ich über die Programmoptionen ein Package einbinde, dann ist das wohl statisch. Das Programm wird mit diesem Package kompiliert und alles aus dem Package ist dann statisch eingebunden. Die Exe-Datei wird kleiner und ich muss nichts irgendwo extra deklarieren. Wenn ich ein Package mit LoadPackage einbinde, wie funktioniert das dann mit dem Verwenden der Routinen und Classen des Packages? Muss ich dann ähnlich wie bei LoadLibrary erstmal alle Routinen und Klassen extra deklarieren, oder kann ich die Unit aus dem Package einfach so wie beim statischen Einbinden nutzen. Damit hab ich mich bisher überhaupt nicht beschäftigt und verstehe das mit den Packages gar nicht.
LoadPackage
Also nochmal vielen Dank Euch allen und viele Grüße Harald |
AW: Packages in anderem Verzeichnis
Zitat:
|
AW: Packages in anderem Verzeichnis
Mit LoadPackage kann man zur Laufzeit weitere Packages einbinden, die für die Funktion optional sind. So, wie die IDE das für Package-basierte Plugins und auch mit den Designtime-Packages der Komponenten macht.
Ich habe mal eine Zeit lang damit geliebäugelt, das für unsere internen Programme zur Modularisierung zu verwenden, aber da die Voraussetzung ist, dass man die Delphi RTL und VCL ebenfalls als Packages einbinden muss, habe ich wieder davon abgesehen. Da Du aber sowieso mit Runtime-Packages arbeitest, wäre das eine Option. |
AW: Packages in anderem Verzeichnis
LoadPackage will not be much of a help here, as itself (LoadPackage) does exist within RTLxxx.BPL, so even if you managed to change you application and remove all the designtime packages from the IDE designer for all the auto-created forms/frames/modules you still will have trouble to handle RTLxxx.BPL and most likely VCLxxx.BPL with fewer others.
There is other solution i didn't mention before, but because you are interested i will explain it, but before that i will include this small loader, that works perfectly everywhere (i hope) with any adjustment to OS settings, namely the path in environment:
Delphi-Quellcode:
The other solution is to look and understand how packers works, namely UPX for the easy understanding.
program Loader;
// This application is VCL application and not console/cmd, we don't need the console window to pop every time and scare everyone!! uses Windows; {$R *.res} const APPLICATION_EXE_NAME = 'DelphiRuntimeTest.exe'; APPLICATION_EXTRA_COMMANDLINE = ''; APPLICATION_PATH_TO_ADD ='D:\Program Files (x86)\Embarcadero\Studio\16.0\bin'; procedure SetPathAndRun; var si: TStartupInfo; pi: TProcessInformation; Path:string; PathLen:Integer; // length in characters begin // adjust the path PathLen := GetEnvironmentVariable('PATH',nil,0); SetLength(Path,PathLen); GetEnvironmentVariable('PATH',@Path[1],PathLen); Path := APPLICATION_PATH_TO_ADD +';'+Path; // we add out path first to skip handling the null terminator SetEnvironmentVariable(PChar('PATH'), PChar(Path)); //SetEnvironmentVariable(PChar('PATH'), PChar(APPLICATION_PATH_TO_ADD+';%PATH%')); // this might be enough though, instead of all above // run and don't wait ZeroMemory(@si,SizeOf(si)); //si := Default(TStartupInfo); // ZeroMem for old Delphi versions si.cb := sizeof(si); CreateProcess(PChar(APPLICATION_EXE_NAME), // EXE Name with or without path PChar(GetCommandLine + APPLICATION_EXTRA_COMMANDLINE), // this will pass the same command line to the exe with the extra nil, nil, False, 0, nil, nil, si, pi); end; begin SetPathAndRun; // will run the exe and exit without waiting end. UPX is executable packer, that strip and compress sections ... bla bla, we care about one thing here, how it does handle the import table, UPX strip/remove the functions leaving only one from each statically loaded/imported DLL, then when it is unpacking the exe it does resolve the rest, from its own stored and compressed table. The reason to strip them all, because that table is not optimized on byte level, and might be big, but that is irrelevant as UPX tries to squeeze space every where it can, the question is why it does leave one ? The answer is: for two reasons first security, it doesn't want to irritate AV(security analyzing software) more than needed, and secondly to keep the OS behavior consistent when loading and handling DLL, so it doesn't go to full length and loaded the libraries on its own and resolve the import addresses, this for compatibility and also will keep the unpacker code as small as it could be. What can be done here is: UPX is on GitHub with license GPL-2, but it does some changes, we need to remove the one imported function and replace them with your slightly adjusted table. This solution should work, but the work and changes could be not-so-practical. Anyway, wrote this as food for thought. |
Alle Zeitangaben in WEZ +1. Es ist jetzt 04:19 Uhr. |
Powered by vBulletin® Copyright ©2000 - 2025, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024-2025 by Thomas Breitkreuz