blob: 3f8b3e335b1361016a240061bb3662aabcf691dd [file] [log] [blame]
/* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/*
*
* @author Mladen Turk
* @version $Revision$, $Date$
*/
#ifndef _WIN32_WINNT
#define _WIN32_WINNT 0x0500
#endif
#include <winsock2.h>
#include <mswsock.h>
#include <ws2tcpip.h>
#include <shlwapi.h>
#include "apr.h"
#include "apr_pools.h"
#include "apr_arch_misc.h" /* for apr_os_level */
#include "apr_arch_atime.h" /* for FileTimeToAprTime */
#include "tcn.h"
#define SAFE_CLOSE_KEY(k) \
if ((k) != NULL && (k) != INVALID_HANDLE_VALUE) { \
RegCloseKey((k)); \
(k) = NULL; \
}
typedef struct {
apr_pool_t *pool;
HKEY root;
HKEY key;
} tcn_nt_registry_t;
#define TCN_HKEY_CLASSES_ROOT 1
#define TCN_HKEY_CURRENT_CONFIG 2
#define TCN_HKEY_CURRENT_USER 3
#define TCN_HKEY_LOCAL_MACHINE 4
#define TCN_HKEY_USERS 5
static const struct {
HKEY k;
} TCN_KEYS[] = {
INVALID_HANDLE_VALUE,
HKEY_CLASSES_ROOT,
HKEY_CURRENT_CONFIG,
HKEY_CURRENT_USER,
HKEY_LOCAL_MACHINE,
HKEY_USERS,
INVALID_HANDLE_VALUE
};
#define TCN_KEY_ALL_ACCESS 0x0001
#define TCN_KEY_CREATE_LINK 0x0002
#define TCN_KEY_CREATE_SUB_KEY 0x0004
#define TCN_KEY_ENUMERATE_SUB_KEYS 0x0008
#define TCN_KEY_EXECUTE 0x0010
#define TCN_KEY_NOTIFY 0x0020
#define TCN_KEY_QUERY_VALUE 0x0040
#define TCN_KEY_READ 0x0080
#define TCN_KEY_SET_VALUE 0x0100
#define TCN_KEY_WOW64_64KEY 0x0200
#define TCN_KEY_WOW64_32KEY 0x0400
#define TCN_KEY_WRITE 0x0800
#define TCN_REGSAM(s, x) \
s = 0; \
if (x & TCN_KEY_ALL_ACCESS) \
s |= KEY_ALL_ACCESS; \
if (x & TCN_KEY_CREATE_LINK) \
s |= KEY_CREATE_LINK; \
if (x & TCN_KEY_CREATE_SUB_KEY) \
s |= KEY_CREATE_SUB_KEY; \
if (x & TCN_KEY_ENUMERATE_SUB_KEYS) \
s |= KEY_ENUMERATE_SUB_KEYS; \
if (x & TCN_KEY_EXECUTE) \
s |= KEY_EXECUTE; \
if (x & TCN_KEY_NOTIFY) \
s |= KEY_NOTIFY; \
if (x & TCN_KEY_READ) \
s |= KEY_READ; \
if (x & TCN_KEY_SET_VALUE) \
s |= KEY_SET_VALUE; \
if (x & TCN_KEY_WOW64_64KEY) \
s |= KEY_WOW64_64KEY; \
if (x & TCN_KEY_WOW64_32KEY) \
s |= KEY_WOW64_32KEY; \
if (x & TCN_KEY_WRITE) \
s |= KEY_WRITE
#define TCN_REG_BINARY 1
#define TCN_REG_DWORD 2
#define TCN_REG_EXPAND_SZ 3
#define TCN_REG_MULTI_SZ 4
#define TCN_REG_QWORD 5
#define TCN_REG_SZ 6
static const struct {
DWORD t;
} TCN_REGTYPES[] = {
REG_NONE,
REG_BINARY,
REG_DWORD,
REG_EXPAND_SZ,
REG_MULTI_SZ,
REG_QWORD,
REG_SZ,
REG_NONE
};
static apr_status_t registry_cleanup(void *data)
{
tcn_nt_registry_t *reg = (tcn_nt_registry_t *)data;
if (reg) {
SAFE_CLOSE_KEY(reg->key);
}
return APR_SUCCESS;
}
TCN_IMPLEMENT_CALL(jlong, Registry, create)(TCN_STDARGS, jint root, jstring name,
jint sam, jlong pool)
{
apr_pool_t *p = J2P(pool, apr_pool_t *);
tcn_nt_registry_t *reg = NULL;
TCN_ALLOC_WSTRING(name);
HKEY key;
LONG rc;
REGSAM s;
UNREFERENCED(o);
TCN_ASSERT(pool != 0);
if (root < TCN_HKEY_CLASSES_ROOT || root > TCN_HKEY_USERS) {
tcn_ThrowException(e, "Invalid Registry Root Key");
goto cleanup;
}
if (sam < TCN_KEY_ALL_ACCESS || root > TCN_KEY_WRITE) {
tcn_ThrowException(e, "Invalid Registry Key Security");
goto cleanup;
}
reg = (tcn_nt_registry_t *)apr_palloc(p, sizeof(tcn_nt_registry_t));
reg->pool = p;
reg->root = TCN_KEYS[root].k;
reg->key = NULL;
TCN_INIT_WSTRING(name);
TCN_REGSAM(s, sam);
rc = RegCreateKeyExW(reg->root, J2W(name), 0, NULL, REG_OPTION_NON_VOLATILE,
s, NULL, &key, NULL);
if (rc != ERROR_SUCCESS) {
tcn_ThrowAPRException(e, APR_FROM_OS_ERROR(rc));
goto cleanup;
}
reg->key = key;
apr_pool_cleanup_register(p, (const void *)reg,
registry_cleanup,
apr_pool_cleanup_null);
cleanup:
TCN_FREE_WSTRING(name);
return P2J(reg);
}
TCN_IMPLEMENT_CALL(jlong, Registry, open)(TCN_STDARGS, jint root, jstring name,
jint sam, jlong pool)
{
apr_pool_t *p = J2P(pool, apr_pool_t *);
tcn_nt_registry_t *reg = NULL;
TCN_ALLOC_WSTRING(name);
HKEY key;
LONG rc;
REGSAM s;
UNREFERENCED(o);
TCN_ASSERT(pool != 0);
if (root < TCN_HKEY_CLASSES_ROOT || root > TCN_HKEY_USERS) {
tcn_ThrowException(e, "Invalid Registry Root Key");
goto cleanup;
}
if (sam < TCN_KEY_ALL_ACCESS || root > TCN_KEY_WRITE) {
tcn_ThrowException(e, "Invalid Registry Key Security");
goto cleanup;
}
reg = (tcn_nt_registry_t *)apr_palloc(p, sizeof(tcn_nt_registry_t));
reg->pool = p;
reg->root = TCN_KEYS[root].k;
reg->key = NULL;
TCN_INIT_WSTRING(name);
TCN_REGSAM(s, sam);
rc = RegOpenKeyExW(reg->root, J2W(name), 0, s, &key);
if (rc != ERROR_SUCCESS) {
tcn_ThrowAPRException(e, APR_FROM_OS_ERROR(rc));
goto cleanup;
}
reg->key = key;
apr_pool_cleanup_register(p, (const void *)reg,
registry_cleanup,
apr_pool_cleanup_null);
cleanup:
TCN_FREE_WSTRING(name);
return P2J(reg);
}
TCN_IMPLEMENT_CALL(jint, Registry, close)(TCN_STDARGS, jlong reg)
{
tcn_nt_registry_t *r = J2P(reg, tcn_nt_registry_t *);
UNREFERENCED_STDARGS;
TCN_ASSERT(reg != 0);
registry_cleanup(r);
apr_pool_cleanup_kill(r->pool, r, registry_cleanup);
return APR_SUCCESS;
}
TCN_IMPLEMENT_CALL(jint, Registry, getType)(TCN_STDARGS, jlong key,
jstring name)
{
tcn_nt_registry_t *k = J2P(key, tcn_nt_registry_t *);
TCN_ALLOC_WSTRING(name);
LONG rc;
DWORD v;
UNREFERENCED(o);
TCN_ASSERT(key != 0);
TCN_INIT_WSTRING(name);
rc = RegQueryValueExW(k->key, J2W(name), NULL, &v, NULL, NULL);
if (rc != ERROR_SUCCESS)
v = -rc;
TCN_FREE_WSTRING(name);
switch (v) {
case REG_BINARY:
v = TCN_REG_BINARY;
break;
case REG_DWORD:
v = TCN_REG_DWORD;
break;
case REG_EXPAND_SZ:
v = TCN_REG_EXPAND_SZ;
break;
case REG_MULTI_SZ:
v = TCN_REG_MULTI_SZ;
break;
case REG_QWORD:
v = TCN_REG_QWORD;
break;
case REG_SZ:
v = TCN_REG_SZ;
break;
case REG_DWORD_BIG_ENDIAN:
v = 0;
break;
}
return v;
}
TCN_IMPLEMENT_CALL(jint, Registry, getSize)(TCN_STDARGS, jlong key,
jstring name)
{
tcn_nt_registry_t *k = J2P(key, tcn_nt_registry_t *);
TCN_ALLOC_WSTRING(name);
LONG rc;
DWORD v;
UNREFERENCED(o);
TCN_ASSERT(key != 0);
TCN_INIT_WSTRING(name);
rc = RegQueryValueExW(k->key, J2W(name), NULL, NULL, NULL, &v);
if (rc != ERROR_SUCCESS)
v = -rc;
TCN_FREE_WSTRING(name);
return v;
}
TCN_IMPLEMENT_CALL(jint, Registry, getValueI)(TCN_STDARGS, jlong key,
jstring name)
{
tcn_nt_registry_t *k = J2P(key, tcn_nt_registry_t *);
TCN_ALLOC_WSTRING(name);
LONG rc;
DWORD t, l;
DWORD v = 0;
UNREFERENCED(o);
TCN_ASSERT(key != 0);
TCN_INIT_WSTRING(name);
rc = RegQueryValueExW(k->key, J2W(name), NULL, &t, NULL, &l);
if (rc != ERROR_SUCCESS) {
tcn_ThrowAPRException(e, APR_FROM_OS_ERROR(rc));
goto cleanup;
}
if (t == REG_DWORD) {
l = sizeof(DWORD);
rc = RegQueryValueExW(k->key, J2W(name), NULL, NULL, (LPBYTE)&v, &l);
if (rc != ERROR_SUCCESS) {
tcn_ThrowAPRException(e, APR_FROM_OS_ERROR(rc));
goto cleanup;
}
}
else if (t == REG_SZ || t == REG_BINARY ||
t == REG_MULTI_SZ || t == REG_EXPAND_SZ)
v = l;
else {
v = 0;
tcn_ThrowException(e, "Unable to convert the value to integer");
}
cleanup:
TCN_FREE_WSTRING(name);
return v;
}
TCN_IMPLEMENT_CALL(jlong, Registry, getValueJ)(TCN_STDARGS, jlong key,
jstring name)
{
tcn_nt_registry_t *k = J2P(key, tcn_nt_registry_t *);
TCN_ALLOC_WSTRING(name);
LONG rc;
DWORD t, l;
UINT64 v = 0;
UNREFERENCED(o);
TCN_ASSERT(key != 0);
TCN_INIT_WSTRING(name);
rc = RegQueryValueExW(k->key, J2W(name), NULL, &t, NULL, &l);
if (rc != ERROR_SUCCESS) {
tcn_ThrowAPRException(e, APR_FROM_OS_ERROR(rc));
goto cleanup;
}
if (t == REG_DWORD) {
DWORD tv;
l = sizeof(DWORD);
rc = RegQueryValueExW(k->key, J2W(name), NULL, NULL, (LPBYTE)&tv, &l);
if (rc != ERROR_SUCCESS) {
tcn_ThrowAPRException(e, APR_FROM_OS_ERROR(rc));
goto cleanup;
}
v = tv;
}
else if (t == REG_QWORD) {
l = sizeof(UINT64);
rc = RegQueryValueExW(k->key, J2W(name), NULL, NULL, (LPBYTE)&v, &l);
if (rc != ERROR_SUCCESS) {
tcn_ThrowAPRException(e, APR_FROM_OS_ERROR(rc));
goto cleanup;
}
}
else if (t == REG_SZ || t == REG_BINARY ||
t == REG_MULTI_SZ || t == REG_EXPAND_SZ)
v = l;
else {
v = 0;
tcn_ThrowException(e, "Unable to convert the value to long");
}
cleanup:
TCN_FREE_WSTRING(name);
return v;
}
TCN_IMPLEMENT_CALL(jstring, Registry, getValueS)(TCN_STDARGS, jlong key,
jstring name)
{
tcn_nt_registry_t *k = J2P(key, tcn_nt_registry_t *);
TCN_ALLOC_WSTRING(name);
LONG rc;
DWORD t, l;
jstring v = NULL;
UNREFERENCED(o);
TCN_ASSERT(key != 0);
TCN_INIT_WSTRING(name);
rc = RegQueryValueExW(k->key, J2W(name), NULL, &t, NULL, &l);
if (rc != ERROR_SUCCESS) {
tcn_ThrowAPRException(e, APR_FROM_OS_ERROR(rc));
goto cleanup;
}
if (t == REG_SZ || t == REG_EXPAND_SZ) {
jchar *vw = (jchar *)malloc(l);
rc = RegQueryValueExW(k->key, J2W(name), NULL, NULL, (LPBYTE)vw, &l);
if (rc != ERROR_SUCCESS) {
tcn_ThrowAPRException(e, APR_FROM_OS_ERROR(rc));
free(vw);
goto cleanup;
}
v = (*e)->NewString((e), vw, wcslen(vw));
free(vw);
}
cleanup:
TCN_FREE_WSTRING(name);
return v;
}
TCN_IMPLEMENT_CALL(jbyteArray, Registry, getValueB)(TCN_STDARGS, jlong key,
jstring name)
{
tcn_nt_registry_t *k = J2P(key, tcn_nt_registry_t *);
TCN_ALLOC_WSTRING(name);
LONG rc;
DWORD t, l;
jbyteArray v = NULL;
UNREFERENCED(o);
TCN_ASSERT(key != 0);
TCN_INIT_WSTRING(name);
rc = RegQueryValueExW(k->key, J2W(name), NULL, &t, NULL, &l);
if (rc != ERROR_SUCCESS) {
tcn_ThrowAPRException(e, APR_FROM_OS_ERROR(rc));
goto cleanup;
}
if (t == REG_BINARY) {
BYTE *b = (BYTE *)malloc(l);
rc = RegQueryValueExW(k->key, J2W(name), NULL, NULL, b, &l);
if (rc != ERROR_SUCCESS) {
tcn_ThrowAPRException(e, APR_FROM_OS_ERROR(rc));
free(b);
goto cleanup;
}
v = tcn_new_arrayb(e, b, l);
free(b);
}
cleanup:
TCN_FREE_WSTRING(name);
return v;
}
static jsize get_multi_sz_count(LPCWSTR str)
{
LPCWSTR p = str;
jsize cnt = 0;
for ( ; p && *p; p++) {
cnt++;
while (*p)
p++;
}
return cnt;
}
TCN_IMPLEMENT_CALL(jobjectArray, Registry, getValueA)(TCN_STDARGS, jlong key,
jstring name)
{
tcn_nt_registry_t *k = J2P(key, tcn_nt_registry_t *);
TCN_ALLOC_WSTRING(name);
LONG rc;
DWORD t, l;
jobjectArray v = NULL;
UNREFERENCED(o);
TCN_ASSERT(key != 0);
TCN_INIT_WSTRING(name);
rc = RegQueryValueExW(k->key, J2W(name), NULL, &t, NULL, &l);
if (rc != ERROR_SUCCESS) {
tcn_ThrowAPRException(e, APR_FROM_OS_ERROR(rc));
goto cleanup;
}
if (t == REG_MULTI_SZ) {
jsize cnt = 0;
jchar *p;
jchar *vw = (jchar *)malloc(l);
rc = RegQueryValueExW(k->key, J2W(name), NULL, NULL, (LPBYTE)vw, &l);
if (rc != ERROR_SUCCESS) {
tcn_ThrowAPRException(e, APR_FROM_OS_ERROR(rc));
free(vw);
goto cleanup;
}
cnt = get_multi_sz_count(vw);
if (cnt) {
jsize idx = 0;
v = tcn_new_arrays(e, cnt);
for (p = vw ; p && *p; p++) {
jstring s;
jchar *b = p;
while (*p)
p++;
s = (*e)->NewString((e), b, (jsize)(p - b));
(*e)->SetObjectArrayElement((e), v, idx++, s);
}
}
free(vw);
}
cleanup:
TCN_FREE_WSTRING(name);
return v;
}
TCN_IMPLEMENT_CALL(jint, Registry, setValueI)(TCN_STDARGS, jlong key,
jstring name, jint val)
{
tcn_nt_registry_t *k = J2P(key, tcn_nt_registry_t *);
TCN_ALLOC_WSTRING(name);
LONG rc;
DWORD v = (DWORD)val;
UNREFERENCED(o);
TCN_ASSERT(key != 0);
TCN_INIT_WSTRING(name);
rc = RegSetValueExW(k->key, J2W(name), 0, REG_DWORD, (CONST BYTE *)&v, sizeof(DWORD));
TCN_FREE_WSTRING(name);
return v;
}
TCN_IMPLEMENT_CALL(jint, Registry, setValueJ)(TCN_STDARGS, jlong key,
jstring name, jlong val)
{
tcn_nt_registry_t *k = J2P(key, tcn_nt_registry_t *);
TCN_ALLOC_WSTRING(name);
LONG rc;
UINT64 v = (UINT64)val;
UNREFERENCED(o);
TCN_ASSERT(key != 0);
TCN_INIT_WSTRING(name);
rc = RegSetValueExW(k->key, J2W(name), 0, REG_QWORD, (CONST BYTE *)&v, sizeof(UINT64));
TCN_FREE_WSTRING(name);
return rc;
}
TCN_IMPLEMENT_CALL(jint, Registry, setValueS)(TCN_STDARGS, jlong key,
jstring name, jstring val)
{
tcn_nt_registry_t *k = J2P(key, tcn_nt_registry_t *);
TCN_ALLOC_WSTRING(name);
TCN_ALLOC_WSTRING(val);
LONG rc;
DWORD len;
UNREFERENCED(o);
TCN_ASSERT(key != 0);
TCN_INIT_WSTRING(name);
TCN_INIT_WSTRING(val);
len = wcslen(J2W(val));
rc = RegSetValueExW(k->key, J2W(name), 0, REG_SZ,
(CONST BYTE *)J2W(val), (len + 1) * 2);
TCN_FREE_WSTRING(name);
TCN_FREE_WSTRING(val);
return rc;
}
TCN_IMPLEMENT_CALL(jint, Registry, setValueE)(TCN_STDARGS, jlong key,
jstring name, jstring val)
{
tcn_nt_registry_t *k = J2P(key, tcn_nt_registry_t *);
TCN_ALLOC_WSTRING(name);
TCN_ALLOC_WSTRING(val);
LONG rc;
DWORD len;
UNREFERENCED(o);
TCN_ASSERT(key != 0);
TCN_INIT_WSTRING(name);
TCN_INIT_WSTRING(val);
len = wcslen(J2W(val));
rc = RegSetValueExW(k->key, J2W(name), 0, REG_EXPAND_SZ,
(CONST BYTE *)J2W(val), (len + 1) * 2);
TCN_FREE_WSTRING(name);
TCN_FREE_WSTRING(val);
return rc;
}
TCN_IMPLEMENT_CALL(jint, Registry, setValueA)(TCN_STDARGS, jlong key,
jstring name,
jobjectArray vals)
{
tcn_nt_registry_t *k = J2P(key, tcn_nt_registry_t *);
TCN_ALLOC_WSTRING(name);
LONG rc;
jsize i, len;
jsize sl = 0;
jchar *msz, *p;
UNREFERENCED(o);
TCN_ASSERT(key != 0);
TCN_INIT_WSTRING(name);
len = (*e)->GetArrayLength((e), vals);
for (i = 0; i < len; i++) {
jstring s = (jstring)(*e)->GetObjectArrayElement((e), vals, i);
sl += (*e)->GetStringLength((e), s) + 1;
}
sl = (sl + 1) * 2;
p = msz = (jchar *)calloc(1, sl);
for (i = 0; i < len; i++) {
jsize l;
jstring s = (jstring)(*e)->GetObjectArrayElement((e), vals, i);
l = (*e)->GetStringLength((e), s);
wcsncpy(p, (*e)->GetStringChars(e, s, 0), l);
p += l + 1;
}
rc = RegSetValueExW(k->key, J2W(name), 0, REG_MULTI_SZ,
(CONST BYTE *)msz, sl);
TCN_FREE_WSTRING(name);
free(msz);
return rc;
}
TCN_IMPLEMENT_CALL(jint, Registry, setValueB)(TCN_STDARGS, jlong key,
jstring name,
jbyteArray val)
{
tcn_nt_registry_t *k = J2P(key, tcn_nt_registry_t *);
TCN_ALLOC_WSTRING(name);
jsize nbytes = (*e)->GetArrayLength(e, val);
jbyte *bytes = (*e)->GetByteArrayElements(e, val, NULL);
LONG rc;
rc = RegSetValueExW(k->key, J2W(name), 0, REG_BINARY,
bytes, (DWORD)nbytes);
(*e)->ReleaseByteArrayElements(e, val, bytes, JNI_ABORT);
TCN_FREE_WSTRING(name);
return rc;
}
#define MAX_VALUE_NAME 4096
TCN_IMPLEMENT_CALL(jobjectArray, Registry, enumKeys)(TCN_STDARGS, jlong key)
{
tcn_nt_registry_t *k = J2P(key, tcn_nt_registry_t *);
LONG rc;
jobjectArray v = NULL;
jsize cnt = 0;
WCHAR achKey[MAX_PATH];
WCHAR achClass[MAX_PATH] = L"";
DWORD cchClassName = MAX_PATH;
DWORD cSubKeys;
DWORD cbMaxSubKey;
DWORD cchMaxClass;
DWORD cValues;
DWORD cchMaxValue;
DWORD cbMaxValueData;
DWORD cbSecurityDescriptor;
FILETIME ftLastWriteTime;
DWORD cchValue = MAX_VALUE_NAME;
UNREFERENCED(o);
TCN_ASSERT(key != 0);
rc = RegQueryInfoKeyW(k->key,
achClass,
&cchClassName,
NULL,
&cSubKeys,
&cbMaxSubKey,
&cchMaxClass,
&cValues,
&cchMaxValue,
&cbMaxValueData,
&cbSecurityDescriptor,
&ftLastWriteTime);
if (rc != ERROR_SUCCESS) {
tcn_ThrowAPRException(e, APR_FROM_OS_ERROR(rc));
goto cleanup;
}
cnt = cSubKeys;
if (cnt) {
jsize idx = 0;
v = tcn_new_arrays(e, cnt);
for (idx = 0; idx < cnt; idx++) {
jstring s;
DWORD achKeyLen = MAX_PATH;
rc = RegEnumKeyExW(k->key,
idx,
achKey,
&achKeyLen,
NULL,
NULL,
NULL,
&ftLastWriteTime);
if (rc == (DWORD)ERROR_SUCCESS) {
s = (*e)->NewString((e), achKey, wcslen(achKey));
(*e)->SetObjectArrayElement((e), v, idx, s);
}
}
}
cleanup:
return v;
}
TCN_IMPLEMENT_CALL(jobjectArray, Registry, enumValues)(TCN_STDARGS, jlong key)
{
tcn_nt_registry_t *k = J2P(key, tcn_nt_registry_t *);
LONG rc;
jobjectArray v = NULL;
jsize cnt = 0;
WCHAR achClass[MAX_PATH] = L"";
DWORD cchClassName = MAX_PATH;
DWORD cSubKeys;
DWORD cbMaxSubKey;
DWORD cchMaxClass;
DWORD cValues;
DWORD cchMaxValue;
DWORD cbMaxValueData;
DWORD cbSecurityDescriptor;
FILETIME ftLastWriteTime;
WCHAR achValue[MAX_VALUE_NAME];
DWORD cchValue = MAX_VALUE_NAME;
UNREFERENCED(o);
TCN_ASSERT(key != 0);
/* Get the class name and the value count. */
rc = RegQueryInfoKeyW(k->key,
achClass,
&cchClassName,
NULL,
&cSubKeys,
&cbMaxSubKey,
&cchMaxClass,
&cValues,
&cchMaxValue,
&cbMaxValueData,
&cbSecurityDescriptor,
&ftLastWriteTime);
if (rc != ERROR_SUCCESS) {
tcn_ThrowAPRException(e, APR_FROM_OS_ERROR(rc));
goto cleanup;
}
cnt = cValues;
if (cnt) {
jsize idx = 0;
v = tcn_new_arrays(e, cnt);
for (idx = 0; idx < cnt; idx++) {
jstring s;
cchValue = MAX_VALUE_NAME;
achValue[0] = '\0';
rc = RegEnumValueW(k->key, idx,
achValue,
&cchValue,
NULL,
NULL, // &dwType,
NULL, // &bData,
NULL); // &bcData
if (rc == (DWORD)ERROR_SUCCESS) {
s = (*e)->NewString((e), achValue, wcslen(achValue));
(*e)->SetObjectArrayElement((e), v, idx, s);
}
}
}
cleanup:
return v;
}
TCN_IMPLEMENT_CALL(jint, Registry, deleteKey)(TCN_STDARGS, jint root, jstring name,
jboolean only_if_empty)
{
DWORD rv;
TCN_ALLOC_WSTRING(name);
UNREFERENCED(o);
if (root < TCN_HKEY_CLASSES_ROOT || root > TCN_HKEY_USERS) {
rv = EBADF;
goto cleanup;
}
if (only_if_empty)
rv = SHDeleteEmptyKeyW(TCN_KEYS[root].k, J2W(name));
else
rv = SHDeleteKeyW(TCN_KEYS[root].k, J2W(name));
cleanup:
TCN_FREE_WSTRING(name);
return rv;
}
TCN_IMPLEMENT_CALL(jint, Registry, deleteValue)(TCN_STDARGS, jlong key,
jstring name)
{
LONG rv;
TCN_ALLOC_WSTRING(name);
tcn_nt_registry_t *k = J2P(key, tcn_nt_registry_t *);
UNREFERENCED(o);
rv = RegDeleteValueW(k->key, J2W(name));
TCN_FREE_WSTRING(name);
return (jint)rv;
}