Unable to receive / capture Windows Messages - c++

I'm fairly new to MFC and the Message handling context.
I've a DLL Consumer application, which has a CFrameWndEx derived class,CMainFrame. Now this calls a DLL, which puts a CDialog etc. into this MainFrame window.
I wish to receive certain messages into my application.
So what I have done is, declared the expected messages in the Message Map, of the DLL Consumer application, and defined the appropriate message handlers.
Now, even though I can see that the application is being sent those registered messages, I'm not able to receive / handle them in the Consumer Window, i.e., nothing happens when those messages are broadcast.
Mainfrm.h
class CMainFrame : public CFrameWndEx
{
public:
CMainFrame();
protected:
DECLARE_DYNAMIC(CMainFrame)
public:
void OnFileDialogdisplay(void);
afx_msg LRESULT OnLogonChanged(WPARAM,LPARAM);
afx_msg LRESULT OnLanguageChanged(WPARAM,LPARAM);
afx_msg LRESULT OnShutdownRequested(WPARAM,LPARAM);
afx_msg LRESULT OnReconnectServer(WPARAM,LPARAM);
afx_msg LRESULT OnChangeRole(WPARAM,LPARAM);
}
Mainfrm.cpp
<some header files>
static UINT UWM_LOGON_CHANGED = ::RegisterWindowMessage(UWM_LOGON_CHANGE);
static UINT UWM_LANGUAGE_CHANGED = ::RegisterWindowMessage(UWM_LANGUAGE_CHANGE);
static UINT UWM_RECONNECT = ::RegisterWindowMessage(UWM_RECONNECT_SERVER);
static UINT UWM_SHUTDOWN_REQUESTED = ::RegisterWindowMessage(UWM_REQUEST_SHUTDOWN);
static UINT UWM_ROLE = ::RegisterWindowMessage(UWM_ROLE_CHANGE);
BEGIN_MESSAGE_MAP(CMainFrame, CFrameWndEx)
ON_WM_CREATE()
ON_WM_SETFOCUS()
ON_COMMAND(ID_VIEW_CUSTOMIZE, &CMainFrame::OnViewCustomize)
ON_REGISTERED_MESSAGE(AFX_WM_CREATETOOLBAR, &CMainFrame::OnToolbarCreateNew)
ON_COMMAND(ID_FILE_DIALOGDISPLAY, &CMainFrame::OnFileDialogdisplay)
ON_REGISTERED_MESSAGE(UWM_LOGON_CHANGED, OnLogonChanged)
ON_REGISTERED_MESSAGE(UWM_LANGUAGE_CHANGED, OnLanguageChanged)
ON_REGISTERED_MESSAGE(UWM_SHUTDOWN_REQUESTED, OnShutdownRequested)
ON_REGISTERED_MESSAGE(UWM_RECONNECT, OnReconnectServer)
ON_REGISTERED_MESSAGE(UWM_ROLE, OnChangeRole)
//ON_WM_NCCALCSIZE()
END_MESSAGE_MAP()
//code to register to Main server application to be able to receive messages
void manageregistration(CMainFrame* pFrame, bool flag)
{
if (flag)
{ // registration
HWND MyHandle = (HWND)pFrame->GetActiveWindow();
RegisterApmsClientPgm(_T("AAUserInterface"), MyHandle);
}
}
//Handlers
LRESULT CMainFrame::OnShutdownRequested(WPARAM,LPARAM lp)
{
AfxMessageBox(_T("Error"),MB_ICONERROR | MB_OK);
testProgram();
return 0;
}
LRESULT CMainFrame::OnChangeRole(WPARAM,LPARAM lp)
{
AfxMessageBox(_T("Error"),MB_ICONERROR | MB_OK);
testProgram();
return 0;
}
// etc etc.etc.
So, after all this, I can see that the Consumer application, is registered to receive these messages from another application which broadcasts them.
However, upon creating the condition where the messages are being broadcast, and they are as I can verify from other applications which receive them, no such message is being caught in my application.
I am not sure where the problem could be. The window is always on top, albeit with another CDialog derived DLL inside it.

Try using pFrame->m_hWnd. You can't assume that the Mainframe window is always active.

Related

