惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

酷 壳 – CoolShell
酷 壳 – CoolShell
H
Hacker News: Front Page
P
Palo Alto Networks Blog
T
ThreatConnect
Apple Machine Learning Research
Apple Machine Learning Research
博客园_首页
T
True Tiger Recordings
P
Privacy & Cybersecurity Law Blog
B
Blog
IT之家
IT之家
Last Week in AI
Last Week in AI
F
Full Disclosure
Hacker News: Ask HN
Hacker News: Ask HN
C
Comments on: Blog
Microsoft Azure Blog
Microsoft Azure Blog
C
Cybersecurity and Infrastructure Security Agency CISA
Microsoft Security Blog
Microsoft Security Blog
博客园 - 【当耐特】
N
News and Events Feed by Topic
NISL@THU
NISL@THU
腾讯CDC
雷峰网
雷峰网
Security Latest
Security Latest
李成银的技术随笔
M
Microsoft Research Blog - Microsoft Research
L
LangChain Blog
L
Lohrmann on Cybersecurity
cs.CL updates on arXiv.org
cs.CL updates on arXiv.org
C
Check Point Blog
Y
Y Combinator Blog
Recent Announcements
Recent Announcements
博客园 - Franky
N
News | PayPal Newsroom
V
V2EX
A
About on SuperTechFans
The Register - Security
The Register - Security
月光博客
月光博客
奇客Solidot–传递最新科技情报
奇客Solidot–传递最新科技情报
Google Online Security Blog
Google Online Security Blog
MyScale Blog
MyScale Blog
Cisco Talos Blog
Cisco Talos Blog
Vercel News
Vercel News
WordPress大学
WordPress大学
C
Cyber Attacks, Cyber Crime and Cyber Security
The Hacker News
The Hacker News
IntelliJ IDEA : IntelliJ IDEA – the Leading IDE for Professional Development in Java and Kotlin | The JetBrains Blog
IntelliJ IDEA : IntelliJ IDEA – the Leading IDE for Professional Development in Java and Kotlin | The JetBrains Blog
爱范儿
爱范儿
A
Arctic Wolf
L
LINUX DO - 最新话题
freeCodeCamp Programming Tutorials: Python, JavaScript, Git & More

博客园 - AllenDang

创业心得 - 从确定投资意向到开始发工资还有多远? 什么样的人适合创业公司? NoSql数据库使用半年后在设计上面的一些心得 Go语言实战 - 使用SendCloud群发邮件 用Go语言做产品半年的一些感觉 - AllenDang 我是怎么拿到投资的 Go语言实战 - 我需要站内搜索 Go语言实战 - revel框架教程之CSRF(跨站请求伪造)保护 Go语言实战 - revel框架教程之缓存和Job Go语言实战 - 网站性能优化第一弹“七牛云存储” - AllenDang 坚持是什么? - 作为创业者在与投资人见面之后想到的 Go语言实战 - revel框架教程之MongDB的最佳搭档revmgo Go语言实战 - revel框架教程之权限控制 Go语言实战 - revel框架教程之用户注册 Go语言实战 - 创业进行时之创业伊始 我为什么喜欢Go语言 用Go写Windows桌面应用 - 使用窗体设计器 用Go写Windows桌面应用 - 使用资源文件 用Go写Windows桌面应用 - 使用Form
使用CGO封装Windows API
AllenDang · 2012-02-21 · via 博客园 - AllenDang

Go使用C的库非常简单,通过cgo这个工具基本上可以说是无缝集成了。下面就演示一下用cgo在Windows下面封装API的过程。注意,请把Go更新到最新一个Weekly版本。

首先,在$GOPATH\src(如果不知道$GOPATH是什么,请移步这里看详细信息)下面新建一个文件夹“w32api”,然后在其内新建一个文件“kernel32.go”,内容如下。

package w32api

// #define WIN32_LEAN_AND_MEAN
// #include <windows.h>
import "C"
import "syscall"

func GetCurrentDirectory() string {
    if bufLen := C.GetCurrentDirectoryW(0, nil); bufLen != 0 {
        buf := make([]uint16, bufLen)
        if bufLen := C.GetCurrentDirectoryW(bufLen, (*C.WCHAR)(&buf[0])); bufLen != 0 {
            return syscall.UTF16ToString(buf)
        }
    }
    return ""
}

保存,打开命令行,运行

go build w32api

go install w32api

此时,w32api这个包就编译完成了,用用看吧。

写一个testapp,代码如下。

package main

import "w32api"

func main() {
    println(w32api.GetCurrentDirectory())
}
运行之后应该就能看到该文件的当前目录在控制台被打印出来了。感觉如何?是不是简单到令人发指了?这就是为什么Go在很短的时间内就拥有了很多第三方库的秘密,呵呵。

现在重点介绍几个要点,先从kernel32.go的内容说起。

// #define WIN32_LEAN_AND_MEAN
// #include <windows.h>
import "C"

这三行应该很熟悉,定义了相关的宏和需要引用的头文件。这里需要注意的是 import “C” 与上一行注释之间不能有空行!否则编译会失败。

之后,就可以用"C.”去引用C库里的函数了,这个前缀还可以引用简单类型,如C.char, C.schar (signed char), C.uchar (unsigned char), C.short, C.ushort (unsigned short), C.int, C.uint (unsigned int), C.long, C.ulong (unsigned long), C.longlong (long long), C.ulonglong (unsigned long long), C.float, C.double。

如果是struct, union和enum的话,需要加上如下前缀,struct_、union_和enum_,比如 C.struct_MSG。

对于字符串的处理比较特殊,cgo提供的字符串处理函数只能处理char类型,这对于Windows上的程序员来说太不够了,因为大多数情况调用的都是Unicode方式的API。我很早之前就提过Bug,且这个Bug一度被标上了Go1的标签,但最近又被从Go1的范畴里剔除了,理由是wchar_t很少见。

没办法了,只能自己先凑活着解决吧!其实也简单,wchar_t其实对应到Go的uint16类型,所以如果要用buffer的话,可以用slice来代替,就像上面代码里写的方法。

buf := make([]uint16, bufLen)
if bufLen := C.GetCurrentDirectoryW(bufLen, (*C.WCHAR)(&buf[0])); bufLen != 0 {
    return syscall.UTF16ToString(buf)
}
如果某个函数仅仅只是返回wchar_t指针的话,可以用下面代码得到Go的string。

func UTF16PtrToString(cstr *uint16) string {
    if cstr != nil {
        us := make([]uint16, 0, 256)
        for p := uintptr(unsafe.Pointer(cstr)); ; p += 2 {
            u := *(*uint16)(unsafe.Pointer(p))
            if u == 0 {
                return string(utf16.Decode(us))
            }
            us = append(us, u)
        }
    }

    return ""
}

另外,cgo目前在windows下面仅支持配合dll使用,还无法做到静态编译*.lib。

以上就是cgo使用的初步介绍,你已经可以开始动手自己玩玩了。也许你更感兴趣的是如何用Go调用C++写的库,恩,好问题,后面我会介绍一种更加简单的封装方式——swig,这个工具大家也许已经知道了,它能自动生成封装层!尽请期待吧!