Tek-Tips is the largest IT community on the Internet today!

Members share and learn making Tek-Tips Forums the best source of peer-reviewed technical information on the Internet!

  • Congratulations Shaun E on being selected by the Tek-Tips community for having the most helpful posts in the forums last week. Way to Go!

attn: API GURUs... Api to highlight a window... such as with Spy++ 3

Status
Not open for further replies.

CubeE101

Programmer
Nov 19, 2002
1,492
US
Is there (I think I've seen it before...?) a funtion to highlight a window by it's handle...

I want to use this the same way that Spy++ (comes as a packaged tool with VC++) does as you drag the mouse accross windows...

I will be using GetCursorPos with WindowFromPoint to get the hWnd of a window...

Then possibly even GetAncestor to get the root window...

I would just like to be able to highlight the currently selected window as a visual aid...

but... I can't remember the name of it...

Thanks in advance...

Have Fun, Be Young... Code BASIC
-Josh

cubee101.gif


PROGRAMMER: (n) Red-eyed, mumbling mammal capable of conversing with inanimate objects.
 
If only...

Once upon a time (because of the primitive way the window fram was drawn), there was quite simple function in 16-bit Windows called...um...FastWindowFrame - but it never survived into the 32-bit world.

There's always DrawFocusRect, DrawEdge or FrameRgn - but each has drawbacks - in my opinion - for the task you outline

So here's the core of my own rubberbanding code, which emulates the old FastWindowFrame function. Note that drawing the frame a second time to the same rectangle erases the frame. I leave it to you to figure how to determine the correct DC and RECT...
Code:
[blue]Option Explicit

Private Type RECT
        Left As Long
        Top As Long
        Right As Long
        Bottom As Long
End Type

Private Declare Function DeleteObject Lib "gdi32" (ByVal hObject As Long) As Long

Private Declare Function CombineRgn Lib "gdi32" (ByVal hDestRgn As Long, ByVal hSrcRgn1 As Long, ByVal hSrcRgn2 As Long, ByVal nCombineMode As Long) As Long
Private Declare Function CreateRectRgnIndirect Lib "gdi32" (lpRect As RECT) As Long
Private Declare Function InvertRgn Lib "gdi32" (ByVal hdc As Long, ByVal hRgn As Long) As Long
Private Const RGN_XOR = 3

' Draws frame of rectangle you pass for the given DC
Private Function FastWindowFrame(ByVal hdc As Long, lpRect As RECT, Optional ByVal FrameWidth As Long = 1) ' xWidth As Long, yWidth As Long) As Long
    Dim InsideRect As RECT
    Dim tmpVar As Long
    Dim OuterRgn As Long
    Dim InnerRgn As Long
        
    ' Swap coordinates if necessary to ensure legit regions (else we get speckles)
    ' possibly not necessary if we are just framing rather than rubberbanding
    If lpRect.Right < lpRect.Left Then
        tmpVar = lpRect.Right
        lpRect.Right = lpRect.Left
        lpRect.Left = tmpVar
    End If
    If lpRect.Bottom < lpRect.Top Then
        tmpVar = lpRect.Top
        lpRect.Top = lpRect.Bottom
        lpRect.Bottom = tmpVar
    End If
    
    InsideRect.Left = lpRect.Left + FrameWidth
    InsideRect.Right = lpRect.Right - FrameWidth
    InsideRect.Top = lpRect.Top + FrameWidth
    InsideRect.Bottom = lpRect.Bottom - FrameWidth

    OuterRgn = CreateRectRgnIndirect(lpRect)
    InnerRgn = CreateRectRgnIndirect(InsideRect)
    
    CombineRgn OuterRgn, OuterRgn, InnerRgn, RGN_XOR

    InvertRgn hdc, OuterRgn

    ' Clean up
    DeleteObject OuterRgn
    DeleteObject InnerRgn

End Function
[/blue]

 
When you right-click a node in the "Windows" treeview in Spy++, you see a "Highlight" option. Choosing this command causes the Window to flash momentarily so that you can see and identify it.

The following code provides a similar functionality. Start a new project. Place a big listbox on your form and insert the following code in Form1.
___
[tt]
Private Declare Function GetWindow Lib "user32" (ByVal hwnd As Long, ByVal wCmd As Long) As Long
Private Declare Function IsWindowVisible Lib "user32" (ByVal hwnd As Long) As Long
Private Declare Function GetWindowTextLength Lib "user32" Alias "GetWindowTextLengthA" (ByVal hwnd As Long) As Long
Private Declare Function GetWindowText Lib "user32" Alias "GetWindowTextA" (ByVal hwnd As Long, ByVal lpString As String, ByVal cch As Long) As Long
Private Declare Function GetWindowRect Lib "user32" (ByVal hwnd As Long, lpRect As RECT) As Long
Private Declare Function GetWindowDC Lib "user32" (ByVal hwnd As Long) As Long
Private Declare Function InvertRect Lib "user32" (ByVal hDC As Long, lpRect As RECT) As Long
Private Declare Function OffsetRect Lib "user32" (lpRect As RECT, ByVal x As Long, ByVal y As Long) As Long
Private Declare Function ReleaseDC Lib "user32" (ByVal hwnd As Long, ByVal hDC As Long) As Long
Private Declare Sub Sleep Lib "kernel32" (ByVal dwMilliseconds As Long)
Private Const GW_CHILD = 5
Private Const GW_HWNDNEXT = 2
Private Type RECT
Left As Long
Top As Long
Right As Long
Bottom As Long
End Type
Private Sub Form_Load()
Dim S As String, hwnd As Long
hwnd = GetWindow(Me.hwnd, 0)
While hwnd
If IsWindowVisible(hwnd) Then
S = GetWindowTitle(hwnd)
If Len(S) Then
List1.AddItem S
List1.ItemData(List1.NewIndex) = hwnd
End If
End If
hwnd = GetWindow(hwnd, GW_HWNDNEXT)
Wend
End Sub

Function GetWindowTitle(hwnd As Long) As String
GetWindowTitle = Space$(GetWindowTextLength(hwnd))
GetWindowText hwnd, GetWindowTitle, Len(GetWindowTitle) + 1
End Function

Private Sub List1_DblClick()
If List1.ListIndex >= 0 Then HighlightWindow List1.ItemData(List1.ListIndex)
End Sub

Sub HighlightWindow(hwnd As Long)
Dim rc1 As RECT, rc2 As RECT, rc3 As RECT, rc4 As RECT
GetWindowRect hwnd, rc1
OffsetRect rc1, -rc1.Left, -rc1.Top
rc2 = rc1
rc3 = rc1
rc4 = rc1
rc1.Right = 5
rc2.Bottom = 5
rc3.Left = rc3.Right - 5
rc4.Top = rc4.Bottom - 5
Dim hDC As Long
hDC = GetWindowDC(hwnd)
Dim N As Long
For N = 1 To 10 '<- this must be an even number
InvertRect hDC, rc1
InvertRect hDC, rc2
InvertRect hDC, rc3
InvertRect hDC, rc4
Sleep 100
Next
ReleaseDC hwnd, hDC
End Sub[/tt]
___

Now run the program. All the programs currently running are listed. Double-click any window title in the listbox and it will cause the window to flash.

Note: You need a little tweaking in the code (perhaps some rectangle intersection) to cause a maximized window to flash. Currently they don't appear to flash as the edges of the window are outside the screen area.
 
close, but not quite...

How about a visual ;-)

