Skip to content

gmslPostingPairClass

The service class PostingPair gives simple gives access to the SortPair class in the services library.


PropertyBag ComboBox/ListBox .ItemData and .List

Section titled “PropertyBag ComboBox/ListBox .ItemData and .List”

Both List and ItemData must be specified in the property bag for these controls. The internal logic will use the presence in the Registry of this Database to trigger the migration.

<Registry type="Table" source="ItemData" />

The test for the trigger is in the analyser code used to create .NET interface controls based on VB6 specifications

if(Registry_GetNameRoot("Table","ItemData") == 0) return 0;
iRet = GmslHandlers_CallMethod("Utility.ListControls",iChild,0,iStart);
return iRet;

and in the code that authors these controls

if(Registry_GetNameRoot("Table","ItemData") != 0)
{
GmslHandlers_CallMethod("Utility.ListControls",root,1,0);
}

The additional code in the analyser is called when the property migration logic notices that a ListBox or ComboBox have both ItemData and List specified. A crucial point is that this check is done easily here in the analyser. It is difficult to do in the authoring logic that assumes that everything has been set up properly. Also to block the Items AddRange for the migrated code the specification for the List must be removed from the property bag. A messy problem because this very same information is still needed to author the new AddRange.

Here is the new gmSL method ListControls in the Utilities.gmsl language file.

int ListControls(int iRoot,int action,int iStart)
{
tCodeBlock codptr;
int ctlType;
int listAddr;
int itemDataAddr;
int list;
int itemData;
int Record[2];
int levels[19];
int iChild;
int index;
string listEntry;
string itemEntry;
string tokens[64];
string token;
int nToken;
int tokenType;
int member;
int pairRoot;
int postPair;
Handle storeArea;
if(action == 0)
{
codptr = Opcode.GetCode();
ctlType = Store.GetObjectType(iRoot);
listAddr = ControlData.FindProperty(ctlType,"List",iStart);
itemDataAddr = ControlData.FindProperty(ctlType,"ItemData",iStart);
Opcode.GetOperation(codptr,listAddr,list);
Opcode.GetOperation(codptr,itemDataAddr,itemData);
pairRoot = Registry.GetNameRoot("Table","ItemData");
postPair = Registry.GetPosting(pairRoot);
storeArea = Store.GetHandle();
if(postPair == 0)
{
postPair = PostingPair.Create(storeArea);
Registry.SetPosting(pairRoot,postPair);
}
Record[0] = list;
Record[1] = itemData;
index = Store.String(Record);
PostingPair.Write(storeArea,postPair,iRoot,index);
Opcode.Delete(listAddr,2);
return 1;
}
else if(action == 1)
{
pairRoot = Registry.GetNameRoot("Table","ItemData");
postPair = Registry.GetPosting(pairRoot);
if(postPair == 0) return 0;
storeArea = Store.GetHandle();
for(iChild = Store.FindFirstChild(levels,iRoot); iChild != 0; iChild = Store.FindNextChild(levels))
{
index = PostingPair.Find(storeArea,postPair,iChild);
if(index != 0)
{
if(Select.Dialect == Dialects.vbn)
{
Write.Line("Me." + Store.GetName(iChild) + ".Items.AddRange(new MigrationSupport.UI.ItemData() {");
}
else Write.Line("this." + Store.GetName(iChild) + ".Items.AddRange(new MigrationSupport.UI.ItemData[] {");
Store.GetInfo(index,Record);
listEntry = Store.GetString(Record[0]);
itemEntry = Store.GetString(Record[1]);
Parser.SetStatement(listEntry);
nToken = 0;
while(true)
{
token = Parser.GetToken(tokenType);
if(tokenType == 0) break;
if(token != ",")
{
tokens[nToken] = token;
nToken = nToken + 1;
}
}
Parser.SetStatement(itemEntry);
Write.ChangeMargin(1);
for(member = 0; member < nToken; member = member + 1)
{
token = Parser.GetToken(tokenType);
Write.Text("new MigrationSupport.UI.ItemData(""");
Write.Text(tokens[member] + """," + token + ")");
if(member < (nToken-1)) Write.Text(",");
else if(Select.Dialect == Dialects.vbn) Write.Text("})");
else Write.Text("});");
Write.Record();
token = Parser.GetToken(tokenType);
}
Write.ChangeMargin(-1);
}
}
}
return 0;
}

If the PostingPair associated with the Table.ItemData registry entry has not yet been created, then it must be created. The table has 3 fields: an identifier field “Control” and two varchar fields “List” and “ItemData” that contain the property strings. The “symbol” type takes root offsets from the symbol table and VarChar fields are simple “Store_String” offsets. All of this information is directly available at this point in the property bag code so it can be moved directly into the record and written to the table. Once this is in place, we can verify that the strings have been properly stored by using the new gmMetrics tool.


The Create method creates a small integer SortPair used for looking up links and relationships between components in long memory based on their defining root offsets.

<Method id="Create" type="Integer" opcode="SCM.PostingPair_Create" >
<Argument id="Store" type="Object" status="ByVal" />
</Method>

The information structure associated with posting pairs itself is allocated locally on the stack and is never left open; therefore, posting pairs do not have handles and are controlled entirely via their root offsets. Its parameter is:

ParameterDescription
Storespecifies the long memory area that is to contain the sort pair

If all goes well, then the method returns the root offset in the long memory area of the control information vector for the posting pair. If there is a problem, then a zero is returned.


The Find method looks up the posting value associated with a posting index into a posting pair.

<Method id="Find" type="Integer" opcode="SCM.PostingPair_Find" >
<Argument id="Store" type="Object" status="ByVal" />
<Argument id="Base" type="Integer" status="ByVal" />
<Argument id="Index" type="Integer" status="ByVal" />
</Method>

Its parameters are:

ParameterDescription
StoreSpecifies the handle for the long memory area containing the posting pair.
BaseSpecifies the root offset of the posting pair in the storage area.
IndexSpecifies the index value for which a corresponding posting value is desired.

If the posting pair contains an entry for the index, then its associated value is returned; else a zero is returned.


The Write method writes a new posting to a posting pair.

<Method id="Write" type="Integer" opcode="SCM.PostingPair_Write" >
<Argument id="Store" type="Object" status="ByVal" />
<Argument id="Base" type="Integer" status="ByVal" />
<Argument id="Index" type="Integer" status="ByVal" />
<Argument id="Posting" type="Integer" status="ByVal"/>
</Method>

Its parameters are:

ParameterDescription
StoreSpecifies the handle for the long memory area containing the posting pair.
BaseSpecifies the root offset of the posting pair in the storage area.
IndexSpecifies the index value for which a corresponding posting value is needed.
PostingSpecifies the posting value to be associated with the index.

If the pair already exists and has a nonzero value associated with it, the method returns a zero.