AGB  ·  Datenschutz  ·  Impressum  







Anmelden
Nützliche Links
Registrieren
Zurück Delphi-PRAXiS Sprachen und Entwicklungsumgebungen Sonstige Fragen zu Delphi Delphi Strings und DLL - OnCreate abfangen - und andere Probleme...

Strings und DLL - OnCreate abfangen - und andere Probleme...

Offene Frage von "CherryDT"
Ein Thema von CherryDT · begonnen am 28. Apr 2010 · letzter Beitrag vom 2. Mai 2010
Antwort Antwort
CherryDT

Registriert seit: 28. Apr 2010
5 Beiträge
 
#1

Strings und DLL - OnCreate abfangen - und andere Probleme...

  Alt 28. Apr 2010, 12:40
Hallo allerseits!

Ich hab mehrere komplizierte Probleme und hoffe, hier eine Lösung zu finden. Ich bin wirklich keiner, der sofort in einem Forum fragt, aber in diesem Fall hab ich im Internet sonst keine Lösung gefunden.

Ich erstelle eine Erweiterung für ein in Delphi geschriebenes Programm, und zwar den RPG Maker 2000 (Delphi 5) bzw. 2003 (Delphi 6). Die Erweiterung selber programmiere ich mit FreeBasic. Und zwar habe ich eine DLL erstellt, die ich über einen Loader beim Programmstart in den Address Space des RPG Makers laden lasse. Hier werden einige Hooks installiert und im Folgenden Fenster des RPG Makers gesubclassed und so die Funktionen und das Verhalten des RPG Makers verändert und erweitert.

Um nun auch auf die Eigenschaften der einzelnen VCL-Controls zugreifen zu können, habe ich eine weitere DLL geschrieben, und zwar in Delphi 5/6 (passend zur Version des RPG Makers), welche mir die RTTI zugänglich macht und den Zugriff auf TStrings-Objekte ermöglicht.

Ein Beispiel:

1. Ich habe ein HWND von einem Fenster.
2. Ich hole den Pointer zum TForm-Objekt aus der ControlOfs-Property des Fensters.
3. Ich rufe eine Funktion aus meiner Delphi-DLL auf, um den Pointer zum TListBox-Objekt einer Listbox zu erhalten: listbox = Component_GetChild(form, "ListBox1")
Delphi-Quellcode:
function Component_GetChild(parent: TComponent; compname: PChar): TComponent; stdcall;

begin
  Result := nil;
  if Assigned(parent) = false then exit;
  Result := parent.FindComponent(String(compname));
end;
4. Ich rufe eine Funktion aus meiner Delphi-DLL auf, um über RTTI die "Items"-Eigenschaft zu bekommen (ich verwende die Unit clRTTI für einfachen RTTI-Zugriff): items = RTTI_GetPropAsObject(listbox, "Items")
Delphi-Quellcode:
function RTTI_GetPropAsObject(obj: TObject; propname: PChar): TObject; stdcall;

var
  RTObj: TrtWrapper;

begin
  Result := nil;
  RTObj := TrtWrapper.Create(obj);
  try
    if RTObj.HasProperty(propname) = false then exit;
    Result := RTObj[propname].AsObject;
  finally
    RTObj.Free;
  end;
end;
5. Und schließlich verwende ich eine weitere Funktion aus meiner Delphi-DLL, um der Listbox einen Eintrag hinzuzufügen: Strings_Add(items, "Ein neuer Eintrag!")
Delphi-Quellcode:
function Strings_Add(s: TStrings; buffer: PChar): Boolean; stdcall;

begin
  Result := false;
  if Assigned(s) = false then exit;
  s.Add(String(buffer));
  Result := true;
end;
Und damit wären wir schon bei Problem 1:

Das funktioniert alles soweit. Wenn allerdings einem von dem RPG Maker erstellten Objekt (hier eben mit listbox.Items.Add) ein String zugewiesen wird, dann gibt es ein Chaos:

