veandco / go-sdl2

SDL2 binding for Go
https://godoc.org/github.com/veandco/go-sdl2
BSD 3-Clause "New" or "Revised" License
2.2k stars 218 forks source link

Question: how do I port callbacks to DLL #390

Closed gonutz closed 5 years ago

gonutz commented 5 years ago

Hello again, I am still working on my DLL port but in my tests I discovered a serious problem. I have recreated a minimal sample of the problem to demonstrate it and ask for help.

Basically I use syscall.NewCallback to create a hint callback but when it gets triggered by SDL_SetHint there is a runtime exception. The code works on 64 bit Windows with the 64 bit DLL but not in 32 bit mode. Can anyone help me on this?

gen2brain commented 5 years ago

@gonutz I think you should use syscall.StringToUTF16Ptr() instead of &name[0], something like this:

addHintCallback.Call(uintptr(unsafe.Pointer(syscall.StringToUTF16Ptr(name))), hintCallbackPtr, 0)
setHint.Call(uintptr(unsafe.Pointer(syscall.StringToUTF16Ptr(name))), uintptr(unsafe.Pointer(syscall.StringToUTF16Ptr(value))))
gonutz commented 5 years ago

I tried it just to be sure but that was not the problem. The UTF-16 pointer stuff is there for Windows because the Win API uses UTF-16 for Unicode and not UTF-8 like Go. However, the SDL2 was converted to use UTF-8 internally but strings have a NULL terminator, that is why I just convert the string to []byte and append a 0 to indicate the end to the SDL function.

The strange thing about the error is that the call to addHintCallback actually triggers the callback right away, only when I call setHint and the callback is triggered for the second time, that is when it crashes. Here is the result of running the code:

C:\Users\gonutz\Documents\gocode\src\github.com\gonutz\go-sdl2\issue>go run dll_callback.go
theHintCallback 0 522314496 0 0
theHintCallback 0 522314496 0 522322096
Exception 0xc0000005 0x1 0x46ec0a 0x50f5bc
PC=0x50f5bc

syscall.Syscall(0x6c959bc0, 0x2, 0x1f21e300, 0x1f2200b0, 0x0, 0x0, 0x0, 0x0)
        C:/Go/src/runtime/syscall_windows.go:171 +0xcf
syscall.(*Proc).Call(0x1f212120, 0x1f2200d8, 0x2, 0x2, 0x8, 0x48f580, 0x4b8501, 0x1f2200d8)
        C:/Go/src/syscall/dll_windows.go:148 +0x1c9
syscall.(*LazyProc).Call(0x1f2279a0, 0x1f2200d8, 0x2, 0x2, 0x6c959be0, 0x16fba377, 0x4b8510, 0x521800)
        C:/Go/src/syscall/dll_windows.go:302 +0x48
main.main()
        C:/Users/gonutz/Documents/gocode/src/github.com/gonutz/go-sdl2/issue/dll_callback.go:17 +0x239
eax     0x1
ebx     0x447f75
ecx     0x0
edx     0x2
edi     0x1f2200b0
esi     0x1f21e300
ebp     0x446e34
esp     0x18fec4
eip     0x50f5bc
eflags  0x10202
cs      0x23
fs      0x53
gs      0x2b
exit status 2
gonutz commented 5 years ago

Alright, great news for me, hajimehoshi solved the case in the issue's repo :-)

Turns out that SDL2.dll uses the cdelc and not stdcall convention so using syscall.NewCallback is wrong, I needed to use syscall.NewCallbackCDecl and now it works. The reason it worked for 64 bit builds was thus just a coincidence I guess.