Явно комонуемая DLL. Гуру, помогите!!

Модераторы: Hawk, Romeo, Absurd, DeeJayC, WinMain

Ответить
Redcat
Сообщения: 19
Зарегистрирован: 08 дек 2005, 18:48
Откуда: Russia

Народ, у меня следующая проблема. Помогите, кто сможет, оч. надо!

В коде для Win32 API я явно подключаю некоторую DLL, чтобы потом вызывать её функции по адресу (разрешение имени в адрес). В итоге у меня есть указатель на требуемую функцию lpDllFunc. Я вызываю её из метода своего класса, например:

SomeClass::SomeMethod(Arg1 arg1, &Arg2 arg2)
{
long RetVal = (lpDllFunc)(arg1, arg2);

// Затем я присваиваю значения закрытым полям класса _attr1 и
// _attr2

this->_attr1 = 0;
this->_attr2 = 0;
}

Проблема в том, что к моменту возврата из библиотечной функции lpDllFunc, содержимое памяти, где записан указатель на объект, для которого вызван этот метод, т.е this, меняется, и я теряю указатель на объект, и программа падает на строке this->_attr1 = 0.

Т.е, например, если до вызова lpDllFunc:
&this = 0x00aa00bb и this = 0x00db98bc,
то после:
&this = 0x00aa00bb а this=0x00ffcc00.

ДО

0x00aa00bb : 0x00db98bc 00000000 (сюда пишется RetVal)

ПОСЛЕ

0x00aa00bb : 0x00ffcc00 bff012ce (получил RetVal)

Меняется содержимое памяти по адресу &this. Причем эта функция меняет 4 байта по адресу &this и записывает возвращаемое значение в следующие 4 байта памяти.


А если я компоную эту библиотеку неявно, то прямой вызов функции по имени все делает корректно и она записывает возвращаемое значение в те же следущие 4 байта после 4-х байтов с указателем this, а память &this не портит.

ДО

0x00aa00bb : 0x00db98bc 00000000 (сюда пишется RetVal)

ПОСЛЕ

0x00aa00bb : 0x00db98bc bff012ce (получил RetVal)
Аватара пользователя
Romeo
Сообщения: 3126
Зарегистрирован: 02 мар 2004, 17:25
Откуда: Крым, Севастополь
Контактная информация:

95% - использовано неправильное тип (соглашение) вызова. Все функции, загружаемые из DLL динамически, должны быть stdcall.
Entites should not be multiplied beyond necessity @ William Occam
---
Для выделения С++ кода используйте конструкцию [ code=cpp ] Код [ /code ] (без пробелов)
---
Сообщение "Спасибо" малоинформативно. Благодарность правильнее высказать, воспользовавшись кнопкой "Reputation" в виде звёздочки, расположенной в левом нижнем углу рамки сообщения.
Redcat
Сообщения: 19
Зарегистрирован: 08 дек 2005, 18:48
Откуда: Russia

Этот трюк мне действительно необходим. А что значит функция должна быть stdcall? как это сделать?
Аватара пользователя
Romeo
Сообщения: 3126
Зарегистрирован: 02 мар 2004, 17:25
Откуда: Крым, Севастополь
Контактная информация:

Это не "трюк". Это квалификатор, который используется для измениния соглашения о передачи параметров. Выглядит это примерно так:

Код: Выделить всё

void __stdcall SomeFunction(...);
Entites should not be multiplied beyond necessity @ William Occam
---
Для выделения С++ кода используйте конструкцию [ code=cpp ] Код [ /code ] (без пробелов)
---
Сообщение "Спасибо" малоинформативно. Благодарность правильнее высказать, воспользовавшись кнопкой "Reputation" в виде звёздочки, расположенной в левом нижнем углу рамки сообщения.
Redcat
Сообщения: 19
Зарегистрирован: 08 дек 2005, 18:48
Откуда: Russia

Romeo, псасибо большое, проблема была именно в этом. Теперь усё работает!! :D
Eugie
Сообщения: 708
Зарегистрирован: 17 фев 2004, 23:59
Откуда: SPb

95% - использовано неправильное тип (соглашение) вызова. Все функции, загружаемые из DLL динамически, должны быть stdcall.
Не обязательно, соглашение м.б. любое, главное, оно должно быть одинаковым в определении функции в DLL и в типе указателя на функцию при ее явном экспорте в целевом коде. Чаще всего используется __stdcall , это правда.
Ответить