can I have main window procedure as a lambda in Wi

2019-06-20 07:24发布

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 ?

3条回答
我只想做你的唯一
2楼-- · 2019-06-20 07:34

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.

查看更多
淡お忘
3楼-- · 2019-06-20 07:44

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.

查看更多
三岁会撩人
4楼-- · 2019-06-20 07:45

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;
}
查看更多
登录 后发表回答