mirror of
https://github.com/golang/sys.git
synced 2026-02-08 11:46:04 +03:00
windows: add GUID handling functions
Virtually every project that works with x/sys/window's GUIDs winds up rolling their own version of this in one way or another. So let's add the correct win32 wrappers for it, so that these are always generated, parsed, and converted in the uniform correct way. Change-Id: I35f4b4ab5fc681d3e16fc5bbaf2cb20031eb3f12 Reviewed-on: https://go-review.googlesource.com/c/sys/+/180938 Run-TryBot: Jason Donenfeld <Jason@zx2c4.com> TryBot-Result: Gobot Gobot <gobot@golang.org> Reviewed-by: Brad Fitzpatrick <bradfitz@golang.org>
This commit is contained in:
committed by
Jason Donenfeld
parent
5da285871e
commit
7fc4e5ec14
@@ -286,6 +286,9 @@ func NewCallbackCDecl(fn interface{}) uintptr {
|
||||
//sys SetVolumeLabel(rootPathName *uint16, volumeName *uint16) (err error) = SetVolumeLabelW
|
||||
//sys SetVolumeMountPoint(volumeMountPoint *uint16, volumeName *uint16) (err error) = SetVolumeMountPointW
|
||||
//sys MessageBox(hwnd Handle, text *uint16, caption *uint16, boxtype uint32) (ret int32, err error) [failretval==0] = user32.MessageBoxW
|
||||
//sys clsidFromString(lpsz *uint16, pclsid *GUID) (err error) [failretval!=0] = ole32.CLSIDFromString
|
||||
//sys stringFromGUID2(rguid *GUID, lpsz *uint16, cchMax int) (chars int) = ole32.StringFromGUID2
|
||||
//sys coCreateGuid(pguid *GUID) (ret error) = ole32.CoCreateGuid
|
||||
|
||||
// syscall interface implementation for other packages
|
||||
|
||||
@@ -1241,3 +1244,39 @@ func Readlink(path string, buf []byte) (n int, err error) {
|
||||
|
||||
return n, nil
|
||||
}
|
||||
|
||||
// GUIDFromString parses a string in the form of
|
||||
// "{XXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX}" into a GUID.
|
||||
func GUIDFromString(str string) (GUID, error) {
|
||||
guid := GUID{}
|
||||
str16, err := syscall.UTF16PtrFromString(str)
|
||||
if err != nil {
|
||||
return guid, err
|
||||
}
|
||||
err = clsidFromString(str16, &guid)
|
||||
if err != nil {
|
||||
return guid, err
|
||||
}
|
||||
return guid, nil
|
||||
}
|
||||
|
||||
// GenerateGUID creates a new random GUID.
|
||||
func GenerateGUID() (GUID, error) {
|
||||
guid := GUID{}
|
||||
err := coCreateGuid(&guid)
|
||||
if err != nil {
|
||||
return guid, err
|
||||
}
|
||||
return guid, nil
|
||||
}
|
||||
|
||||
// String returns the canonical string form of the GUID,
|
||||
// in the form of "{XXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX}".
|
||||
func (guid GUID) String() string {
|
||||
var str [100]uint16
|
||||
chars := stringFromGUID2(&guid, &str[0], len(str))
|
||||
if chars <= 1 {
|
||||
return ""
|
||||
}
|
||||
return string(utf16.Decode(str[:chars-1]))
|
||||
}
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
package windows_test
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"path/filepath"
|
||||
@@ -169,3 +170,25 @@ func TestPseudoTokens(t *testing.T) {
|
||||
t.Fatal("The real process token does not have the same as the pseudo thread token after impersonating self")
|
||||
}
|
||||
}
|
||||
|
||||
func TestGUID(t *testing.T) {
|
||||
guid, err := windows.GenerateGUID()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if guid.Data1 == 0 && guid.Data2 == 0 && guid.Data3 == 0 && guid.Data4 == [8]byte{} {
|
||||
t.Fatal("Got an all zero GUID, which is overwhelmingly unlikely")
|
||||
}
|
||||
want := fmt.Sprintf("{%08X-%04X-%04X-%04X-%012X}", guid.Data1, guid.Data2, guid.Data3, guid.Data4[:2], guid.Data4[2:])
|
||||
got := guid.String()
|
||||
if got != want {
|
||||
t.Fatalf("String = %q; want %q", got, want)
|
||||
}
|
||||
guid2, err := windows.GUIDFromString(got)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if guid2 != guid {
|
||||
t.Fatalf("Did not parse string back to original GUID = %q; want %q", guid2, guid)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -42,6 +42,7 @@ var (
|
||||
modmswsock = NewLazySystemDLL("mswsock.dll")
|
||||
modcrypt32 = NewLazySystemDLL("crypt32.dll")
|
||||
moduser32 = NewLazySystemDLL("user32.dll")
|
||||
modole32 = NewLazySystemDLL("ole32.dll")
|
||||
modws2_32 = NewLazySystemDLL("ws2_32.dll")
|
||||
moddnsapi = NewLazySystemDLL("dnsapi.dll")
|
||||
modiphlpapi = NewLazySystemDLL("iphlpapi.dll")
|
||||
@@ -221,6 +222,9 @@ var (
|
||||
procSetVolumeLabelW = modkernel32.NewProc("SetVolumeLabelW")
|
||||
procSetVolumeMountPointW = modkernel32.NewProc("SetVolumeMountPointW")
|
||||
procMessageBoxW = moduser32.NewProc("MessageBoxW")
|
||||
procCLSIDFromString = modole32.NewProc("CLSIDFromString")
|
||||
procStringFromGUID2 = modole32.NewProc("StringFromGUID2")
|
||||
procCoCreateGuid = modole32.NewProc("CoCreateGuid")
|
||||
procWSAStartup = modws2_32.NewProc("WSAStartup")
|
||||
procWSACleanup = modws2_32.NewProc("WSACleanup")
|
||||
procWSAIoctl = modws2_32.NewProc("WSAIoctl")
|
||||
@@ -2406,6 +2410,32 @@ func MessageBox(hwnd Handle, text *uint16, caption *uint16, boxtype uint32) (ret
|
||||
return
|
||||
}
|
||||
|
||||
func clsidFromString(lpsz *uint16, pclsid *GUID) (err error) {
|
||||
r1, _, e1 := syscall.Syscall(procCLSIDFromString.Addr(), 2, uintptr(unsafe.Pointer(lpsz)), uintptr(unsafe.Pointer(pclsid)), 0)
|
||||
if r1 != 0 {
|
||||
if e1 != 0 {
|
||||
err = errnoErr(e1)
|
||||
} else {
|
||||
err = syscall.EINVAL
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func stringFromGUID2(rguid *GUID, lpsz *uint16, cchMax int) (chars int) {
|
||||
r0, _, _ := syscall.Syscall(procStringFromGUID2.Addr(), 3, uintptr(unsafe.Pointer(rguid)), uintptr(unsafe.Pointer(lpsz)), uintptr(cchMax))
|
||||
chars = int(r0)
|
||||
return
|
||||
}
|
||||
|
||||
func coCreateGuid(pguid *GUID) (ret error) {
|
||||
r0, _, _ := syscall.Syscall(procCoCreateGuid.Addr(), 1, uintptr(unsafe.Pointer(pguid)), 0, 0)
|
||||
if r0 != 0 {
|
||||
ret = syscall.Errno(r0)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func WSAStartup(verreq uint32, data *WSAData) (sockerr error) {
|
||||
r0, _, _ := syscall.Syscall(procWSAStartup.Addr(), 2, uintptr(verreq), uintptr(unsafe.Pointer(data)), 0)
|
||||
if r0 != 0 {
|
||||
|
||||
Reference in New Issue
Block a user