VB6 ActiveXDLL/EXEとVBS

タグの編集
投稿者 ふっこ  (社会人) 投稿日時 2019/7/9 15:53:24
はじめまして、ふっこと申します。

とあるエディタのマクロプログラムを作成しています。
マクロはVBSで記述します。
「使用したファイルの履歴(textfile)」からファイル名を選択する必要があり、
ListBoxかComboBoxを使えると嬉しいのですが、VBSではそのような入力方法を
サポートしていないようです。
現状では不便ですが、InputBoxのPromptに履歴を読み込んで、
数値入力(行番号)にて対応しています。

そこで、昔使っていたVB6でActiveXDLL/EXEを作成しようと思ったのですが、
「InputBoxのようにOKボタンをクリックすると値をVBS側に返す」方法がわからず、
行き詰っています。

例えば、ActiveXEXEにてListBoxとOKボタンを持つフォーム frmHist を作成し、
ListBox内で選択した値をval、OKボタンをcmdOK、
クラスモジュール clsHist に Property Get GetVal() as Variant を設定したとして、
どのように書けばOKボタンで値val を返せるようになるのでしょうか?

古い話題で申し訳ありませんが、どうぞよろしくお願いいたします。

投稿者 魔界の仮面弁士  (社会人) 投稿日時 2019/7/9 17:38:06
> ListBoxかComboBoxを使えると嬉しいのですが、
> VBSではそのような入力方法をサポートしていないようです。

*.html や *.hta を使うという手も。


下記の内容を "test.hta" というファイル名で保存し、ダブルクリックで起動してみてください。

<?xml version="1.0" encoding="Shift_JIS"?>
<html
 xmlns="http://www.w3.org/1999/xhtml"
 xmlns:HTA="urn:schemas-microsoft-com:hta"
 xml:lang="ja" lang="ja">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=Shift_JIS" />
<meta http-equiv="Content-Script-Type" content="text/VBScript" />
<meta http-equiv="Content-Style-Type" content="text/css" />
<title>さんぷる</title>
<style>
body
{
  overflow: auto;
  background-color: ThreeDFace;
  color: WindowText;
  margin: 12px;
  padding: 0px;
  font: 100% "MS UI Gothic", Serif;
  border-style: None;
  text-align: left;
  cursor: default;
}
</style>
<HTA:APPLICATION
 APPLICATIONNAME="てきとー"
 BORDER="dialog"
 BORDERSTYLE="normal"
 CAPTION="yes"
 CONTEXTMENU="no"
 ID="HTA"
 INNERBORDER="no"
 MAXIMIZEBUTTON="no"
 MINIMIZEBUTTON="yes"
 NAVIGABLE="no"
 SCROLL="no"
 SCROLLFLAT="yes"
 SELECTION="no"
 SHOWINTASKBAR="yes"
 SINGLEINSTANCE="yes"
 SYSMENU="yes"
 VERSION="1.0"
 WINDOWSTATE="normal" />
<script type="text/VBScript">
'<![CDTA[ 
Option Explicit

Sub Initialize()
  window.resizeTo 260, 400
  Set cmbBlood.onchange = GetRef("Foo")
  Set lstHoroscope.onchange = GetRef("Foo")
  Call Foo()
End Sub

Sub Foo()
  'MsgBox "変更されたね?", vbInformation 

  If cmbBlood.selectedIndex = -1 Then
    valBloodSimple.innerText = ""
    txtBloodSimple.innerText = "(未選択)"
  Else
    valBloodSimple.innerText = cmbBlood.value
    txtBloodSimple.innerText = cmbBlood.options(cmbBlood.selectedIndex).text
  End If

  If lstHoroscope.selectedIndex = -1 Then
    valContentsMulti.innerText = ""
    txtContentsMulti.innerText = "(未選択)"
  Else
    Dim s1, s2
    s1 = ""
    s2 = ""
    Dim opt
    For Each opt In lstHoroscope.options
      If opt.selected Then
        s1 = s1 & "," & opt.value
        s2 = s2 & "," & opt.text
      End If
    Next
    valContentsMulti.innerText = Mid(s1, 2)
    txtContentsMulti.innerText = Mid(s2, 2)
  End If
End Sub

Set window.onload = GetRef("Initialize")

']]> 
</script>

</head>
<body>

<p>血液型:
<select id="cmbBlood">
<option value="A">A型</option>
<option value="B" selected="selected">B型</option>
<option value="O">O型</option>
<option value="AB">AB型</option>
</select></p>

<p>星座:<br />
<select name="lstHoroscope" size="8" multiple="multiple">
<option value="Aries">おひつじ座</option>
<option value="Taurus">おうし座</option>
<option value="Gemini">ふたご座</option>
<option value="Cancer">かに座</option>
<option value="Leo">しし座</option>
<option value="Virgo" selected="selected">おとめ座</option>
<option value="Libra" selected="selected">てんびん座</option>
<option value="Scorpio">さそり座</option>
<option value="Saggitarius">いて座</option>
<option value="Capricorn">やぎ座</option>
<option value="Aquarius">みずがめ座</option>
<option value="Pisces">うお座</option>
</select></p>

<hr/>

<div id="valBloodSimple" style="color:red"></div>
<div id="txtBloodSimple" style="color:blue"></div>
<hr/>
<div id="valContentsMulti" style="color:red"></div>
<div id="txtContentsMulti" style="color:blue"></div>

</body>
</html>
投稿者 ふっこ  (社会人) 投稿日時 2019/7/9 19:04:49
魔界の仮面弁士様、早速のご回答ありがとうございます。

