Autor |
Beitrag |
jensenwb
      
Beiträge: 36
|
Verfasst: So 06.10.02 17:56
Hallo ich möchte in einer DLL die größe meiner Komponenten ändern.
Mein Quelltext der DLL ist
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:
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
      
Beiträge: 1247
Erhaltene Danke: 2
Apple Mac OSX 10.11
|
Verfasst: 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 
      
Beiträge: 36
|
Verfasst: So 06.10.02 18:16
Ich habe doch die Proceduren im Implementations-Teil.
Ich weiß jetze nicht so richtig was Du meinst.
|
|
Udontknow
      
Beiträge: 2596
Win7
D2006 WIN32, .NET (C#)
|
Verfasst: 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,
Udontknow
|
|
jensenwb 
      
Beiträge: 36
|
Verfasst: 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
      
Beiträge: 2596
Win7
D2006 WIN32, .NET (C#)
|
Verfasst: 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 
      
Beiträge: 36
|
Verfasst: 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
      

Beiträge: 9839
Erhaltene Danke: 45
Windows 8.1
Delphi XE4
|
Verfasst: 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
      
Beiträge: 2596
Win7
D2006 WIN32, .NET (C#)
|
Verfasst: Mo 21.10.02 12:17
Oh, stimmt.
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
      
Beiträge: 1173
Erhaltene Danke: 14
RAD Studio XE2
|
Verfasst: 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; |
_________________ Ist Zeit wirklich Geld?
|
|
Udontknow
      
Beiträge: 2596
Win7
D2006 WIN32, .NET (C#)
|
Verfasst: 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...
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
      
Beiträge: 1173
Erhaltene Danke: 14
RAD Studio XE2
|
Verfasst: 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.
_________________ Ist Zeit wirklich Geld?
|
|
Udontknow
      
Beiträge: 2596
Win7
D2006 WIN32, .NET (C#)
|
Verfasst: 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...
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,
Udontknow
|
|
|