精易论坛

标题: 易语言调用64位dll [打印本页]

作者: zxxiaopi    时间: 2024-10-22 17:12
标题: 易语言调用64位dll
最近要搞这个,所以,弄了个C++实现了下调用64位dll,前提是这个64位dll函数公开啊,不公开的用其他大神的模块或者工具,汇编啥的整不来。
这个设计主要涉及两个组件:32位的 Bridge32.dll 和 64位的 Helper64.exe。让我们逐步分析这个调用过程:
初始化阶段:
当 Bridge32.dll 被加载时(通常是在 DLL_PROCESS_ATTACH),它会启动 Helper64.exe。
Helper64.exe 启动后会创建一个命名管道,等待来自 Bridge32.dll 的连接。
调用过程:
当 32位应用程序调用 Bridge32.dll 中的 CallFunction 时,以下步骤会发生:
a. Bridge32.dll 连接到 Helper64.exe 创建的命名管道。
b. Bridge32.dll 将调用信息(DLL名称、函数名、参数)通过管道发送给 Helper64.exe。
c. Helper64.exe 接收这些信息,然后动态加载指定的 64位 DLL。
d. Helper64.exe 使用 GetProcAddress 获取指定函数的地址。
e. Helper64.exe 调用该函数,并获取返回值。
f. Helper64.exe 将返回值通过管道发送回 Bridge32.dll。
g. Bridge32.dll 接收结果并返回给调用它的 32位应用程序。
通信机制:
使用命名管道进行 32位和 64位进程间的通信。
命名管道允许双向通信,适合请求-响应模型。
4. 动态加载:
Helper64.exe 使用 LoadLibrary 动态加载 64位 DLL。
使用 GetProcAddress 获取函数地址,允许调用未在编译时链接的函数。

[C++] 纯文本查看 复制代码
#include <windows.h>
#include <string>
#include <sstream>
#include <map>

#define PIPE_NAME "\\\\.\\pipe\\UniversalBridge64Pipe"
#define SHUTDOWN_EVENT_NAME "Global\\Helper64ShutdownEvent"

typedef int(__stdcall* GENERICFUNCTION)();

std::map<std::string, HMODULE> loadedDlls;

HMODULE LoadDLL(const std::string& dllName) {
    if (loadedDlls.find(dllName) == loadedDlls.end()) {
        HMODULE hDll = LoadLibraryA(dllName.c_str());
        if (hDll) {
            loadedDlls[dllName] = hDll;
        }
        return hDll;
    }
    return loadedDlls[dllName];
}

std::string CallFunction(const std::string& dllName, const std::string& funcName, const std::string& args) {
    HMODULE hDll = LoadDLL(dllName);
    if (!hDll) {
        return "ERROR: Failed to load DLL";
    }

    FARPROC func = GetProcAddress(hDll, funcName.c_str());
    if (!func) {
        return "ERROR: Failed to find function";
    }

    if (funcName == "GetNetworkAdapterInfo") {
        typedef const char* (__stdcall* GetNetworkAdapterInfoFunc)(int);
        GetNetworkAdapterInfoFunc getNetworkAdapterInfo = reinterpret_cast<GetNetworkAdapterInfoFunc>(func);
        int index = std::stoi(args);
        const char* result = getNetworkAdapterInfo(index);
        return result ? result : "ERROR: Null result";
    }
    else if (funcName == "GetActiveNetworkAdapterInfo") {
        typedef const char* (__stdcall* GetActiveNetworkAdapterInfoFunc)();
        GetActiveNetworkAdapterInfoFunc getActiveNetworkAdapterInfo = reinterpret_cast<GetActiveNetworkAdapterInfoFunc>(func);
        const char* result = getActiveNetworkAdapterInfo();
        return result ? result : "ERROR: Null result";
    }
    else {
        int result = reinterpret_cast<int(*)()>(func)();
        return std::to_string(result);
    }
}

