Nestačila. Jak jsem již uvedl v úvodním příspěvku, dotaz na:
proc.MainWindowHandle
vrací nulu pokud je proces je minimalizovaný do "System Tray". Přitom se jedná třeba i o Total Commander, nebo Outlook, ale taky třeba Eset Smart Security apod. i když jak píšete, že „Outlook i Total Commander mají stále hlavní okno které má právě Handle“ Můj původní kód vede správným směrem, (alespoň si to myslím) ale má jednu zásadní chybu. Nalezne první Handle okna a ukončí prohledávání. A právě to první Handle nemusí být tím od hlavního okna. Proto jsem ho předělal tak, že nalezne všechny Handle a zůstane na uživateli, aby vybral to hlavní. Dají se využít různé filtry, např., že okno musí splňovat: - musí mít titulní proužek - musí mít titulek okna - musí mít systémové menu - musí mít minimalizační a maximalizační tlačítko - musí umožňovat změnu velikosti … a pak již zůstane většinou jenom jedno okno s relevantním názvem, případně ikonou. Znovu opakuji, že nalezne i Handle oken, které jsou umístěny "System Tray", ale i oken, které jsou standardně skryté. Kód:
Private Declare Function FindWindow Lib "user32" Alias "FindWindowA" (ByVal lpClassName As String, ByVal lpWindowName As String) As IntPtr
Private Declare Function GetParent Lib "user32" (ByVal hwnd As IntPtr) As IntPtr
Private Declare Function GetWindowThreadProcessId Lib "user32" (ByVal hwnd As IntPtr, ByRef lpdwProcessId As UInteger) As UInteger
Private Declare Function GetWindow Lib "user32" (ByVal hwnd As IntPtr, ByVal wCmd As Integer) As IntPtr
Private Declare Function GetWindowText Lib "user32" Alias "GetWindowTextA" (ByVal hWnd As IntPtr, ByVal lpString As String, ByVal nMaxCount As Integer) As Integer
Private Declare Function GetWindowTextLength Lib "user32" Alias "GetWindowTextLengthA" (ByVal hWnd As IntPtr) As Integer
Private Declare Function GetWindowLong Lib "user32" Alias "GetWindowLongA" (ByVal hwnd As IntPtr, ByVal nIndex As Integer) As Integer
Private Declare Function GetClassLong Lib "user32" Alias "GetClassLongA" (ByVal hwnd As IntPtr, ByVal nIndex As Integer) As IntPtr
Friend Declare Function ShowWindow Lib "user32" (ByVal hwnd As IntPtr, ByVal nCmdShow As Integer) As Integer
Private Const GW_HWNDNEXT = 2
Private Const GWL_STYLE = (-16)
Public Const WS_SYSMENU = &H80000
Public Const WS_OVERLAPPED = &H0
Public Const WS_CAPTION = &HC00000
Public Const WS_THICKFRAME = &H40000
Public Const WS_MINIMIZEBOX = &H20000
Public Const WS_MAXIMIZEBOX = &H10000
Private Const WS_OVERLAPPEDWINDOW = (WS_OVERLAPPED Or WS_CAPTION Or WS_SYSMENU Or WS_THICKFRAME Or WS_MINIMIZEBOX Or WS_MAXIMIZEBOX)
Private Const GCL_HICON = (-14)
Private Const GCL_HICONSM = (-34)
Public SEARCHCONST As Integer = WS_OVERLAPPEDWINDOW
Public IsCaption As Boolean = True
Public Const SW_HIDE = 0
Public Const SW_MINIMIZE = 6
Public Const SW_MAXIMIZE = 3
Public Const SW_RESTORE = 9
Public Const SW_SHOWMAXIMIZED = 3
Public Const SW_SHOW = 5
Public Const SW_SHOWMINIMIZED = 2
Public Const SW_SHOWMINNOACTIVE = 7
Public Const SW_SHOWNA = 8
Public Const SW_SHOWNOACTIVATE = 4
Public Const SW_SHOWNORMAL = 1
Public Structure WinStructure
Dim Caption As String
Dim MaxBox As Boolean
Dim MinBox As Boolean
Dim Sizing As Boolean
Dim SysMenu As Boolean
Dim CaptBar As Boolean
Dim Whwnd As IntPtr
Dim Icon As Icon
End Structure
Friend Function SearchWnd(ByVal ProcessID As IntPtr) As WinStructure()
Dim WStrct() As WinStructure = Nothing, Caption As String
Dim test_hwnd As IntPtr, test_pid As UInteger, test_thread_id As UInteger
Dim i As Integer, CP As Boolean = True
'Nalezení prvního okna
test_hwnd = FindWindow(vbNullString, vbNullString)
'procházení oken
Do While test_hwnd <> 0
'Kontrola jestli okno není podoknem
If GetParent(test_hwnd) = 0 Then
'Obdržení vlákna okna
test_thread_id = GetWindowThreadProcessId(test_hwnd, test_pid)
' souhlasí ID procesu?
If test_pid = ProcessID Then
'zjištění délky nadpisu a alokace prostoru bufferu
Dim Length As Integer = GetWindowTextLength(test_hwnd)
Dim Buff As String = Space(Length + 1)
'Zjištění nadpisu okna
Length = GetWindowText(test_hwnd, Buff, Length + 1)
Caption = Buff.Substring(0, Length)
'Pokud chceme filtrovat i podle přítomnosti titulku okna
If IsCaption Then CP = CBool(Length)
'Zjištění stylu okna
Dim WStyle As Integer = GetWindowLong(test_hwnd, GWL_STYLE)
'Filtr Stylu a Titulku
If (WStyle Or SEARCHCONST) = WStyle And CP Then
ReDim Preserve WStrct(i)
WStrct(i).Caption = Caption
WStrct(i).MaxBox = CBool(WStyle And WS_MAXIMIZEBOX)
WStrct(i).MinBox = CBool(WStyle And WS_MINIMIZEBOX)
WStrct(i).Sizing = CBool(WStyle And WS_THICKFRAME)
WStrct(i).SysMenu = CBool(WStyle And WS_SYSMENU)
WStrct(i).CaptBar = CBool(WStyle And WS_CAPTION)
WStrct(i).Whwnd = test_hwnd
Dim IcHanlde As IntPtr = GetClassLong(test_hwnd, GCL_HICONSM)
If IcHanlde = 0 Then
IcHanlde = GetClassLong(test_hwnd, GCL_HICON)
End If
If IcHanlde = 0 Then
WStrct(i).Icon = Nothing
Else
WStrct(i).Icon = System.Drawing.Icon.FromHandle(IcHanlde)
End If
i += 1
End If
End If
End If
'Nalezení dalšího okna
test_hwnd = GetWindow(test_hwnd, GW_HWNDNEXT)
Loop
Return WStrct
End Function
Jako příklad uvedu okno Eset Smart Security. Process Explorer neumožňuje operaci s jeho oknem, ale výše uvedený kód nalezne jeho Handle a je na uživateli jakou operaci s oknem provede. Kód lze samozřejmě měnit a upravovat dle vlastní potřeby. (Určitě obsahuje i zbytečné deklarace, konstanty apod. – nutno vyzkoušet) Na závěr podotýkám, že byl odzkoušen s VB2005 EE s .NET Framework 2 ve WindowsXP.
|