gpt4 book ai didi

c - 是否可以在 Windows 上的 c-dll 中加载 go-dll?

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

我想将一个 c-dll 注入(inject)一个进程。在 c-dll 中,它将加载另一个由 golang 编写的 dll。这是我的 C 代码:
当loader.dll被加载时,它会自动加载用golang编写的worker.dll。

// loader.c  

#include <windows.h>
#include <stdio.h>
#include <memory.h>

typedef void (*StartWorker)();
HMODULE hWorker = NULL;


BOOL APIENTRY DllMain(HMODULE hModule,
DWORD ul_reason_for_call,
LPVOID lpReserved)
{
switch (ul_reason_for_call)
{
case DLL_PROCESS_ATTACH:
{

hWorker = LoadLibrary("D:\\code\\toys\\worker.dll");
if (hWorker == NULL)
{
exit(1);
}

StartWorker startWorker = (StartWorker)GetProcAddress(hWorker, "StartWorker");
MessageBox(NULL, "worker starting", TEXT("Warning:"), MB_OK);
if (startWorker == NULL)
{
MessageBox(NULL, "error", TEXT("Warning:"), MB_OK);
exit(1);
}
startWorker();
MessageBox(NULL, "worker started", TEXT("Warning:"), MB_OK);
FreeLibrary(hWorker);
break;
}
case DLL_PROCESS_DETACH:
case DLL_THREAD_ATTACH:
case DLL_THREAD_DETACH:
default:
break;
}
return TRUE;
}

去代码是:
// worker.go

package main

/*
#include <stdlib.h>
#include <windows.h>
*/
import "C"

//export StartWorker
func StartWorker {
C.MessageBox(nil, C.CString("Hello Worker"), C.CString("Warning:"), 0)
}
func main() {
}
我已将它们编译到 MinGW-w64 .当 loader.dll 试图调用 StartWorker()在worker.dll 中,进程没有显示MessageBox。在我用c重写worker.dll后,一切正常。我也可以调用 StartWorker()通过以下代码:
#include <windows.h>
#include <stdio.h>
#include <memory.h>

typedef void (*StartWorker)();

int main()
{
char *dllPath = "D:\\code\\toys\\loader.dll";
HMODULE hWorker = NULL;
hWorker = LoadLibrary(dllPath);
StartWorker startWorker = (StartWorker)GetProcAddress(hWorker, "StartWorker");
if (startWorker == NULL)
{
MessageBox(NULL, "dllPath", TEXT("Warning:"), MB_OK);
exit(1);
}
startWorker();
MessageBox(NULL, "target", TEXT("Warning:"), MB_OK);
FreeLibrary(hWorker);
return 0;
}

我想知道是否与 go-runtime 有任何冲突?

最佳答案

测试很好,也许你调用了 Microsoft-Windows-Only api。尝试将 MessageBox() (它使用 win32 user32.dll )更改为 Sum() 以测试称为 c-dllgo-dll
这是转到 gen go-dll 的文件
//gosum.go

package main

/*
#include <stdlib.h>
*/
import "C"

//export Sum
func Sum(a int32, b int32) int32 {
return a + b
}

func main() {
}
去构建 c-shared Windows dll:
go build -ldflags "-s -w" -buildmode=c-shared -o gosum.dll
您可以在 c/cpp 中编写测试文件:
#include <stdio.h>
#include <malloc.h>
#include <string.h>
#include "gosum.h"

int main() {
printf("Sum(1,2)=%d\n", Sum(1,2));
return 1;
}
在 MinGW-w64 中编译
g++ -c test_gosum.cpp -o test_gosum.o -g -std=c++11
g++ test_gosum.o gosum.dll -o test_gosum.exe -g -std=c++11
.\test_gosum.exe
enter image description here
然后在 loader.dll 中构建 Visual Studio 称为 gosum.dll//复制 go-dll CGO gen gosum.h 文件到项目,可能你需要删除一些错误代码
//gosum.h 文件:
/* Code generated by cmd/cgo; DO NOT EDIT. */

/* package gosum */


#line 1 "cgo-builtin-export-prolog"

#include <stddef.h> /* for ptrdiff_t below */

#ifndef GO_CGO_EXPORT_PROLOGUE_H
#define GO_CGO_EXPORT_PROLOGUE_H

#ifndef GO_CGO_GOSTRING_TYPEDEF
typedef struct { const char* p; ptrdiff_t n; } _GoString_;
#endif

#endif

/* Start of preamble from import "C" comments. */


#line 3 "gosum.go"

#include <stdlib.h>

#line 1 "cgo-generated-wrapper"


/* End of preamble from import "C" comments. */


/* Start of boilerplate cgo prologue. */
#line 1 "cgo-gcc-export-header-prolog"

