I have a simple window application with declared main window callback procedure:
WNDCLASSEXW wcx;
/* ... */
wcx.lpfnWndProc = MainWndProc;
and after the WinMain
I declared LRESULT CALLBACK MainWndProc(HWND mainWindow, UINT msg, WPARAM wparam, LPARAM lparam) { /* ... */}
and all is working ok, but I wonder is it possible to have this MainWndProc
as a lambda inside WinMain ?
You can use a lambda, provided it has no captures then it has an implicit conversion to function pointer:
#include <iostream>
typedef void (*func)();
static func some_func;
int global;
int main() {
some_func = [](){ std::cout << "Hello\n"; }; // Fine
some_func();
int local;
some_func = [&](){ local = 1; }; // Illegal - No conversion
some_func = [](){ global = 1; }; // Fine
}
The problem really is how much you can usefully do in a lambda as a callback without captures. You can still resort to "globals", in the same way you might with a regular function as the callback.
You can use a lambda, but it must not capture any variable in [ ], for example:
wc.lpfnWndProc=[](HWND h, UINT m, WPARAM w, LPARAM l)->LRESULT
{
if (m==WM_CLOSE)
PostQuitMessage(0);
else
return DefWindowProc(h,m,w,l);
return 0;
};
works in Visual C++ 2012.
With a wrapping class, you can do it using the old technique of storing the "this" pointer as cargo data on the HWND.
One limitation of this technique is that you can't process any messages that arrive before WM_CREATE, which is the message that carries the creation parameter (there's only a handful of these early messages, and they are quite exotic).
#pragma once
// LambdaWindow.h -- Lambda Window utility
#include <windows.h>
#include <tchar.h>
#include <functional>
class LambdaWindow
{
public:
typedef
std::function<LRESULT(HWND h, UINT m, WPARAM w, LPARAM l)>
WindowProcFunction;
public:
LambdaWindow(const WindowProcFunction &pfn) : fn(pfn) { }
virtual ~LambdaWindow() { }
static LRESULT CALLBACK Stub(HWND h, UINT m, WPARAM w, LPARAM l)
{
LambdaWindow *pThis = (LambdaWindow *)GetWindowLongPtr(h, GWLP_USERDATA);
if (pThis)
{
return pThis->fn(h, m, w, l);
}
else if (m == WM_CREATE)
{
pThis = (LambdaWindow *)(((CREATESTRUCT *)l)->lpCreateParams);
SetWindowLongPtr(h, GWLP_USERDATA, (LONG_PTR)pThis);
return pThis->fn(h, m, w, l);
}
return DefWindowProc(h, m, w, l);
}
private:
WindowProcFunction fn;
};
Sample use of the utility above:
#include "LambdaWindow.h"
int WINAPI WinMain(HINSTANCE hInstance,
HINSTANCE hPrevInstance,
LPSTR lpCmdLine,
int nCmdShow)
{
HWND wnd;
TCHAR testText[] = _T("Some Text");
RECT textLocation = { 10, 10, 150, 30 };
WNDCLASS wc = { 0 };
wc.lpfnWndProc = LambdaWindow::Stub;
wc.hInstance = hInstance;
wc.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
wc.lpszClassName = L"minwindowsapp";
wc.hCursor = LoadCursor(NULL, IDC_ARROW);
LambdaWindow wlambda =
[&](HWND h, UINT m, WPARAM w, LPARAM l)->LRESULT
{
switch (m)
{
case WM_PAINT:
{
PAINTSTRUCT ps;
HDC hdc;
hdc = BeginPaint(h, &ps);
DrawText(hdc, testText, -1,
&textLocation, DT_CENTER| DT_VCENTER );
EndPaint(h, &ps);
}
break;
case WM_CLOSE:
PostQuitMessage(0);
break;
default:
return DefWindowProc(h, m, w, l);
}
return 0;
};
if (RegisterClass(&wc))
{
wnd = CreateWindow(wc.lpszClassName,
L"Minimal Windows Application",
WS_OVERLAPPEDWINDOW,
0, 0, 640, 480, NULL, NULL, hInstance, &wlambda);
if (wnd)
{
MSG msg;
ShowWindow(wnd, nCmdShow);
UpdateWindow(wnd);
while (GetMessage(&msg, NULL, 0, 0) > 0)
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
}
return 0;
}