FAQ (exicalendar)
Exontrol.COM Software - Frequently Asked Questions - ExICalendar Component
1:
The control's release notes can be found on our web site, looking for the Release Notes column in the control's main page. Click here for direct link.
2:
The control's assembly manifest is:
<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
	<assemblyIdentity name="exicalendar.X" version="10.0.0.1" type="win32" processorArchitecture="x86"></assemblyIdentity>
	<file name="exicalendar.dll" hashalg="SHA1">
		<comClass clsid="{D6C87100-38E2-4ABB-8AC2-4C0097AEE2D6}" tlbid="{13892953-B45F-470C-8AAC-A4D0EC376DA0}" progid="Exontrol.ICalendar.1" description="ICalendar Class"></comClass>
		<comClass clsid="{585997D0-7A9A-4163-A067-5F03B677E721}" tlbid="{13892953-B45F-470C-8AAC-A4D0EC376DA0}" progid="ExICalendar.Component.1" description="Component Class"></comClass>
		<comClass clsid="{A245500A-1569-4047-9852-229C206F3223}" tlbid="{13892953-B45F-470C-8AAC-A4D0EC376DA0}" progid="ExICalendar.Components.1" description="Components Class"></comClass>
		<comClass clsid="{99036FF6-3E52-4EDD-BF3A-C9382A0BC9F5}" tlbid="{13892953-B45F-470C-8AAC-A4D0EC376DA0}" progid="ExICalendar.Properties.1" description="Properties Class"></comClass>
		<comClass clsid="{A6082B7F-8FE0-44A1-8769-7B73D6DA75B2}" tlbid="{13892953-B45F-470C-8AAC-A4D0EC376DA0}" progid="ExICalendar.Property.1" description="Property Class"></comClass>
		<comClass clsid="{6369497C-0030-4558-B4F8-DF05332327BC}" tlbid="{13892953-B45F-470C-8AAC-A4D0EC376DA0}" progid="ExICalendar.Parameters.1" description="Parameters Class"></comClass>
		<comClass clsid="{F6A7988E-A60B-447C-B5FE-E1DA98F0E5CE}" tlbid="{13892953-B45F-470C-8AAC-A4D0EC376DA0}" progid="ExICalendar.Parameter.1" description="Parameter Class"></comClass>
		<typelib tlbid="{13892953-B45F-470C-8AAC-A4D0EC376DA0}" version="1.0" helpdir="" flags="HASDISKIMAGE"></typelib>
	</file>
	<comInterfaceExternalProxyStub name="IProperties" iid="{86F9FF3F-4AE0-441B-A099-ED28DE0A21F3}" tlbid="{13892953-B45F-470C-8AAC-A4D0EC376DA0}" proxyStubClsid32="{00020424-0000-0000-C000-000000000046}"></comInterfaceExternalProxyStub>
	<comInterfaceExternalProxyStub name="IComponents" iid="{A1336AEE-CF5E-4A86-A86A-4F0FB75B1CC4}" tlbid="{13892953-B45F-470C-8AAC-A4D0EC376DA0}" proxyStubClsid32="{00020424-0000-0000-C000-000000000046}"></comInterfaceExternalProxyStub>
	<comInterfaceExternalProxyStub name="IProperty" iid="{AE48CD7D-2F1A-40D9-9F07-507706218CE3}" tlbid="{13892953-B45F-470C-8AAC-A4D0EC376DA0}" proxyStubClsid32="{00020424-0000-0000-C000-000000000046}"></comInterfaceExternalProxyStub>
	<comInterfaceExternalProxyStub name="IICalendar" iid="{C4A195D9-6597-46F2-ACAF-860B104040C9}" tlbid="{13892953-B45F-470C-8AAC-A4D0EC376DA0}" proxyStubClsid32="{00020424-0000-0000-C000-000000000046}"></comInterfaceExternalProxyStub>
	<comInterfaceExternalProxyStub name="IComponent" iid="{CD470F49-77B6-4C82-BA14-19E62BDA01AC}" tlbid="{13892953-B45F-470C-8AAC-A4D0EC376DA0}" proxyStubClsid32="{00020424-0000-0000-C000-000000000046}"></comInterfaceExternalProxyStub>
	<comInterfaceExternalProxyStub name="IParameters" iid="{D156D528-0EA3-46E3-AFDD-66D0966003C9}" tlbid="{13892953-B45F-470C-8AAC-A4D0EC376DA0}" proxyStubClsid32="{00020424-0000-0000-C000-000000000046}"></comInterfaceExternalProxyStub>
	<comInterfaceExternalProxyStub name="IParameter" iid="{DD72A320-C88A-4A9B-A805-784FAAA14499}" tlbid="{13892953-B45F-470C-8AAC-A4D0EC376DA0}" proxyStubClsid32="{00020424-0000-0000-C000-000000000046}"></comInterfaceExternalProxyStub>
