How to detect whether the focused window is an Edit 'type' control? - c++

How can I detect whether the focused window is an Edit 'type' control? One method I am aware of is using Microsoft Active Accessibility which is looking like it will involve alot of effort using this method.
Is there another method I could use that is simpler?
My use-case is: when an edit control has the focus, store that hwnd.
// Callback set by SetWinEventHook(EVENT_OBJECT_FOCUS, EVENT_OBJECT_FOCUS, NULL, (WINEVENTPROC)&winEventProc, 0, 0, WINEVENT_SKIPOWNPROCESS);
void CALLBACK KeyboardComponent::winEventProc(HWINEVENTHOOK hWinEventHook, DWORD event, HWND hwnd, LONG idObject,
LONG idChild, DWORD dwEventThread, DWORD dwmsEventTime)
{
// if hwnd == "Edit Control" store hwnd to send key input events
// One technique but not comprehensive
TCHAR wndClassName[255];
GetClassName(hwnd, wndClassName, 255);
if (_tcsicmp(wndClassName, _T("edit")) == 0)
targetEdit = hwnd;
// Class names I am receiving are subclassed or new window classes that look and operate like Edit controls.
// Ie when clicking the Firefox address bar I get: MozillaWindowClass
// Ie when clicking the Chrome address bar I get: Chrome_WidgetWin_1
}

Active Accessibility is the correct solution. You can use AccessibleObjectFromEvent() to get an IAccessible interface for the HWND that is triggering your winEventProc hook, and then check the IAccessible::AccRole property for ROLE_SYSTEM_TEXT:
ROLE_SYSTEM_TEXT
The object represents selectable text that allows edits or is designated as read-only.
For example:
// Callback set by SetWinEventHook(EVENT_OBJECT_FOCUS, EVENT_OBJECT_FOCUS, NULL, (WINEVENTPROC)&winEventProc, 0, 0, WINEVENT_SKIPOWNPROCESS);
void CALLBACK KeyboardComponent::winEventProc(HWINEVENTHOOK hWinEventHook, DWORD event, HWND hwnd, LONG idObject,
LONG idChild, DWORD dwEventThread, DWORD dwmsEventTime)
{
IAccessible* pAcc = NULL;
VARIANT varChild;
HRESULT hr = AccessibleObjectFromEvent(hwnd, idObject, idChild, &pAcc, &varChild);
if ((hr == S_OK) && (pAcc != NULL))
{
VARIANT varRole;
hr = pAcc->get_accRole(varChild, &varRole);
if ((hr == S_OK) && (varRole.vt == VT_I4) && (varRole.lVal == ROLE_SYSTEM_TEXT))
{
// ...
}
pAcc->Release();
}
}

For reliable result try using RealGetWindowClass, it should deal with a case when window was subclassed. If you don't care about that use regular GetClassName.
In case you want to handle controls that are not derived from standard Edit class, none of that will work of course.

You can use this code to know if focused window is Edit control
CWnd* pControl;
pControl = this->GetFocus();
if(pControl->IsKindOf(RUNTIME_CLASS(CEdit))){
//----
-----
----//
}
Get more details Here
Convert Cwnd to HWND
pControl->GetSafeHwnd();

Related

How to create a service for monitoring of opening and switching of active application on Windows using Win32 api? [duplicate]

I have been working on a project which needs to detect current active window and get the active window title continuously.
Can anyone explain me how to use SetWinEventHook() function to get Active Window changed message.
[ i used GetForegroundWindow() function with a timer to get the active window. That approach is not very accurate because of the timer. So i need to use it with SetWinEventHook() function. can someone explain me how to do that? ]
hEvent = SetWinEventHook(EVENT_SYSTEM_FOREGROUND , EVENT_SYSTEM_FOREGROUND ,NULL,
WinEventProcCallback, 0, 0, WINEVENT_OUTOFCONTEXT | WINEVENT_SKIPOWNPROCESS);
VOID CALLBACK WinEventProcCallback ( HWINEVENTHOOK hWinEventHook, DWORD dwEvent, HWND hwnd, LONG idObject, LONG idChild, DWORD dwEventThread, DWORD dwmsEventTime)
{
/* how to get active window message */
}
I have found the solution. EVENT_SYSTEM_FOREGROUND Event is the missing piece. The system sends this event even if the foreground window has changed to another window. We can use this event to get the current active window.
VOID CALLBACK WinEventProcCallback ( HWINEVENTHOOK hWinEventHook, DWORD dwEvent, HWND hwnd, LONG idObject, LONG idChild, DWORD dwEventThread, DWORD dwmsEventTime)
{
if (dwEvent == EVENT_SYSTEM_FOREGROUND)
{
/* do something */
}
}

How to track Application closed event in c++ winapp?

I wanted to know if any application in the foreground(except this application) is closed by clicking the cross button on the top-right or any other way like Ctrl + f4.
Here is what I have created so far:
create window event
void CALLBACK WinEventProc(
HWINEVENTHOOK hWinEventHook,
DWORD event,
HWND hwnd,
LONG idObject,
LONG idChild,
DWORD dwEventThread,
DWORD dwmsEventTime
) {
handleProcess(hwnd);
// handleProcess does other operations
}
Call the window event in wWinMain()
...
winDestructionHook = SetWinEventHook(EVENT_OBJECT_DESTROY, EVENT_OBJECT_DESTROY,
NULL, WinEventProc, 0, 0, WINEVENT_OUTOFCONTEXT);
...
The problem here is the window event is triggered without any window-closed action, but I wanted to activate it only on application closed.

How to disable MFC Edit control popup menu additional items?

Is there a clean and easy way to disable "Right to left reading order" and Unicode related messages from a context popup menu for an edit control. Yes, I know that I can subclass and intercept WM_CONTEXTPOPUP, then walk the menu. Attached is the image with menu items in question.
I
I know you said you don't want to subclass, but I don't think it's that painful.
Derive from CEdit, in this case I used the class name CEditContextMenu and add WM_CONTEXTMENU to your message map:
EditContextMenu.cpp
// ...
BEGIN_MESSAGE_MAP(CEditContextMenu, CEdit)
ON_MESSAGE(WM_CONTEXTMENU, &CEditContextMenu::OnContextMenu)
END_MESSAGE_MAP()
// CEditContextMenu message handlers
LRESULT CEditContextMenu::OnContextMenu(WPARAM wParam, LPARAM lParam){
HWINEVENTHOOK hWinEventHook{
SetWinEventHook(EVENT_SYSTEM_MENUPOPUPSTART, EVENT_SYSTEM_MENUPOPUPSTART, NULL,
[](HWINEVENTHOOK hWinEventHook, DWORD Event, HWND hWnd, LONG idObject,
LONG idChild, DWORD idEventThread, DWORD dwmsEventTime){
if (idObject == OBJID_CLIENT && idChild == CHILDID_SELF){
CMenu* pMenu{
CMenu::FromHandle((HMENU)::SendMessage(
hWnd, MN_GETHMENU, NULL, NULL))
};
pMenu->EnableMenuItem(32768, MF_DISABLED);
}
},
GetCurrentProcessId(), GetCurrentThreadId(), WINEVENT_OUTOFCONTEXT)
};
LRESULT ret{ Default() };
UnhookWinEvent(hWinEventHook);
return ret;
}
// ...
Maybe you could do something fancy and watch for WS_EX_RTLREADING and block it some how.
At the end of the day you want to change how the OS functions at a low level. I don't think there is an elegant way to do it organically.

WinApi - How to obtain SHELLDLL_DefView

