4 * This file contains the implementation of the "registry" Tcl built-in
5 * command. This command is built as a dynamically loadable extension in
8 * Copyright (c) 1997 by Sun Microsystems, Inc.
9 * Copyright (c) 1998-1999 by Scriptics Corporation.
11 * See the file "license.terms" for information on usage and redistribution of
12 * this file, and for a DISCLAIMER OF ALL WARRANTIES.
17 # define USE_TCL_STUBS
21 # pragma comment (lib, "advapi32.lib")
26 * Ensure that we can say which registry is being accessed.
29 #ifndef KEY_WOW64_64KEY
30 # define KEY_WOW64_64KEY (0x0100)
32 #ifndef KEY_WOW64_32KEY
33 # define KEY_WOW64_32KEY (0x0200)
37 * The maximum length of a sub-key name.
40 #ifndef MAX_KEY_LENGTH
41 # define MAX_KEY_LENGTH 256
45 * The following macros convert between different endian ints.
48 #define SWAPWORD(x) MAKEWORD(HIBYTE(x), LOBYTE(x))
49 #define SWAPLONG(x) MAKELONG(SWAPWORD(HIWORD(x)), SWAPWORD(LOWORD(x)))
52 * The following flag is used in OpenKeys to indicate that the specified key
53 * should be created if it doesn't currently exist.
59 * The following tables contain the mapping from registry root names to the
60 * system predefined keys.
63 static const char *const rootKeyNames[] = {
64 "HKEY_LOCAL_MACHINE", "HKEY_USERS", "HKEY_CLASSES_ROOT",
65 "HKEY_CURRENT_USER", "HKEY_CURRENT_CONFIG",
66 "HKEY_PERFORMANCE_DATA", "HKEY_DYN_DATA", NULL
69 static const HKEY rootKeys[] = {
70 HKEY_LOCAL_MACHINE, HKEY_USERS, HKEY_CLASSES_ROOT, HKEY_CURRENT_USER,
71 HKEY_CURRENT_CONFIG, HKEY_PERFORMANCE_DATA, HKEY_DYN_DATA
74 static const char REGISTRY_ASSOC_KEY[] = "registry::command";
77 * The following table maps from registry types to strings. Note that the
78 * indices for this array are the same as the constants for the known registry
79 * types so we don't need a separate table to hold the mapping.
82 static const char *const typeNames[] = {
83 "none", "sz", "expand_sz", "binary", "dword",
84 "dword_big_endian", "link", "multi_sz", "resource_list", NULL
87 static DWORD lastType = REG_RESOURCE_LIST;
90 * Declarations for functions defined in this file.
93 static void AppendSystemError(Tcl_Interp *interp, DWORD error);
94 static int BroadcastValue(Tcl_Interp *interp, int objc,
95 Tcl_Obj *const objv[]);
96 static DWORD ConvertDWORD(DWORD type, DWORD value);
97 static void DeleteCmd(void *clientData);
98 static int DeleteKey(Tcl_Interp *interp, Tcl_Obj *keyNameObj,
100 static int DeleteValue(Tcl_Interp *interp, Tcl_Obj *keyNameObj,
101 Tcl_Obj *valueNameObj, REGSAM mode);
102 static int GetKeyNames(Tcl_Interp *interp, Tcl_Obj *keyNameObj,
103 Tcl_Obj *patternObj, REGSAM mode);
104 static int GetType(Tcl_Interp *interp, Tcl_Obj *keyNameObj,
105 Tcl_Obj *valueNameObj, REGSAM mode);
106 static int GetValue(Tcl_Interp *interp, Tcl_Obj *keyNameObj,
107 Tcl_Obj *valueNameObj, REGSAM mode);
108 static int GetValueNames(Tcl_Interp *interp, Tcl_Obj *keyNameObj,
109 Tcl_Obj *patternObj, REGSAM mode);
110 static int OpenKey(Tcl_Interp *interp, Tcl_Obj *keyNameObj,
111 REGSAM mode, int flags, HKEY *keyPtr);
112 static DWORD OpenSubKey(char *hostName, HKEY rootKey,
113 char *keyName, REGSAM mode, int flags,
115 static int ParseKeyName(Tcl_Interp *interp, char *name,
116 char **hostNamePtr, HKEY *rootKeyPtr,
118 static DWORD RecursiveDeleteKey(HKEY hStartKey,
119 const WCHAR * pKeyName, REGSAM mode);
120 static int RegistryObjCmd(void *clientData,
121 Tcl_Interp *interp, int objc,
122 Tcl_Obj *const objv[]);
123 static int SetValue(Tcl_Interp *interp, Tcl_Obj *keyNameObj,
124 Tcl_Obj *valueNameObj, Tcl_Obj *dataObj,
125 Tcl_Obj *typeObj, REGSAM mode);
127 #if (TCL_MAJOR_VERSION < 9) && (TCL_MINOR_VERSION < 7)
129 # define Tcl_WCharToUtfDString(a,b,c) Tcl_WinTCharToUtf((TCHAR *)(a),(b)*sizeof(WCHAR),c)
130 # define Tcl_UtfToWCharDString(a,b,c) (WCHAR *)Tcl_WinUtfToTChar(a,b,c)
132 # define Tcl_WCharToUtfDString Tcl_UniCharToUtfDString
133 # define Tcl_UtfToWCharDString Tcl_UtfToUniCharDString
137 static unsigned char *
144 unsigned char *result = Tcl_GetByteArrayFromObj(objPtr, &length);
145 #if TCL_MAJOR_VERSION > 8
146 if (sizeof(TCL_HASH_TYPE) > sizeof(int)) {
147 /* 64-bit and TIP #494 situation: */
148 *lengthPtr = *(TCL_HASH_TYPE *) objPtr->internalRep.twoPtrValue.ptr1;
151 /* 32-bit or without TIP #494 */
152 *lengthPtr = (size_t) (unsigned) length;
159 DLLEXPORT int Registry_Init(Tcl_Interp *interp);
160 DLLEXPORT int Registry_Unload(Tcl_Interp *interp, int flags);
166 *----------------------------------------------------------------------
170 * This function initializes the registry command.
173 * A standard Tcl result.
178 *----------------------------------------------------------------------
187 if (Tcl_InitStubs(interp, "8.5", 0) == NULL) {
191 cmd = Tcl_CreateObjCommand(interp, "registry", RegistryObjCmd,
193 Tcl_SetAssocData(interp, REGISTRY_ASSOC_KEY, NULL, cmd);
194 return Tcl_PkgProvideEx(interp, "registry", "1.3.5", NULL);
198 *----------------------------------------------------------------------
202 * This function removes the registry command.
205 * A standard Tcl result.
208 * The registry command is deleted and the dll may be unloaded.
210 *----------------------------------------------------------------------
215 Tcl_Interp *interp, /* Interpreter for unloading */
216 int flags) /* Flags passed by the unload system */
223 * Unregister the registry package. There is no Tcl_PkgForget()
226 objv[0] = Tcl_NewStringObj("package", -1);
227 objv[1] = Tcl_NewStringObj("forget", -1);
228 objv[2] = Tcl_NewStringObj("registry", -1);
229 Tcl_EvalObjv(interp, 3, objv, TCL_EVAL_GLOBAL);
232 * Delete the originally registered command.
235 cmd = (Tcl_Command)Tcl_GetAssocData(interp, REGISTRY_ASSOC_KEY, NULL);
237 Tcl_DeleteCommandFromToken(interp, cmd);
244 *----------------------------------------------------------------------
248 * Cleanup the interp command token so that unloading doesn't try to
249 * re-delete the command (which will crash).
255 * The unload command will not attempt to delete this command.
257 *----------------------------------------------------------------------
264 Tcl_Interp *interp = (Tcl_Interp *)clientData;
266 Tcl_SetAssocData(interp, REGISTRY_ASSOC_KEY, NULL, NULL);
270 *----------------------------------------------------------------------
274 * This function implements the Tcl "registry" command.
277 * A standard Tcl result.
282 *----------------------------------------------------------------------
287 void *dummy, /* Not used. */
288 Tcl_Interp *interp, /* Current interpreter. */
289 int objc, /* Number of arguments. */
290 Tcl_Obj *const objv[]) /* Argument values. */
295 const char *errString = NULL;
297 static const char *const subcommands[] = {
298 "broadcast", "delete", "get", "keys", "set", "type", "values", NULL
301 BroadcastIdx, DeleteIdx, GetIdx, KeysIdx, SetIdx, TypeIdx, ValuesIdx
303 static const char *const modes[] = {
304 "-32bit", "-64bit", NULL
310 Tcl_WrongNumArgs(interp, 1, objv, "?-32bit|-64bit? option ?arg ...?");
314 if (Tcl_GetString(objv[n])[0] == '-') {
315 if (Tcl_GetIndexFromObj(interp, objv[n++], modes, "mode", 0,
321 mode |= KEY_WOW64_32KEY;
324 mode |= KEY_WOW64_64KEY;
332 if (Tcl_GetIndexFromObj(interp, objv[n++], subcommands, "option", 0,
339 case BroadcastIdx: /* broadcast */
340 if (argc == 1 || argc == 3) {
341 int res = BroadcastValue(interp, argc, objv + n);
343 if (res != TCL_BREAK) {
347 errString = "keyName ?-timeout milliseconds?";
349 case DeleteIdx: /* delete */
351 return DeleteKey(interp, objv[n], mode);
352 } else if (argc == 2) {
353 return DeleteValue(interp, objv[n], objv[n+1], mode);
355 errString = "keyName ?valueName?";
357 case GetIdx: /* get */
359 return GetValue(interp, objv[n], objv[n+1], mode);
361 errString = "keyName valueName";
363 case KeysIdx: /* keys */
365 return GetKeyNames(interp, objv[n], NULL, mode);
366 } else if (argc == 2) {
367 return GetKeyNames(interp, objv[n], objv[n+1], mode);
369 errString = "keyName ?pattern?";
371 case SetIdx: /* set */
376 * Create the key and then close it immediately.
379 mode |= KEY_ALL_ACCESS;
380 if (OpenKey(interp, objv[n], mode, 1, &key) != TCL_OK) {
385 } else if (argc == 3) {
386 return SetValue(interp, objv[n], objv[n+1], objv[n+2], NULL,
388 } else if (argc == 4) {
389 return SetValue(interp, objv[n], objv[n+1], objv[n+2], objv[n+3],
392 errString = "keyName ?valueName data ?type??";
394 case TypeIdx: /* type */
396 return GetType(interp, objv[n], objv[n+1], mode);
398 errString = "keyName valueName";
400 case ValuesIdx: /* values */
402 return GetValueNames(interp, objv[n], NULL, mode);
403 } else if (argc == 2) {
404 return GetValueNames(interp, objv[n], objv[n+1], mode);
406 errString = "keyName ?pattern?";
409 Tcl_WrongNumArgs(interp, (mode ? 3 : 2), objv, errString);
414 *----------------------------------------------------------------------
418 * This function deletes a registry key.
421 * A standard Tcl result.
426 *----------------------------------------------------------------------
431 Tcl_Interp *interp, /* Current interpreter. */
432 Tcl_Obj *keyNameObj, /* Name of key to delete. */
433 REGSAM mode) /* Mode flags to pass. */
435 char *tail, *buffer, *hostName, *keyName;
436 const WCHAR *nativeTail;
437 HKEY rootKey, subkey;
440 REGSAM saveMode = mode;
443 * Find the parent of the key being deleted and open it.
446 keyName = Tcl_GetString(keyNameObj);
447 buffer = (char *)Tcl_Alloc(keyNameObj->length + 1);
448 strcpy(buffer, keyName);
450 if (ParseKeyName(interp, buffer, &hostName, &rootKey,
451 &keyName) != TCL_OK) {
456 if (*keyName == '\0') {
457 Tcl_SetObjResult(interp,
458 Tcl_NewStringObj("bad key: cannot delete root keys", -1));
459 Tcl_SetErrorCode(interp, "WIN_REG", "DEL_ROOT_KEY", NULL);
464 tail = strrchr(keyName, '\\');
472 mode |= KEY_ENUMERATE_SUB_KEYS | DELETE;
473 result = OpenSubKey(hostName, rootKey, keyName, mode, 0, &subkey);
474 if (result != ERROR_SUCCESS) {
476 if (result == ERROR_FILE_NOT_FOUND) {
479 Tcl_SetObjResult(interp,
480 Tcl_NewStringObj("unable to delete key: ", -1));
481 AppendSystemError(interp, result);
486 * Now we recursively delete the key and everything below it.
489 Tcl_DStringInit(&buf);
490 nativeTail = Tcl_UtfToWCharDString(tail, -1, &buf);
491 result = RecursiveDeleteKey(subkey, nativeTail, saveMode);
492 Tcl_DStringFree(&buf);
494 if (result != ERROR_SUCCESS && result != ERROR_FILE_NOT_FOUND) {
495 Tcl_SetObjResult(interp,
496 Tcl_NewStringObj("unable to delete key: ", -1));
497 AppendSystemError(interp, result);
509 *----------------------------------------------------------------------
513 * This function deletes a value from a registry key.
516 * A standard Tcl result.
521 *----------------------------------------------------------------------
526 Tcl_Interp *interp, /* Current interpreter. */
527 Tcl_Obj *keyNameObj, /* Name of key. */
528 Tcl_Obj *valueNameObj, /* Name of value to delete. */
529 REGSAM mode) /* Mode flags to pass. */
537 * Attempt to open the key for deletion.
540 mode |= KEY_SET_VALUE;
541 if (OpenKey(interp, keyNameObj, mode, 0, &key) != TCL_OK) {
545 valueName = Tcl_GetString(valueNameObj);
546 Tcl_DStringInit(&ds);
547 Tcl_UtfToWCharDString(valueName, valueNameObj->length, &ds);
548 result = RegDeleteValueW(key, (const WCHAR *)Tcl_DStringValue(&ds));
549 Tcl_DStringFree(&ds);
550 if (result != ERROR_SUCCESS) {
551 Tcl_SetObjResult(interp, Tcl_ObjPrintf(
552 "unable to delete value \"%s\" from key \"%s\": ",
553 Tcl_GetString(valueNameObj), Tcl_GetString(keyNameObj)));
554 AppendSystemError(interp, result);
564 *----------------------------------------------------------------------
568 * This function enumerates the subkeys of a given key. If the optional
569 * pattern is supplied, then only keys that match the pattern will be
573 * Returns the list of subkeys in the result object of the interpreter,
574 * or an error message on failure.
579 *----------------------------------------------------------------------
584 Tcl_Interp *interp, /* Current interpreter. */
585 Tcl_Obj *keyNameObj, /* Key to enumerate. */
586 Tcl_Obj *patternObj, /* Optional match pattern. */
587 REGSAM mode) /* Mode flags to pass. */
589 const char *pattern; /* Pattern being matched against subkeys */
590 HKEY key; /* Handle to the key being examined */
591 WCHAR buffer[MAX_KEY_LENGTH];
592 /* Buffer to hold the subkey name */
593 DWORD bufSize; /* Size of the buffer */
594 DWORD index; /* Position of the current subkey */
595 char *name; /* Subkey name */
596 Tcl_Obj *resultPtr; /* List of subkeys being accumulated */
597 int result = TCL_OK; /* Return value from this command */
598 Tcl_DString ds; /* Buffer to translate subkey name to UTF-8 */
601 pattern = Tcl_GetString(patternObj);
607 * Attempt to open the key for enumeration.
610 mode |= KEY_QUERY_VALUE | KEY_ENUMERATE_SUB_KEYS;
611 if (OpenKey(interp, keyNameObj, mode, 0, &key) != TCL_OK) {
616 * Enumerate the subkeys.
619 resultPtr = Tcl_NewObj();
620 for (index = 0;; ++index) {
621 bufSize = MAX_KEY_LENGTH;
622 result = RegEnumKeyExW(key, index, buffer, &bufSize,
623 NULL, NULL, NULL, NULL);
624 if (result != ERROR_SUCCESS) {
625 if (result == ERROR_NO_MORE_ITEMS) {
628 Tcl_SetObjResult(interp, Tcl_ObjPrintf(
629 "unable to enumerate subkeys of \"%s\": ",
630 Tcl_GetString(keyNameObj)));
631 AppendSystemError(interp, result);
636 Tcl_DStringInit(&ds);
637 name = Tcl_WCharToUtfDString(buffer, bufSize, &ds);
638 if (pattern && !Tcl_StringMatch(name, pattern)) {
639 Tcl_DStringFree(&ds);
642 result = Tcl_ListObjAppendElement(interp, resultPtr,
643 Tcl_NewStringObj(name, Tcl_DStringLength(&ds)));
644 Tcl_DStringFree(&ds);
645 if (result != TCL_OK) {
649 if (result == TCL_OK) {
650 Tcl_SetObjResult(interp, resultPtr);
652 Tcl_DecrRefCount(resultPtr); /* BUGFIX: Don't leak on failure. */
660 *----------------------------------------------------------------------
664 * This function gets the type of a given registry value and places it in
665 * the interpreter result.
668 * Returns a normal Tcl result.
673 *----------------------------------------------------------------------
678 Tcl_Interp *interp, /* Current interpreter. */
679 Tcl_Obj *keyNameObj, /* Name of key. */
680 Tcl_Obj *valueNameObj, /* Name of value to get. */
681 REGSAM mode) /* Mode flags to pass. */
686 const char *valueName;
687 const WCHAR *nativeValue;
690 * Attempt to open the key for reading.
693 mode |= KEY_QUERY_VALUE;
694 if (OpenKey(interp, keyNameObj, mode, 0, &key) != TCL_OK) {
699 * Get the type of the value.
702 valueName = Tcl_GetString(valueNameObj);
703 Tcl_DStringInit(&ds);
704 nativeValue = Tcl_UtfToWCharDString(valueName, valueNameObj->length, &ds);
705 result = RegQueryValueExW(key, nativeValue, NULL, &type,
707 Tcl_DStringFree(&ds);
710 if (result != ERROR_SUCCESS) {
711 Tcl_SetObjResult(interp, Tcl_ObjPrintf(
712 "unable to get type of value \"%s\" from key \"%s\": ",
713 Tcl_GetString(valueNameObj), Tcl_GetString(keyNameObj)));
714 AppendSystemError(interp, result);
719 * Set the type into the result. Watch out for unknown types. If we don't
720 * know about the type, just use the numeric value.
723 if (type > lastType) {
724 Tcl_SetObjResult(interp, Tcl_NewIntObj((int) type));
726 Tcl_SetObjResult(interp, Tcl_NewStringObj(typeNames[type], -1));
732 *----------------------------------------------------------------------
736 * This function gets the contents of a registry value and places a list
737 * containing the data and the type in the interpreter result.
740 * Returns a normal Tcl result.
745 *----------------------------------------------------------------------
750 Tcl_Interp *interp, /* Current interpreter. */
751 Tcl_Obj *keyNameObj, /* Name of key. */
752 Tcl_Obj *valueNameObj, /* Name of value to get. */
753 REGSAM mode) /* Mode flags to pass. */
756 const char *valueName;
757 const WCHAR *nativeValue;
758 DWORD result, length, type;
759 Tcl_DString data, buf;
762 * Attempt to open the key for reading.
765 mode |= KEY_QUERY_VALUE;
766 if (OpenKey(interp, keyNameObj, mode, 0, &key) != TCL_OK) {
771 * Initialize a Dstring to maximum statically allocated size we could get
772 * one more byte by avoiding Tcl_DStringSetLength() and just setting
773 * length to TCL_DSTRING_STATIC_SIZE, but this should be safer if the
774 * implementation of Dstrings changes.
776 * This allows short values to be read from the registy in one call.
777 * Longer values need a second call with an expanded DString.
780 Tcl_DStringInit(&data);
781 Tcl_DStringSetLength(&data, TCL_DSTRING_STATIC_SIZE - 1);
782 length = TCL_DSTRING_STATIC_SIZE/sizeof(WCHAR) - 1;
784 valueName = Tcl_GetString(valueNameObj);
785 Tcl_DStringInit(&buf);
786 nativeValue = Tcl_UtfToWCharDString(valueName, valueNameObj->length, &buf);
788 result = RegQueryValueExW(key, nativeValue, NULL, &type,
789 (BYTE *) Tcl_DStringValue(&data), &length);
790 while (result == ERROR_MORE_DATA) {
792 * The Windows docs say that in this error case, we just need to
793 * expand our buffer and request more data. Required for
794 * HKEY_PERFORMANCE_DATA
797 length = Tcl_DStringLength(&data) * (2 / sizeof(WCHAR));
798 Tcl_DStringSetLength(&data, (int) length * sizeof(WCHAR));
799 result = RegQueryValueExW(key, nativeValue,
800 NULL, &type, (BYTE *) Tcl_DStringValue(&data), &length);
802 Tcl_DStringFree(&buf);
804 if (result != ERROR_SUCCESS) {
805 Tcl_SetObjResult(interp, Tcl_ObjPrintf(
806 "unable to get value \"%s\" from key \"%s\": ",
807 Tcl_GetString(valueNameObj), Tcl_GetString(keyNameObj)));
808 AppendSystemError(interp, result);
809 Tcl_DStringFree(&data);
814 * If the data is a 32-bit quantity, store it as an integer object. If it
815 * is a multi-string, store it as a list of strings. For null-terminated
816 * strings, append up the to first null. Otherwise, store it as a binary
820 if (type == REG_DWORD || type == REG_DWORD_BIG_ENDIAN) {
821 Tcl_SetObjResult(interp, Tcl_NewIntObj((int) ConvertDWORD(type,
822 *((DWORD *) Tcl_DStringValue(&data)))));
823 } else if (type == REG_MULTI_SZ) {
824 char *p = Tcl_DStringValue(&data);
825 char *end = Tcl_DStringValue(&data) + length;
826 Tcl_Obj *resultPtr = Tcl_NewObj();
829 * Multistrings are stored as an array of null-terminated strings,
830 * terminated by two null characters. Also do a bounds check in case
834 while ((p < end) && *((WCHAR *) p) != 0) {
835 WCHAR *wp = (WCHAR *) p;
837 Tcl_DStringInit(&buf);
838 Tcl_WCharToUtfDString(wp, wcslen(wp), &buf);
839 Tcl_ListObjAppendElement(interp, resultPtr,
840 Tcl_NewStringObj(Tcl_DStringValue(&buf),
841 Tcl_DStringLength(&buf)));
843 while (*wp++ != 0) {/* empty body */}
845 Tcl_DStringFree(&buf);
847 Tcl_SetObjResult(interp, resultPtr);
848 } else if ((type == REG_SZ) || (type == REG_EXPAND_SZ)) {
849 WCHAR *wp = (WCHAR *) Tcl_DStringValue(&data);
850 Tcl_DStringInit(&buf);
851 Tcl_WCharToUtfDString((const WCHAR *)Tcl_DStringValue(&data), wcslen(wp), &buf);
852 Tcl_DStringResult(interp, &buf);
855 * Save binary data as a byte array.
858 Tcl_SetObjResult(interp, Tcl_NewByteArrayObj(
859 (BYTE *) Tcl_DStringValue(&data), (int) length));
861 Tcl_DStringFree(&data);
866 *----------------------------------------------------------------------
870 * This function enumerates the values of the a given key. If the
871 * optional pattern is supplied, then only value names that match the
872 * pattern will be returned.
875 * Returns the list of value names in the result object of the
876 * interpreter, or an error message on failure.
881 *----------------------------------------------------------------------
886 Tcl_Interp *interp, /* Current interpreter. */
887 Tcl_Obj *keyNameObj, /* Key to enumerate. */
888 Tcl_Obj *patternObj, /* Optional match pattern. */
889 REGSAM mode) /* Mode flags to pass. */
893 DWORD index, size, result;
894 Tcl_DString buffer, ds;
895 const char *pattern, *name;
898 * Attempt to open the key for enumeration.
901 mode |= KEY_QUERY_VALUE;
902 if (OpenKey(interp, keyNameObj, mode, 0, &key) != TCL_OK) {
906 resultPtr = Tcl_NewObj();
907 Tcl_DStringInit(&buffer);
908 Tcl_DStringSetLength(&buffer, (int) (MAX_KEY_LENGTH * sizeof(WCHAR)));
913 pattern = Tcl_GetString(patternObj);
919 * Enumerate the values under the given subkey until we get an error,
920 * indicating the end of the list. Note that we need to reset size after
921 * each iteration because RegEnumValue smashes the old value.
924 size = MAX_KEY_LENGTH;
925 while (RegEnumValueW(key,index, (WCHAR *)Tcl_DStringValue(&buffer),
926 &size, NULL, NULL, NULL, NULL) == ERROR_SUCCESS) {
928 Tcl_DStringInit(&ds);
929 Tcl_WCharToUtfDString((const WCHAR *)Tcl_DStringValue(&buffer), size, &ds);
930 name = Tcl_DStringValue(&ds);
931 if (!pattern || Tcl_StringMatch(name, pattern)) {
932 result = Tcl_ListObjAppendElement(interp, resultPtr,
933 Tcl_NewStringObj(name, Tcl_DStringLength(&ds)));
934 if (result != TCL_OK) {
935 Tcl_DStringFree(&ds);
939 Tcl_DStringFree(&ds);
942 size = MAX_KEY_LENGTH;
944 Tcl_SetObjResult(interp, resultPtr);
945 Tcl_DStringFree(&buffer);
951 *----------------------------------------------------------------------
955 * This function opens the specified key. This function is a simple
956 * wrapper around ParseKeyName and OpenSubKey.
959 * Returns the opened key in the keyPtr argument and a Tcl result code.
964 *----------------------------------------------------------------------
969 Tcl_Interp *interp, /* Current interpreter. */
970 Tcl_Obj *keyNameObj, /* Key to open. */
971 REGSAM mode, /* Access mode. */
972 int flags, /* 0 or REG_CREATE. */
973 HKEY *keyPtr) /* Returned HKEY. */
975 char *keyName, *buffer, *hostName;
979 keyName = Tcl_GetString(keyNameObj);
980 buffer = (char *)Tcl_Alloc(keyNameObj->length + 1);
981 strcpy(buffer, keyName);
983 result = ParseKeyName(interp, buffer, &hostName, &rootKey, &keyName);
984 if (result == TCL_OK) {
985 result = OpenSubKey(hostName, rootKey, keyName, mode, flags, keyPtr);
986 if (result != ERROR_SUCCESS) {
987 Tcl_SetObjResult(interp,
988 Tcl_NewStringObj("unable to open key: ", -1));
989 AppendSystemError(interp, result);
1001 *----------------------------------------------------------------------
1005 * This function opens a given subkey of a root key on the specified
1009 * Returns the opened key in the keyPtr and a Windows error code as the
1015 *----------------------------------------------------------------------
1020 char *hostName, /* Host to access, or NULL for local. */
1021 HKEY rootKey, /* Root registry key. */
1022 char *keyName, /* Subkey name. */
1023 REGSAM mode, /* Access mode. */
1024 int flags, /* 0 or REG_CREATE. */
1025 HKEY *keyPtr) /* Returned HKEY. */
1031 * Attempt to open the root key on a remote host if necessary.
1035 Tcl_DStringInit(&buf);
1036 hostName = (char *) Tcl_UtfToWCharDString(hostName, -1, &buf);
1037 result = RegConnectRegistryW((WCHAR *)hostName, rootKey,
1039 Tcl_DStringFree(&buf);
1040 if (result != ERROR_SUCCESS) {
1046 * Now open the specified key with the requested permissions. Note that
1047 * this key must be closed by the caller.
1051 Tcl_DStringInit(&buf);
1052 keyName = (char *) Tcl_UtfToWCharDString(keyName, -1, &buf);
1054 if (flags & REG_CREATE) {
1057 result = RegCreateKeyExW(rootKey, (WCHAR *)keyName, 0, NULL,
1058 REG_OPTION_NON_VOLATILE, mode, NULL, keyPtr, &create);
1059 } else if (rootKey == HKEY_PERFORMANCE_DATA) {
1061 * Here we fudge it for this special root key. See MSDN for more info
1062 * on HKEY_PERFORMANCE_DATA and the peculiarities surrounding it.
1065 *keyPtr = HKEY_PERFORMANCE_DATA;
1066 result = ERROR_SUCCESS;
1068 result = RegOpenKeyExW(rootKey, (WCHAR *)keyName, 0, mode,
1072 Tcl_DStringFree(&buf);
1076 * Be sure to close the root key since we are done with it now.
1080 RegCloseKey(rootKey);
1086 *----------------------------------------------------------------------
1090 * This function parses a key name into the host, root, and subkey parts.
1093 * The pointers to the start of the host and subkey names are returned in
1094 * the hostNamePtr and keyNamePtr variables. The specified root HKEY is
1095 * returned in rootKeyPtr. Returns a standard Tcl result.
1098 * Modifies the name string by inserting nulls.
1100 *----------------------------------------------------------------------
1105 Tcl_Interp *interp, /* Current interpreter. */
1116 * Split the key into host and root portions.
1119 *hostNamePtr = *keyNamePtr = rootName = NULL;
1120 if (name[0] == '\\') {
1121 if (name[1] == '\\') {
1122 *hostNamePtr = name;
1123 for (rootName = name+2; *rootName != '\0'; rootName++) {
1124 if (*rootName == '\\') {
1134 Tcl_SetObjResult(interp, Tcl_ObjPrintf(
1135 "bad key \"%s\": must start with a valid root", name));
1136 Tcl_SetErrorCode(interp, "WIN_REG", "NO_ROOT_KEY", NULL);
1141 * Split the root into root and subkey portions.
1144 for (*keyNamePtr = rootName; **keyNamePtr != '\0'; (*keyNamePtr)++) {
1145 if (**keyNamePtr == '\\') {
1146 **keyNamePtr = '\0';
1153 * Look for a matching root name.
1156 rootObj = Tcl_NewStringObj(rootName, -1);
1157 result = Tcl_GetIndexFromObj(interp, rootObj, rootKeyNames, "root name",
1159 Tcl_DecrRefCount(rootObj);
1160 if (result != TCL_OK) {
1163 *rootKeyPtr = rootKeys[index];
1168 *----------------------------------------------------------------------
1170 * RecursiveDeleteKey --
1172 * This function recursively deletes all the keys below a starting key.
1173 * Although Windows 95 does this automatically, we still need to do this
1177 * Returns a Windows error code.
1180 * Deletes all of the keys and values below the given key.
1182 *----------------------------------------------------------------------
1187 HKEY startKey, /* Parent of key to be deleted. */
1188 const WCHAR *keyName, /* Name of key to be deleted in external
1189 * encoding, not UTF. */
1190 REGSAM mode) /* Mode flags to pass. */
1195 REGSAM saveMode = mode;
1196 static int checkExProc = 0;
1197 static LONG (* regDeleteKeyExProc) (HKEY, LPCWSTR, REGSAM, DWORD) = (LONG (*) (HKEY, LPCWSTR, REGSAM, DWORD)) NULL;
1200 * Do not allow NULL or empty key name.
1203 if (!keyName || *keyName == '\0') {
1204 return ERROR_BADKEY;
1207 mode |= KEY_ENUMERATE_SUB_KEYS | DELETE | KEY_QUERY_VALUE;
1208 result = RegOpenKeyExW(startKey, keyName, 0, mode, &hKey);
1209 if (result != ERROR_SUCCESS) {
1213 Tcl_DStringInit(&subkey);
1214 Tcl_DStringSetLength(&subkey, (int) (MAX_KEY_LENGTH * sizeof(WCHAR)));
1217 while (result == ERROR_SUCCESS) {
1219 * Always get index 0 because key deletion changes ordering.
1222 size = MAX_KEY_LENGTH;
1223 result = RegEnumKeyExW(hKey, 0, (WCHAR *)Tcl_DStringValue(&subkey),
1224 &size, NULL, NULL, NULL, NULL);
1225 if (result == ERROR_NO_MORE_ITEMS) {
1227 * RegDeleteKeyEx doesn't exist on non-64bit XP platforms, so we
1228 * can't compile with it in. We need to check for it at runtime
1229 * and use it if we find it.
1232 if (mode && !checkExProc) {
1236 handle = GetModuleHandleW(L"ADVAPI32");
1237 regDeleteKeyExProc = (LONG (*) (HKEY, LPCWSTR, REGSAM, DWORD))
1238 (void *)GetProcAddress(handle, "RegDeleteKeyExW");
1240 if (mode && regDeleteKeyExProc) {
1241 result = regDeleteKeyExProc(startKey, keyName, mode, 0);
1243 result = RegDeleteKeyW(startKey, keyName);
1246 } else if (result == ERROR_SUCCESS) {
1247 result = RecursiveDeleteKey(hKey,
1248 (const WCHAR *) Tcl_DStringValue(&subkey), mode);
1251 Tcl_DStringFree(&subkey);
1257 *----------------------------------------------------------------------
1261 * This function sets the contents of a registry value. If the key or
1262 * value does not exist, it will be created. If it does exist, then the
1263 * data and type will be replaced.
1266 * Returns a normal Tcl result.
1269 * May create new keys or values.
1271 *----------------------------------------------------------------------
1276 Tcl_Interp *interp, /* Current interpreter. */
1277 Tcl_Obj *keyNameObj, /* Name of key. */
1278 Tcl_Obj *valueNameObj, /* Name of value to set. */
1279 Tcl_Obj *dataObj, /* Data to be written. */
1280 Tcl_Obj *typeObj, /* Type of data to be written. */
1281 REGSAM mode) /* Mode flags to pass. */
1286 const char *valueName;
1287 Tcl_DString nameBuf;
1289 if (typeObj == NULL) {
1291 } else if (Tcl_GetIndexFromObj(interp, typeObj, typeNames, "type",
1292 0, (int *) &type) != TCL_OK) {
1293 if (Tcl_GetIntFromObj(NULL, typeObj, (int *) &type) != TCL_OK) {
1296 Tcl_ResetResult(interp);
1298 mode |= KEY_ALL_ACCESS;
1299 if (OpenKey(interp, keyNameObj, mode, 1, &key) != TCL_OK) {
1303 valueName = Tcl_GetString(valueNameObj);
1304 Tcl_DStringInit(&nameBuf);
1305 valueName = (char *) Tcl_UtfToWCharDString(valueName, valueNameObj->length, &nameBuf);
1307 if (type == REG_DWORD || type == REG_DWORD_BIG_ENDIAN) {
1310 if (Tcl_GetIntFromObj(interp, dataObj, &value) != TCL_OK) {
1312 Tcl_DStringFree(&nameBuf);
1316 value = ConvertDWORD((DWORD) type, (DWORD) value);
1317 result = RegSetValueExW(key, (WCHAR *) valueName, 0,
1318 (DWORD) type, (BYTE *) &value, sizeof(DWORD));
1319 } else if (type == REG_MULTI_SZ) {
1320 Tcl_DString data, buf;
1324 if (Tcl_ListObjGetElements(interp, dataObj, &objc, &objv) != TCL_OK) {
1326 Tcl_DStringFree(&nameBuf);
1331 * Append the elements as null terminated strings. Note that we must
1332 * not assume the length of the string in case there are embedded
1333 * nulls, which aren't allowed in REG_MULTI_SZ values.
1336 Tcl_DStringInit(&data);
1337 for (i = 0; i < objc; i++) {
1338 const char *bytes = Tcl_GetString(objv[i]);
1340 Tcl_DStringAppend(&data, bytes, objv[i]->length);
1343 * Add a null character to separate this value from the next.
1346 Tcl_DStringAppend(&data, "", 1); /* NUL-terminated string */
1349 Tcl_DStringInit(&buf);
1350 Tcl_UtfToWCharDString(Tcl_DStringValue(&data), Tcl_DStringLength(&data)+1,
1352 result = RegSetValueExW(key, (WCHAR *) valueName, 0,
1353 (DWORD) type, (BYTE *) Tcl_DStringValue(&buf),
1354 (DWORD) Tcl_DStringLength(&buf));
1355 Tcl_DStringFree(&data);
1356 Tcl_DStringFree(&buf);
1357 } else if (type == REG_SZ || type == REG_EXPAND_SZ) {
1359 const char *data = Tcl_GetString(dataObj);
1361 Tcl_DStringInit(&buf);
1362 data = (char *) Tcl_UtfToWCharDString(data, dataObj->length, &buf);
1365 * Include the null in the length, padding if needed for WCHAR.
1368 Tcl_DStringSetLength(&buf, Tcl_DStringLength(&buf)+1);
1370 result = RegSetValueExW(key, (WCHAR *) valueName, 0,
1371 (DWORD) type, (BYTE *) data, (DWORD) Tcl_DStringLength(&buf) + 1);
1372 Tcl_DStringFree(&buf);
1378 * Store binary data in the registry.
1381 data = (BYTE *) getByteArrayFromObj(dataObj, &bytelength);
1382 result = RegSetValueExW(key, (WCHAR *) valueName, 0,
1383 (DWORD) type, data, (DWORD) bytelength);
1386 Tcl_DStringFree(&nameBuf);
1389 if (result != ERROR_SUCCESS) {
1390 Tcl_SetObjResult(interp,
1391 Tcl_NewStringObj("unable to set value: ", -1));
1392 AppendSystemError(interp, result);
1399 *----------------------------------------------------------------------
1403 * This function broadcasts a WM_SETTINGCHANGE message to indicate to
1404 * other programs that we have changed the contents of a registry value.
1407 * Returns a normal Tcl result.
1410 * Will cause other programs to reload their system settings.
1412 *----------------------------------------------------------------------
1417 Tcl_Interp *interp, /* Current interpreter. */
1418 int objc, /* Number of arguments. */
1419 Tcl_Obj *const objv[]) /* Argument values. */
1422 DWORD_PTR sendResult;
1431 str = Tcl_GetString(objv[1]);
1432 len = objv[1]->length;
1433 if ((len < 2) || (*str != '-') || strncmp(str, "-timeout", len)) {
1436 if (Tcl_GetIntFromObj(interp, objv[2], &timeout) != TCL_OK) {
1441 str = Tcl_GetString(objv[0]);
1442 Tcl_DStringInit(&ds);
1443 wstr = Tcl_UtfToWCharDString(str, objv[0]->length, &ds);
1444 if (Tcl_DStringLength(&ds) == 0) {
1449 * Use the ignore the result.
1452 result = SendMessageTimeoutW(HWND_BROADCAST, WM_SETTINGCHANGE,
1453 (WPARAM) 0, (LPARAM) wstr, SMTO_ABORTIFHUNG, (UINT) timeout, &sendResult);
1454 Tcl_DStringFree(&ds);
1456 objPtr = Tcl_NewObj();
1457 Tcl_ListObjAppendElement(NULL, objPtr, Tcl_NewWideIntObj((Tcl_WideInt) result));
1458 Tcl_ListObjAppendElement(NULL, objPtr, Tcl_NewWideIntObj((Tcl_WideInt) sendResult));
1459 Tcl_SetObjResult(interp, objPtr);
1465 *----------------------------------------------------------------------
1467 * AppendSystemError --
1469 * This routine formats a Windows system error message and places it into
1470 * the interpreter result.
1478 *----------------------------------------------------------------------
1483 Tcl_Interp *interp, /* Current interpreter. */
1484 DWORD error) /* Result code from error. */
1487 WCHAR *tMsgPtr, **tMsgPtrPtr = &tMsgPtr;
1489 char id[TCL_INTEGER_SPACE], msgBuf[24 + TCL_INTEGER_SPACE];
1491 Tcl_Obj *resultPtr = Tcl_GetObjResult(interp);
1493 if (Tcl_IsShared(resultPtr)) {
1494 resultPtr = Tcl_DuplicateObj(resultPtr);
1496 length = FormatMessageW(FORMAT_MESSAGE_FROM_SYSTEM
1497 | FORMAT_MESSAGE_ALLOCATE_BUFFER, NULL, error,
1498 MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (WCHAR *) tMsgPtrPtr,
1501 sprintf(msgBuf, "unknown error: %ld", error);
1506 Tcl_DStringInit(&ds);
1507 Tcl_WCharToUtfDString(tMsgPtr, wcslen(tMsgPtr), &ds);
1510 msgPtr = Tcl_DStringValue(&ds);
1511 length = Tcl_DStringLength(&ds);
1514 * Trim the trailing CR/LF from the system message.
1517 if (msgPtr[length-1] == '\n') {
1520 if (msgPtr[length-1] == '\r') {
1527 sprintf(id, "%ld", error);
1528 Tcl_SetErrorCode(interp, "WINDOWS", id, msg, NULL);
1529 Tcl_AppendToObj(resultPtr, msg, length);
1530 Tcl_SetObjResult(interp, resultPtr);
1533 Tcl_DStringFree(&ds);
1538 *----------------------------------------------------------------------
1542 * This function determines whether a DWORD needs to be byte swapped, and
1543 * returns the appropriately swapped value.
1546 * Returns a converted DWORD.
1551 *----------------------------------------------------------------------
1556 DWORD type, /* Either REG_DWORD or REG_DWORD_BIG_ENDIAN */
1557 DWORD value) /* The value to be converted. */
1559 const DWORD order = 1;
1563 * Check to see if the low bit is in the first byte.
1566 localType = (*((const char *) &order) == 1)
1567 ? REG_DWORD : REG_DWORD_BIG_ENDIAN;
1568 return (type != localType) ? (DWORD) SWAPLONG(value) : value;