</assembly>
3:
While running a sample you might encounter the following exception:

An unhandled exception of type 'System.Runtime.InteropServices.COMException' occurred in exe

Additional information: Retrieving the COM class factory for component with CLSID failed due to the following error: 80040154. 

The most probably you have installed the /COM x86 version ( 32-bit ) of the component on a Windows x64 machine, so in order to prevent this error do any of the following:

  • In VS - project properties - in the Build tab - platform target X86 ( AnyCPU to X86 )
  • Install the x64 version of the component as well, as the application runs as 64-bit on a Windows 64 machine
4:
The idea of adding recurring events to eXCalendar consists in:
  • Handle the DateChanged event of the eXCalendar component
  • Collects the occurrences of the recurrence expression between FirstVisibleDate, LastVisibleDate properties of the eXCalendar component, using the RecurRange method of the eXICalendar library
  • For each occurrence found, add a new events using the Add method of the Events collection of  eXCalendar component

The following VB sample adds recurring events to eXCalendar :

Private Sub Calendar1_DateChanged()
    DoEvents
    With Calendar1
        .BeginUpdate
        Dim o As Variant
        For Each o In CreateObject("Exontrol.ICalendar").RecurRange("DTSTART=20151201;FREQ=WEEKLY;BYDAY=FR", .FirstVisibleDate, .LastVisibleDate)
            .Events.Add(o).Marker = True
        Next
        .EndUpdate
    End With
End Sub

Private Sub Form_Load()
    With Calendar1
        .FirstDay = Monday
        .AlignmentDay = CenterAlignment
        .GridLineColor = RGB(128, 128, 128)
        Calendar1_DateChanged
    End With
End Sub

and you should get:

The same sample in C++, should look such as:

void C...Dlg::DateChangedCalendar1()
{
	DoEvents();
	EXCALENDARLib::ICalendarPtr spCalendar1 = GetDlgItem(IDC_CALENDAR1)->GetControlUnknown();
	if ( spCalendar1 != NULL )
	{
		EXCALENDARLib::IEventsPtr spEvents = spCalendar1->Events;
		spCalendar1->BeginUpdate();
		EXICALENDARLib::IICalendarPtr spICal = ::CreateObject(L"Exontrol.ICalendar");
		if ( spICal != NULL )
		{
			_variant_t vtRecurRange = spICal->GetRecurRange(L"DTSTART=20151201;FREQ=WEEKLY;BYDAY=FR",spCalendar1->FirstVisibleDate,spCalendar1->LastVisibleDate);
			if ( V_VT( &vtRecurRange ) == ( VT_ARRAY | VT_DATE ) )
			{
				SAFEARRAY* pArray = V_ARRAY( &vtRecurRange );
				DATE* pData = NULL;
				if ( SUCCEEDED( SafeArrayAccessData( pArray, (LPVOID*)&pData ) ) )
				{
					long lowerBound = 0, upperBound = 0;
					SafeArrayGetLBound(pArray, 1 , &lowerBound);
					SafeArrayGetUBound(pArray, 1, &upperBound);
					long nCount = upperBound - lowerBound + 1; 
					SafeArrayUnaccessData( pArray );
					for ( long i = 0; i < nCount; i++, pData++ )  // iterate through returned values
						spEvents->Add( *pData )->Marker = VARIANT_TRUE;
				}
			}
		}
		spCalendar1->EndUpdate();
	}
}


BOOL C...Dlg::OnInitDialog()
{
	CDialogEx::OnInitDialog();

	...

	EXCALENDARLib::ICalendarPtr spCalendar1 = GetDlgItem(IDC_CALENDAR1)->GetControlUnknown();
	if ( spCalendar1 != NULL )
	{
		spCalendar1->PutAlignmentDay(EXCALENDARLib::CenterAlignment);
		spCalendar1->PutFirstDay(EXCALENDARLib::Monday);
		spCalendar1->PutGridLineColor(RGB(128,128,128));

		DateChangedCalendar1();
	}

	return TRUE;  // return TRUE  unless you set the focus to a control
}

