匿名管道 c# WPF
Posted
技术标签:
【中文标题】匿名管道 c# WPF【英文标题】:Anonymous Pipes c# WPF 【发布时间】:2020-08-05 12:28:06 【问题描述】:我正在尝试通过在同一台机器上运行两个 WPF 应用程序来实现 IPC。我需要实现类似于 Example using Winform 的东西。有人可以将下面的代码转换为 WPF/C#,因为您可以看到委托调用直接依赖于 Winform 控件,
if (theArgs.Length == 0)
this.Text = "Pipe Server";
pipe = new AnonymousPipes("Server end of the pipe.", Application.ExecutablePath, "additionalArgs=your_own_command_line_args_here", delegate(String msg)
this.Invoke((MethodInvoker)delegate()
this.lbTextIn.Items.Add(msg);
);
, delegate()
// We're disconnected!
try
if (!this.IsDisposed)
this.Invoke((MethodInvoker)delegate()
this.lbTextIn.Items.Add("Client disconnected!");
);
catch (Exception)
);
else
this.Text = "Pipe Client";
pipe = new AnonymousPipes("Client end of the pipe.");
pipe.ConnectToPipe(theArgs[0], delegate(String msg)
this.Invoke((MethodInvoker)delegate()
lbTextIn.Items.Add(msg);
);
, delegate()
// We're disconnected!
this.Close();
);
Wrapper类的实现如下,
public class AnonymousPipes
private String clientPath;
private AnonymousPipeServerStream outGoingServerPipe;
private AnonymousPipeServerStream inComingServerPipe;
private PipeStream clientIn;
private PipeStream clientOut;
private Process pipeClient;
private String incomingHandle;
private String outgoingHandle;
private StreamWriter ssw;
private StreamWriter csw;
private bool serverMode;
private bool running;
private CallBack callback;
private DisconnectEvent disconnectEvent;
private String msgError;
private String name;
public delegate void CallBack(String msg);
public delegate void DisconnectEvent();
public String ermsg;
public bool isConnected()
return running;
public String GetPipeName()
return name;
public AnonymousPipes(String pipeName)
this.name = pipeName;
private String StartPipeServer()
serverMode = true;
outGoingServerPipe = new AnonymousPipeServerStream(PipeDirection.Out, HandleInheritability.Inheritable);
inComingServerPipe = new AnonymousPipeServerStream(PipeDirection.In, HandleInheritability.Inheritable);
return outGoingServerPipe.GetClientHandleAsString() + ":::" + inComingServerPipe.GetClientHandleAsString();
public AnonymousPipes(String pipeName, String clientPath, String cmdLineArgs, CallBack callback,
DisconnectEvent disconnectEvent)
String args;
this.clientPath = clientPath;
this.callback = callback;
this.disconnectEvent = disconnectEvent;
this.name = pipeName;
this.running = true;
serverMode = true;
args = StartPipeServer() + " " + cmdLineArgs;
try
pipeClient = new Process();
pipeClient.StartInfo.FileName = clientPath;
pipeClient.StartInfo.Arguments = args;
pipeClient.StartInfo.UseShellExecute = false;
pipeClient.Start();
catch (Exception ex)
ermsg = ex.Message;
running = false;
return;
outGoingServerPipe.DisposeLocalCopyOfClientHandle();
inComingServerPipe.DisposeLocalCopyOfClientHandle();
ssw = new StreamWriter(outGoingServerPipe);
ssw.AutoFlush = true;
ssw.WriteLine("SYNC");
outGoingServerPipe.WaitForPipeDrain();
new Thread(delegate ()
using (StreamReader isr = new StreamReader(inComingServerPipe))
String tmp;
while (running && inComingServerPipe.IsConnected)
tmp = isr.ReadLine();
if (tmp != null)
callback(tmp);
running = false;
disconnectEvent();
).Start();
public bool SendText(String msg)
return SendText(msg, ref msgError);
public bool SendText(String msg, ref String errMsg)
if (serverMode)
try
ssw.WriteLine(msg);
outGoingServerPipe.WaitForPipeDrain();
return true;
catch (Exception ex)
errMsg = ex.Message;
return false;
else
try
csw.WriteLine(msg);
clientOut.WaitForPipeDrain();
catch (Exception)
return true;
public void ConnectToPipe(String clientHandles, CallBack callback, DisconnectEvent disconnectEvent)
String[] handles = System.Text.RegularExpressions.Regex.Split(clientHandles, ":::");
this.incomingHandle = handles[0];
this.outgoingHandle = handles[1];
this.callback = callback;
this.disconnectEvent = disconnectEvent;
running = true;
serverMode = false;
new Thread(delegate ()
clientIn = new AnonymousPipeClientStream(PipeDirection.In, this.incomingHandle);
clientOut = new AnonymousPipeClientStream(PipeDirection.Out, this.outgoingHandle);
csw = new StreamWriter(clientOut);
csw.AutoFlush = true;
using (StreamReader sr = new StreamReader(clientIn))
string temp;
do
temp = sr.ReadLine();
while (!temp.StartsWith("SYNC") && running);
while (running && clientIn.IsConnected)
temp = sr.ReadLine();
if (temp != null) callback(temp);
running = false;
disconnectEvent();
).Start();
public void Close()
running = false;
try
pipeClient.Close();
catch (Exception)
try
outGoingServerPipe.Close();
catch (Exception)
try
inComingServerPipe.Close();
catch (Exception)
try
clientOut.Close();
catch (Exception)
try
clientIn.Close();
catch (Exception)
try
ssw.Close();
catch (Exception)
try
csw.Close();
catch (Exception)
【问题讨论】:
WPF 不会影响 IPC 的工作方式。您真正要问的是如何从另一个线程修改 UI,而答案是 - 根本不是那样的。自 2010 年引入 Tasks 以来,也没有更早。你关注的文章不好 我建议您改为查看文档,尤其是 How to: Use Anonymous Pipes for Local Interprocess Communication。 PipeStream 仍然是一个流,这意味着您可以使用async/await
从中读取数据并更新 UI,而无需启动原始线程、使用包装器或必须使用 Invoke
。
Progress reporting 可通过Process<T>
、cancellation 至CancellationToken
获得
感谢您的建议,我正在尝试在 IPC 上使用 wpf 到 wpf 通信之间的任意管道找到一个很好的示例。
再一次,WPF 与 IPC 没有任何关系。您可以只使用 doc 示例来设置客户端和服务器流。您的 实际 问题是如何从另一个线程修改 UI。对于 Winforms 和 WPF,自 2012 年以来的答案都是 async/await
,而不是 Invoke
。如果您查看管道的文档示例,您会发现它比您的代码简单很多。
【参考方案1】:
将Invoke
替换为Dispatcher.Invoke
,例如:
this.Dispatcher.Invoke(delegate ()
this.lbTextIn.Items.Add(msg);
);
【讨论】:
以上是关于匿名管道 c# WPF的主要内容,如果未能解决你的问题,请参考以下文章
匿名管道:当子进程被杀死时,父进程中的 ReadFile 继续等待