VB6.0から.NET C#(Vb.Net)への移植(VB6互換コンポーネントを排除)

VB6.0から.NET C#(Vb.Net)への移植(VB6コンポーネントを排除)

  1. VB6.0開発環境、対象のVSがインストールされているものとします。
    ・VS2008はVB6.0からVb.Netへのコンバート用。
    ・他のコンバートツールが有ればそちらを使用。
    ・VB6.0(SP6)開発環境。(無くても実行環境が有ればなんとかなります)
  2. VS2008等を使用して、VB6.0からVb.Netへコンバートを実施。
  3. SharpDeveloper等を使用して、Vb.NetからC#へ変換する。
  4. コントーロールを配列としてアクセスクラスを作成
    VB6.0でコントロール配列を使用している場合は必須。
  5. Gridは、DataGridViewを使用して作り直しになる。
  6. VB6.0使用のコンポーネントは、.NETのコンポーネントに置き換え。
    VB6.0のコンポーネントは、使用しないことを前提にしています。

フォーム移行

C#へのコンバート後の1つのフォームのソースファイル。

  • TestForm.cs
  • TestForm.Designer.cs
  • TestForm.resx
コンバート後フォームデザイナーでのエラーを修正。

 TestForm.Designer.cs をVSで自動生成されるソースに合わせて編集する。

  1. usingを全て削除。
    デザイナーソースではネームスペースを含めたフルのクラス名を使用するので必要ない。
  2. namespaceの変更。
    自分の環境に合わせてお好きなnamespaceに変更。
  3. クラス定義の直前の行の以下を削除。
    [Microsoft.VisualBasic.CompilerServices.DesignerGenerated()]
  4. 以下の範囲を削除して、置き換え。
    この時コンストラクタも削除するので、TestForm.csへコンストラクタを作成。 

    #region "Windows フォーム デザイナによって生成されたコード "
    [System.Diagnostics.DebuggerNonUserCode()]
    public TestForm() : base()
    {
        ・・・
    }
    //Windows フォーム デザイナで必要です。
    private System.ComponentModel.IContainer components;
    ⇒ 以下VSのデザイナーで作成されるロジック
    /// <summary>

    /// Required designer variable.
    /// </summary>
    private System.ComponentModel.IContainer components = null;
    /// <summary>
    /// Clean up any resources being used.
    /// </summary>
    /// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
    protected override void Dispose(bool disposing)
    {
        if (disposing && (components != null)) {
            components.Dispose();
        }
        base.Dispose(disposing);
    }
    #region "Windows フォーム デザイナによって生成されたコード "
    /// <summary>
    /// Required method for Designer support - do not modify
    /// the contents of this method with the code editor.
    /// </summary>
  5. 削除した次の行から、private void InitializeComponent()までの変数定義を最後に移動
    [System.Diagnostics.DebuggerStepThrough()]定義は、削除する。
    //Windows フォーム デザイナで必要です。

    private System.ComponentModel.IContainer components;
    ────────────────────────────────────
    ここまで削除しているので、以下が削除した次の行
    ────────────────────────────────────
    public System.Windows.Forms.ToolTip ToolTip1;

    private System.Windows.Forms.Button withEventsField_cmdCancel;
    public System.Windows.Forms.Button cmdCancel {
        get { return withEventsField_cmdCancel; }
        set {
            if (withEventsField_cmdCancel != null) {
            withEventsField_cmdCancel.Click -= cmdCancel_Click;
        }
        withEventsField_cmdCancel = value;
        if (withEventsField_cmdCancel != null) {
            withEventsField_cmdCancel.Click += cmdCancel_Click;
        }
    }
    public System.Windows.Forms.RichTextBox rtxt;
    ────────────────────────────────────
    この行までを最後に移動する。
    以下は削除
    ────────────────────────────────────
    //メモ: 以下のプロシージャは Windows フォーム デザイナで必要です。

    //Windows フォーム デザイナを使って変更できます。
    //コード エディタを使用して、変更しないでください。
    [System.Diagnostics.DebuggerStepThrough()]
    ────────────────────────────────────
    private void InitializeComponent()

    {
        ・・・
    }
  6. ここまでの編集結果
    namespace Test.Name.Space

    {
        partial class TestForm
        {
            /// <summary>
            /// Required designer variable.
            /// </summary>
            private System.ComponentModel.IContainer components = null;
            /// <summary>
            /// Clean up any resources being used.
            /// </summary>
            /// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
            protected override void Dispose(bool disposing)
            {
                if (disposing && (components != null)) {
                    components.Dispose();
                }
                base.Dispose(disposing);
            }
            #region "Windows フォーム デザイナによって生成されたコード "
            /// <summary>
            /// Required method for Designer support - do not modify
            /// the contents of this method with the code editor.
            /// </summary>
            private void InitializeComponent()
            {
                ・・・
                this.Font = new System.Drawing.Font("Arial", 9f,
                    System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, Convert.ToByte(0));
                ・・・
            }
            #endregion
            public System.Windows.Forms.ToolTip ToolTip1;
            private System.Windows.Forms.Button withEventsField_cmdCancel;
            public System.Windows.Forms.Button cmdCancel {
                get { return withEventsField_cmdCancel; }
                set {
                    if (withEventsField_cmdCancel != null) {
                        withEventsField_cmdCancel.Click -= cmdCancel_Click;
                    }
                    withEventsField_cmdCancel = value;
                    if (withEventsField_cmdCancel != null) {
                        withEventsField_cmdCancel.Click += cmdCancel_Click;
                    }
                }
            }
            public System.Windows.Forms.RichTextBox rtxt;
       }
    }
  7. 以下のフォント定義でエラーが出ているので、フォント定義を全て削除する。
    this._lblSelect_0.Font = new System.Drawing.Font("Arial", 9f, System.Drawing.FontStyle.Regular,
           System.Drawing.GraphicsUnit.Point, Convert.ToByte(0));
    後でデザイナーで設定するか、以下のように置き換えます。
    Convert.ToByte(0) ⇒ ((byte)(128))
    全てのコントロールが同じフォントでサイズを使用していれば、フォームに設定するだけで、全て同一のフォントとサイズが使用されますので、
    同じであれば、削除してフォームにのみ設定するほうが良いでしょう。
    削除する場合は、コントロール個別にフォントやサイズなどを使用して設定している場合は、覚えておいてください。
    もしくは、上記の置換えを行ってください。
  8. イベント定義を修正、もしくは削除する。
    イベント定義も変わってきますので、別途テキストに保存しておいて削除して、後でデザイナーで追加するほうが間違いありません。
    特に色々なイベントを使用していたり、コントロール配列のイベントの場合は削除してデザイナーで追加するほうが良いです。
    コントロール配列でない場合の同一パターンのイベントの場合は一つ追加して、各コントロールに追加していくことも可能ですので、
  9. コントーロール配列の置き換え
    デザイナーで編集した場合に影響しないように以下のVB6コンポーネントを使用したコントーロール配列設定を全て削除してメンバ変数として追加しコンストラクタにて初期化する。
    ────────────────────────────────────
    this.lblSelect = new Microsoft.VisualBasic.Compatibility.VB6.LabelArray(components);
    ((System.ComponentModel.ISupportInitialize)this.lblSelect).BeginInit();
    this.Controls.Add(_lblSelect_99);
    ・・・
    this.Controls.Add(_lblSelect_0);
    this.lblSelect.SetIndex(_lblSelect_99, Convert.ToInt16(99));
    ・・・
    this.lblSelect.SetIndex(_lblSelect_0, Convert.ToInt16(0));
    ((System.ComponentModel.ISupportInitialize)this.lblSelect).EndInit();
    ────────────────────────────────────
    メンバ変数として作成した対象のコントロール配列を追加。
    private LabelArray labelSelect;
    コンストラクタで初期化。
    this.labelSelect = new LabelArray(this, "_lblSelect_", 0, 99);
    ここまでの変更で、デザイナーで表示可能なはずですので表示してみてください。
    エラーが発生する場合は、表示されたエラーのアンカーをクリックしてエラー箇所を修正してください。
デザイナーで変更
  1. ボタンのプロパティ。
    UseVisualStyleBackColor True
  2. イベントの追加。
    別途テキストへコピーしておいたイベント定義を確認しながらコントロールを選択して追加していきます。
    private System.Windows.Forms.Button withEventsField_cmdCancel;
    public System.Windows.Forms.Button cmdCancel {
        get { return withEventsField_cmdCancel; }
        set {
            if (withEventsField_cmdCancel != null)
    {

                // cmdCancel_Clickがイベント名です。
                withEventsField_cmdCancel.Click -= cmdCancel_Click;
            }
            withEventsField_cmdCancel = value;
            if (withEventsField_cmdCancel != null)
    {

                withEventsField_cmdCancel.Click += cmdCancel_Click;
            }
        }
    }
    cmdCancel_Click の場合は、cmdCancel がコントロール名称で、Click がイベント名です。
    コントロールを選択、もしくは一覧から選択して、該当のイベントにメソッドを追加していきます。
    デザイナーで cmdCancel ボタンを追加して、Click イベントに 「cmdCancel_Click」を貼り付けます。
    コントロール配列の場合は、対象のコントロールをすべて選択してから行うと選択した全てのコントロールにイベントが追加されます。
ロジックの修正

 ロジックの修正では、元のロジックによるのでよくあるパターのみご紹介します。

  1. コンバートした結果の関数の戻り値。
    関数の戻り地がobjectになっているなど、数値で関数の戻り値を設定していると、
    C#の場合は面倒なので、boolに置き換えます。
  2. 文字列のフォーマット。
    Microsoft.VisualBasic.Compatibility.VB6.Support.Format(value, "###0.0");
    string.Format ("{0:###0.0}", value);
    もしくは、
    $"{value:###0.0}";
  3. 数値変換。
    double dd = Convert.Double(value);
  4. FileSystemオブジェクトの変更。
    FileSystemオブジェクトの変更は、
    System.IO空間のFile、Directory、Path、StreamXXXに置き換えていきます。

    FileSystem.FileOpen(1, filePath, OpenMode.Output);
    for (int i = 0; i < XXXX; ++i) {
        FileSystem.PrintLine(1, lineString[i]);
    }
    こんな場合は、
    using (StreamWriter sw = new StreamWriter(filePath, true, Encoding.GetEncoding("Shift-Jis"))) {
        for (int i = 0; i < XXXX; ++i) {
        sw.WriteLine(lineString[i]);
        }
    }
コントロールの配列格納クラス
  1. コントール別の配列格納規定クラス。
    using System;
    using System.Collections;


    using System.Reflection;


    using System.Windows.Forms;


    namespace Test.Name.Common
    {

        /// <summary>
        /// コントロールを配列化するための基底クラス
        /// </summary>
        public class ControlArray : CollectionBase
        {
           protected readonly Form HostForm;
            /// <summary>
            /// コンストラクタ
            /// </summary>
            /// <param name="form">親フォーム</param>
            public ControlArray(Form form)
            {
                this.HostForm = form;
            }
            /// <summary>
            /// コンストラクタ
            /// </summary>
            /// <param name="form">親フォーム</param>
            /// <param name="prefix">コントロールの名称先頭</param>
            /// <param name="startIndex">開始番号</param>
            /// <param name="endIndex">終了番号</param>
            public ControlArray(Form form, string prefix, int startIndex, int endIndex)
            {
                this.HostForm = form;
                this.Add(prefix, startIndex, endIndex);
            }
            /// <summary>
            /// 格納されたコントロールの指定配列番号での取得
            /// </summary>
            /// <param name="index">コントロール番号(1~)</param>
            /// <returns>配列番号でしてしたコントロールオブジェクト(存在しない場合は、null)</returns>
            public Control this[int index]
            {
                get
                {
                    if (index < 0 || index >= this.List.Count)
                    {
                        throw new ArgumentOutOfRangeException($"index out of Range [index:[{index}]");
                    }
                    Control ctrl = (Control)this.List[index];
                    return ctrl;
                }
            }
            public int Max
           {
                get { return this.List.count; }
            }
            public int GetIndex(Control control)
            {
                int index = 0;
                foreach (Control ctl in this.List)
                {
                    if (ctl.Name.Equals(control.Name))
                    {
                        return index;
                    }
                    ++index;
                }
                return 0;
            }
            /// <summary>
            /// プレフィックス指定名称のテキストボックスコントロールを登録
            /// </summary>
            /// <param name="prefix">コントロールの名称先頭</param>
            /// <param name="startIndex">開始番号</param>
            /// <param name="endIndex">終了番号</param>
            /// <returns>取得したコントロールの数を戻す</returns>
            public int Add(string prefix, int startIndex, int endIndex)
            {
                try
                {
                    for (int i = startIndex; i <= endIndex; i++)
                    {
                        Control ctrl = GetContorol(prefix, i);
                        if (ctrl == null)
                        {
                            ctrl = new Control("Null Control");
                        }
                        this.List.Add(ctrl);
                    }
                }
                catch (Exception ex)
                {
                    MessageBox.Show("ControlArray Add Exception.\n" + ex.Message);
                }
                int count = this.List.Count;
                return count;
            }
            /// <summary>
            /// 指定名称のコントロールオブジェクト取得
            /// </summary>
            /// <param name="prefix">コントロールの名称先頭</param>
            /// <param name="number">名称に付加する番号</param>
            /// <returns>名称先頭と番号に一致する名称のコントロールオブジェクトを戻す</returns>
            private Control GetContorol(string prefix, int number)
            {
                // リフレクションを使用してメタデータを取得し名称でコントロールオブジェクトを取得
                string fieldname = $"{prefix}{number}";
                // 親フォームからタイプを取得
                Type type = this.HostForm.GetType();
                // 指定名称のフィールド情報取得
                FieldInfo fieldInfo =
                type.GetField(fieldname,
                        BindingFlags.Public |
                        BindingFlags.NonPublic |
                        BindingFlags.Instance |
                        BindingFlags.DeclaredOnly);
                if (fieldInfo == null)
                {
                    // 対象のコントロール無し
                    return null;
                }
                Control ctrl = (Control)fieldInfo.GetValue(this.HostForm);
                // フィールド情報からコントロール取得
                return ctrl;
            }
        }
    }
  2. テキストボック用配列化クラス。
    このTextBoxArrayを元にButtonArray、CheckBoxArray、LabelArrayなどを作成する。
    using System.Windows.Forms;
    namespace Test.Name.Space.Common
    {
        /// <summary>
        /// テキストボックスを配列として使用するためのクラス
        /// </summary>
        public class TextBoxArray : ControlArray
        {
            /// <summary>
            /// コンストラクタ
            /// </summary>
            /// <param name="form">親フォーム</param>
            public TextBoxArray(Form form) : base(form)
            {
            }
            /// <summary>
            /// コンストラクタ

            /// </summary>
            /// <param name="form">親フォーム</param>
            /// <param name="prefix">コントロール名称先頭</param>
            /// <param name="startIndex">開始番号</param>
            /// <param name="endIndex">終了番号</param>
            public TextBoxArray(Form form, string prefix, int startIndex, int endIndex)
                : base(form, prefix, startIndex, endIndex)
            {
            }
            /// <summary>
            /// 格納されたテキストボックスの指定配列番号での取得
            /// </summary>
            /// <param name="index">配列番号</param>
            /// <returns>配列番号指定でテキストボックスオブジェクトを戻す。</returns>
            public new TextBox this[int index]{
                get {
                    return (TextBox)base[index];
                }
            }
        }
    }
  3. Arrayクラスの使用方法。
    こんな感じで使用できます。
    private TextBoxArray textBoxArray;
    // TextBoxのName先頭が"textBox"のTextBoxコントロールtextBoxArrayに格納します
    this.textBoxArray = new TextBoxArray(this, "textBox", 0, 3);
    // textBoxArrayを全て非表示にする
    for (var index=0; index < this.textBox.Max; ++index)
    {
        this.textBoxArray[index].Visible = true;
    }
後は好みで変数名を変更する

イベント定義などでは、

private void lblSelect_Click(System.Object eventSender, System.EventArgs eventArgs)

となっていますが、VSで作成した場合は

private void lblSelect_Click(object sender, EventArgs e)

となるので、置き換えて変更するなどしてください。

変更すると、イベント内で使用している変数名もそれぞれ、sender、e に変更する必要があります。

ここまででVB6から.Net C#への移行はほぼ完了です。

VB6でDLLを使用して配列データ取得時の注意点

VB6でDLLなどを使用してデータを配列で受け取っている場合は注意が必要です。

VB6の配列は行列ではなく「列行」になっているのでDLL側を変更するか、C#側でDLLよりデータを受け取った後に行列に変換する処理が必要になります。

参考として、そのまま使用する場合は以下のような方法でも可能です。