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:
- Non-VCL (am Beispiel einer Dialogprozedur):
Quelltext
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18:
| function dlgproc(hwndDlg: HWND; uMsg: UINT; wp: WPARAM; lp: LPARAM): bool; stdcall; var buf : array[0..MAX_PATH]of char; begin Result := true;
case uMsg of WM_COPYDATA: begin ZeroMemory(@buf,sizeof(buf)); lstrcpyn(buf,PCopyDataStruct(lp)^.lpData,PCopyDataStruct(lp)^.cbData);
MessageBox(hwndDlg,buf,'Empfangen ->',0); end; else Result := false; end; end; |
- VCL:
Quelltext
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15:
| type TForm1 = class(TForm) { ... } private procedure WmCopyData(var Msg: TWMCopyData); message WM_COPYDATA; { ... }
procedure TForm1.WmCopyData(var Msg: TWMCopyData); var buf : array[0..MAX_PATH]of char; begin StrLCopy(buf,Msg.CopyDataStruct.lpData,Msg.CopyDataStruct.cbData); MessageBox(Form1.Handle,buf,'Empfangen ->',0); end; |
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
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
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!