Meistens geht alles gut, bis ich die Form, die ich manipuliert habe, schließe, oder manchmal auch bis ich dann eine neue öffne. Doch dann kommen Fehler ohne Ende: Access Violation, Invalid Pointer Operation, Corrupt String A, oder auch gar keine Meldung sondern das Programm beendet sich einfach, mit Exit Code C0000005 (= Access Violation).

Durch ein wenig Recherche im Internet hab ich rausgefunden, dass es ein Problem mit dem Memory Manager gibt, weil ja die Listbox sowie das Items-Objekt vom RPG Maker erzeugt wurden, der neue String jedoch von meiner DLL (und jetzt versucht der RPG Maker dann, ein Objekt zu "free"en, was er gar nicht erzeugt hat) - das passiert nicht nur bei Strings, sondern auch bei TBitmaps oder allem anderen, was die DLL erzeugt (und nicht die EXE). Als Lösung müsste man, wie ich jetzt weiß, als erste Unit "ShareMem" einbinden. Das Problem dabei ist nur: Ich habe ja keinen Zugriff auf den Sourcecode des RPG Makers (sonst müsste ich ja gar nicht diesen Aufwand betreiben)! Gibt es nicht irgendeine Möglichkeit, das anders zu lösen? Ich bin da echt am Verzweifeln...

Problem 2 ist was ganz anderes. Und zwar will ich meinen eigenen Code einschleusen, wenn bei einer Form schon alle Controls erzeugt wurden, aber noch nicht mit Werten befüllt o.ä.

Konkret hab ich das Problem, dass ich z.B. einem TDialEdit-Control (ein Editcontrol mit Auf-Ab-Pfeilen und zwei Eigenschaften "MaxValue" und "MinValue" - ist glaub ich nicht bei Delphi dabei) eine höhere MaxValue verpassen will. Ich hab dazu einen CallWndProc-Hook installiert, und wenn die Form das erste Mal eine der Messages WM_NCPAINT, WM_ERASEBKGND, WM_SHOWWINDOW oder CM_ACTIVATE bekommt, weiß ich, dass alle Controls da sind und setze die MaxValue hoch. Leider wurde dabei auch schon der Wert eingetragen. Wenn ich nun in dieser Form (wo original MaxValue = 20 ist und ich es bereits auf 100 hochgesetzt habe) 100 eintrage, auf "OK" klicke und sie wieder öffne, steht 20 darin, weil der Wert vom RPG Maker eingetragen (und auf den höchsten Wert - 20 - runterkorrigiert) wurde, bevor mein Hook den Maximalwert auf 100 gestellt hat. Das ist sehr ärgerlich.

Der Wert wird offenbar von dem Code eingetragen, der die Form erzeugt hat, nicht von einem Event der Form. Manuelles Aufrufen von OnCreate ändert den Wert nämlich nicht.

Gibt es irgendeinen Weg, von außen den Zeitpunkt abzupassen, wenn OnCreate aktiviert wird (oder gerade fertig ist, das ist nicht so wichtig), und dann eigenen Code einzuschleusen? Irgendwelche charakteristischen Window Messages werden da leider nicht verschickt.

Problem 3 ist sicher irgendwas primitives, aber ich komm trotzdem nicht drauf: Ich hab mit meiner FreeBasic-DLL in einer Delphi-Form mit CreateWindow eine zusätzliche Combobox eingefügt. Die Form hab ich gesubclassed, um die Auswahl in der Combobox auswerten zu können. Das funktioniert auch soweit. Nur zeichnet sich die Combobox nicht ordentlich. Wird sie von einem anderen Fenster überdeckt, verschwindet sie, bis man mit der Maus drüberfährt, und in der Dropdownliste ist alles durchsichtig (man sieht die Form durch) bis auf die Stellen, wo Text steht.

mfG Cherry

[edit=mkinzler]Code-Tags durch Delphi-Tags ersetzt Mfg, mkinzler[/edit]
  Mit Zitat antworten Zitat
