質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

ただいまの
回答率

90.35%

  • VB.NET

    1124questions

    Microsoft Visual Basic .NETのことで、Microsoft Visual Basic(VB6)の後継。 .NET環境向けのプログラムを開発することができます。 現在のVB.NETでは、.NET Frameworkを利用して開発を行うことが可能です。

  • VB

    358questions

    VB(ビジュアルベーシック)はマイクロソフトによってつくられたオブジェクト指向プログラミング言語のひとつで、同社のQuickBASICが拡張されたものです。VB6の進化版といわれています。

  • Visual Studio 2013

    321questions

    Microsoft Visual Studio 2013は、Microsoftによる統合開発環境(IDE)であり、多種多様なプログラミング言語に対応しています。 Visual Studio 2012の次のバージョンです

VBでTCM_SETCURSELのSendMessage処理と、その後のBM_CLICK操作が正常に動作しない

解決済

回答 1

投稿

  • 評価
  • クリップ 1
  • VIEW 1,827

ot2os

score 19

自動でプリンターの[印刷設定]を呼び出し、[ノズルチェックパターン印刷]を実施するプログラムをVBで制作したいと思います。
途中、SendMessageでTCM_SETCURSELを投げた際、「印刷設定」ダイアログ内の選択タブは切り替わりますが、タブ内の描画が切り替わりません。(下記コード●02部分)
下記スクリーンショットの通り、「ユーティリティ」タブが選ばれていますが、表示されいる中身は「基本設定」タブのものになっています。
イメージ説明
ちなみに、このまま続けて手動で別タブに切り替えると、タブ内の表示が空白状態になり、画面下部の[OK]や[キャンセル]のボタンが残ります。

また、該当コードの●02部分をコメントアウトし、一旦処理を止めてから手動でタブを切り替え、その後の●03部分を実行しても「ノズルチェックパターン印刷」のウィンドウが出てきません。
●02、●03を両方コメントアウトし、手動で「ノズルチェックパターン印刷」ウィンドウを出すと、その後の処理は●04~●07まですべて正常に動きます。

そのため、タブを含むウィンドウの操作が何かうまくいっていない気がしますが、原因と対処法がわかりません。

