打包的 UWP 应用程序和 Desktop .Net 6.0 程序之间带有管道的 IPC
关于在 UWP 中执行管道 IPC 的复杂性的几个问题(不要告诉我使用应用服务,对于我的项目来说,它的解决方案延迟太低)。
我正在尝试在我的两个项目之间建立工作 IPC,其中一个是 UWP 打包应用程序,另一个是 C# .net6 应用程序。我已成功创建 NamedPipeServerStream 在我的 .net6 程序中。最初,我的 UWP 侧管道客户端 (NamedPipeClientStream) 在创建过程中会由于“访问路径被拒绝”错误而失败。
进行研究,我推断出我需要添加一些与我的 UWP 包的 SID 相关的访问规则,以便我的 UWP 应用程序可以成功与我的外部应用程序通信。似乎普通的 .net NamedPipeServerStream 不允许通过构造函数添加访问规则,但我可以使用 一个 nuget 包,NamedPipeServerStream.NetFrameworkVersion。我能够使用文档中描述的函数获取 SID,尽管结果证明这是错误的 SID。使用 powershell 命令“CheckNetIsolation.exe LoopbackExempt -s”中的硬编码 SID,我能够在 UWP 应用程序中成功创建 NamedPipeClientStream 对象,从而克服访问被拒绝错误。
但是,我之后直接调用的 connect 方法没有成功。我最终得到一个错误:
无法加载文件或程序集“System.Security.Principal.Windows, 版本=5.0.0.0,文化=中性,PublicKeyToken=b03f5f7f11d50a3a'。 找到的程序集的清单定义与程序集不匹配 参考。 (HRESULT 异常:0x80131040)
几个问题:
在两个项目之间建立管道实际上有这么困难吗?我已经接近隧道尽头的光明了吗?
为什么我的两种接收打包应用程序 SID 的方法会导致不同的 SIDS? C# 中有没有一种很好的编程方式来做到这一点?
以下是我的一些代码示例:
服务器:
//IntPtr ptr = IntPtr.Zero;
//var result = DeriveAppContainerSidFromAppContainerName("PackageFamilyName", ref ptr);
//var appSid = new SecurityIdentifier(ptr); //results in incorrect SID
var appSid = new SecurityIdentifier("hardCodedSID");
var access = new PipeSecurity();
SecurityIdentifier sid = new SecurityIdentifier(WellKnownSidType.WorldSid, null);
access.AddAccessRule(new PipeAccessRule(sid, PipeAccessRights.FullControl, System.Security.AccessControl.AccessControlType.Allow));
access.AddAccessRule(new PipeAccessRule(sid, PipeAccessRights.AccessSystemSecurity, System.Security.AccessControl.AccessControlType.Allow));
access.AddAccessRule(new PipeAccessRule(appSid, PipeAccessRights.FullControl, System.Security.AccessControl.AccessControlType.Allow));
access.AddAccessRule(new PipeAccessRule(appSid, PipeAccessRights.AccessSystemSecurity, System.Security.AccessControl.AccessControlType.Allow));
pipeServer = NamedPipeServerStreamConstructors.New("testpipe", PipeDirection.InOut, 1, PipeTransmissionMode.Message, PipeOptions.None, 0, 0, access);
pipeServer.WaitForConnection(); // gets past here when client creates NamedPipeClientStream
客户端:
pipeClient = new NamedPipeClientStream(".", "testpipe", PipeDirection.InOut, PipeOptions.Asynchronous);
pipeClient.Connect(5000); // fails here
A couple questions about the intricacies of doing pipe IPC in UWP (Don't tell me to use an app service, it's too low latency of a solution for my project).
I'm trying to get working IPC between two of my projects, one of them being a UWP packaged app, and the other being a C# .net6 app. I have successfully created a NamedPipeServerStream inside of my .net6 program. Initially, my UWP side pipe client (NamedPipeClientStream) would fail during creation due to a "Access to the path is denied" error.
Doing research, I have deduced that I need to add some access rules related to my UWP package's SID so that my UWP app can successfully communicate with my external app. It seems vanilla .net NamedPipeServerStream does not allow for access rules to be added via constructor, but I was able to work around it with a nuget package, NamedPipeServerStream.NetFrameworkVersion. I was able to get a SID using a function described in the docs, although this turned out to be the wrong SID. Using a hard coded SID from the powershell command "CheckNetIsolation.exe LoopbackExempt -s", I was able to successfully create the NamedPipeClientStream object in my UWP app, getting past the access denied error.
However, the connect method that I call directly after does not succeed. I end up getting an error:
Could not load file or assembly 'System.Security.Principal.Windows,
Version=5.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a'.
The located assembly's manifest definition does not match the assembly
reference. (Exception from HRESULT: 0x80131040)
A couple questions:
Is making a pipe between the two projects actually this difficult? Am I close to the light at the end of the tunnel?
Why did my two methods of receiving the SID for my packaged app result in different SIDS? Is there a nice programmatic way in C# to do this?
Here are some of my code samples:
Server:
//IntPtr ptr = IntPtr.Zero;
//var result = DeriveAppContainerSidFromAppContainerName("PackageFamilyName", ref ptr);
//var appSid = new SecurityIdentifier(ptr); //results in incorrect SID
var appSid = new SecurityIdentifier("hardCodedSID");
var access = new PipeSecurity();
SecurityIdentifier sid = new SecurityIdentifier(WellKnownSidType.WorldSid, null);
access.AddAccessRule(new PipeAccessRule(sid, PipeAccessRights.FullControl, System.Security.AccessControl.AccessControlType.Allow));
access.AddAccessRule(new PipeAccessRule(sid, PipeAccessRights.AccessSystemSecurity, System.Security.AccessControl.AccessControlType.Allow));
access.AddAccessRule(new PipeAccessRule(appSid, PipeAccessRights.FullControl, System.Security.AccessControl.AccessControlType.Allow));
access.AddAccessRule(new PipeAccessRule(appSid, PipeAccessRights.AccessSystemSecurity, System.Security.AccessControl.AccessControlType.Allow));
pipeServer = NamedPipeServerStreamConstructors.New("testpipe", PipeDirection.InOut, 1, PipeTransmissionMode.Message, PipeOptions.None, 0, 0, access);
pipeServer.WaitForConnection(); // gets past here when client creates NamedPipeClientStream
Client:
pipeClient = new NamedPipeClientStream(".", "testpipe", PipeDirection.InOut, PipeOptions.Asynchronous);
pipeClient.Connect(5000); // fails here
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
通过独立研究,我获得了一些可行的解决方案。有几个答案:
NamedPipeServerStreamConstructors.New via NamedPipeServerStream.NetFrameworkVersion 已弃用战略。 .Net 6.0 提供了我试图通过 NamedPipeServerStreamACL。我选择使用它而不是我的示例中当前的内容。
尝试使用 NamedPipeClientStream 连接时,我无法找出 UWP 应用程序中发生的“System.Security.Principal.Windows”错误。我认为这可能只是一个错误或其他什么。如果有人知道那里发生了什么,将不胜感激。
为了解决问题 2,我使用 CreateFileW。这是一个较低级别的 C++ 函数,而前一个函数是 C# 的等效函数。看来 C# 版本对“.\pipe\”前缀具有一定的智能,因此在创建管道服务器时不需要它。但是,UWP 客户端代码中的 C++ 函数需要包含该函数(不需要使用 LOCAL 前缀)。通过此设置,我能够将请求从 .Net 6.0 管道服务器发送到 UWP 管道客户端并获取响应。最后是一些代码片段:
仍然不知道为什么我通过 DeriveAppContainerSidFromAppContainerName。我查看了我的注册表,甚至找不到它试图指向我的 SID。超级困惑。
客户端代码:
服务端构建代码:
I was able to get somewhat of a working solution doing independent research. A couple answers:
NamedPipeServerStreamConstructors.New via NamedPipeServerStream.NetFrameworkVersion is a deprecated strategy. .Net 6.0 provides what I was trying to do via NamedPipeServerStreamACL. I opted to use this instead of what is currently in my sample.
I could not figure out the error with "System.Security.Principal.Windows" that was happening in my UWP app when trying to connect using NamedPipeClientStream. I think it just might be a bug or something. If anyone knows what is going on there, would be appreciated.
To work around #2, I implemented a lower level version of what I was trying to do using CreateFileW. This is a lower level c++ function, whilst the previous is the C# equivalent. It appears that the C# version has some intelligence with the ".\pipe\" prefix, so it is not needed when creating the pipe server. However, the C++ function in the client code for UWP will need to include that (no use of LOCAL prefix was needed). With this set up, I was able to send requests from my .Net 6.0 pipe server to my UWP pipe client and get responses back. Towards the end are some code snippets:
Still do not know the answer as to why I got the incorrect SID via DeriveAppContainerSidFromAppContainerName. I looked in my Registry and could not even located the SID it was trying to point me at. Mega confused.
Client code:
Server construction code: