I have a third party app that I want to control from my own application. The third party app is a single main window with several controls, one of those controls being a Tab Control window containing about a dozen tab pages.
Launching the third part app manually and using Spy++ (Visual C++ .NET), I see that only the default tab page can be seen by Spy++, the other tab pages are presumably not instantiated yet. I confirmed this by manually clicking on one of the other tab pages, and then Spy++ could see that page (window) and all the controls (child windows) on that page.
Since the controls I wish to manipulate remotely are not on the default tab page when the program launches, I have to display the tab page of interest before I can proceed.
So, the order of business is:
1) launch the third party app remotely
2) bring up the tab page of interest
3) get the window handles of the controls on the new tab page
4) manipulate the controls on the tab page to achieve my goal
5) close the app
Launching (and closing) the app was not a problem. Since the app (when focused) responds to keyboard shortcuts Ctrl-PageUp and Ctrl-PageDown to switch tabs, my first approach was to emulate this programmatically. I got the window handle of the third party app, and tried the following code:
This did absolutely nothing. I have no idea why. So question #1 – why didn’t this approach work?
Being resourceful, I tried a different approach. Spy++ told me that the name of the Tab Control window in the third party app was "SysTabControl32". Using this information and EnumChildWindows() I obtained the handle of this window and sent messages to it directly. I used two macros (TabCtrl_SetCurSel() and TabCtrl_SetCurFocus()) to select tab #1 (the tab of interest) and give it focus.
This had the following bizarre result – the TAB_OF_INTEREST_INDEX was in fact selected, but the visible contents of the displayed tab page still remained the same as before, i.e., it still looked like the original default tab page when the app first came up. This actually astonished me. I consider this to be an “illegal” or perhaps “incomplete” state, as though the Tab Control changed its tab index but didn’t instantiate or draw the contents (i.e., child controls) of the newly selected tab page.
So question #2 – what’s going on here? What have I forgotten to do?
At this point I’m completely stumped. Until I can get the desired tab page selected, instantiated and displayed, I can’t proceed toward my goal. Can anyone help? Or perhaps suggest an entirely different method for changing tab pages on a third party app?
Thanks in advance for your help.
Launching the third part app manually and using Spy++ (Visual C++ .NET), I see that only the default tab page can be seen by Spy++, the other tab pages are presumably not instantiated yet. I confirmed this by manually clicking on one of the other tab pages, and then Spy++ could see that page (window) and all the controls (child windows) on that page.
Since the controls I wish to manipulate remotely are not on the default tab page when the program launches, I have to display the tab page of interest before I can proceed.
So, the order of business is:
1) launch the third party app remotely
2) bring up the tab page of interest
3) get the window handles of the controls on the new tab page
4) manipulate the controls on the tab page to achieve my goal
5) close the app
Launching (and closing) the app was not a problem. Since the app (when focused) responds to keyboard shortcuts Ctrl-PageUp and Ctrl-PageDown to switch tabs, my first approach was to emulate this programmatically. I got the window handle of the third party app, and tried the following code:
Code:
SendMessage(appWindow,WM_SETFOCUS,0,0);
SendMessage(appWindow,WM_KEYDOWN,VK_CONTROL,0);
SendMessage(appWindow,WM_KEYDOWN,VK_NEXT,0);
SendMessage(appWindow,WM_KEYUP,VK_NEXT,0);
SendMessage(appWindow,WM_KEYUP,VK_CONTROL,0);
SendMessage(appWindow,WM_PAINT,0,0);
Being resourceful, I tried a different approach. Spy++ told me that the name of the Tab Control window in the third party app was "SysTabControl32". Using this information and EnumChildWindows() I obtained the handle of this window and sent messages to it directly. I used two macros (TabCtrl_SetCurSel() and TabCtrl_SetCurFocus()) to select tab #1 (the tab of interest) and give it focus.
Code:
static void switchToTabOfInterest(HWND appWindow)
{
HWND tabControlWindow;
tabControlWindow = NULL;
EnumChildWindows(appWindow,getTabCtrlWindow,(LPARAM)&tabControlWindow);
if (tabControlWindow != NULL) //class name = SysTabControl32
{
TabCtrl_SetCurSel(tabControlWindow,TAB_OF_INTEREST_INDEX);
TabCtrl_SetCurFocus(tabControlWindow, TAB_OF_INTEREST_INDEX);
SendMessage(tabControlWindow,WM_ERASEBKGND,0,0);
SendMessage(tabControlWindow,WM_PAINT,0,0);
}
}
BOOL CALLBACK getTabCtrlWindow(HWND handle,LPARAM pointer)
{
TCHAR name[128];
GetClassName(handle,(LPSTR)&name,sizeof(name));
if (_tcscmp(name,_T("SysTabControl32")) == 0)
{
*reinterpret_cast<HWND*>(pointer) = handle;
return(false); //we're done, no more child windows
}
else
return(true);
}
So question #2 – what’s going on here? What have I forgotten to do?
At this point I’m completely stumped. Until I can get the desired tab page selected, instantiated and displayed, I can’t proceed toward my goal. Can anyone help? Or perhaps suggest an entirely different method for changing tab pages on a third party app?
Thanks in advance for your help.