This is how Spy handles non standard windows...
spy select.jpg


I'm guessing they HAVE to be using regions...
so...

What about...

FrameRgn

...

ExtCreateRegion

or...

OffsetRgn

with...
InvertRgn

wadaya think ?

Have Fun, Be Young... Code BASIC
-Josh

cubee101.gif


PROGRAMMER: (n) Red-eyed, mumbling mammal capable of conversing with inanimate objects.
 
OK...

between both code posts above, and THIS SITE...

I Figured It Out!!!

Here ya go...

Code:
'Region & Graphic Tools
Private Declare Function CreateRectRgn Lib "gdi32.dll" (ByVal X1 As Long, ByVal Y1 As Long, ByVal X2 As Long, ByVal Y2 As Long) As Long
Private Declare Function GetWindowRgn Lib "user32.dll" (ByVal hWnd As Long, ByVal hRgn As Long) As Long
Private Declare Function GetWindowDC Lib "user32" (ByVal hWnd As Long) As Long
Private Declare Function FrameRgn Lib "gdi32.dll" (ByVal hdc As Long, ByVal hRgn As Long, ByVal hBrush As Long, ByVal nWidth As Long, ByVal nHeight As Long) As Long
Private Declare Function CreateSolidBrush Lib "gdi32" (ByVal crColor As Long) As Long
Private Declare Function SetROP2 Lib "gdi32" (ByVal hdc As Long, ByVal nDrawMode As Long) As Long

