Q: How do I attached deep migration event handlers to a COM API?
Wiki Markup
A: One approach is to implement the migration event handler using gmSL and attach the gmSL to the IDF for the COM API. The FileExplorer sample shows the gmSL approach for Windows Common Controls. The other approach is to implement the migration event handlers in a gmBasic utility using gmAPI and invoke the utility using a gmMU command. The WPFScanTool sample shows th gmAPI approach. This article provides an additional example of the gmSL approach.
Example
I have a VB6 code that uses the MSgrid API described in this IDF:
Code Block |
---|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
C:\gmSpec\Migrate\MSGridTest\proj\idf\FromIdl\GRID32.OCX.xml
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1 <DescriptionFile>
> 2 <library id="GRID32.OCX"
3 name="MSGrid"
4 uuid="A8B3B723-0B5A-101B-B22E-00AA0037B2FC"
5 netVersion="1.0"
6 source="GRID32.OCX"
|
I prepare a RefactorLibrary called grid32.ocx.Winforms.Refactor.xml to organize the declarative migration rules that will take this to gmRTL.MSGrid.
Code Block |
---|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
C:\gmSpec\Migrate\MSGridTest\proj\usr\grid32.ocx.Winforms.Refactor.xml
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
<RefactorLibrary>
<!--
Description: Map MSGrid.Grid control to gmRTL.MSGrid.Grid
-->
<Refactor id=" |
...
[GRID32.OCX |
...
]" >
<!--
Library
-->
<Migrate migName="gmRTL.MSGrid" libType="Internal" location="DoNotDeclare" axLocation="DoNotDeclare"/>
<!--
CoClasses
-->
<Migrate id="Grid" role="Control" migStatus="NeedsInit" />
<!--
Enums
-->
<Migrate id="ScrollBarsConstants" migName="ScrollBars" migStatus="External" />
<Migrate id="ScrollBarsConstants.grdNone" migName="ScrollBars.None" migStatus="External" />
<Migrate id="ScrollBarsConstants.grdHorizontal" migName="ScrollBars.Horizontal" migStatus="External" />
<Migrate id="ScrollBarsConstants.grdVertical" migName="ScrollBars.Vertical" migStatus="External" />
<Migrate id="ScrollBarsConstants.grdBoth" migName="ScrollBars.Both" migStatus="External" />
<!--
Interfaces
-->
<Migrate id="IGridCtrl.AddItem" nPram="3" migPattern="%1d.AddItem(%2d,%3o)" />
<Migrate id="IGridCtrl.AddItem.Index" type="Integer" />
<Migrate id="IGridCtrl.Rows" migName="MaxRows" />
<Migrate id="IGridCtrl.ColWidth" type="TwipsX" />
<!--
Designers
-->
<migClass id="NetControl.Grid" migName="gmRTL.MSGrid.Grid" parent="Grid">
<property id="BackColor" type="OLE_COLOR" value="IGridCtrl.BackColor" nPram="3"
migPattern="System.Drawing.Color.FromArgb(%3d, %2d, %1d)"
default="System.Drawing.SystemColors.Window"
/>
<property id="ColumnHeadersVisible" type="Boolean" default="false" />
<property id="Cols" type="Integer" value="IGridCtrl.Cols" default="3"/>
<property id="Enabled" type="boolean" value="IGridCtrl.Enabled" default="true"/>
<property id="ForeColor" type="OLE_COLOR" value="IGridCtrl.ForeColor" nPram="3"
migPattern="System.Drawing.Color.FromArgb(%3d, %2d, %1d)"
default="System.Drawing.SystemColors.ControlText"
/>
<property id="Location" value="(Left,Top)" nPram="2" migPattern="new System.Drawing.Point(%1d, %2d)" />
<property id="MaxRows" type="Integer" value="IGridCtrl.Rows" default="1"/>
<property id="Name" type="string" value="SYM.name" />
<property id="FixedRows" value="IGridCtrl.FixedRows"/>
<property id="RowTemplate.Height" default="18" />
<property id="Size" value="(Width,Height)" nPram="2" migPattern="new System.Drawing.Size(%1d, %2d)" />
<property id="ScrollBars" type="ScrollBarConstants" value="IGridCtrl.ScrollBars" />
<property id="TabIndex" type="Integer" value="TabIndex" default="0" />
<property id="TabStop" type="boolean" value="TabStop" default="true" />
</migClass>
</Refactor>
</RefactorLibrary> |
...
I can associate the RefactorLibrary rules with the IDF using Registry/MigFile before the Compile in the translation script.
Code Block |
---|
<Registry type="MigFile" source="grid32.ocx" target="grid32.ocx.Winforms.Refactor" /> |
...
Supposing we require a deeper migration, for example authoring a boolean assignment in designer code based on the FixedRows property of each grid control as specified in the VB6 Form header.
For reference, here are the migration handlers/helpers implementing those rules:
Code Block |
---|
int Grid(int context,int ctlRoot,int iStart)
|
...
{ // migration event handler: called by translation process |
...
when |
...
it |
...
encounters an MSGrid.Grid class member reference |
...
string propName;
string Value;
string Name;
|
...
if(context == EventType.ControlValue)
|
...
{
propName = Store.GetIdent(iStart);
Value = Write.Clear();
Name = Store.GetName(ctlRoot);
if(propName == "FixedRows") Grid_FixedRows(Name,Value);
else return 0;
return 1;
|
...
}
if(context != EventType.InitializeComponent) return 0;
return 1;
|
...
}
void Grid_FixedRows(string Name, string Value)
|
...
{ // migration event helper: called from handler when Authoring |
...
the FixedRows |
...
property in the designer |
...
MigClass |
...
if (Value > 0)
|
...
{
System.LogMessage("Grid_FixedRows:" + Name + "," + Value);
if(Select.Dialect == Dialects.vbn)
|
...
{
Write.Line("Me." + Name + ". |
...
ColumnHeadersVisible= True"); |
...
}
else
|
...
{
Write.Line("this." + Name + ". |
...
ColumnHeadersVisible= true;"); |
...
}
|
...
}
|
...
} |
...
To engage the migration handler, I need to attach gmSL code block to the RefactorLibrary. I must do this in the RefactorLibrary file. 1) Add an event attribute to the top level Refactor element the IDF my modifying the RefactorLibrary file as follows:
1) Add an event attribute to the top level Refactor element
Code Block |
---|
<Refactor id=" |
...
[GRID32.OCX |
...
]" event="MSGridRefactor" > |
...
2) Attach the gmSL code block to the RefactorLibrary:
Code Block |
---|
<gmSL NameSpace="MSGridRefactor" Class="Transform"><! |
...
[CDATA |
...
[
... embed the gmsl code above ...
|
...
] |
...
]></gmSL> |
...
or place the gmSL in its own file and reference it using gmsl@source attribute:
Code Block |
---|
<gmSL NameSpace="MSGridRefactor" Class="Transform" Source="grid32.ocx.WinForms.gmsl" /> |
...
Note: the value of the Refactor@event must be the same as the gmSL@NameSpace and it must be unique among the namespaces presently loaded in the upgrade model. Our convention is to name it as <Name><Purpose> where <Name> is the library name and <Purpose> is the reason for creating the new gmSL namespace. For example a namespace containing event handlers/helpers refactoring the MSGrid API could be named something like MSGridRefactor.