Entwickler-Ecke

Sonstiges (Delphi) - Komponente und Form mit .Close .Free sauber beenden


CoWa - Do 21.08.08 14:41
Titel: Komponente und Form mit .Close .Free sauber beenden
Hallo,

Verwendete Delphiversion: 5

Wenn ich auf den Reboot Button Klicke bekomme ich eine Zugriffsverletzung.


Delphi-Quelltext
1:
2:
3:
4:
5:
6:
procedure KeyboardClose();
begin
    Form1.mfSoftkeysControl1.ClosePage;
    Form1.mfSoftkeysControl1.Destroy;
    Form1.mfSoftkeysControl1.free;
end;




Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
procedure TForm1.BTNRebootClick(Sender: TObject);
begin

     KeyboardClose;
     ShellExecute(0'open''shutdown.exe''-r -f -t 0''C:\WINDOWS\SYSTEM32\', SW_SHOWNORMAL);
     Form1.Close;

end;


Wenn ich nur so einen Neustart erzwinge ohne die Form zu schließen bekomme ich die Fehlermeldung das eine Komponente (mfSoftkeysControl1) nicht beendet wurde.

Ideen wie ich das besser lösen kann?

Gruß CoWa


Martin1966 - Do 21.08.08 14:44
Titel: Re: Komponente und Form mit .Close .Free sauber beenden
Keine Ahnung was die Komponente macht aber pack auf jeden Fall das Destroy raus...


Delphi-Quelltext
1:
2:
3:
4:
5:
procedure KeyboardClose();
begin
    Form1.mfSoftkeysControl1.ClosePage;
    Form1.mfSoftkeysControl1.free;
end;


Der Aufruf von Free ruft nämlich intern den Destruktor selbst auf.

Lg, Martin


Boldar - Do 21.08.08 14:44
Titel: Re: Komponente und Form mit .Close .Free sauber beenden
user profile iconCoWa hat folgendes geschrieben:


Delphi-Quelltext
1:
2:
3:
4:
5:
6:
procedure KeyboardClose();
begin
    Form1.mfSoftkeysControl1.ClosePage;
    Form1.mfSoftkeysControl1.Destroy;
    Form1.mfSoftkeysControl1.free; ///Niemals free und destroy gleichzeitig aufrufen!
end;



[edit]Shit...Wo war den da wieder dieses Orange ding??[/edit]


Martin1966 - Do 21.08.08 14:45
Titel: Re: Komponente und Form mit .Close .Free sauber beenden
user profile iconBoldar hat folgendes geschrieben:
Niemals free und destroy gleichzeitig aufrufen!

Soweit ich weiß sollte man NUR destroy nie aufrufen!


Boldar - Do 21.08.08 14:50
Titel: Re: Komponente und Form mit .Close .Free sauber beenden
user profile iconMartin1966 hat folgendes geschrieben:
user profile iconBoldar hat folgendes geschrieben:
Niemals free und destroy gleichzeitig aufrufen!

Soweit ich weiß sollte man NUR destroy nie aufrufen!


Wenn du destroy aufrufst, wird intern schon free aufgerufen. Wenn du dann nochmal free aufrufst, ist es einmal zu viel!


Martin1966 - Do 21.08.08 14:53
Titel: Re: Komponente und Form mit .Close .Free sauber beenden
user profile iconBoldar hat folgendes geschrieben:
Wenn du destroy aufrufst, wird intern schon free aufgerufen.

Nein, eigentlich nicht.

Wenn man Free aufruft wird Destroy intern aufgerufen. Anders herum nicht.

Lg, Martin


Yogu - Do 21.08.08 14:57

Free prüft das Objekt zuerst auf nil und ruft gegebenfalls Destroy auf. Deshalb gelten zwei Regeln:

  1. Rufe Destroy niemals selber auf - dazu ist Free da.
  2. Globale oder kritische Objektvariablen müssen immer entweder auf ein gültiges Objekt zeigen, oder nil sein. Andernfalls würde ein Free auch eine Zugriffsverletzung auslösen. Also: nach Free die Variable immer auf nil setzen, oder einfach gleich FreeAndNil aufrufen.


Martin1966 - Do 21.08.08 15:06

user profile iconYogu hat folgendes geschrieben:
Rufe Destroy niemals selber auf - dazu ist Free da.

Ja, so hab ich es ja schon geschrieben. ;-)

