Hello,
I've encountered a problem with a base win32 class I'm developing. I'm using a std:map to map function pointers to a windows message but having thought i had done so correctly, get a run-time assertion error:
map/set iterators incompatible
Here is the source code to the class responsible...
//+--------------------------------------------------------------------------------+//
// //
// AP_BASEWINDOW //
// //
// Last Updated: 16/09/2008 //
// //
// WIN32 wrapper class used to provide basic functionality of a window //
// //
//+--------------------------------------------------------------------------------+//
#pragma once
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#include "console.h"
#include <map>
using namespace std;
typedef long (*fpMessageHandler)(HWND, long, long);
typedef map<long, fpMessageHandler> MessageMap;
typedef MessageMap::iterator MessageMapIterator;
class AP_BASEWINDOW
{
public:
AP_BASEWINDOW();
~AP_BASEWINDOW(void);
static LRESULT CALLBACK MessageRouter(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam);
bool Create_Window(HINSTANCE _hInstance, int x_offset, int y_offset, int width, int height, char* title);
bool changeWindowTitle(LPCTSTR new_title);
HWND getHandle(){return hWnd;};
MessageMapIterator GetMessageHandler(long message);
fpMessageHandler RegisterMessageHandler(long message, fpMessageHandler handler);
MessageMap getMessageMap(){return message_map;};
protected:
HWND hWnd;
HINSTANCE hInstance;
virtual LRESULT WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam);
private:
MessageMap message_map;
static long OnWM_CLOSE(HWND hwnd, long wParam, long lParam);
static long OnWM_DESTROY(HWND hwnd, long wParam, long lParam);
bool Register_Class(HINSTANCE _hInstance, LPTSTR szWindowClass);
};
#include "AP_BASEWINDOW.h"
AP_BASEWINDOW::AP_BASEWINDOW(void)
{
hInstance = 0;
}
AP_BASEWINDOW::~AP_BASEWINDOW(void)
{
}
//+--------------------------------------------------------------------------------+//
// //
// +-MessageRouter(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) //
// //
// //
// Purpose: //
// Determines which instance of the class is the recipient of the generated //
// message, then calls the Windows Procedure for that instance. //
// //
// Comments: //
// You can not initialize the window class with a class method as the window //
// procedure unless it is a static method, so the class also needs a static //
// message handler that determines which instance of the class is the //
// recipient of the message and calls that instance's window procedure. //
// //
//+--------------------------------------------------------------------------------+//
LRESULT CALLBACK AP_BASEWINDOW::MessageRouter(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
AP_BASEWINDOW* pWnd = 0;
//+-TODO: Possibility that the WM_GETMINMAXINFO message could be sent before
if(msg == WM_NCCREATE) // The WM_NCCREATE message must be handled explicitly
{ // within this message router, and the object pointer stored
pWnd = reinterpret_cast<AP_BASEWINDOW*>((long)((LPCREATESTRUCT)lParam)->lpCreateParams);
::SetWindowLong(hwnd, GWL_USERDATA, (LONG)((LPCREATESTRUCT)lParam)->lpCreateParams); // Retrieve Window instance from window creation data and associate
if(pWnd) // Make sure access is not trying to be made to a null pointer
{
pWnd->hWnd = hwnd; // Save the Windows Handle
}
}
else // If the window is already created then 32-but value associated with it is already stored
{
pWnd = reinterpret_cast<AP_BASEWINDOW*>(::GetWindowLong(hwnd, GWL_USERDATA)); // Retrieve the associated windows instance
}
if(pWnd) // Make sure access is not trying to be made to a null pointer
{
MessageMapIterator it;
it = pWnd->GetMessageHandler(msg);
if(it != (pWnd->getMessageMap().end()))
{
return (it->second)(hwnd, (long)wParam, (long)lParam);
}
//return pWnd->WndProc(hwnd, msg, wParam, lParam); // Call the appropriate windows procedure
}
return DefWindowProc(hwnd, msg, wParam, lParam); // Tell Windows to handle in a default way
}
//+--------------------------------------------------------------------------------+//
// //
// +-Register_Class(HINSTANCE _hInstance, LPTSTR szWindowClass) //
// //
// //
// Purpose: //
// Will register a window class with a set of default values. The class will //
// be registered in the name of the second parameter //
// //
// Comments: //
// This method will return true if the windows class has been registered //
// properly, and false if the registration failed //
// //
//+--------------------------------------------------------------------------------+//
bool AP_BASEWINDOW::Register_Class(HINSTANCE _hInstance, LPTSTR szWindowClass)
{
// Windows Class Structure
WNDCLASSEX wc;
// Fill the windows class structure
wc.cbSize = sizeof(WNDCLASSEX);
wc.style = CS_HREDRAW | CS_VREDRAW; // Specifies the class styles
wc.lpfnWndProc = (WNDPROC)MessageRouter; // Pointer to the Windows Procedure
wc.cbClsExtra = 0; // Specifies the number of extra bytes to allocate following the window-class structure
wc.cbWndExtra = 0; // Specifies the number of extra bytes to allocate following the window instance
wc.hInstance = _hInstance; // Handle to the instance that contains the window procedure for the class
wc.hIcon = NULL; // Handle to the class icon
wc.hCursor = 0; // Handle to the class cursor
wc.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH); // Handle to the class background brush
wc.lpszMenuName = 0; // Pointer to a null-terminated character string that specifies the resource name of the
// class menu, as the name appears in the resource file
wc.lpszClassName = szWindowClass; // Pointer to a null-terminated string or is an atom. If this parameter is an atom, it must
// be a class atom created by a previous call to the RegisterClass or RegisterClassEx function
wc.hIconSm = LoadIcon(NULL, IDI_APPLICATION);
if(!RegisterClassEx(&wc))
{
// Window class could not be registered
return false;
}
return true;
}
//+--------------------------------------------------------------------------------+//
// //
// +-Create_Window(HINSTANCE _hInstance, int x_offset, int y_offset, int width, //
// int height, char* title) //
// //
// Purpose: //
// This method will setup a basic Win32 window based on the given parameteres //
// by first registering a windows class, then creating the window based on //
// this class. //
// //
// Comments: //
// The method will return false if the windows class cannot be registered, or //
// a window cannot be created based on the registered class. //
// //
//+--------------------------------------------------------------------------------+//
bool AP_BASEWINDOW::Create_Window(HINSTANCE _hInstance, int x_offset, int y_offset, int width, int height, char* title)
{
hInstance = _hInstance; // Store instance handle in our global variable
// Step 1 - Register the Windows Class
if(!Register_Class(_hInstance, "123"))
{
DWORD dw = GetLastError();
MessageBox(NULL, "Window Creation Failed: Window Class could not be registered", "Error", MB_OK );
return false;
}
// Step 2 - Create the window
hWnd = CreateWindowEx(WS_EX_OVERLAPPEDWINDOW, "123", title, WS_OVERLAPPEDWINDOW,
x_offset, y_offset, width, height, NULL, NULL, hInstance, static_cast<AP_BASEWINDOW*>(this));
if(!hWnd)
{
//1407 Cannot find window class. ERROR_CANNOT_FIND_WND_CLASS
DWORD dw = GetLastError();
MessageBox(NULL, "Window Creation Failed: CANNOT FIND WND CLASS", "Error", MB_OK );
return false;
}
ShowWindow(hWnd, SW_SHOWNORMAL);
UpdateWindow(hWnd);
RegisterMessageHandler(WM_CLOSE, OnWM_CLOSE);
RegisterMessageHandler(WM_CLOSE, OnWM_DESTROY);
return true;
}
//+--------------------------------------------------------------------------------+//
// //
// +-WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) //
// //
// //
// Purpose: //
// //
// Comments: //
// //
//+--------------------------------------------------------------------------------+//
LRESULT AP_BASEWINDOW::WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
switch(msg)
{
case WM_CLOSE:
{
if(hWnd)
{
if(!DestroyWindow(hWnd))
{
MessageBox(NULL,"AP_BASEGLWINDOW: Could Not Destroy Window","ERROR",MB_OK | MB_ICONINFORMATION);
hWnd = NULL;
}
}
//+-TODO: Insert code to unregister windows class used to create window
return false;
}
case WM_DESTROY:
{
PostQuitMessage(0);
return false;
}
case WM_GETMINMAXINFO:
{
LPMINMAXINFO pMMI = (LPMINMAXINFO)lParam;
pMMI->ptMaxTrackSize.x = 500;
pMMI->ptMaxTrackSize.y = 500;
}
case WM_KEYDOWN: // Is A Key Being Held Down?
{
if(wParam == VK_RIGHT)
{
cout << "Message Handlers: " << message_map.size() << endl;
}
}
default:
return DefWindowProc(hwnd, msg, wParam, lParam);
}
}
//+--------------------------------------------------------------------------------+//
// //
// +-changeWindowTitle(LPCTSTR new_title) //
// //
// //
// Purpose: //
// This method will change the title of this window to the given string //
// //
// Comments: //
// //
//+--------------------------------------------------------------------------------+//
bool AP_BASEWINDOW::changeWindowTitle(LPCTSTR new_title)
{
return SetWindowText(hWnd, new_title);
}
//+--------------------------------------------------------------------------------+//
// //
// +-GetMessageHandler(long message) //
// //
// //
// Purpose: //
// This method will return the address of the registered message handler for //
// the provided message. If no message handler is regisered then the method //
// will return NULL. //
// //
// Comments: //
// //
//+--------------------------------------------------------------------------------+//
MessageMapIterator AP_BASEWINDOW::GetMessageHandler(long message)
{
MessageMapIterator it = message_map.find(message); // Element is found in O(logn) time given the key (message)
if(it == message_map.end()) // If there element matching the provided key then the iterator
{ // will be equal to the last element in the map, so return NULL
return NULL;
}
return it;
}
long AP_BASEWINDOW::OnWM_CLOSE(HWND hwnd, long wParam, long lParam)
{
DestroyWindow(hwnd);
return 0;
}
long AP_BASEWINDOW::OnWM_DESTROY(HWND hwnd, long wParam, long lParam)
{
PostQuitMessage(0);
return 0;
}
fpMessageHandler AP_BASEWINDOW::RegisterMessageHandler(long message, fpMessageHandler handler)
{
fpMessageHandler m = NULL;
MessageMapIterator it = message_map.find(message); // Element is found in O(logn) time given the key (message)
if(it != message_map.end())
{
m = it->second;
}
message_map.insert(pair<long, fpMessageHandler>(message, handler)); // Insert Message Handler into Message Map
return m;
}
From what I understand, these errors are usually caused by comparisons of 2 iterators, however as far as I can see it's being done correctly. the problem seems to be with both comparing the iterators and calling the function pointer in MessageRouter()
Hopefully someone will be able to shed light on the situation for me as I've never encountered an error like this before.
Thanks for reading