Support Statement: ListView.Add example of using gmSL to map COM to .NET

Q. How does gmBasic migrate COM ListView.Add to WinForm ListView.Add?

A: This migration is implemented using a RefactorLibrary with some gmSL to facilitate a "deep migration":

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
C:\gmTestBed\FileExplorer\proj_csh\usr\Mscomctl.ocx.WinForms.Refactor.xml
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    1 <RefactorLibrary>
    2 <Refactor id="[mscomctl.ocx]" event="mscomctl" >
  627 <!--
  628 ********************************************************** 
  629 * ListView Migration Rules Helper Class
  630 ********************************************************** 
  631 -->
  632 <migClass id="ListViewLogic">
...
  671    <Method id="Insert_Index_Key_SmallIcon" type="ListItem" nPram="6" migPattern="%1d.Insert(%2D,%3d,%4d,%6d)" />
  672    <Method id="Insert_Index_Key_Icon" type="ListItem" nPram="6" migPattern="%1d.Insert(%2D,%3d,%4d,%5d)" />
  673    <Method id="Insert_Index_Key" type="ListItem" nPram="6" migPattern="%1d.Insert(%2D,%3d,%4d)" />
  674    <Method id="Insert_Index_SmallIcon" type="ListItem" nPram="6" migPattern="%1d.Insert(%2D,%4d,%6d)" />
  675    <Method id="Insert_Index_Icon" type="ListItem" nPram="6" migPattern="%1d.Insert(%2D,%4d,%5d)" />
  676    <Method id="Insert_Index" type="ListItem" nPram="6" migPattern="%1d.Insert(%2D,%4d)" />
  677    
> 678    <Method id="Add_Key_SmallIcon" type="ListItem" nPram="6" migPattern="%1d.Add(%3d,%4d,%6d)" />
  679    <Method id="Add_Key_Icon" type="ListItem" nPram="6" migPattern="%1d.Add(%3d,%4d,%5d)" />
  680    <Method id="Add_Key" type="ListItem" nPram="6"
  681            cshPattern="%1d.Add(new ListViewItem { Name=%3d, Text=%4d })"
  682            vbnPattern="%1d.Add(New ListViewItem() With {.Name = %3d, .Text = %4d})"
  683    />
  684    <Method id="Add_SmallIcon" type="ListItem" nPram="6" migPattern="%1d.Add(%4d,%6d)" />
  685    <Method id="Add_Icon" type="ListItem" nPram="6" migPattern="%1d.Add(%4d,%5d)" />
  686    <Method id="Add" type="ListItem" nPram="6" migPattern="%1d.Add(%4o)" />
  687 </migClass>
...
  882 <!--
  883 ********************************************************** 
  884 * Procedural Transformation Rules
  885 ********************************************************** 
  886 -->
  887 <gmSL NameSpace="mscomctl" Class="Transform" Source="Mscomctl.ocx.WinForms.Transform.gmsl" />
  888 </Refactor>
  889 </RefactorLibrary>  

The migClass provides a structure for declaring and organizing metadata supporting some custom migration requirements. This problem being solved here is that the WinForms ListView does not support all of the same Add operations as the COM ListView: WinForms only has Insert and Add operations as well as only one size of Image. These API changes need be considered when expressing a COM Listview.Add operations with WinForms.ListView. The upgrade solution must examine the call and determine which one of the patterns to use. This analysis and selection is done in the Mscomctl.ocx.WinForms.Transform.gmsl file associated with the MSComCtl API.

