Колбек для метода класса.

Тема в разделе "LANGS.C", создана пользователем n0name, 10 мар 2007.

  1. xcode

    xcode Member

    Публикаций:
    0
    Регистрация:
    8 апр 2007
    Сообщения:
    105
    В функции типа EnumWindows в любом случае придется передавать адрес статического метода. тут не помогут ни интерфейсы, ни указатели на функции-члены. И хорошо если винда предусматривает аргумент через который можно передать this.
     
  2. Smile

    Smile New Member

    Публикаций:
    0
    Регистрация:
    28 июл 2004
    Сообщения:
    129
    Код (Text):
    1. #define _STDCALL 0
    2. #define _CCALL   1
    3.  
    4. extern "C"
    5. {
    6.     void* make_shell(void*, void*, void*, int);
    7. }
    8.  
    9. // __thiscall => __cdecl
    10. template <typename C, typename M, typename F>
    11. F method_cptr(C* class_ptr, M method_ptr)
    12. {
    13.     return((F)make_shell(new char[512],&class_ptr,&method_ptr,_CCALL));
    14. }
    15.  
    16. // __thiscall => __stdcall
    17. template <typename C, typename M, typename F>
    18. F method_stdptr(C* class_ptr, M method_ptr)
    19. {
    20.     return((F)make_shell(new char[512],&class_ptr,&method_ptr,_STDCALL));
    21. }
    Код (Text):
    1. ; fasm-1.66
    2. format MS COFF
    3.  
    4. public _make_shell
    5.  
    6. section '.code' readable executable
    7.  
    8.     ; fasm-1.66
    9.     ; Функция преобразует вызов __stdcall/__cdecl в __thiscall.
    10.  
    11.        shell_data:
    12.     this_ptr   = $-shell_data
    13.      dd ?
    14.     method_ptr = $-shell_data
    15.      dd ?
    16.     func_type  = $-shell_data
    17.      dd ?
    18.     ret_addr   = $-shell_data
    19.      dd ?
    20.     old_ecx    = $-shell_data
    21.      dd ?
    22.     old_esp    = $-shell_data
    23.      dd ?
    24.  
    25.        shell_code:
    26.     ; Сохранить ecx от повреждения
    27.     push    ecx
    28.     ; Получить текущий адрес
    29.     call    get_eip
    30.        get_eip:
    31.     ; Переместится к полю данных
    32.     sub dword [esp],get_eip-shell_data
    33.     pop ecx
    34.     ; Сохранить ecx
    35.     pop dword[ecx+old_ecx]
    36.     ; Адрес возврата
    37.     pop dword[ecx+ret_addr]
    38.     ; Сохранить указатель стека
    39.     mov dword[ecx+old_esp],esp
    40.     ; Загрузить this и вызвать метод
    41.     push    ecx
    42.     add dword[esp],return-shell_data
    43.     push    dword[ecx+method_ptr]
    44.     mov ecx,[ecx+this_ptr]
    45.     ret
    46.     ; Сюда вернется управление после вызова
    47.        return:
    48.     ; Получить текущий адрес
    49.     call    get_eip2
    50.        get_eip2:
    51.     sub dword[esp],get_eip2-shell_data
    52.     pop ecx
    53.     ; __cdecl восстанавливает стек, его еще должна очистить
    54.     ; вызывающая функция :)
    55.     cmp dword [ecx+func_type],0
    56.     jz  esp_ok
    57.     mov esp,[ecx+old_esp]
    58.        esp_ok:
    59.     ; Загрузить адрес возврата
    60.     push    dword [ecx+ret_addr]
    61.     ; Восстановить ecx
    62.     mov ecx,[ecx+old_ecx]
    63.     ret
    64.        shell_end:  
    65.  
    66.  
    67.  
    68.     ; fasm 1.66
    69.     ; Функия создания обертки
    70.  
    71.     ; void* make_shell(void* buffer, void* class, void* method, int type)
    72.       _make_shell:
    73.     push    ebp
    74.     mov ebp,esp
    75.     push    esi
    76.     push    edi
    77.     push    ecx
    78.     ; Память для хранения функции (buffer)
    79.     mov eax,[ebp+8]
    80.     mov edi,eax
    81.     ; Указатель this (c_ptr)
    82.     mov eax,[ebp+12]
    83.     mov esi,eax
    84.     lods    dword[esi]
    85.     stos    dword[edi]
    86.     ; Указатель на метод (m_ptr)
    87.     mov eax,[ebp+16]
    88.     mov esi,eax
    89.     lods    dword[esi]
    90.     stos    dword[edi]
    91.     ; Тип функции (type)
    92.     mov eax,[ebp+20]
    93.     stos    dword[edi]
    94.     ; Поля для ecx,esp,адреса возврата
    95.     stos    dword[edi]
    96.     stos    dword[edi]
    97.     stos    dword[edi]
    98.     ; Копируем код функции
    99.     mov esi,shell_code
    100.     mov ecx,shell_end-shell_code
    101.     rep movsb
    102.     ; Возврашаем указатель на shell_code
    103.     mov eax,[ebp+8]
    104.     add eax,shell_code-shell_data
    105.     ; Выход
    106.     pop ecx
    107.     pop edi
    108.     pop esi
    109.     pop ebp
    110.     ret
    Код (Text):
    1. #include <stdio.h>
    2. #include "cppint.h"
    3.  
    4.  
    5. class A
    6. {
    7. public:
    8.     int print_0();
    9.     int print_2(const char* s, int n);
    10.  
    11.     typedef (A::*t_mp0)();
    12.     typedef (A::*t_mp2)(const char*,int);
    13. };
    14.  
    15. int
    16. A::print_0()
    17. {
    18.     return(printf("print_0\n"));
    19. }
    20.  
    21. int
    22. A::print_2(const char* s, int n)
    23. {
    24.     return(printf("print_2(%s,%d)\n",s,n));
    25. }
    26.  
    27.  
    28. typedef int (*t_fn0)();
    29. typedef int (*t_fn2)(const char*,int);
    30. typedef int (__stdcall *t_fn3)(const char*,int);
    31.  
    32. void
    33. test_0(t_fn0 f)
    34. {
    35.     f();
    36. }
    37.  
    38. void
    39. test_2(t_fn2 f)
    40. {
    41.     f("One",1);
    42. }
    43.  
    44. void
    45. test_std(t_fn3 f)
    46. {
    47.     f("std",1);
    48. }
    49.  
    50. int
    51. main()
    52. {
    53.     A a;
    54.     test_0( method_cptr<A,A::t_mp0,t_fn0>(&a, &A::print_0) );
    55.     test_2( method_cptr<A,A::t_mp2,t_fn2>(&a, &A::print_2) );
    56.     test_std( method_stdptr<A,A::t_mp2,t_fn3>(&a, &A::print_2) );
    57.     return(0);
    58. }
     
  3. Nouzui

    Nouzui New Member

    Публикаций:
    0
    Регистрация:
    17 ноя 2006
    Сообщения:
    856
    Smile
    все хорошо, пока ты не включишь NX
     
  4. IceStudent

    IceStudent Active Member

    Публикаций:
    0
    Регистрация:
    2 окт 2003
    Сообщения:
    4.300
    Адрес:
    Ukraine
    Тогда уж заглушки по типу MFC/ATL, они попроще будут и переносить легче.