使用GetProcAddress调用外部函数会使应用程序崩溃

时间:2014-05-18 19:49:09

标签: c++ winapi

我一直在尝试使用GetProcAddress函数调用外部函数,但每次调用该函数时都会崩溃控制台,我一直在寻找但是在每个帖子中我得到相同的最终解决方案但是当我在我的DLL中尝试它时崩溃了应用程序。

以下是代码:

#include <Windows.h>
#include <vector>
#include "SDK\plugin.h"

typedef void (*logprintf_t)(char* format, ...);
logprintf_t logprintf;
// static void* m_AMXExports[44];

typedef bool (PLUGIN_CALL *ServerPluginLoad_t)(void **data);
typedef void (PLUGIN_CALL *ServerPluginUnload_t)();
typedef unsigned int (PLUGIN_CALL *ServerPluginSupports_t)();
typedef void (PLUGIN_CALL *ServerPluginProcessTick_t)();

typedef int (PLUGIN_CALL *ServerPluginAmxLoad_t)(AMX *amx);
typedef int (PLUGIN_CALL *ServerPluginAmxUnload_t)(AMX *amx);

struct Plugins
{
    void* AppData[256];
    SUPPORTS_FLAGS FlagSupport;
    HMODULE Module;
    ServerPluginLoad_t      LOAD;
    ServerPluginUnload_t    UNLOAD;
    ServerPluginSupports_t  SUPPORTS;
    ServerPluginProcessTick_t   PROCESSTICK;

    // AMX Plugin Interface
    ServerPluginAmxLoad_t   AMXLOAD;
    ServerPluginAmxUnload_t AMXUNLOAD;
};
Plugins* ServerPlugins;

void **ppPluginData ;

extern void *pAMXFunctions;

//native LoadLibrary(libraryname[]);
static cell AMX_NATIVE_CALL my_LoadLibrary(AMX* amx, cell* params)
{
    bool validfunc = false;
    char *path;
    amx_StrParam(amx, params[1], path);
    logprintf("Loading plugin %s", path);
    ServerPlugins = new Plugins();
    ServerPlugins->Module = LoadLibraryA(path);
    if (ServerPlugins->Module == NULL)
    {
        delete ServerPlugins;
        logprintf("Failed loading plugin %s (Error: %d)", path, GetLastError());
        return 0;
    }
    logprintf("NULL");
    ServerPlugins->LOAD = (ServerPluginLoad_t)GetProcAddress(ServerPlugins->Module, "Load");
    ServerPlugins->UNLOAD = (ServerPluginUnload_t)GetProcAddress(ServerPlugins->Module, "Unload");
    ServerPlugins->SUPPORTS = (ServerPluginSupports_t)GetProcAddress(ServerPlugins->Module, "Supports");
    if (ServerPlugins->LOAD == NULL || ServerPlugins->SUPPORTS == NULL || ServerPlugins->UNLOAD == NULL)
    {
        logprintf(" Plugin doesnt conform to architecture");
        FreeLibrary(ServerPlugins->Module);
        delete ServerPlugins;
        return false;
    }
    logprintf("NULL 1");
    ServerPlugins->FlagSupport = (SUPPORTS_FLAGS)ServerPlugins->SUPPORTS();
    if ((ServerPlugins->FlagSupport & SUPPORTS_VERSION_MASK) > SUPPORTS_VERSION)
    {
        logprintf("Unsupported Version; unloading.");
        FreeLibrary(ServerPlugins->Module);
        delete ServerPlugins;
        return false;
    }
    logprintf("NULL 2");
    if ((ServerPlugins->FlagSupport & SUPPORTS_AMX_NATIVES) > SUPPORTS_VERSION)
    {
        ServerPlugins->AMXLOAD = (ServerPluginAmxLoad_t)GetProcAddress(ServerPlugins->Module, "AmxLoad");
        ServerPlugins->AMXUNLOAD = (ServerPluginAmxUnload_t)GetProcAddress(ServerPlugins->Module, "AmxUnload");
    }
    else
    {
        ServerPlugins->AMXLOAD = NULL;
        ServerPlugins->AMXUNLOAD = NULL;
        logprintf("Any Abstract Machine has been loaded");
    }
    logprintf("NULL 3");
    if ((ServerPlugins->FlagSupport & SUPPORTS_PROCESS_TICK) != 0)
    {
        ServerPlugins->PROCESSTICK = (ServerPluginProcessTick_t)GetProcAddress(ServerPlugins->Module, "ProcessTick");
    }
    else
    {
        ServerPlugins->PROCESSTICK = NULL;
    }
    logprintf("NULL 4"); //debugging
    ServerPlugins->AppData[PLUGIN_DATA_AMX_EXPORTS] = pAMXFunctions;
    ServerPlugins->AppData[PLUGIN_DATA_LOGPRINTF] = &logprintf;
    if (!(ServerPlugins->LOAD)(ServerPlugins->AppData)) //i didnt put it as &ServerPlugins->AppData because it causes an error
    {

        logprintf("Initialized failed loading plugin %s", path);
        FreeLibrary(ServerPlugins->Module);
        logprintf("NULL 5");
        delete ServerPlugins;
        return false;
    }
    logprintf("Plugin %s loaded", path);
    return true;
}
//native UnloadLibrary(libraryname[]);
static cell AMX_NATIVE_CALL my_UnloadLibrary(AMX*amx, cell*params)
{
    char *path;
    amx_StrParam(amx, params[1], path);
    ServerPlugins->Module = GetModuleHandle((LPCTSTR)path);
    if (ServerPlugins->Module != NULL)
    {
        ServerPlugins->UNLOAD = (ServerPluginUnload_t)GetProcAddress(ServerPlugins->Module, "Unload");
        if (ServerPlugins->UNLOAD != NULL)
        {
            ServerPlugins->UNLOAD();
            FreeLibrary(GetModuleHandleA(path));
            logprintf("Library %s has been unloaded correctly", path);
            return 1;
        }
        else
        {
            logprintf("Unloading library %s failed (Error: %d)", GetLastError());
            return 0;
        }
    }
    return 1;
}