MSHTAを用いた手法試してみました。
しかし、当方、これを使ったことといえば、「クリップボードから標準出力への吐き出し」、
くらいなので、どうやって選択した値を取り出していいか見当もつきません。
また、ファイルの使用履歴は、現状テキストファイルに保存されており、
常に更新されていきますので、このHTAファイルを使用するのであれば
(option value項目)を更新することになり、より複雑なファイル操作になりそうです。

すみません、勉強不足で見当違いのことを言っているかもしれません。

もしお時間があれば当方のHPを見ていただけないでしょうか?

http://mfi.sub.jp/_html_awk/gawk_sakura.html

この中で、InputBoxをActiveX(できればVB6で)に置き換えたいと思っているのです。

もしかして、VB6ではできないことだったのでしょうか?








投稿者 魔界の仮面弁士  (社会人) 投稿日時 2019/7/9 19:51:53
> クラスモジュール clsHist に Property Get GetVal() as Variant を設定したとして、

プロパティなのに「GetVal」という命名に違和感が…。

プロパティは 名詞 もしくは 形容詞、
メソッドは 動詞 あるいは 動詞句 とするのが一般的なので、
「Property Get Value()」とか「Function GetValue()」の方が良いかも。


とりあえずモーダルダイアログとしての実装例。

もし、メソッドの戻り値として結果を返すのではなく、
非同期通知イベントで提供したい場合には、
VB6 付属の Coffee2.vbp サンプルプロジェクトを参考にしてみてください。


🟪VBScript🟪
' Example.vbs 
Option Explicit
MsgBox "選択画面を表示", vbInformation Or vbSystemModal

Dim indexArray
indexArray = CreateObject("ExampleProject.clsHist").ShowDialog

Dim cnt, idx, s
cnt = UBound(indexArray) - LBound(indexArray) + 1
s = "選択されたアイテムの総数:" & CStr(cnt)
For Each idx In indexArray
  s = s & vbCrLf & "Index=" & CStr(idx)
Next
MsgBox s, vbInformation Or vbSystemModal, "列挙終了"


🔹Visual Basic 6.0🔹
' clsHist.cls 
Option Explicit

Public Function ShowDialog() As Variant
    Dim dlg As frmHist
    Set dlg = New frmHist
    Load dlg
    dlg.Show vbModal
    ShowDialog = dlg.SelectedIndices
    Set dlg = Nothing
End Function


'frmHist.frm 
Option Explicit
Option Base 0
Private m_selectedIndices() As Variant
Friend Property Get SelectedIndices() As Variant()
    SelectedIndices = m_selectedIndices
End Property
Private Sub Form_Initialize()
    Set frmHist = Nothing
End Sub
Private Sub Form_Load()
    m_selectedIndices = Array()
    cmdOK.Default = True
End Sub
Private Sub cmdOK_Click()
    Dim indexArray() As Variant
    If List1.ListIndex = -1 Then
        indexArray = Array()
    Else
        ReDim indexArray(List1.SelCount - 1)
        Dim idx As Integer, n As Integer
        n = -1
        For idx = 0 To List1.ListCount - 1
            If List1.Selected(idx) Then
                n = n + 1
                indexArray(n) = idx
            End If
        Next
    End If
    Unload Me
    m_selectedIndices = indexArray
End Sub
投稿者 (削除されました)  () 投稿日時 2019/7/9 20:29:40
(削除されました)
投稿者 魔界の仮面弁士  (社会人) 投稿日時 2019/7/9 20:30:51
先の提示例では、複数選択可能な ListBox を想定しています。
また、ListBox にアイテムを初期表示したり、初期選択するコードは省略しています。


「ListBox に表示するデータ」を VB6 側で用意するのではなく、
VBScript 側で用意するのであれば、たとえばこのように書けます。

<クラス側>
' items は、VBScript 側から渡されたデータ(配列でも Dictionary でも String でもお好みで) 
'  
Public Function ShowDialog(ByVal items As VariantAs Variant
    Dim dlg As frmHist
    Set dlg = New frmHist
    dlg.Constructor items
    Load dlg
    dlg.Show vbModal
    ShowDialog = dlg.SelectedIndices
    Set dlg = Nothing
End Function


<フォーム側>
Private m_items As Variant
Private m_selectedIndices() As Variant
Friend Sub Constructor(ByVal items As Variant)
    m_items = items
End Sub
Private Sub Form_Load()
    m_selectedIndices = Array()
    cmdOK.Default = True
    Dim vnt As Variant
    For Each vnt In m_items
        List1.Items.Add vnt
    Next
End Sub



また、「選択されたアイテムのインデックス群」を返すのではなく、
選択されたアイテム(の一覧)を直接返却させるようにしたり、
あるいは Dictionary を用いて キーと値の一覧を返すように実装しても良いかと。

※ Dictionary で返す場合、VBScript 側で Set ステートメントでの受け取りが必要になります。
投稿者 (削除されました)  () 投稿日時 2019/7/9 20:49:45
(削除されました)
投稿者 ふっこ  (社会人) 投稿日時 2019/7/10 00:31:04
魔界の仮面弁士様

ありがとうございます。
VBSにて動作する「最近使ったファイル」を選択する
リストボックス/コンボボックス共に実現しました。
ここ数年悩んでいたので本当に助かりました。


Property ですが、一目でわかるように、Getには「Get~」、Letには「Let~」、Setも同様
として名前を付けておりました。
おっしゃる通りですね。これからは名詞、形容詞で名づけます。