Accessing ExpressScheduler Resource Information from .NET

In a previous blog post I discussed how to access the recurrence information that the VCL ExpressScheduler stores in its DB from a .NET application. Reading and writing the recurrence information is possible from .NET given a knowledge of the struct layout that the Delphi control uses.

However, if you want to read the resource information that ExpressScheduler stores in its DB from .NET, this requires using a Delphi DLL. This is because the Delphi scheduler control stores the resource ID’s for appointments in a single field but in multiple formats depending on the appointment. For instance, if the appointment has only one associated resource, its resource ID will be stored as a Delphi variant. However, the value will be stored as a Delphi variant array of variants if the appointment is associated with multiple resources.

Luckily, both Delphi and .NET make it straight-forward to interoperate between them and DevExpress has a simple utility method we can use to simplify things as well.

Start off with a new Delphi DLL project by clicking File>New>Other in Delphi XE2. On the New Items dialob, select Delphi Projects followed by Dynamic-link Library.

Start by adding both Variants and cxSchedulerStorage to the uses clause of the DPR. Then, add the following exported method to the DPR:

procedure ResourceIDBlobToString(const AResourceID: PByteArray; out AResult: PByteArray); export; stdcall;

  ResourceIDVar: Variant;
  ResourceIDVar := cxFieldValueToVariant(AnsiString(AResourceID));
  if VarIsArray(ResourceIDVar) then
    AResult := PByteArray(VarArrayToArrayStr(ResourceIDVar))
    //the cast to AnsiString below is necessary or a Unicode string will sneak in and gum up the works
    AResult := PByteArray(AnsiString(VarToStr(ResourceIDVar)));

exports ResourceIDBlobToString;

This method uses the cxFieldValueToVariant utility method found in cxSchedulerStorage to translate the string representation of the field value to a Delphi variant. We then use VarIsArray to test if the variant is an array. If it is not, we simply return the variant as a string. If the variant is a variant array, we will use the following method to parse it:

//input is a variant array of strings
//output is a comma delimited string composed of the members of the input array
function VarArrayToArrayStr(const ResourceIDArray: Variant): AnsiString;
  I: Integer;
  Result := '';
  for I := VarArrayLowBound(ResourceIDArray, 1) to VarArrayHighBound(ResourceIDArray, 1) do
    if Result <> '' then
      Result := Result + ',';
    Result := Result + VarToStr(ResourceIDArray[I]);

This simple function iterates through the variant array using VarArrayLowBound and VarArrayHighBound, building up a comma-delimited list of the resource ID’s.

And that’s it for the Delphi DLL.

Next we’ll create a new C# WinForms solution to test out our DLL. Click File>New>Project and select a Windows Forms Application.

I’ll skip the data access code as it’s straight-forward. The interesting bit here is the DllImport attribute we’ll use to call our Delphi DLL:

[DllImport("ExpressSchedulerInterop.dll", CallingConvention = CallingConvention.StdCall, CharSet = CharSet.Ansi)]
static extern void ResourceIDBlobToString([MarshalAs(UnmanagedType.AnsiBStr)] string resourceID, [Out, MarshalAs(UnmanagedType.AnsiBStr)] out string result);

With this method defined properly, the following code can be used to read the resource data from the DB in C#:

string result = null;
ResourceIDBlobToString((string)reader["ResourceID"], out result);

You can download a Delphi scheduler app here, the Delphi scheduler interop project here, and the C# example data reader here.

UPDATE: I updated the code in this Blog post, along with the interop Delphi project source, to address a bug when using Unicode versions of Delphi. A cast to AnsiString is necessary or only the first character in the resource ID will be returned.

UPDATE #2: There’s a real-world example of this technique you can find here. It is an open source project for transferring data from ExpressScheduler to XtraScheduler.


One thought on “Accessing ExpressScheduler Resource Information from .NET

  1. Pingback: Accessing ExpressScheduler Recurrence Information from .NET « Development Technobabble

Leave a Reply

Fill in your details below or click an icon to log in: Logo

You are commenting using your account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s