mkinzler
(Moderator)

Registriert seit: 9. Dez 2005
Ort: Heilbronn
39.851 Beiträge
 
Delphi 11 Alexandria
 
#2

Re: Strings und DLL - OnCreate abfangen - und andere Problem

  Alt 28. Apr 2010, 12:46
Versuch es mal mit einer temporären lokalen Stringvariable
Markus Kinzler
  Mit Zitat antworten Zitat
CherryDT

Registriert seit: 28. Apr 2010
5 Beiträge
 
#3

Re: Strings und DLL - OnCreate abfangen - und andere Problem

  Alt 28. Apr 2010, 13:04
Zitat von mkinzler:
Versuch es mal mit einer temporären lokalen Stringvariable
Das funktioniert auch nicht...

Kann es ja gar nicht, da das Stringobjekt dann ja trotzdem von der DLL erstellt und von der EXE gelöscht wird.

Das Problem hab ich ja nicht nur bei Strings, sondern auch wenn ich andere Objekte (wie eine TBitmap) in der DLL erstelle und zuweise (sodass sie dann von der EXE gelöscht werden, was ja nicht gehen kann -> falscher Heap).

Die Frage war jetzt eher, wie man diese Memory-Management-Probleme lösen kann, ohne ShareMem zu verwenden (geht ja nicht, da Closed Source). Ich muss Objekte in der DLL erstellen.

Und ich kann nichtmal das alte Objekt zwischenlagern, WM_DESTROY abfangen und das neue selber "free"en und das alte wieder zuweisen, weil einiges dann nicht funktioniert, z.B. wenn ich einer Listbox Items hinzufüge - wenn ich sie dann am Ende wieder lösche, kann der RPG Maker den Text nicht mehr lesen und speichern - und genau das wäre das Ziel gewesen.
  Mit Zitat antworten Zitat
Benutzerbild von himitsu
himitsu

Registriert seit: 11. Okt 2003
Ort: Elbflorenz
43.016 Beiträge
 
Delphi 12 Athens
 
#4

Re: Strings und DLL - OnCreate abfangen - und andere Problem

  Alt 28. Apr 2010, 13:11
Zitat von CherryDT:
Um nun auch auf die Eigenschaften der einzelnen VCL-Controls zugreifen zu können, habe ich eine weitere DLL geschrieben, und zwar in Delphi 5/6 (passend zur Version des RPG Makers), welche mir die RTTI zugänglich macht und den Zugriff auf TStrings-Objekte ermöglicht.
Du weißt aber, daß die RTTI dennoch getrennt ist
Delphi-5/6-DLL benutzt dennoch seine eigene RTTI.

Außerdem nutzen beide Module (DLL und EXE) ihren eigenen Speichermanager,
wewegen es hier natürlich knallen MUß.
s.Add(String(buffer)); Du müßtest also den Speichermanager der EXE und eventuell noch einige Teile der RTTI erstmal irgendwie in deine DLL umleiten, bzw. es so hinbekommen, daß die DLL den Speichermanager der EXE verwendet.
Denn der String MUß im Speichermanager der EXE liegen, wenn dieser damit arbeiten soll.

Und dieses ist nur eines von vielen derartigen Problemen, welche sich nicht leicht, bzw. garnicht lösen lassen.



Was möglich wäre,
der ListBox, also dem Windows-Control, welches von der VCL dort gekapselt wird, entsprechende Windows-Messages zu schicken und so die Liste zu ändern.

Also ich kann nur von derartigen VCL-Zugriffen abraten.
Nicht umsonst sollte man bei eigenen Programmen besser entsprechende Packages verwenden, welche den gemeinsamen Zugriff ermöglichen. Welche aber natürlich auch in allen Modulen (DLL und EXE) eingebunden sein müssen.
Garbage Collector ... Delphianer erzeugen keinen Müll, also brauchen sie auch keinen Müllsucher.
my Delphi wish list : BugReports/FeatureRequests
  Mit Zitat antworten Zitat
