gmplRegistryStatement

Registry Statement Summary

Registry is either a terminal or nonterminal command statement that occurs in both command and reference scripts. The registry is a directory which stores named settings and options for a variety of special uses within gmBasic or within user specified runtime Dlls. It contains a simple hierarchical set of name-value pairs stored under a type identifier. The values are either simple strings or a text buffer.


The attributes of the Registry statement are as follows:


Attribute Description
TypeThis attribute contains the identifier of the "special use" of the name-value pair being entered. If it is omitted, then the value LibName is supplied. Though gmBasic, itself uses a set of these types which are reserved, any other identifiers may be used. They are simple identifiers beginning with a letter and containing only letters and numbers. They are not case-sensitive.
SourceThis attribute contains the source name of the pair to which a target value is to be assigned. It may have any content. If a given pair is intended to be unique within a given type, then its name must be unique within that type only. They are not case-sensitive and may contain special characters like periods.
TargetThis attribute is used only with the terminal form of the statement. It contains the target value of the pair. It may have any content and need not be unique. At any given time a given source with a given type can have only one target. If the target attribute is missing or empty then the name value pair is treated as though it no longer exists within its location.


For the nonterminal form of the Registry statement the records in the scope of the statement are entered into a text buffer in raw form and that buffer is then associated with the source name. Any gmSL processing which these raw statements might undergo is performed when they are used not here where they are simply stored.


The current, globalsettings, and language storage areas all contain registries. Which registry is searched for a given type depends upon the type. They are as follows.

Dependency: Specify a possibly omitted include file dependency

Dependency is a terminal registry type that is stored in the current storage area. Many ASP sites suffer from what is called "Omitted Include Syndrome". That is they contain code that depends on other includes, but not all of these needed includes are in the scope of every pageslice. This is particularly troublesome when the omitted includes contain variable declarations or scripted classes. The registry Dependency type is used to deal with this syndrome.


The attributes of the Dependency type are as follows:


Attribute Description
SourcePathname of include with a dependency
TargetPathname of include depended upon


The tool processes this registry type as follows:

  1. Before loading a reference to an include, determine if that include has a Dependency target entry. If the target include has already been loaded into the application being loaded, do nothing.
  2. If the target has not yet been loaded, load the target as if there had been an #include of target above the reference to source in the active pageslice.
  3. If target is also a source in another registry dependency type recursively process that dependency as well.
  4. If source is already loaded do not load it again. This is needed because a target include may well follow the source -- i.e., not actually be an omitted include file -- in an include sequence and will thus already have been loaded by this algorithm.

Since the algorithm does not require that dependent includes precede their sources, it is not expected to cycle. However, sites with cyclic include references do exist which may well be complicated by the aggressive use of this facility -- so user beware.

EditFile: Supply a set of Fix statements for a specified file

EditFile is a nonterminal registry type that is stored in the globalsettings storage area. Very large code sites consisting of many, often shared, code files that require fixes need a way to organize these fixes. The simple use of general script templates to apply to all jobs in a migration set requires that each command script processed by gmBasic include all fixes for all jobs. In these template script files Fix statements are skipped if their host is not defined in the job at hand. In processing these, the search for the host has to be performed and the actual statements being skipped have to be checked for the termination record. These are trivial operations for small sites, but can quickly build up for large sites.


The EditFile source attribute specifies the full pathname of the file to be edited. The actual Fix statements then form the target text buffer.


<Registry type="EditFile" source="Pathname of file to be fixed" >
   <Fix>
      fix statements
   </Fix>
</Registry>

When a source file is initially loaded, be it a code file, or a VBP project file, or a web file, the globalsettings registry is checked for an EditFile on its full pathname. If present, the fixes are applied to the file using the standard facilities of the Fix statement.


The other advantage of using EditFile as opposed to the Compile Fix statement is that it is file specific not compilation set specific. Compile fix, for example, cannot edit the project file directly in its raw form as EditFile can. In the case of web files they are first converted into compilable form before they are presented to the compiler for processing. This form is close to the form of the raw web page, but it is sometimes difficult to construct the fix specifications correctly. EditFile simply sees the web file when it is loaded before any other processing occurs.