I am trying to obtain handle to SHELLDLL_DefView.
So, I have this code.
HWND hProgman = FindWindow(L"Progman", NULL);
HWND hWnd = FindWindowEx(hProgman, 0, L"SHELLDLL_DefView", NULL);
Eveyrtihing works OK, until I change in Windows desktop brackground to slideshow. Then when I search with spy++ hierarchy of the windows, than SHELLDLL_DefView has another parent. Now it is #32769 (Desktop) -> WorkerW -> SHELLDLL_DefView. So I can't find it. Problem is that when I try
HWND desktop = GetDesktopWindow();
HWND hWnd = FindWindowEx(desktop , 0, L"WorkerW", NULL);
HWND hWnd = FindWindowEx(hWnd, 0, L"SHELLDLL_DefView", NULL);
Than SHELLDLL_DefView is not found. WorkerW yes.
Can anybody help?
Your code only works on some Windows versions as "SHELLDLL_DefView" can be found under "WorkerW" or "Progman" and as you discovered there can be many windows under the "WorkerW" class (normal in Win7).
Microsoft Docs report EnumWindows() is more reliable than calling GetWindow()/FindWindowEx() functions in loops, so more universal code (tested on Windows 98/Windows 7) would look like this (say you want to refresh the desktop):
BOOL CALLBACK EnumWindowsProc(HWND hwnd, LPARAM lParam) {
HWND hNextWin;
hNextWin = FindWindowExA(hwnd, 0, "SHELLDLL_DefView", 0);
if ( hNextWin ) {
// The correct desktop shell window under Progman/WorkerW will have only 1 child window!
if ( GetNextWindow(hNextWin, GW_HWNDNEXT) || GetNextWindow(hNextWin, GW_HWNDPREV) )
return true;
// We found correct handle
PostMessageA(hNextWin, WM_KEYDOWN, VK_F5, 0);
return false;
}
return true;
}
void main() {
EnumWindows(&EnumWindowsProc, 0);
}
I found the answer. Need to iterate through all WorkerW.
HWND destop = GetDesktopWindow();
HWND hWorkerW = NULL;
HWND hShellViewWin = NULL;
do
{
hWorkerW = FindWindowEx(destop, hWorkerW, L"WorkerW", NULL);
hShellViewWin = FindWindowEx(hWorkerW, 0, L"SHELLDLL_DefView", 0);
} while (hShellViewWin == NULL && hWorkerW != NULL);

How to get HWND of an embedded web browser control in MFC

