Поиск:

Ответ в темуСоздание новой темы Создание опроса
> [VC++]импорт методов, и работа с их адресами 
:(
    Опции темы
GoldFinch
Дата 17.7.2009, 12:49 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата



****


Профиль
Группа: Завсегдатай
Сообщений: 2141
Регистрация: 30.11.2008

Репутация: нет
Всего: 26



а еще лучше выкинуть класс Imp_ из метода:
Код

struct Imp_
{
    void* addr;
    Imp_(const char* name) { Dll::import(addr,name); }            

    template<typename T>
    T call_(T proto)
    {
        BOOST_STATIC_ASSERT(sizeof(proto)==sizeof(addr));
        union U
        {
            void* x;
            T y;
        } u = {addr};
        return u.y;
    }
};

Код

class Foo
{
public:
...
    void init(char* str) 
    { 
        static Imp_ imp_("?init@Foo@@UAEXPAD@Z");
        return (this->*imp_.call_(&Foo::init))(str); 
    }
...
}


Добавлено через 14 минут и 30 секунд
хм... только вот не получается получить адрес конструктора и деструктора =\
PM MAIL ICQ   Вверх
GoldFinch
Дата 17.7.2009, 13:19 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата



****


Профиль
Группа: Завсегдатай
Сообщений: 2141
Регистрация: 30.11.2008

Репутация: нет
Всего: 26



значит всетаки так:
Код

template<typename T>
struct Imp_
{
    T addr;
    Imp_(const char* name) { Dll::import(addr,name); }            
};

class Foo
{
public:
    int* vftable;
    char* str;
public:    
    Foo()
    {
        static Imp_<void(Foo::*)()> imp_("??0Foo@@QAE@XZ");
        (this->*imp_.addr)(); 

        Dll::import(vftable,"??1Foo@@UAE@XZ");
    }
    ~Foo() 
    {
        static Imp_<void(Foo::*)()> imp_("??0Foo@@QAE@XZ");
        (this->*imp_.addr)();
    }

    void init(char* str) 
    { 
        static Imp_<void(Foo::*)(char*)> imp_("?init@Foo@@UAEXPAD@Z");
        return (this->*imp_.addr)(str); 
    }

    void test() 
    { 
        static Imp_<void(Foo::*)()> imp_("?test@Foo@@UAEXXZ");
        return (this->*imp_.addr)(); 
    }    

};

PM MAIL ICQ   Вверх
mes
Дата 17.7.2009, 14:36 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


любитель
****


Профиль
Группа: Участник Клуба
Сообщений: 7954
Регистрация: 14.1.2006

Репутация: 1
Всего: 250



Цитата(GoldFinch @  17.7.2009,  12:19 Найти цитируемый пост)
   return (this->*imp_.addr)(); 

добавьте в структуру Imp_ :   
Код

 operator T () { return addr; } 

и отпадет надобность писать .addr
 smile 


Это сообщение отредактировал(а) mes - 17.7.2009, 14:38


--------------------
PM MAIL WWW   Вверх
GoldFinch
Дата 17.7.2009, 16:33 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата



****


Профиль
Группа: Завсегдатай
Сообщений: 2141
Регистрация: 30.11.2008

Репутация: нет
Всего: 26



mes, я решил пойти еще дальше, и написать эту структуру так:
Код

namespace import {

    ...

    template<typename T>
    T inline union_cast(void* x)
    {
        BOOST_STATIC_ASSERT(sizeof(T)==sizeof(x));
        union U
        {
            void* x;
            T y;
        } u = {x};
        return u.y;
    }

    template<typename retT=void>
    struct Import
    {
        void* addr;
        Import(const char* name) { Dll::import(addr,name); }

        template<typename classT>
        retT operator() (classT* that) 
        { return (that->*union_cast<retT(classT::*)()>(addr))();    }

        template<typename classT, typename T1>
        retT operator() (classT* that, T1 arg1) 
        { return (that->*union_cast<retT(classT::*)(T1)>(addr))(arg1); }

        template<typename classT, typename T1, typename T2>
        retT operator() (classT* that, T1 arg1, T2 arg2) 
        { return (that->*union_cast<retT(classT::*)(T1,T2)>(addr))(arg1,arg2); } 
        
        ...
    };

} // namespace import

тогда ее можно использовать так:
Код

class Foo
{
    ...

    int sum(int a,char b)
    {
        static import::Import<int> imp_("?sum@Foo@@QAEHHD@Z");
        return imp_(this,a,b); 
    }
};

PM MAIL ICQ   Вверх
GoldFinch
Дата 17.7.2009, 17:17 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата



****


Профиль
Группа: Завсегдатай
Сообщений: 2141
Регистрация: 30.11.2008

Репутация: нет
Всего: 26



объявляю эту тему форума репозиторием версий кода импорта методов =)

