Unhandled Exception: System.EntryPointNotFoundException: Unable to find an entry point named 'SampleMethod' in DLL 'goDLL.dll'

huangapple go评论85阅读模式
英文:

Unhandled Exception: System.EntryPointNotFoundException: Unable to find an entry point named 'SampleMethod' in DLL 'goDLL.dll'

问题

我正在尝试从C#调用一个Go语言的DLL,并将结果和性能与从C#调用C语言的DLL进行比较,所以我按照以下步骤进行了操作:

首先,我构建了C语言的DLL并进行了调用:
步骤1:编写C代码

// cmdll.c
// 编译命令: -LD
int __declspec(dllexport) SampleMethod(int i)
{
  return i*10;
}

步骤2:编译C代码:

  • 打开“Visual Studio x64 Native Tools Command Prompt”
  • 运行命令:cl -LD cmdll.c

步骤3:编写C#代码

// cm.cs
using System;
using System.Runtime.InteropServices;
public class MainClass
{
    [DllImport("Cmdll.dll")]
    public static extern int SampleMethod(int x); // 函数签名,必须有返回类型

    static void Main()
    {
        Console.WriteLine("SampleMethod() 返回 {0}。", SampleMethod(5));
    }
}

步骤4:编译C#文件并构建可执行文件:

  • 打开“Visual Studio x64 Native Tools Command Prompt”
  • 运行命令:csc -platform:x64 cm.cs

以上步骤顺利运行。

我想用相同的方法来调用Go语言的DLL,按照以下步骤进行操作:
步骤1:编写Go代码:

//lib.go
package main

import "C"

//export SampleMethod
func SampleMethod(i int) int {
	return i * 10
}

func main() {
	// 需要一个main函数以便将CGO编译包作为C共享库
}

步骤2:通过以下方式编译上述代码,生成DLL文件:

go build -ldflags="-s -w" -o lib.dll -buildmode=c-shared lib.go

我使用了-ldflags="-s -w"来减小生成文件的大小,并且不确定应该使用哪个-buildmode,所以随机选择了c-shared而不是c-archive
更新:我还尝试了go build -ldflags="-s -w" -o lib.dll -buildmode=c-archive lib.go,结果相同。

步骤3:编写一个C代码,将从Go生成的.dll.h文件组合起来生成一个等效的C DLL:

//goDll.c
#include <stdio.h>
#include "lib.h"
// 强制gcc链接Go运行时(可能有更好的解决方案)
GoInt SampleMethod(GoInt i);

void main() {
}

步骤4:将goDll.c文件编译为:

gcc -shared -pthread -o goDll.dll goDll.c lib.dll -lWinMM -lntdll -lWS2_32

步骤5:构建C#代码以调用生成的DLL,代码与上述相同,只需更改DLL文件名:

// cm.cs
using System;
using System.Runtime.InteropServices;
public class MainClass
{
    [DllImport("goDll.dll")]
    public static extern int SampleMethod(int x); // 函数签名,必须有返回类型

    static void Main()
    {
        Console.WriteLine("SampleMethod() 返回 {0}。", SampleMethod(5));
    }
}

步骤6:编译C#文件并构建可执行文件:

  • 打开“Visual Studio x64 Native Tools Command Prompt”
  • 运行命令:csc -platform:x64 cm.cs

然后尝试运行生成的./cm.exe文件,但出现以下错误:

Unhandled Exception: System.EntryPointNotFoundException: Unable to find an entry point named 'SampleMethod' in DLL 'goDll.dll'.
   at MainClass.SampleMethod(Int32 i)
   at MainClass.Main()
英文:

I'm trying to call a golang dll from c#, and comparing the results and performance against calling c dll from c#, so I did the below:

I started with building the c dll and calling it
step 1: Writting the c code

// cmdll.c
// Compile with: -LD
int __declspec(dllexport) SampleMethod(int i)
{
  return i*10;
}

step 2: Compiling the c code:

  • Open the Visual Studio x64 Native Tools Command Prompt
  • Run the command: cl -LD cmdll.c

