通过指针传入函数方法参数
import "C"
import (
"bytes"
"encoding/json"
"fmt"
"io/ioutil"
"net/http"
)
//export PrintHello2
func PrintHello2(Input *C.char, Output **C.char) int32 {
*Output = C.CString(fmt.Sprintf("From DLL: Hello, %s!
", C.GoString(Input)))
return int32(len(C.GoString(*Output)))
}
//export PrintHello4
func PrintHello4(Input *C.char) *C.char{
return C.CString(fmt.Sprintf("From DLL: Hello, %s!
", C.GoString(Input)))
}
一定要加 “import “C”” 否则方法不能导出
编译成 DLL
#动态库
go build -buildmode=c-shared -o libmain32.dll main.go
//.dll 和 .so 名字而已,习惯而已
go build -buildmode=c-shared -o libmain32.so main.go
#静态库
go build -buildmode=c-archive -o libmain32.a main.go
c#调用DLL
class Program
{
[DllImport("goDLL.dll", CharSet = CharSet.Unicode, CallingConvention = CallingConvention.StdCall)]
public static extern int PrintHello2([In] byte[] data, ref IntPtr output);
[DllImport("goDLL.dll", CharSet = CharSet.Unicode, CallingConvention = CallingConvention.StdCall)]
public static extern IntPtr PrintHello4(byte[] data);
static void Main(string[] args)
{
string res = "demo";
IntPtr output= IntPtr.Zero;
var a = PrintHello4(Encoding.UTF8.GetBytes(res));
Console.WriteLine("PrintHello4 Returns: " + Marshal.PtrToStringAnsi(a));
var i = PrintHello2(Encoding.UTF8.GetBytes(res), ref output);
Console.WriteLine("PrintHello2 Returns: " + i);
Console.WriteLine("Ref Val changed to: " + Marshal.PtrToStringAnsi(output, i));
}
}
通过指针将数据输出
C#适配 Any CPU
实现的基本思路为(x64和x86环境都装上,编译两种dll,根据运行环境选择dll)
分别导入x64和x86的函数 ,并添加后缀
判断当前进程是x64还是x86
呼叫与对应的函数
[DllImport("testdll32.dll", EntryPoint="add")
private static extern int add86(int a, intb);
[DllImport("testdll64.dll", EntryPoint="add")
private static extern int add64(int a, intb);
public static int add(int a, int b)
{
if (Environment.Is64BitProcess)
return add64(a,b);
return add86(a,b);
}
x64运行挺好,但是在x86运行出现异常: 调用导致堆栈不对称。原因可能是托管的 PInvoke 签名与非托管的目标签名不匹配。请检查 PInvoke 签名的调用约定和参数与非托管的目标签名是否匹配
出现这个错误,可能
1.参数类型不匹配
难道char*不能用string来表示,IntPtr是一定可以的.将C++类型更改成int类型后测试,发现仍然出错,这样看来,不可能是参数类型不匹配了
2. 调用约定不匹配
DllImport还有一个CallingConvention的属性,默认值是CallingCovention.Stdcall, 此处更改成Cdecl(c/c++默认调用方式)就可以了
[DllImport("datalib.dll", EntryPoint = "test",CallingConvention=CallingConvention.Cdecl)]
public static extern void test(string str);