user profile iconYogu hat folgendes geschrieben:
Globale oder kritische Objektvariablen müssen immer entweder auf ein gültiges Objekt zeigen, oder nil sein.

Das sehe ich nicht so. Ein Objekt das ich freigeben will sollte meiner Meinung nach nie NIL sein. Denn das würde ja bedeuten das ich entweder ein Objekt freigeben will das noch gar nicht erstellt wurde oder aber das ich ein Objekt freigeben will welches bereits freigegeben wurde. Beides ist meiner Meinung nach Fehler. Denn: Ein mal ein Objekt erzeugen heißt auch nur (genau) einmal das Objekt wieder freigeben!

user profile iconYogu hat folgendes geschrieben:
Andernfalls würde ein Free auch eine Zugriffsverletzung auslösen. Also: nach Free die Variable immer auf nil setzen, oder einfach gleich FreeAndNil aufrufen.

Genau das soll es ja auch damit ich als Entwickler auf diesen Fehler aufmerksam werde. ;-) FreeAndNil versteckt nur diesen Fehler.

Lg, Martin


Yogu - Do 21.08.08 15:16

Ok, vielleicht siehst du das anders. Aber meiner Meinung nach darf ein Objekt durchaus mal nil sein, bevor ich versuche, es freigebe. Ein Beispiel:

Eine 3D-Engine, die ein Sound-Modul besitzt. Dieses wird nicht automatisch erstellt, sondern durch eine Methode. Eine zweite gibt das Modul wieder frei. Weil die Engine aber saubar geschrieben ist, wird auch beim Entfernen der Engine das Sound-Modul wieder entfernt, falls das nicht manuell geschah. Wenn es jetzt durch die Methode freigegeben wird, muss das Objekt genillt werden, um anzuzeigen, dass es nicht mehr existiert.


Martin1966 - Do 21.08.08 15:33

user profile iconYogu hat folgendes geschrieben:
Weil die Engine aber saubar geschrieben ist,

Da du davon ausgehst, dass der Programmierer, der die Engine verwendet, nicht sauber programmiert hat, musst du das Objekt eventl. selbst freigeben. Ok. Aber das ist denke ich ein Sonderfall. Wie du die Überprüfung machst (ob auf NIL überprüfen oder eine Boolean Variable setzen) ist dann natürlich Geschmacksache.

Lg, Martin


Yogu - Do 21.08.08 15:43

Ok, dann eben noch ein Versuch, dich zu überzeugen: Der Programmierer will nun wissen, ob das Sound-Modul schon initialisiert wurde. Beziehungsweise noch verfügbar ist. Wenn das Modul einfach freigegeben wurde, liefert Assigned(SoundModule) True. Er weiß also nicht, ob er auf das Modul zugreifen darf oder nicht. Bevor du mir jetzt mit einer Boolean-Variable kommst: Wozu eine neue Variable vereinbaren, wo wir doch schon eine haben? Das ist nur eine zusätzliche Fehlerquelle, denn wenn die beiden widersprüchlich sind, dann ist es aus mit der Kontrolle.


Martin1966 - Do 21.08.08 15:54

Ich hatte doch schon angedeutet, dass es bei Bibliotheken eventl. Sinn machen könnte.

Zitat:
Der Programmierer will nun wissen, ob das Sound-Modul schon initialisiert wurde. Beziehungsweise noch verfügbar ist.

Dann stelle ich mal die Frage: Warum weiß der Programmierer das nicht? Entweder er hat das Sound-Modul initialisiert oder eben nicht. ;-) Aber wie auch immer: Ich will jetzt nicht rum diskutieren ob es in einer Bibliothek, wo ein Programmierer von Außen Objekt initialisieren und wieder frei geben kann, sinn macht oder nicht.

Lg, Martin


iKilledKenny - Do 21.08.08 16:00

user profile iconMartin1966 hat folgendes geschrieben:

Das sehe ich nicht so. Ein Objekt das ich freigeben will sollte meiner Meinung nach nie NIL sein. Denn das würde ja bedeuten das ich entweder ein Objekt freigeben will das noch gar nicht erstellt wurde oder aber das ich ein Objekt freigeben will welches bereits freigegeben wurde. Beides ist meiner Meinung nach Fehler. Denn: Ein mal ein Objekt erzeugen heißt auch nur (genau) einmal das Objekt wieder freigeben!


Das sehe ich auch anders, z.B. finde ich folgendes ein sehr elegantes Konstrukt.


Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
var list: TList;

begin
  list := nil;
  try
    if (irgendwas > irgendwasAnderes) then
      Exit;

    list := TList.Create;
    {...}
  finally
    list.Free;
  end;
end;


Martin1966 - Do 21.08.08 16:04

user profile iconiKilledKenny hat folgendes geschrieben:
z.B. finde ich folgendes ein sehr elegantes Konstrukt.

Du findest es also elegant ein Objekt freizugeben welches nicht initialisiert wurde - also Sourcecode umsonst auszuführen? Hm... :gruebel: ich jedenfalls nicht. ;-)

Lg, Martin


iKilledKenny - Do 21.08.08 16:06

Initialisiert schon, aber eben mit nil. Analog verfahre ich auch mit Strings (''), Integern (0) etc.
:tongue:


Yogu - Do 21.08.08 16:12

Den try ... finally-Block brauchst du nur um das Create zu spannen:


Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
var list: TList;
begin
  list := nil;
  if (irgendwas > irgendwasAnderes) then
    Exit;

  list := TList.Create;
  try    
    {...}
  finally
    list.Free;
  end;
end;

Allerdings kommt dann die Meldung, dass list zugewiesen wurde, der Wert aber nicht verwendet wurde. In diesem Fall kannst du die Initialisierung also weglassen. Aus diesem Grund initialisiert Delphi die Variablen nicht - dadurch werden Befehle und somit Zeit gespart. Du solltest Variablen nur dann initialisieren, wenn es auch notwendig ist.


iKilledKenny - Do 21.08.08 16:15

Das Beispiel war vielleicht ein bischen kurz und knapp. Wenn ich solch ein Konstrukt verwende, dann meistens in großen Routinen mit vielen Objekt-Variablen. Am Anfang initialisiere ich die alle mit nil und beim Verlassen ruf ich für alle ein free auf. Damit gehe ich sicher, dass ich jederzeit aus dieser Routine rauspringen kann und kein Speicherleck habe.

Das mit dem Rauspringen im Übrigen deshalb, weil es den Code wesentlich lesbarer macht. Man hat keine 14. Einrückung mehr in der 6 geschachtelten if-Abfrage und solch Zeug.


CoWa - Do 21.08.08 16:39

Hab das .destroy entfernt, Zugriffsfehler bleibt aber erhalten :(


Boldar - Do 21.08.08 16:44

Dann müsstest du vielleicht mehr code rausrücken, meine Kristallkugel hat grad nen Sprung!


elundril - Do 21.08.08 16:44

gibst du vielleicht etwas frei was noch gar nicht exisitiert??

Vielleicht wird die Procedure mit dem Create vorher gar nicht aufgerufen..

lg elundril


mkinzler - Do 21.08.08 16:46

user profile iconelundril hat folgendes geschrieben:
gibst du vielleicht etwas frei was noch gar nicht exisitiert??

Vielleicht wird die Procedure mit dem Create vorher gar nicht aufgerufen..

lg elundril

Dann sollte .Free() das aber erkennen


elundril - Do 21.08.08 16:47

Nicht zwangsläufig, denke ich. Ich habe so das gefühl das bei meinen Programmen, wenn ich da was gefreeed habe was noch nicht existierte das dann das programm gemeckert hat.

lg elundril


jaenicke - Do 21.08.08 18:45

Der Name der freizugebenden Variable sieht für mich so aus als ob es sich um eine Komponente handelt, die auf dem Formular liegt, und falls das so ist, dann sollte man die auch nicht einfach freigeben, denn das geschieht automatisch.

Freigeben sollte man nur, was man auch vorher per Code erstellt hat und was nicht zum automatischen Freigeben bei der Elternkomponente eingetragen wurde.


CoWa - Mo 25.08.08 15:47

So, mal mehr Code:

Sagt mir einfach wo ihr noch etwas sehen wollt:)

