golang调用Windows API

Table of Contents

    golang还能调用Windows API非常有意思,下面写了一个golang换壁纸的demo。 准备了两张bmp格式的图片,没三秒钟换一下壁纸。

    主要是先通过dll获取里面api,要注意api参数的写法,dll用完了要释放句柄,这里我用缓存把api缓存起来不必每次调用都去dll里加载。

    代码:

    package main
    
    import (
    	"log"
    	"syscall"
    	"time"
    	"unsafe"
    )
    
    var ApiList = map[string][]string {
    	"user32.dll": []string {
    		"MessageBoxW",
    		"SystemParametersInfoW",
    	},
    	"kernel32.dll": []string {
    
    	},
    }
    
    var ProcCache map[string]*syscall.Proc
    
    func init() {
    	ProcCache = make(map[string]*syscall.Proc)
    	for dllName, apiList := range ApiList {
    		d, err := syscall.LoadDLL(dllName)
    		if err != nil {
    			panic(err)
    		}
    
    		for _, name := range apiList {
    			api, err := d.FindProc(name)
    			if err != nil {
    				syscall.FreeLibrary(d.Handle)
    				panic(err)
    			}
    			ProcCache[name] = api
    		}
    		syscall.FreeLibrary(d.Handle)
    	}
    }
    
    func WinCall(name string, a ...uintptr) {
    	if api, ok := ProcCache[name]; ok {
    		_, _, err := api.Call(a...)
    		if err != nil {
    			log.Println(err)
    		}
    	} else {
    		log.Println("api not found, name:", name)
    	}
    }
    
    func IntPtr(n int) uintptr {
    	return uintptr(n)
    }
    
    func StrPtr(s string) uintptr {
    	p, _ := syscall.UTF16PtrFromString(s)
    	return uintptr(unsafe.Pointer(p))
    }
    
    func ShowMessage(title, text string) {
    	WinCall("MessageBoxW", IntPtr(0), StrPtr(text), StrPtr(title), IntPtr(0))
    }
    
    func SetWallpaper(bmpPath string) {
    	WinCall("SystemParametersInfoW", IntPtr(20), IntPtr(0), StrPtr(bmpPath), IntPtr(3))
    }
    
    func main() {
    	for i := 0; i < 10; i++ {
    		SetWallpaper("E:\\CppProject\\WindowsProject1\\test.bmp")
    		time.Sleep(3 * time.Second)
    		SetWallpaper("E:\\CppProject\\WindowsProject1\\test2.bmp")
    		time.Sleep(3 * time.Second)
    	}
    }