VB6から.net Frameworkへの移行

# VB6から.net Frameworkに移行
現在でも需要があるかわからないですが、VB6で作成されたのシステムを.net Frameworkに移行する必要があったので、メモを残します。以下、移行に際してVB6で作成されたソースコードがあることが前提となります。

# 移行についてのアイデア
移行の方法ですが、過去にはVB6で作成したソースコードから自動で変換するツールもあったのですが、経験上、変換制度が良くなく大量に事後修正をする必要があり、あまり効率が良くないのがネックでした。そこで、独自にVB6で作成したソースコードをVB.netのソースコードに変換するプログラムを作成し利用することにします。.net FrameworkにはC#を使うという方法もありますが、VB6と文法が近いVB.netを変換先に選択しています。

# VB6の拡張子
VB6ですが、代表的なファイルの拡張子に以下のようなものがあります。
.vbp プロジェクトファイル　・・・　今回は使用しません
.vbw プロジェクトワークスペースファイル　・・・　今回は使用しません
.bas 標準モジュール
.frm フォームモジュール
.frx バイナリフォーム
他にも多数の拡張子がありますが、使用頻度は少ないと思いますので、説明を割愛します。

まず、.basファイルですが、標準モジュールになりますが、同様の機能がVB.netにもあるので、そのまま移行します。
.frmですが、Windows Formsのフォームに変換します。.frmの中に何が記述されているかですが、前半部分がコントロールのデザイン情報、後半はコントロールイベントに対応するプログラムが記述されています。

# .frmファイルの仕様を確認
.frmファイルの仕様ですが、前半部分は以下の様になっています。
```form1.frmの抜粋
Begin VB.Form form1 
   BorderStyle     =   1  '固定(実線)
   Caption         =   "メイン"
   ClientHeight    =   3015
   ClientLeft      =   45
   ClientTop       =   615
   ClientWidth     =   5640
   Icon            =   "form1.frx":0000
   LinkTopic       =   "Form1"
   MaxButton       =   0   'False
   ScaleHeight     =   3015
   ScaleWidth      =   5640
   StartUpPosition =   2  '画面の中央
   Begin VB.CommandButton button1 
      Caption         =   "ボタン１"
      BeginProperty Font 
         Name            =   "ＭＳ Ｐゴシック"
         Size            =   9.75
         Charset         =   128
         Weight          =   400
         Underline       =   0   'False
         Italic          =   0   'False
         Strikethrough   =   0   'False
      EndProperty
      Height          =   975
      Left            =   3720
      Picture         =   "form1.frx":3C1A
      Style           =   1  'ｸﾞﾗﾌｨｯｸｽ
      TabIndex        =   8
      Top             =   1920
      Width           =   1815
   End
```

これを見ると分かるように "Begin xxx yyy" で始まって"End"で終わるというような入れ子構造になっています。Beginの後にはコントロールの型と名前が続いています。これを見てVB.netへの変換処理の判別を行います。

# コントロールの判別
処理の判別の例を一部ご紹介します。
Begin VB.Form -> System.Windows.Forms.Form
Begin VB.CommandButton -> System.Windows.Forms.Button
Begin VB.TextBox -> System.Windows.Forms.TextBox
Begin VB.Label -> System.Windows.Forms.Label
Begin VB.CheckBox -> System.Windows.Forms.CheckBox
Begin VB.ComboBox -> System.Windows.Forms.ComboBox
Begin VB.Menu -> System.Windows.Forms.MenuStrip

# フォームの場合
VB.Formについては、フォームの基本になるところなので、フォームを定義するおまじないを沢山指定する必要があります。
```sample.vb VB.netフォームの作成例
<Global.Microsoft.VisualBasic.CompilerServices.DesignerGenerated()> _
Partial Class sample
    Inherits System.Windows.Forms.Form

    'フォームがコンポーネントの一覧をクリーンアップするために dispose をオーバーライドします。
    <System.Diagnostics.DebuggerNonUserCode()> _
    Protected Overrides Sub Dispose(ByVal disposing As Boolean)
        Try
            If disposing AndAlso components IsNot Nothing Then
                components.Dispose()
            End If
        Finally
            MyBase.Dispose(disposing)
        End Try
    End Sub

    'Windows フォーム デザイナーで必要です。
    Private components As System.ComponentModel.IContainer

    'メモ: 以下のプロシージャは Windows フォーム デザイナーで必要です。
    'Windows フォーム デザイナーを使用して変更できます。
    'コード エディターを使って変更しないでください。
    <System.Diagnostics.DebuggerStepThrough()> _
    Private Sub InitializeComponent()
    ''''''この後に各コントロールの処理を記述します''''''
```

