none
How can I get a handle to a window of executed process in VBA? RRS feed

  • Question


  • In my VBA application I start IExplore process with:

    Shell sIE, vbMaximizedFocus

    Now I need to resize created window. For that I can use SetWindowPos function, which takes a handle to the window as one of the arguments. And I don't have that handle...

    I would use FindWindowLike function (which goes threw windows, compares caption with pattern and returns array of handles of windows with matching caption), but I cann't rely on window caption. I cann't just resize all of the IE windows also.

    So, I was thinking of using SOMETHING that would give me a handle of a window to the process I just ran. Shell does not provide this.

    I have some example code, how to do this in C++ using CoCreateInstance function:

        CoCreateInstance(CLSID_InternetExplorer, NULL, CLSCTX_LOCAL_SERVER, IID_IWebBrowser2, (void**)&m_pBrowser);
           
    if (m_pBrowser)
           
    {
                pom  
    = buffer;
                m_pBrowser
    ->put_Visible(VARIANT_TRUE);
                m_pBrowser
    ->Navigate(pom, &(_variant_t(flaga)), &vDummy, &vDummy, &vDummy);
                m_pBrowser
    ->get_HWND((long *)&hWnd);
               
    if (hWnd != NULL)
               
    {
                 
    ...
                 
    ...

    I would've port this to VBA, but I'm not so sure, what to put for fourth parameter:

    riid [in] Reference to the identifier of the interface to be used to communicate with the object.

    Well I don't know witch interface I should pass... I'm not even sure if I can use it in VBA.

    So. Is there a way to execute process, which would provide me a handle to it's window?

    Tuesday, October 18, 2011 2:15 PM

Answers


  • In my VBA application I start IExplore process with:

    Shell sIE, vbMaximizedFocus

    Now I need to resize created window. For that I can use SetWindowPos function, which takes a handle to the window as one of the arguments. And I don't have that handle...

    I would use FindWindowLike function (which goes threw windows, compares caption with pattern and returns array of handles of windows with matching caption), but I cann't rely on window caption. I cann't just resize all of the IE windows also.

    So, I was thinking of using SOMETHING that would give me a handle of a window to the process I just ran. Shell does not provide this.

    I have some example code, how to do this in C++ using CoCreateInstance function:

        CoCreateInstance(CLSID_InternetExplorer, NULL, CLSCTX_LOCAL_SERVER, IID_IWebBrowser2, (void**)&m_pBrowser);
           
    if (m_pBrowser)
           
    {
                pom  
    = buffer;
                m_pBrowser
    ->put_Visible(VARIANT_TRUE);
                m_pBrowser
    ->Navigate(pom, &(_variant_t(flaga)), &vDummy, &vDummy, &vDummy);
                m_pBrowser
    ->get_HWND((long *)&hWnd);
               
    if (hWnd != NULL)
               
    {
                 
    ...
                 
    ...

    I would've port this to VBA, but I'm not so sure, what to put for fourth parameter:

    riid [in] Reference to the identifier of the interface to be used to communicate with the object.

    Well I don't know witch interface I should pass... I'm not even sure if I can use it in VBA.

    So. Is there a way to execute process, which would provide me a handle to it's window?


    The shell function returns a taskid, which you can map to a handle with the appropriate code.  For an example of how see http://www.vbforums.com/showthread.php?t=33038  I've copied the relevant code below with an example of how to use the function

    Sub getHwnd()
        Debug.Print GetWinHandle(Shell("c:\windows\system32\notepad.exe"))
        End Sub

     

    Option Explicit

    Public Const GW_HWNDNEXT = 2

    Public Declare Function GetParent Lib "user32" (ByVal hwnd As Long) As Long
    Public Declare Function GetWindow Lib "user32" (ByVal hwnd As Long, _
      ByVal wCmd As Long) As Long
    Public Declare Function FindWindow Lib "user32" Alias "FindWindowA" _
      (ByVal lpClassName As String, ByVal lpWindowName As String) As Long

    Public Declare Function GetWindowThreadProcessId Lib "user32" _
      (ByVal hwnd As Long, lpdwprocessid As Long) As Long
     
    Public Declare Function ShellExecute Lib "shell32.dll" Alias "ShellExecuteA" _
            (ByVal hwnd As Long, _
            ByVal lpOperation As String, _
            ByVal lpFile As String, _
            ByVal lpParameters As String, _
            ByVal lpDirectory As String, ByVal nShowCmd As Long) As Long


    Function ProcIDFromWnd(ByVal hwnd As Long) As Long
       Dim idProc As Long
     
       ' Get PID for this HWnd
       GetWindowThreadProcessId hwnd, idProc
       ProcIDFromWnd = idProc
    End Function
         
    Function GetWinHandle(hInstance As Long) As Long
       Dim tempHwnd As Long
         
       ' Grab the first window handle that Windows finds:
       tempHwnd = FindWindow(vbNullString, vbNullString)
      
       ' Loop until you find a match or there are no more window handles:
       Do Until tempHwnd = 0
          ' Check if no parent for this window
          If GetParent(tempHwnd) = 0 Then
             ' Check for PID match
             If hInstance = ProcIDFromWnd(tempHwnd) Then
                ' Return found handle
                GetWinHandle = tempHwnd
                ' Exit search loop
                Exit Do
             End If
          End If
      
          ' Get the next window handle
          tempHwnd = GetWindow(tempHwnd, GW_HWNDNEXT)
       Loop
    End Function

     


    Tushar Mehta (Technology and Operations Consulting)
    www.tushar-mehta.com (Excel and PowerPoint add-ins and tutorials)
    Microsoft MVP Excel 2000-Present
    Tuesday, October 18, 2011 3:09 PM

All replies


  • In my VBA application I start IExplore process with:

    Shell sIE, vbMaximizedFocus

    Now I need to resize created window. For that I can use SetWindowPos function, which takes a handle to the window as one of the arguments. And I don't have that handle...

    I would use FindWindowLike function (which goes threw windows, compares caption with pattern and returns array of handles of windows with matching caption), but I cann't rely on window caption. I cann't just resize all of the IE windows also.

    So, I was thinking of using SOMETHING that would give me a handle of a window to the process I just ran. Shell does not provide this.

    I have some example code, how to do this in C++ using CoCreateInstance function:

        CoCreateInstance(CLSID_InternetExplorer, NULL, CLSCTX_LOCAL_SERVER, IID_IWebBrowser2, (void**)&m_pBrowser);
           
    if (m_pBrowser)
           
    {
                pom  
    = buffer;
                m_pBrowser
    ->put_Visible(VARIANT_TRUE);
                m_pBrowser
    ->Navigate(pom, &(_variant_t(flaga)), &vDummy, &vDummy, &vDummy);
                m_pBrowser
    ->get_HWND((long *)&hWnd);
               
    if (hWnd != NULL)
               
    {
                 
    ...
                 
    ...

    I would've port this to VBA, but I'm not so sure, what to put for fourth parameter:

    riid [in] Reference to the identifier of the interface to be used to communicate with the object.

    Well I don't know witch interface I should pass... I'm not even sure if I can use it in VBA.

    So. Is there a way to execute process, which would provide me a handle to it's window?


    The shell function returns a taskid, which you can map to a handle with the appropriate code.  For an example of how see http://www.vbforums.com/showthread.php?t=33038  I've copied the relevant code below with an example of how to use the function

    Sub getHwnd()
        Debug.Print GetWinHandle(Shell("c:\windows\system32\notepad.exe"))
        End Sub

     

    Option Explicit

    Public Const GW_HWNDNEXT = 2

    Public Declare Function GetParent Lib "user32" (ByVal hwnd As Long) As Long
    Public Declare Function GetWindow Lib "user32" (ByVal hwnd As Long, _
      ByVal wCmd As Long) As Long
    Public Declare Function FindWindow Lib "user32" Alias "FindWindowA" _
      (ByVal lpClassName As String, ByVal lpWindowName As String) As Long

    Public Declare Function GetWindowThreadProcessId Lib "user32" _
      (ByVal hwnd As Long, lpdwprocessid As Long) As Long
     
    Public Declare Function ShellExecute Lib "shell32.dll" Alias "ShellExecuteA" _
            (ByVal hwnd As Long, _
            ByVal lpOperation As String, _
            ByVal lpFile As String, _
            ByVal lpParameters As String, _
            ByVal lpDirectory As String, ByVal nShowCmd As Long) As Long


    Function ProcIDFromWnd(ByVal hwnd As Long) As Long
       Dim idProc As Long
     
       ' Get PID for this HWnd
       GetWindowThreadProcessId hwnd, idProc
       ProcIDFromWnd = idProc
    End Function
         
    Function GetWinHandle(hInstance As Long) As Long
       Dim tempHwnd As Long
         
       ' Grab the first window handle that Windows finds:
       tempHwnd = FindWindow(vbNullString, vbNullString)
      
       ' Loop until you find a match or there are no more window handles:
       Do Until tempHwnd = 0
          ' Check if no parent for this window
          If GetParent(tempHwnd) = 0 Then
             ' Check for PID match
             If hInstance = ProcIDFromWnd(tempHwnd) Then
                ' Return found handle
                GetWinHandle = tempHwnd
                ' Exit search loop
                Exit Do
             End If
          End If
      
          ' Get the next window handle
          tempHwnd = GetWindow(tempHwnd, GW_HWNDNEXT)
       Loop
    End Function

     


    Tushar Mehta (Technology and Operations Consulting)
    www.tushar-mehta.com (Excel and PowerPoint add-ins and tutorials)
    Microsoft MVP Excel 2000-Present
    Tuesday, October 18, 2011 3:09 PM
  • I sort of do something similar.

     

      Call GetScreenSize(ss)
      Call AppActivate("MyApp")
      hndl = GetForegroundWindow()
      If hndl > 0 Then
        retval = GetWindowPlacement(hndl, wp)
        wp.rcNormalPosition.x1 = ss.x2 - 420
        wp.rcNormalPosition.x2 = ss.x2 + 80
        wp.rcNormalPosition.y1 = 0
        wp.rcNormalPosition.y2 = 600
        retval = SetWindowPlacement(hndl, wp)

     

    GetForegroundWindow should get the handle to the last window active.  My code is positioning MyApp in top right corner.

    Thursday, October 20, 2011 11:05 PM