CherryDT

Registriert seit: 28. Apr 2010
5 Beiträge
 
#5

Re: Strings und DLL - OnCreate abfangen - und andere Problem

  Alt 28. Apr 2010, 14:36
Das Problem ist nur, dass das vielleicht im Falle der Listbox funktioniert, aber bei anderen Nicht-Standard-Controls nicht (die gibts keine passenden Window Messages), und im Falle von Objekten wie z.B. TBitmap eben gar nicht...

Mit RTTI gibts keinerlei Probleme übrigens, nur mit den Strings/Objekten.

"Umleiten" - ja, das klingt zwar schlüssig, ich wüsste aber nicht, wie ich das umsetzen kann...

Ich kann ja leider nicht die Techniken anwenden, die man normalerweise anwendet, weil ich ja auf den Source Code keinen Zugriff habe.
  Mit Zitat antworten Zitat
Benutzerbild von himitsu
himitsu

Registriert seit: 11. Okt 2003
Ort: Elbflorenz
43.016 Beiträge
 
Delphi 12 Athens
 
#6

Re: Strings und DLL - OnCreate abfangen - und andere Problem

  Alt 28. Apr 2010, 14:49
In der Unit System gibt es ja die Prozeduren GetMamoryManager und an diese, bzw. an das Ergbnis welches diese liefert müßtest du rankommen und könntest dann via SetMemoryManager diesen deiner DLL zuweisen.

Ansonsten gäbe es nur eine einzige Möglichkeit einem "fremden" Speichermanager einen externen String unterzujubeln ... man muß den String wie eine Konstante aussehen lassen.
Schau dir mal die beiden Threads an > Hier im Forum suchenPAnsiStringInfo

Strings, welche von der EXE in die eigene DLL ausgelesen werden sollen mäßten entweder über einen PChar gecastet oder über UniqueString in den eigenen Speichermanager geladen werden.

PS: Ein TBitmap kapselt intern auch nur Windows-Objekte.
bitmap.Hande = HIMAGE
und im TBitmap verstecht sich ein TBitmapImage, welches das Bild und Anderes kapselt.
Delphi-Quellcode:
TBitmapImage = class(TSharedImage)
private
  FHandle: HBITMAP; // DDB or DIB handle, used for drawing
  FMaskHandle: HBITMAP; // DDB handle
  FPalette: HPALETTE;
  FDIBHandle: HBITMAP; // DIB handle corresponding to TDIBSection
  FDIB: TDIBSection;
  FSaveStream: TMemoryStream; // Save original RLE stream until image is modified
  FHalftone: Boolean; // FPalette is halftone; don't write to file
Garbage Collector ... Delphianer erzeugen keinen Müll, also brauchen sie auch keinen Müllsucher.
my Delphi wish list : BugReports/FeatureRequests
  Mit Zitat antworten Zitat
CherryDT

Registriert seit: 28. Apr 2010
5 Beiträge
 
#7

Re: Strings und DLL - OnCreate abfangen - und andere Problem

  Alt 28. Apr 2010, 17:47
Hurraaaaa!

Das mit dem Memory Manager hat mein erstes Problem gelöst.

Ich mache das jetzt so:

FreeBASIC-Code:
Code:
' gets pointer to Delphi's memory manager
Function GetMemoryManager() As TMemoryManager Ptr
   #Define UNKNOWN &hCC
   Dim pattern(...) As UByte = {&h53, &h85, &hC0, &h7E, &h15, &hFF, &h15, UNKNOWN, UNKNOWN, UNKNOWN, UNKNOWN, _
      &h8B, &hD8, &h85, &hDB, &h75, &h0B, &hB0, &h01, &hE8, UNKNOWN, UNKNOWN, UNKNOWN, UNKNOWN, &hEB, &h02, _
      &h33, &hDB, &h8B, &hC3, &h5B, &hC3}
   Dim j As Integer = 0
   For i As UByte Ptr = &h401000 To &h40F000 Step 1
      If pattern(j) = UNKNOWN OrElse *i = pattern(j) Then
         j += 1
         If j > UBound(pattern) Then Return *CPtr(TMemoryManager Ptr Ptr, i - UBound(pattern) + 7)
      Else
         j = 0
      EndIf
   Next
   Return NULL