step 3: Writting the c# code

// cm.cs
using System;
using System.Runtime.InteropServices;
public class MainClass
{
    [DllImport(&quot;Cmdll.dll&quot;)]
    public static extern int SampleMethod(int x); // function signature, must have a return type

    static void Main()
    {
        Console.WriteLine(&quot;SampleMethod() returns {0}.&quot;, SamplMethod(5));
    }
}

step 4: Compile the c# file and build the exe as:

  • Open the Visual Studio x64 Native Tools Command Prompt
  • Run the command: csc -platform:x64 cm.cs

The things above run smoothly

I wanted to do the same using golang, and followed the below:

step 1: Write the go code:

//lib.go
package main

import &quot;C&quot;

//export SamplMethod
func SamplMethod(i int) int {
	return i * 10
}

func main() {
	// Need a main function to make CGO compile package as C shared library
}

step 2: Build the dll file, by compiling the above code as:

go build -ldflags=&quot;-s -w&quot; -o lib.dll -buildmode=c-shared lib.go

I used the -ldflags=&quot;-s -w&quot; to reduce the resulting file size, and not sure what -buildmode shall i use, so randomly selected c-shared instead of c-archive
update: I tried also with go build -ldflags=&quot;-s -w&quot; -o lib.dll -buildmode=c-archive lib.go and got the same result

step 3: Write a c code that combine the .dll and .h file generated from the go to generate an equivalent c dll

//goDll.c
#include &lt;stdio.h&gt;
#include &quot;lib.h&quot;
// force gcc to link in go runtime (may be a better solution than this)
GoInt SamplMethod(GoInt i);

void main() {
}

step 4: Compile the goDll.c file as:

gcc -shared -pthread -o goDll.dll goDll.c lib.dll -lWinMM -lntdll -lWS2_32

step 5: Build the c# code to call the generated dll, same code as above, but changing the dll file name:

// cm.cs
using System;
using System.Runtime.InteropServices;
public class MainClass
{
    [DllImport(&quot;goDll.dll&quot;)]
    public static extern int SampleMethod(int x); // function signature, must have a return type

    static void Main()
    {
        Console.WriteLine(&quot;SampleMethod() returns {0}.&quot;, SamplMethod(5));
    }
}

step 4: Compile the c# file and build the exe as:

  • Open the Visual Studio x64 Native Tools Command Prompt
  • Run the command: csc -platform:x64 cm.cs

Then tried to run the generated ./cm.exe file, but got the below error:

Unhandled Exception: System.EntryPointNotFoundException: Unable to find an entry point named &#39;SampleMethod&#39; in DLL &#39;goDll.dll&#39;.
   at MainClass.SampleMethod(Int32 i)
   at MainClass.Main()

答案1

得分: 0

感谢@Pak Uula的评论,以下是我翻译好的内容:

步骤1:编写Go代码:

// main.go
package main

import "C"
import "fmt"

//export HelloWorld
func HelloWorld() {
	fmt.Printf("hello world from GO\n")
}

func main() {}

// 编译代码:
// go build -ldflags="-s -w" -buildmode=c-shared -o libgo.dll main.go

步骤2:编写C#代码:

// main.cs
using System;
using System.Runtime.InteropServices;
public class MainClass
{
    [DllImport("libgo.dll")]
    public static extern void HelloWorld(); // 函数签名,必须有返回类型

    static void Main()
    {
        HelloWorld();
    }
}

// 编译代码:
// 打开:
// Visual Studio x64 Native Tools Command Prompt
// csc -platform:x64 cm.cs

步骤3:编译两个文件,首先编译go文件。

步骤4:运行可执行文件。

更新

  1. Go文件:
// main.go
package main

import (
	"fmt"
)

// The import "C" should come directly after the // #include ..., i.e. no empty lines allowed,
// if there are empty lines, the compliler will read the // #include as normal comment, not as C import

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

//export GetHello
func GetHello(Input *C.char) *C.char {
	cStr := C.CString(fmt.Sprintf("From DLL: Hello, %s!\n", C.GoString(Input)))
	//	C.free(unsafe.Pointer(cStr))
	return cStr
}