Specifically the IListItems_Add routine is automatically called when gmBasic encounters a reference to ListView Add:

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
C:\gmTestBed\FileExplorer\proj_csh\usr\Mscomctl.ocx.Winforms.Transform.gmsl
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  110 int IListItems_Add(int subRoot, int iStart, int iRefer)
  111 {
  112    int         icode;
  113    int         nCode;
  114    tCodeBlock  codptr;
  115    int         oper;
  116    int         subc;
  117    tCodeBlock  isOmitted;
  118    int         nOper;
  119    int         omitIndex;
  120    int         omitKey;
  121    int         omitIcon;
  122    int         omitSmallIcon;
  123    int         pattern;
  124    
  125    codptr = Opcode.GetCode();
  126    nCode = Opcode.GetLength()
  127    icode = Opcode.GetNext(codptr,iRefer,nCode);
  128    subc = 0;
  129    oper = Opcode.GetOperation(codptr,icode,subc);
  130    if(oper != OPC.MEM) return 0;
  131    icode = Opcode.GetNext(codptr,icode,nCode);
  132    oper = Opcode.GetOperation(codptr,icode,subc);
  133    if(oper != OPC.LEV) return 0;
  134 //Index
  135    nOper = 0;
  136    isOmitted = CodePattern.Read("LEV,DEF,ARG",nOper);
  137    omitIndex = CodePattern.Match(icode,isOmitted);
  138    icode = Opcode.FindArgumentEnd(codptr,icode,nCode);
  139    oper = Opcode.GetOperation(codptr,icode,subc);
  140    if(oper != OPC.LEV) return 0;
  141 // Key   
  142    omitKey = CodePattern.Match(icode,isOmitted);
  143    icode = Opcode.FindArgumentEnd(codptr,icode,nCode);
  144    oper = Opcode.GetOperation(codptr,icode,subc);
  145    if(oper != OPC.LEV) return 0;
  146 // Text
  147    icode = Opcode.FindArgumentEnd(codptr,icode,nCode);
  148    oper = Opcode.GetOperation(codptr,icode,subc);
  149    if(oper != OPC.LEV) return 0;
  150 // Icon
  151    omitIcon = CodePattern.Match(icode,isOmitted);
  152    icode = Opcode.FindArgumentEnd(codptr,icode,nCode);
  153    oper = Opcode.GetOperation(codptr,icode,subc);
  154    if(oper != OPC.LEV) return 0;
  155 // SmallIcon   
  156    omitSmallIcon = CodePattern.Match(icode,isOmitted);
  157    icode = Opcode.FindArgumentEnd(codptr,icode,nCode);
  158    oper = Opcode.GetOperation(codptr,icode,subc);
  159    if(oper != OPC.CUF) return 0;
  160     
  161    if(!omitIndex && !omitKey && !omitSmallIcon)
  162    {
  163       pattern =  Symbol.FindIdentifier("MsComctlLib.ListViewLogic.Insert_Index_Key_SmallIcon");
  164    }
  165    else if(!omitIndex && !omitKey && !omitIcon)
  166    {
  167       pattern = Symbol.FindIdentifier("MsComctlLib.ListViewLogic.Insert_Index_Key_Icon");
  168    }
  169    else if(!omitIndex && !omitKey)
  170    {
  171       pattern = Symbol.FindIdentifier("MsComctlLib.ListViewLogic.Insert_Index_Key");
  172    }
  173    else if(!omitIndex && omitKey && !omitSmallIcon)
  174    {
  175       pattern = Symbol.FindIdentifier("MsComctlLib.ListViewLogic.Insert_Index_SmallIcon");
  176    }
  177    else if(!omitIndex && omitKey && !omitIcon)
  178    {
  179       pattern = Symbol.FindIdentifier("MsComctlLib.ListViewLogic.Insert_Index_Icon");
  180    }
  181    else if(!omitIndex && omitKey)
  182    {
  183       pattern = Symbol.FindIdentifier("MsComctlLib.ListViewLogic.Insert_Index");
  184    }
  185    else if (omitIndex && !omitKey && !omitSmallIcon)
  186    {
> 187       pattern = Symbol.FindIdentifier("MsComctlLib.ListViewLogic.Add_Key_SmallIcon");
  188    }
  189    else if (omitIndex && !omitKey && !omitIcon)
  190    {
  191       pattern = Symbol.FindIdentifier("MsComctlLib.ListViewLogic.Add_Key_Icon");
  192    }
  193    else if (omitIndex && !omitKey)
  194    {
  195       pattern = Symbol.FindIdentifier("MsComctlLib.ListViewLogic.Add_Key");
  196    }
  197    else if (omitIndex && omitKey && !omitSmallIcon)
  198    {
  199       pattern = Symbol.FindIdentifier("MsComctlLib.ListViewLogic.Add_SmallIcon");
  200    }
  201    else if (omitIndex && omitKey && !omitIcon)
  202    {
  203       pattern = Symbol.FindIdentifier("MsComctlLib.ListViewLogic.Add_Icon");
  204    }
  205    else if (omitIndex && omitKey)
  206    {
  207       pattern = Symbol.FindIdentifier("MsComctlLib.ListViewLogic.Add");
  208    }
  209    else
  210    {
  211       pattern = Symbol.FindIdentifier("MsComctlLib.ListViewLogic.Add");
  212    }
  213    if(pattern == 0) return 0;
  214    Opcode.Replace(icode,OPC.PAT,pattern,1);
  215    Opcode.Delete(iRefer,2);
  216    return 1;
  217 }


