2015-10-24 18 views
7

Ho creato una classe base che aggiunge due numeri in C#. L'ho costruito in una DLL ma quando cerco di chiamarlo in golang non ho successo. Prima è possibile ora al golang? Se è così, qualcuno può fornire un esempio su come farlo?È possibile utilizzare una dll in C# in un'applicazione golang

Modifica: ho incluso l'ultimo tentativo che ho fatto a questo scopo. Il C# dll è semplicemente un metodo che aggiunge i due numeri che sono passati 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) 
} 
+0

Come stai provando a fare questo? Puoi per favore mostrarci un codice? – rhughes

+0

Ho aggiunto l'ultimo tentativo che ho fatto. Questa versione causa un errore quando si tenta di chiamare go install con _undefined: syscall.NewLazyDLL_ – 165plo

risposta

7

sì è possibile:. https://github.com/golang/go/wiki/WindowsDLLs

(Copia qui nel caso in cui il link muore)

Ci sono alcuni modi per chiamare il codice "C" dall'interno Go

Primo modo: caricare dinamicamente una DLL, quindi richiamare un metodo su di esso. Puoi chiamare tramite "syscallXX" (il XX è il numero di parametri, ma se ne ha pochi, come se hai bisogno di sette parametri, quindi syscall9 funzionerà ancora, devi solo dire che il numero di argomenti è 7). In questo modo funziona anche con le librerie condivise di Linux, come pure, se ci si rivolge linux:

Un esempio di programma che chiama DLL di Windows da 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\n", MessageBox("Done Title", "This test is Done.", MB_YESNOCANCEL)) 
} 

func init() { 
    fmt.Print("Starting Up\n") 
} 

secondo modo è tramite chiamata di sistema .NewProc (ecc.) Invece di syscall.GetProcAddress. Queste sono fondamentalmente alcuni metodi di supporto oltre quelli syscall, si è visto sopra, e sono disponibili in Windows solo: 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\n", ret) 

} 

Un terzo modo sarebbe quello di chiamare in librerie fondamentalmente dal "collega" contro la libreria, utilizzando il metodo "CGO" (in questo modo funziona in Linux e Windows):

in questo modo sarebbe simile a questa

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

Vedi cgo per ulteriori dettagli.

+0

Grazie. Dovrò tentare questo su una macchina Windows. Ho provato le prime 2 opzioni senza successo. Ho evitato l'ultima opzione in quanto sembra essere principalmente per C (importando i file .h). – 165plo

+0

qualsiasi successo a 165plo? Non riuscivo a farlo funzionare. –

+0

@RaviKumar Non ho avuto l'opportunità di riprovare. Ma avevo seguito i passaggi precedenti nei miei test e non ero mai riuscito a farlo funzionare. La mia ipotesi è che il mio problema è che sto usando C# piuttosto che C o C++. Dal momento che C# si compila fino al codice byte che viene utilizzato dalla CLI, ritengo che il sistema non sia in grado di gestire l'utilizzo di tale dll. Ma questa è solo la mia teoria. – 165plo

Problemi correlati