#ifndef GO_CGO_PROLOGUE_H
#define GO_CGO_PROLOGUE_H

typedef signed char GoInt8;
typedef unsigned char GoUint8;
typedef short GoInt16;
typedef unsigned short GoUint16;
typedef int GoInt32;
typedef unsigned int GoUint32;
typedef long long GoInt64;
typedef unsigned long long GoUint64;
typedef GoInt64 GoInt;
typedef GoUint64 GoUint;
typedef float GoFloat32;
typedef double GoFloat64;

/*
static assertion to make sure the file is being used on architecture
at least with matching size of GoInt.
*/
typedef char _check_for_64_bit_pointer_matching_GoInt[sizeof(void*) == 64 / 8 ? 1 : -1];

#ifndef GO_CGO_GOSTRING_TYPEDEF
typedef _GoString_ GoString;
#endif
typedef void* GoMap;
typedef void* GoChan;
typedef struct { void* t; void* v; } GoInterface;
typedef struct { void* data; GoInt len; GoInt cap; } GoSlice;

#endif

/* End of boilerplate cgo prologue. */

#ifdef __cplusplus
extern "C" {
#endif
extern GoInt32 Sum(GoInt32 a, GoInt32 b);
#ifdef __cplusplus
}
#endif
//pch.h 文件(由 vs 生成,需要添加一些东西):
#define PCH_H
#include "framework.h"
#endif

// ----- added
#ifdef IMPORT_DLL
#else
#define IMPORT_DLL extern "C" _declspec(dllimport)
#endif

IMPORT_DLL int get_sum_by_another_dll(int a, int b);

// ----- added
//dllmain.cpp 文件(由 vs 生成):
#include "pch.h"

BOOL APIENTRY DllMain( HMODULE hModule,
DWORD ul_reason_for_call,
LPVOID lpReserved
)
{
switch (ul_reason_for_call)
{
case DLL_PROCESS_ATTACH:
case DLL_THREAD_ATTACH:
case DLL_THREAD_DETACH:
case DLL_PROCESS_DETACH:
break;
}
return TRUE;
}
//loader.cpp 文件:
#include "pch.h"
#include <stdlib.h>
#include <windows.h>
#include "gosum.h" // also need add `gosum.dll` to VS project file
using namespace std;

typedef int (CALLBACK* GOSUMFUNC)(GoInt32 a, GoInt32 b);

int __stdcall get_sum_by_another_dll(int a, int b)
{
HMODULE h = LoadLibrary(TEXT("gosum.dll"));
if (NULL == h || INVALID_HANDLE_VALUE == h) {
return 0;
}
GOSUMFUNC go_dll_sum = (GOSUMFUNC)GetProcAddress(h, "Sum");
if (go_dll_sum) {
return go_dll_sum(a, b);
}
return 1;
}
然后在 VS 中编译它们,你会得到 loader.dll
其中 gosum.dllgo-dllloader.dll 是由 VisualStudio 编译的 c-dll ,称为 gosum.dll
enter image description here
你可以尝试在 golang 或 clang 中调用它们。
//demo.go 用 golang 测试 loader.dll 和 gosum.dll,同样需要将 gosum.dllloader.dll 复制到同一个目录下。
package main

import (
"fmt"
"log"
"syscall"
)

func main() {
h, e := syscall.LoadLibrary("loader.dll") //Make sure this DLL follows Golang machine bit architecture (64-bit in my case)
if e != nil {
log.Fatal(e)
}
defer syscall.FreeLibrary(h)
proc, e := syscall.GetProcAddress(h, "get_sum_by_another_dll") //One of the functions in the DLL
if e != nil {
log.Fatal(e)
}
var a int32 = 2
var b int32 = 5
ret, _, err := syscall.Syscall(proc, 2, uintptr(a), uintptr(b), 0) //Pay attention to the positioning of the parameter
fmt.Println(ret)
fmt.Println(err)
}
运行它你会得到结果: get_sum_by_another_dll(2,5) = 7 enter image description here
//callloader.cpp 用c/cpp测试loader.dll和gosum.dll,同样需要将 gosum.dllloader.dll复制到同一个目录下。
#include <iostream>
#include <Windows.h>

int main()
{
HINSTANCE hDllInst;
hDllInst = LoadLibrary(L"loader.dll");
typedef int(*SUMFUNC)(int a, int b);
SUMFUNC dll_sum_fun = (SUMFUNC)GetProcAddress(hDllInst, "get_sum_by_another_dll");
std::cout << dll_sum_fun(1, 2);
}
然后在VS中编译,运行./callloader.exe,你会得到结果: get_sum_by_another_dll(1,2) = 3 enter image description here

关于c - 是否可以在 Windows 上的 c-dll 中加载 go-dll?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/65304131/

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