Tcl Source Code

Check-in [5205e9ee6e]
Login

Many hyperlinks are disabled.
Use anonymous login to enable hyperlinks.

Overview
Comment:[Bug #3362446]: registry keys command fails with 8.5/8.6 update registry version to 1.2.2
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | core-8-5-branch
Files: files | file ages | folders
SHA1: 5205e9ee6e87c12b7a359274ef66e1998b4008b9
User & Date: jan.nijtmans 2012-06-21 09:34:53
Context
2012-06-21
11:02
[Bug 3362446]: possible allocation error when using UNICODE check-in: 38a393d995 user: jan.nijtmans tags: core-8-5-branch
09:48
[Bug #3362446]: registry keys command fails with 8.5/8.6 check-in: 0aac52c609 user: jan.nijtmans tags: trunk
09:34
[Bug #3362446]: registry keys command fails with 8.5/8.6 update registry version to 1.2.2 check-in: 5205e9ee6e user: jan.nijtmans tags: core-8-5-branch
2012-06-20
19:49
Purge more dead fs path code. check-in: 2c1828bed8 user: dgp tags: core-8-5-branch
13:26
remove some unused code Closed-Leaf check-in: b69d567218 user: jan.nijtmans tags: bug-3362446
Changes
Hide Diffs Unified Diffs Ignore Whitespace Patch

Changes to ChangeLog.

1
2
3


4
5
6
7
8
9
10
2012-06-19  Jan Nijtmans  <[email protected]>

	* win/tclWinReg.c:  Plug memory leak, part of [Bug #3362446]



2012-06-11  Don Porter  <[email protected]>

	* generic/tclBasic.c:	[Bug 3532959] Make sure the lifetime management
	* generic/tclProc.c:	of entries in the linePBodyPtr hash table can
	* tests/proc.test:	tolerate either order of teardown, interp first,
	or Proc first.
|

|
>
>







1
2
3
4
5
6
7
8
9
10
11
12
2012-06-21  Jan Nijtmans  <[email protected]>

	* win/tclWinReg.c:          [Bug #3362446]: registry keys command fails
	* tests/registry.test:      with 8.5/8.6
	* library/reg/pkgIndex.tcl: registry version to 1.2.2

2012-06-11  Don Porter  <[email protected]>

	* generic/tclBasic.c:	[Bug 3532959] Make sure the lifetime management
	* generic/tclProc.c:	of entries in the linePBodyPtr hash table can
	* tests/proc.test:	tolerate either order of teardown, interp first,
	or Proc first.

Changes to library/reg/pkgIndex.tcl.

1
2
3
4
5
6
7
8
9
if {![package vsatisfies [package provide Tcl] 8]} return
if {[info sharedlibextension] != ".dll"} return
if {[info exists ::tcl_platform(debug)]} {
    package ifneeded registry 1.2.1 \
            [list load [file join $dir tclreg12g.dll] registry]
} else {
    package ifneeded registry 1.2.1 \
            [list load [file join $dir tclreg12.dll] registry]
}



|


|


1
2
3
4
5
6
7
8
9
if {![package vsatisfies [package provide Tcl] 8]} return
if {[info sharedlibextension] != ".dll"} return
if {[info exists ::tcl_platform(debug)]} {
    package ifneeded registry 1.2.2 \
            [list load [file join $dir tclreg12g.dll] registry]
} else {
    package ifneeded registry 1.2.2 \
            [list load [file join $dir tclreg12.dll] registry]
}

Changes to tests/registry.test.

456
457
458
459
460
461
462






463
464
465
466
467
468
469
} "foo ba\u00c7r baz"
test registry-6.20 {GetValue: values with Unicode strings with embedded nulls} {win reg} {
    registry set HKEY_CURRENT_USER\\TclFoobar val1 {foo ba\u0000r baz} multi_sz
    set result [registry get HKEY_CURRENT_USER\\TclFoobar val1]
    registry delete HKEY_CURRENT_USER\\TclFoobar
    set result
} "foo ba r baz"







test registry-7.1 {GetValueNames: bad key} {win reg english} {
    registry delete HKEY_CURRENT_USER\\TclFoobar
    list [catch {registry values HKEY_CURRENT_USER\\TclFoobar} msg] $msg
} {1 {unable to open key: The system cannot find the file specified.}}
test registry-7.2 {GetValueNames} {win reg} {
    registry delete HKEY_CURRENT_USER\\TclFoobar







>
>
>
>
>
>







456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
} "foo ba\u00c7r baz"
test registry-6.20 {GetValue: values with Unicode strings with embedded nulls} {win reg} {
    registry set HKEY_CURRENT_USER\\TclFoobar val1 {foo ba\u0000r baz} multi_sz
    set result [registry get HKEY_CURRENT_USER\\TclFoobar val1]
    registry delete HKEY_CURRENT_USER\\TclFoobar
    set result
} "foo ba r baz"
test registry-6.21 {GetValue: very long value names and values} {pcOnly} {
    registry set HKEY_CURRENT_USER\\TclFoobar [string repeat k 16383] [string repeat x 16383] multi_sz
    set result [registry get HKEY_CURRENT_USER\\TclFoobar [string repeat k 16383]]
    registry delete HKEY_CURRENT_USER\\TclFoobar
    set result
} [string repeat x 16383]

test registry-7.1 {GetValueNames: bad key} {win reg english} {
    registry delete HKEY_CURRENT_USER\\TclFoobar
    list [catch {registry values HKEY_CURRENT_USER\\TclFoobar} msg] $msg
} {1 {unable to open key: The system cannot find the file specified.}}
test registry-7.2 {GetValueNames} {win reg} {
    registry delete HKEY_CURRENT_USER\\TclFoobar

Changes to win/tclWinReg.c.

9
10
11
12
13
14
15

16
17
18
19
20
21
22
23
24
25
26
27
28
29








30
31
32
33
34
35
36
 * Copyright (c) 1998-1999 by Scriptics Corporation.
 *
 * See the file "license.terms" for information on usage and redistribution of
 * this file, and for a DISCLAIMER OF ALL WARRANTIES.
 */

#include "tclInt.h"

#ifdef _MSC_VER
#   pragma comment (lib, "advapi32.lib")
#endif
#include <stdlib.h>

/*
 * TCL_STORAGE_CLASS is set unconditionally to DLLEXPORT because the
 * Registry_Init declaration is in the source file itself, which is only
 * accessed when we are building a library.
 */

#undef TCL_STORAGE_CLASS
#define TCL_STORAGE_CLASS DLLEXPORT









/*
 * The following macros convert between different endian ints.
 */

#define SWAPWORD(x) MAKEWORD(HIBYTE(x), LOBYTE(x))
#define SWAPLONG(x) MAKELONG(SWAPWORD(HIWORD(x)), SWAPWORD(LOWORD(x)))








>














>
>
>
>
>
>
>
>







9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
 * Copyright (c) 1998-1999 by Scriptics Corporation.
 *
 * See the file "license.terms" for information on usage and redistribution of
 * this file, and for a DISCLAIMER OF ALL WARRANTIES.
 */

#include "tclInt.h"
#include "tclPort.h"
#ifdef _MSC_VER
#   pragma comment (lib, "advapi32.lib")
#endif
#include <stdlib.h>

/*
 * TCL_STORAGE_CLASS is set unconditionally to DLLEXPORT because the
 * Registry_Init declaration is in the source file itself, which is only
 * accessed when we are building a library.
 */

#undef TCL_STORAGE_CLASS
#define TCL_STORAGE_CLASS DLLEXPORT

/*
 * The maximum length of a sub-key name.
 */

#ifndef MAX_KEY_LENGTH
#define MAX_KEY_LENGTH		256
#endif

/*
 * The following macros convert between different endian ints.
 */

#define SWAPWORD(x) MAKEWORD(HIBYTE(x), LOBYTE(x))
#define SWAPLONG(x) MAKELONG(SWAPWORD(HIWORD(x)), SWAPWORD(LOWORD(x)))

90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
    LONG (WINAPI *regEnumKeyProc)(HKEY, DWORD, TCHAR *, DWORD);
    LONG (WINAPI *regEnumKeyExProc)(HKEY, DWORD, TCHAR *, DWORD *, DWORD *,
	    TCHAR *, DWORD *, FILETIME *);
    LONG (WINAPI *regEnumValueProc)(HKEY, DWORD, TCHAR *, DWORD *, DWORD *,
	    DWORD *, BYTE *, DWORD *);
    LONG (WINAPI *regOpenKeyExProc)(HKEY, CONST TCHAR *, DWORD, REGSAM,
	    HKEY *);
    LONG (WINAPI *regQueryInfoKeyProc)(HKEY, TCHAR *, DWORD *, DWORD *,
	    DWORD *, DWORD *, DWORD *, DWORD *, DWORD *, DWORD *, DWORD *,
	    FILETIME *);
    LONG (WINAPI *regQueryValueExProc)(HKEY, CONST TCHAR *, DWORD *, DWORD *,
	    BYTE *, DWORD *);
    LONG (WINAPI *regSetValueExProc)(HKEY, CONST TCHAR *, DWORD, DWORD,
	    CONST BYTE*, DWORD);
} RegWinProcs;

static RegWinProcs *regWinProcs;







<
<
<







99
100
101
102
103
104
105



106
107
108
109
110
111
112
    LONG (WINAPI *regEnumKeyProc)(HKEY, DWORD, TCHAR *, DWORD);
    LONG (WINAPI *regEnumKeyExProc)(HKEY, DWORD, TCHAR *, DWORD *, DWORD *,
	    TCHAR *, DWORD *, FILETIME *);
    LONG (WINAPI *regEnumValueProc)(HKEY, DWORD, TCHAR *, DWORD *, DWORD *,
	    DWORD *, BYTE *, DWORD *);
    LONG (WINAPI *regOpenKeyExProc)(HKEY, CONST TCHAR *, DWORD, REGSAM,
	    HKEY *);



    LONG (WINAPI *regQueryValueExProc)(HKEY, CONST TCHAR *, DWORD *, DWORD *,
	    BYTE *, DWORD *);
    LONG (WINAPI *regSetValueExProc)(HKEY, CONST TCHAR *, DWORD, DWORD,
	    CONST BYTE*, DWORD);
} RegWinProcs;

static RegWinProcs *regWinProcs;
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
    (LONG (WINAPI *)(HKEY, DWORD, TCHAR *, DWORD)) RegEnumKeyA,
    (LONG (WINAPI *)(HKEY, DWORD, TCHAR *, DWORD *, DWORD *,
	    TCHAR *, DWORD *, FILETIME *)) RegEnumKeyExA,
    (LONG (WINAPI *)(HKEY, DWORD, TCHAR *, DWORD *, DWORD *,
	    DWORD *, BYTE *, DWORD *)) RegEnumValueA,
    (LONG (WINAPI *)(HKEY, CONST TCHAR *, DWORD, REGSAM,
	    HKEY *)) RegOpenKeyExA,
    (LONG (WINAPI *)(HKEY, TCHAR *, DWORD *, DWORD *,
	    DWORD *, DWORD *, DWORD *, DWORD *, DWORD *, DWORD *, DWORD *,
	    FILETIME *)) RegQueryInfoKeyA,
    (LONG (WINAPI *)(HKEY, CONST TCHAR *, DWORD *, DWORD *,
	    BYTE *, DWORD *)) RegQueryValueExA,
    (LONG (WINAPI *)(HKEY, CONST TCHAR *, DWORD, DWORD,
	    CONST BYTE*, DWORD)) RegSetValueExA,
};

static RegWinProcs unicodeProcs = {







<
<
<







123
124
125
126
127
128
129



130
131
132
133
134
135
136
    (LONG (WINAPI *)(HKEY, DWORD, TCHAR *, DWORD)) RegEnumKeyA,
    (LONG (WINAPI *)(HKEY, DWORD, TCHAR *, DWORD *, DWORD *,
	    TCHAR *, DWORD *, FILETIME *)) RegEnumKeyExA,
    (LONG (WINAPI *)(HKEY, DWORD, TCHAR *, DWORD *, DWORD *,
	    DWORD *, BYTE *, DWORD *)) RegEnumValueA,
    (LONG (WINAPI *)(HKEY, CONST TCHAR *, DWORD, REGSAM,
	    HKEY *)) RegOpenKeyExA,



    (LONG (WINAPI *)(HKEY, CONST TCHAR *, DWORD *, DWORD *,
	    BYTE *, DWORD *)) RegQueryValueExA,
    (LONG (WINAPI *)(HKEY, CONST TCHAR *, DWORD, DWORD,
	    CONST BYTE*, DWORD)) RegSetValueExA,
};

static RegWinProcs unicodeProcs = {
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
    (LONG (WINAPI *)(HKEY, DWORD, TCHAR *, DWORD)) RegEnumKeyW,
    (LONG (WINAPI *)(HKEY, DWORD, TCHAR *, DWORD *, DWORD *,
	    TCHAR *, DWORD *, FILETIME *)) RegEnumKeyExW,
    (LONG (WINAPI *)(HKEY, DWORD, TCHAR *, DWORD *, DWORD *,
	    DWORD *, BYTE *, DWORD *)) RegEnumValueW,
    (LONG (WINAPI *)(HKEY, CONST TCHAR *, DWORD, REGSAM,
	    HKEY *)) RegOpenKeyExW,
    (LONG (WINAPI *)(HKEY, TCHAR *, DWORD *, DWORD *,
	    DWORD *, DWORD *, DWORD *, DWORD *, DWORD *, DWORD *, DWORD *,
	    FILETIME *)) RegQueryInfoKeyW,
    (LONG (WINAPI *)(HKEY, CONST TCHAR *, DWORD *, DWORD *,
	    BYTE *, DWORD *)) RegQueryValueExW,
    (LONG (WINAPI *)(HKEY, CONST TCHAR *, DWORD, DWORD,
	    CONST BYTE*, DWORD)) RegSetValueExW,
};









<
<
<







145
146
147
148
149
150
151



152
153
154
155
156
157
158
    (LONG (WINAPI *)(HKEY, DWORD, TCHAR *, DWORD)) RegEnumKeyW,
    (LONG (WINAPI *)(HKEY, DWORD, TCHAR *, DWORD *, DWORD *,
	    TCHAR *, DWORD *, FILETIME *)) RegEnumKeyExW,
    (LONG (WINAPI *)(HKEY, DWORD, TCHAR *, DWORD *, DWORD *,
	    DWORD *, BYTE *, DWORD *)) RegEnumValueW,
    (LONG (WINAPI *)(HKEY, CONST TCHAR *, DWORD, REGSAM,
	    HKEY *)) RegOpenKeyExW,



    (LONG (WINAPI *)(HKEY, CONST TCHAR *, DWORD *, DWORD *,
	    BYTE *, DWORD *)) RegQueryValueExW,
    (LONG (WINAPI *)(HKEY, CONST TCHAR *, DWORD, DWORD,
	    CONST BYTE*, DWORD)) RegSetValueExW,
};


232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
    } else {
	regWinProcs = &asciiProcs;
    }

    cmd = Tcl_CreateObjCommand(interp, "registry", RegistryObjCmd,
	(ClientData)interp, DeleteCmd);
    Tcl_SetAssocData(interp, REGISTRY_ASSOC_KEY, NULL, (ClientData)cmd);
    return Tcl_PkgProvide(interp, "registry", "1.2.1");
}

