繁体   English   中英

从 C++ Z06416233FE5EC4C5933122E4AB248AF1 调用 Go dll

[英]Calling a Go dll from a C++ dll

I have created this dll in Go with an exported function which works fine while I'm calling it with rundll32 or from a c++ executable with the loadlbraryA. 但是从 c++ dll 调用时出现错误,我试图读取GetLastError()它说cannot find the module you are calling 我尝试了所有可能的方法来提供 loadlibraryA 的完整路径,但同样的错误发生了,并且 Go DLL 的句柄每次都是 null。 此外,我检查了 Go DLL,测试 function 正确导出。

简而言之,它在调用 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

现在 c++ dll 源代码从my-go-library.dll调用Test

#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 函数。

动态链接库最佳实践明确指出您不应在 DllMain 中创建线程:

永远不要在 DllMain 中执行以下任务:

  • 调用 CreateThread。 如果你不与其他线程同步,创建一个线程可以工作,但它是有风险的。
  • 调用 LoadLibrary 或 LoadLibraryEx(直接或间接)。 这可能会导致死锁或崩溃

因此,当您使用 rundll32 时它可能会起作用,如果您以另一种方式加载 DLL,它可能会不起作用。

编辑:添加了关于 LoadLibrary 的摘录

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM