Sample: Windows Forms Control as ActiveX for a Dialog System Application

The Customer + .NET GridView User Control sample shows a Windows Forms user control wrapped as an ActiveX control. Since Dialog System can host ActiveX controls, the new Windows Forms user control is built to be exposed as an ActiveX control. The sample shows how a user control can be hosted, how it can have methods invoked and how it can fire events, which can be consumed in the Dialog System application.

The sample is based on the original CustGrid sample from Dialog System. It has two projects: one is the original CustGrid sample and the second contains the code for a simple Windows Forms DataGridView user control written in COBOL. The DataGridView control is similar to the one used in the Customer samples (Customer +.NET WPF User Control and Customer + WinForm). Here, in this sample, the DataGridView is a .NET user control instead of a WPF user control or a control contained in Windows Forms.

The following diagram shows the native code on the left, with Dialog System handling the screenset. The managed code is on the right, with the Windows Forms user control wrapped as an ActiveX. The image also shows the native code interfacing with a COM Callable Wrapper (CCW) containing the managed code.

Note:

In this sample, the control is not a complete implementation of a grid control and the application is not a complete implementation. The sample is designed to illustrate the principles only.

CustGrid Project

The CustGrid project contains the original CustGrid project from Dialog System and contains:

  • CustGrid.gs is the screenset, which now contains the DataGridView control instead of the original ActiveX grid control. In the same way as before, Dialog System communicates with the native code gridctrl.cbl, using callouts and callbacks.
  • GridCtrl.cbl handles the events generated by the DataGridView control. It invokes the COM code in the same way that it invoked the ActiveX code before. For example, the Delete-A-Row Section handles the delete-row event and invokes the COM code, as follows:
      INVOKE  RowSet  "GetSelect"  USING  theRow  RETURNING  Numeric-Value
      INVOKE  RowSet  "Remove"  USING  Numeric-Value

    Where RowSet is defined in the COM interface for the Windows Forms user control. See the ControlInterface.cbl section, later in this topic.

GridViewUserControl Project

The GridViewUserControl project is registered for COM interop. In addition, the COMRegister() method puts the appropriate entries into the registry so that ActiveX containers see this as a control. This is covered in more detail later.

The managed COBOL grid user control is exposed to COM by declaring a class interface, an events interface, and the class itself, as follows:

  • Class interface, MicroFocus.VisualCOBOL.ISampleGridView in ControlInterface.cbl
  • Class SampleGridView in GridViewControl.cbl
  • Events interface, IGridViewEvents in GridViewEvents.cbl

The project contains other classes to complete the implementation:

  • UserDataGridViewRow class, which contains the methods to handle the row
  • RowSet class, which contains the methods to handle a row of the grid
  • CalendarColumn class, which implements a calendar editor column for use in the data grid

ControlInterface.cbl

ControlInterface.cbl defines the interface that exposes the methods and properties of the control to COM:

  interface-id  MicroFocus.VisualCOBOL.ISampleGridView
      attribute  Guid("5A0AED5B-7D47-48C9-9F95-DEE8BC2D4807").
  method-id  get  property  RowSet.
  ...

GridViewControl.cbl [code]

GridViewControl.cbl contains the class that defines the behavior of the DataGridView control. Its main task is to replicate the behavior of the old ActiveX control in the new DataGridView control.

GridViewControl.cbl includes the following code that is of interest:

Class-id SampleGridView

Define the SampleGridView class, which inherits from the Windows Forms UserControl class and implements the ISampleGridView interface declared in ControlInterface.cbl. It also implements the ISerializable interface, which enables the class to control its serialization behavior:

  Class-id SampleGridView
  inherits type System.Windows.Forms.UserControl
  implements type System.Runtime.Serialization.ISerializable
  type MicroFocus.VisualCOBOL.ISampleGridView
						
attribute Serializable()

Enable the class to be serialized. This attribute is required even though the class also implements the ISerializable interface to control the serialization process:

  attribute Serializable()
attribute ComVisible(true)

Make the managed class visible to COM. In other words, exposes the class to COM:

 attribute ComVisible(true)
attribute ProgId

Specify the ProgID for the COM object. This is a human-readable version of the class identifier (CLSID) used to identify COM/ActiveX objects:

  attribute ProgId
      ("MicroFocus.VisualCOBOL.SampleGridView")
attribute ClassInterface

Generate a class interface that supports early and late binding:

  attribute ClassInterface
      (type ClassInterfaceType::AutoDual)
attribute ComDefaultInterface

Specify the interface ISampleGridView as the default interface to expose to COM:

  attribute ComDefaultInterface
      (type of MicroFocus.VisualCOBOL.ISampleGridView)
attribute ComSourceInterfaces

Identify the IGridViewEvents as the interface to be exposed as COM event sources for the library WindowsFormsControlLibrary1.dll (which is built by the GridViewUserControl project):

  attribute ComSourceInterfaces
      (type of GridViewUserControl.IGridViewEvents)
attribute Guid

Specify an explicit GUID. This is useful during the debugging phase, as it avoids a new GUID being generated each time you build and register:

  attribute Guid("B33E4887-6BC0-4382-883B-EB0015F55D9B")
COMRegister()

Adds an entry to the Registry for the specified object. It sets the appropriate entries to register the object as an ActiveX, so that ActiveX containers see this as a control. This enables Dialog System to list the ActiveX as one of the controls available for import.

The project property Register for COM Interop registers the object as COM, but does not register it as ActiveX.

COMUnregister()

Removes the entry for the specified object from the Registry.

New()

Create an instance of the SampleGridView.

GetObjectData()

This is used as part of serialization of the control. However, this sample does not have anything to persist so this method is unused.

Event Handling methods
  • FireOnChanged() - handles the OnChanged event
  • FireRowSelected() - handles the OnRowSelected event
  • FireRowDeleted() - handles the OnRowDeleted event
  • OnRowEnter() - invokes the FireRowSelected() method
Get property RowSet

Implements the interface ISampleGridView. Creates an instance of the row.

Get property OrderGrid

This enables the Windows Forms user control to access the DataGridView user control.

  01 OrdersGridView 
         type System.Windows.Forms.DataGridView.
  method-id. get property OrderGrid.
  procedure division 
          returning thegrid as type DataGridView.
    set thegrid to self::OrdersGridView
    goback.
  end method.
						
OrdersGridView_CellEndEdit()

Handles the cell editing event and invokes FireOnChanged().

	
  method-id OrdersGridView_CellEndEdit
      final private.
  procedure division using by value  
      sender as object  
      e as type System.Windows.Forms.DataGridViewCellEventArgs.
      invoke self::FireOnChanged 
         (e::RowIndex, e::ColumnIndex)
						
Delegates

Defines the delegates for our events.

  01 OnRowSelected type RowSelectedEventHandler event public.
  01 OnRowDeleted type RowDeletedEventHandler event public.
  01 OnChanged type RowChangedEventHandler event public.
	 ...
  delegate-id RowSelectedEventHandler.
  delegate-id RowDeletedEventHandler.
  delegate-id RowChangedEventHandler.

						

GridViewEvents.cbl

GridViewEvents.cbl defines an interface for the events and assigns each event a COM dispatch identifier (DispId), as follows:

  method-id OnRowSelected attribute DispId(29).
  procedure division using by value  
      row as binary-long, 
      coln as binary-long.
      ...  
  method-id OnRowDeleted attribute DispId(18).
  method-id OnChanged attribute DispId(6).
			

The events correspond to the delegates defined in the SampleGridView class in GridViewControl.cbl.

Note, this interface is not implemented in our solution.