Delphi-PRAXiS
Seite 1 von 2  1 2      

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Win32/Win64 API (native code) (https://www.delphipraxis.net/17-win32-win64-api-native-code/)
-   -   Delphi Problem mit Dateiaufruf per paramstr (https://www.delphipraxis.net/7254-problem-mit-dateiaufruf-per-paramstr.html)

wb32 7. Aug 2003 10:39


Problem mit Dateiaufruf per paramstr
 
Also folgendes Problem:

Habe ein programm das sich im Contextmenü einträgt.
Wenn ich eine Datei über den Eintrag im CMenü auswähle

startet mein Programm 1x und hat im paramstr(1) den Pfad zur Datei die gewählt wurde...

Wenn ich mehr als eine datei aufrufe sollen diese natürlich auch von meinem programm geöffnet werden mein programm startet aber bei 3 dateien dann 3x ???

es soll aber nur 1x starten und die anderen dateien ebanfalls bearbeiten...

Lösungsansatz:

das Programm darf nur einmal starten und muss wenn es bemerkt das es mehrfach gestartet wurde sich selbst beenden und den jeweiligen paramstr(1) an das ersdte gestartet programm senden

Code:
// ===================================================
Initialization
mHandle:=CreateMutex(nil,True,'my_programm');
if GetLastError=ERROR_ALREADY_EXISTS then begin
// hier die Daten senden ??? wenn ja wie ?
 Halt;
end;
finalization
if mHandle<>0 then CloseHandle(mHandle)
end.

Danke für Eure Hilfe :spin:

negaH 7. Aug 2003 12:28

Re: Problem mit Dateiaufruf per paramstr
 
Delphi-Quellcode:

const
  cMagic = $1234567;
  cResult = $7654321;
  sTitle = 'my_program$XY12345678_Moeglichst_Eindeutiger_Name';
           // als sTitle kann auch ParamStr(0) herhalten
 
var
  WndHandle: hWnd = 0;

type
  TSingleInstance = class
    class procedure WndProc(var Msg: TMessage);
    class procedure Start;
    class procedure Stop;
  end;

class function TSingleInstance.WndProc(var Msg: TMessage);
var
  Param: String;
begin
  with Msg do
    if (Msg = wm_CopyData) and (PCopyDataStruct(lParam).cwData = cMagic) then
    begin
      Param := PCopyDataStruct(lParam).lpData;
      OpenFile(Param); // o.ä.
      Result := cResult;
    end else
      Result := DefWindowProc(WndHandle, Msg, wParam, lParam);
end;

class procedure TSingleInstance.Start;
var
  PrevWnd: hWnd;
  Data: TCopyDataStruct;
  Param: String;
begin
  PrevWnd := FindWindow('TPUtilWindow', sTitle);
  if IsWindow(PrevWnd) then
  begin
    Param := ParamStr(1);
    Data.cwData := cMagic;
    Data.cbData := Length(Param) +1;
    Data.lpData := Pointer(Param);
    if SendMessage(PrevWnd, wm_CopyData, 0, Integer(@Data)) = cResult then ; // erfolgreich
    Halt;
  end;
  WndHandle := AllocateHWnd(WndProc);
  SetWindowText(WndHandle, sTitle);
end;

class procedure TSingleInstance.Stop;
begin
  if IsWindow(WndHandle) then DeallocateHWnd(WndHandle);
end;

initialization
  TSingleInstance.Start;
finalization
  TSingleInstance.Stop;
end;
Unter Win9x werden Mutexe/Atome/Semaphore usw. nicht mehr korrekt freigeben falls die Anwednung crasht. Dadurch könnte es passieren das eine einmal gecrashte Anwendung nicht erneut gestartet werden kann, da der globale benammte Mutex noch existiert. ABER!, das feine ist das Fensterhandles auch unter Win9x ungültig werden wenn die Anwendung gecrasht ist. Deshalb nutzen wir oben ein Fensterhandle mit möglichst eindeutigen Namen um 1. zu erkennen ob unsere Anwendung schon läuft und 2. gleichzeigt als Transportweg um ParamStr(1) zu übertragen.

Allerdings auch diese Methode hat ihre Nachteile, z.b. bei Services die in einer anderen WinSta laufen.

Gruß Hagen

PS: obiger Code ist nur aus'm Gedächtnis, also keine Garantie das alles absolut korrekt ist ;)

Luckie 7. Aug 2003 14:26

Re: Problem mit Dateiaufruf per paramstr
 
Kommt so erst mal in die Code-Lib. Irgendwelche Vorschlage für eine Überschrift, die kurz und aussagekräftig ist?

@Hagen: Das mit dem Schlüsselwort class vor den Methoden der Klasse sehe ich zum ersten mal. Dient das nur der Lesbarkeit oder hat das noch einen tieferen Sinn?

wb32 7. Aug 2003 14:47

Re: Problem mit Dateiaufruf per paramstr
 
wäre jemand so nett den source oben etwas näher zu erläutern ??

ich will ihn nicht nur kopieren sondern auch verstehen :)

danke ...

wb32 7. Aug 2003 14:58

Re: Problem mit Dateiaufruf per paramstr
 
[Fehler] Unit1.pas(101): Funktion benötigt Ergebnistyp
[Fehler] Unit1.pas(106): Undefinierter Bezeichner: 'cwData'
[Warnung] Unit1.pas(106): Der Vergleich ergibt immer Falsch
[Fehler] Unit1.pas(108): Inkompatible Typen: 'String' und 'Pointer'
[Fehler] Unit1.pas(109): Inkompatible Typen: 'String' und 'PChar'
[Fehler] Unit1.pas(121): Inkompatible Typen: 'String' und 'PChar'
[Fehler] Unit1.pas(125): Undefinierter Bezeichner: 'cwData'
[Warnung] Unit1.pas(131): Symbol 'AllocateHWnd' wird abgelehnt
[Warnung] Unit1.pas(137): Symbol 'DeallocateHWnd' wird abgelehnt
[Fataler Fehler] filekiller.dpr(5): Verwendete Unit 'Unit1.pas' kann nicht compiliert werden

Luckie 7. Aug 2003 15:03

Re: Problem mit Dateiaufruf per paramstr
 
Das muß dwData heißen.
Den String kannst du einfach nach PChar casten.

Desweiteren helfen uns deine Zeilennummern nicht wirklich. Gib mal die Stellen im Code an.

wb32 7. Aug 2003 16:03

Re: Problem mit Dateiaufruf per paramstr
 
ich glaube ich weiß wo mein problem liegt ...

ich will das eine *.exe einzelne dateien als auch mehrere datein löschen kann...

wenn ich das versuche mit den hier genannten beispielen zu lösen passiert folgendes:

3 Dateien ausgewählt -> myprogramm.exe startet 3x

exe1 heisst 'myprogramm' soll da bleiben und daten von 2,3 empfangen
exe2 heisst 'myprogramm' soll paramstr(1) an 1 exe senden + schliessen
exe3 heisst 'myprogramm' soll paramstr(1) an 1 exe senden + schliessen

und genau da ist das problem, in dem moment wenn ich sende sind läuft mein programm mehr als 1 mal...

wie kann ich das lösen ?

negaH 7. Aug 2003 16:37

Re: Problem mit Dateiaufruf per paramstr
 
@wb32: so wie oben angedeutet. Der Source ist allerdings eben aus dem Gedächtnis und NICHT garantiert lauffähig.

@Lucki: Ich werde den Source lieber nochmal überarbeiten, so daß er auch tatsächlich funktioniert (per Copy&Paste, war aber eigentlich nicht so gedacht von mir :)

Zur Frage mit dem Klassen Methoden -> class function ...
Ja dies ist absolut notwendig, zumindestens für class procedure WndProc(). Diese Deklaration ist Typkompatibel mit TWndMethod die ja in AllocateHWnd(TSingleInstance.WndProc) benötigt wird. Normalerweise deklarieren wir ein TObject mit procedure WndMethod(), erzeugen ein solches Object um dann AllocateHWnd(MyObject.WndProc) benutzen zu können. Wir müssten im Normalfall also immer eine Objectinstance erzeugen. Um dies nicht machen zu müssen gibt es zwei Wege: 1.) über den obigen Klassenmethoden Weg oder 2.) über ein getürktes Event bei TMethod(Event).Code := @Procedure. Der Weg über Klassenmethoden ist aber sauberer.
Um nun alles noch sauberer zu kapseln habe ich gleich noch die Methoden .Start und .Stop als Klassenmethode deklariert.

