Support Statement: Sample Migration of CommonDialog to Winforms

Overview

The CommonDialog control is a one-to-many migration: In COM, the CommonDialog control is a "jack of all trades" has a complex interface supporting several use cases. In .NET, there are several different Dialog components (PrintDialog, OpenDialog, SaveDialog, ColorDialog, FontDialog) and you use the one you need depending on the desire use case.

In addition, the COM CommonDialog was an "invisible control". It could be placed on a VB6 form and declared in logic. In .NET, the Common Dialog is a set of Components.

Sample Application Analysis

The following is an example of analysis on the nature of CommonDialog usage in a typical application.

The following VBPs use MSComDlg:

  • ic_FuncLib
  • devOPOSposprn
  • ic_Company
  • ic_RptsFinancial
  • ic_RptsGeneral
  • appmain

The following API elements are used (from Reference report):

MemType                        MemClas                        MemName                        refs
------------------------------ ------------------------------ ------------------------------ -----------
Lib_Method                     ICommonDialog                  ShowColor                      1
Lib_Method                     ICommonDialog                  ShowSave                       1
Lib_EnumEntry                  ColorConstants                 cdlCCRGBInit                   1
GUI_Property                   CommonDialog                   Filter                         1
Lib_Property                   ICommonDialog                  InitDir                        2
Coclass                        MSComDlg                       CommonDialog                   3
Lib_EnumEntry                  FileOpenConstants              cdlOFNHideReadOnly             1
Lib_Property                   ICommonDialog                  CancelError                    8
Lib_Property                   ICommonDialog                  Filter                         7
Lib_Property                   ICommonDialog                  FilterIndex                    2
Lib_Method                     ICommonDialog                  ShowOpen                       4
Lib_Property                   ICommonDialog                  PrinterDefault                 2
Lib_EnumEntry                  PrinterConstants               cdlPDSelection                 1
GUI_Control                    CommonDialog                   _ctor                          6
Lib_Property                   ICommonDialog                  Color                          2
Lib_EnumEntry                  FileOpenConstants              cdlOFNFileMustExist            1
Lib_Method                     ICommonDialog                  ShowPrinter                    2
Lib_EnumEntry                  PrinterConstants               cdlPDAllPages                  1
Lib_Property                   ICommonDialog                  Flags                          6
Lib_Property                   ICommonDialog                  hDC                            1
Lib_EnumEntry                  PrinterConstants               cdlPDNoPageNums                1
Lib_Property                   ICommonDialog                  FileName                       10

ShowSave, ShowColor, ShowOpen, and ShowPrinter are used. The CommonDialog class declared both in GUI and Logic.

There are 8 methods that use CommonDialg:

Srcname             LocName             locmemb                  memName                 
------------------- ------------------- ------------------------ --------------
appmain             frmUpgrade          abtnManual_Click         ShowOpen      
ic_RptsGeneral      IcAcctPrintStmnt    abtnPrintResults_Click   ShowPrinter   
devOPOSposprn       pnlLoadPix          cmdLoad1_Click           ShowOpen      
devOPOSposprn       pnlLoadPix          cmdLoad2_Click           ShowOpen      
ic_Company          IcCompanyMainSystem GetColor                 ShowColor     
ic_FuncLib          clsFuncLib          OpenFileDialog           ShowOpen      
ic_FuncLib          clsFuncLib          SaveAsDialog             ShowSave      
ic_FuncLib          clsFuncLib          SetDefaultPrinter        ShowPrinter   

Notice that each instance of CommonDialog is used for only one type of Show operation. This simplifies things and means we can migrate each instance to a specific .NET replacement.

Migrating CommonDialog to different Winforms Common dialog components

The migration has three steps:

1) Declare the different types and add migration rules map them to .NET replacement. These rules will be placed in a RefactorLibrary, comdlg32.ocx.WinForms.Refactor.xml. A copy of this file is attached to the gmStudio Extensions page.  Notice that some of the API members are marked with migStatus=NotImplemented which will result in their being commented out in the translated logic.

