1
2
3
4
5 package windows_test
6
7 import (
8 "bufio"
9 "bytes"
10 "debug/pe"
11 "errors"
12 "fmt"
13 "os"
14 "os/exec"
15 "path/filepath"
16 "runtime"
17 "strconv"
18 "strings"
19 "syscall"
20 "testing"
21 "time"
22 "unicode/utf8"
23 "unsafe"
24
25 "golang.org/x/sys/windows"
26 )
27
28 func TestWin32finddata(t *testing.T) {
29 path := filepath.Join(t.TempDir(), "long_name.and_extension")
30 f, err := os.Create(path)
31 if err != nil {
32 t.Fatalf("failed to create %v: %v", path, err)
33 }
34 f.Close()
35
36 type X struct {
37 fd windows.Win32finddata
38 got byte
39 pad [10]byte
40
41 }
42 var want byte = 2
43 x := X{got: want}
44
45 pathp, _ := windows.UTF16PtrFromString(path)
46 h, err := windows.FindFirstFile(pathp, &(x.fd))
47 if err != nil {
48 t.Fatalf("FindFirstFile failed: %v", err)
49 }
50 err = windows.FindClose(h)
51 if err != nil {
52 t.Fatalf("FindClose failed: %v", err)
53 }
54
55 if x.got != want {
56 t.Fatalf("memory corruption: want=%d got=%d", want, x.got)
57 }
58 }
59
60 func TestFormatMessage(t *testing.T) {
61 dll := windows.MustLoadDLL("netevent.dll")
62
63 const TITLE_SC_MESSAGE_BOX uint32 = 0xC0001B75
64 const flags uint32 = syscall.FORMAT_MESSAGE_FROM_HMODULE | syscall.FORMAT_MESSAGE_ARGUMENT_ARRAY | syscall.FORMAT_MESSAGE_IGNORE_INSERTS
65 buf := make([]uint16, 300)
66 _, err := windows.FormatMessage(flags, uintptr(dll.Handle), TITLE_SC_MESSAGE_BOX, 0, buf, nil)
67 if err != nil {
68 t.Fatalf("FormatMessage for handle=%x and errno=%x failed: %v", dll.Handle, TITLE_SC_MESSAGE_BOX, err)
69 }
70 }
71
72 func abort(funcname string, err error) {
73 panic(funcname + " failed: " + err.Error())
74 }
75
76 func ExampleLoadLibrary() {
77 h, err := windows.LoadLibrary("kernel32.dll")
78 if err != nil {
79 abort("LoadLibrary", err)
80 }
81 defer windows.FreeLibrary(h)
82 proc, err := windows.GetProcAddress(h, "GetVersion")
83 if err != nil {
84 abort("GetProcAddress", err)
85 }
86 r, _, _ := syscall.Syscall(uintptr(proc), 0, 0, 0, 0)
87 major := byte(r)
88 minor := uint8(r >> 8)
89 build := uint16(r >> 16)
90 print("windows version ", major, ".", minor, " (Build ", build, ")\n")
91 }
92
93 func TestTOKEN_ALL_ACCESS(t *testing.T) {
94 if windows.TOKEN_ALL_ACCESS != 0xF01FF {
95 t.Errorf("TOKEN_ALL_ACCESS = %x, want 0xF01FF", windows.TOKEN_ALL_ACCESS)
96 }
97 }
98
99 func TestCreateWellKnownSid(t *testing.T) {
100 sid, err := windows.CreateWellKnownSid(windows.WinBuiltinAdministratorsSid)
101 if err != nil {
102 t.Fatalf("Unable to create well known sid for administrators: %v", err)
103 }
104 if got, want := sid.String(), "S-1-5-32-544"; got != want {
105 t.Fatalf("Builtin Administrators SID = %s, want %s", got, want)
106 }
107 }
108
109 func TestPseudoTokens(t *testing.T) {
110 version, err := windows.GetVersion()
111 if err != nil {
112 t.Fatal(err)
113 }
114 if ((version&0xffff)>>8)|((version&0xff)<<8) < 0x0602 {
115 return
116 }
117
118 realProcessToken, err := windows.OpenCurrentProcessToken()
119 if err != nil {
120 t.Fatal(err)
121 }
122 defer realProcessToken.Close()
123 realProcessUser, err := realProcessToken.GetTokenUser()
124 if err != nil {
125 t.Fatal(err)
126 }
127
128 pseudoProcessToken := windows.GetCurrentProcessToken()
129 pseudoProcessUser, err := pseudoProcessToken.GetTokenUser()
130 if err != nil {
131 t.Fatal(err)
132 }
133 if !windows.EqualSid(realProcessUser.User.Sid, pseudoProcessUser.User.Sid) {
134 t.Fatal("The real process token does not have the same as the pseudo process token")
135 }
136
137 runtime.LockOSThread()
138 defer runtime.UnlockOSThread()
139
140 err = windows.RevertToSelf()
141 if err != nil {
142 t.Fatal(err)
143 }
144
145 pseudoThreadToken := windows.GetCurrentThreadToken()
146 _, err = pseudoThreadToken.GetTokenUser()
147 if err != windows.ERROR_NO_TOKEN {
148 t.Fatal("Expected an empty thread token")
149 }
150 pseudoThreadEffectiveToken := windows.GetCurrentThreadEffectiveToken()
151 pseudoThreadEffectiveUser, err := pseudoThreadEffectiveToken.GetTokenUser()
152 if err != nil {
153 t.Fatal(nil)
154 }
155 if !windows.EqualSid(realProcessUser.User.Sid, pseudoThreadEffectiveUser.User.Sid) {
156 t.Fatal("The real process token does not have the same as the pseudo thread effective token, even though we aren't impersonating")
157 }
158
159 err = windows.ImpersonateSelf(windows.SecurityImpersonation)
160 if err != nil {
161 t.Fatal(err)
162 }
163 defer windows.RevertToSelf()
164 pseudoThreadUser, err := pseudoThreadToken.GetTokenUser()
165 if err != nil {
166 t.Fatal(err)
167 }
168 if !windows.EqualSid(realProcessUser.User.Sid, pseudoThreadUser.User.Sid) {
169 t.Fatal("The real process token does not have the same as the pseudo thread token after impersonating self")
170 }
171 }
172
173 func TestGUID(t *testing.T) {
174 guid, err := windows.GenerateGUID()
175 if err != nil {
176 t.Fatal(err)
177 }
178 if guid.Data1 == 0 && guid.Data2 == 0 && guid.Data3 == 0 && guid.Data4 == [8]byte{} {
179 t.Fatal("Got an all zero GUID, which is overwhelmingly unlikely")
180 }
181 want := fmt.Sprintf("{%08X-%04X-%04X-%04X-%012X}", guid.Data1, guid.Data2, guid.Data3, guid.Data4[:2], guid.Data4[2:])
182 got := guid.String()
183 if got != want {
184 t.Fatalf("String = %q; want %q", got, want)
185 }
186 guid2, err := windows.GUIDFromString(got)
187 if err != nil {
188 t.Fatal(err)
189 }
190 if guid2 != guid {
191 t.Fatalf("Did not parse string back to original GUID = %q; want %q", guid2, guid)
192 }
193 _, err = windows.GUIDFromString("not-a-real-guid")
194 if err != syscall.Errno(windows.CO_E_CLASSSTRING) {
195 t.Fatalf("Bad GUID string error = %v; want CO_E_CLASSSTRING", err)
196 }
197 }
198
199 func TestKnownFolderPath(t *testing.T) {
200 token, err := windows.OpenCurrentProcessToken()
201 if err != nil {
202 t.Fatal(err)
203 }
204 defer token.Close()
205 profileDir, err := token.GetUserProfileDirectory()
206 if err != nil {
207 t.Fatal(err)
208 }
209 want := filepath.Join(profileDir, "Desktop")
210 got, err := windows.KnownFolderPath(windows.FOLDERID_Desktop, windows.KF_FLAG_DEFAULT)
211 if err != nil {
212 t.Fatal(err)
213 }
214 if want != got {
215 t.Fatalf("Path = %q; want %q", got, want)
216 }
217 }
218
219 func TestRtlGetVersion(t *testing.T) {
220 version := windows.RtlGetVersion()
221 major, minor, build := windows.RtlGetNtVersionNumbers()
222
223
224 if version.MajorVersion != major || version.MinorVersion != minor || version.BuildNumber != build {
225 t.Fatalf("%d.%d.%d != %d.%d.%d", version.MajorVersion, version.MinorVersion, version.BuildNumber, major, minor, build)
226 }
227 }
228
229 func TestGetNamedSecurityInfo(t *testing.T) {
230 path, err := windows.GetSystemDirectory()
231 if err != nil {
232 t.Fatal(err)
233 }
234 sd, err := windows.GetNamedSecurityInfo(path, windows.SE_FILE_OBJECT, windows.OWNER_SECURITY_INFORMATION)
235 if err != nil {
236 t.Fatal(err)
237 }
238 if !sd.IsValid() {
239 t.Fatal("Invalid security descriptor")
240 }
241 sdOwner, _, err := sd.Owner()
242 if err != nil {
243 t.Fatal(err)
244 }
245 if !sdOwner.IsValid() {
246 t.Fatal("Invalid security descriptor owner")
247 }
248 }
249
250 func TestGetSecurityInfo(t *testing.T) {
251 sd, err := windows.GetSecurityInfo(windows.CurrentProcess(), windows.SE_KERNEL_OBJECT, windows.DACL_SECURITY_INFORMATION)
252 if err != nil {
253 t.Fatal(err)
254 }
255 if !sd.IsValid() {
256 t.Fatal("Invalid security descriptor")
257 }
258 sdStr := sd.String()
259 if !strings.HasPrefix(sdStr, "D:(A;") {
260 t.Fatalf("DACL = %q; want D:(A;...", sdStr)
261 }
262 }
263
264 func TestSddlConversion(t *testing.T) {
265 sd, err := windows.SecurityDescriptorFromString("O:BA")
266 if err != nil {
267 t.Fatal(err)
268 }
269 if !sd.IsValid() {
270 t.Fatal("Invalid security descriptor")
271 }
272 sdOwner, _, err := sd.Owner()
273 if err != nil {
274 t.Fatal(err)
275 }
276 if !sdOwner.IsValid() {
277 t.Fatal("Invalid security descriptor owner")
278 }
279 if !sdOwner.IsWellKnown(windows.WinBuiltinAdministratorsSid) {
280 t.Fatalf("Owner = %q; want S-1-5-32-544", sdOwner)
281 }
282 }
283
284 func TestBuildSecurityDescriptor(t *testing.T) {
285 const want = "O:SYD:(A;;GA;;;BA)"
286
287 adminSid, err := windows.CreateWellKnownSid(windows.WinBuiltinAdministratorsSid)
288 if err != nil {
289 t.Fatal(err)
290 }
291 systemSid, err := windows.CreateWellKnownSid(windows.WinLocalSystemSid)
292 if err != nil {
293 t.Fatal(err)
294 }
295
296 access := []windows.EXPLICIT_ACCESS{{
297 AccessPermissions: windows.GENERIC_ALL,
298 AccessMode: windows.GRANT_ACCESS,
299 Trustee: windows.TRUSTEE{
300 TrusteeForm: windows.TRUSTEE_IS_SID,
301 TrusteeType: windows.TRUSTEE_IS_GROUP,
302 TrusteeValue: windows.TrusteeValueFromSID(adminSid),
303 },
304 }}
305 owner := &windows.TRUSTEE{
306 TrusteeForm: windows.TRUSTEE_IS_SID,
307 TrusteeType: windows.TRUSTEE_IS_USER,
308 TrusteeValue: windows.TrusteeValueFromSID(systemSid),
309 }
310
311 sd, err := windows.BuildSecurityDescriptor(owner, nil, access, nil, nil)
312 if err != nil {
313 t.Fatal(err)
314 }
315 sd, err = sd.ToAbsolute()
316 if err != nil {
317 t.Fatal(err)
318 }
319 err = sd.SetSACL(nil, false, false)
320 if err != nil {
321 t.Fatal(err)
322 }
323 if got := sd.String(); got != want {
324 t.Fatalf("SD = %q; want %q", got, want)
325 }
326 sd, err = sd.ToSelfRelative()
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
334 sd, err = windows.NewSecurityDescriptor()
335 if err != nil {
336 t.Fatal(err)
337 }
338 acl, err := windows.ACLFromEntries(access, nil)
339 if err != nil {
340 t.Fatal(err)
341 }
342 err = sd.SetDACL(acl, true, false)
343 if err != nil {
344 t.Fatal(err)
345 }
346 err = sd.SetOwner(systemSid, false)
347 if err != nil {
348 t.Fatal(err)
349 }
350 if got := sd.String(); got != want {
351 t.Fatalf("SD = %q; want %q", got, want)
352 }
353 sd, err = sd.ToSelfRelative()
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 }
361
362
363 func getEntriesFromACL(acl *windows.ACL) (aces []*windows.ACCESS_ALLOWED_ACE, err error) {
364 aces = make([]*windows.ACCESS_ALLOWED_ACE, acl.AceCount)
365
366 for i := uint16(0); i < acl.AceCount; i++ {
367 err = windows.GetAce(acl, uint32(i), &aces[i])
368 if err != nil {
369 return nil, err
370 }
371 }
372
373 return aces, nil
374 }
375
376 func TestGetACEsFromACL(t *testing.T) {
377
378 f, err := os.CreateTemp("", "foo.lish")
379 defer os.Remove(f.Name())
380
381 if err = f.Close(); err != nil {
382 t.Fatal(err)
383 }
384
385
386
387 ownerSid, err := windows.StringToSid("S-1-3-2")
388 if err != nil {
389 t.Fatal(err)
390 }
391 groupSid, err := windows.StringToSid("S-1-3-3")
392 if err != nil {
393 t.Fatal(err)
394 }
395 worldSid, err := windows.StringToSid("S-1-1-0")
396 if err != nil {
397 t.Fatal(err)
398 }
399
400 ownerPermissions := windows.ACCESS_MASK(windows.GENERIC_ALL)
401 groupPermissions := windows.ACCESS_MASK(windows.GENERIC_READ | windows.GENERIC_EXECUTE)
402 worldPermissions := windows.ACCESS_MASK(windows.GENERIC_READ)
403
404 access := []windows.EXPLICIT_ACCESS{
405 {
406 AccessPermissions: ownerPermissions,
407 AccessMode: windows.GRANT_ACCESS,
408 Trustee: windows.TRUSTEE{
409 TrusteeForm: windows.TRUSTEE_IS_SID,
410 TrusteeValue: windows.TrusteeValueFromSID(ownerSid),
411 },
412 },
413 {
414 AccessPermissions: groupPermissions,
415 AccessMode: windows.GRANT_ACCESS,
416 Trustee: windows.TRUSTEE{
417 TrusteeForm: windows.TRUSTEE_IS_SID,
418 TrusteeType: windows.TRUSTEE_IS_GROUP,
419 TrusteeValue: windows.TrusteeValueFromSID(groupSid),
420 },
421 },
422 {
423 AccessPermissions: worldPermissions,
424 AccessMode: windows.GRANT_ACCESS,
425 Trustee: windows.TRUSTEE{
426 TrusteeForm: windows.TRUSTEE_IS_SID,
427 TrusteeType: windows.TRUSTEE_IS_GROUP,
428 TrusteeValue: windows.TrusteeValueFromSID(worldSid),
429 },
430 },
431 }
432
433 acl, err := windows.ACLFromEntries(access, nil)
434 if err != nil {
435 t.Fatal(err)
436 }
437
438
439 err = windows.SetNamedSecurityInfo(
440 f.Name(),
441 windows.SE_FILE_OBJECT,
442 windows.DACL_SECURITY_INFORMATION|windows.PROTECTED_DACL_SECURITY_INFORMATION,
443 nil,
444 nil,
445 acl,
446 nil,
447 )
448 if err != nil {
449 t.Fatal(err)
450 }
451
452 descriptor, err := windows.GetNamedSecurityInfo(
453 f.Name(),
454 windows.SE_FILE_OBJECT,
455 windows.DACL_SECURITY_INFORMATION|windows.PROTECTED_DACL_SECURITY_INFORMATION|windows.OWNER_SECURITY_INFORMATION|windows.GROUP_SECURITY_INFORMATION,
456 )
457 if err != nil {
458 t.Fatal(err)
459 }
460
461 dacl, _, err := descriptor.DACL()
462 if err != nil {
463 t.Fatal(err)
464 }
465
466 owner, _, err := descriptor.Owner()
467 if err != nil {
468 t.Fatal(err)
469 }
470
471 group, _, err := descriptor.Group()
472 if err != nil {
473 t.Fatal(err)
474 }
475
476 entries, err := getEntriesFromACL(dacl)
477 if err != nil {
478 t.Fatal(err)
479 }
480
481 if len(entries) != 3 {
482 t.Fatalf("Expected newly set ACL to only have 3 entries.")
483 }
484
485
486 read := uint32(windows.FILE_READ_DATA | windows.FILE_READ_ATTRIBUTES)
487 write := uint32(windows.FILE_WRITE_DATA | windows.FILE_APPEND_DATA | windows.FILE_WRITE_ATTRIBUTES | windows.FILE_WRITE_EA)
488 execute := uint32(windows.FILE_READ_DATA | windows.FILE_EXECUTE)
489
490
491 for _, entry := range entries {
492 mask := uint32(entry.Mask)
493 actual := 0
494
495 if mask&read == read {
496 actual |= 4
497 }
498 if mask&write == write {
499 actual |= 2
500 }
501 if mask&execute == execute {
502 actual |= 1
503 }
504
505 entrySid := (*windows.SID)(unsafe.Pointer(&entry.SidStart))
506 if owner.Equals(entrySid) {
507 if actual != 7 {
508 t.Fatalf("Expected owner to have FullAccess permissions.")
509 }
510 } else if group.Equals(entrySid) {
511 if actual != 5 {
512 t.Fatalf("Expected group to have only Read and Execute permissions.")
513 }
514 } else if worldSid.Equals(entrySid) {
515 if actual != 4 {
516 t.Fatalf("Expected the World to have only Read permissions.")
517 }
518 } else {
519 t.Fatalf("Unexpected SID in ACEs: %s", entrySid.String())
520 }
521 }
522 }
523
524 func TestGetDiskFreeSpaceEx(t *testing.T) {
525 cwd, err := windows.UTF16PtrFromString(".")
526 if err != nil {
527 t.Fatalf(`failed to call UTF16PtrFromString("."): %v`, err)
528 }
529 var freeBytesAvailableToCaller, totalNumberOfBytes, totalNumberOfFreeBytes uint64
530 if err := windows.GetDiskFreeSpaceEx(cwd, &freeBytesAvailableToCaller, &totalNumberOfBytes, &totalNumberOfFreeBytes); err != nil {
531 t.Fatalf("failed to call GetDiskFreeSpaceEx: %v", err)
532 }
533
534 if freeBytesAvailableToCaller == 0 {
535 t.Errorf("freeBytesAvailableToCaller: got 0; want > 0")
536 }
537 if totalNumberOfBytes == 0 {
538 t.Errorf("totalNumberOfBytes: got 0; want > 0")
539 }
540 if totalNumberOfFreeBytes == 0 {
541 t.Errorf("totalNumberOfFreeBytes: got 0; want > 0")
542 }
543 }
544
545 func TestGetPreferredUILanguages(t *testing.T) {
546 tab := map[string]func(flags uint32) ([]string, error){
547 "GetProcessPreferredUILanguages": windows.GetProcessPreferredUILanguages,
548 "GetThreadPreferredUILanguages": windows.GetThreadPreferredUILanguages,
549 "GetUserPreferredUILanguages": windows.GetUserPreferredUILanguages,
550 "GetSystemPreferredUILanguages": windows.GetSystemPreferredUILanguages,
551 }
552 for fName, f := range tab {
553 lang, err := f(windows.MUI_LANGUAGE_ID)
554 if err != nil {
555 t.Errorf(`failed to call %v(MUI_LANGUAGE_ID): %v`, fName, err)
556 }
557 for _, l := range lang {
558 _, err := strconv.ParseUint(l, 16, 16)
559 if err != nil {
560 t.Errorf(`%v(MUI_LANGUAGE_ID) returned unexpected LANGID: %v`, fName, l)
561 }
562 }
563
564 lang, err = f(windows.MUI_LANGUAGE_NAME)
565 if err != nil {
566 t.Errorf(`failed to call %v(MUI_LANGUAGE_NAME): %v`, fName, err)
567 }
568 }
569 }
570
571 func TestProcessWorkingSetSizeEx(t *testing.T) {
572
573 hProcess := windows.CurrentProcess()
574
575
576 var minimumWorkingSetSize, maximumWorkingSetSize uintptr
577
578
579 var flag uint32
580 windows.GetProcessWorkingSetSizeEx(hProcess, &minimumWorkingSetSize, &maximumWorkingSetSize, &flag)
581
582
583 if err := windows.SetProcessWorkingSetSizeEx(hProcess, minimumWorkingSetSize, maximumWorkingSetSize, flag); err != nil {
584 t.Error(err)
585 }
586 }
587
588 func TestJobObjectInfo(t *testing.T) {
589 jo, err := windows.CreateJobObject(nil, nil)
590 if err != nil {
591 t.Fatalf("CreateJobObject failed: %v", err)
592 }
593 defer windows.CloseHandle(jo)
594
595 var info windows.JOBOBJECT_EXTENDED_LIMIT_INFORMATION
596
597 err = windows.QueryInformationJobObject(jo, windows.JobObjectExtendedLimitInformation,
598 uintptr(unsafe.Pointer(&info)), uint32(unsafe.Sizeof(info)), nil)
599 if err != nil {
600 t.Fatalf("QueryInformationJobObject failed: %v", err)
601 }
602
603 const wantMemLimit = 4 * 1024
604
605 info.BasicLimitInformation.LimitFlags |= windows.JOB_OBJECT_LIMIT_PROCESS_MEMORY
606 info.ProcessMemoryLimit = wantMemLimit
607 _, err = windows.SetInformationJobObject(jo, windows.JobObjectExtendedLimitInformation,
608 uintptr(unsafe.Pointer(&info)), uint32(unsafe.Sizeof(info)))
609 if err != nil {
610 t.Fatalf("SetInformationJobObject failed: %v", err)
611 }
612
613 err = windows.QueryInformationJobObject(jo, windows.JobObjectExtendedLimitInformation,
614 uintptr(unsafe.Pointer(&info)), uint32(unsafe.Sizeof(info)), nil)
615 if err != nil {
616 t.Fatalf("QueryInformationJobObject failed: %v", err)
617 }
618
619 if have := info.ProcessMemoryLimit; wantMemLimit != have {
620 t.Errorf("ProcessMemoryLimit is wrong: want %v have %v", wantMemLimit, have)
621 }
622 }
623
624 func TestIsWow64Process2(t *testing.T) {
625 var processMachine, nativeMachine uint16
626 err := windows.IsWow64Process2(windows.CurrentProcess(), &processMachine, &nativeMachine)
627 if errors.Is(err, windows.ERROR_PROC_NOT_FOUND) {
628 maj, min, build := windows.RtlGetNtVersionNumbers()
629 if maj < 10 || (maj == 10 && min == 0 && build < 17763) {
630 t.Skip("not available on older versions of Windows")
631 return
632 }
633 }
634 if err != nil {
635 t.Fatalf("IsWow64Process2 failed: %v", err)
636 }
637 if processMachine == pe.IMAGE_FILE_MACHINE_UNKNOWN {
638 processMachine = nativeMachine
639 }
640 switch {
641 case processMachine == pe.IMAGE_FILE_MACHINE_AMD64 && runtime.GOARCH == "amd64":
642 case processMachine == pe.IMAGE_FILE_MACHINE_I386 && runtime.GOARCH == "386":
643 case processMachine == pe.IMAGE_FILE_MACHINE_ARMNT && runtime.GOARCH == "arm":
644 case processMachine == pe.IMAGE_FILE_MACHINE_ARM64 && runtime.GOARCH == "arm64":
645 default:
646 t.Errorf("IsWow64Process2 is wrong: want %v have %v", runtime.GOARCH, processMachine)
647 }
648 }
649
650 func TestNTStatusString(t *testing.T) {
651 want := "The name limit for the local computer network adapter card was exceeded."
652 got := windows.STATUS_TOO_MANY_NAMES.Error()
653 if want != got {
654 t.Errorf("NTStatus.Error did not return an expected error string - want %q; got %q", want, got)
655 }
656 }
657
658 func TestNTStatusConversion(t *testing.T) {
659 want := windows.ERROR_TOO_MANY_NAMES
660 got := windows.STATUS_TOO_MANY_NAMES.Errno()
661 if want != got {
662 t.Errorf("NTStatus.Errno = %q (0x%x); want %q (0x%x)", got.Error(), got, want.Error(), want)
663 }
664 }
665
666 func TestPEBFilePath(t *testing.T) {
667 peb := windows.RtlGetCurrentPeb()
668 if peb == nil || peb.Ldr == nil {
669 t.Error("unable to retrieve PEB with valid Ldr")
670 }
671 var entry *windows.LDR_DATA_TABLE_ENTRY
672 for cur := peb.Ldr.InMemoryOrderModuleList.Flink; cur != &peb.Ldr.InMemoryOrderModuleList; cur = cur.Flink {
673 e := (*windows.LDR_DATA_TABLE_ENTRY)(unsafe.Pointer(uintptr(unsafe.Pointer(cur)) - unsafe.Offsetof(windows.LDR_DATA_TABLE_ENTRY{}.InMemoryOrderLinks)))
674 if e.DllBase == peb.ImageBaseAddress {
675 entry = e
676 break
677 }
678 }
679 if entry == nil {
680 t.Error("unable to find Ldr entry for current process")
681 }
682 osPath, err := os.Executable()
683 if err != nil {
684 t.Errorf("unable to get path to current executable: %v", err)
685 }
686 pebPath := entry.FullDllName.String()
687 if osPath != pebPath {
688 t.Errorf("peb.Ldr.{entry}.FullDllName = %#q; want %#q", pebPath, osPath)
689 }
690 paramPath := peb.ProcessParameters.ImagePathName.String()
691 if osPath != paramPath {
692 t.Errorf("peb.ProcessParameters.ImagePathName.{entry}.ImagePathName = %#q; want %#q", paramPath, osPath)
693 }
694 osCwd, err := os.Getwd()
695 if err != nil {
696 t.Errorf("unable to get working directory: %v", err)
697 }
698 osCwd = filepath.Clean(osCwd)
699 paramCwd := filepath.Clean(peb.ProcessParameters.CurrentDirectory.DosPath.String())
700 if paramCwd != osCwd {
701 t.Errorf("peb.ProcessParameters.CurrentDirectory.DosPath = %#q; want %#q", paramCwd, osCwd)
702 }
703 }
704
705 func TestResourceExtraction(t *testing.T) {
706 system32, err := windows.GetSystemDirectory()
707 if err != nil {
708 t.Errorf("unable to find system32 directory: %v", err)
709 }
710 cmd, err := windows.LoadLibrary(filepath.Join(system32, "cmd.exe"))
711 if err != nil {
712 t.Errorf("unable to load cmd.exe: %v", err)
713 }
714 defer windows.FreeLibrary(cmd)
715 rsrc, err := windows.FindResource(cmd, windows.CREATEPROCESS_MANIFEST_RESOURCE_ID, windows.RT_MANIFEST)
716 if err != nil {
717 t.Errorf("unable to find cmd.exe manifest resource: %v", err)
718 }
719 manifest, err := windows.LoadResourceData(cmd, rsrc)
720 if err != nil {
721 t.Errorf("unable to load cmd.exe manifest resource data: %v", err)
722 }
723 if !bytes.Contains(manifest, []byte("</assembly>")) {
724 t.Errorf("did not find </assembly> in manifest")
725 }
726 }
727
728 func FuzzComposeCommandLine(f *testing.F) {
729 f.Add(`C:\foo.exe /bar /baz "-bag qux"`)
730 f.Add(`"C:\Program Files\Go\bin\go.exe" env`)
731 f.Add(`C:\"Program Files"\Go\bin\go.exe env`)
732 f.Add(`C:\"Program Files"\Go\bin\go.exe env`)
733 f.Add(`C:\"Pro"gram Files\Go\bin\go.exe env`)
734 f.Add(``)
735 f.Add(` `)
736 f.Add(`W\"0`)
737 f.Add("\"\f")
738 f.Add("\f")
739 f.Add("\x16")
740 f.Add(`"" ` + strings.Repeat("a", 8193))
741 f.Add(strings.Repeat(`"" `, 8193))
742
743 f.Add("\x00abcd")
744 f.Add("ab\x00cd")
745 f.Add("abcd\x00")
746 f.Add("\x00abcd\x00")
747 f.Add("\x00ab\x00cd\x00")
748 f.Add("\x00\x00\x00")
749 f.Add("\x16\x00\x16")
750 f.Add(`C:\Program Files\Go\bin\go.exe` + "\x00env")
751 f.Add(`"C:\Program Files\Go\bin\go.exe"` + "\x00env")
752 f.Add(`C:\"Program Files"\Go\bin\go.exe` + "\x00env")
753 f.Add(`C:\"Pro"gram Files\Go\bin\go.exe` + "\x00env")
754 f.Add("\x00" + strings.Repeat("a", 8192))
755 f.Add("\x00" + strings.Repeat("a", 8193))
756 f.Add(strings.Repeat("\x00"+strings.Repeat("a", 8192), 4))
757
758 f.Fuzz(func(t *testing.T, s string) {
759
760
761
762
763
764
765
766
767 args, err := windows.DecomposeCommandLine(s)
768 argsFromSplit := false
769
770 if err == nil {
771 if testing.Verbose() {
772 t.Logf("DecomposeCommandLine(%#q) = %#q", s, args)
773 }
774 } else {
775 t.Logf("DecomposeCommandLine: %v", err)
776 if !strings.Contains(s, "\x00") {
777
778
779
780
781
782 t.Fatal("(error unexpected)")
783 }
784
785
786
787 args = strings.Split(s, "\x00")
788 argsFromSplit = true
789 for i, arg := range args {
790 if !utf8.ValidString(arg) {
791
792
793
794 t.Skipf("skipping: input %d is not valid UTF-8", i)
795 }
796 }
797 if testing.Verbose() {
798 t.Logf("using input: %#q", args)
799 }
800 }
801
802
803
804
805 commandLine := windows.ComposeCommandLine(args)
806 t.Logf("ComposeCommandLine(_) = %#q", commandLine)
807
808 got, err := windows.DecomposeCommandLine(commandLine)
809 if err != nil {
810 t.Fatalf("DecomposeCommandLine: unexpected error: %v", err)
811 }
812 if testing.Verbose() {
813 t.Logf("DecomposeCommandLine(_) = %#q", got)
814 }
815
816 var badMatches []int
817 for i := range args {
818 if i >= len(got) {
819 badMatches = append(badMatches, i)
820 continue
821 }
822 want := args[i]
823 if got[i] != want {
824 if i == 0 && argsFromSplit {
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845 if got[i] == strings.ReplaceAll(want, `"`, ``) {
846 continue
847 }
848 }
849 badMatches = append(badMatches, i)
850 }
851 }
852 if len(badMatches) != 0 {
853 t.Errorf("Incorrect decomposition at indices: %v", badMatches)
854 }
855 })
856 }
857
858 func TestWinVerifyTrust(t *testing.T) {
859 evsignedfile := `.\testdata\ev-signed-file.exe`
860 evsignedfile16, err := windows.UTF16PtrFromString(evsignedfile)
861 if err != nil {
862 t.Fatalf("unable to get utf16 of %s: %v", evsignedfile, err)
863 }
864 data := &windows.WinTrustData{
865 Size: uint32(unsafe.Sizeof(windows.WinTrustData{})),
866 UIChoice: windows.WTD_UI_NONE,
867 RevocationChecks: windows.WTD_REVOKE_NONE,
868 UnionChoice: windows.WTD_CHOICE_FILE,
869 StateAction: windows.WTD_STATEACTION_VERIFY,
870 FileOrCatalogOrBlobOrSgnrOrCert: unsafe.Pointer(&windows.WinTrustFileInfo{
871 Size: uint32(unsafe.Sizeof(windows.WinTrustFileInfo{})),
872 FilePath: evsignedfile16,
873 }),
874 }
875 verifyErr := windows.WinVerifyTrustEx(windows.InvalidHWND, &windows.WINTRUST_ACTION_GENERIC_VERIFY_V2, data)
876 data.StateAction = windows.WTD_STATEACTION_CLOSE
877 closeErr := windows.WinVerifyTrustEx(windows.InvalidHWND, &windows.WINTRUST_ACTION_GENERIC_VERIFY_V2, data)
878 if verifyErr != nil {
879 t.Errorf("%s did not verify: %v", evsignedfile, verifyErr)
880 }
881 if closeErr != nil {
882 t.Errorf("unable to free verification resources: %v", closeErr)
883 }
884
885
886
887 corruptedEvsignedfile := filepath.Join(t.TempDir(), "corrupted-file")
888 evsignedfileBytes, err := os.ReadFile(evsignedfile)
889 if err != nil {
890 t.Fatalf("unable to read %s bytes: %v", evsignedfile, err)
891 }
892 if len(evsignedfileBytes) > 0 {
893 evsignedfileBytes[len(evsignedfileBytes)/2-1]++
894 }
895 err = os.WriteFile(corruptedEvsignedfile, evsignedfileBytes, 0755)
896 if err != nil {
897 t.Fatalf("unable to write corrupted ntoskrnl.exe bytes: %v", err)
898 }
899 evsignedfile16, err = windows.UTF16PtrFromString(corruptedEvsignedfile)
900 if err != nil {
901 t.Fatalf("unable to get utf16 of ntoskrnl.exe: %v", err)
902 }
903 data = &windows.WinTrustData{
904 Size: uint32(unsafe.Sizeof(windows.WinTrustData{})),
905 UIChoice: windows.WTD_UI_NONE,
906 RevocationChecks: windows.WTD_REVOKE_NONE,
907 UnionChoice: windows.WTD_CHOICE_FILE,
908 StateAction: windows.WTD_STATEACTION_VERIFY,
909 FileOrCatalogOrBlobOrSgnrOrCert: unsafe.Pointer(&windows.WinTrustFileInfo{
910 Size: uint32(unsafe.Sizeof(windows.WinTrustFileInfo{})),
911 FilePath: evsignedfile16,
912 }),
913 }
914 verifyErr = windows.WinVerifyTrustEx(windows.InvalidHWND, &windows.WINTRUST_ACTION_GENERIC_VERIFY_V2, data)
915 data.StateAction = windows.WTD_STATEACTION_CLOSE
916 closeErr = windows.WinVerifyTrustEx(windows.InvalidHWND, &windows.WINTRUST_ACTION_GENERIC_VERIFY_V2, data)
917 if verifyErr != windows.Errno(windows.TRUST_E_BAD_DIGEST) {
918 t.Errorf("%s did not fail to verify as expected: %v", corruptedEvsignedfile, verifyErr)
919 }
920 if closeErr != nil {
921 t.Errorf("unable to free verification resources: %v", closeErr)
922 }
923
924 }
925
926 func TestEnumProcesses(t *testing.T) {
927 var (
928 pids [2]uint32
929 outSize uint32
930 )
931 err := windows.EnumProcesses(pids[:], &outSize)
932 if err != nil {
933 t.Fatalf("unable to enumerate processes: %v", err)
934 }
935
936
937 if outSize != 8 {
938 t.Errorf("unexpected bytes returned: %d", outSize)
939 }
940
941
942
943 if pids[0] == 0 && pids[1] == 0 {
944 t.Errorf("all PIDs are 0")
945 }
946 }
947
948 func TestProcessModules(t *testing.T) {
949 process, err := windows.GetCurrentProcess()
950 if err != nil {
951 t.Fatalf("unable to get current process: %v", err)
952 }
953
954 var module windows.Handle
955 var cbNeeded uint32
956 err = windows.EnumProcessModules(process, &module, uint32(unsafe.Sizeof(module)), &cbNeeded)
957 if err != nil {
958 t.Fatalf("EnumProcessModules failed: %v", err)
959 }
960
961 var moduleEx windows.Handle
962 err = windows.EnumProcessModulesEx(process, &moduleEx, uint32(unsafe.Sizeof(moduleEx)), &cbNeeded, windows.LIST_MODULES_DEFAULT)
963 if err != nil {
964 t.Fatalf("EnumProcessModulesEx failed: %v", err)
965 }
966 if module != moduleEx {
967 t.Fatalf("module from EnumProcessModules does not match EnumProcessModulesEx: %v != %v", module, moduleEx)
968 }
969
970 exePath, err := os.Executable()
971 if err != nil {
972 t.Fatalf("unable to get current executable path: %v", err)
973 }
974
975 modulePathUTF16 := make([]uint16, len(exePath)+1)
976 err = windows.GetModuleFileNameEx(process, module, &modulePathUTF16[0], uint32(len(modulePathUTF16)))
977 if err != nil {
978 t.Fatalf("GetModuleFileNameEx failed: %v", err)
979 }
980
981 modulePath := windows.UTF16ToString(modulePathUTF16)
982 if modulePath != exePath {
983 t.Fatalf("module does not match executable for GetModuleFileNameEx: %s != %s", modulePath, exePath)
984 }
985
986 err = windows.GetModuleBaseName(process, module, &modulePathUTF16[0], uint32(len(modulePathUTF16)))
987 if err != nil {
988 t.Fatalf("GetModuleBaseName failed: %v", err)
989 }
990
991 modulePath = windows.UTF16ToString(modulePathUTF16)
992 baseExePath := filepath.Base(exePath)
993 if modulePath != baseExePath {
994 t.Fatalf("module does not match executable for GetModuleBaseName: %s != %s", modulePath, baseExePath)
995 }
996
997 var moduleInfo windows.ModuleInfo
998 err = windows.GetModuleInformation(process, module, &moduleInfo, uint32(unsafe.Sizeof(moduleInfo)))
999 if err != nil {
1000 t.Fatalf("GetModuleInformation failed: %v", err)
1001 }
1002
1003 peFile, err := pe.Open(exePath)
1004 if err != nil {
1005 t.Fatalf("unable to open current executable: %v", err)
1006 }
1007 defer peFile.Close()
1008
1009 var peSizeOfImage uint32
1010 switch runtime.GOARCH {
1011 case "amd64", "arm64":
1012 peSizeOfImage = peFile.OptionalHeader.(*pe.OptionalHeader64).SizeOfImage
1013 case "386", "arm":
1014 peSizeOfImage = peFile.OptionalHeader.(*pe.OptionalHeader32).SizeOfImage
1015 default:
1016 t.Fatalf("unable to test GetModuleInformation on arch %v", runtime.GOARCH)
1017 }
1018
1019 if moduleInfo.SizeOfImage != peSizeOfImage {
1020 t.Fatalf("module size does not match executable: %v != %v", moduleInfo.SizeOfImage, peSizeOfImage)
1021 }
1022 }
1023
1024 func TestQueryWorkingSetEx(t *testing.T) {
1025 var a int
1026
1027 process := windows.CurrentProcess()
1028 information := windows.PSAPI_WORKING_SET_EX_INFORMATION{
1029 VirtualAddress: windows.Pointer(unsafe.Pointer(&a)),
1030 }
1031 infos := []windows.PSAPI_WORKING_SET_EX_INFORMATION{information}
1032
1033 cb := uint32(uintptr(len(infos)) * unsafe.Sizeof(infos[0]))
1034 if err := windows.QueryWorkingSetEx(process, uintptr(unsafe.Pointer(&infos[0])), cb); err != nil {
1035 t.Fatalf("%+v", err)
1036 }
1037
1038 if !infos[0].VirtualAttributes.Valid() {
1039 t.Errorf("memory location not valid")
1040 }
1041 }
1042
1043 func TestReadWriteProcessMemory(t *testing.T) {
1044 testBuffer := []byte{0xBA, 0xAD, 0xF0, 0x0D}
1045
1046 process, err := windows.GetCurrentProcess()
1047 if err != nil {
1048 t.Fatalf("unable to get current process: %v", err)
1049 }
1050
1051 buffer := make([]byte, len(testBuffer))
1052 err = windows.ReadProcessMemory(process, uintptr(unsafe.Pointer(&testBuffer[0])), &buffer[0], uintptr(len(buffer)), nil)
1053 if err != nil {
1054 t.Errorf("ReadProcessMemory failed: %v", err)
1055 }
1056 if !bytes.Equal(testBuffer, buffer) {
1057 t.Errorf("bytes read does not match buffer: 0x%X != 0x%X", testBuffer, buffer)
1058 }
1059
1060 buffer = []byte{0xDE, 0xAD, 0xBE, 0xEF}
1061 err = windows.WriteProcessMemory(process, uintptr(unsafe.Pointer(&testBuffer[0])), &buffer[0], uintptr(len(buffer)), nil)
1062 if err != nil {
1063 t.Errorf("WriteProcessMemory failed: %v", err)
1064 }
1065 if !bytes.Equal(testBuffer, buffer) {
1066 t.Errorf("bytes written does not match buffer: 0x%X != 0x%X", testBuffer, buffer)
1067 }
1068 }
1069
1070 func TestSystemModuleVersions(t *testing.T) {
1071 var modules []windows.RTL_PROCESS_MODULE_INFORMATION
1072 for bufferSize := uint32(128 * 1024); ; {
1073 moduleBuffer := make([]byte, bufferSize)
1074 err := windows.NtQuerySystemInformation(windows.SystemModuleInformation, unsafe.Pointer(&moduleBuffer[0]), bufferSize, &bufferSize)
1075 switch err {
1076 case windows.STATUS_INFO_LENGTH_MISMATCH:
1077 continue
1078 case nil:
1079 break
1080 default:
1081 t.Error(err)
1082 return
1083 }
1084 mods := (*windows.RTL_PROCESS_MODULES)(unsafe.Pointer(&moduleBuffer[0]))
1085 modules = unsafe.Slice(&mods.Modules[0], int(mods.NumberOfModules))
1086 break
1087 }
1088 for i := range modules {
1089 moduleName := windows.ByteSliceToString(modules[i].FullPathName[modules[i].OffsetToFileName:])
1090 driverPath := `\\?\GLOBALROOT` + windows.ByteSliceToString(modules[i].FullPathName[:])
1091 var zero windows.Handle
1092 infoSize, err := windows.GetFileVersionInfoSize(driverPath, &zero)
1093 if err != nil {
1094 if err != windows.ERROR_FILE_NOT_FOUND && err != windows.ERROR_RESOURCE_TYPE_NOT_FOUND {
1095 t.Errorf("%v: %v", moduleName, err)
1096 }
1097 continue
1098 }
1099 versionInfo := make([]byte, infoSize)
1100 if err = windows.GetFileVersionInfo(driverPath, 0, infoSize, unsafe.Pointer(&versionInfo[0])); err != nil {
1101 t.Errorf("%v: %v", moduleName, err)
1102 continue
1103 }
1104 var fixedInfo *windows.VS_FIXEDFILEINFO
1105 fixedInfoLen := uint32(unsafe.Sizeof(*fixedInfo))
1106 err = windows.VerQueryValue(unsafe.Pointer(&versionInfo[0]), `\`, (unsafe.Pointer)(&fixedInfo), &fixedInfoLen)
1107 if err != nil {
1108 t.Errorf("%v: %v", moduleName, err)
1109 continue
1110 }
1111 t.Logf("%s: v%d.%d.%d.%d", moduleName,
1112 (fixedInfo.FileVersionMS>>16)&0xff,
1113 (fixedInfo.FileVersionMS>>0)&0xff,
1114 (fixedInfo.FileVersionLS>>16)&0xff,
1115 (fixedInfo.FileVersionLS>>0)&0xff)
1116 }
1117 }
1118
1119 type fileRenameInformation struct {
1120 ReplaceIfExists uint32
1121 RootDirectory windows.Handle
1122 FileNameLength uint32
1123 FileName [1]uint16
1124 }
1125
1126 func TestNtCreateFileAndNtSetInformationFile(t *testing.T) {
1127 var iosb windows.IO_STATUS_BLOCK
1128 var allocSize int64 = 0
1129
1130 testDirPath := t.TempDir()
1131 objectName, err := windows.NewNTUnicodeString("\\??\\" + testDirPath)
1132 if err != nil {
1133 t.Fatal(err)
1134 }
1135 oa := &windows.OBJECT_ATTRIBUTES{
1136 ObjectName: objectName,
1137 }
1138 oa.Length = uint32(unsafe.Sizeof(*oa))
1139 var testDirHandle windows.Handle
1140 err = windows.NtCreateFile(&testDirHandle, windows.FILE_GENERIC_READ|windows.FILE_GENERIC_WRITE, oa, &iosb,
1141 &allocSize, 0, windows.FILE_SHARE_READ|windows.FILE_SHARE_WRITE|windows.FILE_SHARE_DELETE, windows.FILE_OPEN,
1142 windows.FILE_DIRECTORY_FILE, 0, 0)
1143 if err != nil {
1144 t.Fatalf("NtCreateFile(%v) failed: %v", testDirPath, err)
1145 }
1146 defer windows.CloseHandle(testDirHandle)
1147
1148 fileName := "filename"
1149 filePath := filepath.Join(testDirPath, fileName)
1150 objectName, err = windows.NewNTUnicodeString(fileName)
1151 if err != nil {
1152 t.Fatal(err)
1153 }
1154 oa.RootDirectory = testDirHandle
1155 oa.ObjectName = objectName
1156 var fileHandle windows.Handle
1157 err = windows.NtCreateFile(&fileHandle, windows.FILE_GENERIC_READ|windows.FILE_GENERIC_WRITE|windows.DELETE, oa, &iosb,
1158 &allocSize, 0, windows.FILE_SHARE_READ|windows.FILE_SHARE_WRITE|windows.FILE_SHARE_DELETE, windows.FILE_CREATE,
1159 0, 0, 0)
1160 if err != nil {
1161 t.Fatalf("NtCreateFile(%v) failed: %v", filePath, err)
1162 }
1163 defer windows.CloseHandle(fileHandle)
1164 _, err = os.Stat(filePath)
1165 if err != nil {
1166 t.Fatalf("cannot stat file created with NtCreatefile: %v", err)
1167 }
1168
1169 newName := "newname"
1170 newPath := filepath.Join(testDirPath, newName)
1171 newNameUTF16, err := windows.UTF16FromString(newName)
1172 if err != nil {
1173 t.Fatal(err)
1174 }
1175 fileNameLen := len(newNameUTF16)*2 - 2
1176 var dummyFileRenameInfo fileRenameInformation
1177 bufferSize := int(unsafe.Offsetof(dummyFileRenameInfo.FileName)) + fileNameLen
1178 buffer := make([]byte, bufferSize)
1179 typedBufferPtr := (*fileRenameInformation)(unsafe.Pointer(&buffer[0]))
1180 typedBufferPtr.ReplaceIfExists = windows.FILE_RENAME_REPLACE_IF_EXISTS | windows.FILE_RENAME_POSIX_SEMANTICS
1181 typedBufferPtr.FileNameLength = uint32(fileNameLen)
1182 copy((*[windows.MAX_LONG_PATH]uint16)(unsafe.Pointer(&typedBufferPtr.FileName[0]))[:fileNameLen/2:fileNameLen/2], newNameUTF16)
1183 err = windows.NtSetInformationFile(fileHandle, &iosb, &buffer[0], uint32(bufferSize), windows.FileRenameInformation)
1184 if err != nil {
1185 t.Fatalf("NtSetInformationFile(%v) failed: %v", newPath, err)
1186 }
1187 _, err = os.Stat(newPath)
1188 if err != nil {
1189 t.Fatalf("cannot stat rename target %v: %v", newPath, err)
1190 }
1191 }
1192
1193 var deviceClassNetGUID = &windows.GUID{0x4d36e972, 0xe325, 0x11ce, [8]byte{0xbf, 0xc1, 0x08, 0x00, 0x2b, 0xe1, 0x03, 0x18}}
1194 var deviceInterfaceNetGUID = &windows.GUID{0xcac88484, 0x7515, 0x4c03, [8]byte{0x82, 0xe6, 0x71, 0xa8, 0x7a, 0xba, 0xc3, 0x61}}
1195
1196 func TestListLoadedNetworkDevices(t *testing.T) {
1197 devInfo, err := windows.SetupDiGetClassDevsEx(deviceClassNetGUID, "", 0, windows.DIGCF_PRESENT, 0, "")
1198 if err != nil {
1199 t.Fatal(err)
1200 }
1201 defer devInfo.Close()
1202 for i := 0; ; i++ {
1203 devInfoData, err := devInfo.EnumDeviceInfo(i)
1204 if err != nil {
1205 if err == windows.ERROR_NO_MORE_ITEMS {
1206 break
1207 }
1208 continue
1209 }
1210 friendlyName, err := devInfo.DeviceRegistryProperty(devInfoData, windows.SPDRP_DEVICEDESC)
1211 if err != nil {
1212 t.Fatal(err)
1213 }
1214 var status, problemCode uint32
1215 err = windows.CM_Get_DevNode_Status(&status, &problemCode, devInfoData.DevInst, 0)
1216 if err != nil || (status&windows.DN_DRIVER_LOADED|windows.DN_STARTED) != windows.DN_DRIVER_LOADED|windows.DN_STARTED {
1217 continue
1218 }
1219 instanceId, err := devInfo.DeviceInstanceID(devInfoData)
1220 if err != nil {
1221 t.Fatal(err)
1222 }
1223 interfaces, err := windows.CM_Get_Device_Interface_List(instanceId, deviceInterfaceNetGUID, windows.CM_GET_DEVICE_INTERFACE_LIST_PRESENT)
1224 if err != nil || len(interfaces) == 0 {
1225 continue
1226 }
1227 t.Logf("%s - %s", friendlyName, interfaces[0])
1228 }
1229 }
1230
1231 func TestListWireGuardDrivers(t *testing.T) {
1232 devInfo, err := windows.SetupDiCreateDeviceInfoListEx(deviceClassNetGUID, 0, "")
1233 if err != nil {
1234 t.Fatal(err)
1235 }
1236 defer devInfo.Close()
1237 devInfoData, err := devInfo.CreateDeviceInfo("WireGuard", deviceClassNetGUID, "", 0, windows.DICD_GENERATE_ID)
1238 if err != nil {
1239 t.Fatal(err)
1240 }
1241 err = devInfo.SetDeviceRegistryProperty(devInfoData, windows.SPDRP_HARDWAREID, []byte("W\x00i\x00r\x00e\x00G\x00u\x00a\x00r\x00d\x00\x00\x00\x00\x00"))
1242 if err != nil {
1243 t.Fatal(err)
1244 }
1245 err = devInfo.BuildDriverInfoList(devInfoData, windows.SPDIT_COMPATDRIVER)
1246 if err != nil {
1247 t.Fatal(err)
1248 }
1249 defer devInfo.DestroyDriverInfoList(devInfoData, windows.SPDIT_COMPATDRIVER)
1250 for i := 0; ; i++ {
1251 drvInfoData, err := devInfo.EnumDriverInfo(devInfoData, windows.SPDIT_COMPATDRIVER, i)
1252 if err != nil {
1253 if err == windows.ERROR_NO_MORE_ITEMS {
1254 break
1255 }
1256 continue
1257 }
1258 drvInfoDetailData, err := devInfo.DriverInfoDetail(devInfoData, drvInfoData)
1259 if err != nil {
1260 t.Error(err)
1261 continue
1262 }
1263 t.Logf("%s - %s", drvInfoData.Description(), drvInfoDetailData.InfFileName())
1264 }
1265 }
1266
1267 func TestProcThreadAttributeHandleList(t *testing.T) {
1268 const sentinel = "the gopher dance"
1269 system32, err := windows.GetSystemDirectory()
1270 if err != nil {
1271 t.Fatal(err)
1272 }
1273 executable16, err := windows.UTF16PtrFromString(filepath.Join(system32, "cmd.exe"))
1274 if err != nil {
1275 t.Fatal(err)
1276 }
1277 args16, err := windows.UTF16PtrFromString(windows.ComposeCommandLine([]string{"/c", "echo " + sentinel}))
1278 if err != nil {
1279 t.Fatal(err)
1280 }
1281 attributeList, err := windows.NewProcThreadAttributeList(1)
1282 if err != nil {
1283 t.Fatal(err)
1284 }
1285 defer attributeList.Delete()
1286 si := &windows.StartupInfoEx{
1287 StartupInfo: windows.StartupInfo{Cb: uint32(unsafe.Sizeof(windows.StartupInfoEx{}))},
1288 ProcThreadAttributeList: attributeList.List(),
1289 }
1290 pipeR, pipeW, err := os.Pipe()
1291 if err != nil {
1292 t.Fatal(err)
1293 }
1294 defer pipeR.Close()
1295 defer pipeW.Close()
1296 func() {
1297
1298 handles := []windows.Handle{windows.Handle(pipeW.Fd())}
1299 attributeList.Update(windows.PROC_THREAD_ATTRIBUTE_HANDLE_LIST, unsafe.Pointer(&handles[0]), uintptr(len(handles))*unsafe.Sizeof(handles[0]))
1300 si.Flags |= windows.STARTF_USESTDHANDLES
1301 si.StdOutput = handles[0]
1302
1303 windows.SetHandleInformation(handles[0], windows.HANDLE_FLAG_INHERIT, windows.HANDLE_FLAG_INHERIT)
1304 }()
1305 pi := new(windows.ProcessInformation)
1306 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)
1307 if err != nil {
1308 t.Fatal(err)
1309 }
1310 defer windows.CloseHandle(pi.Thread)
1311 defer windows.CloseHandle(pi.Process)
1312 pipeR.SetReadDeadline(time.Now().Add(time.Minute))
1313 out, _, err := bufio.NewReader(pipeR).ReadLine()
1314 if err != nil {
1315 t.Fatal(err)
1316 }
1317 if string(out) != sentinel {
1318 t.Fatalf("got %q; want %q", out, sentinel)
1319 }
1320 }
1321
1322 func TestWSALookupService(t *testing.T) {
1323 var flags uint32 = windows.LUP_CONTAINERS
1324 flags |= windows.LUP_RETURN_NAME
1325 flags |= windows.LUP_RETURN_ADDR
1326
1327 var querySet windows.WSAQUERYSET
1328 querySet.NameSpace = windows.NS_BTH
1329 querySet.Size = uint32(unsafe.Sizeof(windows.WSAQUERYSET{}))
1330
1331 var handle windows.Handle
1332 err := windows.WSALookupServiceBegin(&querySet, flags, &handle)
1333 if err != nil {
1334 if errors.Is(err, windows.WSASERVICE_NOT_FOUND) {
1335 t.Skip("WSA Service not found, so skip this test")
1336 }
1337 t.Fatal(err)
1338 }
1339
1340 defer windows.WSALookupServiceEnd(handle)
1341
1342 n := int32(unsafe.Sizeof(windows.WSAQUERYSET{}))
1343 buf := make([]byte, n)
1344 items_loop:
1345 for {
1346 q := (*windows.WSAQUERYSET)(unsafe.Pointer(&buf[0]))
1347 err := windows.WSALookupServiceNext(handle, flags, &n, q)
1348 switch err {
1349 case windows.WSA_E_NO_MORE, windows.WSAENOMORE:
1350
1351 break items_loop
1352 case windows.WSAEFAULT:
1353
1354 buf = make([]byte, n)
1355 case nil:
1356
1357 var addr string
1358 for _, e := range q.SaBuffer.RemoteAddr.Sockaddr.Addr.Data {
1359 if e != 0 {
1360 addr += fmt.Sprintf("%x", e)
1361 }
1362 }
1363 t.Logf("%s -> %s\n", windows.UTF16PtrToString(q.ServiceInstanceName), addr)
1364
1365 default:
1366 t.Fatal(err)
1367 }
1368 }
1369 }
1370
1371 func TestTimePeriod(t *testing.T) {
1372 if err := windows.TimeBeginPeriod(1); err != nil {
1373 t.Fatal(err)
1374 }
1375 if err := windows.TimeEndPeriod(1); err != nil {
1376 t.Fatal(err)
1377 }
1378 }
1379
1380 func TestGetStartupInfo(t *testing.T) {
1381 var si windows.StartupInfo
1382 err := windows.GetStartupInfo(&si)
1383 if err != nil {
1384
1385 t.Fatalf("GetStartupInfo: got error %v, want nil", err)
1386 }
1387 }
1388
1389 func TestAddRemoveDllDirectory(t *testing.T) {
1390 if _, err := exec.LookPath("gcc"); err != nil {
1391 t.Skip("skipping test: gcc is missing")
1392 }
1393 dllSrc := `#include <stdint.h>
1394 #include <windows.h>
1395
1396 uintptr_t beep(void) {
1397 return 5;
1398 }`
1399 tmpdir := t.TempDir()
1400 srcname := "beep.c"
1401 err := os.WriteFile(filepath.Join(tmpdir, srcname), []byte(dllSrc), 0)
1402 if err != nil {
1403 t.Fatal(err)
1404 }
1405 name := "beep.dll"
1406 cmd := exec.Command("gcc", "-shared", "-s", "-Werror", "-o", name, srcname)
1407 cmd.Dir = tmpdir
1408 out, err := cmd.CombinedOutput()
1409 if err != nil {
1410 t.Fatalf("failed to build dll: %v - %v", err, string(out))
1411 }
1412
1413 if _, err := windows.LoadLibraryEx("beep.dll", 0, windows.LOAD_LIBRARY_SEARCH_USER_DIRS); err == nil {
1414 t.Fatal("LoadLibraryEx unexpectedly found beep.dll")
1415 }
1416
1417 dllCookie, err := windows.AddDllDirectory(windows.StringToUTF16Ptr(tmpdir))
1418 if err != nil {
1419 t.Fatalf("AddDllDirectory failed: %s", err)
1420 }
1421
1422 handle, err := windows.LoadLibraryEx("beep.dll", 0, windows.LOAD_LIBRARY_SEARCH_USER_DIRS)
1423 if err != nil {
1424 t.Fatalf("LoadLibraryEx failed: %s", err)
1425 }
1426
1427 if err := windows.FreeLibrary(handle); err != nil {
1428 t.Fatalf("FreeLibrary failed: %s", err)
1429 }
1430
1431 if err := windows.RemoveDllDirectory(dllCookie); err != nil {
1432 t.Fatalf("RemoveDllDirectory failed: %s", err)
1433 }
1434
1435 _, err = windows.LoadLibraryEx("beep.dll", 0, windows.LOAD_LIBRARY_SEARCH_USER_DIRS)
1436 if err == nil {
1437 t.Fatal("LoadLibraryEx unexpectedly found beep.dll")
1438 }
1439 }
1440
1441 func TestToUnicodeEx(t *testing.T) {
1442 var utf16Buf [16]uint16
1443
1444
1445
1446 ara, err := windows.UTF16PtrFromString("00000401")
1447 if err != nil {
1448 t.Fatalf("UTF16PtrFromString failed: %v", err)
1449 }
1450 araLayout, err := windows.LoadKeyboardLayout(ara, windows.KLF_ACTIVATE)
1451 if err != nil {
1452 t.Fatalf("LoadKeyboardLayout failed: %v", err)
1453 }
1454
1455 var keyState [256]byte
1456 ret := windows.ToUnicodeEx(
1457 0x41,
1458 0x1e,
1459 &keyState[0],
1460 &utf16Buf[0],
1461 int32(len(utf16Buf)),
1462 0x4,
1463 araLayout,
1464 )
1465
1466 if ret != 1 {
1467 t.Errorf("ToUnicodeEx failed, wanted 1, got %d", ret)
1468 }
1469 if utf16Buf[0] != 'ش' {
1470 t.Errorf("ToUnicodeEx failed, wanted 'ش', got %q", utf16Buf[0])
1471 }
1472 if err := windows.UnloadKeyboardLayout(araLayout); err != nil {
1473 t.Errorf("UnloadKeyboardLayout failed: %v", err)
1474 }
1475 }
1476
View as plain text