First the gmBasic compiler processes this VB6:

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
C:\gmTestBed\FileExplorer\src\frmExploreLite.frm
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
> 657     Set liListItem = lvListView.ListItems.Add(, , itemText, "genericMedium", "genericSmall")
  658 
  659     With liListItem.ListSubItems

And produces this "gmIL" in the system model:

Compiled IL
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
C:\gmTestBed\FileExplorer\proj_csh\report\FileExplorer_csh-CustomSearch.tab
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 4082 Detailed Description of Subprogram FileExplorer.frmExploreLite.AddListItem with root address 266343:
...
 4097 Actual vb7 Codeblock Associated with AddListItem:
 4098 Offset |  Sl.Start |  Ql.Start | Quantity type        | Opcode | Operation support information
 4099 ------ |  -------- |  -------- | -------------        | ------ | -----------------------------
 4100      0 |           |           |                      | REM    | NULL
 4101      5 |           |           |                      | REM    | 57:Add a ListItem, then additional columns as ListSubItems.
 4102     10 |           |           |                      | NEW    | 656 Dim liListItem As ListItem
 4103     13 |           |           |                      | DCL    | Variable:liListItem:266701
>4104     18 |           |           |                      | NEW    | 657 Set liListItem = lvListView.ListItems.Add(, , itemText, "genericMedium", "genericSmall")
 4105     21 |      1.21 |      1.21 | MSComctlLib.ListItem | LDA    | Variable:liListItem:266701
 4106     26 |      1.21 |      1.21 | MSComctlLib.ListItem | LEV    | Nest0
 4107     28 |      2.28 |      2.28 | MSComctlLib.ListView | LDA    | MSComctlLib.ListView:lvListView:262825
 4108     33 |      3.33 |      2.28 | MSComctlLib.ListItem | LLP    | Component:ListItems:157565
 4109     38 |      2.28 |      2.28 | MSComctlLib.ListItem | MEM    | Child
 4110     40 |      3.40 |      2.28 | MSComctlLib.ListItem | LLP    | Component:Add:163224
 4111     45 |      2.28 |      2.28 | MSComctlLib.ListItem | MEM    | Child
 4112     47 |      2.28 |      2.28 | MSComctlLib.ListItem | LEV    | Nest1
 4113     49 |      3.49 |      3.49 | Void                 | DEF    | Overload
 4114     51 |      3.49 |      2.28 | MSComctlLib.ListItem | ARG    | Integer
 4115     53 |      3.49 |      2.28 | MSComctlLib.ListItem | LEV    | Nest1
 4116     55 |      4.55 |      3.55 | Void                 | DEF    | Overload
 4117     57 |      4.55 |      2.28 | MSComctlLib.ListItem | ARG    | String
 4118     59 |      4.55 |      2.28 | MSComctlLib.ListItem | LEV    | Nest1
 4119     61 |      5.61 |      3.61 | String               | LDA    | Variable:itemText:266487
 4120     66 |      5.61 |      2.28 | MSComctlLib.ListItem | ARG    | String
 4121     68 |      5.61 |      2.28 | MSComctlLib.ListItem | LEV    | Nest1
 4122     70 |      6.70 |      3.70 | String               | LSC    | 13:genericMedium
 4123     75 |      6.70 |      2.28 | MSComctlLib.ListItem | ARG    | String
 4124     77 |      6.70 |      2.28 | MSComctlLib.ListItem | LEV    | Nest1
 4125     79 |      7.79 |      3.79 | String               | LSC    | 12:genericSmall
 4126     84 |      7.79 |      2.28 | MSComctlLib.ListItem | ARG    | String
 4127     86 |      2.28 |      2.28 | MSComctlLib.ListItem | CUF    | Args5
>4128     88 |      2.28 |      2.28 | MSComctlLib.ListItem | REF    | Component:Add:163224
 4129     93 |      2.28 |      1.21 | MSComctlLib.ListItem | ARG    | Object
 4130     95 |           |      2.95 | Void                 | CMD    | Set
 4131     97 |           |           |                      | REM    | NULL
 4132    102 |           |           |                      | NEW    | 659 With liListItem.ListSubItems

