#include<shlwapi.h>
#include<kconfiginternal.h>
#include<netidmgr_intver.h>
#include<assert.h>
kconf_conf_space * conf_root = NULL;
kconf_handle * conf_handles = NULL;
kconf_handle * conf_free_handles = NULL;
CRITICAL_SECTION cs_conf_global;
CRITICAL_SECTION cs_conf_handle;
LONG conf_init = 0;
LONG conf_status = 0;
void init_kconf(void) {
if(InterlockedIncrement(&conf_init) == 1L) {
InitializeCriticalSection(&cs_conf_global);
EnterCriticalSection(&cs_conf_global);
conf_root = khcint_create_empty_space();
conf_root->name = PWCSDUP(L"Root");
conf_root->regpath = PWCSDUP(CONFIG_REGPATHW);
conf_root->refcount++;
conf_status = 1;
InitializeCriticalSection(&cs_conf_handle);
LeaveCriticalSection(&cs_conf_global);
}
}
void exit_kconf(void) {
if(khc_is_config_running()) {
kconf_handle * h;
EnterCriticalSection(&cs_conf_global);
conf_init = 0;
conf_status = 0;
khcint_free_space(conf_root);
LeaveCriticalSection(&cs_conf_global);
DeleteCriticalSection(&cs_conf_global);
EnterCriticalSection(&cs_conf_handle);
while(conf_free_handles) {
LPOP(&conf_free_handles, &h);
if(h) {
PFREE(h);
}
}
while(conf_handles) {
LPOP(&conf_handles, &h);
if(h) {
PFREE(h);
}
}
LeaveCriticalSection(&cs_conf_handle);
DeleteCriticalSection(&cs_conf_handle);
}
}
#if defined(DEBUG) && (defined(KH_BUILD_PRIVATE) || defined(KH_BUILD_SPECIAL))
#include<stdio.h>
static void
khcint_dump_space(FILE * f, kconf_conf_space * sp) {
kconf_conf_space * sc;
fprintf(f, "c12\t[%S]\t[%S]\t%d\t0x%x\tWin(%s|%s)|%s\n",
((sp->regpath) ? sp->regpath : L"!No Reg path"),
sp->name,
(int) sp->refcount,
(int) sp->flags,
((sp->regkey_user)? "HKCU" : ""),
((sp->regkey_machine)? "HKLM" : ""),
((sp->schema)? "Schema" : ""));
sc = TFIRSTCHILD(sp);
while(sc) {
khcint_dump_space(f, sc);
sc = LNEXT(sc);
}
}
KHMEXP void KHMAPI
khcint_dump_handles(FILE * f) {
if (khc_is_config_running()) {
kconf_handle * h, * sh;
EnterCriticalSection(&cs_conf_handle);
EnterCriticalSection(&cs_conf_global);
fprintf(f, "c00\t*** Active handles ***\n");
fprintf(f, "c01\tHandle\tName\tFlags\tRegpath\n");
h = conf_handles;
while(h) {
kconf_conf_space * sp;
sp = h->space;
if (!khc_is_handle(h) || sp == NULL) {
fprintf(f, "c02\t!!INVALID HANDLE!!\n");
} else {
fprintf(f, "c02\t0x%p\t[%S]\t0x%x\t[%S]\n",
h,
sp->name,
h->flags,
sp->regpath);
sh = khc_shadow(h);
while(sh) {
sp = sh->space;
if (!khc_is_handle(sh) || sp == NULL) {
fprintf(f, "c02\t0x%p:Shadow:0x%p\t[!!INVALID HANDLE!!]\n",
h, sh);
} else {
fprintf(f, "c02\t0x%p:Shadow:0x%p,[%S]\t0x%x\t[%S]\n",
h, sh,
sp->name,
sh->flags,
sp->regpath);
}
sh = khc_shadow(sh);
}
}
h = LNEXT(h);
}
fprintf(f, "c03\t------ End ---------\n");
fprintf(f, "c10\t*** Active Configuration Spaces ***\n");
fprintf(f, "c11\tReg path\tName\tRefcount\tFlags\tLayers\n");
khcint_dump_space(f, conf_root);
fprintf(f, "c13\t------ End ---------\n");
LeaveCriticalSection(&cs_conf_global);
LeaveCriticalSection(&cs_conf_handle);
} else {
fprintf(f, "c00\t------- KHC Configuration not running -------\n");
}
}
#endif
kconf_handle *
khcint_handle_from_space(kconf_conf_space * s, khm_int32 flags)
{
kconf_handle * h;
EnterCriticalSection(&cs_conf_handle);
LPOP(&conf_free_handles, &h);
if(!h) {
h = PMALLOC(sizeof(kconf_handle));
assert(h != NULL);
}
ZeroMemory((void *) h, sizeof(kconf_handle));
h->magic = KCONF_HANDLE_MAGIC;
khcint_space_hold(s);
h->space = s;
h->flags = flags;
LPUSH(&conf_handles, h);
LeaveCriticalSection(&cs_conf_handle);
return h;
}
void
khcint_handle_free(kconf_handle * h)
{
kconf_handle * lower;
EnterCriticalSection(&cs_conf_handle);
#ifdef DEBUG
{
kconf_handle * a;
a = conf_handles;
while(a) {
if(h == a)
break;
a = LNEXT(a);
}
if(a == NULL) {
DebugBreak();
LeaveCriticalSection(&cs_conf_handle);
return;
}
}
#endif
while(h) {
LDELETE(&conf_handles, h);
if(h->space) {
khcint_space_release(h->space);
h->space = NULL;
}
lower = h->lower;
h->magic = 0;
LPUSH(&conf_free_handles, h);
h = lower;
}
LeaveCriticalSection(&cs_conf_handle);
}
kconf_handle *
khcint_handle_dup(kconf_handle * o)
{
kconf_handle * h;
kconf_handle * r;
r = khcint_handle_from_space(o->space, o->flags);
h = r;
while(o->lower) {
h->lower = khcint_handle_from_space(o->lower->space, o->lower->flags);
o = o->lower;
h = h->lower;
}
return r;
}
void
khcint_space_hold(kconf_conf_space * s) {
EnterCriticalSection(&cs_conf_global);
s->refcount ++;
LeaveCriticalSection(&cs_conf_global);
}
void
khcint_try_free_space(kconf_conf_space * s) {
if (TFIRSTCHILD(s) == NULL &&
s->refcount == 0 &&
s->schema == NULL) {
kconf_conf_space * p;
p = TPARENT(s);
if (p == NULL)
return;
TDELCHILD(p, s);
khcint_free_space(s);
khcint_try_free_space(p);
}
}
void
khcint_space_release(kconf_conf_space * s) {
khm_int32 l;
EnterCriticalSection(&cs_conf_global);
l = -- s->refcount;
if (l == 0) {
if(s->regkey_machine)
RegCloseKey(s->regkey_machine);
if(s->regkey_user)
RegCloseKey(s->regkey_user);
s->regkey_machine = NULL;
s->regkey_user = NULL;
if (s->flags &
(KCONF_SPACE_FLAG_DELETE_M |
KCONF_SPACE_FLAG_DELETE_U)) {
khcint_remove_space(s, s->flags);
} else {
#ifdef USE_TRY_FREE
khcint_try_free_space(s);
#endif
}
}
LeaveCriticalSection(&cs_conf_global);
}
LONG
khcint_RegOpenKeyEx(HKEY hkey, LPCWSTR sSubKey, DWORD ulOptions,
REGSAM samDesired, PHKEY phkResult) {
int i;
wchar_t sk_name[KCONF_MAXCCH_NAME];
FILETIME ft;
size_t cch;
HKEY hkp = NULL;
const wchar_t * t;
LONG rv = ERROR_SUCCESS;
hkp = hkey;
t = sSubKey;
if (!_wcsnicmp(sSubKey, CONFIG_REGPATHW, ARRAYLENGTH(CONFIG_REGPATHW) - 1)) {
HKEY hkt;
t = sSubKey + (ARRAYLENGTH(CONFIG_REGPATHW) - 1);
#ifdef DEBUG
assert(*t == L'\0' || *t == L'\\');
#endif
rv = RegOpenKeyEx(hkp,
CONFIG_REGPATHW,
ulOptions,
samDesired,
&hkt);
if (rv != ERROR_SUCCESS)
return rv;
if (*t == L'\0') {
*phkResult = hkt;
return rv;
}
t++;
hkp = hkt;
}
while(TRUE) {
wchar_t * slash;
HKEY hkt;
slash = wcschr(t, L'\\');
if (slash == NULL)
break;
if (FAILED(StringCchCopyN(sk_name, ARRAYLENGTH(sk_name),
t, slash - t))) {
rv = ERROR_CANTOPEN;
goto _cleanup;
}
sk_name[slash - t] = L'\0';
t = slash+1;
if (khcint_RegOpenKeyEx(hkp, sk_name, ulOptions, samDesired, &hkt) ==
ERROR_SUCCESS) {
if (hkp != hkey)
RegCloseKey(hkp);
hkp = hkt;
} else {
rv = ERROR_CANTOPEN;
goto _cleanup;
}
}
if (FAILED(StringCchLength(t, KCONF_MAXCCH_NAME, &cch))) {
rv = ERROR_CANTOPEN;
goto _cleanup;
}
for (i=0; ;i++) {
LONG l;
DWORD dw;
dw = ARRAYLENGTH(sk_name);
l = RegEnumKeyEx(hkp, i, sk_name, &dw,
NULL, NULL, NULL, &ft);
if (l != ERROR_SUCCESS) {
rv = ERROR_CANTOPEN;
goto _cleanup;
}
if (!(wcsncmp(sk_name, t, cch))) {
if (cch < KCONF_MAXCCH_NAME &&
(sk_name[cch] == L'\0' ||
sk_name[cch] == L'~')) {
rv = RegOpenKeyEx(hkp, sk_name, ulOptions,
samDesired, phkResult);
goto _cleanup;
}
}
}
_cleanup:
if (hkp != hkey && hkp != NULL)
RegCloseKey(hkp);
return rv;
}
LONG
khcint_RegDeleteKey(HKEY hKey,
LPCWSTR lpSubKey) {
int i;
wchar_t sk_name[KCONF_MAXCCH_NAME];
FILETIME ft;
size_t cch;
LONG rv = ERROR_SUCCESS;
if (FAILED(StringCchLength(lpSubKey, KCONF_MAXCCH_NAME, &cch)))
return ERROR_BADKEY;
for (i=0; ;i++) {
LONG l;
DWORD dw;
dw = ARRAYLENGTH(sk_name);
l = RegEnumKeyEx(hKey, i, sk_name, &dw,
NULL, NULL, NULL, &ft);
if (l != ERROR_SUCCESS) {
rv = ERROR_BADKEY;
goto _cleanup;
}
if (!(wcsncmp(sk_name, lpSubKey, cch))) {
if ((sk_name[cch] == L'\0' ||
sk_name[cch] == L'~')) {
rv = SHDeleteKey(hKey, sk_name);
goto _cleanup;
}
}
}
_cleanup:
return rv;
}
LONG
khcint_RegCreateKeyEx(HKEY hKey,
LPCWSTR lpSubKey,
DWORD Reserved,
LPWSTR lpClass,
DWORD dwOptions,
REGSAM samDesired,
LPSECURITY_ATTRIBUTES lpSecurityAttributes,
PHKEY phkResult,
LPDWORD lpdwDisposition) {
LONG l;
int i;
long index = 0;
wchar_t sk_name[KCONF_MAXCCH_NAME];
FILETIME ft;
size_t cch;
const wchar_t * t;
LONG rv = ERROR_SUCCESS;
HKEY hkp = NULL;
hkp = hKey;
t = lpSubKey;
if (!_wcsnicmp(lpSubKey, CONFIG_REGPATHW, ARRAYLENGTH(CONFIG_REGPATHW) - 1)) {
HKEY hkt;
t = lpSubKey + (ARRAYLENGTH(CONFIG_REGPATHW) - 1);
#ifdef DEBUG
assert(*t == L'\0' || *t == L'\\');
#endif
rv = RegCreateKeyEx(hkp,
CONFIG_REGPATHW,
Reserved,
lpClass,
dwOptions,
samDesired,
lpSecurityAttributes,
&hkt,
lpdwDisposition);
if (rv != ERROR_SUCCESS)
return rv;
if (*t == L'\0') {
*phkResult = hkt;
return rv;
}
t++;
hkp = hkt;
}
while(TRUE) {
wchar_t * slash;
HKEY hkt;
slash = wcschr(t, L'\\');
if (slash == NULL)
break;
if (FAILED(StringCchCopyN(sk_name, ARRAYLENGTH(sk_name),
t, slash - t))) {
rv = ERROR_CANTOPEN;
goto _cleanup;
}
sk_name[slash - t] = L'\0';
t = slash+1;
if (khcint_RegOpenKeyEx(hkp, sk_name, 0, samDesired, &hkt) ==
ERROR_SUCCESS) {
if (hkp != hKey)
RegCloseKey(hkp);
hkp = hkt;
} else {
rv = RegCreateKeyEx(hKey,
lpSubKey,
Reserved,
lpClass,
dwOptions,
samDesired,
lpSecurityAttributes,
phkResult,
lpdwDisposition);
goto _cleanup;
}
}
if (FAILED(StringCchLength(t, KCONF_MAXCCH_NAME, &cch))) {
rv = ERROR_CANTOPEN;
goto _cleanup;
}
for (i=0; ;i++) {
DWORD dw;
dw = ARRAYLENGTH(sk_name);
l = RegEnumKeyEx(hkp, i, sk_name, &dw,
NULL, NULL, NULL, &ft);
if (l != ERROR_SUCCESS)
break;
if (!(wcsncmp(sk_name, t, cch))) {
if (sk_name[cch] == L'\0' ||
sk_name[cch] == L'~') {
l = RegOpenKeyEx(hkp, sk_name, 0,
samDesired, phkResult);
if (l == ERROR_SUCCESS && lpdwDisposition)
*lpdwDisposition = REG_OPENED_EXISTING_KEY;
rv = l;
goto _cleanup;
}
}
if (!_wcsnicmp(sk_name, t, cch) &&
(sk_name[cch] == L'\0' ||
sk_name[cch] == L'~')) {
long new_idx;
if (sk_name[cch] == L'\0')
new_idx = 1;
else if (cch + 1 < KCONF_MAXCCH_NAME)
new_idx = wcstol(sk_name + (cch + 1), NULL, 10);
else
return ERROR_BUFFER_OVERFLOW;
assert(new_idx > 0);
if (new_idx > index)
index = new_idx;
}
}
if (index != 0) {
if (FAILED(StringCbPrintf(sk_name, sizeof(sk_name),
L"%s~%d", t, index)))
return ERROR_BUFFER_OVERFLOW;
} else {
StringCbCopy(sk_name, sizeof(sk_name), t);
}
rv = RegCreateKeyEx(hkp,
sk_name,
Reserved,
lpClass,
dwOptions,
samDesired,
lpSecurityAttributes,
phkResult,
lpdwDisposition);
_cleanup:
if (hkp != hKey && hkp != NULL)
RegCloseKey(hkp);
return rv;
}
HKEY
khcint_space_open_key(kconf_conf_space * s, khm_int32 flags) {
HKEY hk = NULL;
int nflags = 0;
DWORD disp;
if(flags & KCONF_FLAG_MACHINE) {
if(s->regkey_machine)
return s->regkey_machine;
if((khcint_RegOpenKeyEx(HKEY_LOCAL_MACHINE, s->regpath, 0,
KEY_READ | KEY_WRITE, &hk) !=
ERROR_SUCCESS) &&
!(flags & KHM_PERM_WRITE)) {
if(khcint_RegOpenKeyEx(HKEY_LOCAL_MACHINE, s->regpath, 0,
KEY_READ, &hk) == ERROR_SUCCESS) {
nflags = KHM_PERM_READ;
}
}
if(!hk && (flags & KHM_FLAG_CREATE)) {
khcint_RegCreateKeyEx(HKEY_LOCAL_MACHINE,
s->regpath,
0,
NULL,
REG_OPTION_NON_VOLATILE,
KEY_READ | KEY_WRITE,
NULL,
&hk,
&disp);
}
if(hk) {
EnterCriticalSection(&cs_conf_global);
s->regkey_machine = hk;
s->regkey_machine_flags = nflags;
LeaveCriticalSection(&cs_conf_global);
}
return hk;
} else {
if(s->regkey_user)
return s->regkey_user;
if((khcint_RegOpenKeyEx(HKEY_CURRENT_USER, s->regpath, 0,
KEY_READ | KEY_WRITE, &hk) !=
ERROR_SUCCESS) &&
!(flags & KHM_PERM_WRITE)) {
if(khcint_RegOpenKeyEx(HKEY_CURRENT_USER, s->regpath, 0,
KEY_READ, &hk) == ERROR_SUCCESS) {
nflags = KHM_PERM_READ;
}
}
if(!hk && (flags & KHM_FLAG_CREATE)) {
khcint_RegCreateKeyEx(HKEY_CURRENT_USER,
s->regpath, 0, NULL,
REG_OPTION_NON_VOLATILE,
KEY_READ | KEY_WRITE,
NULL, &hk, &disp);
}
if(hk) {
EnterCriticalSection(&cs_conf_global);
s->regkey_user = hk;
s->regkey_user_flags = nflags;
LeaveCriticalSection(&cs_conf_global);
}
return hk;
}
}
KHMEXP khm_int32 KHMAPI
khc_shadow_space(khm_handle upper, khm_handle lower)
{
kconf_handle * h;
if(!khc_is_config_running())
return KHM_ERROR_NOT_READY;
if(!khc_is_handle(upper)) {
#ifdef DEBUG
DebugBreak();
#endif
return KHM_ERROR_INVALID_PARAM;
}
h = (kconf_handle *) upper;
EnterCriticalSection(&cs_conf_handle);
if(h->lower) {
EnterCriticalSection(&cs_conf_global);
khcint_handle_free(h->lower);
LeaveCriticalSection(&cs_conf_global);
h->lower = NULL;
}
if(khc_is_handle(lower)) {
kconf_handle * l;
kconf_handle * lc;
l = (kconf_handle *) lower;
lc = khcint_handle_dup(l);
h->lower = lc;
}
LeaveCriticalSection(&cs_conf_handle);
return KHM_ERROR_SUCCESS;
}
kconf_conf_space *
khcint_create_empty_space(void) {
kconf_conf_space * r;
r = PMALLOC(sizeof(kconf_conf_space));
assert(r != NULL);
ZeroMemory(r,sizeof(kconf_conf_space));
return r;
}
void
khcint_free_space(kconf_conf_space * r) {
kconf_conf_space * c;
if(!r)
return;
TPOPCHILD(r, &c);
while(c) {
khcint_free_space(c);
TPOPCHILD(r, &c);
}
if(r->name)
PFREE(r->name);
if(r->regpath)
PFREE(r->regpath);
if(r->regkey_machine)
RegCloseKey(r->regkey_machine);
if(r->regkey_user)
RegCloseKey(r->regkey_user);
PFREE(r);
}
khm_int32
khcint_open_space(kconf_conf_space * parent,
const wchar_t * sname, size_t n_sname,
khm_int32 flags, kconf_conf_space **result) {
kconf_conf_space * p;
kconf_conf_space * c;
HKEY pkey = NULL;
HKEY ckey = NULL;
wchar_t buf[KCONF_MAXCCH_NAME];
size_t cb_regpath = 0;
if(!parent)
p = conf_root;
else
p = parent;
if(n_sname >= KCONF_MAXCCH_NAME || n_sname <= 0)
return KHM_ERROR_INVALID_PARAM;
StringCchCopyN(buf, ARRAYLENGTH(buf), sname, n_sname);
EnterCriticalSection(&cs_conf_global);
c = TFIRSTCHILD(p);
while(c) {
if(c->name && !wcscmp(c->name, buf))
break;
c = LNEXT(c);
}
LeaveCriticalSection(&cs_conf_global);
if(c) {
if (c->flags & KCONF_SPACE_FLAG_DELETED) {
if (flags & KHM_FLAG_CREATE) {
c->flags &= ~(KCONF_SPACE_FLAG_DELETED |
KCONF_SPACE_FLAG_DELETE_M |
KCONF_SPACE_FLAG_DELETE_U);
} else {
*result = NULL;
return KHM_ERROR_NOT_FOUND;
}
}
khcint_space_hold(c);
*result = c;
return KHM_ERROR_SUCCESS;
}
if(!(flags & KHM_FLAG_CREATE)) {
if (flags & KCONF_FLAG_USER)
pkey = khcint_space_open_key(p, KHM_PERM_READ | KCONF_FLAG_USER);
if((!pkey ||
(khcint_RegOpenKeyEx(pkey, buf, 0, KEY_READ, &ckey) !=
ERROR_SUCCESS))
&& (flags & KCONF_FLAG_MACHINE)) {
pkey = khcint_space_open_key(p, KHM_PERM_READ | KCONF_FLAG_MACHINE);
if(!pkey ||
(khcint_RegOpenKeyEx(pkey, buf, 0, KEY_READ, &ckey) !=
ERROR_SUCCESS)) {
*result = NULL;
return KHM_ERROR_NOT_FOUND;
}
}
if(ckey) {
RegCloseKey(ckey);
ckey = NULL;
}
}
c = khcint_create_empty_space();
c->name = PWCSDUP(buf);
cb_regpath = (wcslen(p->regpath) + wcslen(buf) + 2) * sizeof(wchar_t);
c->regpath = PMALLOC(cb_regpath);
assert(c->regpath != NULL);
StringCbCopy(c->regpath, cb_regpath, p->regpath);
StringCbCat(c->regpath, cb_regpath, L"\\");
StringCbCat(c->regpath, cb_regpath, buf);
khcint_space_hold(c);
EnterCriticalSection(&cs_conf_global);
TADDCHILD(p,c);
LeaveCriticalSection(&cs_conf_global);
*result = c;
return KHM_ERROR_SUCCESS;
}
KHMEXP khm_int32 KHMAPI
khc_open_space(khm_handle parent, const wchar_t * cspace, khm_int32 flags,
khm_handle * result) {
kconf_handle * h;
kconf_conf_space * p;
kconf_conf_space * c = NULL;
size_t cbsize;
const wchar_t * str;
khm_int32 rv = KHM_ERROR_SUCCESS;
if(!khc_is_config_running()) {
return KHM_ERROR_NOT_READY;
}
if(!result || (parent && !khc_is_handle(parent))) {
#ifdef DEBUG
DebugBreak();
#endif
return KHM_ERROR_INVALID_PARAM;
}
if(!parent)
p = conf_root;
else {
h = (kconf_handle *) parent;
p = khc_space_from_handle(parent);
}
khcint_space_hold(p);
if(!(flags & KCONF_FLAG_USER) &&
!(flags & KCONF_FLAG_MACHINE) &&
!(flags & KCONF_FLAG_SCHEMA))
flags |= KCONF_FLAG_USER | KCONF_FLAG_MACHINE | KCONF_FLAG_SCHEMA;
if(cspace == NULL) {
*result = (khm_handle) khcint_handle_from_space(p, flags);
khcint_space_release(p);
return KHM_ERROR_SUCCESS;
}
if(FAILED(StringCbLength(cspace, KCONF_MAXCB_PATH, &cbsize))) {
khcint_space_release(p);
*result = NULL;
return KHM_ERROR_INVALID_PARAM;
}
str = cspace;
while(TRUE) {
const wchar_t * end = NULL;
if (!(flags & KCONF_FLAG_NOPARSENAME)) {
end = wcschr(str, L'\\');
}
if(!end) {
if(flags & KCONF_FLAG_TRAILINGVALUE) {
c = p;
khcint_space_hold(c);
break;
} else
end = str + wcslen(str);
}
rv = khcint_open_space(p, str, end - str, flags, &c);
if(KHM_SUCCEEDED(rv) && (*end == L'\\')) {
khcint_space_release(p);
p = c;
c = NULL;
str = end+1;
}
else
break;
}
khcint_space_release(p);
if(KHM_SUCCEEDED(rv)) {
*result = khcint_handle_from_space(c, flags);
} else
*result = NULL;
if (c)
khcint_space_release(c);
return rv;
}
KHMEXP khm_int32 KHMAPI
khc_close_space(khm_handle csp) {
if(!khc_is_config_running())
return KHM_ERROR_NOT_READY;
if(!khc_is_handle(csp)) {
#ifdef DEBUG
DebugBreak();
#endif
return KHM_ERROR_INVALID_PARAM;
}
khcint_handle_free((kconf_handle *) csp);
return KHM_ERROR_SUCCESS;
}
KHMEXP khm_int32 KHMAPI
khc_read_string(khm_handle pconf,
const wchar_t * pvalue,
wchar_t * buf,
khm_size * bufsize)
{
kconf_conf_space * c;
khm_int32 rv = KHM_ERROR_SUCCESS;
if(!khc_is_config_running())
return KHM_ERROR_NOT_READY;
do {
HKEY hku = NULL;
HKEY hkm = NULL;
const wchar_t * value = NULL;
int free_space = 0;
khm_handle conf = NULL;
DWORD size;
DWORD type;
LONG hr;
int i;
if((value = wcsrchr(pvalue, L'\\')) != NULL) {
if(KHM_FAILED(khc_open_space(
pconf,
pvalue,
KCONF_FLAG_TRAILINGVALUE | (pconf?khc_handle_flags(pconf):0),
&conf)))
goto _shadow;
free_space = 1;
if (value) {
value++;
} else {
#ifdef DEBUG
assert(FALSE);
#endif
}
} else {
value = pvalue;
conf = pconf;
free_space = 0;
}
if(!khc_is_handle(conf))
goto _shadow;
c = khc_space_from_handle(conf);
if(khc_is_user_handle(conf))
hku = khcint_space_open_key(c, KHM_PERM_READ);
if(khc_is_machine_handle(conf))
hkm = khcint_space_open_key(c, KHM_PERM_READ | KCONF_FLAG_MACHINE);
size = (DWORD) *bufsize;
if(hku) {
hr = RegQueryValueEx(hku, value, NULL, &type, (LPBYTE) buf, &size);
if(hr == ERROR_SUCCESS) {
if(type != REG_SZ) {
rv = KHM_ERROR_TYPE_MISMATCH;
goto _exit;
}
else {
*bufsize = size;
rv = (buf)? KHM_ERROR_SUCCESS: KHM_ERROR_TOO_LONG;
goto _exit;
}
} else {
if(hr == ERROR_MORE_DATA) {
*bufsize = size;
rv = KHM_ERROR_TOO_LONG;
goto _exit;
}
}
}
size = (DWORD) *bufsize;
if(hkm) {
hr = RegQueryValueEx(hkm, value, NULL, &type, (LPBYTE) buf, &size);
if(hr == ERROR_SUCCESS) {
if(type != REG_SZ) {
rv = KHM_ERROR_TYPE_MISMATCH;
goto _exit;
}
else {
*bufsize = size;
rv = (buf)? KHM_ERROR_SUCCESS: KHM_ERROR_TOO_LONG;
goto _exit;
}
} else {
if(hr == ERROR_MORE_DATA) {
*bufsize = size;
rv = KHM_ERROR_TOO_LONG;
goto _exit;
}
}
}
if(c->schema && khc_is_schema_handle(conf)) {
for(i=0;i<c->nSchema;i++) {
if(c->schema[i].type == KC_STRING && !wcscmp(value, c->schema[i].name)) {
size_t cbsize = 0;
if(!c->schema[i].value) {
rv = KHM_ERROR_NOT_FOUND;
goto _exit;
}
if(FAILED(StringCbLength((wchar_t *) c->schema[i].value, KCONF_MAXCB_STRING, &cbsize))) {
rv = KHM_ERROR_NOT_FOUND;
goto _exit;
}
cbsize += sizeof(wchar_t);
if(!buf || *bufsize < cbsize) {
*bufsize = cbsize;
rv = KHM_ERROR_TOO_LONG;
goto _exit;
}
StringCbCopy(buf, *bufsize, (wchar_t *) c->schema[i].value);
*bufsize = cbsize;
rv = KHM_ERROR_SUCCESS;
goto _exit;
}
}
}
_shadow:
if(free_space && conf)
khc_close_space(conf);
if(khc_is_shadowed(pconf)) {
pconf = khc_shadow(pconf);
continue;
} else {
rv = KHM_ERROR_NOT_FOUND;
break;
}
_exit:
if(free_space && conf)
khc_close_space(conf);
break;
} while(TRUE);
return rv;
}
KHMEXP khm_int32 KHMAPI
khc_read_int32(khm_handle pconf, const wchar_t * pvalue, khm_int32 * buf) {
kconf_conf_space * c;
khm_int32 rv = KHM_ERROR_SUCCESS;
if(!khc_is_config_running())
return KHM_ERROR_NOT_READY;
if(!buf || !pvalue)
return KHM_ERROR_INVALID_PARAM;
do {
DWORD size;
DWORD type;
LONG hr;
HKEY hku = NULL;
HKEY hkm = NULL;
const wchar_t * value = NULL;
int free_space = 0;
khm_handle conf = NULL;
int i;
if((value = wcsrchr(pvalue, L'\\')) != NULL) {
if(KHM_FAILED(khc_open_space(
pconf,
pvalue,
KCONF_FLAG_TRAILINGVALUE | (pconf?khc_handle_flags(pconf):0),
&conf)))
goto _shadow;
free_space = 1;
if (value) {
value++;
} else {
#ifdef DEBUG
assert(FALSE);
#endif
}
} else {
value = pvalue;
conf = pconf;
free_space = 0;
}
if(!khc_is_handle(conf) || !buf)
goto _shadow;
c = khc_space_from_handle(conf);
if(khc_is_user_handle(conf))
hku = khcint_space_open_key(c, KHM_PERM_READ);
if(khc_is_machine_handle(conf))
hkm = khcint_space_open_key(c, KHM_PERM_READ | KCONF_FLAG_MACHINE);
size = sizeof(DWORD);
if(hku) {
hr = RegQueryValueEx(hku, value, NULL, &type, (LPBYTE) buf, &size);
if(hr == ERROR_SUCCESS) {
if(type != REG_DWORD) {
rv = KHM_ERROR_TYPE_MISMATCH;
goto _exit;
}
else {
rv = KHM_ERROR_SUCCESS;
goto _exit;
}
}
}
size = sizeof(DWORD);
if(hkm) {
hr = RegQueryValueEx(hkm, value, NULL, &type, (LPBYTE) buf, &size);
if(hr == ERROR_SUCCESS) {
if(type != REG_DWORD) {
rv= KHM_ERROR_TYPE_MISMATCH;
goto _exit;
}
else {
rv= KHM_ERROR_SUCCESS;
goto _exit;
}
}
}
if(c->schema && khc_is_schema_handle(conf)) {
for(i=0;i<c->nSchema;i++) {
if(c->schema[i].type == KC_INT32 && !wcscmp(value, c->schema[i].name)) {
*buf = (khm_int32) c->schema[i].value;
rv = KHM_ERROR_SUCCESS;
goto _exit;
}
}
}
_shadow:
if(free_space && conf)
khc_close_space(conf);
if(khc_is_shadowed(pconf)) {
pconf = khc_shadow(pconf);
continue;
} else {
rv = KHM_ERROR_NOT_FOUND;
break;
}
_exit:
if(free_space && conf)
khc_close_space(conf);
break;
}
while(TRUE);
return rv;
}
KHMEXP khm_int32 KHMAPI
khc_read_int64(khm_handle pconf, const wchar_t * pvalue, khm_int64 * buf) {
kconf_conf_space * c;
khm_int32 rv = KHM_ERROR_SUCCESS;
if(!khc_is_config_running())
return KHM_ERROR_NOT_READY;
do {
DWORD size;
DWORD type;
LONG hr;
HKEY hku = NULL;
HKEY hkm = NULL;
const wchar_t * value = NULL;
int free_space = 0;
khm_handle conf = NULL;
int i;
if((value = wcsrchr(pvalue, L'\\')) != NULL) {
if(KHM_FAILED(khc_open_space(
pconf,
pvalue,
KCONF_FLAG_TRAILINGVALUE | (pconf?khc_handle_flags(pconf):0),
&conf)))
goto _shadow;
free_space = 1;
if (value) {
value++;
} else {
#ifdef DEBUG
assert(FALSE);
#endif
}
} else {
value = pvalue;
conf = pconf;
free_space = 0;
}
if(!khc_is_handle(conf) || !buf)
goto _shadow;
c = khc_space_from_handle(conf);
if(khc_is_user_handle(conf))
hku = khcint_space_open_key(c, KHM_PERM_READ);
if(khc_is_machine_handle(conf))
hkm = khcint_space_open_key(c, KHM_PERM_READ | KCONF_FLAG_MACHINE);
size = sizeof(khm_int64);
if(hku) {
hr = RegQueryValueEx(hku, value, NULL, &type, (LPBYTE) buf, &size);
if(hr == ERROR_SUCCESS) {
if(type != REG_QWORD) {
rv= KHM_ERROR_TYPE_MISMATCH;
goto _exit;
}
else {
rv = KHM_ERROR_SUCCESS;
goto _exit;
}
}
}
size = sizeof(khm_int64);
if(hkm) {
hr = RegQueryValueEx(hkm, value, NULL, &type, (LPBYTE) buf, &size);
if(hr == ERROR_SUCCESS) {
if(type != REG_QWORD) {
rv = KHM_ERROR_TYPE_MISMATCH;
goto _exit;
}
else {
rv = KHM_ERROR_SUCCESS;
goto _exit;
}
}
}
if(c->schema && khc_is_schema_handle(conf)) {
for(i=0;i<c->nSchema;i++) {
if(c->schema[i].type == KC_INT64 && !wcscmp(value, c->schema[i].name)) {
*buf = (khm_int64) c->schema[i].value;
rv = KHM_ERROR_SUCCESS;
goto _exit;
}
}
}
_shadow:
if(free_space && conf)
khc_close_space(conf);
if(khc_is_shadowed(pconf)) {
pconf = khc_shadow(pconf);
continue;
} else {
rv = KHM_ERROR_NOT_FOUND;
break;
}
_exit:
if(free_space && conf)
khc_close_space(conf);
break;
} while(TRUE);
return rv;
}
KHMEXP khm_int32 KHMAPI
khc_read_binary(khm_handle pconf, const wchar_t * pvalue,
void * buf, khm_size * bufsize) {
kconf_conf_space * c;
khm_int32 rv = KHM_ERROR_SUCCESS;
if(!khc_is_config_running())
return KHM_ERROR_NOT_READY;
do {
DWORD size;
DWORD type;
LONG hr;
HKEY hku = NULL;
HKEY hkm = NULL;
const wchar_t * value = NULL;
int free_space = 0;
khm_handle conf = NULL;
if((value = wcsrchr(pvalue, L'\\')) != NULL) {
if(KHM_FAILED(khc_open_space(
pconf,
pvalue,
KCONF_FLAG_TRAILINGVALUE | (pconf?khc_handle_flags(pconf):0),
&conf)))
goto _shadow;
free_space = 1;
if (value) {
value++;
} else {
#ifdef DEBUG
assert(FALSE);
#endif
}
} else {
value = pvalue;
conf = pconf;
free_space = 0;
}
if(!khc_is_handle(conf))
goto _shadow;
c = khc_space_from_handle(conf);
if(khc_is_user_handle(conf))
hku = khcint_space_open_key(c, KHM_PERM_READ);
if(khc_is_machine_handle(conf))
hkm = khcint_space_open_key(c, KHM_PERM_READ | KCONF_FLAG_MACHINE);
size = (DWORD) *bufsize;
if(hku) {
hr = RegQueryValueEx(hku, value, NULL, &type, (LPBYTE) buf, &size);
if(hr == ERROR_SUCCESS) {
if(type != REG_BINARY) {
rv = KHM_ERROR_TYPE_MISMATCH;
goto _exit;
}
else {
*bufsize = size;
rv = KHM_ERROR_SUCCESS;
goto _exit;
}
} else {
if(hr == ERROR_MORE_DATA) {
*bufsize = size;
rv = KHM_ERROR_TOO_LONG;
goto _exit;
}
}
}
size = (DWORD) *bufsize;
if(hkm) {
hr = RegQueryValueEx(hkm, value, NULL, &type, (LPBYTE) buf, &size);
if(hr == ERROR_SUCCESS) {
if(type != REG_BINARY) {
rv = KHM_ERROR_TYPE_MISMATCH;
goto _exit;
}
else {
*bufsize = size;
rv = KHM_ERROR_SUCCESS;
goto _exit;
}
} else {
if(hr == ERROR_MORE_DATA) {
*bufsize = size;
rv = KHM_ERROR_TOO_LONG;
goto _exit;
}
}
}
_shadow:
if(free_space && conf)
khc_close_space(conf);
if(khc_is_shadowed(pconf)) {
pconf = khc_shadow(pconf);
continue;
} else {
rv = KHM_ERROR_NOT_FOUND;
break;
}
_exit:
if(free_space && conf)
khc_close_space(conf);
break;
}while (TRUE);
return rv;
}
KHMEXP khm_int32 KHMAPI
khc_write_string(khm_handle pconf,
const wchar_t * pvalue,
wchar_t * buf)
{
HKEY pk = NULL;
kconf_conf_space * c;
khm_int32 rv = KHM_ERROR_SUCCESS;
LONG hr;
size_t cbsize;
const wchar_t * value = NULL;
int free_space = 0;
khm_handle conf = NULL;
if(!khc_is_config_running())
return KHM_ERROR_NOT_READY;
if(pconf && !khc_is_machine_handle(pconf) && !khc_is_user_handle(pconf))
return KHM_ERROR_INVALID_OPERATION;
if(FAILED(StringCbLength(buf, KCONF_MAXCB_STRING, &cbsize))) {
rv = KHM_ERROR_INVALID_PARAM;
goto _exit;
}
cbsize += sizeof(wchar_t);
if (khc_handle_flags(pconf) & KCONF_FLAG_WRITEIFMOD) {
wchar_t tmpbuf[512];
wchar_t * buffer;
size_t tmpsize = cbsize;
khm_boolean is_equal = FALSE;
if (cbsize <= sizeof(tmpbuf)) {
buffer = tmpbuf;
} else {
buffer = PMALLOC(cbsize);
}
if (KHM_SUCCEEDED(khc_read_string(pconf, pvalue, buffer, &tmpsize)) &&
tmpsize == cbsize) {
if (khc_handle_flags(pconf) & KCONF_FLAG_IFMODCI)
is_equal = !_wcsicmp(buffer, buf);
else
is_equal = !wcscmp(buffer, buf);
}
if (buffer != tmpbuf)
PFREE(buffer);
if (is_equal) {
return KHM_ERROR_SUCCESS;
}
}
if((value = wcsrchr(pvalue, L'\\')) != NULL) {
if(KHM_FAILED(khc_open_space(pconf, pvalue,
KCONF_FLAG_TRAILINGVALUE | (pconf?khc_handle_flags(pconf):0),
&conf)))
return KHM_ERROR_INVALID_PARAM;
free_space = 1;
if (value) {
value ++;
} else {
#ifdef DEBUG
assert(FALSE);
#endif
}
} else {
value = pvalue;
conf = pconf;
free_space = 0;
}
if(!khc_is_handle(conf) || !buf) {
rv = KHM_ERROR_INVALID_PARAM;
goto _exit;
}
c = khc_space_from_handle(conf);
if(khc_is_user_handle(conf)) {
pk = khcint_space_open_key(c, KHM_PERM_WRITE | KHM_FLAG_CREATE);
} else {
pk = khcint_space_open_key(c, KHM_PERM_WRITE | KCONF_FLAG_MACHINE | KHM_FLAG_CREATE);
}
hr = RegSetValueEx(pk, value, 0, REG_SZ, (LPBYTE) buf, (DWORD) cbsize);
if(hr != ERROR_SUCCESS)
rv = KHM_ERROR_INVALID_OPERATION;
_exit:
if(free_space)
khc_close_space(conf);
return rv;
}
KHMEXP khm_int32 KHMAPI
khc_write_int32(khm_handle pconf,
const wchar_t * pvalue,
khm_int32 buf)
{
HKEY pk = NULL;
kconf_conf_space * c;
khm_int32 rv = KHM_ERROR_SUCCESS;
LONG hr;
const wchar_t * value = NULL;
int free_space = 0;
khm_handle conf = NULL;
if(!khc_is_config_running())
return KHM_ERROR_NOT_READY;
if(pconf && !khc_is_machine_handle(pconf) && !khc_is_user_handle(pconf))
return KHM_ERROR_INVALID_OPERATION;
if (khc_handle_flags(pconf) & KCONF_FLAG_WRITEIFMOD) {
khm_int32 tmpvalue;
if (KHM_SUCCEEDED(khc_read_int32(pconf, pvalue, &tmpvalue)) &&
tmpvalue == buf) {
return KHM_ERROR_SUCCESS;
}
}
if((value = wcsrchr(pvalue, L'\\')) != NULL) {
if(KHM_FAILED(khc_open_space(
pconf,
pvalue,
KCONF_FLAG_TRAILINGVALUE | (pconf?khc_handle_flags(pconf):0),
&conf)))
return KHM_ERROR_INVALID_PARAM;
free_space = 1;
if (value) {
value ++;
} else {
#ifdef DEBUG
assert(FALSE);
#endif
}
} else {
value = pvalue;
conf = pconf;
free_space = 0;
}
if(!khc_is_handle(conf))
return KHM_ERROR_INVALID_PARAM;
c = khc_space_from_handle( conf);
if(khc_is_user_handle(conf)) {
pk = khcint_space_open_key(c, KHM_PERM_WRITE | KHM_FLAG_CREATE);
} else {
pk = khcint_space_open_key(c, KHM_PERM_WRITE | KCONF_FLAG_MACHINE | KHM_FLAG_CREATE);
}
hr = RegSetValueEx(pk, value, 0, REG_DWORD, (LPBYTE) &buf, sizeof(khm_int32));
if(hr != ERROR_SUCCESS)
rv = KHM_ERROR_INVALID_OPERATION;
if(free_space)
khc_close_space(conf);
return rv;
}
KHMEXP khm_int32 KHMAPI
khc_write_int64(khm_handle pconf, const wchar_t * pvalue, khm_int64 buf) {
HKEY pk = NULL;
kconf_conf_space * c;
khm_int32 rv = KHM_ERROR_SUCCESS;
LONG hr;
const wchar_t * value = NULL;
int free_space = 0;
khm_handle conf = NULL;
if(!khc_is_config_running())
return KHM_ERROR_NOT_READY;
if(pconf && !khc_is_machine_handle(pconf) && !khc_is_user_handle(pconf))
return KHM_ERROR_INVALID_OPERATION;
if (khc_handle_flags(pconf) & KCONF_FLAG_WRITEIFMOD) {
khm_int64 tmpvalue;
if (KHM_SUCCEEDED(khc_read_int64(pconf, pvalue, &tmpvalue)) &&
tmpvalue == buf) {
return KHM_ERROR_SUCCESS;
}
}
if((value = wcsrchr(pvalue, L'\\')) != NULL) {
if(KHM_FAILED(khc_open_space(
pconf,
pvalue,
KCONF_FLAG_TRAILINGVALUE | (pconf?khc_handle_flags(pconf):0),
&conf)))
return KHM_ERROR_INVALID_PARAM;
free_space = 1;
if (value) {
value ++;
} else {
#ifdef DEBUG
assert(FALSE);
#endif
}
} else {
value = pvalue;
conf = pconf;
free_space = 0;
}
if(!khc_is_handle(conf))
return KHM_ERROR_INVALID_PARAM;
c = khc_space_from_handle( conf);
if(khc_is_user_handle(conf)) {
pk = khcint_space_open_key(c, KHM_PERM_WRITE | KHM_FLAG_CREATE);
} else {
pk = khcint_space_open_key(c, KHM_PERM_WRITE | KCONF_FLAG_MACHINE | KHM_FLAG_CREATE);
}
hr = RegSetValueEx(pk, value, 0, REG_QWORD, (LPBYTE) &buf, sizeof(khm_int64));
if(hr != ERROR_SUCCESS)
rv = KHM_ERROR_INVALID_OPERATION;
if(free_space)
khc_close_space(conf);
return rv;
}
KHMEXP khm_int32 KHMAPI
khc_write_binary(khm_handle pconf,
const wchar_t * pvalue,
void * buf, khm_size bufsize) {
HKEY pk = NULL;
kconf_conf_space * c;
khm_int32 rv = KHM_ERROR_SUCCESS;
LONG hr;
const wchar_t * value = NULL;
int free_space = 0;
khm_handle conf = NULL;
if(!khc_is_config_running())
return KHM_ERROR_NOT_READY;
if(pconf && !khc_is_machine_handle(pconf) && !khc_is_user_handle(pconf))
return KHM_ERROR_INVALID_OPERATION;
if((value = wcsrchr(pvalue, L'\\')) != NULL) {
if(KHM_FAILED(khc_open_space(
pconf,
pvalue,
KCONF_FLAG_TRAILINGVALUE | (pconf?khc_handle_flags(pconf):0),
&conf)))
return KHM_ERROR_INVALID_PARAM;
free_space = 1;
if (value) {
value ++;
} else {
#ifdef DEBUG
assert(FALSE);
#endif
}
} else {
value = pvalue;
conf = pconf;
free_space = 0;
}
if(!khc_is_handle(conf))
return KHM_ERROR_INVALID_PARAM;
c = khc_space_from_handle(conf);
if(khc_is_user_handle(conf)) {
pk = khcint_space_open_key(c, KHM_PERM_WRITE | KHM_FLAG_CREATE);
} else {
pk = khcint_space_open_key(c, KHM_PERM_WRITE | KCONF_FLAG_MACHINE | KHM_FLAG_CREATE);
}
hr = RegSetValueEx(pk, value, 0, REG_BINARY, buf, (DWORD) bufsize);
if(hr != ERROR_SUCCESS)
rv = KHM_ERROR_INVALID_OPERATION;
if(free_space)
khc_close_space(conf);
return rv;
}
KHMEXP khm_int32 KHMAPI
khc_get_config_space_name(khm_handle conf,
wchar_t * buf, khm_size * bufsize) {
kconf_conf_space * c;
khm_int32 rv = KHM_ERROR_SUCCESS;
if(!khc_is_config_running())
return KHM_ERROR_NOT_READY;
if(!khc_is_handle(conf))
return KHM_ERROR_INVALID_PARAM;
c = khc_space_from_handle(conf);
if(!c->name) {
if(buf && *bufsize > 0)
buf[0] = L'\0';
else {
*bufsize = sizeof(wchar_t);
rv = KHM_ERROR_TOO_LONG;
}
} else {
size_t cbsize;
if(FAILED(StringCbLength(c->name, KCONF_MAXCB_NAME, &cbsize)))
return KHM_ERROR_UNKNOWN;
cbsize += sizeof(wchar_t);
if(!buf || cbsize > *bufsize) {
*bufsize = cbsize;
rv = KHM_ERROR_TOO_LONG;
} else {
StringCbCopy(buf, *bufsize, c->name);
*bufsize = cbsize;
}
}
return rv;
}
KHMEXP khm_int32 KHMAPI
khc_get_config_space_parent(khm_handle conf, khm_handle * parent) {
kconf_conf_space * c;
if(!khc_is_config_running())
return KHM_ERROR_NOT_READY;
if(!khc_is_handle(conf))
return KHM_ERROR_INVALID_PARAM;
c = khc_space_from_handle(conf);
if(c == conf_root || c->parent == conf_root)
*parent = NULL;
else
*parent = khcint_handle_from_space(c->parent, khc_handle_flags(conf));
return KHM_ERROR_SUCCESS;
}
KHMEXP khm_int32 KHMAPI
khc_get_type(khm_handle conf, const wchar_t * value) {
HKEY hkm = NULL;
HKEY hku = NULL;
kconf_conf_space * c;
khm_int32 rv;
LONG hr = ERROR_SUCCESS;
DWORD type = 0;
if(!khc_is_config_running())
return KC_NONE;
if(!khc_is_handle(conf))
return KC_NONE;
c = khc_space_from_handle(conf);
if(!khc_is_machine_handle(conf))
hku = khcint_space_open_key(c, KHM_PERM_READ);
hkm = khcint_space_open_key(c, KHM_PERM_READ | KCONF_FLAG_MACHINE);
if(hku)
hr = RegQueryValueEx(hku, value, NULL, &type, NULL, NULL);
if(!hku || hr != ERROR_SUCCESS)
hr = RegQueryValueEx(hkm, value, NULL, &type, NULL, NULL);
if(((!hku && !hkm) || hr != ERROR_SUCCESS) && c->schema) {
int i;
for(i=0; i<c->nSchema; i++) {
if(!wcscmp(c->schema[i].name, value)) {
return c->schema[i].type;
}
}
return KC_NONE;
}
switch(type) {
case REG_MULTI_SZ:
case REG_SZ:
rv = KC_STRING;
break;
case REG_DWORD:
rv = KC_INT32;
break;
case REG_QWORD:
rv = KC_INT64;
break;
case REG_BINARY:
rv = KC_BINARY;
break;
default:
rv = KC_NONE;
}
return rv;
}
KHMEXP khm_int32 KHMAPI
khc_value_exists(khm_handle conf, const wchar_t * value) {
HKEY hku = NULL;
HKEY hkm = NULL;
kconf_conf_space * c;
khm_int32 rv = 0;
DWORD t;
int i;
if(!khc_is_config_running())
return KHM_ERROR_NOT_READY;
if(!khc_is_handle(conf))
return KHM_ERROR_INVALID_PARAM;
do {
c = khc_space_from_handle(conf);
if (khc_is_user_handle(conf))
hku = khcint_space_open_key(c, KHM_PERM_READ);
if (khc_is_machine_handle(conf))
hkm = khcint_space_open_key(c, KHM_PERM_READ | KCONF_FLAG_MACHINE);
if(hku && (RegQueryValueEx(hku, value, NULL, &t, NULL, NULL) == ERROR_SUCCESS))
rv |= KCONF_FLAG_USER;
if(hkm && (RegQueryValueEx(hkm, value, NULL, &t, NULL, NULL) == ERROR_SUCCESS))
rv |= KCONF_FLAG_MACHINE;
if(c->schema && khc_is_schema_handle(conf)) {
for(i=0; i<c->nSchema; i++) {
if(!wcscmp(c->schema[i].name, value)) {
rv |= KCONF_FLAG_SCHEMA;
break;
}
}
}
if (rv == 0 && khc_is_shadowed(conf))
conf = khc_shadow(conf);
else
break;
} while (conf);
return rv;
}
KHMEXP khm_int32 KHMAPI
khc_remove_value(khm_handle conf, const wchar_t * value, khm_int32 flags) {
HKEY hku = NULL;
HKEY hkm = NULL;
kconf_conf_space * c;
khm_int32 rv = KHM_ERROR_NOT_FOUND;
DWORD t;
LONG l;
if(!khc_is_config_running())
return KHM_ERROR_NOT_READY;
if(!khc_is_handle(conf))
return KHM_ERROR_INVALID_PARAM;
c = khc_space_from_handle(conf);
if(khc_is_user_handle(conf))
hku = khcint_space_open_key(c, KHM_PERM_READ);
hkm = khcint_space_open_key(c, KHM_PERM_READ | KCONF_FLAG_MACHINE);
if((flags == 0 ||
(flags & KCONF_FLAG_USER)) &&
hku && (RegQueryValueEx(hku, value, NULL,
&t, NULL, NULL) == ERROR_SUCCESS)) {
l = RegDeleteValue(hku, value);
if (l == ERROR_SUCCESS)
rv = KHM_ERROR_SUCCESS;
else
rv = KHM_ERROR_UNKNOWN;
}
if((flags == 0 ||
(flags & KCONF_FLAG_MACHINE)) &&
hkm && (RegQueryValueEx(hkm, value, NULL,
&t, NULL, NULL) == ERROR_SUCCESS)) {
l = RegDeleteValue(hkm, value);
if (l == ERROR_SUCCESS)
rv = (rv == KHM_ERROR_UNKNOWN)?KHM_ERROR_PARTIAL:
KHM_ERROR_SUCCESS;
else
rv = (rv == KHM_ERROR_SUCCESS)?KHM_ERROR_PARTIAL:
KHM_ERROR_UNKNOWN;
}
return rv;
}
khm_int32
khcint_remove_space(kconf_conf_space * c, khm_int32 flags) {
kconf_conf_space * cc;
kconf_conf_space * cn;
kconf_conf_space * p;
khm_boolean free_c = FALSE;
p = TPARENT(c);
#ifdef DEBUG
assert(p);
#endif
if (!p)
return KHM_ERROR_INVALID_OPERATION;
cc = TFIRSTCHILD(c);
while (cc) {
cn = LNEXT(cc);
khcint_remove_space(cc, flags);
cc = cn;
}
cc = TFIRSTCHILD(c);
if (!cc && c->refcount == 0) {
TDELCHILD(p, c);
free_c = TRUE;
} else {
c->flags |= (flags &
(KCONF_SPACE_FLAG_DELETE_M |
KCONF_SPACE_FLAG_DELETE_U));
if ((c->flags &
(KCONF_SPACE_FLAG_DELETE_M |
KCONF_SPACE_FLAG_DELETE_U)) ==
(KCONF_SPACE_FLAG_DELETE_M |
KCONF_SPACE_FLAG_DELETE_U) &&
(!c->schema || c->nSchema == 0))
c->flags |= KCONF_SPACE_FLAG_DELETED;
}
if (c->regpath && p->regpath) {
HKEY hk;
if (flags & KCONF_SPACE_FLAG_DELETE_U) {
hk = khcint_space_open_key(p, KCONF_FLAG_USER);
if (hk)
khcint_RegDeleteKey(hk, c->name);
}
if (flags & KCONF_SPACE_FLAG_DELETE_M) {
hk = khcint_space_open_key(p, KCONF_FLAG_MACHINE);
if (hk)
khcint_RegDeleteKey(hk, c->name);
}
}
if (free_c) {
khcint_free_space(c);
}
return KHM_ERROR_SUCCESS;
}
KHMEXP khm_int32 KHMAPI
khc_remove_space(khm_handle conf) {
kconf_conf_space * c;
khm_int32 rv = KHM_ERROR_SUCCESS;
khm_int32 flags = 0;
if(!khc_is_config_running())
return KHM_ERROR_NOT_READY;
if(!khc_is_handle(conf))
return KHM_ERROR_INVALID_PARAM;
c = khc_space_from_handle(conf);
EnterCriticalSection(&cs_conf_global);
if (khc_is_machine_handle(conf))
flags |= KCONF_SPACE_FLAG_DELETE_M;
if (khc_is_user_handle(conf))
flags |= KCONF_SPACE_FLAG_DELETE_U;
rv = khcint_remove_space(c, flags);
LeaveCriticalSection(&cs_conf_global);
return rv;
}
khm_boolean
khcint_is_valid_name(wchar_t * name)
{
size_t cbsize;
if(FAILED(StringCbLength(name, KCONF_MAXCB_NAME, &cbsize)))
return FALSE;
return TRUE;
}
khm_int32
khcint_validate_schema(const kconf_schema * schema,
int begin,
int *end)
{
int i;
int state = 0;
int end_found = 0;
i=begin;
while(!end_found) {
switch(state) {
case 0:
if(!khcint_is_valid_name(schema[i].name) ||
schema[i].type != KC_SPACE)
return KHM_ERROR_INVALID_PARAM;
state = 1;
break;
case 1:
if(!khcint_is_valid_name(schema[i].name))
return KHM_ERROR_INVALID_PARAM;
if(schema[i].type == KC_SPACE) {
if(KHM_FAILED(khcint_validate_schema(schema, i, &i)))
return KHM_ERROR_INVALID_PARAM;
state = 2;
} else if(schema[i].type == KC_ENDSPACE) {
end_found = 1;
if(end)
*end = i;
} else {
if(schema[i].type != KC_STRING &&
schema[i].type != KC_INT32 &&
schema[i].type != KC_INT64 &&
schema[i].type != KC_BINARY)
return KHM_ERROR_INVALID_PARAM;
}
break;
case 2:
if(schema[i].type == KC_SPACE) {
if(KHM_FAILED(khcint_validate_schema(schema, i, &i)))
return KHM_ERROR_INVALID_PARAM;
} else if(schema[i].type == KC_ENDSPACE) {
end_found = 1;
if(end)
*end = i;
} else {
return KHM_ERROR_INVALID_PARAM;
}
break;
default:
return KHM_ERROR_INVALID_PARAM;
}
i++;
}
return KHM_ERROR_SUCCESS;
}
khm_int32
khcint_load_schema_i(khm_handle parent, const kconf_schema * schema,
int begin, int * end)
{
int i;
int state = 0;
int end_found = 0;
kconf_conf_space * thisconf = NULL;
khm_handle h = NULL;
i=begin;
while(!end_found) {
switch(state) {
case 0:
LeaveCriticalSection(&cs_conf_global);
if(KHM_FAILED(khc_open_space(parent, schema[i].name,
KHM_FLAG_CREATE, &h))) {
EnterCriticalSection(&cs_conf_global);
return KHM_ERROR_INVALID_PARAM;
}
EnterCriticalSection(&cs_conf_global);
thisconf = khc_space_from_handle(h);
thisconf->schema = schema + (begin + 1);
thisconf->nSchema = 0;
state = 1;
break;
case 1:
if(schema[i].type == KC_SPACE) {
thisconf->nSchema = i - (begin + 1);
if(KHM_FAILED(khcint_load_schema_i(h, schema, i, &i)))
return KHM_ERROR_INVALID_PARAM;
state = 2;
} else if(schema[i].type == KC_ENDSPACE) {
thisconf->nSchema = i - (begin + 1);
end_found = 1;
if(end)
*end = i;
LeaveCriticalSection(&cs_conf_global);
khc_close_space(h);
EnterCriticalSection(&cs_conf_global);
}
break;
case 2:
if(schema[i].type == KC_SPACE) {
if(KHM_FAILED(khcint_load_schema_i(h, schema, i, &i)))
return KHM_ERROR_INVALID_PARAM;
} else if(schema[i].type == KC_ENDSPACE) {
end_found = 1;
if(end)
*end = i;
LeaveCriticalSection(&cs_conf_global);
khc_close_space(h);
EnterCriticalSection(&cs_conf_global);
} else {
return KHM_ERROR_INVALID_PARAM;
}
break;
default:
return KHM_ERROR_INVALID_PARAM;
}
i++;
}
return KHM_ERROR_SUCCESS;
}
KHMEXP khm_int32 KHMAPI
khc_load_schema(khm_handle conf, const kconf_schema * schema)
{
khm_int32 rv = KHM_ERROR_SUCCESS;
if(!khc_is_config_running())
return KHM_ERROR_NOT_READY;
if(conf && !khc_is_handle(conf))
return KHM_ERROR_INVALID_PARAM;
if(KHM_FAILED(khcint_validate_schema(schema, 0, NULL)))
return KHM_ERROR_INVALID_PARAM;
EnterCriticalSection(&cs_conf_global);
rv = khcint_load_schema_i(conf, schema, 0, NULL);
LeaveCriticalSection(&cs_conf_global);
return rv;
}
khm_int32
khcint_unload_schema_i(khm_handle parent, const kconf_schema * schema,
int begin, int * end)
{
int i;
int state = 0;
int end_found = 0;
kconf_conf_space * thisconf = NULL;
khm_handle h = NULL;
i=begin;
while(!end_found) {
switch(state) {
case 0:
LeaveCriticalSection(&cs_conf_global);
if(KHM_FAILED(khc_open_space(parent, schema[i].name, 0, &h))) {
EnterCriticalSection(&cs_conf_global);
return KHM_ERROR_INVALID_PARAM;
}
EnterCriticalSection(&cs_conf_global);
thisconf = khc_space_from_handle(h);
if(thisconf->schema == (schema + (begin + 1))) {
thisconf->schema = NULL;
thisconf->nSchema = 0;
}
state = 1;
break;
case 1:
if(schema[i].type == KC_SPACE) {
if(KHM_FAILED(khcint_unload_schema_i(h, schema, i, &i)))
return KHM_ERROR_INVALID_PARAM;
state = 2;
} else if(schema[i].type == KC_ENDSPACE) {
end_found = 1;
if(end)
*end = i;
LeaveCriticalSection(&cs_conf_global);
khc_close_space(h);
EnterCriticalSection(&cs_conf_global);
}
break;
case 2:
if(schema[i].type == KC_SPACE) {
if(KHM_FAILED(khcint_unload_schema_i(h, schema, i, &i)))
return KHM_ERROR_INVALID_PARAM;
} else if(schema[i].type == KC_ENDSPACE) {
end_found = 1;
if(end)
*end = i;
LeaveCriticalSection(&cs_conf_global);
khc_close_space(h);
EnterCriticalSection(&cs_conf_global);
} else {
return KHM_ERROR_INVALID_PARAM;
}
break;
default:
return KHM_ERROR_INVALID_PARAM;
}
i++;
}
return KHM_ERROR_SUCCESS;
}
KHMEXP khm_int32 KHMAPI
khc_unload_schema(khm_handle conf, const kconf_schema * schema)
{
khm_int32 rv = KHM_ERROR_SUCCESS;
if(!khc_is_config_running())
return KHM_ERROR_NOT_READY;
if(conf && !khc_is_handle(conf))
return KHM_ERROR_INVALID_PARAM;
if(KHM_FAILED(khcint_validate_schema(schema, 0, NULL)))
return KHM_ERROR_INVALID_PARAM;
EnterCriticalSection(&cs_conf_global);
rv = khcint_unload_schema_i(conf, schema, 0, NULL);
LeaveCriticalSection(&cs_conf_global);
return rv;
}
KHMEXP khm_int32 KHMAPI
khc_enum_subspaces(khm_handle conf,
khm_handle prev,
khm_handle * next)
{
kconf_conf_space * s;
kconf_conf_space * c;
kconf_conf_space * p;
khm_int32 rv = KHM_ERROR_SUCCESS;
if(!khc_is_config_running())
return KHM_ERROR_NOT_READY;
if(!khc_is_handle(conf) || next == NULL ||
(prev != NULL && !khc_is_handle(prev)))
return KHM_ERROR_INVALID_PARAM;
s = khc_space_from_handle(conf);
if(prev == NULL) {
{
HKEY hk_conf;
hk_conf = khcint_space_open_key(s, 0);
if(hk_conf) {
wchar_t name[KCONF_MAXCCH_NAME];
khm_handle h;
int idx;
idx = 0;
while(RegEnumKey(hk_conf, idx,
name, ARRAYLENGTH(name)) == ERROR_SUCCESS) {
wchar_t * tilde;
tilde = wcschr(name, L'~');
if (tilde)
*tilde = 0;
if(KHM_SUCCEEDED(khc_open_space(conf, name, 0, &h)))
khc_close_space(h);
idx++;
}
}
}
{
HKEY hk_conf;
hk_conf = khcint_space_open_key(s, KCONF_FLAG_MACHINE);
if(hk_conf) {
wchar_t name[KCONF_MAXCCH_NAME];
khm_handle h;
int idx;
idx = 0;
while(RegEnumKey(hk_conf, idx,
name, ARRAYLENGTH(name)) == ERROR_SUCCESS) {
wchar_t * tilde;
tilde = wcschr(name, L'~');
if (tilde)
*tilde = 0;
if(KHM_SUCCEEDED(khc_open_space(conf, name,
KCONF_FLAG_MACHINE, &h)))
khc_close_space(h);
idx++;
}
}
}
}
EnterCriticalSection(&cs_conf_global);
if(prev == NULL) {
c = TFIRSTCHILD(s);
rv = KHM_ERROR_SUCCESS;
} else {
p = khc_space_from_handle(prev);
if(TPARENT(p) == s)
c = LNEXT(p);
else
c = NULL;
}
LeaveCriticalSection(&cs_conf_global);
if(prev != NULL)
khc_close_space(prev);
if(c) {
*next = khcint_handle_from_space(c, khc_handle_flags(conf));
rv = KHM_ERROR_SUCCESS;
} else {
*next = NULL;
rv = KHM_ERROR_NOT_FOUND;
}
return rv;
}
KHMEXP khm_int32 KHMAPI
khc_write_multi_string(khm_handle conf, const wchar_t * value, wchar_t * buf)
{
size_t cb;
wchar_t vbuf[KCONF_MAXCCH_STRING];
wchar_t *tb;
khm_int32 rv;
if(!khc_is_config_running())
return KHM_ERROR_NOT_READY;
if(!khc_is_handle(conf) || buf == NULL || value == NULL)
return KHM_ERROR_INVALID_PARAM;
if(multi_string_to_csv(NULL, &cb, buf) != KHM_ERROR_TOO_LONG)
return KHM_ERROR_INVALID_PARAM;
if (cb < sizeof(vbuf))
tb = vbuf;
else
tb = PMALLOC(cb);
assert(tb != NULL);
multi_string_to_csv(tb, &cb, buf);
rv = khc_write_string(conf, value, tb);
if (tb != vbuf)
PFREE(tb);
return rv;
}
KHMEXP khm_int32 KHMAPI
khc_read_multi_string(khm_handle conf, const wchar_t * value,
wchar_t * buf, khm_size * bufsize)
{
wchar_t vbuf[KCONF_MAXCCH_STRING];
wchar_t * tb;
khm_size cbbuf;
khm_int32 rv = KHM_ERROR_SUCCESS;
if(!khc_is_config_running())
return KHM_ERROR_NOT_READY;
if(!bufsize)
return KHM_ERROR_INVALID_PARAM;
rv = khc_read_string(conf, value, NULL, &cbbuf);
if(rv != KHM_ERROR_TOO_LONG)
return rv;
if (cbbuf < sizeof(vbuf))
tb = vbuf;
else
tb = PMALLOC(cbbuf);
assert(tb != NULL);
rv = khc_read_string(conf, value, tb, &cbbuf);
if(KHM_FAILED(rv))
goto _exit;
rv = csv_to_multi_string(buf, bufsize, tb);
_exit:
if (tb != vbuf)
PFREE(tb);
return rv;
}