wine-wine/dlls/wbemprox/reg.c

445 lines
13 KiB
C

/*
* StdRegProv implementation
*
* Copyright 2012 Hans Leidekker for CodeWeavers
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
*/
#define COBJMACROS
#include <stdarg.h>
#include "windef.h"
#include "winbase.h"
#include "wbemcli.h"
#include "wine/debug.h"
#include "wbemprox_private.h"
WINE_DEFAULT_DEBUG_CHANNEL(wbemprox);
static HRESULT to_bstr_array( BSTR *strings, DWORD count, VARIANT *var )
{
SAFEARRAY *sa;
HRESULT hr;
LONG i;
if (!(sa = SafeArrayCreateVector( VT_BSTR, 0, count ))) return E_OUTOFMEMORY;
for (i = 0; i < count; i++)
{
if ((hr = SafeArrayPutElement( sa, &i, strings[i] )) != S_OK)
{
SafeArrayDestroy( sa );
return hr;
}
}
set_variant( VT_BSTR|VT_ARRAY, 0, sa, var );
return S_OK;
}
static void free_bstr_array( BSTR *strings, DWORD count )
{
while (count--)
SysFreeString( *(strings++) );
}
static HRESULT to_i4_array( DWORD *values, DWORD count, VARIANT *var )
{
SAFEARRAY *sa;
HRESULT hr;
LONG i;
if (!(sa = SafeArrayCreateVector( VT_I4, 0, count ))) return E_OUTOFMEMORY;
for (i = 0; i < count; i++)
{
if ((hr = SafeArrayPutElement( sa, &i, &values[i] )) != S_OK)
{
SafeArrayDestroy( sa );
return hr;
}
}
set_variant( VT_I4|VT_ARRAY, 0, sa, var );
return S_OK;
}
static HRESULT create_key( HKEY root, const WCHAR *subkey, VARIANT *retval )
{
LONG res;
HKEY hkey;
TRACE("%p, %s\n", root, debugstr_w(subkey));
res = RegCreateKeyExW( root, subkey, 0, NULL, 0, 0, NULL, &hkey, NULL );
set_variant( VT_UI4, res, NULL, retval );
if (!res)
{
RegCloseKey( hkey );
return S_OK;
}
return HRESULT_FROM_WIN32( res );
}
HRESULT reg_create_key( IWbemClassObject *obj, IWbemClassObject *in, IWbemClassObject **out )
{
VARIANT defkey, subkey, retval;
IWbemClassObject *sig, *out_params = NULL;
HRESULT hr;
TRACE("%p, %p\n", in, out);
hr = IWbemClassObject_Get( in, L"hDefKey", 0, &defkey, NULL, NULL );
if (hr != S_OK) return hr;
hr = IWbemClassObject_Get( in, L"sSubKeyName", 0, &subkey, NULL, NULL );
if (hr != S_OK) return hr;
hr = create_signature( L"StdRegProv", L"CreateKey", PARAM_OUT, &sig );
if (hr != S_OK)
{
VariantClear( &subkey );
return hr;
}
if (out)
{
hr = IWbemClassObject_SpawnInstance( sig, 0, &out_params );
if (hr != S_OK)
{
VariantClear( &subkey );
IWbemClassObject_Release( sig );
return hr;
}
}
hr = create_key( (HKEY)(INT_PTR)V_I4(&defkey), V_BSTR(&subkey), &retval );
if (hr == S_OK && out_params)
hr = IWbemClassObject_Put( out_params, L"ReturnValue", 0, &retval, CIM_UINT32 );
VariantClear( &subkey );
IWbemClassObject_Release( sig );
if (hr == S_OK && out)
{
*out = out_params;
IWbemClassObject_AddRef( out_params );
}
if (out_params) IWbemClassObject_Release( out_params );
return hr;
}
static HRESULT enum_key( HKEY root, const WCHAR *subkey, VARIANT *names, VARIANT *retval )
{
HKEY hkey;
HRESULT hr = S_OK;
WCHAR buf[256];
BSTR *strings, *tmp;
DWORD count = 2, len = ARRAY_SIZE( buf );
LONG res, i = 0;
TRACE("%p, %s\n", root, debugstr_w(subkey));
if (!(strings = heap_alloc( count * sizeof(BSTR) ))) return E_OUTOFMEMORY;
if ((res = RegOpenKeyExW( root, subkey, 0, KEY_ENUMERATE_SUB_KEYS, &hkey )))
{
set_variant( VT_UI4, res, NULL, retval );
heap_free( strings );
return S_OK;
}
for (;;)
{
if (i >= count)
{
count *= 2;
if (!(tmp = heap_realloc( strings, count * sizeof(BSTR) )))
{
RegCloseKey( hkey );
return E_OUTOFMEMORY;
}
strings = tmp;
}
if ((res = RegEnumKeyW( hkey, i, buf, len )) == ERROR_NO_MORE_ITEMS)
{
if (i) res = ERROR_SUCCESS;
break;
}
if (res) break;
if (!(strings[i] = SysAllocString( buf )))
{
for (i--; i >= 0; i--) SysFreeString( strings[i] );
hr = E_OUTOFMEMORY;
break;
}
i++;
}
if (hr == S_OK && !res)
{
hr = to_bstr_array( strings, i, names );
free_bstr_array( strings, i );
}
set_variant( VT_UI4, res, NULL, retval );
RegCloseKey( hkey );
heap_free( strings );
return hr;
}
HRESULT reg_enum_key( IWbemClassObject *obj, IWbemClassObject *in, IWbemClassObject **out )
{
VARIANT defkey, subkey, names, retval;
IWbemClassObject *sig, *out_params = NULL;
HRESULT hr;
TRACE("%p, %p\n", in, out);
hr = IWbemClassObject_Get( in, L"hDefKey", 0, &defkey, NULL, NULL );
if (hr != S_OK) return hr;
hr = IWbemClassObject_Get( in, L"sSubKeyName", 0, &subkey, NULL, NULL );
if (hr != S_OK) return hr;
hr = create_signature( L"StdRegProv", L"EnumKey", PARAM_OUT, &sig );
if (hr != S_OK)
{
VariantClear( &subkey );
return hr;
}
if (out)
{
hr = IWbemClassObject_SpawnInstance( sig, 0, &out_params );
if (hr != S_OK)
{
VariantClear( &subkey );
IWbemClassObject_Release( sig );
return hr;
}
}
VariantInit( &names );
hr = enum_key( (HKEY)(INT_PTR)V_I4(&defkey), V_BSTR(&subkey), &names, &retval );
if (hr != S_OK) goto done;
if (out_params)
{
if (!V_UI4( &retval ))
{
hr = IWbemClassObject_Put( out_params, L"sNames", 0, &names, CIM_STRING|CIM_FLAG_ARRAY );
if (hr != S_OK) goto done;
}
hr = IWbemClassObject_Put( out_params, L"ReturnValue", 0, &retval, CIM_UINT32 );
}
done:
VariantClear( &names );
VariantClear( &subkey );
IWbemClassObject_Release( sig );
if (hr == S_OK && out)
{
*out = out_params;
IWbemClassObject_AddRef( out_params );
}
if (out_params) IWbemClassObject_Release( out_params );
return hr;
}
static HRESULT enum_values( HKEY root, const WCHAR *subkey, VARIANT *names, VARIANT *types, VARIANT *retval )
{
HKEY hkey = NULL;
HRESULT hr = S_OK;
BSTR *value_names = NULL;
DWORD count, buflen, len, *value_types = NULL;
LONG res, i = 0;
WCHAR *buf = NULL;
TRACE("%p, %s\n", root, debugstr_w(subkey));
if ((res = RegOpenKeyExW( root, subkey, 0, KEY_QUERY_VALUE, &hkey ))) goto done;
if ((res = RegQueryInfoKeyW( hkey, NULL, NULL, NULL, NULL, NULL, NULL, &count, &buflen, NULL, NULL, NULL )))
goto done;
hr = E_OUTOFMEMORY;
if (!(buf = heap_alloc( (buflen + 1) * sizeof(WCHAR) ))) goto done;
if (!(value_names = heap_alloc( count * sizeof(BSTR) ))) goto done;
if (!(value_types = heap_alloc( count * sizeof(DWORD) ))) goto done;
hr = S_OK;
for (;;)
{
len = buflen + 1;
res = RegEnumValueW( hkey, i, buf, &len, NULL, &value_types[i], NULL, NULL );
if (res == ERROR_NO_MORE_ITEMS)
{
if (i) res = ERROR_SUCCESS;
break;
}
if (res) break;
if (!(value_names[i] = SysAllocString( buf )))
{
for (i--; i >= 0; i--) SysFreeString( value_names[i] );
hr = E_OUTOFMEMORY;
break;
}
i++;
}
if (hr == S_OK && !res)
{
hr = to_bstr_array( value_names, i, names );
free_bstr_array( value_names, i );
if (hr == S_OK) hr = to_i4_array( value_types, i, types );
}
done:
set_variant( VT_UI4, res, NULL, retval );
RegCloseKey( hkey );
heap_free( value_names );
heap_free( value_types );
heap_free( buf );
return hr;
}
HRESULT reg_enum_values( IWbemClassObject *obj, IWbemClassObject *in, IWbemClassObject **out )
{
VARIANT defkey, subkey, names, types, retval;
IWbemClassObject *sig, *out_params = NULL;
HRESULT hr;
TRACE("%p, %p\n", in, out);
hr = IWbemClassObject_Get( in, L"hDefKey", 0, &defkey, NULL, NULL );
if (hr != S_OK) return hr;
hr = IWbemClassObject_Get( in, L"sSubKeyName", 0, &subkey, NULL, NULL );
if (hr != S_OK) return hr;
hr = create_signature( L"StdRegProv", L"EnumValues", PARAM_OUT, &sig );
if (hr != S_OK)
{
VariantClear( &subkey );
return hr;
}
if (out)
{
hr = IWbemClassObject_SpawnInstance( sig, 0, &out_params );
if (hr != S_OK)
{
VariantClear( &subkey );
IWbemClassObject_Release( sig );
return hr;
}
}
VariantInit( &names );
VariantInit( &types );
hr = enum_values( (HKEY)(INT_PTR)V_I4(&defkey), V_BSTR(&subkey), &names, &types, &retval );
if (hr != S_OK) goto done;
if (out_params)
{
if (!V_UI4( &retval ))
{
hr = IWbemClassObject_Put( out_params, L"sNames", 0, &names, CIM_STRING|CIM_FLAG_ARRAY );
if (hr != S_OK) goto done;
hr = IWbemClassObject_Put( out_params, L"Types", 0, &types, CIM_SINT32|CIM_FLAG_ARRAY );
if (hr != S_OK) goto done;
}
hr = IWbemClassObject_Put( out_params, L"ReturnValue", 0, &retval, CIM_UINT32 );
}
done:
VariantClear( &types );
VariantClear( &names );
VariantClear( &subkey );
IWbemClassObject_Release( sig );
if (hr == S_OK && out)
{
*out = out_params;
IWbemClassObject_AddRef( out_params );
}
if (out_params) IWbemClassObject_Release( out_params );
return hr;
}
static HRESULT get_stringvalue( HKEY root, const WCHAR *subkey, const WCHAR *name, VARIANT *value, VARIANT *retval )
{
HRESULT hr = S_OK;
BSTR str = NULL;
DWORD size;
LONG res;
TRACE("%p, %s, %s\n", root, debugstr_w(subkey), debugstr_w(name));
if ((res = RegGetValueW( root, subkey, name, RRF_RT_REG_SZ, NULL, NULL, &size ))) goto done;
if (!(str = SysAllocStringLen( NULL, size / sizeof(WCHAR) - 1 )))
{
hr = E_OUTOFMEMORY;
goto done;
}
if (!(res = RegGetValueW( root, subkey, name, RRF_RT_REG_SZ, NULL, str, &size )))
set_variant( VT_BSTR, 0, str, value );
done:
set_variant( VT_UI4, res, NULL, retval );
if (res) SysFreeString( str );
return hr;
}
HRESULT reg_get_stringvalue( IWbemClassObject *obj, IWbemClassObject *in, IWbemClassObject **out )
{
VARIANT defkey, subkey, name, value, retval;
IWbemClassObject *sig, *out_params = NULL;
HRESULT hr;
TRACE("%p, %p\n", in, out);
hr = IWbemClassObject_Get( in, L"hDefKey", 0, &defkey, NULL, NULL );
if (hr != S_OK) return hr;
hr = IWbemClassObject_Get( in, L"sSubKeyName", 0, &subkey, NULL, NULL );
if (hr != S_OK) return hr;
hr = IWbemClassObject_Get( in, L"sValueName", 0, &name, NULL, NULL );
if (hr != S_OK) return hr;
hr = create_signature( L"StdRegProv", L"GetStringValue", PARAM_OUT, &sig );
if (hr != S_OK)
{
VariantClear( &name );
VariantClear( &subkey );
return hr;
}
if (out)
{
hr = IWbemClassObject_SpawnInstance( sig, 0, &out_params );
if (hr != S_OK)
{
VariantClear( &name );
VariantClear( &subkey );
IWbemClassObject_Release( sig );
return hr;
}
}
VariantInit( &value );
hr = get_stringvalue( (HKEY)(INT_PTR)V_I4(&defkey), V_BSTR(&subkey), V_BSTR(&name), &value, &retval );
if (hr != S_OK) goto done;
if (out_params)
{
if (!V_UI4( &retval ))
{
hr = IWbemClassObject_Put( out_params, L"sValue", 0, &value, CIM_STRING );
if (hr != S_OK) goto done;
}
hr = IWbemClassObject_Put( out_params, L"ReturnValue", 0, &retval, CIM_UINT32 );
}
done:
VariantClear( &name );
VariantClear( &subkey );
IWbemClassObject_Release( sig );
if (hr == S_OK && out)
{
*out = out_params;
IWbemClassObject_AddRef( out_params );
}
if (out_params) IWbemClassObject_Release( out_params );
return hr;
}