During translation, the gmBasic engine calls the gmSL IListItems_Add method that examines the REF to IListItems.Add operation and replaces it with the selected pattern operation, PAT.Add_SmallIcon, instead of the REF.IListItem.Add method:

Modified IL 
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
C:\gmTestBed\FileExplorer\proj_csh\report\FileExplorer_csh-CustomSearch.tab
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 4067 Detailed Description of Subprogram FileExplorer.frmExploreLite.AddListItem with root address 266343:
...
 4082 Actual csh Codeblock Associated with AddListItem:
 4083 Offset |  Sl.Start |  Ql.Start | Quantity type        | Opcode | Operation support information
 4084 ------ |  -------- |  -------- | -------------        | ------ | -----------------------------
 4085      0 |           |           |                      | REM    | NULL
 4086      5 |           |           |                      | REM    | 57:Add a ListItem, then additional columns as ListSubItems.
 4087     10 |           |           |                      | NEW    | 656 Dim liListItem As ListItem
 4088     13 |           |           |                      | DCL    | Variable:liListItem:266701
 4089     18 |           |           |                      | NEW    | 657 Set liListItem = lvListView.ListItems.Add(, , itemText, "genericMedium", "genericSmall")
 4090     21 |      1.21 |      1.21 | MSComctlLib.ListItem | LDA    | Variable:liListItem:266701
 4091     26 |      1.21 |      1.21 | MSComctlLib.ListItem | LEV    | Nest0
 4092     28 |      2.28 |      2.28 | MSComctlLib.ListView | LDA    | MSComctlLib.ListView:lvListView:262825
 4093     33 |      3.33 |      2.28 | MSComctlLib.ListItem | LLP    | Component:ListItems:157565
 4094     38 |      2.28 |      2.28 | MSComctlLib.ListItem | MEM    | Child
 4095     40 |      2.28 |      2.28 | MSComctlLib.ListItem | LEV    | Nest1
 4096     42 |      3.42 |      3.42 | Integer              | DEF    | MissingZero
 4097     44 |      3.42 |      2.28 | MSComctlLib.ListItem | ARG    | Integer
 4098     46 |      3.42 |      2.28 | MSComctlLib.ListItem | LEV    | Nest1
 4099     48 |      4.48 |      3.48 | String               | DEF    | EmptyString
 4100     50 |      4.48 |      2.28 | MSComctlLib.ListItem | ARG    | String
 4101     52 |      4.48 |      2.28 | MSComctlLib.ListItem | LEV    | Nest1
 4102     54 |      5.54 |      3.54 | String               | LDA    | Variable:itemText:266487
 4103     59 |      5.54 |      2.28 | MSComctlLib.ListItem | ARG    | String
 4104     61 |      5.54 |      2.28 | MSComctlLib.ListItem | LEV    | Nest1
 4105     63 |      6.63 |      3.63 | String               | LSC    | 13:genericMedium
 4106     68 |      6.63 |      2.28 | MSComctlLib.ListItem | ARG    | String
 4107     70 |      6.63 |      2.28 | MSComctlLib.ListItem | LEV    | Nest1
 4108     72 |      7.72 |      3.72 | String               | LSC    | 12:genericSmall
 4109     77 |      7.72 |      2.28 | MSComctlLib.ListItem | ARG    | String
>4110     79 |      2.28 |      2.28 | MSComctlLib.ListItem | PAT    | Component:Add_SmallIcon:182799
 4111     84 |      2.28 |      2.28 | MSComctlLib.ListItem | REF    | Component:Add:163224
 4112     89 |      2.28 |      1.21 | MSComctlLib.ListItem | ARG    | Object
 4113     91 |           |      2.91 | Void                 | CMD    | Set
 4114     93 |           |           |                      | REM    | NULL
 4115     98 |           |           |                      | NEW    | 659 With liListItem.ListSubItems

Finally, the Author "executes" the modified IL to emit the surface form of the selected pattern with arguments:

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
\gmTestBed\FileExplorer\proj_csh\deploy\FileExplorer\frmExploreLite.cs
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  378       private void AddListItem(string itemKey,string itemText,string itemSize,string itemType,DateTime itemModified)
  379       {
...
> 383          liListItem = lvListView.Items.Add(itemText,"genericSmall");
...

Notice that the final code for this sample ignores the Icon argument, as there can be only one image in .NET and this particular demo actually uses the SmallIcon when you run it.   

If both icons were needed a different solution would be required and this might require an extended ListView that supports both large and small icons.

See also 

FileExplorer sample