'Clean Up
Private Declare Function ReleaseDC Lib "user32" (ByVal hWnd As Long, ByVal hdc As Long) As Long
Private Declare Function DeleteObject Lib "gdi32" (ByVal hObject As Long) As Long

Sub HighlightWindow(hWnd As Long)
  Dim hdc As Long, hRgn As Long, hBrush As Long
  hBrush = CreateSolidBrush(vbBlack) 'Create Brush
  hRgn = CreateRectRgn(0, 0, 0, 0)   'Create Region
  GetWindowRgn hWnd, hRgn            'Clone Window Region
  hdc = GetWindowDC(hWnd)            'Get Window's hDC
  SetROP2 hdc, vbNotXorPen           'Set XOR Drawing Mode
  FrameRgn hdc, hRgn, hBrush, 3, 3   'Draw Frame
  ReleaseDC hWnd, hdc                'Clean up hDC
  DeleteObject hRgn                  'Clean up hRgn
  DeleteObject hBrush                'Clean up hBrush
End Sub

First Call Draws Border...
Second Call undoes the First...

Thanks Guys !!!

Have Fun, Be Young... Code BASIC
-Josh

cubee101.gif


PROGRAMMER: (n) Red-eyed, mumbling mammal capable of conversing with inanimate objects.
 
And for the comparison...

SPY:
spy select.jpg


MINE:
my select.jpg


Looks Good To Me ;-)

Have Fun, Be Young... Code BASIC
-Josh

cubee101.gif


PROGRAMMER: (n) Red-eyed, mumbling mammal capable of conversing with inanimate objects.
 
Hmmm...

strongm said:
There's always DrawFocusRect, DrawEdge or FrameRgn - but each has drawbacks - in my opinion - for the task you outline

You mentioned this method...
Why do you think it has a drawback?

Have Fun, Be Young... Code BASIC
-Josh

cubee101.gif


PROGRAMMER: (n) Red-eyed, mumbling mammal capable of conversing with inanimate objects.
 
>>I've never found such a thing in GDI

Never found what? the XOR brush?

You use a Solid Brush and set the DC's drawmode to vbNotXorPen with SetROP2

Have Fun, Be Young... Code BASIC
-Josh

cubee101.gif


PROGRAMMER: (n) Red-eyed, mumbling mammal capable of conversing with inanimate objects.
 
I put FrameRgn in as an afterthought. To be honest, it doesn't suffer too many drawbacks, apart from when an 'odd' shaped window achieves its odd shape though the SetLayeredWindowAttributes method rather than through regions
 
>> apart from when an 'odd' shaped window achieves its odd shape though the SetLayeredWindowAttributes method rather than through regions

What would be a case for that?

I thought you used SetLayered.... to set transparency and the like... how do you set the shape with it???

BTW, THNX 4 THE
star.gif
;-)

Have Fun, Be Young... Code BASIC
-Josh

cubee101.gif


PROGRAMMER: (n) Red-eyed, mumbling mammal capable of conversing with inanimate objects.
 
Well, the illustration explained a lot.

After seeing that post of yours I also tried to do this of my own got to almost the same solution except the SetROP2 bit. I was using a solid black brush with default drawing mode. Rest of the technique was same.