Ich kann gezielt per PM auch den kompletten Code versenden.

Gruß Cornelius

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:
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:
104:
105:
106:
107:
108:
109:
110:
111:
112:
113:
114:
115:
116:
117:
118:
119:
120:
121:
122:
123:
124:
125:
126:
127:
128:
129:
130:
131:
132:
133:
134:
135:
136:
137:
138:
139:
140:
141:
142:
143:
144:
145:
146:
147:
148:
149:
150:
151:
152:
153:
154:
155:
156:
157:
158:
159:
160:
161:
162:
163:
164:
165:
166:
167:
168:
169:
170:
171:
172:
173:
174:
175:
176:
177:
178:
179:
180:
181:
182:
183:
184:
185:
186:
187:
188:
189:
190:
191:
192:
193:
194:
195:
196:
197:
198:
199:
200:
201:
202:
203:
204:
205:
206:
207:
208:
209:
210:
211:
212:
213:
214:
215:
216:
217:
218:
219:
220:
221:
222:
223:
224:
225:
226:
227:
228:
229:
230:
231:
232:
233:
234:
235:
236:
237:
238:
239:
240:
241:
242:
243:
244:
245:
246:
247:
248:
249:
250:
251:
252:
253:
254:
255:
256:
257:
258:
259:
260:
261:
262:
263:
264:
265:
266:
267:
268:
269:
270:
271:
272:
273:
274:
275:
276:
277:
278:
279:
280:
281:
282:
283:
284:
285:
286:
287:
288:
289:
290:
291:
292:
293:
294:
295:
296:
297:
298:
299:
300:
301:
302:
303:
304:
305:
306:
307:
308:
309:
310:
311:
312:
313:
314:
315:
316:
317:
318:
319:
320:
321:
322:
323:
324:
325:
326:
327:
328:
329:
330:
331:
332:
333:
334:
335:
336:
337:
338:
339:
340:
341:
342:
343:
unit Unit1;

interface

uses
  Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
  Menus, StdCtrls, ComCtrls, OleServer, KBDLib_TLB, Registry, ShellApi, FileCtrl,
  ExtCtrls;
               