Gruß Hagen

wb32 7. Aug 2003 16:50

Re: Problem mit Dateiaufruf per paramstr
 
also ich hab folgende idee...

1 programmstart form1.caption:='myprogramm';

dann prüfen ob mehrfachstart vorliegt

2,3,4,5,6 form1.caption:='xxxxxxxxx';

dann einfach an 'myprogramm' senden...

geht das so ?

irgendwas stimmt am source aber nicht...

Code:
procedure TForm1.FormShow(Sender: TObject);
begin

if ParamCount > 0 then begin
 Form1.Caption:= 'myprogramm';

 mHandle := CreateMutex(nil,True, 'myprogram_45zg556z5g43');
 Memo1.Lines.Add(SysErrorMessage(GetLastError)); // das funktioniert

 if GetLastError=ERROR_ALREADY_EXISTS then begin // das funktioniert nicht
  Form1.Caption:= 'xxxxxxxxx';
 end;

end;
was stimmt da nicht ?

wb32 7. Aug 2003 16:53

Re: Problem mit Dateiaufruf per paramstr
 
ok ich glaube ich habs, die funktion getlaserror ist nach dem aufruf leer richtig ?

negaH 7. Aug 2003 18:41

Re: Problem mit Dateiaufruf per paramstr
 
Hier also die lauffähige Version. Einfach diese Unit in das Projekt einbinden und die Methode TSingleInstance.OnStartUp mit eigenen Leben füllen. Nicht vergessen den Wert sTitle mit einem eigenen eindeutigen Wert zu ändern.

Gruß Hagen

Delphi-Quellcode:
unit SingleInstance;

interface

implementation

uses Windows, SysUtils, Controls, Messages, Dialogs, Forms;

