/*----------------------------------------------------------- (c) 1998, Daan Leijen, leijen@@fwi.uva.nl 1999-, Sigbjorn Finne sof@galconn.com Changes: * made cygwin32 (&gcc) friendly. -- sof 10/98 -----------------------------------------------------------*/ #if !defined(__CYGWIN32__) && !defined(__MINGW32__) #define CINTERFACE #define COBJMACROS #endif #include #include #if defined(__CYGWIN32__) || defined(__MINGW32__) #include #endif #ifdef __GNUC__ #include "comPrim.h" #include "autoPrim.h" #include "PointerSrc.h" #include #include /* No support for nameless unions..yet. */ #if __W32API_MAJOR_VERSION == 1 #define cyVal n1.n2.n3.cyVal #define bVal n1.n2.n3.bVal #define punkVal n1.n2.n3.punkVal #define boolVal n1.n2.n3.boolVal #define pdispVal n1.n2.n3.pdispVal #define bstrVal n1.n2.n3.bstrVal #define date n1.n2.n3.date #define dblVal n1.n2.n3.dblVal #define fltVal n1.n2.n3.fltVal #define lVal n1.n2.n3.lVal #define ulVal n1.n2.n3.ulVal #define iVal n1.n2.n3.iVal #define parray n1.n2.n3.parray #define pparray n1.n2.n3.pparray #define decVal n1.decVal #define vt n1.n2.vt #endif #endif /*----------------------------------------------------------- -- Invoke -----------------------------------------------------------*/ HRESULT dispatchInvoke( IDispatch* obj, DISPID dispid, LCID lcid, BOOL isfunction, unsigned flags, int cargs, int cargsout, VARIANT* args, VARIANT* argsout, EXCEPINFO** info ) { HRESULT hr; DISPPARAMS dp; EXCEPINFO excepInfo; UINT argErr; VARIANT varRes; VARIANT* res; DISPID dispput; int i; if (info) *info = NULL; /* create VT_BYREF variants for out parameters */ for (i = 0; i < cargsout; i++) { VariantInit( args+i ); args[i].vt = argsout[i].vt | VT_BYREF; #if !defined(__GNUC__) || __W32API_MAJOR_VERSION > 1 args[i].byref = &(argsout[i].byref); #else args[i].n1.n2.n3.byref = &(argsout[i].n1.n2.n3.byref); #endif } if (!obj) return E_POINTER; dp.cArgs = cargs; dp.rgvarg = args; /* set special flags for property puts */ if (flags & DISPATCH_PROPERTYPUT) { dispput = DISPID_PROPERTYPUT; dp.rgdispidNamedArgs = &dispput; dp.cNamedArgs = 1; } else { dp.rgdispidNamedArgs = NULL; dp.cNamedArgs = 0; } /* if this is surely a function, return the result in the first element of argsout, and decrement the number of arguments */ if (isfunction) { dp.cArgs--; dp.rgvarg++; res = argsout; } else { res = &varRes; VariantInit(res); } hr = IDispatch_Invoke( obj, dispid, &IID_NULL, lcid, flags, &dp, res, &excepInfo, &argErr ); /* if guessed that this was not a function, but it returned a result (in varRes) or it complained about the number of arguments, than we again try to call it but now as a function. */ /* Turned this smart off, leaving it to HDirect (and the user) to make the distinction between memberX and functionX. -- sof No, let's not -- sometimes the type information isn't precise enough about this (e.g., the type info for msi.dll's Installer.OpenDatabase() suggests its a _method_, but it turns out to be a _function_. */ if (!isfunction && flags == DISPATCH_METHOD && (hr == DISP_E_BADPARAMCOUNT || hr == DISP_E_TYPEMISMATCH || res->vt != VT_EMPTY) ) { isfunction = TRUE; dp.cArgs--; dp.rgvarg++; VariantClear(res); res = argsout; hr = IDispatch_Invoke( obj, dispid, &IID_NULL, lcid, flags, &dp, res, &excepInfo, &argErr ); } if (!isfunction) VariantClear( res ); /* free the input arguments */ for (i = cargsout; i < cargs; i++) VariantClear( args+i ); /* check for exceptions */ if (hr == DISP_E_EXCEPTION && info) { *info = (EXCEPINFO*)primAllocMemory( sizeof(EXCEPINFO)); if (*info) { **info = excepInfo; if ((*info)->pfnDeferredFillIn) (*info)->pfnDeferredFillIn( *info ); } } return hr; } void freeExcepInfo( EXCEPINFO* info ) { if (!info) return; if (info->bstrSource) SysFreeString( info->bstrSource ); if (info->bstrDescription) SysFreeString( info->bstrDescription ); if (info->bstrHelpFile) SysFreeString( info->bstrHelpFile ); } char* getExcepInfoMessage( EXCEPINFO* info ) { #define MAXMSG 255 #define MAXSTR 80 char member[MAXSTR+1] = ""; char source[MAXSTR+1] = ""; char wcode[MAXSTR+1] = ""; char description[MAXMSG+1] = "Exception occurred"; char* msg; msg = primAllocMemory( MAXMSG+1 ); if (!msg) return NULL; if (info) { if (info->bstrSource) { char sourceReg[MAXSTR]; wcstombs( sourceReg, info->bstrSource, MAXSTR ); if (ERROR_SUCCESS != RegQueryValueA( HKEY_CLASSES_ROOT, sourceReg, source, NULL )) wcstombs( source, info->bstrSource, MAXSTR ); } if (info->wCode) { sprintf( wcode, "(%d)", info->wCode ); } if (info->bstrDescription) { wcstombs( description, info->bstrDescription, MAXMSG); } else if (info->scode) { strncpy( description, hresultString(info->scode), MAXMSG ); } } if (info && info->bstrSource) #ifdef __GNUC__ sprintf(msg, "%s.%s:%s %s", source, member, wcode, description); #else _snprintf( msg, MAXMSG, "%s.%s:%s %s", source,member,wcode,description); #endif else #ifdef __GNUC__ sprintf(msg, "%s %s", wcode, description); #else _snprintf( msg, MAXMSG, "%s %s", wcode,description); #endif return msg; } HRESULT dispatchGetMemberID( IDispatch* obj, BSTR name, LCID lcid, DISPID* dispid ) { if (obj) return IDispatch_GetIDsOfNames( obj, &IID_NULL, &name, 1, lcid, dispid ); else return E_POINTER; } /*----------------------------------------------------------- -- Variant marshalling (we just lack VT_ARRAY support) -----------------------------------------------------------*/ void freeVariants( int count, VARIANT* p ) { int i; if (!p) return; for (i = 0; i < count; i++) VariantClear(p+i); } int readVariantTag(VARIANT* pw) { return(pw->vt); } #define READWRITEVAR(htp,ctp,tp,fld,def) \ void writeVar##htp( ctp x, VARIANT* v ) \ { \ WRITEVAR(tp,fld); \ } \ HRESULT readVar##htp( VARIANT* v, ctp* p ) \ { \ READVAR(tp,fld,def); \ } #define WRITEVAR(tp,fld) { if (!v) return; \ VariantInit(v); \ v->vt = tp; \ v->fld = x; \ } #define READVAR(tp,fld,def) { if (!p) return E_POINTER; \ if (!v) { *p = def; return E_POINTER;} \ if (v->vt == tp) { \ *p = v->fld; \ return S_OK; \ } else { \ VARIANT w; \ HRESULT hr; \ VariantInit( &w ); \ hr = VariantChangeType( &w, v, 0, tp ); \ if (SUCCEEDED(hr)) *p = w.fld; \ else *p = def; \ return hr; \ } \ } #define READWRITETEMPVAR(htp,ctp,tp,fld,def) \ void writeVar##htp( ctp x, VARIANT* v ) \ { \ WRITEVAR(tp,fld); \ } \ HRESULT readVar##htp( VARIANT* v, ctp* p, VARIANT** w ) \ { \ READTEMPVAR(tp,fld,def); \ } #define READTEMPVAR(tp,fld,def) { if (w) *w = NULL; \ if (!p) return E_POINTER; \ if (!v) { *p = def; return E_POINTER; } \ if (v->vt == tp) { \ *p = v->fld; \ return S_OK; \ } else { \ HRESULT hr; \ *p = def; \ if (!w) return E_POINTER; \ *w = primAllocMemory( sizeof(VARIANT)); \ if (*w == NULL) return E_OUTOFMEMORY; \ VariantInit( *w ); \ hr = VariantChangeType( *w, v, 0, tp ); \ if (SUCCEEDED(hr)) *p = (*w)->fld; \ else { primFreeMemory(*w); *w = NULL; } \ return hr; \ } \ } READWRITEVAR( Short, int, VT_I2, iVal, 0 ) READWRITEVAR( Int, int, VT_I4, lVal, 0 ) READWRITEVAR( Word, unsigned int, VT_UI4, ulVal, 0 ) READWRITEVAR( Float, float, VT_R4, fltVal, 0.0 ) READWRITEVAR( Double, double, VT_R8, dblVal, 0.0 ) READWRITEVAR( Date, double, VT_DATE, date, 0.0 ) READWRITETEMPVAR( String, BSTR, VT_BSTR, bstrVal, NULL ) READWRITETEMPVAR( Dispatch, IDispatch*, VT_DISPATCH, pdispVal, NULL ) READWRITEVAR( Bool, BOOL, VT_BOOL, boolVal, 0 ) READWRITETEMPVAR( Unknown, IUnknown*, VT_UNKNOWN, punkVal, NULL ) READWRITEVAR( Byte, unsigned char, VT_UI1, bVal, 0 ) #if __W32API_MAJOR_VERSION == 1 READWRITEVAR( Error, int, VT_ERROR, n1.n2.n3.scode, 0 ) #else READWRITEVAR( Error, int, VT_ERROR, scode, 0 ) #endif void writeVarOptional( VARIANT * v ) { if (!v) return; VariantInit ( v ); v->vt = VT_ERROR; #if __W32API_MAJOR_VERSION == 1 v->n1.n2.n3.scode = DISP_E_PARAMNOTFOUND; #else v->scode = DISP_E_PARAMNOTFOUND; #endif } /* ToDo: readVarOptional */ void writeVarSAFEARRAY( VARIANT* v, SAFEARRAY* sa, VARTYPE ovt ) { if (!v) return; VariantInit(v); v->vt = VT_ARRAY | ovt; v->parray = sa; } HRESULT readVarSAFEARRAY( VARIANT* v, SAFEARRAY** sa, VARTYPE ovt) { if (!v) return E_POINTER; if (v->vt & VT_ARRAY || v->vt == VT_SAFEARRAY) { /* Will return same pointer, but let's follow the rules. */ if (v->vt & VT_BYREF) { *sa = *(v->pparray); } else { *sa = v->parray; } return S_OK; } else { VARIANT w; HRESULT hr; VariantInit(&w); hr = VariantChangeType( &w, v, 0, VT_ARRAY | ovt); if (SUCCEEDED(hr)) { *sa = w.parray; } else { *sa = NULL; } return hr; } } /* VT_EMPTY, VT_NULL, VT_CY, VT_VARIANT */ void writeVarEmpty( VARIANT* v ) { if (!v) return; VariantInit( v ); v->vt = VT_EMPTY; } /* readEmpty; succeeds always */ void writeVarNull( VARIANT* v ) { if (!v) return; VariantInit( v ); v->vt = VT_NULL; } HRESULT readVarNull( VARIANT* v ) { if (!v) return E_POINTER; if (v->vt == VT_NULL) return S_OK; else { VARIANT w; VariantInit( &w ); return VariantChangeType( &w, v, 0, VT_NULL ); } } void writeVarCurrency( int hi, unsigned int lo, VARIANT* v ) { if (!v) return; VariantInit(v); v->vt = VT_CY; v->cyVal.Hi = hi; v->cyVal.Lo = lo; } HRESULT readVarCurrency( VARIANT* v, int* hi, int* lo ) { if (!v) return E_POINTER; if (!hi) return E_POINTER; if (!lo) return E_POINTER; if (v->vt == VT_CY) { *hi = v->cyVal.Hi; *lo = v->cyVal.Lo; return S_OK; } else { VARIANT w; HRESULT hr; VariantInit(&w); hr = VariantChangeType( &w, v, 0, VT_CY); if (SUCCEEDED(hr)) { *hi = w.cyVal.Hi; *lo = w.cyVal.Lo; } else { *hi = *lo = 0; } return hr; } } void writeVarWord64( unsigned int hi, unsigned int lo, VARIANT* v ) { ULONGLONG r; r = (ULONGLONG)hi; r >>= 32; r += (ULONGLONG)lo; if (!v) return; VariantInit(v); v->vt = VT_DECIMAL; v->decVal.Lo64 = r; v->decVal.Hi32 = 0; v->decVal.sign = 0; v->decVal.scale = 0; } HRESULT readVarWord64( VARIANT* v, unsigned int* hi, unsigned int* lo ) { ULONGLONG r; if (!v) return E_POINTER; if (!hi) return E_POINTER; if (!lo) return E_POINTER; if (v->vt == VT_DECIMAL) { r = v->decVal.Lo64; *lo = (unsigned long)r; r <<= 32; *hi = (unsigned long)r; return S_OK; } else { VARIANT w; HRESULT hr; VariantInit(&w); hr = VariantChangeType( &w, v, 0, VT_DECIMAL); if (SUCCEEDED(hr)) { r = v->decVal.Lo64; *lo = (unsigned long)r; r <<= 32; *hi = (unsigned long)r; } else { *hi = *lo = 0; } return hr; } } void writeVarVariant( VARIANT* x, VARIANT* v) { if (!v) return; if (!x) return; VariantInit(v); VariantCopy( v, x ); } HRESULT readVarVariant( VARIANT* v, VARIANT* x ) { if (!v) return E_POINTER; if (!x) return E_POINTER; VariantInit(x); return VariantCopy( x, v ); } /* First VARIANT* is uninitialised chunk of memory. Initialise and copy the second one into it. */ HRESULT primCopyVARIANT ( VARIANT* p1 , VARIANT* p2 ) { VariantInit(p1); return (VariantCopy(p1,p2)); } HRESULT primVARIANTClear ( VARIANT* p1 ) { return VariantClear(p1); } /* * Converting a time_t to date/time representation used by * Automation. */ HRESULT primClockToDate (int t, double *pt) { FILETIME ft; SYSTEMTIME st; LONGLONG l = Int32x32To64(t, 10000000) + 116444736000000000ULL; ft.dwLowDateTime = (DWORD) l; ft.dwHighDateTime = l >>32; if (!FileTimeToSystemTime(&ft,&st)) { return E_FAIL; } #if ( (!defined(__MINGW32__) && !defined(__CYGWIN__)) || \ (__W32API_MAJOR_VERSION >= 1 && \ (__W32API_MAJOR_VERSION > 1 || __W32API_MINOR_VERSION >= 1)) ) /* If on a non-gnuwin platform or on one with a w32api version that's 1.1 or greater. */ if (!SystemTimeToVariantTime(&st, pt)) { return E_FAIL; } return S_OK; #else /* SystemTimeToVariantTime() isn't provided in the oleaut32 import library until w32api 1.1 (or thereabouts, haven't exactly pinpointed when this bug fixed). */ return E_FAIL; #endif }