Reputation: 629
I am using MS Access 2016 VBA to automate access to an external application. The external application window has a video that is displayed in a child window.
If I use spyxx.exe, I can use the "Finder Tool" to obtain the video control's Handle (which changes, of course), Caption ("panel"), Class ("wxWindowNR"), and Style (52000000). When I use the handle returned by spyxx.exe I can successfully use that handle to bring the correct application to the top and activate it. But since that handle changes, I need to obtain it dynamically using MS Access VBA.
The problem I'm having is that I cannot figure out how to obtain that same handle that spyxx.exe comes up with when I use the FindWindowEx API to try to get the child video window's handle. Here's what I'm trying (and a number of variations on the theme): The declartion is:
Public Declare Function FindWindowEx Lib "user32.dll" Alias "FindWindowExA" (ByVal hwndParent As Long, ByVal hwndChildAfter As Long, ByVal lpszClass As String, ByVal lpszWindow As String) As Long
and the code to (try) to get the child video window's handle is (where WinHand is the parent window's handle):
FindWindowEx(WinHand, 0, "wxWindowNR", "panel")
I know WinHand is correct for the parent window because using WinHand I can make the application the active, top-most window. However, I can never get FindWindowEx to return the handle that spyxx.exe shows is the handle of the child "panel" window.
It does return handles when I leave the child window's name blank like this:
FindWindowEx(WinHand, 0, "wxWindowNR", "")
But never the correct handle that spyxx.exe shows.
From searching the net most of the day, it appears I may need to do something with the EnumChildWindows API, but I do not know how to reference it in MS Access VBA nor how to loop through the returned windows to find the "panel" window handle.
Upvotes: 0
Views: 3844
Reputation: 629
For the benefit of those who may run into a similar problem in the future, I am posting the solution I used (although I would love to see a solution offered using EnumChildWindows as that seems like it is probably the more elegant approach, but I am not savvy enough with APIs to know how to set it up).
The FindWindowEx could not find the child video control window I was looking for because that control was buried as a child of a child of a child of a child of a child of a parent. FindWindowEx will only search the children of the immediately preceding parent. Therefore, you have to nest the search for the buried child control.
Steps I followed:
Final Step: Now in the VBA code, to find the window handle of the target child window control, you will have to nest the FindWindowEx commands starting with the parent window and working your way down like this (replace "wxWindowNR" with whatever window class is relevant for the child control you are trying to find):
FindWindowEx (ParentWindowHandle, 0, "wxWindowNR", "[caption from steps 9 to 11]")
For example, here is the code I had to use (where ChildWindow5 is the handle of the video control window that I was looking for; the While...Wend commands are needed because in the application I was targeting, not all child windows existed immediately when the application was run):
ParentWindow = 0
While ParentWindow = 0
ParentWindow = FindWindow("Target Window Caption")
Wend
ChildWindow1 = 0
While ChildWindow1 = 0
ChildWindow1 = FindWindowEx(CLng(ParentWindow), 0, "wxWindowNR", "ID_BOOKMARK_SPLITTERWINDOW")
Wend
ChildWindow2 = 0
While ChildWindow2 = 0
ChildWindow2 = FindWindowEx(CLng(ChildWindow1), 0, "wxWindowNR", "ID_TOPPANEL_SPLITTERWINDOW")
Wend
ChildWindow3 = 0
While ChildWindow3 = 0
ChildWindow3 = FindWindowEx(CLng(ChildWindow2), 0, "wxWindowNR", "ID_MAINDISPLAY_PANEL")
Wend
ChildWindow4 = 0
While ChildWindow4 = 0
ChildWindow4 = FindWindowEx(CLng(ChildWindow3), 0, "wxWindowNR", "ID_VIDEODISPLAY_PANEL")
Wend
ChildWindow5 = 0
While ChildWindow5 = 0
ChildWindow5 = FindWindowEx(CLng(ChildWindow4), 0, "wxWindowNR", "panel")
Wend
Notice that each subsequent search for a child window handle references the prior parent window.
That worked for me. I still think that if someone can point out how to do this with EnumChildWindows, the solution would likely be far more elegant.
Upvotes: 2