【KPI】VB6.0の画面デザイン項目一覧出力機能。【C#】

VB6.0の案件で、過去から改修に改修を重ねた結果、Frameなどの項目が重なり、見た目だけではどこに何の項目が隠れてるか不明になったことがある為、C#にてVB6.0画面デザインの解読ツールを作成。備忘録の代わり。
そもそもこれが必要になる人がいるとは思いたくない。

下記、ソースコード
下記の2つを用意
1.画面のボタン機能（ボタン名btnFunction1で想定のイベント）
2.解読用のデータクラス「VBDesignInfo」

```C#:Frm1.cs
        /// <summary>
        /// 機能1ボタン Click
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void btnFunction1_Click(object sender, EventArgs e)
        {
            try
            {
                string path = @"C:\Users\hogehoge\Desktop\"; // ファイルの置き場所を記載
                string[] sourceCode;
                using (StreamReader sr = new StreamReader(path + "テキストファイル.txt", Encoding.UTF8))
                {
                    string strData = sr.ReadToEnd();
                    sourceCode = strData.Replace("\n", string.Empty).Split('\r');
                }

                List<VBDesignInfo> listVB = new List<VBDesignInfo>();
                List<int> list階層 = new List<int>();
                int i階層 = 0;
                int targetIndex = 0;

                for (int i = 0; i < sourceCode.Length; i++)
                {
                    if (CheckData(sourceCode[i], "Begin "))
                    {
                        listVB.Add(new VBDesignInfo());
                        targetIndex = listVB.Count - 1;

                        i階層++;
                        if (listVB.Count <= 1 || listVB[targetIndex - 1].階層List.Count <= i階層 - 1)
                        {
                            list階層.Add(1);
                        }
                        else
                        {
                            list階層.Add(listVB[targetIndex - 1].階層List[i階層 - 1] + 1);
                        }

                        // クラス名、項目名を取得
                        string[] sourceWords = sourceCode[i].Trim().Substring(6).Split(' ');
                        listVB[targetIndex].SetData(VBDesignInfo.項目一覧.階層, i階層.ToString());
                        for (int j = 0; j < list階層.Count; j++)
                        {
                            listVB[targetIndex].階層List.Add(int.Parse(list階層[j].ToString()));
                        }
                        listVB[targetIndex].SetData(VBDesignInfo.項目一覧.ClassName, sourceWords[0]);
                        listVB[targetIndex].SetData(VBDesignInfo.項目一覧.Name, sourceWords[1]);

                        continue;
                    }

                    // 終了時
                    if (sourceCode[i].Trim().Equals("End"))
                    {
                        i階層--;
                        list階層.RemoveAt(list階層.Count - 1);
                        if (list階層.Count > 0)
                        {
                            targetIndex = listVB.IndexOf(listVB.Where(a => CheckEqualsIntList(a.階層List, list階層)).ToList()[0]);
                        }

                        continue;
                    }

                    // 階層なし=データ無し
                    if (list階層.Count <= 0)
                    {
                        continue;
                    }

                    // 対象行の前後の空白と2つ以上続く空白を全て削除し、1つの空白しか残らないようにする
                    string sourceWord = sourceCode[i].Trim();
                    while (true)
                    {
                        if (sourceWord.Replace("  ", " ").Equals(sourceWord))
                        {
                            break;
                        }
                        sourceWord = sourceWord.Replace("  ", " ");
                    }

                    // TabIndexの取得
                    if (CheckData(sourceWord, "TabIndex ="))
                    {
                        listVB[targetIndex].SetData(VBDesignInfo.項目一覧.TabIndex, sourceWord.Substring(11));
                    }

                    // Indexの取得
                    if (CheckData(sourceWord, "Index ="))
                    {
                        listVB[targetIndex].SetData(VBDesignInfo.項目一覧.Index, sourceWord.Substring(8));
                    }

                    // Tagの取得
                    if (CheckData(sourceWord, "Tag ="))
                    {
                        listVB[targetIndex].SetData(VBDesignInfo.項目一覧.Tag, sourceWord.Substring(6));
                    }

                    // Topの取得
                    if (CheckData(sourceWord, "Top ="))
                    {
                        listVB[targetIndex].SetData(VBDesignInfo.項目一覧.Top, sourceWord.Substring(6));
                    }
                }

                // ファイル出力
                DateTime dtNow = DateTime.Now;
                string filePath = path + "テキストファイル_" + dtNow.ToString("yyyyMMdd_HHmmss") + ".csv";

                string titleText
                    = "Name" + ","
                    + "ClassName" + ","
                    + "階層リスト" + ","
                    + "階層" + ","
                    + "TabIndex" + ","
                    + "Index" + ","
                    + "Tag" + ","
                    + "Top";
                File.AppendAllText(filePath, titleText + Environment.NewLine);

                for (int i = 0; i < listVB.Count; i++)
                {
                    string kaisou = string.Empty;
                    for (int j = 0; j < listVB[i].階層List.Count; j++)
                    {
                        if (!j.Equals(0))
                        {
                            kaisou += "-";
                        }
                        kaisou += listVB[i].階層List[j];
                    }

                    string appendText = string.Empty;
                    appendText
                        = listVB[i].Name + ","
                        + listVB[i].ClassName + ","
                        + kaisou + ","
                        + listVB[i].階層 + ","
                        + listVB[i].TabIndex + ","
                        + listVB[i].Index + ","
                        + listVB[i].Tag + ","
                        + listVB[i].Top;
                    File.AppendAllText(filePath, appendText + Environment.NewLine);
                }

                MessageBox.Show("やったで");
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message);
            }
        }

        private bool CheckData(string sourceCode, string targetWord)
        {
            int codeLength = targetWord.Length;
            return (sourceCode.Trim().Length > codeLength && sourceCode.Trim().Substring(0, codeLength).Equals(targetWord));
        }

        private bool CheckEqualsIntList(List<int> list1, List<int> list2)
        {
            // どちらかがNULLの場合
            if (list1 == null || list2 == null)
            {
                return false;
            }

            // 件数が不一致の場合
            if (!list1.Count.Equals(list2.Count))
            {
                return false;
            }

            // 値が不一致の場合
            for (int i = 0; i < list1.Count; i++)
            {
                if (!list1[i].Equals(list2[i]))
                {
                    return false;
                }
            }

            return true;
        }
```


```C#:VBDesignInfo.cs
using System;
using System.Collections.Generic;
using System.Windows.Forms;

namespace Form
{
    /// <summary>
    /// VBデザイン情報
    /// </summary>
    public class VBDesignInfo
    {
        /// <summary>
        /// 項目一覧
        /// </summary>
        public enum 項目一覧
        {
            階層 = 0,
            Name,
            ClassName,
            TabIndex,
            Index,
            Tag,
            Top,
            VBSourceList
        }

        /// <summary>
        /// 階層
        /// </summary>
        public int 階層 { get; set; }

        /// <summary>
        /// 階層リスト
        /// </summary>
        public List<int> 階層List { get; set; }

        /// <summary>
        /// 項目名
        /// </summary>
        public string Name { get; set; }

        /// <summary>
        /// クラス名
        /// </summary>
        public string ClassName { get; set; }

        /// <summary>
        /// TabIndex
        /// 無ければ-1（デフォルト）
        /// </summary>
        public int TabIndex { get; set; }

        /// <summary>
        /// Index（VB配列）
        /// 無ければ-1（デフォルト）
        /// </summary>
        public int Index { get; set; }

        /// <summary>
        /// Tag
        /// </summary>
        public string Tag { get; set; }

        /// <summary>
        /// Top
        /// </summary>
        public int Top { get; set; }

        /// <summary>
        /// コンストラクタ
        /// </summary>
        public VBDesignInfo()
        {
            this.階層List = new List<int>();
            this.TabIndex = -1;
            this.Index = -1;
        }

        public void SetData(項目一覧 k一覧, string val)
        {
            try
            {
                switch(k一覧)
                {
                    case 項目一覧.階層:
                        this.階層 = int.Parse(val.Trim());
                        break;
                    case 項目一覧.Name:
                        this.Name = val.Trim();
                        break;
                    case 項目一覧.ClassName:
                        this.ClassName = val.Trim();
                        break;
                    case 項目一覧.TabIndex:
                        this.TabIndex = int.Parse(val.Trim());
                        break;
                    case 項目一覧.Index:
                        this.Index = int.Parse(val.Trim());
                        break;
                    case 項目一覧.Top:
                        this.Top = int.Parse(val.Trim());
                        break;
                    case 項目一覧.Tag:
                        this.Tag = val.Trim();
                        break;
                }
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message);
            }
        }
    }
}
```

手順としては、1つ目のソースに、変数pathにテキストファイルとそれを出力するフォルダのパス「C:\Users\hogehoge\Desktop\」を設定。（変数の値を変更）
確認したいVB6.0画面のfrmファイルの値を取得。txtとか何かで開き、中身を「テキストボックス.txt」名称で該当パスに保存。
機能を実行すると、csvファイルが作成される。Nameやtag、位置のプロパティの値の他、「階層リスト」「階層」の項目も出力されている。
これでCSVに、画面項目の一覧が作成される。

「階層リスト」は、項目がFrameに入っている場合、該当Frameの階層リストが「1-2」となる場合、Frame内の項目を「1-2-1」「1-2-2」と順番に設定していく。
「階層」は、上記の場合、Frameの階層が「2」、Frame内の項目の階層が「3」となる。さらにFrameが中にある場合、その中の項目の階層は「4」となる。