How to handle mouse clicks in CMainFrame

How can I detect in an "empty" CMainFrame mouse clicks? With empty I mean a MDI which has not yet any document/view.
I have tried to detect mouse clicks with:
afx_msg void OnLButtonDown(UINT nFlags, CPoint point);
BOOL CMainFrame::PreTranslateMessage(MSG* pMsg);
MDI main frame windows have an 'invisible' client window that occupies the client area of the main frame. This window is inaccessible using 'normal' class override techniques but, if that main frame window is derived from either CMDIFrameWnd or CMDIFrameWndEx, you can use its m_hWndMDIClient member (the HWND of that invisible window) to subclass it, by overriding its WindowProc.
I do this (actually, to draw in that client area) in an override of the main frame's UpdateWindow procedure, using a bool member variable (set to false on construction) to keep track of whether or not the subclassing has already been done.
Here's a possible solution (adapted from my own code) that will likely work for intercepting mouse clicks. (I tested it and did actually get the Beep() diagnostic on mouse clicks!)
// Local function pointer to store the 'original' (default) window procedure...
LRESULT (CALLBACK *DefCliPrc)(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) = nullptr;
// Static definition of our override procedure...
static LRESULT CALLBACK ClientProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
LRESULT answer = DefCliPrc(hWnd, uMsg, wParam, lParam); // First, call default proc.
if (uMsg == WM_LBUTTONDOWN) {
Beep(1000,1000); // Make a sound to show that it's working!
// <Insert your handling code here>
}
//...
// Intercept/handle other messages, as required ...
//...
return answer;
}
// Override of the UpdateWindow function, to enact the subclassing...
void MyMainFrame::UpdateWindow(void)
{
if (!funchange) { // Only do the sub-classing ONCE ...
DefCliPrc = (WNDPROC)(intptr_t)(::GetWindowLongPtr(m_hWndMDIClient, GWLP_WNDPROC));
::SetWindowLongPtr(m_hWndMDIClient, GWLP_WNDPROC, (intptr_t)(ClientProc));
funchange = true; // Set this 'flag' to prevent repetition!
}
CMDIFrameWnd::UpdateWindow(); // Should always call base class
return;
}

MFC - Cannot Post Message to a custom class derived from CWnd

I have a custom class derived from CWnd that I would like to post a message to from a worker thread. I am using the PostMessage function to achieve this. The first argument to PostMessage is the HWND type handle to my class, and the next is the message I would like handled. For the first parameter, I generate the handle to my class using GetSafeHwnd() function, and for the second parameter, I use WM_USER+3. Also, I declare a message map inside my class header file, and add an entry for the message handler inside the BEGIN_MESSAGE_MAP and END_MESSAGE_MAP block. However, my handler is not getting called. I have also checked the return value of PostMessage function, it is 1, that means success.
Here is my code :
Inside MyClass.h
class CMyClass : CWnd
{
....
....
public:
void InitHandle();
protected:
afx_msg LRESULT OnMessageReceived(WPARAM wParam, LPARAM lParam);
DECLARE_MESSAGE_MAP()
}
Inside MyClass.cpp
#define WM_MY_MESSAGE WM_USER+3
HWND handleToMyClassWindow;
BEGIN_MESSAGE_MAP(CMyClass, CWnd)
ON_MESSAGE(WM_MY_MESSAGE, OnMessageReceived)
END_MESSAGE_MAP()
LRESULT CMyClass::OnMessageReceived(WPARAM wParam, LPARAM lParam)
{ .... }
void CMyClass::InitHandle()
{
handleToMyClassWindow = GetSafeHwnd();
}
Inside Worker thread
UINT WorkerThreadFunction(LPVOID pParam )
{
....
PostMessage(handleToMyClassWindow, WM_MY_MESSAGE, NULL, NULL);
....
}
My question is, what are the possible reasons for the OnMessageReceived handler to not be called.
P.S.
I take care that the calling object calls the InitHandle() function.
I tried the same technique with the View class (derived from CView) of my program, and it works there, but fails here.
You cannot post to a window if it has not been created. GetSafeHwnd() will return NULL if you have not actually created a window using your class.

FromHandlePermanent always returns null in injected DLL

