我可以在WinMain中将主窗口程序作为lambda吗?

时间:2013-01-12 11:16:17

标签: c++ winapi c++11 lambda

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

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

WinMain之后我宣布LRESULT CALLBACK MainWndProc(HWND mainWindow, UINT msg, WPARAM wparam, LPARAM lparam) { /* ... */}并且一切正常,但我想知道是否可以将此MainWndProc作为lambda 置于 WinMain中?

3 个答案:

答案 0 :(得分: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中作为没有捕获的回调有多少。您仍然可以使用“全局变量”,就像使用常规函数作为回调一样。

答案 1 :(得分: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。

答案 2 :(得分:2)

使用包装类,您可以使用旧的技术来存储&#34;这个&#34;指针作为HWND上的货物数据。

这种技术的一个限制是你不能处理在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;
}