type
  TSingleInstance = class
    class procedure WndProc(var Msg: TMessage);
    class procedure Start;
    class procedure Stop;
    class function GetParamStr(P: PChar; var Param: string): PChar;
    class function ParamCount: Integer;
    class function ParamStr(Index: Integer): string;

    class procedure OnStartup;
  end;

const
  sTitle = 'my_ProgramXYZ$123456789'; // dieser Wert MUSS individuell angepasst werden

class procedure TSingleInstance.OnStartup;
// diese Methode muß mit eigenen Inhalt gefüllt werden,
// als Beispiel wird hier die 1. Instance sichtbar gemacht
// und der ParamStr() der 2. Instance angezeigt.
var
  S: String;
  I: Integer;
begin
  Application.Minimize;
  Application.Restore;

  S := '';
  for I := 0 to ParamCount do
    S := S + ParamStr(I) + #10;
  ShowMessage(S);
end;

// ab hier Implementierung

const
  cMagic = $BADF00D; // dient zur Idententifizierung der Message wm_CopyData
  cResult = $DAED;

var
  WndHandle: hWnd = 0; // die 1. Instance erzeugt ein Fensterhandle
  CmdLine: PChar = nil; // ParamStr() der 2. Instance per wm_CopyData transportiert

class function TSingleInstance.GetParamStr(P: PChar; var Param: string): PChar;
// diese funktion musste aus System.pas kopiert werden für unser
// ParamStr() udn ParamCount() nötig
var
  Len: Integer;
  Buffer: array[0..4095] of Char;