DWORD WINAPI MonitorParentProcess(LPVOID lpParam) {
    const char* parentProcessIdStr = static_cast<const char*>(lpParam);
    DWORD parentProcessId = strtoul(parentProcessIdStr, NULL, 10);

    HANDLE hParentProcess = OpenProcess(SYNCHRONIZE, FALSE, parentProcessId);
    if (hParentProcess == NULL) {
        return 1;
    }

    WaitForSingleObject(hParentProcess, INFINITE);

    CloseHandle(hParentProcess);

    HANDLE hShutdownEvent = OpenEventA(EVENT_MODIFY_STATE, FALSE, SHUTDOWN_EVENT_NAME);
    if (hShutdownEvent != NULL) {
        SetEvent(hShutdownEvent);
        CloseHandle(hShutdownEvent);
    }

    return 0;
}

DWORD WINAPI ClientHandler(LPVOID lpParam) {
    HANDLE hPipe = (HANDLE)lpParam;
    char buffer[1024];
    DWORD bytesRead;

    if (ReadFile(hPipe, buffer, sizeof(buffer), &bytesRead, NULL)) {
        buffer[bytesRead] = '\0';
        std::string input(buffer);
        std::istringstream iss(input);
        std::string dllName, funcName, args;
        std::getline(iss, dllName, '|');
        std::getline(iss, funcName, '|');
        std::getline(iss, args);

        std::string result = CallFunction(dllName, funcName, args);
        DWORD bytesWritten;
        WriteFile(hPipe, result.c_str(), static_cast<DWORD>(result.length()), &bytesWritten, NULL);

        FlushFileBuffers(hPipe);
    }

    CloseHandle(hPipe);
    return 0;
}

int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) {
    if (__argc <= 1) {
        return 1;
    }

    const char* parentProcessIdStr = __argv[1];

    HANDLE hMonitorThread = CreateThread(NULL, 0, MonitorParentProcess, (LPVOID)parentProcessIdStr, 0, NULL);
    if (hMonitorThread == NULL) {
        return 1;
    }

    HANDLE hShutdownEvent = CreateEventA(NULL, TRUE, FALSE, SHUTDOWN_EVENT_NAME);
    if (hShutdownEvent == NULL) {
        return 1;
    }

    while (true) {
        HANDLE hPipe = CreateNamedPipeA(
            PIPE_NAME,
            PIPE_ACCESS_DUPLEX,
            PIPE_TYPE_MESSAGE | PIPE_READMODE_MESSAGE | PIPE_WAIT,
            PIPE_UNLIMITED_INSTANCES,
            1024,
            1024,
            0,
            NULL
        );

        if (hPipe == INVALID_HANDLE_VALUE) {
            Sleep(1000);
            continue;
        }

        HANDLE waitHandles[2] = { hShutdownEvent, hPipe };
        DWORD waitResult = WaitForMultipleObjects(2, waitHandles, FALSE, INFINITE);

        if (waitResult == WAIT_OBJECT_0) {
            CloseHandle(hPipe);
            break;
        }

        if (waitResult == WAIT_OBJECT_0 + 1) {
            BOOL connected = ConnectNamedPipe(hPipe, NULL) ? TRUE : (GetLastError() == ERROR_PIPE_CONNECTED);
            if (connected) {
                HANDLE hThread = CreateThread(NULL, 0, ClientHandler, (LPVOID)hPipe, 0, NULL);
                if (hThread == NULL) {
                    CloseHandle(hPipe);
                }
                else {
                    CloseHandle(hThread);
                }
            }
            else {
                CloseHandle(hPipe);
            }
        }
    }

    CloseHandle(hShutdownEvent);

    WaitForSingleObject(hMonitorThread, INFINITE);
    CloseHandle(hMonitorThread);

    for (auto& dll : loadedDlls) {
        FreeLibrary(dll.second);
    }
    return 0;
}
[C++] 纯文本查看 复制代码
#include <windows.h>
#include <string>
#include <thread>
#include <chrono>

#define PIPE_NAME "\\\\.\\pipe\\UniversalBridge64Pipe"
#define SHUTDOWN_EVENT_NAME "Global\\Helper64ShutdownEvent"

HANDLE g_hHelper = NULL;

