Why does there OnFinalMessage never be called in ATL? - atl

I am using ATL do build my software. I create a main frame window which contain serviral childen windows. the one of the childen windows contain some chinden windows also.
Now, my app will alway get the failed of assert:
virtual ~CWindowImplRoot()
{
#ifdef _DEBUG
if(m_hWnd != NULL) // should be cleared in WindowProc
{
ATLTRACE(atlTraceWindowing, 0, _T("ERROR - Object deleted before window was destroyed\n"));
ATLASSERT(FALSE);
}
#endif //_DEBUG
}
I defined WM_NCDESTROY handler for any window and set bHanded=FALSE, the code can arrived there.
Anymore, I add OnFinalMessage override function. unfortunatelly, no all of the functions can be called. Actually, the top-level window's OnFinalMessage will be called, the middle-level windows' OnFinalMessage may not be called, the bottom-level windows' OnFinalMessage will never be called.
I oberve the source code of ATL:
template <class TBase, class TWinTraits>
LRESULT CALLBACK CWindowImplBaseT< TBase, TWinTraits >::WindowProc(
_In_ HWND hWnd,
_In_ UINT uMsg,
_In_ WPARAM wParam,
_In_ LPARAM lParam)
{
CWindowImplBaseT< TBase, TWinTraits >* pThis = (CWindowImplBaseT< TBase, TWinTraits >*)hWnd;
// set a ptr to this message and save the old value
_ATL_MSG msg(pThis->m_hWnd, uMsg, wParam, lParam);
const _ATL_MSG* pOldMsg = pThis->m_pCurrentMsg;
pThis->m_pCurrentMsg = &msg;
// pass to the message map to process
LRESULT lRes = 0;
BOOL bRet = pThis->ProcessWindowMessage(pThis->m_hWnd, uMsg, wParam, lParam, lRes, 0);
// restore saved value for the current message
ATLASSERT(pThis->m_pCurrentMsg == &msg);
// do the default processing if message was not handled
if(!bRet)
{
if(uMsg != WM_NCDESTROY)
lRes = pThis->DefWindowProc(uMsg, wParam, lParam);
else
{
// unsubclass, if needed
LONG_PTR pfnWndProc = ::GetWindowLongPtr(pThis->m_hWnd, GWLP_WNDPROC);
lRes = pThis->DefWindowProc(uMsg, wParam, lParam);
if(pThis->m_pfnSuperWindowProc != ::DefWindowProc && ::GetWindowLongPtr(pThis->m_hWnd, GWLP_WNDPROC) == pfnWndProc)
::SetWindowLongPtr(pThis->m_hWnd, GWLP_WNDPROC, (LONG_PTR)pThis->m_pfnSuperWindowProc);
// mark window as destryed
pThis->m_dwState |= WINSTATE_DESTROYED;
}
}
if((pThis->m_dwState & WINSTATE_DESTROYED) && pOldMsg== NULL)
{
// clear out window handle
HWND hWndThis = pThis->m_hWnd;
pThis->m_hWnd = NULL;
pThis->m_dwState &= ~WINSTATE_DESTROYED;
// clean up after window is destroyed
pThis->m_pCurrentMsg = pOldMsg;
pThis->OnFinalMessage(hWndThis);
}else {
pThis->m_pCurrentMsg = pOldMsg;
}
return lRes;
}
In above code, the purpose of the variable "pOldMsg" is to indicate the call stack level. if "pOldMsg" not equal to NULL, it's means that the call stack is not returned. when it's NULL, means the the call stack is outermost level, this moment we can call OnFinalMessage function now.
In my case, it's seems that sometimes "pOldMsg" will never equal to NULL.
chat:
MainFrame V
|----- ViewDevices V
|----- ViewContainer X
|----- ViewBooks X
|----- ViewFiles V
After testing it for many times, I find that, if I didn't add any content to the ViewBooks(ListView) window, every things is OK. Once I add just a line, this issue will repro. I don't know whether the sending message by crossing thread cause the issue.
Can anybody give me some suggestions?

Related

EasyHook stop catching some messages