/*
 *----------------------------------------------------------------------
 *
 * Registry_Unload --
 *







|







232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
    } else {
	regWinProcs = &asciiProcs;
    }

    cmd = Tcl_CreateObjCommand(interp, "registry", RegistryObjCmd,
	(ClientData)interp, DeleteCmd);
    Tcl_SetAssocData(interp, REGISTRY_ASSOC_KEY, NULL, (ClientData)cmd);
    return Tcl_PkgProvide(interp, "registry", "1.2.2");
}

/*
 *----------------------------------------------------------------------
 *
 * Registry_Unload --
 *
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
GetKeyNames(
    Tcl_Interp *interp,		/* Current interpreter. */
    Tcl_Obj *keyNameObj,	/* Key to enumerate. */
    Tcl_Obj *patternObj)	/* Optional match pattern. */
{
    char *pattern;		/* Pattern being matched against subkeys */
    HKEY key;			/* Handle to the key being examined */
    DWORD subKeyCount;		/* Number of subkeys to list */
    DWORD maxSubKeyLen;		/* Maximum string length of any subkey */
    char *buffer;		/* Buffer to hold the subkey name */
    DWORD bufSize;		/* Size of the buffer */
    DWORD index;		/* Position of the current subkey */
    char *name;			/* Subkey name */
    Tcl_Obj *resultPtr;		/* List of subkeys being accumulated */
    int result = TCL_OK;	/* Return value from this command */
    Tcl_DString ds;		/* Buffer to translate subkey name to UTF-8 */








<
<
|







585
586
587
588
589
590
591


592
593
594
595
596
597
598
599
GetKeyNames(
    Tcl_Interp *interp,		/* Current interpreter. */
    Tcl_Obj *keyNameObj,	/* Key to enumerate. */
    Tcl_Obj *patternObj)	/* Optional match pattern. */
{
    char *pattern;		/* Pattern being matched against subkeys */
    HKEY key;			/* Handle to the key being examined */


    TCHAR buffer[MAX_KEY_LENGTH*2];		/* Buffer to hold the subkey name */
    DWORD bufSize;		/* Size of the buffer */
    DWORD index;		/* Position of the current subkey */
    char *name;			/* Subkey name */
    Tcl_Obj *resultPtr;		/* List of subkeys being accumulated */
    int result = TCL_OK;	/* Return value from this command */
    Tcl_DString ds;		/* Buffer to translate subkey name to UTF-8 */

609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645



646
647
648
649
650
651
652

653
654
655
656
657
658
659

    if (OpenKey(interp, keyNameObj,
		KEY_QUERY_VALUE | KEY_ENUMERATE_SUB_KEYS,
		0, &key) != TCL_OK) {
	return TCL_ERROR;
    }

    /*
     * Determine how big a buffer is needed for enumerating subkeys, and
     * how many subkeys there are
     */

    result = (*regWinProcs->regQueryInfoKeyProc)
	(key, NULL, NULL, NULL, &subKeyCount, &maxSubKeyLen, NULL, NULL,
	 NULL, NULL, NULL, NULL);
    if (result != ERROR_SUCCESS) {
	Tcl_SetObjResult(interp, Tcl_NewObj());
	Tcl_AppendResult(interp, "unable to query key \"",
			 Tcl_GetString(keyNameObj), "\": ", NULL);
	AppendSystemError(interp, result);
	RegCloseKey(key);
	return TCL_ERROR;
    }
    if (regWinProcs->useWide) {
	buffer = ckalloc((maxSubKeyLen+1) * sizeof(WCHAR));
    } else {
	buffer = ckalloc(maxSubKeyLen+1);
    }

    /* Enumerate the subkeys */

    resultPtr = Tcl_NewObj();
    for (index = 0; index < subKeyCount; ++index) {
	bufSize = maxSubKeyLen+1;
	result = (*regWinProcs->regEnumKeyExProc)
	    (key, index, buffer, &bufSize, NULL, NULL, NULL, NULL);
	if (result != ERROR_SUCCESS) {



	    Tcl_SetObjResult(interp, Tcl_NewObj());
	    Tcl_AppendResult(interp,
			     "unable to enumerate subkeys of \"",
			     Tcl_GetString(keyNameObj),
			     "\": ", NULL);
	    AppendSystemError(interp, result);
	    result = TCL_ERROR;

	    break;
	}
	if (regWinProcs->useWide) {
	    Tcl_WinTCharToUtf((TCHAR *) buffer, bufSize * sizeof(WCHAR), &ds);
	} else {
	    Tcl_WinTCharToUtf((TCHAR *) buffer, bufSize, &ds);
	}







<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<



|
|



>
>
>
|
|
|
|
<
|
|
>







607
608
609
610
611
612
613






















614
615
616
617
618
619
620
621
622
623
624
625
626
627
628

629
630
631
632
633
634
635
636
637
638

    if (OpenKey(interp, keyNameObj,
		KEY_QUERY_VALUE | KEY_ENUMERATE_SUB_KEYS,
		0, &key) != TCL_OK) {
	return TCL_ERROR;
    }























    /* Enumerate the subkeys */

    resultPtr = Tcl_NewObj();
    for (index = 0;; ++index) {
	bufSize = MAX_KEY_LENGTH;
	result = (*regWinProcs->regEnumKeyExProc)
	    (key, index, buffer, &bufSize, NULL, NULL, NULL, NULL);
	if (result != ERROR_SUCCESS) {
	    if (result == ERROR_NO_MORE_ITEMS) {
		result = TCL_OK;
	    } else {
		Tcl_SetObjResult(interp, Tcl_NewObj());
		Tcl_AppendResult(interp,
			"unable to enumerate subkeys of \"",
			Tcl_GetString(keyNameObj), "\": ", NULL);

		AppendSystemError(interp, result);
		result = TCL_ERROR;
	    }
	    break;
	}
	if (regWinProcs->useWide) {
	    Tcl_WinTCharToUtf((TCHAR *) buffer, bufSize * sizeof(WCHAR), &ds);
	} else {
	    Tcl_WinTCharToUtf((TCHAR *) buffer, bufSize, &ds);
	}
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
    }
    if (result == TCL_OK) {
	Tcl_SetObjResult(interp, resultPtr);
    } else {
	Tcl_DecrRefCount(resultPtr); /* BUGFIX: Don't leak on failure. */
    }

    ckfree(buffer);
    RegCloseKey(key);
    return result;
}

/*
 *----------------------------------------------------------------------
 *







<







650
651
652
653
654
655
656

657
658
659
660
661
662
663
    }
    if (result == TCL_OK) {
	Tcl_SetObjResult(interp, resultPtr);
    } else {
	Tcl_DecrRefCount(resultPtr); /* BUGFIX: Don't leak on failure. */
    }


    RegCloseKey(key);
    return result;
}

