| Autor |
Beitrag |
GuaAck
      
Beiträge: 378
Erhaltene Danke: 32
Windows 8.1
Delphi 10.4 Comm. Edition
|
Verfasst: 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
      
Beiträge: 19326
Erhaltene Danke: 1749
W11 x64 (Chrome, Edge)
Delphi 12 Pro, C# (VS 2022), JS/HTML, Java (NB), PHP, Lazarus
|
Verfasst: 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
      
Beiträge: 1248
Erhaltene Danke: 187
XP - Server 2008R2
D2 - Delphi XE
|
Verfasst: Do 21.10.10 06:46
Vielleicht auch so?
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' ;
{$R *.res}
type TCopyDataStruct = packed record dwData: Integer; cbData: Integer; lpData: Pointer; 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); public end;
var TTest: TTTest;
implementation
{$R *.dfm}
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
      
Beiträge: 8550
Erhaltene Danke: 478
Windows 7, Windows 10
D7 PE, Delphi XE3 Prof, Delphi 10.3 CE
|
Verfasst: Do 21.10.10 09:00
Um noch ein Beispiel zu nennen, wie man das machen kann: Die Unit OneInst. Gibts auf Luckies Seite unter Importe. 
_________________ We are, we were and will not be.
|
|
GuaAck 
      
Beiträge: 378
Erhaltene Danke: 32
Windows 8.1
Delphi 10.4 Comm. Edition
|
Verfasst: 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
      
Beiträge: 591
Erhaltene Danke: 14
|
Verfasst: Do 21.10.10 23:09
Gausi hat folgendes geschrieben : | Um noch ein Beispiel zu nennen, wie man das machen kann: Die Unit OneInst. Gibts auf Luckies Seite unter Importe.  |
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 
      
Beiträge: 378
Erhaltene Danke: 32
Windows 8.1
Delphi 10.4 Comm. Edition
|
Verfasst: 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:
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 = 0) OR (GetLastError = ERROR_ALREADY_EXISTS) THEN BEGIN PDateiliste := MapViewOfFile(Maphandle, File_map_write, 0, 0, sizeof(Tdateiliste)); IF GetLastError = 0 THEN BEGIN selbst_kreiert := true; PDateiliste^.nexttowrite := 0; PDateiliste^.sumbytes := 0; PDateiliste^.lastreadable := -1; END; END ELSE PDateiliste := NIL; END; |
Gruß GuaAck
Moderiert von Martok: Delphi-Tags eingefügt
|
|
jaenicke
      
Beiträge: 19326
Erhaltene Danke: 1749
W11 x64 (Chrome, Edge)
Delphi 12 Pro, C# (VS 2022), JS/HTML, Java (NB), PHP, Lazarus
|
Verfasst: 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?
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
      
Beiträge: 2684
Erhaltene Danke: 32
|
Verfasst: 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. |
jaenicke hat folgendes geschrieben : | | 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
      
Beiträge: 19326
Erhaltene Danke: 1749
W11 x64 (Chrome, Edge)
Delphi 12 Pro, C# (VS 2022), JS/HTML, Java (NB), PHP, Lazarus
|
Verfasst: 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.
delfiphan hat folgendes geschrieben : | | 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.  Funktionieren tut es aber seltsamerweise, ich habe das gerade erst in einem Quelltext zur IPC gesehen. 
|
|
|