where the definitions for CreateObject, DoEvents is:

#include <comdef.h>
IUnknownPtr CreateObject( BSTR Object )
{
	IUnknownPtr spResult;
	spResult.CreateInstance( Object );
	return spResult;
};

void DoEvents()
{
	MSG m = {0};
	while ( PeekMessage( &m, NULL, NULL, NULL, PM_REMOVE ) )
	{
		TranslateMessage( &m );
		DispatchMessage( &m );
	}
}    

The same sample in C#, should look such as:

private void axCalendar1_DateChanged(object sender, EventArgs e)
{
    Application.DoEvents();

    if (iCal != null)
    {
        axCalendar1.BeginUpdate();
        axCalendar1.Events.Clear();
        foreach (System.DateTime d in ( iCal.get_RecurRange("DTSTART=20151201;FREQ=WEEKLY;BYDAY=FR", axCalendar1.FirstVisibleDate, axCalendar1.LastVisibleDate) as Array ))
            axCalendar1.Events.Add(d).Marker = true;
        axCalendar1.EndUpdate();

    }
}
EXICALENDARLib.ICalendar iCal = null;

        private void Form1_Load(object sender, EventArgs e)
        {
            iCal = new EXICALENDARLib.ICalendar();

            axCalendar1.Appearance = EXCALENDARLib.AppearanceEnum.None2;
            axCalendar1.ShowWeeks = true;
            axCalendar1.Date = Convert.ToDateTime("1/1/2015",System.Globalization.CultureInfo.GetCultureInfo("en-US"));
            axCalendar1.ShowNonMonthDays = false;
            axCalendar1.ShowMonthSelector = false;
            axCalendar1.FirstDay = EXCALENDARLib.WeekDayEnum.Monday;
            axCalendar1.AlignmentDay = EXCALENDARLib.AlignmentEnum.CenterAlignment;
            axCalendar1.GridLineColor = Color.Gray;

        }

      
5:
The idea of adding recurring tasks to eXG2antt/eXGantt consists in:
  • Handle the DateChanged event of the eXG2antt component
  • Collects the occurrences of the recurrence expression between first visible date and last visible date, using the RecurRange method of the eXICalendar library
  • For each occurrence found, add a new task using the AddBar method of the Items collection of  eXG2antt component

The following VB sample adds recurring events to eXG2antt :

Function Max(ByVal a As Double, ByVal b As Double) As Double
    Max = IIf(a < b, b, a)
End Function

Private Sub Form_Load()
    With G2antt1
        .BeginUpdate
        .Columns.Add "Tasks"
        .Items.AddItem "Every Friday, starting from 2015, Dec 1st"
        With .Chart
            .LevelCount = 2
            .PaneWidth(0) = 224
            .Bars("Task").Pattern = exPatternSolid
            .FirstVisibleDate = #11/23/2015#
        End With
        .EndUpdate
    End With
End Sub

Private Sub G2antt1_DateChange()
    With G2antt1
        .BeginUpdate
        Dim o As Variant
        For Each o In CreateObject("Exontrol.ICalendar").RecurRange("DTSTART=20151201;FREQ=WEEKLY;BYDAY=FR", .Chart.FirstVisibleDate, Max(.Chart.FirstVisibleDate + (1 + .Chart.PaneWidth(False) + .Chart.PaneWidth(True)) / .Chart.UnitWidth, .Chart.DateFromPoint(1, -1)))
            .Items.AddBar .Items.FirstVisibleItem, "Task", o, o + 1, o
        Next
        .EndUpdate
    End With
End Sub

and you should get:

A few notes:

  • The DateFromPoint(1, -1) property determines the last visible date.
  • The Max(.Chart.FirstVisibleDate + (1 + .Chart.PaneWidth(False) + .Chart.PaneWidth(True)) / .Chart.UnitWidth, .Chart.DateFromPoint(1, -1))), determines the maximum between the last visible date if no columns section is displayed and the currently last visible date
  • The initial FirstVisibleDate should be called after filling the columns/items, so during the DateChange event, the FirstVisibleItem property is NOT zero, so adding bars is possible

The same sample in C++, should look such as:

