| Autor |
Beitrag |
Fuechsl
Hält's aus hier
Beiträge: 6
|
Verfasst: Fr 25.07.03 15:55
hallo miteinander,
Ich möchte in einer DLL-Procedure ein Control erstellen, das als Parent ein Panel des Hauptprogramms erhält.
Ich habe das folgendermassen zu lösen probiert:
Code der DLL:
Delphi-Quelltext 1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20: 21: 22: 23: 24: 25: 26: 27: 28: 29: 30:
| library CallDLL;
uses ShareMem,SysUtils, Classes, stdctrls, extctrls, graphics, controls, windows;
{$R *.RES} type TCreateParProc=procedure(var ctrl:TWinControl; WinCtrlClass: TWinControlClass); stdcall;
var btnButton: TButton;
procedure CallDLLProc(CreateParProc: TCreateParProc); stdcall; begin CreateParProc(TWinControl(btnButton), TButton); with btnButton do begin Left:=20; Top:=20; Width:=80; Height:=30; Caption:='Test'; Visible:=True; end; end;
exports CallDLLProc;
begin end. |
und der code des Hauptprogrammes:
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20: 21: 22: 23: 24: 25: 26: 27: 28: 29: 30: 31: 32: 33: 34: 35: 36: 37: 38: 39: 40:
| unit Main;
interface
uses ShareMem,Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,StdCtrls, ExtCtrls;
type TCreateParProc=procedure(var Ctrl: TWinControl; WinCtrlClass: TWinControlClass); stdcall;
TForm1 = class(TForm) Panel1: TPanel; Button1: TButton; procedure Button1Click(Sender: TObject); end;
procedure CallDLLProc(CreateParProc: TCreateParProc); stdcall; procedure CreateParCtrl(var Ctrl: TWinControl; WinCtrlClass: TWinControlClass); stdcall;
var Form1: TForm1;
implementation
{$R *.DFM}
procedure CallDLLProc; external 'CallDLL.DLL';
procedure TForm1.Button1Click(Sender: TObject); begin CallDLLProc(@CreateParCtrl); end;
procedure CreateParCtrl(var Ctrl: TWinControl; WinCtrlClass: TWinControlClass); stdcall; begin Ctrl:=WinCtrlClass.CreateParented(Form1.Panel1.Handle); Form1.Panel1.InsertControl(ctrl); end;
end. |
Wenn ich das Ding starte und auf den button klicke, dann erhalte ich die Fehlermeldung "TFont kann nicht zu TFont zugewiesen werden" und dann eine Exception.
Wenn ich den Code der DLL debugge (unter Start, Parameter das Programm CallDLLMain als Host angeben), dann passiert folgendes Originelles:
In der Datei Controls, Zeile 3503 steht folgender Code:
Delphi-Quelltext 1: 2: 3: 4:
| procedure TControl.SetFont(Value: TFont); begin FFont.Assign(Value); end; |
Value hat dort einen Wert, zeigt also auf ein Font-Objekt. Wenn ich in TFont.Assign (steht in der Datei Graphics, Zeile 1404) hineintrace, hat der Parameter Source (in dem Value übergeben wird) plötzlich keinen Wert mehr! Deshalb passiert auch die Exception.
Delphi-Quelltext 1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20: 21: 22:
| procedure TFont.Assign(Source: TPersistent); begin if Source is TFont then begin Lock; try TFont(Source).Lock; try FontManager.AssignResource(Self, TFont(Source).FResource); Color := TFont(Source).Color; if PixelsPerInch <> TFont(Source).PixelsPerInch then Size := TFont(Source).Size; finally TFont(Source).Unlock; end; finally Unlock; end; Exit; end; inherited Assign(Source); end; |
Was passiert hier? Ist das irgend ein Speicherverwaltungs-Problem von Win XP auf dem ich arbeite?
Wenn jemand den Code per mail haben möchte um mir zu helfen, dann schicke ich den gerne. Ich arbeite übrigens mit Delphi 5.
Ich bin sehr dankbar, wenn mir irgendjemand einen Tipp geben kann, was hier schief läuft.
mit freundlichem gruss, füchsl (martin)
ps. Eigentlich gehts darum, plugins als dll realisieren zu können. Diese plugins müssen auf ein panel des Hauptprogrammes zugreifen können und sie sollen auch in andern Sprachen als Delphi geschrieben werden können. Vielleicht hat ja jemand einen ganz anderen, besseren Ansatz, mein Problem zu lösen. (Ich habe schon an COM/ActiveX gedacht, aber ich möchte die Sache möglichst einfach halten).
Moderiert von Tino: Code- durch Delphi-Tags ersetzt.
|
|
Motzi
      
Beiträge: 2931
XP Prof, Vista Business
D6, D2k5-D2k7 je Prof
|
Verfasst: Sa 26.07.03 15:56
Fällt dir bei diesen 2 Zeilen etwas auf?
Delphi-Quelltext 1: 2:
| procedure CallDLLProc(CreateParProc: TCreateParProc); stdcall; procedure CallDLLProc; external 'CallDLL.DLL'; |
In der Dll deklarierst du die procedure als stdcall, im Prog importierst du sie allerdings mit der Delphi-Standard-Aufrufkonvention register..!
_________________ gringo pussy cats - eef i see you i will pull your tail out by eets roots!
|
|
Manfred
      