begin
  while True do
  begin
    while (P[0] <> #0) and (P[0] <= ' ') do Inc(P);
    if (P[0] = '"') and (P[1] = '"') then Inc(P, 2) else Break;
  end;
  Len := 0;
  while (P[0] > ' ') and (Len < SizeOf(Buffer)) do
    if P[0] = '"' then
    begin
      Inc(P);
      while (P[0] <> #0) and (P[0] <> '"') do
      begin
        Buffer[Len] := P[0];
        Inc(Len);
        Inc(P);
      end;
      if P[0] <> #0 then Inc(P);
    end else
    begin
      Buffer[Len] := P[0];
      Inc(Len);
      Inc(P);
    end;
  SetString(Param, Buffer, Len);
  Result := P;
end;

class function TSingleInstance.ParamCount: Integer;
// diese Funktion musste aus System.pas kopiert werden für unser
// ParamStr() und ParamCount() nötig da System.pas NICHT auf die
// globale Variable System.CmdLine zugreift sondern per Funktion GetCommandLine() arbeitet.
var
  P: PChar;
  S: string;
begin
  P := GetParamStr(CmdLine, S); // CmdLine statt GetCommandLine
  Result := 0;
  while True do
  begin
    P := GetParamStr(P, S);
    if S = '' then Break;
    Inc(Result);
  end;
end;

class function TSingleInstance.ParamStr(Index: Integer): string;
// siehe ParamCount
var
  P: PChar;
  Buffer: array[0..260] of Char;
begin
  if Index = 0 then
    SetString(Result, Buffer, GetModuleFileName(0, Buffer, SizeOf(Buffer)))
  else
  begin
    P := CmdLine; // CmdLine statt GetCommandLine
    while True do
    begin
      P := GetParamStr(P, Result);
      if (Index = 0) or (Result = '') then Break;
      Dec(Index);
    end;
  end;
end;

class procedure TSingleInstance.WndProc(var Msg: TMessage);
// das ist die Fensterprocedure von WndHandle, sie empfängt innerhalb
// der 1. Instance die wm_CopyData Message mit der CommandLine der
// 2. Instance
begin
  with Msg do
    if (Msg = wm_CopyData) and (PCopyDataStruct(lParam).dwData = cMagic) then
    begin
      Result := cResult;
      CmdLine := PCopyDataStruct(lParam).lpData;
      OnStartup;
    end else Result := DefWindowProc(WndHandle, Msg, wParam, lParam);
end;

class procedure TSingleInstance.Start;
var
  PrevWnd: hWnd;
  Data: TCopyDataStruct;
begin
  if MainInstance = GetModuleHandle(nil) then // nur in EXE's möglich, nicht in DLL's oder packages
  begin
    PrevWnd := FindWindow('TPUtilWindow', sTitle); // suche unser Fenster
    if IsWindow(PrevWnd) then
    begin
    // 1. Instance läuft also schon, sende CommandLine an diese
      Data.dwData := cMagic;
      Data.cbData := StrLen(GetCommandLine) +1;
      Data.lpData := GetCommandLine;
      if SendMessage(PrevWnd, wm_CopyData, 0, Integer(@Data)) = cResult then Halt;
    end;
   // keine 1. Instance gefunden, wir sind also die 1. Instance
    WndHandle := AllocateHWnd(WndProc);
    SetWindowText(WndHandle, sTitle);

// falls auch bei der 1. Instance OnStartup aufgerufen werden soll
//    CmdLine := System.CmdLine;
//    OnStartup;
  end;
end;

class procedure TSingleInstance.Stop;
begin
  if IsWindow(WndHandle) then DeallocateHWnd(WndHandle);
end;

initialization
  TSingleInstance.Start;
finalization
  TSingleInstance.Stop;
end.

wb32 7. Aug 2003 21:43

Re: Problem mit Dateiaufruf per paramstr
 
tut mir leid das is mir zu hoch kann sich mal jemand meinen source ansehen bitte... es funktioniert einwandfrei ausser das beim zuerst gestarteten programm der falsche paramstr ankommt...


Code:

procedure TForm1.WndProc(var msg : TMessage);
begin
  if msg.Msg = dwMessage then begin
    if msg.lParam <> 0 then begin
      m1.Lines.Add(PChar(msg.lParam));
    end else begin
      if msg.WParam > -1 then begin
        m1.Lines.Add(IntToStr(msg.wParam));
      end else begin
         m1.Lines.Add('Keine Daten...');
      end;
    end;
  end else begin
    inherited WndProc(msg);
  end;
end;

function FindSyncDemo(const p_hWindow : DWORD;const p_szCaption : PChar) : Boolean; stdcall;
var
  dwLen : DWORD;
  szWork : PChar;
begin
  Result := true;
  dwLen := SendMessage(p_hWindow,WM_GETTEXTLENGTH,0,0) + 1;
  if Length(p_szCaption) <> (dwLen-1) then exit;
  szWork := AllocMem(dwLen);

 try
   SendMessage(p_hWindow,WM_GETTEXT,dwLen,lParam(szWork));
    if StrLComp(szWork,p_szCaption,dwLen) = 0 then begin
     Form1.m1.Lines.Add('Sende '+Pfad);
     SendMessage(p_hWindow, dwMessage,0, lParam(Pfad));
    end;
 finally
    FreeMem(szWork,dwLen);
  end;
end;

procedure TForm1.FormShow(Sender: TObject);
var
FName: String;
begin
FName:='myprogramm';

if ParamCount > 0 then begin
 Pfad:= paramstr(1);
 Form1.Caption:= FName;

 mHandle  := CreateMutex(nil,True, 'FKILLER-36545tf456-34tf34tf23-23r3');

 if GetLastError=ERROR_ALREADY_EXISTS then begin
  Form1.Caption:= 'xxxxxxxxxxxxxxxxxxxx';

  // jetzt paramstr(1) an exe1 senden
  dwMessage := RegisterWindowMessage(3654-5tf-456-34tf3-4tf23);
  EnumWindows(@FindSyncDemo,integer(FName));

 end;
end;

negaH 7. Aug 2003 22:18

Re: Problem mit Dateiaufruf per paramstr
 
Zitat:

tut mir leid das is mir zu hoch
Hast du überhaupt mal versucht meinen Vorschlag zu testen und zu begreifen ?

In deinem Source gibt es gleich mehrere Probleme.
1.) CreateMutex() kann fehlschlagen wenn unter Win9x der Prozess der diesen Mutex angelegt hat gecrasht ist. Dann besteht dieser Mutex im System weiterhin obwohl es diesen Prozess nicht mehr gibt. Normalerweise würde eine Anwendung die auf CreateMutex() aufbaut dann nicht mehr starten. In deinem Falle würde die 1. Instance dann per EnumWindow() nach dem Fenster suchen, aber keines finden. Somit ist der CreateMutex() Aufruf sinnlos.
2.) Benötigt man zwecks Datenaustausch von ParamStr() ein Fensterhandle dann kann auch CreateMutex() verzichtet werden.
3.) Daten die von einem Prozess zu einem anderen Prozess, über Fensterhandles, ausgetauscht werden sollen müssen per wm_CopyData gesendet werden. wm_CopyData stellt sicher das der Speicherbereich in TCopyDataStruct aus der Gültigkeit des sendenden Prozesses auch gültig im empfangenden Prozess ist. Deshalb wird wm_CopyData immer NUR mit SendMessage() benutzt. Und deshalb funktioniert dein SendMessage() eben nicht.
4.) Dein EnumWindows() kann leicht durch FindWindow() ersetzt werden.
Statt also mit EnumWindows() über alle TopLevel Fenster zu iterieren reicht FindWindow(ClassName, WindowText) völlig aus.
5.) die Überprüfung in .FormShow() und das Erzeugen des Mutex ist an dieser Stelle denkbar ungünstig. Der beste Zeitpunkt, und auch der frühestmögliche, ist innerhalb einer Unit-Initialization. Wird meine obige Unit im Projektquelltext an 1. Stelle eingefügt dann wird sie noch vor der Erstellung jeglicher Forms ausgeführt. Damit würde also die 2. Instance der Anwendung erst garnicht langwierige Initialisierungen durchführen.

