private void WebBrowser_Paint(object sender, OnPaintEventArgs e) { // pixel data for the image: width * height * 4 bytes // BGRA image with upper-left origin int numberOfBytes = e.Height * e.Width * 4; if (paintBitmap == null || numberOfBytes != paintBitmap.Length) { paintBufferSize = numberOfBytes; paintBitmap = new byte[paintBufferSize]; Logr.Log("Paint buffer: Resizing to", paintBufferSize, "bytes"); } try { Marshal.Copy(e.BufferHandle, paintBitmap, 0, paintBufferSize); } catch (AccessViolationException) { Logr.Log("WARN: Marshal copy failed: Access violation while reading frame buffer."); } this.runner.AddTask(new SendFrameTask(paintBitmap)); }
private static void CurrentDomain_UnhandledException(object sender, UnhandledExceptionEventArgs e) { Logr.Log("UNHANDLED EXCEPTION:", e.ExceptionObject); Logr.Log("Forcing shutdown."); Environment.Exit(2); }
public void HandleIncomingMessage(PipeProtoMessage incomingMessage) { LastActivity = DateTime.Now; switch (incomingMessage.Opcode) { case PipeProto.OPCODE_PING: GotRemotePing = true; break; case PipeProto.OPCODE_FRAME: runner.AddTask(new RepaintFrameTask()); break; case PipeProto.OPCODE_MOUSE_EVENT: runner.AddTask(new SetMouseTask(new CefUnityLib.Messages.MouseEventPipeMessage(incomingMessage.Payload))); break; case PipeProto.OPCODE_MOUSE_WHEEL_EVENT: runner.AddTask(new SendMouseWheelEventTask(new CefUnityLib.Messages.MouseWheelEventPipeMessage(incomingMessage.Payload))); break; case PipeProto.OPCODE_KEY_EVENT: runner.AddTask(new SendKeyEventTask(new CefUnityLib.Messages.KeyEventPipeMessage(incomingMessage.Payload))); break; case PipeProto.OPCODE_SHUTDOWN: runner.AddTask(new ShutdownTask()); break; case PipeProto.OPCODE_NAVIGATE: runner.AddTask(new NavigateTask(Encoding.UTF8.GetString(incomingMessage.Payload))); break; case PipeProto.OPCODE_RESIZE: runner.AddTask(new ResizeTask(Encoding.UTF8.GetString(incomingMessage.Payload))); break; case PipeProto.OPCODE_SCRIPT: runner.AddTask(new ExecScriptTask(Encoding.UTF8.GetString(incomingMessage.Payload))); break; default: Logr.Log("Pipe server error. Could not route message due to unrecognized packet opcode:", incomingMessage.Opcode); break; } }
public void SetForcedFps(bool enableForcedFps, int autoRepaintTicks) { this._enableForcedFps = enableForcedFps; this._autoRepaintTicks = autoRepaintTicks; if (enableForcedFps) { Logr.Log($"Forced FPS mode: Repaint must happen every {autoRepaintTicks} ticks"); } }
public void Resize(int width, int height) { // Resize this.webBrowser.Size = new System.Drawing.Size(width, height); // Reset frame buffer paintBitmap = null; // Force repaint if browser is ready Repaint(); Logr.Log(String.Format("Browser host: Resized viewport to {0}x{1}.", width, height)); }
public static void ShutDown() { Logr.Log("Beginning shutdown procedure."); // Shut down pipe server Program.pipeServer.Stop(); // Stop task runner Program.taskRunner.Stop(); // Stop browser process Program.browserHost.Stop(); }
public void RunOnThread(BrowserHost host, PipeServer server) { SetForcedFps(true, 16); try { Logr.Log("Started task runner."); while (KeepAlive) { lock (_taskList) { while (_taskList.Count > 0) { var nextTask = _taskList.Dequeue(); try { if (_enableForcedFps && (nextTask is SendFrameTask || nextTask is RepaintFrameTask)) { _idleTicks = 0; } nextTask.Run(host, server); } catch (Exception ex) { Logr.Log("Exception while executing internal task:", ex.Message, ex); } } if (_enableForcedFps && _idleTicks++ >= _autoRepaintTicks) { host.Repaint(); } } Thread.Sleep(1); // we need to run more than 30 times per second for frame transfers } Logr.Log("Task runner shutting down."); } catch (ThreadInterruptedException) { } catch (ThreadAbortException) { } }
public void SendData(byte[] data) { if (stream != null && stream.IsConnected && GotRemotePing) { lock (stream) { try { stream.Write(data, 0, data.Length); stream.Flush(); } catch (Exception ex) { Logr.Log("Pipe send error:", ex); } } } }
public static void Main(string[] args) { // Read args string pipeName = args.Length > 0 ? args[0] : ""; if (String.IsNullOrWhiteSpace(pipeName)) { pipeName = "default"; } // Environment prep Console.Title = String.Format("CEF Ingame Browser [{0}]", pipeName); Environment.ExitCode = 1; AppDomain.CurrentDomain.UnhandledException += CurrentDomain_UnhandledException; Logr.Log("Starting CefUnityServer at", DateTime.Now); // Initialize core components Program.taskRunner = new TaskRunner(); Program.pipeServer = new PipeServer(pipeName, taskRunner); Program.browserHost = new BrowserHost(taskRunner); Program.browserHost.starturl = args.Length > 1 ? args[1] : "google.com"; Program.browserHost.startsize = args.Length > 2 ? args[2] : "1024x768"; // Initialize CEF browser and wait for it to be ready Logr.Log("Waiting for Chromium to be ready."); Program.browserHost.Start(); Logr.Log("Browser started and initialized."); // Begin named pipe server for data comm pipeServer.StartAsNewTask(); // Begin task runner Program.taskRunner.RunOnThread(browserHost, pipeServer); // Clean shutdown Logr.Log("Nothing left to do on main thread. (Clean shutdown)"); Environment.ExitCode = 0; // Wait before shutdown so msg is visible in console & everything shuts down clean Thread.Sleep(1000); }
protected void DoAutoShutdownCheck() { var now = DateTime.Now; if (KeepAlive && stream != null && stream.CanRead) { // Stream is still open, update activity and move on LastActivity = now; return; } var then = LastActivity; var diff = now - then; if (Math.Abs(diff.TotalSeconds) >= NO_COMM_AUTO_SHUTDOWN_AFTER_SECS) { Logr.Log(String.Format("Named pipe server: No network activity! Starting automatic shutdown. (Triggered after {0} seconds of inactivity.)", NO_COMM_AUTO_SHUTDOWN_AFTER_SECS)); Program.ShutDown(); return; } }
private void WebBrowser_OnPaint(object sender, OnPaintEventArgs e) { if (paintBitmap == null || e.NumberOfBytes != paintBitmap.Length) { paintBufferSize = e.NumberOfBytes;// this.webBrowser.Size.Width * this.webBrowser.Size.Height * e.BytesPerPixel; paintBitmap = new byte[paintBufferSize]; Logr.Log("Paint buffer: Resizing to", paintBufferSize, "bytes"); } try { Marshal.Copy(e.BufferHandle, paintBitmap, 0, paintBufferSize); } catch (AccessViolationException ex) { Logr.Log("WARN: Marshal copy failed: Access violation while reading frame buffer."); } this.runner.AddTask(new SendFrameTask(paintBitmap)); }
public void RunOnThread(BrowserHost host, PipeServer server) { this.host = host; this.server = server; try { Logr.Log("Started task runner."); while (KeepAlive) { lock (taskList) { while (taskList.Count > 0) { var nextTask = taskList[0]; taskList.RemoveAt(0); try { nextTask.Run(host, server); } catch (Exception ex) { Logr.Log("Exception while executing internal task:", ex.Message, ex); } } } Thread.Sleep(1); // we need to run more than 30 times per second for frame transfers } Logr.Log("Task runner shutting down."); } catch (ThreadInterruptedException) { } catch (ThreadAbortException) { } }
public void StartAsNewTask() { // Background task thread: Auto shutdown after inactivity Task.Run(new Action(() => { while (KeepAlive) { DoAutoShutdownCheck(); Thread.Sleep(1000); } })); // Background task thread: Accept connections and receive incoming data Task.Run(new Action(() => { LastActivity = DateTime.Now; while (KeepAlive) { DoAutoShutdownCheck(); if (stream == null) { stream = new NamedPipeServerStream(pipeName, PipeDirection.InOut, 1, PipeTransmissionMode.Byte, PipeOptions.Asynchronous); Logr.Log(String.Format("Started named pipe server [{0}].", pipeName)); } try { GotRemotePing = false; stream.WaitForConnection(); } catch (Exception e) { Logr.Log("Named pipe: Connection is failing.", e.Message); KillStream(); continue; } try { Logr.Log("Named pipe: New connection established."); // Force a repaint to cause frame to be re-sent to the connecting client runner.AddTask(new RepaintFrameTask()); while (stream.CanRead && KeepAlive) { var incomingMessage = PipeProtoMessage.ReadFromStream(stream); if (incomingMessage != null) { Task.Run(new Action(() => { HandleIncomingMessage(incomingMessage); })); } } Logr.Log("Named pipe: Connection is closing."); } catch (Exception ex) { Logr.Log("Named pipe connection had an unexpected failure:", ex.Message, ex); } } Logr.Log("Named pipe server has shut down."); KillStream(); })); }