type
  TForm1 = class(TForm)
    PageControlKonfiguration: TPageControl;
    TabSheetAllgemein: TTabSheet;
    TabSheetSystem: TTabSheet;
    TabSheetAnwendung: TTabSheet;
    Sicherheit: TTabSheet;
    TabSheet5: TTabSheet;
    TabSheet6: TTabSheet;
    TabSheet7: TTabSheet;
    TabSheetXPeSpeichern: TTabSheet;
    GroupBoxAdminpasswort: TGroupBox;
    lblPasswort: TLabel;
    EditPassword: TEdit;
    BTNPasswortOK: TButton;
    GroupBoxUserinterface: TGroupBox;
    BTNanwendung: TButton;
    BTNkalibrieren: TButton;
    GroupBoxTouchtastatur: TGroupBox;
    BTNTastaturEin: TButton;
    BTNTastaturAus: TButton;
    TrackBar1: TTrackBar;
    mfSoftkeysControl1: TmfSoftkeysControl;
    Label1: TLabel;
    StaticText1: TStaticText;
    StaticText2: TStaticText;
    GroupBoxComputername: TGroupBox;
    EditComputername: TEdit;
    BTNComputernameAendern: TButton;
    GroupBoxSystemsteuerung: TGroupBox;
    BTNSystemsteuerung: TButton;
    BTNExplorer: TButton;
    BTNCMD: TButton;
    BTNRegedit: TButton;
    BTNEditor: TButton;
    OpenDialog1: TOpenDialog;
    GroupBoxAnwendung: TGroupBox;
    LBLAnwendung: TLabel;
    BTNAnwendung_auswaehlen: TButton;
    Image2: TImage;
    Image1: TImage;
    Image3: TImage;
    Image4: TImage;
    Image5: TImage;
    Image6: TImage;
    Image7: TImage;
    Image8: TImage;
    GroupBoxTaskbar: TGroupBox;
    BTNshowtaskbarOn: TButton;
    BTNshowtaskbarOff: TButton;
    LBLshowtaskbar: TLabel;
    GroupBoxStartbutton: TGroupBox;
    GroupBoxDesktop: TGroupBox;
    BTNShowDesktopOn: TButton;
    BTNShowDesktopOff: TButton;
    BTNShowStartButtonOn: TButton;
    BTNShowStartButtonOff: TButton;
    LBLShowDesktop: TLabel;
    LBLShowStartButton: TLabel;
    GroupBoxShutdownWithoutLogon: TGroupBox;
    GroupBox2: TGroupBox;
    GroupBox3: TGroupBox;
    GroupBoxDisableLockWorkstation: TGroupBox;
    GroupBoxDisableChangePassword: TGroupBox;
    GroupBoxDisableTaskMgr: TGroupBox;
    GroupBox7: TGroupBox;
    GroupBox8: TGroupBox;
    BTNReboot: TButton;
    BTNShutdown: TButton;
    BTNReboot2: TButton;
    BTNShutdown2: TButton;
    BTNShutdownWithoutLogonOn: TButton;
    BTNShutdownWithoutLogonOff: TButton;
    BTNNoShutdownButtonOn: TButton;
    BTNNoShutdownButtonOff: TButton;
    BTNDisableLockWorkstationOn: TButton;
    BTNDisableLockWorkstationOff: TButton;
    BTNDisableChangePasswordOn: TButton;
    BTNDisableChangePasswordOff: TButton;
    BTNDisableTaskMgrOn: TButton;
    BTNDisableTaskMgrOff: TButton;
    Button9: TButton;
    Button10: TButton;
    Button11: TButton;
    Button12: TButton;
    Button13: TButton;
    Button14: TButton;
    LBLShutdownWithoutLogon: TLabel;
    LBLNoShutdownButton: TLabel;
    LBLDisableLockWorkstation: TLabel;
    LBLDisableChangePassword: TLabel;
    LBLDisableTaskMgr: TLabel;
    Label7: TLabel;
    Label8: TLabel;
    Label9: TLabel;
    procedure BTNPasswortOKClick(Sender: TObject);
    procedure FormCreate(Sender: TObject);
    procedure EditPasswordKeyPress(Sender: TObject; var Key: Char);
    procedure TrackBar1Change(Sender: TObject);
    procedure BTNTastaturEinClick(Sender: TObject);
    procedure BTNTastaturAusClick(Sender: TObject);
    procedure EditComputernameKeyPress(Sender: TObject; var Key: Char);
    procedure PageControlKonfigurationChange(Sender: TObject);
    procedure BTNComputernameAendernClick(Sender: TObject);
    procedure BTNSystemsteuerungClick(Sender: TObject);
    procedure BTNExplorerClick(Sender: TObject);
    procedure BTNEditorClick(Sender: TObject);
    procedure BTNRegeditClick(Sender: TObject);
    procedure BTNCMDClick(Sender: TObject);
    procedure BTNkalibrierenClick(Sender: TObject);
    procedure BTNAnwendung_auswaehlenClick(Sender: TObject);
    procedure URL4logistic(Sender: TObject);
    procedure BTNshowtaskbarOnClick(Sender: TObject);
    procedure BTNshowtaskbarOffClick(Sender: TObject);
    procedure BTNShowDesktopOnClick(Sender: TObject);
    procedure BTNShowDesktopOffClick(Sender: TObject);
    procedure BTNShowStartButtonOnClick(Sender: TObject);
    procedure BTNShowStartButtonOffClick(Sender: TObject);
    procedure BTNRebootClick(Sender: TObject);
    procedure BTNShutdownClick(Sender: TObject);
    procedure BTNanwendungClick(Sender: TObject);
    procedure FormClose(Sender: TObject; var Action: TCloseAction);
    procedure BTNShutdownWithoutLogonOnClick(Sender: TObject);
    procedure BTNShutdownWithoutLogonOffClick(Sender: TObject);
  private
    { Private-Deklarationen }
  public
    { Public-Deklarationen }
  end;