<RefactorLibrary>
<!--
Description: rules to assist with upgrading MSComDlg.CommonDialog to Winforms Dialog components
This RefactorLibrary "extends" the CommonDialg base class with new coclasses to represent the 
different possible .NET targets.  The upgrade solution must indicate which of these is extended types 
is used in different situations.  This may be done with a fixtype commands or gmSL.  Some additional 
cleanup may be needed which may be easily done with Author/Fix or manual edits after translation.
-->
<Refactor id="[comdlg32.ocx]" >

   <Migrate migName="System.Windows.Forms" libType="Internal" location="DoNotDeclare" AssemblyName="Remove.CommonDialog" />

   <Migrate id="CommonDialog" migName="CommonDialog" Role="Define" />

   <Migrate id="ICommonDialog.DialogTitle" migName="Title" />
   <Migrate id="ICommonDialog.InitDir" migName="InitialDirectory" />
   <Migrate id="ICommonDialog.Flags" migName="Options" migStatus="NotImplemented" />
   <Migrate id="ICommonDialog.CancelError" migStatus="NotImplemented" />
   <Migrate id="ICommonDialog.ShowOpen" migName="ShowDialog" />
   <Migrate id="ICommonDialog.ShowSave" migName="ShowDialog" />
   <Migrate id="ICommonDialog.ShowColor" migName="ShowDialog" />
   <Migrate id="ICommonDialog.ShowFont" type="Variant" migName="ShowDialog" />
   <Migrate id="ICommonDialog.ShowPrinter" migName="ShowDialog" />
   <Migrate id="ICommonDialog.ShowHelp" migName="ShowDialog" />
   <Migrate id="ICommonDialog.PrinterDefault" migStatus="NotImplemented" />
   
   <Extend id="CommonDialog">
      <coclass id="ColorDialog"/>
      <coclass id="FontDialog"/>
      <coclass id="HelpDialog"/>
      <coclass id="OpenFileDialog" />
      <coclass id="PrintDialog"/>
      <coclass id="SaveFileDialog"/>
   </Extend>
   
   <Migrate id="ColorDialog" migName="ColorDialog" role="define" />
   <Migrate id="OpenFileDialog" migName="OpenFileDialog" role="define" />
   <Migrate id="PrintDialog" migName="PrintDialog" role="define" />
   <Migrate id="SaveFileDialog" migName="SaveFileDialog" role="define" />
   
   <migClass id="NetControl.CommonDialog" migName="Remove.CommonDialog" parent="CommonDialog">
   <!-- no designer code for this component -->
   </migClass>  

   <migClass id="NetControl.ColorDialog" migName="Remove.ColorDialog" parent="ColorDialog">
   <!-- no designer code for this component -->
   </migClass>    

   <migClass id="NetControl.OpenFileDialog" migName="Remove.OpenFileDialog" parent="OpenFileDialog">
   <!-- no designer code for this component -->
   </migClass>    

   <migClass id="NetControl.PrintDialog" migName="Remove.PrintDialog" parent="PrintDialog">
   <!-- no designer code for this component -->
   </migClass>    

   <migClass id="NetControl.SaveFileDialog" migName="Remove.SaveFileDialog" parent="SaveFileDialog">
   <!-- no designer code for this component -->
   </migClass>    

</Refactor>
</RefactorLibrary>

2) For each CommonDialog instance in the source, specify the custom type to use when migrating it. There are several ways to do this. These rules will be placed in a ScriptRules file, ComDlg32.ocx.Rules.xml.  

<ScriptRules>
<!--
Description: ScriptRules to migrate MSComDlg.CommonDialog to Winforms Common Dialog classes
-->
<ScriptRule id="comdlg32.OCX" Condition="%TaskTag%=~(upg)">
<Option>
   <Registry type="MigFile" source="comdlg32.OCX" target="comdlg32.OCX.WinForms.Refactor" />
</Option>