Beiträge: 90
|
Verfasst: So 27.07.03 01:38
Hi!
Also soweit ich ersehen kann, sind die Aufrufkonventionen alle identisch! Wenn im interface stdcall angegeben wurde, dann ist dies im implementation absolut nicht mehr erforderlich! Andernfalls würde es mich sehr wundern, warum meine DLL's laufen.
Zum Problem:
Ich schätze, die Fonts, die hier erzeugt werden, stammen vom "Elternelement" ab. Dieser Font ist für die DLL aufgrund eines für sie nicht erreichbaren Speicherbereiches (dieser liegt ja im Hauptprogramm) aber ungültig, was zu der Exception führt.
Die Frage ist, ob der Fehler bereits bei CreateParented auftritt, oder erst bei InsertControl. Im letzteren Fall würde ich versuchen, die Eigenschaften ParentFont der neuen Komponenten auf False zu stellen.
_________________ Computer können schneller rechnen als wir, deshalb machen sie auch mehr Fehler
|
|
Fuechsl 
Hält's aus hier
Beiträge: 6
|
Verfasst: So 27.07.03 21:56
ist das wirklich so, dass Hauptprogramm und DLL nicht auf den gleichen Speicher zugreifen können?
Wie kann ich denn mein Problem lösen, dass die DLL auf einem Panel (ist ja windowstechnisch gesehen ein Fenster mit einem Handle) weitere Controls erstellen kann?
Zu deiner Frage noch, Manfred: Die Exception taucht wirklich erst im InsertControl auf und wenn ich ParentFont auf False setze, dann ist das Problem kurzfristig gelöst. Es wird aber dann später (nicht nachvollziehbar wann) wieder eine Exception ausgelöst (Access Violation).
Die Frage ist auch, wieso das InsertControl überhaupt nötig ist, eigentlich sollte doch CreateParented diese Arbeit bereits übernehmen. Oder für was ist denn diese Funktion da? (ohne InsertControl wird aber das Control nicht sichtbar...)
|
|
Fuechsl 
Hält's aus hier
Beiträge: 6
|
Verfasst: So 27.07.03 23:47
ich habe noch ein bisschen ausprobiert und nachgeforscht und herausgefunden, dass ich ein Control mit CreateParented erzeugen und mit ShowWindow anzeigen kann.
Doch nun möchte das OnClick-Event eines Buttons, den ich in dieser DLL erstellt habe abfangen. Wie mach ich das?
Ich habs mit folgendem Code probiert, doch das funktioniert nicht wirklich...
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20: 21: 22: 23: 24: 25: 26: 27: 28: 29: 30: 31: 32: 33: 34: 35: 36: 37: 38: 39: 40: 41: 42: 43: 44: 45: 46: 47:
| library CallDLL;
uses Sharemem,SysUtils, Classes, stdctrls, extctrls, graphics, controls, windows, dialogs, forms;
{$R *.RES} type TDummy=class(TObject) procedure ButtonClicked(Sender: TObject); end;
var btnButton: TButton; dummy: TDummy; fExit: Boolean;
procedure TDummy.ButtonClicked(Sender: TObject); begin MessageDlg('Geklickt!',mtInformation,[mbOK],0); fExit:=True; end;
procedure CallDLLProc(Handle: HWND); stdcall; begin btnButton:=TButton.CreateParented(Handle); with btnButton do begin Left:=20; Top:=20; Width:=80; Height:=30; Caption:='Test'; Visible:=True; OnClick:=dummy.ButtonClicked; end; ShowWindow(btnButton.Handle,SW_SHOW);
fExit:=False; repeat Application.ProcessMessages; until fExit; end;
exports CallDLLProc;
begin end. |
Die procedure CallDLLProc wird aus einen Hauptprogramm aufgerufen, das ein Panel (ist ja auch ein Windows-Handled-Fenster) enthält, folgendermassen:
Delphi-Quelltext 1:
| CallDLLPRoc(Form1.Panel1.Handle); |
Mit freundlichem Gruss und Dank im Voraus, Füchsl (Martin)
Moderiert von Tino: Delphi-Tags hinzugefügt.
|
|
Motzi
      
Beiträge: 2931
XP Prof, Vista Business
D6, D2k5-D2k7 je Prof
|
Verfasst: Mo 28.07.03 09:22
| Manfred hat folgendes geschrieben: | Hi!
Also soweit ich ersehen kann, sind die Aufrufkonventionen alle identisch! Wenn im interface stdcall angegeben wurde, dann ist dies im implementation absolut nicht mehr erforderlich! Andernfalls würde es mich sehr wundern, warum meine DLL's laufen. |
Stimmt.. hab übersehn dass er die Funktion einaml im interface deklariert und erst im implementations-Teil importiert...
| Zitat: | Zum Problem:
Ich schätze, die Fonts, die hier erzeugt werden, stammen vom "Elternelement" ab. Dieser Font ist für die DLL aufgrund eines für sie nicht erreichbaren Speicherbereiches (dieser liegt ja im Hauptprogramm) aber ungültig, was zu der Exception führt. |
Also dass eine Dll nicht im selben Adressraum liegt wie das Hauptprogramm ist mir neu...!
@Fuechsl: schick mir den Code mal per Mail.. würd ihn mir gern mal anschaun..!
_________________ gringo pussy cats - eef i see you i will pull your tail out by eets roots!
|
|
|