Skip to content

Instantly share code, notes, and snippets.

@DrYak
Created April 24, 2015 22:24
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save DrYak/81f73fff0d572130ff9d to your computer and use it in GitHub Desktop.
Save DrYak/81f73fff0d572130ff9d to your computer and use it in GitHub Desktop.
disphelper patch - for wine and byref support - split source
diff --git a/source/convert.c b/source/convert.c
index ae61fe4..0c85ef9 100644
--- a/source/convert.c
+++ b/source/convert.c
@@ -25,13 +25,13 @@
#include <math.h>
/* Number of 100 nannosecond units in a FILETIME day */
-static const LONGLONG FILE_TIME_ONE_DAY = 864000000000;
+static const LONGLONG FILE_TIME_ONE_DAY = 864000000000LL;
/* VARIANT DATE 0 (1899-Dec-30) as a FILETIME */
-static const LONGLONG FILE_TIME_VARIANT_DAY0 = 94353120000000000;
+static const LONGLONG FILE_TIME_VARIANT_DAY0 = 94353120000000000LL;
/* FILETIME of day 1, year 10,000 */
-static const ULONGLONG FILE_TIME_VARIANT_OVERFLOW = 2650467744000000000;
+static const ULONGLONG FILE_TIME_VARIANT_OVERFLOW = 2650467744000000000ULL;
/* FILETIME date 0 (1601-Jan-1) as a VARIANT DATE */
static const DATE VARIANT_FILE_TIME_DAY0 = -109205;
diff --git a/source/dh_enum.c b/source/dh_enum.c
index 406df09..67e2e42 100644
--- a/source/dh_enum.c
+++ b/source/dh_enum.c
@@ -60,10 +60,10 @@ HRESULT dhEnumBeginV(IEnumVARIANT ** ppEnum, IDispatch * pDisp, LPCOLESTR szMemb
if (FAILED(hr)) return DH_EXITEX(hr, TRUE, L"_NewEnum", szMember, &excep, 0);
/* Retrieve an IEnumVariant interface from the returned interface */
- if (vtResult.vt == VT_DISPATCH)
- hr = vtResult.pdispVal->lpVtbl->QueryInterface(vtResult.pdispVal, &IID_IEnumVARIANT, (void **) ppEnum);
- else if (vtResult.vt == VT_UNKNOWN)
- hr = vtResult.punkVal->lpVtbl->QueryInterface(vtResult.punkVal, &IID_IEnumVARIANT, (void **) ppEnum);
+ if (V_VT(&vtResult) == VT_DISPATCH)
+ hr = V_DISPATCH(&vtResult)->lpVtbl->QueryInterface(V_DISPATCH(&vtResult), &IID_IEnumVARIANT, (void **) ppEnum);
+ else if (V_VT(&vtResult) == VT_UNKNOWN)
+ hr = V_UNKNOWN(&vtResult)->lpVtbl->QueryInterface(V_UNKNOWN(&vtResult), &IID_IEnumVARIANT, (void **) ppEnum);
else
hr = E_NOINTERFACE;
@@ -112,14 +112,14 @@ HRESULT dhEnumNextObject(IEnumVARIANT * pEnum, IDispatch ** ppDisp)
if (hr == S_OK)
{
- if (vtResult.vt == VT_DISPATCH)
+ if (V_VT(&vtResult) == VT_DISPATCH)
{
- *ppDisp = vtResult.pdispVal;
+ *ppDisp = V_DISPATCH(&vtResult);
}
else
{
hr = VariantChangeType(&vtResult, &vtResult, 0, VT_DISPATCH);
- if (SUCCEEDED(hr)) *ppDisp = vtResult.pdispVal;
+ if (SUCCEEDED(hr)) *ppDisp = V_DISPATCH(&vtResult);
else VariantClear(&vtResult);
}
}
diff --git a/source/dh_exceptions.c b/source/dh_exceptions.c
index 4b506ab..15de8dc 100644
--- a/source/dh_exceptions.c
+++ b/source/dh_exceptions.c
@@ -20,6 +20,13 @@
#include "disphelper.h"
#include <assert.h>
+#ifdef __WINE__
+// Wine uses the system widechar string function which as C99 compliant ( swprintf is the wide equivalent of snprintf )
+// whereas Windows' API, and thus MinGW, Visual Studio, etc. are not compliant ( swprintf is the wide equivalent of sprintf, snwprintf is the wide equivalent of snprintf)
+#define _snwprintf swprintf
+#endif
+
+
#ifndef DISPHELPER_NO_EXCEPTIONS
/* Structure to store global exception options. */
@@ -314,7 +321,7 @@ HRESULT dhFormatExceptionW(PDH_EXCEPTION pException, LPWSTR szBuffer, UINT cchBu
{
if (!bFixedFont)
{
- _snwprintf(szBuffer, cchBufferSize, L"Member:\t %s\r\nFunction:\t %s\t\t\r\nError In:\t %s\r\nError:\t %s\r\nCode:\t %x\r\nSource:\t %s",
+ _snwprintf(szBuffer, cchBufferSize, L"Member:\t %ls\r\nFunction:\t %ls\t\t\r\nError In:\t %ls\r\nError:\t %ls\r\nCode:\t %x\r\nSource:\t %ls",
pException->szCompleteMember,
pException->szInitialFunction, pException->szErrorFunction,
pException->szDescription, hr,
@@ -322,7 +329,7 @@ HRESULT dhFormatExceptionW(PDH_EXCEPTION pException, LPWSTR szBuffer, UINT cchBu
}
else
{
- _snwprintf(szBuffer, cchBufferSize, L"Member: %s\r\nFunction: %s\r\nError In: %s\r\nError: %s\r\nCode: %x\r\nSource: %s",
+ _snwprintf(szBuffer, cchBufferSize, L"Member: %ls\r\nFunction: %ls\r\nError In: %ls\r\nError: %ls\r\nCode: %x\r\nSource: %ls",
pException->szCompleteMember,
pException->szInitialFunction, pException->szErrorFunction,
pException->szDescription, hr,
diff --git a/source/dh_invoke.c b/source/dh_invoke.c
index eea4093..17338bc 100644
--- a/source/dh_invoke.c
+++ b/source/dh_invoke.c
@@ -23,7 +23,7 @@
static HRESULT TraverseSubObjects(IDispatch ** ppDisp, LPWSTR * lpszMember, va_list * marker);
static HRESULT CreateArgumentArray(LPWSTR szTemp, VARIANT * pArgs, BOOL * pbFreeList, UINT * pcArgs, va_list * marker);
static HRESULT InternalInvokeV(int invokeType, VARTYPE returnType, VARIANT * pvResult, IDispatch * pDisp, LPOLESTR szMember, va_list * marker);
-static HRESULT ExtractArgument(VARIANT * pvArg, WCHAR chIdentifier, BOOL * pbFreeArg, va_list * marker);
+static HRESULT ExtractArgument(VARIANT * pvArg, const WCHAR * chIdentifierPtr, BOOL * pbFreeArg, va_list * marker);
/* **************************************************************************
@@ -120,7 +120,7 @@ static HRESULT TraverseSubObjects(IDispatch ** ppDisp, LPWSTR * lpszMember, va_l
hr = InternalInvokeV(DISPATCH_METHOD|DISPATCH_PROPERTYGET, VT_DISPATCH,
&vtObject, *ppDisp, szTemp, marker);
- if (!vtObject.pdispVal && SUCCEEDED(hr)) hr = E_NOINTERFACE;
+ if (! V_DISPATCH(&vtObject) && SUCCEEDED(hr)) hr = E_NOINTERFACE;
/* Release old object in *ppDisp */
(*ppDisp)->lpVtbl->Release(*ppDisp);
@@ -128,7 +128,7 @@ static HRESULT TraverseSubObjects(IDispatch ** ppDisp, LPWSTR * lpszMember, va_l
if (FAILED(hr)) break;
/* Copy new object into *ppDisp */
- *ppDisp = vtObject.pdispVal;
+ *ppDisp = V_DISPATCH(&vtObject);
/* Point next object name to start at character after '.'.
* eg. szTemp will now equal "Range.Font.Bold" */
@@ -183,7 +183,7 @@ static HRESULT InternalInvokeV(int invokeType, VARTYPE returnType, VARIANT * pvR
/* Coerce result (if it exists) into the desired type.
* Note that VT_EMPTY means do not coerce the return value. */
if (SUCCEEDED(hr) && pvResult != NULL &&
- pvResult->vt != returnType && returnType != VT_EMPTY)
+ V_VT(pvResult) != returnType && returnType != VT_EMPTY)
{
hr = VariantChangeType(pvResult, pvResult, 16 /* = VARIANT_LOCALBOOL */, returnType);
if (FAILED(hr)) VariantClear(pvResult);
@@ -246,7 +246,7 @@ static HRESULT CreateArgumentArray(LPWSTR szMember, VARIANT * pArgs, BOOL * pbFr
szMember++; /* Move forward to actual identifier */
/* Extract argument based on identifier */
- hr = ExtractArgument(&pArgs[iArg], *szMember, &pbFreeList[iArg], marker);
+ hr = ExtractArgument(&pArgs[iArg], szMember, &pbFreeList[iArg], marker);
if (FAILED(hr)) break;
}
@@ -277,31 +277,172 @@ static HRESULT CreateArgumentArray(LPWSTR szMember, VARIANT * pArgs, BOOL * pbFr
* identifier and pack it in a VARIANT.
*
============================================================================ */
-static HRESULT ExtractArgument(VARIANT * pvArg, WCHAR chIdentifier, BOOL * pbFreeArg, va_list * marker)
+static HRESULT ExtractArgument(VARIANT * pvArg, const WCHAR * chIdentifier, BOOL * pbFreeArg, va_list * marker)
{
HRESULT hr = NOERROR;
+ WCHAR chIdentifier = *chIdentifierPtr;
+ BOOL isRef = FALSE;
+ INT size = 0;
/* By default, the argument does not need to be freed */
*pbFreeArg = FALSE;
+ /* C++ -like "byref" modifier */
+ if (chIdentifier == L'&')
+ {
+ isRef = TRUE;
+ chIdentifier = *(++chIdentifierPtr);
+ }
+
+ /* scanf -like format modifier */
+ while(chIdentifier)
+ {
+ if (chIdentifier == L'h')
+ size--;
+ else if (chIdentifier == L'l')
+ size++;
+ else if (chIdentifier == L'L')
+ size=2; // long-long is always 64bits
+ else break;
+
+ chIdentifier = *(++chIdentifierPtr);
+ }
+
/* Change 'T' identifier to 'S' or 's' based on UNICODE mode */
if (chIdentifier == L'T') chIdentifier = (dh_g_bIsUnicodeMode ? L'S' : L's');
switch (chIdentifier)
{
case L'd': /* LONG */
- V_VT(pvArg) = VT_I4;
- V_I4(pvArg) = va_arg(*marker, LONG);
+ if (isRef)
+ {
+ switch(size)
+ {
+ case -2:
+ V_VT(pvArg) = VT_I1 | VT_BYREF;
+// V_I1REF(pvArg) = va_arg(*marker, CHAR *);
+ break;
+ case -1:
+ V_VT(pvArg) = VT_I2 | VT_BYREF;
+ V_I2REF(pvArg) = va_arg(*marker, SHORT *);
+ break;
+ case 0:
+ /* WIN32/WIN64 is assumed : 32bit int (are there still any 16bit OLE in circulation ?!?) */
+ case 1:
+ /* WIN64 is LLP64 thus even long are always 32bits regardless of OS */
+ V_VT(pvArg) = VT_I4 | VT_BYREF;
+ V_I4REF(pvArg) = va_arg(*marker, LONG *);
+ break;
+ case 2:
+ V_VT(pvArg) = VT_I8 | VT_BYREF;
+ V_I8REF(pvArg) = va_arg(*marker, LONGLONG *);
+ break;
+ default:
+ hr = E_INVALIDARG;
+ DEBUG_NOTIFY_INVALID_IDENTIFIER(chIdentifier);
+ break;
+ }
+ }
+ else
+ {
+ if (size == 2)
+ {
+ /* special case for 64-bits integers */
+ V_VT(pvArg) = VT_I8;
+ V_I8(pvArg) = va_arg(*marker, LONGLONG);
+ }
+ else
+ {
+ /* all other are promoted to 32-bits integers when passed as arguments */
+ V_VT(pvArg) = VT_I4;
+ V_I4(pvArg) = va_arg(*marker, LONG);
+ }
+ }
break;
case L'u': /* ULONG */
- V_VT(pvArg) = VT_UI4;
- V_UI4(pvArg) = va_arg(*marker, ULONG);
+ if (isRef) {
+ switch(size)
+ {
+ case -2:
+ V_VT(pvArg) = VT_UI1 | VT_BYREF;
+// V_UI1REF(pvArg) = va_arg(*marker, BYTE *);
+ break;
+ case -1:
+ V_VT(pvArg) = VT_UI2 | VT_BYREF;
+ V_UI2REF(pvArg) = va_arg(*marker, USHORT *);
+ break;
+ case 0:
+ /* WIN32/WIN64 is assumed : 32bit int (are there still any 16bit OLE in circulation ?!?) */
+ case 1:
+ /* WIN64 is LLP64 thus even long are always 32bits regardless of OS */
+ V_VT(pvArg) = VT_UI4 | VT_BYREF;
+ V_UI4REF(pvArg) = va_arg(*marker, ULONG *);
+ break;
+ case 2:
+ V_VT(pvArg) = VT_UI8 | VT_BYREF;
+ V_UI8REF(pvArg) = va_arg(*marker, ULONGLONG *);
+ break;
+ default:
+ hr = E_INVALIDARG;
+ DEBUG_NOTIFY_INVALID_IDENTIFIER(chIdentifier);
+ break;
+ }
+ }
+ else
+ {
+ if (size == 2)
+ {
+ /* special case for 64-bits integers */
+ V_VT(pvArg) = VT_UI8;
+ V_UI8(pvArg) = va_arg(*marker, ULONGLONG);
+ }
+ else
+ {
+ /* all other are promoted to 32-bits integers when passed as arguments */
+ V_VT(pvArg) = VT_UI4;
+ V_UI4(pvArg) = va_arg(*marker, ULONG);
+ }
+ }
break;
case L'e': /* DOUBLE */
- V_VT(pvArg) = VT_R8;
- V_R8(pvArg) = va_arg(*marker, DOUBLE);
+ if (isRef)
+ {
+ switch(size)
+ {
+ case -1:
+ case 0:
+ /* Warning, we mimick SCANF default behaviour with efg being 32bits float by default */
+ V_VT(pvArg) = VT_R4 | VT_BYREF;
+ V_R4REF(pvArg) = va_arg(*marker, FLOAT *);
+ break;
+ case 1:
+ V_VT(pvArg) = VT_R8 | VT_BYREF;
+ V_R8REF(pvArg) = va_arg(*marker, DOUBLE *);
+ break;
+ default:
+ /* OLE32 doesn't support 128bits (default) & 80bits (387) long double floats */
+ hr = E_INVALIDARG;
+ DEBUG_NOTIFY_INVALID_IDENTIFIER(chIdentifier);
+ break;
+ }
+ }
+ else
+ {
+ if (size == 2)
+ {
+ /* long double floats take 80bits or 128bits and should be consumed accordingly */
+ V_VT(pvArg) = VT_R8;
+ V_R8(pvArg) = (DOUBLE) va_arg(*marker, long double);
+ }
+ else
+ {
+ /* float are auto-promoted to 64bit double float when passed as argument */
+ V_VT(pvArg) = VT_R8;
+ V_R8(pvArg) = va_arg(*marker, DOUBLE);
+ }
+ }
break;
case L'b': /* BOOL */
diff --git a/source/disphelper.h b/source/disphelper.h
index 9a3f9c4..c933eab 100644
--- a/source/disphelper.h
+++ b/source/disphelper.h
@@ -19,6 +19,7 @@
#ifndef DISPHELPER_H_INCLUDED
#define DISPHELPER_H_INCLUDED
+#include <ocidl.h>
#include <objbase.h>
#include <time.h>
@@ -547,11 +548,12 @@ inline std::ostream& operator<<(std::ostream& os, const CDhStringA& s)
return os << (s ? s : (char*) "(null)");
}
+#ifdef _GLIBCXX_USE_WCHAR_T
inline std::wostream& operator<<(std::wostream& os, const CDhStringW& s)
{
return os << (s ? s : (wchar_t*) L"(null)");
}
-
+#endif
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment