dongluedeng1524 2015-10-24 05:48
浏览 212

可以在Golang应用程序中使用C#制成的dll吗

I have created a basic class that adds two numbers in c#. I have built it into a dll but when attempting to call it in golang I am unsuccessful.

Is this possible currently in golang? If so can someone provide a example how to do this?

Edit: I have included the last attempt I made at doing this. The C# dll is simply a method that adds the two numbers that are passed in.

package main

import (
    "fmt"
    "syscall"
)

func main() {
    var mod = syscall.NewLazyDLL("MathForGo.dll")
    var proc = mod.NewProc("Add");
    proc.Call(2,3);
    fmt.Printf("%v",proc)
}
  • 写回答

2条回答 默认 最新

  • douhao6557 2015-10-24 05:52
    关注

    Edit: this answer should be deleted but SO won't let me do it. It does not actually work with C#.


    Yes it is possible: https://github.com/golang/go/wiki/WindowsDLLs

    (Copying here in case the link dies)

    There are a few ways to call "C" code from inside Go

    First way: Dynamically load a dll, then call a method on it. You can call the method via "syscallXX" (the XX is number of parameters, but if it has few than that, like if you need seven parameter, then syscall9 will still work, you just tell it the number of arguments is 7). This way also works with Linux shared libraries, as well, if you're targeting linux:

    A sample program that calls Windows DLLs from Go:

    package main
    
    import (
        "fmt"
        "syscall"
        "unsafe"
    )
    
    func abort(funcname string, err error) {
        panic(fmt.Sprintf("%s failed: %v", funcname, err))
    }
    
    var (
        kernel32, _        = syscall.LoadLibrary("kernel32.dll")
        getModuleHandle, _ = syscall.GetProcAddress(kernel32, "GetModuleHandleW")
    
        user32, _     = syscall.LoadLibrary("user32.dll")
        messageBox, _ = syscall.GetProcAddress(user32, "MessageBoxW")
    )
    
    const (
        MB_OK                = 0x00000000
        MB_OKCANCEL          = 0x00000001
        MB_ABORTRETRYIGNORE  = 0x00000002
        MB_YESNOCANCEL       = 0x00000003
        MB_YESNO             = 0x00000004
        MB_RETRYCANCEL       = 0x00000005
        MB_CANCELTRYCONTINUE = 0x00000006
        MB_ICONHAND          = 0x00000010
        MB_ICONQUESTION      = 0x00000020
        MB_ICONEXCLAMATION   = 0x00000030
        MB_ICONASTERISK      = 0x00000040
        MB_USERICON          = 0x00000080
        MB_ICONWARNING       = MB_ICONEXCLAMATION
        MB_ICONERROR         = MB_ICONHAND
        MB_ICONINFORMATION   = MB_ICONASTERISK
        MB_ICONSTOP          = MB_ICONHAND
    
        MB_DEFBUTTON1 = 0x00000000
        MB_DEFBUTTON2 = 0x00000100
        MB_DEFBUTTON3 = 0x00000200
        MB_DEFBUTTON4 = 0x00000300
    )
    
    func MessageBox(caption, text string, style uintptr) (result int) {
        var nargs uintptr = 4
        ret, _, callErr := syscall.Syscall9(uintptr(messageBox),
            nargs,
            0,
            uintptr(unsafe.Pointer(syscall.StringToUTF16Ptr(text))),
            uintptr(unsafe.Pointer(syscall.StringToUTF16Ptr(caption))),
            style,
            0,
            0,
            0,
            0,
            0)
        if callErr != 0 {
            abort("Call MessageBox", callErr)
        }
        result = int(ret)
        return
    }
    
    func GetModuleHandle() (handle uintptr) {
        var nargs uintptr = 0
        if ret, _, callErr := syscall.Syscall(uintptr(getModuleHandle), nargs, 0, 0, 0); callErr != 0 {
            abort("Call GetModuleHandle", callErr)
        } else {
            handle = ret
        }
        return
    }
    
    func main() {
        defer syscall.FreeLibrary(kernel32)
        defer syscall.FreeLibrary(user32)
    
        fmt.Printf("Return: %d
    ", MessageBox("Done Title", "This test is Done.", MB_YESNOCANCEL))
    }
    
    func init() {
        fmt.Print("Starting Up
    ")
    }
    

    Second way is via syscall.NewProc (etc.) instead of syscall.GetProcAddress. These are basically some helper methods over the syscall ones, you saw above, and are available in Windows only: http://golang.org/src/pkg/syscall/dll_windows.go

    package main
    
    import (
        "fmt"
        "syscall"
        "unsafe"
    )
    
    func main() {
        var mod = syscall.NewLazyDLL("user32.dll")
        var proc = mod.NewProc("MessageBoxW")
        var MB_YESNOCANCEL = 0x00000003
    
        ret, _, _ := proc.Call(0,
            uintptr(unsafe.Pointer(syscall.StringToUTF16Ptr("Done Title"))),
            uintptr(unsafe.Pointer(syscall.StringToUTF16Ptr("This test is Done."))),
            uintptr(MB_YESNOCANCEL))
        fmt.Printf("Return: %d
    ", ret)
    
    }
    

    A third way would be to call into libraries basically by "linking" against the library, using the "cgo" method (this way works in Linux and Windows):

    This way would look something like this

    import ("C")
    ...
    C.MessageBoxW(...)
    

    See cgo for further details.

    评论

报告相同问题?

悬赏问题

  • ¥20 腾讯企业邮箱邮件可以恢复么
  • ¥15 有人知道怎么将自己的迁移策略布到edgecloudsim上使用吗?
  • ¥15 错误 LNK2001 无法解析的外部符号
  • ¥50 安装pyaudiokits失败
  • ¥15 计组这些题应该咋做呀
  • ¥60 更换迈创SOL6M4AE卡的时候,驱动要重新装才能使用,怎么解决?
  • ¥15 让node服务器有自动加载文件的功能
  • ¥15 jmeter脚本回放有的是对的有的是错的
  • ¥15 r语言蛋白组学相关问题
  • ¥15 Python时间序列如何拟合疏系数模型