As soon EasyHook EasyHook64.dll intercepts the first DefWindowProcW message, and from it starts a thread, it does not catch any DefWindowProcW anymore:
|___ DefWindowProcW (caught)
|--
|--
|--
|-- DefWindowProcW (don't 'intercept' anymore)
|-- ...
It stops 'catching' all DefWindowProcW messages until the thread end.
I was told:
This is by design, it is part of the thread deadlock barrier.
And:
You could install two hooks for the same function, leaving the second disabled until you enter your first hook, you would enable it by setting its ACL inclusive to the current thread, then disable it again as you leave the first hook.
Then I tried to call it like:
HOOK_TRACE_INFO hHook = { NULL };
HOOK_TRACE_INFO hHook2 = { NULL };
HOOK_TRACE_INFO hHook3 = { NULL };
LRESULT __stdcall DefWindowProcW_Hook( HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam)
{
switch (Msg) {
//......
}
ULONG ACLEntries[1] = { 0 };
LhSetInclusiveACL(ACLEntries, 1, &hHook);
ULONG ACLEntries2[1] = { 0 };
LhSetInclusiveACL(ACLEntries2, 1, &hHook2);
ULONG ACLEntries3[1] = { 0 };
LhSetInclusiveACL(ACLEntries2, 1, &hHook3);
return DefWindowProcW(hWnd, Msg, wParam, lParam);
}
// =======================================
void __stdcall NativeInjectionEntryPoint(REMOTE_ENTRY_INFO* inRemoteInfo)
{
LhInstallHook(
GetProcAddress(GetModuleHandle(TEXT("user32")), "DefWindowProcW"),
DefWindowProcW_Hook, NULL, &hHook);
ULONG ACLEntries[1] = { 0 };
LhSetExclusiveACL(ACLEntries4, 1, &hHook);
LhInstallHook(
GetProcAddress(GetModuleHandle(TEXT("user32")), "DefWindowProcW"),
DefWindowProcW_Hook, NULL, &hHook2);
LhInstallHook(
GetProcAddress(GetModuleHandle(TEXT("user32")), "DefWindowProcW"),
DefWindowProcW_Hook, NULL, &hHook3);
}
But now, looks like all hooks are doing the same thing:
Result:
Would like to ask someone who uses or already used EasyHook how to properly read the same function when there is a 2nd or more nested call.
There is no elegant solution for this in EasyHook, however if you are happy to install as many intermediate hooks as you need for the nesting levels you can chain them together.
The outermost hook will be the only one enabled initially.
It will first ensure all innermost hooks are disabled, then enable the next hook.
To prevent calling the hook for the same DefWindowProcW call, we can retrieve the next hook's bypass address and call that instead of the original DefWindowProcW like you would normally do.
As you have already discovered, once within a hook handler for a hook it will not trigger that same hook again until after the return statement has completed and we have gone back up the call stack. This is due to the thread-deadlock barrier in EasyHook.
Example:
HOOK_TRACE_INFO hHook = { NULL };
HOOK_TRACE_INFO hHook2 = { NULL };
HOOK_TRACE_INFO hHook3 = { NULL };
typedef LRESULT __stdcall DefWindowProcFunc(HWND, UINT, WPARAM, LPARAM);
// Innermost hook handler
LRESULT __stdcall DefWindowProcW_Hook( HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam)
{
switch (Msg) {
//......
}
// Innermost hook just call original
return DefWindowProcW(hWnd, Msg, wParam, lParam);
}
// Middle hook handler
LRESULT __stdcall DefWindowProcW_Hook2( HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam)
{
switch (Msg) {
//......
}
// Activate next hook handler for next nesting level
ULONG ACLEntries[1] = { 0 };
LhSetInclusiveACL(ACLEntries, 1, &hHook);
PVOID* bypass_address;
LhGetHookBypassAddress(&hHook, &bypass_address);
//return DefWindowProcW(hWnd, Msg, wParam, lParam);
// Bypass the handler for THIS call to DefWindowProcW - the next nested call will be captured in DefWindowProcW_Hook
return ((DefWindowProcFunc*)bypass_address)(hWnd, Msg, wParam, lParam);
}
// Outermost hook handler
LRESULT __stdcall DefWindowProcW_Hook3( HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam)
{
// Outermost hook handler - this will be called first for new calls to DefWindowProcW
switch (Msg) {
//......
}
// Disable innermost hook(s) - do this for each inner hook that isn't the next hook
ULONG disableACLEntries[1] = { 0 };
LhSetExclusiveACL(disableACLEntries, 1, &hHook);
// Activate next hook handler for first nesting level
ULONG ACLEntries[1] = { 0 };
LhSetInclusiveACL(ACLEntries, 1, &hHook2);
PVOID* bypass_address;
LhGetHookBypassAddress(&hHook2, &bypass_address);
//return DefWindowProcW(hWnd, Msg, wParam, lParam);
// Bypass the handler for THIS call to DefWindowProcW - the next nested call will be captured in DefWindowProcW_Hook2
return ((DefWindowProcFunc*)bypass_address)(hWnd, Msg, wParam, lParam);
}
// =======================================
void __stdcall NativeInjectionEntryPoint(REMOTE_ENTRY_INFO* inRemoteInfo)
{
// NOTE: the last installed hook handler will be the first called i.e. hHook3, then hHook2 then hHook.
LhInstallHook(
GetProcAddress(GetModuleHandle(TEXT("user32")), "DefWindowProcW"),
DefWindowProcW_Hook, NULL, &hHook);
LhInstallHook(
GetProcAddress(GetModuleHandle(TEXT("user32")), "DefWindowProcW"),
DefWindowProcW_Hook2, NULL, &hHook2);
LhInstallHook(
GetProcAddress(GetModuleHandle(TEXT("user32")), "DefWindowProcW"),
DefWindowProcW_Hook3, NULL, &hHook3);
// Activate outermost hook (ie last installed hook which will be the first called - hHook3)
ULONG ACLEntries[1] = { 0 };
LhSetExclusiveACL(ACLEntries, 1, &hHook3);
}

Use class member as WNDPROC/DLGPROC with or without global

I'll go ahead and give a summary to this, how can I use a dialog procedure that is a member of a class? I am creating a window wrapper class, but CreateDialogParam needs a global dialog procedure, so I tried this workaround:
I have done a bit of searching on this topic. I am making a Dialog class which I am subclassing to make a CMainWnd and then instantiating that. In the Dialog class I have a member function defined as INT_PTR CALLBACK Dialog::cb_proc(HWND,UINT,WPARAM,LPARAM). Now, I know that windows must have a global function as a callback procedure.
So I made a std::map<HWND,Dialog*> DlgProcs map to associate the dialogs window handle with its Dialog class pointer.
And a INT_PTR CALLBACK DlgMainProc(HWND,UINT,WPARAM,LPARAM) so I could pass that to CreateDialogParam(). In the body of DlgMainProc(...) I search the map for using the hWnd parameter to find the Dialog* and return its cb_proc(..) member.
My problem is that none of the messages get processed, this is because the member procedure in my Dialog class never gets called. Even though when I put a MessageBox() in DlgMainProc inside a if (DlgProcs.find(hWnd) != DlgProcs.end()) { statement, the messagebox is displayed, over and over again until I have to abort the program from Visual Studio 2008. Which tells me that it is finding the hWnd in my map. The weird thing is it also does this if I put it in the else statement after that, which contradictingly tells me it is NOT finding the hWnd in the map.
If I put a messagebox in the cb_proc member function it does not get displayed at all. But during this I never get any compiler, linker, or runtime errors. When I remove the messagebox from it (as to not have to abort the program, it was just for debugging purposes) the program runs but no messages get processed, the X button does not close the program, button clicks do nothing.
Here is the PasteBin code: http://pastebin.com/GsGUBpZU
Btw, I have no problem subclassing this, my window is created fine, just no messages are processed, cb_proc just never gets called.
EDIT: Here is the relevant parts of the code
map<HWND,Dialog*> g_DlgProcs;
INT_PTR CALLBACK g_MainDlgProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam) {
if (g_DlgProcs.find(hWnd) != g_DlgProcs.end()) {
Alert("blah"); // Gets executed repeatedly
return g_DlgProcs[hWnd]->cb_proc(hWnd, msg, wParam, lParam);
} else {
Alert("blah"); // Removing the above alert, this gets
// executed repeatedly, erm, as well.. O.o strange
return FALSE;
}
}
Dialog::Dialog(int id, HWND parent /* = HWND_DESKTOP */) {
_id = id;
_parent = parent;
// Tried this before CreateDialogParam
g_DlgProcs.insert(make_pair(_handle, this));
_handle = CreateDialogParam(
(HINSTANCE)GetModuleHandle(NULL),
MAKEINTRESOURCE(id), _parent,
(DLGPROC)g_MainDlgProc, NULL
);
// Then tried it after CreateDialogParam
g_DlgProcs.insert(make_pair(_handle, this));
}
INT_PTR CALLBACK Dialog::cb_proc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam) {
Alert("blah"); // Never gets executed
bool handled = true;
switch (msg)
{
case WM_INITDIALOG:
OnInitialize();
break;
case WM_COMMAND:
if (HIWORD(wParam) == 0 || HIWORD(wParam) == 1) {
OnMenuCommand((HIWORD(wParam) == 1), (int)LOWORD(wParam));
} else {
OnCtrlCommand((int)HIWORD(wParam), (int)LOWORD(wParam), (HWND)lParam);
}
break;
case WM_NOTIFY:
{
LPNMHDR head = (LPNMHDR)lParam;
OnNotification(head->code, head->idFrom, head->hwndFrom);
}
break;
case WM_CLOSE:
OnClose(); // DestroyWindow(_handle)
break;
case WM_DESTROY:
OnDestroy(); // PostQuitMessage(0)
default:
handled = ProcessMsg(msg, wParam, lParam);
}
// Convert bool to Windows BOOL enum
return ((handled == true) ? TRUE : FALSE);
}
Does anybody know why it never gets called? Or maybe just guide me to another way to use a member function as a DLGPROC?
The standard solution is to pass your this pointer as the last parameter to Create,DialogParam, stash it in DWLP_USER in your WM_INITDIALOG handler, and retrieve it from DWLP_USER thereafter. Basically you use DWLP_USER as your map.
I tried your code and it worked: cb_proc gets called. You will miss any messages (e.g. WM_INITDIALOG) that get sent before CreateDialogParam returns.
You can fix the latter problem by adding the window handle and the object to the map in g_MainDlgProc. If you get a message for an unknown window, you know it belongs to the window you're creating; put the object in a global and you can add the handle/object to the map.
I'm just adding this here in case someone finds it useful; using the magic of C++11 lambdas and templates you can have a simple wrapper template that means you don't have to continually rewrite the boiler-plate code for saving and loading userdata in window and dialog box procedures.
Here's an example for the DialogBoxParam function, but the same technique can be applied to CreateDialogParam and CreateWindowEx as well.
template <typename T, INT_PTR (T::*P)(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)>
INT_PTR DialogBoxThis(T* pThis, HINSTANCE hInstance, LPCWSTR lpTemplateName, HWND hWndParent)
{
return ::DialogBoxParam(hInstance, lpTemplateName, hWndParent, [](HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) -> INT_PTR {
if (uMsg == WM_INITDIALOG) SetWindowLongPtr(hWnd, DWLP_USER, lParam);
T* pThis = reinterpret_cast<T*>(GetWindowLongPtr(hWnd, DWLP_USER));
return pThis ? (pThis->*P)(hWnd, uMsg, wParam, lParam) : FALSE;
}, reinterpret_cast<LPARAM>(pThis));
}
You would use it like this:
class MyClass
{
INT_PTR MyDlgProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
};
// from inside MyClass, we can show a dialog that uses member function MyDlgProc as the dialog procedure
// note it is NOT a static function
DialogBoxThis<MyClass, &MyClass::MyDlgProc>(this, hInstance,
MAKEINTRESOURCE(IDD_MYDIALOG), hWndParent);

