Entwickler-Ecke
Dateizugriff - Komponeneten in DLL ändern
jensenwb - So 06.10.02 17:56
Titel: Komponeneten in DLL ändern
Hallo ich möchte in einer DLL die größe meiner Komponenten ändern.
Mein Quelltext der DLL ist
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: 31: 32: 33: 34: 35: 36: 37: 38: 39: 40: 41: 42: 43: 44: 45: 46: 47: 48: 49: 50: 51: 52: 53: 54: 55: 56: 57: 58: 59: 60: 61: 62: 63: 64: 65: 66: 67: 68: 69: 70: 71: 72: 73: 74: 75: 76: 77: 78: 79: 80: 81: 82: 83: 84: 85: 86: 87: 88: 89: 90: 91: 92: 93: 94: 95: 96: 97: 98: 99: 100: 101: 102: 103:
| library anpassen;
{ Wichtiger Hinweis zur DLL-Speicherverwaltung: ShareMem muß die erste Unit im Uses-Anweisungsteil des Interface-Abschnitts Ihrer Unit sein, wenn Ihre DLL Prozeduren oder Funktionen exportiert, die String-Parameter oder Funktionsergebnisse übergeben. Dies gilt für alle Strings die an und von Ihrer DLL übergeben werden -- selbst für diese, die in Records oder Klassen verschachtelt sind. ShareMem ist die Schnittstellen-Unit zur DELPHIMM.DLL, welche Sie mit Ihrer DLL weitergeben müssen. Um die Verwendung von DELPHIMM.DLL zu vermeiden, übergeben Sie String-Parameter unter Verwendung von PChar- oder ShortString-Parametern. }
uses SysUtils, Windows, Messages, Classes, Graphics, Controls, StdCtrls, Forms, DBCtrls, DB, Mask, Grids, DBGrids, ComCtrls, Tabnotbk, DBTables, ExtCtrls, Buttons, Dialogs;
{$R *.RES}
procedure anpassendbCombobox(objekt:tdbComboBox); stdcall; begin objekt.left:=round(objekt.left*screen.width/800); objekt.width:=round(objekt.width*screen.width/800); objekt.height:=round(objekt.height*screen.height/600); objekt.top:=round(objekt.top*screen.height/600); objekt.Font.size:=round(objekt.font.size*screen.width/800); end;
procedure anpassendbgrid(objekt:tdbgrid); stdcall; begin objekt.left:=round(objekt.left*screen.width/800); objekt.width:=round(objekt.width*screen.width/800); objekt.height:=round(objekt.height*screen.height/600); objekt.top:=round(objekt.top*screen.height/600); objekt.Font.size:=round(objekt.font.size*screen.width/800); end;
procedure anpassenlabel(objekt:tlabel); stdcall; begin objekt.left:=round(objekt.left*screen.width/800); objekt.width:=round(objekt.width*screen.width/800); objekt.height:=round(objekt.height*screen.height/600); objekt.top:=round(objekt.top*screen.height/600); objekt.Font.size:=round(objekt.font.size*screen.width/800); end;
procedure anpassenbitbtn(objekt:tbitbtn); stdcall; begin objekt.left:=round(objekt.left*screen.width/800); objekt.width:=round(objekt.width*screen.width/800); objekt.height:=round(objekt.height*screen.height/600); objekt.top:=round(objekt.top*screen.height/600); objekt.Font.size:=round(objekt.font.size*screen.width/800); end;
procedure anpassendbedit(objekt:tdbedit); stdcall; begin objekt.left:=round(objekt.left*screen.width/800); objekt.width:=round(objekt.width*screen.width/800); objekt.height:=round(objekt.height*screen.height/600); objekt.top:=round(objekt.top*screen.height/600); objekt.Font.size:=round(objekt.font.size*screen.width/800); end;
procedure anpassentabbednotebook(objekt:ttabbednotebook); stdcall; begin objekt.left:=round(objekt.left*screen.width/800); objekt.width:=round(objekt.width*screen.width/800); objekt.height:=round(objekt.height*screen.height/600); objekt.top:=round(objekt.top*screen.height/600); objekt.tabFont.size:=round(objekt.tabfont.size*screen.width/800); end;
procedure anpassenform(objekt:tform); stdcall; begin objekt.left:=round(objekt.left*screen.width/800); objekt.width:=round(objekt.width*screen.width/800); objekt.height:=round(objekt.height*screen.height/600); objekt.top:=round(objekt.top*screen.height/600); objekt.Font.size:=round(objekt.font.size*screen.width/800); end;
procedure anpassendbmemo(objekt:tdbmemo); stdcall; begin objekt.left:=round(objekt.left*screen.width/800); objekt.width:=round(objekt.width*screen.width/800); objekt.height:=round(objekt.height*screen.height/600); objekt.top:=round(objekt.top*screen.height/600); objekt.Font.size:=round(objekt.font.size*screen.width/800); end;
Exports anpassendbCombobox, anpassendbgrid, anpassenlabel, anpassenbitbtn, anpassendbedit, anpassentabbednotebook, anpassenform, anpassendbmemo;
begin end. |
Der Quelltext meines Prog ist:
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: 31: 32: 33: 34: 35: 36: 37: 38: 39: 40:
| unit testanpassen;
interface
uses Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs, Grids, DBGrids, StdCtrls;
type TForm1 = class(TForm) Label1: TLabel; Label2: TLabel; DBGrid1: TDBGrid; procedure FormCreate(Sender: TObject); private { Private-Deklarationen } public { Public-Deklarationen } end;
var Form1: TForm1;
implementation
{$R *.DFM} procedure anpassenlabel(objekt:tlabel);stdcall;external 'anpassen.dll'; procedure anpassendbgrid(objekt:tdbgrid);stdcall;external 'anpassen.dll'; procedure anpassenform(objekt:tform);stdcall;external 'anpassen.dll';
procedure TForm1.FormCreate(Sender: TObject); begin anpassenform(form1); anpassenlabel(form1.label1); anpassenlabel(form1.label2); anpassendbgrid(form1.dbgrid1); end;
end. |
Wenn ich dann das Programm beende erscheint folgende Fehlermeldung:
Exception EAccessViolation im Modul Testanpass.exe bei 00015953.
Zugriffsverletzung bei Adresse 00415953 in Modul 'Testanpass.exe' Lesen von Adresse FFFFFFFF.
Ich hoffe Ihr könnt mir helfen.
bis11 - So 06.10.02 18:07
Du mußt die Proceduren auch noch unter der implementation deklarieren. z.B. so :
procedure anpassenlabel(objekt:tlabel);stdcall;
jensenwb - So 06.10.02 18:16
Ich habe doch die Proceduren im Implementations-Teil.
Ich weiß jetze nicht so richtig was Du meinst.
Udontknow - Mo 07.10.02 14:37
Ja, wo ist denn Sharemem bei dir eingetragen? Um dynamische Datenstrukturen wie Objekte und Strings zwischen DLL und einer Anwendung hin und herzuschieben, musst du doch Sharemem in der Interface-Uses-Klausel sowohl in deinem Programm als auch in deiner DLL angeben (siehe "der Shared-Memory-Manager" in der Delphi-Hilfe), und zwar als
erste Unit.
Mal ne andere Sache:
Wieso hast du viele Prozeduren, die alle ein und dasselbe machen, und nur andere Eingabeparametertypen haben? Alle Typen von Objekten, die du übergeben willst, haben haben doch schliesslich die Eigenschaften left,width,height,top und Font von einem einzigen Vorfahren, nämlich TControl, bezogen.
Schreib also einfach eine Routine, der du ein TControl-Objekt übergibst (diese Routine akzeptiert dann
sowohl Labels als auch DBGrids, es sind ja Nachfahren von TControl):
Quelltext
1: 2: 3: 4: 5: 6: 7: 8:
| procedure anpassen(objekt:tcontrol); stdcall; begin objekt.left:=round(objekt.left*screen.width/800); objekt.width:=round(objekt.width*screen.width/800); objekt.height:=round(objekt.height*screen.height/600); objekt.top:=round(objekt.top*screen.height/600); objekt.Font.size:=round(objekt.font.size*screen.width/800); end; |
Cu, :D
Udontknow
jensenwb - So 13.10.02 17:14
Habe den Code so geändert. Der Fehler ist aber trotzdem noch da.
Bitte helft Mir, bin mit meinen latein am ende.
Udontknow - Mo 14.10.02 07:58
Nun, dann setze mal einen Haltepunkt direkt auf die erste Zeile im Ereignis OnCreate. Wenn du bis dorthin ohne Fehler kommst, drücke F8, um eine Zeile weiter zu gehen. Wann tritt der Fehler auf?
Du kannst testweise auch mal die Routine Objektanpassen aus deiner DLL herausnehmen und direkt ins Formular packen.
jensenwb - Sa 19.10.02 20:03
Der Fehler tritt auf wenn ich das Programm schließe.
Ich habe auch schon die Procedure in meinen Programm direkt eingebunden (rufe keine Procedure aus DLL mehr auf), aber da erscheint immer wenn ich das Prog compilieren will die Fehlermeldung "Undefinierter Bezeichner: 'Font'. "
Meine Procedure sieht wie folgt aus.
Quelltext
1: 2: 3: 4: 5: 6: 7: 8:
| procedure anpassen(objekt1:tcontrol); begin objekt1.left:=round(objekt1.left*screen.width/800); objekt1.width:=round(objekt1.width*screen.width/800); objekt1.height:=round(objekt1.height*screen.height/600); objekt1.top:=round(objekt1.top*screen.height/600); objekt1.Font.size:=round(objekt1.Font.size*screen.width/800); end; |
Woran kann das denn jetzt liegen.
(20.10.02 14:47 Tino) Code-Tags hinzugefügt.
Tino - So 20.10.02 14:48
jensenwb hat folgendes geschrieben: |
Woran kann das denn jetzt liegen. |
Die Eigenschaft
Font ist in dem Objekt
tControl in der
Protected-Sektion definiert. Diese Eingeschaft ist also nur in abgeleiteten Klassen sichtbar.
Gruß
TINO
Udontknow - Mo 21.10.02 12:17
Oh, stimmt. :oops:
Du musst also für jede Objektart, die direkt Nachfahre von TControl ist und bei der du den Font ändern willst, eine weitere Routine schreiben... Ärgerlich... Naja, in dieser Routine kannst du dann wenigstens auf die oben gepostete Routine zurückgreifen, dann sparst ein wenig Code...
Cu,
Udontknow
AndyB - Mo 21.10.02 12:30
Das ist nicht nötig.
Man kann das protected-Attribut so umgehen:
Quelltext
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12:
| type THackControl = class(TControl);
procedure anpassen(objekt1:tcontrol); begin objekt1.left:=round(objekt1.left*screen.width/800); objekt1.width:=round(objekt1.width*screen.width/800); objekt1.height:=round(objekt1.height*screen.height/600); objekt1.top:=round(objekt1.top*screen.height/600); with THackControl(objekt1) do Font.size:=round(Font.size*screen.width/800); end; |
Udontknow - Mo 21.10.02 15:37
Achja, du hast recht! Das ist ein Kniff, den ich auch schon öfter angewendet habe, wieso ich da nicht draufgekommen bin... :oops:
Die ganze Sache ist natürlich ein wenig heikel, da man eigentlich nie ein Objekt als einen Nachfahren seiner selbst casten sollte. Es klappt aber einwandfrei, wenn man eben nur auf Daten zugreift, die schon in der Vorfahrklasse implementiert sind (wie eben das protected-Element font).
Sogar Prozeduren der Nachfahrklasse lassen sich ausführen, sofern diese nicht Übersteuerungen darstellen. Einzig und allein steht die Bedingung, daß keine in Nachfahrklassen deklarierten Datenfelder in den aufzurufenden Routinen benötigt werden.
Cu,
Udontknow
AndyB - Mo 21.10.02 21:18
Zitat: |
Die ganze Sache ist natürlich ein wenig heikel |
Nur wenn man nicht weiß, was man macht also mit TWinControl() sollte man nicht auf ein von TControl, aber nicht von TWinControl abgeleitete Klasse zugreifen.
Zitat: |
Einzig und allein steht die Bedingung, daß keine in Nachfahrklassen deklarierten Datenfelder in den aufzurufenden Routinen benötigt werden. |
Diese Bedingung besteht nicht. Das bei nicht virtuellen Methoden wird die in TControl deklarierte Version der Methode aufgerufen, die natürlich nur auf in TWinControl vorhandene Felder zugreifen kann. Wird jedoch eine virtuelle bzw. dynamische Methode aufgerufen, dann kann diese sehrwohl auf die "neuen" Felder zugreifen.
Udontknow - Di 22.10.02 09:40
Hallo!
Zitat: |
Nur wenn man nicht weiß, was man macht also mit TWinControl() sollte man nicht auf ein von TControl, aber nicht von TWinControl abgeleitete Klasse zugreifen. |
Ähh... Wie bitte? Das ist ein bisschen konfus... :wink:
Ich glaube, wir missverstehen uns. Wie willst du auf Felder zugreifen, die im Objekt gar nicht vorhanden sind?
Nehmen wir mal 2 Klassen:
Quelltext
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20:
| type TA=class(TObject) Element1:Integer; end;
type TB=Class(TA) Element2:integer; function GetElement2:integer; function Element1Mal2:Integer; end;
function TB.GetElement2:integer; begin Result:=Element2; end;
function TB.Element1Mal2:Integer; begin Result:=Element1*2; end; |
Nehmen wir nun an, das du ein Objekt der Klasse A hast.
Quelltext
1: 2: 3: 4: 5: 6: 7: 8: 9: 10:
| var A:TA; begin A:=TA.Create; try A.Element1:=20; ... finally A.Free; end; end; |
Folgendes ist erlaubt, da die in TB deklarierte Prozedur Element1Mal2 nur auf Datenfelder zugreift, die bereits in A deklariert wurden:
Quelltext
1:
| ShowMessage(IntToStr(TB(A).Element1Mal2)); |
Das hier ist dagegen fatal, weil das Objekt gar kein Element2 besitzt, du greifst irgendwo in den Speicher, häufig kommt es bei solchen Aktionen zur Zugriffsschutzverletzung, manchmal bekommt man einfach Müll zurück.
Quelltext
1:
| ShowMessage(IntToStr(TB(A).GetElement2)); |
Cu, :D
Udontknow
Entwickler-Ecke.de based on phpBB
Copyright 2002 - 2011 by Tino Teuber, Copyright 2011 - 2025 by Christian Stelzmann Alle Rechte vorbehalten.
Alle Beiträge stammen von dritten Personen und dürfen geltendes Recht nicht verletzen.
Entwickler-Ecke und die zugehörigen Webseiten distanzieren sich ausdrücklich von Fremdinhalten jeglicher Art!