我正在编写一个可执行文件,通过
NamedPipe
将数据发送到开放进程(Unity 游戏),以使用自定义 URI 方案“模拟”来自浏览器的深层链接。这意味着管道客户端和管道服务器都只能在 IPC 的本地用户上运行。
游戏开始
NamedPipeServerStream
并等待,直到客户端连接并发送数据:
var pipeSecurity = new PipeSecurity();
SecurityIdentifier everyone = new SecurityIdentifier(WellKnownSidType.WorldSid, null);
pipeSecurity.AddAccessRule(new PipeAccessRule(everyone, PipeAccessRights.Read, AccessControlType.Allow));
pipe = new NamedPipeServerStream(PIPE_NAME, PipeDirection.InOut, 1,
PipeTransmissionMode.Message, PipeOptions.Asynchronous,
8192, 8192, pipeSecurity);
try
{
await pipe.WaitForConnectionAsync(cancellationTokenSource.Token);
}
我的
Deeplink.exe
(使用 Rider 构建的 WinExe
)在打开并尝试连接时会创建 NamedPipeClientStream
:
using NamedPipeClientStream pipeClient = new(".", PIPE_NAME,
PipeDirection.InOut, PipeOptions.Asynchronous);
try
{
pipeClient.Connect(PIPE_TIMEOUT);
}
仅当 Deeplink.exe 以管理员身份运行时才能正常工作。
如果不是,pipeClient.Connect
会抛出
UnauthorizedAccessException: Access to the path is denied
。 我不能让我的应用程序在每次使用深层链接时都请求 UAC!从public mono repo 来看,这似乎与
UnauthorizedAccess_IODenied_NoPathName
字符串匹配,但我检查过,
PIPE_NAMEs
是正确的。起初我以为这是由于
Deeplink.exe
被放置在
C:/Program Files
文件夹下,靠近 Unity 程序的位置,但事实并非如此,即使尝试从桌面运行它,问题仍然存在。我尝试过使用
PipeAccessRights.FullAccess
来代替,但也没有运气。鉴于 UAC 是它工作与不工作之间的唯一区别,我必须假设问题与权限相关(尽管我期望
WorldSid
允许任何人和任何东西访问管道)。有什么是我忽略的吗?没有管理员权限真的没有办法连接到管道吗?
Game Launcher 程序(我也在 Unity 中开发)运行,该程序简单地调用:
Process process = new();
process.StartInfo.FileName = "/path/to/game.exe";
process.StartInfo.UseShellExecute = true;
process.StartInfo.CreateNoWindow = false;
process.Start();
我发现:
Game.exe
,然后运行
Deeplink.exe
按预期工作。
Launcher.exe
,然后启动
Game.exe
进程,然后运行
Deeplink.exe
不起作用。在此过程中的任何步骤中,UAC 都应该不是 是必需的。
NamedPipeClientStream
有问题,但也许以这些特定的
Game.exe
属性开始
StartInfo
是阻止正确创建
NamedPipeServerStream
的原因?
game.exe
开始
UseShellExecute = false
,现在管道可以正确通信......但只是有时!它似乎在 75% 的时间内有效。我真的不知道是什么偶尔拒绝我的客户端管道访问,服务器总是根据我的日志启动。
问题似乎是,如果我的启动器以提升的权限打开,那么它运行的任何进程也会继承它们。这意味着我的
NamedPipeServerStream
有时会在提升的权限下运行,但我的
NamedPipeClientStream
始终会在 没有的情况下运行。无论我在创建过程中设置什么访问规则,我的管道客户端总是拒绝连接到它。 由于我不需要
game.exe
来获得提升的访问权限,因此我研究了如何取消提升由提升的子流程启动的子流程,并最终按照
这篇博文中的建议通过
explorer.exe
.
// If the Launcher has UAC, use the explorer to launch the game
if (FileUtility.HasElevatedPermissions())
{
ProcessStartInfo processInfo = new()
{
FileName = "explorer.exe",
UseShellExecute = true,
Arguments = $"\"{exePath}\""
};
Process.Start(processInfo);
}
// If the Launcher doesn't have UAC, open the game normally
else
{
ProcessStartInfo processInfo = new()
{
FileName = exePath,
UseShellExecute = true,
Verb = "open"
};
Process.Start(processInfo);
}
这似乎可以解决问题,
game.exe
总是在没有权限的情况下打开,并且
deeplinker.exe
管道可以毫无问题地进行通信。
感谢 @Sinatr和 @BenVoigt 的建议。 如果有人对
HasElevatedPermissions()
感兴趣,我尝试在
C:/Program Files
下创建一个目录并返回无论成功与否。public static bool HasElevatedPermissions(string _path = null)
{
if (string.IsNullOrEmpty(_path))
_path = Environment.GetFolderPath(Environment.SpecialFolder.ProgramFiles);
float random = UnityEngine.Random.Range(0f, 1f);
var path = @$"{_path}\temp{random}"; // Random to prevent user interference
try
{
Directory.CreateDirectory(path);
}
catch (UnauthorizedAccessException)
{
return false;
}
Directory.Delete(path);
return true;
}
我承认这不是最好的方法,但我找不到任何可以通过 Unity 程序轻松运行的方法。