packages feed

hdirect-0.21.0: comlib/AutoPrimSrc.c

/*-----------------------------------------------------------
 (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 <windows.h>
#include <stdio.h>

#if defined(__CYGWIN32__) || defined(__MINGW32__)
#include <w32api.h>
#endif

#ifdef __GNUC__
#include "comPrim.h"
#include "autoPrim.h"
#include "PointerSrc.h"
#include <stdlib.h>
#include <string.h>

/* 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) + 116444736000000000;

  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
  
}