перенес аргумент шаблона retT из класса в operator()
Код

    template<typename T=void> struct ret_tag{};

    struct Import
    {
        void* addr;
        Import(const char* name) { Dll::import(addr,name); }

        template<typename retT,typename classT>
        retT operator() (ret_tag<retT>,classT* that) 
        { return (that->*union_cast<retT(classT::*)()>(addr))();    }

        template<typename retT,typename classT, typename T1>
        retT operator() (ret_tag<retT>,classT* that, T1 arg1) 
        { return (that->*union_cast<retT(classT::*)(T1)>(addr))(arg1); }

        template<typename retT,typename classT, typename T1, typename T2>
        retT operator() (ret_tag<retT>,classT* that, T1 arg1, T2 arg2) 
        { return (that->*union_cast<retT(classT::*)(T1,T2)>(addr))(arg1,arg2); } 

    };

// ************************* использование *****************
class Foo
{
    ...

    int sum(int a,char b)
    {
        static import::Import imp_("?sum@Foo@@QAEHHD@Z");
        return imp_(import::ret_tag<int>(),this,a,b); 
    }
};


в стл или бусте есть класс 
template<typename T> struct какое_нибудь_имя{}; ?

Добавлено через 7 минут и 15 секунд
и есть ли гденить в бусте (в стл нет) аналог такой функции?
Код

    template<typename yT,typename xT>
    yT inline union_cast(xT x)
    {
        BOOST_STATIC_ASSERT(sizeof(xT)==sizeof(yT));
        union U
        {
            xT x;
            yT y;
        } u = {x};
        return u.y;
    }


(нужна для приведения указателей на члены классов, т.к. они не приводятся приведеним типов в С-стиле)
PM MAIL ICQ   Вверх
mes
Дата 17.7.2009, 20:22 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


любитель
****


Профиль
Группа: Участник Клуба
Сообщений: 7954
Регистрация: 14.1.2006

Репутация: 1
Всего: 250



Цитата(GoldFinch @  17.7.2009,  15:33 Найти цитируемый пост)
решил пойти еще дальше, и написать эту структуру так:

Цитата(GoldFinch @  17.7.2009,  15:33 Найти цитируемый пост)
      union U
        {
            void* x;
            T y;
        } u = {x};
        return u.y;


Mне кажется Вас опять относит в сторону - снова перекладываете работу по контролю типов с компилятора на свои плечи...


Это сообщение отредактировал(а) mes - 17.7.2009, 20:23


--------------------
PM MAIL WWW   Вверх
GoldFinch
Дата 18.7.2009, 10:22 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата



****


Профиль
Группа: Завсегдатай
Сообщений: 2141
Регистрация: 30.11.2008

Репутация: нет
Всего: 26



mes, если компилятор не умеет присваивать такие указатели, мне приходится делать это за него.


переписал с использованием boost.preprocessor :

Код

//import.h

...

#include <boost/preprocessor/comma_if.hpp>
#include <boost/preprocessor/cat.hpp>
#include <boost/preprocessor/array/elem.hpp>
#include <boost/preprocessor/array/size.hpp>
#include <boost/preprocessor/repeat.hpp>
#include <boost/preprocessor/if.hpp>
#include <boost/preprocessor/repetition/enum_params.hpp>

#define IMPORT_IMPL_ARG_DECL_(z, i, data)    \
    BOOST_PP_COMMA_IF(i)                    \
    BOOST_PP_ARRAY_ELEM(i,data)                \
    BOOST_PP_CAT(arg,i)                        \
    /*--*/

#define IMPORT_IMPL_ARGLIST_DECL_(a_arg)    \
    BOOST_PP_REPEAT(                        \
        BOOST_PP_ARRAY_SIZE(a_arg),            \
        IMPORT_IMPL_ARG_DECL_,                \
        a_arg)                                \
    /*--*/

#define IMPORT_IMPL_EMPTY_1_(x)     /*nothing*/

#define IMPORT_IMPL_SIGNATURE_(name,arg_t,arg_n)    \
    name(                                            \
        BOOST_PP_IF(arg_n,                            \
            IMPORT_IMPL_ARGLIST_DECL_,                \
            IMPORT_IMPL_EMPTY_1_                    \
        )((arg_n,arg_t))                            \
    )                                                \
    /*--*/