void StartHelper() {
    STARTUPINFOA si = { sizeof(si) };
    PROCESS_INFORMATION pi;

    DWORD parentProcessId = GetCurrentProcessId();
    std::string parentProcessIdStr = std::to_string(parentProcessId);

    std::string cmdLine = "Helper64.exe " + parentProcessIdStr;

    if (CreateProcessA(NULL, const_cast<char*>(cmdLine.c_str()), NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi)) {
        CloseHandle(pi.hThread);
        g_hHelper = pi.hProcess;
    }
}

bool EnsureHelperRunning() {
    if (g_hHelper == NULL || WaitForSingleObject(g_hHelper, 0) == WAIT_OBJECT_0) {
        StartHelper();
        std::this_thread::sleep_for(std::chrono::milliseconds(500));
    }
    return g_hHelper != NULL;
}

extern "C" __declspec(dllexport) const char* __stdcall CallFunction(const char* dllName, const char* funcName, const char* params)
{
    static char resultBuffer[1024] = { 0 };

    for (int retry = 0; retry < 3; retry++) {
        if (!EnsureHelperRunning()) {
            strcpy_s(resultBuffer, "ERROR: Helper not running");
            return resultBuffer;
        }

        HANDLE hPipe = CreateFileA(PIPE_NAME, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, NULL);
        if (hPipe == INVALID_HANDLE_VALUE) {
            if (retry == 2) {
                strcpy_s(resultBuffer, "ERROR: Failed to connect to pipe after 3 attempts");
                return resultBuffer;
            }
            Sleep(100);
            continue;
        }

        std::string message = std::string(dllName) + "|" + funcName + "|" + (params ? params : "");

        DWORD bytesWritten;
        if (!WriteFile(hPipe, message.c_str(), static_cast<DWORD>(message.length()), &bytesWritten, NULL) || bytesWritten != message.length()) {
            CloseHandle(hPipe);
            if (retry == 2) {
                strcpy_s(resultBuffer, "ERROR: Failed to write to pipe after 3 attempts");
                return resultBuffer;
            }
            continue;
        }

        DWORD bytesRead;
        if (!ReadFile(hPipe, resultBuffer, sizeof(resultBuffer) - 1, &bytesRead, NULL)) {
            CloseHandle(hPipe);
            if (retry == 2) {
                strcpy_s(resultBuffer, "ERROR: Failed to read from pipe after 3 attempts");
                return resultBuffer;
            }
            continue;
        }

        resultBuffer[bytesRead] = '\0';
        CloseHandle(hPipe);
        return resultBuffer;
    }

    strcpy_s(resultBuffer, "ERROR: Unexpected failure in CallFunction");
    return resultBuffer;
}

BOOL APIENTRY DllMain(HMODULE hModule, DWORD ul_reason_for_call, LPVOID lpReserved)
{
    switch (ul_reason_for_call)
    {
    case DLL_PROCESS_ATTACH:
        EnsureHelperRunning();
        break;
    case DLL_PROCESS_DETACH:
        if (g_hHelper) {
            HANDLE hShutdownEvent = OpenEventA(EVENT_MODIFY_STATE, FALSE, SHUTDOWN_EVENT_NAME);
            if (hShutdownEvent != NULL) {
                SetEvent(hShutdownEvent);
                CloseHandle(hShutdownEvent);
            }
            WaitForSingleObject(g_hHelper, 5000);
            TerminateProcess(g_hHelper, 0);
            CloseHandle(g_hHelper);
        }
        break;
    }
    return TRUE;
}
  
DLL命令名返回值类型公开备 注
CallFunction文本型 同步,返回函数调用的结果字符串。如果发生错误,返回以 "ERROR:" 开头的错误信息。
DLL库文件名:
Bridge32.dll
在DLL库中对应命令名:
CallFunction
参数名类 型传址数组备 注
dllName文本型表示要调用的 64 位 DLL 的名称
funcName文本型表示要调用的函数名
params文本型表示传递给函数的参数,多个参数用 "|" 分隔

Bridge32.rar

7.56 KB, 下载次数: 108, 下载积分: 精币 -2 枚

Helper64.rar