Here's what I had got so far.
___
[tt]
Private Declare Function GetWindowRgn Lib "user32" (ByVal hwnd As Long, ByVal hRgn As Long) As Long
Private Declare Function CreateRectRgn Lib "gdi32" (ByVal X1 As Long, ByVal Y1 As Long, ByVal X2 As Long, ByVal Y2 As Long) As Long
Private Declare Function GetCursorPos Lib "user32" (lpPoint As POINTAPI) As Long
Private Declare Function WindowFromPoint Lib "user32" (ByVal xPoint As Long, ByVal yPoint As Long) As Long
Private Declare Function RedrawWindow Lib "user32" (ByVal hwnd As Long, lprcUpdate As Any, ByVal hrgnUpdate As Long, ByVal fuRedraw As Long) As Long
Private Declare Function FrameRgn Lib "gdi32" (ByVal hdc As Long, ByVal hRgn As Long, ByVal hBrush As Long, ByVal nWidth As Long, ByVal nHeight As Long) As Long
Private Declare Function GetStockObject Lib "gdi32" (ByVal nIndex As Long) As Long
Private Declare Function GetWindowDC Lib "user32" (ByVal hwnd As Long) As Long
Private Declare Function ReleaseDC Lib "user32" (ByVal hwnd As Long, ByVal hdc As Long) As Long
Private Declare Function DeleteObject Lib "gdi32" (ByVal hObject As Long) As Long
Private Declare Function GetAncestor Lib "user32" (ByVal hwnd As Long, ByVal gaFlags As Long) As Long
Private Declare Function GetWindowRect Lib "user32" (ByVal hwnd As Long, lpRect As RECT) As Long
Private Declare Function OffsetRect Lib "user32" (lpRect As RECT, ByVal x As Long, ByVal y As Long) As Long
Private Declare Function EqualRgn Lib "gdi32" (ByVal hSrcRgn1 As Long, ByVal hSrcRgn2 As Long) As Long
Private Declare Function SetROP2 Lib "gdi32" (ByVal hdc As Long, ByVal nDrawMode As Long) As Long

Private Type POINTAPI
x As Long
y As Long
End Type
Private Type RECT
Left As Long
Top As Long
Right As Long
Bottom As Long
End Type
Const RGN_AND = 1
Const BLACK_BRUSH = 4
Const GA_ROOT = 2
Const RDW_INVALIDATE = &H1
Const RDW_FRAME = &H400

Private Sub Form_Load()
Show
Dim hwnd As Long, hWndCurrent As Long, hRgnNull As Long, hRgn As Long
Dim pt As POINTAPI, hBrush As Long, hdc As Long
hBrush = GetStockObject(BLACK_BRUSH)
hRgnNull = CreateRectRgn(0, 0, 0, 0)
While DoEvents
GetCursorPos pt
hwnd = WindowFromPoint(pt.x, pt.y)
hwnd = GetAncestor(hwnd, GA_ROOT)
If hWndCurrent <> hwnd Then
RedrawWindow hWndCurrent, ByVal 0&, 0, RDW_INVALIDATE Or RDW_FRAME
hWndCurrent = hwnd
hRgn = CreateRectRgn(0, 0, 0, 0)
GetWindowRgn hwnd, hRgn
hdc = GetWindowDC(hwnd)
If EqualRgn(hRgn, hRgnNull) Then 'window has null region
'create the default rectangular region
Dim rc As RECT
GetWindowRect hwnd, rc
DeleteObject hRgn
hRgn = CreateRectRgn(0, 0, rc.Right - rc.Left, rc.Bottom - rc.Top)
End If
'this is what I was missing
'SetROP2 hdc, vbNotXorPen
FrameRgn hdc, hRgn, hBrush, 3, 3
DeleteObject hRgn
ReleaseDC hwnd, hdc
End If
Wend
DeleteObject hRgnNull
End Sub[/tt]
___

Just run this program and point any window to get it framed.
Works for both rectangular and non-rectangular windows.

To test this code or your own code you may like to see some cool shaped windows in thread222-972212.

CubeE, we can use the SetLayeredWindowAttributes function for both purposes. To set the transparency of a window or to clip a window using a color mask. See thread222-493597 for examples of both cases.

strongm, you are very thoughtful. Surely this function will not work with windows clipped using this function as they are not clipped using regions.

Do we have other alternatives?
 
Set your forms border style to none, then try the following (with acknowledgement to Hypetia):
Code:
[blue]
Option Explicit