var
  Form1: TForm1;
//  Registry: TRegistry;


implementation

{$R *.DFM}


function RegReadStr(rootkey: hkey; Key,Value: String): String;
[...]

function RegReadInt(rootkey: HKEY; Key,Value: String): Integer;
[...]

function RegWriteStr(rootkey: HKEY; Key, Value: String; Content: String): Boolean;
[...]

function RegWriteInt(rootkey: HKEY; Key, Value: String; Content: Integer): Boolean;
[...]

function RegWriteDWORD(rootkey: HKEY; Key, Value: String; Content: DWORD): Boolean;
[...]

function RegReadDWORD(rootkey: HKEY; Key,Value: String): DWORD;
[...]

// Computernamen auslesen
function GetComputerName: string;
[...]

// Computernamen schreiben/aendern
function SetComputerName(AComputerName: string): Boolean;
[...]

procedure ShowTaskBar(AShow: Boolean);
[...]

procedure ShowWindowsStartButton(bvisible: Boolean);
[...]

procedure ShowDesktop(bVisible: boolean);
[...]

procedure KeyboardClose();
begin
    Form1.mfSoftkeysControl1.ClosePage;
//    Form1.mfSoftkeysControl1.Destroy;
    Form1.mfSoftkeysControl1.free;
end;

procedure TForm1.BTNPasswortOKClick(Sender: TObject);
[...]

procedure TForm1.FormCreate(Sender: TObject);
var
  I: Integer;
