dllcall

command module
v0.9.1 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Mar 17, 2024 License: MIT Imports: 17 Imported by: 0

README

DLLCall tool

DLLCall is an interface generator.

DLLCall will use a single go file as an interface description and from that file it will generate wrappers to call DLL implementing the same interface.

See why DLLCall for comparision between CGO and DLLCall interfaces.

Using DLLCall

Install DLLCall tool using go install github.com/lakal3/dllcall

Invoke: dllcall {interface}.go {c++ interface}.h

Example interface dbif.go

package {package name}

/*
#ctype Stmt *
*/
type stmtHandle uintptr

/*
#cmethod Open
#cmethod Close
*/
type dbIf struct{
	handle stmtHandle
	dbName string	
}

Generate interface

When we invoke dllcall tool such as dllcall dbif.go {otherdir}/dbif.h, dllcall will generate a dbif_impl_windows_amd64.go and dbif_impl_linux_amd64.go file into the current directory and dbif.h to a specified location.

The file name of dbif_impl_{os}_amd64.go is derived from the original go file name. C++ -file can be freely named.

You can use //go:generate directive and go generate command to easily upgrade the interface whenever it changes.

Interface definition

Interface definition must be a single go file containing only type definitions. You can't add functions or methods to the interface file.

Interface usage

After you have generated the interface, you can call it like any other go method

func main()  {
	err := load_dbif("docdbdll.dll") 
	// on Linux:  err := load_dbif(".\libdocdbdll.so") 
	if err != nil { log.Fatal( err )}
	d := &dbIf{ dbName: "test.db"}
	err = d.Open()
	if err != nil { log.Fatal( err )}
	/// ... Do something with db
	err = d.Close()
	if err != nil { log.Fatal( err )}
}

Generator will create an {interface}_impl_{os}_amd64.go file that contains all methods defined with #cmethod.

It will also contain load_{interface} method that takes a single file path to shared library (dll). How libraries are located depends on your operating system.

You must call load_{interface} before you try to invoke any other methods from interface.

Interface implementation

Generator will create a .h-file that you must include into the shared library project.

You must also implement the generated method stubs in a shared library project. In this example the methods to implement are:

GoError *dbIf::Open();
GoError *dbIf::Close();

For more detailed description of comment annotations, generation process and supported types, see generator or examples.

Cgocheck

Go 1.16 introduced new check that prevents pointers structures that contains pointer to Go memory. But in dllcall library all code must be aware of Go garbage collector and do not retain any references to structure member after call has been completed, so this check is unnecessary.

There are three ways to suppress this check

Pinned memory

In version 1.21 Go introduced new Pin mechanism that allows marking all pointer that we want to use in calls to C++ program so that Gos garbage collector is aware of them.

You can enable generating pinned memory pointer with -pin flag.

Pinning is a standard way to handle pointers to Go memory, but unfortunately it add some overhead to calls. Hello Example uses this method.

Disable cgocheck with code

Dllcall uses hack to turn off cgocheck. This hack is in function DisableCgocheck. Generated code will call this function when loading .dll/.so file.

If you select -pin option, cgocheck is not disabled because it will allow pinned memory pointers without panic. Pin option is available only in go 1.21 and later.

It is possible this hack will not work in some future version of Go, so you can change this function to disable this hack.

Windows

Actually Windows syscalls don't apply any checks for go pointers, so dllcall generator will not emit any code to disable checks of to pin memory even if -pin flag is given

Safe method (experimental)

In go 1.21.1 safemethod calls will fail because they set new value to SP (Stack pointer). This is due to change in go1.21. It has been fixed in go1.22 for Windows but Linux still

Added new experimental #csafe_method that mostly allows bypassing Go call overhead to native libraries. This method has several limitations and is experimental. See Generator and new sample fibon for more details.

You should only use fast call when absolutely necessary like accessing high resolution timer in Windows.

Status

Currently only 64 bit (amd64) Windows and 64 bit Linux (amd64) are supported.

Version 0.8.2 breaking changes

  • Renamed generated Go interface. Generated files have now _amd64 extension to prevent build on other architectures. To fix this, remove old generated files from project.
  • Linux CGO wrapper has been moved to a new package linux/syscall to support fastcall. Wrapper packages must be compiled without CGO.

TODO?

  • Pinned memory available with Go 1.21
  • Fastcall (Experimental)
  • Better support for types imported from other modules
  • Linux support

Documentation

The Go Gopher

There is no documentation for this package.

Directories

Path Synopsis
examples
linux

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL