Лямбду в WinAPI
От: Слава Израиль  
Дата: 28.03.11 05:41
Оценка:
Здравствуйте.

А можно как нибудь заставить работать такое:

HWND FindApplicationWindow()
{
    HWND foundHWnd = 0;
    DWORD procID = GetCurrentProcessId();
    EnumWindows([&foundHWnd,&procID](HWND hWnd, LPARAM lParam) -> BOOL
    {
        /*
         ********************************************
         */
        return TRUE;
    },
    0);
}


error C2664: 'EnumWindows' : cannot convert parameter 1 from '`anonymous-namespace'::<lambda0>' to 'WNDENUMPROC'

Спасибо за внимание
Re: Лямбду в WinAPI
От: ilnar Россия  
Дата: 28.03.11 05:45
Оценка:
Здравствуйте, Слава, Вы писали:

С>Здравствуйте.


С>А можно как нибудь заставить работать такое:


С>
С>HWND FindApplicationWindow()
С>{
С>    HWND foundHWnd = 0;
С>    DWORD procID = GetCurrentProcessId();
С>    EnumWindows([&foundHWnd,&procID](HWND hWnd, LPARAM lParam) -> BOOL
С>    {
С>        /*
С>         ********************************************
С>         */
С>        return TRUE;
С>    },
С>    0);
С>}
С>


С>

С>error C2664: 'EnumWindows' : cannot convert parameter 1 from '`anonymous-namespace'::<lambda0>' to 'WNDENUMPROC'


сделай фугкцию обертку.
лямбда функции это объекты с перегруженным оператором, а WINAPI хочет чистые функции с с особой конвенцией вызова
Re[2]: Лямбду в WinAPI
От: Слава Израиль  
Дата: 28.03.11 05:48
Оценка:
Здравствуйте, ilnar, Вы писали:

I>сделай фугкцию обертку.

I>лямбда функции это объекты с перегруженным оператором, а WINAPI хочет чистые функции с с особой конвенцией вызова

Ну тогда проще будет по старинке.
Спасибо за внимание
Re: Лямбду в WinAPI
От: alexeiz  
Дата: 28.03.11 07:33
Оценка:
Здравствуйте, Слава, Вы писали:

С>Здравствуйте.


С>А можно как нибудь заставить работать такое:


С>
С>HWND FindApplicationWindow()
С>{
С>    HWND foundHWnd = 0;
С>    DWORD procID = GetCurrentProcessId();
С>    EnumWindows([&foundHWnd,&procID](HWND hWnd, LPARAM lParam) -> BOOL
С>    {
С>        /*
С>         ********************************************
С>         */
С>        return TRUE;
С>    },
С>    0);
С>}
С>


С>

С>error C2664: 'EnumWindows' : cannot convert parameter 1 from '`anonymous-namespace'::<lambda0>' to 'WNDENUMPROC'


Убери capture parameters [&foundHWnd, &procID], и тогда будет работать. Например:
typedef int (*func)(int);

int foo(func f)
{
    return f(10);
}

int main()
{
    return foo([](int a) { return 2 * a; });
}
Re[2]: Лямбду в WinAPI
От: Слава Израиль  
Дата: 28.03.11 07:38
Оценка:
Здравствуйте, alexeiz, Вы писали:

A>Убери capture parameters [&foundHWnd, &procID], и тогда будет работать. Например:

A>
A>typedef int (*func)(int);

A>int foo(func f)
A>{
A>    return f(10);
A>}

A>int main()
A>{
A>    return foo([](int a) { return 2 * a; });
A>}
A>


Ну во первых они мне нужны, без них проще и короче будет по старому.
А во вторых, можешь обяснить причину такого поведения?
Спасибо за внимание
Re[3]: Лямбду в WinAPI
От: _nn_ www.nemerleweb.com
Дата: 28.03.11 07:48
Оценка: 4 (1)
Здравствуйте, Слава, Вы писали:

