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.

609 lines
12 KiB

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