Windows: FromHandle and FromHandlePermanent
For CWnd-derived classes, you can get a temporary CWnd * object from FromHandle. Thus, if you have a class CMyCoolWindow and you do something like GetFocus you may or may not get an actual pointer to your CMyCoolWindow * object. I've had numerous failures in this way. For example, I've taken to doing
CWnd * capture = GetCapture(); if(capture != NULL && capture->m_hWnd == m_hWnd) { /* I have capture */ // ... do something } /* I have capture */
If you need a handle to your actual object for a given HWND, you should use CWnd::FromHandlePermanent. This will return a handle from the permanent window map. Note that CWnd::FromHandlemight return a handle to a permanent window, and then again, it might not. You have no guarantee.
CWnds and Threads
The object maps are thread-local. This means that if you are in a thread and do a CWnd::FromHandle you will get a new, temporary window object which is not the same C++ object that represented your class initially. Thus this is always fatal in a thread:
CMyCoolWindowClass * me = (CMyCoolWindowClass *)CWnd::FromHandle(hWnd); me->MyCoolVariable = 17; // modifies some location you've never // heard of!
You will actually get a generic CWnd pointer, and if you did
me->IsKindOf(RUNTIME_CLASS(CMyCoolWindowClass))
you would get FALSE. If you did
CMyCoolWindowClass * me = (CMyCoolWindowClass *)CWnd::FromHandlePermanent(hWnd);
you would always get NULL because the permanent handle map for the thread is empty, unless you actually created the window in that UI-thread.
If you need access to a window class in a thread, particularly in a worker thread, pass it into the thread via the thread routine's initial pointer. See my essay on Worker Threads for more details.
Comments