golang.org/x/sys@v0.9.0/windows/syscall_windows_test.go (about)

     1  // Copyright 2012 The Go Authors. All rights reserved.
     2  // Use of this source code is governed by a BSD-style
     3  // license that can be found in the LICENSE file.
     4  
     5  package windows_test
     6  
     7  import (
     8  	"bufio"
     9  	"bytes"
    10  	"debug/pe"
    11  	"errors"
    12  	"fmt"
    13  	"io/ioutil"
    14  	"math/rand"
    15  	"os"
    16  	"path/filepath"
    17  	"runtime"
    18  	"strconv"
    19  	"strings"
    20  	"syscall"
    21  	"testing"
    22  	"time"
    23  	"unsafe"
    24  
    25  	"golang.org/x/sys/internal/unsafeheader"
    26  	"golang.org/x/sys/windows"
    27  )
    28  
    29  func TestWin32finddata(t *testing.T) {
    30  	dir, err := ioutil.TempDir("", "go-build")
    31  	if err != nil {
    32  		t.Fatalf("failed to create temp directory: %v", err)
    33  	}
    34  	defer os.RemoveAll(dir)
    35  
    36  	path := filepath.Join(dir, "long_name.and_extension")
    37  	f, err := os.Create(path)
    38  	if err != nil {
    39  		t.Fatalf("failed to create %v: %v", path, err)
    40  	}
    41  	f.Close()
    42  
    43  	type X struct {
    44  		fd  windows.Win32finddata
    45  		got byte
    46  		pad [10]byte // to protect ourselves
    47  
    48  	}
    49  	var want byte = 2 // it is unlikely to have this character in the filename
    50  	x := X{got: want}
    51  
    52  	pathp, _ := windows.UTF16PtrFromString(path)
    53  	h, err := windows.FindFirstFile(pathp, &(x.fd))
    54  	if err != nil {
    55  		t.Fatalf("FindFirstFile failed: %v", err)
    56  	}
    57  	err = windows.FindClose(h)
    58  	if err != nil {
    59  		t.Fatalf("FindClose failed: %v", err)
    60  	}
    61  
    62  	if x.got != want {
    63  		t.Fatalf("memory corruption: want=%d got=%d", want, x.got)
    64  	}
    65  }
    66  
    67  func TestFormatMessage(t *testing.T) {
    68  	dll := windows.MustLoadDLL("netevent.dll")
    69  
    70  	const TITLE_SC_MESSAGE_BOX uint32 = 0xC0001B75
    71  	const flags uint32 = syscall.FORMAT_MESSAGE_FROM_HMODULE | syscall.FORMAT_MESSAGE_ARGUMENT_ARRAY | syscall.FORMAT_MESSAGE_IGNORE_INSERTS
    72  	buf := make([]uint16, 300)
    73  	_, err := windows.FormatMessage(flags, uintptr(dll.Handle), TITLE_SC_MESSAGE_BOX, 0, buf, nil)
    74  	if err != nil {
    75  		t.Fatalf("FormatMessage for handle=%x and errno=%x failed: %v", dll.Handle, TITLE_SC_MESSAGE_BOX, err)
    76  	}
    77  }
    78  
    79  func abort(funcname string, err error) {
    80  	panic(funcname + " failed: " + err.Error())
    81  }
    82  
    83  func ExampleLoadLibrary() {
    84  	h, err := windows.LoadLibrary("kernel32.dll")
    85  	if err != nil {
    86  		abort("LoadLibrary", err)
    87  	}
    88  	defer windows.FreeLibrary(h)
    89  	proc, err := windows.GetProcAddress(h, "GetVersion")
    90  	if err != nil {
    91  		abort("GetProcAddress", err)
    92  	}
    93  	r, _, _ := syscall.Syscall(uintptr(proc), 0, 0, 0, 0)
    94  	major := byte(r)
    95  	minor := uint8(r >> 8)
    96  	build := uint16(r >> 16)
    97  	print("windows version ", major, ".", minor, " (Build ", build, ")\n")
    98  }
    99  
   100  func TestTOKEN_ALL_ACCESS(t *testing.T) {
   101  	if windows.TOKEN_ALL_ACCESS != 0xF01FF {
   102  		t.Errorf("TOKEN_ALL_ACCESS = %x, want 0xF01FF", windows.TOKEN_ALL_ACCESS)
   103  	}
   104  }
   105  
   106  func TestCreateWellKnownSid(t *testing.T) {
   107  	sid, err := windows.CreateWellKnownSid(windows.WinBuiltinAdministratorsSid)
   108  	if err != nil {
   109  		t.Fatalf("Unable to create well known sid for administrators: %v", err)
   110  	}
   111  	if got, want := sid.String(), "S-1-5-32-544"; got != want {
   112  		t.Fatalf("Builtin Administrators SID = %s, want %s", got, want)
   113  	}
   114  }
   115  
   116  func TestPseudoTokens(t *testing.T) {
   117  	version, err := windows.GetVersion()
   118  	if err != nil {
   119  		t.Fatal(err)
   120  	}
   121  	if ((version&0xffff)>>8)|((version&0xff)<<8) < 0x0602 {
   122  		return
   123  	}
   124  
   125  	realProcessToken, err := windows.OpenCurrentProcessToken()
   126  	if err != nil {
   127  		t.Fatal(err)
   128  	}
   129  	defer realProcessToken.Close()
   130  	realProcessUser, err := realProcessToken.GetTokenUser()
   131  	if err != nil {
   132  		t.Fatal(err)
   133  	}
   134  
   135  	pseudoProcessToken := windows.GetCurrentProcessToken()
   136  	pseudoProcessUser, err := pseudoProcessToken.GetTokenUser()
   137  	if err != nil {
   138  		t.Fatal(err)
   139  	}
   140  	if !windows.EqualSid(realProcessUser.User.Sid, pseudoProcessUser.User.Sid) {
   141  		t.Fatal("The real process token does not have the same as the pseudo process token")
   142  	}
   143  
   144  	runtime.LockOSThread()
   145  	defer runtime.UnlockOSThread()
   146  
   147  	err = windows.RevertToSelf()
   148  	if err != nil {
   149  		t.Fatal(err)
   150  	}
   151  
   152  	pseudoThreadToken := windows.GetCurrentThreadToken()
   153  	_, err = pseudoThreadToken.GetTokenUser()
   154  	if err != windows.ERROR_NO_TOKEN {
   155  		t.Fatal("Expected an empty thread token")
   156  	}
   157  	pseudoThreadEffectiveToken := windows.GetCurrentThreadEffectiveToken()
   158  	pseudoThreadEffectiveUser, err := pseudoThreadEffectiveToken.GetTokenUser()
   159  	if err != nil {
   160  		t.Fatal(nil)
   161  	}
   162  	if !windows.EqualSid(realProcessUser.User.Sid, pseudoThreadEffectiveUser.User.Sid) {
   163  		t.Fatal("The real process token does not have the same as the pseudo thread effective token, even though we aren't impersonating")
   164  	}
   165  
   166  	err = windows.ImpersonateSelf(windows.SecurityImpersonation)
   167  	if err != nil {
   168  		t.Fatal(err)
   169  	}
   170  	defer windows.RevertToSelf()
   171  	pseudoThreadUser, err := pseudoThreadToken.GetTokenUser()
   172  	if err != nil {
   173  		t.Fatal(err)
   174  	}
   175  	if !windows.EqualSid(realProcessUser.User.Sid, pseudoThreadUser.User.Sid) {
   176  		t.Fatal("The real process token does not have the same as the pseudo thread token after impersonating self")
   177  	}
   178  }
   179  
   180  func TestGUID(t *testing.T) {
   181  	guid, err := windows.GenerateGUID()
   182  	if err != nil {
   183  		t.Fatal(err)
   184  	}
   185  	if guid.Data1 == 0 && guid.Data2 == 0 && guid.Data3 == 0 && guid.Data4 == [8]byte{} {
   186  		t.Fatal("Got an all zero GUID, which is overwhelmingly unlikely")
   187  	}
   188  	want := fmt.Sprintf("{%08X-%04X-%04X-%04X-%012X}", guid.Data1, guid.Data2, guid.Data3, guid.Data4[:2], guid.Data4[2:])
   189  	got := guid.String()
   190  	if got != want {
   191  		t.Fatalf("String = %q; want %q", got, want)
   192  	}
   193  	guid2, err := windows.GUIDFromString(got)
   194  	if err != nil {
   195  		t.Fatal(err)
   196  	}
   197  	if guid2 != guid {
   198  		t.Fatalf("Did not parse string back to original GUID = %q; want %q", guid2, guid)
   199  	}
   200  	_, err = windows.GUIDFromString("not-a-real-guid")
   201  	if err != syscall.Errno(windows.CO_E_CLASSSTRING) {
   202  		t.Fatalf("Bad GUID string error = %v; want CO_E_CLASSSTRING", err)
   203  	}
   204  }
   205  
   206  func TestKnownFolderPath(t *testing.T) {
   207  	token, err := windows.OpenCurrentProcessToken()
   208  	if err != nil {
   209  		t.Fatal(err)
   210  	}
   211  	defer token.Close()
   212  	profileDir, err := token.GetUserProfileDirectory()
   213  	if err != nil {
   214  		t.Fatal(err)
   215  	}
   216  	want := filepath.Join(profileDir, "Desktop")
   217  	got, err := windows.KnownFolderPath(windows.FOLDERID_Desktop, windows.KF_FLAG_DEFAULT)
   218  	if err != nil {
   219  		t.Fatal(err)
   220  	}
   221  	if want != got {
   222  		t.Fatalf("Path = %q; want %q", got, want)
   223  	}
   224  }
   225  
   226  func TestRtlGetVersion(t *testing.T) {
   227  	version := windows.RtlGetVersion()
   228  	major, minor, build := windows.RtlGetNtVersionNumbers()
   229  	// Go is not explictly added to the application compatibility database, so
   230  	// these two functions should return the same thing.
   231  	if version.MajorVersion != major || version.MinorVersion != minor || version.BuildNumber != build {
   232  		t.Fatalf("%d.%d.%d != %d.%d.%d", version.MajorVersion, version.MinorVersion, version.BuildNumber, major, minor, build)
   233  	}
   234  }
   235  
   236  func TestGetNamedSecurityInfo(t *testing.T) {
   237  	path, err := windows.GetSystemDirectory()
   238  	if err != nil {
   239  		t.Fatal(err)
   240  	}
   241  	sd, err := windows.GetNamedSecurityInfo(path, windows.SE_FILE_OBJECT, windows.OWNER_SECURITY_INFORMATION)
   242  	if err != nil {
   243  		t.Fatal(err)
   244  	}
   245  	if !sd.IsValid() {
   246  		t.Fatal("Invalid security descriptor")
   247  	}
   248  	sdOwner, _, err := sd.Owner()
   249  	if err != nil {
   250  		t.Fatal(err)
   251  	}
   252  	if !sdOwner.IsValid() {
   253  		t.Fatal("Invalid security descriptor owner")
   254  	}
   255  }
   256  
   257  func TestGetSecurityInfo(t *testing.T) {
   258  	sd, err := windows.GetSecurityInfo(windows.CurrentProcess(), windows.SE_KERNEL_OBJECT, windows.DACL_SECURITY_INFORMATION)
   259  	if err != nil {
   260  		t.Fatal(err)
   261  	}
   262  	if !sd.IsValid() {
   263  		t.Fatal("Invalid security descriptor")
   264  	}
   265  	sdStr := sd.String()
   266  	if !strings.HasPrefix(sdStr, "D:(A;") {
   267  		t.Fatalf("DACL = %q; want D:(A;...", sdStr)
   268  	}
   269  }
   270  
   271  func TestSddlConversion(t *testing.T) {
   272  	sd, err := windows.SecurityDescriptorFromString("O:BA")
   273  	if err != nil {
   274  		t.Fatal(err)
   275  	}
   276  	if !sd.IsValid() {
   277  		t.Fatal("Invalid security descriptor")
   278  	}
   279  	sdOwner, _, err := sd.Owner()
   280  	if err != nil {
   281  		t.Fatal(err)
   282  	}
   283  	if !sdOwner.IsValid() {
   284  		t.Fatal("Invalid security descriptor owner")
   285  	}
   286  	if !sdOwner.IsWellKnown(windows.WinBuiltinAdministratorsSid) {
   287  		t.Fatalf("Owner = %q; want S-1-5-32-544", sdOwner)
   288  	}
   289  }
   290  
   291  func TestBuildSecurityDescriptor(t *testing.T) {
   292  	const want = "O:SYD:(A;;GA;;;BA)"
   293  
   294  	adminSid, err := windows.CreateWellKnownSid(windows.WinBuiltinAdministratorsSid)
   295  	if err != nil {
   296  		t.Fatal(err)
   297  	}
   298  	systemSid, err := windows.CreateWellKnownSid(windows.WinLocalSystemSid)
   299  	if err != nil {
   300  		t.Fatal(err)
   301  	}
   302  
   303  	access := []windows.EXPLICIT_ACCESS{{
   304  		AccessPermissions: windows.GENERIC_ALL,
   305  		AccessMode:        windows.GRANT_ACCESS,
   306  		Trustee: windows.TRUSTEE{
   307  			TrusteeForm:  windows.TRUSTEE_IS_SID,
   308  			TrusteeType:  windows.TRUSTEE_IS_GROUP,
   309  			TrusteeValue: windows.TrusteeValueFromSID(adminSid),
   310  		},
   311  	}}
   312  	owner := &windows.TRUSTEE{
   313  		TrusteeForm:  windows.TRUSTEE_IS_SID,
   314  		TrusteeType:  windows.TRUSTEE_IS_USER,
   315  		TrusteeValue: windows.TrusteeValueFromSID(systemSid),
   316  	}
   317  
   318  	sd, err := windows.BuildSecurityDescriptor(owner, nil, access, nil, nil)
   319  	if err != nil {
   320  		t.Fatal(err)
   321  	}
   322  	sd, err = sd.ToAbsolute()
   323  	if err != nil {
   324  		t.Fatal(err)
   325  	}
   326  	err = sd.SetSACL(nil, false, false)
   327  	if err != nil {
   328  		t.Fatal(err)
   329  	}
   330  	if got := sd.String(); got != want {
   331  		t.Fatalf("SD = %q; want %q", got, want)
   332  	}
   333  	sd, err = sd.ToSelfRelative()
   334  	if err != nil {
   335  		t.Fatal(err)
   336  	}
   337  	if got := sd.String(); got != want {
   338  		t.Fatalf("SD = %q; want %q", got, want)
   339  	}
   340  
   341  	sd, err = windows.NewSecurityDescriptor()
   342  	if err != nil {
   343  		t.Fatal(err)
   344  	}
   345  	acl, err := windows.ACLFromEntries(access, nil)
   346  	if err != nil {
   347  		t.Fatal(err)
   348  	}
   349  	err = sd.SetDACL(acl, true, false)
   350  	if err != nil {
   351  		t.Fatal(err)
   352  	}
   353  	err = sd.SetOwner(systemSid, false)
   354  	if err != nil {
   355  		t.Fatal(err)
   356  	}
   357  	if got := sd.String(); got != want {
   358  		t.Fatalf("SD = %q; want %q", got, want)
   359  	}
   360  	sd, err = sd.ToSelfRelative()
   361  	if err != nil {
   362  		t.Fatal(err)
   363  	}
   364  	if got := sd.String(); got != want {
   365  		t.Fatalf("SD = %q; want %q", got, want)
   366  	}
   367  }
   368  
   369  func TestGetDiskFreeSpaceEx(t *testing.T) {
   370  	cwd, err := windows.UTF16PtrFromString(".")
   371  	if err != nil {
   372  		t.Fatalf(`failed to call UTF16PtrFromString("."): %v`, err)
   373  	}
   374  	var freeBytesAvailableToCaller, totalNumberOfBytes, totalNumberOfFreeBytes uint64
   375  	if err := windows.GetDiskFreeSpaceEx(cwd, &freeBytesAvailableToCaller, &totalNumberOfBytes, &totalNumberOfFreeBytes); err != nil {
   376  		t.Fatalf("failed to call GetDiskFreeSpaceEx: %v", err)
   377  	}
   378  
   379  	if freeBytesAvailableToCaller == 0 {
   380  		t.Errorf("freeBytesAvailableToCaller: got 0; want > 0")
   381  	}
   382  	if totalNumberOfBytes == 0 {
   383  		t.Errorf("totalNumberOfBytes: got 0; want > 0")
   384  	}
   385  	if totalNumberOfFreeBytes == 0 {
   386  		t.Errorf("totalNumberOfFreeBytes: got 0; want > 0")
   387  	}
   388  }
   389  
   390  func TestGetPreferredUILanguages(t *testing.T) {
   391  	tab := map[string]func(flags uint32) ([]string, error){
   392  		"GetProcessPreferredUILanguages": windows.GetProcessPreferredUILanguages,
   393  		"GetThreadPreferredUILanguages":  windows.GetThreadPreferredUILanguages,
   394  		"GetUserPreferredUILanguages":    windows.GetUserPreferredUILanguages,
   395  		"GetSystemPreferredUILanguages":  windows.GetSystemPreferredUILanguages,
   396  	}
   397  	for fName, f := range tab {
   398  		lang, err := f(windows.MUI_LANGUAGE_ID)
   399  		if err != nil {
   400  			t.Errorf(`failed to call %v(MUI_LANGUAGE_ID): %v`, fName, err)
   401  		}
   402  		for _, l := range lang {
   403  			_, err := strconv.ParseUint(l, 16, 16)
   404  			if err != nil {
   405  				t.Errorf(`%v(MUI_LANGUAGE_ID) returned unexpected LANGID: %v`, fName, l)
   406  			}
   407  		}
   408  
   409  		lang, err = f(windows.MUI_LANGUAGE_NAME)
   410  		if err != nil {
   411  			t.Errorf(`failed to call %v(MUI_LANGUAGE_NAME): %v`, fName, err)
   412  		}
   413  	}
   414  }
   415  
   416  func TestProcessWorkingSetSizeEx(t *testing.T) {
   417  	// Grab a handle to the current process
   418  	hProcess := windows.CurrentProcess()
   419  
   420  	// Allocate memory to store the result of the query
   421  	var minimumWorkingSetSize, maximumWorkingSetSize uintptr
   422  
   423  	// Make the system-call
   424  	var flag uint32
   425  	windows.GetProcessWorkingSetSizeEx(hProcess, &minimumWorkingSetSize, &maximumWorkingSetSize, &flag)
   426  
   427  	// Set the new limits to the current ones
   428  	if err := windows.SetProcessWorkingSetSizeEx(hProcess, minimumWorkingSetSize, maximumWorkingSetSize, flag); err != nil {
   429  		t.Error(err)
   430  	}
   431  }
   432  
   433  func TestJobObjectInfo(t *testing.T) {
   434  	jo, err := windows.CreateJobObject(nil, nil)
   435  	if err != nil {
   436  		t.Fatalf("CreateJobObject failed: %v", err)
   437  	}
   438  	defer windows.CloseHandle(jo)
   439  
   440  	var info windows.JOBOBJECT_EXTENDED_LIMIT_INFORMATION
   441  
   442  	err = windows.QueryInformationJobObject(jo, windows.JobObjectExtendedLimitInformation,
   443  		uintptr(unsafe.Pointer(&info)), uint32(unsafe.Sizeof(info)), nil)
   444  	if err != nil {
   445  		t.Fatalf("QueryInformationJobObject failed: %v", err)
   446  	}
   447  
   448  	const wantMemLimit = 4 * 1024
   449  
   450  	info.BasicLimitInformation.LimitFlags |= windows.JOB_OBJECT_LIMIT_PROCESS_MEMORY
   451  	info.ProcessMemoryLimit = wantMemLimit
   452  	_, err = windows.SetInformationJobObject(jo, windows.JobObjectExtendedLimitInformation,
   453  		uintptr(unsafe.Pointer(&info)), uint32(unsafe.Sizeof(info)))
   454  	if err != nil {
   455  		t.Fatalf("SetInformationJobObject failed: %v", err)
   456  	}
   457  
   458  	err = windows.QueryInformationJobObject(jo, windows.JobObjectExtendedLimitInformation,
   459  		uintptr(unsafe.Pointer(&info)), uint32(unsafe.Sizeof(info)), nil)
   460  	if err != nil {
   461  		t.Fatalf("QueryInformationJobObject failed: %v", err)
   462  	}
   463  
   464  	if have := info.ProcessMemoryLimit; wantMemLimit != have {
   465  		t.Errorf("ProcessMemoryLimit is wrong: want %v have %v", wantMemLimit, have)
   466  	}
   467  }
   468  
   469  func TestIsWow64Process2(t *testing.T) {
   470  	var processMachine, nativeMachine uint16
   471  	err := windows.IsWow64Process2(windows.CurrentProcess(), &processMachine, &nativeMachine)
   472  	if errors.Is(err, windows.ERROR_PROC_NOT_FOUND) {
   473  		maj, min, build := windows.RtlGetNtVersionNumbers()
   474  		if maj < 10 || (maj == 10 && min == 0 && build < 17763) {
   475  			t.Skip("not available on older versions of Windows")
   476  			return
   477  		}
   478  	}
   479  	if err != nil {
   480  		t.Fatalf("IsWow64Process2 failed: %v", err)
   481  	}
   482  	if processMachine == pe.IMAGE_FILE_MACHINE_UNKNOWN {
   483  		processMachine = nativeMachine
   484  	}
   485  	switch {
   486  	case processMachine == pe.IMAGE_FILE_MACHINE_AMD64 && runtime.GOARCH == "amd64":
   487  	case processMachine == pe.IMAGE_FILE_MACHINE_I386 && runtime.GOARCH == "386":
   488  	case processMachine == pe.IMAGE_FILE_MACHINE_ARMNT && runtime.GOARCH == "arm":
   489  	case processMachine == pe.IMAGE_FILE_MACHINE_ARM64 && runtime.GOARCH == "arm64":
   490  	default:
   491  		t.Errorf("IsWow64Process2 is wrong: want %v have %v", runtime.GOARCH, processMachine)
   492  	}
   493  }
   494  
   495  func TestNTStatusString(t *testing.T) {
   496  	want := "The name limit for the local computer network adapter card was exceeded."
   497  	got := windows.STATUS_TOO_MANY_NAMES.Error()
   498  	if want != got {
   499  		t.Errorf("NTStatus.Error did not return an expected error string - want %q; got %q", want, got)
   500  	}
   501  }
   502  
   503  func TestNTStatusConversion(t *testing.T) {
   504  	want := windows.ERROR_TOO_MANY_NAMES
   505  	got := windows.STATUS_TOO_MANY_NAMES.Errno()
   506  	if want != got {
   507  		t.Errorf("NTStatus.Errno = %q (0x%x); want %q (0x%x)", got.Error(), got, want.Error(), want)
   508  	}
   509  }
   510  
   511  func TestPEBFilePath(t *testing.T) {
   512  	peb := windows.RtlGetCurrentPeb()
   513  	if peb == nil || peb.Ldr == nil {
   514  		t.Error("unable to retrieve PEB with valid Ldr")
   515  	}
   516  	var entry *windows.LDR_DATA_TABLE_ENTRY
   517  	for cur := peb.Ldr.InMemoryOrderModuleList.Flink; cur != &peb.Ldr.InMemoryOrderModuleList; cur = cur.Flink {
   518  		e := (*windows.LDR_DATA_TABLE_ENTRY)(unsafe.Pointer(uintptr(unsafe.Pointer(cur)) - unsafe.Offsetof(windows.LDR_DATA_TABLE_ENTRY{}.InMemoryOrderLinks)))
   519  		if e.DllBase == peb.ImageBaseAddress {
   520  			entry = e
   521  			break
   522  		}
   523  	}
   524  	if entry == nil {
   525  		t.Error("unable to find Ldr entry for current process")
   526  	}
   527  	osPath, err := os.Executable()
   528  	if err != nil {
   529  		t.Errorf("unable to get path to current executable: %v", err)
   530  	}
   531  	pebPath := entry.FullDllName.String()
   532  	if osPath != pebPath {
   533  		t.Errorf("peb.Ldr.{entry}.FullDllName = %#q; want %#q", pebPath, osPath)
   534  	}
   535  	paramPath := peb.ProcessParameters.ImagePathName.String()
   536  	if osPath != paramPath {
   537  		t.Errorf("peb.ProcessParameters.ImagePathName.{entry}.ImagePathName = %#q; want %#q", paramPath, osPath)
   538  	}
   539  	osCwd, err := os.Getwd()
   540  	if err != nil {
   541  		t.Errorf("unable to get working directory: %v", err)
   542  	}
   543  	osCwd = filepath.Clean(osCwd)
   544  	paramCwd := filepath.Clean(peb.ProcessParameters.CurrentDirectory.DosPath.String())
   545  	if paramCwd != osCwd {
   546  		t.Errorf("peb.ProcessParameters.CurrentDirectory.DosPath = %#q; want %#q", paramCwd, osCwd)
   547  	}
   548  }
   549  
   550  func TestResourceExtraction(t *testing.T) {
   551  	system32, err := windows.GetSystemDirectory()
   552  	if err != nil {
   553  		t.Errorf("unable to find system32 directory: %v", err)
   554  	}
   555  	cmd, err := windows.LoadLibrary(filepath.Join(system32, "cmd.exe"))
   556  	if err != nil {
   557  		t.Errorf("unable to load cmd.exe: %v", err)
   558  	}
   559  	defer windows.FreeLibrary(cmd)
   560  	rsrc, err := windows.FindResource(cmd, windows.CREATEPROCESS_MANIFEST_RESOURCE_ID, windows.RT_MANIFEST)
   561  	if err != nil {
   562  		t.Errorf("unable to find cmd.exe manifest resource: %v", err)
   563  	}
   564  	manifest, err := windows.LoadResourceData(cmd, rsrc)
   565  	if err != nil {
   566  		t.Errorf("unable to load cmd.exe manifest resource data: %v", err)
   567  	}
   568  	if !bytes.Contains(manifest, []byte("</assembly>")) {
   569  		t.Errorf("did not find </assembly> in manifest")
   570  	}
   571  }
   572  
   573  func TestCommandLineRecomposition(t *testing.T) {
   574  	const (
   575  		maxCharsPerArg  = 35
   576  		maxArgsPerTrial = 80
   577  		doubleQuoteProb = 4
   578  		singleQuoteProb = 1
   579  		backSlashProb   = 3
   580  		spaceProb       = 1
   581  		trials          = 1000
   582  	)
   583  	randString := func(l int) []rune {
   584  		s := make([]rune, l)
   585  		for i := range s {
   586  			s[i] = rand.Int31()
   587  		}
   588  		return s
   589  	}
   590  	mungeString := func(s []rune, char rune, timesInTen int) {
   591  		if timesInTen < rand.Intn(10)+1 || len(s) == 0 {
   592  			return
   593  		}
   594  		s[rand.Intn(len(s))] = char
   595  	}
   596  	argStorage := make([]string, maxArgsPerTrial+1)
   597  	for i := 0; i < trials; i++ {
   598  		args := argStorage[:rand.Intn(maxArgsPerTrial)+2]
   599  		args[0] = "valid-filename-for-arg0"
   600  		for j := 1; j < len(args); j++ {
   601  			arg := randString(rand.Intn(maxCharsPerArg + 1))
   602  			mungeString(arg, '"', doubleQuoteProb)
   603  			mungeString(arg, '\'', singleQuoteProb)
   604  			mungeString(arg, '\\', backSlashProb)
   605  			mungeString(arg, ' ', spaceProb)
   606  			args[j] = string(arg)
   607  		}
   608  		commandLine := windows.ComposeCommandLine(args)
   609  		decomposedArgs, err := windows.DecomposeCommandLine(commandLine)
   610  		if err != nil {
   611  			t.Errorf("Unable to decompose %#q made from %v: %v", commandLine, args, err)
   612  			continue
   613  		}
   614  		if len(decomposedArgs) != len(args) {
   615  			t.Errorf("Incorrect decomposition length from %v to %#q to %v", args, commandLine, decomposedArgs)
   616  			continue
   617  		}
   618  		badMatches := make([]int, 0, len(args))
   619  		for i := range args {
   620  			if args[i] != decomposedArgs[i] {
   621  				badMatches = append(badMatches, i)
   622  			}
   623  		}
   624  		if len(badMatches) != 0 {
   625  			t.Errorf("Incorrect decomposition at indices %v from %v to %#q to %v", badMatches, args, commandLine, decomposedArgs)
   626  			continue
   627  		}
   628  	}
   629  
   630  	// check that windows.DecomposeCommandLine returns error for strings with NUL
   631  	testsWithNUL := []string{
   632  		"\x00abcd",
   633  		"ab\x00cd",
   634  		"abcd\x00",
   635  		"\x00abcd\x00",
   636  		"\x00ab\x00cd\x00",
   637  		"\x00\x00\x00",
   638  	}
   639  	for _, test := range testsWithNUL {
   640  		_, err := windows.DecomposeCommandLine(test)
   641  		if err == nil {
   642  			t.Errorf("Failed to return error while decomposing %#q string with NUL inside", test)
   643  		}
   644  	}
   645  }
   646  
   647  func TestWinVerifyTrust(t *testing.T) {
   648  	evsignedfile := `.\testdata\ev-signed-file.exe`
   649  	evsignedfile16, err := windows.UTF16PtrFromString(evsignedfile)
   650  	if err != nil {
   651  		t.Fatalf("unable to get utf16 of %s: %v", evsignedfile, err)
   652  	}
   653  	data := &windows.WinTrustData{
   654  		Size:             uint32(unsafe.Sizeof(windows.WinTrustData{})),
   655  		UIChoice:         windows.WTD_UI_NONE,
   656  		RevocationChecks: windows.WTD_REVOKE_NONE, // No revocation checking, in case the tests don't have network connectivity.
   657  		UnionChoice:      windows.WTD_CHOICE_FILE,
   658  		StateAction:      windows.WTD_STATEACTION_VERIFY,
   659  		FileOrCatalogOrBlobOrSgnrOrCert: unsafe.Pointer(&windows.WinTrustFileInfo{
   660  			Size:     uint32(unsafe.Sizeof(windows.WinTrustFileInfo{})),
   661  			FilePath: evsignedfile16,
   662  		}),
   663  	}
   664  	verifyErr := windows.WinVerifyTrustEx(windows.InvalidHWND, &windows.WINTRUST_ACTION_GENERIC_VERIFY_V2, data)
   665  	data.StateAction = windows.WTD_STATEACTION_CLOSE
   666  	closeErr := windows.WinVerifyTrustEx(windows.InvalidHWND, &windows.WINTRUST_ACTION_GENERIC_VERIFY_V2, data)
   667  	if verifyErr != nil {
   668  		t.Errorf("%s did not verify: %v", evsignedfile, verifyErr)
   669  	}
   670  	if closeErr != nil {
   671  		t.Errorf("unable to free verification resources: %v", closeErr)
   672  	}
   673  
   674  	// Now that we've verified the legitimate file verifies, let's corrupt it and see if it correctly fails.
   675  
   676  	dir, err := ioutil.TempDir("", "go-build")
   677  	if err != nil {
   678  		t.Fatalf("failed to create temp directory: %v", err)
   679  	}
   680  	defer os.RemoveAll(dir)
   681  	corruptedEvsignedfile := filepath.Join(dir, "corrupted-file")
   682  	evsignedfileBytes, err := ioutil.ReadFile(evsignedfile)
   683  	if err != nil {
   684  		t.Fatalf("unable to read %s bytes: %v", evsignedfile, err)
   685  	}
   686  	if len(evsignedfileBytes) > 0 {
   687  		evsignedfileBytes[len(evsignedfileBytes)/2-1]++
   688  	}
   689  	err = ioutil.WriteFile(corruptedEvsignedfile, evsignedfileBytes, 0755)
   690  	if err != nil {
   691  		t.Fatalf("unable to write corrupted ntoskrnl.exe bytes: %v", err)
   692  	}
   693  	evsignedfile16, err = windows.UTF16PtrFromString(corruptedEvsignedfile)
   694  	if err != nil {
   695  		t.Fatalf("unable to get utf16 of ntoskrnl.exe: %v", err)
   696  	}
   697  	data = &windows.WinTrustData{
   698  		Size:             uint32(unsafe.Sizeof(windows.WinTrustData{})),
   699  		UIChoice:         windows.WTD_UI_NONE,
   700  		RevocationChecks: windows.WTD_REVOKE_NONE, // No revocation checking, in case the tests don't have network connectivity.
   701  		UnionChoice:      windows.WTD_CHOICE_FILE,
   702  		StateAction:      windows.WTD_STATEACTION_VERIFY,
   703  		FileOrCatalogOrBlobOrSgnrOrCert: unsafe.Pointer(&windows.WinTrustFileInfo{
   704  			Size:     uint32(unsafe.Sizeof(windows.WinTrustFileInfo{})),
   705  			FilePath: evsignedfile16,
   706  		}),
   707  	}
   708  	verifyErr = windows.WinVerifyTrustEx(windows.InvalidHWND, &windows.WINTRUST_ACTION_GENERIC_VERIFY_V2, data)
   709  	data.StateAction = windows.WTD_STATEACTION_CLOSE
   710  	closeErr = windows.WinVerifyTrustEx(windows.InvalidHWND, &windows.WINTRUST_ACTION_GENERIC_VERIFY_V2, data)
   711  	if verifyErr != windows.Errno(windows.TRUST_E_BAD_DIGEST) {
   712  		t.Errorf("%s did not fail to verify as expected: %v", corruptedEvsignedfile, verifyErr)
   713  	}
   714  	if closeErr != nil {
   715  		t.Errorf("unable to free verification resources: %v", closeErr)
   716  	}
   717  
   718  }
   719  
   720  func TestEnumProcesses(t *testing.T) {
   721  	var (
   722  		pids    [2]uint32
   723  		outSize uint32
   724  	)
   725  	err := windows.EnumProcesses(pids[:], &outSize)
   726  	if err != nil {
   727  		t.Fatalf("unable to enumerate processes: %v", err)
   728  	}
   729  
   730  	// Regression check for go.dev/issue/60223
   731  	if outSize != 8 {
   732  		t.Errorf("unexpected bytes returned: %d", outSize)
   733  	}
   734  	// Most likely, this should be [0, 4].
   735  	// 0 is the system idle pseudo-process. 4 is the initial system process ID.
   736  	// This test expects that at least one of the PIDs is not 0.
   737  	if pids[0] == 0 && pids[1] == 0 {
   738  		t.Errorf("all PIDs are 0")
   739  	}
   740  }
   741  
   742  func TestProcessModules(t *testing.T) {
   743  	process, err := windows.GetCurrentProcess()
   744  	if err != nil {
   745  		t.Fatalf("unable to get current process: %v", err)
   746  	}
   747  	// NB: Assume that we're always the first module. This technically isn't documented anywhere (that I could find), but seems to always hold.
   748  	var module windows.Handle
   749  	var cbNeeded uint32
   750  	err = windows.EnumProcessModules(process, &module, uint32(unsafe.Sizeof(module)), &cbNeeded)
   751  	if err != nil {
   752  		t.Fatalf("EnumProcessModules failed: %v", err)
   753  	}
   754  
   755  	var moduleEx windows.Handle
   756  	err = windows.EnumProcessModulesEx(process, &moduleEx, uint32(unsafe.Sizeof(moduleEx)), &cbNeeded, windows.LIST_MODULES_DEFAULT)
   757  	if err != nil {
   758  		t.Fatalf("EnumProcessModulesEx failed: %v", err)
   759  	}
   760  	if module != moduleEx {
   761  		t.Fatalf("module from EnumProcessModules does not match EnumProcessModulesEx: %v != %v", module, moduleEx)
   762  	}
   763  
   764  	exePath, err := os.Executable()
   765  	if err != nil {
   766  		t.Fatalf("unable to get current executable path: %v", err)
   767  	}
   768  
   769  	modulePathUTF16 := make([]uint16, len(exePath)+1)
   770  	err = windows.GetModuleFileNameEx(process, module, &modulePathUTF16[0], uint32(len(modulePathUTF16)))
   771  	if err != nil {
   772  		t.Fatalf("GetModuleFileNameEx failed: %v", err)
   773  	}
   774  
   775  	modulePath := windows.UTF16ToString(modulePathUTF16)
   776  	if modulePath != exePath {
   777  		t.Fatalf("module does not match executable for GetModuleFileNameEx: %s != %s", modulePath, exePath)
   778  	}
   779  
   780  	err = windows.GetModuleBaseName(process, module, &modulePathUTF16[0], uint32(len(modulePathUTF16)))
   781  	if err != nil {
   782  		t.Fatalf("GetModuleBaseName failed: %v", err)
   783  	}
   784  
   785  	modulePath = windows.UTF16ToString(modulePathUTF16)
   786  	baseExePath := filepath.Base(exePath)
   787  	if modulePath != baseExePath {
   788  		t.Fatalf("module does not match executable for GetModuleBaseName: %s != %s", modulePath, baseExePath)
   789  	}
   790  
   791  	var moduleInfo windows.ModuleInfo
   792  	err = windows.GetModuleInformation(process, module, &moduleInfo, uint32(unsafe.Sizeof(moduleInfo)))
   793  	if err != nil {
   794  		t.Fatalf("GetModuleInformation failed: %v", err)
   795  	}
   796  
   797  	peFile, err := pe.Open(exePath)
   798  	if err != nil {
   799  		t.Fatalf("unable to open current executable: %v", err)
   800  	}
   801  	defer peFile.Close()
   802  
   803  	var peSizeOfImage uint32
   804  	switch runtime.GOARCH {
   805  	case "amd64", "arm64":
   806  		peSizeOfImage = peFile.OptionalHeader.(*pe.OptionalHeader64).SizeOfImage
   807  	case "386", "arm":
   808  		peSizeOfImage = peFile.OptionalHeader.(*pe.OptionalHeader32).SizeOfImage
   809  	default:
   810  		t.Fatalf("unable to test GetModuleInformation on arch %v", runtime.GOARCH)
   811  	}
   812  
   813  	if moduleInfo.SizeOfImage != peSizeOfImage {
   814  		t.Fatalf("module size does not match executable: %v != %v", moduleInfo.SizeOfImage, peSizeOfImage)
   815  	}
   816  }
   817  
   818  func TestQueryWorkingSetEx(t *testing.T) {
   819  	var a int
   820  
   821  	process := windows.CurrentProcess()
   822  	information := windows.PSAPI_WORKING_SET_EX_INFORMATION{
   823  		VirtualAddress: windows.Pointer(unsafe.Pointer(&a)),
   824  	}
   825  	infos := []windows.PSAPI_WORKING_SET_EX_INFORMATION{information}
   826  
   827  	cb := uint32(uintptr(len(infos)) * unsafe.Sizeof(infos[0]))
   828  	if err := windows.QueryWorkingSetEx(process, uintptr(unsafe.Pointer(&infos[0])), cb); err != nil {
   829  		t.Fatalf("%+v", err)
   830  	}
   831  
   832  	if !infos[0].VirtualAttributes.Valid() {
   833  		t.Errorf("memory location not valid")
   834  	}
   835  }
   836  
   837  func TestReadWriteProcessMemory(t *testing.T) {
   838  	testBuffer := []byte{0xBA, 0xAD, 0xF0, 0x0D}
   839  
   840  	process, err := windows.GetCurrentProcess()
   841  	if err != nil {
   842  		t.Fatalf("unable to get current process: %v", err)
   843  	}
   844  
   845  	buffer := make([]byte, len(testBuffer))
   846  	err = windows.ReadProcessMemory(process, uintptr(unsafe.Pointer(&testBuffer[0])), &buffer[0], uintptr(len(buffer)), nil)
   847  	if err != nil {
   848  		t.Errorf("ReadProcessMemory failed: %v", err)
   849  	}
   850  	if !bytes.Equal(testBuffer, buffer) {
   851  		t.Errorf("bytes read does not match buffer: 0x%X != 0x%X", testBuffer, buffer)
   852  	}
   853  
   854  	buffer = []byte{0xDE, 0xAD, 0xBE, 0xEF}
   855  	err = windows.WriteProcessMemory(process, uintptr(unsafe.Pointer(&testBuffer[0])), &buffer[0], uintptr(len(buffer)), nil)
   856  	if err != nil {
   857  		t.Errorf("WriteProcessMemory failed: %v", err)
   858  	}
   859  	if !bytes.Equal(testBuffer, buffer) {
   860  		t.Errorf("bytes written does not match buffer: 0x%X != 0x%X", testBuffer, buffer)
   861  	}
   862  }
   863  
   864  func TestSystemModuleVersions(t *testing.T) {
   865  	var modules []windows.RTL_PROCESS_MODULE_INFORMATION
   866  	for bufferSize := uint32(128 * 1024); ; {
   867  		moduleBuffer := make([]byte, bufferSize)
   868  		err := windows.NtQuerySystemInformation(windows.SystemModuleInformation, unsafe.Pointer(&moduleBuffer[0]), bufferSize, &bufferSize)
   869  		switch err {
   870  		case windows.STATUS_INFO_LENGTH_MISMATCH:
   871  			continue
   872  		case nil:
   873  			break
   874  		default:
   875  			t.Error(err)
   876  			return
   877  		}
   878  		mods := (*windows.RTL_PROCESS_MODULES)(unsafe.Pointer(&moduleBuffer[0]))
   879  		hdr := (*unsafeheader.Slice)(unsafe.Pointer(&modules))
   880  		hdr.Data = unsafe.Pointer(&mods.Modules[0])
   881  		hdr.Len = int(mods.NumberOfModules)
   882  		hdr.Cap = int(mods.NumberOfModules)
   883  		break
   884  	}
   885  	for i := range modules {
   886  		moduleName := windows.ByteSliceToString(modules[i].FullPathName[modules[i].OffsetToFileName:])
   887  		driverPath := `\\?\GLOBALROOT` + windows.ByteSliceToString(modules[i].FullPathName[:])
   888  		var zero windows.Handle
   889  		infoSize, err := windows.GetFileVersionInfoSize(driverPath, &zero)
   890  		if err != nil {
   891  			if err != windows.ERROR_FILE_NOT_FOUND {
   892  				t.Error(err)
   893  			}
   894  			continue
   895  		}
   896  		versionInfo := make([]byte, infoSize)
   897  		err = windows.GetFileVersionInfo(driverPath, 0, infoSize, unsafe.Pointer(&versionInfo[0]))
   898  		if err != nil && err != windows.ERROR_FILE_NOT_FOUND {
   899  			t.Error(err)
   900  			continue
   901  		}
   902  		var fixedInfo *windows.VS_FIXEDFILEINFO
   903  		fixedInfoLen := uint32(unsafe.Sizeof(*fixedInfo))
   904  		err = windows.VerQueryValue(unsafe.Pointer(&versionInfo[0]), `\`, (unsafe.Pointer)(&fixedInfo), &fixedInfoLen)
   905  		if err != nil {
   906  			t.Error(err)
   907  			continue
   908  		}
   909  		t.Logf("%s: v%d.%d.%d.%d", moduleName,
   910  			(fixedInfo.FileVersionMS>>16)&0xff,
   911  			(fixedInfo.FileVersionMS>>0)&0xff,
   912  			(fixedInfo.FileVersionLS>>16)&0xff,
   913  			(fixedInfo.FileVersionLS>>0)&0xff)
   914  	}
   915  }
   916  
   917  type fileRenameInformation struct {
   918  	ReplaceIfExists uint32
   919  	RootDirectory   windows.Handle
   920  	FileNameLength  uint32
   921  	FileName        [1]uint16
   922  }
   923  
   924  func TestNtCreateFileAndNtSetInformationFile(t *testing.T) {
   925  	var iosb windows.IO_STATUS_BLOCK
   926  	var allocSize int64 = 0
   927  	// Open test directory with NtCreateFile.
   928  	testDirPath := t.TempDir()
   929  	objectName, err := windows.NewNTUnicodeString("\\??\\" + testDirPath)
   930  	if err != nil {
   931  		t.Fatal(err)
   932  	}
   933  	oa := &windows.OBJECT_ATTRIBUTES{
   934  		ObjectName: objectName,
   935  	}
   936  	oa.Length = uint32(unsafe.Sizeof(*oa))
   937  	var testDirHandle windows.Handle
   938  	err = windows.NtCreateFile(&testDirHandle, windows.FILE_GENERIC_READ|windows.FILE_GENERIC_WRITE, oa, &iosb,
   939  		&allocSize, 0, windows.FILE_SHARE_READ|windows.FILE_SHARE_WRITE|windows.FILE_SHARE_DELETE, windows.FILE_OPEN,
   940  		windows.FILE_DIRECTORY_FILE, 0, 0)
   941  	if err != nil {
   942  		t.Fatalf("NtCreateFile(%v) failed: %v", testDirPath, err)
   943  	}
   944  	defer windows.CloseHandle(testDirHandle)
   945  	// Create a file in test directory with NtCreateFile.
   946  	fileName := "filename"
   947  	filePath := filepath.Join(testDirPath, fileName)
   948  	objectName, err = windows.NewNTUnicodeString(fileName)
   949  	if err != nil {
   950  		t.Fatal(err)
   951  	}
   952  	oa.RootDirectory = testDirHandle
   953  	oa.ObjectName = objectName
   954  	var fileHandle windows.Handle
   955  	err = windows.NtCreateFile(&fileHandle, windows.FILE_GENERIC_READ|windows.FILE_GENERIC_WRITE|windows.DELETE, oa, &iosb,
   956  		&allocSize, 0, windows.FILE_SHARE_READ|windows.FILE_SHARE_WRITE|windows.FILE_SHARE_DELETE, windows.FILE_CREATE,
   957  		0, 0, 0)
   958  	if err != nil {
   959  		t.Fatalf("NtCreateFile(%v) failed: %v", filePath, err)
   960  	}
   961  	defer windows.CloseHandle(fileHandle)
   962  	_, err = os.Stat(filePath)
   963  	if err != nil {
   964  		t.Fatalf("cannot stat file created with NtCreatefile: %v", err)
   965  	}
   966  	// Rename file with NtSetInformationFile.
   967  	newName := "newname"
   968  	newPath := filepath.Join(testDirPath, newName)
   969  	newNameUTF16, err := windows.UTF16FromString(newName)
   970  	if err != nil {
   971  		t.Fatal(err)
   972  	}
   973  	fileNameLen := len(newNameUTF16)*2 - 2
   974  	var dummyFileRenameInfo fileRenameInformation
   975  	bufferSize := int(unsafe.Offsetof(dummyFileRenameInfo.FileName)) + fileNameLen
   976  	buffer := make([]byte, bufferSize)
   977  	typedBufferPtr := (*fileRenameInformation)(unsafe.Pointer(&buffer[0]))
   978  	typedBufferPtr.ReplaceIfExists = windows.FILE_RENAME_REPLACE_IF_EXISTS | windows.FILE_RENAME_POSIX_SEMANTICS
   979  	typedBufferPtr.FileNameLength = uint32(fileNameLen)
   980  	copy((*[windows.MAX_LONG_PATH]uint16)(unsafe.Pointer(&typedBufferPtr.FileName[0]))[:fileNameLen/2:fileNameLen/2], newNameUTF16)
   981  	err = windows.NtSetInformationFile(fileHandle, &iosb, &buffer[0], uint32(bufferSize), windows.FileRenameInformation)
   982  	if err != nil {
   983  		t.Fatalf("NtSetInformationFile(%v) failed: %v", newPath, err)
   984  	}
   985  	_, err = os.Stat(newPath)
   986  	if err != nil {
   987  		t.Fatalf("cannot stat rename target %v: %v", newPath, err)
   988  	}
   989  }
   990  
   991  var deviceClassNetGUID = &windows.GUID{0x4d36e972, 0xe325, 0x11ce, [8]byte{0xbf, 0xc1, 0x08, 0x00, 0x2b, 0xe1, 0x03, 0x18}}
   992  var deviceInterfaceNetGUID = &windows.GUID{0xcac88484, 0x7515, 0x4c03, [8]byte{0x82, 0xe6, 0x71, 0xa8, 0x7a, 0xba, 0xc3, 0x61}}
   993  
   994  func TestListLoadedNetworkDevices(t *testing.T) {
   995  	devInfo, err := windows.SetupDiGetClassDevsEx(deviceClassNetGUID, "", 0, windows.DIGCF_PRESENT, 0, "")
   996  	if err != nil {
   997  		t.Fatal(err)
   998  	}
   999  	defer devInfo.Close()
  1000  	for i := 0; ; i++ {
  1001  		devInfoData, err := devInfo.EnumDeviceInfo(i)
  1002  		if err != nil {
  1003  			if err == windows.ERROR_NO_MORE_ITEMS {
  1004  				break
  1005  			}
  1006  			continue
  1007  		}
  1008  		friendlyName, err := devInfo.DeviceRegistryProperty(devInfoData, windows.SPDRP_DEVICEDESC)
  1009  		if err != nil {
  1010  			t.Fatal(err)
  1011  		}
  1012  		var status, problemCode uint32
  1013  		err = windows.CM_Get_DevNode_Status(&status, &problemCode, devInfoData.DevInst, 0)
  1014  		if err != nil || (status&windows.DN_DRIVER_LOADED|windows.DN_STARTED) != windows.DN_DRIVER_LOADED|windows.DN_STARTED {
  1015  			continue
  1016  		}
  1017  		instanceId, err := devInfo.DeviceInstanceID(devInfoData)
  1018  		if err != nil {
  1019  			t.Fatal(err)
  1020  		}
  1021  		interfaces, err := windows.CM_Get_Device_Interface_List(instanceId, deviceInterfaceNetGUID, windows.CM_GET_DEVICE_INTERFACE_LIST_PRESENT)
  1022  		if err != nil || len(interfaces) == 0 {
  1023  			continue
  1024  		}
  1025  		t.Logf("%s - %s", friendlyName, interfaces[0])
  1026  	}
  1027  }
  1028  
  1029  func TestListWireGuardDrivers(t *testing.T) {
  1030  	devInfo, err := windows.SetupDiCreateDeviceInfoListEx(deviceClassNetGUID, 0, "")
  1031  	if err != nil {
  1032  		t.Fatal(err)
  1033  	}
  1034  	defer devInfo.Close()
  1035  	devInfoData, err := devInfo.CreateDeviceInfo("WireGuard", deviceClassNetGUID, "", 0, windows.DICD_GENERATE_ID)
  1036  	if err != nil {
  1037  		t.Fatal(err)
  1038  	}
  1039  	err = devInfo.SetDeviceRegistryProperty(devInfoData, windows.SPDRP_HARDWAREID, []byte("W\x00i\x00r\x00e\x00G\x00u\x00a\x00r\x00d\x00\x00\x00\x00\x00"))
  1040  	if err != nil {
  1041  		t.Fatal(err)
  1042  	}
  1043  	err = devInfo.BuildDriverInfoList(devInfoData, windows.SPDIT_COMPATDRIVER)
  1044  	if err != nil {
  1045  		t.Fatal(err)
  1046  	}
  1047  	defer devInfo.DestroyDriverInfoList(devInfoData, windows.SPDIT_COMPATDRIVER)
  1048  	for i := 0; ; i++ {
  1049  		drvInfoData, err := devInfo.EnumDriverInfo(devInfoData, windows.SPDIT_COMPATDRIVER, i)
  1050  		if err != nil {
  1051  			if err == windows.ERROR_NO_MORE_ITEMS {
  1052  				break
  1053  			}
  1054  			continue
  1055  		}
  1056  		drvInfoDetailData, err := devInfo.DriverInfoDetail(devInfoData, drvInfoData)
  1057  		if err != nil {
  1058  			t.Error(err)
  1059  			continue
  1060  		}
  1061  		t.Logf("%s - %s", drvInfoData.Description(), drvInfoDetailData.InfFileName())
  1062  	}
  1063  }
  1064  
  1065  func TestProcThreadAttributeHandleList(t *testing.T) {
  1066  	const sentinel = "the gopher dance"
  1067  	system32, err := windows.GetSystemDirectory()
  1068  	if err != nil {
  1069  		t.Fatal(err)
  1070  	}
  1071  	executable16, err := windows.UTF16PtrFromString(filepath.Join(system32, "cmd.exe"))
  1072  	if err != nil {
  1073  		t.Fatal(err)
  1074  	}
  1075  	args16, err := windows.UTF16PtrFromString(windows.ComposeCommandLine([]string{"/c", "echo " + sentinel}))
  1076  	if err != nil {
  1077  		t.Fatal(err)
  1078  	}
  1079  	attributeList, err := windows.NewProcThreadAttributeList(1)
  1080  	if err != nil {
  1081  		t.Fatal(err)
  1082  	}
  1083  	defer attributeList.Delete()
  1084  	si := &windows.StartupInfoEx{
  1085  		StartupInfo:             windows.StartupInfo{Cb: uint32(unsafe.Sizeof(windows.StartupInfoEx{}))},
  1086  		ProcThreadAttributeList: attributeList.List(),
  1087  	}
  1088  	pipeR, pipeW, err := os.Pipe()
  1089  	if err != nil {
  1090  		t.Fatal(err)
  1091  	}
  1092  	defer pipeR.Close()
  1093  	defer pipeW.Close()
  1094  	func() {
  1095  		// We allocate handles in a closure to provoke a UaF in the case of attributeList.Update being buggy.
  1096  		handles := []windows.Handle{windows.Handle(pipeW.Fd())}
  1097  		attributeList.Update(windows.PROC_THREAD_ATTRIBUTE_HANDLE_LIST, unsafe.Pointer(&handles[0]), uintptr(len(handles))*unsafe.Sizeof(handles[0]))
  1098  		si.Flags |= windows.STARTF_USESTDHANDLES
  1099  		si.StdOutput = handles[0]
  1100  		// Go 1.16's pipe handles aren't inheritable, so mark it explicitly as such here.
  1101  		windows.SetHandleInformation(handles[0], windows.HANDLE_FLAG_INHERIT, windows.HANDLE_FLAG_INHERIT)
  1102  	}()
  1103  	pi := new(windows.ProcessInformation)
  1104  	err = windows.CreateProcess(executable16, args16, nil, nil, true, windows.CREATE_DEFAULT_ERROR_MODE|windows.CREATE_UNICODE_ENVIRONMENT|windows.EXTENDED_STARTUPINFO_PRESENT, nil, nil, &si.StartupInfo, pi)
  1105  	if err != nil {
  1106  		t.Fatal(err)
  1107  	}
  1108  	defer windows.CloseHandle(pi.Thread)
  1109  	defer windows.CloseHandle(pi.Process)
  1110  	pipeR.SetReadDeadline(time.Now().Add(time.Minute))
  1111  	out, _, err := bufio.NewReader(pipeR).ReadLine()
  1112  	if err != nil {
  1113  		t.Fatal(err)
  1114  	}
  1115  	if string(out) != sentinel {
  1116  		t.Fatalf("got %q; want %q", out, sentinel)
  1117  	}
  1118  }
  1119  
  1120  func TestWSALookupService(t *testing.T) {
  1121  	var flags uint32 = windows.LUP_CONTAINERS
  1122  	flags |= windows.LUP_RETURN_NAME
  1123  	flags |= windows.LUP_RETURN_ADDR
  1124  
  1125  	var querySet windows.WSAQUERYSET
  1126  	querySet.NameSpace = windows.NS_BTH
  1127  	querySet.Size = uint32(unsafe.Sizeof(windows.WSAQUERYSET{}))
  1128  
  1129  	var handle windows.Handle
  1130  	err := windows.WSALookupServiceBegin(&querySet, flags, &handle)
  1131  	if err != nil {
  1132  		if errors.Is(err, windows.WSASERVICE_NOT_FOUND) {
  1133  			t.Skip("WSA Service not found, so skip this test")
  1134  		}
  1135  		t.Fatal(err)
  1136  	}
  1137  
  1138  	defer windows.WSALookupServiceEnd(handle)
  1139  
  1140  	n := int32(unsafe.Sizeof(windows.WSAQUERYSET{}))
  1141  	buf := make([]byte, n)
  1142  items_loop:
  1143  	for {
  1144  		q := (*windows.WSAQUERYSET)(unsafe.Pointer(&buf[0]))
  1145  		err := windows.WSALookupServiceNext(handle, flags, &n, q)
  1146  		switch err {
  1147  		case windows.WSA_E_NO_MORE, windows.WSAENOMORE:
  1148  			// no more data available - break the loop
  1149  			break items_loop
  1150  		case windows.WSAEFAULT:
  1151  			// buffer is too small - reallocate and try again
  1152  			buf = make([]byte, n)
  1153  		case nil:
  1154  			// found a record - display the item and fetch next item
  1155  			var addr string
  1156  			for _, e := range q.SaBuffer.RemoteAddr.Sockaddr.Addr.Data {
  1157  				if e != 0 {
  1158  					addr += fmt.Sprintf("%x", e)
  1159  				}
  1160  			}
  1161  			t.Logf("%s -> %s\n", windows.UTF16PtrToString(q.ServiceInstanceName), addr)
  1162  
  1163  		default:
  1164  			t.Fatal(err)
  1165  		}
  1166  	}
  1167  }