我用createprocess运行程序a.exe,然后用sendmessage向a.exe中的一个窗体(唯一的窗体)发送消息。
我现在用findwindow方法得到窗体的hwnd.但是我怕有多个程序运行,窗体的caption不唯一。
能否在用createprocess运行后,用其他的方法得到窗体的hmnd.

解决方案 »

  1.   

    FindWindow后调用API函数GetWindowThreadProcessId得到ProcessId
    与createprocess最后一个参数
    Private Type PROCESS_INFORMATION
            hProcess As Long
            hThread As Long
            dwProcessId As Long
            dwThreadId As Long
    End Type
    中的dwProcessId比较
      

  2.   

    如果不一致,再如何处理呢。
    有没有不用findwindow,而得到hmwd的方法呢。
      

  3.   

    PROCESS_INFORMATION pi;
    CreateProcess(...., pi, ...);
    ::EnumWindows(&EnumWindowsProc, pi.threadid);
    BOOL CALLBACK EnumWindowsProc(HWND hwnd, LPARAM param)
    {DWORD id = GetWindowThreadProcessId(hwnd, NULL)
    if (id == (DWORD)param)
    {
    //do whatever we want to do
    return false;
    }
    return true;
    }
      
      

  4.   

    我通常的做法是用三个API函数GetDesktopWindow, GetTopWindow, GetNextWindow
    遍历窗体, 直到找出想要的, 包括TextBox, CommandButton等等的句柄
      

  5.   

    现在有个问题是,我用
    GetDesktopWindow, GetTopWindow, GetNextWindow得到hwnd可以发送关闭程序的消息,但是发数据不可以,也不能修改标题(用setwindowText),但是用FindWindow得到的hwnd可以发送关闭程序的消息,也可以发送数据,也可以修改标题(用setwindowText).下面是我的接收的程序的模块:
    Option ExplicitType COPYDATASTRUCT
        dwData As Long
        cbData As Long
        lpData As Long
     End Type Public Const GWL_WNDPROC = (-4)
     Public Const WM_COPYDATA = &H4A
     Global lpPrevWndProc As Long
     Global gHW As Long 'Copies a block of memory from one location to another. Declare Sub CopyMemory Lib "kernel32" Alias "RtlMoveMemory" _
        (hpvDest As Any, hpvSource As Any, ByVal cbCopy As Long) Declare Function CallWindowProc Lib "user32" Alias _
        "CallWindowProcA" (ByVal lpPrevWndFunc As Long, ByVal hwnd As _
        Long, ByVal Msg As Long, ByVal wParam As Long, ByVal lParam As _
        Long) As Long Declare Function SetWindowLong Lib "user32" Alias "SetWindowLongA" _
        (ByVal hwnd As Long, ByVal nIndex As Long, ByVal dwNewLong As _
        Long) As Long Public Sub Hook()
         lpPrevWndProc = SetWindowLong(gHW, GWL_WNDPROC, _
         AddressOf WindowProc)
         Debug.Print lpPrevWndProc
     End Sub Public Sub Unhook()
         Dim temp As Long
         temp = SetWindowLong(gHW, GWL_WNDPROC, lpPrevWndProc)
     End Sub Function WindowProc(ByVal hw As Long, ByVal uMsg As Long, _
        ByVal wParam As Long, ByVal lParam As Long) As Long
         If uMsg = WM_COPYDATA Then
             Call mySub(lParam)
             frmRecieve.Print "hw:" & hw & " uMsg:" & uMsg & " wParam:" & wParam & " lparam:" & lParam
         End If
         WindowProc = CallWindowProc(lpPrevWndProc, hw, uMsg, wParam, _
            lParam)
     End Function Sub mySub(lParam As Long)
         Dim cds As COPYDATASTRUCT
         Dim buf(1 To 255) As Byte
           Dim a As String
         Call CopyMemory(cds, ByVal lParam, Len(cds))     Select Case cds.dwData
          Case 1
             Debug.Print "got a 1"
             'frmRecieve.Print "got a 1"
             frmRecieve.Label1.Caption = a$ & " time: " & Now
    '         If frmRecieve.Visible = False Then
    '           frmRecieve.Show
    '         Else
    '           frmRecieve.Hide
    '         End If
          Case 2
             Debug.Print "got a 2"
             frmRecieve.Print "got a 2"
          Case 3
             Call CopyMemory(buf(1), ByVal cds.lpData, cds.cbData)
             a$ = StrConv(buf, vbUnicode)
             a$ = Left$(a$, InStr(1, a$, Chr$(0)) - 1)
             frmRecieve.Label1.Caption = a$ & " time: " & Now
             
         End Select
     End Sub
    Public Sub Main()
             Dim strTitle As String
              strTitle = Command()
              'MsgBox strTitle
              If strTitle <> "" Then
                frmRecieve.Caption = strTitle
              Else
                frmRecieve.Caption = "Target0"
              End If
    End Sub
    下面是发送端的程序:' Return information about this window.
    Private Sub GetWindowInfo(ByVal app_hWnd As Long, ByRef app_parent As Long, ByRef app_owner As Long, ByRef app_visible As Boolean, ByRef app_style As Long, ByRef app_text As String, ByRef app_class As String)
    Const MAX_LENGTH = 1024Dim buf As String * MAX_LENGTH
    Dim length As Long    app_parent = GetParent(app_hWnd)
        app_owner = GetWindowLong(app_hWnd, GWL_HWNDPARENT)
        app_visible = IsWindowVisible(app_hWnd)
        app_style = GetWindowLong(app_hWnd, GWL_STYLE)    length = GetWindowText(app_hWnd, buf, MAX_LENGTH)
        app_text = Left$(buf, length)    length = GetClassName(app_hWnd, buf, MAX_LENGTH)
        app_class = Left$(buf, length)
    End SubPublic Function InstanceToWnd(ByVal target_pid As Long) As Long
    Dim app_hWnd As Long
    Dim app_parent As Long
    Dim app_owner As Long
    Dim app_visible As Boolean
    Dim app_style As Long
    Dim app_text As String
    Dim app_class As String
    Dim wid As Single
    Dim col_wid() As Single
    Dim r As Integer
    Dim c As Integer
    Dim test_pid As Long
    Dim test_thread_id As Long    GetWindowInfo app_hWnd, app_parent, app_owner, _
            app_visible, app_style, app_text, app_class    app_hWnd = GetTopWindow(0)
        r = 1
        Do While app_hWnd <> 0
            ' Get information about this window.
            GetWindowInfo app_hWnd, app_parent, app_owner, _
                app_visible, app_style, app_text, app_class        ' See if this window is interesting.
            If app_visible And _
                app_parent = 0 And _
                app_owner = 0 And _
                Len(app_text) > 0 And _
                Left$(app_text, 8) <> "VBBubble" And _
                (Left$(app_class, 7) <> "Progman" Or _
                    (app_style And WS_OVERLAPPEDWINDOW) <> 0) _
            Then
                If GetParent(app_hWnd) = 0 Then
                    ' This is a top-level window. See if
                    ' it has the target instance handle.
                    test_thread_id = _
                        GetWindowThreadProcessId(app_hWnd, _
                        test_pid)                If test_pid = target_pid Then
                        ' This is the target.
                        InstanceToWnd = app_hWnd
                        Exit Do
                    End If
                End If
                r = r + 1
            End If        app_hWnd = GetNextWindow(app_hWnd, GW_HWNDNEXT)
        Loop
    End Function下面的好用的启动程序(用findwindow方法,不用sleep有时不能得到hwnd)
    Dim cds As COPYDATASTRUCT
              
              Dim buf(1 To 255) As Byte
              Dim i As Long
            Dim A As String
            
            
            ''''''''''''''''''''''''''''''''''''''''''''''''
            Dim res&
           
            sinfo.cb = Len(sinfo)
            sinfo.lpReserved = vbNullString
            sinfo.lpDesktop = vbNullString
            sinfo.lpTitle = vbNullString
            sinfo.dwFlags = 0
            
            Label1.Caption = "&Otilde;&yacute;&Ocirc;&Uacute;&AElig;&ocirc;&para;&macr;&sup3;&Igrave;&ETH;ò"
            Label1.Refresh
            ' CreateProcess&ordm;&macr;&Ecirc;&yacute;&pound;&not;&Oacute;&Atilde;&Oacute;&Uacute;&acute;&acute;&frac12;¨&Ograve;&raquo;&cedil;&ouml;&ETH;&Acirc;&micro;&Auml;&frac12;&oslash;&sup3;&Igrave;
            
            'res = CreateProcess("Target.exe", vbNullString, ByVal 0&, ByVal 0&, 1&, NORMAL_PRIORITY_CLASS, ByVal 0&, vbNullString, sinfo, pinfo)
            res = CreateProcess(vbNullString, App.Path & "\Target.exe " & strTitle, ByVal 0&, ByVal 0&, 1&, NORMAL_PRIORITY_CLASS, ByVal 0&, vbNullString, sinfo, pinfo)
            'MsgBox res
            If res Then
                Label1.Caption = "&sup3;&Igrave;&ETH;ò&Otilde;&yacute;&Ocirc;&Uacute;&Ocirc;&Euml;&ETH;&ETH;"
            Else
                Label1.Caption = "&sup3;&Igrave;&ETH;ò&Ocirc;&Euml;&ETH;&ETH;err"
            End If
        
            'ThWnd = pinfo.hProcess
    A:
            Sleep (100)
             'MsgBox pinfo.hProcess & " " & pinfo.dwProcessID
            '''''''''''''''''''''''''''''''''''''''''''''''
          ' Get the hWnd of the target application
              ThWnd = FindWindow(vbNullString, strTitle)
              Static ii As Integer
              If ThWnd = 0 Then
                ii = ii + 1
                If ii < 100 Then
                    GoTo A:
                End If
                MsgBox strTitle & " &Atilde;&raquo;&Oacute;&ETH;&Ocirc;&Euml;&ETH;&ETH;"
                Exit Sub
              End If
    '           'l MsgBox ThWnd
            'ThWnd = pinfo.hProcess
            res = CloseHandle(pinfo.hProcess)
    ''          a$ = "It Works!"
    ''      ' Copy the string into a byte array, converting it to ASCII
    ''          Call CopyMemory(buf(1), ByVal a$, Len(a$))
    ''          cds.dwData = 1
    ''          cds.cbData = Len(a$) + 1
    ''          cds.lpData = VarPtr(buf(1))
    ''          i = SendMessage(ThWnd, WM_COPYDATA, Me.hwnd, cds)
      

  6.   

    下面的用与程序对比方法来(GetWindowThreadProcessId)
    Dim h_wnd As Long
        Dim buf As String
        Dim buf_len As Long
            Dim cds As COPYDATASTRUCT
              
              
              Dim i As Long
            Dim A As String
            
            
            ''''''''''''''''''''''''''''''''''''''''''''''''
            Dim res&
           
            sinfo.cb = Len(sinfo)
            sinfo.lpReserved = vbNullString
            sinfo.lpDesktop = vbNullString
            sinfo.lpTitle = vbNullString
            sinfo.dwFlags = 0
            
            Label1.Caption = "&Otilde;&yacute;&Ocirc;&Uacute;&AElig;&ocirc;&para;&macr;&sup3;&Igrave;&ETH;ò"
            Label1.Refresh
            ' CreateProcess&ordm;&macr;&Ecirc;&yacute;&pound;&not;&Oacute;&Atilde;&Oacute;&Uacute;&acute;&acute;&frac12;¨&Ograve;&raquo;&cedil;&ouml;&ETH;&Acirc;&micro;&Auml;&frac12;&oslash;&sup3;&Igrave;
            
            'res = CreateProcess("Target.exe", vbNullString, ByVal 0&, ByVal 0&, 1&, NORMAL_PRIORITY_CLASS, ByVal 0&, vbNullString, sinfo, pinfo)
            res = CreateProcess(vbNullString, App.Path & "\Target.exe " & strTitle, ByVal 0&, ByVal 0&, 1&, NORMAL_PRIORITY_CLASS, ByVal 0&, vbNullString, sinfo, pinfo)        m_Pid = pinfo.dwProcessID
            
        ' Start the program.
    '    m_Pid = Shell(Text1.Text, vbNormalFocus)
        
        If m_Pid = 0 Then
            MsgBox "Error starting program"
            Exit Sub
        End If    ' Get the window handle.
        Sleep (100)
         pCurrentPlayerHandle = InstanceToWnd(m_Pid)
         MsgBox pCurrentPlayerHandle
         ThWnd = pCurrentPlayerHandle
         If ThWnd = 0 Then
            
                MsgBox strTitle & " &Atilde;&raquo;&Oacute;&ETH;&Ocirc;&Euml;&ETH;&ETH;"
                Exit Sub
              End If
        'SetWindowText pCurrentPlayerHandle, "The handle to Notepad is " ' & CStr(pCurrentPlayerHandle & vbNullChar)
        ' Display the program's caption.
        buf = Space$(256)
        buf_len = GetWindowText(pCurrentPlayerHandle, buf, Len(buf))
        buf = Left$(buf, buf_len)
        MsgBox buf
      

  7.   

    建议用Microsoft Visual Studio 6.0 Tools里Spy++检查一下得到的句柄是否正确
      

  8.   

    我用spy++查看了。
    有两个与我的接收程序有关
    一个是以我Target.exe文件名一致的,
    000E05DC "Target"
    另一个是与我的窗体同名(FindWindow 中用的窗体名)
    000609EE "Target02"但是他们的Process ID,Thread ID 相同都是下面数值:
    Process ID:00000720
    Thread ID :00000520如果我用FindWindow的方法查找"Target02",得到的是000609EE
    如果我用test_thread_id = _
                        GetWindowThreadProcessId(app_hWnd, _
                        test_pid)
    方法得到的是000E05DC为什么不同呢。
      

  9.   

    hWndOwner = GetWindow(hWnd, GW_OWNER)其中一个是Owner Window, ThunderRT6Main的另一个是ThunderRT6FormDC的这和VB程序的窗体树结构有关FindWindow比较窗体的Caption我们也可以自己调用GetWindowText比较窗体的Caption
      

  10.   

    InstanceToWnd要找到满足Process ID和Caption两个条件的窗体