2015-09-23 8 views
12

Es gibt ein Problem mit der NamedPipeClientStream Klasse in .NET, dass Sie nicht eine Instanz dieser Klasse mit PipeDirection.In erstellen können, und dann erfolgreich die ReadMode-PipeTransmissionMode.Message ändern .C# UnauthorizedAccessException beim Aktivieren Message für Nur-Lese-Named Pipe (NamedPipeClientStream Klasse)

Der Versuch, dies zu tun, wird einen UnauthorizedAccessException auslösen. Obwohl Rohre in der Regel verwendet werden würden, zwischen den Prozessen, dieses einfache Beispiel in einem einzigen Prozess zeigt, das Problem zu kommunizieren:

var pipeOut = new NamedPipeServerStream("SomeNamedPipe", 
             PipeDirection.Out, 
             1, 
             PipeTransmissionMode.Message); 
var pipeIn = new NamedPipeClientStream(".", 
             "SomeNamedPipe", 
             PipeDirection.In); 
pipeIn.Connect(); 
pipeIn.ReadMode = PipeTransmissionMode.Message; 

Dieser Code ein UnauthorizedAccessException werfen wird, wenn versucht wird, die ReadMode Property zu setzen.


Bei der Suche nach Informationen zu diesem Problem, fand ich Verweise auf sie in anderen Orten, wie zum Beispiel hier:

Alle diese Posts erwähnen, dass dies "seltsam", "seltsam" usw. ist, aber nicht erklären, "warum" es nicht funktioniert, und alle geben die gleiche Problemumgehung, die "aus irgendeinem seltsamen Grund" Einstellung Rohrrichtung zu InOut macht es funktioniert.

Es stimmt zwar, dass es funktioniert, aber es erfordert grundlegende Änderung der Definition der Leitung, an beiden Enden, zu Vollduplex, anstatt in eine einzige Richtung zu gehen, die ich für einen sehr schlechten Ansatz halte, und es sei denn, Sie können sowohl den Client als auch den Server ändern, ist dies möglicherweise nicht möglich.


Meine Frage war, warum ermöglicht Nachrichtenmodus auf eine eingehende Rohr eine Ausnahme verursachen, und gibt es einen besseren Weg, um dieses Problem zu lösen, als das Rohr bidirektionalen Modus zu wechseln?

+0

Es hilft sicherlich nicht, dass die 'PipeDirection'-Enumeration genau rückwärts benannt wird. Sie schreiben an das Eingabeende einer unidirektionalen Pipe, die Daten gehen durch die Pipe zum anderen Prozess und können dann vom Ausgabeende gelesen werden. Aber 'PipeDirection.In' bedeutet lesbar (das Ausgabeende der Pipe). –

Antwort

17

Mit Blick auf die Microsoft-Referenzquelle konnte ich sehen, dass das Setzen der ReadMode Eigenschaft einfach die win32 SetNamedPipeHandleState-Funktion aufruft, um die Operation auszuführen, mit Fehlern von diesem Aufruf ausgelöst als Ausnahmen. Gemäß der Dokumentation SetNamedPipeHandleState function es um das Rohr besagt behandeln, dass, um

der Griff diese Funktion aufzurufen muss für eine Schreib nur GENERIC_WRITE Zugriff auf die Named Pipe oder/Schreibrohr lesen, oder es muss GENERIC_READ und FILE_WRITE_ATTRIBUTES Zugriff für eine schreibgeschützte Pipe.

Hier liegt das Problem.

Wenn wir die Konstrukteure für NamedPipeClientStream suchen, die in einer PipeDirection Einstellung nehmen, sehen wir, dass sie nur GENERIC_READ Zugang für PipeDirection.In fordern und GENERIC_WRITE Zugang für PipeDirection.Out (oder beides für InOut).Dies bedeutet, dass jedes Rohr in Out geöffnet oder InOut Modus funktionieren wird, wie GENERIC_WRITE Zugang für jene Fälle ausreichend ist, aber wir müssen beide GENERIC_READ und FILE_WRITE_ATTRIBUTES für ein Nur-Lese-Rohr, das die NamedPipeClientStream Klasse nie verlangt. Dies ist ein Fehler in der Klasse und sollte von Microsoft behoben werden.

Ich habe einen Fehlerbericht an Microsoft Connect hier vorgelegt:

https://connect.microsoft.com/VisualStudio/feedback/details/1825187

Bitte up-vote es, wenn Sie über dieses Problem selbst kommen, könnte es einen Fix beschleunigen helfen.


Bis einem Update (kein Stand 3/2017) kann man sich ganz um dieses Problem zu umgehen, indem eine andere Konstruktor für NamedPipeClientStream verwenden.

Es gibt eine Überladung des Konstruktors, die anstatt einer PipeDirection Enumeration eine PipeAccessRights Enumeration einnimmt, wo Sie die bestimmte Kombination von Zugriffsrechten angeben können, die Sie für das Handle erhalten möchten. Der Konstruktor leitet dann die Richtung des Rohres aus der Kombination von bestimmten Zugriffsrechten (In wenn ReadData angegeben, Out "wenn WriteData angegeben ist, InOut wenn sie beide festgelegt sind).

Das bedeutet, Sie dieses Problem lösen können ohne Ihre Rohre Vollduplex zu machen, indem man einfach einen Konstruktor Zeile wie diese zu ändern:

var pipeIn = new NamedPipeClientStream("<ServerName>", "<PipeName>", PipeDirection.In); 

dazu:

var pipeIn = 
    new NamedPipeClientStream("<ServerName>", 
          "<PipeName>", 
          PipeAccessRights.ReadData | PipeAccessRights.WriteAttributes, 
          PipeOptions.None, 
          System.Security.Principal.TokenImpersonationLevel.None, 
          System.IO.HandleInheritability.None); 

Wenn Sie diesen alternativen Konstruktor als eine vorgeschlagene Problemumgehung verwenden, ist das Ergebnis identisch und nicht von dem Ergebnis zu unterscheiden, das Sie von der ersten Form des Konstruktors erhalten würden, mit der Ausnahme, dass dieses zusätzliche Zugriffsrecht erhalten wird aktiviert sein.

Verwandte Themen