![]() |
WM_COPYDATA mit arrays?
Hallo Community,
ich bräuchte mal einen Denkanschub in Richtung Datenaustausch zwischen Prozessen. Ich habe a.) hier gesucht b.) mit WM_COPYDATA Messages experimentiert c.) und mich auch an MMF's (Memory Mapped Files) versucht War leider alles nicht sonderlich erfolgreich. Was will ich überhaupt erreichen? Einen Datenaustausch zwischen zweier, von mir kontrollierten (und auch entwickelten) Apps, die ein array of Records austauschen sollen, deren Anzahl vorher nicht bekannt ist. App1 fragt per SendMessage an, App2 antwortet datenbankgestützt (und deshalb in variabler Länge) und das per COPYDATA Message und App1 reagiert darauf. Wie kann ich das am besten angehen? Messaging an sich ist für mich nicht so das Problem, mein aktuelles Problem ist das der variablen Länge. ;) Gruss nru |
Re: WM_COPYDATA mit arrays?
Entweder steht am Anfang der Daten immer die Länge, oder ist da nicht noch ein Param frei in dem du die Länge übertragen kannst?
Zitat:
Grüsse, Dirk |
Re: WM_COPYDATA mit arrays?
Und was MMFs angeht: Die habe ich zum Datenaustausch hier in diesem Projekt auch benutzt:
![]() Dort habe ich die Größe per Parameter an eine neue Instanz übergeben, du kannst hier ja einfach Messages benutzen, das macht es noch einfacher. Der Quelltext ist auch relativ kurz. Dies sind die relevanten Teile des Codes:
Delphi-Quellcode:
Ich erzeuge also eine neue MMF mit der Größe des Streams FileListStream. Dann setze ich den View entsprechend und kopiere die Daten hinein, fertig. Jetzt übergebe ich diese Größe (bei mir als Parameter) an den zweiten Prozess.
// ab Zeile 453:
FMMFFileHandle := CreateFileMapping(INVALID_HANDLE_VALUE, nil, PAGE_READWRITE, 0, FileListStream.Size, MmfCommunicationName); // Handle will be closed in our destructor if FMMFFileHandle <> 0 then begin MMFPointer := MapViewOfFile(FMMFFileHandle, FILE_MAP_WRITE, 0, 0, FileListStream.Size); FileListStream.Position := 0; CopyMemory(MMFPointer, FileListStream.Memory, FileListStream.Size); UnmapViewOfFile(MMFPointer); Dort öffne ich dann die MMF:
Delphi-Quellcode:
Hier öffne ich einfach mit Offset und Größe 0, so dass die gesamte MMF gemappt wird. Du musst die Größe also gar nicht angeben. Wenn du zum Beispiel am Anfang immer einen Integerwert mit der Größe usw. als Header speicherst, dann reicht das bereits zum Auslesen. Den bekommst du dann mit PInteger(Integer(MMFPointer))^ ausgelesen.
// ab Zeile 512:
var HandleCount: Integer; MMFPointer: Pointer; MMFFileHandle: THandle; begin MMFFileHandle := OpenFileMapping(FILE_MAP_READ, True, MmfCommunicationName); if AStep2 then // only here we have to wait for the mutex to ensure the file mapping is open CreateMutex(nil, False, PChar(UpdateNotifyMutexName)); if MMFFileHandle <> 0 then begin MMFPointer := MapViewOfFile(MMFFileHandle, FILE_MAP_READ, 0, 0, 0); Das sieht bei mir in den folgenden Zeilen so aus um den Integer am Ende des Mappings auszulesen und dann einen Teil der Daten zu kopieren, aber das ist für dich nicht weiter wichtig:
Delphi-Quellcode:
// Read update list, size is 4 byte less than in AListStreamSize, because we
// have an integer with the count of handles at the end. HandleCount := PInteger(Integer(MMFPointer) + AListStreamSize - SizeOf(HandleCount))^; AFileListStream.Size := AListStreamSize - HandleCount * SizeOf(THandle) - SizeOf(HandleCount); CopyMemory(AFileListStream.Memory, MMFPointer, AFileListStream.Size); |
Re: WM_COPYDATA mit arrays?
Schick die Records doch einzeln in einer Schleife per WM_COPYDATA.
|
Re: WM_COPYDATA mit arrays?
Zitat:
Zuvor werd ich mich mit jaenicke's MMF-Ansatz auseinandersetzen. Vielen Dank für Euren Input. |
Re: WM_COPYDATA mit arrays?
Und warum nicht? Damit kann man auch eine schönen Fortschrittsanzeige einbauen. ;)
|
Re: WM_COPYDATA mit arrays?
Zitat:
Zudem ist es denke ich komplizierter die ganzen einzelnen Daten zu schicken und zu empfangen und das alles zu synchronisieren. Möglich ist aber auch das. Zitat:
Wenn man das Programm entsprechend baut, dann kann man auch direkt mit dem Speicherbereich arbeiten und braucht gar kein Array. Dadurch hat man dann die maximale Geschwindigkeit, da man sich auch das Kopieren in die MMF spart. |
Re: WM_COPYDATA mit arrays?
Zitat:
Doch man kommt ja leider oft sehr schnell auf den Boden der Tatsachen zurück - so auch ich in diesem Fall. Denn meine MMF-Versuche waren leider alles andere als glücklich bzw. erfolgreich. Vielen Dank nochmal an jaenicke für die vielen sehr brauchbaren Code-Schnipsel. :thumb: Aber ich habe feststellen müssen, dass mir hier dann doch noch ein paar basics fehlen. Ich habs leider nicht hinbekommen, das dyn. Array of TFindTitel als Pointer in das MMF zu schreiben und anschl. daraus wieder was brauchbares zu casten. Das ist, was ich mit basics meine :cry: Hättet ihr hierzu vielleicht auch noch ein paar Ideen? Das wär echt klasse. Hier mal meine bisherigen Ansätze (Fragmente). Sender sucht Infos in DB und verpackt die in ein array, welches dann in die MMF geschrieben werden soll. Die Rückgabe von FindFilmTitel wird an dvbWriteMMF übergeben (ist hier nicht aufgeführt).
Delphi-Quellcode:
type TFindTitel = packed record Name: String[255]; ID: Integer; end; PFindTitel = ^TFindTitel; TFindTitelArray = array of TFindTitel; function FindFilmTitel( cSearch: String ): TFindTitelArray; var i: Integer; x: TFindTitelArray; begin // weggelassener DB-Stuff SetLength( x, RecCount ); i := 0; while not eof do begin x[i].Name := FieldByName('TITEL').AsString; x[i].ID := FieldByName('FNUM').AsInteger; Inc(i); Next; end; result := x; end; procedure dvbWriteMMFile(hwnd: THandle; const x: array of TFindTitel ); var FMMFFileHandle: THandle; MMFPointer: Pointer; memSize: Integer; begin memSize := SizeOf(TFindTitel)*(High(x)+1); FMMFFileHandle := CreateFileMapping(INVALID_HANDLE_VALUE, nil, PAGE_READWRITE, 0, memSize, PChar( MmfCommunicationName )); if FMMFFileHandle <> 0 then begin MMFPointer := MapViewOfFile(FMMFFileHandle, FILE_MAP_WRITE, 0, 0, memSize); CopyMemory(MMFPointer, @x, memSize); UnmapViewOfFile(MMFPointer); end; // Benachrichtigung an wartenden Emfpänger senden (incl. Anzahl Datensätze!) // Empfänger geht dann hin und soll MMF lesen SendMessage( hwnd, CatchMsg, High(x)+1, 0 ); end; Empfänger bekommt die Msg und weiss, dass nun aus dem MMF gelesen werden könnte ... und versucht das erfolglos über die folgende Funktion.
Delphi-Quellcode:
Das resultierende TFindTitelArray bzw. die darin enthaltenen Records sollte dann vom Emfpänger weiterverarbeitet werden können. Geht aber nicht - Exception beim Zuweisen an Result.
function dvbReadMMF( nCount: Integer ): TFindTitelArray;
var HandleCount: Integer; MMFPointer: Pointer; MMFFileHandle: THandle; x: TFindTitelArray; memSize: Integer; begin MMFFileHandle := OpenFileMapping(FILE_MAP_READ, True, PChar( MmfCommunicationName) ); if MMFFileHandle <> 0 then begin MMFPointer := MapViewOfFile(MMFFileHandle, FILE_MAP_READ, 0, 0, 0); SetLength( x, nCount ); memSize := nCount * SizeOf(TFindTitel); CopyMemory(@x, MMFPointer, memSize); UnmapViewOfFile(MMFPointer); end; result := x; end; Mit sowas PFindTitelArray = ^TFindTitelArray; und CopyMemory(y, MMFPointer, memSize); result := TFindTitelArray(y^); hab ich dann auch ohne Erfolg experiementiert. Ihr wisst sicher auch warum - ich leider noch nicht ;) Vielleicht doch lieber die "WM_COPYDATA-Je-Datensatz"-Variante? Gruss Norbert |
Re: WM_COPYDATA mit arrays?
Vielleicht anstatt
Delphi-Quellcode:
...
CopyMemory(MMFPointer, @x, memSize); ...
Delphi-Quellcode:
:gruebel:
CopyMemory(MMFPointer, @x[0], memSize);
|
Re: WM_COPYDATA mit arrays?
Da hast du Recht, denn sonst wird nicht mit den Werten gearbeitet.
Hier mal aus dem Kopf kurz getippselt eine Variante, bei der die Größenangabe direkt am Anfang der MMF steht. So kann man auch andere Headerangaben mit übertragen. Das zusätzliche Array beim Empfang wird gar nicht gebraucht. Mit alzaimars Korrektur sollte es aber auch direkt schon klappen.
Delphi-Quellcode:
Ich denke mal so sollte es klappen.
procedure dvbWriteMMFile(hwnd: THandle; const x: array of TFindTitel );
var FMMFFileHandle: THandle; MMFPointer: Pointer; memSize: Integer; begin memSize := SizeOf(TFindTitel)*(High(x)+1); FMMFFileHandle := CreateFileMapping(INVALID_HANDLE_VALUE, nil, PAGE_READWRITE, 0, memSize + SizeOf(Integer), PChar( MmfCommunicationName )); if FMMFFileHandle <> 0 then begin MMFPointer := MapViewOfFile(FMMFFileHandle, FILE_MAP_WRITE, 0, 0, 0); PInteger(MMFPointer)^ := Length(x); // Anzahl der Datensätze an den Anfang schreiben Inc(PInteger(MMFPointer)); // Nach der Angabe der Anzahl weitermachen CopyMemory(MMFPointer, @x[0], memSize); UnmapViewOfFile(MMFPointer); end; // Benachrichtigung an wartenden Emfpänger senden // Empfänger geht dann hin und soll MMF lesen SendMessage( hwnd, CatchMsg, 0, 0 ); end; function dvbReadMMF(): TFindTitelArray; var MMFPointer: Pointer; MMFFileHandle: THandle; memSize: Integer; begin MMFFileHandle := OpenFileMapping(FILE_MAP_READ, True, PChar( MmfCommunicationName) ); if MMFFileHandle <> 0 then begin MMFPointer := MapViewOfFile(MMFFileHandle, FILE_MAP_READ, 0, 0, 0); SetLength(Result, PInteger(MMFPointer)^); // Anzahl der Datensätze auslesen memSize := PInteger(MMFPointer)^ * SizeOf(TFindTitel); Inc(PInteger(MMFPointer)); // Nach der Angabe der Anzahl weitermachen CopyMemory(@Result[0], MMFPointer, memSize); UnmapViewOfFile(MMFPointer); end; end; |
Alle Zeitangaben in WEZ +1. Es ist jetzt 08:30 Uhr. |
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