/*
 *----------------------------------------------------------------------
 *
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
GetValueNames(
    Tcl_Interp *interp,		/* Current interpreter. */
    Tcl_Obj *keyNameObj,	/* Key to enumerate. */
    Tcl_Obj *patternObj)	/* Optional match pattern. */
{
    HKEY key;
    Tcl_Obj *resultPtr;
    DWORD index, size, maxSize, result;
    Tcl_DString buffer, ds;
    char *pattern, *name;

    /*
     * Attempt to open the key for enumeration.
     */

    if (OpenKey(interp, keyNameObj, KEY_QUERY_VALUE, 0, &key)
	    != TCL_OK) {
	return TCL_ERROR;
    }

    /*
     * Query the key to determine the appropriate buffer size to hold the
     * largest value name plus the terminating null.
     */

    result = (*regWinProcs->regQueryInfoKeyProc)(key, NULL, NULL, NULL, NULL,
	    NULL, NULL, &index, &maxSize, NULL, NULL, NULL);
    if (result != ERROR_SUCCESS) {
	Tcl_AppendResult(interp, "unable to query key \"",
		Tcl_GetString(keyNameObj), "\": ", NULL);
	AppendSystemError(interp, result);
	RegCloseKey(key);
	result = TCL_ERROR;
	goto done;
    }
    maxSize++;

    resultPtr = Tcl_NewObj();
    Tcl_DStringInit(&buffer);
    Tcl_DStringSetLength(&buffer,
	    (int) ((regWinProcs->useWide) ? maxSize*2 : maxSize));
    index = 0;
    result = TCL_OK;

    if (patternObj) {
	pattern = Tcl_GetString(patternObj);
    } else {
	pattern = NULL;
    }

    /*
     * Enumerate the values under the given subkey until we get an error,
     * indicating the end of the list. Note that we need to reset size after
     * each iteration because RegEnumValue smashes the old value.
     */

    size = maxSize;
    while ((*regWinProcs->regEnumValueProc)(key, index,
	    Tcl_DStringValue(&buffer), &size, NULL, NULL, NULL, NULL)
	    == ERROR_SUCCESS) {

	if (regWinProcs->useWide) {
	    size *= 2;
	}







|












<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<



|















|







885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904

















905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
GetValueNames(
    Tcl_Interp *interp,		/* Current interpreter. */
    Tcl_Obj *keyNameObj,	/* Key to enumerate. */
    Tcl_Obj *patternObj)	/* Optional match pattern. */
{
    HKEY key;
    Tcl_Obj *resultPtr;
    DWORD index, size, result;
    Tcl_DString buffer, ds;
    char *pattern, *name;

    /*
     * Attempt to open the key for enumeration.
     */

    if (OpenKey(interp, keyNameObj, KEY_QUERY_VALUE, 0, &key)
	    != TCL_OK) {
	return TCL_ERROR;
    }


















    resultPtr = Tcl_NewObj();
    Tcl_DStringInit(&buffer);
    Tcl_DStringSetLength(&buffer,
	    (int) ((regWinProcs->useWide) ? MAX_KEY_LENGTH*2 : MAX_KEY_LENGTH));
    index = 0;
    result = TCL_OK;

    if (patternObj) {
	pattern = Tcl_GetString(patternObj);
    } else {
	pattern = NULL;
    }

    /*
     * Enumerate the values under the given subkey until we get an error,
     * indicating the end of the list. Note that we need to reset size after
     * each iteration because RegEnumValue smashes the old value.
     */

    size = MAX_KEY_LENGTH;
    while ((*regWinProcs->regEnumValueProc)(key, index,
	    Tcl_DStringValue(&buffer), &size, NULL, NULL, NULL, NULL)
	    == ERROR_SUCCESS) {

	if (regWinProcs->useWide) {
	    size *= 2;
	}
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
		Tcl_DStringFree(&ds);
		break;
	    }
	}
	Tcl_DStringFree(&ds);

	index++;
	size = maxSize;
    }
    Tcl_SetObjResult(interp, resultPtr);
    Tcl_DStringFree(&buffer);

  done:
    RegCloseKey(key);
    return result;
}

/*
 *----------------------------------------------------------------------
 *







|



<
<







940
941
942
943
944
945
946
947
948
949
950


951
952
953
954
955
956
957
		Tcl_DStringFree(&ds);
		break;
	    }
	}
	Tcl_DStringFree(&ds);

	index++;
	size = MAX_KEY_LENGTH;
    }
    Tcl_SetObjResult(interp, resultPtr);
    Tcl_DStringFree(&buffer);


    RegCloseKey(key);
    return result;
}

/*
 *----------------------------------------------------------------------
 *
1222
1223
1224
1225
1226
1227
1228
1229
1230
1231
1232
1233
1234
1235
1236
1237
1238
1239
1240
1241
1242
1243
1244
1245
1246
1247
1248
1249
1250
1251
1252
1253
1254
1255
1256
1257
1258
1259
1260
1261
1262
1263
1264
1265
1266
1267
1268
1269

static DWORD
RecursiveDeleteKey(
    HKEY startKey,		/* Parent of key to be deleted. */
    CONST char *keyName)	/* Name of key to be deleted in external
				 * encoding, not UTF. */
{
    DWORD result, size, maxSize;
    Tcl_DString subkey;
    HKEY hKey;

    /*
     * Do not allow NULL or empty key name.
     */

    if (!keyName || *keyName == '\0') {
	return ERROR_BADKEY;
    }

    result = (*regWinProcs->regOpenKeyExProc)(startKey, keyName, 0,
	    KEY_ENUMERATE_SUB_KEYS | DELETE | KEY_QUERY_VALUE, &hKey);
    if (result != ERROR_SUCCESS) {
	return result;
    }
    result = (*regWinProcs->regQueryInfoKeyProc)(hKey, NULL, NULL, NULL, NULL,
	    &maxSize, NULL, NULL, NULL, NULL, NULL, NULL);
    maxSize++;
    if (result != ERROR_SUCCESS) {
	return result;
    }

    Tcl_DStringInit(&subkey);
    Tcl_DStringSetLength(&subkey,
	    (int) ((regWinProcs->useWide) ? maxSize * 2 : maxSize));

    while (result == ERROR_SUCCESS) {
	/*
	 * Always get index 0 because key deletion changes ordering.
	 */

	size = maxSize;
	result=(*regWinProcs->regEnumKeyExProc)(hKey, 0,
		Tcl_DStringValue(&subkey), &size, NULL, NULL, NULL, NULL);
	if (result == ERROR_NO_MORE_ITEMS) {
	    result = (*regWinProcs->regDeleteKeyProc)(startKey, keyName);
	    break;
	} else if (result == ERROR_SUCCESS) {
	    result = RecursiveDeleteKey(hKey, Tcl_DStringValue(&subkey));







|
















<
<
<
<
<
<



|






|







1181
1182
1183
1184
1185
1186
1187
1188
1189
1190
1191
1192
1193
1194
1195
1196
1197
1198
1199
1200
1201
1202
1203
1204






1205
1206
1207
1208
1209
1210
1211
1212
1213
1214
1215
1216
1217
1218
1219
1220
1221
1222

static DWORD
RecursiveDeleteKey(
    HKEY startKey,		/* Parent of key to be deleted. */
    CONST char *keyName)	/* Name of key to be deleted in external
				 * encoding, not UTF. */
{
    DWORD result, size;
    Tcl_DString subkey;
    HKEY hKey;

    /*
     * Do not allow NULL or empty key name.
     */

    if (!keyName || *keyName == '\0') {
	return ERROR_BADKEY;
    }

    result = (*regWinProcs->regOpenKeyExProc)(startKey, keyName, 0,
	    KEY_ENUMERATE_SUB_KEYS | DELETE | KEY_QUERY_VALUE, &hKey);
    if (result != ERROR_SUCCESS) {
	return result;
    }







    Tcl_DStringInit(&subkey);
    Tcl_DStringSetLength(&subkey,
	    (int) ((regWinProcs->useWide) ? MAX_KEY_LENGTH * 2 : MAX_KEY_LENGTH));

    while (result == ERROR_SUCCESS) {
	/*
	 * Always get index 0 because key deletion changes ordering.
	 */

	size = MAX_KEY_LENGTH;
	result=(*regWinProcs->regEnumKeyExProc)(hKey, 0,
		Tcl_DStringValue(&subkey), &size, NULL, NULL, NULL, NULL);
	if (result == ERROR_NO_MORE_ITEMS) {
	    result = (*regWinProcs->regDeleteKeyProc)(startKey, keyName);
	    break;
	} else if (result == ERROR_SUCCESS) {
	    result = RecursiveDeleteKey(hKey, Tcl_DStringValue(&subkey));