Autor Beitrag
GuaAck
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 378
Erhaltene Danke: 32

Windows 8.1
Delphi 10.4 Comm. Edition
BeitragVerfasst: Mi 20.10.10 22:21 
Hallo,

ich habe ein bestimmtes Dateiformat *.AAA das ich in *.BBB konvertieren möchte. Dafür habe ich ein Delphi-Programm gemacht, und in Windows den Dateityp AAA mit diesem Programm verknüpft. Geht bestens, Doppelclick auf die *.AAA-Datei oder im Kontext-Menü "Öffnen"; den Filenamen bekomme ich in Delphi aus dem Parameter-String.

Mein Problem: Man kann ja auch mehrere Dateien markieren, dann wird nach "Öffnen" im Kontext-Menü für jede markierte Datei die Anwendung erneut als Prozess gestartet. Wenn man nun 1000 Dateien konvertieren will, dann hätte man 1000 Prozesse unter Windows, das kann nicht gut sein.

Eine Sperre über Mutex nützt nichts, dann dann ist der Prozess bereits generiert. (Ich nutze aktuell Mutex, damit bei Folgeaufrufen alle Konvertierungsoptionen aus der *.ini Datei ohne Nachfrage übernommen werden, die Konvertierung in den Folgeprozessen startet so
erst, nachdem der erste Prozess die *.ini Datei aktualisiert hat.)

Wäre schön, jemand hätte eine Idee,

Grüße GuaAck
jaenicke
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 19326
Erhaltene Danke: 1749

W11 x64 (Chrome, Edge)
Delphi 12 Pro, C# (VS 2022), JS/HTML, Java (NB), PHP, Lazarus
BeitragVerfasst: Do 21.10.10 05:39 
Du müsstest dann den Parameter an die schon laufende Instanz weitergeben, wenn du merkst, dass das Programm schon läuft (z.B. durch den Mutex). ;-)

Ein Beispiel findest du hier, da werden Atoms dafür missbraucht:
www.swissdelphicente...showcode.php?id=2126
bummi
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 1248
Erhaltene Danke: 187

XP - Server 2008R2
D2 - Delphi XE
BeitragVerfasst: Do 21.10.10 06:46 
Vielleicht auch so?
ausblenden volle Höhe 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:
program Project1;

uses
  Forms,
  windows,
  Messages,
  Classes,
  sysutils,
  shellapi,
  Unit1 in 'Unit1.pas' {TTest};

{$R *.res}



type
   TCopyDataStruct = packed record
    dwData: Integer; //up to 32 bits of data to be passed to the receiving application
    cbData: Integer; //the size, in bytes, of the data pointed to by the lpData member
    lpData: Pointer; //Points to data to be passed to the receiving application. This member can be nil.
   end;
var
  G_copyDataStruct : TCopyDataStruct;
Function SendData(const Application,Param:String):Boolean;
var
  rchandle:THandle;
begin
 Result := false;
 G_copyDataStruct.dwData := 0;
 G_copyDataStruct.cbData := 1 + Length(Param);
 G_copyDataStruct.lpData := PChar(Param);
 rcHandle := FindWindow(PChar(Application),nil);
 if rcHandle <> 0 then
  begin
  SendMessage(rcHandle, WM_COPYDATA, Integer(rcHandle), Integer(@G_copyDataStruct));
  SetForeGroundWindow(rcHandle);
  Result := true;
  end;
end;

begin
  if not SendData('TTTest',Paramstr(1)) then
    begin
      Application.Initialize;
      Application.MainFormOnTaskbar := True;
      Application.CreateForm(TTTest, TTest);
      Application.Run;
    end;
end.



unit Unit1;

interface

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

type
  TTTest = class(TForm)
    procedure FormCreate(Sender: TObject);

  private
    procedure WMCopyData(var Msg : TWMCopyData) ; message WM_COPYDATA;
    procedure TuWasMit(s: String);
    { Private-Deklarationen }
  public
    { Public-Deklarationen }
  end;

