Dealing with Twips to Pixels
By default, VB6 describe the size and layout of elements on a form using a unit of measure called a Twip. WinForms .NET on the other hand uses Pixels. Generally speaking, you can think of a Twip as 1/15 of a Pixel. So, for example, a button that is 300 Twips wide in VB6 should be 20 Pixels wide in WinForms.
It is quite common to find hard coded numeric constants in the calculations for laying layout and sizing. For example, here is a const and a function, taken from our FileExplorer sample. These are used to layout and size controls in response to user actions:
Const mSplitLimit = 2000 ' Minimum width for TreeView and ListView Sub SizeControls(X As Single) ' Set sizes and locations for the movable controls On Error GoTo ErrorHandler 'Set the TreeView's width If X < 1500 Then X = 1500 If X > (Me.Width - 1500) Then X = Me.Width - 1500 tvTreeView.Width = X imgSplitter.Left = X ' Set up the ListView With lvListView .Left = X + 75 .Width = Me.Width - (tvTreeView.Width + 190) lblPath.Left = .Left + 30 lblPath.Width = .Width - 60 RichTextBox1.Left = .Left RichTextBox1.Width = .Width End With ErrorHandler: ' trying to resize during minimize? End Sub
In the code above, calculations involving numeric literals should be modified so they are expressed as Pixels rather than Twips.
Process for Twips Migration
1) Identify the application and COM API symbols that are involved with control/form sizing and layout. We typically refer to these as Screen Geometry variables. These may be identified in several ways:
- Expressions with names containing Left, Top, Width, Height, and variations of these (e.g ColumnWidth, ColWidth, RowHeight, etc.)
- Variables used in Resize event handlers and supporting functions (e.g. SizeControls above
- Variables known to be used for layout based on your knowledge of the legacy code or COM Controls. (e.g. Constants defining limits and default sizes)
For example, you may search the VB6 code for names in assignments that include numeric literals using the Source Search with a pattern such as this:
(\w+Height|\w+Top|\w+Width|\w+Left|\w+Bottom)\s{0,3}(\s*As.?\s*)?=.?-?\d\d+
The regular expression pattern above will ignore assignments to geometry variables in the Form property bag (e.g. ClientHeight, ClientWidth, etc) as these are already handled as Twips by the tool.
The fully qualified identifiers of symbols may be reported using the Search panel / Symbols report. For example:
(\w+Height|\w+Top|\w+Width|\w+Left|\w+Bottom)\s{0,3}(\s*As.?\s*)?=.?-?\d\d+
2) Once you have the fully qualified identifiers of the variables computed using Twips literals, you may prepare FixType statements to tell gmStudio to make the Twips to Pixels adjustment of the literal values used in computing those variables. This is done by changing the type of the variable to TwipsX or TwipsY using a FixType statement. This is typically done in a Compile\Refactor block:
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C:\gmTestBed\FileExplorer\proj_csh\usr\tran.FileExplorer_mgd.xml ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 41 <Compile Project="%SrcPath%" Resx="%ResxFolder%"> 42 <Refactor> 43 <!-- Some application variables are used for screen geometry so Twips must be converted to pixels --> > 44 <FixType identifier="FileExplorer.frmExploreLite.mSplitLimit" type="TwipsX" /> 45 <Fixtype identifier="FileExplorer.frmExploreLite.SizeControls.X" type="TwipsX" status="ByVal" /> 46 </Refactor> 47 </Compile>
In addition, you will often use type="TwipsX" in Interface Description Files and RefactorLibrary for COM APIs:
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C:\gmTestBed\FileExplorer\proj_csh\usr\Mscomctl.ocx.WinForms.Refactor.xml ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~> 71 <Migrate id="IToolbar.ButtonHeight" type="TwipsY" migName="ButtonSize.Height" /> 72 <Migrate id="IToolbar.ButtonWidth" type="TwipsX" migName="ButtonSize.Width" /> 178 <Migrate id="IPanel.Width" type="TwipsX" /> 203 <Migrate id="ITreeView.Indentation" type="TwipsX" /> 422 <Migrate id="IColumnHeaders.Add.Width" status="ByVal" type="TwipsX" Optional="1440"/> 431 <Migrate id="IColumnHeader.Width" type="TwipsX"/> 497 <Migrate id="IComboItem.Indentation" type="TwipsX"/> 501 <Migrate id="IImageCombo.Indentation" type="TwipsX"/> 736 <property id="Width" type="TwipsX" value="IColumnHeader.Width"/>
Given these rules, the translation will express the screen geometry as Pixels:
private const int mSplitLimit = (2000)/15; // Minimum width for TreeView and ListView ... public void SizeControls(int X) { // Set sizes and locations for the movable controls try { gmRTL.Core.GlobalException.Clear(); // Set the TreeView's width if (X < 100) { X = 100; } if (X > this.Width - 100) { X = ((int)(this.Width - 100)); } tvTreeView.Width = X; imgSplitter.Left = X; // Set up the ListView lvListView.Left = ((int)(X + 5)); lvListView.Width = ((int)(this.Width - (tvTreeView.Width + 13))); lblPath.Left = ((int)(lvListView.Left + 2)); lblPath.Width = ((int)(lvListView.Width - 4)); RichTextBox1.Left = lvListView.Left; RichTextBox1.Width = lvListView.Width; } catch(Exception exc) { gmRTL.Core.GlobalException.Initialize(exc); } // trying to resize during minimize? }