12.86 KB, 下载次数: 110, 下载积分: 精币 -2 枚


作者: bianyuan456    时间: 2024-10-23 20:49
已经顶贴,感谢您对论坛的支持!
作者: 暴力男神阿帅    时间: 2024-10-23 21:25
那如果我这个dll返回值类型是整数型该怎么办
作者: 查过    时间: 2024-10-24 07:07
感谢您对论坛的支持!
作者: 豆豆灰常开心    时间: 2024-10-24 07:12
已经顶贴,感谢您对论坛的支持!
作者: qq1056123185    时间: 2024-10-24 07:34
只能返回文本型?
那就是在dll中把全部的数据类型转换成文本型?
在易语言中用的时候,再把文本型转换回去呗?
作者: 胖子葛格    时间: 2024-10-24 09:45
感谢大神分享~!
作者: gaoqing    时间: 2024-10-24 10:45
谢谢分享
作者: dawnjava    时间: 2024-10-24 14:13
谢谢分享
作者: 轻风影    时间: 2024-10-24 19:59
果然是大神,这样也行!
作者: chis777780    时间: 2024-10-25 08:38
支持开源~!感谢分享
作者: please    时间: 2024-10-25 09:37
感谢分享,支持开源!!!
作者: 89787018a    时间: 2024-10-25 12:46

感谢分享!!!!
作者: 杰西卡技术传媒    时间: 2024-10-25 13:04
        支持开源~!感谢分享
作者: Coly    时间: 2024-10-27 20:55
感谢分享

作者: qx0013    时间: 2024-10-28 16:29
    支持开源~!感谢分享
作者: 光影魔术    时间: 2024-10-29 13:14
感谢分享源码
作者: 胖子葛格    时间: 2024-10-30 08:52
感谢大神分享~!
作者: zjlsqt    时间: 2024-10-30 17:59
轻风影 发表于 2024-10-24 19:59
果然是大神,这样也行!

参数三 为结构类型的  怎么传递啊

作者: 熊不熊    时间: 2024-12-4 07:08
感谢分享,很给力!~
作者: 乱世情殇    时间: 2024-12-16 16:47
7.56 KB, 下载次数: 39, 下载积分: 精币 -2 枚
作者: 乱世情殇    时间: 2024-12-16 16:48
7.56 KB, 下载次数: 39, 下载积分: 精币 -2 枚
作者: 乱世情殇    时间: 2024-12-16 16:48
Helper64.rar
作者: 乱世情殇    时间: 2024-12-16 16:48
Helper64.rar
作者: 温暖的舌骨    时间: 2024-12-17 16:33

作者: huhuhuf    时间: 2025-1-7 15:43
感谢分享,很给力!~
作者: neigui001    时间: 2025-3-2 23:44
很好很强大
作者: 小竺    时间: 2025-3-4 01:21
真的牛逼!!!刚好碰到一个鼠标硬件DLL64位 易语言无法调用!!论坛大神多
作者: 614430887    时间: 2025-3-20 13:53
感谢分享,很给力!~
作者: e688    时间: 2025-3-23 12:00
感谢分享
作者: lxn2wyf    时间: 2025-3-23 13:32
哈哈,搞64位DLL这事儿挺折腾呢。32位桥接确实是个办法,不过汇编那块儿我是真头大啊。慢慢摸索吧,加油!
作者: 熙洛    时间: 2025-3-25 21:56

Helper64.ra
作者: luo794043199    时间: 2025-4-4 17:12
意思俩个都要下载是吗

作者: yuzhong    时间: 2025-4-9 10:02
1111111111111111111111111111
作者: kyo9766    时间: 2025-4-19 16:25
学习一下64位DLL调用,感谢分享
作者: Dekey    时间: 2025-4-29 16:01
支持开源~!感谢分享
作者: 1dfd    时间: 2025-5-4 13:50
这是啥情况呀?

QQ20250504-140154.png (22.63 KB, 下载次数: 0)

QQ20250504-140154.png





欢迎光临 精易论坛 (https://125.confly.eu.org/) Powered by Discuz! X3.4