home *** CD-ROM | disk | FTP | other *** search
- /***
- *dspcalc2.cpp
- *
- * This is a part of the Microsoft Source Code Samples.
- *
- * Copyright (C) 1993-1997 Microsoft Corporation. All rights reserved.
- *
- * This source code is only intended as a supplement to Microsoft Development
- * Tools and/or WinHelp documentation. See these sources for detailed
- * information regarding the Microsoft samples programs.
- *
- *Purpose:
- * This module implements the basic user interface and arithmetic
- * functionality of the IDispatch calculator.
- *
- * The implementation of IDispatch is via aggregation with an
- * instance of the "standard" IDispatch implementation, which is
- * initialized with a TypeInfo loaded from the TypeLib that was
- * constructed from the ODL description of the calculator.
- *
- *Implementation Notes:
- *
- *****************************************************************************/
-
- #include "dspcalc2.h"
-
- CCalc FAR* g_pcalc = NULL;
-
- unsigned long g_dwCCalcCF = 0;
- unsigned long g_dwRegisterCCalc = 0;
-
- #ifdef _MAC
- extern Boolean g_fQuit;
- #endif //_MAC
-
-
- /***
- *CCalc *CCalc::Create(void)
- *Purpose:
- * Create an instance of the IDispatch calculator, load the
- * TypeInfo that describes the exposed functionality and
- * aggregate with an instance of CStdDispatch that has been
- * initialized with this TypeInfo.
- *
- *Entry:
- * None
- *
- *Exit:
- * return value = CCalc*, NULL if the creation failed.
- *
- ***********************************************************************/
- CCalc FAR*
- CCalc::Create()
- {
- HRESULT hresult;
- CCalc FAR* pcalc;
- ITypeLib FAR* ptlib;
- ITypeInfo FAR* ptinfo;
- IUnknown FAR* punkStdDisp;
-
- ptlib = NULL;
- ptinfo = NULL;
-
- if((pcalc = new FAR CCalc()) == NULL)
- return NULL;
- pcalc->AddRef();
-
- // first try to load the type library from the information in the registry
- if((hresult = LoadRegTypeLib(LIBID_DspCalc2, 1, 0, 0x0409, &ptlib)) != NOERROR){
-
- #define TLB_NAME OLESTR("dspcalc2.tlb")
-
- // if it wasn't registered, try to load it from the path/current directory
- // if this succeeds, it will have registered the type library for us
- // for the next time.
- if((hresult = LoadTypeLib(TLB_NAME, &ptlib)) != NOERROR){
- #ifndef _MAC
- MessageBox(NULL, TSTR("error loading TypeLib"),
- TSTR("dspcalc2"), MB_OK);
- #endif
- goto LError0;
- }
-
- }
-
- if((hresult = ptlib->GetTypeInfoOfGuid(IID_ICalculator, &ptinfo)) != NOERROR){
- #ifndef _MAC
- MessageBox(NULL, TSTR("error accessing TypeInfo"),
- TSTR("dspcalc2"), MB_OK);
- #endif
- goto LError0;
- }
-
- // Create and aggregate with an instance of the default
- // implementation of IDispatch that is initialized with our
- // TypeInfo.
- //
- hresult = CreateStdDispatch(
- pcalc, // controlling unknown
- &(pcalc->m_arith), // vtable* to dispatch on
- ptinfo,
- &punkStdDisp);
-
- if(hresult != NOERROR)
- goto LError0;
-
- pcalc->m_punkStdDisp = punkStdDisp;
-
- ptinfo->Release();
- ptlib->Release();
-
- return pcalc;
-
- LError0:;
- pcalc->Release();
- if(ptinfo != NULL)
- ptinfo->Release();
- if(ptlib != NULL)
- ptlib->Release();
- return NULL;
- }
-
-
- //---------------------------------------------------------------------
- // IUnknown methods
- //---------------------------------------------------------------------
-
-
- STDMETHODIMP
- CCalc::QueryInterface(REFIID riid, void FAR* FAR* ppv)
- {
- if(IsEqualIID(riid, IID_IUnknown)){
- *ppv = this;
- }else
- if(IsEqualIID(riid, IID_IDispatch) ||
- IsEqualIID(riid, IID_DCalculator)){
- return m_punkStdDisp->QueryInterface(IID_IDispatch, ppv);
- }else
- if(IsEqualIID(riid, IID_ICalculator)){
- *ppv = &m_arith;
- }else {
- *ppv = NULL;
- return E_NOINTERFACE;
- }
-
- AddRef();
- return NOERROR;
- }
-
-
- STDMETHODIMP_(ULONG)
- CCalc::AddRef()
- {
- return ++m_refs;
- }
-
-
- STDMETHODIMP_(ULONG)
- CCalc::Release()
- {
- if(--m_refs == 0){
- if(m_punkStdDisp != NULL)
- m_punkStdDisp->Release();
- #ifndef _MAC
- PostQuitMessage(0);
- #endif
- delete this;
- return 0;
- }
- return m_refs;
- }
-
-
- STDMETHODIMP
- CArith::QueryInterface(REFIID riid, void FAR* FAR* ppv)
- {
- return m_pcalc->QueryInterface(riid, ppv);
- }
-
-
- STDMETHODIMP_(ULONG)
- CArith::AddRef()
- {
- return m_pcalc->AddRef();
- }
-
-
- STDMETHODIMP_(ULONG)
- CArith::Release()
- {
- return m_pcalc->Release();
- }
-
-
- //---------------------------------------------------------------------
- // Arithmetic features
- //---------------------------------------------------------------------
-
-
- STDMETHODIMP_(void)
- CArith::DCClear()
- {
- m_opnd = 0;
- m_accum = 0;
- m_op = OP_NONE;
- m_state = STATE_LOPND;
- }
-
- STDMETHODIMP_(void)
- CArith::put_Accum(long l)
- {
- m_accum = l;
- }
-
-
- STDMETHODIMP_(long)
- CArith::get_Accum()
- {
- return m_accum;
- }
-
-
- STDMETHODIMP_(void)
- CArith::put_Opnd(long l)
- {
- m_opnd = l;
- }
-
-
- STDMETHODIMP_(long)
- CArith::get_Opnd()
- {
- return m_opnd;
- }
-
-
- STDMETHODIMP_(void)
- CArith::put_Op(OPERATORS op)
- {
- m_op = op;
- }
-
-
- STDMETHODIMP_(OPERATORS)
- CArith::get_Op()
- {
- return m_op;
- }
-
-
- STDMETHODIMP_(VARIANT_BOOL)
- CArith::Eval()
- {
- if(m_op == OP_NONE)
- return FALSE;
-
- switch(m_op){
- case OP_PLUS:
- m_accum += m_opnd;
- break;
- case OP_MINUS:
- m_accum -= m_opnd;
- break;
- case OP_MULT:
- m_accum *= m_opnd;
- break;
- case OP_DIV:
- m_accum = (m_opnd == 0) ? 0 : (m_accum / m_opnd);
- break;
- default:
- // ASSERT(UNREACHED);
- return FALSE;
-
- }
-
- m_state = STATE_EVAL;
-
- return VARIANT_TRUE;
- }
-
-
- //---------------------------------------------------------------------
- // User Interface features
- //---------------------------------------------------------------------
-
-
- /***
- *void CArith::Display()
- *Purpose:
- * Display the contents of the register currently being edited.
- *
- *Entry:
- * None
- *
- *Exit:
- * None
- *
- ***********************************************************************/
- STDMETHODIMP_(void)
- CArith::Display()
- {
- VARIANT var;
-
- VariantInit(&var);
- V_VT(&var) = VT_I4;
- V_I4(&var) = (m_state == STATE_ROPND) ? m_opnd : m_accum;
- VariantChangeType(&var, &var, 0, VT_BSTR);
-
- #ifdef _MAC
- {
- Rect rcItem;
- Handle hItem;
- char str[255];
- short sItemKind;
-
- strcpy(str, V_BSTR(&var));
- GetDItem(m_pcalc->m_pdlg, IDC_DISPLAY, &sItemKind, &hItem, &rcItem);
- SetIText(hItem, c2pstr(str));
- }
- #else
- SetDlgItemText(m_pcalc->m_hwnd, IDC_DISPLAY, STRING(V_BSTR(&var)));
- #endif
-
- VariantClear(&var);
- }
-
-
- STDMETHODIMP_(VARIANT_BOOL)
- CArith::Button(SAFEARRAY FAR * psa)
- {
- int i, button;
-
- static struct {
- OLECHAR ch;
- int idc;
- } NEAR rgIdcOfCh[] = {
- { OLESTR('+'), IDC_PLUS }
- , { OLESTR('-'), IDC_MINUS }
- , { OLESTR('*'), IDC_MULT }
- , { OLESTR('/'), IDC_DIV }
- , { OLESTR('C'), IDC_CLEAR }
- , { OLESTR('c'), IDC_CLEAR }
- , { OLESTR('='), IDC_EQUALS }
- , { OLESTR('0'), IDC_ZERO }
- , { OLESTR('1'), IDC_ONE }
- , { OLESTR('2'), IDC_TWO }
- , { OLESTR('3'), IDC_THREE }
- , { OLESTR('4'), IDC_FOUR }
- , { OLESTR('5'), IDC_FIVE }
- , { OLESTR('6'), IDC_SIX }
- , { OLESTR('7'), IDC_SEVEN }
- , { OLESTR('8'), IDC_EIGHT }
- , { OLESTR('9'), IDC_NINE }
- , { (OLECHAR)-1 , -1 }
- };
- LONG saIndex, saUbound;
- VARIANT varButton;
-
- // Since this is a vararg function, we should be given a 1-dimensional
- // array with 0 for the lower bound. The array could be uninitialized
- // if 0 args were passed to us -- this call will give an error in this case.
- if (SafeArrayGetUBound(psa, 1, &saUbound) != NOERROR)
- return FALSE; // most likely 0 args were passed to us
-
- for (saIndex = 0; saIndex <= saUbound; saIndex++) {
-
- // get next parameter
- if (SafeArrayGetElement(psa, &saIndex, &varButton) != NOERROR)
- return FALSE;
-
- // convert it to a string in-place
- if (VariantChangeType(&varButton, &varButton, 0, VT_BSTR) != NOERROR)
- goto Error;
-
- // if the string is more that 1 character long, then we know its wrong.
- if(SysStringLen(varButton.bstrVal) > 1)
- goto Error;
-
- // translate button string into control ID
- for(i = 0;; ++i){
- if(rgIdcOfCh[i].ch == -1)
- goto Error;
- if(rgIdcOfCh[i].ch == varButton.bstrVal[0]){
- button = rgIdcOfCh[i].idc;
- break;
- }
- }
-
- VariantClear(&varButton); // done with the parameter
-
- if (!ButtonPush(button))
- return FALSE;
-
- } // for
-
- return VARIANT_TRUE; // success
-
- Error:
- VariantClear(&varButton);
- return FALSE; // failure
- }
-
-
- // the following method is internal, and not exposed for programmability
- BOOL
- CArith::ButtonPush(int button)
- {
- if(button >= IDC_ZERO && button <= IDC_NINE){
-
- long lVal = button - IDC_ZERO;
-
- switch(m_state){
- case STATE_EVAL:
- m_accum = lVal;
- m_state = STATE_LOPND;
- break;
- case STATE_OP:
- m_opnd = lVal;
- m_state = STATE_ROPND;
- break;
- case STATE_LOPND:
- m_accum = (m_accum * 10) + lVal;
- break;
- case STATE_ROPND:
- m_opnd = (m_opnd * 10) + lVal;
- break;
- }
-
- }else if(button >= IDC_PLUS && button <= IDC_DIV){
-
- if(m_state == STATE_ROPND)
- Eval();
-
- m_opnd = m_accum;
- m_state = STATE_OP;
- m_op = (OPERATORS)(button - IDC_PLUS + OP_PLUS);
-
- }else if(button == IDC_EQUALS){
-
- if(m_state > STATE_LOPND)
- Eval();
-
- }else if (button == IDC_CLEAR){
-
- DCClear();
-
- } else {
-
- return 0; // unknown button
-
- }
-
-
- // Flash the button
-
- #ifdef _MAC
- {
- Rect rcItem;
- long lDummy;
- Handle hItem;
- short sItemKind;
-
- GetDItem(m_pcalc->m_pdlg, button, &sItemKind, &hItem, &rcItem);
- HiliteControl((ControlHandle)hItem, 1);
- Delay(6, &lDummy);
- HiliteControl((ControlHandle)hItem, 0);
- }
- #else
- SendMessage(m_pcalc->m_hwnd, BM_SETSTATE, 1, 0L);
- SendMessage(m_pcalc->m_hwnd, BM_SETSTATE, 0, 0L);
- #endif
-
- // Update the calculator display
-
- Display();
-
- return TRUE;
- }
-
- /***
- *void CArith::Quit()
- *Purpose:
- *
- *Entry:
- * None
- *
- *Exit:
- * None
- *
- ***********************************************************************/
- STDMETHODIMP_(void)
- CArith::Quit()
- {
- #ifndef _MAC
- PostQuitMessage(0);
- #else
- g_fQuit = TRUE;
- #endif
- }
-
-
- //---------------------------------------------------------------------
- // The CCalc Class Factory
- //---------------------------------------------------------------------
-
-
- IClassFactory FAR*
- CCalcCF::Create()
- {
- return new FAR CCalcCF();
- }
-
-
- STDMETHODIMP
- CCalcCF::QueryInterface(REFIID riid, void FAR* FAR* ppv)
- {
- if(IsEqualIID(riid, IID_IUnknown) || IsEqualIID(riid, IID_IClassFactory)){
- AddRef();
- *ppv = this;
- return NOERROR;
- }
- *ppv = NULL;
- return E_NOINTERFACE;
- }
-
-
- STDMETHODIMP_(ULONG)
- CCalcCF::AddRef()
- {
- return ++m_refs;
- }
-
-
- STDMETHODIMP_(ULONG)
- CCalcCF::Release()
- {
- if(--m_refs == 0){
- delete this;
- return 0;
- }
- return m_refs;
- }
-
-
- STDMETHODIMP
- CCalcCF::CreateInstance(
- IUnknown FAR* punkOuter,
- REFIID riid,
- void FAR* FAR* ppv)
- {
- extern CCalc FAR* g_pcalc;
-
- UNUSED(punkOuter);
- return g_pcalc->QueryInterface(riid, ppv);
- }
-
-
- STDMETHODIMP
- #ifdef _MAC
- CCalcCF::LockServer(unsigned long fLock)
- #else
- CCalcCF::LockServer(BOOL fLock)
- #endif
- {
- UNUSED(fLock);
- return NOERROR;
- }
-
- #ifdef _MAC
- struct regentry{
- char *szKey;
- char *szValue;
- } g_rgregentry[] = {
-
- { "CLSID\\{00020469-0000-0000-C000-000000000046}",
- "OLE Automation DspCalc2 1.0 Application" }
-
- , { "CLSID\\{00020469-0000-0000-C000-000000000046}\\LocalServer",
- "DCL2" }
-
- , { "CLSID\\{00020469-0000-0000-C000-000000000046}\\ProgID",
- "Dspcalc2.Application" }
-
- , { "CLSID\\{00020469-0000-0000-C000-000000000046}\\InprocHandler",
- "OLE2:Def$DefFSet" }
-
- , { "DCL2", "{00020469-0000-0000-C000-000000000046}" }
-
- , { "Dspcalc2.Application\\CLSID",
- "{00020469-0000-0000-C000-000000000046}" }
-
- };
-
- HRESULT
- EnsureRegistration()
- {
- HKEY hkey;
-
- if(RegOpenKey(HKEY_CLASSES_ROOT, "DCL2", &hkey) == NOERROR){
- RegCloseKey(hkey);
- return NOERROR;
- }
-
- for(int i = 0; i < DIM(g_rgregentry); ++i){
- if(RegSetValue(HKEY_CLASSES_ROOT, g_rgregentry[i].szKey, REG_SZ, g_rgregentry[i].szValue, 0) != ERROR_SUCCESS)
- return E_FAIL;
- }
-
- return NOERROR;
- }
- #endif //_MAC
-
-
- /***
- *HRESULT InitOle(void)
- *Purpose:
- * Initialize Ole, and register our class factories.
- *
- *Entry:
- * None
- *
- *Exit:
- * None
- *
- ***********************************************************************/
- HRESULT
- InitOle()
- {
- HRESULT hresult;
- IClassFactory FAR* pcf;
-
-
- if((hresult = OleInitialize(NULL)) != NOERROR)
- goto LError0;
-
- #ifdef _MAC
- if((hresult = EnsureRegistration()) != NOERROR)
- goto LError0;
- #endif
-
- // create the single global instance of CCalc
- if((g_pcalc = CCalc::Create()) == NULL){
- hresult = E_OUTOFMEMORY;
- goto LError0;
- }
-
- if((pcf = CCalcCF::Create()) == NULL)
- goto LError1;
-
- hresult = CoRegisterClassObject(
- CLSID_CCalc2,
- pcf,
- CLSCTX_LOCAL_SERVER,
- REGCLS_MULTIPLEUSE,
- &g_dwCCalcCF);
- if(FAILED(hresult))
- goto LError2;
-
- hresult = RegisterActiveObject(
- g_pcalc, CLSID_CCalc2, NULL, &g_dwRegisterCCalc);
- if(FAILED(hresult))
- goto LError2;
-
- pcf->Release();
-
- return NOERROR;
-
- LError2:;
- pcf->Release();
-
- LError1:;
- UninitOle();
-
- LError0:;
- return hresult;
- }
-
-
- HRESULT
- UninitOle()
- {
- if(g_dwRegisterCCalc != 0)
- RevokeActiveObject(g_dwRegisterCCalc, NULL);
-
- if(g_dwCCalcCF != 0)
- CoRevokeClassObject(g_dwCCalcCF);
-
- // cause the remaining typeinfo to be released
- if(g_pcalc != NULL)
- g_pcalc->Release();
-
- OleUninitialize();
-
- return NOERROR;
- }
-