Aber im Grunde macht mein Vorschlag genau das was du versucht zu erreichen.
1.) TSingleInstance.Start sucht im System nach einem Fenster vom Typ "TPUtilWindow" + Caption "my_programXYZ12345". Dies erhöt die Sicherheit.
2.) wenn es gefunden wird wird der aktuelle ParamStr() = GetCommandLine an dieses Fenster per wm_CopyData gesendet. Wir senden also nicht nur ParamStr(1) sondern die komplette Kommandozeile.
3.) sollte das Fenster korrekt antworten so wird die aktuelle Anwendung angehalten und terminiert
4.) sollte kein Fenster "PrevWnd" gefunden worden sein, oder das Fenster hat nicht korrekt geantwortet dann wird die aktuelle Anwendung zur 1. Instance. Sie erzeugt ein Fenster vom Typ "TPUtilWindow" + Caption "my_programxyz123445"
5.) TSingleInstance.WndProc() wartet nun auf die Message wm_CopyData die durch eine 2. Instance der Anwendung aufgerufen wird. Punkte 1.) bis 3.) oben.
6.) sollte TSingleInstance.WndProc() eine gültige wm_CopyData Message erhalten so setzt sie die globale Variable CmdLine auf die Daten die per wm_CopyData empfangen wurde. CmdLine entspricht in diesem Moment der Kommandozeile der zweiten Instance der Anwendung.
7.) nun wird TSingleInstance.OnStartup() aufgerufen, die DEINEN Code enthalten sollte. Innerhalb .OnStartup() kannst du über die Methoden .ParamCount und .ParamStr() auf die Kommandozeile der zweiten Anwendung zugreifen.
8.) TSingleInstance.Stop wird bei der Terminierung der Anwendung aufgerufen und zerstört unser Helperfenster.

So was ist daran kompliziert ? besonders weil es auch sauberer und lesbarer Source ist ! :)

D.h. für dich:

1.) füge Unit Singleinstance zu deinem Projekt hinzu
2.) ändere den Wert von sTitle auf einen eindeutigen String
3.) ändere den Code in .OnStartup so wie du ihn brauchst. Innerhalb von .OnStartup nutzt du ParamCount und ParamStr() so als würdest du ganz normal damit wie in deiner Anwendung arbeiten.

Das wars.

Gruß Hagen

wb32 8. Aug 2003 09:47

Re: Problem mit Dateiaufruf per paramstr
 
Sooo danke noch mal für die Hilfe gestern abend, heute morgen usw *gg*...

war gar nich so schwer wie ich dachte aber manchmal muss man nach stundenlangem verzweifeln einfach ne Pause machen und dann später nochmal schauen...

soweit so gut jetzt taucht das nächste problem auf :(...

wenn ich mit deiner Unit alle dateien fein nacheinander auswäle und öffne dann geht es wunderbar, wenn ich aber 3 markiere und sage mit myprogramm öffnen dann öffnet sich myprogramm 3x ...

woran könnte das liegen ?

negaH 8. Aug 2003 10:13

Re: Problem mit Dateiaufruf per paramstr
 
Jay, jetzt's wirds kritisch. Das lässt sich so ohne weiteres nicht ändern, leider. Es liegt an der Vorgehensweise wie die Shell = Explorer eine Anwendung startet. Sie hat die 3 Dateien und erzeugt mit CreateProcess() 3 mal deinen Prozess. ABER! sie gibt diesen 3 neuen Prozessen erst dann eine Chance anzulaufen wenn alle 3 Prozesse schon erzeugt wurden. Deshalb ist es enorm wichtig den "Einmal-Startcode" so früh und so effizient wie möglich einzubauen. Leider bewirkt die Benutzung von Fensterhandles in unserem "Einmal-Startcode" das auch die beiden anderen Prozesse Rechenzeit bekommen, noch bevor überhaupt ein Fensterhandle vollständig erzeugt wurde.
Man kann dies ändern, aber das wird vom Verständnis echt komplizierter. Dafür müssen wir auf Semaphores und Interprozesskommunikation ausweichen. D.h. alle 3 Prozesse laufen korrekt an, wissen aber welche die 1. 2. und 3. Instance ist. Wenn die 1. Instance ordentlich läuft senden die zwei nachfolgenden Prozesse ihre Parameter an die 1. Instance und terminieren. D.h. falls die 2 nachfolgenden Prozesse anhand der Semaphore bemerken das sie nicht die 1. Instance sind müssen die solange warten bis sie mit der 1. Instance kommunizieren können.

Allerdings, irgendwie verstehe ich dein Problem noch nicht so recht. Wenn ich mich richtig erinnere kann man den Registryschlüssel für ShellEx/Commmand so anlegen das der Explorer multiple Files an EINE Instance der Anwendung sendet. Er startet dann nur eine Instance und übergibt alle Files als Params.

Ansonsten, gibts noch den Weg über COM Interfaces ein eigenes Shell-Interface zu programmieren. Statt dann über ParamStr() und ein EXE zu gehen, codet man eine DLL als Handler. In dieser kann über die Shellextension direkt auf die ausgewählte Dateiliste im Explorer zugegriffen werden. Bei Delphi sind zwei Beispiel dafür vorhanden IShellContextMenu und IShellExecuteHook.

Gruß Hagen

wb32 8. Aug 2003 10:27

Re: Problem mit Dateiaufruf per paramstr
 
Zitat:

Allerdings, irgendwie verstehe ich dein Problem noch nicht so recht. Wenn ich mich richtig erinnere kann man den Registryschlüssel für ShellEx/Commmand so anlegen das der Explorer multiple Files an EINE Instance der Anwendung sendet. Er startet dann nur eine Instance und übergibt alle Files als Params.

????????????????????????????????????????????


das geht ? dann hätten wir uns die Aktion doch sparen können ich habe doch mehrmals geschrieben wofür ich das benutzen will :)

wie geht das mit der einstellung für multiple files ?

