home *** CD-ROM | disk | FTP | other *** search
/ Tricks of the Windows Gam…ming Gurus (2nd Edition) / Disc2.iso / vc98 / mfc / src / oledisp2.cpp < prev    next >
C/C++ Source or Header  |  1998-06-16  |  13KB  |  520 lines

  1. // This is a part of the Microsoft Foundation Classes C++ library.
  2. // Copyright (C) 1992-1998 Microsoft Corporation
  3. // All rights reserved.
  4. //
  5. // This source code is only intended as a supplement to the
  6. // Microsoft Foundation Classes Reference and related
  7. // electronic documentation provided with the library.
  8. // See these sources for detailed information regarding the
  9. // Microsoft Foundation Classes product.
  10.  
  11. #include "stdafx.h"
  12. #include <stdarg.h>
  13.  
  14. #ifdef AFX_OLE5_SEG
  15. #pragma code_seg(AFX_OLE5_SEG)
  16. #endif
  17.  
  18. #ifdef _DEBUG
  19. #undef THIS_FILE
  20. static char THIS_FILE[] = __FILE__;
  21. #endif
  22.  
  23. #define new DEBUG_NEW
  24.  
  25. /////////////////////////////////////////////////////////////////////////////
  26. // COleDispatchDriver constructors/destructors
  27.  
  28. HRESULT AFXAPI AfxGetClassIDFromString(LPCTSTR lpsz, LPCLSID lpClsID)
  29. {
  30.     USES_CONVERSION;
  31.  
  32.     HRESULT hr;
  33.     if (lpsz[0] == '{')
  34.         hr = CLSIDFromString((LPOLESTR)T2COLE(lpsz), lpClsID);
  35.     else
  36.         hr = CLSIDFromProgID(T2COLE(lpsz), lpClsID);
  37.     return hr;
  38. }
  39.  
  40. COleDispatchDriver::COleDispatchDriver()
  41. {
  42.     m_lpDispatch = NULL;
  43.     m_bAutoRelease = TRUE;
  44. }
  45.  
  46. COleDispatchDriver::COleDispatchDriver(LPDISPATCH lpDispatch, BOOL bAutoRelease)
  47. {
  48.     m_lpDispatch = lpDispatch;
  49.     m_bAutoRelease = bAutoRelease;
  50. }
  51.  
  52. COleDispatchDriver::COleDispatchDriver(const COleDispatchDriver& dispatchSrc)
  53. {
  54.     ASSERT(this != &dispatchSrc);   // constructing from self?
  55.  
  56.     m_lpDispatch = dispatchSrc.m_lpDispatch;
  57.     if (m_lpDispatch != NULL)
  58.         m_lpDispatch->AddRef();
  59.     m_bAutoRelease = TRUE;
  60. }
  61.  
  62. const COleDispatchDriver&
  63. COleDispatchDriver::operator=(const COleDispatchDriver& dispatchSrc)
  64. {
  65.     if (this != &dispatchSrc)
  66.     {
  67.         LPDISPATCH lpTemp = m_lpDispatch;
  68.         m_lpDispatch = dispatchSrc.m_lpDispatch;
  69.         if (m_lpDispatch != NULL)
  70.             m_lpDispatch->AddRef();
  71.         if (lpTemp != NULL && m_bAutoRelease)
  72.             lpTemp->Release();
  73.         m_bAutoRelease = TRUE;
  74.     }
  75.     return *this;
  76. }
  77.  
  78. BOOL COleDispatchDriver::CreateDispatch(REFCLSID clsid, COleException* pError)
  79. {
  80.     ASSERT(m_lpDispatch == NULL);
  81.  
  82.     m_bAutoRelease = TRUE;  // good default is to auto-release
  83.  
  84.     // create an instance of the object
  85.     LPUNKNOWN lpUnknown = NULL;
  86.     SCODE sc = CoCreateInstance(clsid, NULL, CLSCTX_ALL | CLSCTX_REMOTE_SERVER,
  87.         IID_IUnknown, (LPLP)&lpUnknown);
  88.     if (sc == E_INVALIDARG)
  89.     {
  90.         // may not support CLSCTX_REMOTE_SERVER, so try without
  91.         sc = CoCreateInstance(clsid, NULL, CLSCTX_ALL & ~CLSCTX_REMOTE_SERVER,
  92.             IID_IUnknown, (LPLP)&lpUnknown);
  93.     }
  94.     if (FAILED(sc))
  95.         goto Failed;
  96.  
  97.     // make sure it is running
  98.     sc = OleRun(lpUnknown);
  99.     if (FAILED(sc))
  100.         goto Failed;
  101.  
  102.     // query for IDispatch interface
  103.     m_lpDispatch = QUERYINTERFACE(lpUnknown, IDispatch);
  104.     if (m_lpDispatch == NULL)
  105.         goto Failed;
  106.  
  107.     lpUnknown->Release();
  108.     ASSERT(m_lpDispatch != NULL);
  109.     return TRUE;
  110.  
  111. Failed:
  112.     RELEASE(lpUnknown);
  113.     if (pError != NULL)
  114.         pError->m_sc = sc;
  115.     TRACE1("Warning: CreateDispatch returning scode = %s.\n",
  116.         AfxGetFullScodeString(sc));
  117.     return FALSE;
  118. }
  119.  
  120. BOOL COleDispatchDriver::CreateDispatch(LPCTSTR lpszProgID,
  121.     COleException* pError)
  122. {
  123.     ASSERT(m_lpDispatch == NULL);
  124.  
  125.     // map prog id to CLSID
  126.     CLSID clsid;
  127.     SCODE sc = AfxGetClassIDFromString(lpszProgID, &clsid);
  128.     if (FAILED(sc))
  129.     {
  130.         if (pError != NULL)
  131.             pError->m_sc = sc;
  132.         return FALSE;
  133.     }
  134.  
  135.     // create with CLSID
  136.     return CreateDispatch(clsid, pError);
  137. }
  138.  
  139. void COleDispatchDriver::AttachDispatch(LPDISPATCH lpDispatch,
  140.     BOOL bAutoRelease)
  141. {
  142.     ASSERT(lpDispatch != NULL);
  143.  
  144.     ReleaseDispatch();  // detach previous
  145.     m_lpDispatch = lpDispatch;
  146.     m_bAutoRelease = bAutoRelease;
  147. }
  148.  
  149. void COleDispatchDriver::ReleaseDispatch()
  150. {
  151.     if (m_lpDispatch != NULL)
  152.     {
  153.         if (m_bAutoRelease)
  154.             m_lpDispatch->Release();
  155.         m_lpDispatch = NULL;
  156.     }
  157. }
  158.  
  159. LPDISPATCH COleDispatchDriver::DetachDispatch()
  160. {
  161.     LPDISPATCH lpDispatch = m_lpDispatch;
  162.     m_lpDispatch = NULL;    // detach without Release
  163.     return lpDispatch;
  164. }
  165.  
  166. /////////////////////////////////////////////////////////////////////////////
  167. // COleDispatchDriver implementation
  168.  
  169. void COleDispatchDriver::InvokeHelperV(DISPID dwDispID, WORD wFlags,
  170.     VARTYPE vtRet, void* pvRet, const BYTE* pbParamInfo, va_list argList)
  171. {
  172.     USES_CONVERSION;
  173.  
  174.     if (m_lpDispatch == NULL)
  175.     {
  176.         TRACE0("Warning: attempt to call Invoke with NULL m_lpDispatch!\n");
  177.         return;
  178.     }
  179.  
  180.     DISPPARAMS dispparams;
  181.     memset(&dispparams, 0, sizeof dispparams);
  182.  
  183.     // determine number of arguments
  184.     if (pbParamInfo != NULL)
  185.         dispparams.cArgs = lstrlenA((LPCSTR)pbParamInfo);
  186.  
  187.     DISPID dispidNamed = DISPID_PROPERTYPUT;
  188.     if (wFlags & (DISPATCH_PROPERTYPUT|DISPATCH_PROPERTYPUTREF))
  189.     {
  190.         ASSERT(dispparams.cArgs > 0);
  191.         dispparams.cNamedArgs = 1;
  192.         dispparams.rgdispidNamedArgs = &dispidNamed;
  193.     }
  194.  
  195.     if (dispparams.cArgs != 0)
  196.     {
  197.         // allocate memory for all VARIANT parameters
  198.         VARIANT* pArg = new VARIANT[dispparams.cArgs];
  199.         ASSERT(pArg != NULL);   // should have thrown exception
  200.         dispparams.rgvarg = pArg;
  201.         memset(pArg, 0, sizeof(VARIANT) * dispparams.cArgs);
  202.  
  203.         // get ready to walk vararg list
  204.         const BYTE* pb = pbParamInfo;
  205.         pArg += dispparams.cArgs - 1;   // params go in opposite order
  206.  
  207.         while (*pb != 0)
  208.         {
  209.             ASSERT(pArg >= dispparams.rgvarg);
  210.  
  211.             pArg->vt = *pb; // set the variant type
  212.             if (pArg->vt & VT_MFCBYREF)
  213.             {
  214.                 pArg->vt &= ~VT_MFCBYREF;
  215.                 pArg->vt |= VT_BYREF;
  216.             }
  217.             switch (pArg->vt)
  218.             {
  219.             case VT_UI1:
  220.                 pArg->bVal = va_arg(argList, BYTE);
  221.                 break;
  222.             case VT_I2:
  223.                 pArg->iVal = va_arg(argList, short);
  224.                 break;
  225.             case VT_I4:
  226.                 pArg->lVal = va_arg(argList, long);
  227.                 break;
  228.             case VT_R4:
  229.                 pArg->fltVal = (float)va_arg(argList, double);
  230.                 break;
  231.             case VT_R8:
  232.                 pArg->dblVal = va_arg(argList, double);
  233.                 break;
  234.             case VT_DATE:
  235.                 pArg->date = va_arg(argList, DATE);
  236.                 break;
  237.             case VT_CY:
  238.                 pArg->cyVal = *va_arg(argList, CY*);
  239.                 break;
  240.             case VT_BSTR:
  241.                 {
  242.                     LPCOLESTR lpsz = va_arg(argList, LPOLESTR);
  243.                     pArg->bstrVal = ::SysAllocString(lpsz);
  244.                     if (lpsz != NULL && pArg->bstrVal == NULL)
  245.                         AfxThrowMemoryException();
  246.                 }
  247.                 break;
  248. #if !defined(_UNICODE) && !defined(OLE2ANSI)
  249.             case VT_BSTRA:
  250.                 {
  251.                     LPCSTR lpsz = va_arg(argList, LPSTR);
  252.                     pArg->bstrVal = ::SysAllocString(T2COLE(lpsz));
  253.                     if (lpsz != NULL && pArg->bstrVal == NULL)
  254.                         AfxThrowMemoryException();
  255.                     pArg->vt = VT_BSTR;
  256.                 }
  257.                 break;
  258. #endif
  259.             case VT_DISPATCH:
  260.                 pArg->pdispVal = va_arg(argList, LPDISPATCH);
  261.                 break;
  262.             case VT_ERROR:
  263.                 pArg->scode = va_arg(argList, SCODE);
  264.                 break;
  265.             case VT_BOOL:
  266.                 V_BOOL(pArg) = (VARIANT_BOOL)(va_arg(argList, BOOL) ? -1 : 0);
  267.                 break;
  268.             case VT_VARIANT:
  269.                 *pArg = *va_arg(argList, VARIANT*);
  270.                 break;
  271.             case VT_UNKNOWN:
  272.                 pArg->punkVal = va_arg(argList, LPUNKNOWN);
  273.                 break;
  274.  
  275.             case VT_I2|VT_BYREF:
  276.                 pArg->piVal = va_arg(argList, short*);
  277.                 break;
  278.             case VT_UI1|VT_BYREF:
  279.                 pArg->pbVal = va_arg(argList, BYTE*);
  280.                 break;
  281.             case VT_I4|VT_BYREF:
  282.                 pArg->plVal = va_arg(argList, long*);
  283.                 break;
  284.             case VT_R4|VT_BYREF:
  285.                 pArg->pfltVal = va_arg(argList, float*);
  286.                 break;
  287.             case VT_R8|VT_BYREF:
  288.                 pArg->pdblVal = va_arg(argList, double*);
  289.                 break;
  290.             case VT_DATE|VT_BYREF:
  291.                 pArg->pdate = va_arg(argList, DATE*);
  292.                 break;
  293.             case VT_CY|VT_BYREF:
  294.                 pArg->pcyVal = va_arg(argList, CY*);
  295.                 break;
  296.             case VT_BSTR|VT_BYREF:
  297.                 pArg->pbstrVal = va_arg(argList, BSTR*);
  298.                 break;
  299.             case VT_DISPATCH|VT_BYREF:
  300.                 pArg->ppdispVal = va_arg(argList, LPDISPATCH*);
  301.                 break;
  302.             case VT_ERROR|VT_BYREF:
  303.                 pArg->pscode = va_arg(argList, SCODE*);
  304.                 break;
  305.             case VT_BOOL|VT_BYREF:
  306.                 {
  307.                     // coerce BOOL into VARIANT_BOOL
  308.                     BOOL* pboolVal = va_arg(argList, BOOL*);
  309.                     *pboolVal = *pboolVal ? MAKELONG(-1, 0) : 0;
  310.                     pArg->pboolVal = (VARIANT_BOOL*)pboolVal;
  311.                 }
  312.                 break;
  313.             case VT_VARIANT|VT_BYREF:
  314.                 pArg->pvarVal = va_arg(argList, VARIANT*);
  315.                 break;
  316.             case VT_UNKNOWN|VT_BYREF:
  317.                 pArg->ppunkVal = va_arg(argList, LPUNKNOWN*);
  318.                 break;
  319.  
  320.             default:
  321.                 ASSERT(FALSE);  // unknown type!
  322.                 break;
  323.             }
  324.  
  325.             --pArg; // get ready to fill next argument
  326.             ++pb;
  327.         }
  328.     }
  329.  
  330.     // initialize return value
  331.     VARIANT* pvarResult = NULL;
  332.     VARIANT vaResult;
  333.     AfxVariantInit(&vaResult);
  334.     if (vtRet != VT_EMPTY)
  335.         pvarResult = &vaResult;
  336.  
  337.     // initialize EXCEPINFO struct
  338.     EXCEPINFO excepInfo;
  339.     memset(&excepInfo, 0, sizeof excepInfo);
  340.  
  341.     UINT nArgErr = (UINT)-1;  // initialize to invalid arg
  342.  
  343.     // make the call
  344.     SCODE sc = m_lpDispatch->Invoke(dwDispID, IID_NULL, 0, wFlags,
  345.         &dispparams, pvarResult, &excepInfo, &nArgErr);
  346.  
  347.     // cleanup any arguments that need cleanup
  348.     if (dispparams.cArgs != 0)
  349.     {
  350.         VARIANT* pArg = dispparams.rgvarg + dispparams.cArgs - 1;
  351.         const BYTE* pb = pbParamInfo;
  352.         while (*pb != 0)
  353.         {
  354.             switch ((VARTYPE)*pb)
  355.             {
  356. #if !defined(_UNICODE) && !defined(OLE2ANSI)
  357.             case VT_BSTRA:
  358. #endif
  359.             case VT_BSTR:
  360.                 VariantClear(pArg);
  361.                 break;
  362.             }
  363.             --pArg;
  364.             ++pb;
  365.         }
  366.     }
  367.     delete[] dispparams.rgvarg;
  368.  
  369.     // throw exception on failure
  370.     if (FAILED(sc))
  371.     {
  372.         VariantClear(&vaResult);
  373.         if (sc != DISP_E_EXCEPTION)
  374.         {
  375.             // non-exception error code
  376.             AfxThrowOleException(sc);
  377.         }
  378.  
  379.         // make sure excepInfo is filled in
  380.         if (excepInfo.pfnDeferredFillIn != NULL)
  381.             excepInfo.pfnDeferredFillIn(&excepInfo);
  382.  
  383.         // allocate new exception, and fill it
  384.         COleDispatchException* pException =
  385.             new COleDispatchException(NULL, 0, excepInfo.wCode);
  386.         ASSERT(pException->m_wCode == excepInfo.wCode);
  387.         if (excepInfo.bstrSource != NULL)
  388.         {
  389.             pException->m_strSource = excepInfo.bstrSource;
  390.             SysFreeString(excepInfo.bstrSource);
  391.         }
  392.         if (excepInfo.bstrDescription != NULL)
  393.         {
  394.             pException->m_strDescription = excepInfo.bstrDescription;
  395.             SysFreeString(excepInfo.bstrDescription);
  396.         }
  397.         if (excepInfo.bstrHelpFile != NULL)
  398.         {
  399.             pException->m_strHelpFile = excepInfo.bstrHelpFile;
  400.             SysFreeString(excepInfo.bstrHelpFile);
  401.         }
  402.         pException->m_dwHelpContext = excepInfo.dwHelpContext;
  403.         pException->m_scError = excepInfo.scode;
  404.  
  405.         // then throw the exception
  406.         THROW(pException);
  407.         ASSERT(FALSE);  // not reached
  408.     }
  409.  
  410.     if (vtRet != VT_EMPTY)
  411.     {
  412.         // convert return value
  413.         if (vtRet != VT_VARIANT)
  414.         {
  415.             SCODE sc = VariantChangeType(&vaResult, &vaResult, 0, vtRet);
  416.             if (FAILED(sc))
  417.             {
  418.                 TRACE0("Warning: automation return value coercion failed.\n");
  419.                 VariantClear(&vaResult);
  420.                 AfxThrowOleException(sc);
  421.             }
  422.             ASSERT(vtRet == vaResult.vt);
  423.         }
  424.  
  425.         // copy return value into return spot!
  426.         switch (vtRet)
  427.         {
  428.         case VT_UI1:
  429.             *(BYTE*)pvRet = vaResult.bVal;
  430.             break;
  431.         case VT_I2:
  432.             *(short*)pvRet = vaResult.iVal;
  433.             break;
  434.         case VT_I4:
  435.             *(long*)pvRet = vaResult.lVal;
  436.             break;
  437.         case VT_R4:
  438.             *(_AFX_FLOAT*)pvRet = *(_AFX_FLOAT*)&vaResult.fltVal;
  439.             break;
  440.         case VT_R8:
  441.             *(_AFX_DOUBLE*)pvRet = *(_AFX_DOUBLE*)&vaResult.dblVal;
  442.             break;
  443.         case VT_DATE:
  444.             *(_AFX_DOUBLE*)pvRet = *(_AFX_DOUBLE*)&vaResult.date;
  445.             break;
  446.         case VT_CY:
  447.             *(CY*)pvRet = vaResult.cyVal;
  448.             break;
  449.         case VT_BSTR:
  450.             AfxBSTR2CString((CString*)pvRet, vaResult.bstrVal);
  451.             SysFreeString(vaResult.bstrVal);
  452.             break;
  453.         case VT_DISPATCH:
  454.             *(LPDISPATCH*)pvRet = vaResult.pdispVal;
  455.             break;
  456.         case VT_ERROR:
  457.             *(SCODE*)pvRet = vaResult.scode;
  458.             break;
  459.         case VT_BOOL:
  460.             *(BOOL*)pvRet = (V_BOOL(&vaResult) != 0);
  461.             break;
  462.         case VT_VARIANT:
  463.             *(VARIANT*)pvRet = vaResult;
  464.             break;
  465.         case VT_UNKNOWN:
  466.             *(LPUNKNOWN*)pvRet = vaResult.punkVal;
  467.             break;
  468.  
  469.         default:
  470.             ASSERT(FALSE);  // invalid return type specified
  471.         }
  472.     }
  473. }
  474.  
  475. void AFX_CDECL COleDispatchDriver::InvokeHelper(DISPID dwDispID, WORD wFlags,
  476.     VARTYPE vtRet, void* pvRet, const BYTE* pbParamInfo, ...)
  477. {
  478.     va_list argList;
  479.     va_start(argList, pbParamInfo);
  480.  
  481.     InvokeHelperV(dwDispID, wFlags, vtRet, pvRet, pbParamInfo, argList);
  482.  
  483.     va_end(argList);
  484. }
  485.  
  486. void COleDispatchDriver::GetProperty(DISPID dwDispID, VARTYPE vtProp,
  487.     void* pvProp) const
  488. {
  489.     ((COleDispatchDriver*)this)->InvokeHelper(dwDispID,
  490.         DISPATCH_PROPERTYGET, vtProp, pvProp, NULL);
  491. }
  492.  
  493. void AFX_CDECL COleDispatchDriver::SetProperty(DISPID dwDispID, VARTYPE vtProp, ...)
  494. {
  495.     va_list argList;    // really only one arg, but...
  496.     va_start(argList, vtProp);
  497.  
  498.     BYTE rgbParams[2];
  499.     if (vtProp & VT_BYREF)
  500.     {
  501.         vtProp &= ~VT_BYREF;
  502.         vtProp |= VT_MFCBYREF;
  503.     }
  504.  
  505. #if !defined(_UNICODE) && !defined(OLE2ANSI)
  506.         if (vtProp == VT_BSTR)
  507.             vtProp = VT_BSTRA;
  508. #endif
  509.  
  510.     rgbParams[0] = (BYTE)vtProp;
  511.     rgbParams[1] = 0;
  512.     WORD wFlags = (WORD)(vtProp == VT_DISPATCH ?
  513.         DISPATCH_PROPERTYPUTREF : DISPATCH_PROPERTYPUT);
  514.     InvokeHelperV(dwDispID, wFlags, VT_EMPTY, NULL, rgbParams, argList);
  515.  
  516.     va_end(argList);
  517. }
  518.  
  519. /////////////////////////////////////////////////////////////////////////////
  520.