func main() {}

// 编译代码:
// go build -ldflags="-s -w" -buildmode=c-shared -o libgo.dll main.go
  1. C#文件:
// main.cs
using System;
using System.Text;
using System.Runtime.InteropServices;
public class MainClass
{
    [DllImport("libgo.dll", CharSet = CharSet.Unicode, 
    CallingConvention = CallingConvention.StdCall)]
    public static extern IntPtr GetHello(byte[] data);

    static string CallDll(string name) {
        IntPtr output= IntPtr.Zero;
        var a = GetHello(Encoding.UTF8.GetBytes(name));

        return "GetHello Returns: " + Marshal.PtrToStringAnsi(a);
    }

    static void Main()
    {
        Console.WriteLine(CallDll("Ahmad"));
    }
}

// 编译代码:
// 打开:
// Visual Studio x64 Native Tools Command Prompt
// csc -platform:x64 main.cs

这是一个使用字符串的示例:

英文:

Thanks for @Pak Uula comment, it worked with me as below:

step 1: Write the go code:

// main.go
package main

import &quot;C&quot;
import &quot;fmt&quot;

//export HelloWorld
func HelloWorld() {
	fmt.Printf(&quot;hello world from GO\n&quot;)
}

func main() {}

// compile the code as:
// go build -ldflags=&quot;-s -w&quot; -buildmode=c-shared -o libgo.dll main.go

step 2: Write the c# code as:

// main.cs
using System;
using System.Runtime.InteropServices;
public class MainClass
{
    [DllImport(&quot;libgo.dll&quot;)]
    public static extern void HelloWorld(); // function signature, must have a return type

    static void Main()
    {
        HelloWorld();
    }
}

// compile as:
// open:
// Visual Studio x64 Native Tools Command Prompt
// csc -platform:x64 cm.cs

step 3: Compile both files, start by compiling the go file

step 4: Run the executable file:

Unhandled Exception: System.EntryPointNotFoundException: Unable to find an entry point named 'SampleMethod' in DLL 'goDLL.dll'

UPDATE

  1. Go file:
// main.go
package main

import (
	&quot;fmt&quot;
)

// The import &quot;C&quot; should come directly after the // #include ..., i.e. no empty lines allowed,
// if there are empty lines, the compliler will read the // #include as normal comment, not as C import

/*
#include &lt;stdlib.h&gt;
*/
import &quot;C&quot;

//export GetHello
func GetHello(Input *C.char) *C.char {
	cStr := C.CString(fmt.Sprintf(&quot;From DLL: Hello, %s!\n&quot;, C.GoString(Input)))
	//	C.free(unsafe.Pointer(cStr))
	return cStr
}

func main() {}

// compile the code as:
// go build -ldflags=&quot;-s -w&quot; -buildmode=c-shared -o libgo.dll main.go
  1. C# file:
// main.cs
using System;
using System.Text;
using System.Runtime.InteropServices;
public class MainClass
{
    [DllImport(&quot;libgo.dll&quot;, CharSet = CharSet.Unicode, 
    CallingConvention = CallingConvention.StdCall)]
    public static extern IntPtr GetHello(byte[] data);

    static string CallDll(string name) {
        IntPtr output= IntPtr.Zero;
        var a = GetHello(Encoding.UTF8.GetBytes(name));

        return &quot;GetHello Returns: &quot; + Marshal.PtrToStringAnsi(a);
    }

    static void Main()
    {
        Console.WriteLine(CallDll(&quot;Ahmad&quot;));
    }
}

// compile as:
// open:
// Visual Studio x64 Native Tools Command Prompt
// csc -platform:x64 main.cs

Here is an example that is working with string:

Unhandled Exception: System.EntryPointNotFoundException: Unable to find an entry point named 'SampleMethod' in DLL 'goDLL.dll'

huangapple
  • 本文由 发表于 2022年10月27日 00:59:04
  • 转载请务必保留本文链接:https://go.coder-hub.com/74211556.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定