Kommunikation zwischen zwei Prozessen
-
Hallo alle zusammen...
Kann mir einer von Euch das mit dem File Mapping bzw. Named Pipes o.Ä. erklären?
Mein Problem (Beide Programme unter Windows geschrieben):
Ich habe eine C Anwendung geschrieben, welche ich allerdings nicht mit dem Visual Studio kompilieren kann, sondern nur mit dem MinGW. Nun habe ich eine GUI mit QT4 und Visual Studio 6 (C++) geschrieben. In dieser Oberfläche rufe ich die executable des C Programmes auf. Ich möchte allerdings gerne, dass die Oberfläche und die Konsolenanwendung Daten untereinander austauschen.z.B.
- Fehlermeldungen
- Fortschritt (für einen Progressbar)
- usw.Ich habe nun erfahren, dass es unter windows nicht direkt so etwas wie shared memory gibt, aber dass es andere Möglichkeiten gibt, mehrere Prozesse mit einander Kommunizieren zu lassen.
Kennt jemand eine url, wo ich ein gutes !!!Einsteiger- Tutorial!!! für Mapped Files, Named Pipes, oder etwas ähnliches was mir bei meinem Problem helfen kann?
Kann mir jemand von euch sagen, ob es überhaupt möglich ist, sowas mit C und dem MinGW GCC Compiler zu realisieren?
Wenn möglich, könntet ihr mir auch ein Beispiel geben?!?
Ich bin echt verzweifelt....
Gruß Patrick
Nachtrag:
Ich habe schon ein bischen rumprobiert:filemappingwrite.cpp
#include <windows.h> #include <stdio.h> int main(int argc, char *argv[]) { char *test; test = (char*) malloc(sizeof(char) * 500); test = "Hallo Test!"; HANDLE hMapObject; // Create a named file mapping object. hMapObject = CreateFileMapping( (HANDLE) 0xFFFFFFFF, // use paging file NULL, // no security attributes PAGE_READWRITE, // read/write access 0, // size: high 32-bits sizeof(test), // size: low 32-bits "MeinFile"); // name of map object if (hMapObject == NULL) return FALSE; // Get a pointer to the file-mapped shared memory. HANDLE PMyObject; PMyObject = MapViewOfFile( hMapObject, // object to map view of FILE_MAP_WRITE, // read/write access 0, // high offset: map from 0, // low offset: beginning 0); // default: map entire file unsigned long *zahl; zahl = (unsigned long*)malloc(sizeof(long)); WriteFile(PMyObject,test,strlen(test),zahl,NULL); Sleep(10000); return(0); }
FilemappingRead.cpp
#include <windows.h> #include <stdio.h> int main(int argc, char *argv[]) { char *test; test = (char*) malloc(sizeof(char) * 500); HANDLE hMapObject; hMapObject = OpenFileMapping(FILE_MAP_READ,true,"MeinFile"); // Get a pointer to the file-mapped shared memory. HANDLE PMyObject; PMyObject = MapViewOfFile( hMapObject, // object to map view of FILE_MAP_READ, // read/write access 0, // high offset: map from 0, // low offset: beginning 0); // default: map entire file unsigned long *zahl; zahl = (unsigned long*)malloc(sizeof(long)); bool t = ReadFile(PMyObject,&test,20,zahl,NULL); if(t) printf("1\n"); else printf("0\n"); printf("%s",test); return(0); }
Es gibt keine Fehler, keine Warnungen, allerdings liest read nichts aus. Weiß einer von euch wieso?
-
Vielleicht sowas in der Art: Creating a Child Process with Redirected Input and Output
-
Vielleicht hilft das ein bischen weiter.
In der MSDN sind die named Pipes eine OS Mechanismus beschrieben, diese Mechanismen sind in dem meisten
Betriebsystemen vorhanden und somit ist auch eine gewisse Portabilit"at gew"ahrleistet.
Eine named Pipe kann man sich als ein file im Betriebsystem vorstellen in das der eine schreibt
und der andere liest, d.h. nach dem Erstellen der Named Pipe brauche ich nur noch File Read und Write
Mechanismen zu benutzen.Als Grundlage dient das Beispiel multithreaded pipe server aus der MSDN
Über die named pipes kommst du auch an die anderen OS-Mechanismen in der MSDN (Die gibts auch im Internet)
//Ausriss for (;;) { PipeData.hPipe = CreateNamedPipe( PipeData.Name, // pipe name PIPE_ACCESS_DUPLEX, // read/write access PIPE_TYPE_MESSAGE | // message type pipe PIPE_READMODE_MESSAGE | // message-read mode PIPE_WAIT, // blocking mode PIPE_UNLIMITED_INSTANCES, // max. instances IPC_BUFFERSIZE, // output buffer size IPC_BUFFERSIZE, // input buffer size PipeData.TimeOut, // client time-out NULL); // no security attribute if (PipeData.hPipe == INVALID_HANDLE_VALUE) return (ETZDispErr(MODULEID,9999,SERRLVL, "Error creating Pipe %s",PipeData.Name)); // Wait for the client to connect; if it succeeds, // the function returns a nonzero value. If the function returns // zero, GetLastError returns ERROR_PIPE_CONNECTED. fConnected = ConnectNamedPipe(PipeData.hPipe, NULL) ? TRUE : (GetLastError() == ERROR_PIPE_CONNECTED); if (fConnected) { PipeData.PipesRunning++; #ifdef _DEBUG printf( "Connected PS %s Pipes# %i", PipeData.Name,PipeData.PipesRunning); #endif // Create a thread for this client. hThread = CreateThread( NULL, // no security attribute 0, // default stack size (LPTHREAD_START_ROUTINE) ServerThread, (LPVOID) &PipeData, // thread parameter 0, // not suspended &dwThreadId); // returns thread ID WaitForSingleObject(PipeData.hSerial,INFINITE); ResetEvent(PipeData.hSerial); if (hThread == NULL) { CloseHandle(PipeData.hPipe); printf("Error creating Pipe Thread"); return(-1); } else CloseHandle(hThread); } else // The client could not connect, so close the pipe. CloseHandle(PipeData.hPipe); }
-
Das Problem wird sich zwar für Paddy inzwischen gelöst haben, falls aber jemand anderes mit dem selben Problem auf die Seite stößt (wie ich), hier ein Lösungsansatz für das CreateFileMapping (Paddys geposteter Code).
Da ich selber in Cobol programmiere, kann ich leider keinen fertigen Code posten, es dürfte aber kein Problem sein, sich den korrekten Syntax selber zusammenzusuchen.
Hauptanwendung:
fileHwnd = CreateFileMapping ptr = MapViewOfFile pID = GetCurrentProcessID
fileHwnd und pID müssen an die Nebenanwendung übergeben werden. Ob dies durch Kommandozeilenparameter, eine Windowsmessage (ggf. vorher FindWindow, dann SendMessage und die beiden Werte als wParam bzw. lParam übergeben), über die alten Umgebungsvariablen oder anderweilig geschieht, ist egal.
Nebenanwendung:
ownHwnd = GetCurrentProcess // ist standardmäßig -1 mainHwnd = OpenProcess(PROCESS_ALL_ACCESS, False, pID) // die pID aus der Hauptanwendung übergeben // ownFileHwnd muß als Referenz (Pointer) übergeben werden (in VB z.B. über die ByRef-Deklaration) retcode = DuplicateHandle (mainHwnd, fileHwnd, ownHwnd, &ownFileHwnd, 0, TRUE, DUPLICATE_SAME_ACCESS) ownPtr = MapViewOfFile // ownFileHwnd übergeben
Jetzt kann in der Nebenanwendung über den Pointer ownPtr auf den selben Datenbereich wie in der Hauptanwendung zugegriffen werden.
mfg
Thomas
-
Ich habe mir diesem Quelltext als Vorbild genommen,
char *test; test = (char*) malloc(sizeof(char) * 500); test = "Hallo Test!"; HANDLE hMapObject; // Create a named file mapping object. hMapObject = CreateFileMapping( (HANDLE) 0xFFFFFFFF, // use paging file NULL, // no security attributes PAGE_READWRITE, // read/write access 0, // size: high 32-bits sizeof(test), // size: low 32-bits "MeinFile"); // name of map object if (hMapObject == NULL) return FALSE; // Get a pointer to the file-mapped shared memory. HANDLE PMyObject; PMyObject = MapViewOfFile( hMapObject, // object to map view of FILE_MAP_WRITE, // read/write access 0, // high offset: map from 0, // low offset: beginning 0); // default: map entire file unsigned long *zahl; zahl = (unsigned long*)malloc(sizeof(long)); WriteFile(PMyObject,test,strlen(test),zahl,NULL);
um nun keinen String zu übertragen, sondern einen int-Wert. Folglich ergab sich:
int i = 6; i = (int) malloc(sizeof(int) * 500); HANDLE hMapObject; // Create a named file mapping object. hMapObject = CreateFileMapping( (HANDLE) 0xFFFFFFFF, // use paging file NULL, // no security attributes PAGE_READWRITE, // read/write access 0, // size: high 32-bits sizeof(i), // size: low 32-bits "MeinFile"); // name of map object if (hMapObject == NULL) {} // Get a pointer to the file-mapped shared memory. HANDLE PMyObject; PMyObject = MapViewOfFile( hMapObject, // object to map view of FILE_MAP_WRITE, // read/write access 0, // high offset: map from 0, // low offset: beginning 0); // default: map entire file unsigned long *zahl; zahl = (unsigned long*)malloc(sizeof(long)); WriteFile(PMyObject,i,20,zahl,NULL);
Leider meckert der Compiler bei der letzten Zeile
C:\Dokumente und Einstellungen\joerg\dll-30s\Dialog1.cpp(983) : error C2664: 'WriteFile' : Konvertierung des Parameters 2 von 'int' in 'const void *' nicht moeglich
Diese Meldung verstehe ich nicht... Was mache ich hier falsch???
-
Der zweite Parameter dürfte die Adresse der Daten sein, die du schreiben willst. Also müsstest du dort auch eine Adresse (z.B. &i) angeben (übrigens ist ein int-Wert bestimmt größer als 20 Byte).
PS: Und es ist auch nicht wirklich nötig, für deinen Rückgabewert Speicher per malloc() anzufordern.
-
Danke, nun gehts- zumidnest ist es compilierbar.
Nun entsteht aber ein weiteres Problem:
Oben genannter Code wird irgendwann im Verlauf des Programms aufgerufen. Das heisst,dass ich mit ReadFile(..) beliebig lange warten muss. Also warte ich bis die Funktion true zurückgibt. Dies passiert dann aber nicht... Hier der Code dazu:
while(true) { hMapObject = OpenFileMapping(FILE_MAP_READ,true,"MeinFile"); // Get a pointer to the file-mapped shared memory. HANDLE PMyObject; PMyObject = MapViewOfFile( hMapObject, // object to map view of FILE_MAP_READ, // read/write access 0, // high offset: map from 0, // low offset: beginning 0); // default: map entire file int i; unsigned long *zahl; zahl = (unsigned long*)malloc(sizeof(long)); bool t = ReadFile(PMyObject,&i,200,zahl,NULL); if(t) { //Datei1 exists AfxMessageBox(test); } else { AfxMessageBox("nein"); }
Ist das überhaupt ein sinnvoller Ansatz? Wie klappt das mit dem "Warten auf den Wert" sonst?