Accessing ExpressScheduler Recurrence Information from .NET

One challenge I’ve come up against recently is using C# to read the scheduler information saved by the DevExpress ExpressScheduler VCL control. Most of the data is fairly straight forward to read. However, there are two exceptions: recurrence information and associated resources.

This post will discuss how to read the recurrence information. This can be done directly in C#. A future post will explore how to read the associated resources. If your Delphi application only allows one resource to be associated to an event this isn’t an issue. However, if you allow multiple resources per event these are stored as Delphi variants in the DB and require Delphi to read the values out.

The recurrence information, on the other hand, is stored in a packed Delphi record which is in turn stored directly as an array of bytes in the DB field. The Delphi record is called TcxSchedulerEventRecurrenceInfoData and is defined in cxSchedulerStorage.pas:

TcxSchedulerEventRecurrenceInfoData = packed record
  Count: Integer;
  DayNumber: Integer;
  DayType: TcxDayType;
  Finish: TDateTime;
  OccurDays: TDays;
  Periodicity: Integer;
  Recurrence: TcxRecurrence;
  Start: TDateTime;
  YearPeriodicity: Integer;
  Reserved1: Byte;
  DismissDate: Integer;

In order to read the recurrence information in .NET, this record and its associated types must be translated into their .NET counterparts. Here is an example of an equivalent C# struct:

[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi, Pack = 1)]
struct SchedulerEventRecurrenceInfoData
    public int Count;
    public int DayNumber;
    public DayType DayType;
    public double Finish;
    public Days OccurDays;
    public int Periodicity;
    public Recurrence Recurrence;
    public double Start;
    public int YearPeriodicity;
    public byte Reserved1;
    public int DismissDate;

The rest of the C# types can be found in the accompanying sample.

With these types in place, the only thing left is some code to convert the recurrence information from the string value stored in the DB to the SchedulerEventRecurrenceInfoData struct. This post on StackOverflow gives a simple solution for doing this:

T ByteArrayToStructure(byte[] bytes) where T: struct
    GCHandle handle = GCHandle.Alloc(bytes, GCHandleType.Pinned);
    T stuff = (T)Marshal.PtrToStructure(handle.AddrOfPinnedObject(), typeof(T));
    return stuff;

There is a working Delphi sample here and the .NET sample app can be found here.

UPDATE: 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.

2 thoughts on “Accessing ExpressScheduler Recurrence Information from .NET

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

  2. Gerry

    Note that it is also possible (but messy) to decode the RecurrenceInfo field from SQL Server T-SQL.
    The main problem is endianness, which can be handled by casting to char, using REVERSE, then casting back:

    The enums are easy:
    CAST(SUBSTRING(RECURRENCEINFO, 9, 1) as tinyInt) DayType,
    integers need to be reversed:
    CAST(CAST(REVERSE(CAST(SUBSTRING(RECURRENCEINFO, 5, 4) as char(4))) as binary(4)) as int) DayNumber,

    Date time is harder, as we need to convert to float, then to SQL DATETIME
    See for details of converting to float.
    e.g. for FinishDate
    SIGN(CAST(cast(reverse(cast(substring(RECURRENCEINFO, 10, 8) as CHAR(8))) as binary(8)) AS BIGINT))
    * (1.0 + (CAST(cast(reverse(cast(substring(RECURRENCEINFO, 10, 8) as CHAR(8))) as binary(8)) AS BIGINT) & 0x000FFFFFFFFFFFFF) * POWER(CAST(2 AS FLOAT), -52))
    (CAST(cast(reverse(cast(substring(RECURRENCEINFO, 10, 8) as CHAR(8))) as binary(8)) AS BIGINT) & 0x7ff0000000000000) / 0x0010000000000000 – 1023),
    ‘1899-12-30’) as FinishDate,


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 )

Google photo

You are commenting using your Google 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 )

Connecting to %s