home *** CD-ROM | disk | FTP | other *** search
/ Tricks of the Windows Gam…ming Gurus (2nd Edition) / Disc2.iso / msdn_vcb / samples / vc98 / sdk / com / oleaut / dspcalc2 / dspcalc2.cpp < prev    next >
Encoding:
C/C++ Source or Header  |  1997-07-31  |  14.3 KB  |  696 lines

  1. /*** 
  2. *dspcalc2.cpp
  3. *
  4. *  This is a part of the Microsoft Source Code Samples.
  5. *
  6. *  Copyright (C) 1993-1997 Microsoft Corporation. All rights reserved.
  7. *
  8. *  This source code is only intended as a supplement to Microsoft Development
  9. *  Tools and/or WinHelp documentation.  See these sources for detailed
  10. *  information regarding the Microsoft samples programs.
  11. *
  12. *Purpose:
  13. *  This module implements the basic user interface and arithmetic
  14. *  functionality of the IDispatch calculator.
  15. *
  16. *  The implementation of IDispatch is via aggregation with an
  17. *  instance of the "standard" IDispatch implementation, which is
  18. *  initialized with a TypeInfo loaded from the TypeLib that was
  19. *  constructed from the ODL description of the calculator.
  20. *
  21. *Implementation Notes:
  22. *
  23. *****************************************************************************/
  24.  
  25. #include "dspcalc2.h"
  26.  
  27. CCalc FAR* g_pcalc = NULL;
  28.  
  29. unsigned long g_dwCCalcCF = 0;
  30. unsigned long g_dwRegisterCCalc = 0;
  31.  
  32. #ifdef _MAC         
  33. extern Boolean g_fQuit;
  34. #endif //_MAC
  35.  
  36.  
  37. /***
  38. *CCalc *CCalc::Create(void)
  39. *Purpose:
  40. *  Create an instance of the IDispatch calculator, load the
  41. *  TypeInfo that describes the exposed functionality and
  42. *  aggregate with an instance of CStdDispatch that has been
  43. *  initialized with this TypeInfo.
  44. *
  45. *Entry:
  46. *  None
  47. *
  48. *Exit:
  49. *  return value = CCalc*, NULL if the creation failed.
  50. *
  51. ***********************************************************************/
  52. CCalc FAR*
  53. CCalc::Create()
  54. {
  55.     HRESULT hresult;
  56.     CCalc FAR* pcalc;
  57.     ITypeLib FAR* ptlib;
  58.     ITypeInfo FAR* ptinfo;
  59.     IUnknown FAR* punkStdDisp;
  60.  
  61.     ptlib = NULL;
  62.     ptinfo = NULL;
  63.  
  64.     if((pcalc = new FAR CCalc()) == NULL)
  65.       return NULL;
  66.     pcalc->AddRef();
  67.     
  68.     // first try to load the type library from the information in the registry
  69.     if((hresult = LoadRegTypeLib(LIBID_DspCalc2, 1, 0, 0x0409, &ptlib)) != NOERROR){
  70.  
  71.       #define TLB_NAME OLESTR("dspcalc2.tlb")
  72.  
  73.       // if it wasn't registered, try to load it from the path/current directory
  74.       // if this succeeds, it will have registered the type library for us
  75.       // for the next time.
  76.       if((hresult = LoadTypeLib(TLB_NAME, &ptlib)) != NOERROR){
  77. #ifndef _MAC        
  78.     MessageBox(NULL, TSTR("error loading TypeLib"),
  79.            TSTR("dspcalc2"), MB_OK);
  80. #endif   
  81.     goto LError0;
  82.       }
  83.  
  84.     }
  85.  
  86.     if((hresult = ptlib->GetTypeInfoOfGuid(IID_ICalculator, &ptinfo)) != NOERROR){
  87. #ifndef _MAC        
  88.       MessageBox(NULL, TSTR("error accessing TypeInfo"), 
  89.          TSTR("dspcalc2"), MB_OK);
  90. #endif   
  91.       goto LError0;
  92.     }
  93.  
  94.     // Create and aggregate with an instance of the default
  95.     // implementation of IDispatch that is initialized with our
  96.     // TypeInfo.
  97.     //
  98.     hresult = CreateStdDispatch(
  99.       pcalc,                            // controlling unknown
  100.       &(pcalc->m_arith),                // vtable* to dispatch on
  101.       ptinfo,
  102.       &punkStdDisp);
  103.  
  104.     if(hresult != NOERROR)
  105.       goto LError0;
  106.  
  107.     pcalc->m_punkStdDisp = punkStdDisp;
  108.  
  109.     ptinfo->Release();
  110.     ptlib->Release();
  111.  
  112.     return pcalc;
  113.  
  114. LError0:;
  115.     pcalc->Release();
  116.     if(ptinfo != NULL)
  117.       ptinfo->Release();
  118.     if(ptlib != NULL)
  119.       ptlib->Release();
  120.     return NULL;
  121. }
  122.  
  123.  
  124. //---------------------------------------------------------------------
  125. //                        IUnknown methods
  126. //---------------------------------------------------------------------
  127.  
  128.  
  129. STDMETHODIMP
  130. CCalc::QueryInterface(REFIID riid, void FAR* FAR* ppv)
  131. {
  132.     if(IsEqualIID(riid, IID_IUnknown)){
  133.       *ppv = this;
  134.     }else
  135.     if(IsEqualIID(riid, IID_IDispatch) ||
  136.        IsEqualIID(riid, IID_DCalculator)){
  137.       return m_punkStdDisp->QueryInterface(IID_IDispatch, ppv);
  138.     }else 
  139.     if(IsEqualIID(riid, IID_ICalculator)){
  140.       *ppv = &m_arith;
  141.     }else {
  142.       *ppv = NULL;          
  143.       return E_NOINTERFACE;
  144.     }
  145.  
  146.     AddRef();
  147.     return NOERROR;
  148. }
  149.  
  150.  
  151. STDMETHODIMP_(ULONG)
  152. CCalc::AddRef()
  153. {
  154.     return ++m_refs;
  155. }
  156.  
  157.  
  158. STDMETHODIMP_(ULONG)
  159. CCalc::Release()
  160. {
  161.     if(--m_refs == 0){
  162.       if(m_punkStdDisp != NULL)
  163.     m_punkStdDisp->Release();
  164. #ifndef _MAC
  165.       PostQuitMessage(0);
  166. #endif
  167.       delete this;
  168.       return 0;
  169.     }
  170.     return m_refs;
  171. }
  172.  
  173.  
  174. STDMETHODIMP
  175. CArith::QueryInterface(REFIID riid, void FAR* FAR* ppv)
  176. {
  177.     return m_pcalc->QueryInterface(riid, ppv);
  178. }
  179.  
  180.  
  181. STDMETHODIMP_(ULONG)
  182. CArith::AddRef()
  183. {
  184.     return m_pcalc->AddRef();
  185. }
  186.  
  187.  
  188. STDMETHODIMP_(ULONG)
  189. CArith::Release()
  190. {
  191.     return m_pcalc->Release();
  192. }
  193.  
  194.  
  195. //---------------------------------------------------------------------
  196. //                       Arithmetic features
  197. //---------------------------------------------------------------------
  198.  
  199.  
  200. STDMETHODIMP_(void)
  201. CArith::DCClear()
  202. {
  203.     m_opnd = 0;
  204.     m_accum = 0;
  205.     m_op = OP_NONE;
  206.     m_state = STATE_LOPND;
  207. }
  208.  
  209. STDMETHODIMP_(void)
  210. CArith::put_Accum(long l)
  211. {
  212.     m_accum = l;
  213. }
  214.  
  215.  
  216. STDMETHODIMP_(long)
  217. CArith::get_Accum()
  218. {
  219.     return m_accum;
  220. }
  221.  
  222.  
  223. STDMETHODIMP_(void)
  224. CArith::put_Opnd(long l)
  225. {
  226.     m_opnd = l;
  227. }
  228.  
  229.  
  230. STDMETHODIMP_(long)
  231. CArith::get_Opnd()
  232. {
  233.     return m_opnd;
  234. }
  235.  
  236.  
  237. STDMETHODIMP_(void)
  238. CArith::put_Op(OPERATORS op)
  239. {
  240.     m_op = op;
  241. }
  242.  
  243.  
  244. STDMETHODIMP_(OPERATORS)
  245. CArith::get_Op()
  246. {
  247.     return m_op;
  248. }
  249.  
  250.  
  251. STDMETHODIMP_(VARIANT_BOOL)
  252. CArith::Eval()
  253. {
  254.     if(m_op == OP_NONE)
  255.       return FALSE;
  256.  
  257.     switch(m_op){
  258.     case OP_PLUS:
  259.       m_accum += m_opnd;
  260.       break;
  261.     case OP_MINUS:
  262.       m_accum -= m_opnd;
  263.       break;
  264.     case OP_MULT:
  265.       m_accum *= m_opnd;
  266.       break;
  267.     case OP_DIV:
  268.       m_accum = (m_opnd == 0) ? 0 : (m_accum / m_opnd);
  269.       break;
  270.     default:
  271.       // ASSERT(UNREACHED);
  272.       return FALSE;
  273.       
  274.     }
  275.  
  276.     m_state = STATE_EVAL;
  277.  
  278.     return VARIANT_TRUE;
  279. }
  280.  
  281.  
  282. //---------------------------------------------------------------------
  283. //                       User Interface features
  284. //---------------------------------------------------------------------
  285.  
  286.  
  287. /***
  288. *void CArith::Display()
  289. *Purpose:
  290. *  Display the contents of the register currently being edited.
  291. *
  292. *Entry:
  293. *  None
  294. *
  295. *Exit:
  296. *  None
  297. *
  298. ***********************************************************************/
  299. STDMETHODIMP_(void)
  300. CArith::Display()
  301. {
  302.     VARIANT var;
  303.  
  304.     VariantInit(&var);
  305.     V_VT(&var) = VT_I4;
  306.     V_I4(&var) = (m_state == STATE_ROPND) ? m_opnd : m_accum;
  307.     VariantChangeType(&var, &var, 0, VT_BSTR);
  308.  
  309.     #ifdef _MAC
  310.     {
  311.       Rect rcItem;
  312.       Handle hItem;
  313.       char str[255];
  314.       short sItemKind;
  315.  
  316.       strcpy(str, V_BSTR(&var));
  317.       GetDItem(m_pcalc->m_pdlg, IDC_DISPLAY, &sItemKind, &hItem, &rcItem);
  318.       SetIText(hItem, c2pstr(str));
  319.     }
  320. #else
  321.     SetDlgItemText(m_pcalc->m_hwnd, IDC_DISPLAY, STRING(V_BSTR(&var)));
  322. #endif
  323.  
  324.     VariantClear(&var);
  325. }
  326.  
  327.  
  328. STDMETHODIMP_(VARIANT_BOOL)
  329. CArith::Button(SAFEARRAY FAR * psa)
  330. {
  331.     int i, button;
  332.  
  333. static struct {
  334.     OLECHAR ch;
  335.     int idc;
  336. } NEAR rgIdcOfCh[] = {
  337.       { OLESTR('+'), IDC_PLUS   }
  338.     , { OLESTR('-'), IDC_MINUS  }
  339.     , { OLESTR('*'), IDC_MULT   }
  340.     , { OLESTR('/'), IDC_DIV    }
  341.     , { OLESTR('C'), IDC_CLEAR  }
  342.     , { OLESTR('c'), IDC_CLEAR  }
  343.     , { OLESTR('='), IDC_EQUALS }
  344.     , { OLESTR('0'), IDC_ZERO   }
  345.     , { OLESTR('1'), IDC_ONE    }
  346.     , { OLESTR('2'), IDC_TWO    }
  347.     , { OLESTR('3'), IDC_THREE  }
  348.     , { OLESTR('4'), IDC_FOUR   }
  349.     , { OLESTR('5'), IDC_FIVE   }
  350.     , { OLESTR('6'), IDC_SIX    }
  351.     , { OLESTR('7'), IDC_SEVEN  }
  352.     , { OLESTR('8'), IDC_EIGHT  }
  353.     , { OLESTR('9'), IDC_NINE   }
  354.     , { (OLECHAR)-1 , -1         }
  355. };
  356.     LONG saIndex, saUbound;
  357.     VARIANT varButton;
  358.  
  359.     // Since this is a vararg function, we should be given a 1-dimensional
  360.     // array with 0 for the lower bound. The array could be uninitialized
  361.     // if 0 args were passed to us -- this call will give an error in this case.
  362.     if (SafeArrayGetUBound(psa, 1, &saUbound) != NOERROR)
  363.       return FALSE;     // most likely 0 args were passed to us
  364.  
  365.     for (saIndex = 0; saIndex <= saUbound; saIndex++) {
  366.  
  367.       // get next parameter
  368.       if (SafeArrayGetElement(psa, &saIndex, &varButton) != NOERROR)
  369.     return FALSE;
  370.  
  371.       // convert it to a string in-place
  372.       if (VariantChangeType(&varButton, &varButton, 0, VT_BSTR) != NOERROR)
  373.     goto Error;
  374.  
  375.       // if the string is more that 1 character long, then we know its wrong.
  376.       if(SysStringLen(varButton.bstrVal) > 1)
  377.     goto Error;
  378.  
  379.       // translate button string into control ID
  380.       for(i = 0;; ++i){
  381.     if(rgIdcOfCh[i].ch == -1)
  382.       goto Error;
  383.     if(rgIdcOfCh[i].ch == varButton.bstrVal[0]){
  384.       button = rgIdcOfCh[i].idc;
  385.       break;
  386.     }
  387.       }
  388.  
  389.       VariantClear(&varButton);         // done with the parameter
  390.  
  391.       if (!ButtonPush(button))
  392.     return FALSE;
  393.  
  394.     } // for
  395.  
  396.     return VARIANT_TRUE;        // success
  397.  
  398. Error:
  399.     VariantClear(&varButton);
  400.     return FALSE;       // failure
  401. }
  402.  
  403.  
  404. // the following method is internal, and not exposed for programmability
  405. BOOL
  406. CArith::ButtonPush(int button)
  407. {
  408.     if(button >= IDC_ZERO && button <= IDC_NINE){
  409.  
  410.       long lVal = button - IDC_ZERO;
  411.  
  412.       switch(m_state){
  413.       case STATE_EVAL:
  414.     m_accum = lVal;
  415.     m_state = STATE_LOPND;
  416.     break;
  417.       case STATE_OP:
  418.     m_opnd = lVal;
  419.     m_state = STATE_ROPND;
  420.     break;
  421.       case STATE_LOPND:
  422.     m_accum = (m_accum * 10) + lVal;
  423.     break;
  424.       case STATE_ROPND:
  425.     m_opnd  = (m_opnd * 10) + lVal;
  426.     break;
  427.       }
  428.  
  429.     }else if(button >= IDC_PLUS && button <= IDC_DIV){
  430.  
  431.       if(m_state == STATE_ROPND)
  432.     Eval();
  433.  
  434.       m_opnd  = m_accum;
  435.       m_state = STATE_OP;
  436.       m_op    = (OPERATORS)(button - IDC_PLUS + OP_PLUS);
  437.  
  438.     }else if(button == IDC_EQUALS){
  439.  
  440.       if(m_state > STATE_LOPND)
  441.     Eval();
  442.  
  443.     }else if (button == IDC_CLEAR){
  444.  
  445.       DCClear();
  446.  
  447.     } else {
  448.  
  449.       return 0; // unknown button
  450.  
  451.     }
  452.         
  453.  
  454.     // Flash the button
  455.  
  456. #ifdef _MAC
  457.     {
  458.       Rect rcItem;
  459.       long lDummy;
  460.       Handle hItem;
  461.       short sItemKind;
  462.  
  463.       GetDItem(m_pcalc->m_pdlg, button, &sItemKind, &hItem, &rcItem);
  464.       HiliteControl((ControlHandle)hItem, 1);
  465.       Delay(6, &lDummy);
  466.       HiliteControl((ControlHandle)hItem, 0);
  467.     }
  468. #else
  469.     SendMessage(m_pcalc->m_hwnd, BM_SETSTATE, 1, 0L);
  470.     SendMessage(m_pcalc->m_hwnd, BM_SETSTATE, 0, 0L);
  471. #endif
  472.  
  473.     // Update the calculator display
  474.  
  475.     Display();
  476.  
  477.     return TRUE;
  478. }
  479.  
  480. /***
  481. *void CArith::Quit()
  482. *Purpose:
  483. *
  484. *Entry:
  485. *  None
  486. *
  487. *Exit:
  488. *  None
  489. *
  490. ***********************************************************************/
  491. STDMETHODIMP_(void)
  492. CArith::Quit()
  493. {
  494. #ifndef _MAC
  495.     PostQuitMessage(0);
  496. #else
  497.     g_fQuit = TRUE;
  498. #endif
  499. }
  500.  
  501.  
  502. //---------------------------------------------------------------------
  503. //                      The CCalc Class Factory
  504. //---------------------------------------------------------------------
  505.  
  506.  
  507. IClassFactory FAR*
  508. CCalcCF::Create()
  509. {
  510.     return new FAR CCalcCF();
  511. }
  512.  
  513.  
  514. STDMETHODIMP
  515. CCalcCF::QueryInterface(REFIID riid, void FAR* FAR* ppv)
  516. {
  517.     if(IsEqualIID(riid, IID_IUnknown) || IsEqualIID(riid, IID_IClassFactory)){
  518.       AddRef();
  519.       *ppv = this;
  520.       return NOERROR;
  521.     }
  522.     *ppv = NULL;
  523.     return E_NOINTERFACE;
  524. }
  525.  
  526.  
  527. STDMETHODIMP_(ULONG)
  528. CCalcCF::AddRef()
  529. {
  530.     return ++m_refs;
  531. }
  532.  
  533.  
  534. STDMETHODIMP_(ULONG)
  535. CCalcCF::Release()
  536. {
  537.     if(--m_refs == 0){
  538.       delete this;
  539.       return 0;
  540.     }
  541.     return m_refs;
  542. }
  543.  
  544.  
  545. STDMETHODIMP
  546. CCalcCF::CreateInstance(
  547.     IUnknown FAR* punkOuter,
  548.     REFIID riid,
  549.     void FAR* FAR* ppv)
  550. {
  551. extern CCalc FAR* g_pcalc;
  552.  
  553.     UNUSED(punkOuter);
  554.     return g_pcalc->QueryInterface(riid, ppv);
  555. }
  556.  
  557.  
  558. STDMETHODIMP
  559. #ifdef _MAC
  560. CCalcCF::LockServer(unsigned long fLock)
  561. #else
  562. CCalcCF::LockServer(BOOL fLock)
  563. #endif
  564. {
  565.     UNUSED(fLock);
  566.     return NOERROR;
  567. }
  568.  
  569. #ifdef _MAC
  570. struct regentry{
  571.     char *szKey;
  572.     char *szValue;
  573. } g_rgregentry[] = {
  574.  
  575.       { "CLSID\\{00020469-0000-0000-C000-000000000046}",
  576.     "OLE Automation DspCalc2 1.0 Application" }
  577.  
  578.     , { "CLSID\\{00020469-0000-0000-C000-000000000046}\\LocalServer",
  579.     "DCL2" }
  580.  
  581.     , { "CLSID\\{00020469-0000-0000-C000-000000000046}\\ProgID",
  582.     "Dspcalc2.Application" }
  583.  
  584.     , { "CLSID\\{00020469-0000-0000-C000-000000000046}\\InprocHandler",
  585.     "OLE2:Def$DefFSet" }
  586.  
  587.     , { "DCL2", "{00020469-0000-0000-C000-000000000046}" }
  588.  
  589.     , { "Dspcalc2.Application\\CLSID",
  590.     "{00020469-0000-0000-C000-000000000046}" }
  591.  
  592. };
  593.  
  594. HRESULT
  595. EnsureRegistration()
  596. {
  597.     HKEY hkey;
  598.  
  599.     if(RegOpenKey(HKEY_CLASSES_ROOT, "DCL2", &hkey) == NOERROR){
  600.       RegCloseKey(hkey);
  601.       return NOERROR;
  602.     }
  603.  
  604.     for(int i = 0; i < DIM(g_rgregentry); ++i){
  605.       if(RegSetValue(HKEY_CLASSES_ROOT, g_rgregentry[i].szKey, REG_SZ, g_rgregentry[i].szValue, 0) != ERROR_SUCCESS)
  606.     return E_FAIL;
  607.     }
  608.  
  609.     return NOERROR;
  610. }
  611. #endif //_MAC
  612.  
  613.  
  614. /***
  615. *HRESULT InitOle(void)
  616. *Purpose:
  617. *  Initialize Ole, and register our class factories.
  618. *
  619. *Entry:
  620. *  None
  621. *
  622. *Exit:
  623. *  None
  624. *
  625. ***********************************************************************/
  626. HRESULT
  627. InitOle()
  628. {
  629.     HRESULT hresult;
  630.     IClassFactory FAR* pcf;
  631.  
  632.  
  633.     if((hresult = OleInitialize(NULL)) != NOERROR)
  634.       goto LError0;
  635.  
  636. #ifdef _MAC
  637.     if((hresult = EnsureRegistration()) != NOERROR)
  638.       goto LError0;
  639. #endif
  640.  
  641.     // create the single global instance of CCalc
  642.     if((g_pcalc = CCalc::Create()) == NULL){
  643.       hresult = E_OUTOFMEMORY;
  644.       goto LError0;
  645.     }
  646.  
  647.     if((pcf = CCalcCF::Create()) == NULL)
  648.       goto LError1;
  649.  
  650.     hresult = CoRegisterClassObject(
  651.       CLSID_CCalc2,
  652.       pcf,
  653.       CLSCTX_LOCAL_SERVER,
  654.       REGCLS_MULTIPLEUSE,
  655.       &g_dwCCalcCF);
  656.     if(FAILED(hresult))
  657.       goto LError2;
  658.  
  659.     hresult = RegisterActiveObject(
  660.       g_pcalc, CLSID_CCalc2, NULL, &g_dwRegisterCCalc);
  661.     if(FAILED(hresult))
  662.       goto LError2;
  663.  
  664.     pcf->Release();
  665.  
  666.     return NOERROR;
  667.  
  668. LError2:;
  669.     pcf->Release();
  670.  
  671. LError1:;
  672.     UninitOle();
  673.  
  674. LError0:;
  675.     return hresult;
  676. }
  677.  
  678.  
  679. HRESULT
  680. UninitOle()
  681. {
  682.     if(g_dwRegisterCCalc != 0)
  683.       RevokeActiveObject(g_dwRegisterCCalc, NULL);
  684.  
  685.     if(g_dwCCalcCF != 0)
  686.       CoRevokeClassObject(g_dwCCalcCF);
  687.  
  688.     // cause the remaining typeinfo to be released
  689.     if(g_pcalc != NULL)
  690.       g_pcalc->Release();
  691.  
  692.     OleUninitialize();
  693.  
  694.     return NOERROR;
  695. }
  696.