Загрузка DLL в C ++ - PullRequest
       5

Загрузка DLL в C ++

0 голосов
/ 31 мая 2018

Я пытаюсь загрузить DLL LoadLibrary способом.Вот файл .h моей DLL:

#ifdef CALLBACKTESTDLL_EXPORTS
#define CALLBACKTESTDLL_API __declspec(dllexport)    
#else
#define CALLBACKTESTDLL_API __declspec(dllimport)
#endif

typedef int(CALLBACK *p)(char*);  

extern "C" __declspec(dllexport) int __stdcall StrToInt(char* InputString);     

extern "C" __declspec(dllexport) char* __stdcall NumCompare(p FuncP, char* InputString, int b); 

В нем есть две функции.StrToInt преобразовать ввод char* в int.Другой - NumCompare, где вызывается StrToInt, и его возвращаемое значение сравнивается с другим входным значением int, а затем NumCompare возвращает результат сравнения.Эти две функции экспортируются в DLL с именем callbacktestDLL.dll.

Теперь я хочу назвать эту DLL LoadLibrary способом.(Способ pragma comment(lib,"callbacktestDLL") уже успешно протестирован, поэтому я хочу протестировать другой способ).

Для вызова функций DLL это то, что я делаю в CallDLL.cpp:

#include "stdafx.h"
#include <iostream>
#include <windows.h>

typedef int (*P_to_Func1)(char*);       //pointer for StrToInt

typedef char* (*P_to_Func2)(P_to_Func1, char*, int);        //pointer for NumCompare


int main()
{
    //load DLL:
    HINSTANCE LDLL = LoadLibrary("callbacktestDLL.dll");

    if (LDLL == NULL)
    {
        printf("DLL loading failed");
        FreeLibrary(LDLL);
    }
    else
    {
        P_to_Func1 p1 = (P_to_Func1)GetProcAddress(LDLL, "_StrToInt@4");

        if (p1 = NULL)
        {
            printf("StrToInt loading failed");
        };

        P_to_Func2 p2 = (P_to_Func2)GetProcAddress(LDLL, "_NumCompare@12");
        if (p2 = NULL)
        {
            printf("NumCompare loading failed");
        };

        //Call StrToInt:
        std::cout << p1("1234") << std::endl;
        //call NumCompare:
        p2(p1, "1234", 20);
        //release:
        FreeLibrary(LDLL);
    };
    return 0;
}

Это имена функций, показанные в зависимости от: enter image description here

Когда я генерирую проект CallDLL, ошибка не возникает и генерируется успешно.Однако, когда я запускаю проект, выскакивает диалоговое окно с сообщением CallDLL.exe has stopped, а в окне cmd - «нажмите любую клавишу для продолжения».Может ли кто-нибудь быть так любезен, чтобы помочь мне понять и решить эту проблему?

1 Ответ

0 голосов
/ 31 мая 2018

Соглашения о вызовах довольно важны, и поскольку GetProcAddress работает с таблицей экспорта, информация о типах отсутствует, и компилятор не может отследить вашу ошибку.

Разница между соглашениями о вызовах по умолчанию в Visual C ++(__cdecl) и __stdcall в порядке передачи аргументов и кто отвечает за восстановление указателя стека.__cdecl помещает последний аргумент в стек первым, и вызывающая сторона удаляет аргументы из стека.Эти выборы заставляют «варагг» работать.При __stdcall первый аргумент передается первым, а вызываемая функция удаляет аргументы при возврате.Этот выбор немного более эффективен.

Когда у вас есть несоответствие, двоичные данные вставляются в неправильные аргументы, а затем указатель стека корректируется неправильно (в вашем случае он корректируется дважды, но не корректируетсявообще бы тоже было возможно).Эта двойная настройка указателя стека приводит к сбою вашей программы при возврате из вызова на p1("1234").Если бы вы сначала вызвали p2(p1, "1234", 20), неверное истолкование 20 как указателя на функцию привело бы к краху вашей программы ... и если бы оно чудом выжило, то (решив не вызывать функцию обратного вызова) несовпадение стека при возврате p2вызвать аварию.

Обратите особое внимание на соглашения о вызовах, и вы можете избежать этой боли.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...