From: Connor McAdams cmcadams@codeweavers.com
Signed-off-by: Connor McAdams cmcadams@codeweavers.com --- dlls/mmdevapi/devenum.c | 150 ++++++++++++++++++++++++++++++-- dlls/mmdevapi/tests/propstore.c | 4 +- 2 files changed, 147 insertions(+), 7 deletions(-)
diff --git a/dlls/mmdevapi/devenum.c b/dlls/mmdevapi/devenum.c index adce05da954..0f48fe161a6 100644 --- a/dlls/mmdevapi/devenum.c +++ b/dlls/mmdevapi/devenum.c @@ -44,6 +44,14 @@ WINE_DEFAULT_DEBUG_CHANNEL(mmdevapi);
DEFINE_GUID(GUID_NULL,0,0,0,0,0,0,0,0,0,0,0);
+#define WINE_REG_PROP_MAGIC 0xbeef +struct reg_prop_serialized { + VARTYPE vt; + WORD unk; /* Uninitialized memory on native, we store a magic value here. */ + ULONG elems; + BYTE data[]; +}; + static HKEY key_render; static HKEY key_capture;
@@ -260,6 +268,116 @@ static HRESULT MMDevPropStore_OpenPropKey(const GUID *guid, DWORD flow, HKEY *pr return S_OK; }
+static BOOL is_vector_vt(VARTYPE vt) +{ + return !!(vt & VT_VECTOR); +} + +static unsigned int get_vt_elem_size(VARTYPE vt) +{ + switch (vt & VT_TYPEMASK) + { + case VT_BOOL: + return sizeof(VARIANT_BOOL); + + default: + return 0; + } +} + +static BOOL is_valid_serialized_reg_prop(BYTE *data, DWORD data_size) +{ + struct reg_prop_serialized *reg_prop; + unsigned int elem_size; + + if (data_size <= sizeof(*reg_prop)) + return FALSE; + + reg_prop = (struct reg_prop_serialized *)data; + if (reg_prop->unk != WINE_REG_PROP_MAGIC) + return FALSE; + + if (((reg_prop->vt & VT_TYPEMASK) > VT_CLSID)) + return FALSE; + + if (!!(reg_prop->vt & ~VT_TYPEMASK) && !is_vector_vt(reg_prop->vt)) + return FALSE; + + if (!reg_prop->elems || ((reg_prop->elems > 1) && !is_vector_vt(reg_prop->vt))) + return FALSE; + + elem_size = get_vt_elem_size(reg_prop->vt); + if (elem_size && (((elem_size * reg_prop->elems) + sizeof(*reg_prop)) > data_size)) + return FALSE; + + return TRUE; +} + +static HRESULT deserialize_reg_prop(BYTE *data, DWORD data_size, PROPVARIANT *pv) +{ + struct reg_prop_serialized *reg_prop = (struct reg_prop_serialized *)data; + unsigned int elems_size; + HRESULT hr = S_OK; + + switch (reg_prop->vt) + { + case VT_BOOL: + pv->vt = reg_prop->vt; + pv->boolVal = ((VARIANT_BOOL *)reg_prop->data)[0]; + break; + + case VT_BOOL | VT_VECTOR: + pv->vt = reg_prop->vt; + pv->cabool.cElems = reg_prop->elems; + elems_size = sizeof(*pv->cabool.pElems) * reg_prop->elems; + pv->cabool.pElems = CoTaskMemAlloc(elems_size); + memcpy(pv->cabool.pElems, reg_prop->data, elems_size); + break; + + default: + ERR("Tried to deserialize unhandled vt %#x.\n", reg_prop->vt); + hr = E_NOTIMPL; + break; + } + + return hr; +} + +static HRESULT serialize_reg_prop(HKEY reg_key, const WCHAR *prop_id, PROPVARIANT *pv) +{ + const struct reg_prop_serialized reg_prop_init = { pv->vt, WINE_REG_PROP_MAGIC }; + struct reg_prop_serialized *reg_prop = NULL; + unsigned int size = sizeof(reg_prop_init); + unsigned int elems_size, elem_count = 1; + void *elems_val = NULL; + LONG ret; + + switch (pv->vt) + { + case VT_BOOL: + elems_size = sizeof(pv->boolVal); + elems_val = &pv->boolVal; + break; + + case VT_BOOL | VT_VECTOR: + elem_count = pv->cabool.cElems; + elems_size = elem_count * sizeof(*pv->cabool.pElems); + elems_val = pv->cabool.pElems; + break; + } + + size += elems_size; + if (!(reg_prop = malloc(size))) + return E_OUTOFMEMORY; + + *reg_prop = reg_prop_init; + reg_prop->elems = elem_count; + memcpy(reg_prop->data, elems_val, elems_size); + ret = RegSetValueExW(reg_key, prop_id, 0, REG_BINARY, (BYTE *)reg_prop, size); + free(reg_prop); + return !ret ? S_OK : E_FAIL; +} + static HRESULT MMDevice_GetPropValue(const GUID *devguid, DWORD flow, REFPROPERTYKEY key, PROPVARIANT *pv) { WCHAR buffer[80]; @@ -304,13 +422,26 @@ static HRESULT MMDevice_GetPropValue(const GUID *devguid, DWORD flow, REFPROPERT } case REG_BINARY: { - pv->vt = VT_BLOB; - pv->blob.cbSize = size; - pv->blob.pBlobData = CoTaskMemAlloc(size); - if (!pv->blob.pBlobData) + BYTE *data = CoTaskMemAlloc(size); + + if (!data) + { hr = E_OUTOFMEMORY; + break; + } + + RegGetValueW(regkey, NULL, buffer, RRF_RT_REG_BINARY, NULL, data, &size); + if (is_valid_serialized_reg_prop(data, size)) + { + hr = deserialize_reg_prop(data, size, pv); + CoTaskMemFree(data); + } else - RegGetValueW(regkey, NULL, buffer, RRF_RT_REG_BINARY, NULL, (BYTE*)pv->blob.pBlobData, &size); + { + pv->vt = VT_BLOB; + pv->blob.cbSize = size; + pv->blob.pBlobData = data; + } break; } default: @@ -343,6 +474,15 @@ static HRESULT MMDevice_SetPropValue(const GUID *devguid, DWORD flow, REFPROPERT ret = RegSetValueExW(regkey, buffer, 0, REG_DWORD, (const BYTE*)&pv->ulVal, sizeof(DWORD)); break; } + + case VT_BOOL: + case VT_BOOL | VT_VECTOR: + { + hr = serialize_reg_prop(regkey, buffer, (PROPVARIANT *)pv); + ret = 0; + break; + } + case VT_BLOB: { ret = RegSetValueExW(regkey, buffer, 0, REG_BINARY, pv->blob.pBlobData, pv->blob.cbSize); diff --git a/dlls/mmdevapi/tests/propstore.c b/dlls/mmdevapi/tests/propstore.c index 88496375dd8..15d1f5b4866 100644 --- a/dlls/mmdevapi/tests/propstore.c +++ b/dlls/mmdevapi/tests/propstore.c @@ -254,8 +254,8 @@ static void test_setvalue_on_wow64(IPropertyStore *store) BOOL todo_data; } propvar_tests[] = { - { VT_BOOL, vt_bool_vals, sizeof(vt_bool_vals[0]), S_OK, REG_BINARY, 0xa, TRUE, TRUE }, - { VT_BOOL | VT_VECTOR, vt_bool_vals, sizeof(vt_bool_vals), S_OK, REG_BINARY, 0xc, TRUE, TRUE }, + { VT_BOOL, vt_bool_vals, sizeof(vt_bool_vals[0]), S_OK, REG_BINARY, 0xa }, + { VT_BOOL | VT_VECTOR, vt_bool_vals, sizeof(vt_bool_vals), S_OK, REG_BINARY, 0xc }, { VT_CLSID, vt_clsid_vals, sizeof(vt_clsid_vals[0]), S_OK, REG_BINARY, 0x18, TRUE, TRUE }, { VT_CLSID | VT_VECTOR, vt_clsid_vals, sizeof(vt_clsid_vals), S_OK, REG_BINARY, 0x28, TRUE, TRUE }, { VT_BSTR, vt_bstr_val, sizeof(vt_bstr_val), S_OK, REG_BINARY, 0x14, TRUE, TRUE },