Skip to content

Support Statement: Using gmSL to determine if an optional argument was omitted

Q: How to judge %1d has value or empty? Like if ( %1d != ‘ ‘ or “ “ or Null or ???…

A: The %1d is a format string placeholder that tells the tool’s code authoring service where to emit the 1st item on the operation stack when it authors a code pattern into the output buffer.

The items on the operation stack may be many different things such as variables, literals, arguments, methods, and operations organized into related groups.

I assume you are trying to determine if an optional argument is specified or not so you can select an appropriate pattern to express a COM API call as .NET.

Consider this COM API MSComctlLib.INodes.Add

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
C:\gmTestBed\FileExplorer\proj_csh\idf\FromIdl\mscomctl.ocx.xml
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
>1067 <method id="Add" type="Node">
1068 <argument id="Relative" type="Variant" status="ByRef" optional="Default"/>
1069 <argument id="Relationship" type="Variant" status="ByRef" optional="Default"/>
1070 <argument id="Key" type="Variant" status="ByRef" optional="Default"/>
1071 <argument id="Text" type="Variant" status="ByRef" optional="Default"/>
1072 <argument id="Image" type="Variant" status="ByRef" optional="Default"/>
1073 <argument id="SelectedImage" type="Variant" status="ByRef" optional="Default"/>
1074 </method>

Use in the following statement

Set nodRoot = tvTreeView.Nodes.Add(, , drv.RootFolder.Path, drv.DriveLetter & ":\")

Only Key and Text arguments specified, the rest of the arguments are omitted and therefore they contain default values.

Here for example is the operation stack this modestly complex line of code:

386 | | | | NEW | 401 Set nodRoot = tvTreeView.Nodes.Add(, , drv.RootFolder.Path, drv.DriveLetter & ":\")
389 | 1.389 | 1.389 | MSComctlLib.Node | LDA | Variable:nodRoot:263980
394 | 1.389 | 1.389 | MSComctlLib.Node | LEV | Nest0
396 | 2.396 | 2.396 | MSComctlLib.TreeView | LDA | MSComctlLib.TreeView:tvTreeView:262914
401 | 3.401 | 2.396 | MSComctlLib.Nodes | LLP | Component:Nodes:150631
406 | 2.396 | 2.396 | MSComctlLib.Nodes | MEM | Child
408 | 3.408 | 2.396 | MSComctlLib.Node | LLP | Component:Add:155184
413 | 2.396 | 2.396 | MSComctlLib.Node | MEM | Child
415 | 2.396 | 2.396 | MSComctlLib.Node | LEV | Nest1
417 | 3.417 | 3.417 | Void | DEF < \| Overload
419 | 3.417 | 2.396 | MSComctlLib.Node | ARG | Object
421 | 3.417 | 2.396 | MSComctlLib.Node | LEV | Nest1
423 | 4.423 | 3.423 | Void | DEF < \| Overload
425 | 4.423 | 2.396 | MSComctlLib.Node | ARG | Integer
427 | 4.423 | 2.396 | MSComctlLib.Node | LEV | Nest1
429 | 5.429 | 3.429 | Scripting.Drive | LDA | Variable:drv:263878
434 | 6.434 | 3.429 | Scripting.Folder | LLP | Component:RootFolder:67849
439 | 5.429 | 3.429 | Scripting.Folder | MEM | Child
441 | 6.441 | 3.429 | String | LLP | Component:Path:68307
446 | 5.429 | 3.429 | String | MEM | Child
448 | 5.429 | 2.396 | MSComctlLib.Node | ARG | String
450 | 5.429 | 2.396 | MSComctlLib.Node | LEV | Nest1
452 | 6.452 | 3.452 | Scripting.Drive | LDA | Variable:drv:263878
457 | 7.457 | 3.452 | String | LLP | Component:DriveLetter:67693
462 | 6.452 | 3.452 | String | MEM | Child
464 | 7.464 | 4.464 | String | LSC | 2::\
469 | 6.452 | 3.452 | String | CAT | String
471 | 6.452 | 2.396 | MSComctlLib.Node | ARG | String
473 | 6.452 | 2.396 | MSComctlLib.Node | LEV | Nest1
475 | 7.475 | 3.475 | Void | DEF < \| Overload
477 | 7.475 | 2.396 | MSComctlLib.Node | ARG | Variant
479 | 7.475 | 2.396 | MSComctlLib.Node | LEV | Nest1
481 | 8.481 | 3.481 | Void | DEF < \| Overload
483 | 8.481 | 2.396 | MSComctlLib.Node | ARG | Variant
485 | 2.396 | 2.396 | MSComctlLib.Node | CUF | Args6
487 | 2.396 | 2.396 | MSComctlLib.Node | REF | Component:Add:155184
492 | 2.396 | 1.389 | MSComctlLib.Node | ARG | Object
494 | | 2.494 | Void | CMD | Set

In order to determine if arguments to INode.Add are specified or not, the gmSL code must look for LEV,DEF,ARG operations in sequence. This is done in an INode.Add migration event handler in the gmSL script associated with the MSComctlLib API. This is a rather complex migration because the one COM API has five different ways it may be expressed in C# (and additional variations for VB.NET). The code to determine if an argument is used or not is as follows:

int INodes_Add(int subRoot, int iStart, int iRefer)
{
int icode;
int nCode;
tCodeBlock codptr;
int oper;
int subc;
tCodeBlock isOmitted;
int nOper;
int omitRelative;
int iType;
int stringRelative;
int omitRelation;
int lcode;
int iRet;
int intValue;
int tvwChild;
int tvwLast;
tLibComp libComp;
int addChild;
int addLast;
int pattern;
int objRoot;
int objType;
int propAddr;
string strValue;
int imageAddr;
int selectedAddr;
int omitKey;
// Position the stack pointer to the beginning of the arguments list
codptr = Opcode.GetCode();
nCode = Opcode.GetLength()
icode = Opcode.GetNext(codptr,iRefer,nCode);
subc = 0;
oper = Opcode.GetOperation(codptr,icode,subc);
if(oper != OPC.MEM) return 0;
icode = Opcode.GetNext(codptr,icode,nCode);
oper = Opcode.GetOperation(codptr,icode,subc);
if(oper != OPC.LEV) return 0;
// INodes.Add.Relative
nOper = 0;
isOmitted = CodePattern.Read("LEV,DEF,ARG",nOper);
omitRelative = CodePattern.Match(icode,isOmitted);
...

Given the logic above the variable omitRelative will be non-zero it argument INodes.Add.Relative was omitted.