Entwickler-Ecke

Windows API - Probleme mit ShellExecute


Hybrid - Sa 29.11.03 16:40
Titel: Probleme mit ShellExecute
Also, ich will per Variable einpaar Buttons erstellen und mit onclick und ShellExecute ein beliebiges Programm, bzw. Datei ausführen. Aber ich bekomme immer die Fehlermeldung:

[Fehler] Unit1.pas(51): Inkompatible Typen: 'TNotifyEvent' und 'Cardinal'

So weit bin ich bisher:


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:
var
  Form1: TForm1;hallo:string;
  Pfad,button,Titel,Path:array of String;
  buttons : array of Tbutton;
  ini:Tinifile;

...

procedure TForm1.FormCreate(Sender: TObject);
VAR i,n:integer;
begin
n:=3;
n:=n-1;
SetLength(Titel,n+1);
SetLength(path,n+1);

hallo:='c:';

 for i:=0 TO n DO
  begin

    Titel[i]:='c:';  //<-für Testzwecke

    SetLength(buttons, Length(buttons)+1);
    buttons[i]:=TButton.Create(self);
    with buttons[i] do
    begin
      parent:=form1;
      height:=50;
      width:=50;
      left:=1;
      top:=i*50;
      name:='command'+IntToStr(i+1);
      caption:=titel[i];
      OnClick:=ShellExecute(Handle, 'OPEN', PChar(path[i]), '', '', SW_SHOWNORMAL);
    end;
  end;
end;


Verbesserungsvorschläge nehme ich gerne an!


StefanH - Sa 29.11.03 16:53

also...
gugg mal:

Delphi-Quelltext
1:
2:
3:
4:
n:=3; 
n:=n-1; 
SetLength(Titel,n+1); 
SetLength(path,n+1);


du setzt n auf 3, dann ziehst du eins ab, und dann addierst du eins... wozu???
einfach

Delphi-Quelltext
1:
2:
3:
4:
5:
SetLength(Titel,3); 
SetLength(path,3);

hallo:='c:'; 
 for i:=0 TO 2 DO

reicht doch...

das waren die Verbesserungsvorschläge...

und nun zur Fehlermeldung:
so musst du das machen:



Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
...
procedure BtnClick(i: integer);
begin
ShellExecute(Handle, 'OPEN', PChar(path[i]), '', '', SW_SHOWNORMAL); 
end;

procedure TForm1.FormCreate(Sender: TObject); 
VAR i:integer; 
begin
...
OnClick:= BtnClick(i);
...


Sollte gehen,
Stefan


Hybrid - Sa 29.11.03 17:12

Ich hab jetzt alles eingesetzt, bekomme aber dennoch Fehlermeldungen.
Ich schreib jetzt mal den kompletten Quelltext auf:


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:
unit Unit1;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, StdCtrls, shellapi;

type
  TForm1 = class(TForm)
    procedure FormCreate(Sender: TObject);
  private
    { Private-Deklarationen }
  public
    { Public-Deklarationen }
  end;

var
  Form1: TForm1;hallo:string;
  Pfad,button,Titel,Path:array of String;
  buttons : array of Tbutton;

implementation

{$R *.dfm}

procedure BtnClick(i: integer);
begin
   ShellExecute(Handle, 'OPEN', PChar(path[i]), '', '', SW_SHOWNORMAL);
end;

procedure TForm1.FormCreate(Sender: TObject);
VAR n,i:INTEGER;
begin
n:=4;
SetLength(Titel,n);
SetLength(path,n);

 for i:=0 TO n DO
  begin
   Titel[i]:='c:';  //<-für Testzwecke
    SetLength(buttons, Length(buttons)+1);
    buttons[i]:=TButton.Create(self);
    with buttons[i] do
    begin
      parent:=form1;
      height:=50;
      width:=50;
      left:=1;
      top:=i*50;
      name:='command'+IntToStr(i+1);
      caption:=titel[i];
      OnClick:= BtnClick(i);
    end;
  end;
end;

end.


Hier die Fehlermeldungen:
[Fehler] Unit1.pas(30): Undefinierter Bezeichner: 'Handle'
[Fehler] Unit1.pas(54): Inkompatible Typen: 'TNotifyEvent' und 'procedure, untyped pointer or untyped parameter'


Delete - Sa 29.11.03 17:24