PLUGIN_EXPORT bool PLUGIN_CALL Load(void **ppData)
{
    pAMXFunctions = ppData[PLUGIN_DATA_AMX_EXPORTS];
    logprintf = (logprintf_t)ppData[PLUGIN_DATA_LOGPRINTF];
    return 1;
}

PLUGIN_EXPORT void PLUGIN_CALL Unload()
{
}

PLUGIN_EXPORT unsigned int PLUGIN_CALL Supports()
{
    return SUPPORTS_VERSION | SUPPORTS_AMX_NATIVES;
}

AMX_NATIVE_INFO projectNatives[] =
{
    { "LoadLibrary", my_LoadLibrary },
    { "UnloadLibrary", my_UnloadLibrary }
};

PLUGIN_EXPORT int PLUGIN_CALL AmxLoad(AMX *amx)
{
    return amx_Register(amx, projectNatives, -1);
}

PLUGIN_EXPORT int PLUGIN_CALL AmxUnload(AMX *amx)
{
    return AMX_ERR_NONE;
}

1 个答案:

答案 0 :(得分:0)

convertCharArrayToLPCWSTR()中有内存泄漏。您永远不会释放您分配的wchar_t*。不需要convertCharArrayToLPCWSTR()函数本身,您可以简单地将char*路径原样传递给LoadLibraryA()

char *path;
amx_StrParam(amx, params[1], path);
...
ServerPlugins->Module = LoadLibraryA(path);

您没有检查ServerPlugins->UNLOAD是否成功加载了GetProcAddress("Unload")

您对GetProcAddress("Load")ServerPlugins->LOAD使用ServerPlugins->AMXLOADGetProcAddress("Unload")ServerPlugins->UNLOAD使用ServerPlugins->AMXUNLOAD。这对我来说非常可疑。 DLL是否真的对AMX和非AMX入口点使用相同的导出?如果是这样,那么设计非常糟糕,因为ServerPluginLoad_t的签名与ServerPluginAmxLoad_t的签名截然不同,ServerPlugin(Amx)Unload_t的签名也相同。这是一个等待发生的损坏的调用堆栈。让DLL导出单独的AmxLoad()AmxUnload()函数会更安全。

就此而言,SUPPORTS_AMX_NATIVESSUPPORTS_PROCESS_TICK标志是多余的,因为GetProcAddress()会告诉您这些导出是否可用。

至于调用ServerPlugins->LOAD时的崩溃,我没有看到您在将ppData传递给Load()之前使用任何数据初始化PLUGIN_DATA_AMX_EXPORTS。当然不是PLUGIN_DATA_LOGPRINTFppData[PLUGIN_DATA_AMX_EXPORTS] = pAMXFunctions; ppData[PLUGIN_DATA_LOGPRINTF] = &logprintf; if (!(ServerPlugins->LOAD)(ppData)) 广告位,至少是:

Load()

因此,即使对pAMXFunctions本身的调用没有崩溃,DLL也会在以后尝试使用其本地logprintfLoad()指针时崩溃。在void*中分配。

就此而言,为什么要将这样的内容传递为struct数组而不是struct PluginInitData { void* pAMXFunctions; logprintf_t logprintf; ... }; typedef bool (__stdcall *ServerPluginLoad_t)(PluginInitData* data); PluginInitData pInitData; pInitData.pAMXFunctions = pAMXFunctions; pInitData.logprintf = &logprintf; ... if (!(ServerPlugins->LOAD)(&pInitData)) ?那会更安全,例如:

extern "C" bool __stdcall Load(PluginInitData* data)
{
    pAMXFunctions = data->pAMXFunctions;
    logprintf = data->logprintf;
    ...
    return true;
}

my_UnloadLibrary()

更新:您已修复我提到的大部分问题,但现在我发现您的GetModuleHandle()功能实施错误。 不要完全致电GetProcAddress()Module,使用UNLOAD中之前初始化的现有my_LoadLibrary()static cell AMX_NATIVE_CALL my_LoadLibrary(AMX* amx, cell* params) { char *path; amx_StrParam(amx, params[1], path); ... ServerPlugins->Path = path; ... } static cell AMX_NATIVE_CALL my_UnloadLibrary(AMX*amx, cell*params) { if (ServerPlugins) { if (ServerPlugins->UNLOAD != NULL) ServerPlugins->UNLOAD(); if (ServerPlugins->Module != NULL) { FreeLibrary(ServerPlugins->Module); ServerPlugins->Module = NULL; } logprintf("Library %s has been unloaded", ServerPlugins->Path); delete ServerPlugins; ServerPlugins = NULL; } return 1; } 指针。

Load()

如果您仍然遇到{{1}}崩溃的问题,那么您将不得不使用编译器的调试器来查找运行时实际发生的情况。到目前为止显示的代码不应该崩溃,因此要么您具有调用约定不匹配,要么数据对齐不匹配,或内存损坏,或类似的东西。我们无法为您运行调试程序。