logo WinWrap®

Inter-Process

WinWrap® Basic is an embedded language control available for .NET/COM 32/64 bit Windows applications. The WinWrap® Basic Component is compatible with VBA, Sax Basic, VB.NET and Visual Basic 6.0 style scripts.

Edit, debug and execute scripts in a different process.

Inter-Process

  • Script execution in a different process.
  • UI process requires a WWAC02X Application Certificate.
  • Collaboratively edit, debug and execute from a BasicIdeCtl control.
  • Scripts managed by the service (requires a WWAC12 Application Certificate).
  • Collaborative editing requires the Collaborative Editing option on the WWAC12 Application Certificate.

Inter-Process

Inter-Process

WinWrap® Basic scripting functionality in a remote process can be configured to limit user capabilities:

  • No limitations: Requires application level user authentication. (WinWrap® Basic does not provide this.)
  • Safe scripting: See the Secure Scripting best practices solution.
  • Script source: See the Virtual File System best practices solution.
  • Edit only: See the EditOnly property.

WinWrap® Basic inter-process communication requires that the synchronize messages be passed between to the two processes. This example shows how to implement a server using a WCF service containing a BasicNoUIObj object and a client using a BasicIdeCtl control.

Server: WinWrap® Basic in a WCF Service

The process executing WinWrap® Basic scripts can be a service or a regular Windows Application. This sample shows how to edit, debug and execute scripts in a WCF service. In this sample two WCF entry points are used:

namespace SyncInterProcessWcfService { [ServiceContract] public interface ISyncMessagesService { [OperationContract] string GetResponses(int[] ids); [OperationContract] void SendRequests(string requests); } }

Each implements communicating with the BasicNoUIObj object:

  • GetResponses returns queued BasicNoUIObj object Sychronizing event data.
  • SendRequests receives Synchronizing event data from the remote BasicIdeCtl control.

The WCF service implements these two entry points:

namespace SyncInterProcessWcfService { // NOTE: In order to launch WCF Test Client for testing this service, please select WinWrapBasicService.svc or WinWrapBasicService.svc.cs at the Solution Explorer and start debugging. [ServiceBehavior(InstanceContextMode = InstanceContextMode.Single /*, ConcurrencyMode = ConcurrencyMode.Multiple*/)] public class SyncMessagesService : ISyncMessagesService { BasicThread basic_thread_; string log_file_; object lock_ = new object(); WWB.SynchronizingQueues responses_sqs_ = new WWB.SynchronizingQueues(); public SyncMessagesService() { } // GetResponses operation public string GetResponses(int[] ids) { string responses = null; WWB.SynchronizingQueue sq = new WWB.SynchronizingQueue(0); for (int i = 0; i < 20; ++i) { // get all pending responses lock (lock_) foreach (int id in ids) sq.Enqueue(responses_sqs_.Dequeue(id)); responses = sq.DequeueAll(); if (responses != null) break; // wait for more responses Thread.Sleep(50); } return responses; } // SendRequests operation public void SendRequests(string requests) { if (basic_thread_ == null) { // authorizing application name is: // "@" + System.ServiceModel.OperationContext.Current.Host.Description.ServiceType.Assembly.FullName Util.SetCurrentServiceType(); log_file_ = Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments) + "\\SyncMessagesService.txt"; File.WriteAllText(log_file_, ""); basic_thread_ = new BasicThread(); SynchronizationContext sc = new SynchronizationContext(); basic_thread_.SendAction(basic => { // configure basic basic.Synchronizing += (sender2, e2) => { // response/notification from the remote BasicNoUIObj lock (lock_) responses_sqs_.Enqueue(e2.Param, e2.Id); Log(e2.Param); }; Util.IgnoreDialogs = true; // set the BasicNoUIObj's secret basic.Secret = new Guid("00000000-0000-0000-0000-000000000001"); // initialize basic in the remote thread basic.Initialize(); // block unsafe scripting basic.Sandboxed = true; // block UI instructions basic.BlockedKeywords = "AboutWinWrapBasic Beep Dialog GetFilePath InputBox MsgBox ShowPopupMenu"; // restrict file access basic.VirtualFileSystem = new WWB.MyFileSystem(Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments) + @"\SyncInterProcess"); // turn on NoUI's synchronized edit basic.SynchronizedEdit = true; }); } Log(requests); basic_thread_.PostAction(basic => basic.Synchronize(requests, 0)); } private void Log(string param) { if (param != "[]") lock (lock_) File.AppendAllText(log_file_, param + "\r\n\r\n"); } } }

Client: WinWrap® Basic IDE in a Windows Application

The user can edit, debug and scripts using a client process which contains a WinWrap® Basic IDE communicating with the WCF service. The client process uses the WCF service entry points to communicate with the remote BasicNoUIObj object:

namespace SyncInterProcessClient { public partial class Form1 : Form { private SyncInterProcessWcfServiceReference.SyncMessagesServiceClient smsc_; private string log_file_; private int sync_id_; private Task responses_task_; private object lock_ = new object(); public Form1() { InitializeComponent(); // create log file log_file_ = Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments) + $"\\SyncInterProcessClient.txt"; // delete previous log File.WriteAllText(log_file_, ""); } private void Shutdown() { if (smsc_ != null) { // close the service client smsc_.Close(); // wait for responses task to end responses_task_.Wait(); // dispose of the task responses_task_.Dispose(); smsc_ = null; } } private void Form1_Load(object sender, EventArgs e) { // create the service client smsc_ = new SyncInterProcessWcfServiceReference.SyncMessagesServiceClient(); // start responses task responses_task_ = Task.Run(() => { // responses task while (smsc_.State != System.ServiceModel.CommunicationState.Closed) { int[] ids; lock (lock_) ids = new int[] { sync_id_ }; try { // get responses string responses = smsc_.GetResponses(ids); // synchronize IDE basicIdeCtl1.Synchronize(responses, 0); } catch { } } }); } private void Form1_Activated(object sender, EventArgs e) { if (!basicIdeCtl1.SynchronizedEdit) { // turn on synchronized editing basicIdeCtl1.SynchronizedEdit = true; // share the synchronized id with the get responses task lock (lock_) sync_id_ = basicIdeCtl1.SynchronizedId; } } private void Form1_FormClosed(object sender, FormClosedEventArgs e) { Shutdown(); } private void basicIdeCtl1_Disconnected(object sender, EventArgs e) { Shutdown(); } private void basicIdeCtl1_Synchronizing(object sender, WinWrap.Basic.Classic.SynchronizingEventArgs e) { if (smsc_ != null) { string requests = e.Param; // log requests if (requests != null && requests != "[]") File.AppendAllText(log_file_, $"-- Id={basicIdeCtl1.SynchronizedId} Synchronizing --\r\n{requests}\r\n\r\n"); // send requests to the service smsc_.SendRequests(requests); } } } }

Sample source code available.

  • Run the WCF Service from Visual Studio.
    Service
  • Run the Client from Visual Studio.
    Client
  • All editing, debugging and execution controlled from the client occurs in the server.
  • Multiple clients can collaboratively edit the same script.

Client/Server Solutions:


Cross Thread

Inter-Process

Web Server

Web Page Client

Copyright Polar Engineering, Inc.