I'm using the embedded web browser control in my dialog-based MFC window and I need to know the HWND of the web browser control in it. I was able to find the following code that claims to retrieve it:
HWND hWndWebBrowser = NULL;
LPUNKNOWN unknown = m_browser.GetControlUnknown();
IWebBrowser2* pWB = NULL;
if(SUCCEEDED(unknown->QueryInterface(IID_IWebBrowser2,(void **)&pWB)))
{
CComPtr<IServiceProvider> pServiceProvider;
if (SUCCEEDED(pWB->QueryInterface(IID_IServiceProvider, (void**)&pServiceProvider)))
{
CComPtr<IOleWindow> pWindow;
if (SUCCEEDED(pServiceProvider->QueryService(SID_SShellBrowser, IID_IOleWindow, (void**)&pWindow)))
{
SHANDLE_PTR hBrowser = 0;
if (SUCCEEDED(pWindow->GetWindow(&hBrowser)))
{
hWndWebBrowser = (HWND)hBrowser;
}
}
}
}
if(unknown)
{
unknown->Release();
}
but the problem is that when it runs, it returns a handle, but not the one I would expect. The best way to illustrate it is with this Spy++ screenshot:
I understand that I can use EnumChildWindows and look for a window with the Internet Explorer_Server class, but I'm somewhat concerned about using this undocumented class name.
Does anyone have a better way to retrieve that (web browser) window handle?
Per Obtaining the HWND for the WebBrowser control, you can use following function to retrieve HWND.
IOleWindow *pOWin;
HWND hBWnd;
HRESULT hRes = m_pBrowserApp->QueryInterface(IID_IOleWindow, (void **)&pOWin);
if (SUCCEEDED(hRes)) {
hRes = pOWin->GetWindow(&hBWnd);
if (SUCCEEDED(hRes)) {
// Place hBWnd-manipulating code here
}
pOWin->Release(); // Missing from the MS example
}
Because the class names (Shell DocObject View and Internet Explorer_Server) could change, the above code should be preferred, although it is unlikely given the fact that Internet Explorer is now discontinued.
The lexical of the question is a little tricky.
The HWND of the (Web Browser) is indeed the answer
that you posted and the answer posted by Santosh Dhanawade.
When a document is loaded, the web browser control creates a
new window or iframe, see the DWebBrowserEvents2::DocumentComplete event.
Event handler parameters:
" pDisp [in] "
A pointer to the IDispatch interface of the window or frame in which the document is loaded. This IDispatch interface can be queried for the IWebBrowser2 interface.
so, changing the question:
"Does anyone have a better way to retrieve that (web browser) window handle?"
to:
"Does anyone have a better way to retrieve that (window or iframe) window handle?"
we have that the window or iframe HWND that you are locking for,
will be abailable after that the document has been completed loaded.
Which means that we can do the follow:
Implement a DocumentComplete event handler throw a raw c or c++ implementation of
IDispatch or an ATL DispEventImpl or ATL DispEventSimpleImpl.
See Understanding COM Event Handling.
Sink our event handler into the the web browser control to get the events report.
And get the window or iframe HWND from the DocumentComplete event:
assuming a raw c++ IDispatch implementation:
IFACEMETHODIMP DWebBrowserEvents2Impl::Invoke(DISPID dispIdMember, REFIID riid, LCID lcid, WORD wFlags, DISPPARAMS * pDispParams, VARIANT * pVarResult, EXCEPINFO * pExcepInfo, UINT * puArgErr)
{
if (dispIdMember == DISPID_DOCUMENTCOMPLETE) {
VARIANT variantDispatch;
VariantInit(&variantDispatch);
HRESULT hr = DispGetParam(pDispParams, 0, VT_DISPATCH, &variantDispatch, NULL);
if (SUCCEEDED(hr)) {
IOleWindow* iOleWindow;
hr = variantDispatch.pdispVal->QueryInterface(IID_IOleWindow, (LPVOID*) &iOleWindow);
if (SUCCEEDED(hr)) {
HWND hwnd;
hr = iOleWindow->GetWindow(&hwnd);
iOleWindow->Release();
if (SUCCEEED(hr)){
//now the hwnd correponds to the Internet Explorer_Server window.
//Do what ever you want with the HWND handler.
}
}
}
return S_OK;
}
return E_NOTIMPL;
}
From my experience, the window we're looking for is a direct descendance of the CHtmlView derived CWnd, so I use this hack to get the window and set the focus to it:
static CWnd* findChildWebbrowser(CWnd* pWnd) {
if(pWnd == NULL) { return NULL; }
CWnd* pC = pWnd->GetWindow(GW_CHILD);
if(pC == NULL) { return NULL; };
CString buf;
::GetClassName(pC->GetSafeHwnd(), buf.GetBuffer(2048), 2047);
buf.ReleaseBuffer();
if(buf == _T("Internet Explorer_Server")) {
return pC;
}
return findChildWebbrowser(pC);
}
void CMyWebView::OnSetFocus(CWnd* pOldWnd) {
// CHtmlView::OnSetFocus(pOldWnd);
CWnd* pIE = findChildWebbrowser(this);
if(pIE!=NULL) {
// this makes cursor/page keys work
pIE->SetFocus();
// this makes the TAB key work
pIE->SendMessage(WM_LBUTTONDOWN);
pIE->SendMessage(WM_LBUTTONUP);
}
}