Bei der Button-Click Prozedur darf nicht als Parameter ein Integer übergeben werden, sondern es muss ein TObject sein. Kuck dir mal die Methoden an, die die IDE automatisch generiert. Und kuck mal in der Hilfe wie ein TNotifyEvent aufgebaut sein muss.


Chatfix - Sa 29.11.03 18:48

Schreib mal anstatt


Delphi-Quelltext
1:
ShellExecute(Handle, 'OPEN', PChar(path[i]), '', '', SW_SHOWNORMAL);                    


das hier:


Delphi-Quelltext
1:
ShellExecute(Handle, 'OPEN', PChar(path[i]), nil, nil, SW_SHOWNORMAL);                    


habs bei mir probiert und hab keine fehler


Hybrid - Sa 29.11.03 19:01

Klappt alles nicht. :(
Wenn einer weiß wie das geht bitte ich ihn hier mal einen funktionierenden Quelltext einzufügen, damit ich da mal besser durchblicken kann.


Christian S. - Sa 29.11.03 19:25

Poste doch mal, was Du ausprobiert hast. Mit Luckies Hinweis solltest Du schon verdammt dicht dran sein.

Dein BtnClick war ansich schon nicht schlecht. Lediglich der Parameter war nicht wie bei einem NotifyEvent und außerdem muss es, soweit ich weiß, eine Memberprozedur von Form1 sein.

Wie Luckie schon sagte: schau Dir die Hilfe zu TNotifyEvent an und außerdem das, was die IDE Dir für einen Buttonklick erzeugt.


Hybrid - Sa 29.11.03 19:56

Ich hab vorkurzem erst mit Delphi angefangen und befasse mich zum erstem mal mit Komponenten die per Quelltext erstellt werden. Deshalb bitte ich um verständniss dass ich nicht alle Begriffe kenne.

Ich hab bisher die Quelltexte ausprobiert die ich auch gepostet habe.
Außerdem habe ich den Code von chatfix einmal bei der prozedur BtnClick angewendet und später - als es nicht funktionierte - bei OnClick:= getestet.
Hat net funktioniert.
Aus der Delphi Hilfe werd ich nicht schlau, da steht nur:

Zitat:
Der Typ TNotifyEvent wird für Ereignisse ohne Parameter verwendet.

Unit

Classes

type TNotifyEvent = procedure (Sender: TObject) ofobject;

Beschreibung

TNotifyEvent ist der Typ für Ereignisse, die keine Parameter benötigen. Diese Ereignisse benachrichtigen einfach die Komponente, daß ein bestimmtes Ereignis aufgetreten ist. So benachrichtigt beispielsweise OnClick
(Typ TNotifyEvent) das Steuerelement, daß im Steuerelement ein Klickereignis stattgefunden hat.

Der Parameter Sender ist das Objekt, dessen Ereignisbehandlungsroutine aufgerufen wird. Beispielsweise ist bei einem OnClick-Ereignis einer Schaltfläche der Parameter Sender die Schaltflächenkomponente, die angeklickt wurde.


Daraus werd ich überhaupt nicht schlau.

Es währe sehr net wenn einer von euch der ahnung von Delphi hat einfachmal den quelltext von weiter oben nehmen, verbessern und dann wieder hier einfügen würde.


Christian S. - Sa 29.11.03 20:34

Okay. Die Prozedur "BtnClick" muss so aussehen:


Delphi-Quelltext
1:
2:
3:
4:
procedure TForm1.BtnClick(Sender : TObject);
begin
  ShellExecute(handle,'open',PChar(exename),'',PChar(ExtractFilePath(exename)),SW_SHOWNORMAL);
end;


Und dann sollte die Zuweisung OnClick := BtnClick auch funktionieren. BtnClick muss natürlich noch im Interface-Teil verewigt werden.

Da ich das Ganze im Browser geschrieben habe, kann es sein, das das noch Fehler drin sind.

Ach ja, und "exename" gibt es bei Dir wahrscheinlich auch nicht, ist einfach die Datei, die gestartet werden soll.

MfG
Peter


Hybrid - So 30.11.03 18:40

Das Programm läuft soweit richtig, allerdings bekomme ich beim starten immer diese Fehlermeldung, obwohl es funktioniert.

user defined image

Außerdem muss die onclick prozedur für jeden button extra konfiguriert werden können, da jeder etwas anderes öffnet, und zwar mit dem path array.
Wenn ich nun wie zuvor OnClick:=BtnClick(i); schreibe bekomme ich folgende fehlermeldung:

[Fehler] Unit1.pas(56): Inkompatible Typen: 'TObject' und'Integer'

Ich kenne zwar Funktionen wie IntToStr(i) und ähnliche, aber wie man aus einem Integer ein TObject macht weiß ich leider nicht.

Hier ist der jetztige Scriptstand:


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:
unit Unit1;

interface


uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, 
  Dialogs, StdCtrls, shellapi;

type
  TForm1 = class(TForm)
    procedure BtnClick(Sender : TObject);
    procedure FormCreate(Sender: TObject);
  private
    { Private-Deklarationen }
  public
    { Public-Deklarationen }
  end;

var
  Form1: TForm1;hallo:string;
  Titel,Path:array of String;
  buttons : array of Tbutton;

implementation

{$R *.dfm}

procedure TForm1.BtnClick(Sender : TObject);
begin
  ShellExecute(handle,'open',PChar(path[1]),'',PChar(ExtractFilePath(path[1])),SW_SHOWNORMAL);
end;

procedure TForm1.FormCreate(Sender: TObject);
VAR n,i:INTEGER; 
begin 
n:=4; 
SetLength(Titel,n);
SetLength(path,n);
 for i:=0 TO n DO
  begin
   Titel[i]:='c:';  //<-für Testzwecke
   Path[i]:='c:';   //<-für Testzwecke

    SetLength(buttons, Length(buttons)+1);
    buttons[i]:=TButton.Create(self); 
    with buttons[i] do 
    begin 
      parent:=form1; 
      height:=50; 
      width:=50; 
      left:=1; 
      top:=i*50; 
      name:='command'+IntToStr(i+1); 
      caption:=titel[i]; 
      OnClick:=BtnClick;
    end;
  end;
end; 

end.


Christian S. - So 30.11.03 18:49

Woher diese Meldung kommt, weiß ich nicht. In welcher Zeile tritt die auf?

Wenn Du wirklich das gelesen hast, was hier schon mehrfach geschrieben wurde, sollte Dir eigentlich klar sein, dass BtnClick(i) nicht funktionieren kann.

Wenn Du mit einem Patharray arbeiten willst, solltest Du jedem Button über die Tag-Eigenschaft eine Nummer geben. Die kannst Du im BtnClick dann abfragen und den entsprechenden Pfad verwenden.

MfG
Peter


Keldorn - So 30.11.03 18:56


Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
SetLength(Titel,n);
SetLength(path,n);
 for i:=0 TO n DO
  begin
   Titel[i]:='c:';  //<-für Testzwecke
   Path[i]:='c:';   //<-für Testzwecke

    SetLength(buttons, Length(buttons)+1); 
    ...

muß ja in die Hose gehen.
wenn n=4 reservierst du für 4 Elemnte bei setlength platz. mit der for-Schleife greift du auf das 5. element zu (0,1,2,3,4) und bist außerhalb des Array-bereiches.

Delphi-Quelltext
1:
SetLength(Titel,n+1);                    

wäre in deinem Fall besser.
Zitat:

SetLength(buttons, Length(buttons)+1);

is auch nicht so gut. Besser ist es, die Anzahl einmalig zu reservieren und nicht einzeln in einer Schleife.

Mfg Frank


Hybrid - So 30.11.03 19:54

Soweit so gut, dank keldorn ist der fehler weg.
Aber wie kann ich vernümpftig die Tag eigenschaft der buttons abfragen?
Wenn ich in BtnClick einfach nur i:=tag eingebe kommt da immer nur 0 raus.


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:
procedure TForm1.FormCreate(Sender: TObject);
VAR n,i:INTEGER;
begin
n:=3;
SetLength(Titel,n+1);
SetLength(path,n+1);
Path[0]:='c:';   //<-für Testzwecke
Path[1]:='d:';   //<-für Testzwecke
Path[2]:='';   //<-für Testzwecke
Path[3]:='e:';   //<-für Testzwecke
 for i:=0 TO n DO
  begin
   Titel[i]:='c:';  //<-für Testzwecke
    SetLength(buttons, Length(buttons)+1);
    buttons[i]:=TButton.Create(self);
    with buttons[i] do
    begin
      parent:=form1;
      height:=50;
      width:=50;
      left:=1;
      top:=i*50;
      name:='btn'+IntToStr(i+1);
      Tag:=i;
      caption:=titel[i];
      OnClick:=BtnClick;
    end;
  end;
end;

procedure TForm1.BtnClick(Sender : TObject);
var i:integer;
begin
  i:=Tag;
  ShellExecute(handle,'open',PChar(path[i]),'',PChar(ExtractFilePath(path[i])),SW_SHOWNORMAL);
  label1.caption:=inttostr(tag);
end;


Das label ist übrigens nur zum testen.
Die tags bei den buttons sind aber richtig verteilt, von 0-n.


Christian S. - So 30.11.03 20:07

Hallo!

Das da Null rauskommt, verstehe ich nicht. Eigentlich müsste er bei Deiner Version ne Fehlermeldung beim kompilieren rausschmeissen ...

Du machst es so:

Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
procedure TForm1.BtnClick(Sender : TObject); 
var i:integer; 
begin 
  if Sender is TButton then
    i:=TButton(Sender).Tag;

  ShellExecute(handle,'open',PChar(path[i]),'',PChar(ExtractFilePath(path[i])),SW_SHOWNORMAL); 
  label1.caption:=inttostr(i); 
end;


Wenn Du sonst alles richtig gemacht hast, sollte es so funktionieren.

MfG
Peter


Hybrid - So 30.11.03 20:17

Danke jetzt funktioniert alles, allerdings wird folgende meldung beim starten ausgegeben:

[Warnung] Unit1.pas(65): Variable 'i' ist möglicherweise nicht initialisiert worden

welche sich auf folgende zeile bezieht (rot):


Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
procedure TForm1.BtnClick(Sender : TObject);
var i:integer;
begin
  if Sender is TButton then
   i:=TButton(Sender).Tag;
<span style="color: red">ShellExecute(handle,'open',PChar(path[i]),'',PChar(ExtractFilePath(path[i])),SW_SHOWNORMAL);</span>
end;


Anonymous - So 30.11.03 20:24

probiers mal so:


Delphi-Quelltext
1:
2:
3:
4:
5:
 if Sender is TButton then 
 begin
   i:=TButton(Sender).Tag; 
 hellExecute(handle,'open',PChar(path[i]),'',PChar(ExtractFilePath(path[i])),SW_SHOWNORMAL); 
 end;


Hybrid - So 30.11.03 20:29

Jo, danke jetzt ist es perfekt.
Und hier noch für alle anderen die das später noch lesen das komplette Script:


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:
unit Unit1;

interface


uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, 
  Dialogs, StdCtrls, shellapi;

type
  TForm1 = class(TForm)
    procedure BtnClick(Sender : TObject);
    procedure FormCreate(Sender: TObject);
  private
    { Private-Deklarationen }
  public
    { Public-Deklarationen }
  end;

var
  Form1: TForm1;
  Titel,Path:array of String;
  buttons : array of Tbutton;

implementation

{$R *.dfm}

procedure TForm1.FormCreate(Sender: TObject);
VAR n,i:INTEGER;
begin
n:=3;
SetLength(Titel,n+1);
SetLength(path,n+1);
Path[0]:='c:';   //<-für Testzwecke
Path[1]:='d:';   //<-für Testzwecke
Path[2]:='';   //<-für Testzwecke
Path[3]:='e:';   //<-für Testzwecke
 for i:=0 TO n DO
  begin
   Titel[i]:='c:';  //<-für Testzwecke
    SetLength(buttons, Length(buttons)+1);
    buttons[i]:=TButton.Create(self);
    with buttons[i] do
    begin
      parent:=form1;
      height:=50;
      width:=50;
      left:=1;
      top:=i*50;
      name:='btn'+IntToStr(i+1);
      Tag:=i;
      caption:=titel[i];
      OnClick:=BtnClick;
    end;
  end;
end;

procedure TForm1.BtnClick(Sender : TObject);
var i:integer;
begin
if Sender is TButton then  
 begin
   i:=TButton(Sender).Tag;
 ShellExecute(handle,'open',PChar(path[i]),'',PChar(ExtractFilePath(path[i])),SW_SHOWNORMAL);
 end;
end;
end.