Tcl Source Code

Artifact [82bdd95f18]
Login

Artifact 82bdd95f18ec422bba19756ebb75bae46942d7b5:

Attachment "windows-32-and-64-bit-registry.patch" to ticket [2960976fff] added by damonc 2010-03-09 12:27:15.
--- tclWinReg.c	10 Jan 2010 22:58:40 -0000	1.50
+++ tclWinReg.c	8 Mar 2010 01:54:07 -0000
@@ -24,6 +24,14 @@
 #endif
 #include <stdlib.h>
 
+#ifndef KEY_WOW64_64KEY
+#define KEY_WOW64_64KEY (0x0100)
+#endif
+
+#ifndef KEY_WOW64_32KEY
+#define KEY_WOW64_32KEY (0x0200)
+#endif
+
 /*
  * TCL_STORAGE_CLASS is set unconditionally to DLLEXPORT because the
  * Registry_Init declaration is in the source file itself, which is only
@@ -171,17 +179,18 @@ static int		BroadcastValue(Tcl_Interp *i
 			    Tcl_Obj *const objv[]);
 static DWORD		ConvertDWORD(DWORD type, DWORD value);
 static void		DeleteCmd(ClientData clientData);
-static int		DeleteKey(Tcl_Interp *interp, Tcl_Obj *keyNameObj);
+static int		DeleteKey(Tcl_Interp *interp, Tcl_Obj *keyNameObj,
+                            REGSAM mode);
 static int		DeleteValue(Tcl_Interp *interp, Tcl_Obj *keyNameObj,
-			    Tcl_Obj *valueNameObj);
+			    Tcl_Obj *valueNameObj, REGSAM mode);
 static int		GetKeyNames(Tcl_Interp *interp, Tcl_Obj *keyNameObj,
-			    Tcl_Obj *patternObj);
+			    Tcl_Obj *patternObj, REGSAM mode);
 static int		GetType(Tcl_Interp *interp, Tcl_Obj *keyNameObj,
-			    Tcl_Obj *valueNameObj);
+			    Tcl_Obj *valueNameObj, REGSAM mode);
 static int		GetValue(Tcl_Interp *interp, Tcl_Obj *keyNameObj,
-			    Tcl_Obj *valueNameObj);
+			    Tcl_Obj *valueNameObj, REGSAM mode);
 static int		GetValueNames(Tcl_Interp *interp, Tcl_Obj *keyNameObj,
-			    Tcl_Obj *patternObj);
+			    Tcl_Obj *patternObj, REGSAM mode);
 static int		OpenKey(Tcl_Interp *interp, Tcl_Obj *keyNameObj,
 			    REGSAM mode, int flags, HKEY *keyPtr);
 static DWORD		OpenSubKey(char *hostName, HKEY rootKey,
@@ -191,13 +200,13 @@ static int		ParseKeyName(Tcl_Interp *int
 			    char **hostNamePtr, HKEY *rootKeyPtr,
 			    char **keyNamePtr);
 static DWORD		RecursiveDeleteKey(HKEY hStartKey,
-			    const TCHAR * pKeyName);
+			    const TCHAR * pKeyName, REGSAM mode);
 static int		RegistryObjCmd(ClientData clientData,
 			    Tcl_Interp *interp, int objc,
 			    Tcl_Obj *const objv[]);
 static int		SetValue(Tcl_Interp *interp, Tcl_Obj *keyNameObj,
 			    Tcl_Obj *valueNameObj, Tcl_Obj *dataObj,
-			    Tcl_Obj *typeObj);
+			    Tcl_Obj *typeObj, REGSAM mode);
 
 EXTERN int		Registry_Init(Tcl_Interp *interp);
 EXTERN int		Registry_Unload(Tcl_Interp *interp, int flags);
@@ -336,7 +345,9 @@ RegistryObjCmd(
     int objc,			/* Number of arguments. */
     Tcl_Obj *const objv[])	/* Argument values. */
 {
-    int index;
+    int n = 1;
+    int index, argc;
+    REGSAM mode = 0;
     const char *errString = NULL;
 
     static const char *const subcommands[] = {
@@ -347,76 +358,99 @@ RegistryObjCmd(
     };
 
     if (objc < 2) {
+	Tcl_WrongNumArgs(interp, objc, objv,"?-32bit|-64bit? option ?arg ...?");
+	return TCL_ERROR;
+    }
+
+    if (strncasecmp(Tcl_GetString(objv[n]), "-32bit", 6) == 0) {
+        ++n;
+        mode |= KEY_WOW64_32KEY;
+    } else if (strncasecmp(Tcl_GetString(objv[n]), "-64bit", 6) == 0) {
+        ++n;
+        mode |= KEY_WOW64_64KEY;
+    }
+
+    if (mode && objc < 3) {
 	Tcl_WrongNumArgs(interp, objc, objv, "option ?arg ...?");
 	return TCL_ERROR;
     }
 
-    if (Tcl_GetIndexFromObj(interp, objv[1], subcommands, "option", 0, &index)
+    if (Tcl_GetIndexFromObj(interp, objv[n++], subcommands, "option", 0, &index)
 	    != TCL_OK) {
 	return TCL_ERROR;
     }
 
+    argc = (objc - n);
     switch (index) {
     case BroadcastIdx:		/* broadcast */
-	return BroadcastValue(interp, objc, objv);
+        if (argc == 1 || argc == 3) {
+            int res;
+            if ((res = BroadcastValue(interp, argc, objv + n)) != TCL_BREAK) {
+                return res;
+            }
+        }
+	errString = "keyName ?-timeout milliseconds?";
 	break;
     case DeleteIdx:		/* delete */
-	if (objc == 3) {
-	    return DeleteKey(interp, objv[2]);
-	} else if (objc == 4) {
-	    return DeleteValue(interp, objv[2], objv[3]);
+	if (argc == 1) {
+	    return DeleteKey(interp, objv[n], mode);
+	} else if (argc == 2) {
+	    return DeleteValue(interp, objv[n], objv[++n], mode);
 	}
 	errString = "keyName ?valueName?";
 	break;
     case GetIdx:		/* get */
-	if (objc == 4) {
-	    return GetValue(interp, objv[2], objv[3]);
+	if (argc == 2) {
+	    return GetValue(interp, objv[n], objv[++n], mode);
 	}
 	errString = "keyName valueName";
 	break;
     case KeysIdx:		/* keys */
-	if (objc == 3) {
-	    return GetKeyNames(interp, objv[2], NULL);
-	} else if (objc == 4) {
-	    return GetKeyNames(interp, objv[2], objv[3]);
+	if (argc == 1) {
+	    return GetKeyNames(interp, objv[n], NULL, mode);
+	} else if (argc == 2) {
+	    return GetKeyNames(interp, objv[n], objv[++n], mode);
 	}
 	errString = "keyName ?pattern?";
 	break;
     case SetIdx:		/* set */
-	if (objc == 3) {
+	if (argc == 1) {
 	    HKEY key;
 
 	    /*
 	     * Create the key and then close it immediately.
 	     */
 
-	    if (OpenKey(interp, objv[2], KEY_ALL_ACCESS, 1, &key) != TCL_OK) {
+            mode |= KEY_ALL_ACCESS;
+	    if (OpenKey(interp, objv[n], mode, 1, &key) != TCL_OK) {
 		return TCL_ERROR;
 	    }
 	    RegCloseKey(key);
 	    return TCL_OK;
-	} else if (objc == 5 || objc == 6) {
-	    Tcl_Obj *typeObj = (objc == 5) ? NULL : objv[5];
-	    return SetValue(interp, objv[2], objv[3], objv[4], typeObj);
+	} else if (argc == 3) {
+	    return SetValue(interp, objv[n], objv[++n], objv[++n], NULL, mode);
+        } else if (argc == 4) {
+	    return SetValue(interp, objv[n], objv[++n], objv[++n], objv[++n],
+                mode);
 	}
 	errString = "keyName ?valueName data ?type??";
 	break;
     case TypeIdx:		/* type */
-	if (objc == 4) {
-	    return GetType(interp, objv[2], objv[3]);
+	if (argc == 2) {
+	    return GetType(interp, objv[n], objv[++n], mode);
 	}
 	errString = "keyName valueName";
 	break;
     case ValuesIdx:		/* values */
-	if (objc == 3) {
-	    return GetValueNames(interp, objv[2], NULL);
-	} else if (objc == 4) {
-	    return GetValueNames(interp, objv[2], objv[3]);
+	if (argc == 1) {
+	    return GetValueNames(interp, objv[n], NULL, mode);
+	} else if (argc == 2) {
+	    return GetValueNames(interp, objv[n], objv[++n], mode);
 	}
 	errString = "keyName ?pattern?";
 	break;
     }
-    Tcl_WrongNumArgs(interp, 2, objv, errString);
+    Tcl_WrongNumArgs(interp, (mode ? 3 : 2), objv, errString);
     return TCL_ERROR;
 }
 
@@ -439,7 +473,8 @@ RegistryObjCmd(
 static int
 DeleteKey(
     Tcl_Interp *interp,		/* Current interpreter. */
-    Tcl_Obj *keyNameObj)	/* Name of key to delete. */
+    Tcl_Obj *keyNameObj,	/* Name of key to delete. */
+    REGSAM mode)                /* mode flags to pass. */
 {
     char *tail, *buffer, *hostName, *keyName;
     const char *nativeTail;
@@ -447,6 +482,7 @@ DeleteKey(
     DWORD result;
     int length;
     Tcl_DString buf;
+    REGSAM saveMode = mode;
 
     /*
      * Find the parent of the key being deleted and open it.
@@ -477,8 +513,8 @@ DeleteKey(
 	keyName = NULL;
     }
 
-    result = OpenSubKey(hostName, rootKey, keyName,
-	    KEY_ENUMERATE_SUB_KEYS | DELETE, 0, &subkey);
+    mode |= KEY_ENUMERATE_SUB_KEYS | DELETE;
+    result = OpenSubKey(hostName, rootKey, keyName, mode, 0, &subkey);
     if (result != ERROR_SUCCESS) {
 	ckfree(buffer);
 	if (result == ERROR_FILE_NOT_FOUND) {
@@ -495,7 +531,7 @@ DeleteKey(
      */
 
     nativeTail = Tcl_WinUtfToTChar(tail, -1, &buf);
-    result = RecursiveDeleteKey(subkey, nativeTail);
+    result = RecursiveDeleteKey(subkey, nativeTail, saveMode);
     Tcl_DStringFree(&buf);
 
     if (result != ERROR_SUCCESS && result != ERROR_FILE_NOT_FOUND) {
@@ -532,7 +568,8 @@ static int
 DeleteValue(
     Tcl_Interp *interp,		/* Current interpreter. */
     Tcl_Obj *keyNameObj,	/* Name of key. */
-    Tcl_Obj *valueNameObj)	/* Name of value to delete. */
+    Tcl_Obj *valueNameObj,	/* Name of value to delete. */
+    REGSAM mode)                /* mode flags to pass. */
 {
     HKEY key;
     char *valueName;
@@ -544,10 +581,8 @@ DeleteValue(
      * Attempt to open the key for deletion.
      */
 
-    if (OpenKey(interp, keyNameObj, KEY_SET_VALUE, 0, &key)
-	    != TCL_OK) {
-	return TCL_ERROR;
-    }
+    mode |= KEY_SET_VALUE;
+    if (OpenKey(interp, keyNameObj, mode, 0, &key) != TCL_OK) return TCL_ERROR;
 
     valueName = Tcl_GetStringFromObj(valueNameObj, &length);
     Tcl_WinUtfToTChar(valueName, length, &ds);
@@ -589,9 +624,10 @@ static int
 GetKeyNames(
     Tcl_Interp *interp,		/* Current interpreter. */
     Tcl_Obj *keyNameObj,	/* Key to enumerate. */
-    Tcl_Obj *patternObj)	/* Optional match pattern. */
+    Tcl_Obj *patternObj,	/* Optional match pattern. */
+    REGSAM mode)                /* mode flags to pass. */
 {
-    const char *pattern; /* Pattern being matched against subkeys */
+    const 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 */
@@ -611,11 +647,8 @@ GetKeyNames(
 
     /* Attempt to open the key for enumeration. */
 
-    if (OpenKey(interp, keyNameObj,
-		KEY_QUERY_VALUE | KEY_ENUMERATE_SUB_KEYS,
-		0, &key) != TCL_OK) {
-	return TCL_ERROR;
-    }
+    mode |= KEY_QUERY_VALUE | KEY_ENUMERATE_SUB_KEYS;
+    if (OpenKey(interp, keyNameObj, mode, 0, &key) != TCL_OK) return TCL_ERROR;
 
     /*
      * Determine how big a buffer is needed for enumerating subkeys, and
@@ -703,7 +736,8 @@ static int
 GetType(
     Tcl_Interp *interp,		/* Current interpreter. */
     Tcl_Obj *keyNameObj,	/* Name of key. */
-    Tcl_Obj *valueNameObj)	/* Name of value to get. */
+    Tcl_Obj *valueNameObj,	/* Name of value to get. */
+    REGSAM mode)                /* mode flags to pass. */
 {
     HKEY key;
     DWORD result;
@@ -716,10 +750,8 @@ GetType(
      * Attempt to open the key for reading.
      */
 
-    if (OpenKey(interp, keyNameObj, KEY_QUERY_VALUE, 0, &key)
-	    != TCL_OK) {
-	return TCL_ERROR;
-    }
+    mode |= KEY_QUERY_VALUE;
+    if (OpenKey(interp, keyNameObj, mode, 0, &key) != TCL_OK) return TCL_ERROR;
 
     /*
      * Get the type of the value.
@@ -774,7 +806,8 @@ static int
 GetValue(
     Tcl_Interp *interp,		/* Current interpreter. */
     Tcl_Obj *keyNameObj,	/* Name of key. */
-    Tcl_Obj *valueNameObj)	/* Name of value to get. */
+    Tcl_Obj *valueNameObj,	/* Name of value to get. */
+    REGSAM mode)                /* mode flags to pass. */
 {
     HKEY key;
     const char *valueName, *nativeValue;
@@ -786,9 +819,8 @@ GetValue(
      * Attempt to open the key for reading.
      */
 
-    if (OpenKey(interp, keyNameObj, KEY_QUERY_VALUE, 0, &key) != TCL_OK) {
-	return TCL_ERROR;
-    }
+    mode |= KEY_QUERY_VALUE;
+    if (OpenKey(interp, keyNameObj, mode, 0, &key) != TCL_OK) return TCL_ERROR;
 
     /*
      * Initialize a Dstring to maximum statically allocated size we could get
@@ -907,7 +939,8 @@ static int
 GetValueNames(
     Tcl_Interp *interp,		/* Current interpreter. */
     Tcl_Obj *keyNameObj,	/* Key to enumerate. */
-    Tcl_Obj *patternObj)	/* Optional match pattern. */
+    Tcl_Obj *patternObj,	/* Optional match pattern. */
+    REGSAM mode)                /* mode flags to pass. */
 {
     HKEY key;
     Tcl_Obj *resultPtr;
@@ -919,10 +952,8 @@ GetValueNames(
      * Attempt to open the key for enumeration.
      */
 
-    if (OpenKey(interp, keyNameObj, KEY_QUERY_VALUE, 0, &key)
-	    != TCL_OK) {
-	return TCL_ERROR;
-    }
+    mode |= KEY_QUERY_VALUE;
+    if (OpenKey(interp, keyNameObj, mode, 0, &key) != TCL_OK) return TCL_ERROR;
 
     /*
      * Query the key to determine the appropriate buffer size to hold the
@@ -1223,12 +1254,17 @@ ParseKeyName(
 static DWORD
 RecursiveDeleteKey(
     HKEY startKey,		/* Parent of key to be deleted. */
-    const char *keyName)	/* Name of key to be deleted in external
+    const char *keyName,	/* Name of key to be deleted in external
 				 * encoding, not UTF. */
+    REGSAM mode)                /* mode flags to pass. */
 {
     DWORD result, size, maxSize;
     Tcl_DString subkey;
     HKEY hKey;
+    REGSAM saveMode = mode;
+    static int checkExProc = 0;
+    static HINSTANCE dllH = NULL;
+    static FARPROC regDeleteKeyExProc = NULL;
 
     /*
      * Do not allow NULL or empty key name.
@@ -1238,8 +1274,8 @@ RecursiveDeleteKey(
 	return ERROR_BADKEY;
     }
 
-    result = regWinProcs->regOpenKeyExProc(startKey, keyName, 0,
-	    KEY_ENUMERATE_SUB_KEYS | DELETE | KEY_QUERY_VALUE, &hKey);
+    mode |= KEY_ENUMERATE_SUB_KEYS | DELETE | KEY_QUERY_VALUE;
+    result = regWinProcs->regOpenKeyExProc(startKey, keyName, 0, mode, &hKey);
     if (result != ERROR_SUCCESS) {
 	return result;
     }
@@ -1254,6 +1290,7 @@ RecursiveDeleteKey(
     Tcl_DStringSetLength(&subkey,
 	    (int) ((regWinProcs->useWide) ? maxSize * 2 : maxSize));
 
+    mode = saveMode;
     while (result == ERROR_SUCCESS) {
 	/*
 	 * Always get index 0 because key deletion changes ordering.
@@ -1263,10 +1300,32 @@ RecursiveDeleteKey(
 	result = regWinProcs->regEnumKeyExProc(hKey, 0,
 		Tcl_DStringValue(&subkey), &size, NULL, NULL, NULL, NULL);
 	if (result == ERROR_NO_MORE_ITEMS) {
-	    result = regWinProcs->regDeleteKeyProc(startKey, keyName);
+            /*
+             * RegDeleteKeyEx doesn't exist on non-64bit XP platforms, so
+             * we can't compile with it in.  We need to check for it at
+             * runtime and use it if we find it.
+             */
+            if (mode && !checkExProc) {
+                checkExProc = 1;
+                dllH = LoadLibrary("advapi32.dll");
+                if (dllH) {
+                    if (regWinProcs->useWide) {
+                        regDeleteKeyExProc =
+                            (FARPROC)GetProcAddress(dllH, "RegDeleteKeyExW");
+                    } else {
+                        regDeleteKeyExProc =
+                            (FARPROC)GetProcAddress(dllH, "RegDeleteKeyExA");
+                    }
+                }
+            }
+            if (mode && regDeleteKeyExProc) {
+                result = regDeleteKeyExProc(startKey, keyName, mode, 0);
+            } else {
+                result = regWinProcs->regDeleteKeyProc(startKey, keyName);
+            }
 	    break;
 	} else if (result == ERROR_SUCCESS) {
-	    result = RecursiveDeleteKey(hKey, Tcl_DStringValue(&subkey));
+	    result = RecursiveDeleteKey(hKey, Tcl_DStringValue(&subkey), mode);
 	}
     }
     Tcl_DStringFree(&subkey);
@@ -1298,7 +1357,8 @@ SetValue(
     Tcl_Obj *keyNameObj,	/* Name of key. */
     Tcl_Obj *valueNameObj,	/* Name of value to set. */
     Tcl_Obj *dataObj,		/* Data to be written. */
-    Tcl_Obj *typeObj)		/* Type of data to be written. */
+    Tcl_Obj *typeObj,		/* Type of data to be written. */
+    REGSAM mode)                /* mode flags to pass. */
 {
     int type;
     DWORD result;
@@ -1316,9 +1376,8 @@ SetValue(
 	}
 	Tcl_ResetResult(interp);
     }
-    if (OpenKey(interp, keyNameObj, KEY_ALL_ACCESS, 1, &key) != TCL_OK) {
-	return TCL_ERROR;
-    }
+    mode |= KEY_ALL_ACCESS;
+    if (OpenKey(interp, keyNameObj, mode, 1, &key) != TCL_OK) return TCL_ERROR;
 
     valueName = Tcl_GetStringFromObj(valueNameObj, &length);
     valueName = Tcl_WinUtfToTChar(valueName, length, &nameBuf);
@@ -1445,24 +1504,18 @@ BroadcastValue(
     const char *str;
     Tcl_Obj *objPtr;
 
-    if ((objc != 3) && (objc != 5)) {
-	Tcl_WrongNumArgs(interp, 2, objv, "keyName ?-timeout millisecs?");
-	return TCL_ERROR;
-    }
-
-    if (objc > 3) {
-	str = Tcl_GetStringFromObj(objv[3], &len);
+    if (objc == 3) {
+	str = Tcl_GetStringFromObj(objv[1], &len);
 	if ((len < 2) || (*str != '-')
 		|| strncmp(str, "-timeout", (size_t) len)) {
-	    Tcl_WrongNumArgs(interp, 2, objv, "keyName ?-timeout millisecs?");
-	    return TCL_ERROR;
+	    return TCL_BREAK;
 	}
-	if (Tcl_GetIntFromObj(interp, objv[4], (int *) &timeout) != TCL_OK) {
+	if (Tcl_GetIntFromObj(interp, objv[2], (int *) &timeout) != TCL_OK) {
 	    return TCL_ERROR;
 	}
     }
 
-    str = Tcl_GetStringFromObj(objv[2], &len);
+    str = Tcl_GetStringFromObj(objv[0], &len);
     if (len == 0) {
 	str = NULL;
     }