Win32: More "object oriented" window message handling system

In Win32 API a window has the pointer to a user defined version of WndProc function that handling its messages.
There are some ways to cover this low-level mechanism with a solution like MFC message map and so on.
In my very little app I'm looking for a way to encapsulate this low-level thing with a object oriented solution.
I tried to create a C++ map with HWND key and "MyWindowClass" item and when I created an object of the MyClass I added a pair to the map and then looking for the MyWindowClass object by HWN. But the problem is after CreateWindowEx called Win32 internally send a WM_CREATE message to the just created window so I can't add pair in the map before this message and can't control WM_CREATE through passing it to the object instanced WndProc.
The code is:
#ifndef NOTIFYWINDOW_H
#define NOTIFYWINDOW_H
#include "Bacn.h"
class NotifyWindow
{
private:
HWND m_hWnd;
Gdiplus::Graphics* m_graphics;
protected:
static std::map<HWND, NotifyWindow*> s_NotifyWindows;
static LRESULT CALLBACK s_WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
static void s_WndMessageLoop();
LRESULT WndProc(UINT uMsg, WPARAM wParam, LPARAM lParam);
void Initialize();
void OnPaint();
void OnCreate();
public:
NotifyWindow();
~NotifyWindow();
};
#endif //NOTIFYWINDOW_H
And its implementation:
#include "NotifyWindow.h"
using namespace Gdiplus;
using namespace std;
map<HWND*, NotifyWindow> NotifyWindow::s_NotifyWindows;
LRESULT CALLBACK NotifyWindow::s_WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
map<HWND, NotifyWindow*>::iterator search = s_NotifyWindows.find(hWnd);
if (search != s_NotifyWindows.end())
{
search->second->WndProc(uMsg, wParam, lParam);
}
return DefWindowProc(hWnd, uMsg, wParam, lParam);
}
void NotifyWindow::s_WndMessageLoop()
{
}
LRESULT NotifyWindow::WndProc(UINT uMsg, WPARAM wParam, LPARAM lParam)
{
switch (uMsg)
{
case WM_CREATE:
OnCreate();
break;
case WM_PAINT:
OnPaint();
break;
case WM_DESTROY:
PostQuitMessage(0);
break;
case WM_SIZE:
break;
case WM_SETFOCUS:
break;
case WM_KILLFOCUS:
break;
case WM_MOUSEMOVE:
break;
default:
return DefWindowProc(m_hWnd, uMsg, wParam, lParam);
}
return 0;
}
void NotifyWindow::Initialize()
{
WNDCLASSEX wc;
const wchar_t *className = L"BacnNotifyWindowClass";
const wchar_t *windowName = L"BacnNotifyWindow";
HINSTANCE hInstance = GetModuleHandle(NULL);
wc.cbSize = sizeof(WNDCLASSEX);
wc.lpszClassName = className;
wc.lpfnWndProc = NotifyWindow::s_WndProc;
wc.hInstance = hInstance;
wc.hCursor = LoadCursor(NULL, IDC_ARROW);
wc.hIcon = NULL;
wc.hIconSm = NULL;
wc.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
wc.lpszMenuName = NULL;
wc.style = CS_HREDRAW | CS_VREDRAW | CS_OWNDC;
wc.cbClsExtra = 0;
wc.cbWndExtra = 0;
RegisterClassEx(&wc);
DWORD dwExtStyle = WS_EX_TOPMOST;
DWORD dwStyle = WS_POPUP | WS_SYSMENU;
m_hWnd = CreateWindowEx(
dwExtStyle,
className,
windowName,
dwStyle,
300,
300,
100,
100,
NULL,
NULL,
hInstance,
NULL);
s_NotifyWindows.insert(pair<HWND, NotifyWindow*>(m_hWnd, this));
ShowWindow(m_hWnd, SW_SHOW);
}
NotifyWindow::NotifyWindow()
{
Initialize();
}
NotifyWindow::~NotifyWindow()
{
}
void NotifyWindow::OnPaint()
{
}
void NotifyWindow::OnCreate()
{
}
Suggestion: make WndProc virtual in your window base class. Request Windows to allocate extra memory for each window instance big enough to store a pointer (use cbWndExtra). When creating a window, put a pointer to your windows class object into this extra memory associated with each window instance using SetWindowLongPtr. In your static sWndProc, retrieve this pointer using GetWindowLongPtr and call your window base class function virtual WndProc. In my opinion, it's more neat way than having a whole extra map object dedicated to dispatching WndProc calls.
EDIT: Plus, you do realize, in your code you are trying to register Windows window class every time you create an object of your window class? If you create just one window this is technically fine, I guess, but even then it's error-prone design. Windows window class should be registered just once, not every time you create a window with this Windows window class.
EDIT: Also, in your code, if you are not processing Windows message in your WndProc, you code will call DefWindowProc twice for this message: first time in member function within switch clause, second time in static sWndProc. DefWindowProc shouldn't be called twice on the same message.
EDIT: Sorry, I missed your actual question before somehow, I thought your post was about design, not about WM_CREATE. In order to process WM_NCCREATE, WM_NCCALCSIZE or WM_CREATE in a uniform way, you can set lpParam in call to CreateWindowEx to, again, pointer to the object of your window class. This parameter will be passed to your static sWndProc as a member of CREATESTRUCT with WM_NCCREATE and WM_CREATE. You can process, say, WM_NCCREATE (first message to be sent) inside static sWndProc, get this pointer to your object, use SetWindowLongPtr to put it into window instance extra memory, and then use it to call member function WndProc (just be careful about calling not fully created object of your windows class, if you call CreateWindowEx from its constructor). This way, you don't need to worry about "low-level" Windows message dispatching anywhere else in your program. You, of course, will still need your member function WndProc to dispatch messages to actual function calls.

