I have a composite control with a declaration like this:
class ATL_NO_VTABLE CFooCtrl :
public CComObjectRootEx<CComSingleThreadModel>,
public IDispatchImpl<CFooCtrl, &IID_IFooCtrl, &LIBID_FooLib>,
public CComCompositeControl<CFooCtrl>,
public IPersistStreamInitImpl<CFooCtrl>,
public IOleControlImpl<CFooCtrl>,
public IOleObjectImpl<CFooCtrl>,
public IOleInPlaceActiveObjectImpl<CFooCtrl>,
public IViewObjectExImpl<CFooCtrl>,
public IOleInPlaceObjectWindowlessImpl<CFooCtrl>,
public IConnectionPointContainerImpl<CFooCtrl>,
public IPersistStorageImpl<CFooCtrl>,
public ISpecifyPropertyPagesImpl<CFooCtrl>,
public IQuickActivateImpl<CFooCtrl>,
public IDataObjectImpl<CFooCtrl>,
public IProvideClassInfo2Impl<&CLSID_FooCtrl, &DIID__IFooCtrlEvents, &LIBID_FooCtrlLib>,
public IPropertyNotifySinkCP<CFooCtrl>,
public CComCoClass<CFooCtrl, &CLSID_FooCtrl>,
public CProxy_IFooCtrlEvents<CFooCtrl>,
{
...
BEGIN_MSG_MAP(CFooCtrl)
CHAIN_MSG_MAP(CComCompositeControl< CFooCtrl >)
DEFAULT_REFLECTION_HANDLER()
MESSAGE_HANDLER(WM_TIMER, OnTimer)
MESSAGE_HANDLER(WM_ERASEBKGND, OnEraseBkgnd)
MESSAGE_HANDLER(WM_KEYDOWN, OnKeyDown)
MESSAGE_HANDLER(WM_KEYUP, OnKeyUp)
MESSAGE_HANDLER(WM_LBUTTONDBLCLK, OnLButtonDblClk)
MESSAGE_HANDLER(WM_LBUTTONDOWN, OnLButtonDown)
MESSAGE_HANDLER(WM_LBUTTONUP, OnLButtonUP)
MESSAGE_HANDLER(WM_PAINT, OnPaint)
MESSAGE_HANDLER(WM_RBUTTONDBLCLK, OnRButtonDblClk)
MESSAGE_HANDLER(WM_RBUTTONDOWN, OnRButtonDown)
MESSAGE_HANDLER(WM_RBUTTONUP, OnRButtonUp)
MESSAGE_HANDLER(WM_MOUSEMOVE, OnMouseMove)
MESSAGE_HANDLER(WM_MOUSEWHEEL, OnMouseWheel)
MESSAGE_HANDLER(WM_SIZE, OnSize)
MESSAGE_HANDLER(WM_INITDIALOG, OnInitDialog)
MESSAGE_HANDLER(WM_DESTROY, OnDestroy)
END_MSG_MAP()
LRESULT OnTimer(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled);
LRESULT OnEraseBkgnd(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled);
LRESULT OnKeyDown(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled);
LRESULT OnKeyUp(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled);
LRESULT OnLButtonDblClk(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled);
LRESULT OnLButtonDown(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled);
LRESULT OnLButtonUP(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled);
LRESULT OnPaint(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled);
LRESULT OnRButtonDblClk(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled);
LRESULT OnRButtonDown(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled);
LRESULT OnRButtonUp(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled);
LRESULT OnMouseMove(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled);
LRESULT OnMouseWheel(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled);
LRESULT OnSize(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled);
LRESULT OnInitDialog(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled);
LRESULT OnDestroy(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled);
I get events like OnMouseMove, OnLButtonDown/Up/DblClk, but I don't get events like KeyUp, KeyDown or MouseWheel.
Everything seems to be defined correctly. I've moved
CHAIN_MSG_MAP(CComCompositeControl< CFooCtrl >)
DEFAULT_REFLECTION_HANDLER()
To the end of the Message Map and no difference. I find that when I remove the Reflection_handler() I don't get crashes on KeyDown, but I suspect those are from my Python program that's driving the control.
The only thing I can assume is that the chained msg map is eating these events, but there is no parent control that should be interested in them.
Anyone have any ideas why I get some messages but not others? Any ideas for regaining those messages?
I believe your code is using ATL and not MFC.
Keyboard handling on composite controls happens through IOleInPlaceActiveObject. The base implementation in ATL will call your PreTranslateMessage on your class (if implemented) where you can get a crack at the message before it goes into TranslateMessage.
The ATL composite control is a control container (it's a child dialog that can host other activex controls). For more information, see the "Keyboard Handling" section in http://www.microsoft.com/msj/1299/containment/containment.aspx
Related
static std::function<LRESULT(int nCode, WPARAM wParam, LPARAM lParam)> keyProc =
[](int nCode, WPARAM wParam, LPARAM lParam)->LRESULT {
return 1;
};
keyHook = SetWindowsHookEx(WH_KEYBOARD_LL, keyProc, theApp.m_hInstance, NULL);
Error C2664 'HHOOK SetWindowsHookExW(int,HOOKPROC,HINSTANCE,DWORD)':
cannot convert argument 2 from 'std::function' to
'HOOKPROC' MFCTest d:\test\mfctest2\mfctest\keymaphooker.cpp 62
PS: Why did I use such a long expression rather than auto? Because I want to it be static.
I changed it to
auto keyProc =
[this](int nCode, WPARAM wParam, LPARAM lParam)->LRESULT {
return 1;//return KeyboardProc(keyHook, keyMap, nCode, wParam, lParam);
};
It doesn't work again.
error C2664: 'HHOOK SetWindowsHookExW(int,HOOKPROC,HINSTANCE,DWORD)':
cannot convert argument 2 from
'KeyMapHooker::StartHook::'
to 'HOOKPROC'
A stateless lambda (such as the one you are using) can indeed be converted to a pointer to function, and thus can be used as CALLBACK. However, std::function cannot be converted in this manner.
Note that the type of a lambda expression is not std::function, it's an unnamed class type (the closure type of the lambda expression). You can capture the correct type using auto (which has no effect on storage duration):
static auto keyProc =
[](int nCode, WPARAM wParam, LPARAM lParam)->LRESULT {
return 1;
};
keyHook = SetWindowsHookEx(WH_KEYBOARD_LL, keyProc, theApp.m_hInstance, NULL);
I made a small application that sends text to notepad via SendMessage and EM_REPLACESEL.
Now I’m trying to hook notepad to get the EM_REPLACESEL value (the lParam value and in this case the “GET THIS TEXT” text).
EDIT: See this picture: http://i.stack.imgur.com/8scNL.jpg
The hook works fine, my problem is to listen for the EM_REPLACESEL message and grab the value from the lParam.
This code works fine, when messages are sent to notepad:
LRESULT CALLBACK GetMsgProc(int nCode, WPARAM wParam, LPARAM lParam)
{
Beep (2000,100);
return(CallNextHookEx(g_hHook, nCode, wParam, lParam));
}
So now I want to intercept EM_REPLACESEL messages. This do not work:
LRESULT CALLBACK GetMsgProc(int nCode, WPARAM wParam, LPARAM lParam)
{
if (nCode == EM_REPLACESEL)
{
Beep (2000,100);
}
return(CallNextHookEx(g_hHook, nCode, wParam, lParam));
}
1) How to listen for the EM_REPLACESEL message?
2) When I have gotten the message how to grab the lParam value and e.g. show it in a MessageBox. Something like this:
LRESULT CALLBACK GetMsgProc(int nCode, WPARAM wParam, LPARAM lParam)
{
if (nCode == EM_REPLACESEL)
{
MSG *lpMsg;
lpMsg = (MSG *) lParam;
MessageBox(NULL,(LPCWSTR)lpMsg,NULL,NULL);
}
return(CallNextHookEx(g_hHook, nCode, wParam, lParam));
}
Thanks
EM_REPLACESEL is a sent message, not a posted message, so you need to use a WH_CALLWNDPROC hook instead of a WH_GETMESSAGE hook, eg:
LRESULT CALLBACK CallWndProc(int nCode, WPARAM wParam, LPARAM lParam)
{
if (nCode == HC_ACTION) {
CWPSTRUCT* cwps = (CWPSTRUCT*)lParam;
if (cwps->message == EM_REPLACESEL) {
Beep (2000,100);
// etc..
}
}
return CallNextHookEx(g_hHook, nCode, wParam, lParam);
}
... = SetWindowsHookEx(WH_CALLWNDPROC, CallWndProc, ...),
Your GetMsgProc() callback is coded wrong. Carefully read the linked MSDN page to see what the arguments of the callback mean. The nCode argument is not the message number, it specifies whether or not you should process the message. You want to use the passed lParam to recover the message that you intercepted. Make it look similar to this instead:
LRESULT CALLBACK GetMsgProc(int nCode, WPARAM wParam, LPARAM lParam)
{
if (nCode == HC_ACTION) {
MSG* pmsg = (MSG*)lParam;
if (pmsg->message == WM_LBUTTONDOWN) {
Beep (2000,100);
// etc..
}
}
return CallNextHookEx(g_hHook, nCode, wParam, lParam);
}
Do note that you appear to use the WH_GETMESSAGE hook. It only works for messages that are posted to the message queue with PostMessage(). But EM_REPLACESEL is a message that's sent with SendMessage(). That requires a different hook, WH_CALLWNDPROC or WH_CALLWNDPROCRET.
This is how I normally do it.
LRESULT CALLBACK GetMsgProc(MSG nCode, WPARAM wParam, LPARAM lParam)
{
while(GetMessage(&nCode, NULL, 0, 0) > 0)
{
if(nCode.message == EM_REPLACESEL)
{
//Do something
}
else
DispatchMessage(&nCode);
}
return 0;
}
I wrote a super simple ATL dialog inside a project. Even when I noted that every example on the web implemented the CDialogImpl class inline (that is, the class definition and it's implmentation where in the definition itself) I wrote it normally, separating my definition in a .h file and implementation in a .cpp file. This class is summarized below:
CMainDialog.hpp
class CMainDialog: public CDialogImpl<CMainDialog>
{
public:
enum { IDD = IDD_MYDIALOGS_DIALOG};
BEGIN_MSG_MAP(CMainDialog)
MESSAGE_HANDLER(WM_INITDIALOG, OnInitDialog)
COMMAND_ID_HANDLER(IDCANCEL, OnCancel)
END_MSG_MAP()
CMainDialog();
~CMainDialog();
LRESULT OnInitDialog(UINT uMsg, WPARAM wParam, LPARAM lParam,
BOOL& bHandled);
LRESULT OnCancel(UINT uMsg, WORD wID, HWND hWndCtl, BOOL& bHandled);
}
CMainDialog.cpp
CMainDialog::CMainDialog()
{
}
CMainDialog::~CMainDialog()
{
}
LRESULT CMainDialog::OnInitDialog(UINT uMsg, WPARAM wParam, LPARAM lParam,
BOOL& bHandled)
{
}
LRESULT CMainDialog::OnCancel(UINT uMsg, WORD wID, HWND hWndCtl,
BOOL& bHandled)
{
}
If I call this class from the same project, everything goes fine. The dialog shows. Example:
Calling DoModal
int APIENTRY _tWinMain(_In_ HINSTANCE hInstance,
_In_opt_ HINSTANCE hPrevInstance,
_In_ LPTSTR lpCmdLine,
_In_ int nCmdShow)
{
UNREFERENCED_PARAMETER(hPrevInstance);
UNREFERENCED_PARAMETER(lpCmdLine);
CMainDialog dialog;
dialog.DoModal();
return 0;
}
So I converted this project from .exe to static library and removed _tWinMain.
So, if I create a new ATL project, reference my newly created library and call CMainDialog.DoModal ... well, nothing happens. The constructor does get called, but the messages never start dispatching and the program ends inmediatly. Maybe I'm missing something?
I'm totally new to Win32 programming (although definitely not new to c++) so any help would be appreciated.
A static library does not have resources associated with it. Most likely the dialog code is trying to load the dialog template from the program resources but can't find it.
I'm learning windows api for some weeks, now I got a problem, my code is like this
LRESULT CALLBACK MainWndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam){
switch(message){
case(...)
DialogBox(hInstance,MAKEINTRESOURCE(IDD_MYDIALOG),hwnd,(DLGPROC)MyDialogProc);
return 0;
}
bool MyDialogProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam){
switch (message){
...
}
return false;
}
I don't know what else should I do before I use DialogBox where should I place EndDialog(). IDD_MYDIALOG is a resource file created by myself. I don't understand what is hInstance and how to get it, I think I just need a simple example, than I can know how use DialogBox. Thank you for helping!
i've made a simple windows api program having the functions WinMain() and WinProc() , but i'm getting this error :
error C2440: '=' : cannot convert from 'LRESULT (__stdcall *)(HWND,UINT,LPARAM,WPARAM)' to 'WNDPROC'
1> This conversion requires a reinterpret_cast, a C-style cast or function-style cast
#include<windows.h>
LRESULT CALLBACK WindowProc(HWND hWnd, UINT message, LPARAM lParam, WPARAM wParam);
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
{
WNDCLASSEX WindowClass;
static LPCTSTR szAppName = L"OFWin";
HWND hWnd;
MSG msg;
WindowClass.cbSize = sizeof(WNDCLASSEX);
WindowClass.style = CS_HREDRAW | CS_VREDRAW;
WindowClass.lpfnWndProc = WindowProc; // error
....
}
LRESULT CALLBACK WindowProc(HWND hWnd, UINT message, LPARAM lParam, WPARAM wParam)
{ ..... }
the program's taken word to word from my book (ivor horton's beginning visual c++ 2010), what's wrong?
LRESULT CALLBACK WindowProc(HWND hWnd, UINT message, LPARAM lParam, WPARAM wParam);
Here's your problem: the LPARAM and WPARAM are backwards, it should be:
LRESULT CALLBACK WindowProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam);
WPARAM and LPARAM have two different types (UINT_PTR and INT_PTR respectively - for historical reasons mostly), so you get a type related error if you accidentally swap them around. Which is a lucky thing in your case: if they were the same type, then instead of getting a compiler error, the code would compile fine, and you'd instead spend some time wondering why your wndproc was apparently getting mixed up parameters passed to it!