negaH 8. Aug 2003 10:42

Re: Problem mit Dateiaufruf per paramstr
 
Zitat:

das geht ? dann hätten wir uns die Aktion doch sparen können ich habe doch mehrmals geschrieben wofür ich das benutzen will
Jo ich weiß :) aber dann hätten wir nicht diese schöne Exkursion machen können.

Zitat:

wie geht das mit der einstellung für multiple files ?
Shit, jetzt haste mich erwischt. Da muß ich selber erstmal nachschauen. Ich glaube etwa so "C:\MyProgram.EXE %1 %2 %3" oder so ähnlich. Wichtig dabei waren die doppelten Anführungsstriche.

Vielleicht weiß ja ein anderer DP'ler schnell die Antwort.

Gruß Hagen

wb32 8. Aug 2003 10:48

Re: Problem mit Dateiaufruf per paramstr
 
Zitat:

Jo ich weiß aber dann hätten wir nicht diese schöne Exkursion machen können.
stimmt war sehr lehrreich *gg*...


Zitat:

Shit, jetzt haste mich erwischt
wurde ja auch langsam Zeit :)

Zitat:

C:\MyProgram.EXE %1 %2 %3"
für jedes file ein %x ??? nee oder ?

also ich hab schon in der msdn gesucht bin aber nich so wirklich fündig geworden :(

negaH 8. Aug 2003 10:59

Re: Problem mit Dateiaufruf per paramstr
 
Ich habe mal auf die schnelle meine Registry gescannt.
Es gäbe den Weg über DDE, ein sehr alter Weg, oder eben über die Shell Extensionen.

Lass mir ein bißchen Zeit, am Wochenende werde ich mal TSingleInstance erweitern um die Semaphores, eventuell mit Memory Mapped Files + Events in Threads. Auf jeden Fall habe ich noch nie einen absolut sauber arbeitenden Single Instance Code gefunden.

Zur Zeit muß ich erstmal Geld verdienen.

Gruß Hagen

wb32 8. Aug 2003 11:03

Re: Problem mit Dateiaufruf per paramstr
 
hmm falls jemand anderes weiß wie man mutltiple files an eine instance senden kann bitte trotzdem posten mal schauen ob wir was finden und was letztendlich dann der beste weg ist :)

@Hagen danke erstmal, mal schauen ob du es hinbekommst

negaH 8. Aug 2003 11:05

Re: Problem mit Dateiaufruf per paramstr
 
Zitat:

@Hagen danke erstmal, mal schauen ob du es hinbekommst
Na, das ist doch keine Frage, die Frage ist ob ich 2 Wochen oder 3 Monate benötige :)

Gruß hagen

wb32 8. Aug 2003 14:21

Re: Problem mit Dateiaufruf per paramstr
 
also ich habe folgendes festgestellt:

