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 / dispcalc / dispcalc.cpp < prev    next >
Encoding:
C/C++ Source or Header  |  1997-07-31  |  12.5 KB  |  616 lines

  1. /*** 
  2. *dispcalc.cpp
  3. *
  4. *  This is a part of the Microsoft Source Code Samples.
  5. *
  6. *  Copyright (C) 1992-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 it via aggregation with an
  17. *  instance of the "standard" IDispatch implementation, which is
  18. *  initialized with a DispTypeInfo constructed from an INTERFACEDATA
  19. *  description.
  20. *
  21. *Implementation Notes:
  22. *
  23. *****************************************************************************/
  24.  
  25. #include "dispcalc.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. CCalc::CCalc() : m_arith(this)
  38. {
  39.     m_refs = 0;
  40. #ifdef _MAC
  41.     m_pdlg = nil;
  42. #else
  43.     m_hwnd = NULL;
  44. #endif
  45.     m_punkStdDisp = NULL;
  46. }
  47.  
  48. /***
  49. *CCalc *CCalc::Create(void)
  50. *Purpose:
  51. *  Create an instance of the IDispatch calculator, build a
  52. *  TypeInfo that describes the exposed functionality and
  53. *  aggregate with an instance of CStdDispatch that has been
  54. *  initialized with this TypeInfo.
  55. *
  56. *Entry:
  57. *  None
  58. *
  59. *Exit:
  60. *  return value = CCalc*, NULL if the creation failed.
  61. *
  62. ***********************************************************************/
  63. CCalc FAR*
  64. CCalc::Create()
  65. {
  66.     HRESULT hresult;
  67.     CCalc FAR* pcalc;
  68.     CArith FAR* parith;
  69.     ITypeInfo FAR* ptinfo;
  70.     IUnknown FAR* punkStdDisp;
  71. extern INTERFACEDATA NEARDATA g_idataCCalc;
  72.  
  73.     if((pcalc = new FAR CCalc()) == NULL)
  74.       return NULL;
  75.     pcalc->AddRef();
  76.  
  77.     parith = &(pcalc->m_arith);
  78.  
  79.     // Build a TypeInfo for the functionality on this object that
  80.     // is being exposing for external programmability.
  81.     //
  82.     hresult = CreateDispTypeInfo(
  83.       &g_idataCCalc, LOCALE_SYSTEM_DEFAULT, &ptinfo);
  84.     if(hresult != NOERROR)
  85.       goto LError0;
  86.  
  87.     // Create and aggregate with an instance of the default
  88.     // implementation of IDispatch that is initialized with our
  89.     // TypeInfo.
  90.     //
  91.     hresult = CreateStdDispatch(
  92.       pcalc,                    // controlling unknown
  93.       parith,                   // instance to dispatch on
  94.       ptinfo,                   // typeinfo describing the instance
  95.       &punkStdDisp);
  96.  
  97.     ptinfo->Release();
  98.  
  99.     if(hresult != NOERROR)
  100.       goto LError0;
  101.  
  102.     pcalc->m_punkStdDisp = punkStdDisp;
  103.  
  104.     return pcalc;
  105.  
  106. LError0:;
  107.     pcalc->Release();
  108.  
  109.     return NULL;
  110. }
  111.  
  112. //---------------------------------------------------------------------
  113. //                        IUnknown methods
  114. //---------------------------------------------------------------------
  115.  
  116. STDMETHODIMP
  117. CCalc::QueryInterface(REFIID riid, void FAR* FAR* ppv)
  118. {
  119.     if(IsEqualIID(riid, IID_IUnknown)){
  120.       *ppv = this;
  121.     }else
  122.     if(IsEqualIID(riid, IID_IDispatch)){
  123.       return m_punkStdDisp->QueryInterface(riid, ppv);
  124.     }else {
  125.       *ppv = NULL;          
  126.       return E_NOINTERFACE; 
  127.     }
  128.  
  129.     AddRef();
  130.     return NOERROR;
  131. }
  132.  
  133. STDMETHODIMP_(unsigned long)
  134. CCalc::AddRef()
  135. {
  136.     return ++m_refs;
  137. }
  138.  
  139. STDMETHODIMP_(unsigned long)
  140. CCalc::Release()
  141. {
  142.     if(--m_refs == 0){
  143.       if(m_punkStdDisp != NULL)
  144.     m_punkStdDisp->Release();
  145. #ifndef _MAC
  146.       PostQuitMessage(0);
  147. #endif
  148.       delete this;
  149.       return 0;
  150.     }
  151.     return m_refs;
  152. }
  153.  
  154.  
  155. //---------------------------------------------------------------------
  156. //                       Arithmetic features
  157. //---------------------------------------------------------------------
  158.  
  159. STDMETHODIMP_(void)
  160. CArith::Clear()
  161. {
  162.     m_opnd = 0;
  163.     m_accum = 0;
  164.     m_op = OP_NONE;
  165.     m_state = STATE_LOPND;
  166. }
  167.  
  168. STDMETHODIMP_(void)
  169. CArith::put_Accum(long l)
  170. {
  171.     m_accum = l;
  172. }
  173.  
  174.  
  175. STDMETHODIMP_(long)
  176. CArith::get_Accum()
  177. {
  178.     return m_accum;
  179. }
  180.  
  181. STDMETHODIMP_(void)
  182. CArith::put_Opnd(long l)
  183. {
  184.     m_opnd = l;
  185. }
  186.  
  187. STDMETHODIMP_(long)
  188. CArith::get_Opnd()
  189. {
  190.     return m_opnd;
  191. }
  192.  
  193. STDMETHODIMP_(void)
  194. CArith::put_Op(short op)
  195. {
  196.     m_op = op;
  197. }
  198.  
  199. STDMETHODIMP_(short)
  200. CArith::get_Op()
  201. {
  202.     return m_op;
  203. }
  204.  
  205. STDMETHODIMP_(short)
  206. CArith::Eval()
  207. {
  208.     if(m_op == OP_NONE)
  209.       return 0;
  210.  
  211.     switch(m_op){
  212.     case OP_PLUS:
  213.       m_accum += m_opnd;
  214.       break;
  215.     case OP_MINUS:
  216.       m_accum -= m_opnd;
  217.       break;
  218.     case OP_MULT:
  219.       m_accum *= m_opnd;
  220.       break;
  221.     case OP_DIV:
  222.       m_accum = (m_opnd == 0) ? 0 : (m_accum / m_opnd);
  223.       break;
  224.     default:
  225.       // ASSERT(UNREACHED);
  226.       return 0;
  227.       
  228.     }
  229.  
  230.     m_state = STATE_EVAL;
  231.  
  232.     return 1;
  233. }
  234.  
  235.  
  236. //---------------------------------------------------------------------
  237. //                       User Interface features
  238. //---------------------------------------------------------------------
  239.  
  240. /***
  241. *void CArith::Display()
  242. *Purpose:
  243. *  Display the contents of the register currently being edited.
  244. *
  245. *Entry:
  246. *  None
  247. *
  248. *Exit:
  249. *  None
  250. *
  251. ***********************************************************************/
  252. STDMETHODIMP_(void)
  253. CArith::Display()
  254. {
  255.     VARIANT var;
  256.  
  257.     VariantInit(&var);
  258.     
  259.     V_VT(&var) = VT_I4;
  260.     V_I4(&var) = (m_state == STATE_ROPND) ? m_opnd : m_accum;
  261.     VariantChangeType(&var, &var, 0, VT_BSTR);
  262.  
  263. #ifdef _MAC
  264.     {
  265.       Rect rcItem;
  266.       Handle hItem;
  267.       char str[255];
  268.       short sItemKind;
  269.  
  270.       strcpy(str, V_BSTR(&var));
  271.       GetDItem(m_pcalc->m_pdlg, IDC_DISPLAY, &sItemKind, &hItem, &rcItem);
  272.       SetIText(hItem, c2pstr(str));
  273.     }
  274. #else
  275.     SetDlgItemText(m_pcalc->m_hwnd, IDC_DISPLAY, STRING(V_BSTR(&var)));
  276. #endif
  277.  
  278.     VariantClear(&var);
  279. }
  280.  
  281. STDMETHODIMP_(short)
  282. CArith::Button(BSTR bstrButton)
  283. {
  284.     int i, button;
  285.  
  286. static struct {
  287.     OLECHAR ch;
  288.     int idc;
  289. } NEARDATA rgIdcOfCh[] = {
  290.       { OLESTR('+'), IDC_PLUS   }
  291.     , { OLESTR('-'), IDC_MINUS  }
  292.     , { OLESTR('*'), IDC_MULT   }
  293.     , { OLESTR('/'), IDC_DIV    }
  294.     , { OLESTR('C'), IDC_CLEAR  }
  295.     , { OLESTR('c'), IDC_CLEAR  }
  296.     , { OLESTR('='), IDC_EQUALS }
  297.     , { OLESTR('0'), IDC_ZERO   }
  298.     , { OLESTR('1'), IDC_ONE    }
  299.     , { OLESTR('2'), IDC_TWO    }
  300.     , { OLESTR('3'), IDC_THREE  }
  301.     , { OLESTR('4'), IDC_FOUR   }
  302.     , { OLESTR('5'), IDC_FIVE   }
  303.     , { OLESTR('6'), IDC_SIX    }
  304.     , { OLESTR('7'), IDC_SEVEN  }
  305.     , { OLESTR('8'), IDC_EIGHT  }
  306.     , { OLESTR('9'), IDC_NINE   }
  307.     , { (OLECHAR)-1 , -1         }
  308. };
  309.  
  310.     // if the string is more that 1 character long, then we know its wrong.
  311.     if(SysStringLen(bstrButton) > 1)
  312.       return 0;
  313.  
  314.     // translate button string into control ID
  315.     for(i = 0;; ++i){
  316.       if(rgIdcOfCh[i].ch == -1)
  317.     return 0;
  318.       if(rgIdcOfCh[i].ch == bstrButton[0]){
  319.     button = rgIdcOfCh[i].idc;
  320.     break;
  321.       }
  322.     }
  323.  
  324.     return ButtonPush(button);
  325. }
  326.  
  327. // the following method is internal, and not exposed for programmability
  328. int
  329. CArith::ButtonPush(int button)
  330. {
  331.     if(button >= IDC_ZERO && button <= IDC_NINE){
  332.  
  333.       long lVal = button - IDC_ZERO;
  334.  
  335.       switch(m_state){
  336.       case STATE_EVAL:
  337.     m_accum = lVal;
  338.     m_state = STATE_LOPND;
  339.     break;
  340.       case STATE_OP:
  341.     m_opnd = lVal;
  342.     m_state = STATE_ROPND;
  343.     break;
  344.       case STATE_LOPND:
  345.     m_accum = (m_accum * 10) + lVal;
  346.     break;
  347.       case STATE_ROPND:
  348.     m_opnd  = (m_opnd * 10) + lVal;
  349.     break;
  350.       }
  351.  
  352.     }else if(button >= IDC_PLUS && button <= IDC_DIV){
  353.  
  354.       if(m_state == STATE_ROPND)
  355.     Eval();
  356.  
  357.       m_opnd  = m_accum;
  358.       m_state = STATE_OP;
  359.       m_op    = button - IDC_PLUS + OP_PLUS;
  360.  
  361.     }else if(button == IDC_EQUALS){
  362.  
  363.       if(m_state > STATE_LOPND)
  364.     Eval();
  365.  
  366.     }else if (button == IDC_CLEAR){
  367.  
  368.       Clear();
  369.  
  370.     }else{
  371.  
  372.       return 0; // unknown button
  373.  
  374.     }
  375.  
  376.     // Flash the button
  377.  
  378. #ifdef _MAC
  379.     {
  380.       Rect rcItem;
  381.       long lDummy;
  382.       Handle hItem;
  383.       short sItemKind;
  384.  
  385.       GetDItem(m_pcalc->m_pdlg, button, &sItemKind, &hItem, &rcItem);
  386.       HiliteControl((ControlHandle)hItem, 1);
  387.       Delay(6, &lDummy);
  388.       HiliteControl((ControlHandle)hItem, 0);
  389.     }
  390. #else
  391.     SendMessage(m_pcalc->m_hwnd, BM_SETSTATE, 1, 0L);
  392.     SendMessage(m_pcalc->m_hwnd, BM_SETSTATE, 0, 0L);
  393. #endif
  394.  
  395.     // Update the calculator display
  396.  
  397.     Display();
  398.  
  399.     return 1;
  400. }
  401.  
  402. /***
  403. *void CArith::Quit()
  404. *Purpose:
  405. *
  406. *Entry:
  407. *  None
  408. *
  409. *Exit:
  410. *  None
  411. *
  412. ***********************************************************************/
  413. STDMETHODIMP_(void)
  414. CArith::Quit()
  415. {
  416. #ifndef _MAC
  417.     PostQuitMessage(0);
  418. #else
  419.     g_fQuit = 1;
  420. #endif
  421. }
  422.  
  423.  
  424. //---------------------------------------------------------------------
  425. //                      The CCalc Class Factory
  426. //---------------------------------------------------------------------
  427.  
  428. IClassFactory FAR*
  429. CCalcCF::Create()
  430. {
  431.     return new FAR CCalcCF();
  432. }
  433.  
  434. STDMETHODIMP
  435. CCalcCF::QueryInterface(REFIID riid, void FAR* FAR* ppv)
  436. {
  437.     if(IsEqualIID(riid, IID_IUnknown) || 
  438.        IsEqualIID(riid, IID_IClassFactory)){
  439.       AddRef();
  440.       *ppv = this;
  441.       return NOERROR;
  442.     }
  443.     
  444.     *ppv = NULL;
  445.     return E_NOINTERFACE;
  446. }
  447.  
  448. STDMETHODIMP_(unsigned long)
  449. CCalcCF::AddRef()
  450. {
  451.     return ++m_refs;
  452. }
  453.  
  454. STDMETHODIMP_(unsigned long)
  455. CCalcCF::Release()
  456. {
  457.     if(--m_refs == 0){
  458.       delete this;
  459.       return 0;
  460.     }
  461.     return m_refs;
  462. }
  463.  
  464. STDMETHODIMP
  465. CCalcCF::CreateInstance(
  466.     IUnknown FAR* punkOuter,
  467.     REFIID riid,
  468.     void FAR* FAR* ppv)
  469. {
  470.     if(punkOuter != NULL)
  471.       return CLASS_E_NOAGGREGATION;
  472.     return g_pcalc->QueryInterface(riid, ppv);
  473. }
  474.  
  475. STDMETHODIMP
  476. #ifdef _MAC
  477. CCalcCF::LockServer(unsigned long fLock)
  478. #else
  479. CCalcCF::LockServer(BOOL fLock)
  480. #endif
  481. {
  482.     UNUSED(fLock);
  483.     return NOERROR;
  484. }
  485.  
  486.  
  487. //---------------------------------------------------------------------
  488. //                        Ole Init/Uninit
  489. //---------------------------------------------------------------------
  490.  
  491. HRESULT
  492. UninitOle()
  493. {
  494.     if(g_dwRegisterCCalc != 0)
  495.       RevokeActiveObject(g_dwRegisterCCalc, NULL);
  496.  
  497.     if(g_dwCCalcCF != 0)
  498.       CoRevokeClassObject(g_dwCCalcCF);
  499.  
  500.     if(g_pcalc != NULL)
  501.       g_pcalc->Release();
  502.  
  503.     OleUninitialize();
  504.  
  505.     return NOERROR;
  506. }
  507.  
  508. #ifdef _MAC
  509. struct regentry{
  510.     char *szKey;
  511.     char *szValue;
  512. } g_rgregentry[] = {
  513.  
  514.       { "CLSID\\{00020467-0000-0000-C000-000000000046}",
  515.     "OLE Automation DispCalc 1.0 Application" }
  516.  
  517.     , { "CLSID\\{00020467-0000-0000-C000-000000000046}\\LocalServer",
  518.     "DCLC" }
  519.  
  520.     , { "CLSID\\{00020467-0000-0000-C000-000000000046}\\ProgID",
  521.     "Dispcalc.Application" }
  522.  
  523.     , { "CLSID\\{00020467-0000-0000-C000-000000000046}\\InprocHandler",
  524.     "OLE2:Def$DefFSet" }
  525.  
  526.     , { "DCLC", "{00020467-0000-0000-C000-000000000046}" }
  527.  
  528.     , { "Dispcalc.Application\\CLSID",
  529.     "{00020467-0000-0000-C000-000000000046}" }
  530.  
  531. };
  532.  
  533. HRESULT
  534. EnsureRegistration()
  535. {
  536.     HKEY hkey;
  537.  
  538.     if(RegOpenKey(HKEY_CLASSES_ROOT, "DCLC", &hkey) == NOERROR){
  539.       RegCloseKey(hkey);
  540.       return NOERROR;
  541.     }
  542.  
  543.     for(int i = 0; i < DIM(g_rgregentry); ++i){
  544.       if(RegSetValue(HKEY_CLASSES_ROOT, g_rgregentry[i].szKey, REG_SZ, g_rgregentry[i].szValue, 0) != ERROR_SUCCESS)
  545.     return E_FAIL;
  546.     }
  547.  
  548.     return NOERROR;
  549. }
  550. #endif
  551.  
  552. /***
  553. *HRESULT InitOle(void)
  554. *Purpose:
  555. *  Initialize Ole, and register our class factories.
  556. *
  557. *Entry:
  558. *  None
  559. *
  560. *Exit:
  561. *  None
  562. *
  563. ***********************************************************************/
  564. HRESULT
  565. InitOle()
  566. {
  567.     HRESULT hresult;
  568.     IClassFactory FAR* pcf;
  569.  
  570.     if(FAILED(hresult = OleInitialize(NULL)))
  571.       goto LError0;
  572.  
  573. #ifdef _MAC
  574.     if(FAILED(hresult = EnsureRegistration()))
  575.       goto LError0;
  576. #endif
  577.  
  578.     // create the single global instance of CCalc
  579.     if((g_pcalc = CCalc::Create()) == NULL){
  580.       hresult = E_OUTOFMEMORY;
  581.       goto LError0;
  582.     }
  583.  
  584.     if((pcf = CCalcCF::Create()) == NULL)
  585.       goto LError1;
  586.  
  587.     hresult = CoRegisterClassObject(
  588.       CLSID_CCalc,
  589.       pcf,
  590.       CLSCTX_LOCAL_SERVER,
  591.       REGCLS_MULTIPLEUSE,
  592.       &g_dwCCalcCF);
  593.     if(FAILED(hresult))
  594.       goto LError2;
  595.  
  596.     hresult = RegisterActiveObject(
  597.       g_pcalc, CLSID_CCalc, NULL, &g_dwRegisterCCalc);
  598.     if(FAILED(hresult))
  599.       goto LError2;
  600.  
  601.     pcf->Release();
  602.  
  603.     return NOERROR;
  604.  
  605. LError2:;
  606.     pcf->Release();
  607.  
  608. LError1:;
  609.     UninitOle();
  610.  
  611. LError0:;
  612.     return hresult;
  613. }
  614.  
  615.  
  616.