<Compile Condition="%SrcName%=='ic_FuncLib'">
<Refactor errorStatus="Warn">
   <FixType identifier="ic_FuncLib.clsFuncLib.OpenFileDialog.cDlg" type="MSComDlg.OpenFileDialog" />
   <FixType identifier="ic_FuncLib.clsFuncLib.SaveAsDialog.cDlg" type="MSComDlg.SaveFileDialog" />
   <FixType identifier="ic_FuncLib.clsFuncLib.SetDefaultPrinter.cDlg" type="MSComDlg.PrintDialog" />
</Refactor>
</Compile>

<Author Condition="%SrcName%=='ic_FuncLib'">
<Fix host="ic_FuncLib" name="PostEdit">
<Replace status="active" name="Cleanup Common Dialog instance">
<OldBlock><![CDATA[this.cmDlg = new System.Windows.Forms.CommonDialog();]]></OldBlock>
</Replace>
</Fix>
</Author>

<Compile Condition="%SrcName%=~'devOPOSposprn|appmain'">
<Fix host="%SrcName%" name="PreEdit">
   <Replace status="active" name="Migrate CommonDialog as OpenFileDialog">
   <OldBlock><![CDATA[Begin MSComDlg.CommonDialog]]></OldBlock>
   <NewBlock><![CDATA[Begin MSComDlg.OpenFileDialog]]></NewBlock>
   </Replace>
</Fix>
</Compile>

<Compile Condition="%SrcName%=='ic_Company'">
<Fix host="%SrcName%" name="PreEdit">
   <Replace status="active" name="Migrate CommonDialog as ColorDialog">
   <OldBlock><![CDATA[Begin MSComDlg.CommonDialog CommonDialog1]]></OldBlock>
   <NewBlock><![CDATA[Begin MSComDlg.ColorDialog CommonDialog1]]></NewBlock>
   </Replace>
</Fix>
</Compile>

<Compile Condition="%SrcName%=='ic_RptsFinancial'">
<Fix host="%SrcName%" name="PreEdit">
   <Replace status="active" name="Remove unused CommonDialog">
   <OldBlock><![CDATA[
   Begin MSComDlg.CommonDialog CommonDialog1
   ...
   End
   ]]></OldBlock>
   </Replace>
</Fix>
</Compile>

<Compile Condition="%SrcName%=='ic_RptsGeneral'">
<Fix host="ic_RptsGeneral" name="PreEdit">
   <Replace status="active" name="Migrate CommonDialog as PrintDialog">
   <OldBlock><![CDATA[Begin MSComDlg.CommonDialog CommonDialog1]]></OldBlock>
   <NewBlock><![CDATA[Begin MSComDlg.PrintDialog CommonDialog1]]></NewBlock>
   </Replace>
</Fix>
</Compile>

<Author Condition="%SrcName%=='ic_FuncLib|devOPOSposprn'">
<Fix host="%SrcName%" name="PostEdit">
   <Replace status="active" name="Cleanup Spurious new from control">
   <OldBlock><![CDATA[this.cmDlg = new System.Windows.Forms.CommonDialog();]]></OldBlock>
   </Replace>
</Fix>
</Author>

</ScriptRule>
</ScriptRules>

3) Load your ScriptRules using a command in your translation script (line 76):

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Migration.tran.xml
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
...
   72 <ScriptRule id="SYSINFO.OCX" FileName="..\usr\SysInfo.ocx.Rules.xml" />
   73 <ScriptRule id="mswinsck.ocx" FileName="..\usr\mswinsck.ocx.Rules.xml" />
   74 <ScriptRule id="msado15.dll" FileName="..\usr\msado15.dll.Custom.Rules.xml" />
   75 <ScriptRule id="RICHTX32.ocx" FileName="..\usr\RICHTX32.OCX.Rules.xml" />
>  76 <ScriptRule id="comdlg32.ocx" FileName="..\usr\comdlg32.ocx.Rules.xml" />
   77 <ScriptRule id="ieframe.dll" FileName="..\usr\ieframe.dll.Rules.xml" />
   78 <ScriptRule id="mscomm32.ocx" FileName="..\usr\mscomm32.ocx.Rules.xml" />
   79 
   80 <Compile Project="%SrcPath%" Resx="%ResxFolder%"/>
...