FixType: Fix the type of a source component

FixType is a terminal registry type that is stored in the current storage area. It is used to fix the types of source code symbols when they are first encountered. gmBasic uses FixType registry statements when it authors the TypeInference reference script; however, they can also easily be entered into command scripts or be authored via gmNI.


The attributes of the FixType type are as follows:


Attribute Description
SourceThe possibly qualified identifier of a source code symbol whose type is the be fixed. Each time a new symbol reference is encountered gmBasic forms its fully qualified identifier, namespace.class.member.[..]. This identifier is then checked for a FixType target. If not found, the namespace component is removed from the fully qualified identifier, and that is checked for a target, and so on. Thus, depending upon how this attribute is written it can fix the type of only one symbol or of many symbols that have the same name.
TargetThe type to be applied to symbols whose identifiers match the source. This is either an identifier of one of the built in types or it is the qualified identifier of a user or external type.


The checks for the FixType registry entries are made during pass1 of the compiler when it encounters the definition of a variable or subprogram that is specified as VARIANT or OBJECT. They are also made by the pass2 compiler when it encounters the reference to an undeclared variable,

FixStatus: Specify an ASP page status

FixStatus is a terminal registry type that is stored in the current storage area. It is used to change the translation status of a web page to UserControl as opposed to a code class or a regular aspx page.


The attributes of the FixStatus type are as follows:


Attribute Description
SourceThe full pathname of the asp page whose status is to change.
TargetAn identifier for the status desired. At this time the only entry is UserControl which means to translate the page as a usercontrol.


The FixStatus entries are checked for at compile time, so they must precede the first compile statement that will load the file.

Guid: Define the value of a GUID

Guid is a terminal registry type that is stored either in the current storage area or the language storage area. The user storage area is checked first. Entries of this type are checked for by the gmSL.Runtime.Guid() method, which has one string parameter GuidName. That method attempts to find a Guid type entry whose source matches its parameter. If found, the target value is the guid to be used. If not found a new guid is generated and used.


The attributes of the Guid type are as follows:


Attribute Description
SourceThe logical name of the guid being sought. At the present time authoring methods within gmBasic seek the following logical names: Project, ProjectType1, ProjectType2, Flavor, and Interfaces. All have default values registered in the language file. Users can add additional logical names as needed.
TargetThe actual GUID to be used for the logical name.


The default values for the logical names currently being used are


 <Registry type="guid" source="Project"      target="{7EE74E01-07B7-4C4F-B053-895BB67A3A51}" />
 <Registry type="guid" source="ProjectType1" target="{349C5851-65DF-11DA-9384-00065B846F21}" />
 <Registry type="guid" source="ProjectType2" target="{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}" />
 <Registry type="guid" source="Flavor"       target="{349C5851-65DF-11DA-9384-00065B846F21}" />
 <Registry type="guid" source="Interfaces"   target="{447E0939-9DC6-40F4-A30E-26DC252607D3}" />

To change them, simply add an equivalent statement to the command script that does the authoring. Such entries are often put in the environment files loaded by scripts.

IdfStatus: Specify the Interface Description File status of an external

IdfStatus is a terminal registry type that is stored in the current storage area. Reference scripts describing an external component like a Dll, or an ocx, or an olb, or a tlb are referred to as IDFs -- "Interface Description Files". The IdfStatus specifies how references to these components are to be treated. There four possible target settings -- Build, Migrate, Interop and External:

  • When the Buildfile Select is local or global then the default IdfStatus is Build and the tool will author external dependencies as stub files or stub projects respectively.
  • When BuildFile is off then the default IdfStatus is Migrate and the tool will author external dependencies as an assembly reference.
  • The Interop setting is an intermediate one which says that any Mig files associated with the reference should be ignored.
  • The External status blocks the authoring of stubs completely.