begin
     // Anwendung aus der Registry auslesen
     LBLAnwendung.Caption := RegReadStr(HKEY_CURRENT_USER,'Software\4logistic\Anwendung\','Default');
     // Trackbar Position = Tastaturtransparenz aus Registry
     TrackBar1.Position := RegReadInt(HKEY_CURRENT_USER,'Software\4logistic\Tastatur\','Blend');
     // PageControl Reiter unsichtbar
with PageControlKonfiguration.Pages[0do
  For I := 0 to PageControlKonfiguration.PageCount-1 do
   PageControlKonfiguration.Pages[I].TabVisible := False;
   // Erster PageControl Reiter sichtbar
   PageControlKonfiguration.Pages[0].TabVisible := TRUE;

// HideTaskbar
[...]

// HideDesktop
[...]

   // HideStartbutton
[...]

// ShutdownWithoutLogon
[...]

// Tastatur nach aktivierung verstecken

mfSoftkeysControl1.Hide;


end;

procedure TForm1.EditPasswordKeyPress(Sender: TObject; var Key: Char);
[...]

procedure TForm1.TrackBar1Change(Sender: TObject);
begin
     // Tastaturtransparenz = Trackbar Position
     mfSoftkeysControl1.Blend := TrackBar1.Position;

     // Aktuelle Trackbar Position/Transparenz in Registry schreiben
     RegWriteInt(HKEY_CURRENT_USER,'Software\4logistic\Tastatur\','Blend',TrackBar1.Position);
end;

procedure TForm1.BTNTastaturEinClick(Sender: TObject);
begin
     // Tastatur-Transparenz aus Registry auslesen
     mfSoftkeysControl1.Blend := RegReadInt(HKEY_CURRENT_USER,'\Software\4logistic\Tastatur\','Blend');

     // Tastatur starten
     mfSoftkeysControl1.Connect;
     // Find the name of the keyboard file
     // s := ChangeFileExt( Application.ExeName, '.kbd' );
     // Load it
     mfSoftkeysControl1.LoadKeyboard( 'C:\Tastatur\BlackWhite_deutsch4.kbd' );
     // Set the Runtime Keyboard position to "Anywhere"
     // The actual positioning (Left/Top) is done in the WM_WindowPosChanging handler
     mfSoftkeysControl1.Position := 4;
     mfSoftkeysControl1.Top := 200;
     TrackBar1.Position := mfSoftkeysControl1.Blend;
     mfSoftkeysControl1.Show;
end;

procedure TForm1.BTNTastaturAusClick(Sender: TObject);
begin
     // Tastatur unsichtbar
     mfSoftkeysControl1.hide;
end;

procedure TForm1.EditComputernameKeyPress(Sender: TObject; var Key: Char);
begin
     // Bei Enter Button klicken
     if key = Char(VK_Return) then
     Form1.BTNComputernameAendern.Click;
end;

procedure TForm1.PageControlKonfigurationChange(Sender: TObject);
[...]

procedure TForm1.BTNComputernameAendernClick(Sender: TObject);
[...]

procedure TForm1.BTNSystemsteuerungClick(Sender: TObject);
[...]

procedure TForm1.BTNExplorerClick(Sender: TObject);
[...]

procedure TForm1.BTNEditorClick(Sender: TObject);
[...]

procedure TForm1.BTNRegeditClick(Sender: TObject);
[...]

procedure TForm1.BTNCMDClick(Sender: TObject);
[...]

procedure TForm1.BTNkalibrierenClick(Sender: TObject);
[...]

procedure TForm1.BTNAnwendung_auswaehlenClick(Sender: TObject);
[...]

procedure TForm1.URL4logistic(Sender: TObject);
[...]

procedure TForm1.BTNshowtaskbarOnClick(Sender: TObject);
[...]

procedure TForm1.BTNshowtaskbarOffClick(Sender: TObject);
[...]

procedure TForm1.BTNShowDesktopOnClick(Sender: TObject);
[...]

procedure TForm1.BTNShowDesktopOffClick(Sender: TObject);
[...]

procedure TForm1.BTNShowStartButtonOnClick(Sender: TObject);
[...]

procedure TForm1.BTNShowStartButtonOffClick(Sender: TObject);
[...]

procedure TForm1.BTNRebootClick(Sender: TObject);
[...]

procedure TForm1.BTNShutdownClick(Sender: TObject);
[...]

procedure TForm1.BTNanwendungClick(Sender: TObject);
[...]

procedure TForm1.FormClose(Sender: TObject; var Action: TCloseAction);
begin
     KeyboardClose;
     PageControlKonfiguration.Free;
     Form1.Free;
end;

procedure TForm1.BTNShutdownWithoutLogonOnClick(Sender: TObject);
[...]

procedure TForm1.BTNShutdownWithoutLogonOffClick(Sender: TObject);
[...]

end.


Tilman - Mo 25.08.08 16:07

Weiß ja net was jetzt genau das problem ist, aber man sollte Komponenten nie in ihrer eigenen Ereignisbehandlung freigeben:


Delphi-Quelltext
1:
2:
3:
4:
5:
6:
procedure TForm1.FormClose(Sender: TObject; var Action: TCloseAction);
begin
     KeyboardClose;
     PageControlKonfiguration.Free;
     Form1.Free;
end;


zitat Delphi-Hilfe:
Zitat:

Warnung: Sie dürfen eine Komponente nie in einer ihrer eigenen Ereignisbehandlungsroutinen oder in einer Ereignisbehandlungsroutine eines untergeordneten Objekts freigeben. Geben Sie beispielsweise auf keinen Fall eine Schaltfläche oder ihr übergeordnetes Formular in der OnClick-Ereignisbehandlungsroutine der Schaltfläche frei.

Um ein Formular freizugeben, ruften Sie seine Methode Release auf. Dadurch wird sichergestellt, dass das Formular erst aus dem Speicher entfernt wird, wenn die Ausführung seiner eigenen und der Ereignisbehandlungsroutinen seiner Komponenten beendet ist.


CoWa - Mo 25.08.08 16:16

Hab deinen Vorschlag beherzigt und Form1.free auskommentiert.

Problem: Wenn ich TForm1.BTNRebootClick ausführe erhalte ich einen Zugriffsfehler


CoWa - Mo 25.08.08 16:41

Nachdem ich Form1.Free entfernt habe bekomme ich wieder die "Com Server Warning" Fehlermeldung. (Siehe Anhang)


Boldar - Di 26.08.08 19:43

dann nimm halt form1.release!!!


CoWa - Do 28.08.08 14:45

Danke dir! :) Vielen dank. Deine Loesung funktioniert. Werde mir mal den Unterschied zwischen .free .close und .release durchlesen.