gpt4 book ai didi

c++ - 从C++ dll调用Go dll

转载 作者:行者123 更新时间:2023-12-03 10:08:35 25 4
gpt4 key购买 nike

我在Go中使用导出的函数创建了该dll,当我使用rundll32或使用loadlbraryA从c++可执行文件调用它时,该函数运行良好。但是我从c++ dll调用时遇到错误,我尝试读取GetLastError()并显示cannot find the module you are calling。我尝试了所有可能的方法来提供loadlibraryA的完整路径,但是会发生相同的错误,并且每次DLL的句柄都为空。另外,我检查了Go DLL,并正确导出了Test函数。
简而言之,它在调用Test()时起作用:

  • 来自rundll32
  • 来自c++ main()和loadlibrary

  • 并且在Test()中不起作用:

    来自C++ DllMain()和loadlibrary的
  • 从c++ DllMain()和loadlibrary直接从kernel32.dll调用
  • 来自c++ DllMain()和在DllMain()中创建的ThreadFunction

  • 资料夹结构
    ProjectFolder
    -- main.go
    -- dllmain.h
    -- dllmain.go
    建立
    go build -buildmode=c-shared -o my-go-library.dll main.go
    调用示例dll
    rundll32 my-go-library.dll Test
    工作来源
    main.go:
    package main

    import "C"

    import (
    "syscall"
    "time"
    "unsafe"
    )

    //export Test
    func Test() {
    MessageBoxPlain("TestMsgbox","Test")
    main()
    }

    //export OnProcessAttach
    func OnProcessAttach() {
    MessageBoxPlain("OnAttachMsgbox","OnAttach")
    Test()
    }

    // MessageBox of Win32 API.
    func MessageBox(hwnd uintptr, caption, title string, flags uint) int {
    ret, _, _ := syscall.NewLazyDLL("user32.dll").NewProc("MessageBoxW").Call(
    uintptr(hwnd),
    uintptr(unsafe.Pointer(syscall.StringToUTF16Ptr(caption))),
    uintptr(unsafe.Pointer(syscall.StringToUTF16Ptr(title))),
    uintptr(flags))

    return int(ret)
    }

    // MessageBoxPlain of Win32 API.
    func MessageBoxPlain(title, caption string) int {
    const (
    NULL = 0
    MB_OK = 0
    )
    return MessageBox(NULL, caption, title, MB_OK)
    }

    func main() {}
    dllmain.h:
    #include <windows.h>

    void OnProcessAttach(HINSTANCE, DWORD, LPVOID);

    typedef struct {
    HINSTANCE hinstDLL; // handle to DLL module
    DWORD fdwReason; // reason for calling function // reserved
    LPVOID lpReserved; // reserved
    } MyThreadParams;

    DWORD WINAPI MyThreadFunction(LPVOID lpParam) {
    MyThreadParams params = *((MyThreadParams*)lpParam);
    OnProcessAttach(params.hinstDLL, params.fdwReason, params.lpReserved);
    free(lpParam);
    return 0;
    }

    BOOL WINAPI DllMain(
    HINSTANCE _hinstDLL, // handle to DLL module
    DWORD _fdwReason, // reason for calling function
    LPVOID _lpReserved) // reserved
    {
    switch (_fdwReason) {
    case DLL_PROCESS_ATTACH:
    // Initialize once for each new process.
    // Return FALSE to fail DLL load.
    {
    MyThreadParams* lpThrdParam = (MyThreadParams*)malloc(sizeof(MyThreadParams));
    lpThrdParam->hinstDLL = _hinstDLL;
    lpThrdParam->fdwReason = _fdwReason;
    lpThrdParam->lpReserved = _lpReserved;
    HANDLE hThread = CreateThread(NULL, 0, MyThreadFunction, lpThrdParam, 0, NULL);
    // CreateThread() because otherwise DllMain() is highly likely to deadlock.
    }
    break;
    case DLL_PROCESS_DETACH:
    // Perform any necessary cleanup.
    break;
    case DLL_THREAD_DETACH:
    // Do thread-specific cleanup.
    break;
    case DLL_THREAD_ATTACH:
    // Do thread-specific initialization.
    break;
    }
    return TRUE; // Successful.
    }
    dllmain.go:
    package main

    //#include "dllmain.h"
    import "C"
    C++ DLL
    现在,从 Test调用 my-go-library.dll的c++ dll源:
    #include "pch.h"
    #define WIN32_LEAN_AND_MEAN
    #include <Windows.h>
    #include <winternl.h>
    #include <malloc.h>
    #include <intrin.h>
    #include <Windows.h>
    #include <winternl.h>
    #include <malloc.h>
    #include <ostream>
    #include <iostream>
    #include <string>

    using namespace std;

    typedef int(__stdcall* TestFromGo)();

    void Error()
    {
    wchar_t err[256];
    memset(err, 0, 256);
    FormatMessageW(FORMAT_MESSAGE_FROM_SYSTEM, NULL, GetLastError(),MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), err, 255, NULL);
    int msgboxID = MessageBoxW(NULL,err,(LPCWSTR)L"Error",MB_OK);
    }

    BOOL APIENTRY DllMain(HMODULE hModule, DWORD ul_reason_for_call, LPVOID lpReserved)
    {
    MessageBoxA(0, "The C++ DLL", "title", 0);

    HINSTANCE hGetProcIDDLL = LoadLibraryA("C:\\User\\.....path to go dll.....\\my-go-library.dll");
    if (!hGetProcIDDLL) {
    Error();
    MessageBoxA(0, "could not load the dynamic library", "Test", 0);
    }
    TestFromGo TestFunction = (TestFromGo)GetProcAddress(hGetProcIDDLL, "Test");
    if (!TestFunction) {
    MessageBoxA(0, "could not locate the function", "Test", 0);
    }

    TestFromGo();
    }

    extern "C" __declspec(dllexport) void jojo()
    {
    DllMain(0, 1, 0);
    }
    调用C++ dll
    现在,这个应该先调用 jojo,再调用 DllMain,再调用 my-go-library.dllTest
    rundll32 theCiplasplas.dll jojo

    最佳答案

    我帮不上Golang。但是您的DllMain中存在问题。 DllMain仅允许有限的一组API函数。
    Dynamic-Link Library Best Practices明确指出您不应在DllMain中创建线程:

    You should never perform the following tasks from within DllMain:

    • Call CreateThread. Creating a thread can work if you do not synchronize with other threads, but it is risky.
    • Call LoadLibrary or LoadLibraryEx (either directly or indirectly). This can cause a deadlock or a crash

    因此,当您使用rundll32时,它可能会起作用;如果以其他方式加载DLL,则它可能会不起作用。
    编辑:添加了有关LoadLibrary的摘录

    关于c++ - 从C++ dll调用Go dll,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/65651662/

    25 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com