Поиск:

Ответ в темуСоздание новой темы Создание опроса
> Один код работет в Builder, но не работает в Qt, Один код работет в Builder, но не работа 
:(
    Опции темы
nvrrus
Дата 4.4.2011, 11:42 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



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

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



Здравствуйте, уважаемые форумчане! Помогите, пожалуйста разобраться с одной проблемой

Проблема использования билдеровской библиотеки в Qt

В обоих случаях работаю с функциями библиотеки собранной в Builder.
Получаю интерфейс I_archSource.
Вызываю последовательно три метода, GetListOfQueries, size, Get. Каждый при отработке выводит сообщение с названием метода.

Builder:

Код

            I_archSource *m_Src;

            const GUID xxx = {0xa167cb35, 0x2572, 0x453d, 0x876a, 0x1b4a24f7f40e};

            //CreateInstance - функция библиотеки собранной в Builder (получаем объект с интерфейсом I_archSource для работы с библиотекой)
            CreateInstance(xxx, (void**)&m_Src);
            
            I_QuerriesList* Queries;

            m_Src->GetListOfQueries((void*)getPstk(),  (void*)&getConnect(), sizeof(CONNECTKLIENT), &Queries);

            unsigned size = Queries->size();

            I_archQuery* Q = Queries->Get(0);




Все четко отрабатывает. В итоге три сообщения - GetListOfQueries, size, Get
Qt:
Код

    I_archSource *m_Src;

    GUID xxx = {0xa167cb35, 0x2572, 0x453d, 0x876a, 0x1b4a24f7f40e};

    //Acreate_instance - функция той же библиотеки выгруженная из нее динамически (получаем объект с интерфейсом I_archSource //для работы с библиотекой)
    Acreate_instance(xxx, (void**)&m_Src);

    I_QuerriesList* Queries;

    m_Src->GetListOfQueries(NULL, NULL, 0, &Queries);

    unsigned size = Queries->size();

    I_archQuery* Q = Queries->Get(0);



Валится на последней строчке  I_archQuery* Q = Queries->Get(0);

При этом если пройти size() и встать на последнюю строчку получаю два сообщения: GetListOfQueries, Get (вместо GetListOfQueries, size)

Заранее спасибо! Буду очень признателен, если что-то подскажете.
PM MAIL   Вверх
borisbn
Дата 4.4.2011, 12:46 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


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

Репутация: 18
Всего: 135



покажи интерфейс I_archSource. Лучше ВЕСЬ h-ник.


--------------------
Женщины отличаются от программистов тем, что у них чары состоят из стрингов
PM MAIL Jabber   Вверх
nvrrus
Дата 4.4.2011, 12:55 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



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

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



Нашли ошибку. Кажется она в Билдере.

Это интерфейс нашей библиотеки собранной в билдере:

Код:

Код

class I_QuerriesList : public C_UnknownStub
{
public:
    virtual void clear() = 0;
    virtual void push_back(I_archQuery* Q) = 0;
    virtual unsigned size() = 0;
    virtual I_archQuery* Get(unsigned i) = 0;
};

class C_UnknownStub : public IUnknown
{
private:
    volatile long m_cRef;
public:
    C_UnknownStub();
    virtual~C_UnknownStub();

    virtual HRESULT __stdcall QueryInterface(REFIID riid, void** ppvObject);
    virtual ULONG __stdcall AddRef();
    virtual ULONG __stdcall Release();
};





Билдер не заносит виртуальный деструктор в таблицу виртуальных функций. А Qt заносит (что правильно).
Поэтому происходит сдвиг при вызове. Вместо  clear() вызывается push_back, вместо push_back, size(). И т.д.

Убрали виртуальный деструктор, все заработало...

Но так же нельзя, без виртуального деструктора... Подскажите, пожалуйста, может кто сталкивался с этой проблемой.
PM MAIL   Вверх
borisbn
Дата 4.4.2011, 13:06 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


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

Репутация: 18
Всего: 135



Цитата(nvrrus @  4.4.2011,  12:55 Найти цитируемый пост)
Билдер не заносит виртуальный деструктор в таблицу виртуальных функций. А Qt заносит (что правильно).

Qt - это набор классов. Какой у тебя компилятор ?
(будем считать, что MSVC).

Тогда, возможно, проблема не в этом. Builder и студия по-разному выравнивают указатель на виртуальную таблицу, если в опциях проекта указано выравнивание на 8 (на 4 - одинакого).

Здесь ещё пару моментов, от которых можно ожидать подвоха:
1. Интерфейс нужно в явном виде (не полагаясь на настройки проекта) выровнять на 4
2. Нужно явно задать тип вызова функций
3. В явном виде добавить виртуальный деструктор

Код

#pragma pack( push, 4 )

class I_QuerriesList : public C_UnknownStub
{
public:
    virtual ~I_QuerriesList() {}
    virtual void __stdcall clear() = 0;
    virtual void __stdcall push_back(I_archQuery* Q) = 0;
    virtual unsigned __stdcall size() = 0;
    virtual I_archQuery* __stdcall Get(unsigned i) = 0;
};

#pragma pack( pop )


у меня в таком вот виде работают десятки dll-ек, написанные как в bcb, так и в студии, и используемые и там и там.


--------------------
Женщины отличаются от программистов тем, что у них чары состоят из стрингов
PM MAIL Jabber   Вверх
xvr
Дата 4.4.2011, 13:19 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Комодератор
Сообщений: 7046
Регистрация: 28.8.2007
Где: Дублин, Ирландия

Репутация: 48
Всего: 223



Виртуальные деструкторы COM объектов не попадают в их Интерфейсы. Ваш I_QuerriesList не является валидным COM интерфейсом (хотя и является валидным С++ классом)
Интерфейсы должны выглядеть так:
Код

class IQuerriesList : public IUnknownStub
{
public:
    virtual void clear() = 0;
    virtual void push_back(I_archQuery* Q) = 0;
    virtual unsigned size() = 0;
    virtual I_archQuery* Get(unsigned i) = 0;
};
class IUnknownStub : public IUnknown
{
public:
    virtual HRESULT __stdcall QueryInterface(REFIID riid, void** ppvObject);
    virtual ULONG __stdcall AddRef();
    virtual ULONG __stdcall Release();
};
Или скорее так:
Код

class IQuerriesList : public IUnknown
{
public:
    virtual void clear() = 0;
    virtual void push_back(I_archQuery* Q) = 0;
    virtual unsigned size() = 0;
    virtual I_archQuery* Get(unsigned i) = 0;
};

Унаследуйте ваш I_QuerriesList от IQuerriesList (и не забудьте преобразовать тип к IQuerriesList* когда будете его возвращать)

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


Новичок



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

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



Цитата(borisbn @  4.4.2011,  13:06 Найти цитируемый пост)
1. Интерфейс нужно в явном виде (не полагаясь на настройки проекта) выровнять на 4
2. Нужно явно задать тип вызова функций
3. В явном виде добавить виртуальный деструктор



Что значит явно задать тип вызова функций?
PM MAIL   Вверх
borisbn
Дата 4.4.2011, 14:26 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


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

Репутация: 18
Всего: 135



__stdcall или __cdecl (в коде, который я привёл - __stdcall)
Зачем это нужно ?
Представь, что в настройках проекта в билдере установлен тип вызова __stdcall, а в студии - __cdecl.
Если в коде явно не указан тип вызова, то студия будет вызывать ф-цию, например, clear() по сишному, а билдер будет отрабатывать вызов по паскалевски.


--------------------
Женщины отличаются от программистов тем, что у них чары состоят из стрингов
PM MAIL Jabber   Вверх
nvrrus
Дата 4.4.2011, 17:49 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



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

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



Сделал все как посоветовали.  И теперь вообще ничего не понимаю.

Для тестирования создал интерфейс (без родителей) с одним методом Get5().
Реализовал его и еще 4 метода. Каждый пишет на экран соответствующую цифру - 1, 2, 3, 4, 5.


Builder библиотека:

Код

//Интерфейс
#pragma pack(push,4)
class I_archSource2
{
public:
    virtual __stdcall ~I_archSource2() {}
    virtual long __stdcall Get5() = 0;
};
#pragma pack(pop)

//Реализация
#pragma pack(push,4)
class C_Source: public I_archSource2
{
public:
    virtual __stdcall ~ C_Source() {}
    virtual long __stdcall Get1(){ MessageBox(NULL, "1", "sdf",MB_OK); return 1; }
    virtual long __stdcall Get2(){ MessageBox(NULL, "2", "sdf",MB_OK); return 2; }
    virtual long __stdcall Get3(){ MessageBox(NULL, "3", "sdf",MB_OK); return 3; }
    virtual long __stdcall Get4(){ MessageBox(NULL, "4", "sdf",MB_OK); return 4; }
    virtual long __stdcall Get5(){ MessageBox(NULL, "5", "sdf",MB_OK); return 5; }
};
#pragma pack(pop)




Qt использование:

Код

    //получаю интерфейс
    Acreate_instance(xxx, (void**)&m_Src);
    //вызываю метод, который должен вывести на экран "5"
    res = m_Src->Get5();

    //на экран выводится "1", т.е. вызов Get1()




Если оставить в реализации только одну функцию Get5(), валится с "Segmentation fault"

В чем проблема? Подскажите, пожалуйста.
PM MAIL   Вверх
borisbn
Дата 4.4.2011, 19:16 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


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

Репутация: 18
Всего: 135



Хммм. Странно. Должно работать. 

1. У деструктора не может быть никакого типа вызова (билдер это ещё кушает, а студия не должна). Но это не имеет отношения к делу. Так, ремарка
2. Покажи ф-цию Acreate_instance, а лучше весь тестовый проект

Ты так и не сказал, какой у тебя компилятор. Qt - не компилятор, а набор h-ников, lib-ин и dll

Это сообщение отредактировал(а) borisbn - 4.4.2011, 20:49


--------------------
Женщины отличаются от программистов тем, что у них чары состоят из стрингов
PM MAIL Jabber   Вверх
nvrrus
Дата 5.4.2011, 10:46 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



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

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



Компилятор mingw.

Вот функция CreateInstance, библиотеки Builder:
Код

extern "C" __declspec(dllexport) int WINAPI CreateInstance(const GUID& archSourceI, void** pOuter)
{             
    if (archSourceI == IID_DAServerSource)
    {
        C_Source *xxx = new C_Source();
        *pOuter = static_cast<I_archSource2*>(xxx);
    }
}


Так я ее выгружаю из библиотеки в Qt:

Код


     typedef int __stdcall (*Tcreate_instance)(const GUID& archSourceI, void** pOuter);

     if (hArx.isLibrary("C:\\Up_Archive\\arch_db_lib\\trunk\\dll\\ArxDll.dll"))
    {
        hArx.setFileName("C:\\Up_Archive\\arch_db_lib\\trunk\\dll\\ArxDll.dll");
        if (!hArx.load())
        {
            throw "Couldn't load ARX.DLL library";
        }
    }

    Acreate_instance = (Tcreate_instance) hArx.resolve("CreateInstance");
    if (!Acreate_instance)
    {
        throw "Couldn't find CreateInstance function";
    }





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


Эксперт
****


Профиль
Группа: Комодератор
Сообщений: 7046
Регистрация: 28.8.2007
Где: Дублин, Ирландия

Репутация: 48
Всего: 223



Кстати, деструкторы между mingw/Builder могут не работать. У разных компиляторов могут быть разные взгляды на способы реализации конструкторов и деструкторов  smile 

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


Эксперт
****


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

Репутация: 18
Всего: 135



действительно, странно.
сделал всё как у тебя, за исключением того, что у меня нет minGW, поэтому сделал в студии. У меня "выплёвывается" 5. см. аттач 

Присоединённый файл ( Кол-во скачиваний: 6 )
Присоединённый файл  bcb_dll.zip 33,89 Kb


--------------------
Женщины отличаются от программистов тем, что у них чары состоят из стрингов
PM MAIL Jabber   Вверх
nvrrus
Дата 5.4.2011, 12:38 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



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

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



Спасибо, огромное, за участие. 

Я тоже сделал пустой проект в Qt. Беру интерфейс из вашей библиотеки.

Get5() пишет "1".



Цитата

 Кстати, деструкторы между mingw/Builder могут не работать. У разных компиляторов могут быть разные взгляды на способы реализации конструкторов и деструкторов   


Возможно в этом проблема. Можно ли что-то докрутить, чтобы деструкторы Builder нормально виделись mingw?

PM MAIL   Вверх
borisbn
Дата 5.4.2011, 12:42 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


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

Репутация: 18
Всего: 135



Цитата(nvrrus @  5.4.2011,  12:38 Найти цитируемый пост)
Можно ли что-то докрутить, чтобы деструкторы Builder нормально виделись mingw?

можно. Выкинуть деструктор. Добавить виртуальную ф-цию destroy, в реализации которой вызывать
Код

void __sdtcall C_Source::destroy() {
    delete this;
}



--------------------
Женщины отличаются от программистов тем, что у них чары состоят из стрингов
PM MAIL Jabber   Вверх
nvrrus
Дата 5.4.2011, 13:31 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



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

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



 Да, спасибо, это действительно было бы выходом.

Но при отсутствии деструктора, все равно возникает та же проблема.
PM MAIL   Вверх
Ответ в темуСоздание новой темы Создание опроса
Правила форума "С++ Builder"
Rrader

Запрещается!

1. Публиковать ссылки на вскрытые компоненты

2. Обсуждать взлом компонентов и делиться вскрытыми компонентами

  • Литературу по С++ Builder обсуждаем здесь
  • Действия модераторов можно обсудить здесь
  • С просьбами о написании курсовой, реферата и т.п. обращаться сюда
  • Настоятельно рекомендуем заглянуть в DRKB (Delphi Russian Knowledge Base) - крупнейший в рунете сборник материалов по Дельфи


Если Вам понравилась атмосфера форума, заходите к нам чаще! С уважением, Rrader.

 
0 Пользователей читают эту тему (0 Гостей и 0 Скрытых Пользователей)
0 Пользователей:
« Предыдущая тема | C++ Builder | Следующая тема »


 




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


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

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