Code:
procedure TForm1.addClick(Sender: TObject);
begin
 reg:=tregistry.create();
  // Dateien ins Context Menü
  Reg.RootKey:=HKEY_CLASSES_ROOT;
  Reg.OpenKey('*\shell',true);
  Reg.CloseKey;
  Reg.OpenKey('*\shell\'+Name,true);
  Reg.WriteString('',Title);//optional
  Reg.CloseKey;
  Reg.OpenKey('*\shell\'+Name+'\command',true);
  Reg.WriteString('',Adress); // adress="c:\test\meinprogramm.exe %1"
  Reg.CloseKey;
  Reg.OpenKey('*\shell\'+Name+'\ddeexec\',true);
  Reg.WriteString('','[open("%1")]');
  Reg.CloseKey;

   // Ordner ins Context Menü
   Reg.OpenKey('Directory\shell',true);
   Reg.CloseKey;
   Reg.OpenKey('Directory\shell\'+Name,true);
   Reg.WriteString('',Title);//optional
   Reg.CloseKey;
   Reg.OpenKey('Directory\shell\'+Name+'\command',true);
   Reg.WriteString('',Adress);
   Reg.CloseKey;

  reg.free;
  del.enabled:=true;
  add.Enabled:=false;
end;


Dieser Code hier:

Code:
 
Reg.OpenKey('*\shell\'+Name+'\ddeexec\',true);
Reg.WriteString('','[open("%1")]');
Reg.CloseKey;
bewirkt das man multiple dateien auswählen kann, wenn ich mehr als eine Datei wähle funktioniert alles bestens, wenn ich nun aber nur eine wähle kommt eine Messagebox das die mit Rechtsklick gewählte Datei nicht gefunden wurde ????

der pfad zur datei wird aber wie programmiert in meine Listbox eingetragen...

es funktioniert also alles ausser das dann dieser hinweis kommt,
weiß jemand woran das liegt ?

wb32 8. Aug 2003 17:12

Re: Problem mit Dateiaufruf per paramstr
 
hat niemand eine Idee ?

negaH 8. Aug 2003 17:43

Re: Problem mit Dateiaufruf per paramstr
 
ich habe das mal mit dem deexec probiert, das klappt nicht bei mir öffnet er die exe trotzdem mehrmals und bringt zusätzlich nich merhmals eine Fehlermeldung. Natürlich habe ich keine DDE Komponente drauf :)

Gruß hagen

wb32 8. Aug 2003 18:11

Re: Problem mit Dateiaufruf per paramstr
 
man man man das ist doch zum verrückt werden :evil:

es gibt hunderte von programmen die mehr als eine datei mit einem rechtsklick öffnen können das kann doch nich so schwer sein...

zum beispiel beim dateien löschen kann man doch mehr als eine gleichzeitig markeiren und alle löschen...

hab hier mal nen link zum source von eraser einem Delete Tool

Download

der kann mehr als eine markierte datei auf einmal lsöchen vielleicht kann damit jemand was anfangen und da mal reinschauen.. is aber C glaube ich ...

negaH 8. Aug 2003 18:19

Re: Problem mit Dateiaufruf per paramstr
 
Also mit dem DDE ist das ziemlich einfach.
Als erstes in dein Formular eine TDDEServerConv rein, bei dieser den Namen auf "System" un das Event OnexecuteMacro etwa so:

Delphi-Quellcode:
procedure TForm1.SystemExecuteMacro(Sender: TObject; Msg: TStrings);
begin
  ListBox1.Items.AddStrings(Msg);
end;
Nun noch die Registry.

Zitat:


[HKEY_CLASSES_ROOT\.step]
@="stepfile"

[HKEY_CLASSES_ROOT\stepfile]

[HKEY_CLASSES_ROOT\stepfile\shell]
@=""

[HKEY_CLASSES_ROOT\stepfile\shell\open]

[HKEY_CLASSES_ROOT\stepfile\shell\open\command]
@="d:\\borland\\delphi5\\projects\\project11.exe "

[HKEY_CLASSES_ROOT\stepfile\shell\open\ddeexec]
@="%1"

[HKEY_CLASSES_ROOT\stepfile\shell\open\ddeexec\Appl ication]
@="project11"

[HKEY_CLASSES_ROOT\stepfile\shell\open\ddeexec\Topi c]
@="System"

D.h. alle Dateien mit Extension *.step werden durch die Anwendung "d:\borland\delphi5\projects\project11.exe" geöffnet. Dabei wird der TDDEServerConv mit Namen "System" das Makro gesendet das bei "\open\ddeexec" steht. Hier besteht das Makro nur aus dem Dateinamen der zu öffnenden Datei. Das war alles.

Über'n Explorer im Menu\Extras\Ordneroptionen...\Dateitypen kann man dies auch komfortabel editieren.

Ich schätze mal das wars dann :)

Gruß Hagen

wb32 8. Aug 2003 18:26

Re: Problem mit Dateiaufruf per paramstr
 
ich muss dich leider enttäuschen *gg*...

ich will ein programm bauen wie diesen eraser der dateien löscht, dazu ist es wie bereits beschrieben nötig alle möglichen dateiarten *.rtf oder *.doc oder *.txt zu markieren und dieses werte also den pfad der datei auf der platte (den ich ja zum löschen einer datei brauche) an meine exe zu senden...

es nützt mir also nichts wenn ich nur dateien die eine bestimmte endung haben damit öffnen kann ...

sorry :)

wb32 8. Aug 2003 18:53

Re: Problem mit Dateiaufruf per paramstr
 
oder ich trenne das auf in 2 exe dateien ?

den klick auf eine datei lenke ich auf die umleitung.exe die prüft ob die delete.exe schon gestartet ist, wenn nicht wird sie gestartet...

danach sendet die umleitung.exe die daten paramstr an die delete.exe und beendet sich selbst...

dbaei wäre es egal wie oft die umletiung exe gestartet wird da sie eh unsichtbar ist und sich selbst beendet...

ist doch besser so oder ?

wb32 8. Aug 2003 19:42

Re: Problem mit Dateiaufruf per paramstr
 
ok ich hab die DDE Kompos drauf, hab auch schon einbeispiel gefunden dazu


http://www.elsdoerfer.net/delphi/delphitut_dde.html


nur leider funktioniert es bei einem klick nur einmal und das mit der rückmeldung vom server geht nich so wie es da steht...

der text aus dem memo im client wird aber korrekt an den server gesendet...

hat jemand noch ein beispiel oder ähnliches dazu ?

negaH 8. Aug 2003 20:43

Re: Problem mit Dateiaufruf per paramstr
 
Liste der Anhänge anzeigen (Anzahl: 1)
ich verstehe dein Problem nicht. Nun habe ich mal in hKey_Classes_Root den * Eintrag für alle Dateien erweitert

Zitat:

Windows Registry Editor Version 5.00

[HKEY_CLASSES_ROOT\*\shell]

[HKEY_CLASSES_ROOT\*\shell\open]

[HKEY_CLASSES_ROOT\*\shell\open\command]
@="d:\\borland\\delphi5\\projects\\project11.exe "

[HKEY_CLASSES_ROOT\*\shell\open\ddeexec]
@="%1"

[HKEY_CLASSES_ROOT\*\shell\open\ddeexec\application]
@="project11"

[HKEY_CLASSES_ROOT\*\shell\open\ddeexec\topic]
@="System"

Bei mir ruft er es absolut korrekt auf.
Mit nachfolgender Registry habe ich sogar für Verzeichnise einen neuen Eintrag im Contextmenu der "Suchen" heist. Wird er angeklickt so wird korrekterweise der Project11.exe der Verzeichnisname gesendet.

Zitat:


[HKEY_CLASSES_ROOT\Folder\shell\Suchen]

[HKEY_CLASSES_ROOT\Folder\shell\Suchen\command]
@="d:\\borland\\delphi5\\projects\\project11.exe "

[HKEY_CLASSES_ROOT\Folder\shell\Suchen\ddeexec]
@="%1"

[HKEY_CLASSES_ROOT\Folder\shell\Suchen\ddeexec\Appl ication]
@="project11"

Bei mir klappt also alles wie gewünscht.

Gruß Hagen

wb32 9. Aug 2003 07:57

Re: Problem mit Dateiaufruf per paramstr
 
hmmm also ich hab mir dein projekt mal runtergeladen und aus dem reg zeugs ne *.reg gemacht...

nur elider passiert da gar nicht, ich hab keinen zusätzlichen punkt im context menu und kann darum auch natürlich nichts testen ...

was hat das mit den @ zeichen zu bedeuten und wo wird das in die registry geschrieben ? es kam zwar die meldung das meine *.reg registriert wurde aber vielleicht ist da was schiefgegangen ich finde die einträge jedenfalls im shell ordner nicht...

wb32 9. Aug 2003 08:11

Re: Problem mit Dateiaufruf per paramstr
 
sooo also der schlüssel wird in der registry angelegt...
nur wurde er wie gesagt nicht im contextmenu angezeigt,
also hab ich ihn mal umbenannt in 123456 und siehe da plötzlich taucht im context menu 123456 auf, open scheint nicht zu funktionieren...
als ich den schlüssel wieder in open umbennnen wollte sagte die registry das dieser name bereits vorhanden wäre ???
aber nicht im ordner shell, oder dar er gar nicht doppelt vorkommen ???

jedenfalls wenn ich rechtsklick auf ne datei mache und klicke 123456 kommt die meldung

Zitat:

Für diesen Vorgang ist keine Anwendung der angegebenen Datei zugeordnet. Erstellen Sie eine Zuordnung indem Sie unter "Systemsteuerung" auf "Ordneroptionen" klicken...

was ist denn das nu wieder

:bouncing4: *verücktwerd* :bouncing4:

wb32 9. Aug 2003 08:20

Re: Problem mit Dateiaufruf per paramstr
 
boahhhhhhhhhhhhhhhh icke hab et *gg*
also er hat zwar alle daten in die reg importiert aber komischerweise nicht die pfad zur exe unter command... habs soeben bemerkt und sieh da nun gehts *freu*...

vielen vielen dank, für Eure (@Hagen und besonders Deine Hilfe)

:bounce2:

negaH 9. Aug 2003 09:32

Re: Problem mit Dateiaufruf per paramstr
 
Puh schwitz, ist das Thema damit jetzt abgegessen ??

Gruß Hagen

wb32 9. Aug 2003 10:35

Re: Problem mit Dateiaufruf per paramstr
 
joaaahhhh is zwar nich sehr schnell wenn man mehrere dateien laden will aber ich denke damit werde ich leben müssen :)

ich brauche ne Routine die Ordner rekursiv löscht auch wenn diese Unterordner enthalten, wichtig ist sie muss mit mit DeleteFile() arbeiten...

haste da ne idee ? wenn nich stell ich die frage nochmal im neuen thread ...


vielen dank nochmal...

negaH 9. Aug 2003 12:48

Re: Problem mit Dateiaufruf per paramstr
 
Such hier im Form nach TSreachRec und du findest alles was du brauchst.

wb32 9. Aug 2003 13:00

Re: Problem mit Dateiaufruf per paramstr
 
ok jetzt hab ich alles zusammen, bin fast fertig...
hab ne routine gefunden die gleich noch die atrribute ändert usw. zum löschen...


nochmal vielen dank :spin:

wb32 22. Aug 2003 12:41

Re: Problem mit Dateiaufruf per paramstr
 
muss leider den thread nochmal fortführen...

funktioniert zwar alles aber die dde server compo ist sehr langsam :( wenn man mehrere dateien auswählt und dann mit dem programm öffnet dauert es sehr lange weil die dateien nacheinander über die compo gesendet werden ...

hat jemand ne idee ?

negaH 22. Aug 2003 13:02

Re: Problem mit Dateiaufruf per paramstr
 
Dann bleiben nur die Shell Extensionen übrig. Diese sind sehr schnell weil man dort direkt auf die Datenstrukturen des Explorers zu greifen kann. D.h. der Explorer übergibt der ShellExtension alle selektierten Dateien. Interessant für die solltt das IContexMenu Demo im Demoordner von Delphi sein.

Gruß Hagen

wb32 22. Aug 2003 13:10

Re: Problem mit Dateiaufruf per paramstr
 
ich hab ne demo shellext im order activex ansonsten nichts was so ähnlich heisst ??? --> delphi 6 enterprise


Alle Zeitangaben in WEZ +1. Es ist jetzt 15:50 Uhr.
Seite 1 von 2  1 2      

Powered by vBulletin® Copyright ©2000 - 2025, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024-2025 by Thomas Breitkreuz