# 各コントロールの変換例
VB.TextBoxやVB.Labelなどは同名のコントロールがあるので、それを使用します。プロパティも同様に対応します。

例えば、以下のようなTextBoxがあった場合、の変換例を示します。
```text1.frm VB6のソース
   Begin VB.TextBox text1 
      BeginProperty Font 
         Name            =   "ＭＳ Ｐゴシック"
         Size            =   9.75
         Charset         =   128
         Weight          =   400
         Underline       =   0   'False
         Italic          =   0   'False
         Strikethrough   =   0   'False
      EndProperty
      Height          =   300
      IMEMode         =   4  '全角ひらがな
      Left            =   1080
      MaxLength       =   60
      TabIndex        =   3
      ToolTipText     =   "あいうえお"
      Top             =   600
      Width           =   3735
   End
```

```text1.vb 変換後のVB.netのソース
Me.text1 = New System.Windows.Forms.TextBox()
Me.text1.Name = "text1"
Me.text1.ImeMode = System.Windows.Forms.ImeMode.Hiragana
Me.text1.MaxLength = 60
Me.text1.Size = New System.Drawing.Size(249, 20)
Me.text1.Location = New System.Drawing.Point(72, 40)
```

今回の例でのプロパティのうち、Font,TabIndex,ToolTipTextは変換していません。理由ですが、FontプロパティとTabIndexプロパティはデフォルトの値を利用する想定なのであえて入れていません。ToolTipTextは対応するプロパティがないため、対応を保留にしています。この辺については、コントロールを独自に拡張してプロパティを追加するか、今回の変換ツールで対応するか検討する必要があります。今回は説明を割愛しますが、最終的にはコントロールを独自に拡張してカスタムコントロールにした方が、移行しやすいような気がします。

VB6でのHeight,WidthプロパティはSizeプロパティ、Top,LeftプロパティはLocationプロパティが相当しますので、こちらに変換します。ただし、単位がTwipとPixelとで異なるので便宜的に15で割ってPixelの値を求めています。

# メニューに関する変換
VB.Menu
# Pictureプロパティ
個人的に一番課題と思ったのがPictureプロパティです。一部を抜粋して例示しますと、以下の様に、frxファイルのファイル名とデータのあるオフセットが書かれています。
```form1.frm
   Begin VB.CommandButton button1 
      Caption         =   "ボタン１"
      Picture         =   "form1.frx":3C1A
```
このPictureプロパティで使用している画像データが別途用意があればよいのですが、そういったものがない場合、あるいは、元のソースがたくさんあるような場合はfrxファイルから抽出できた方が便利です。幸いオフセットがわかるので、その情報を基に抽出することが出来ます。
オフセットから先のデータ取得についてですが、バイナリファイルなので多少コツが必要になります。
事前情報としてオフセット位置からヘッダー情報があり、その後に実際の画像データがあるという知識が必要になります。 ヘッダーの構造ですが、順に以下の様になっています。
* ヘッダーのタイプの識別子 4バイト
* ヘッダーのサイズ　4バイト
* 画像のサイズ 4バイト

私の場合は、多少試行錯誤したのですが、思い通りに画像を抽出することが出来ました。抽出したファイルは一旦Tempフォルダに出力して、ソース上から参照するようにしています。
```form1.vb
        Me.button1 = New System.Windows.Forms.Button()
        Me.button1.Name = "button1"
        Me.button1.Image = Image.FromFile("C:\temp\form1.frx\012.gif")
```

# まとめ
すべてをうまく変換できるかというとそういう訳にはいかないのですが、独自に変換ツールを作成することで、サードパーティ製のコントロールへの対応が容易になったり、後から、変換ルールが変わった場合にも変換ツールを修正することで対応可能になります。個別のソースをいちいち修正しなくても済むようになることが大きいです。
これを読んでいただいた方の少しでも参考になれば幸いです。