6 Stimmen

Wie man Nachrichten zwischen C++ .dll und C# app mit benannten Pipe senden?

Ich mache eine injizierte DLL, die in C++ geschrieben ist, und ich möchte mit einer C#-Anwendung über benannte Pipes kommunizieren.

Ich verwende die eingebauten System.IO.Pipe .net-Klassen in der C#-Anwendung und die regulären Funktionen in C++.

Ich habe nicht viel Erfahrung in C++ (Lesen: Dies ist mein erster C++-Code..), obwohl ich in C# erfahren bin.

Es scheint, dass die Verbindung mit dem Server und dem Client funktioniert, das einzige Problem ist, dass die Nachrichten nicht gesendet werden. Ich habe versucht, die .dll der Server, die C# app der Server, so dass die Rohrrichtung InOut (duplex), aber keiner scheint zu funktionieren.

Als ich versucht habe, die .dll zum Server zu machen, der Nachrichten an die C#-Anwendung sendet, war der verwendete Code wie folgt:

DWORD ServerCreate() // function to create the server and wait till it successfully creates it to return.
{
    hPipe = CreateNamedPipe(pipename,//The unique pipe name. This string must have the following form:  \\.\pipe\pipename
    PIPE_ACCESS_DUPLEX, 
    PIPE_TYPE_MESSAGE | PIPE_READMODE_MESSAGE | PIPE_NOWAIT, //write and read and return right away
    PIPE_UNLIMITED_INSTANCES,//The maximum number of instances that can be created for this pipe
    4096 , // output time-out 
    4096 , // input time-out 
    0,//client time-out 
    NULL);

   if(hPipe== INVALID_HANDLE_VALUE)
   {
    return 1;//failed
   }
   else
    return 0;//success
}

void SendMsg(string msg)
{
    DWORD cbWritten;
    WriteFile(hPipe,msg.c_str(), msg.length()+1, &cbWritten,NULL);
}

void ProccesingPipeInstance()
{
    while(ServerCreate() == 1)//if failed
{
    Sleep(1000);    
}

//if created success, wait to connect
ConnectNamedPipe(hPipe, NULL);
for(;;)
{
    SendMsg("HI!");
    if( ConnectNamedPipe(hPipe, NULL)==0)
        if(GetLastError()==ERROR_NO_DATA)
        {
            DebugPrintA("previous closed,ERROR_NO_DATA");
            DisconnectNamedPipe(hPipe);
            ConnectNamedPipe(hPipe, NULL);
        }
    Sleep(1000);

}

Und der C#-Client wie folgt:

static void Main(string[] args)
    {
        Console.WriteLine("Hello!");

        using (var pipe = new NamedPipeClientStream(".", "HyprPipe", PipeDirection.In))
        {
            Console.WriteLine("Created Client!");

            Console.Write("Connecting to pipe server in the .dll ...");
            pipe.Connect();

            Console.WriteLine("DONE!");

            using (var pr = new StreamReader(pipe))
            {
                string t;
                while ((t = pr.ReadLine()) != null)
                {
                    Console.WriteLine("Message: {0}",t);
                }
            }
        }
    }

Ich sehe, dass der C#-Client eine Verbindung zur .dll hergestellt hat, aber er empfängt keine Nachricht. Ich habe versucht, es andersherum zu tun, wie ich schon sagte, und versuchen, die C# Nachrichten an die .dll zu senden, die sie in einem Nachrichtenfeld anzeigen würde. Die .dll wurde injiziert und mit dem C#-Server verbunden, aber wenn es eine Nachricht erhielt, stürzte die Anwendung, in die es injiziert wurde, einfach ab.

Bitte helfen Sie mir, oder führen Sie mich auf, wie man benannte Rohre zwischen C++ und C# app verwenden

17voto

Chris Taylor Punkte 50950

Ein paar Dinge.

1- Verwenden Sie denselben Leitungsnamen
C++ : " \\.\pipe\HyperPipe "
C# : "HyperPipe"

2- Ich denke, dass es auf der C#-Seite besser sein könnte, ReadToEnd() zu verwenden. Ich habe nur benannte Pipes in C++ verwendet, aber ich nehme an, dass ReadToEnd() eine Nachricht lesen wird, da Sie message basierte Pipes verwenden.

3- Auf der C++-Seite versuchen Sie, nicht blockierende Pipes zu verwenden und die Pipe nach Verbindungen und Daten usw. abzufragen. Ich würde eines von drei Dingen vorschlagen.

  a - Use a blocking pipe on a separate thread or
  b - Use non blocking pipes using Overlapped IO
  c - Use non blocking pipes using IOCompletion ports

Die erste Option wäre die einfachste und für das, was du vorhast, ist sie gut skalierbar. Hier ist ein Link zu einem einfachen Beispiel zu (a) http://msdn.microsoft.com/en-us/library/aa365588(VS.85).aspx

4- Stellen Sie sicher, dass Ihre Kodierungen auf beiden Seiten übereinstimmen. Wenn Ihr C++-Code zum Beispiel für Unicode kompiliert ist, müssen Sie den Pipe-Stream auf der C#-Seite mit Unicode-Kodierung lesen. So etwas wie das Folgende.

using (StreamReader rdr = new StreamReader(pipe, System.Text.Encoding.Unicode))
{
  System.Console.WriteLine(rdr.ReadToEnd());
}

Update : Da ich nicht mit diesem in C# gearbeitet hatte, dachte ich, ich würde einen kleinen Test schreiben. Nur mit Blocking Pipes kein Threading oder irgendetwas, nur um zu bestätigen, die Grundlagen funktionieren, hier ist die sehr grobe Test-Code.

C++ Server

#include <tchar.h>
#include <windows.h>

int _tmain(int argc, _TCHAR* argv[])
{
  HANDLE hPipe = ::CreateNamedPipe(_T("\\\\.\\pipe\\HyperPipe"),
    PIPE_ACCESS_DUPLEX,
    PIPE_TYPE_MESSAGE | PIPE_READMODE_MESSAGE,
    PIPE_UNLIMITED_INSTANCES,
    4096,
    4096,
    0,
    NULL);

  ConnectNamedPipe(hPipe, NULL);

  LPTSTR data = _T("Hello");
  DWORD bytesWritten = 0;
  WriteFile(hPipe, data, _tcslen(data) * sizeof(TCHAR), &bytesWritten, NULL);
  CloseHandle(hPipe);
  return 0;
}

C#-Client

using System;
using System.Text;
using System.IO;
using System.IO.Pipes;

namespace CSPipe
{
  class Program
  {
    static void Main(string[] args)
    {
      NamedPipeClientStream pipe = new NamedPipeClientStream(".", "HyperPipe", PipeDirection.InOut);
      pipe.Connect();
      using (StreamReader rdr = new StreamReader(pipe, Encoding.Unicode))
      {
        System.Console.WriteLine(rdr.ReadToEnd());
      }

      Console.ReadKey();
    }
  }
}

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X