I'm using Go to build a DLL.
I'm not able to implement windows DllMain entry point.
My goal is when an app loads the dll via LoadLibrary
to call the Test
method, the DllMain
will be called as well. However currently the app is kind of stuck in deadlock and nothing happens.
The app is quite simple python code
# App code
import ctypes
lib = ctypes.CDLL("./mydll.dll")
lib.Test()
Notes:
I am building using
go version go1.16.4 windows/amd64
and building using
go build -o mydll.dll --buildmode=c-shared
If I remove DllMain
, everything works fine and app can call the Test
method successfully.
I'm aware that I can switch
case under DllMain
to specify conditions such as process attached, detached ...etc, I just wanted to keep it as simple as possible.
//Go Code
package main
import "C"
import (
"fmt"
"os"
)
//export Test
func Test() {
os.Create("fooFile")
}
//export DllMain
func DllMain(a uintptr, b uint32, c uintptr) int32 {
return 1
}
func main() {
}
DllMain
can't be a Go function, since invoking a Go function the first time initializes the Go runtime, which can't be done in scope of DllMain
(there are very few things that can be done in scope of DllMain
).
As a workaround, you can write DllMain
in C and invoke Go code in a separate thread as in this example. But you can't synchronize with that thread in the scope of DllMain
, doing so will again lead to a deadlock.
There's also _cgo_wait_runtime_init_done
, but it also is asynchronous.
So if you need to perform some Go action synchronously on DLL attachment, you're out of luck. It's best to just define an "Init
" exported function and call it before calling any other API.
And of course, the idiomatic way in Go to initialize on load is via an init()
function:
package main
import "C"
import (
"fmt"
)
func init() {
fmt.Println("init()")
}
//export Test
func Test() {
fmt.Println("Test()")
}
func main() {
}
Compile and run:
go build -o mydll.dll --buildmode=c-shared
rundll32 mydll,Test
Output:
init()
Test()