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 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?


Anmelden zum Antworten