VB6で別のVB6プログラムのSliderを操作したい

タグの編集
投稿者 ひでぽん  (社会人) 投稿日時 2021/2/5 18:51:31
VB6で作成されているプログラム、FormA.exeとFormB.exeがあります。
FormA.exeのSlider(スライダーバー)をFormB.exeから操作したいのです。

試しにFormA.exeにCommandボタンを配置してFormB.exeから操作してみたのですがそれはクリックできました。
ただSlider(スライダーバー)を操作する際のSendMessageの引数の2番目と3番目がよくわからなくて困っています。ご存じの方ご教示ください。

以降にテストサンプルを記述します。

--FormA.exe--
'フォームのキャプション=FomrA
'Slider1とCommand1を1配置

'※Slider1バーが移動するので操作が確認できるので
'※Command1のみ操作されたことがわかるようにメッセージを表示

Private Sub Command1_Click()
    MsgBox "操作されました"
End Sub


--FormB.exe--
'フォームのキャプション=FomrB
'Command1とCommand2を1配置
'※Command1でFomrAのCommand1を操作
'※Command2でFomrAのSlider1を操作

Option Explicit

Private Declare Function FindWindow Lib "user32" Alias "FindWindowA" (ByVal lpClassName As String, ByVal lpWindowName As String) As Long
Private Declare Function SendMessage Lib "user32" Alias "SendMessageA" (ByVal hwnd As Long, ByVal wMsg As Long, ByVal wParam As Long, lParam As Any) As Long

Private Declare Function FindWindowEx Lib "user32" Alias "FindWindowExA" (ByVal hWnd1 As Long, ByVal hWnd2 As Long, ByVal lpsz1 As String, ByVal lpsz2 As String) As Long

Private Const WM_COMMAND = &H111
Private Const BN_CLICKED = &H0&
Private Const WM_CLOSE As Long = &H10

'FormA.exeのボタン(Command1)を操作
Private Sub Command1_Click()
    Dim lngWindWnd As Long
    Dim lngBtnWnd1 As Long
  
    lngWindWnd = FindWindow(vbNullString, "FormA")
    lngBtnWnd1 = FindWindowEx(lngWindWnd, 0, "ThunderRT6CommandButton", vbNullString)
    Call SendMessage(lngWindWnd, WM_COMMAND, BN_CLICKED, ByVal lngBtnWnd1)

End Sub


'FormA.exeのSlider1を操作
Private Sub Command2_Click()
    Dim lngWindWnd As Long
    Dim lngBtnWnd1 As Long
  
    lngWindWnd = FindWindow(vbNullString, "FormA")
    lngBtnWnd1 = FindWindowEx(lngWindWnd, 0, "Slider20WndClass", vbNullString)
    Call SendMessage(lngWindWnd, ????, ????, ByVal lngBtnWnd1)
  '※引数の2番目と3番目の設定値がよくわかりません。
End Sub



投稿者 るきお  (社会人) 投稿日時 2021/2/5 20:27:31
直接の回答ではありません。

Spy++ というツールを使うとウィンドウが受け取っているメッセージを傍受できます。
Spy++ を仕掛けてからスライダーを操作することで、メッセージとパラメーターがわかるかもしれません。

Spy++ はVisual Studio に付属しています。

このサイトでの場所の説明がわかりやすかったです。
https://buralog.jp/visual-studio-2019-spyxx-path/

Spy++ のメッセージビュー
https://docs.microsoft.com/ja-jp/visualstudio/debugger/messages-view?view=vs-2019

ただ、これを素の状態で仕掛けるとものすごい大量のメッセージが次々と表示されるので、目的のメッセージを探すのは大変です…。
投稿者 魔界の仮面弁士  (社会人) 投稿日時 2021/2/6 12:27:06
> SendMessageの引数の2番目と3番目がよくわからなくて困っています。

TBM_SETPOS メッセージ (&H405&) ですね。
WPARAM には ByVal 1& (再描画する) を渡し、
LPARAM を スライダー値を表す Long 値にします。


> FormA.exeのSlider(スライダーバー)をFormB.exeから操作したいのです。

FormA と FormB が共に自作なら、プロセス間通信のために
DDE を使うという選択肢もあります。

以下サンプル。On Error 処理は省いています。