Object oriented c++ win32?

I want to create my own class to handle creating windows and the window procedure but I have noticed that the window procedure has to be static! I'm now wondering whether its possible to make the window procedure object oriented? I have read some tutorials on object oriented windows, but they always make the procedure static -.- whats the use in that? :/
Any links or info on how to get around this problem would be appreciated,
thanks
You can get around that by making the static WndProc delegate everything to the members:
// Forward declarations
class MyWindowClass;
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
std::map<HWND, MyWindowClass *> windowMap;
// Your class
class MyWindowClass {
private:
HWND m_handle;
// The member WndProc
LRESULT MyWndProc(UINT message, WPARAM wParam, LPARAM lParam) { /* ... */ }
public:
MyWindowClass()
{
/* TODO: Create the window here and assign its handle to m_handle */
/* Pass &WndProc as the pointer to the Window procedure */
// Register the window
windowMap[m_handle] = this;
}
};
// The delegating WndProc
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
std::map<HWND, MyWindowClass *>::iterator it = windowMap.find(hWnd);
if (it != windowMap.end())
return it->second->MyWndProc(message, wParam, lParam);
return 0;
}
The general technique of allowing a window instance to be represented by as class instance is to make use of the SetWindowLongPtr and GetWindowLongPtr to associate your class instance pointer with the window handle. Below is some sample code to get you started. It may not compile without a few tweaks. It's only meant to be a reference.
Personally, I've stopped rolling my own window classes back a few years ago when I discovered ATL's CWindow and CWindowImpl template class. They take care of doing all this mundane coding for you so can focus on just writing methods that handle window messages. See the example code I wrote up here.
Hope this helps.
class CYourWindowClass
{
private:
HWND m_hwnd;
public:
LRESULT WndProc(UINT uMsg, WPARAM wParam, LPARAM lParam)
{
switch (uMsg)
{
case WM_CREATE: return OnCreate(wParam, lParam);
case wM_PAINT: return OnPaint(wParam, lParam);
case WM_DESTROY:
{
SetWindowLongPtr(m_hwnd, GWLP_USERDATA, NULL);
m_hwnd = NULL;
return 0;
}
}
return DefWindowProc(m_hwnd, uMsg, wParam, lParam);
}
CYourWindowClass()
{
m_hwnd = NULL;
}
~CYourWindowClass()
{
ASSERT(m_hwnd == NULL && "You forgot to destroy your window!");
if (m_hwnd)
{
SetWindowLong(m_hwnd, GWLP_USERDATA, 0);
}
}
bool Create(...) // add whatever parameters you want
{
HWND hwnd = CreateWindow("Your Window Class Name", "Your Window title", dwStyle, x, y, width, height, NULL, hMenu, g_hInstance, (LPARAM)this);
if (hwnd == NULL)
return false;
ASSERT(m_hwnd == hwnd);
return true;
}
static LRESULT __stdcall StaticWndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
CYourWindowClass* pWindow = (CYourWindowClass*)GetWindowLongPtr(hwnd, GWLP_USERDATA);
if (uMsg == WM_CREATE)
{
pWindow = ((CREATESTRUCT*)lParam)->lpCreateParams;
SetWindowLongPtr(hwnd, GWLP_USERDATA, (void*)pWindow);
m_hWnd = hwnd;
}
if (pWindow != NULL)
{
return pWindow->WndProc(uMsg, wParam, lParam);
}
return DefWindowProc(hwnd, uMsg, wParam, lParam);
};
};
If you are looking for object oriented Win32 API then you should look to MFC and/or WTL.
Just to add to Brian's answer but for a win32 framework that's more beginner friendly take a look at Win32++. The library itself isn't as comprehensive in features compared to MFC or QT but that is a tradeoff the designer made at the beginning to keep the library easy to understand and simple to use.
If you're still interested in this topic, I highly encourage you to take a look at it since it uses yet another technique for saving the 'this' pointer by utilizing thread local storage.
You can use the window handle passed to the WindowProc to grab an object you've created for that particular window and delegate the event handling to that object.
e.g.
IMyWindowInterface* pWnd = getMyWindowObject(hWnd);
pWnd->ProcessMessage(uMsg, wParam, lParam);