void C...Dlg::DateChangedG2antt1()
{
	EXG2ANTTLib::IG2anttPtr spG2antt1 = GetDlgItem(IDC_G2ANTT1)->GetControlUnknown();
	if ( spG2antt1 != NULL )
	{
		EXG2ANTTLib::IItemsPtr spItems = spG2antt1->Items;
		spG2antt1->BeginUpdate();
		EXIG2ANTTLib::IIG2anttPtr spICal = ::CreateObject(L"Exontrol.ICalendar");
		if ( spICal != NULL )
		{
			_variant_t vtRecurRange = spICal->GetRecurRange(L"DTSTART=20151201;FREQ=WEEKLY;BYDAY=FR",spG2antt1->FirstVisibleDate,spG2antt1->LastVisibleDate);
			if ( V_VT( &vtRecurRange ) == ( VT_ARRAY | VT_DATE ) )
			{
				SAFEARRAY* pArray = V_ARRAY( &vtRecurRange );
				DATE* pData = NULL;
				if ( SUCCEEDED( SafeArrayAccessData( pArray, (LPVOID*)&pData ) ) )
				{
					long lowerBound = 0, upperBound = 0;
					SafeArrayGetLBound(pArray, 1 , &lowerBound);
					SafeArrayGetUBound(pArray, 1, &upperBound);
					long nCount = upperBound - lowerBound + 1; 
					SafeArrayUnaccessData( pArray );
					for ( long i = 0; i < nCount; i++, pData++ )  // iterate through returned values
						spItems->AddBar( spItems->FirstVisibleItem, :L"Task", *pData, *pData, *pData );
				}
			}
		}
		spG2antt1->EndUpdate();
	}
}

where the definitions for CreateObject, DoEvents is:

#include <comdef.h>
IUnknownPtr CreateObject( BSTR Object )
{
	IUnknownPtr spResult;
	spResult.CreateInstance( Object );
	return spResult;
};

void DoEvents()
{
	MSG m = {0};
	while ( PeekMessage( &m, NULL, NULL, NULL, PM_REMOVE ) )
	{
		TranslateMessage( &m );
		DispatchMessage( &m );
	}
}
6:
Please check the Repetitive property of the Event object, of the eXSchedule.
7:
The following methods:
  • RecurAll
  • RecurAllAsString
  • RecurRange
  • RecurRangeAsString

are limited to 16 occurrences only if:

  • running the trial version of the eXICalendar library ( Please check the Version property of the component, if contains DEMO )
  • RuntimeKey property has not been called, or using invalid key, if running the registered version.

If you are running the registered version, you have to call the RuntimeKey property right after creating the component like in the following sample:

Set iCal = CreateObject("Exontrol.ICalendar.1")
With iCal
	.RuntimeKey = "..."
	Debug.Print( .RecurAllAsString("DTSTART=19970805;FREQ=MONTHLY;BYDAY=MO,TU,WE,TH,FR;BYSETPOS=-1",255) )
End With

where the "..." is your runtime license key that was provided in the email you have received by the time you purchased the component. In case you have miss it, please contact us to request your runtime license key.

8:
The Load / LoadFile / LoadFileU methods loads iCalendar format into the component. The Root / Content property gives access to the root / content Component of the loaded format. Each component can have other components, so the Count property of the Components collection counts the number of Component objects in the collection, not including the inner components. 

A) The following getComponentsCount function returns the number of components in the control ( all/recursively Component objects ): 

Function getComponentsCount(ByVal c As EXICALENDARLib.Component) As Long
    Dim nCount As Long, i As EXICALENDARLib.Component
    nCount = c.Components.Count
    For Each i In c.Components
        nCount = nCount + getComponentsCount(i)
    Next
    getComponentsCount = nCount
End Function

and you can call it using a code like: getComponentsCount(iCal.Content)

B) The following method shows how you can count the number of Components begin found while loading the iCalendar format:

Dim nComponents As Long
Dim WithEvents iCal As EXICALENDARLib.ICalendar

Private Sub Form_Load()
    Set iCal = New EXICALENDARLib.ICalendar
	nComponents = 0
End Sub


Private Sub iCal_StartLoad()
    nComponents = 0
End Sub

Private Sub iCal_AddComponent(ByVal NewComponent As EXICALENDARLib.IComponent)
    nComponents = nComponents + 1
End Sub

Private Sub iCal_EndLoad()
    Debug.Print (nComponents)
End Sub

where the nComponents member is increased each time the AddComponent event occurs.

How-To Questions
General Questions