End Function
So kriege ich den Memory Manager der EXE.

In der DLL hab ich jetzt diese Funktion, die ich dann aufrufe: Ultimate_SetMemoryManager(GetMemoryManager())

Delphi-Quellcode:
function Ultimate_SetMemoryManager(memmgr: PMemoryManager): Boolean; stdcall;

begin
  Result := false;
  SetMemoryManager(memmgr^);
  Result := true;
end;
Übrigens: mich wundert, warum es ShareMem und sonstwelche Units dafür gibt, wenn es reichen würde, dass die DLL eine SetDLLMemoryManager-Funktion exportiert und man in der EXE dann einfach SetDLLMemoryManager(GetMemoryManager()) macht.

Danke Leute!

Problem 1 ist somit endlich gelöst!

Jetzt bleiben allerdings noch Problem 2 und 3!

mfG Cherry
  Mit Zitat antworten Zitat
Benutzerbild von himitsu
himitsu

Registriert seit: 11. Okt 2003
Ort: Elbflorenz
43.016 Beiträge
 
Delphi 12 Athens
 
#8

Re: Strings und DLL - OnCreate abfangen - und andere Problem

  Alt 28. Apr 2010, 17:56
Zitat von CherryDT:
Übrigens: mich wundert, warum es ShareMem und sonstwelche Units dafür gibt, wenn es reichen würde, dass die DLL eine SetDLLMemoryManager-Funktion exportiert und man in der EXE dann einfach SetDLLMemoryManager(GetMemoryManager()) macht.
Weil viele ihre DLLs statisch Linken, wobei die DLL vor der EXE geladen wird und man somit noch keinen Zugriff auf die EXE hat.

Und ShareMem nutzt auch die selben SetMemoryManager-Funktionen, nur daß dort die EXE den Manager von der DLL übernimmt.

http://www.delphipraxis.net/internal...light=sharemem
http://www.delphipraxis.net/internal...light=sharemem
Garbage Collector ... Delphianer erzeugen keinen Müll, also brauchen sie auch keinen Müllsucher.
my Delphi wish list : BugReports/FeatureRequests
  Mit Zitat antworten Zitat
CherryDT

Registriert seit: 28. Apr 2010
5 Beiträge
 
#9

Re: Strings und DLL - OnCreate abfangen - und andere Problem

  Alt 2. Mai 2010, 12:42
Problem 3 hab ich nun selber gelöst.

Aber Problem 2 besteht noch immer!

Ich hab jetzt außerdem noch ein Problem 4:

- Wie stelle ich es am besten an, im Speicher nach einer Klasse zu suchen, von der ich nur den Namen kenne?
- Wenn ich da die Adresse gefunden habe, wie kann ich von dieser Klasse eine Instanz erzeugen?

mfG Cherry
  Mit Zitat antworten Zitat
Themen-Optionen Thema durchsuchen
Thema durchsuchen:

Erweiterte Suche
Ansicht

Forumregeln

Es ist dir nicht erlaubt, neue Themen zu verfassen.
Es ist dir nicht erlaubt, auf Beiträge zu antworten.
Es ist dir nicht erlaubt, Anhänge hochzuladen.
Es ist dir nicht erlaubt, deine Beiträge zu bearbeiten.

BB-Code ist an.
Smileys sind an.
[IMG] Code ist an.
HTML-Code ist aus.
Trackbacks are an
Pingbacks are an
Refbacks are aus

Gehe zu:

Impressum · AGB · Datenschutz · Nach oben
Alle Zeitangaben in WEZ +1. Es ist jetzt 20:12 Uhr.
Powered by vBulletin® Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024 by Thomas Breitkreuz