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;
}