#define IMPORT_IMPL_ARGLIST_(arg_n)        \
    BOOST_PP_COMMA_IF(arg_n)            \
    BOOST_PP_ENUM_PARAMS( arg_n, arg)    \
    /*--*/

#define IMPORT_METHOD(ret_t,name,arg_t,arg_n,exp_name)    \
    ret_t IMPORT_IMPL_SIGNATURE_(name,arg_t,arg_n)        \
    {                                                    \
        static import::Import imp_(exp_name);            \
        return imp_(import::ret_tag<ret_t>(),this        \
            IMPORT_IMPL_ARGLIST_(arg_n)    );                \
    }                                                    \
    /*--*/

#define IMPORT_CONSTRUCTOR(clsname,arg_t,arg_n,exp_name,vft_name)    \
    IMPORT_IMPL_SIGNATURE_(clsname,arg_t,arg_n)                        \
    {                                                                \
        import::Dll::import(vftable,vft_name);                        \
        static import::Import imp_(exp_name);                        \
        imp_(import::ret_tag<>(),this                                \
            IMPORT_IMPL_ARGLIST_(arg_n)    );                            \
    }                                                                \
    /*--*/

#define IMPORT_DESTRUCTOR(clsname,exp_name)        \
    ~clsname()                                    \
    {                                            \
        static import::Import imp_(exp_name);    \
        imp_(import::ret_tag<>(),this);            \
    }                                            \
    /*--*/

...

Код

// foo.h

#ifndef Foo_h__
#define Foo_h__

#include "Import.h"

class Foo
{
public:
    int* vftable;
    char* str;
public:    
    IMPORT_CONSTRUCTOR( Foo, (),0, "??0Foo@@QAE@XZ", "??1Foo@@UAE@XZ")
    IMPORT_DESTRUCTOR( Foo, "??1Foo@@UAE@XZ")

    IMPORT_METHOD(void,    init,    (char*),1,        "?init@Foo@@UAEXPAD@Z")
    IMPORT_METHOD(int,    sum,    (int,char),2,    "?sum@Foo@@QAEHHD@Z")
    IMPORT_METHOD(void,    test,    (),0,            "?test@Foo@@UAEXXZ")
};

#endif // Foo_h__


оригинальный класс:
Код

class __declspec(dllexport) Foo {
public:
    Foo();

    virtual void init(char* str);
    virtual void test();

    int sum(int a, char b); 

    virtual ~Foo();

private:
    char* str_;
};


Добавлено через 48 секунд
косушки расползлись =\
PM MAIL ICQ   Вверх
mes
Дата 18.7.2009, 14:09 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


любитель
****


Профиль
Группа: Участник Клуба
Сообщений: 7954
Регистрация: 14.1.2006

Репутация: 1
Всего: 250



Цитата(GoldFinch @  17.7.2009,  16:17 Найти цитируемый пост)

(нужна для приведения указателей на члены классов, т.к. они не приводятся приведеним типов в С-стиле) 

я так понял, что это проблема возникает при присвоении результата импорта. так ?
импортом я никогда не занимался , но мне полагаю, что результат этой функции можно рассматривать, как указатель на обычную функцию.
Тогда не возникнет проблем, в случае разных компиляторов (this как первый параметр или последний.)

Вобщем я так вижу
Код

class Foo 
{
 public: 
      void f (int m)  { static Imp<void (*)(Foo*, int )> imp; imp(this, m); }
}

Сейчас времени больше нет, приду если что не понятно поподробней опишу.



--------------------
PM MAIL WWW   Вверх
GoldFinch
Дата 18.7.2009, 19:07 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата



****


Профиль
Группа: Завсегдатай
Сообщений: 2141
Регистрация: 30.11.2008

Репутация: нет
Всего: 26



mes, там __thiscall, this передается в ecx
PM MAIL ICQ   Вверх
mes
Дата 18.7.2009, 20:05 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


любитель
****


Профиль
Группа: Участник Клуба
Сообщений: 7954
Регистрация: 14.1.2006

Репутация: 1
Всего: 250



Цитата(GoldFinch @  18.7.2009,  18:07 Найти цитируемый пост)
там __thiscall, this передается в ecx 

теперь тогда понятно в чем загвоздка. Имхо импортировать такую функцию как метод не красиво,хотя бы потому что работать будет работать только если Ваш код и длл откомпилированы однотипным компилятором.
Как решение предполагаю, сделать адаптер, который при вызове импортируемой функции будет создавать для нее нужный контекст. Без низкоуровневого кода здесь не обойдется (тут я умываю руки), зато все зависимости останутся в этой обертке.
 smile 





