2015-10-24 5 views
7

Stworzyłem podstawową klasę, która dodaje dwie liczby w języku C#. Zbudowałem go do biblioteki dll, ale gdy próbuję go wywołać w golangu, nie udaje mi się. Po pierwsze jest to możliwe obecnie w golangu? Jeśli tak, to czy ktoś może podać przykład, jak to zrobić?Czy dll wykonane w języku C# być używane w aplikacji golang

Edytuj: Zawarłem ostatnią próbę dokonania tego. DLL C# jest po prostu metodą, która dodaje dwie liczby, które są przekazywane w

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

Jak próbujesz to zrobić? Czy możesz nam pokazać kod? – rhughes

+0

Dodałem ostatnią próbę, którą zrobiłem. Ta wersja powoduje błąd podczas próby wywołania go install z _undefined: syscall.NewLazyDLL_ – 165plo

Odpowiedz

7

Tak to jest możliwe. https://github.com/golang/go/wiki/WindowsDLLs

(Kopiowanie tutaj w przypadku matryc link)

Nie jest kilka sposobów wywoływania kodu "C" od wewnątrz Go

Pierwszy sposób: Dynamicznie ładować bibliotekę dll, a następnie wywołać na niej metodę. Możesz wywołać metodę przez "syscallXX" (XX jest liczbą parametrów, ale , jeśli ma kilka parametrów, tak jakbyś potrzebował siedmiu parametrów, wtedy syscall9 nadal będzie działać, po prostu powiedz, że liczba argumentów jest 7). W ten sposób działa także z bibliotek współdzielonych Linux, jak również, jeśli jesteś kierowania Linux:

przykładowy program, który wywołuje DLL systemu Windows z 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") 
} 

Drugim sposobem jest za pośrednictwem syscall .NewProc (itp.) Zamiast syscall.GetProcAddress. Są to w zasadzie pewne metody pomocnika ponad że syscall te, obejrzałeś powyżej, i są dostępne tylko w systemach Windows: 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) 

} 

Trzecim sposobem byłoby zadzwonić do biblioteki w zasadzie przez „łączenie” przeciwko biblioteki, stosując metodę „CGO” (w ten sposób działa w Linuksie i Windows):

ten sposób będzie wyglądać mniej więcej tak

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

Zobacz cgo dla dalszych szczegółów.

+0

Dziękuję. Będę musiał spróbować tego na maszynie Windows. Wypróbowałem pierwsze 2 opcje bez powodzenia. Uniknąłem ostatniej opcji, ponieważ wydaje się być przede wszystkim dla C (import plików .h). – 165plo

+0

jakikolwiek sukces @ 165plo? Nie mogłem go uruchomić. –

+0

@RaviKumar Nie miałem okazji spróbować ponownie. Ale podążałem za powyższymi krokami w moich testach i nigdy nie byłem w stanie go uruchomić. Zgaduję, że moim problemem jest to, że używam C# zamiast C lub C++. Ponieważ C# kompiluje się do kodu bajtowego używanego przez CLI, myślę, że system nie jest w stanie obsłużyć tej biblioteki DLL. Ale to tylko moja teoria. – 165plo

Powiązane problemy