2013-01-12 10 views
6

Mam proste zastosowanie okien z zadeklarowanym głównego postępowania okno callback:Czy mogę mieć procedurę okna głównego jako lambda w WinMain?

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

i po WinMain oświadczyłem LRESULT CALLBACK MainWndProc(HWND mainWindow, UINT msg, WPARAM wparam, LPARAM lparam) { /* ... */} i wszystko działa ok, ale zastanawiam się, czy to możliwe, aby ten MainWndProc jako lambda wewnątrz WinMain?

Odpowiedz

7

Można użyć lambda, pod warunkiem, że nie ma to rejestruje to ma niejawna konwersja do funkcjonowania wskazówka:

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

Problem jest naprawdę ile można z powodzeniem zrobić w lambda jako zwrotnego bez przechwytywania . Możesz nadal uciekać się do "globaliów", w taki sam sposób, w jaki możesz normalnie funkcjonować jako callback.

+0

W jego przypadku, może on być w porządku, bo parametry dostaje jako wejście WndProc, może on wykorzystać je do przechowywania rzeczy jak dodatkowe bajtów dla klasy okna/okna okna. –

+0

, jeśli nie możesz uzyskać dostępu do lokalnych zmiennych z funkcji zawierania w lambda, istnieje całkiem mały powód, aby w ogóle używać lambda. Dlatego wysłałem odpowiedź na dole z mechanizmem umożliwiającym korzystanie z lokalnych ... –

4

Można użyć lambda, ale to nie musi uchwycić każdą zmienną w [], na przykład:

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

prac w Visual C++ 2012.

+1

Przepraszam, że wskrzesiłem, ale ... czy wytłumaczyłbyś, dlaczego nie mogę niczego przechwycić? – rev

+1

Ponieważ tylko lambdy, które niczego nie przechwytują, mogą być używane jako wskaźniki funkcji. W wskaźniku funkcji nie ma miejsca na zapisanie dowolnego stanu (przechwyconych zmiennych). – Azarien

1

z klasą owijania, można to zrobić używając starej techniki przechowywania "tego" wskaźnika jako danych ładunku na HWND.

Jednym z ograniczeń tej techniki jest to, że nie można przetwarzać żadnych komunikatów, które pojawią się przed WM_CREATE, który jest komunikatem, który przenosi parametr tworzenia (jest tylko kilka z tych wczesnych wiadomości i są one dość egzotyczne).

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

Przykładowe użycie narzędzia powyżej:

#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; 
} 
Powiązane problemy