golang.org/x/sys@v0.9.0/windows/registry/registry_test.go (about) 1 // Copyright 2015 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 //go:build windows 6 // +build windows 7 8 package registry_test 9 10 import ( 11 "bytes" 12 "crypto/rand" 13 "os" 14 "syscall" 15 "testing" 16 "time" 17 "unsafe" 18 19 "golang.org/x/sys/windows/registry" 20 ) 21 22 func randKeyName(prefix string) string { 23 const numbers = "0123456789" 24 buf := make([]byte, 10) 25 rand.Read(buf) 26 for i, b := range buf { 27 buf[i] = numbers[b%byte(len(numbers))] 28 } 29 return prefix + string(buf) 30 } 31 32 func TestReadSubKeyNames(t *testing.T) { 33 k, err := registry.OpenKey(registry.CLASSES_ROOT, "TypeLib", registry.ENUMERATE_SUB_KEYS) 34 if err != nil { 35 t.Fatal(err) 36 } 37 defer k.Close() 38 39 names, err := k.ReadSubKeyNames(-1) 40 if err != nil { 41 t.Fatal(err) 42 } 43 var foundStdOle bool 44 for _, name := range names { 45 // Every PC has "stdole 2.0 OLE Automation" library installed. 46 if name == "{00020430-0000-0000-C000-000000000046}" { 47 foundStdOle = true 48 } 49 } 50 if !foundStdOle { 51 t.Fatal("could not find stdole 2.0 OLE Automation") 52 } 53 } 54 55 func TestCreateOpenDeleteKey(t *testing.T) { 56 k, err := registry.OpenKey(registry.CURRENT_USER, "Software", registry.QUERY_VALUE) 57 if err != nil { 58 t.Fatal(err) 59 } 60 defer k.Close() 61 62 testKName := randKeyName("TestCreateOpenDeleteKey_") 63 64 testK, exist, err := registry.CreateKey(k, testKName, registry.CREATE_SUB_KEY) 65 if err != nil { 66 t.Fatal(err) 67 } 68 defer testK.Close() 69 70 if exist { 71 t.Fatalf("key %q already exists", testKName) 72 } 73 74 testKAgain, exist, err := registry.CreateKey(k, testKName, registry.CREATE_SUB_KEY) 75 if err != nil { 76 t.Fatal(err) 77 } 78 defer testKAgain.Close() 79 80 if !exist { 81 t.Fatalf("key %q should already exist", testKName) 82 } 83 84 testKOpened, err := registry.OpenKey(k, testKName, registry.ENUMERATE_SUB_KEYS) 85 if err != nil { 86 t.Fatal(err) 87 } 88 defer testKOpened.Close() 89 90 err = registry.DeleteKey(k, testKName) 91 if err != nil { 92 t.Fatal(err) 93 } 94 95 testKOpenedAgain, err := registry.OpenKey(k, testKName, registry.ENUMERATE_SUB_KEYS) 96 if err == nil { 97 defer testKOpenedAgain.Close() 98 t.Fatalf("key %q should already been deleted", testKName) 99 } 100 if err != registry.ErrNotExist { 101 t.Fatalf(`unexpected error ("not exist" expected): %v`, err) 102 } 103 } 104 105 func equalStringSlice(a, b []string) bool { 106 if len(a) != len(b) { 107 return false 108 } 109 if a == nil { 110 return true 111 } 112 for i := range a { 113 if a[i] != b[i] { 114 return false 115 } 116 } 117 return true 118 } 119 120 type ValueTest struct { 121 Type uint32 122 Name string 123 Value interface{} 124 WillFail bool 125 } 126 127 var ValueTests = []ValueTest{ 128 {Type: registry.SZ, Name: "String1", Value: ""}, 129 {Type: registry.SZ, Name: "String2", Value: "\000", WillFail: true}, 130 {Type: registry.SZ, Name: "String3", Value: "Hello World"}, 131 {Type: registry.SZ, Name: "String4", Value: "Hello World\000", WillFail: true}, 132 {Type: registry.EXPAND_SZ, Name: "ExpString1", Value: ""}, 133 {Type: registry.EXPAND_SZ, Name: "ExpString2", Value: "\000", WillFail: true}, 134 {Type: registry.EXPAND_SZ, Name: "ExpString3", Value: "Hello World"}, 135 {Type: registry.EXPAND_SZ, Name: "ExpString4", Value: "Hello\000World", WillFail: true}, 136 {Type: registry.EXPAND_SZ, Name: "ExpString5", Value: "%PATH%"}, 137 {Type: registry.EXPAND_SZ, Name: "ExpString6", Value: "%NO_SUCH_VARIABLE%"}, 138 {Type: registry.EXPAND_SZ, Name: "ExpString7", Value: "%PATH%;."}, 139 {Type: registry.BINARY, Name: "Binary1", Value: []byte{}}, 140 {Type: registry.BINARY, Name: "Binary2", Value: []byte{1, 2, 3}}, 141 {Type: registry.BINARY, Name: "Binary3", Value: []byte{3, 2, 1, 0, 1, 2, 3}}, 142 {Type: registry.DWORD, Name: "Dword1", Value: uint64(0)}, 143 {Type: registry.DWORD, Name: "Dword2", Value: uint64(1)}, 144 {Type: registry.DWORD, Name: "Dword3", Value: uint64(0xff)}, 145 {Type: registry.DWORD, Name: "Dword4", Value: uint64(0xffff)}, 146 {Type: registry.QWORD, Name: "Qword1", Value: uint64(0)}, 147 {Type: registry.QWORD, Name: "Qword2", Value: uint64(1)}, 148 {Type: registry.QWORD, Name: "Qword3", Value: uint64(0xff)}, 149 {Type: registry.QWORD, Name: "Qword4", Value: uint64(0xffff)}, 150 {Type: registry.QWORD, Name: "Qword5", Value: uint64(0xffffff)}, 151 {Type: registry.QWORD, Name: "Qword6", Value: uint64(0xffffffff)}, 152 {Type: registry.MULTI_SZ, Name: "MultiString1", Value: []string{"a", "b", "c"}}, 153 {Type: registry.MULTI_SZ, Name: "MultiString2", Value: []string{"abc", "", "cba"}}, 154 {Type: registry.MULTI_SZ, Name: "MultiString3", Value: []string{""}}, 155 {Type: registry.MULTI_SZ, Name: "MultiString4", Value: []string{"abcdef"}}, 156 {Type: registry.MULTI_SZ, Name: "MultiString5", Value: []string{"\000"}, WillFail: true}, 157 {Type: registry.MULTI_SZ, Name: "MultiString6", Value: []string{"a\000b"}, WillFail: true}, 158 {Type: registry.MULTI_SZ, Name: "MultiString7", Value: []string{"ab", "\000", "cd"}, WillFail: true}, 159 {Type: registry.MULTI_SZ, Name: "MultiString8", Value: []string{"\000", "cd"}, WillFail: true}, 160 {Type: registry.MULTI_SZ, Name: "MultiString9", Value: []string{"ab", "\000"}, WillFail: true}, 161 } 162 163 func setValues(t *testing.T, k registry.Key) { 164 for _, test := range ValueTests { 165 var err error 166 switch test.Type { 167 case registry.SZ: 168 err = k.SetStringValue(test.Name, test.Value.(string)) 169 case registry.EXPAND_SZ: 170 err = k.SetExpandStringValue(test.Name, test.Value.(string)) 171 case registry.MULTI_SZ: 172 err = k.SetStringsValue(test.Name, test.Value.([]string)) 173 case registry.BINARY: 174 err = k.SetBinaryValue(test.Name, test.Value.([]byte)) 175 case registry.DWORD: 176 err = k.SetDWordValue(test.Name, uint32(test.Value.(uint64))) 177 case registry.QWORD: 178 err = k.SetQWordValue(test.Name, test.Value.(uint64)) 179 default: 180 t.Fatalf("unsupported type %d for %s value", test.Type, test.Name) 181 } 182 if test.WillFail { 183 if err == nil { 184 t.Fatalf("setting %s value %q should fail, but succeeded", test.Name, test.Value) 185 } 186 } else { 187 if err != nil { 188 t.Fatal(err) 189 } 190 } 191 } 192 } 193 194 func enumerateValues(t *testing.T, k registry.Key) { 195 names, err := k.ReadValueNames(-1) 196 if err != nil { 197 t.Error(err) 198 return 199 } 200 haveNames := make(map[string]bool) 201 for _, n := range names { 202 haveNames[n] = false 203 } 204 for _, test := range ValueTests { 205 wantFound := !test.WillFail 206 _, haveFound := haveNames[test.Name] 207 if wantFound && !haveFound { 208 t.Errorf("value %s is not found while enumerating", test.Name) 209 } 210 if haveFound && !wantFound { 211 t.Errorf("value %s is found while enumerating, but expected to fail", test.Name) 212 } 213 if haveFound { 214 delete(haveNames, test.Name) 215 } 216 } 217 for n, v := range haveNames { 218 t.Errorf("value %s (%v) is found while enumerating, but has not been cretaed", n, v) 219 } 220 } 221 222 func testErrNotExist(t *testing.T, name string, err error) { 223 if err == nil { 224 t.Errorf("%s value should not exist", name) 225 return 226 } 227 if err != registry.ErrNotExist { 228 t.Errorf("reading %s value should return 'not exist' error, but got: %s", name, err) 229 return 230 } 231 } 232 233 func testErrUnexpectedType(t *testing.T, test ValueTest, gottype uint32, err error) { 234 if err == nil { 235 t.Errorf("GetXValue(%q) should not succeed", test.Name) 236 return 237 } 238 if err != registry.ErrUnexpectedType { 239 t.Errorf("reading %s value should return 'unexpected key value type' error, but got: %s", test.Name, err) 240 return 241 } 242 if gottype != test.Type { 243 t.Errorf("want %s value type %v, got %v", test.Name, test.Type, gottype) 244 return 245 } 246 } 247 248 func testGetStringValue(t *testing.T, k registry.Key, test ValueTest) { 249 got, gottype, err := k.GetStringValue(test.Name) 250 if err != nil { 251 t.Errorf("GetStringValue(%s) failed: %v", test.Name, err) 252 return 253 } 254 if got != test.Value { 255 t.Errorf("want %s value %q, got %q", test.Name, test.Value, got) 256 return 257 } 258 if gottype != test.Type { 259 t.Errorf("want %s value type %v, got %v", test.Name, test.Type, gottype) 260 return 261 } 262 if gottype == registry.EXPAND_SZ { 263 _, err = registry.ExpandString(got) 264 if err != nil { 265 t.Errorf("ExpandString(%s) failed: %v", got, err) 266 return 267 } 268 } 269 } 270 271 func testGetIntegerValue(t *testing.T, k registry.Key, test ValueTest) { 272 got, gottype, err := k.GetIntegerValue(test.Name) 273 if err != nil { 274 t.Errorf("GetIntegerValue(%s) failed: %v", test.Name, err) 275 return 276 } 277 if got != test.Value.(uint64) { 278 t.Errorf("want %s value %v, got %v", test.Name, test.Value, got) 279 return 280 } 281 if gottype != test.Type { 282 t.Errorf("want %s value type %v, got %v", test.Name, test.Type, gottype) 283 return 284 } 285 } 286 287 func testGetBinaryValue(t *testing.T, k registry.Key, test ValueTest) { 288 got, gottype, err := k.GetBinaryValue(test.Name) 289 if err != nil { 290 t.Errorf("GetBinaryValue(%s) failed: %v", test.Name, err) 291 return 292 } 293 if !bytes.Equal(got, test.Value.([]byte)) { 294 t.Errorf("want %s value %v, got %v", test.Name, test.Value, got) 295 return 296 } 297 if gottype != test.Type { 298 t.Errorf("want %s value type %v, got %v", test.Name, test.Type, gottype) 299 return 300 } 301 } 302 303 func testGetStringsValue(t *testing.T, k registry.Key, test ValueTest) { 304 got, gottype, err := k.GetStringsValue(test.Name) 305 if err != nil { 306 t.Errorf("GetStringsValue(%s) failed: %v", test.Name, err) 307 return 308 } 309 if !equalStringSlice(got, test.Value.([]string)) { 310 t.Errorf("want %s value %#v, got %#v", test.Name, test.Value, got) 311 return 312 } 313 if gottype != test.Type { 314 t.Errorf("want %s value type %v, got %v", test.Name, test.Type, gottype) 315 return 316 } 317 } 318 319 func testGetValue(t *testing.T, k registry.Key, test ValueTest, size int) { 320 if size <= 0 { 321 return 322 } 323 // read data with no buffer 324 gotsize, gottype, err := k.GetValue(test.Name, nil) 325 if err != nil { 326 t.Errorf("GetValue(%s, [%d]byte) failed: %v", test.Name, size, err) 327 return 328 } 329 if gotsize != size { 330 t.Errorf("want %s value size of %d, got %v", test.Name, size, gotsize) 331 return 332 } 333 if gottype != test.Type { 334 t.Errorf("want %s value type %v, got %v", test.Name, test.Type, gottype) 335 return 336 } 337 // read data with short buffer 338 gotsize, gottype, err = k.GetValue(test.Name, make([]byte, size-1)) 339 if err == nil { 340 t.Errorf("GetValue(%s, [%d]byte) should fail, but succeeded", test.Name, size-1) 341 return 342 } 343 if err != registry.ErrShortBuffer { 344 t.Errorf("reading %s value should return 'short buffer' error, but got: %s", test.Name, err) 345 return 346 } 347 if gotsize != size { 348 t.Errorf("want %s value size of %d, got %v", test.Name, size, gotsize) 349 return 350 } 351 if gottype != test.Type { 352 t.Errorf("want %s value type %v, got %v", test.Name, test.Type, gottype) 353 return 354 } 355 // read full data 356 gotsize, gottype, err = k.GetValue(test.Name, make([]byte, size)) 357 if err != nil { 358 t.Errorf("GetValue(%s, [%d]byte) failed: %v", test.Name, size, err) 359 return 360 } 361 if gotsize != size { 362 t.Errorf("want %s value size of %d, got %v", test.Name, size, gotsize) 363 return 364 } 365 if gottype != test.Type { 366 t.Errorf("want %s value type %v, got %v", test.Name, test.Type, gottype) 367 return 368 } 369 // check GetValue returns ErrNotExist as required 370 _, _, err = k.GetValue(test.Name+"_not_there", make([]byte, size)) 371 if err == nil { 372 t.Errorf("GetValue(%q) should not succeed", test.Name) 373 return 374 } 375 if err != registry.ErrNotExist { 376 t.Errorf("GetValue(%q) should return 'not exist' error, but got: %s", test.Name, err) 377 return 378 } 379 } 380 381 func testValues(t *testing.T, k registry.Key) { 382 for _, test := range ValueTests { 383 switch test.Type { 384 case registry.SZ, registry.EXPAND_SZ: 385 if test.WillFail { 386 _, _, err := k.GetStringValue(test.Name) 387 testErrNotExist(t, test.Name, err) 388 } else { 389 testGetStringValue(t, k, test) 390 _, gottype, err := k.GetIntegerValue(test.Name) 391 testErrUnexpectedType(t, test, gottype, err) 392 // Size of utf16 string in bytes is not perfect, 393 // but correct for current test values. 394 // Size also includes terminating 0. 395 testGetValue(t, k, test, (len(test.Value.(string))+1)*2) 396 } 397 _, _, err := k.GetStringValue(test.Name + "_string_not_created") 398 testErrNotExist(t, test.Name+"_string_not_created", err) 399 case registry.DWORD, registry.QWORD: 400 testGetIntegerValue(t, k, test) 401 _, gottype, err := k.GetBinaryValue(test.Name) 402 testErrUnexpectedType(t, test, gottype, err) 403 _, _, err = k.GetIntegerValue(test.Name + "_int_not_created") 404 testErrNotExist(t, test.Name+"_int_not_created", err) 405 size := 8 406 if test.Type == registry.DWORD { 407 size = 4 408 } 409 testGetValue(t, k, test, size) 410 case registry.BINARY: 411 testGetBinaryValue(t, k, test) 412 _, gottype, err := k.GetStringsValue(test.Name) 413 testErrUnexpectedType(t, test, gottype, err) 414 _, _, err = k.GetBinaryValue(test.Name + "_byte_not_created") 415 testErrNotExist(t, test.Name+"_byte_not_created", err) 416 testGetValue(t, k, test, len(test.Value.([]byte))) 417 case registry.MULTI_SZ: 418 if test.WillFail { 419 _, _, err := k.GetStringsValue(test.Name) 420 testErrNotExist(t, test.Name, err) 421 } else { 422 testGetStringsValue(t, k, test) 423 _, gottype, err := k.GetStringValue(test.Name) 424 testErrUnexpectedType(t, test, gottype, err) 425 size := 0 426 for _, s := range test.Value.([]string) { 427 size += len(s) + 1 // nil terminated 428 } 429 size += 1 // extra nil at the end 430 size *= 2 // count bytes, not uint16 431 testGetValue(t, k, test, size) 432 } 433 _, _, err := k.GetStringsValue(test.Name + "_strings_not_created") 434 testErrNotExist(t, test.Name+"_strings_not_created", err) 435 default: 436 t.Errorf("unsupported type %d for %s value", test.Type, test.Name) 437 continue 438 } 439 } 440 } 441 442 func testStat(t *testing.T, k registry.Key) { 443 subk, _, err := registry.CreateKey(k, "subkey", registry.CREATE_SUB_KEY) 444 if err != nil { 445 t.Error(err) 446 return 447 } 448 defer subk.Close() 449 450 defer registry.DeleteKey(k, "subkey") 451 452 ki, err := k.Stat() 453 if err != nil { 454 t.Error(err) 455 return 456 } 457 if ki.SubKeyCount != 1 { 458 t.Error("key must have 1 subkey") 459 } 460 if ki.MaxSubKeyLen != 6 { 461 t.Error("key max subkey name length must be 6") 462 } 463 if ki.ValueCount != 24 { 464 t.Errorf("key must have 24 values, but is %d", ki.ValueCount) 465 } 466 if ki.MaxValueNameLen != 12 { 467 t.Errorf("key max value name length must be 10, but is %d", ki.MaxValueNameLen) 468 } 469 if ki.MaxValueLen != 38 { 470 t.Errorf("key max value length must be 38, but is %d", ki.MaxValueLen) 471 } 472 if mt, ct := ki.ModTime(), time.Now(); ct.Sub(mt) > 100*time.Millisecond { 473 t.Errorf("key mod time is not close to current time: mtime=%v current=%v delta=%v", mt, ct, ct.Sub(mt)) 474 } 475 } 476 477 func deleteValues(t *testing.T, k registry.Key) { 478 for _, test := range ValueTests { 479 if test.WillFail { 480 continue 481 } 482 err := k.DeleteValue(test.Name) 483 if err != nil { 484 t.Error(err) 485 continue 486 } 487 } 488 names, err := k.ReadValueNames(-1) 489 if err != nil { 490 t.Error(err) 491 return 492 } 493 if len(names) != 0 { 494 t.Errorf("some values remain after deletion: %v", names) 495 } 496 } 497 498 func TestValues(t *testing.T) { 499 softwareK, err := registry.OpenKey(registry.CURRENT_USER, "Software", registry.QUERY_VALUE) 500 if err != nil { 501 t.Fatal(err) 502 } 503 defer softwareK.Close() 504 505 testKName := randKeyName("TestValues_") 506 507 k, exist, err := registry.CreateKey(softwareK, testKName, registry.CREATE_SUB_KEY|registry.QUERY_VALUE|registry.SET_VALUE) 508 if err != nil { 509 t.Fatal(err) 510 } 511 defer k.Close() 512 513 if exist { 514 t.Fatalf("key %q already exists", testKName) 515 } 516 517 defer registry.DeleteKey(softwareK, testKName) 518 519 setValues(t, k) 520 521 enumerateValues(t, k) 522 523 testValues(t, k) 524 525 testStat(t, k) 526 527 deleteValues(t, k) 528 } 529 530 func TestExpandString(t *testing.T) { 531 got, err := registry.ExpandString("%PATH%") 532 if err != nil { 533 t.Fatal(err) 534 } 535 want := os.Getenv("PATH") 536 if got != want { 537 t.Errorf("want %q string expanded, got %q", want, got) 538 } 539 } 540 541 func TestInvalidValues(t *testing.T) { 542 softwareK, err := registry.OpenKey(registry.CURRENT_USER, "Software", registry.QUERY_VALUE) 543 if err != nil { 544 t.Fatal(err) 545 } 546 defer softwareK.Close() 547 548 testKName := randKeyName("TestInvalidValues_") 549 550 k, exist, err := registry.CreateKey(softwareK, testKName, registry.CREATE_SUB_KEY|registry.QUERY_VALUE|registry.SET_VALUE) 551 if err != nil { 552 t.Fatal(err) 553 } 554 defer k.Close() 555 556 if exist { 557 t.Fatalf("key %q already exists", testKName) 558 } 559 560 defer registry.DeleteKey(softwareK, testKName) 561 562 var tests = []struct { 563 Type uint32 564 Name string 565 Data []byte 566 }{ 567 {registry.DWORD, "Dword1", nil}, 568 {registry.DWORD, "Dword2", []byte{1, 2, 3}}, 569 {registry.QWORD, "Qword1", nil}, 570 {registry.QWORD, "Qword2", []byte{1, 2, 3}}, 571 {registry.QWORD, "Qword3", []byte{1, 2, 3, 4, 5, 6, 7}}, 572 {registry.MULTI_SZ, "MultiString1", nil}, 573 {registry.MULTI_SZ, "MultiString2", []byte{0}}, 574 {registry.MULTI_SZ, "MultiString3", []byte{'a', 'b', 0}}, 575 {registry.MULTI_SZ, "MultiString4", []byte{'a', 0, 0, 'b', 0}}, 576 {registry.MULTI_SZ, "MultiString5", []byte{'a', 0, 0}}, 577 } 578 579 for _, test := range tests { 580 err := k.SetValue(test.Name, test.Type, test.Data) 581 if err != nil { 582 t.Fatalf("SetValue for %q failed: %v", test.Name, err) 583 } 584 } 585 586 for _, test := range tests { 587 switch test.Type { 588 case registry.DWORD, registry.QWORD: 589 value, valType, err := k.GetIntegerValue(test.Name) 590 if err == nil { 591 t.Errorf("GetIntegerValue(%q) succeeded. Returns type=%d value=%v", test.Name, valType, value) 592 } 593 case registry.MULTI_SZ: 594 value, valType, err := k.GetStringsValue(test.Name) 595 if err == nil { 596 if len(value) != 0 { 597 t.Errorf("GetStringsValue(%q) succeeded. Returns type=%d value=%v", test.Name, valType, value) 598 } 599 } 600 default: 601 t.Errorf("unsupported type %d for %s value", test.Type, test.Name) 602 } 603 } 604 } 605 606 func TestGetMUIStringValue(t *testing.T) { 607 if err := registry.LoadRegLoadMUIString(); err != nil { 608 t.Skip("regLoadMUIString not supported; skipping") 609 } 610 if err := procGetDynamicTimeZoneInformation.Find(); err != nil { 611 t.Skipf("%s not supported; skipping", procGetDynamicTimeZoneInformation.Name) 612 } 613 var dtzi DynamicTimezoneinformation 614 if _, err := GetDynamicTimeZoneInformation(&dtzi); err != nil { 615 t.Fatal(err) 616 } 617 tzKeyName := syscall.UTF16ToString(dtzi.TimeZoneKeyName[:]) 618 timezoneK, err := registry.OpenKey(registry.LOCAL_MACHINE, 619 `SOFTWARE\Microsoft\Windows NT\CurrentVersion\Time Zones\`+tzKeyName, registry.READ) 620 if err != nil { 621 t.Fatal(err) 622 } 623 defer timezoneK.Close() 624 625 type testType struct { 626 name string 627 want string 628 } 629 var tests = []testType{ 630 {"MUI_Std", syscall.UTF16ToString(dtzi.StandardName[:])}, 631 } 632 if dtzi.DynamicDaylightTimeDisabled == 0 { 633 tests = append(tests, testType{"MUI_Dlt", syscall.UTF16ToString(dtzi.DaylightName[:])}) 634 } 635 636 for _, test := range tests { 637 got, err := timezoneK.GetMUIStringValue(test.name) 638 if err != nil { 639 t.Error("GetMUIStringValue:", err) 640 } 641 642 if got != test.want { 643 t.Errorf("GetMUIStringValue: %s: Got %q, want %q", test.name, got, test.want) 644 } 645 } 646 } 647 648 type DynamicTimezoneinformation struct { 649 Bias int32 650 StandardName [32]uint16 651 StandardDate syscall.Systemtime 652 StandardBias int32 653 DaylightName [32]uint16 654 DaylightDate syscall.Systemtime 655 DaylightBias int32 656 TimeZoneKeyName [128]uint16 657 DynamicDaylightTimeDisabled uint8 658 } 659 660 var ( 661 kernel32DLL = syscall.NewLazyDLL("kernel32") 662 663 procGetDynamicTimeZoneInformation = kernel32DLL.NewProc("GetDynamicTimeZoneInformation") 664 ) 665 666 func GetDynamicTimeZoneInformation(dtzi *DynamicTimezoneinformation) (rc uint32, err error) { 667 r0, _, e1 := syscall.Syscall(procGetDynamicTimeZoneInformation.Addr(), 1, uintptr(unsafe.Pointer(dtzi)), 0, 0) 668 rc = uint32(r0) 669 if rc == 0xffffffff { 670 if e1 != 0 { 671 err = error(e1) 672 } else { 673 err = syscall.EINVAL 674 } 675 } 676 return 677 }