Golang通过syscall调用win32的Api

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

What you are wasting today is tomorrow for those who died yesterday; what you hate now is the future you can not go back.

你所浪费的今天是昨天死去的人奢望的明天; 你所厌恶的现在是未来的你回不去的曾经。 

 Golang不是完全的跨平台, 并没有提供Windows下的相关方法,只能通过Syscall包去调用Win库。

开始

    如果你不了解Windows下API调用,请观看MSDN文档,我知道有些人找不到,没关系:

1. 英文版: https://msdn.microsoft.com/en-us/library/windows/desktop/hh447209(v=vs.85)

2. 中文版本:http://www.office-cn.net/t/api/api_content.htm

(仅作参考,还有其他中文版本就不一一列举了)

Golang syscall包

syscall包下面有5个关于系统调用的方法,分别表示调用参数的个数。 (golang文档上可能没有,请查询其他文档或直接在IDE中查看)

func Syscall(trap, nargs, a1, a2, a3 uintptr) (r1, r2 uintptr, err Errno)
func Syscall6(trap, nargs, a1, a2, a3, a4, a5, a6 uintptr) (r1, r2 uintptr, err Errno)
func Syscall9(trap, nargs, a1, a2, a3, a4, a5, a6, a7, a8, a9 uintptr) (r1, r2 uintptr, err Errno)
func Syscall12(trap, nargs, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12 uintptr) (r1, r2 uintptr, err Errno)
func Syscall15(trap, nargs, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15 uintptr) (r1, r2 uintptr, err Errno)

第二个参数, nargs 即参数的个数,一旦传错, 轻则调用失败,重者直接崩溃 多余的参数, 用0代替。

小实例

    获取磁盘的空间

package main

import (
	"syscall"
	"unsafe"
	"fmt"
)

func main(){
	getDiskGreeSpace()
}

/**
获取磁盘空间
 */
func getDiskGreeSpace(){
	// 磁盘
	diskName := "E:"
	diskNameUtf16Ptr , _:= syscall.UTF16PtrFromString(diskName)
	// 一下参数类型需要跟API 的类型相符
	lpFreeBytesAvailable ,lpTotalNumberOfBytes,
	lpTotalNumberOfFreeBytes := int64(0),int64(0),int64(0)

	// 获取方法引用
	kernel32 , err := syscall.LoadLibrary("kernel32.dll")
	if err != nil{
		panic("获取方法引用失败:")
	}
	// 释放引用
	defer syscall.FreeLibrary(kernel32)


	getDisFreeSpaceEx , err := syscall.GetProcAddress(kernel32, "GetDiskFreeSpaceExW")
	if err != nil{
		panic("失败1")
	}

	// 根据参数个数使用对象SyscallN方法, 只需要4个参数
	r , _ , errno := syscall.Syscall6(uintptr(getDisFreeSpaceEx), 4,
			uintptr(unsafe.Pointer(diskNameUtf16Ptr)), //
			uintptr(unsafe.Pointer(&lpFreeBytesAvailable)),
			uintptr(unsafe.Pointer(&lpTotalNumberOfBytes)),
			uintptr(unsafe.Pointer(&lpTotalNumberOfFreeBytes)),
			0, 0)
	// 此处的errno不是error接口, 而是type Errno uintptr
	// MSDN GetDiskFreeSpaceEx function 文档说明:
	// Return value
	// 		If the function succeeds, the return value is nonzero.
	// 		If the function fails, the return value is zero (0). To get extended error information, call GetLastError.
	// 只要是0 就是错误
	if  r!= 0{
		fmt.Printf("剩余空间 %d M.\n", lpFreeBytesAvailable/1024/1204)
		fmt.Printf("用户可用总空间 %d G.\n", lpTotalNumberOfBytes/1024/1204/1024)
		fmt.Printf("剩余空间2 %d M.\n", lpTotalNumberOfFreeBytes/1024/1204)
	}else{
		fmt.Println("失败2")
		panic(errno)
	}
}

首先现将MSDN官方的文档贴出来,方便一下解释:

https://msdn.microsoft.com/en-us/library/windows/desktop/aa364937(v=vs.85)

BOOL WINAPI GetDiskFreeSpaceEx(
  _In_opt_  LPCTSTR         lpDirectoryName,
  _Out_opt_ PULARGE_INTEGER lpFreeBytesAvailable,
  _Out_opt_ PULARGE_INTEGER lpTotalNumberOfBytes,
  _Out_opt_ PULARGE_INTEGER lpTotalNumberOfFreeBytes
);

解释:

1. 将磁盘的名称转为*UTF16类型,

 LPCTSTR类型:

L表示long指针 这是为了兼容Windows 3.1等16位操作系统遗留下来的,在win32中以及其他的32位操作系统中, long指针和near指针及far修饰符都是为了兼容的作用。没有实际意义。

P表示这是一个指针

C表示是一个常量

T表示在Win32环境中, 有一个_T宏

STR表示这个变量是一个字符串

这是了解一下就好了。

2.  PULARGE_INTEGER 是存储了64位数据的一种类型。

3. GetProcAddress中GetDiskFreeSpaceExW多了一个W具体是啥意思呢?请留言

简单记录一下,要熟悉MSDN API 文档可能写起来顺手多了。

 

 

 

 


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

本文来自:开源中国博客

感谢作者:90design

查看原文:Golang通过syscall调用win32的Api

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

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