2013-01-12 10 views
6

Ben ilan ana pencere geri arama prosedürü ile basit pencere uygulaması vardır: WinMain'de lambda olarak ana pencere prosedürüne sahip olabilir miyim?

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

ve

WinMain sonra LRESULT CALLBACK MainWndProc(HWND mainWindow, UINT msg, WPARAM wparam, LPARAM lparam) { /* ... */} ve tüm Tamam çalışıyor ilan etmesine karşın acaba o içeride bir lambda olarak bu MainWndProc sahip olmak mümkündür WinMain?

cevap

7

Bir lambda kullanabilirsiniz, bunun çalışması için örtülü bir dönüşüm vardır o zaman hiçbir yakalar vardır sağlanan işaretçi:

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

sorun gerçekten yararlı yakalar olmadan bir geri gibi bir lambda yapabileceğiniz ne kadar . Yine de "globals" a başvurabilirsin, aynı şekilde geri arama olarak normal bir fonksiyonla olabilir.

+0

, o iyi olabilir pencere örneği/pencere sınıfı için bayt. –

+0

Yerel değişkenlere lambda içindeki işlevden erişemiyorsanız, lambda'yı kullanmak için oldukça az sebep vardır. İşte bu yüzden yerel halkın kullanımına izin verecek bir mekanizma ile bir yanıt gönderdim ... –

4

Bir lambda kullanabilirsiniz, ancak örneğin [] herhangi değişkeni yakalamak olmamalıdır: Bir sarma sınıfına ile Visual C++ 2012

+1

canlandırdığım için üzgünüm, ama neden bir şey yakalayamadığımı açıklar mısınız? – rev

+1

Sadece hiçbir şey yakalamayan lambdalar işlev gösterici olarak kullanılabilir. Herhangi bir durum türünü (yakalanan değişkenleri) saklamak için bir fonksiyon göstergesinde yer yoktur. – Azarien

1

yılında

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

eser, bunu yapabilirsin "Bu" işaretçisini HWND'de kargo verileri olarak saklamak için eski tekniği kullanmak.

Bu tekniğin bir kısıtlaması, WM_CREATE'den önce gelen iletilerin işlenmesini sağlayan iletiyi işleyen iletiyi işleyememenizdir (bu erken iletilerin yalnızca bir kısmı vardır ve oldukça egzotiktir). Yukarıdaki fayda

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

Numune kullanımı: o WndProc ait girdi olarak alır parametrelerin, o ekstra gibi şeyler saklamak için kullanabilirsiniz, çünkü onun durumu için

#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; 
} 
İlgili konular