(在我看来)使用Windows DLL是直接使用Win32 API的最佳方法。
如果查看
src/syscallGo安装目录,则可以找到名为mksyscall_windows.go的文件。Go团队似乎就是这样来管理所有DLL包装器的。
使用go generate
生成的代码
看一下syscall_windows.go如何使用它。具体来说,它具有以下
gogenerate命令:
// go:generate go run mksyscall_windows.go -output zsyscall_windows.go
syscall_windows.go security_windows.go
定义Win32 API类型
然后,他们定义自己的类型。您将需要自己手动执行此操作。
有时这是一个挑战,因为保留结构字段的大小和对齐方式至关重要。我使用Visual Studio Community
Edition在Microsoft定义的众多基本类型中四处寻找,以便确定它们的Go等效项。
Windows使用UTF16作为字符串。因此,您将把它们表示为
*uint16。用于
syscall.UTF16PtrFromString从Go字符串生成一个。
注释Win32 API函数以导出
整个过程的重点
mksyscall_windows.go是生成所有样板代码,因此您最终得到一个Go函数,该函数为您调用DLL。
这可以通过添加注释(转到注释)来完成。
例如,
syscall_windows.go您具有以下注释:
//sys GetLastError() (lasterr error)//...//sys CreateHardlink(filename *uint16, existingfilename *uint16, reserved uintptr) (err error) [failretval&0xff==0] = CreateHardlinkW
mksyscall_windows.go有文档注释可帮助您了解其工作原理。您还可以在zsyscall_windows.go中查看生成的代码。
跑 go generate
它很容易,只需运行:
go generate
例:
对于您的示例,创建一个名为的文件
win32_windows.go:
package win32//go generate go run mksyscall_windows.go -output zwin32_windows.go win32_windows.gotype ( LPVOID uintptr LMSTR *uint16 DWORD uint32 LPBYTE *byte LPDWORD *uint32 LPWSTR *uint16 NET_API_STATUS DWORD USER_INFO_1 struct { Usri1_name LPWSTR Usri1_password LPWSTR Usri1_password_age DWORD Usri1_priv DWORD Usri1_home_dir LPWSTR Usri1_comment LPWSTR Usri1_flags DWORD Usri1_script_path LPWSTR } GROUP_USERS_INFO_0 struct { Grui0_name LPWSTR } USER_INFO_1003 struct { Usri1003_password LPWSTR })const ( // from LMaccess.h USER_PRIV_GUEST = 0 USER_PRIV_USER = 1 USER_PRIV_ADMIN = 2 UF_script = 0x0001 UF_ACCOUNTDISABLE = 0x0002 UF_HOMEDIR_REQUIRED = 0x0008 UF_LOCKOUT = 0x0010 UF_PASSWD_NOTREQD = 0x0020 UF_PASSWD_CANT_CHANGE = 0x0040 UF_ENCRYPTED_TEXT_PASSWORD_ALLOWED = 0x0080 UF_TEMP_DUPLICATE_ACCOUNT = 0x0100 UF_NORMAL_ACCOUNT = 0x0200 UF_INTERDOMAIN_TRUST_ACCOUNT = 0x0800 UF_WORKSTATION_TRUST_ACCOUNT = 0x1000 UF_SERVER_TRUST_ACCOUNT = 0x2000 UF_ACCOUNT_TYPE_MASK = UF_TEMP_DUPLICATE_ACCOUNT | UF_NORMAL_ACCOUNT | UF_INTERDOMAIN_TRUST_ACCOUNT | UF_WORKSTATION_TRUST_ACCOUNT | UF_SERVER_TRUST_ACCOUNT UF_DONT_EXPIRE_PASSWD = 0x10000 UF_MNS_LOGON_ACCOUNT= 0x20000 UF_SMARTCARD_REQUIRED = 0x40000 UF_TRUSTED_FOR_DELEGATION = 0x80000 UF_NOT_DELEGATED = 0x100000 UF_USE_DES_KEY_onLY = 0x200000 UF_DONT_REQUIRE_PREAUTH = 0x400000 UF_PASSWORD_EXPIRED = 0x800000 UF_TRUSTED_TO_AUTHENTICATE_FOR_DELEGATION = 0x1000000 UF_NO_AUTH_DATA_REQUIRED = 0x2000000 UF_PARTIAL_SECRETS_ACCOUNT = 0x4000000 UF_USE_AES_KEYS = 0x8000000 UF_SETTABLE_BITS = UF_script | UF_ACCOUNTDISABLE | UF_LOCKOUT | UF_HOMEDIR_REQUIRED | UF_PASSWD_NOTREQD | UF_PASSWD_CANT_CHANGE | UF_ACCOUNT_TYPE_MASK | UF_DONT_EXPIRE_PASSWD | UF_MNS_LOGON_ACCOUNT | UF_ENCRYPTED_TEXT_PASSWORD_ALLOWED | UF_SMARTCARD_REQUIRED | UF_TRUSTED_FOR_DELEGATION | UF_NOT_DELEGATED | UF_USE_DES_KEY_onLY | UF_DONT_REQUIRE_PREAUTH | UF_PASSWORD_EXPIRED | UF_TRUSTED_TO_AUTHENTICATE_FOR_DELEGATION | UF_NO_AUTH_DATA_REQUIRED | UF_USE_AES_KEYS | UF_PARTIAL_SECRETS_ACCOUNT FILTER_TEMP_DUPLICATE_ACCOUNT = (0x0001) FILTER_NORMAL_ACCOUNT = (0x0002) FILTER_INTERDOMAIN_TRUST_ACCOUNT = (0x0008) FILTER_WORKSTATION_TRUST_ACCOUNT = (0x0010) FILTER_SERVER_TRUST_ACCOUNT = (0x0020) LG_INCLUDE_INDIRECT = (0x0001) // etc...)//sys NetApiBufferFree(Buffer LPVOID) (status NET_API_STATUS) = netapi32.NetApiBufferFree//sys NetUserAdd(servername LMSTR, level DWORD, buf LPBYTE, parm_err LPDWORD) (status NET_API_STATUS) = netapi32.NetUserAdd//sys NetUserChangePassword(domainname LPCWSTR, username LPCWSTR, oldpassword LPCWSTR, newpassword LPCWSTR) (status NET_API_STATUS) = netapi32.NetUserChangePassword//sys NetUserDel(servername LPCWSTR, username LPCWSTR) (status NET_API_STATUS) = netapi32.NetUserDel//sys NetUserEnum(servername LPCWSTR, level DWORD, filter DWORD, bufptr *LPBYTE, prefmaxlen DWORD, entriesread LPDWORD, totalentries LPDWORD, resume_handle LPDWORD) (status NET_API_STATUS) = netapi32.NetUserEnum//sys NetUserGetGroups(servername LPCWSTR, username LPCWSTR, level DWORD, bufptr *LPBYTE, prefmaxlen DWORD, entriesread LPDWORD, totalentries LPDWORD) (status NET_API_STATUS) = netapi32.NetUserGetGroups//sys NetUserSetGroups(servername LPCWSTR, username LPCWSTR, level DWORD, buf LPBYTE, num_entries DWORD) (status NET_API_STATUS) = netapi32.NetUserSetGroups//sys NetUserSetInfo(servername LPCWSTR, username LPCWSTR, level DWORD, buf LPBYTE, parm_err LPDWORD) (status NET_API_STATUS) = netapi32.NetUserSetInfo运行后
go generate(只要您复制
mksyscall_windows.go到同一目录),您将拥有一个名为“
zwin32_windows.go”的文件(类似这样):
// MACHINE GENERATED BY 'go generate' COMMAND; DO NOT EDITpackage win32import "unsafe"import "syscall"var _ unsafe.Pointervar ( modnetapi32 = syscall.NewLazyDLL("netapi32.dll") procNetApiBufferFree = modnetapi32.NewProc("NetApiBufferFree") procNetUserAdd = modnetapi32.NewProc("NetUserAdd") procNetUserChangePassword = modnetapi32.NewProc("NetUserChangePassword") procNetUserDel = modnetapi32.NewProc("NetUserDel") procNetUserEnum= modnetapi32.NewProc("NetUserEnum") procNetUserGetGroups = modnetapi32.NewProc("NetUserGetGroups") procNetUserSetGroups = modnetapi32.NewProc("NetUserSetGroups") procNetUserSetInfo = modnetapi32.NewProc("NetUserSetInfo"))func NetApiBufferFree(Buffer LPVOID) (status NET_API_STATUS) { r0, _, _ := syscall.Syscall(procNetApiBufferFree.Addr(), 1, uintptr(Buffer), 0, 0) status = NET_API_STATUS(r0) return}func NetUserAdd(servername LMSTR, level DWORD, buf LPBYTE, parm_err LPDWORD) (status NET_API_STATUS) { r0, _, _ := syscall.Syscall6(procNetUserAdd.Addr(), 4, uintptr(servername), uintptr(level), uintptr(buf), uintptr(parm_err), 0, 0) status = NET_API_STATUS(r0) return}func NetUserChangePassword(domainname LPCWSTR, username LPCWSTR, oldpassword LPCWSTR, newpassword LPCWSTR) (status NET_API_STATUS) { r0, _, _ := syscall.Syscall6(procNetUserChangePassword.Addr(), 4, uintptr(domainname), uintptr(username), uintptr(oldpassword), uintptr(newpassword), 0, 0) status = NET_API_STATUS(r0) return}func NetUserDel(servername LPCWSTR, username LPCWSTR) (status NET_API_STATUS) { r0, _, _ := syscall.Syscall(procNetUserDel.Addr(), 2, uintptr(servername), uintptr(username), 0) status = NET_API_STATUS(r0) return}func NetUserEnum(servername LPCWSTR, level DWORD, filter DWORD, bufptr *LPBYTE, prefmaxlen DWORD, entriesread LPDWORD, totalentries LPDWORD, resume_handle LPDWORD) (status NET_API_STATUS) { r0, _, _ := syscall.Syscall9(procNetUserEnum.Addr(), 8, uintptr(servername), uintptr(level), uintptr(filter), uintptr(unsafe.Pointer(bufptr)), uintptr(prefmaxlen), uintptr(entriesread), uintptr(totalentries), uintptr(resume_handle), 0) status = NET_API_STATUS(r0) return}func NetUserGetGroups(servername LPCWSTR, username LPCWSTR, level DWORD, bufptr *LPBYTE, prefmaxlen DWORD, entriesread LPDWORD, totalentries LPDWORD) (status NET_API_STATUS) { r0, _, _ := syscall.Syscall9(procNetUserGetGroups.Addr(), 7, uintptr(servername), uintptr(username), uintptr(level), uintptr(unsafe.Pointer(bufptr)), uintptr(prefmaxlen), uintptr(entriesread), uintptr(totalentries), 0, 0) status = NET_API_STATUS(r0) return}func NetUserSetGroups(servername LPCWSTR, username LPCWSTR, level DWORD, buf LPBYTE, num_entries DWORD) (status NET_API_STATUS) { r0, _, _ := syscall.Syscall6(procNetUserSetGroups.Addr(), 5, uintptr(servername), uintptr(username), uintptr(level), uintptr(buf), uintptr(num_entries), 0) status = NET_API_STATUS(r0) return}func NetUserSetInfo(servername LPCWSTR, username LPCWSTR, level DWORD, buf LPBYTE, parm_err LPDWORD) (status NET_API_STATUS) { r0, _, _ := syscall.Syscall6(procNetUserSetInfo.Addr(), 5, uintptr(servername), uintptr(username), uintptr(level), uintptr(buf), uintptr(parm_err), 0) status = NET_API_STATUS(r0) return}显然,大多数工作是将Win32类型转换为它们的Go等效项。
随意浏览
syscall包装-它们通常已经定义了您可能感兴趣的结构。
ZOMG认真地?? 1!2多工作!
比手动编写代码要好。而且不需要CGo!
声明: 我还没有测试上面的代码来验证它是否确实满足您的要求。使用Win32 API本身就是一件很有趣的事情。



