Вызов callback-функции из динамической Dll
От: JekSoft  
Дата: 08.09.08 09:11
Оценка:
Здравствуйте!

Я пишу Dll-плагин, который динамически подгружает MFC-библиотеку (dll). Необходимо из MFC-библиотеки вызывать функцию главной dll-ки. Через экспортируемую функцию MFC-библиотеки я передаю ей адрес необходимой функции, и пытаюсь вызвать эту функцию по нажатию кнопки на форме MFC. Выбрасывается исключение (обращение по указанному адресу недопустимо), в результате программа закрывается. Есть ли какие то ограничения по передаче адресов функций? Или что то другое не так?

Вот участки кода:
— основная dll-ка:

typedef void (PASCAL* JekVOID_INT_INT_FUNC)(int, int);

static void LoadWindowLibrary()
{
    lib = LoadLibrary(dllFileName);
    if (lib != NULL)
    {
        InitMainWindow = (JekVOID_VOID_FUNC)GetProcAddress(lib, "InitMainWindow");
        SetCallbacks = (JekVOID_LPVOID_FUNC)GetProcAddress(lib, "SetCallbacks");

        SetCallbacks((JekVOID_INT_INT_FUNC**)MoveTracker);
    }
}

extern "C" void static PASCAL MoveTracker1(int dx, int dy)
{
    MessageBox(NULL, "Test", "Test", MB_ICONINFORMATION);
    pMyPlugin->MoveTracker(dx, dy);
}


— MFC-библиотека:


JekVOID_INT_INT_FUNC* MoveTracker; // объявлена в MainForm.h внутри класса формы.

extern "C" void PASCAL EXPORT SetCallbacks(JekVOID_INT_INT_FUNC** moveTracker)
{
    AFX_MANAGE_STATE(AfxGetStaticModuleState())    

    MessageBox(NULL, "MoveTracker", "Start", MB_ICONERROR);

    form.MoveTracker = (JekVOID_INT_INT_FUNC*)(moveTracker);

    if (form.MoveTracker == NULL)
        MessageBox(NULL, "MoveTracker", "Error", MB_ICONERROR);
    else
        MessageBox(NULL, "MoveTracker", "End", MB_ICONERROR);
}

void CMainForm::OnBnClickedButton2()
{
    AFX_MANAGE_STATE(AfxGetStaticModuleState())
    
    (*MoveTracker)(0, 10000);
}


В дебаге проверял, в функцию SetCallbacks заходит, и адрес вроде как верный у функции MoveTracker.
Заранее благодарю за помощь.
Re: Вызов callback-функции из динамической Dll
От: VoidEx  
Дата: 08.09.08 09:23
Оценка:
Здравствуйте, JekSoft, Вы писали:

JS>Здравствуйте!


Здравствуй!

JekVOID_INT_INT_FUNC уже означает "указатель на функцию..."
Ты же зачем-то принимаешь в SetCallbacks тип
JekVOID_INT_INT_FUNC**
(указатель на указатель на указатель на функцию)
А хранишь
JekVOID_INT_INT_FUNC*
(указатель на указатель на функцию)

Тебе нужно исправить код так:

JS>

JS>typedef void (PASCAL* JekVOID_INT_INT_FUNC_PTR)(int, int);

JS>static void LoadWindowLibrary()
JS>{
JS>    lib = LoadLibrary(dllFileName);
JS>    if (lib != NULL)
JS>    {
JS>        InitMainWindow = (JekVOID_VOID_FUNC)GetProcAddress(lib, "InitMainWindow");
JS>        SetCallbacks = (JekVOID_LPVOID_FUNC)GetProcAddress(lib, "SetCallbacks");

JS>        SetCallbacks(&MoveTracker);
JS>    }
JS>}

JS>extern "C" void static PASCAL MoveTracker1(int dx, int dy)
JS>{
JS>    MessageBox(NULL, "Test", "Test", MB_ICONINFORMATION);
JS>    pMyPlugin->MoveTracker(dx, dy);
JS>}
JS>


JS>- MFC-библиотека:


JS>

JS>JekVOID_INT_INT_FUNC_PTR MoveTracker; // объявлена в MainForm.h внутри класса формы.

JS>extern "C" void PASCAL EXPORT SetCallbacks(JekVOID_INT_INT_FUNC_PTR moveTracker)
JS>{
JS>    AFX_MANAGE_STATE(AfxGetStaticModuleState())    

JS>    MessageBox(NULL, "MoveTracker", "Start", MB_ICONERROR);

JS>    form.MoveTracker = moveTracker;

JS>    if (form.MoveTracker == NULL)
JS>        MessageBox(NULL, "MoveTracker", "Error", MB_ICONERROR);
JS>    else
JS>        MessageBox(NULL, "MoveTracker", "End", MB_ICONERROR);
JS>}