var
  TTest: TTTest;

implementation

{$R *.dfm}

{ TForm1 }
procedure TTTest.FormCreate(Sender: TObject);
begin
  Showmessage(Paramstr(1));
end;

procedure TTTest.TuWasMit(s:String);
begin
  Showmessage(s);
end;

procedure TTTest.WMCopyData(var Msg: TWMCopyData);
var
  s : string;
begin
  s := PChar(Msg.CopyDataStruct.lpData) ;
  msg.Result := 1;
  TuWasMit(s);
  BringToFront;
end;


end.
Gausi
ontopic starontopic starontopic starontopic starontopic starontopic starofftopic starofftopic star
Beiträge: 8550
Erhaltene Danke: 478

Windows 7, Windows 10
D7 PE, Delphi XE3 Prof, Delphi 10.3 CE
BeitragVerfasst: Do 21.10.10 09:00 
Um noch ein Beispiel zu nennen, wie man das machen kann: Die Unit OneInst. Gibts auf user profile iconLuckies Seite unter Importe. :D

_________________
We are, we were and will not be.
GuaAck Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 378
Erhaltene Danke: 32

Windows 8.1
Delphi 10.4 Comm. Edition
BeitragVerfasst: Do 21.10.10 19:59 
Danke an Euch drei, scheint auf den ersten Blick alles das zu sein, was ich brauche. Habbe alle drei Varianten kopiert und werde Sie mir morgen mal im Detail ansehen.

Beste Grüße
GuaAck
Reinhard Kern
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 591
Erhaltene Danke: 14



BeitragVerfasst: Do 21.10.10 23:09 
user profile iconGausi hat folgendes geschrieben Zum zitierten Posting springen:
Um noch ein Beispiel zu nennen, wie man das machen kann: Die Unit OneInst. Gibts auf user profile iconLuckies Seite unter Importe. :D


Hallo,

die üblichen Lösungen haben alle den Nachteil, dass die 2. Instanz gestartet wird, erkennt, dass sie nicht die erste ist, die Parameter an die erste übergibt und sich beendet. Als schlanke Alternative könnte man auch einen klitzekleinen Minidispatcher schreiben, der anstelle des Programms gestartet wird und dieses startet, falls nötig, oder Parameter an das bereits laufende Programm übergibt. Damit wäre auch das angefragte serielle Problem lösbar. Der Footprint könnte minimal sein, je nach Sprache, ausser bei Fehlern könnte/sollte das Progrämmchen unsichtbar bleiben.

Im Grunde bräuchte man überhaupt nur ein solches Programm, das an das Projekt angepasst werden kann.

Gruss Reinhard
GuaAck Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 378
Erhaltene Danke: 32

Windows 8.1
Delphi 10.4 Comm. Edition
BeitragVerfasst: Fr 29.10.10 19:42 
Nachtrag:

Ich habe jetzt einiges probiert und es läuft jetzt.

Aber: Alle Lösungen, die einen lokalen Speicherbereich nutzen und dess Adresse per @ in einer Message übergeben, funktionieren nicht. Die Adrsse scheint sich auf einen lokalen
Adrssraum zu beziehen, jedenfalls geben mehrere gleichzeitig laufende Instanzen alle genau die glkeiche Adresse aus; Bei einem Zugriff aus dem Zielprogramm kommt es zu einer Acces-Violation.

Ich mache es jetzt über eine Liste in einem Glabal Shared Memory (CreateFilemapping ist dafür nach Delphi-Hilfe der einzige Weg).Falls es das Memory schon gibt, dann Eintrag des Parameters und sofort Application.terminate.

Hier der wichtigste Teil des Code:

ausblenden 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:
CONSTRUCTOR TSharedDateiliste.Create;
BEGIN
  selbst_kreiert := false;
  Filehandle := createfile('Dummy.dat', generic_read OR generic_write,
  FILE_SHARE_READ  or FILE_SHARE_WRITE,nil,create_always, FILE_ATTRIBUTE_TEMPORARY OR
  FILE_FLAG_DELETE_ON_CLOSE, 0);

  Maphandle := CreateFilemapping(Filehandle, NIL, Page_ReadWrite, 0, sizeof(Tdateiliste), 'HPTOCGM_MAP');
  IF (GetLastError = 0OR (GetLastError = ERROR_ALREADY_EXISTS) THEN
    BEGIN
      PDateiliste := MapViewOfFile(Maphandle, File_map_write, 00, sizeof(Tdateiliste));
      IF GetLastError = 0 THEN
        BEGIN
          selbst_kreiert := true;
          { Initialisisierung der Listen }
          PDateiliste^.nexttowrite := 0;
          PDateiliste^.sumbytes := 0;
          PDateiliste^.lastreadable := -1;
        END;
    END
  ELSE
    PDateiliste := NIL;
END;



Gruß GuaAck

Moderiert von user profile iconMartok: Delphi-Tags eingefügt
jaenicke
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 19326
Erhaltene Danke: 1749

W11 x64 (Chrome, Edge)
Delphi 12 Pro, C# (VS 2022), JS/HTML, Java (NB), PHP, Lazarus
BeitragVerfasst: Fr 29.10.10 20:04 
Eine MMF ist eine Lösung, allerdings hast du (bei einem festen MMF Namen) ein Problem, wenn mehrere Instanzen parallel neu gestartet werden.

Was ich gar nicht verstehe: Wozu die echte Datei? :shock:
Dir reicht doch eine MMF, die im Speicher liegt.
Benutzt habe ich das z.B. hier in meinem Updater:
www.delphi-forum.de/viewtopic.php?t=94339

Für globalen Speicher kannst du aber auch GlobalAlloc benutzen:
msdn.microsoft.com/e...aa366574(VS.85).aspx
delfiphan
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 2684
Erhaltene Danke: 32



BeitragVerfasst: Sa 30.10.10 09:32 
GlobalAlloc kommt noch aus 16-bit Zeiten. Im Kontext von 32-bit Apps ist an dem Speicher nichts mehr "globales". Die Funktion ist lediglich ein Wrapper auf die normalen Heap funktionen wie HeapAlloc.
msdn hat folgendes geschrieben:
Memory objects allocated by GlobalAlloc and LocalAlloc are in private, committed pages with read/write access that cannot be accessed by other processes. Memory allocated by using GlobalAlloc with GMEM_DDESHARE is not actually shared globally as it is in 16-bit Windows. This value has no effect and is available only for compatibility. Applications requiring shared memory for other purposes must use file-mapping objects.


user profile iconjaenicke hat folgendes geschrieben Zum zitierten Posting springen:
Dir reicht doch eine MMF, die im Speicher liegt.
Eine MMF liegt im Pagefile (natürlich ist das meiste in RAM gecached, aber die Aussage oben ist irreführend).
jaenicke
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 19326
Erhaltene Danke: 1749

W11 x64 (Chrome, Edge)
Delphi 12 Pro, C# (VS 2022), JS/HTML, Java (NB), PHP, Lazarus
BeitragVerfasst: Sa 30.10.10 09:53 
Wenn der View die komplette MMF umfasst, liegt auch alles im Arbeitsspeicher, oder? ;-)

Was ich aber meinte war, dass eben keine Dummydatei irgendwo auf der Festplatte benötigt wird. Wie Windows das intern dann mit der MMF macht, kann mir ja im Grunde egal sein.

user profile icondelfiphan hat folgendes geschrieben Zum zitierten Posting springen:
GlobalAlloc kommt noch aus 16-bit Zeiten. Im Kontext von 32-bit Apps ist an dem Speicher nichts mehr "globales".
Hmm, da habe ich nicht weiter geschaut. :oops: Funktionieren tut es aber seltsamerweise, ich habe das gerade erst in einem Quelltext zur IPC gesehen. :gruebel: