如何异步运行NamedPipeServerStream?
我没有通过服务器在另一台计算机上使用该管道。我只在我的电脑上使用它。这是代码:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Drawing;
using System.IO.Pipes;
using System.Runtime.InteropServices;
namespace ScreenVideoRecorder
{
class Ffmpeg
{
NamedPipeServerStream p;
String pipename = "mytestpipe";
byte[] b;
//int i, j;
System.Diagnostics.Process process;
public Ffmpeg()
{
}
public void Start(string FileName, int BitmapRate )
{
p = new NamedPipeServerStream(pipename, PipeDirection.Out, 1, PipeTransmissionMode.Byte);
b = new byte[1920 * 1080 * 3]; // Some buffer for the R, G and B of pixels of an image of size 720p.
process = new System.Diagnostics.Process();
process.StartInfo.FileName = @"D:\pipetest\pipetest\ffmpegx86\ffmpeg.exe";
process.EnableRaisingEvents = false;
process.StartInfo.WorkingDirectory = @"D:\pipetest\pipetest\ffmpegx86";
process.StartInfo.Arguments = @"-f rawvideo -pix_fmt bgr0 -video_size 1920x1080 -i \\.\pipe\mytestpipe -map 0 -c:v libx264 -r " + BitmapRate + " " + FileName;
process.Start();
process.StartInfo.UseShellExecute = false;
process.StartInfo.CreateNoWindow = false;
p.WaitForConnection();
}
一切正常。问题是当进程启动时,我看到命令提示符窗口并看到窗口中的所有工作。我无法进入表格。我可以在屏幕上拖动/移动命令提示符窗口,但我无法进入窗体窗口单击按钮或停止操作。我需要等待它先完成在命令提示符窗口或进程窗口中完成工作。
使用以下代码行,我看到了变量p的一个属性来检查它是否异步但是如何将它设置为异步?
p.IsAsync
我试图找到示例,但它们都是根据我认为安全的两台计算机之间的服务器而来的。
后来,我更改了这一行:
p = new NamedPipeServerStream(pipename, PipeDirection.Out, 1, PipeTransmissionMode.Byte,PipeOptions.Asynchronous);
最后添加:PipeOptions.Asynchronous
现在,当我正在运行我的应用程序时,我遇到了异常:
p.Write(rgbValues, 0, length);
例外:
InvalidOpertionException:管道尚未连接。
这是我的完整代码,包含所有更改:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Drawing;
using System.IO.Pipes;
using System.Runtime.InteropServices;
namespace ScreenVideoRecorder
{
class Ffmpeg
{
NamedPipeServerStream p;
String pipename = "mytestpipe";
byte[] b;
//int i, j;
System.Diagnostics.Process process;
IAsyncResult ar;
public Ffmpeg()
{
}
public void Start(string FileName, int BitmapRate )
{
p = new NamedPipeServerStream(pipename, PipeDirection.Out, 1, PipeTransmissionMode.Byte,PipeOptions.Asynchronous);
b = new byte[1920 * 1080 * 3]; // Some buffer for the R G and B of pixels of an image of size 720p.
process = new System.Diagnostics.Process();
process.StartInfo.FileName = @"D:\pipetest\pipetest\ffmpegx86\ffmpeg.exe";
process.EnableRaisingEvents = false;
process.StartInfo.WorkingDirectory = @"D:\pipetest\pipetest\ffmpegx86";
process.StartInfo.Arguments = @"-f rawvideo -pix_fmt bgr0 -video_size 1920x1080 -i \\.\pipe\mytestpipe -map 0 -c:v libx264 -r " + BitmapRate + " " + FileName;
process.Start();
process.StartInfo.UseShellExecute = false;
process.StartInfo.CreateNoWindow = false;
ar = p.BeginWaitForConnection(EndWait,null);
}
void EndWait(IAsyncResult iar)
{
var state = ar.AsyncState; //fetch result, mandatory!
}
public void PushFrame(Bitmap bmp)
{
int length;
// Lock the bitmap's bits.
//bmp = new Bitmap(1920, 1080);
Rectangle rect = new Rectangle(0, 0, bmp.Width, bmp.Height);
//Rectangle rect = new Rectangle(0, 0, 1280, 720);
System.Drawing.Imaging.BitmapData bmpData =
bmp.LockBits(rect, System.Drawing.Imaging.ImageLockMode.ReadOnly,
bmp.PixelFormat);
int absStride = Math.Abs(bmpData.Stride);
// Get the address of the first line.
IntPtr ptr = bmpData.Scan0;
// Declare an array to hold the bytes of the bitmap.
//length = 3 * bmp.Width * bmp.Height;
length = absStride * bmpData.Height;
byte[] rgbValues = new byte[length];
//Marshal.Copy(ptr, rgbValues, 0, length);
int j = bmp.Height - 1;
for (int i = 0; i < bmp.Height; i++)
{
IntPtr pointer = new IntPtr(bmpData.Scan0.ToInt32() + (bmpData.Stride * j));
System.Runtime.InteropServices.Marshal.Copy(pointer, rgbValues, absStride * (bmp.Height - i - 1), absStride);
j--;
}
p.Write(rgbValues, 0, length);
bmp.UnlockBits(bmpData);
异常消息:
System.InvalidOperationException was unhandled
HResult=-2146233079
Message=Pipe hasn't been connected yet.
Source=System.Core
StackTrace:
at System.IO.Pipes.PipeStream.CheckWriteOperations()
at System.IO.Pipes.PipeStream.Write(Byte[] buffer, Int32 offset, Int32 count)
at ScreenVideoRecorder.Ffmpeg.PushFrame(Bitmap bmp) in d:\C-Sharp\ScreenVideoRecorder\ScreenVideoRecorderWorkingVersion\Ffmpeg.cs:line 77
at ScreenVideoRecorder.Form1.StartRecording_Click(Object sender, EventArgs e) in d:\C-Sharp\ScreenVideoRecorder\ScreenVideoRecorderWorkingVersion\Form1.cs:line 53
at System.Windows.Forms.Control.OnClick(EventArgs e)
at System.Windows.Forms.Button.OnClick(EventArgs e)
at System.Windows.Forms.Button.OnMouseUp(MouseEventArgs mevent)
at System.Windows.Forms.Control.WmMouseUp(Message& m, MouseButtons button, Int32 clicks)
at System.Windows.Forms.Control.WndProc(Message& m)
at System.Windows.Forms.ButtonBase.WndProc(Message& m)
at System.Windows.Forms.Button.WndProc(Message& m)
at System.Windows.Forms.Control.ControlNativeWindow.OnMessage(Message& m)
at System.Windows.Forms.Control.ControlNativeWindow.WndProc(Message& m)
at System.Windows.Forms.NativeWindow.DebuggableCallback(IntPtr hWnd, Int32 msg, IntPtr wparam, IntPtr lparam)
at System.Windows.Forms.UnsafeNativeMethods.DispatchMessageW(MSG& msg)
at System.Windows.Forms.Application.ComponentManager.System.Windows.Forms.UnsafeNativeMethods.IMsoComponentManager.FPushMessageLoop(IntPtr dwComponentID, Int32 reason, Int32 pvLoopData)
at System.Windows.Forms.Application.ThreadContext.RunMessageLoopInner(Int32 reason, ApplicationContext context)
at System.Windows.Forms.Application.ThreadContext.RunMessageLoop(Int32 reason, ApplicationContext context)
at System.Windows.Forms.Application.Run(Form mainForm)
at ScreenVideoRecorder.Program.Main() in d:\C-Sharp\ScreenVideoRecorder\ScreenVideoRecorderWorkingVersion\Program.cs:line 18
at System.AppDomain._nExecuteAssembly(RuntimeAssembly assembly, String[] args)
at System.AppDomain.ExecuteAssembly(String assemblyFile, Evidence assemblySecurity, String[] args)
at Microsoft.VisualStudio.HostingProcess.HostProc.RunUsersAssembly()
at System.Threading.ThreadHelper.ThreadStart_Context(Object state)
at System.Threading.ExecutionContext.RunInternal(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx)
at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx)
at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state)
at System.Threading.ThreadHelper.ThreadStart()
InnerException:
答案 0 :(得分:2)
使用NamedPipeServerStream.WaitForConnection
时,当前线程将阻塞,直到操作完成
您可以使用BeginWaitForConnection
创建一个可在后台运行的线程
使用返回的IAsyncResult
,您可以获取异步操作的结果。
来自MSDN:
IAsyncResult接口由包含可以异步操作的方法的类实现。它是启动异步操作的返回类型的方法,例如FileStream.BeginRead
,它被传递给结束异步操作的方法,例如FileStream.EndRead
。当异步操作完成时,IAsyncResult
个对象也会传递给AsyncCallback
个委托调用的方法。
支持IAsyncResult
接口的对象存储异步操作的状态信息,并提供同步对象以允许在操作完成时发出线程信号。
class Ffmpeg
{
NamedPipeServerStream p;
String pipename = "mytestpipe";
byte[] b;
//int i, j;
System.Diagnostics.Process process;
IAsyncResult ar;
public Ffmpeg()
{
}
public void Start(string FileName, int BitmapRate )
{
p = new NamedPipeServerStream(pipename, PipeDirection.Out, 1, PipeTransmissionMode.Byte);
b = new byte[1920 * 1080 * 3]; // some buffer for the r g and b of pixels of an image of size 720p
process = new System.Diagnostics.Process();
process.StartInfo.FileName = @"D:\pipetest\pipetest\ffmpegx86\ffmpeg.exe";
process.EnableRaisingEvents = false;
process.StartInfo.WorkingDirectory = @"D:\pipetest\pipetest\ffmpegx86";
process.StartInfo.Arguments = @"-f rawvideo -pix_fmt bgr0 -video_size 1920x1080 -i \\.\pipe\mytestpipe -map 0 -c:v libx264 -r " + BitmapRate + " " + FileName;
process.Start();
process.StartInfo.UseShellExecute = false;
process.StartInfo.CreateNoWindow = false;
ar = p.BeginWaitForConnection(EndWait, null);
}
//callback when client connects
void EndWait(IAsyncResult iar){
var state = iar.AsyncState; // fetch state -> cast to desired type
//do something when client connected
}