Safely remove window subclassing?

I am trying to subclass the currently focused window on a Windows system using a global CBT hook. This is related to what happens in this question, but the bug is different.
What happens when this subclassing is in effect, is that Opera's (version 10.50) main window is prevented from displaying. Opera has a "splash screen" where you are required to click "Start" for the main window to show that appears after Opera has not shut down properly. Whenever this window pops up, Opera's main window won't show. If Opera was shut down properly, and this splash screen does not show, the main window displays as it should.
HHOOK hHook;
HWND hWndSubclass = 0;
void SubclassWindow(HWND hWnd)
{
Unsubclass();
FARPROC lpfnOldWndProc = (FARPROC)SetWindowLongPtr(hWnd, GWLP_WNDPROC, (LPARAM)SubClassFunc);
SetProp(hWnd, L"PROP_OLDWNDPROC", lpfnOldWndProc);
hWndSubclass = hWnd;
}
void Unsubclass()
{
if (hWndSubclass != 0 && IsWindow(hWndSubclass))
{
FARPROC lpfnOldWndProc = (FARPROC)GetProp(hWndSubclass, L"PROP_OLDWNDPROC");
RemoveProp(hWndSubclass, L"PROP_OLDWNDPROC");
SetWindowLongPtr(hWndSubclass, GWLP_WNDPROC, (LPARAM)lpfnOldWndProc);
hWndSubclass = 0;
}
}
static LRESULT CALLBACK SubClassFunc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
if (message == WM_MOVING)
{
// do something irrelevant
}
else if (message == WM_DESTROY)
{
Unsubclass();
}
FARPROC lpfnOldWndProc = (FARPROC)GetProp(hWndSubclass, L"PROP_OLDWNDPROC");
return CallWindowProc((WNDPROC)lpfnOldWndProc, hWndSubclass, message, wParam, lParam);
}
static LRESULT CALLBACK CBTProc(int nCode, WPARAM wParam, LPARAM lParam)
{
if (nCode == HCBT_SETFOCUS && hWndServer != NULL)
{
SubclassWindow((HWND)wParam);
}
if (nCode < 0)
{
return CallNextHookEx(hHook, nCode, wParam, lParam);
}
return 0;
}
BOOL APIENTRY DllMain( HINSTANCE hInstance,
DWORD Reason,
LPVOID Reserved
)
{
switch(Reason)
{
case DLL_PROCESS_ATTACH:
hInst = hInstance;
return TRUE;
case DLL_PROCESS_DETACH:
Unsubclass();
return TRUE;
}
return TRUE;
}
My suspicion is that Opera's main window is somehow already subclassed. I imagine the following is happening:
The window is created with it's own basic WndProc, and is given focus
My application subclasses the window, storing the original WndProc
Opera subclasses its own window
When the window loses focus, I restore the original WndProc, thus ignoring the second WndProc
Can this really be the case? Are there any other explanations?
This can happen, as Raymond Chen writes:
Consider what would happen if somebody else had subclassed the window during the "... do stuff ..." section. When we unsubclassed the window, we would have removed two subclasses, the one we installed, and the one that was installed after us. If the other subclass allocated memory (which is very common), then that memory got leaked, in addition to the subclass failing to do whatever it was trying to do.
He continues with a solution:
This is quite a cumbersome process, so the shell team wrote some helper functions to do all this for you. The SetWindowSubclass function does all the grunt work of installing a subclass procedure, remembering the previous one, and passing reference data to the subclass procedure you provide. You use the DefSubclassProc function to forward the message to the previous subclass procedure, and when you're done, you use the RemoveWindowSubclass function to remove yourself from the chain. RemoveWindowSubclass does all the work to do the right thing if you are not the window procerure at the top of the chain.