tagCANDY CGI VBレスキュー(花ちゃん)の Visual Basic 6.0用 掲示板 [ツリー表示へ]   [Home]
一括表示(VB6.0)
タイトルEnumの項目名を変数で指定できないか。
記事No16458
投稿日: 2018/10/03(Wed) 11:20
投稿者まだまだVB6ユーザー
いつも利用させていただいています。
早速ですが、質問です。
表題にもあるように、Enumの項目名を変数で指定できないか
というものです。
例としては、
Enum TEISU
   AA
   BB
   CC
end Enum
と定数を作成して、これを

Dim KOUMOKUMEI as String

KOUMOKUMEI="BB"

MsgBox TEISU.KOUMOKUMEI

としたら、メッセージに『1』と表示されるような
ことって出来るんでしょうか?
どなたかご教授いただけると助かります。
よろしくお願いします。

[ツリー表示へ]
タイトルRe: Enumの項目名を変数で指定できないか。
記事No16459
投稿日: 2018/10/04(Thu) 16:03
投稿者魔界の仮面弁士
> 表題にもあるように、Enumの項目名を変数で指定できないか

VB6 の列挙型には、文字列でアクセスするための機構がありません。

VB6 の型システムにおいて、たとえば VbMsgBoxResult.vbAbort と VbMsgBoxStyle.vbYesNoCancel が
異なる列挙型の値であることを検知できず、ともに「Long 型の 3 の別名」として扱われてしまい、
同一視されるというのも、理由の一つです。

列挙型の型名を調べるために
 TypeName(vbYesNoCancel)
を実行した場合、VB.NET は "MsgBoxStyle" という型名を返すのですが、
VB6 や VBA は "Long" という文字列になってしまいます。


これが VB.NET であれば、MsgBoxResult.Abort と MsgBoxStyle.YesNoCancel を区別できますし、
 x = System.Enum.Parse(GetType(MsgBoxStyle), "YesNoCancel")
のようにして、文字列でアクセスすることも可能なのですけれども。



ですから VB6 の場合は、VBA.Collection か Scripting.Dictionary に
詰め替えておくことで妥協するぐらいしか手が無いと思います。

Private dictTEISU As VBA.Collection

Private Sub Form_Load()
    Set dictTEISU = New VBA.Collection
    dictTEISU.Add TEISU.AA, "AA"
    dictTEISU.Add TEISU.BB, "BB"
    dictTEISU.Add TEISU.CC, "CC"
End Sub

Private Sub Command1_Click()
    Dim KOUMOKUMEI As String
    KOUMOKUMEI = "BB"

    MsgBox dictTEISU(KOUMOKUMEI)
End Sub



ただしその列挙型が、ActiveX DLL (というかタイプライブラリ)にてレジストリ登録された、
公開された列挙型であるのなら、TypeLib Information 経由でメンバー名を抜き出す事が可能です。

具体的には、TypeLibInfoFromRegistry メソッドあるいは TypeLibInfoFromFile メソッドで
タイプライブラリの型情報を読み取り、Constants プロパティから
ConstantInfo オブジェクトのコレクションを得て、対象となる列挙型の
メンバーにアクセスするといった具合です。※要TLBINF32.DLL

列挙型以外の型にもアクセスしたいなら、Constants の代わりに TypeInfos プロパティを
用いることもできます。とりあえずこんな感じ。

Private Sub Form_Load()
    Dim filePath As String
    filePath = "C:\Program Files (x86)\Common Files\Microsoft Shared\DAO\dao360.dll"

    Dim tlbInfo As Object, typeInfo As Object, memberInfo As Object
    Set tlbInfo = CreateObject("TLI.TLIApplication").TypeLibInfoFromFile(filePath)

    For Each typeInfo In tlbInfo.TypeInfos
        If typeInfo.TypeKind = 0 Then
            Debug.Print typeInfo.Name
            For Each memberInfo In typeInfo.Members
                Debug.Print , memberInfo.Name; " ="; memberInfo.Value
            Next
        End If
    Next
End Sub


※ 相手が Enum ではなくオブジェクトであった場合は、TypeLib Information は不要です。
 オブジェクトならこんな回りくどいことをせずとも、CallByName 関数を使えば済む話なので。

[ツリー表示へ]
タイトルRe^2: Enumの項目名を変数で指定できないか。
記事No16461
投稿日: 2018/10/05(Fri) 17:00
投稿者まだまだVB6ユーザー
魔界の仮面弁士さん、返信ありがとうございます。
丁寧な解説で助かりました。
結果としては、難しそう(というか無理)ですね。
何か他の方法を探してみます。

今回、このような方法ができないか探したのは
今現在、私が携わっているプログラムで必要に
なったからでした。
そのプログラムは、ある製品の検査プログラムで
その検査項目が製品によって変動するため
その検査範囲値などを配列に格納するためEnumを
使って配列の添え字を定数で持つというプログラムを
前任者が作成していたのでそれをなんとかできないかと
思って投稿しました。

例としては、まずプログラム上で

Enum Index
   AAA
   BBB
   CCC
End Enum
と定数を作り検査結果などを
Dim Result() As Stiring

Result(AAA)=検査結果

のように使用しています。
これを今回私が前任者が退職したのを機に改修することになり
改修の方法としてEnumの記述はそのままにして
検査値をIniファイルの持つことにしました。
Iniファイルを
[Section]
AAA=検査値
BBB=検査値
CCC=検査値
と作成して

プログラムでAPI関数を使ってキー名ごとデータを取得
Idx=GetIni() ←API関数を使ってキー名ごとデータを取得する
とすれば『Idx』の中には『AAA』が入るので

kensa(Index.Idx)=検査値
としてやれば、配列の定数番目に検査値を入れらるのではないかと
思ったのです。
ですが、ちょっと無理があったようですね。
他の方法を考えようと思います。
ありがとうございました。
ただ、他の方法といっても何かいい方法があればいいのですが。

[ツリー表示へ]