Shim Wrappers

Shim Wrappers

CrossTalk cannot easily support generics. For more information, see this topic about generics. Fortunately if the API that you need to access is blocked because of generics, interfaces or other, you can use a shim rapper.

To write a shim wrapper you will need to write some basic code in some .NET language such as C#. This code is minimal, simple and small. The goal of this code is to create a .NET library that wraps and transforms the API to a simpler easier to consume API for CrossTalk without generics or interfaces.

Event Callbacks with Ref Arguments

If you have events that use ref arguments, shim wrappers are also necessary. In this example, we will show a simple example of this. Events can pass objects or primitive types, but do not have full support for ref arguments. Note that this restriction only applies to event callbacks, and not normal method calls. Normal method calls support ref arguments.

Adding full support for ref arguments is possible, but it simply is not that common of a case and writing a shim wrapper is fairly easy.

Creating a Shim Wrapper

Whether it is because of generics, interfaces, or ref arguments in event callbacks, this method applies to all cases.

First create a .NET library project and create a class of your own naming. In this example we have called it EventShim.

public class EventShim {
}

Now let’s consume a class which exposes an event which has a ref argument. Normally we can just consume the event normally in Delphi with no shim wrapper needed, but in the case of ref arguments there is a limitation in event callbacks.

The class we want to use in this case is called OtherClass and exposes a GetStatus event which has the following signature:

(ref bool aValue1, ref bool aValue2)

To wrap this we make a new event on our EventShim class that does not have ref arguments. To get the data back and forth, we can use an object. We then pass the object to Delphi and our Delphi code can update the properties of the object instead.

public class EventData {
public bool Value1;
public bool Value2;
}

Now add a new delegate and event in EventShim.

public delegate void GetStatusDelegate(EventData aValues);
public event GetStatusDelegate GetStatus;

The last step is that we need to catch the original event on OtherClass, and in EventShim transform it into our new event. Then in Delphi, we simply consume EventShim and its GetStatus event instead of GetStatus in OtherClass.

private OtherClass _OtherClass = new OtherClass();

public EventShim() {
_OtherClass.GetStatus += OnGetStatus;
}

private void OnGetStatus(ref bool aValue1, ref bool aValue2) {
var xValues = new EventData();
xValues.Value1 = aValue1;
xValues.Value2 = aValue2;
if (GetStatus != null) {
GetStatus(xValues);
aValue1 = xValues.Value1;
aValue2 = xValues.Value2;
}
}