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