Private Declare Function GetWindowLong Lib "user32" Alias "GetWindowLongA" (ByVal hWnd As Long, ByVal nIndex As Long) As Long
Private Declare Function SetWindowLong Lib "user32" Alias "SetWindowLongA" (ByVal hWnd As Long, ByVal nIndex As Long, ByVal dwNewLong As Long) As Long
Private Declare Function SetLayeredWindowAttributes Lib "user32.dll" (ByVal hWnd As Long, ByVal crKey As Long, ByVal bAlpha As Byte, ByVal dwFlags As Long) As Long

Const GWL_EXSTYLE = (-20)
Const WS_EX_LAYERED = &H80000
Const LWA_COLORKEY = &H1&

Private Sub Form_Load()
    Dim StyleEx As Long
    
    Me.Show
    
    Form1.AutoRedraw = True
    Form1.ScaleMode = vbPixels
    Form1.BackColor = RGB(1, 0, 0)
    
    ' Demonstrating with a couple off offset circles, but this could be ANY
    ' image
    Form1.DrawStyle = 5
    Form1.FillStyle = 0
    Form1.FillColor = RGB(0, 255, 0)
    Form1.Circle (100, 100), 100
    Form1.Circle (175, 175), 100

    StyleEx = GetWindowLong(hWnd, GWL_EXSTYLE)
    StyleEx = StyleEx Or WS_EX_LAYERED
    SetWindowLong hWnd, GWL_EXSTYLE, StyleEx
    SetLayeredWindowAttributes hWnd, RGB(1, 0, 0), 0, LWA_COLORKEY
End Sub[/blue]
 
strongm,
hmmm... you're right... it doesn't work for those...

Is there anything that would work?
Or is that an example why you should use Regions instead?

...Spy selected the Invisible outter Window...


Hypetia,
Cool!!! Your looks really close to what mine does...

I was using this to select Explorer Windows... Here is the Full Module code...
Code:
' Requires reference to:
' Microsoft Shell Controls and Automation
' Microsoft Internet Controls
' Microsoft HTML Object Library
Option Explicit
Private Type POINTAPI
  x As Long
  y As Long
End Type
Private Declare Function GetCursorPos Lib "user32" (lpPoint As POINTAPI) As Long
Private Declare Function WindowFromPoint Lib "user32" (ByVal xPoint As Long, ByVal yPoint As Long) As Long
Private Declare Function GetAncestor Lib "user32" (ByVal hWnd As Long, ByVal gaFlags As Long) As Long

'Region & Graphic Tools
Private Declare Function CreateRectRgn Lib "gdi32.dll" (ByVal X1 As Long, ByVal Y1 As Long, ByVal X2 As Long, ByVal Y2 As Long) As Long
Private Declare Function GetWindowRgn Lib "user32.dll" (ByVal hWnd As Long, ByVal hRgn As Long) As Long
Private Declare Function GetWindowDC Lib "user32" (ByVal hWnd As Long) As Long
Private Declare Function FrameRgn Lib "gdi32.dll" (ByVal hdc As Long, ByVal hRgn As Long, ByVal hBrush As Long, ByVal nWidth As Long, ByVal nHeight As Long) As Long
Private Declare Function CreateSolidBrush Lib "gdi32" (ByVal crColor As Long) As Long
Private Declare Function SetROP2 Lib "gdi32" (ByVal hdc As Long, ByVal nDrawMode As Long) As Long

'Clean Up
Private Declare Function ReleaseDC Lib "user32" (ByVal hWnd As Long, ByVal hdc As Long) As Long
Private Declare Function DeleteObject Lib "gdi32" (ByVal hObject As Long) As Long

Private LastWnd As Long

Public Function GetBrowserDocument() As IHTMLDocument2
  Dim TargetHWND As Long
  Dim p As POINTAPI
  Dim myShell As Shell
  Dim myBrowserWindow As WebBrowser
  Dim myBrowserDoc As IHTMLDocument2
  GetCursorPos p
  TargetHWND = GetAncestor(WindowFromPoint(p.x, p.y), 2)
  Set myShell = New Shell
  For Each myBrowserWindow In myShell.Windows
  On Error Resume Next
    If myBrowserWindow.hWnd = TargetHWND Then
      If Err = 0 Then
        Set myBrowserDoc = myBrowserWindow.document
        If TargetHWND <> LastWnd Then
          If LastWnd <> 0 Then HighlightWindow LastWnd
          HighlightWindow TargetHWND
          LastWnd = TargetHWND
        End If
      End If
    End If
  On Error GoTo 0
  Next
  Set GetBrowserDocument = myBrowserDoc
