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  }