• R/O
  • SSH
  • HTTPS

Tags
No Tags

Frequently used words (click to add to your profile)

javac++androidlinuxc#windowsobjective-ccocoa誰得qtpythonphprubygameguibathyscaphec計画中(planning stage)翻訳omegatframeworktwitterdomtestvb.netdirectxゲームエンジンbtronarduinopreviewer

テンキー押下でWin32アプリのウインドウをキャプチャする。ただしUWPアプリはキャプチャできない。


File Info

Rev. 31
Size 13,962 bytes
Time 2017-11-13 22:54:32
Author hor931101jp
Log Message

(empty log message)

Content

Imports TenKeyShot.ClassMyCommon ''ClassMyConmonのプロパティ・メソッドを参照するためのImportsステートメント
Imports TenKeyShot.ClassConfig ''ClassConfigのプロパティ・メソッドを参照するためのImportsステートメント
Imports System.Runtime.InteropServices
Imports System.Text

''' <summary>メイン(スタートアップ)フォーム</summary>
Public Class FormMain
    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
    Declare Function EnumWindows Lib "user32" (ByVal lpEnumFunc As Long, ByVal lParam As Long) As Long '可視判定
    Public Declare Function IsWindowVisible Lib "user32" (ByVal hWnd As Long) As Long 'キャプション取得
    Public Declare Function GetWindowText Lib "user32" Alias "GetWindowTextA" (ByVal hWnd As Long, ByVal lpString As String, ByVal cch As Long) As Long 'オーナーフォームを指定してハンドル取得
    Public Declare Function GetWindow Lib "user32" (ByVal hWnd As Long, ByVal wCmd As Long) As Long '定数:オーナーフォームチェック用
    Public Const GW_OWNER = 4

    Public Structure RECT
        Public Left As Integer
        Public Top As Integer
        Public Right As Integer
        Public Bottom As Integer
    End Structure
    Declare Function GetWindowRect Lib "user32" (ByVal hwnd As Integer, ByRef lpRect As RECT) As Integer

    <System.Runtime.InteropServices.DllImport("User32.dll")>
    Private Shared Function PrintWindow(ByVal hwnd As IntPtr, ByVal hDC As IntPtr, ByVal nFlags As Integer) As Boolean
    End Function

    Dim KeyboardHooker1 As New KeyboardHooker
    Shared Tcommand As String
    Public Shared CaptureProcess As Boolean = False
    Shared NowTime As Date = Now

    Private Sub FormMain_FormClosing(ByVal sender As Object, ByVal e As System.Windows.Forms.FormClosingEventArgs) Handles Me.FormClosing
        On Error Resume Next

        ''ウインドウポップアップ
        Me.Visible = True
        Me.WindowState = FormWindowState.Normal
        Me.TopMost = True

        Config.Save()

        Log.Put(TITLE + " 終了" + vbCrLf)
        Log.Save()

        AppClosingFlag = True

    End Sub

    ''' <summary>メイン(スタートアップ)フォームのロード</summary>
    ''' <param name="sender">イベントを発生させたオブジェクト</param>
    ''' <param name="e">イベントオプション</param>
    Private Sub FormMain_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
        ''多重起動チェック
        'Process.GetProcessesByName メソッド
        '指定したプロセス名を共有するリモートコンピュータ上の
        'すべてのプロセスリソースに関連付けます。
        Dim pn As String = Process.GetCurrentProcess.ProcessName 'Process.ProcessName プロパティ(プロセスの名前を取得します)
        If Process.GetProcessesByName(pn).GetUpperBound(0) > 0 Then
            ''多重起動しているならばエラーメッセージ表示して終了。
            MessageBox.Show("すでに起動しています。", TITLE + " エラーメッセージ",
                MessageBoxButtons.OK,
                MessageBoxIcon.Error)
            End
        End If

        frmMain = Me

        FormControlBoxCustomize(Me)

        Me.Text = TITLE + " " + VERSION

        Log = New ClassLog(TextBox4)

        NotifyIcon1.Text = TITLE + " " + VERSION
        NotifyIcon1.Visible = True

        Log.DebugPut("タスクトレイに登録しました。" + vbCrLf)
        Log.DebugPut("起動しました。" + vbCrLf)

        Button4.PerformClick()

        Config.Load()

        Popup()

        NowTime = Now

        System.IO.Directory.CreateDirectory(AppPath() & Format(NowTime, "yyMMdd") & "\")
    End Sub

    ''' <summary>「このプログラムについて」のボタンを押された時の処理</summary>
    Private Sub Button4_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button4.Click
        Log.Add("--------------------------------------------------------------------------" + vbCrLf)
        Log.Add(TITLE + " " + VERSION + vbCrLf)
        Log.Add(OPENING_MSG)
        Log.Add(vbCrLf)
        Log.DebugPut("DebugFlag=" + Format(Config.DebugFlag) + vbCrLf)
        Log.Add("--------------------------------------------------------------------------" + vbCrLf)
        Log.Put()
    End Sub

    ''' <summary>ログの表示クリアを行う</summary>
    Private Sub Button5_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button5.Click
        Log.Clear()
    End Sub

    ''' <summary>プログラムの終了ボタンを押された。もしくはタスクトレイアイコンのメニューから Quit を選択された時の処理</summary>
    Private Sub Button6_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button6.Click, QuitToolStripMenuItem.Click

        Log.Put("終了します。" + vbCrLf)
        Popup()
        AppClosingFlag = True
        WaitTickCount(1000)
        Me.Close() 'ここで closingイベントが発生。
        End

    End Sub

    Private Sub Me_Resize() Handles Me.Resize
        '最小化時に、フォームを非表示にする
        If Me.WindowState = FormWindowState.Minimized Then
            Me.Visible = False

            ''トレイアイコンの状態を初期化する
            NotifyIcon1.Text = TITLE + " " + VERSION

        End If
    End Sub

    ''' <summary>メインウインドウのポップアップ</summary>
    ''' <remarks></remarks>
    Public Sub Popup()
        Me.Visible = True
        Me.WindowState = FormWindowState.Normal

        ''短時間かならずトップに表示。
        Me.TopMost = True
        WaitTickCount(100)
        Me.TopMost = False

        ''トレイアイコンの状態を初期化する
        NotifyIcon1.Text = TITLE + " " + VERSION

        ''最新ログを表示
        Log.Put()

    End Sub

    Private Sub NotifyIcon1_MouseDoubleClick(ByVal sender As System.Object, ByVal e As System.Windows.Forms.MouseEventArgs) Handles NotifyIcon1.MouseDoubleClick
        Popup()
    End Sub

    Private Sub MainToolStripMenuItem_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MainToolStripMenuItem.Click
        Popup()
    End Sub

    Private Sub Timer1_Tick(sender As Object, e As EventArgs) Handles Timer1.Tick
        NowTime = Now
        Try
            'Log.Put("KeyCode = " & KeyCode)
            Select Case KeyCode
                Case 96
                    Tcommand = T0
                Case 97
                    Tcommand = T1
                Case 98
                    Tcommand = T2
                Case 99
                    Tcommand = T3
                Case 100
                    Tcommand = T4
                Case 101
                    Tcommand = T5
                Case 102
                    Tcommand = T6
                Case 103
                    Tcommand = T7
                Case 104
                    Tcommand = T8
                Case 105
                    Tcommand = T9
                Case 106
                    Tcommand = Tastah
                Case 107
                    Tcommand = Tplus
                Case 108
                    'なし
                Case 109
                    Tcommand = Tminus
                Case 110
                    Tcommand = Tdot
                Case 111
                    Tcommand = Tslash
            End Select
            If InStr(Tcommand, "[capture]") > 0 Then
                CaptureWindows()
            End If
            CSVsave()
            Beep()
        Catch

        End Try

        Timer1.Enabled = False

        WaitTickCount(50)
        CaptureProcess = False

    End Sub

    Private Sub CSVsave()
        Dim SaveString As String
        Using sw As New System.IO.StreamWriter(AppPath() & Format(NowTime, "yyMMdd") & "\" & Format(NowTime, "yyMMdd") & ".csv", True, System.Text.Encoding.GetEncoding("shift_jis"))
            If InStr(Tcommand, "[capture]") > 0 Then
                SaveString = Format(NowTime, "HH:mm:ss,") & Replace(Tcommand, "[capture]", "")
                sw.Write(vbCrLf & SaveString)
            Else
                SaveString = Tcommand
                sw.Write(SaveString)
            End If
        End Using
        Log.Put(SaveString)
    End Sub

    Private Sub CaptureWindows()

        System.IO.Directory.CreateDirectory(AppPath() & Format(NowTime, "yyMMMdd") & "\")
        'ウィンドウを列挙する
        EnumWindows(New EnumWindowsDelegate(AddressOf EnumWindowCallBack), IntPtr.Zero)

    End Sub

    Public Delegate Function EnumWindowsDelegate(hWnd As IntPtr,
        lparam As IntPtr) As Boolean

    <DllImport("user32.dll")>
    Public Shared Function EnumWindows(lpEnumFunc As EnumWindowsDelegate,
        lparam As IntPtr) As <MarshalAs(UnmanagedType.Bool)> Boolean
    End Function

    <DllImport("user32.dll", CharSet:=CharSet.Auto, SetLastError:=True)>
    Private Shared Function GetWindowText(hWnd As IntPtr,
        lpString As StringBuilder, nMaxCount As Integer) As Integer
    End Function

    <DllImport("user32.dll", CharSet:=CharSet.Auto, SetLastError:=True)>
    Private Shared Function GetWindowTextLength(hWnd As IntPtr) As Integer
    End Function

    <DllImport("user32.dll", CharSet:=CharSet.Auto, SetLastError:=True)>
    Private Shared Function GetClassName(hWnd As IntPtr,
        lpClassName As StringBuilder, nMaxCount As Integer) As Integer
    End Function

    <DllImport("user32")>
    Private Shared Function IsWindowVisible(ByVal hWnd As IntPtr) As Boolean
    End Function

    Private Shared Function EnumWindowCallBack(hWnd As IntPtr,
            lparam As IntPtr) As Boolean

        'visibleでないなら即リターン
        If (Not IsWindowVisible(hWnd)) Then
            Return True
        End If

        'ウィンドウのタイトルの長さが0以下なら即リターン
        Dim textLen As Integer = GetWindowTextLength(hWnd)
        If textLen <= 0 Then
            Return True
        End If

        'ウィンドウのタイトルを取得する
        Dim tsb As New StringBuilder(textLen + 1)
        GetWindowText(hWnd, tsb, tsb.Capacity)
        If (tsb.ToString().Length <= 0) Then
            Return True
        End If
        For Each str As String In ClassConfig.IgnoreWindowTitles
            If InStr(tsb.ToString, str) > 0 Then
                Log.Put("WindowTitle が " & str & " と一致したのでキャプチャ処理スキップ")
                Return True
            End If
        Next
        'ウィンドウのクラス名を取得する
        Dim csb As New StringBuilder(256)
        GetClassName(hWnd, csb, csb.Capacity)
        If (csb.ToString().Length <= 0) Then
            Return True
        End If

        Try
            Dim gWB As RECT
            If (Not hWnd.Equals(IntPtr.Zero)) Then
                GetWindowRect(hWnd, gWB)
                If (gWB.Right - gWB.Left) < 100 Or (gWB.Bottom - gWB.Top) < 100 Then
                    Return True
                End If
#if 0 then
                If gWB.Right < -100 Or gWB.Bottom < -100 Then
                    Return True
                End If
#end if
                'Log.Put("----------")
                'Log.Put("タイトル,ハンドル:" & tsb.ToString() & "_" & Hex(hWnd.ToInt64))
                'Log.Put("left,right,top,bottom:" & gWB.Left & "," & gWB.Right & "," & gWB.Top & "," & gWB.Bottom)

                Using img As New Bitmap(gWB.Right - gWB.Left, gWB.Bottom - gWB.Top)
                    Using memg As Graphics = Graphics.FromImage(img)
                        Dim dc As IntPtr = memg.GetHdc()

                        PrintWindow(hWnd, dc, 0)
                        memg.ReleaseHdc(dc)
                        If InStr(tsb.ToString, "mpc-hc") Then
                            img.Save(AppPath() & Format(NowTime, "yyMMdd") & "\" _
                                     & Format(NowTime, "yyMMdd_HHmmssfff") & "_" _
                                     & Split(Replace(Tcommand, "[capture]", ""), ",")(0) & "_" _
                                     & tsb.ToString() & "_" _
                                     & Microsoft.VisualBasic.Right("00000000" & Hex(hWnd.ToInt64), 8) _
                                     & ".jpg", Drawing.Imaging.ImageFormat.Jpeg)
                        Else
                            img.Save(AppPath() & Format(NowTime, "yyMMdd") & "\" _
                                     & Format(NowTime, "yyMMdd_HHmmssfff") & "_" _
                                     & Split(Replace(Tcommand, "[capture]", ""), ",")(0) & "_" _
                                     & tsb.ToString() & "_" _
                                     & Microsoft.VisualBasic.Right("00000000" & Hex(hWnd.ToInt64), 8) _
                                     & ".png", Drawing.Imaging.ImageFormat.Png)
                        End If
                    End Using
                End Using
            End If
        Catch
            'Log.Put("例外" & tsb.ToString)
        End Try

        Return True

    End Function

    Public Sub New()

        ' この呼び出しはデザイナーで必要です。
        InitializeComponent()

        ' InitializeComponent() 呼び出しの後で初期化を追加します。

    End Sub

End Class