JS>void CMainForm::OnBnClickedButton2()
JS>{
JS>    AFX_MANAGE_STATE(AfxGetStaticModuleState())
    
JS>    (*MoveTracker)(0, 10000);
JS>    // MoveTracker(0, 10000);
JS>    // Можно и так, и так.
JS>}
JS>
Re[2]: Вызов callback-функции из динамической Dll
От: JekSoft  
Дата: 08.09.08 09:37
Оценка:
Здравствуйте, VoidEx, сделал так как вы сказали... та же ошибка:
---------------------------
grym.exe — Ошибка приложения
---------------------------
Инструкция по адресу "0x6aec8b55" обратилась к памяти по адресу "0x6aec8b55". Память не может быть "read".
Re[3]: Вызов callback-функции из динамической Dll
От: VoidEx  
Дата: 08.09.08 09:54
Оценка:
Здравствуйте, JekSoft, Вы писали:

JS>Здравствуйте, VoidEx, сделал так как вы сказали... та же ошибка:

JS>---------------------------
JS>grym.exe — Ошибка приложения
JS>---------------------------
JS>Инструкция по адресу "0x6aec8b55" обратилась к памяти по адресу "0x6aec8b55". Память не может быть "read".

Ну кроме этой опечатки ничего не вижу, свежий взгляд нажуен кого-нибудь ещё
SetCallbacks(&MoveTracker1);
Re[4]: Вызов callback-функции из динамической Dll
От: JekSoft  
Дата: 08.09.08 09:59
Оценка:
Здравствуйте, VoidEx, Вы писали:

VE>Ну кроме этой опечатки ничего не вижу, свежий взгляд нажуен кого-нибудь ещё

VE>
VE>SetCallbacks(&MoveTracker1);
VE>


А может проблема заключаться в том, что в MFC какой нибудь свой менеджер памяти, и он теряет ссылку на функцию? Т.к. ссылка хранится внутри класса окна?
Может быть, прислать архив с проектом, чтобы код можно было посмотреть нормально?
Re[5]: Вызов callback-функции из динамической Dll
От: VoidEx  
Дата: 08.09.08 10:38
Оценка:
Здравствуйте, JekSoft, Вы писали:

JS>А может проблема заключаться в том, что в MFC какой нибудь свой менеджер памяти, и он теряет ссылку на функцию? Т.к. ссылка хранится внутри класса окна?

JS>Может быть, прислать архив с проектом, чтобы код можно было посмотреть нормально?

Архив с проектом можно, но только если вечером, так как сейчас на работе.
Re: Вызов callback-функции из динамической Dll
От: Кодт Россия  
Дата: 08.09.08 11:28
Оценка:
Здравствуйте, JekSoft, Вы писали:

Прекращаем заниматься reinterpret_cast'ами как бог на душу положит.

JS>

JS>typedef void (PASCAL* JekVOID_INT_INT_FUNC)(int, int);

// назовём-ка по-человечески!!! то есть, осмысленно!

typedef void (PASCAL *PFN_TrackerCallbackFunction)(int,int);

typedef void (PASCAL *PFN_SetCallback)(PFN_TrackerCallbackFunction);
// функция SetCallback принимает не LPVOID, который неизвестно как кастить,
// а именно указатель на колбэк

typedef void (PASCAL *PFN_InitMainWindow)();


JS>static void LoadWindowLibrary()
JS>{
JS>    lib = LoadLibrary(dllFileName);
JS>    if (lib != NULL)
JS>    {
JS>        InitMainWindow = (PFN_InitMainWindow)GetProcAddress(lib, "InitMainWindow");
JS>        SetCallbacks = (PFN_SetCallback)GetProcAddress(lib, "SetCallbacks");

JS>        SetCallbacks(MoveTracker1); // безо всякого кастинга!
JS>    }
JS>}

JS>extern "C" void PASCAL MoveTracker1(int dx, int dy) // здесь либо extern лишнее, либо static; определись!
JS>{
JS>    MessageBox(NULL, "Test", "Test", MB_ICONINFORMATION);
JS>    pMyPlugin->MoveTracker(dx, dy);
JS>}
JS>


JS>- MFC-библиотека:


JS>

JS>PFN_TrackerCallbackFunction* MoveTracker; // объявлена в MainForm.h внутри класса формы.

JS>extern "C" void PASCAL EXPORT SetCallbacks(PFN_TrackerCallbackFunction moveTracker)
JS>{
JS>    AFX_MANAGE_STATE(AfxGetStaticModuleState())    

JS>    MessageBox(NULL, "MoveTracker", "Start", MB_ICONERROR);

JS>    form.MoveTracker = moveTracker;

JS>    if (form.MoveTracker == NULL)
JS>        MessageBox(NULL, "MoveTracker", "Error", MB_ICONERROR);
JS>    else
JS>        MessageBox(NULL, "MoveTracker", "End", MB_ICONERROR);
JS>}

JS>void CMainForm::OnBnClickedButton2()
JS>{
JS>    AFX_MANAGE_STATE(AfxGetStaticModuleState())
    
JS>    MoveTracker(0, 10000); // разыменовывать указатели на функции не нужно.
JS>}
JS>
... << RSDN@Home 1.2.0 alpha 4 rev. 1111>>
Перекуём баги на фичи!
Re: Вызов callback-функции из динамической Dll
От: JekSoft  
Дата: 08.09.08 14:11
Оценка:
Огромное спасибо всем, кто ответил! Разобрался с этими ошибками, видимо и правда перемудрил с указателями
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.