This attribute overrides the default status of the reference. The attributes of the IdfStatus type are as follows:


Attribute Description
SourceThe identifier of the external component whose default status is to be overridden.
TargetOne of the status identifiers: Build, Migrate, Interop or External.


MigrationSupport has special status in the system. The registry entry


  <Registry type="IdfStatus" source="MigrationSupport.dll" target="External" />

or adding the attribute idfStatus="external" to the library command causes MigrationSupport.dll to behave as other libraries do.

Include: Specify the path to an include file

Include is a terminal registry type is stored in the current storage area. When gmBasic loads include files from ASP pages it first forms the full name of the include based on the pathname of the including file. Once this has been formed, the registry is checked for an Include entry that can specify a different pathname.


The attributes of the Include type are as follows:


Attribute Description
SourceThe pathname of the include as it would be formed by combining it with the pathname of the including file.
TargetThe actual pathname to be used for the include.



LibName: Specify a library name or file name

LibName is a terminal registry type that is stored in the current storage area. It is used to change the name of an external component from the way it is being referenced either in the project file or in the source code into the name of the component describing it in the migration. External libraries are ultimately identified via their filename like mso.dll or msword9.olb or mscomctl.ocx or msado20.tlb. There are, however, in the windows registries at the home sites often alternative ProgIds registered for these names. It is these ProgIds that are used in the codes. The first reason for using the this registry type is to reconvert the ProgIds back into the local filenames.


The second reason for using the LibName registry type is to supply the name of a migrated description of the component to the translation scripts. Thus, if mscomctl.ocx has a migrated description in a file GM.mscomctl.ocx, then this type is used to make the switch.


The third reason is that source code bases often reference different versions of what is logically the same external component. For example there might be references to both msado25.tlb and msado21.tlb. In the translations the two get mixed and as such their classes are viewed as being different. Also redundant migration instructions need to be constructed. A set of statements like


   <Registry type="libname" source="msado15.dll" target="msado26.tlb"/>
   <Registry type="libname" source="msado20.tlb" target="msado26.tlb"/>
   <Registry type="libname" source="msado21.tlb" target="msado26.tlb"/>
   <Registry type="libname" source="msado25.tlb" target="msado26.tlb"/>
   <Registry type="libname" source="msado27.tlb" target="msado26.tlb"/>

resolves these problems.


The attributes of the Libname type are as follows:


Attribute Description
SourceThe pathname or ProgId of the external as it appears in the source code or project file.
TargetThe actual library local filename to be used to load the reference script that describes the external.



MigFile: Associate a Migration File with an IDF

MigFile is a terminal registry type that is stored in the current storage area. It is used to specify the name of a Migration File to be associated with an Interface Description File (IDF). This allows more descriptive Migration Filenames to be used as is making it easier to work with different version of Migration Files and so more details arereported in the translation log.


For example, suppose you have three different Migration files for excel.exe, each one specifying a different strategy for upgrading references to the Excel API:


Filename Description
mig.Excel_StrongTypeStub.xmlA RefactorLibrary containing rules that improve type inference of excel references
mig.Excel_MSInterop.xmlA RefactorLibrary containing rules that migrate to use the Primary Interop Assembly for excel
mig.Excel_Aspose.xmlA RefactorLibrary containing rules that migrate to use the Aspose Cells API


Then the different commands could be used to load one of the Migration Files. Generally only one would be used at a time:

<Registry type="MigFile" source="Excel.exe" target="mig.Excel_StrongTypeStub"/>
or
<Registry type="MigFile" source="Excel.exe" target="mig.Excel_MSInterop"/>
or
<Registry type="MigFile" source="Excel.exe" target="mig.Excel_Aspose"/>

The attributes of the MigFile type are as follows:

Attribute Description
SourceThe name of the IDF (note the XML extension is not specified)
TargetThe name of the Migration File to associate with the source IDF (note this form does not include the file extension, .xml is assumed).  Alternatively, Target may be the path of the file to be loaded in either absolute form or relative to the working directory (generally the workspace\log folder).


