Golang: using Windows 10 API / UWP / System.WindowsRuntime? - winapi

Using syscall in Go how can I call the UWP APIs within Windows 10? I have seen and tried many win32 examples, but when I tried using System.WindowsRuntime.dll it was a no-go; specifically, I received:
panic: Failed to load System.WindowsRuntime.dll: The specified module could not be found.
(this was at runtime, the binary built fine)
I tried building both with a standard go build as well as
go build -ldflags="-H windows"
example code:
var(
windowsRuntime = syscall.NewLazyDLL("System.WindowsRuntime.dll")
getDiskFreeSpace = windowsRuntime.NewProc("GetDiskFreeSpace")
)
Note: Other variants tried:
windowsRuntime = syscall.NewLazyDLL("System.Runtime.WindowsRuntime.dll")
&
windowsRuntime = syscall.NewLazyDLL("WindowsRuntime.dll")
Anyone been able to get this running or have any advice on the matter?
As always, greatly appreciated!!

Create a file like this:
//go:generate mkwinsyscall -output zfree.go free.go
//sys getDiskFreeSpace(pathName string, sectorsPerCluster *int, bytesPerSector *int, freeClusters *int, numberOfClusters *int) (err error) = GetDiskFreeSpaceA
package main
func main() {
var bytesPerSector, freeClusters, numberOfClusters, sectorsPerCluster int
getDiskFreeSpace(
`C:\`,
&sectorsPerCluster,
&bytesPerSector,
&freeClusters,
&numberOfClusters,
)
println("bytesPerSector", bytesPerSector)
println("freeClusters", freeClusters)
println("numberOfClusters", numberOfClusters)
println("sectorsPerCluster", sectorsPerCluster)
}
Then build:
go generate
go mod init free
go mod tidy
go build
Result:
bytesPerSector 512
freeClusters 12511186
numberOfClusters 25434879
sectorsPerCluster 8
https://github.com/golang/sys/tree/master/windows/mkwinsyscall

I have no idea where you found "System.WindowsRuntime.dll" because as far as I can tell, it doesn't exist (unless you manually made a DLL named that).
As for System.Runtime.WindowsRuntime.dll: it's part of .NET Framework, not Windows, and it is a managed DLL. You cannot load such DLLs using syscall.NewLazyDLL. What's more, that DLL doesn't really contain any Windows APIs - just glue for .NET to be able to work with them.
You're probably looking for functions like RoGetActivationFactory in combase.dll.

Related

Go plugin core dumps when using go routines and variables

I am unable to use variables inside my go routine started in a go plugin.
The following code is an example of what I am trying to do.
The code
// Can be an non-empty struct as well
var channel = make(chan string)
log.Println(channel)
go func(ch chan string) {
log.Println(ch)
}(channel)
crahes with a coredump when executed in a go plugin on darwin.
-Yes Go plugins work on darwin: http://prntscr.com/iq8czy
I recently reported this issue to golang: Issue related to go plugin crashes
This only appears to be the case on darwin (OS X).

Stringer tool complains about wrong archive header

I am trying to use go generate/stringer (golang.org/x/tools/cmd/stringer) to generate String() methods on enums. I have problems, which I believe, are because of slightly different format of .a packages on different systems. I have this file:
package main
import (
"math/rand"
)
//go:generate stringer -type=Foo
type Foo int;
const (
FooPrime Foo = iota
FooBis
)
func main() {
//Just use rand anywhere, otherwise we get a compiler error
rand.Seed(1)
}
Now if I run go generate example.go on my machine everything is all right: foo_string.go is created. However, on a test machine I get:
stringer: checking package: example.go:4:2: could not import math/rand (reading export data: /usr/lib64/go/pkg/linux_amd64/math/rand.a: go archive is missing __.PKGDEF)
Now, after some digging in the code I think that I get this error, because on my machine rand.a has the following header:
!<arch>
__.PKGDEF 0 0 0 644 2051
`
while on test machine it has the following header:
!<arch>
__.PKGDEF/ 0 399 399 100644 2051
`
I think that the crucial difference is slash after PKGDEFF. gcimporter refuses to process .a file, if it doesn't have __.PKGDEF header.
To check this, I edited manually gcimporter/exportdata.go and changed one of the line from this:
if name != "__.PKGDEF"
to this:
if name != "__.PKGDEF" && name != "__.PKGDEF\"
After this change (and compiling and installing everything) I was able to run go generate on example.go.
My questions are: why do I get this problem and how do I get rid of it (other then manually editing external library)?
What I can see from the spec for openSUSE's packaging they are disabling reinstallation of the standard library at updates. __.PKGDEF is a Go specific informational section, and some linker OpenSUSE has used has simply produced incompatible output.
There's nothing you can do except install a healthy Go from the official source.

Cross compile net/http for distribution

I have build the following code in a docker container with the following architecture:
cat /proc/version
Linux version 3.16.7-tinycore64 (root#064f0e1ce709) (gcc version 4.7.2 (Debian 4.7.2-5) ) #1 SMP Tue Dec 16 23:03:39 UTC 2014
package main
import "fmt"
func main() {
fmt.Println("Hello")
}
The binary distributed, runs with no problem on a busybox container, with the same architecture without installing golang.
The problem
When I do the same for the following code:
package main
import (
"fmt"
"net/http"
)
const (
port = ":80"
)
var calls = 0
func HelloWorld(w http.ResponseWriter, r *http.Request) {
calls++
fmt.Fprintf(w, "Hello, world! You have called me %d times.\n", calls)
}
func init() {
fmt.Printf("Started server at http://localhost%v.\n", port)
http.HandleFunc("/", HelloWorld)
http.ListenAndServe(port, nil)
}
func main() {}
Then I get:
ash: ./hello_world: not found
I might be missing some dependencies - like "net/http"?
But I thought the go build would build all into the binaries.
This is for both go build & go install.
Any idea?
The answer is most probably the one described in this article.
Some critical parts of the standard library use CGO [...] if you cross-compile Go to Darwin or Linux your programs won’t use the system DNS resolver. They also can’t use the native host certificate store. They also can’t look up the user’s home directory, either.
And CGO links against some standard system interfaces by default, dynamically.
The article suggests using gonative to fix the problem. If that's not your cup of tea, some people suggest using:
go build -ldflags "-linkmode external -extldflags -static"
Also read: https://groups.google.com/d/topic/golang-nuts/H-NTwhQVp-8/discussion
I think you need to disable cgo and build with netgo flag :
The net package requires cgo by default because the host operating
system must in general mediate network call setup. On some systems,
though, it is possible to use the network without cgo, and useful to
do so, for instance to avoid dynamic linking. The new build tag netgo
(off by default) allows the construction of a net package in pure Go
on those systems where it is possible.
The netgo tag requires version 1.2 and above.

Import issue with docker's libcontainer

When using the docker's libcontainer (specifically the network part), I get an undefined error while building using go build on my project.
import (
"encoding/json"
...
"github.com/docker/libcontainer/network"
)
func SetIP(a Address) (err error) {
...
err = network.SetInterfaceIp(a.Link, a.IP)
....
}
The error itself:
./addresses.go:170: undefined: network.SetInterfaceIp
I've checked inside the library itself and I can find this so called function.
I was building on OSX, which cannot be done when using libcontainer. After using a debian VM the whole project was built correctly.
Kudos to #JimB and #Not_a_Golfer for the hints.

Building and linking dynamically from a go binary

My problem is the following:
I have a go binary on a machine
From that binary I need to compile an external .go file
Once compiled, I need to link the compiled go file into the current binary so I can use the just-compiled go code.
Do you think that's possible ?
I did a few researches and it does not seem to be possible, but I might have overlooked something.
Thanks :)
The first go binary would contain something like
func main() {
// Here I need to compile an external go file (or package) which contains
// The definition of runFoo()
// Once the file/package is compiled and linked I need to call the compiled code
runFoo()
// Continue the execution process normally here
}
The ability to create shared libraries will be in Go 1.5 in August 2015¹.
From "The State of Go" talk by Andrew Gerrand:
Shared libraries
Go 1.5 can produce Go shared libraries that can be consumed by Go
programs.
Build the standard library as shared libraries:
$ go install -buildmode=shared std
Build a "Hello, world" program that links against the shared
libraries:
$ go build -linkshared hello.go
$ ls -l hello
-rwxr-xr-x 1 adg adg 13926 May 26 02:13 hello
Go 1.5 can also build Go programs as C archive files (for static
linking) or shared libraries (for dynamic linking) that can be
consumed by C programs.
[See:] golang.org/s/execmodes
¹ Note, gccgo already had limited support for this for some time, Go 1.5 will be the first time this is supported by the regular go build tools.
Update: It is now possible to do this in mainline Go, see Go Execution Modes
From the Go 1.5 release notes:
For the amd64 architecture only, the compiler has a new option,
-dynlink, that assists dynamic linking by supporting references to Go symbols defined in external shared libraries.
Old Answer (useful discussion of other options):
It is not currently possible to create dynamically linked libraries* in main line Go. There has been some talk about this, so you may see support in the future. However, there is a 3rd party go project called goandroid that needed the same functionality you need, so they maintain patches that should allow you to patch the official Go code base to support the dynamic linked support you are requesting.
If you want to use a the standard Go run-time, I would recommend the one of the following.
Invoke your Go program from your other program, and communicate using:
Pipes to communicate
A UNIX domain socket
An mmaped region of shared memory.
That is, create a file on /dev/shm and have both programs mmap it.
The Go mmap library: https://github.com/edsrzf/mmap-go
Each consecutive option will take more effort to setup, be more platform specific, but potentially be more powerful than the previous one.
*Note: That is, DLLs in the Windows world, and .so files in the UNIX/Linux world.
I think go plugins could be also related to this question, they are supported from go version 1.8. It allows you to dynamically link go binaries implementing required interfaces at runtime.
For example your code has a dependency for a logging backend, but you'd like to support several of them and resolve it at runtime, elasticsearch and splunk could fit here.
You might need to have 2 files: es.go and splunk.go which should both contain a struct of type LoggingBackend implementing a method Write(log string).
To create plugins you need to use buildmode plugin during compilation:
go build -buildmode=plugin -o es.so es.go
go build -buildmode=plugin -o splunk.so splunk.go
After that you could pass the needed plugin via command line arguments and load it:
package main
import "plugin"
import "flag"
type LoggingBackend interface {
Write(log string)
}
var (
backend = flag.String("backend", "elasticsearch", "Default logging backend is elasticsearch")
)
func main() {
flag.Parse()
var mode string
switch backend {
case "elasticsearch":
mode = "./es.so"
case "splunk":
mode = "./splunk.so"
default:
fmt.Println("Didn't recognise your backend")
os.Exit(1)
plug, _ := plugin.Open(mod)
loggingBackend, _ := plug.Lookup("LoggingBackend")
logWriter, _ := loggingBackend.(LoggingBackend)
logWriter.Write("Hello world")
}
This is very possible, you can even compile it as a native shared library
go build -buildmode=c-shared goc.go
# file goc
goc: ELF 32-bit LSB shared object, ARM, EABI5 version 1 (SYSV),
dynamically linked,
BuildID[sha1]=f841e63ee8e916d7848ac8ee50d9980642b3ad86,
not stripped
nm -D --defined-only ./goc | grep "T"
0004ebe8 T _cgoexp_f88ec80374ab_PrintInt
000a6178 T _cgo_panic
0004e954 T _cgo_sys_thread_start
000a48c8 T _cgo_topofstack
0004e88c T _cgo_wait_runtime_init_done
000a61a4 T crosscall2
0004ebc8 T crosscall_arm1
0004e7b0 T fatalf
00102648 T _fini
0004e544 T _init
0004e76c T PrintInt
0004ebe4 T __stack_chk_fail_local
0004eb5c T x_cgo_free
0004ea60 T x_cgo_init
0004eb24 T x_cgo_malloc
0004e8e0 T x_cgo_notify_runtime_init_done
0004eb14 T x_cgo_setenv
0004e820 T x_cgo_sys_thread_create
0004eb64 T x_cgo_thread_start
0004eb20 T x_cgo_unsetenv
like so (tested on go 1.5.1 linux/arm)
goc.go:
package main
import (
"C"
"fmt"
)
//export PrintInt
func PrintInt(x int) {
fmt.Println(x)
}
// http://stackoverflow.com/questions/32215509/using-go-code-in-an-existing-c-project
// go build -buildmode=c-archive goc.go
// go build -buildmode=c-shared goc.go
// https://groups.google.com/forum/#!topic/golang-nuts/1oELh6joLQg
// Trying it on windows/amd64, looks like it isn't supported yet. Is this planned for the 1.5 release?
// It will not be in the 1.5 release.
// It would be nice if somebody worked on it for 1.6.
// https://golang.org/s/execmodes
// http://stackoverflow.com/questions/19431296/building-and-linking-dynamically-from-a-go-binary
// go build -linkshared hello.g
// go install -buildmode=shared std
func main() {
fmt.Println("Hello world")
}
Feature promiced since 1.5 :)
http://talks.golang.org/2015/state-of-go-may.slide#23

Resources