С>А во вторых, можешь обяснить причину такого поведения?


По стандарту:
http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2010/n3052.html

Если нет захваченных аргументов, то есть преобразование в указатель на функцию.

5.1.2.6

The closure type for a lambda-expression with no lambda-capture has a public non-virtual non-explicit const
conversion function to pointer to function having the same parameter and return types as the closure type’s
function call operator. The value returned by this conversion function shall be the address of a function
that, when invoked, has the same effect as invoking the closure type’s function call operator.

http://rsdn.nemerleweb.com
http://nemerleweb.com
Re[4]: Лямбду в WinAPI
От: ilnar Россия  
Дата: 28.03.11 07:54
Оценка:
Здравствуйте, _nn_, Вы писали:

__>Здравствуйте, Слава, Вы писали:


С>>А во вторых, можешь обяснить причину такого поведения?


__>По стандарту:

__>http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2010/n3052.html

__>Если нет захваченных аргументов, то есть преобразование в указатель на функцию.


__>5.1.2.6

__>

__>The closure type for a lambda-expression with no lambda-capture has a public non-virtual non-explicit const
__>conversion function to pointer to function having the same parameter and return types as the closure type’s
__>function call operator. The value returned by this conversion function shall be the address of a function
__>that, when invoked, has the same effect as invoking the closure type’s function call operator.


вот бы еще побороть __stdcall
Re[5]: Лямбду в WinAPI
От: _nn_ www.nemerleweb.com
Дата: 28.03.11 08:00
Оценка:
Здравствуйте, ilnar, Вы писали:


I>вот бы еще побороть __stdcall



Тут две проблемы

Во первых VC2010 не компилирует этот пример.
Во вторых для преобразования в указатель на функцию придется писать обертку.


Лямбду с __stdcall создать легко:
auto p = [](int a) -> int __stdcall { return a; }

Можно даже завернуть в std::function
std::function<int(int)> px(p);
http://rsdn.nemerleweb.com
http://nemerleweb.com
Re[2]: Лямбду в WinAPI
От: баг  
Дата: 28.03.11 08:02
Оценка:
Здравствуйте, alexeiz, Вы писали:

A>Убери capture parameters [&foundHWnd, &procID], и тогда будет работать. Например:

Не будет. Нужна функция а) статическая б) stdcall. У лямбда же иное — это объект с перегруженным оператором вызова. Скрестить их можно только через переходники.
Re[3]: Лямбду в WinAPI
От: jyuyjiyuijyu  
Дата: 28.03.11 08:45
Оценка:
лямбда без capture параметров прекрасно подходит для
вызова из уже скомпиленного двоичного кода ничто
не мешает конвертнуть ее в указатель на функцию
а вот с capture параметрами сложнее надо this передавать
по всей видимости иначе как она до capture параметров
дотянется естественно не совместимо с WINAPI
если я все правильно понял
Re: Лямбду в WinAPI
От: jyuyjiyuijyu  
Дата: 28.03.11 11:32
Оценка:
еще такое бывает )))
по мотивам http://www.gamedev.ru/code/forum/?id=85183&amp;page=2
#include <windows.h>
#include <stdio.h>

typedef unsigned __int32 uint32;
typedef unsigned __int16 uint16;
typedef unsigned __int8   uint8;

#include <PshPack1.h>
struct thunk
{
  uint16 a; uint8 b; uint32 c; void* param;
  uint8 d; void* pfn; uint16 e;
  //---------------------
  uint16 aa; uint8 bb; uint32 cc; void* paramm;
  uint8 dd; void* pfnn; uint16 ee;
};
#include <PopPack.h>

template<class ArgType1>
struct objCallback1
{
    void *f;
    ArgType1 a1;
    thunk &t;
    objCallback1(void *f, ArgType1 a1):f(f),t(*new thunk)
    {
        typedef char buf[sizeof(ArgType1) <= sizeof(void*) ? 1 : 0];
        objCallback1::a1 = a1;
    }
    template<class Ret_t>
    operator Ret_t *()
    {
        return join<Ret_t>();
    }
    template<class Ret_t>
    Ret_t * join()
    {
        t.a = 0x34FF; t.b = 0x24;  t.c = 0x042444C7;  t.param = (void*)a1;
        t.d = 0xB8; t.pfn = f; t.e = 0xE0FF;
        //------------------------
        t.aa = 0x34FF; t.bb = 0x24;  t.cc = 0x042444C7;  t.paramm = (void*)&t;
        t.dd = 0xB8; t.pfnn = free_join; t.ee = 0xE0FF;
        atexit((void(*)())((char*)&t + 18));
        return (Ret_t *)&t;
    }
    /*
     testlinkage.exe!objCallback1<unsigned int>::free_join(void * mem=0x00356d00)  Line 48    C++
     msvcr90d.dll!doexit(int code=0x00000000, int quick=0x00000000, int retcaller=0x00000000)  Line 591    C
     msvcr90d.dll!exit(int code=0x00000000)  Line 412 + 0xd bytes    C
     testlinkage.exe!__tmainCRTStartup()  Line 595    C
     testlinkage.exe!mainCRTStartup()  Line 399    C
     kernel32.dll!_BaseProcessStart@4()  + 0x23 bytes    
    */
    static void __stdcall free_join(void *mem)
    {
        delete mem;
    }
};

template<class ArgType1>
objCallback1<ArgType1> Join(void *f, ArgType1 a1)
{
    return objCallback1<ArgType1>(f, a1);
}

VOID CALLBACK 
MyTimerProc(void* userdata, HWND hwnd, UINT uMsg,  UINT idEvent,  DWORD dwTime)
{
    printf("User data @ 0x%p\n", userdata );
}

int main()
{
    SetTimer(0, 0, 1000, Join(MyTimerProc, 0xdeadc0de));

    MSG msg;
    int ecx = 0;
    while(ecx++ < 3 && GetMessage(&msg, NULL, 0, 0))
        DispatchMessage(&msg);
}

можно сделать доступным от 1 и более
параметров для склейки ограничение та к кому клеим
должна быть с __stdcall соглашением
Re[2]: Лямбду в WinAPI
От: Слава Израиль  
Дата: 28.03.11 19:45
Оценка:
Здравствуйте, alexeiz, Вы писали:

A>Здравствуйте, Слава, Вы писали:


A>Убери capture parameters [&foundHWnd, &procID], и тогда будет работать. Например:

A>
A>typedef int (*func)(int);

A>int foo(func f)
A>{
A>    return f(10);
A>}

A>int main()
A>{
A>    return foo([](int a) { return 2 * a; });
A>}
A>