--------------------
PM MAIL WWW   Вверх
GoldFinch
Дата 18.7.2009, 20:21 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата



****


Профиль
Группа: Завсегдатай
Сообщений: 2141
Регистрация: 30.11.2008

Репутация: нет
Всего: 26



mes, так и есть, нужная мне длл, и мой код компилятся одним компилятором
PM MAIL ICQ   Вверх
mes
Дата 18.7.2009, 20:50 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


любитель
****


Профиль
Группа: Участник Клуба
Сообщений: 7954
Регистрация: 14.1.2006

Репутация: 1
Всего: 250



Цитата(GoldFinch @  18.7.2009,  19:21 Найти цитируемый пост)
так и есть, нужная мне длл, и мой код компилятся одним компилятором 

в таком случае самым простым способом будет все таки union... (и программист как гарант типо-преобразований)
мне кажется только сам union было бы удобно спрятать в Вашем адаптере (Imp_) :
Код

template<typename T>
struct ThiscallImport_
{   
      union
      {
            T       mtd;
            void*   proc;             
       } addr;

       operator T () { return addr.mtd; } 

      ThiscallImport_(const char* name) { Dll::import(addr.proc,name); }            
};

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


Это сообщение отредактировал(а) mes - 18.7.2009, 20:52


--------------------
PM MAIL WWW   Вверх
GoldFinch
Дата 6.8.2009, 14:28 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата



****


Профиль
Группа: Завсегдатай
Сообщений: 2141
Регистрация: 30.11.2008

Репутация: нет
Всего: 26



ап.
практически всю информацию о методе можно выдрать из его типа.
в msvc есть интринсик _AddressOfReturnAddress() возвращающий указатель на фрейм стека

поэтому возможен следующий код
Код

class Foo
{
...

    void init(char* some_arg_name)
    {        
        static import::Import2 imp_("?init@Foo@@UAEXPAD@Z");
        return imp_( _AddressOfReturnAddress(), this, &Foo::init );
    }

где
Код

namespace import {
    struct Import2
    {
        void* addr;
        Import2(const char* name) { Dll::import(addr,name); }

        template<typename retT, typename clsT, typename T1>
        retT operator() ( void* frame, clsT* that, retT (clsT::*ptr)(T1) )
        {
#pragma pack(push,4)
            struct StackFrame
            {
                char* ret;
                T1 a1;
            } *f = (StackFrame*)frame;
#pragma pack(pop)
            return (that->*union_cast<retT(clsT::*)(T1)>(addr))(f->a1);
        }

    };
} // namespace import


Добавлено через 9 минут и 56 секунд
с макросами это будет
Код

#define IMPORT_METHOD_2(retT,name,args,exp_name)                \
    retT name args                                                \
    {                                                            \
        static import::Import2 imp_(exp_name);                    \
        return imp_( _AddressOfReturnAddress(), this, &name );    \
    }

// void Foo::init(char*);
IMPORT_METHOD_2( void, Foo::init, (char* some_arg_name), "?init@Foo@@UAEXPAD@Z" )


вместо 
Код

IMPORT_METHOD(void,    init,    (char*),1,        "?init@Foo@@UAEXPAD@Z")

и никакого BOOST_PP

Это сообщение отредактировал(а) GoldFinch - 6.8.2009, 14:30
PM MAIL ICQ   Вверх
GoldFinch
Дата 7.8.2009, 14:45 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата



****


Профиль
Группа: Завсегдатай
Сообщений: 2141
Регистрация: 30.11.2008

Репутация: нет
Всего: 26



а вот адрес конструктора получить нельзя =\

Добавлено @ 14:49
другое дело, что конструктор можно объявить как обычный метод, и вызывать его явно.

а с деструктором проблем нет, т.к. его сигнатура всегда известна

Это сообщение отредактировал(а) GoldFinch - 7.8.2009, 14:52
PM MAIL ICQ   Вверх
Ответ в темуСоздание новой темы Создание опроса
0 Пользователей читают эту тему (0 Гостей и 0 Скрытых Пользователей)
0 Пользователей:
« Предыдущая тема | Visual C++/MFC/WTL | Следующая тема »


 




[ Время генерации скрипта: 0.0676 ]   [ Использовано запросов: 22 ]   [ GZIP включён ]


Реклама на сайте     Информационное спонсорство

 
По вопросам размещения рекламы пишите на vladimir(sobaka)vingrad.ru
Отказ от ответственности     Powered by Invision Power Board(R) 1.3 © 2003  IPS, Inc.