=== FormA.exe ===
プロジェクト名 = "ProjectA"
メインフォーム … Name や Caption は任意
  LinkMode: 1 - ソース
  LinkTopic: "HideponForm"
TextBox コントロール … Visible は True でも False でも良い
  Name: SliderLinkText

Private Sub SliderLinkText_Change()
    Slider1.Value = CLng(SliderLabelText.Text)
End Sub


=== FormB.exe ===
Private Sub Form_Load()
    TextBox1.Text = "5"    'Slider に渡したい値 
    Text1.LinkTopic = "ProjectA|HideponForm"
    Text1.LinkItem = "SliderLinkText"
End Sub
Private Sub Command1_Click()
    '現在の Text1.Text の値を FormA.exe に送り込む 
    Text1.LinkMode = vbLinkManual
    Text1.LinkPoke
    Text1.LinkMode = vbLinkNone
End Sub
投稿者 魔界の仮面弁士  (社会人) 投稿日時 2021/2/7 10:46:13
> Slider1.Value = CLng(SliderLabelText.Text)
SliderLabelText じゃなくて
SliderLinkText でした…。

まあ SendMessage を使って組んであるものを
今更 DDE に置き換える必要もないですし、蛇足でしたね。


> TBM_SETPOS メッセージ (&H405&) ですね。
参考までに、その他のメッセージも紹介しておきます。
https://docs.microsoft.com/en-us/windows/win32/controls/bumper-trackbar-control-reference-messages


> FindWindowEx(lngWindWnd, 0, "Slider20WndClass", vbNullString)
これは MSCOMCTL.OCX の方の Slider ですね。
SliderWndClass          - Microsoft Windows Common Controls 5.0   [COMCTL32.OCX] (Slider)
Slider20WndClass        - Microsoft Windows Common Controls 6.0   [MSCOMCTL.OCX] (Slider)

http://www.thevbzone.com/modControls.bas
投稿者 ひでぽん  (社会人) 投稿日時 2021/2/10 10:04:10
るきおさん
spy++は試してみてメッセージが受信できる事はわかったのですがその後が勉強不足でわからなかったのです。回答ありがとうございました。
投稿者 ひでぽん  (社会人) 投稿日時 2021/2/10 10:27:57
魔界の仮面弁士さま

回答ありがとうございます。
>FormA と FormB が共に自作なら、プロセス間通信のために
>DDE を使うという選択肢もあります。
DDEについては共に変更可能なので試してみようと思います。

後SendMessageの方もご教示頂きました方法で動作確認できました。これでとりあえず行けそうです。
ご教示ありがとうございました。
以下に修正したソースのせておきます。

Private Const TBM_SETPOS As Long = &H405&

'FormA.exeのSlider1を操作
Private Sub Command2_Click()
    Dim lngWindWnd As Long
    Dim lngBtnWnd1 As Long
  
    lngWindWnd = FindWindow(vbNullString, "FormA")
    lngBtnWnd1 = FindWindowEx(lngWindWnd, 0, "Slider20WndClass", vbNullString)
    Call SendMessage(lngBtnWnd1, TBM_SETPOS, 1&, ByVal 5)
End Sub

解決しましたのでこれで完了とさせて頂きます。

投稿者 魔界の仮面弁士  (社会人) 投稿日時 2021/2/10 11:15:52
> Call SendMessage(lngBtnWnd1, TBM_SETPOS, 1&, ByVal 5)

今回は、API 宣言を ByRef lParam As Any にしているようなので、
実際には ByVal 5 ではなく、ByVal 5& と記述するべきですね。
(実際には固定値ではなく、Long 型変数を指定されるのだと思いますが)

WPARAM 型 … Win16 では 16bit長、Win32 では 32bit長、Win64 では 64bit長
LPARAM 型 … Win16 では 32bit長、Win32 では 32bit長、Win64 では 64bit長
投稿者 ひでぽん  (社会人) 投稿日時 2021/2/10 12:34:30
魔界の仮面弁士様
>WPARAM 型 … Win16 では 16bit長、Win32 では 32bit長、Win64 では 64bit長
>LPARAM 型 … Win16 では 32bit長、Win32 では 32bit長、Win64 では 64bit長
ご指摘ありがとうございます。修正しておきます。

それとご教示頂きましたDDEリンクも試してみたました。
こちらもうまくいきました。色々とありがとうございました。