Не взлетело,
и так тоже

    EnumWindows([](HWND hwnd,LPARAM lParam) -> BOOL __stdcall 
    {
Спасибо за внимание
Re[3]: Лямбду в WinAPI
От: alexeiz  
Дата: 28.03.11 20:07
Оценка:
Здравствуйте, Слава, Вы писали:

С>Здравствуйте, alexeiz, Вы писали:


A>>Здравствуйте, Слава, Вы писали:


A>>Убери capture parameters [&foundHWnd, &procID], и тогда будет работать. Например:

A>>
A>>typedef int (*func)(int);

A>>int foo(func f)
A>>{
A>>    return f(10);
A>>}

A>>int main()
A>>{
A>>    return foo([](int a) { return 2 * a; });
A>>}
A>>


С>Не взлетело,

С>и так тоже

С>
С>    EnumWindows([](HWND hwnd,LPARAM lParam) -> BOOL __stdcall 
С>    {

С>


В Visual C++, вероятно, такое еще не реализовано. В G++ 4.6 всё нормально.
Re[4]: Лямбду в WinAPI
От: _nn_ www.nemerleweb.com
Дата: 30.03.11 09:43
Оценка:
Здравствуйте, alexeiz, Вы писали:

A>В Visual C++, вероятно, такое еще не реализовано. В G++ 4.6 всё нормально.


В следующем релизе будет работать
http://rsdn.nemerleweb.com
http://nemerleweb.com
Re[5]: Лямбду в WinAPI
От: 23W http://kyselgov.pp.ua/
Дата: 15.12.11 11:28
Оценка:
Здравствуйте, _nn_, Вы писали:

__>Здравствуйте, alexeiz, Вы писали:

A>>В Visual C++, вероятно, такое еще не реализовано. В G++ 4.6 всё нормально.
__>В следующем релизе будет работать

а сейчас как быть ? может через std::bind(), std::mem_fn() или через еще что-то можно передать лямбду в качестве callback функции ?
P.S.: кстати, по стандарту лямбды не поддерживают модели вызовов. Т.е. такое []() -> BOOL __stdcall {return TRUE;} компилироваться не должно. В VC++ 2010 SP1 такой код все же компилируется, но при этом __stdcall выбрасывается, как будто бы его нет...
Re[6]: Лямбду в WinAPI
От: _NN_ www.nemerleweb.com
Дата: 15.12.11 12:18
Оценка:
Здравствуйте, 23W, Вы писали:

23W>Здравствуйте, _nn_, Вы писали:


__>>Здравствуйте, alexeiz, Вы писали:

A>>>В Visual C++, вероятно, такое еще не реализовано. В G++ 4.6 всё нормально.
__>>В следующем релизе будет работать

23W>а сейчас как быть ? может через std::bind(), std::mem_fn() или через еще что-то можно передать лямбду в качестве callback функции ?

Сейчас использовать просто функцию.
Чем вариант плох ?

23W>P.S.: кстати, по стандарту лямбды не поддерживают модели вызовов. Т.е. такое []() -> BOOL __stdcall {return TRUE;} компилироваться не должно. В VC++ 2010 SP1 такой код все же компилируется, но при этом __stdcall выбрасывается, как будто бы его нет...

По стандарту и __stdcall не существует
http://rsdn.nemerleweb.com
http://nemerleweb.com
Re[7]: Лямбду в WinAPI
От: 23W http://kyselgov.pp.ua/
Дата: 15.12.11 12:54
Оценка:
Здравствуйте, _NN_, Вы писали:

_NN>Здравствуйте, 23W, Вы писали:


23W>>Здравствуйте, _nn_, Вы писали:


__>>>Здравствуйте, alexeiz, Вы писали:

A>>>>В Visual C++, вероятно, такое еще не реализовано. В G++ 4.6 всё нормально.
__>>>В следующем релизе будет работать

23W>>а сейчас как быть ? может через std::bind(), std::mem_fn() или через еще что-то можно передать лямбду в качестве callback функции ?

_NN>Сейчас использовать просто функцию.
_NN>Чем вариант плох ?

хотелось все и сразу

23W>>P.S.: кстати, по стандарту лямбды не поддерживают модели вызовов. Т.е. такое []() -> BOOL __stdcall {return TRUE;} компилироваться не должно. В VC++ 2010 SP1 такой код все же компилируется, но при этом __stdcall выбрасывается, как будто бы его нет...

_NN>По стандарту и __stdcall не существует
это точно но в принципе поведением VC++ 2010 я удивлен, принял модель вызова и проигнорировал ее
Re: Лямбду в WinAPI
От: Кодт Россия  
Дата: 15.12.11 13:37
Оценка:
Здравствуйте, Слава, Вы писали:

С>Здравствуйте.


С>А можно как нибудь заставить работать такое:


С>
С>HWND FindApplicationWindow()
С>{
С>    HWND foundHWnd = 0;
С>    DWORD procID = GetCurrentProcessId();
С>    EnumWindows([&foundHWnd,&procID](HWND hWnd, LPARAM lParam) -> BOOL
С>    {
С>        /*
С>         ********************************************
С>         */
С>        return TRUE;
С>    },
С>    0);
С>}
С>


Только если сделать ещё один переходник
BOOL CALLBACK enumwindows_thunk(HWND hwnd, LPARAM arg)
{
  return (*(const function<BOOL(HWND)>*)arg)(hwnd);
}

LPARAM enumwindows_arg(const function<BOOL(HWND)>& fun)
{
  return (LPARAM)&fun;
}

.......
EnumWindows(
  enumwindows_thunk,
  enumwindows_arg(
    [&foundHWnd,&procId](HWND hwnd) -> BOOL
    {
      .....
    }
  )
);
.....

Идея в том, чтобы передавать замыкание как аргумент в колбек, и уже в колбеке вызывать всё по-человечески.
Перекуём баги на фичи!
Re[2]: Лямбду в WinAPI
От: Centaur Россия  
Дата: 15.12.11 14:25
Оценка:
Здравствуйте, jyuyjiyuijyu, Вы писали:

J>еще такое бывает )))

J>    template<class Ret_t>
J>    Ret_t * join()
J>    {
J>        t.a = 0x34FF; t.b = 0x24;  t.c = 0x042444C7;  t.param = (void*)a1;
J>        t.d = 0xB8; t.pfn = f; t.e = 0xE0FF;
J>        //------------------------
J>        t.aa = 0x34FF; t.bb = 0x24;  t.cc = 0x042444C7;  t.paramm = (void*)&t;
J>        t.dd = 0xB8; t.pfnn = free_join; t.ee = 0xE0FF;
J>        atexit((void(*)())((char*)&t + 18));
J>        return (Ret_t *)&t;
J>    }

:maniac: Убивать. Это развалится при первой же попытке скомпилировать и запустить на любой другой платформе. Начиная с x64.
Re[2]: Лямбду в WinAPI
От: 23W http://kyselgov.pp.ua/
Дата: 16.12.11 10:54
Оценка:
Здравствуйте, Кодт, Вы писали:

К>Здравствуйте, Слава, Вы писали:


С>>Здравствуйте.


С>>А можно как нибудь заставить работать такое:


С>>
С>>HWND FindApplicationWindow()
С>>{
С>>    HWND foundHWnd = 0;
С>>    DWORD procID = GetCurrentProcessId();
С>>    EnumWindows([&foundHWnd,&procID](HWND hWnd, LPARAM lParam) -> BOOL
С>>    {
С>>        /*
С>>         ********************************************
С>>         */
С>>        return TRUE;
С>>    },
С>>    0);
С>>}
С>>


К>Только если сделать ещё один переходник

К>
К>BOOL CALLBACK enumwindows_thunk(HWND hwnd, LPARAM arg)
К>{
К>  return (*(const function<BOOL(HWND)>*)arg)(hwnd);
К>}

К>LPARAM enumwindows_arg(const function<BOOL(HWND)>& fun)
К>{
К>  return (LPARAM)&fun;
К>}

К>.......
К>EnumWindows(
К>  enumwindows_thunk,
К>  enumwindows_arg(
К>    [&foundHWnd,&procId](HWND hwnd) -> BOOL
К>    {
К>      .....
К>    }
К>  )
К>);
К>.....
К>

К>Идея в том, чтобы передавать замыкание как аргумент в колбек, и уже в колбеке вызывать всё по-человечески.


Эта идей не работает, т.к. все калбеки имеют разный список параметров... что писать под каждый из них enumwindows_thunk ? толку тогда от лябды... ведь основная идея была уйти от статических функций в своем коде.
Шаблоном к сожалению тут тоже не помочь. Можно сделать шаблоную ф-ю с форматом вызова __stdcall которая бы вызывала экивиалентную ей по списку параметров лямбду, но как эту лямбду передать в шаблон ?
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.