The tool looks for the target Migration File using the standard metalanguage search process: looking in the target, local, system and language locations in that order.

Note: The Migration File name mig.file.ext.xml is automatically associated with the IDF named file.ext.xml so a registry command is not needed for that case.

ProgId: Resolve a ProgId

ProgId is a terminal registry type that is stored in the current storage area. It is used in two different contexts to change site specific application.class names into fully qualified external class names. The attributes of the ProgId registry type are as follows:


Attribute Description
SourceThe identifier of the ProgId as determined from the call. The details of this determination are described below.
TargetThe identifier to be substituted for the ProgId to resolve its reference.



The first context is to resolve the ProgId argument value passed to the VB6/ASP CreateObject methods. There are two ways to invoke a component within the VB6-ASP environment: Server.CreateObject and CreateObject.


CreateObject(progid As string,[servername As string])
Server.CreateObject(progid As string

The original VB6 CreateObject method creates and returns a reference to an ActiveX object. The ProgId argument contains the application name and class name of the object to create. The optional servername contains the name of the network where the object will be created. So far in this development effort this second argument is ignored. The Server.CreateObject method has the same first ProgId argument but does not have the second optional servername argument. Since this one is ignored anyway, we can treat the two in the same way.


The ProgId argument uses the syntax appname.objecttype and has these parts:


Part Description
appnameis the name of the application. In so as this implementation is concerned it is the name member of a currently loaded library or is the name of a current project within a multi-project script.
objecttypeis the name of the CLASS or INTERFACE that specifies the object type to be created.


The runtime difference between the two is that Server.CreateObject invokes Microsoft Transaction Server (MTS) to create the object and handle it, whereas CreateObject goes straight to it.


In the migrated code this decision would be made at a component or application level, rather than depending upon the decision made by the original programmer, so here the two are treated in the same way as follows:

  1. The tool attempts to determine what the actual ProgId is at compile time. If the ProgId is already a string, or a string constant this is no problem. If the argument is a variable, it scans the preceeding code for a string assignment to the variable.
  2. If the ProgId can be determined, the tool next scans the ProgId entries in the registry for any substitutions. Then it scans the current storage space for the component underlying the ProgId to resolve it. If this component is found then an SPV.New operation is emitted using the located components root.


       <subcode id="SPV.New">
          <vbn narg="1" code="New %1d"/>
          <csh narg="1" code="new %1d()"/>
       </subcode>
    
  3. If the ProgId can not be resolved as a string or cannot the found in the symbol space then a VBF.CreateObject operation is emitted using the original code for the argument.


      <subcode id="CreateObject">
         <vbn role="function" narg="1" code="CreateObject(%1d,\Q)"/>
         <csh role="function" narg="1" code="VBNET.Interaction.CreateObject(%1d,\Q)"/>
       </subcode>
    

Here are some examples


XML: <Registry type="progid" source="AcroExch.App" target="Acrobat.CAcroApp" />
VB6: Set lIAcroExchApp= CreateObject("AcroExch.App")
OLD ProgId: AcroExch.App
NEW ProgId: Acrobat.CAcroApp>
CS: lIAcroExchApp = new Acrobat.CAcroApp();

XML: <Registry type="ProgID" source="MSXML2.FreeThreadedDOMDocument.3.0" target="MSXML2.DomDocument" />
ASP: Set webConfigXMLDoc = Server.CreateObject("MSXML2.FreeThreadedDOMDocument.3.0")
OLD ProgID: MSXML2.FreeThreadedDOMDocument.3.0
NEW ProgID: MSXML2.DomDocument
ASCX.CS: webConfigXMLDoc = new MSXML2.DOMDocument();


The second context is in ASP OBJECT statement references. In this case the object defined in the ID attribute is declared with the class type of the PROGID attribute. The tool scans the ProgId entries in the registry for any substitutions before it attempts to resolve the actual class reference. Here is an example


XML: <Registry type="ProgID"  source="OracleInProcServer.XOraSession" target="OracleInProcServer.OraSessionClass" />
ASP: <OBJECT RUNAT="Server" SCOPE="Application" ID="OraSession" PROGID="OracleInProcServer.XOraSession">
OLD ProgId: OracleInProcServer.XOraSession
NEW ProgId: OracleInProcServer.OraSessionClass
ASAX.VB: Public Shared OraSession As New OracleInProcServer.OraSessionClass


RefactorFile: Supply a set of Refactor statements for a specified file

RefactorFile is a nonterminal registry type that is stored in the globalsettings storage area. Very large code sites consisting of many, often shared, code files whose symbols require refactoring organize these statements. The simple use of general script templates to apply to all jobs in a migration set requires that each command script processed by gmBasic check all refactoring statements for all jobs. In processing these, the symbol search has to be performed for each. This is a trivial operation for small sites, but can quickly build up for large sites.


The RefactorFile source attribute specifies the full pathname of the file whose symbols are to be refactored. The actual Refactor statements then form the target text buffer.


<Registry type="RefactorFile" source="Pathname of file to be refactored" >
   <Refactor>
      refactor statements
   </Refactor>
</Registry>

The registry is checked once for a RefactorFile entry for each class, module, form, or ASP file after the symbols for that file have been loaded but before and code has been compiled. There is nothing special about the refactor statements themselves. They behave exactly the same as Refactor statements placed within a Compile statement for a code project containing the specified file. Thus, the entry


   <Registry type="RefactorFile" source="\code\vb6\CommonFunctions.cls" >
     <Refactor>
       <FixType identifier="SortCollection.aObject" type="Interfaces.Icbn_Compare" />
    </Refactor>
  </Registry>

in a selected global settings file is identical to the following in a translation script


   <Compile project="\code\vb6\VariousCommonFunctions.vbp" >
      <Refactor fileFilter="[\code\vb6\CommonFunctions.cls]">
          <FixType identifier="SortCollection.aObject" type="Interfaces.Icbn_Compare" />
      </Refactor>
  </Compile>

Note the need in the FileFilter attribute for the square brackets surrounding the filename. They are supplied for the registry filename which must not contain those the brackets.

SharedFile: Specifies that a file is shared and should only be processed once

SharedFile is a terminal registry type that is stored in the globalsettings storage area. The statements themselves are authored by the SharedFile utility statement. It is used to identify those files that are used by more than one VB6 project and to identify which project should be the only one that processes it. The other projects then refer to the components in the shared file as though they were external library components.


The attributes of the SharedFile type are as follows:


Attribute Description
SourceThe full pathname of a code file that is shared by multiple code project.
TargetThe full pathname of a project file that is to be defining project for the shared file.


The SharedFile statement description contains a detailed discussion.

StubBaseClass: Specifies a base class to be used when declaring a stub class

When present, the StubBaseClass is authored in the stub framework case as the base class of the specified coclass.  This base class will typically replace "System.Windows.Forms.Control" in the stub declaration.  This registry command may be placed in the script or an Environment file.  If this registry command is in effect when the IDF declaring the coclass is generated, a StubBaseClass attribute will be added to the coclass element in that IDF. 

The attributes of the StubBaseClass type are as follows:

Attribute Description
SourceThe full name of the COM coclass that is being declared in the stub framework.
TargetThe name of a base class to inherit in the stub declaration

Examples:

Environment.std.xml
<EnvironmentFile>
   <Registry type="StubBaseClass" source="SHDocVw.InternetExplorer" target="System.Windows.Forms.WebBrowser" />
   <Registry type="StubBaseClass" source="MSComCtl2.UpDown" target="System.Windows.Forms.NumericUpDown" />
   <Registry type="StubBaseClass" source="MSComCtl2.DTPicker" target="System.Windows.Forms.DateTimePicker" />
   <Registry type="StubBaseClass" source="MSDataGridLib.DataGrid" target="System.Windows.Forms.DataGridView" />
   <Registry type="StubBaseClass" source="MSFlexGridLib.MSFlexGrid" target="System.Windows.Forms.DataGridView" />
   <Registry type="StubBaseClass" source="RichTextLib.RichTextBox" target="System.Windows.Forms.RichTextBox" />
   <Registry type="StubBaseClass" source="MSMask.MaskEdBox" target="System.Windows.Forms.MaskedTextBox" />
   <Registry type="StubBaseClass" source="MSComctlLib.StatusBar" target="System.Windows.Forms.StatusBar" />
   <Registry type="StubBaseClass" source="MSComctlLib.ProgressBar" target="System.Windows.Forms.ProgressBar" />
   <Registry type="StubBaseClass" source="MSComctlLib.TreeView" target="System.Windows.Forms.TreeView" />
   <Registry type="StubBaseClass" source="MSComctlLib.ListView" target="System.Windows.Forms.ListView" />
</EnvironmentFile>


UsesInterfaces: Specifies that a project file uses certain interfaces

UsesInterfaces is a terminal registry type is stored in the globalsettings storage area. It is used to resolve references between independent projects that do not correspond to the build order -- i.e., a reference by a project early in the build order to one later in the order. These can even become circular references. A circular reference occurs when two projects reference each other either directly or indirectly via intermediate references. Clearly no rearrangement of the build order can be made to resolve circular references. To make this workable under .NET a migration is needed that uses interfaces to describe those classes that are being referenced before they are defined. Codes that use these interfaces must now reference the interface classes and not the concrete classes; and codes that define classes that are to be used in interface form must define those interfaces.


For example, assume a small system consisting of two projects Project1 and Project2 is built in that order. The problem is that Project1 references a class2 in Project2 and Project2 references a class1 in Project1. To resolve this, gmBasic creates an interface for class2 that defines the public methods of that class in project2 and any references to class2 in Project1 are changed into references to the interface class as opposed to the concrete class. Now when gmBasic processes Project2 it makes certain that Project2 implements the interface class in the concrete code for that class.


The first problem is to determine what information is needed to perform the uses interfaces migration and how that information can be specified. The information needed is a list of projects that must use interfaces along with a list of which projects supply those interfaces. In the example described above then the list would be


  project1 usesInterfaces project2
  project2 usesInterfaces project1

Note that the list is in build order since some of the low level symbol referencing migrations are dependent on this order. The UsesInterfaces registry type is used to store the list.


The attributes of the UsesInterfaces type are as follows:


Attribute Description
SourceThis attribute contains the Exename32 name of the using project.
TargetThis attribute contains a comma-delimited list of the Exename32 names of the supplying projects.


The symbol table retains the order in which the registry commands are entered under a given type, so determining order of entry is simple. In the present case then the registry statements would be as follows.


  <Registry type="UsesInterfaces" source="Project1.dll"  target="Project2.dll" />
  <Registry type="UsesInterfaces" source="Project2.dll"  target="Project1.dll" />

If a given project must reference more that one other project via an interface, then the target entry may contain a comma-delimited list. This might look as follows.


  <Registry type="UsesInterfaces" source="Project2.dll"
            target="Project1.dll,Project3.dll,Project4.dll" />

The Exename32 attributes are used to reference projects, not their filenames. This is because within referencing projects the library name is needed. It is the Exename32 attribute that supplies this name. Though the worse case scenario is a circular reference, the approach here does not assume this. Rather as each project code is processed, if its Exename32 is one of the target UsesInterfaces entries then all global classes in that project are classified as supplying an interface and all classes referenced in library files whose library name is one of the source are classified as using an interface.


At this point in time the UsesInterfaces list must be constructed by hand. The BuildOrder report does detect ordering problems but that detection does not appear to have enough information at this time. The basic rule is that if a project references a class from an earlier project either as the type of a method or as the type of a parameter to a method or as an instantiation within a method, then an interface must be used.

Table of Contents