Go调用SDL2的C语言动态库

weiwg521 · · 1405 次点击 · · 开始浏览    
这是一个创建于 的文章,其中的信息可能已经有所发展或是发生改变。

# Go调用SDL2的C语言动态库 在网上找到go的GUI项目基本都需要安装额外软件库,尝试了一下使用go调用dll库的,有所收获,抛砖引玉,留个记录怕以后忘了。 ## 1.目录结构 ``` └─libtest │ main.go │ sdl.go └─ lib SDL2.dll ``` ## 2. 库函数封装(sdl.go) ``` package main import ( "syscall" "unsafe" ) //SDL_INIT_Flag 初始化标志 const ( SDL_INIT_TIMER = 0x00000001 SDL_INIT_AUDIO = 0x00000010 SDL_INIT_VIDEO = 0x00000020 /**< SDL_INIT_VIDEO implies SDL_INIT_EVENTS */ SDL_INIT_JOYSTICK = 0x00000200 /**< SDL_INIT_JOYSTICK implies SDL_INIT_EVENTS */ SDL_INIT_HAPTIC = 0x00001000 SDL_INIT_GAMECONTROLLER = 0x00002000 /**< SDL_INIT_GAMECONTROLLER implies SDL_INIT_JOYSTICK */ SDL_INIT_EVENTS = 0x00004000 SDL_INIT_NOPARACHUTE = 0x00100000 /**< compatibility; this flag is ignored. */ SDL_INIT_EVERYTHING = SDL_INIT_TIMER | SDL_INIT_AUDIO | SDL_INIT_VIDEO | SDL_INIT_EVENTS | SDL_INIT_JOYSTICK | SDL_INIT_HAPTIC | SDL_INIT_GAMECONTROLLER ) // SDL_WindowFlags 窗体标志 const ( /* !!! FIXME: change this to name = (1<<x). */ SDL_WINDOW_FULLSCREEN = 0x00000001 /**< fullscreen window */ SDL_WINDOW_OPENGL = 0x00000002 /**< window usable with OpenGL context */ SDL_WINDOW_SHOWN = 0x00000004 /**< window is visible */ SDL_WINDOW_HIDDEN = 0x00000008 /**< window is not visible */ SDL_WINDOW_BORDERLESS = 0x00000010 /**< no window decoration */ SDL_WINDOW_RESIZABLE = 0x00000020 /**< window can be resized */ SDL_WINDOW_MINIMIZED = 0x00000040 /**< window is minimized */ SDL_WINDOW_MAXIMIZED = 0x00000080 /**< window is maximized */ SDL_WINDOW_INPUT_GRABBED = 0x00000100 /**< window has grabbed input focus */ SDL_WINDOW_INPUT_FOCUS = 0x00000200 /**< window has input focus */ SDL_WINDOW_MOUSE_FOCUS = 0x00000400 /**< window has mouse focus */ SDL_WINDOW_FULLSCREEN_DESKTOP = (SDL_WINDOW_FULLSCREEN | 0x00001000) SDL_WINDOW_FOREIGN = 0x00000800 /**< window not created by SDL */ SDL_WINDOW_ALLOW_HIGHDPI = 0x00002000 /**< window should be created in high-DPI mode if supported. On macOS NSHighResolutionCapable must be set true in the application's Info.plist for this to have any effect. */ SDL_WINDOW_MOUSE_CAPTURE = 0x00004000 /**< window has mouse captured (unrelated to INPUT_GRABBED) */ SDL_WINDOW_ALWAYS_ON_TOP = 0x00008000 /**< window should always be above others */ SDL_WINDOW_SKIP_TASKBAR = 0x00010000 /**< window should not be added to the taskbar */ SDL_WINDOW_UTILITY = 0x00020000 /**< window should be treated as a utility window */ SDL_WINDOW_TOOLTIP = 0x00040000 /**< window should be treated as a tooltip */ SDL_WINDOW_POPUP_MENU = 0x00080000 /**< window should be treated as a popup menu */ SDL_WINDOW_VULKAN = 0x10000000 /**< window usable for Vulkan surface */ ) // SDL_Window SDL窗体 type SDL_Window struct{} // SDL_Event SDL 事件 type SDL_Event struct{} // SDL_Init SDL 初始化 func SDL_Init(flags uint32) bool { ret := SysCallDll("SDL_Init", 1, uintptr(flags)) if int(ret) == 0 { return true } return false } // SDL_CreateWindow 创建window窗体,失败返回nil func SDL_CreateWindow(title string, posX, posY, width, height, sdlWindowFlag int32) *SDL_Window { var tp, _ = syscall.BytePtrFromString(title) // 将string转为*byte var tptr = unsafe.Pointer(tp) // 获取*byte指针 ret := SysCallDll("SDL_CreateWindow", 6, uintptr(tptr), uintptr(posX), uintptr(posY), uintptr(width), uintptr(height), uintptr(sdlWindowFlag)) if int(ret) == 0 { return nil } return (*SDL_Window)(unsafe.Pointer(ret)) } // SDL_Delay 延迟xxx ms后返回 func SDL_Delay(ms uint32) { SysCallDll("SDL_Delay", 1, uintptr(ms)) } // SDL_DestroyWindow 销毁窗体 func SDL_DestroyWindow(window *SDL_Window) { SysCallDll("SDL_DestroyWindow", 1, uintptr(unsafe.Pointer(window))) } //SDL_Quit(void) 退出SDL系统 func SDL_Quit() { SysCallDll("SDL_Quit", 0) } // SDL_PollEvent 轮询当前挂起的事件 func SDL_PollEvent(event *SDL_Event) bool { ret := SysCallDll("SDL_PollEvent", 1, uintptr(unsafe.Pointer(event))) if int(ret) == 1 { return true } return false } ``` ## 3. 加载动态库(main.go) ``` package main import ( "fmt" "syscall" "unsafe" ) // ThrowErr 抛出异常 func ThrowErr(str string, err error) { if err != nil { fmt.Printf("[Err]:%s,%v\n", str, err) } } // 动态库的指针 var hsdl syscall.Handle // LoadDLL 加载动态库 func LoadDll() { var err error hsdl, err = syscall.LoadLibrary("lib/SDL2.dll") ThrowErr("LoadLibrary-SDL", err) } // FreeDll 释放动态库 func FreeDll() { if hsdl != 0 { syscall.FreeLibrary(hsdl) } } // SysCallDll 包装syscall.Syscall/6/9/12 调用动态库内函数 // funcName 函数名; argsNum 参数个数; args 可变参数 func SysCallDll(funcName string, argsNum int32, args ...uintptr) (r uintptr) { proc, err := syscall.GetProcAddress(hsdl, funcName) ThrowErr(funcName, err) var errs error var debug bool = false var fargs = [12]uintptr{} //获取参数 for i, arg := range args { fargs[i] = arg } if (argsNum > -1) && (argsNum < 4) { //小于等于3个参数 r, _, errs = syscall.Syscall(uintptr(proc), uintptr(argsNum), fargs[0], fargs[1], fargs[2]) //ThrowErr(funcName, errs) } else if (argsNum > 3) && (argsNum < 7) { //小于等于6个参数 r, _, errs = syscall.Syscall6(uintptr(proc), uintptr(argsNum), fargs[0], fargs[1], fargs[2], fargs[3], fargs[4], fargs[5]) //ThrowErr(funcName, errs) } else if (argsNum > 6) && (argsNum < 10) { //小于等于9个参数 r, _, errs = syscall.Syscall9(uintptr(proc), uintptr(argsNum), fargs[0], fargs[1], fargs[2], fargs[3], fargs[4], fargs[5], fargs[6], fargs[7], fargs[8]) //ThrowErr(funcName, errs) } else if (argsNum > 9) && (argsNum < 13) { //小于等于12个参数 r, _, errs = syscall.Syscall12(uintptr(proc), uintptr(argsNum), fargs[0], fargs[1], fargs[2], fargs[3], fargs[4], fargs[5], fargs[6], fargs[7], fargs[8], fargs[9], fargs[10], fargs[11]) //ThrowErr(funcName, errs) } else { fmt.Println("The args number was bigger than 12.") } if debug { fmt.Println(errs) } return r } // CharPtr2String 从char指针读取string func CharPtr2String(vcode uintptr) string { var vbyte []byte for i := 0; i < 20; i++ { sbyte := *((*byte)(unsafe.Pointer(vcode))) if sbyte == 0 { break } vbyte = append(vbyte, sbyte) vcode += 1 } return string(vbyte) } // testSdlWindow 创建窗体,然后暂停程序所以窗体没响应 func testSdlWindow() { LoadDll() // 加载动态库 if SDL_Init(SDL_INIT_VIDEO) { // 初始化视频子系统 // 创建窗体 win := SDL_CreateWindow("SDL窗体标题", 50, 50, 600, 480, SDL_WINDOW_SHOWN) if win == nil { fmt.Println("SDL_CreateWindow 失败") } SDL_Delay(6000) // 暂停程序6000ms SDL_DestroyWindow(win) // 销毁释放窗体 } SDL_Quit() // 退出清理SDL defer FreeDll() // 释放动态库SDL2.dll } // testSdlWindow2 创建窗体,使用事件循环显示可响应窗体 func testSdlWindow2() { LoadDll() // 加载动态库 if SDL_Init(SDL_INIT_VIDEO) { // 初始化视频子系统 // 创建窗体 win := SDL_CreateWindow("SDL窗体标题", 50, 50, 600, 480, SDL_WINDOW_SHOWN) if win == nil { fmt.Println("SDL_CreateWindow 失败") } for { // 事件循环 if SDL_PollEvent(evt) { // 轮询事件队列 // 此处SDL_Event在C语言中为联合,需要其他处理 // if GetEventType(evt) == SDL_QUIT { // 退出事件 // break // } } } SDL_DestroyWindow(win) // 销毁释放窗体 SDL_Quit() // 退出清理SDL defer FreeDll() // 释放动态库SDL2.dll } } var evt = new(SDL_Event) // SDL事件 func main() { testSdlWindow2() } ``` ![sdl.jpg](https://static.studygolang.com/190601/11584c5f5662ac24a2e4d91e0626dd01.jpg)

有疑问加站长微信联系(非本文作者))

入群交流(和以上内容无关):加入Go大咖交流群,或添加微信:liuxiaoyan-s 备注:入群;或加QQ群:692541889

1405 次点击  
加入收藏 微博
暂无回复
添加一条新回复 (您需要 登录 后才能回复 没有账号 ?)
  • 请尽量让自己的回复能够对别人有帮助
  • 支持 Markdown 格式, **粗体**、~~删除线~~、`单行代码`
  • 支持 @ 本站用户;支持表情(输入 : 提示),见 Emoji cheat sheet
  • 图片支持拖拽、截图粘贴等方式上传