6

我有一个简单的窗口应用程序,其中声明了主窗口回调过程:

WNDCLASSEXW wcx;
/* ... */
wcx.lpfnWndProc = MainWndProc;

WinMain我声明之后LRESULT CALLBACK MainWndProc(HWND mainWindow, UINT msg, WPARAM wparam, LPARAM lparam) { /* ... */}一切正常,但我想知道是否可以WinMainMainWndProc中将其作为 lambda 表达式?

4

3 回答 3

7

您可以使用 lambda,前提是它没有捕获,然后它具有到函数指针的隐式转换:

#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
}

问题实际上是在没有捕获的情况下,您可以在 lambda 中作为回调做多少有用的事情。您仍然可以使用“全局变量”,就像使用常规函数作为回调一样。

于 2013-01-12T11:29:15.240 回答
4

您可以使用 lambda,但它不能捕获 [ ] 中的任何变量,例如:

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;
};

适用于 Visual C++ 2012。

于 2013-05-28T20:22:25.263 回答
3

使用包装类,您可以使用将“this”指针作为货物数据存储在 HWND 上的旧技术来实现。

这种技术的一个限制是您不能处理在 WM_CREATE 之前到达的任何消息,WM_CREATE 是带有创建参数的消息(这些早期消息中只有少数,而且它们非常奇特)。

#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;
};

上述实用程序的示例使用:

#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;
}
于 2017-02-02T01:43:24.007 回答