Go调用SDL2的C语言动态库

栏目: C · 发布时间: 4年前

内容简介:在网上找到go的GUI项目基本都需要安装额外软件库,尝试了一下使用go调用dll库的,有所收获,抛砖引玉,留个记录怕以后忘了。

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()
}

Go调用SDL2的C语言动态库


以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

Inside Larry's and Sergey's Brain

Inside Larry's and Sergey's Brain

Richard Brandt / Portfolio / 17 Sep 2009 / USD 24.95

You’ve used their products. You’ve heard about their skyrocketing wealth and “don’t be evil” business motto. But how much do you really know about Google’s founders, Larry Page and Sergey Brin? Inside......一起来看看 《Inside Larry's and Sergey's Brain》 这本书的介绍吧!

JSON 在线解析
JSON 在线解析

在线 JSON 格式化工具

XML、JSON 在线转换
XML、JSON 在线转换

在线XML、JSON转换工具

HEX HSV 转换工具
HEX HSV 转换工具

HEX HSV 互换工具