Public Class Form1

    'FindWindow関数(Unicode実行)
    Declare Unicode Function FindWindow Lib "user32.dll" Alias "FindWindowW" _
    (ByVal lpClassName As String, ByVal lpWindowName As String) As Integer
    '<DllImport("user32.dll", CharSet:=CharSet.Unicode)>
    'Private Shared Function FindWindow(ByVal lpClassName As String, ByVal lpWindowName As String) As Integer
    'End Function

    Declare Function FindWindowEx Lib "user32.dll" Alias "FindWindowExA" _
    (ByVal hwndParent As Integer, ByVal hwndChildAfter As Integer, _
    ByVal lpszClass As String, ByVal lpszWindow As String) As Integer


    'SendMessage用
    Declare Function SendMessage Lib "user32.dll" Alias "SendMessageA" _
    (ByVal hWnd As Integer, ByVal MSG As Integer, _
    ByVal wParam As Integer, ByVal lParam As Integer) As Integer

    'PostMessage用
    Declare Function PostMessage Lib "user32" Alias "PostMessageA" _
    (ByVal hWnd As Long, ByVal wMsg As Long, ByVal wParam As Long, ByVal lParam As Long) As Long

    Public Const BM_CLICK = &HF5
    Public Const TCM_SETCURSEL = &H130C
    Public Const TCM_GETITEMCOUNT = &H1304


    Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
        Dim Printer_Name As String = "【ダミー】Canon Inkjet MP630 series"

        'Processオブジェクトを作成
        Dim p As New System.Diagnostics.Process()


        'ComSpec(cmd.exe)のパスを取得して、FileNameプロパティに指定
        p.StartInfo.FileName = System.Environment.GetEnvironmentVariable("ComSpec")

        'ウィンドウを表示しないようにする
        p.StartInfo.CreateNoWindow = True
        'コマンドラインを指定("/c"は実行後閉じるために必要)
        p.StartInfo.Arguments = "/c start rundll32 printui.dll, PrintUIEntry /e /n """ & Printer_Name & """"

        '●01起動
        p.Start()

        'プロセス終了まで待機する
        'WaitForExitはReadToEndの後である必要がある
        '(親プロセス、子プロセスでブロック防止のため)
        p.WaitForExit()
        p.Close()


        'Text: 【ダミー】Canon Inkjet MP630 series 印刷設定
        Dim hwnd1 As Integer, hwnd2 As Integer
        Dim Result As String

        '印刷設定ウィンドウのIDとタブバーのIDを取得
        hwnd1 = FW("#32770", Printer_Name & " 印刷設定")
        hwnd2 = FWex(hwnd1, 0, "SysTabControl32", "")


        'タブ数カウント
        Debug.Print("タブ数:" & SendMessage(hwnd2, TCM_GETITEMCOUNT, 0, 0))

        '●02「ユーティリティ」タブへの切り替え
        Result = SendMessage(hwnd2, TCM_SETCURSEL, 3, 0)
        Debug.Print("タブ切り替え前:" & Result)


        '●03「ノズルチェックパターン印刷」ボタンクリック
        hwnd2 = FWex(hwnd1, 0, "Button", "ノズルチェックパターン印刷")
        'hwnd3 = FWex(hwnd1, 0, "Button", "ノズルチェックパターン印刷")
        SendMessage(hwnd2, BM_CLICK, 1, 0)


        '●04「ノズルチェックパターン印刷」ウィンドウで「カセット」をクリック
        hwnd1 = FW("#32770", "ノズルチェックパターン印刷")
        hwnd2 = FWex(hwnd1, 0, "Button", "カセット(&C)")
        SendMessage(hwnd2, BM_CLICK, 1, 0)
        '●05「確認パターン印刷」をクリック
        hwnd2 = FWex(hwnd1, 0, "Button", "確認パターン印刷(&P)")
        SendMessage(hwnd2, BM_CLICK, 1, 0)

        '●06印刷完了後、「パターンの確認」ウィンドウの「終了」ボタンをクリック
        hwnd1 = FW("#32770", "パターンの確認")
        hwnd2 = FWex(hwnd1, 0, "Button", "終了(&X)")
        SendMessage(hwnd2, BM_CLICK, 1, 0)

        '●07最後に「OK」ボタンクリックですべて終了
        hwnd1 = FW("#32770", Printer_Name & " 印刷設定")
        hwnd2 = FWex(hwnd1, 0, "Button", "OK")
        SendMessage(hwnd2, BM_CLICK, 1, 0)

    End Sub

    Private Function FW(ByVal Class_Name As String, ByVal Window_Name As String)
        Dim hwnd As Integer = 0
        Do Until hwnd > 0
            'Debug.Print("Window_Name:" & Window_Name)
            hwnd = FindWindow(Class_Name, Window_Name)
            System.Threading.Thread.Sleep(200)     '念のため0.2秒停止
            My.Application.DoEvents() '描画フリーズ防止
        Loop
        FW = hwnd
        Debug.Print(Window_Name & ":" & hwnd)
    End Function

    Private Function FWex(ByVal hwnd1 As Integer, ByVal Arg As Integer, ByVal Class_Name As String, ByVal Obj_Name As String)
        Dim hwnd2 As Integer = 0
        Do Until hwnd2 > 0
            hwnd2 = FindWindowEx(hwnd1, 0, Class_Name, Obj_Name)
            System.Threading.Thread.Sleep(200)     '念のため0.2秒停止
            My.Application.DoEvents() '描画フリーズ防止
        Loop
        FWex = hwnd2
        Debug.Print(Obj_Name & "、" & Class_Name & ":" & hwnd2)
    End Function

End Class

Immediate Windowの結果は下記のとおりです。

【ダミー】Canon Inkjet MP630 series 印刷設定:853970
、SysTabControl32:591850
タブ数:4
タブ切り替え前:0

下記資料を見る限り、TCM_SETCURSELの戻り値が0なので、上記の結果を見るとここまでは正常に進んでいるはずなのかなと思っております。
https://msdn.microsoft.com/ja-jp/library/windows/desktop/bb760612(v=vs.85).aspx

タブ切り替えを正常に成功させる方法と、その後のタブ内の「ノズルチェックパターン印刷」ボタンの操作を成功させる方法をお願いいたします。

開発環境:
OS:Windows10x86 1703
Visual Studio 2013

  • 気になる質問をクリップする

    クリップした質問は、後からいつでもマイページで確認できます。

    またクリップした質問に回答があった際、通知やメールを受け取ることができます。

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

回答 1

checkベストアンサー

+1

同じような事をVBAでやろうとしていました。
Result = SendMessage(hwnd2, TCM_SETCURSEL, 3, 0)

Private Const TCM_FIRST As Int32 = &H1300
Private Const TCM_SETCURFOCUS As UInt32 = (TCM_FIRST + 48)
Result = SendMessage(hwnd2, TCM_SETCURFOCUS, 3, 0)
でいかがでしょうか?

TCM_SETCURSELのリファレンスに以下の記載があるので、更新通知が飛んでないのが原因ではないでしょうか?
A tab control does not send a TCN_SELCHANGING or TCN_SELCHANGE notification code when a tab is selected using this message. 

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2017/08/17 18:05

    BM_CLICKのアドバイスありがとうございます。

    ●03に関して、ご指摘通り、hwnd2が取得できていないため、先に進めていない状態です。

    ちなみに、Spy++で見た結果、それぞれの親子関係は「デスクトップ」直下から、下記のように表示されています。
    「`【ダミー】Canon Inkjet MP630 series 印刷設定`#32770 (ダイアログ)」
     └「`ユーティリティ`#32770 (ダイアログ)」
      └「`ノズルチェックパターン印刷`Button」

    InputBoxコマンドにて「ノズルチェックパターン印刷」のウィンドウハンドル(Spy++で調査)をhwnd2に代入すれば「ノズルチェックパターン印刷」のボタンクリックまでは動作したので、やはりウィンドウハンドルが正常に取得できていないのが問題の様子です。

    ただし、これを行うと、なぜかその後の●04以降でウィンドウハンドルが取得できず先に進めなくなります。
    手作業で「ノズルチェックパターン印刷」ボタンを押下した場合は、●04以降からすべて正常に動作します。

    ちなみに、「ノズルチェックパターン印刷」ダイアログウィンドウは、Spy++で見た結果は「デスクトップ」直下に存在します。
    「`ノズルチェックパターン印刷`#32770 (ダイアログ)」

    キャンセル

  • 2017/08/17 21:57

    Syp++の階層から
    '●03「ノズルチェックパターン印刷」ボタンクリック
    hwnd1_1 = FWex( hwnd1, 0, "#32770", "ユーティリティ" )
    hwnd2 = FWex( hwnd1_1, 0, "Button", "ノズルチェックパターン印刷" )
    PostMessage( hwnd2, BM_CLICK, 0, 0 )
    でいかがでしょうか。
    後、ボタン押した後に次のウィンドウ(保存ダイヤログなど)が開く場合はPostmessageで押さないと応答待ちにで固まる事が多いです。(上部の定義はSendmessageと同じくLongじゃなくIntegerでいいと思います)
    Declare Function PostMessage Lib "user32" Alias "PostMessageA" _
    (ByVal hWnd As Integer, ByVal wMsg As Integer, ByVal wParam As Integer ByVal lParam As Integer) As Integer

    キャンセル

  • 2017/08/18 16:15

    ありがとうございます!
    FWexにて「ユーティリティ」タブから順に取得したところ、正常に動作しました。
    また、おっしゃる通り、PostMessageにて改善したところ、●04以降の動作もすべて問題なく動作しました。応答待ちで固まっていただけだったんですね。
    重ねてお礼申し上げます。

    キャンセル

15分調べてもわからないことは、teratailで質問しよう!

  • ただいまの回答率 90.35%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる

同じタグがついた質問を見る

  • VB.NET

    1124questions

    Microsoft Visual Basic .NETのことで、Microsoft Visual Basic(VB6)の後継。 .NET環境向けのプログラムを開発することができます。 現在のVB.NETでは、.NET Frameworkを利用して開発を行うことが可能です。

  • VB

    358questions

    VB(ビジュアルベーシック)はマイクロソフトによってつくられたオブジェクト指向プログラミング言語のひとつで、同社のQuickBASICが拡張されたものです。VB6の進化版といわれています。

  • Visual Studio 2013

    321questions

    Microsoft Visual Studio 2013は、Microsoftによる統合開発環境(IDE)であり、多種多様なプログラミング言語に対応しています。 Visual Studio 2012の次のバージョンです