I am writing a test automation program, that must interact with a grid control in a legacy MFC application. My program must connect to the legacy app, and read the data from the grid.
I know the HWND of the window that contains the grid, and so now I need to find the CWnd-derived class pointer associated with that HWND. CWnd::FromHandlePermanent seems to be my friend, but yes, I know, you cannot call CWnd::FromHandlePermanent from outside the application, as the AFX window map (afxMapHWND()) is only contained in the target application.
Therefore, I inject a DLL (using CreateRemoteThread/LoadLibrary) into the target app, and get it to call FromHandlePermanent. But even this is not good enough, because I am not in the thread of the HWND, and afxMapHWND() is looking at the wrong local thread storage.
Therefore, in my injected DLL, I also (temporarily) subclass the WndProc of the HWND (SetWindowLong etc), then call SendMessage. Now I am in the correct thread (the main thread of the target application) and I try to call CWnd::FromHandlePermanent with my HWND, but it returns NULL!!
If I look at afxMapHWND()->m_permanentMap->m_nCount, we see it is 0. So there are NO attached classes in the permanentMap, which seems wrong to me.
So how can I get the derived CWnd pointer??
Some other info:
The Target application is statically linked to MFC
It's a different version of MFC, the windowclass is AfxWnd70s
I am using VS2010 to compile the injected DLL
The injected DLL also links statically to the (VS2010) MFC libraries.
Here is the code in the injected DLL:
// this is how we pass the HWND to the target DLL
// (this shared segment is also loaded in calling app)
#pragma data_seg (".shared")
__declspec(dllexport) HWND g_hWnd = 0;
#pragma data_seg ()
#pragma comment(linker,"/SECTION:.shared,RWS")
BEGIN_MESSAGE_MAP(CLibSpyMFCDllApp, CWinApp)
END_MESSAGE_MAP()
CLibSpyMFCDllApp::CLibSpyMFCDllApp()
{
}
CLibSpyMFCDllApp theApp;
extern CHandleMap* PASCAL afxMapHWND(BOOL bCreate = FALSE);
UINT g_WM_GETGRIDDATA = 0;
WNDPROC wpOrigEditProc;
LRESULT CALLBACK SpySubProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
if (g_WM_GETGRIDDATA != 0 && message == g_WM_GETGRIDDATA) {
CWnd * target1 = CWnd::FromHandlePermanent(hWnd);
// fails - target1 is null
return 0;
}
return CallWindowProc((WNDPROC ) wpOrigEditProc, hWnd, message, wParam, lParam);
}
BOOL CLibSpyMFCDllApp::InitInstance()
{
CoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
CWinApp::InitInstance();
if (g_hWnd) {
g_WM_GETGRIDDATA = RegisterWindowMessage(L"GetGridData");
wpOrigEditProc = (WNDPROC) SetWindowLong(g_hWnd, GWL_WNDPROC, (LONG) SpySubProc);
::SendMessage(g_hWnd, g_WM_GETGRIDDATA, 0, 0);
SetWindowLong(g_hWnd, GWL_WNDPROC, (LONG) wpOrigEditProc);
}
return TRUE;
}

Can't get the handle of a Cwnd Class in MFC Windowless Activex?

