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
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.
- Run the Client from Visual Studio.
-
All editing, debugging and execution controlled from the client occurs in
the server.
-
Multiple clients can collaboratively edit the same script.
Client/Server Solutions:
Copyright Polar Engineering, Inc.