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 func TestGetDiskFreeSpaceEx(t *testing.T) {
363 cwd, err := windows.UTF16PtrFromString(".")
364 if err != nil {
365 t.Fatalf(`failed to call UTF16PtrFromString("."): %v`, err)
366 }
367 var freeBytesAvailableToCaller, totalNumberOfBytes, totalNumberOfFreeBytes uint64
368 if err := windows.GetDiskFreeSpaceEx(cwd, &freeBytesAvailableToCaller, &totalNumberOfBytes, &totalNumberOfFreeBytes); err != nil {
369 t.Fatalf("failed to call GetDiskFreeSpaceEx: %v", err)
370 }
371
372 if freeBytesAvailableToCaller == 0 {
373 t.Errorf("freeBytesAvailableToCaller: got 0; want > 0")
374 }
375 if totalNumberOfBytes == 0 {
376 t.Errorf("totalNumberOfBytes: got 0; want > 0")
377 }
378 if totalNumberOfFreeBytes == 0 {
379 t.Errorf("totalNumberOfFreeBytes: got 0; want > 0")
380 }
381 }
382
383 func TestGetPreferredUILanguages(t *testing.T) {
384 tab := map[string]func(flags uint32) ([]string, error){
385 "GetProcessPreferredUILanguages": windows.GetProcessPreferredUILanguages,
386 "GetThreadPreferredUILanguages": windows.GetThreadPreferredUILanguages,
387 "GetUserPreferredUILanguages": windows.GetUserPreferredUILanguages,
388 "GetSystemPreferredUILanguages": windows.GetSystemPreferredUILanguages,
389 }
390 for fName, f := range tab {
391 lang, err := f(windows.MUI_LANGUAGE_ID)
392 if err != nil {
393 t.Errorf(`failed to call %v(MUI_LANGUAGE_ID): %v`, fName, err)
394 }
395 for _, l := range lang {
396 _, err := strconv.ParseUint(l, 16, 16)
397 if err != nil {
398 t.Errorf(`%v(MUI_LANGUAGE_ID) returned unexpected LANGID: %v`, fName, l)
399 }
400 }
401
402 lang, err = f(windows.MUI_LANGUAGE_NAME)
403 if err != nil {
404 t.Errorf(`failed to call %v(MUI_LANGUAGE_NAME): %v`, fName, err)
405 }
406 }
407 }
408
409 func TestProcessWorkingSetSizeEx(t *testing.T) {
410
411 hProcess := windows.CurrentProcess()
412
413
414 var minimumWorkingSetSize, maximumWorkingSetSize uintptr
415
416
417 var flag uint32
418 windows.GetProcessWorkingSetSizeEx(hProcess, &minimumWorkingSetSize, &maximumWorkingSetSize, &flag)
419
420
421 if err := windows.SetProcessWorkingSetSizeEx(hProcess, minimumWorkingSetSize, maximumWorkingSetSize, flag); err != nil {
422 t.Error(err)
423 }
424 }
425
426 func TestJobObjectInfo(t *testing.T) {
427 jo, err := windows.CreateJobObject(nil, nil)
428 if err != nil {
429 t.Fatalf("CreateJobObject failed: %v", err)
430 }
431 defer windows.CloseHandle(jo)
432
433 var info windows.JOBOBJECT_EXTENDED_LIMIT_INFORMATION
434
435 err = windows.QueryInformationJobObject(jo, windows.JobObjectExtendedLimitInformation,
436 uintptr(unsafe.Pointer(&info)), uint32(unsafe.Sizeof(info)), nil)
437 if err != nil {
438 t.Fatalf("QueryInformationJobObject failed: %v", err)
439 }
440
441 const wantMemLimit = 4 * 1024
442
443 info.BasicLimitInformation.LimitFlags |= windows.JOB_OBJECT_LIMIT_PROCESS_MEMORY
444 info.ProcessMemoryLimit = wantMemLimit
445 _, err = windows.SetInformationJobObject(jo, windows.JobObjectExtendedLimitInformation,
446 uintptr(unsafe.Pointer(&info)), uint32(unsafe.Sizeof(info)))
447 if err != nil {
448 t.Fatalf("SetInformationJobObject failed: %v", err)
449 }
450
451 err = windows.QueryInformationJobObject(jo, windows.JobObjectExtendedLimitInformation,
452 uintptr(unsafe.Pointer(&info)), uint32(unsafe.Sizeof(info)), nil)
453 if err != nil {
454 t.Fatalf("QueryInformationJobObject failed: %v", err)
455 }
456
457 if have := info.ProcessMemoryLimit; wantMemLimit != have {
458 t.Errorf("ProcessMemoryLimit is wrong: want %v have %v", wantMemLimit, have)
459 }
460 }
461
462 func TestIsWow64Process2(t *testing.T) {
463 var processMachine, nativeMachine uint16
464 err := windows.IsWow64Process2(windows.CurrentProcess(), &processMachine, &nativeMachine)
465 if errors.Is(err, windows.ERROR_PROC_NOT_FOUND) {
466 maj, min, build := windows.RtlGetNtVersionNumbers()
467 if maj < 10 || (maj == 10 && min == 0 && build < 17763) {
468 t.Skip("not available on older versions of Windows")
469 return
470 }
471 }
472 if err != nil {
473 t.Fatalf("IsWow64Process2 failed: %v", err)
474 }
475 if processMachine == pe.IMAGE_FILE_MACHINE_UNKNOWN {
476 processMachine = nativeMachine
477 }
478 switch {
479 case processMachine == pe.IMAGE_FILE_MACHINE_AMD64 && runtime.GOARCH == "amd64":
480 case processMachine == pe.IMAGE_FILE_MACHINE_I386 && runtime.GOARCH == "386":
481 case processMachine == pe.IMAGE_FILE_MACHINE_ARMNT && runtime.GOARCH == "arm":
482 case processMachine == pe.IMAGE_FILE_MACHINE_ARM64 && runtime.GOARCH == "arm64":
483 default:
484 t.Errorf("IsWow64Process2 is wrong: want %v have %v", runtime.GOARCH, processMachine)
485 }
486 }
487
488 func TestNTStatusString(t *testing.T) {
489 want := "The name limit for the local computer network adapter card was exceeded."
490 got := windows.STATUS_TOO_MANY_NAMES.Error()
491 if want != got {
492 t.Errorf("NTStatus.Error did not return an expected error string - want %q; got %q", want, got)
493 }
494 }
495
496 func TestNTStatusConversion(t *testing.T) {
497 want := windows.ERROR_TOO_MANY_NAMES
498 got := windows.STATUS_TOO_MANY_NAMES.Errno()
499 if want != got {
500 t.Errorf("NTStatus.Errno = %q (0x%x); want %q (0x%x)", got.Error(), got, want.Error(), want)
501 }
502 }
503
504 func TestPEBFilePath(t *testing.T) {
505 peb := windows.RtlGetCurrentPeb()
506 if peb == nil || peb.Ldr == nil {
507 t.Error("unable to retrieve PEB with valid Ldr")
508 }
509 var entry *windows.LDR_DATA_TABLE_ENTRY
510 for cur := peb.Ldr.InMemoryOrderModuleList.Flink; cur != &peb.Ldr.InMemoryOrderModuleList; cur = cur.Flink {
511 e := (*windows.LDR_DATA_TABLE_ENTRY)(unsafe.Pointer(uintptr(unsafe.Pointer(cur)) - unsafe.Offsetof(windows.LDR_DATA_TABLE_ENTRY{}.InMemoryOrderLinks)))
512 if e.DllBase == peb.ImageBaseAddress {
513 entry = e
514 break
515 }
516 }
517 if entry == nil {
518 t.Error("unable to find Ldr entry for current process")
519 }
520 osPath, err := os.Executable()
521 if err != nil {
522 t.Errorf("unable to get path to current executable: %v", err)
523 }
524 pebPath := entry.FullDllName.String()
525 if osPath != pebPath {
526 t.Errorf("peb.Ldr.{entry}.FullDllName = %#q; want %#q", pebPath, osPath)
527 }
528 paramPath := peb.ProcessParameters.ImagePathName.String()
529 if osPath != paramPath {
530 t.Errorf("peb.ProcessParameters.ImagePathName.{entry}.ImagePathName = %#q; want %#q", paramPath, osPath)
531 }
532 osCwd, err := os.Getwd()
533 if err != nil {
534 t.Errorf("unable to get working directory: %v", err)
535 }
536 osCwd = filepath.Clean(osCwd)
537 paramCwd := filepath.Clean(peb.ProcessParameters.CurrentDirectory.DosPath.String())
538 if paramCwd != osCwd {
539 t.Errorf("peb.ProcessParameters.CurrentDirectory.DosPath = %#q; want %#q", paramCwd, osCwd)
540 }
541 }
542
543 func TestResourceExtraction(t *testing.T) {
544 system32, err := windows.GetSystemDirectory()
545 if err != nil {
546 t.Errorf("unable to find system32 directory: %v", err)
547 }
548 cmd, err := windows.LoadLibrary(filepath.Join(system32, "cmd.exe"))
549 if err != nil {
550 t.Errorf("unable to load cmd.exe: %v", err)
551 }
552 defer windows.FreeLibrary(cmd)
553 rsrc, err := windows.FindResource(cmd, windows.CREATEPROCESS_MANIFEST_RESOURCE_ID, windows.RT_MANIFEST)
554 if err != nil {
555 t.Errorf("unable to find cmd.exe manifest resource: %v", err)
556 }
557 manifest, err := windows.LoadResourceData(cmd, rsrc)
558 if err != nil {
559 t.Errorf("unable to load cmd.exe manifest resource data: %v", err)
560 }
561 if !bytes.Contains(manifest, []byte("</assembly>")) {
562 t.Errorf("did not find </assembly> in manifest")
563 }
564 }
565
566 func FuzzComposeCommandLine(f *testing.F) {
567 f.Add(`C:\foo.exe /bar /baz "-bag qux"`)
568 f.Add(`"C:\Program Files\Go\bin\go.exe" env`)
569 f.Add(`C:\"Program Files"\Go\bin\go.exe env`)
570 f.Add(`C:\"Program Files"\Go\bin\go.exe env`)
571 f.Add(`C:\"Pro"gram Files\Go\bin\go.exe env`)
572 f.Add(``)
573 f.Add(` `)
574 f.Add(`W\"0`)
575 f.Add("\"\f")
576 f.Add("\f")
577 f.Add("\x16")
578 f.Add(`"" ` + strings.Repeat("a", 8193))
579 f.Add(strings.Repeat(`"" `, 8193))
580
581 f.Add("\x00abcd")
582 f.Add("ab\x00cd")
583 f.Add("abcd\x00")
584 f.Add("\x00abcd\x00")
585 f.Add("\x00ab\x00cd\x00")
586 f.Add("\x00\x00\x00")
587 f.Add("\x16\x00\x16")
588 f.Add(`C:\Program Files\Go\bin\go.exe` + "\x00env")
589 f.Add(`"C:\Program Files\Go\bin\go.exe"` + "\x00env")
590 f.Add(`C:\"Program Files"\Go\bin\go.exe` + "\x00env")
591 f.Add(`C:\"Pro"gram Files\Go\bin\go.exe` + "\x00env")
592 f.Add("\x00" + strings.Repeat("a", 8192))
593 f.Add("\x00" + strings.Repeat("a", 8193))
594 f.Add(strings.Repeat("\x00"+strings.Repeat("a", 8192), 4))
595
596 f.Fuzz(func(t *testing.T, s string) {
597
598
599
600
601
602
603
604
605 args, err := windows.DecomposeCommandLine(s)
606 argsFromSplit := false
607
608 if err == nil {
609 if testing.Verbose() {
610 t.Logf("DecomposeCommandLine(%#q) = %#q", s, args)
611 }
612 } else {
613 t.Logf("DecomposeCommandLine: %v", err)
614 if !strings.Contains(s, "\x00") {
615
616
617
618
619
620 t.Fatal("(error unexpected)")
621 }
622
623
624
625 args = strings.Split(s, "\x00")
626 argsFromSplit = true
627 for i, arg := range args {
628 if !utf8.ValidString(arg) {
629
630
631
632 t.Skipf("skipping: input %d is not valid UTF-8", i)
633 }
634 }
635 if testing.Verbose() {
636 t.Logf("using input: %#q", args)
637 }
638 }
639
640
641
642
643 commandLine := windows.ComposeCommandLine(args)
644 t.Logf("ComposeCommandLine(_) = %#q", commandLine)
645
646 got, err := windows.DecomposeCommandLine(commandLine)
647 if err != nil {
648 t.Fatalf("DecomposeCommandLine: unexpected error: %v", err)
649 }
650 if testing.Verbose() {
651 t.Logf("DecomposeCommandLine(_) = %#q", got)
652 }
653
654 var badMatches []int
655 for i := range args {
656 if i >= len(got) {
657 badMatches = append(badMatches, i)
658 continue
659 }
660 want := args[i]
661 if got[i] != want {
662 if i == 0 && argsFromSplit {
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683 if got[i] == strings.ReplaceAll(want, `"`, ``) {
684 continue
685 }
686 }
687 badMatches = append(badMatches, i)
688 }
689 }
690 if len(badMatches) != 0 {
691 t.Errorf("Incorrect decomposition at indices: %v", badMatches)
692 }
693 })
694 }
695
696 func TestWinVerifyTrust(t *testing.T) {
697 evsignedfile := `.\testdata\ev-signed-file.exe`
698 evsignedfile16, err := windows.UTF16PtrFromString(evsignedfile)
699 if err != nil {
700 t.Fatalf("unable to get utf16 of %s: %v", evsignedfile, err)
701 }
702 data := &windows.WinTrustData{
703 Size: uint32(unsafe.Sizeof(windows.WinTrustData{})),
704 UIChoice: windows.WTD_UI_NONE,
705 RevocationChecks: windows.WTD_REVOKE_NONE,
706 UnionChoice: windows.WTD_CHOICE_FILE,
707 StateAction: windows.WTD_STATEACTION_VERIFY,
708 FileOrCatalogOrBlobOrSgnrOrCert: unsafe.Pointer(&windows.WinTrustFileInfo{
709 Size: uint32(unsafe.Sizeof(windows.WinTrustFileInfo{})),
710 FilePath: evsignedfile16,
711 }),
712 }
713 verifyErr := windows.WinVerifyTrustEx(windows.InvalidHWND, &windows.WINTRUST_ACTION_GENERIC_VERIFY_V2, data)
714 data.StateAction = windows.WTD_STATEACTION_CLOSE
715 closeErr := windows.WinVerifyTrustEx(windows.InvalidHWND, &windows.WINTRUST_ACTION_GENERIC_VERIFY_V2, data)
716 if verifyErr != nil {
717 t.Errorf("%s did not verify: %v", evsignedfile, verifyErr)
718 }
719 if closeErr != nil {
720 t.Errorf("unable to free verification resources: %v", closeErr)
721 }
722
723
724
725 corruptedEvsignedfile := filepath.Join(t.TempDir(), "corrupted-file")
726 evsignedfileBytes, err := os.ReadFile(evsignedfile)
727 if err != nil {
728 t.Fatalf("unable to read %s bytes: %v", evsignedfile, err)
729 }
730 if len(evsignedfileBytes) > 0 {
731 evsignedfileBytes[len(evsignedfileBytes)/2-1]++
732 }
733 err = os.WriteFile(corruptedEvsignedfile, evsignedfileBytes, 0755)
734 if err != nil {
735 t.Fatalf("unable to write corrupted ntoskrnl.exe bytes: %v", err)
736 }
737 evsignedfile16, err = windows.UTF16PtrFromString(corruptedEvsignedfile)
738 if err != nil {
739 t.Fatalf("unable to get utf16 of ntoskrnl.exe: %v", err)
740 }
741 data = &windows.WinTrustData{
742 Size: uint32(unsafe.Sizeof(windows.WinTrustData{})),
743 UIChoice: windows.WTD_UI_NONE,
744 RevocationChecks: windows.WTD_REVOKE_NONE,
745 UnionChoice: windows.WTD_CHOICE_FILE,
746 StateAction: windows.WTD_STATEACTION_VERIFY,
747 FileOrCatalogOrBlobOrSgnrOrCert: unsafe.Pointer(&windows.WinTrustFileInfo{
748 Size: uint32(unsafe.Sizeof(windows.WinTrustFileInfo{})),
749 FilePath: evsignedfile16,
750 }),
751 }
752 verifyErr = windows.WinVerifyTrustEx(windows.InvalidHWND, &windows.WINTRUST_ACTION_GENERIC_VERIFY_V2, data)
753 data.StateAction = windows.WTD_STATEACTION_CLOSE
754 closeErr = windows.WinVerifyTrustEx(windows.InvalidHWND, &windows.WINTRUST_ACTION_GENERIC_VERIFY_V2, data)
755 if verifyErr != windows.Errno(windows.TRUST_E_BAD_DIGEST) {
756 t.Errorf("%s did not fail to verify as expected: %v", corruptedEvsignedfile, verifyErr)
757 }
758 if closeErr != nil {
759 t.Errorf("unable to free verification resources: %v", closeErr)
760 }
761
762 }
763
764 func TestEnumProcesses(t *testing.T) {
765 var (
766 pids [2]uint32
767 outSize uint32
768 )
769 err := windows.EnumProcesses(pids[:], &outSize)
770 if err != nil {
771 t.Fatalf("unable to enumerate processes: %v", err)
772 }
773
774
775 if outSize != 8 {
776 t.Errorf("unexpected bytes returned: %d", outSize)
777 }
778
779
780
781 if pids[0] == 0 && pids[1] == 0 {
782 t.Errorf("all PIDs are 0")
783 }
784 }
785
786 func TestProcessModules(t *testing.T) {
787 process, err := windows.GetCurrentProcess()
788 if err != nil {
789 t.Fatalf("unable to get current process: %v", err)
790 }
791
792 var module windows.Handle
793 var cbNeeded uint32
794 err = windows.EnumProcessModules(process, &module, uint32(unsafe.Sizeof(module)), &cbNeeded)
795 if err != nil {
796 t.Fatalf("EnumProcessModules failed: %v", err)
797 }
798
799 var moduleEx windows.Handle
800 err = windows.EnumProcessModulesEx(process, &moduleEx, uint32(unsafe.Sizeof(moduleEx)), &cbNeeded, windows.LIST_MODULES_DEFAULT)
801 if err != nil {
802 t.Fatalf("EnumProcessModulesEx failed: %v", err)
803 }
804 if module != moduleEx {
805 t.Fatalf("module from EnumProcessModules does not match EnumProcessModulesEx: %v != %v", module, moduleEx)
806 }
807
808 exePath, err := os.Executable()
809 if err != nil {
810 t.Fatalf("unable to get current executable path: %v", err)
811 }
812
813 modulePathUTF16 := make([]uint16, len(exePath)+1)
814 err = windows.GetModuleFileNameEx(process, module, &modulePathUTF16[0], uint32(len(modulePathUTF16)))
815 if err != nil {
816 t.Fatalf("GetModuleFileNameEx failed: %v", err)
817 }
818
819 modulePath := windows.UTF16ToString(modulePathUTF16)
820 if modulePath != exePath {
821 t.Fatalf("module does not match executable for GetModuleFileNameEx: %s != %s", modulePath, exePath)
822 }
823
824 err = windows.GetModuleBaseName(process, module, &modulePathUTF16[0], uint32(len(modulePathUTF16)))
825 if err != nil {
826 t.Fatalf("GetModuleBaseName failed: %v", err)
827 }
828
829 modulePath = windows.UTF16ToString(modulePathUTF16)
830 baseExePath := filepath.Base(exePath)
831 if modulePath != baseExePath {
832 t.Fatalf("module does not match executable for GetModuleBaseName: %s != %s", modulePath, baseExePath)
833 }
834
835 var moduleInfo windows.ModuleInfo
836 err = windows.GetModuleInformation(process, module, &moduleInfo, uint32(unsafe.Sizeof(moduleInfo)))
837 if err != nil {
838 t.Fatalf("GetModuleInformation failed: %v", err)
839 }
840
841 peFile, err := pe.Open(exePath)
842 if err != nil {
843 t.Fatalf("unable to open current executable: %v", err)
844 }
845 defer peFile.Close()
846
847 var peSizeOfImage uint32
848 switch runtime.GOARCH {
849 case "amd64", "arm64":
850 peSizeOfImage = peFile.OptionalHeader.(*pe.OptionalHeader64).SizeOfImage
851 case "386", "arm":
852 peSizeOfImage = peFile.OptionalHeader.(*pe.OptionalHeader32).SizeOfImage
853 default:
854 t.Fatalf("unable to test GetModuleInformation on arch %v", runtime.GOARCH)
855 }
856
857 if moduleInfo.SizeOfImage != peSizeOfImage {
858 t.Fatalf("module size does not match executable: %v != %v", moduleInfo.SizeOfImage, peSizeOfImage)
859 }
860 }
861
862 func TestQueryWorkingSetEx(t *testing.T) {
863 var a int
864
865 process := windows.CurrentProcess()
866 information := windows.PSAPI_WORKING_SET_EX_INFORMATION{
867 VirtualAddress: windows.Pointer(unsafe.Pointer(&a)),
868 }
869 infos := []windows.PSAPI_WORKING_SET_EX_INFORMATION{information}
870
871 cb := uint32(uintptr(len(infos)) * unsafe.Sizeof(infos[0]))
872 if err := windows.QueryWorkingSetEx(process, uintptr(unsafe.Pointer(&infos[0])), cb); err != nil {
873 t.Fatalf("%+v", err)
874 }
875
876 if !infos[0].VirtualAttributes.Valid() {
877 t.Errorf("memory location not valid")
878 }
879 }
880
881 func TestReadWriteProcessMemory(t *testing.T) {
882 testBuffer := []byte{0xBA, 0xAD, 0xF0, 0x0D}
883
884 process, err := windows.GetCurrentProcess()
885 if err != nil {
886 t.Fatalf("unable to get current process: %v", err)
887 }
888
889 buffer := make([]byte, len(testBuffer))
890 err = windows.ReadProcessMemory(process, uintptr(unsafe.Pointer(&testBuffer[0])), &buffer[0], uintptr(len(buffer)), nil)
891 if err != nil {
892 t.Errorf("ReadProcessMemory failed: %v", err)
893 }
894 if !bytes.Equal(testBuffer, buffer) {
895 t.Errorf("bytes read does not match buffer: 0x%X != 0x%X", testBuffer, buffer)
896 }
897
898 buffer = []byte{0xDE, 0xAD, 0xBE, 0xEF}
899 err = windows.WriteProcessMemory(process, uintptr(unsafe.Pointer(&testBuffer[0])), &buffer[0], uintptr(len(buffer)), nil)
900 if err != nil {
901 t.Errorf("WriteProcessMemory failed: %v", err)
902 }
903 if !bytes.Equal(testBuffer, buffer) {
904 t.Errorf("bytes written does not match buffer: 0x%X != 0x%X", testBuffer, buffer)
905 }
906 }
907
908 func TestSystemModuleVersions(t *testing.T) {
909 var modules []windows.RTL_PROCESS_MODULE_INFORMATION
910 for bufferSize := uint32(128 * 1024); ; {
911 moduleBuffer := make([]byte, bufferSize)
912 err := windows.NtQuerySystemInformation(windows.SystemModuleInformation, unsafe.Pointer(&moduleBuffer[0]), bufferSize, &bufferSize)
913 switch err {
914 case windows.STATUS_INFO_LENGTH_MISMATCH:
915 continue
916 case nil:
917 break
918 default:
919 t.Error(err)
920 return
921 }
922 mods := (*windows.RTL_PROCESS_MODULES)(unsafe.Pointer(&moduleBuffer[0]))
923 modules = unsafe.Slice(&mods.Modules[0], int(mods.NumberOfModules))
924 break
925 }
926 for i := range modules {
927 moduleName := windows.ByteSliceToString(modules[i].FullPathName[modules[i].OffsetToFileName:])
928 driverPath := `\\?\GLOBALROOT` + windows.ByteSliceToString(modules[i].FullPathName[:])
929 var zero windows.Handle
930 infoSize, err := windows.GetFileVersionInfoSize(driverPath, &zero)
931 if err != nil {
932 if err != windows.ERROR_FILE_NOT_FOUND && err != windows.ERROR_RESOURCE_TYPE_NOT_FOUND {
933 t.Errorf("%v: %v", moduleName, err)
934 }
935 continue
936 }
937 versionInfo := make([]byte, infoSize)
938 if err = windows.GetFileVersionInfo(driverPath, 0, infoSize, unsafe.Pointer(&versionInfo[0])); err != nil {
939 t.Errorf("%v: %v", moduleName, err)
940 continue
941 }
942 var fixedInfo *windows.VS_FIXEDFILEINFO
943 fixedInfoLen := uint32(unsafe.Sizeof(*fixedInfo))
944 err = windows.VerQueryValue(unsafe.Pointer(&versionInfo[0]), `\`, (unsafe.Pointer)(&fixedInfo), &fixedInfoLen)
945 if err != nil {
946 t.Errorf("%v: %v", moduleName, err)
947 continue
948 }
949 t.Logf("%s: v%d.%d.%d.%d", moduleName,
950 (fixedInfo.FileVersionMS>>16)&0xff,
951 (fixedInfo.FileVersionMS>>0)&0xff,
952 (fixedInfo.FileVersionLS>>16)&0xff,
953 (fixedInfo.FileVersionLS>>0)&0xff)
954 }
955 }
956
957 type fileRenameInformation struct {
958 ReplaceIfExists uint32
959 RootDirectory windows.Handle
960 FileNameLength uint32
961 FileName [1]uint16
962 }
963
964 func TestNtCreateFileAndNtSetInformationFile(t *testing.T) {
965 var iosb windows.IO_STATUS_BLOCK
966 var allocSize int64 = 0
967
968 testDirPath := t.TempDir()
969 objectName, err := windows.NewNTUnicodeString("\\??\\" + testDirPath)
970 if err != nil {
971 t.Fatal(err)
972 }
973 oa := &windows.OBJECT_ATTRIBUTES{
974 ObjectName: objectName,
975 }
976 oa.Length = uint32(unsafe.Sizeof(*oa))
977 var testDirHandle windows.Handle
978 err = windows.NtCreateFile(&testDirHandle, windows.FILE_GENERIC_READ|windows.FILE_GENERIC_WRITE, oa, &iosb,
979 &allocSize, 0, windows.FILE_SHARE_READ|windows.FILE_SHARE_WRITE|windows.FILE_SHARE_DELETE, windows.FILE_OPEN,
980 windows.FILE_DIRECTORY_FILE, 0, 0)
981 if err != nil {
982 t.Fatalf("NtCreateFile(%v) failed: %v", testDirPath, err)
983 }
984 defer windows.CloseHandle(testDirHandle)
985
986 fileName := "filename"
987 filePath := filepath.Join(testDirPath, fileName)
988 objectName, err = windows.NewNTUnicodeString(fileName)
989 if err != nil {
990 t.Fatal(err)
991 }
992 oa.RootDirectory = testDirHandle
993 oa.ObjectName = objectName
994 var fileHandle windows.Handle
995 err = windows.NtCreateFile(&fileHandle, windows.FILE_GENERIC_READ|windows.FILE_GENERIC_WRITE|windows.DELETE, oa, &iosb,
996 &allocSize, 0, windows.FILE_SHARE_READ|windows.FILE_SHARE_WRITE|windows.FILE_SHARE_DELETE, windows.FILE_CREATE,
997 0, 0, 0)
998 if err != nil {
999 t.Fatalf("NtCreateFile(%v) failed: %v", filePath, err)
1000 }
1001 defer windows.CloseHandle(fileHandle)
1002 _, err = os.Stat(filePath)
1003 if err != nil {
1004 t.Fatalf("cannot stat file created with NtCreatefile: %v", err)
1005 }
1006
1007 newName := "newname"
1008 newPath := filepath.Join(testDirPath, newName)
1009 newNameUTF16, err := windows.UTF16FromString(newName)
1010 if err != nil {
1011 t.Fatal(err)
1012 }
1013 fileNameLen := len(newNameUTF16)*2 - 2
1014 var dummyFileRenameInfo fileRenameInformation
1015 bufferSize := int(unsafe.Offsetof(dummyFileRenameInfo.FileName)) + fileNameLen
1016 buffer := make([]byte, bufferSize)
1017 typedBufferPtr := (*fileRenameInformation)(unsafe.Pointer(&buffer[0]))
1018 typedBufferPtr.ReplaceIfExists = windows.FILE_RENAME_REPLACE_IF_EXISTS | windows.FILE_RENAME_POSIX_SEMANTICS
1019 typedBufferPtr.FileNameLength = uint32(fileNameLen)
1020 copy((*[windows.MAX_LONG_PATH]uint16)(unsafe.Pointer(&typedBufferPtr.FileName[0]))[:fileNameLen/2:fileNameLen/2], newNameUTF16)
1021 err = windows.NtSetInformationFile(fileHandle, &iosb, &buffer[0], uint32(bufferSize), windows.FileRenameInformation)
1022 if err != nil {
1023 t.Fatalf("NtSetInformationFile(%v) failed: %v", newPath, err)
1024 }
1025 _, err = os.Stat(newPath)
1026 if err != nil {
1027 t.Fatalf("cannot stat rename target %v: %v", newPath, err)
1028 }
1029 }
1030
1031 var deviceClassNetGUID = &windows.GUID{0x4d36e972, 0xe325, 0x11ce, [8]byte{0xbf, 0xc1, 0x08, 0x00, 0x2b, 0xe1, 0x03, 0x18}}
1032 var deviceInterfaceNetGUID = &windows.GUID{0xcac88484, 0x7515, 0x4c03, [8]byte{0x82, 0xe6, 0x71, 0xa8, 0x7a, 0xba, 0xc3, 0x61}}
1033
1034 func TestListLoadedNetworkDevices(t *testing.T) {
1035 devInfo, err := windows.SetupDiGetClassDevsEx(deviceClassNetGUID, "", 0, windows.DIGCF_PRESENT, 0, "")
1036 if err != nil {
1037 t.Fatal(err)
1038 }
1039 defer devInfo.Close()
1040 for i := 0; ; i++ {
1041 devInfoData, err := devInfo.EnumDeviceInfo(i)
1042 if err != nil {
1043 if err == windows.ERROR_NO_MORE_ITEMS {
1044 break
1045 }
1046 continue
1047 }
1048 friendlyName, err := devInfo.DeviceRegistryProperty(devInfoData, windows.SPDRP_DEVICEDESC)
1049 if err != nil {
1050 t.Fatal(err)
1051 }
1052 var status, problemCode uint32
1053 err = windows.CM_Get_DevNode_Status(&status, &problemCode, devInfoData.DevInst, 0)
1054 if err != nil || (status&windows.DN_DRIVER_LOADED|windows.DN_STARTED) != windows.DN_DRIVER_LOADED|windows.DN_STARTED {
1055 continue
1056 }
1057 instanceId, err := devInfo.DeviceInstanceID(devInfoData)
1058 if err != nil {
1059 t.Fatal(err)
1060 }
1061 interfaces, err := windows.CM_Get_Device_Interface_List(instanceId, deviceInterfaceNetGUID, windows.CM_GET_DEVICE_INTERFACE_LIST_PRESENT)
1062 if err != nil || len(interfaces) == 0 {
1063 continue
1064 }
1065 t.Logf("%s - %s", friendlyName, interfaces[0])
1066 }
1067 }
1068
1069 func TestListWireGuardDrivers(t *testing.T) {
1070 devInfo, err := windows.SetupDiCreateDeviceInfoListEx(deviceClassNetGUID, 0, "")
1071 if err != nil {
1072 t.Fatal(err)
1073 }
1074 defer devInfo.Close()
1075 devInfoData, err := devInfo.CreateDeviceInfo("WireGuard", deviceClassNetGUID, "", 0, windows.DICD_GENERATE_ID)
1076 if err != nil {
1077 t.Fatal(err)
1078 }
1079 err = devInfo.SetDeviceRegistryProperty(devInfoData, windows.SPDRP_HARDWAREID, []byte("W\x00i\x00r\x00e\x00G\x00u\x00a\x00r\x00d\x00\x00\x00\x00\x00"))
1080 if err != nil {
1081 t.Fatal(err)
1082 }
1083 err = devInfo.BuildDriverInfoList(devInfoData, windows.SPDIT_COMPATDRIVER)
1084 if err != nil {
1085 t.Fatal(err)
1086 }
1087 defer devInfo.DestroyDriverInfoList(devInfoData, windows.SPDIT_COMPATDRIVER)
1088 for i := 0; ; i++ {
1089 drvInfoData, err := devInfo.EnumDriverInfo(devInfoData, windows.SPDIT_COMPATDRIVER, i)
1090 if err != nil {
1091 if err == windows.ERROR_NO_MORE_ITEMS {
1092 break
1093 }
1094 continue
1095 }
1096 drvInfoDetailData, err := devInfo.DriverInfoDetail(devInfoData, drvInfoData)
1097 if err != nil {
1098 t.Error(err)
1099 continue
1100 }
1101 t.Logf("%s - %s", drvInfoData.Description(), drvInfoDetailData.InfFileName())
1102 }
1103 }
1104
1105 func TestProcThreadAttributeHandleList(t *testing.T) {
1106 const sentinel = "the gopher dance"
1107 system32, err := windows.GetSystemDirectory()
1108 if err != nil {
1109 t.Fatal(err)
1110 }
1111 executable16, err := windows.UTF16PtrFromString(filepath.Join(system32, "cmd.exe"))
1112 if err != nil {
1113 t.Fatal(err)
1114 }
1115 args16, err := windows.UTF16PtrFromString(windows.ComposeCommandLine([]string{"/c", "echo " + sentinel}))
1116 if err != nil {
1117 t.Fatal(err)
1118 }
1119 attributeList, err := windows.NewProcThreadAttributeList(1)
1120 if err != nil {
1121 t.Fatal(err)
1122 }
1123 defer attributeList.Delete()
1124 si := &windows.StartupInfoEx{
1125 StartupInfo: windows.StartupInfo{Cb: uint32(unsafe.Sizeof(windows.StartupInfoEx{}))},
1126 ProcThreadAttributeList: attributeList.List(),
1127 }
1128 pipeR, pipeW, err := os.Pipe()
1129 if err != nil {
1130 t.Fatal(err)
1131 }
1132 defer pipeR.Close()
1133 defer pipeW.Close()
1134 func() {
1135
1136 handles := []windows.Handle{windows.Handle(pipeW.Fd())}
1137 attributeList.Update(windows.PROC_THREAD_ATTRIBUTE_HANDLE_LIST, unsafe.Pointer(&handles[0]), uintptr(len(handles))*unsafe.Sizeof(handles[0]))
1138 si.Flags |= windows.STARTF_USESTDHANDLES
1139 si.StdOutput = handles[0]
1140
1141 windows.SetHandleInformation(handles[0], windows.HANDLE_FLAG_INHERIT, windows.HANDLE_FLAG_INHERIT)
1142 }()
1143 pi := new(windows.ProcessInformation)
1144 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)
1145 if err != nil {
1146 t.Fatal(err)
1147 }
1148 defer windows.CloseHandle(pi.Thread)
1149 defer windows.CloseHandle(pi.Process)
1150 pipeR.SetReadDeadline(time.Now().Add(time.Minute))
1151 out, _, err := bufio.NewReader(pipeR).ReadLine()
1152 if err != nil {
1153 t.Fatal(err)
1154 }
1155 if string(out) != sentinel {
1156 t.Fatalf("got %q; want %q", out, sentinel)
1157 }
1158 }
1159
1160 func TestWSALookupService(t *testing.T) {
1161 var flags uint32 = windows.LUP_CONTAINERS
1162 flags |= windows.LUP_RETURN_NAME
1163 flags |= windows.LUP_RETURN_ADDR
1164
1165 var querySet windows.WSAQUERYSET
1166 querySet.NameSpace = windows.NS_BTH
1167 querySet.Size = uint32(unsafe.Sizeof(windows.WSAQUERYSET{}))
1168
1169 var handle windows.Handle
1170 err := windows.WSALookupServiceBegin(&querySet, flags, &handle)
1171 if err != nil {
1172 if errors.Is(err, windows.WSASERVICE_NOT_FOUND) {
1173 t.Skip("WSA Service not found, so skip this test")
1174 }
1175 t.Fatal(err)
1176 }
1177
1178 defer windows.WSALookupServiceEnd(handle)
1179
1180 n := int32(unsafe.Sizeof(windows.WSAQUERYSET{}))
1181 buf := make([]byte, n)
1182 items_loop:
1183 for {
1184 q := (*windows.WSAQUERYSET)(unsafe.Pointer(&buf[0]))
1185 err := windows.WSALookupServiceNext(handle, flags, &n, q)
1186 switch err {
1187 case windows.WSA_E_NO_MORE, windows.WSAENOMORE:
1188
1189 break items_loop
1190 case windows.WSAEFAULT:
1191
1192 buf = make([]byte, n)
1193 case nil:
1194
1195 var addr string
1196 for _, e := range q.SaBuffer.RemoteAddr.Sockaddr.Addr.Data {
1197 if e != 0 {
1198 addr += fmt.Sprintf("%x", e)
1199 }
1200 }
1201 t.Logf("%s -> %s\n", windows.UTF16PtrToString(q.ServiceInstanceName), addr)
1202
1203 default:
1204 t.Fatal(err)
1205 }
1206 }
1207 }
1208
1209 func TestTimePeriod(t *testing.T) {
1210 if err := windows.TimeBeginPeriod(1); err != nil {
1211 t.Fatal(err)
1212 }
1213 if err := windows.TimeEndPeriod(1); err != nil {
1214 t.Fatal(err)
1215 }
1216 }
1217
1218 func TestGetStartupInfo(t *testing.T) {
1219 var si windows.StartupInfo
1220 err := windows.GetStartupInfo(&si)
1221 if err != nil {
1222
1223 t.Fatalf("GetStartupInfo: got error %v, want nil", err)
1224 }
1225 }
1226
1227 func TestAddRemoveDllDirectory(t *testing.T) {
1228 if _, err := exec.LookPath("gcc"); err != nil {
1229 t.Skip("skipping test: gcc is missing")
1230 }
1231 dllSrc := `#include <stdint.h>
1232 #include <windows.h>
1233
1234 uintptr_t beep(void) {
1235 return 5;
1236 }`
1237 tmpdir := t.TempDir()
1238 srcname := "beep.c"
1239 err := os.WriteFile(filepath.Join(tmpdir, srcname), []byte(dllSrc), 0)
1240 if err != nil {
1241 t.Fatal(err)
1242 }
1243 name := "beep.dll"
1244 cmd := exec.Command("gcc", "-shared", "-s", "-Werror", "-o", name, srcname)
1245 cmd.Dir = tmpdir
1246 out, err := cmd.CombinedOutput()
1247 if err != nil {
1248 t.Fatalf("failed to build dll: %v - %v", err, string(out))
1249 }
1250
1251 if _, err := windows.LoadLibraryEx("beep.dll", 0, windows.LOAD_LIBRARY_SEARCH_USER_DIRS); err == nil {
1252 t.Fatal("LoadLibraryEx unexpectedly found beep.dll")
1253 }
1254
1255 dllCookie, err := windows.AddDllDirectory(windows.StringToUTF16Ptr(tmpdir))
1256 if err != nil {
1257 t.Fatalf("AddDllDirectory failed: %s", err)
1258 }
1259
1260 handle, err := windows.LoadLibraryEx("beep.dll", 0, windows.LOAD_LIBRARY_SEARCH_USER_DIRS)
1261 if err != nil {
1262 t.Fatalf("LoadLibraryEx failed: %s", err)
1263 }
1264
1265 if err := windows.FreeLibrary(handle); err != nil {
1266 t.Fatalf("FreeLibrary failed: %s", err)
1267 }
1268
1269 if err := windows.RemoveDllDirectory(dllCookie); err != nil {
1270 t.Fatalf("RemoveDllDirectory failed: %s", err)
1271 }
1272
1273 _, err = windows.LoadLibraryEx("beep.dll", 0, windows.LOAD_LIBRARY_SEARCH_USER_DIRS)
1274 if err == nil {
1275 t.Fatal("LoadLibraryEx unexpectedly found beep.dll")
1276 }
1277 }
1278
View as plain text