Windows NT 4.0 source code leak
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

689 lines
13 KiB

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