![]() |
ShareMem ohne ShareMem.dll und Co.
Liste der Anhänge anzeigen (Anzahl: 1)
Hier habt ihr noch ein kleines "Abfallprodukt" meines
![]() Es schleift praktisch jeden Speichermanager von einer Delphi-EXE in eine Delphi-DLL durch. Dabei ist es egal, ob nun der Standard-SpeicherManager verwendet wird oder ein Anderer. Und es wird auch keine zusätzliche Datei benötigt, wie es bei ![]() Systemvorausstzung: die DLL (bzw. die himiSM.pas) benötigt mindestens ein Delphi, wo TMemoryManagerEx verfügbar ist und die EXE sollte vermutlich mindestens mit Delphi 4 erstellt werden. Diese Unit muß in die DLL aufgenommen werden: > erster Uses-Eintrag in deren .DPR
Delphi-Quellcode:
Und zum Laden der DLL wird dann "einfach" nur noch statt LoadLibrary das LoadLibrarySM verwendet :mrgreen:
Unit himiSM_DLLInit;
Interface Implementation {$WARN SYMBOL_DEPRECATED OFF} Uses Windows; Var Name: Array[0..29] of AnsiChar = 'himiShareMem_xxxxxxxxxxxxxxxx'#0; i, i2: Integer; Map: THandle; View: PAnsiChar; MemMgr: TMemoryManager; MemMgrEx: TMemoryManagerEx; OldMemMgr: TMemoryManagerEx; Initialization GetMemoryManager(OldMemMgr); i2 := GetCurrentProcessId; For i := 15 downto 0 do Begin If Byte(i2 and $0F) <= 9 Then Name[i + 13] := AnsiChar((i2 and $0F) + Ord('0')) Else Name[i + 13] := AnsiChar((i2 and $0F) - 10 + Ord('A')); i2 := i2 shr 4; End; Map := OpenFileMappingA(FILE_MAP_READ, False, @Name); View := MapViewOfFile(Map, FILE_MAP_READ, 0, 0, 0); If (Map <> 0) and Assigned(View) Then If Assigned(PPointer(View + 3 * SizeOf(Pointer))^) Then Begin CopyMemory(@MemMgrEx, View, SizeOf(MemMgrEx)); SetMemoryManager(MemMgrEx); End Else Begin CopyMemory(@MemMgr, View, SizeOf(MemMgr)); SetMemoryManager(MemMgr); End; UnmapViewOfFile(View); CloseHandle(Map); Finalization SetMemoryManager(OldMemMgr); End.
Delphi-Quellcode:
Function LoadLibrarySM(LibFileName: PChar): HMODULE;
Var Name: Array[0..29] of AnsiChar; i, i2: Integer; Map: THandle; View: PAnsiChar; MemMgr: {$IF Declared(TMemoryManagerEx)}TMemoryManagerEx{$ELSE}TMemoryManager{$IFEND}; Error: HRESULT; Begin Error := ERROR_INVALID_FUNCTION; Name := 'himiShareMem_xxxxxxxxxxxxxxxx'#0; i2 := GetCurrentProcessId; For i := 15 downto 0 do Begin If Byte(i2 and $0F) <= 9 Then Name[i + 13] := AnsiChar((i2 and $0F) + Ord('0')) Else Name[i + 13] := AnsiChar((i2 and $0F) - 10 + Ord('A')); i2 := i2 shr 4; End; Map := CreateFileMappingA(INVALID_HANDLE_VALUE, nil, FILE_MAP_READ, 0, 6 * SizeOf(Pointer), @Name); View := MapViewOfFile(Map, FILE_MAP_READ or FILE_MAP_WRITE, 0, 0, 0); _DLL := 0; Try If (Map <> 0) and Assigned(View) Then Begin GetMemoryManager(MemMgr); ZeroMemory(View, 6 * SizeOf(Pointer)); CopyMemory(View, @MemMgr, SizeOf(MemMgr)); Result := LoadLibrary(LibFileName); Error := GetLastError; End Else Begin Result := 0; Error := ERROR_ACCESS_DENIED; End; Finally UnmapViewOfFile(View); CloseHandle(Map); SetLastError(Error); End; End; Info: Es macht übrigens auch nichts aus, wenn in einem von Beiden (EXE und DLL) keiner der Codes eingebaut ist ... in diesem Falls wird einfach nur keine Umleitung eingerichtet. Also wenn die DLL mit deim "einfachen" LoadLibrary geladen wird oder die DLL den Code nicht enthält. Anhang: himiSM_DLLInit.pas * » * kommt in die DLL himiSM_LoadLibrary.pas * » * kommt in die EXE (oder eine andere DLL) und enthällt die LoadLibrarySM |
Re: ShareMem ohne ShareMem.DLL
Gute Idee! :thumb:
Nach LoadLibrary könntest du noch GetLastError speichern und am Ende der Funktion wieder setzen (die Funktionen im Finally-Block könnten sonst am Fehlercode herumpfuschen). |
Re: ShareMem ohne ShareMem.dll und Co.
Stimmt, hab ich garnicht dran gedacht :oops:
(kommt davon, wenn man im eigenem Code eine Exception wirft und es extra hierfür mit als eigenständige Funktion umbaut) Und schon geändert :angel: |
Re: ShareMem ohne ShareMem.dll und Co.
Es geht auch einiges einfacher, auch wenn dann manuell eine Funktion aufgerufen werden muss. Allerdings entstehen so auch keine "wilden" Abhängigkeiten zur Windows-API.
Dll:
Delphi-Quellcode:
Host:
var
old_mgr: TMemoryManagerEx; new_mgr: TMemoryManagerEx; mem_mgt: Boolean = false; procedure InitMemMgr(mgr: TMemoryManagerEx); begin if not mem_mgt then begin mem_mgt := true; GetMemoryManager(old_mgr); new_mgr := mgr; SetMemoryManager(new_mgr); end; end; exports InitMemMgr; initialization finalization if mem_mgt then SetMemoryManager(old_mgr);
Delphi-Quellcode:
PS: Ich frage mich ja, warum Borland das mit einer extra DLL gelöst hat... Gibt es da einen Grund? Die DLL-Daten und somit die Pointer auf die Memorymanagement-Funktionen werden bei jedem Laden der DLL doch instanziert und somit an die aufrufende Anwendung angepasst... Gibt es da einen guten Grund?
type
TInitMemMgrProc = procedure(mgr: TMemoryManagerEx); var proc: TInitMemMgrProc; handle: THandle; mgr: TMemoryManagerEx; [...] handle := LoadLibrary('foo'); @proc := GetProcAddress(handle, 'InitMemMgr'); if Assigned(proc) then begin GetMemoryManager(mgr); proc(mgr); end; |
Re: ShareMem ohne ShareMem.dll und Co.
Du hast da aber ein "kleines" Problem:
Und zwar wenn in der DLL Initialisations-Abschnitte anderer Units existieren. z.B. wenn die SysUtils oder andere Units in der DLL eingebunden sind, dann würde der Speicher-Manager der DLL schon vor Aufruf deiner Init-Prozedur verwendet und du würdest einfach diesen Manager mit dem anderen überschreiben. > also es ist im "alten" Manager schon Speicher reserviert, welcher eventuell versucht wird über den "neuen" Manager zu verändern. Wenn du nun nicht sicherstellen kannst, daß deine Änderung des Speichermanagers korrekt abläuft, dann solltest du vorher wenigstens, z.B. via GetMemoryManagerState (seit FastMM), feststellen, ob die "alte" Speicherverwaltung noch ungenutzt ist und dann entweder nicht diese ersetzen und/oder eine Fehlermeldung ausgeben. Ach ja, warum Borland es in einer DLL verlagert hat: - diese DLL wurde statisch geladen - sie wird also schon vor der EXE geladen und ebenfalls vor einer anderen DLL, wo sie eingebunden wurde - sie wird auch als Letztes wieder entladen - und da diese DLL immer als Erstes geladen und Letzes entladen wird, kann man ihre Speicherverwaltung ohne Probleme für alles Andere verwenden - ein winziger Nachteil ist, daß man dann alles, was die Speicherverwaltung betrifft, in diese DLL auslagern muß, welches nun auch eventuell in der EXE verwendete Fehlerüberwachungen anginge ... drum hab ich auch versucht die Verwaltung der EXE in die DLL durchzuschleifen, wärend Borlands ShareMem den Manager der DLL in die EXE einfügt PS: so wild ist es garnicht ... es wird nur vor dem Start der DLL ein gemeinsamer Speicherbereich besorgt (in diesem Fall eine MMF) und dort der Speichermanager der EXE gespeichert und der Rest st eine Prüfung, ob auch wirklich ein externer Manager vorhanden ist und nur dann wird er ersetzt und außerdem wurde auf die unterschiedlichen Manager-Verwaltungen eingegangen ... heißt, man kann die DLL genauso mit einer Delphi7-EXE (TMemoryManager) laufen lassen, wie mit z.B. einer EXE von Delphi 2009 (TMemoryManagerEx). |
Re: ShareMem ohne ShareMem.dll und Co.
Liste der Anhänge anzeigen (Anzahl: 1)
Hab 'nen kleinen Fehler behoben (da war noch 'ne alte Variable im Code, welche nicht mehr deklariert war)
Außerdem wurde die Unit himiSM_LoadLibrary so geändert, daß die nun auch in älteren Delphis läuft, welche noch kein TMemoryManagerEx kennen. Und zusätzlich hab ich noch eine weitere Prozedur eingefügt. entweder man läßt seine DLL via LoadLibrarySM oder initialisiert Einiges mit PreLoadSM - hier kann man dann seine DLL mit LoadLibrary laden - allerdings bleibt dann der SharingSpeicher erhalten (sind aber nur 24 Byte) ach ja, es gibt im Anhang auch eine kleine Demo dazu |
Alle Zeitangaben in WEZ +1. Es ist jetzt 11:57 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