簡體   English   中英

為只讀命名管道啟用MessageMode時的C#UnauthorizedAccessException(NamedPipeClientStream類)

[英]C# UnauthorizedAccessException when enabling MessageMode for read-only named pipe (NamedPipeClientStream class)

.NET中的NamedPipeClientStream類存在問題,因為您無法使用PipeDirection.In創建此類的實例,然后成功將ReadMode更改為PipeTransmissionMode.Message

嘗試這樣做會引發UnauthorizedAccessException 雖然管道通常用於在進程之間進行通信,但是在單個進程中的這個簡單示例顯示了問題:

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

嘗試設置ReadMode屬性時,此代碼將拋出UnauthorizedAccessException


在搜索有關此問題的信息時,我在其他地方找到了對它的引用,例如:

所有這些帖子都提到這是“奇怪的”,“奇怪的”等,但不解釋“為什么”它不起作用,並且都給出相同的解決方法,“出於某種奇怪的原因”設置管道方向到InOut使它工作。

確實,這確實使它工作,但它需要從根本上改變管道的兩端定義到全雙工,而不是單向,我認為這是一個非常差的方法,除非你是能夠改變客戶端和服務器,這甚至可能是不可能的。


我的問題是,為什么在入站管道上啟用消息模式會導致異常,是否有更好的方法來解決此問題,而不是將管道更改為雙向模式?

查看Microsoft參考源,我可以看到設置ReadMode屬性只是調用win32 SetNamedPipeHandleState函數來執行操作,此調用的錯誤作為異常引發。 根據文檔SetNamedPipeHandleState函數,它說明了管道句柄,以便調用此函數

句柄必須具有對只讀或讀/寫管道的命名管道的GENERIC_WRITE訪問權限,或者對於只讀管道必須具有GENERIC_READ和FILE_WRITE_ATTRIBUTES訪問權限。

這就是問題所在。

如果我們看一下構造函數NamedPipeClientStream是參加一個PipeDirection設置,我們可以看到,他們只要求GENERIC_READ訪問PipeDirection.InGENERIC_WRITE訪問PipeDirection.Out (或兩者InOut )。 這意味着以OutInOut模式打開的任何管道都可以工作,因為GENERIC_WRITE訪問對於這些情況就足夠了,但我們需要GENERIC_READFILE_WRITE_ATTRIBUTES作為只讀管道, NamedPipeClientStream類從不請求。 這是課堂上的缺陷,應由Microsoft更正。

我在這里提交了有關Microsoft Connect的錯誤報告:

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

如果您自己遇到此問題,請向上投票,這可能有助於加快修復速度。


直到修復(從2017年3月開始沒有),人們可以通過為NamedPipeClientStream使用不同的構造函數來完全解決這個問題。

還有,它接受,而不是一個構造函數的一個重載PipeDirection枚舉,一個PipeAccessRights枚舉相反,在那里你可以指定你想獲得手柄的訪問權限的特定組合。 構造函數然后導出管的從指定的訪問權的組合(該方向In如果ReadData被指定時, Out “如果WriteData被指定時, InOut如果它們都指定)。

這意味着,您可以通過簡單地更改構造函數行來解決此問題,而無需使管道全雙工:

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

對此:

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

如果您使用此備用構造函數作為建議的解決方法,則結果將與您從構造函數的第一種形式獲得的結果相同且無法區分,除了將獲得此附加訪問權限,以便消息模式可以是啟用。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM