[PATCH 5/6] propsys: Partially implement property stringification
Jonas Kümmerlin
rgcjonas at gmail.com
Tue Jul 14 10:07:45 CDT 2015
This implements PropVariantToString, PropVariantToStringAlloc,
PropVariantToBSTR and PropVariantChangeType for stringifying
numbers and converting between different types of strings.
MSDN specifies a lot more conversion, so there's plenty of
room for future improvements.
---
dlls/propsys/propsys.spec | 6 +-
dlls/propsys/propvar.c | 319 +++++++++++++++++++++++++++++++++++++++++++
dlls/propsys/tests/propsys.c | 80 ++++++++++-
include/propvarutil.h | 3 +
4 files changed, 404 insertions(+), 4 deletions(-)
diff --git a/dlls/propsys/propsys.spec b/dlls/propsys/propsys.spec
index 50bdf6e..970b5c0 100644
--- a/dlls/propsys/propsys.spec
+++ b/dlls/propsys/propsys.spec
@@ -106,7 +106,7 @@
@ stub PropVariantGetUInt16Elem
@ stub PropVariantGetUInt32Elem
@ stub PropVariantGetUInt64Elem
-@ stub PropVariantToBSTR
+@ stdcall PropVariantToBSTR(ptr ptr)
@ stub PropVariantToBoolean
@ stub PropVariantToBooleanVector
@ stub PropVariantToBooleanVectorAlloc
@@ -133,8 +133,8 @@
@ stub PropVariantToInt64VectorAlloc
@ stub PropVariantToInt64WithDefault
@ stub PropVariantToStrRet
-@ stub PropVariantToString
-@ stub PropVariantToStringAlloc
+@ stdcall PropVariantToString(ptr ptr long)
+@ stdcall PropVariantToStringAlloc(ptr ptr)
@ stub PropVariantToStringVector
@ stub PropVariantToStringVectorAlloc
@ stub PropVariantToStringWithDefault
diff --git a/dlls/propsys/propvar.c b/dlls/propsys/propvar.c
index e7ba3f3..df195aa 100644
--- a/dlls/propsys/propvar.c
+++ b/dlls/propsys/propvar.c
@@ -32,6 +32,7 @@
#include "propvarutil.h"
#include "mimeole.h"
#include "oleauto.h"
+#include "strsafe.h"
#include "wine/debug.h"
#include "wine/unicode.h"
@@ -211,6 +212,299 @@ HRESULT WINAPI PropVariantToUInt64(REFPROPVARIANT propvarIn, ULONGLONG *ret)
return hr;
}
+static HRESULT PropVariantToString_Size(REFPROPVARIANT propvarIn, UINT *pcch)
+{
+ HRESULT hr = S_OK;
+
+ TRACE("%p %p\n", propvarIn, pcch);
+
+ *pcch = 0;
+
+ switch (propvarIn->vt)
+ {
+ case VT_EMPTY:
+ *pcch = 0;
+ break;
+ case VT_I1:
+ case VT_I2:
+ case VT_I4:
+ case VT_I8:
+ case VT_INT:
+ case VT_UI1:
+ case VT_UI2:
+ case VT_UI4:
+ case VT_UI8:
+ case VT_UINT:
+ *pcch = 21; /* enough for all 64bit integers */
+ break;
+ case VT_LPWSTR:
+ *pcch = lstrlenW(propvarIn->u.pwszVal);
+ break;
+ case VT_LPSTR:
+ *pcch = MultiByteToWideChar(CP_ACP, 0, propvarIn->u.pszVal, -1, NULL, 0);
+ break;
+ case VT_BSTR:
+ *pcch = SysStringLen(propvarIn->u.bstrVal);
+ break;
+ default:
+ FIXME("Unsupported variant type %d\n", propvarIn->vt);
+ hr = E_NOTIMPL;
+ }
+
+ return hr;
+}
+
+/* FIXME: It is 2015, why do I have to write this? */
+static UINT i64_to_wstr(LONGLONG llVal, WCHAR *buf)
+{
+ UINT size = 0;
+ LONGLONG i;
+
+ /* special case 0 */
+ if (llVal == 0)
+ {
+ buf[0] = '0';
+ buf[1] = 0;
+ return 1;
+ }
+
+ /* calculate size needed */
+ if (llVal < 0)
+ size += 1;
+
+ for (i = llVal; i != 0; i /= 10)
+ size++;
+
+ TRACE("Required size: %u chars\n", size);
+
+ /* offset the buffer */
+ buf += size;
+
+ /* insert terminating null */
+ *buf-- = 0;
+
+ /* begin writing */
+ for (i = llVal; i != 0; i /= 10)
+ {
+ *buf-- = '0' + abs(i % 10);
+ }
+
+ if (llVal < 0)
+ *buf = '-';
+
+ return size;
+}
+
+static UINT u64_to_wstr(ULONGLONG ullVal, WCHAR *buf)
+{
+ UINT size = 0;
+ ULONGLONG i;
+
+ /* special case 0 */
+ if (ullVal == 0)
+ {
+ buf[0] = '0';
+ buf[1] = 0;
+ return 1;
+ }
+
+ /* calculate size needed */
+ for (i = ullVal; i > 0; i /= 10)
+ size++;
+
+ /* offset the buffer */
+ buf += size;
+
+ /* insert terminating null */
+ *buf-- = 0;
+
+ /* begin writing */
+ for (i = ullVal; i > 0; i /= 10)
+ {
+ *buf-- = '0' + (i % 10);
+ }
+
+ return size;
+}
+
+HRESULT WINAPI PropVariantToString(REFPROPVARIANT propvar, WCHAR *buf, UINT cch)
+{
+ HRESULT hr = S_OK;
+ WCHAR numBuffer[22];
+
+ TRACE("%p %p %u\n", propvar, buf, cch);
+
+ if (cch < 1)
+ return E_FAIL;
+
+ switch (propvar->vt)
+ {
+ case VT_EMPTY:
+ *buf = 0;
+ break;
+ case VT_I1:
+ case VT_I2:
+ case VT_I4:
+ case VT_I8:
+ case VT_INT:
+ {
+ LONGLONG ll;
+ UINT numLen;
+
+ hr = PropVariantToInt64(propvar, &ll);
+ if (FAILED(hr))
+ break;
+
+ numLen = i64_to_wstr(ll, numBuffer);
+
+ if (numLen < cch)
+ {
+ memcpy(buf, numBuffer, (numLen+1)*sizeof(WCHAR));
+ }
+ else
+ {
+ memcpy(buf, numBuffer, (cch-1)*sizeof(WCHAR));
+ buf[cch - 1] = 0;
+ hr = STRSAFE_E_INSUFFICIENT_BUFFER;
+ }
+
+ break;
+ }
+ case VT_UI1:
+ case VT_UI2:
+ case VT_UI4:
+ case VT_UI8:
+ case VT_UINT:
+ {
+ ULONGLONG ll;
+ UINT numLen;
+
+ hr = PropVariantToUInt64(propvar, &ll);
+ if (FAILED(hr))
+ break;
+
+ numLen = u64_to_wstr(ll, numBuffer);
+
+ if (numLen < cch)
+ {
+ memcpy(buf, numBuffer, (numLen+1)*sizeof(WCHAR));
+ }
+ else
+ {
+ memcpy(buf, numBuffer, (cch-1)*sizeof(WCHAR));
+ buf[cch - 1] = 0;
+ hr = STRSAFE_E_INSUFFICIENT_BUFFER;
+ }
+
+ break;
+ }
+ case VT_LPWSTR:
+ {
+ UINT len = lstrlenW(propvar->u.pwszVal);
+
+ if (len < cch)
+ {
+ memcpy(buf, propvar->u.pwszVal, (len+1)*sizeof(WCHAR));
+ }
+ else
+ {
+ memcpy(buf, propvar->u.pwszVal, (cch-1)*sizeof(WCHAR));
+ buf[cch-1] = 0;
+ hr = STRSAFE_E_INSUFFICIENT_BUFFER;
+ }
+ break;
+ }
+ case VT_LPSTR:
+ {
+ UINT len = MultiByteToWideChar(CP_ACP, 0, propvar->u.pszVal, -1, NULL, 0);
+ if (len == 0)
+ {
+ hr = E_FAIL;
+ break;
+ }
+
+ if (len < cch)
+ {
+ MultiByteToWideChar(CP_ACP, 0, propvar->u.pszVal, -1, buf, len+1);
+ }
+ else
+ {
+ /* TODO: allocate large buffer, copy truncated result */
+ FIXME("Truncating narrow string not implemented\n");
+ hr = E_NOTIMPL;
+ }
+ break;
+ }
+ case VT_BSTR:
+ {
+ UINT len = SysStringLen(propvar->u.bstrVal);
+
+ if (len < cch)
+ {
+ memcpy(buf, propvar->u.bstrVal, len*sizeof(WCHAR));
+ buf[len] = 0;
+ }
+ else
+ {
+ memcpy(buf, propvar->u.bstrVal, (cch-1)*sizeof(WCHAR));
+ buf[cch-1] = 0;
+ hr = STRSAFE_E_INSUFFICIENT_BUFFER;
+ }
+ break;
+ }
+ default:
+ FIXME("Unsupported variant type %d\n", propvar->vt);
+ hr = E_NOTIMPL;
+ }
+
+ return hr;
+}
+
+HRESULT WINAPI PropVariantToStringAlloc(REFPROPVARIANT prop, WCHAR **pbuf)
+{
+ HRESULT hr;
+ UINT size;
+
+ TRACE("%p %p\n", prop, pbuf);
+
+ hr = PropVariantToString_Size(prop, &size);
+ if (FAILED(hr))
+ return hr;
+
+ *pbuf = CoTaskMemAlloc((size+1) * sizeof(WCHAR));
+ if (!*pbuf)
+ return E_OUTOFMEMORY;
+
+ hr = PropVariantToString(prop, *pbuf, size+1);
+ if (FAILED(hr))
+ {
+ CoTaskMemFree(*pbuf);
+ *pbuf = NULL;
+ }
+
+ return hr;
+}
+
+HRESULT WINAPI PropVariantToBSTR(REFPROPVARIANT prop, BSTR *pbstr)
+{
+ HRESULT hr;
+ WCHAR *buf;
+
+ TRACE("%p %p\n", prop, pbstr);
+
+ hr = PropVariantToStringAlloc(prop, &buf);
+ if (FAILED(hr))
+ return hr;
+
+ *pbstr = SysAllocString(buf);
+ if (!*pbstr)
+ hr = E_OUTOFMEMORY;
+
+ CoTaskMemFree(buf);
+
+ return hr;
+}
+
/******************************************************************
* PropVariantChangeType (PROPSYS.@)
*/
@@ -290,6 +584,31 @@ HRESULT WINAPI PropVariantChangeType(PROPVARIANT *ppropvarDest, REFPROPVARIANT p
}
return hr;
}
+ case VT_LPWSTR:
+ {
+ WCHAR *str;
+
+ hr = PropVariantToStringAlloc(propvarSrc, &str);
+ if (SUCCEEDED(hr))
+ {
+ ppropvarDest->vt = VT_LPWSTR;
+ ppropvarDest->u.pwszVal = str;
+ }
+ return hr;
+ }
+ case VT_BSTR:
+ {
+ BSTR str;
+
+ hr = PropVariantToBSTR(propvarSrc, &str);
+ if (SUCCEEDED(hr))
+ {
+ ppropvarDest->vt = VT_BSTR;
+ ppropvarDest->u.bstrVal = str;
+ }
+
+ return hr;
+ }
}
switch (propvarSrc->vt)
diff --git a/dlls/propsys/tests/propsys.c b/dlls/propsys/tests/propsys.c
index acc35fa..347df4f 100644
--- a/dlls/propsys/tests/propsys.c
+++ b/dlls/propsys/tests/propsys.c
@@ -31,6 +31,7 @@
#include "objbase.h"
#include "propsys.h"
#include "propvarutil.h"
+#include "strsafe.h"
#include "wine/test.h"
#include "initguid.h"
@@ -713,7 +714,7 @@ static void test_PropVariantCompare(void)
todo_wine ok(res == 0, "res=%i\n", res);
res = PropVariantCompareEx(&str_2, &i2_2, 0, 0);
- todo_wine ok(res == 0, "res=%i\n", res);
+ ok(res == 0, "res=%i\n", res);
res = PropVariantCompareEx(&str_02, &i2_2, 0, 0);
ok(res == -1, "res=%i\n", res);
@@ -865,6 +866,82 @@ static void test_intconversions(void)
ok(llval == -7, "got wrong value %s\n", debugstr_longlong(llval));
}
+static void test_stringify(void)
+{
+ PROPVARIANT propvar;
+ SHORT sVal = -235;
+ WCHAR sValStr[] = { '-', '2', '3', '5', 0 };
+ LONG lVal = 0;
+ WCHAR lValStr[] = { '0', 0 };
+ ULONGLONG ullVal = 0xDEAFBABECAFEBEEF;
+ WCHAR ullValStr[] = { '1','6','0','4','6','2','4','9','3','2','5','9','5','6','6','1','1','8','2','3',0 };
+ WCHAR wszVal[] = { 'H','e','l','l','o','W','o','r','l','d',0 };
+ char szVal[] = "HelloWorld";
+ WCHAR buffer[22];
+ WCHAR smallBuffer[10];
+ HRESULT hr;
+
+ ZeroMemory(buffer, sizeof(buffer));
+ ZeroMemory(smallBuffer, sizeof(smallBuffer));
+
+ /* Warm up using a small integer */
+ propvar.vt = VT_I2;
+ propvar.u.iVal = sVal;
+
+ hr = PropVariantToString(&propvar, buffer, sizeof(buffer)/sizeof(buffer[0]));
+ ok(hr == S_OK, "PropVariantToString(VT_I2) failed, hr=%08x\n", hr);
+ ok(!lstrcmpW(buffer, sValStr), "Unexpected result %s\n", wine_dbgstr_w(buffer));
+
+ /* Test zero */
+ propvar.vt = VT_I4;
+ propvar.u.lVal = lVal;
+
+ hr = PropVariantToString(&propvar, buffer, sizeof(buffer)/sizeof(buffer[0]));
+ ok(hr == S_OK, "PropVariantToString(VT_I2) failed, hr=%08x\n", hr);
+ ok(!lstrcmpW(buffer, lValStr), "Unexpected result %s\n", wine_dbgstr_w(buffer));
+
+ /* Test bigger integers */
+ propvar.vt = VT_UI8;
+ propvar.u.uhVal.QuadPart = ullVal;
+ hr = PropVariantToString(&propvar, buffer, sizeof(buffer)/sizeof(buffer[0]));
+ ok(hr == S_OK, "PropVariantToString(VT_UI8) failed, hr=%08x\n", hr);
+ ok(!lstrcmpW(buffer, ullValStr), "Unexpected result %s\n", wine_dbgstr_w(buffer));
+
+ /* Test truncation */
+ hr = PropVariantToString(&propvar, smallBuffer, sizeof(smallBuffer)/sizeof(buffer[0]));
+ ok(hr == STRSAFE_E_INSUFFICIENT_BUFFER, "Unexpected hr=%08x\n", hr);
+ ok(!memcmp(ullValStr, smallBuffer, lstrlenW(smallBuffer)*sizeof(WCHAR)),
+ "Unexpected result %s\n", wine_dbgstr_w(smallBuffer));
+
+ /* Test narrow string conversion */
+ propvar.vt = VT_LPSTR;
+ propvar.u.pszVal = szVal;
+
+ hr = PropVariantToString(&propvar, buffer, sizeof(buffer)/sizeof(buffer[0]));
+ ok(hr == S_OK, "PropVariantToString(VT_LPSTR) failed, hr=%08x\n", hr);
+ ok(!lstrcmpW(buffer, wszVal), "Unexpected result %s\n", wine_dbgstr_w(buffer));
+
+ /* Test wide string copy */
+ propvar.vt = VT_LPWSTR;
+ propvar.u.pwszVal = wszVal;
+
+ hr = PropVariantToString(&propvar, buffer, sizeof(buffer)/sizeof(buffer[0]));
+ ok(hr == S_OK, "PropVariantToString(VT_LPWSTR) failed, hr=%08x\n", hr);
+ ok(!lstrcmpW(buffer, wszVal), "Unexpected result %s\n", wine_dbgstr_w(buffer));
+
+ /* Test bstr */
+ propvar.vt = VT_BSTR;
+ propvar.u.bstrVal = SysAllocString(wszVal);
+
+ hr = PropVariantToString(&propvar, buffer, sizeof(buffer)/sizeof(buffer[0]));
+ ok(hr == S_OK, "PropVariantToString(VT_BSTR) failed, hr=%08x\n", hr);
+ ok(!lstrcmpW(buffer, wszVal), "Unexpected result %s\n", wine_dbgstr_w(buffer));
+
+ SysFreeString(propvar.u.bstrVal);
+
+ /* TODO test all other funny strigifications */
+}
+
static char *buffer_printable(void *buffer, size_t buffer_size)
{
char *heap_buffer, *p;
@@ -1250,6 +1327,7 @@ START_TEST(propsys)
test_InitPropVariantFromBuffer();
test_PropVariantToGUID();
test_PropVariantCompare();
+ test_stringify();
test_intconversions();
test_serialization();
}
diff --git a/include/propvarutil.h b/include/propvarutil.h
index a2ec2af..571588a 100644
--- a/include/propvarutil.h
+++ b/include/propvarutil.h
@@ -78,6 +78,9 @@ HRESULT WINAPI PropVariantToInt64(REFPROPVARIANT propvarIn, LONGLONG *ret);
HRESULT WINAPI PropVariantToUInt16(REFPROPVARIANT propvarIn, USHORT *ret);
HRESULT WINAPI PropVariantToUInt32(REFPROPVARIANT propvarIn, ULONG *ret);
HRESULT WINAPI PropVariantToUInt64(REFPROPVARIANT propvarIn, ULONGLONG *ret);
+HRESULT WINAPI PropVariantToString(REFPROPVARIANT propvarIn, WCHAR *psz, UINT cch);
+HRESULT WINAPI PropVariantToBSTR(REFPROPVARIANT propvarIn, BSTR *pbstr);
+HRESULT WINAPI PropVariantToStringAlloc(REFPROPVARIANT propvarIn, WCHAR **ppszOut);
#ifdef NO_PROPVAR_INLINES
HRESULT InitPropVariantFromBoolean(BOOL fVal, PROPVARIANT *ppropvar);
--
2.4.3
More information about the wine-devel
mailing list