2013-10-31 325 views
3

我發現一些代碼可以將瀏覽器置於最前面,即使它已被最小化。 我不知道如何獲得瀏覽器的hwnd。查找Chrome瀏覽器的窗口句柄

我看了一下FindWindow API函數,但是你需要classname和windowname。 我發現我需要的classname是「Chrome_WidgetWin_1」 windowname雖然會根據瀏覽器中打開的內容而不斷變化。

我覺得這個窗口的'孩子'有一個類名「WrapperNativeWindowClass」 我不知道我是否可以用它來找到原始的父母。

任何人都可以建議如何找到瀏覽器的窗口句柄(使用VBA)?

回答

1

參數FindWindow function are optional。如果您僅提供lpClassName,它將找到該類的句柄第一個窗口。如果您僅提供lpWindowName,則使用該名稱處理第一個窗口。如果您同時提供,則只能返回符合兩個條件的窗口的句柄。我(不幸)的是Internet Explorer,所以我會做你的要求如下,假設只有一個窗口:

Declare Function FindWindow Lib "User32.dll" Alias "FindWindowA" (ByVal lpClassName As Any, ByVal lpWindowName As Any) As Long 
Declare Function BringWindowToTop Lib "user32" (ByVal hwnd As Long) As Long 

Public Sub Test() 
    Dim ClassName As String 
    Dim WindowName As String 
    Dim hwnd As Long 
    Dim Ret As Long 
    ClassName = "IEFrame" 'You would use "Chrome_WidgetWin_1" 
    WindowName = vbNullString 
    hwnd = FindWindow(ClassName, WindowName) 
    Ret BringWindowToTop(hwnd) 
End Sub 

如果你有一個以上的瀏覽器窗口更多,你將不得不看改用EnumWindows函數。

1

謝謝你史蒂夫 - 我很感激你花時間看這個。它證實我是在正確的路線上。

在瀏覽器打開並且只顯示一個默認選項卡的情況下,有4個「Chrome_WidgetWin_1」實例。

我還發現,如果瀏覽器打開但不在gmail中,類名「WrapperNativeWindowClass」不適合。我最終使用了類名「Chrome_RenderWidgetHostHWND」(下一個兄弟) - 但也有一個以上的實例。所以我必須確定父級的名稱(Chrome_WidgetWin_1),並且其中一個孩子擁有類名稱(RenderWidgetHostHWND)。

我想我已經管理它了。

另一件出現的問題是,Windows8並未將Chrome應用程序始終存儲在同一個地方。某些版本在程序(x86)下,其他版本在appdata下。不知道是否有切換回Windows7的位置或其他東西,但我已經將它包含在我的代碼中,任何人都可以使用它(代碼中標註了鏈接,因爲我傾向於將人們與我脫節的'風格「)。

BringWindowToFront還有一個宏,因爲API調用BringWindowToTop沒有管理它。 在可能的情況下,我已經注意到誰發佈了代碼,從哪裏來,儘管我確信我錯過了一些人。我仍然想說感謝讓我走得這麼遠。

我沒有時間充分評論我的代碼,如果它的工作,我可能不會因爲這是送我圈子。在用正確的類名識別href之後,我必須循環查找下一個父級,然後檢查href的最終父級是否具有適當的類名。

如果您發現任何問題,請告訴我,或者告訴我是否有任何問題會導致問題無法解決。

'Mark007 - VBA to find all Window Handles http://www.vbaexpress.com/kb/getarticle.php?kb_id=52 
'Thanks to Ivan F Moala at MrExcel - I'm not sure if i used any of his code, but reading the comments on his code defiantely helped my understanding. 
'Jaafar Tribak who posted the BringWindowToFront function at the start of the month 
'Scott Huish who posted the GetFolder macro (helped with disparity in location of Chrome) 
Option Explicit 

Private Declare Function SHGetFolderPath Lib "shell32.dll" Alias "SHGetFolderPathA" (ByVal hwndOwner As Long, ByVal nFolder As Long, ByVal hToken As Long, ByVal dwFlags As Long, ByVal lpszPath As String) As Long 
Private Declare Function SetForegroundWindow Lib "User32.dll" (ByVal hwnd As Long) As Long 
Private Declare Function ShowWindow Lib "User32.dll" (ByVal hwnd As Long, ByVal lCmdShow As Long) As Boolean 
Private Declare Function GetAncestor Lib "user32" (ByVal hwnd As Long, ByVal flags As Long) As Long 
Private Declare Function GetClassName Lib "user32" Alias "GetClassNameA" (ByVal hwnd As Long, ByVal lpClassName As String, ByVal nMaxCount As Long) 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 Declare Function GetWindow Lib "user32" (ByVal hwnd As Long, ByVal wCmd As Long) As Long 
Private Declare Function GetWindowThreadProcessId Lib "user32" (ByVal hwnd As Long, lpdwProcessId As Long) As Long 
Private Declare Function GetNextWindow Lib "user32" Alias "GetWindow" (ByVal hwnd As Long, ByVal wFlag As Long) As Long 
Private Declare Function AttachThreadInput Lib "user32" (ByVal idAttach As Long, ByVal idAttachTo As Long, ByVal fAttach As Long) As Long 
Private Declare Function GetForegroundWindow Lib "user32"() As Long 
Private Declare Function IsIconic Lib "user32" (ByVal hwnd As Long) As Long 

Private Const S_OK = &H0 
Private Const S_FALSE = &H1 
Private Const E_INVALIDARG = &H80070057 
Private Const SHGFP_TYPE_CURRENT = 0 
Private Const SHGFP_TYPE_DEFAULT = 1 
Private Const GW_HWNDNEXT = 2 
Private Const GA_PARENT = 1 
Private Const SW_SHOW = 5 
Private Const SW_RESTORE = 9 

Public retainedChromeHwnd As Long, ChildHwnd As Long, ChildFound As Boolean, origChildFound As Boolean 
Public NextHandle As Boolean, GotNextParent As Boolean 

Private Function BringWindowToFront(ByVal hwnd As Long) As Boolean 
'Many thanks to Jaafar Tribak who posted this on MrExcel 
'http://www.mrexcel.com/forum/excel-questions/730660-visual-basic-applications-code-maximise-view-activeworksheet-after-having-ie-navigation.html 
    Dim ThreadID1 As Long 
    Dim ThreadID2 As Long 
    Dim nRet As Long 

    On Error Resume Next 

    ' Nothing to do if already in foreground. 
    If hwnd = GetForegroundWindow() Then 
     BringWindowToFront = True 
    Else 
     'First need to get the thread responsible for this window, 
     'and the thread for the foreground window. 
     ThreadID1 = _ 
     GetWindowThreadProcessId(GetForegroundWindow, ByVal 0&) 
     ThreadID2 = _ 
     GetWindowThreadProcessId(hwnd, ByVal 0&) 

     'By sharing input state, threads share their concept of 
     'the active window. 
     Call AttachThreadInput(ThreadID1, ThreadID2, True) 
     nRet = SetForegroundWindow(hwnd) 

     'Restore and repaint. 
     If IsIconic(hwnd) Then 
      Call ShowWindow(hwnd, SW_RESTORE) 
     Else 
      Call ShowWindow(hwnd, SW_SHOW) 
     End If 

     'BringWindowToFront returns TRUE if success. 
     BringWindowToFront = CBool(nRet) 
    End If 
End Function 

Private Function GetFolder(ByVal lngFolder As Long) As String 
' With thanks to Scott Huish who posted this macro on MrExcel 
'http://www.mrexcel.com/forum/excel-questions/706627-using-visual-basic-applications-open-links-non-default-browser.html 

    Dim strBuffer As String * 1000 
    Dim strPath As String 
    Dim lngReturn As Long 

    lngReturn = SHGetFolderPath(0&, lngFolder, 0&, SHGFP_TYPE_CURRENT, strBuffer) 
    If lngReturn = S_OK Then 
     strPath = Left$(strBuffer, InStr(strBuffer, Chr$(0)) - 1) 
    Else 
     strPath = "(error)" 
    End If 
    GetFolder = strPath 
End Function 

Public Sub Chromelink(hparent As Long, xcount As Long) 
Dim ChromeID As Long, strtext As String, ChromeClassName As String, ChromeHwnd As Long 
Dim lngret As Long 

ChromeHwnd = FindWindowEx(hparent, 0&, vbNullString, vbNullString) 
If origChildFound = True Then 
    ChromeHwnd = retainedChromeHwnd 
    origChildFound = False 
End If 
If ChildFound = True And GotNextParent = True Then 
    Exit Sub 
ElseIf ChildFound = True Then 
    NextHandle = True 
    ChildFound = False 
End If 
While ChromeHwnd <> 0 
    strtext = String$(100, Chr$(0)) 
    lngret = GetClassName(ChromeHwnd, strtext, 100) 
    ChromeClassName = Left$(strtext, lngret) 
    If ChromeClassName = "Chrome_RenderWidgetHostHWND" Then 
     ChildFound = True 
     ChildHwnd = ChromeHwnd 
    End If 

    xcount = xcount + 1 
    Chromelink ChromeHwnd, xcount 'loop through next level of child windows 

    If ChildFound = True Then Exit Sub 
    ChromeHwnd = FindWindowEx(hparent, ChromeHwnd, vbNullString, vbNullString) 
    If hparent = 0 And NextHandle = True Then 
     retainedChromeHwnd = ChromeHwnd 
     ChildFound = True 
     GotNextParent = True 
    End If 
Wend 
End Sub 

Sub ChromeSetup() 
Dim myURL As String, ChromePath As String, strtext As String, lngret As Long 
Dim ChromeOpen As Boolean 
Dim W As Object 
Dim ProcessQuery As String 
Dim processes As Object 
Dim process As Object 

Set W = GetObject("winmgmts:") 
ProcessQuery = "SELECT * FROM win32_process" 
Set processes = W.execquery(ProcessQuery) 
'helpful process properties - http://msdn.microsoft.com/en-us/library/aa394372(v=vs.85).aspx 
For Each process In processes 
    'check if Chrome is open 
    If process.Name = "chrome.exe" Then 
     'Chrome is open, find the Handle for the Chrome Browser 
     Chromelink 0&, 0 
     strtext = String$(100, Chr$(0)) 
     lngret = GetClassName(ChildHwnd, strtext, 100) 
     'loop incase of more siblings 
     While Not Left$(strtext, lngret) = "Chrome_WidgetWin_1" 
      ChildHwnd = GetAncestor(ChildHwnd, GA_PARENT) 
      strtext = String$(100, Chr$(0)) 
      lngret = GetClassName(ChildHwnd, strtext, 100) 
      'Duplicate of classname but WidgetWin_0 
      If ChildHwnd = 0 Then 
       origChildFound = True 
       Chromelink retainedChromeHwnd, 0 
      End If 
     Wend 
     ChromeOpen = True 
     Exit For 
    End If 
Next process 

myURL = "http://www.google.com/" 

If ChromeOpen = False Then 'Chrome needs to be opened so more time required 
    'which localtion is Chrome at? 
    ChromePath = "C:\Program Files (x86)\Google\Chrome\Application\chrome.exe" 
    If Len(Dir(ChromePath)) Then 
     shell "C:\Program Files (x86)\Google\Chrome\Application\chrome.exe -url " & myURL 
    Else 
     ChromePath = GetFolder(&H1C) & "\Google\Chrome\Application\chrome.exe" 
     If Len(Dir(ChromePath)) Then 
      shell GetFolder(&H1C) & "\Google\Chrome\Application\chrome.exe -url " & myURL 
     Else 
      MsgBox "Chrome could not be found." 
      Exit Sub 
     End If 
    End If 
    Application.Wait Now() + TimeValue("00:00:10") 
Else 
    BringWindowToFront ChildHwnd 
    Application.Wait Now() + TimeValue("00:00:01") 
End If 
End Sub 

我可能應該把錯誤處理,並可能找到更多關於'借來的'代碼。其中一些我不明白 - 即使像0這樣的基礎知識也不是0 &。 那一個把我扔了一下。

1

典型的鉻/鉻運行會話(多進程,處理渲染/縮小過程iframe也離線瀏覽器的應用和(標準)的擴展。

typical run NirSoft的優良WinExplorer工具(間許多許多其他的)

顯示以下內容(可能與你相似)類顯示器 enter image description here

嘗試尋找兩個Chrome_WidgetWin_1Chrome_RenderWidgetHostHWND

+0

謝謝! 'Chrome_WidgetWin_1'爲我工作。通過以下函數調用':: FindWindowEx(0,0,「Chrome_WidgetWin_1」,0)' – d34th4ck3r