使用CGO封裝Windows API

來源:互聯網
上載者:User
這是一個建立於 的文章,其中的資訊可能已經有所發展或是發生改變。

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,這個工具大家也許已經知道了,它能自動產生封裝層!盡請期待吧!

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.