1293 lines
34 KiB
C
1293 lines
34 KiB
C
/* This file is the compacted single file version of the DispHelper COM helper library.
|
|
* DispHelper allows you to call COM objects with an extremely simple printf style syntax.
|
|
* DispHelper can be used from C++ or even plain C. It works with most Windows compilers
|
|
* including Dev-CPP, Visual C++ and LCC-WIN32. Including DispHelper in your project
|
|
* couldn't be simpler as it is available in a compacted single file version (this file).
|
|
*
|
|
* Included with DispHelper are over 20 samples that demonstrate using COM objects
|
|
* including ADO, CDO, Outlook, Eudora, Excel, Word, Internet Explorer, MSHTML,
|
|
* PocketSoap, Word Perfect, MS Agent, SAPI, MSXML, WIA, dexplorer and WMI.
|
|
*
|
|
* DispHelper is free open source software provided under the BSD license.
|
|
*
|
|
* Find out more, browse the readable version of the source code
|
|
* and download DispHelper at:
|
|
* http://sourceforge.net/projects/disphelper/
|
|
* http://disphelper.sourceforge.net/
|
|
*/
|
|
|
|
|
|
/* To use DispHelper in your project, include this file(disphelper.c) and the
|
|
* header (disphelper.h). For Visual C++, Borland C++ and LCC-Win32 import
|
|
* libraries are included via pragma directives. For other compilers you may
|
|
* need to add ole32, oleaut32 and uuid. To do this in Dev-CPP add
|
|
* "-lole32 -loleaut32 -luuid" to the linker box under Project->Project Options->Parameters.
|
|
*/
|
|
|
|
|
|
/* If you are using Dev-CPP and get errors when compiling this file:
|
|
* Make sure this file is set to compile as C and not C++ under
|
|
* Project->Project Options->Files.
|
|
*/
|
|
|
|
|
|
#define DISPHELPER_INTERNAL_BUILD
|
|
#include "disphelper.h"
|
|
#include <math.h>
|
|
#include <assert.h>
|
|
|
|
/* ----- convert.h ----- */
|
|
|
|
HRESULT ConvertFileTimeToVariantTime(FILETIME * pft, DATE * pDate);
|
|
HRESULT ConvertVariantTimeToFileTime(DATE date, FILETIME * pft);
|
|
|
|
HRESULT ConvertVariantTimeToSystemTime(DATE date, SYSTEMTIME * pSystemTime);
|
|
HRESULT ConvertSystemTimeToVariantTime(SYSTEMTIME * pSystemTime, DATE * pDate);
|
|
|
|
HRESULT ConvertTimeTToVariantTime(time_t timeT, DATE * pDate);
|
|
HRESULT ConvertVariantTimeToTimeT(DATE date, time_t * pTimeT);
|
|
|
|
HRESULT ConvertAnsiStrToBStr(LPCSTR szAnsiIn, BSTR * lpBstrOut);
|
|
HRESULT ConvertBStrToAnsiStr(BSTR bstrIn, LPSTR * lpszOut);
|
|
|
|
/* ----- dh_create.c ----- */
|
|
|
|
HRESULT dhCreateObjectEx(LPCOLESTR szProgId, REFIID riid, DWORD dwClsContext,
|
|
COSERVERINFO * pServerInfo, void ** ppv)
|
|
{
|
|
CLSID clsid;
|
|
HRESULT hr;
|
|
IClassFactory * pCf = NULL;
|
|
|
|
DH_ENTER(L"CreateObjectEx");
|
|
|
|
if (!szProgId || !riid || !ppv) return DH_EXIT(E_INVALIDARG, szProgId);
|
|
|
|
if (L'{' == szProgId[0])
|
|
hr = CLSIDFromString((LPOLESTR) szProgId, &clsid);
|
|
else
|
|
hr = CLSIDFromProgID(szProgId, &clsid);
|
|
|
|
if (SUCCEEDED(hr)) hr = CoGetClassObject(&clsid, dwClsContext, pServerInfo, &IID_IClassFactory, (void **) &pCf);
|
|
if (SUCCEEDED(hr)) hr = pCf->lpVtbl->CreateInstance(pCf, NULL, riid, ppv);
|
|
|
|
if (pCf) pCf->lpVtbl->Release(pCf);
|
|
|
|
return DH_EXIT(hr, szProgId);
|
|
}
|
|
|
|
HRESULT dhGetObjectEx(LPCOLESTR szPathName, LPCOLESTR szProgId, REFIID riid,
|
|
DWORD dwClsContext, LPVOID lpvReserved, void ** ppv)
|
|
{
|
|
HRESULT hr;
|
|
|
|
DH_ENTER(L"GetObjectEx");
|
|
|
|
if ((!szProgId && !szPathName) || !riid || !ppv || lpvReserved) return DH_EXIT(E_INVALIDARG, szProgId);
|
|
|
|
if (szPathName)
|
|
{
|
|
|
|
if (!szProgId)
|
|
{
|
|
hr = CoGetObject(szPathName, NULL, riid, ppv);
|
|
}
|
|
else
|
|
{
|
|
IPersistFile * ppf = NULL;
|
|
|
|
hr = dhCreateObjectEx(szProgId, &IID_IPersistFile, dwClsContext, NULL, (void **) &ppf);
|
|
|
|
if (SUCCEEDED(hr)) hr = ppf->lpVtbl->Load(ppf, szPathName, 0);
|
|
if (SUCCEEDED(hr)) hr = ppf->lpVtbl->QueryInterface(ppf, riid, ppv);
|
|
|
|
if (ppf) ppf->lpVtbl->Release(ppf);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
|
|
CLSID clsid;
|
|
IUnknown * pUnk = NULL;
|
|
|
|
if (L'{' == szProgId[0])
|
|
hr = CLSIDFromString((LPOLESTR) szProgId, &clsid);
|
|
else
|
|
hr = CLSIDFromProgID(szProgId, &clsid);
|
|
|
|
if (SUCCEEDED(hr)) hr = GetActiveObject(&clsid, NULL, &pUnk);
|
|
if (SUCCEEDED(hr)) hr = pUnk->lpVtbl->QueryInterface(pUnk, riid, ppv);
|
|
|
|
if (pUnk) pUnk->lpVtbl->Release(pUnk);
|
|
}
|
|
|
|
return DH_EXIT(hr, szProgId);
|
|
}
|
|
|
|
HRESULT dhCreateObject(LPCOLESTR szProgId, LPCWSTR szMachine, IDispatch ** ppDisp)
|
|
{
|
|
COSERVERINFO si = { 0 };
|
|
|
|
DH_ENTER(L"CreateObject");
|
|
|
|
si.pwszName = (LPWSTR) szMachine;
|
|
|
|
return DH_EXIT(dhCreateObjectEx(szProgId, &IID_IDispatch,
|
|
szMachine ? CLSCTX_REMOTE_SERVER : CLSCTX_LOCAL_SERVER|CLSCTX_INPROC_SERVER,
|
|
szMachine ? &si : NULL, (void **) ppDisp), szProgId);
|
|
}
|
|
|
|
HRESULT dhGetObject(LPCOLESTR szPathName, LPCOLESTR szProgId, IDispatch ** ppDisp)
|
|
{
|
|
DH_ENTER(L"GetObject");
|
|
|
|
return DH_EXIT(dhGetObjectEx(szPathName, szProgId, &IID_IDispatch,
|
|
CLSCTX_LOCAL_SERVER|CLSCTX_INPROC_SERVER, NULL, (void **) ppDisp), szProgId);
|
|
}
|
|
|
|
HRESULT dhCallMethod(IDispatch * pDisp, LPCOLESTR szMember, ... )
|
|
{
|
|
HRESULT hr;
|
|
va_list marker;
|
|
|
|
DH_ENTER(L"CallMethod");
|
|
|
|
va_start(marker, szMember);
|
|
|
|
hr = dhCallMethodV(pDisp, szMember, &marker);
|
|
|
|
va_end(marker);
|
|
|
|
return DH_EXIT(hr, szMember);
|
|
}
|
|
|
|
HRESULT dhPutValue(IDispatch * pDisp, LPCOLESTR szMember, ...)
|
|
{
|
|
HRESULT hr;
|
|
va_list marker;
|
|
|
|
DH_ENTER(L"PutValue");
|
|
|
|
va_start(marker, szMember);
|
|
|
|
hr = dhPutValueV(pDisp, szMember, &marker);
|
|
|
|
va_end(marker);
|
|
|
|
return DH_EXIT(hr, szMember);
|
|
}
|
|
|
|
HRESULT dhPutRef(IDispatch * pDisp, LPCOLESTR szMember, ...)
|
|
{
|
|
HRESULT hr;
|
|
va_list marker;
|
|
|
|
DH_ENTER(L"PutRef");
|
|
|
|
va_start(marker, szMember);
|
|
|
|
hr = dhPutRefV(pDisp, szMember, &marker);
|
|
|
|
va_end(marker);
|
|
|
|
return DH_EXIT(hr, szMember);
|
|
}
|
|
|
|
HRESULT dhGetValue(LPCWSTR szIdentifier, void * pResult, IDispatch * pDisp, LPCOLESTR szMember, ...)
|
|
{
|
|
HRESULT hr;
|
|
va_list marker;
|
|
|
|
DH_ENTER(L"GetValue");
|
|
|
|
va_start(marker, szMember);
|
|
|
|
hr = dhGetValueV(szIdentifier, pResult, pDisp, szMember, &marker);
|
|
|
|
va_end(marker);
|
|
|
|
return DH_EXIT(hr, szMember);
|
|
}
|
|
|
|
HRESULT dhInvoke(int invokeType, VARTYPE returnType, VARIANT * pvResult, IDispatch * pDisp, LPCOLESTR szMember, ...)
|
|
{
|
|
HRESULT hr;
|
|
va_list marker;
|
|
|
|
DH_ENTER(L"Invoke");
|
|
|
|
va_start(marker, szMember);
|
|
|
|
hr = dhInvokeV(invokeType, returnType, pvResult, pDisp, szMember, &marker);
|
|
|
|
va_end(marker);
|
|
|
|
return DH_EXIT(hr, szMember);
|
|
}
|
|
|
|
/* ----- dh_core.c ----- */
|
|
|
|
BOOL dh_g_bIsUnicodeMode;
|
|
|
|
HRESULT dhInvokeArray(int invokeType, VARIANT * pvResult, UINT cArgs,
|
|
IDispatch * pDisp, LPCOLESTR szMember, VARIANT * pArgs)
|
|
{
|
|
DISPPARAMS dp = { 0 };
|
|
EXCEPINFO excep = { 0 };
|
|
DISPID dispidNamed = DISPID_PROPERTYPUT;
|
|
DISPID dispID;
|
|
UINT uiArgErr;
|
|
HRESULT hr;
|
|
|
|
DH_ENTER(L"InvokeArray");
|
|
|
|
if(!pDisp || !szMember || (cArgs != 0 && !pArgs)) return DH_EXIT(E_INVALIDARG, szMember);
|
|
|
|
hr = pDisp->lpVtbl->GetIDsOfNames(pDisp, &IID_NULL, (LPOLESTR *) &szMember, 1, LOCALE_USER_DEFAULT, &dispID);
|
|
|
|
if(FAILED(hr)) return DH_EXITEX(hr, TRUE, szMember, szMember, NULL, 0);
|
|
|
|
if (pvResult != NULL) VariantInit(pvResult);
|
|
|
|
dp.cArgs = cArgs;
|
|
dp.rgvarg = pArgs;
|
|
|
|
if(invokeType & (DISPATCH_PROPERTYPUT | DISPATCH_PROPERTYPUTREF))
|
|
{
|
|
dp.cNamedArgs = 1;
|
|
dp.rgdispidNamedArgs = &dispidNamed;
|
|
}
|
|
|
|
hr = pDisp->lpVtbl->Invoke(pDisp, dispID, &IID_NULL, LOCALE_USER_DEFAULT, (WORD) invokeType, &dp, pvResult, &excep, &uiArgErr);
|
|
|
|
return DH_EXITEX(hr, TRUE, szMember, szMember, &excep, uiArgErr);
|
|
}
|
|
|
|
HRESULT dhCallMethodV(IDispatch * pDisp, LPCOLESTR szMember, va_list * marker)
|
|
{
|
|
DH_ENTER(L"CallMethodV");
|
|
|
|
return DH_EXIT(dhInvokeV(DISPATCH_METHOD, VT_EMPTY, NULL, pDisp, szMember, marker), szMember);
|
|
}
|
|
|
|
HRESULT dhPutValueV(IDispatch * pDisp, LPCOLESTR szMember, va_list * marker)
|
|
{
|
|
DH_ENTER(L"PutValueV");
|
|
|
|
return DH_EXIT(dhInvokeV(DISPATCH_PROPERTYPUT, VT_EMPTY, NULL, pDisp, szMember, marker), szMember);
|
|
}
|
|
|
|
HRESULT dhPutRefV(IDispatch * pDisp, LPCOLESTR szMember, va_list * marker)
|
|
{
|
|
DH_ENTER(L"PutRefV");
|
|
|
|
return DH_EXIT(dhInvokeV(DISPATCH_PROPERTYPUTREF, VT_EMPTY, NULL, pDisp, szMember, marker), szMember);
|
|
}
|
|
|
|
HRESULT dhGetValueV(LPCWSTR szIdentifier, void * pResult, IDispatch * pDisp, LPCOLESTR szMember, va_list * marker)
|
|
{
|
|
VARIANT vtResult;
|
|
VARTYPE returnType;
|
|
HRESULT hr;
|
|
|
|
DH_ENTER(L"GetValueV");
|
|
|
|
if (!pResult || !szIdentifier) return DH_EXIT(E_INVALIDARG, szMember);
|
|
|
|
if (*szIdentifier == L'%') szIdentifier++;
|
|
|
|
switch(*szIdentifier)
|
|
{
|
|
case L'd': returnType = VT_I4; break;
|
|
case L'u': returnType = VT_UI4; break;
|
|
case L'e': returnType = VT_R8; break;
|
|
case L'b': returnType = VT_BOOL; break;
|
|
case L'v': returnType = VT_EMPTY; break;
|
|
case L'B': returnType = VT_BSTR; break;
|
|
case L'S': returnType = VT_BSTR; break;
|
|
case L's': returnType = VT_BSTR; break;
|
|
case L'T': returnType = VT_BSTR; break;
|
|
case L'o': returnType = VT_DISPATCH; break;
|
|
case L'O': returnType = VT_UNKNOWN; break;
|
|
case L't': returnType = VT_DATE; break;
|
|
case L'W': returnType = VT_DATE; break;
|
|
case L'f': returnType = VT_DATE; break;
|
|
case L'D': returnType = VT_DATE; break;
|
|
#ifndef _WIN64
|
|
case L'p': returnType = VT_I4; break;
|
|
#else
|
|
case L'p': returnType = VT_I8; break;
|
|
#endif
|
|
default:
|
|
DEBUG_NOTIFY_INVALID_IDENTIFIER(*szIdentifier);
|
|
return DH_EXIT(E_INVALIDARG, szMember);
|
|
}
|
|
|
|
hr = dhInvokeV(DISPATCH_PROPERTYGET|DISPATCH_METHOD, returnType, &vtResult, pDisp, szMember, marker);
|
|
if (FAILED(hr)) return DH_EXIT(hr, szMember);
|
|
|
|
switch(*szIdentifier)
|
|
{
|
|
case L'd':
|
|
*((LONG *) pResult) = V_I4(&vtResult);
|
|
break;
|
|
|
|
case L'u':
|
|
*((ULONG *) pResult) = V_UI4(&vtResult);
|
|
break;
|
|
|
|
case L'e':
|
|
*((DOUBLE *) pResult) = V_R8(&vtResult);
|
|
break;
|
|
|
|
case L'b':
|
|
*((BOOL *) pResult) = V_BOOL(&vtResult);
|
|
break;
|
|
|
|
case L'v':
|
|
*((VARIANT *) pResult) = vtResult;
|
|
break;
|
|
|
|
case L'B':
|
|
*((BSTR *) pResult) = V_BSTR(&vtResult);
|
|
break;
|
|
|
|
case L'S':
|
|
*((LPWSTR *) pResult) = V_BSTR(&vtResult);
|
|
break;
|
|
|
|
case L's':
|
|
hr = ConvertBStrToAnsiStr(V_BSTR(&vtResult), (LPSTR *) pResult);
|
|
SysFreeString(V_BSTR(&vtResult));
|
|
break;
|
|
|
|
case L'T':
|
|
if (dh_g_bIsUnicodeMode)
|
|
{
|
|
*((LPWSTR *) pResult) = V_BSTR(&vtResult);
|
|
}
|
|
else
|
|
{
|
|
hr = ConvertBStrToAnsiStr(V_BSTR(&vtResult), (LPSTR *) pResult);
|
|
SysFreeString(V_BSTR(&vtResult));
|
|
}
|
|
break;
|
|
|
|
case L'o':
|
|
*((IDispatch **) pResult) = V_DISPATCH(&vtResult);
|
|
if (V_DISPATCH(&vtResult) == NULL) hr = E_NOINTERFACE;
|
|
break;
|
|
|
|
case L'O':
|
|
*((IUnknown **) pResult) = V_UNKNOWN(&vtResult);
|
|
if (V_UNKNOWN(&vtResult) == NULL) hr = E_NOINTERFACE;
|
|
break;
|
|
|
|
case L't':
|
|
hr = ConvertVariantTimeToTimeT(V_DATE(&vtResult), (time_t *) pResult);
|
|
break;
|
|
|
|
case L'W':
|
|
hr = ConvertVariantTimeToSystemTime(V_DATE(&vtResult), (SYSTEMTIME *) pResult);
|
|
break;
|
|
|
|
case L'f':
|
|
hr = ConvertVariantTimeToFileTime(V_DATE(&vtResult), (FILETIME *) pResult);
|
|
break;
|
|
|
|
case L'D':
|
|
*((DATE *) pResult) = V_DATE(&vtResult);
|
|
break;
|
|
|
|
case L'p':
|
|
#ifndef _WIN64
|
|
*((LPVOID *) pResult) = (LPVOID) V_I4(&vtResult);
|
|
#else
|
|
*((LPVOID *) pResult) = (LPVOID) V_I8(&vtResult);
|
|
#endif
|
|
break;
|
|
}
|
|
|
|
return DH_EXIT(hr, szMember);
|
|
}
|
|
|
|
/* ----- dh_invoke.c ----- */
|
|
|
|
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);
|
|
|
|
HRESULT dhInvokeV(int invokeType, VARTYPE returnType, VARIANT * pvResult,
|
|
IDispatch * pDisp, LPCOLESTR szMember, va_list * marker)
|
|
{
|
|
WCHAR szCopy[DH_MAX_MEMBER];
|
|
LPWSTR szTemp = szCopy;
|
|
SIZE_T cchDest = ARRAYSIZE(szCopy);
|
|
HRESULT hr;
|
|
|
|
DH_ENTER(L"InvokeV");
|
|
|
|
if (!pDisp || !szMember || !marker) return DH_EXIT(E_INVALIDARG, szMember);
|
|
|
|
do
|
|
{
|
|
if (cchDest-- == 0) return DH_EXIT(E_INVALIDARG, szMember);
|
|
}
|
|
while( (*szTemp++ = *szMember++) );
|
|
|
|
szTemp = szCopy;
|
|
|
|
hr = TraverseSubObjects(&pDisp, &szTemp, marker);
|
|
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
hr = InternalInvokeV(invokeType, returnType, pvResult, pDisp, szTemp, marker);
|
|
|
|
pDisp->lpVtbl->Release(pDisp);
|
|
}
|
|
|
|
return DH_EXIT(hr, szMember);
|
|
}
|
|
|
|
static HRESULT TraverseSubObjects(IDispatch ** ppDisp, LPWSTR * lpszMember, va_list * marker)
|
|
{
|
|
LPWSTR szSeperator, szTemp;
|
|
VARIANT vtObject;
|
|
HRESULT hr;
|
|
|
|
DH_ENTER(L"TraverseSubObjects");
|
|
|
|
if (**lpszMember == L'.') (*lpszMember)++;
|
|
|
|
(*ppDisp)->lpVtbl->AddRef(*ppDisp);
|
|
|
|
szSeperator = wcschr(*lpszMember, L'.');
|
|
|
|
if (szSeperator == NULL) return DH_EXIT(NOERROR, *lpszMember);
|
|
|
|
szTemp = *lpszMember;
|
|
|
|
do
|
|
{
|
|
*szSeperator = L'\0';
|
|
|
|
hr = InternalInvokeV(DISPATCH_METHOD|DISPATCH_PROPERTYGET, VT_DISPATCH,
|
|
&vtObject, *ppDisp, szTemp, marker);
|
|
|
|
if (!vtObject.pdispVal && SUCCEEDED(hr)) hr = E_NOINTERFACE;
|
|
|
|
(*ppDisp)->lpVtbl->Release(*ppDisp);
|
|
|
|
if (FAILED(hr)) break;
|
|
|
|
*ppDisp = vtObject.pdispVal;
|
|
|
|
szTemp = szSeperator + 1;
|
|
|
|
}
|
|
while ( (szSeperator = wcschr(szTemp, L'.') ) != NULL);
|
|
|
|
*lpszMember = szTemp;
|
|
|
|
return DH_EXIT(hr, *lpszMember);
|
|
}
|
|
|
|
static HRESULT InternalInvokeV(int invokeType, VARTYPE returnType, VARIANT * pvResult,
|
|
IDispatch * pDisp, LPOLESTR szMember, va_list * marker)
|
|
{
|
|
VARIANT vtArgs[DH_MAX_ARGS];
|
|
BOOL bFreeList[DH_MAX_ARGS];
|
|
HRESULT hr;
|
|
UINT cArgs, iArg;
|
|
|
|
DH_ENTER(L"InternalInvokeV");
|
|
|
|
hr = CreateArgumentArray(szMember, vtArgs, bFreeList, &cArgs, marker);
|
|
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
hr = dhInvokeArray(invokeType, pvResult, cArgs, pDisp, szMember, &vtArgs[DH_MAX_ARGS - cArgs]);
|
|
|
|
for (iArg = DH_MAX_ARGS - cArgs;iArg < DH_MAX_ARGS;iArg++)
|
|
{
|
|
if (bFreeList[iArg]) VariantClear(&vtArgs[iArg]);
|
|
}
|
|
|
|
if (SUCCEEDED(hr) && pvResult != NULL &&
|
|
pvResult->vt != returnType && returnType != VT_EMPTY)
|
|
{
|
|
hr = VariantChangeType(pvResult, pvResult, 16 , returnType);
|
|
if (FAILED(hr)) VariantClear(pvResult);
|
|
}
|
|
}
|
|
|
|
return DH_EXIT(hr, szMember);
|
|
}
|
|
|
|
static HRESULT CreateArgumentArray(LPWSTR szMember, VARIANT * pArgs, BOOL * pbFreeList,
|
|
UINT * pcArgs, va_list * marker)
|
|
{
|
|
HRESULT hr = NOERROR;
|
|
INT iArg = DH_MAX_ARGS;
|
|
BOOL bInArguments = FALSE;
|
|
|
|
DH_ENTER(L"CreateArgumentArray");
|
|
|
|
while (*szMember)
|
|
{
|
|
if (!bInArguments &&
|
|
(*szMember == L'(' || *szMember == L' ' || *szMember == L'=') )
|
|
{
|
|
bInArguments = TRUE;
|
|
|
|
*szMember = L'\0';
|
|
}
|
|
else if (*szMember == L'%')
|
|
{
|
|
if (!bInArguments)
|
|
{
|
|
bInArguments = TRUE;
|
|
*szMember = L'\0';
|
|
}
|
|
|
|
iArg--;
|
|
|
|
if (iArg == -1) { hr = E_INVALIDARG; break; }
|
|
|
|
szMember++;
|
|
|
|
hr = ExtractArgument(&pArgs[iArg], *szMember, &pbFreeList[iArg], marker);
|
|
|
|
if (FAILED(hr)) break;
|
|
}
|
|
|
|
szMember++;
|
|
}
|
|
|
|
*pcArgs = DH_MAX_ARGS - iArg;
|
|
|
|
if (FAILED(hr))
|
|
{
|
|
for (++iArg;iArg < DH_MAX_ARGS; iArg++)
|
|
{
|
|
if (pbFreeList[iArg]) VariantClear(&pArgs[iArg]);
|
|
}
|
|
}
|
|
|
|
return DH_EXIT(hr, szMember);
|
|
}
|
|
|
|
static HRESULT ExtractArgument(VARIANT * pvArg, WCHAR chIdentifier, BOOL * pbFreeArg, va_list * marker)
|
|
{
|
|
HRESULT hr = NOERROR;
|
|
|
|
*pbFreeArg = FALSE;
|
|
|
|
if (chIdentifier == L'T') chIdentifier = (dh_g_bIsUnicodeMode ? L'S' : L's');
|
|
|
|
switch (chIdentifier)
|
|
{
|
|
case L'd':
|
|
V_VT(pvArg) = VT_I4;
|
|
V_I4(pvArg) = va_arg(*marker, LONG);
|
|
break;
|
|
|
|
case L'u':
|
|
V_VT(pvArg) = VT_UI4;
|
|
V_UI4(pvArg) = va_arg(*marker, ULONG);
|
|
break;
|
|
|
|
case L'e':
|
|
V_VT(pvArg) = VT_R8;
|
|
V_R8(pvArg) = va_arg(*marker, DOUBLE);
|
|
break;
|
|
|
|
case L'b':
|
|
V_VT(pvArg) = VT_BOOL;
|
|
V_BOOL(pvArg) = ( va_arg(*marker, BOOL) ? VARIANT_TRUE : VARIANT_FALSE );
|
|
break;
|
|
|
|
case L'v':
|
|
*pvArg = *va_arg(*marker, VARIANT *);
|
|
break;
|
|
|
|
case L'm':
|
|
V_VT(pvArg) = VT_ERROR;
|
|
V_ERROR(pvArg) = DISP_E_PARAMNOTFOUND;
|
|
break;
|
|
|
|
case L'B':
|
|
V_VT(pvArg) = VT_BSTR;
|
|
V_BSTR(pvArg) = va_arg(*marker, BSTR);
|
|
break;
|
|
|
|
case L'S':
|
|
{
|
|
LPOLESTR szTemp = va_arg(*marker, LPOLESTR);
|
|
|
|
V_VT(pvArg) = VT_BSTR;
|
|
V_BSTR(pvArg) = SysAllocString(szTemp);
|
|
|
|
if (V_BSTR(pvArg) == NULL && szTemp != NULL) hr = E_OUTOFMEMORY;
|
|
|
|
*pbFreeArg = TRUE;
|
|
break;
|
|
}
|
|
|
|
case L's':
|
|
V_VT(pvArg) = VT_BSTR;
|
|
hr = ConvertAnsiStrToBStr(va_arg(*marker, LPSTR), &V_BSTR(pvArg));
|
|
*pbFreeArg = TRUE;
|
|
break;
|
|
|
|
case L'o':
|
|
V_VT(pvArg) = VT_DISPATCH;
|
|
V_DISPATCH(pvArg) = va_arg(*marker, IDispatch *);
|
|
break;
|
|
|
|
case L'O':
|
|
V_VT(pvArg) = VT_UNKNOWN;
|
|
V_UNKNOWN(pvArg) = va_arg(*marker, IUnknown *);
|
|
break;
|
|
|
|
case L'D':
|
|
V_VT(pvArg) = VT_DATE;
|
|
V_DATE(pvArg) = va_arg(*marker, DATE);
|
|
break;
|
|
|
|
case L't':
|
|
V_VT(pvArg) = VT_DATE;
|
|
hr = ConvertTimeTToVariantTime(va_arg(*marker, time_t), &V_DATE(pvArg));
|
|
break;
|
|
|
|
case L'W':
|
|
V_VT(pvArg) = VT_DATE;
|
|
hr = ConvertSystemTimeToVariantTime(va_arg(*marker, SYSTEMTIME *), &V_DATE(pvArg));
|
|
break;
|
|
|
|
case L'f':
|
|
V_VT(pvArg) = VT_DATE;
|
|
hr = ConvertFileTimeToVariantTime(va_arg(*marker, FILETIME *), &V_DATE(pvArg));
|
|
break;
|
|
|
|
case L'p':
|
|
#ifndef _WIN64
|
|
V_VT(pvArg) = VT_I4;
|
|
V_I4(pvArg) = (LONG) va_arg(*marker, LPVOID);
|
|
#else
|
|
V_VT(pvArg) = VT_I8;
|
|
V_I8(pvArg) = (LONGLONG) va_arg(*marker, LPVOID);
|
|
#endif
|
|
break;
|
|
|
|
default:
|
|
hr = E_INVALIDARG;
|
|
DEBUG_NOTIFY_INVALID_IDENTIFIER(chIdentifier);
|
|
break;
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
/* ----- dh_enum.c ----- */
|
|
|
|
HRESULT dhEnumBeginV(IEnumVARIANT ** ppEnum, IDispatch * pDisp, LPCOLESTR szMember, va_list * marker)
|
|
{
|
|
DISPPARAMS dp = { 0 };
|
|
EXCEPINFO excep = { 0 };
|
|
VARIANT vtResult;
|
|
IDispatch * pDispObj;
|
|
HRESULT hr;
|
|
|
|
DH_ENTER(L"EnumBeginV");
|
|
|
|
if (!ppEnum || !pDisp) return DH_EXIT(E_INVALIDARG, szMember);
|
|
|
|
if (szMember != NULL)
|
|
{
|
|
hr = dhGetValueV(L"%o", &pDispObj, pDisp, szMember, marker);
|
|
if (FAILED(hr)) return DH_EXIT(hr, szMember);
|
|
}
|
|
else
|
|
{
|
|
pDispObj = pDisp;
|
|
}
|
|
|
|
hr = pDispObj->lpVtbl->Invoke(pDispObj, DISPID_NEWENUM, &IID_NULL, LOCALE_USER_DEFAULT,
|
|
DISPATCH_METHOD | DISPATCH_PROPERTYGET, &dp, &vtResult, &excep, NULL);
|
|
|
|
if (szMember != NULL) pDispObj->lpVtbl->Release(pDispObj);
|
|
|
|
if (FAILED(hr)) return DH_EXITEX(hr, TRUE, L"_NewEnum", szMember, &excep, 0);
|
|
|
|
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);
|
|
else
|
|
hr = E_NOINTERFACE;
|
|
|
|
VariantClear(&vtResult);
|
|
|
|
return DH_EXIT(hr, szMember);
|
|
}
|
|
|
|
HRESULT dhEnumNextVariant(IEnumVARIANT * pEnum, VARIANT * pvResult)
|
|
{
|
|
DH_ENTER(L"EnumNextVariant");
|
|
|
|
if (!pEnum || !pvResult) return DH_EXIT(E_INVALIDARG, L"Enumerator");
|
|
|
|
return DH_EXIT(pEnum->lpVtbl->Next(pEnum, 1, pvResult, NULL), L"Enumerator");
|
|
}
|
|
|
|
HRESULT dhEnumNextObject(IEnumVARIANT * pEnum, IDispatch ** ppDisp)
|
|
{
|
|
VARIANT vtResult;
|
|
HRESULT hr;
|
|
|
|
DH_ENTER(L"EnumNextObject");
|
|
|
|
if (!pEnum || !ppDisp) return DH_EXIT(E_INVALIDARG, L"Enumerator");
|
|
|
|
hr = pEnum->lpVtbl->Next(pEnum, 1, &vtResult, NULL);
|
|
|
|
if (hr == S_OK)
|
|
{
|
|
if (vtResult.vt == VT_DISPATCH)
|
|
{
|
|
*ppDisp = vtResult.pdispVal;
|
|
}
|
|
else
|
|
{
|
|
hr = VariantChangeType(&vtResult, &vtResult, 0, VT_DISPATCH);
|
|
if (SUCCEEDED(hr)) *ppDisp = vtResult.pdispVal;
|
|
else VariantClear(&vtResult);
|
|
}
|
|
}
|
|
|
|
return DH_EXIT(hr, L"Enumerator");
|
|
}
|
|
|
|
HRESULT dhEnumBegin(IEnumVARIANT ** ppEnum, IDispatch * pDisp, LPCOLESTR szMember, ...)
|
|
{
|
|
HRESULT hr;
|
|
va_list marker;
|
|
|
|
DH_ENTER(L"EnumBegin");
|
|
|
|
va_start(marker, szMember);
|
|
|
|
hr = dhEnumBeginV(ppEnum, pDisp, szMember, &marker);
|
|
|
|
va_end(marker);
|
|
|
|
return DH_EXIT(hr, szMember);
|
|
}
|
|
|
|
/* ----- convert.c ----- */
|
|
|
|
static const LONGLONG FILE_TIME_ONE_DAY = 864000000000ULL;
|
|
|
|
static const LONGLONG FILE_TIME_VARIANT_DAY0 = 94353120000000000ULL;
|
|
|
|
static const ULONGLONG FILE_TIME_VARIANT_OVERFLOW = 2650467744000000000ULL;
|
|
|
|
static const DATE VARIANT_FILE_TIME_DAY0 = -109205;
|
|
|
|
static const DATE VARIANT_TIMET_DAY0 = 25569;
|
|
|
|
static const LONG TIMET_ONE_DAY = 86400;
|
|
|
|
#ifndef _WIN64
|
|
static const DATE VARIANT_TIMET_MAX = 50424.13480;
|
|
#else
|
|
static const time_t TIMET_VARIANT_OVERFLOW = 253402300800;
|
|
#endif
|
|
|
|
HRESULT ConvertFileTimeToVariantTime(FILETIME * pft, DATE * pDate)
|
|
{
|
|
ULONGLONG ftScalar;
|
|
|
|
if (!pft || !pDate) return E_INVALIDARG;
|
|
|
|
ftScalar = *((ULONGLONG *) pft) + 500;
|
|
|
|
if (ftScalar >= FILE_TIME_VARIANT_OVERFLOW) return E_INVALIDARG;
|
|
*pDate = (LONGLONG) (ftScalar - FILE_TIME_VARIANT_DAY0) / (double) FILE_TIME_ONE_DAY;
|
|
if (*pDate < 0) *pDate = floor(*pDate) + (floor(*pDate) - *pDate);
|
|
|
|
return NOERROR;
|
|
}
|
|
|
|
HRESULT ConvertVariantTimeToFileTime(DATE date, FILETIME * pft)
|
|
{
|
|
ULONGLONG ftScalar;
|
|
|
|
if (!pft) return E_INVALIDARG;
|
|
|
|
if (date < 0) date = ceil(date) + (ceil(date) - date);
|
|
|
|
if (date < VARIANT_FILE_TIME_DAY0) return E_INVALIDARG;
|
|
ftScalar = (ULONGLONG) ((date * FILE_TIME_ONE_DAY) + FILE_TIME_VARIANT_DAY0);
|
|
|
|
*pft = *((FILETIME *) &ftScalar);
|
|
|
|
return NOERROR;
|
|
}
|
|
|
|
HRESULT ConvertVariantTimeToSystemTime(DATE date, SYSTEMTIME * pSystemTime)
|
|
{
|
|
HRESULT hr;
|
|
FILETIME fileTime;
|
|
|
|
if (!pSystemTime) return E_INVALIDARG;
|
|
if (FAILED(hr = ConvertVariantTimeToFileTime(date, &fileTime))) return hr;
|
|
return (FileTimeToSystemTime(&fileTime, pSystemTime) ? NOERROR : HRESULT_FROM_WIN32( GetLastError() ));
|
|
}
|
|
|
|
HRESULT ConvertSystemTimeToVariantTime(SYSTEMTIME * pSystemTime, DATE * pDate)
|
|
{
|
|
FILETIME fileTime;
|
|
|
|
if (!pSystemTime || !pDate) return E_INVALIDARG;
|
|
if (!SystemTimeToFileTime(pSystemTime, &fileTime)) return HRESULT_FROM_WIN32( GetLastError() );
|
|
return ConvertFileTimeToVariantTime(&fileTime, pDate);
|
|
}
|
|
|
|
HRESULT ConvertVariantTimeToTimeT(DATE date, time_t * pTimeT)
|
|
{
|
|
struct tm * ptm;
|
|
|
|
if (!pTimeT) return E_INVALIDARG;
|
|
|
|
#ifndef _WIN64
|
|
if (date < VARIANT_TIMET_DAY0 || date > VARIANT_TIMET_MAX) return E_INVALIDARG;
|
|
#else
|
|
if (date < VARIANT_TIMET_DAY0) return E_INVALIDARG;
|
|
#endif
|
|
|
|
*pTimeT = (time_t) (((date - VARIANT_TIMET_DAY0) * TIMET_ONE_DAY) + 0.5);
|
|
|
|
if ( (ptm = gmtime(pTimeT)) == NULL || !(ptm->tm_isdst = -1) ||
|
|
(*pTimeT = mktime(ptm)) == (time_t) -1 ) return E_FAIL;
|
|
|
|
return NOERROR;
|
|
}
|
|
|
|
HRESULT ConvertTimeTToVariantTime(time_t timeT, DATE * pDate)
|
|
{
|
|
struct tm localtm, utctm, * ptm;
|
|
time_t timeTLocal, timeTUtc;
|
|
|
|
if (!pDate) return E_INVALIDARG;
|
|
|
|
if ( (ptm = localtime(&timeT)) == NULL) return E_FAIL;
|
|
localtm = *ptm;
|
|
|
|
if ( (ptm = gmtime(&timeT)) == NULL) return E_FAIL;
|
|
utctm = *ptm;
|
|
|
|
localtm.tm_isdst = 0;
|
|
utctm.tm_isdst = 0;
|
|
|
|
if ( (timeTLocal = mktime(&localtm)) == (time_t) -1 ||
|
|
(timeTUtc = mktime(&utctm)) == (time_t) -1) return E_FAIL;
|
|
|
|
timeT += timeTLocal - timeTUtc;
|
|
|
|
#ifdef _WIN64
|
|
if (timeT >= TIMET_VARIANT_OVERFLOW) return E_INVALIDARG;
|
|
#endif
|
|
*pDate = (DATE) (timeT / (double) TIMET_ONE_DAY) + VARIANT_TIMET_DAY0;
|
|
|
|
return NOERROR;
|
|
}
|
|
|
|
HRESULT ConvertAnsiStrToBStr(LPCSTR szAnsiIn, BSTR * lpBstrOut)
|
|
{
|
|
DWORD dwSize;
|
|
|
|
if (lpBstrOut == NULL) return E_INVALIDARG;
|
|
if (szAnsiIn == NULL) { *lpBstrOut = NULL; return NOERROR; }
|
|
|
|
dwSize = MultiByteToWideChar(CP_ACP, 0, szAnsiIn, -1, NULL, 0);
|
|
if (dwSize == 0) return HRESULT_FROM_WIN32( GetLastError() );
|
|
|
|
*lpBstrOut = SysAllocStringLen(NULL, dwSize - 1);
|
|
if (*lpBstrOut == NULL) return E_OUTOFMEMORY;
|
|
|
|
if ( !MultiByteToWideChar(CP_ACP, 0, szAnsiIn, -1, *lpBstrOut, dwSize) )
|
|
{
|
|
SysFreeString(*lpBstrOut);
|
|
return HRESULT_FROM_WIN32( GetLastError() );
|
|
}
|
|
|
|
return NOERROR;
|
|
}
|
|
|
|
HRESULT ConvertBStrToAnsiStr(BSTR bstrIn, LPSTR * lpszOut)
|
|
{
|
|
DWORD dwSize;
|
|
|
|
if (lpszOut == NULL) return E_INVALIDARG;
|
|
if (bstrIn == NULL) { *lpszOut = NULL; return NOERROR; }
|
|
|
|
dwSize = WideCharToMultiByte(CP_ACP, 0, bstrIn, -1, NULL, 0, NULL, NULL);
|
|
if (dwSize == 0) return HRESULT_FROM_WIN32( GetLastError() );
|
|
|
|
*lpszOut = (LPSTR) SysAllocStringByteLen(NULL, dwSize - 1);
|
|
if (*lpszOut == NULL) return E_OUTOFMEMORY;
|
|
|
|
if ( !WideCharToMultiByte(CP_ACP, 0, bstrIn, -1, *lpszOut, dwSize, NULL, NULL) )
|
|
{
|
|
SysFreeString((BSTR) *lpszOut);
|
|
return HRESULT_FROM_WIN32( GetLastError() );
|
|
}
|
|
|
|
return NOERROR;
|
|
}
|
|
|
|
/* ----- dh_exceptions.c ----- */
|
|
|
|
#ifndef DISPHELPER_NO_EXCEPTIONS
|
|
|
|
static DH_EXCEPTION_OPTIONS g_ExceptionOptions;
|
|
|
|
static LONG f_lngTlsInitBegin = -1, f_lngTlsInitEnd = -1;
|
|
static DWORD f_TlsIdxStackCount, f_TlsIdxException;
|
|
|
|
#define SetStackCount(nStackCount) TlsSetValue(f_TlsIdxStackCount, (LPVOID) (nStackCount))
|
|
#define SetExceptionPtr(pException) TlsSetValue(f_TlsIdxException, pException);
|
|
#define GetStackCount() (UINT) TlsGetValue(f_TlsIdxStackCount)
|
|
#define GetExceptionPtr() TlsGetValue(f_TlsIdxException)
|
|
#define CheckTlsInitialized() if (f_lngTlsInitEnd != 0) InitializeTlsIndexes();
|
|
|
|
static void hlprStringCchCopyW(LPWSTR pszDest, SIZE_T cchDest, LPCWSTR pszSrc)
|
|
{
|
|
assert(cchDest > 0);
|
|
|
|
do
|
|
{
|
|
if (--cchDest == 0) break;
|
|
}
|
|
while ((*pszDest++ = *pszSrc++));
|
|
|
|
*pszDest = L'\0';
|
|
}
|
|
|
|
static void InitializeTlsIndexes(void)
|
|
{
|
|
if (0 == InterlockedIncrement(&f_lngTlsInitBegin))
|
|
{
|
|
f_TlsIdxStackCount = TlsAlloc();
|
|
f_TlsIdxException = TlsAlloc();
|
|
f_lngTlsInitEnd = 0;
|
|
}
|
|
else
|
|
{
|
|
while (f_lngTlsInitEnd != 0) Sleep(5);
|
|
}
|
|
}
|
|
|
|
void dhEnter(void)
|
|
{
|
|
CheckTlsInitialized();
|
|
SetStackCount(GetStackCount() + 1);
|
|
}
|
|
|
|
HRESULT dhExitEx(HRESULT hr, BOOL bDispatchError, LPCWSTR szMember, LPCWSTR szCompleteMember,
|
|
EXCEPINFO * pExcepInfo, UINT iArgError, LPCWSTR szFunctionName)
|
|
{
|
|
UINT nStackCount = GetStackCount();
|
|
|
|
SetStackCount(nStackCount - 1);
|
|
|
|
if (FAILED(hr) && !g_ExceptionOptions.bDisableRecordExceptions)
|
|
{
|
|
PDH_EXCEPTION pException = GetExceptionPtr();
|
|
|
|
if (!pException)
|
|
{
|
|
pException = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(DH_EXCEPTION));
|
|
if (!pException) return hr;
|
|
SetExceptionPtr(pException);
|
|
}
|
|
else if (pException->bOld)
|
|
{
|
|
SysFreeString(pException->szDescription);
|
|
SysFreeString(pException->szSource);
|
|
SysFreeString(pException->szHelpFile);
|
|
ZeroMemory(pException, sizeof(DH_EXCEPTION));
|
|
}
|
|
|
|
if (pException->hr == 0)
|
|
{
|
|
pException->hr = hr;
|
|
pException->iArgError = iArgError;
|
|
pException->szErrorFunction = szFunctionName;
|
|
pException->bDispatchError = bDispatchError;
|
|
|
|
if (szMember) hlprStringCchCopyW(pException->szMember, ARRAYSIZE(pException->szMember), szMember);
|
|
|
|
if (pExcepInfo && hr == DISP_E_EXCEPTION)
|
|
{
|
|
if (pExcepInfo->pfnDeferredFillIn &&
|
|
!IsBadCodePtr((FARPROC) pExcepInfo->pfnDeferredFillIn)) pExcepInfo->pfnDeferredFillIn(pExcepInfo);
|
|
|
|
pException->szDescription = pExcepInfo->bstrDescription;
|
|
pException->szSource = pExcepInfo->bstrSource;
|
|
pException->szHelpFile = pExcepInfo->bstrHelpFile;
|
|
pException->dwHelpContext = pExcepInfo->dwHelpContext;
|
|
pException->swCode = (pExcepInfo->wCode ? pExcepInfo->wCode : pExcepInfo->scode);
|
|
}
|
|
}
|
|
|
|
if (nStackCount == 1)
|
|
{
|
|
pException->bOld = TRUE;
|
|
pException->szInitialFunction = szFunctionName;
|
|
|
|
if (szCompleteMember) hlprStringCchCopyW(pException->szCompleteMember, ARRAYSIZE(pException->szCompleteMember), szCompleteMember);
|
|
|
|
if (g_ExceptionOptions.bShowExceptions)
|
|
dhShowException(pException);
|
|
|
|
if (g_ExceptionOptions.pfnExceptionCallback)
|
|
g_ExceptionOptions.pfnExceptionCallback(pException);
|
|
}
|
|
}
|
|
else if (hr == DISP_E_EXCEPTION && pExcepInfo)
|
|
{
|
|
SysFreeString(pExcepInfo->bstrDescription);
|
|
SysFreeString(pExcepInfo->bstrSource);
|
|
SysFreeString(pExcepInfo->bstrHelpFile);
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
HRESULT dhShowException(PDH_EXCEPTION pException)
|
|
{
|
|
WCHAR szMessage[512];
|
|
|
|
dhFormatExceptionW(pException, szMessage, ARRAYSIZE(szMessage), FALSE);
|
|
|
|
MessageBoxW(g_ExceptionOptions.hwnd, szMessage, g_ExceptionOptions.szAppName,
|
|
MB_ICONSTOP | MB_SETFOREGROUND);
|
|
|
|
return NOERROR;
|
|
}
|
|
|
|
HRESULT dhFormatExceptionW(PDH_EXCEPTION pException, LPWSTR szBuffer, UINT cchBufferSize, BOOL bFixedFont)
|
|
{
|
|
HRESULT hr;
|
|
UINT cch = 0;
|
|
# define DESCRIPTION_LENGTH 255
|
|
|
|
if (!szBuffer && cchBufferSize) return E_INVALIDARG;
|
|
|
|
if (!pException)
|
|
{
|
|
dhGetLastException(&pException);
|
|
if (!pException)
|
|
{
|
|
if (cchBufferSize != 0)
|
|
{
|
|
_snwprintf(szBuffer, cchBufferSize, L"No error information available.");
|
|
szBuffer[cchBufferSize - 1] = L'\0';
|
|
}
|
|
|
|
return NOERROR;
|
|
}
|
|
}
|
|
|
|
hr = (pException->hr == DISP_E_EXCEPTION && pException->swCode ?
|
|
pException->swCode : pException->hr);
|
|
|
|
if (!pException->szSource)
|
|
{
|
|
if (pException->bDispatchError)
|
|
pException->szSource = SysAllocString(L"IDispatch Interface");
|
|
else
|
|
pException->szSource = SysAllocString(L"Application");
|
|
}
|
|
|
|
if (!pException->szDescription)
|
|
{
|
|
pException->szDescription = SysAllocStringLen(NULL, DESCRIPTION_LENGTH);
|
|
|
|
if (pException->szDescription)
|
|
{
|
|
switch (hr)
|
|
{
|
|
case E_NOINTERFACE:
|
|
_snwprintf(pException->szDescription, DESCRIPTION_LENGTH, L"Object required");
|
|
break;
|
|
|
|
case DISP_E_UNKNOWNNAME:
|
|
case DISP_E_MEMBERNOTFOUND:
|
|
_snwprintf(pException->szDescription, DESCRIPTION_LENGTH, L"Object doesn't support this property or method: '%s'", pException->szMember);
|
|
break;
|
|
|
|
case DISP_E_TYPEMISMATCH:
|
|
if (pException->szMember[0])
|
|
{
|
|
_snwprintf(pException->szDescription, DESCRIPTION_LENGTH, L"Type mismatch: '%s'. Argument Index: %d", pException->szMember, pException->iArgError);
|
|
break;
|
|
}
|
|
|
|
default:
|
|
{
|
|
#ifndef UNICODE
|
|
CHAR szDescription[DESCRIPTION_LENGTH];
|
|
#else
|
|
LPWSTR szDescription = pException->szDescription;
|
|
#endif
|
|
cch = FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
|
|
NULL, hr, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
|
|
szDescription, DESCRIPTION_LENGTH, NULL);
|
|
|
|
if (!cch) wcscpy(pException->szDescription, L"Unknown runtime error");
|
|
#ifndef UNICODE
|
|
else MultiByteToWideChar(CP_ACP, 0, szDescription, -1, pException->szDescription, DESCRIPTION_LENGTH);
|
|
#endif
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if (pException->szDescription)
|
|
{
|
|
|
|
if (!cch) cch = wcslen(pException->szDescription);
|
|
|
|
if (cch >= 2 && pException->szDescription[cch - 2] == L'\r')
|
|
pException->szDescription[cch - 2] = L'\0';
|
|
else if (cch >= 1 && pException->szDescription[cch - 1] == L'\n')
|
|
pException->szDescription[cch - 1] = L'\0';
|
|
}
|
|
|
|
if (cchBufferSize)
|
|
{
|
|
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",
|
|
pException->szCompleteMember,
|
|
pException->szInitialFunction, pException->szErrorFunction,
|
|
pException->szDescription, hr,
|
|
pException->szSource);
|
|
}
|
|
else
|
|
{
|
|
_snwprintf(szBuffer, cchBufferSize, L"Member: %s\r\nFunction: %s\r\nError In: %s\r\nError: %s\r\nCode: %x\r\nSource: %s",
|
|
pException->szCompleteMember,
|
|
pException->szInitialFunction, pException->szErrorFunction,
|
|
pException->szDescription, hr,
|
|
pException->szSource);
|
|
}
|
|
|
|
szBuffer[cchBufferSize - 1] = L'\0';
|
|
}
|
|
|
|
return NOERROR;
|
|
}
|
|
|
|
HRESULT dhFormatExceptionA(PDH_EXCEPTION pException, LPSTR szBuffer, UINT cchBufferSize, BOOL bFixedFont)
|
|
{
|
|
WCHAR szBufferW[1024];
|
|
|
|
dhFormatExceptionW(pException, szBufferW, ARRAYSIZE(szBufferW), bFixedFont);
|
|
|
|
if (0 == WideCharToMultiByte(CP_ACP, 0, szBufferW, -1, szBuffer, cchBufferSize, NULL, NULL))
|
|
return HRESULT_FROM_WIN32( GetLastError() );
|
|
|
|
return NOERROR;
|
|
}
|
|
|
|
HRESULT dhGetLastException(PDH_EXCEPTION * ppException)
|
|
{
|
|
if (!ppException) return E_INVALIDARG;
|
|
|
|
CheckTlsInitialized();
|
|
*ppException = GetExceptionPtr();
|
|
|
|
return NOERROR;
|
|
}
|
|
|
|
HRESULT dhToggleExceptions(BOOL bShow)
|
|
{
|
|
g_ExceptionOptions.bShowExceptions = bShow;
|
|
if (bShow) g_ExceptionOptions.bDisableRecordExceptions = FALSE;
|
|
|
|
return NOERROR;
|
|
}
|
|
|
|
HRESULT dhSetExceptionOptions(PDH_EXCEPTION_OPTIONS pExceptionOptions)
|
|
{
|
|
if (!pExceptionOptions) return E_INVALIDARG;
|
|
|
|
g_ExceptionOptions.hwnd = pExceptionOptions->hwnd;
|
|
g_ExceptionOptions.szAppName = pExceptionOptions->szAppName;
|
|
g_ExceptionOptions.bShowExceptions = pExceptionOptions->bShowExceptions;
|
|
g_ExceptionOptions.bDisableRecordExceptions = pExceptionOptions->bDisableRecordExceptions;
|
|
g_ExceptionOptions.pfnExceptionCallback = pExceptionOptions->pfnExceptionCallback;
|
|
|
|
return NOERROR;
|
|
}
|
|
|
|
HRESULT dhGetExceptionOptions(PDH_EXCEPTION_OPTIONS pExceptionOptions)
|
|
{
|
|
if (!pExceptionOptions) return E_INVALIDARG;
|
|
|
|
pExceptionOptions->hwnd = g_ExceptionOptions.hwnd;
|
|
pExceptionOptions->szAppName = g_ExceptionOptions.szAppName;
|
|
pExceptionOptions->bShowExceptions = g_ExceptionOptions.bShowExceptions;
|
|
pExceptionOptions->bDisableRecordExceptions = g_ExceptionOptions.bDisableRecordExceptions;
|
|
pExceptionOptions->pfnExceptionCallback = g_ExceptionOptions.pfnExceptionCallback;
|
|
|
|
return NOERROR;
|
|
}
|
|
|
|
void dhCleanupThreadException(void)
|
|
{
|
|
PDH_EXCEPTION pException;
|
|
|
|
CheckTlsInitialized();
|
|
pException = GetExceptionPtr();
|
|
|
|
if (pException)
|
|
{
|
|
SysFreeString(pException->szDescription);
|
|
SysFreeString(pException->szSource);
|
|
SysFreeString(pException->szHelpFile);
|
|
|
|
HeapFree(GetProcessHeap(), 0, pException);
|
|
|
|
SetExceptionPtr(NULL);
|
|
}
|
|
}
|
|
|
|
#endif
|
|
|
|
/* ----- dh_init.c ----- */
|
|
|
|
HRESULT dhInitializeImp(BOOL bInitializeCOM, BOOL bUnicode)
|
|
{
|
|
dh_g_bIsUnicodeMode = bUnicode;
|
|
|
|
if (bInitializeCOM) return CoInitialize(NULL);
|
|
|
|
return NOERROR;
|
|
}
|
|
|
|
void dhUninitialize(BOOL bUninitializeCOM)
|
|
{
|
|
#ifndef DISPHELPER_NO_EXCEPTIONS
|
|
dhCleanupThreadException();
|
|
#endif
|
|
if (bUninitializeCOM) CoUninitialize();
|
|
}
|
|
|