Entwickler-Ecke

Windows API - Programm bei Parameterübergabe nur 1x starten


JacFab - Sa 25.01.03 16:55
Titel: Programm bei Parameterübergabe nur 1x starten
Ich hab mein Programm für den Dateityp *.bmp registriert, aber möchte, dass alle im Explorer markierten Dateien in der selben Instanz des Programms geöffnet werden. Zur Zeit öffnet jede Datei ein eigenes Fenster. Wie vermeide ich das??


Delete - Sa 25.01.03 17:09

Am besten, indem du

1. einen Mutex für dein Programm schreibst, der nur eine Instanz zulässt
2. mit Hilfe der Nachricht WM_COPYDATA den Parameter jeder weiteren, geladenen Instanz an die bereits laufende weiterreichst


Andreas Pfau - Sa 25.01.03 17:14

Ohne DDE gar nicht (oder nur mit extremem Aufwand). DDE geht so:

Du hast ja in der Registry einen Kea angelegt, sagen wir mal, "HKCR\Paint.Picture\Shell\MeinProg". Dort ist dein Command-Ordner. Im Ordner "MeinProg" (oder so ähnlich) legst du den Ordner "DdeExec" an. Der Standard-String hat den Wert "%1". Unterordner "Application" anlegen, Standard-String = "MeinProg". Zurück in "DdeExec" Unterordner "Topic" anlegen, Standard="OpenFile".

Jetzt lädtst Du dein Delphi-Projekt. Den Code zum auswerten der Parameters löschen, den brauchst du für DDe nicht. Dann fügst du die Komponente "TDDEServerConv" ein, Name = "OpenFile". Im Event "OnExecuteMacro" das hier eintragen:

Quelltext
1:
2:
3:
4:
5:
6:
7:
var
 I: Integer;
begin
 For I := 0 To Msg.Count - 1 Do begin
  If FileExists(Msg[I]) Then
   OpenFile(Msg[I]);
 end;

wobei du OpenFile() delbst deklarieren musst. Die Prozedur lädt ganz einfach die angegebene Datei.


JacFab - Sa 25.01.03 18:11

ja, dann wird das prog nur einmal geöffnet, aber die parameter kommen nur einmal an!


Andreas Pfau - Sa 25.01.03 18:24

Immer, wenn das Ereignis von TDDEServerConv aufgerufen wird, kommen neue Dateinamen. Konsolenparameter gibt's keine mehr, läuft alles über DDE. Evtl. kommen mehrere Dateiamen auf einmal, daher ja auch die Schleife.

Noch fragen? :wink:


Delete - Sa 25.01.03 18:52

Andreas Pfau hat folgendes geschrieben:
Ohne DDE gar nicht (oder nur mit extremem Aufwand).

Sagen wir als Beispiel: ein VCL-Projekt. Eine neue Nachricht und eine Zeile in der Unit bezeichnest du als extremen Aufwand? Dazu kommen im Projektquelltext noch ein paar Zeilen zum Senden des Parameters. :)

Mutex-Code und WM_COPYDATA; als Beispiel im Projektquelltext (*.dpr):

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:
var
  cpydata : TCopyDataStruct;
begin
  hm := CreateMutex(nil,false,'MeinProgramm_Version1.0');
  if(GetLastError = ERROR_ALREADY_EXISTS) then begin

    // Parameter übermitteln
    if(paramcount = 1) then begin
      cpydata.dwData := 0;
      cpydata.cbData := length(paramstr(1)) + 1;
      cpydata.lpData := @paramstr(1)[1];

      // Fenster der alten Instanz suchen
      // (als Beispiel die VCL-Version)
      aWnd := findwindow('TForm1','Form1');
      if(aWnd <> 0) then
        SendMessage(aWnd,WM_COPYDATA,0,LPARAM(@cpydata));
    end;

    // diese Instanz beenden!
    Halt;
  end;

  // der Rest vom DPR-Quelltext
  { ... }

  CloseHandle(hm);
end.

Abfrage des Parameters:

Gruß.


Andreas Pfau - Sa 25.01.03 19:40

Na ja, @Mathias, so geht's auch. Aber eines ist mir ein Dorn im Auge: Wenn ich weder Die caption noch die Klasse kenne (z.B. habe ich ja bei jedem Delphi-Programm "TForm", und Die Caption kann je nach geöffneter Datei anders sein), wie kann ich dann das Fenster-Handle rausfinden? Ich würde das auch so machen wie Du, aber wie kann ich das Handle global speichern? Klar, Registry, aber gibt es auch eine professionelle Lösung???


AndyB - Sa 25.01.03 20:02

Andreas Pfau hat folgendes geschrieben:
Klar, Registry

Da würde ich dann lieber MMFs einsetzen.


Du könntest deinem Formular eine Botschaft hinzufpgen (RegisterWindowMessage) und dann alle Formulare mit EnumWindows durchlaufen. Das Formular, dass eine bestimmte Antwort auf diese Botschaft gibt, ist dann das gesuchte.

Diese Komponente [http://www.andreashausladen.de.vu/down.html?Delphi/Comps/OneInstance.zip] dürfte etwas für dich sein.


Andreas Pfau - Sa 25.01.03 22:00

Danke, @Andy, aber was ist eine MMF? Ehrlich gesagt, das habe ich noch nie gehört und kann mir rein gar nix drunter vorstellen.


Rool - So 02.02.03 18:48
Titel: Irgendwas funzt nicht!!!
Hab die Methode von MathiasSimmack mal ausprobiert, vom Kontext-Menu des Dateityps funktionierts ja, aber wie übergebe ich diese Parameter per Code (ShellExecute) oder mit Start->Ausführen ???
Habs so versucht: "C:\Prog.exe" "Datei1" "Datei2" usw. aber das geht nicht!!!
Was muss ich aufrufen???


GSE - So 02.02.03 20:28

Hab´ was bei Torry gefunden:
http://www.torry.net/samples_software.htm

->How to prevent a second instance
By Theodoros Bebekis. Example on How to prevent a second instance of application and take its parameters.

Funktioniert (verwende es selbst in meinen Programmen)!

mfg
GSE


Delete - So 02.02.03 21:24
Titel: Re: Irgendwas funzt nicht!!!
Rool hat folgendes geschrieben:
aber wie übergebe ich diese Parameter per Code (ShellExecute) oder mit Start->Ausführen ???
Habs so versucht: "C:\Prog.exe" "Datei1" "Datei2" usw. aber das geht nicht!!!
Was muss ich aufrufen???

Da ich via WM_COPYDATA nur den ersten Parameter an die laufende Instanz weiterreiche, sollte der Aufruf von

Quelltext
1:
prog.exe Datei1                    

erfolgreich sein. Die zweite Variante wäre eine for-Schleife, die sich durch die übergebenen Parameter "loopt" und jeden nacheinander an die laufende Instanz weiterreicht. Dann, und wirklich erst dann!, kannst du auch

Quelltext
1:
prog.exe Datei1 Datei2 ...                    

aufrufen.


Rool - Mo 03.02.03 13:58
Titel: Jau...
Ok, alles klar, wenn mans dann noch mit Anführungszeiczhen macht, kann man auch Dateinamen mit Leertasten übergeben!

Danke vielmals!!!


Delete - Mo 03.02.03 15:03

Na ja meine Taste wollte ich schon noch behalten :mrgreen:. Du redest wohl von Leerzeichen :wink:


Rool - Mo 03.02.03 15:33
Titel: ;-)))
Ja logo, sorry natürlich meine ich ZEICHEN!!! :D