I have asked two questions earlier about this and for each post there was some solutions i tried them, but the problem still exist.
My first question was : why a windowless Activex does not return the Handle. the suggestion was "change the creation setting an make windowless activate off, i have tried it but still m_hWnd property has returned zero as GetSafeHwnd() method has did.
the second one was the same question this one focused on COleControl class and it's ancestor CWnd. the solution was as this "Create invisible window somewhere in your control initialization code. Handle the messages sent to this window, and call controls methods directly". so i did that but the created class still returns zero handle.
here is my new invisible class source:
// moWind.cpp : implementation file
//
#include "stdafx.h"
#include "PINActive.h"
#include "moWind.h"
#include "include\xfspin.h"
#include <math.h>
// moWind
IMPLEMENT_DYNAMIC(moWind, CWnd)
moWind::moWind(){}
moWind::~moWind(){}
//=============================================================
LRESULT moWind::OnExecuteEvent (WPARAM wParam, LPARAM lParam)
{
WFSRESULT *pResult = (WFSRESULT *)lParam;
CString EK=_T("");
CString str;
int reskey=0;
if (pResult->u.dwEventID=WFS_EXEE_PIN_KEY)
{
LPWFSPINKEY pressedkey;
pressedkey=(LPWFSPINKEY)pResult->lpBuffer;
reskey = log10((double)pressedkey->ulDigit) / log10((double)2);
EK.Format("%d",reskey);
xfsOnKeyEvent->OnKeyRecieved(reskey);
}
else
{
str.Format("ExecuteEvent: ID = %d\r\n", pResult->u.dwEventID);
}
MessageBox("a Execute message Recieved");
return 0;
}
BEGIN_MESSAGE_MAP(moWind, CWnd)
ON_MESSAGE(WFS_EXECUTE_EVENT,OnExecuteEvent)
END_MESSAGE_MAP()
and this is .h file of the class:
// moWind.h
class IXFSEvents
{
protected:
IXFSEvents(){};
virtual ~IXFSEvents(){};
public:
virtual void OnKeyRecieved(int key)=0;
};
class moWind : public CWnd
{
DECLARE_DYNAMIC(moWind)
public:
moWind();
virtual ~moWind();
void Register(IXFSEvents* obj)
{
xfsOnKeyEvent= obj;
}
protected:
IXFSEvents* xfsOnKeyEvent;
LRESULT OnExecuteEvent (WPARAM wParam, LPARAM lParam);
DECLARE_MESSAGE_MAP()
};
and at the end here this the way I've used this class in my Activex:
in the myActivex.h file:
include "moWind.h"
class CmyActivexCtrl : public COleControl, public IXFSEvents
{
...
Class definition
...
protected:
moWind tmpWind;
.
.
};
finally in the creation method of myActivex i have initialized the component callback method an wanted to get it's Handle as this:
CmyActivexCtrl::CmyActivexCtrl()
{
InitializeIIDs(&IID_DmyActivex, &IID_DmyActivexEvents);
tmpWind.Register(this);
myOtherComponent.WindowsHandle=tmpWind.GetSafeHwnd(); //here my Cwnd derived class returns zero
//my other component gets the handle and call an API with it to register
//the given handle and force the API to send the messages to that handle.
}
As you mentioned you need a window handle to be able to receive user messages through it, you always have an option of creating a helper window, such as message only window, see Using CreateWindowEx to Make a Message-Only Window.
For your windowless control it is okay to not have any window handle at all, so you cannot really rely on handle availability unless you own a window yourself.

How to handle events for dynamically created objects in MFC?

I am wondering how I can handle an event for a dynamically created variable, e.g. a list control.
CListCtrl* pList = new CListCtrl();<br/>
pList->Create(...);
How can I handle the event LVN_ITEMCHANGED for pList?
OnLvnItemchangedList(NMHDR *pNMHDR, LRESULT *pResult)
{
//do stuff
}
Do I have to create an extended CListCtrl or is there some other way? I would prefer not creating a extended class.
LVN_ITEMCHANGED is sent through WM_NOTIFY message from control to its parent so you just need to add LVN_ITEMCHANGE handler function in parent's class (e.g. CMyDlg):
In header file:
class CMyDlg : public CDialog
{
...
protected:
afx_msg void OnLvnItemChanged(NMHDR *pNMHDR, LRESULT *pResult);
...
}
In source file:
BEGIN_MESSAGE_MAP(CMyDlg, CDialog)
...
ON_NOTIFY(LVN_ITEMCHANGED, IDC_LIST, &CMyDlg::OnLvnItemChanged)
...
END_MESSAGE_MAP()
...
void CMyDlg::OnLvnItemchanged(NMHDR *pNMHDR, LRESULT *pResult)
{
LPNMLISTVIEW pNMLV = reinterpret_cast<LPNMLISTVIEW>(pNMHDR);
*pResult = 0;
... // examine *pNMLV members for item's information
}
It does not matter how CListCtrl control is created (through resource editor or dynamically), approach is the same. Just make sure you are using correct control ID in ON_NOTIFY message map entry. (ID passed to Create/CreateEx or defined in Properties in resource editor).