End Function

Sub UnHighlightWindow()
  If LastWnd <> 0 Then HighlightWindow LastWnd
  LastWnd = 0
End Sub

Sub HighlightWindow(hWnd As Long)
  Dim hdc As Long
  Dim hRgn As Long
  Dim hBrush As Long
  hBrush = CreateSolidBrush(vbBlack)
  hRgn = CreateRectRgn(0, 0, 0, 0)
  GetWindowRgn hWnd, hRgn
  hdc = GetWindowDC(hWnd)
  SetROP2 hdc, vbNotXorPen
  FrameRgn hdc, hRgn, hBrush, 3, 3
  ReleaseDC hWnd, hdc
  DeleteObject hRgn
  DeleteObject hBrush
End Sub

Then the Form Code:
Code:
Dim TargetDoc As IHTMLDocument2

'Selects the Explorer Window's Document
'Requires:
'  PictureBox (Picture1) [Drag From this box onto an explorer window to select]
'*Note: Picture Box turns blue when window is selected...
Private Sub Picture1_MouseMove(Button As Integer, Shift As Integer, x As Single, y As Single)
  If Button Then
    Set TargetDoc = GetBrowserDocument()
    If TargetDoc Is Nothing Then
      Picture1.BackColor = vbButtonFace
    Else
      Picture1.BackColor = vbBlue
    End If
  End If
End Sub

'Select Window, hide Border, and Show Source
'(Works for those annoying windows that don't want you to see the source...*cough* Yahoo *cough*)
'Requires:
'  TextBox (Text1) [Multiline w/ scrollbars]
Private Sub Picture1_MouseUp(Button As Integer, Shift As Integer, x As Single, y As Single)
  Dim elem As IHTMLElement
  UnHighlightWindow
  If Not TargetDoc Is Nothing Then
    Text1 = TargetDoc.body.innerHTML
  End If
End Sub

'Get Form Control Data
'Requires:
'  CommandButton (Command1)
'  TextBox (Text1) [Multiline w/ scrollbars]
Private Sub Command1_Click()
  Dim elem As IHTMLElement
  Dim elem2 As IHTMLElement
  Dim frm As IHTMLFormElement
  If Not TargetDoc Is Nothing Then
    Text1 = ""
    For Each frm In TargetDoc.Forms
      Text1 = Text1 & frm.Name & " <FORM>" & vbCrLf
      For Each elem In frm
        Text1 = Text1 & "   " & elem.getAttribute("Name") & " <" & elem.tagName & "> = " & elem.getAttribute("Value") & vbCrLf
        If LCase(elem.tagName) = "select" Then
          For Each elem2 In elem.children
            Text1 = Text1 & "      " & elem2.innerText & " <" & elem2.tagName & ">" & vbCrLf
          Next
        End If
      Next
    Next
  End If
End Sub

'Fill Out A Google Form And search
'Requires:
'  CommandButton (Command2)
'  TextBox (Text2)
Private Sub Command2_Click()
  Dim elem As IHTMLElement
  If Not TargetDoc Is Nothing Then
    TargetDoc.Forms("f").Item("q").Value = Text2
    TargetDoc.Forms("f").Item("btnG").Click
  End If
End Sub

Have Fun, Be Young... Code BASIC
-Josh

cubee101.gif


PROGRAMMER: (n) Red-eyed, mumbling mammal capable of conversing with inanimate objects.
 
>Do we have other alternatives?

To be honest, I can't think of anything off the top of my head.
 
Hypetia said:
To test this code or your own code you may like to see some cool shaped windows in Thread222-972212.

hehehe... the first reply points back to my old thread ;-)

thread222-444672

(I guess I like to use Sonique for examples of these odd forms, eh? ;-))

Have Fun, Be Young... Code BASIC
-Josh

cubee101.gif


PROGRAMMER: (n) Red-eyed, mumbling mammal capable of conversing with inanimate objects.
 
Status
Not open for further replies.

Part and Inventory Search

Sponsor

Back
Top