Source file src/internal/syscall/windows/registry/registry_test.go

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

View as plain text