Leaked source code of windows server 2003
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.

9790 lines
241 KiB

  1. #include "precomp.h"
  2. //
  3. // WB.CPP
  4. // Whiteboard Services
  5. //
  6. // Copyright(c) Microsoft 1997-
  7. //
  8. #include <wb.hpp>
  9. #define MLZ_FILE_ZONE ZONE_WB
  10. //
  11. // Constructor
  12. //
  13. BOOL WbClient::WbInit(PUT_CLIENT putTask, UTEVENT_PROC eventProc)
  14. {
  15. BOOL rc = FALSE;
  16. DebugEntry(WbInit);
  17. //
  18. // Fill in the fields
  19. //
  20. m_state = STATE_EMPTY;
  21. m_subState = STATE_EMPTY;
  22. m_hLoadFile = INVALID_HANDLE_VALUE;
  23. wbClientReset();
  24. //
  25. // Set the current state to the start of registration state.
  26. // Store the UT handle - we will need this in any calls to the UT API.
  27. // Set the ObMan handle to NULL to show that we have not registered.
  28. //
  29. m_state = STATE_STARTING;
  30. m_subState = STATE_START_START;
  31. m_putTask = putTask;
  32. m_pomClient = NULL;
  33. UT_RegisterEvent(putTask, eventProc, NULL, UT_PRIORITY_NORMAL);
  34. TRACE_OUT(("Initialized state to STATE_STARTING"));
  35. //
  36. // Register an event handler to trap events from ObMan. The third
  37. // parameter is data that will be passed to the event handler. We give
  38. // the client data pointer so that we can access the correct data for
  39. // each message.
  40. //
  41. UT_RegisterEvent(putTask, wbCoreEventHandler, this, UT_PRIORITY_NORMAL);
  42. //
  43. // Register as a Call Manager Secondary. This is required to query the
  44. // Call Manager personID to insert into the WB_PERSON structure.
  45. //
  46. if (!CMS_Register(putTask, CMTASK_WB, &(m_pcmClient)))
  47. {
  48. ERROR_OUT(("CMS_Register failed"));
  49. DC_QUIT;
  50. }
  51. //
  52. // Update the state
  53. //
  54. m_subState = STATE_START_REGISTERED_EVENT;
  55. TRACE_OUT(("Moved to substate STATE_START_REGISTERED_EVENT"));
  56. //
  57. // Register with ObMan as a client
  58. //
  59. if (OM_Register(putTask, OMCLI_WB, &(m_pomClient)) != 0)
  60. {
  61. ERROR_OUT(("OM_Register failed"));
  62. DC_QUIT;
  63. }
  64. //
  65. // Update the state
  66. //
  67. m_subState = STATE_START_REGISTERED_OM;
  68. TRACE_OUT(("Moved to substate STATE_START_REGISTERED_OM"));
  69. //
  70. // Register an exit handler. This has to be done after registering with
  71. // ObMan so that it gets called before the exit procedure registered by
  72. // ObMan.
  73. //
  74. UT_RegisterExit(putTask, wbCoreExitHandler, this);
  75. //
  76. // Update the state
  77. //
  78. m_state = STATE_STARTED;
  79. m_subState = STATE_STARTED_START;
  80. rc = TRUE;
  81. DC_EXIT_POINT:
  82. DebugExitBOOL(WbInit, rc);
  83. return(rc);
  84. }
  85. //
  86. // CreateWBObject()
  87. //
  88. BOOL WINAPI CreateWBObject
  89. (
  90. UTEVENT_PROC eventProc,
  91. IWbClient** ppwbClient
  92. )
  93. {
  94. BOOL rc = FALSE;
  95. WbClient* pwbClient = NULL;
  96. PUT_CLIENT putTask = NULL;
  97. DebugEntry(CreateWBObject);
  98. //
  99. // Initialize the WB task
  100. //
  101. if (!UT_InitTask(UTTASK_WB, &putTask))
  102. {
  103. ERROR_OUT(("Can't register WB task"));
  104. DC_QUIT;
  105. }
  106. //
  107. // Allocate the WB client object
  108. //
  109. pwbClient = new WbClient();
  110. if (!pwbClient)
  111. {
  112. ERROR_OUT(("Couldn't allocate WbClient object"));
  113. UT_TermTask(&putTask);
  114. DC_QUIT;
  115. }
  116. else
  117. {
  118. rc = pwbClient->WbInit(putTask, eventProc);
  119. if (!rc)
  120. {
  121. pwbClient->WBP_Stop(eventProc);
  122. pwbClient = NULL;
  123. }
  124. }
  125. DC_EXIT_POINT:
  126. *ppwbClient = (IWbClient *)pwbClient;
  127. DebugExitBOOL(CreateWBObject, rc);
  128. return(rc);
  129. }
  130. //
  131. // WBP_Stop()
  132. //
  133. STDMETHODIMP_(void) WbClient::WBP_Stop(UTEVENT_PROC eventProc)
  134. {
  135. PUT_CLIENT putTask;
  136. DebugEntry(WBP_Stop);
  137. //
  138. // UT_TermTask() will call our exit handler and cause cleanup.
  139. //
  140. putTask = m_putTask;
  141. UT_DeregisterEvent(putTask, eventProc, NULL);
  142. // NOTE:
  143. // UT_TermTask() will put NULL into the pointer you pass in after it
  144. // has finished. But part of its job is to call your exit proc. Our
  145. // exit handler will call 'delete this' to kill us off. So when it
  146. // winds back to UT_TermTask(), the UT_CLIENT* pointer will be invalid.
  147. // That's why we use a temp. variable.
  148. //
  149. UT_TermTask(&putTask);
  150. DebugExitVOID(WBP_Stop);
  151. }
  152. //
  153. // WBP_PostEvent()
  154. //
  155. // Post an event back to the WB applet after a delay
  156. //
  157. STDMETHODIMP_(void) WbClient::WBP_PostEvent
  158. (
  159. UINT delay,
  160. UINT event,
  161. UINT_PTR param1,
  162. UINT_PTR param2
  163. )
  164. {
  165. DebugEntry(WBP_PostEvent);
  166. UT_PostEvent(m_putTask, m_putTask, delay, event, param1, param2);
  167. DebugExitVOID(WBP_PostEvent);
  168. }
  169. //
  170. // WBP_JoinCall
  171. //
  172. STDMETHODIMP_(UINT) WbClient::WBP_JoinCall
  173. (
  174. BOOL bContentsKeep,
  175. UINT callID
  176. )
  177. {
  178. UINT result = 0;
  179. DebugEntry(WBP_JoinCall);
  180. TRACE_OUT(("Keep contents = %s", (bContentsKeep) ? "TRUE" : "FALSE"));
  181. TRACE_OUT(("Call ID = %d", callID));
  182. //
  183. // If we are to keep the existing contents, just move our workset group
  184. // into the specified call.
  185. //
  186. if (bContentsKeep)
  187. {
  188. result = OM_WSGroupMoveReq(m_pomClient, m_hWSGroup, callID,
  189. &(m_wsgroupCorrelator));
  190. if (result != 0)
  191. {
  192. ERROR_OUT(("OM_WSGroupMoveReq failed"));
  193. DC_QUIT;
  194. }
  195. //
  196. // The move request was successful, change the state to show that we
  197. // are waiting for a move request to complete.
  198. //
  199. m_state = STATE_REGISTERING;
  200. m_subState = STATE_REG_PENDING_WSGROUP_MOVE;
  201. TRACE_OUT(("Moved to substate STATE_REG_PENDING_WSGROUP_MOVE"));
  202. DC_QUIT;
  203. }
  204. //
  205. // Leave the current call. This returns the client state to what it
  206. // should be after a wbStart call.
  207. //
  208. wbLeaveCall();
  209. //
  210. // Register with the workset group
  211. //
  212. result = OM_WSGroupRegisterPReq(m_pomClient, callID,
  213. OMFP_WB, OMWSG_WB, &(m_wsgroupCorrelator));
  214. if (result != 0)
  215. {
  216. ERROR_OUT(("OM_WSGroupRegisterReq failed, result = %d", result));
  217. DC_QUIT;
  218. }
  219. //
  220. // Update the state
  221. //
  222. m_state = STATE_REGISTERING;
  223. m_subState = STATE_REG_PENDING_WSGROUP_CON;
  224. TRACE_OUT(("Moved to state STATE_REGISTERING"));
  225. TRACE_OUT(("Moved to substate STATE_REG_PENDING_WSGROUP_CON"));
  226. DC_EXIT_POINT:
  227. DebugExitDWORD(WBP_JoinCall, result);
  228. return(result);
  229. }
  230. //
  231. // WBP_ContentsDelete
  232. //
  233. STDMETHODIMP_(UINT) WbClient::WBP_ContentsDelete(void)
  234. {
  235. UINT result = 0;
  236. DebugEntry(WBP_ContentsDelete);
  237. //
  238. // Make sure that we have the Page Order Lock
  239. //
  240. QUIT_NOT_GOT_PAGE_ORDER_LOCK(result);
  241. //
  242. // Request the lock
  243. //
  244. wbContentsDelete(RESET_CHANGED_FLAG);
  245. //
  246. // Reset the flag indicating that the contents have changed
  247. //
  248. m_changed = FALSE;
  249. DC_EXIT_POINT:
  250. DebugExitDWORD(WBP_ContentsDelete, result);
  251. return(result);
  252. }
  253. //
  254. // WBP_ContentsLoad
  255. //
  256. STDMETHODIMP_(UINT) WbClient::WBP_ContentsLoad(LPCSTR pFileName)
  257. {
  258. UINT result = 0;
  259. HANDLE hFile;
  260. DebugEntry(WBP_ContentsLoad);
  261. //
  262. // Check that we have the lock
  263. //
  264. QUIT_NOT_GOT_PAGE_ORDER_LOCK(result);
  265. //
  266. // Check the load state
  267. //
  268. if (m_loadState != LOAD_STATE_EMPTY)
  269. {
  270. result = WB_RC_ALREADY_LOADING;
  271. DC_QUIT;
  272. }
  273. //
  274. // Validate the file, and get a handle to it.
  275. // If there is an error, then no file handle is returned.
  276. //
  277. result = WBP_ValidateFile(pFileName, &hFile);
  278. if (result != 0)
  279. {
  280. ERROR_OUT(("Bad file header"));
  281. DC_QUIT;
  282. }
  283. //
  284. // Save the file handle for the rest of the load process
  285. //
  286. m_hLoadFile = hFile;
  287. //
  288. // We now need to make sure that the contents are deleted before we start
  289. // adding the new objects.
  290. //
  291. wbContentsDelete(DONT_RESET_CHANGED_FLAG);
  292. //
  293. // Update the load state to show that we are waiting for the contents
  294. // delete to complete.
  295. //
  296. m_loadState = LOAD_STATE_PENDING_CLEAR;
  297. TRACE_OUT(("Moved load state to LOAD_STATE_PENDING_CLEAR"));
  298. DC_EXIT_POINT:
  299. DebugExitDWORD(WBP_ContentsLoad, result);
  300. return(result);
  301. }
  302. //
  303. // WBP_ContentsSave
  304. //
  305. STDMETHODIMP_(UINT) WbClient::WBP_ContentsSave(LPCSTR pFileName)
  306. {
  307. UINT result = 0;
  308. UINT index;
  309. HANDLE hFile;
  310. PWB_PAGE_ORDER pPageOrder = &(m_pageOrder);
  311. WB_FILE_HEADER fileHeader;
  312. WB_END_OF_FILE endOfFile;
  313. DebugEntry(WBP_ContentsSave);
  314. //
  315. // Open the file
  316. //
  317. hFile = CreateFile(pFileName, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS,
  318. FILE_ATTRIBUTE_NORMAL, 0);
  319. if (hFile == INVALID_HANDLE_VALUE)
  320. {
  321. result = WB_RC_CREATE_FAILED;
  322. ERROR_OUT(("Error creating file, win32 err=%d", GetLastError()));
  323. DC_QUIT;
  324. }
  325. //
  326. // Write the file header. This contains the name of the function profile
  327. // that wrote the file and allows the file type to be tested when it is
  328. // loaded.
  329. //
  330. ZeroMemory(&fileHeader, sizeof(fileHeader));
  331. fileHeader.length = sizeof(fileHeader);
  332. fileHeader.type = TYPE_FILE_HEADER;
  333. lstrcpy(fileHeader.functionProfile, WB_FP_NAME);
  334. result = wbObjectSave(hFile, (LPBYTE) &fileHeader, sizeof(fileHeader));
  335. if (result != 0)
  336. {
  337. ERROR_OUT(("Error writing end-of-page = %d", result));
  338. DC_QUIT;
  339. }
  340. //
  341. // Loop through the pages, saving each as we go
  342. //
  343. for (index = 0; index < pPageOrder->countPages; index++)
  344. {
  345. //
  346. // Save the page
  347. //
  348. result = wbPageSave((WB_PAGE_HANDLE)pPageOrder->pages[index], hFile);
  349. if (result != 0)
  350. {
  351. ERROR_OUT(("Error saving page = %d", result));
  352. DC_QUIT;
  353. }
  354. }
  355. //
  356. // If we have successfully written the contents, we write an end-of-page
  357. // marker to the file.
  358. //
  359. ZeroMemory(&endOfFile, sizeof(endOfFile));
  360. endOfFile.length = sizeof(endOfFile);
  361. endOfFile.type = TYPE_END_OF_FILE;
  362. //
  363. // Write the end-of-file object
  364. //
  365. result = wbObjectSave(hFile, (LPBYTE) &endOfFile, sizeof(endOfFile));
  366. if (result != 0)
  367. {
  368. ERROR_OUT(("Error writing end-of-page = %d", result));
  369. DC_QUIT;
  370. }
  371. //
  372. // Success!
  373. //
  374. TRACE_OUT(("Resetting changed flag"));
  375. m_changed = FALSE;
  376. DC_EXIT_POINT:
  377. //
  378. // Close the file
  379. //
  380. if (hFile != INVALID_HANDLE_VALUE)
  381. {
  382. CloseHandle(hFile);
  383. }
  384. //
  385. // If an error occurred in saving the contents to file, and the file was
  386. // opened, then delete it.
  387. //
  388. if (result != 0)
  389. {
  390. //
  391. // If the file was opened successfully, close it
  392. //
  393. if (hFile != INVALID_HANDLE_VALUE)
  394. {
  395. DeleteFile(pFileName);
  396. }
  397. }
  398. DebugExitDWORD(WBP_ContentsSave, result);
  399. return(result);
  400. }
  401. //
  402. // WBP_ContentsChanged
  403. //
  404. STDMETHODIMP_(BOOL) WbClient::WBP_ContentsChanged(void)
  405. {
  406. BOOL changed = FALSE;
  407. UINT result;
  408. WB_PAGE_HANDLE hPage;
  409. POM_OBJECT pObj;
  410. DebugEntry(WBP_ContentsChanged);
  411. TRACE_OUT(("changed %d", m_changed));
  412. if (m_changed)
  413. {
  414. //
  415. // The whiteboard may have been changed, but if the change was to
  416. // empty it then don't bother. This is because we cannot detect that
  417. // the New operation was a local New or a remote clear and so we would
  418. // always prompt after New. Assuming that the user never needs to
  419. // always prompt after New. Assuming that the user will manually save
  420. // an workset he really wants to empty solves this problem.
  421. //
  422. //
  423. // Scan all objects looking to see what is there - get handle to first
  424. // page
  425. //
  426. result = wbPageHandle(WB_PAGE_HANDLE_NULL, PAGE_FIRST, &hPage);
  427. while (result == 0)
  428. {
  429. //
  430. // Get the handle of the first object in the page workset.
  431. //
  432. result = OM_ObjectH(m_pomClient, m_hWSGroup,
  433. (OM_WORKSET_ID)hPage, 0, &pObj, FIRST);
  434. if (result != OM_RC_NO_SUCH_OBJECT)
  435. {
  436. changed = TRUE;
  437. break;
  438. }
  439. //
  440. // Try the next page for an object
  441. //
  442. result = wbPageHandle(hPage, PAGE_AFTER, &hPage);
  443. }
  444. }
  445. DebugExitBOOL(WBP_ContentsChanged, changed);
  446. return(changed);
  447. }
  448. //
  449. // WBP_ContentsLock
  450. //
  451. STDMETHODIMP_(void) WbClient::WBP_ContentsLock(void)
  452. {
  453. UINT result;
  454. DebugEntry(WBP_ContentsLock);
  455. //
  456. // Check that there is no lock currently
  457. //
  458. QUIT_LOCKED(result);
  459. QUIT_IF_CANCELLING_LOCK(result, WB_RC_BUSY);
  460. //
  461. // Request the lock
  462. //
  463. result = wbLock(WB_LOCK_TYPE_CONTENTS);
  464. if (result != 0)
  465. {
  466. WBP_PostEvent(0, WBP_EVENT_LOCK_FAILED, result, 0);
  467. }
  468. DC_EXIT_POINT:
  469. DebugExitVOID(WBP_ContentsLock);
  470. }
  471. //
  472. // WBP_PageOrderLock
  473. //
  474. STDMETHODIMP_(void) WbClient::WBP_PageOrderLock(void)
  475. {
  476. UINT result = 0;
  477. DebugEntry(WBP_PageOrderLock);
  478. //
  479. // Check that there is no lock currently
  480. //
  481. QUIT_LOCKED(result);
  482. //
  483. // Check that we are not in the process of cancelling a lock request
  484. //
  485. QUIT_IF_CANCELLING_LOCK(result, WB_RC_BUSY);
  486. //
  487. // Request the lock
  488. //
  489. result = wbLock(WB_LOCK_TYPE_PAGE_ORDER);
  490. if (result != 0)
  491. {
  492. WBP_PostEvent(0, WBP_EVENT_LOCK_FAILED, result, 0);
  493. }
  494. DC_EXIT_POINT:
  495. DebugExitVOID(WBP_PageOrderLock);
  496. }
  497. //
  498. // WBP_Unlock
  499. //
  500. STDMETHODIMP_(void) WbClient::WBP_Unlock(void)
  501. {
  502. UINT result = 0;
  503. DebugEntry(WBP_Unlock);
  504. //
  505. // If we are currently procesing a lock cancel request, leave the
  506. // function - it should unlock soon anyway.
  507. //
  508. QUIT_IF_CANCELLING_LOCK(result, 0);
  509. //
  510. // Check that we are currently processing a lock - the lock need not
  511. // necessarily have completed as we allow an application to call
  512. // WBP_Unlock any time after it has called WBP_Lock, effectively
  513. // cancelling a lock request.
  514. //
  515. QUIT_NOT_PROCESSING_LOCK(result);
  516. //
  517. // If we have completed the last lock request, simply do the unlock:
  518. //
  519. // The lock is not yet released, but will be when the
  520. // OM_OBJECT_DELETE_IND is received.
  521. //
  522. //
  523. if (m_lockState == LOCK_STATE_GOT_LOCK)
  524. {
  525. TRACE_OUT(("Unlock"));
  526. wbUnlock();
  527. }
  528. else
  529. {
  530. //
  531. // Otherwise we are part way through processing the last lock and need
  532. // to cancel the lock on the next OM/lock event. e.g. when we receive
  533. // the OM_WS_LOCK indication, we should abandon lock processing and
  534. // unlock the WS.
  535. //
  536. TRACE_OUT((
  537. "Part way through last lock set state to LOCK_STATE_CANCEL_LOCK"));
  538. m_lockState = LOCK_STATE_CANCEL_LOCK;
  539. }
  540. DC_EXIT_POINT:
  541. DebugExitVOID(WBP_Unlock);
  542. }
  543. //
  544. // WBP_LockStatus
  545. //
  546. STDMETHODIMP_(WB_LOCK_TYPE) WbClient::WBP_LockStatus(POM_OBJECT *ppObjPersonLock)
  547. {
  548. DebugEntry(WBP_LockStatus);
  549. *ppObjPersonLock = m_pObjPersonLock;
  550. DebugExitDWORD(WBP_LockStatus, m_lockType);
  551. return(m_lockType);
  552. }
  553. //
  554. // WBP_ContentsCountPages
  555. //
  556. STDMETHODIMP_(UINT) WbClient::WBP_ContentsCountPages(void)
  557. {
  558. UINT countPages;
  559. DebugEntry(WBP_ContentsCountPages);
  560. countPages = (m_pageOrder).countPages;
  561. DebugExitDWORD(WBP_ContentsCountPages, countPages);
  562. return(countPages);
  563. }
  564. //
  565. // WBP_PageClear
  566. //
  567. STDMETHODIMP_(UINT) WbClient::WBP_PageClear
  568. (
  569. WB_PAGE_HANDLE hPage
  570. )
  571. {
  572. UINT result = 0;
  573. DebugEntry(WBP_PageClear);
  574. QUIT_CONTENTS_LOCKED(result);
  575. result = wbPageClear(hPage, RESET_CHANGED_FLAG);
  576. DC_EXIT_POINT:
  577. DebugExitDWORD(WBP_PageClear, result);
  578. return(result);
  579. }
  580. //
  581. // WBP_PageClearConfirm
  582. //
  583. STDMETHODIMP_(void) WbClient::WBP_PageClearConfirm
  584. (
  585. WB_PAGE_HANDLE hPage
  586. )
  587. {
  588. DebugEntry(WBP_PageClearConfirm);
  589. wbPageClearConfirm(hPage);
  590. DebugExitVOID(WBP_PageClearConfirm);
  591. }
  592. //
  593. // WBP_PageAddBefore - See wb.h
  594. //
  595. STDMETHODIMP_(UINT) WbClient::WBP_PageAddBefore
  596. (
  597. WB_PAGE_HANDLE hRefPage,
  598. PWB_PAGE_HANDLE phPage
  599. )
  600. {
  601. UINT result = 0;
  602. DebugEntry(WBP_PageAddBefore);
  603. //
  604. // Make sure that we have the page order lock
  605. //
  606. QUIT_NOT_GOT_PAGE_ORDER_LOCK(result);
  607. //
  608. // Add a new page before the specified page
  609. //
  610. result = wbPageAdd(hRefPage, PAGE_BEFORE, phPage,
  611. RESET_CHANGED_FLAG);
  612. DC_EXIT_POINT:
  613. DebugExitDWORD(WBP_PageAddBefore, result);
  614. return(result);
  615. }
  616. //
  617. // WBP_PageAddAfter - See wb.h
  618. //
  619. STDMETHODIMP_(UINT) WbClient::WBP_PageAddAfter
  620. (
  621. WB_PAGE_HANDLE hRefPage,
  622. PWB_PAGE_HANDLE phPage
  623. )
  624. {
  625. UINT result = 0;
  626. DebugEntry(WBP_PageAddAfter);
  627. //
  628. // Make sure that we have the Page Order Lock
  629. //
  630. QUIT_NOT_GOT_PAGE_ORDER_LOCK(result);
  631. //
  632. // Add a new page before the specified page
  633. //
  634. result = wbPageAdd(hRefPage, PAGE_AFTER, phPage,
  635. RESET_CHANGED_FLAG);
  636. DC_EXIT_POINT:
  637. DebugExitDWORD(WBP_PageAddAfter, result);
  638. return(result);
  639. }
  640. //
  641. // WBP_PageHandle - See wb.h
  642. //
  643. STDMETHODIMP_(UINT) WbClient::WBP_PageHandle
  644. (
  645. WB_PAGE_HANDLE hRefPage,
  646. UINT where,
  647. PWB_PAGE_HANDLE phPage
  648. )
  649. {
  650. UINT result;
  651. DebugEntry(WBP_PageHandle);
  652. result = wbPageHandle(hRefPage, where, phPage);
  653. DebugExitDWORD(WBP_PageHandle, result);
  654. return(result);
  655. }
  656. //
  657. // WBP_PageHandleFromNumber
  658. //
  659. STDMETHODIMP_(UINT) WbClient::WBP_PageHandleFromNumber
  660. (
  661. UINT pageNumber,
  662. PWB_PAGE_HANDLE phPage
  663. )
  664. {
  665. UINT result;
  666. DebugEntry(WBP_PageHandleFromNumber);
  667. result = wbPageHandleFromNumber(pageNumber, phPage);
  668. DebugExitDWORD(WBP_PageHandleFromNumber, result);
  669. return(result);
  670. }
  671. //
  672. // WBP_PageNumberFromHandle
  673. //
  674. STDMETHODIMP_(UINT) WbClient::WBP_PageNumberFromHandle
  675. (
  676. WB_PAGE_HANDLE hPage
  677. )
  678. {
  679. UINT pageNumber = 0;
  680. DebugEntry(WBP_PageNumberFromHandle);
  681. if ((hPage < FIRST_PAGE_WORKSET) || (hPage > FIRST_PAGE_WORKSET + WB_MAX_PAGES - 1))
  682. {
  683. WARNING_OUT(("WB: Invalid hPage=%u", (UINT) hPage));
  684. DC_QUIT;
  685. }
  686. //
  687. // Validate the page handle given
  688. //
  689. if (GetPageState(hPage)->state != PAGE_IN_USE)
  690. {
  691. DC_QUIT;
  692. }
  693. pageNumber = wbPageOrderPageNumber(&(m_pageOrder), hPage);
  694. DC_EXIT_POINT:
  695. DebugExitDWORD(WBP_PageNumberFromHandle, pageNumber);
  696. return(pageNumber);
  697. }
  698. //
  699. // WBP_PageDelete - See wb.h
  700. //
  701. STDMETHODIMP_(UINT) WbClient::WBP_PageDelete
  702. (
  703. WB_PAGE_HANDLE hPage
  704. )
  705. {
  706. UINT result = 0;
  707. PWB_PAGE_STATE pPageState;
  708. DebugEntry(WBP_PageDelete);
  709. //
  710. // Make sure that we have the Page Order Lock
  711. //
  712. QUIT_NOT_GOT_PAGE_ORDER_LOCK(result);
  713. //
  714. // Delete the page
  715. //
  716. //
  717. // Check whether the page is already being deleted
  718. //
  719. pPageState = GetPageState(hPage);
  720. if ( (pPageState->state == PAGE_IN_USE)
  721. && (pPageState->subState == PAGE_STATE_EMPTY))
  722. {
  723. //
  724. // Set the page state to show that it is now in the delete process
  725. //
  726. pPageState->subState = PAGE_STATE_LOCAL_DELETE;
  727. TRACE_OUT(("Moved page %d substate to PAGE_STATE_LOCAL_DELETE",
  728. hPage));
  729. //
  730. // Update the page control object
  731. //
  732. if (wbWritePageControl(FALSE) != 0)
  733. {
  734. wbError();
  735. DC_QUIT;
  736. }
  737. }
  738. DC_EXIT_POINT:
  739. DebugExitDWORD(WBP_PageDelete, result);
  740. return(result);
  741. }
  742. //
  743. // WBP_PageDeleteConfirm - See wb.h
  744. //
  745. STDMETHODIMP_(void) WbClient::WBP_PageDeleteConfirm
  746. (
  747. WB_PAGE_HANDLE hPage
  748. )
  749. {
  750. UINT result = 0;
  751. PWB_PAGE_ORDER pPageOrder;
  752. PWB_PAGE_STATE pPageState;
  753. DebugEntry(WBP_PageDeleteConfirm);
  754. //
  755. // Validate the specified page
  756. //
  757. ASSERT(GetPageState(hPage)->state == PAGE_IN_USE);
  758. //
  759. // Delete the page
  760. //
  761. //
  762. // Check that the page specified is waiting for a delete confirm
  763. //
  764. pPageState = GetPageState(hPage);
  765. ASSERT(((pPageState->subState == PAGE_STATE_LOCAL_DELETE_CONFIRM) ||
  766. (pPageState->subState == PAGE_STATE_EXTERNAL_DELETE_CONFIRM)));
  767. //
  768. // Delete the page from the page order
  769. //
  770. pPageOrder = &(m_pageOrder);
  771. wbPageOrderPageDelete(pPageOrder, hPage);
  772. //
  773. // Clear the page (to free memory)
  774. //
  775. if (pPageState->subState == PAGE_STATE_LOCAL_DELETE_CONFIRM)
  776. {
  777. TRACE_OUT(("Local delete - clearing the page"));
  778. if (wbPageClear(hPage, RESET_CHANGED_FLAG) != 0)
  779. {
  780. ERROR_OUT(("Unable to clear page"));
  781. DC_QUIT;
  782. }
  783. }
  784. //
  785. // Update the page state to "not in use", with a substate of "ready" (we
  786. // do not close the associated workset.
  787. //
  788. pPageState->state = PAGE_NOT_IN_USE;
  789. pPageState->subState = PAGE_STATE_READY;
  790. TRACE_OUT(("Moved page %d state to PAGE_NOT_IN_USE", hPage));
  791. //
  792. // Continue updating the Page Order
  793. //
  794. wbProcessPageControlChanges();
  795. //
  796. // Check the load state to see whether we are waiting to load the
  797. // contents
  798. //
  799. if (m_loadState == LOAD_STATE_PENDING_DELETE)
  800. {
  801. //
  802. // We are waiting to load. If there is now only one page available, we
  803. // are ready to load, otherwise we wait for the further page deletes to
  804. // happen.
  805. //
  806. if (m_pageOrder.countPages == 1)
  807. {
  808. //
  809. // Start the load proper
  810. //
  811. wbStartContentsLoad();
  812. }
  813. }
  814. DC_EXIT_POINT:
  815. DebugExitVOID(WBP_PageDeleteConfirm);
  816. }
  817. //
  818. // WBP_PageMoveAfter
  819. //
  820. STDMETHODIMP_(UINT) WbClient::WBP_PageMove
  821. (
  822. WB_PAGE_HANDLE hRefPage,
  823. WB_PAGE_HANDLE hPage,
  824. UINT where
  825. )
  826. {
  827. UINT result = 0;
  828. DebugEntry(WBP_PageMove);
  829. //
  830. // Make sure that we have the Page Order Lock
  831. //
  832. QUIT_NOT_GOT_PAGE_ORDER_LOCK(result);
  833. //
  834. // Validate the specified page handles
  835. //
  836. ASSERT(GetPageState(hPage)->state == PAGE_IN_USE);
  837. ASSERT(GetPageState(hRefPage)->state == PAGE_IN_USE);
  838. //
  839. // Move the page
  840. //
  841. result = wbPageMove(hRefPage, hPage, where);
  842. DC_EXIT_POINT:
  843. DebugExitDWORD(WBP_PageMove, result);
  844. return(result);
  845. }
  846. //
  847. // WBP_PageCountGraphics
  848. //
  849. STDMETHODIMP_(UINT) WbClient::WBP_PageCountGraphics
  850. (
  851. WB_PAGE_HANDLE hPage
  852. )
  853. {
  854. UINT count;
  855. DebugEntry(WBP_PageCountGraphics);
  856. //
  857. // Count the number of graphics on the page
  858. //
  859. OM_WorksetCountObjects(m_pomClient, m_hWSGroup,
  860. (OM_WORKSET_ID)hPage, &count);
  861. DebugExitDWORD(WBP_PageCountGraphics, count);
  862. return(count);
  863. }
  864. //
  865. // WBP_GraphicAllocate
  866. //
  867. STDMETHODIMP_(UINT) WbClient::WBP_GraphicAllocate
  868. (
  869. WB_PAGE_HANDLE hPage,
  870. UINT length,
  871. PPWB_GRAPHIC ppGraphic
  872. )
  873. {
  874. UINT result = 0;
  875. POM_OBJECTDATA pData;
  876. DebugEntry(WBP_GraphicAllocate);
  877. //
  878. // Check that the page handle is valid
  879. //
  880. ASSERT(GetPageState(hPage)->state == PAGE_IN_USE);
  881. //
  882. // Allocate a graphic object
  883. //
  884. result = OM_ObjectAlloc(m_pomClient, m_hWSGroup,
  885. (OM_WORKSET_ID)hPage, length, &pData);
  886. if (result != 0)
  887. {
  888. ERROR_OUT(("OM_ObjectAlloc = %d", result));
  889. DC_QUIT;
  890. }
  891. //
  892. // Set the length of the object
  893. //
  894. pData->length = length;
  895. //
  896. // Convert the ObMan pointer to a core pointer
  897. //
  898. *ppGraphic = GraphicPtrFromObjectData(pData);
  899. //
  900. // Initialize the graphic header
  901. //
  902. ZeroMemory(*ppGraphic, sizeof(WB_GRAPHIC));
  903. DC_EXIT_POINT:
  904. DebugExitDWORD(WBP_GraphicAllocate, result);
  905. return(result);
  906. }
  907. //
  908. // WBP_GraphicAddLast
  909. //
  910. STDMETHODIMP_(UINT) WbClient::WBP_GraphicAddLast
  911. (
  912. WB_PAGE_HANDLE hPage,
  913. PWB_GRAPHIC pGraphic,
  914. PWB_GRAPHIC_HANDLE phGraphic
  915. )
  916. {
  917. UINT result = 0;
  918. POM_OBJECTDATA pData;
  919. PWB_PAGE_STATE pPageState;
  920. DebugEntry(WBP_GraphicAddLast);
  921. //
  922. // Check whether another person has an active contents lock
  923. //
  924. QUIT_CONTENTS_LOCKED(result);
  925. //
  926. // Check that the page handle is valid
  927. //
  928. ASSERT(GetPageState(hPage)->state == PAGE_IN_USE);
  929. //
  930. // If the Client is asking for the lock, copy the local person ID into
  931. // the graphic object.
  932. //
  933. if (pGraphic->locked == WB_GRAPHIC_LOCK_LOCAL)
  934. {
  935. pGraphic->lockPersonID = m_personID;
  936. }
  937. //
  938. // Check whether the page has been deleted but not yet confirmed: in this
  939. // case return OK but do not add the object to the workset.
  940. //
  941. pPageState = GetPageState(hPage);
  942. if ( (pPageState->subState == PAGE_STATE_EXTERNAL_DELETE)
  943. || (pPageState->subState == PAGE_STATE_EXTERNAL_DELETE_CONFIRM))
  944. {
  945. TRACE_OUT(("Object add requested in externally deleted page - ignored"));
  946. *phGraphic = 0;
  947. DC_QUIT;
  948. }
  949. //
  950. // Add the graphic object to the page
  951. //
  952. pData = ObjectDataPtrFromGraphic(pGraphic);
  953. result = OM_ObjectAdd(m_pomClient,
  954. m_hWSGroup,
  955. (OM_WORKSET_ID)hPage,
  956. &pData,
  957. sizeof(WB_GRAPHIC),
  958. phGraphic,
  959. LAST);
  960. if (result != 0)
  961. {
  962. ERROR_OUT(("OM_ObjectAdd = %d", result));
  963. DC_QUIT;
  964. }
  965. DC_EXIT_POINT:
  966. DebugExitDWORD(WBP_GraphicAddLast, result);
  967. return(result);
  968. }
  969. //
  970. // WBP_GraphicUpdateRequest
  971. //
  972. STDMETHODIMP_(UINT) WbClient::WBP_GraphicUpdateRequest
  973. (
  974. WB_PAGE_HANDLE hPage,
  975. WB_GRAPHIC_HANDLE hGraphic,
  976. PWB_GRAPHIC pGraphic
  977. )
  978. {
  979. UINT result = 0;
  980. POM_OBJECTDATA pData;
  981. PWB_PAGE_STATE pPageState;
  982. DebugEntry(WBP_GraphicUpdateRequest);
  983. //
  984. // Check that the page handle is valid
  985. //
  986. ASSERT(GetPageState(hPage)->state == PAGE_IN_USE);
  987. //
  988. // Check whether another person has an active contents lock
  989. //
  990. QUIT_CONTENTS_LOCKED(result);
  991. //
  992. // Check whether another person has the graphic locked
  993. //
  994. QUIT_GRAPHIC_LOCKED(hPage, hGraphic, result);
  995. //
  996. // If the Client is asking for the lock, copy the local person ID into
  997. // the graphic object.
  998. //
  999. if (pGraphic->locked == WB_GRAPHIC_LOCK_LOCAL)
  1000. {
  1001. pGraphic->lockPersonID = m_personID;
  1002. }
  1003. //
  1004. // Check whether the page has been deleted but not yet confirmed
  1005. //
  1006. pPageState = GetPageState(hPage);
  1007. if ( (pPageState->subState == PAGE_STATE_EXTERNAL_DELETE)
  1008. || (pPageState->subState == PAGE_STATE_EXTERNAL_DELETE_CONFIRM))
  1009. {
  1010. TRACE_OUT(("Object update requested in externally deleted page - ignored"));
  1011. DC_QUIT;
  1012. }
  1013. //
  1014. // Update the object
  1015. //
  1016. pData = ObjectDataPtrFromGraphic(pGraphic);
  1017. result = OM_ObjectUpdate(m_pomClient,
  1018. m_hWSGroup,
  1019. (OM_WORKSET_ID)hPage,
  1020. hGraphic,
  1021. &pData);
  1022. //
  1023. // Dont worry too much if the update fails because the object has been
  1024. // deleted, just trace an alert and return OK - the front end will be
  1025. // told that the object has gone later.
  1026. //
  1027. if (result != 0)
  1028. {
  1029. if (result == OM_RC_OBJECT_DELETED)
  1030. {
  1031. TRACE_OUT(("Update failed because object has been deleted"));
  1032. result = 0;
  1033. DC_QUIT;
  1034. }
  1035. ERROR_OUT(("OM_ObjectUpdate = %d", result));
  1036. DC_QUIT;
  1037. }
  1038. //
  1039. // Note that the object has not yet been updated. An
  1040. // OM_OBJECT_UPDATE_IND event will be generated.
  1041. //
  1042. DC_EXIT_POINT:
  1043. DebugExitDWORD(WBP_GraphicUpdateRequest, result);
  1044. return(result);
  1045. }
  1046. //
  1047. // WBP_GraphicUpdateConfirm
  1048. //
  1049. STDMETHODIMP_(void) WbClient::WBP_GraphicUpdateConfirm
  1050. (
  1051. WB_PAGE_HANDLE hPage,
  1052. WB_GRAPHIC_HANDLE hGraphic
  1053. )
  1054. {
  1055. DebugEntry(WBP_GraphicUpdateConfirm);
  1056. //
  1057. // Check that the page handle is valid
  1058. //
  1059. ASSERT(GetPageState(hPage)->state == PAGE_IN_USE);
  1060. //
  1061. // Confirm the update to ObMan
  1062. //
  1063. OM_ObjectUpdateConfirm(m_pomClient,
  1064. m_hWSGroup,
  1065. (OM_WORKSET_ID)hPage,
  1066. hGraphic);
  1067. DebugExitVOID(WBP_GraphicUpdateConfirm);
  1068. }
  1069. //
  1070. // WBP_GraphicReplaceRequest
  1071. //
  1072. STDMETHODIMP_(UINT) WbClient::WBP_GraphicReplaceRequest
  1073. (
  1074. WB_PAGE_HANDLE hPage,
  1075. WB_GRAPHIC_HANDLE hGraphic,
  1076. PWB_GRAPHIC pGraphic
  1077. )
  1078. {
  1079. UINT result = 0;
  1080. POM_OBJECTDATA pData;
  1081. POM_OBJECT pObjPersonLock;
  1082. PWB_PAGE_STATE pPageState;
  1083. DebugEntry(WBP_GraphicReplaceRequest);
  1084. //
  1085. // Check that the page handle is valid
  1086. //
  1087. ASSERT(GetPageState(hPage)->state == PAGE_IN_USE);
  1088. //
  1089. // We allow the replace to go ahead if:
  1090. // - The object is locked by the local user
  1091. // - The object is not locked and the contents are not locked by
  1092. // a remote user
  1093. //
  1094. // Note that this allow the replace if the contents are locked by another
  1095. // user, but the local user has the object locked.
  1096. //
  1097. if (wbGraphicLocked(hPage, hGraphic, &pObjPersonLock))
  1098. {
  1099. if (pObjPersonLock != m_pObjLocal)
  1100. {
  1101. TRACE_OUT(("Graphic is locked by remote client"));
  1102. result = WB_RC_GRAPHIC_LOCKED;
  1103. DC_QUIT;
  1104. }
  1105. }
  1106. else
  1107. {
  1108. QUIT_CONTENTS_LOCKED(result);
  1109. }
  1110. //
  1111. // If the Client is asking for the lock, copy the local person ID into
  1112. // the graphic object.
  1113. //
  1114. if (pGraphic->locked == WB_GRAPHIC_LOCK_LOCAL)
  1115. {
  1116. pGraphic->lockPersonID = m_personID;
  1117. }
  1118. //
  1119. // Check whether the page has been deleted but not yet confirmed
  1120. //
  1121. pPageState = GetPageState(hPage);
  1122. if ( (pPageState->subState == PAGE_STATE_EXTERNAL_DELETE)
  1123. || (pPageState->subState == PAGE_STATE_EXTERNAL_DELETE_CONFIRM))
  1124. {
  1125. TRACE_OUT(("Object replace requested in externally deleted page - ignored"));
  1126. DC_QUIT;
  1127. }
  1128. //
  1129. // Replace the object
  1130. //
  1131. pData = ObjectDataPtrFromGraphic(pGraphic);
  1132. result = OM_ObjectReplace(m_pomClient,
  1133. m_hWSGroup,
  1134. (OM_WORKSET_ID)hPage,
  1135. hGraphic,
  1136. &pData);
  1137. if (result != 0)
  1138. {
  1139. ERROR_OUT(("OM_ObjectReplace = %d", result));
  1140. DC_QUIT;
  1141. }
  1142. //
  1143. // Note that the object has not yet been updated. An
  1144. // OM_OBJECT_REPLACE_IND event will be generated.
  1145. //
  1146. DC_EXIT_POINT:
  1147. DebugExitDWORD(WBP_GraphicReplaceRequest, result);
  1148. return(result);
  1149. }
  1150. //
  1151. // WBP_GraphicUpdateConfirm
  1152. //
  1153. STDMETHODIMP_(void) WbClient::WBP_GraphicReplaceConfirm
  1154. (
  1155. WB_PAGE_HANDLE hPage,
  1156. WB_GRAPHIC_HANDLE hGraphic
  1157. )
  1158. {
  1159. DebugEntry(WBP_GraphicReplaceConfirm);
  1160. //
  1161. // Check that the page handle is valid
  1162. //
  1163. ASSERT(GetPageState(hPage)->state == PAGE_IN_USE);
  1164. //
  1165. // Confirm the update to ObMan
  1166. //
  1167. OM_ObjectReplaceConfirm(m_pomClient,
  1168. m_hWSGroup,
  1169. (OM_WORKSET_ID)hPage,
  1170. hGraphic);
  1171. DebugExitVOID(WBP_GraphicReplaceConfirm);
  1172. }
  1173. //
  1174. // WBP_GraphicDeleteRequest
  1175. //
  1176. STDMETHODIMP_(UINT) WbClient::WBP_GraphicDeleteRequest
  1177. (
  1178. WB_PAGE_HANDLE hPage,
  1179. WB_GRAPHIC_HANDLE hGraphic
  1180. )
  1181. {
  1182. UINT result = 0;
  1183. DebugEntry(WBP_GraphicDeleteRequest);
  1184. //
  1185. // Check that the page handle is valid
  1186. //
  1187. ASSERT(GetPageState(hPage)->state == PAGE_IN_USE);
  1188. //
  1189. // Check whether another person has an active contents lock
  1190. //
  1191. QUIT_CONTENTS_LOCKED(result);
  1192. //
  1193. // Check whether another person has the graphic locked
  1194. //
  1195. QUIT_GRAPHIC_LOCKED(hPage, hGraphic, result);
  1196. //
  1197. // Delete the object
  1198. //
  1199. result = OM_ObjectDelete(m_pomClient,
  1200. m_hWSGroup,
  1201. (OM_WORKSET_ID)hPage,
  1202. hGraphic);
  1203. if (result != 0)
  1204. {
  1205. ERROR_OUT(("OM_ObjectDelete = %d", result));
  1206. DC_QUIT;
  1207. }
  1208. //
  1209. // Note that at this point the object is not yet deleted. An
  1210. // OM_OBJECT_DELETE_IND event is raised and processed by the Whiteboard
  1211. // Core event handler. A WB_EVENT_GRAPHIC_DELETED is then posted to the
  1212. // client. The client then calls WBP_GraphicDeleteConfirm to complete
  1213. // the deletion.
  1214. //
  1215. DC_EXIT_POINT:
  1216. DebugExitDWORD(WBP_GraphicDeleteRequest, result);
  1217. return(result);
  1218. }
  1219. //
  1220. // WBP_GraphicDeleteConfirm
  1221. //
  1222. STDMETHODIMP_(void) WbClient::WBP_GraphicDeleteConfirm
  1223. (
  1224. WB_PAGE_HANDLE hPage,
  1225. WB_GRAPHIC_HANDLE hGraphic
  1226. )
  1227. {
  1228. DebugEntry(WBP_GraphicDeleteConfirm);
  1229. //
  1230. // Check that the page handle is valid
  1231. //
  1232. ASSERT(GetPageState(hPage)->state == PAGE_IN_USE);
  1233. //
  1234. // Confirm the delete
  1235. //
  1236. OM_ObjectDeleteConfirm(m_pomClient,
  1237. m_hWSGroup,
  1238. (OM_WORKSET_ID)hPage,
  1239. hGraphic);
  1240. DebugExitVOID(WBP_GraphicDeleteConfirm);
  1241. }
  1242. //
  1243. // WBP_GraphicUnlock
  1244. //
  1245. STDMETHODIMP_(void) WbClient::WBP_GraphicUnlock
  1246. (
  1247. WB_PAGE_HANDLE hPage,
  1248. WB_GRAPHIC_HANDLE hGraphic
  1249. )
  1250. {
  1251. UINT rc;
  1252. POM_OBJECTDATA pData;
  1253. PWB_PAGE_STATE pPageState;
  1254. PWB_GRAPHIC pGraphic = NULL;
  1255. PWB_GRAPHIC pNewGraphic = NULL;
  1256. DebugEntry(WBP_GraphicUnlock);
  1257. //
  1258. // Check that the page handle is valid
  1259. //
  1260. ASSERT(GetPageState(hPage)->state == PAGE_IN_USE);
  1261. //
  1262. // Check whether the page has been deleted but not yet confirmed
  1263. //
  1264. pPageState = GetPageState(hPage);
  1265. if ( (pPageState->subState == PAGE_STATE_EXTERNAL_DELETE)
  1266. || (pPageState->subState == PAGE_STATE_EXTERNAL_DELETE_CONFIRM))
  1267. {
  1268. TRACE_OUT(("Object update requested in externally deleted page - ignored"));
  1269. DC_QUIT;
  1270. }
  1271. //
  1272. // Read the object from ObMan
  1273. //
  1274. if (WBP_GraphicGet(hPage, hGraphic, &pGraphic) != 0)
  1275. {
  1276. TRACE_OUT(("Could not get graphic - leaving function"));
  1277. DC_QUIT;
  1278. }
  1279. //
  1280. // Check the local client has the graphic locked
  1281. //
  1282. QUIT_GRAPHIC_NOT_LOCKED(pGraphic, rc);
  1283. //
  1284. // Allocate a new graphic, copied from the existing one, and clear the
  1285. // lock field.
  1286. //
  1287. if (WBP_GraphicAllocate(hPage, sizeof(WB_GRAPHIC),
  1288. &pNewGraphic) != 0)
  1289. {
  1290. ERROR_OUT(("Could not allocate memory for update object"));
  1291. DC_QUIT;
  1292. }
  1293. memcpy(pNewGraphic, pGraphic, sizeof(WB_GRAPHIC));
  1294. pNewGraphic->locked = WB_GRAPHIC_LOCK_NONE;
  1295. //
  1296. // Unlock & update the object
  1297. //
  1298. pData = ObjectDataPtrFromGraphic(pNewGraphic);
  1299. pData->length = sizeof(WB_GRAPHIC);
  1300. rc = OM_ObjectUpdate(m_pomClient,
  1301. m_hWSGroup,
  1302. (OM_WORKSET_ID)hPage,
  1303. hGraphic,
  1304. &pData);
  1305. //
  1306. // Dont worry too much if the update fails because the object has been
  1307. // deleted, just trace an alert and return OK - the front end will be
  1308. // told that the object has gone later.
  1309. //
  1310. if (rc != 0)
  1311. {
  1312. if (rc == OM_RC_OBJECT_DELETED)
  1313. {
  1314. TRACE_OUT(("Update failed because object has been deleted"));
  1315. }
  1316. else
  1317. {
  1318. ERROR_OUT(("OM_ObjectUpdate = %d", rc));
  1319. }
  1320. DC_QUIT;
  1321. }
  1322. //
  1323. // Note that the object has not yet been updated. An
  1324. // OM_OBJECT_UPDATE_IND event will be generated.
  1325. //
  1326. DC_EXIT_POINT:
  1327. //
  1328. // If we read the graphic successfully, release it now
  1329. //
  1330. if (pGraphic != NULL)
  1331. {
  1332. WBP_GraphicRelease(hPage, hGraphic, pGraphic);
  1333. }
  1334. DebugExitVOID(WBP_GraphicUnlock);
  1335. }
  1336. //
  1337. // WBP_GraphicMove
  1338. //
  1339. STDMETHODIMP_(UINT) WbClient::WBP_GraphicMove
  1340. (
  1341. WB_PAGE_HANDLE hPage,
  1342. WB_GRAPHIC_HANDLE hGraphic,
  1343. UINT where
  1344. )
  1345. {
  1346. UINT result = 0;
  1347. PWB_PAGE_STATE pPageState;
  1348. DebugEntry(WBP_GraphicMove);
  1349. //
  1350. // Check that the page handle is valid
  1351. //
  1352. ASSERT(GetPageState(hPage)->state == PAGE_IN_USE);
  1353. //
  1354. // Check whether another person has an active contents lock
  1355. //
  1356. QUIT_CONTENTS_LOCKED(result);
  1357. //
  1358. // Check whether the page has been deleted but not yet confirmed
  1359. //
  1360. pPageState = GetPageState(hPage);
  1361. if ( (pPageState->subState == PAGE_STATE_EXTERNAL_DELETE)
  1362. || (pPageState->subState == PAGE_STATE_EXTERNAL_DELETE_CONFIRM))
  1363. {
  1364. TRACE_OUT(("Object moved in externally deleted page - ignored"));
  1365. DC_QUIT;
  1366. }
  1367. //
  1368. // Do the move
  1369. //
  1370. result = OM_ObjectMove(m_pomClient,
  1371. m_hWSGroup,
  1372. (OM_WORKSET_ID)hPage,
  1373. hGraphic,
  1374. (OM_POSITION)where);
  1375. if (result != 0)
  1376. {
  1377. ERROR_OUT(("OM_ObjectMove = %d", result));
  1378. DC_QUIT;
  1379. }
  1380. DC_EXIT_POINT:
  1381. DebugExitDWORD(WBP_GraphicMove, result);
  1382. return(result);
  1383. }
  1384. //
  1385. // WBP_GraphicSelectLast
  1386. //
  1387. STDMETHODIMP_(UINT) WbClient::WBP_GraphicSelect
  1388. (
  1389. WB_PAGE_HANDLE hPage,
  1390. POINT point,
  1391. WB_GRAPHIC_HANDLE hRefGraphic,
  1392. UINT where,
  1393. PWB_GRAPHIC_HANDLE phGraphic
  1394. )
  1395. {
  1396. UINT result = 0;
  1397. DebugEntry(WBP_GraphicSelect);
  1398. //
  1399. // Check that the page handle is valid
  1400. //
  1401. ASSERT(GetPageState(hPage)->state == PAGE_IN_USE);
  1402. //
  1403. // Get the handle of the last object in the workset
  1404. //
  1405. result = OM_ObjectH(m_pomClient,
  1406. m_hWSGroup,
  1407. (OM_WORKSET_ID)hPage,
  1408. hRefGraphic,
  1409. &hRefGraphic,
  1410. (OM_POSITION)where);
  1411. if (result == OM_RC_NO_SUCH_OBJECT)
  1412. {
  1413. result = WB_RC_NO_SUCH_GRAPHIC;
  1414. DC_QUIT;
  1415. }
  1416. if (result != 0)
  1417. {
  1418. ERROR_OUT(("OM_ObjectH = %d", result));
  1419. DC_QUIT;
  1420. }
  1421. //
  1422. // Get the previous matching graphic - this function starts from the
  1423. // object in hRefGraphic and works back.
  1424. //
  1425. result = wbGraphicSelectPrevious(hPage,
  1426. &point,
  1427. hRefGraphic,
  1428. phGraphic);
  1429. DC_EXIT_POINT:
  1430. DebugExitDWORD(WBP_GraphicSelect, result);
  1431. return(result);
  1432. }
  1433. //
  1434. // WBP_GraphicGet
  1435. //
  1436. STDMETHODIMP_(UINT) WbClient::WBP_GraphicGet
  1437. (
  1438. WB_PAGE_HANDLE hPage,
  1439. WB_GRAPHIC_HANDLE hGraphic,
  1440. PPWB_GRAPHIC ppGraphic
  1441. )
  1442. {
  1443. UINT result = 0;
  1444. UINT rc;
  1445. POM_OBJECTDATA pData;
  1446. PWB_GRAPHIC pGraphic;
  1447. POM_OBJECT pObjPersonLock;
  1448. DebugEntry(WBP_GraphicGet);
  1449. //
  1450. // Check that the page handle is valid
  1451. //
  1452. ASSERT(GetPageState(hPage)->state == PAGE_IN_USE);
  1453. //
  1454. // Read the object.
  1455. //
  1456. result = OM_ObjectRead(m_pomClient,
  1457. m_hWSGroup,
  1458. (OM_WORKSET_ID)hPage,
  1459. hGraphic,
  1460. &pData);
  1461. if (result != 0)
  1462. {
  1463. ERROR_OUT(("OM_ObjectRead = %d", result));
  1464. DC_QUIT;
  1465. }
  1466. //
  1467. // Convert the ObMan pointer to a core pointer
  1468. //
  1469. pGraphic = GraphicPtrFromObjectData(pData);
  1470. //
  1471. // If the graphic object indicates that it is locked - verify that the
  1472. // locking person is still in the call.
  1473. //
  1474. if (pGraphic->locked != WB_GRAPHIC_LOCK_NONE)
  1475. {
  1476. TRACE_OUT(("Graphic has lock flag set"));
  1477. //
  1478. // Convert the lock person ID in the graphic to a person handle
  1479. //
  1480. rc = OM_ObjectIDToPtr(m_pomClient,
  1481. m_hWSGroup,
  1482. USER_INFORMATION_WORKSET,
  1483. pGraphic->lockPersonID,
  1484. &pObjPersonLock);
  1485. if (rc == OM_RC_BAD_OBJECT_ID)
  1486. {
  1487. //
  1488. // The locking person is no longer in the call - reset the lock flag
  1489. // in the graphic. This tells the client that the graphic can be
  1490. // changed.
  1491. //
  1492. TRACE_OUT(("Lock person has left call - resetting lock flag"));
  1493. pGraphic->locked = WB_GRAPHIC_LOCK_NONE;
  1494. }
  1495. else
  1496. {
  1497. if (rc == 0)
  1498. {
  1499. //
  1500. // The object is locked - check whether the lock belongs to the
  1501. // local person or a remote person.
  1502. //
  1503. if (pObjPersonLock == m_pObjLocal)
  1504. {
  1505. //
  1506. // Change the lock type to local to tell the client that they
  1507. // have the lock on this object.
  1508. //
  1509. TRACE_OUT(("Lock belongs to local person"));
  1510. pGraphic->locked = WB_GRAPHIC_LOCK_LOCAL;
  1511. }
  1512. else
  1513. {
  1514. //
  1515. // Change the lock type to remote to tell the client that another
  1516. // person has the lock on this object.
  1517. //
  1518. TRACE_OUT(("Lock belongs to remote person"));
  1519. pGraphic->locked = WB_GRAPHIC_LOCK_REMOTE;
  1520. }
  1521. }
  1522. }
  1523. }
  1524. //
  1525. // Return the pointer to the graphic data
  1526. //
  1527. *ppGraphic = pGraphic;
  1528. DC_EXIT_POINT:
  1529. DebugExitDWORD(WBP_GraphicGet, result);
  1530. return(result);
  1531. }
  1532. //
  1533. // WBP_GraphicRelease
  1534. //
  1535. STDMETHODIMP_(void) WbClient::WBP_GraphicRelease
  1536. (
  1537. WB_PAGE_HANDLE hPage,
  1538. WB_GRAPHIC_HANDLE hGraphic,
  1539. PWB_GRAPHIC pGraphic
  1540. )
  1541. {
  1542. POM_OBJECTDATA pData;
  1543. DebugEntry(WBP_GraphicRelease);
  1544. //
  1545. // Check that the page handle is valid
  1546. //
  1547. ASSERT(GetPageState(hPage)->state == PAGE_IN_USE);
  1548. //
  1549. // Release the object.
  1550. //
  1551. pData = ObjectDataPtrFromGraphic(pGraphic);
  1552. OM_ObjectRelease(m_pomClient,
  1553. m_hWSGroup,
  1554. (OM_WORKSET_ID)hPage,
  1555. hGraphic,
  1556. &pData);
  1557. DebugExitVOID(WBP_GraphicRelease);
  1558. }
  1559. //
  1560. // WBP_GraphicHandle
  1561. //
  1562. STDMETHODIMP_(UINT) WbClient::WBP_GraphicHandle
  1563. (
  1564. WB_PAGE_HANDLE hPage,
  1565. WB_GRAPHIC_HANDLE hRefGraphic,
  1566. UINT where,
  1567. PWB_GRAPHIC_HANDLE phGraphic
  1568. )
  1569. {
  1570. UINT result;
  1571. DebugEntry(WBP_GraphicHandle);
  1572. //
  1573. // Check that the page handle is valid
  1574. //
  1575. ASSERT(GetPageState(hPage)->state == PAGE_IN_USE);
  1576. //
  1577. // Get the handle of the first object in the page workset.
  1578. //
  1579. result = OM_ObjectH(m_pomClient,
  1580. m_hWSGroup,
  1581. (OM_WORKSET_ID)hPage,
  1582. hRefGraphic,
  1583. phGraphic,
  1584. (OM_POSITION)where);
  1585. if (result == OM_RC_NO_SUCH_OBJECT)
  1586. {
  1587. TRACE_OUT(("No objects there"));
  1588. result = WB_RC_NO_SUCH_GRAPHIC;
  1589. }
  1590. DebugExitDWORD(WBP_GraphicHandle, result);
  1591. return(result);
  1592. }
  1593. //
  1594. // WBP_PersonHandleFirst
  1595. //
  1596. STDMETHODIMP_(void) WbClient::WBP_PersonHandleFirst
  1597. (
  1598. POM_OBJECT * ppObjPerson
  1599. )
  1600. {
  1601. DebugEntry(WBP_PersonHandleFirst);
  1602. OM_ObjectH(m_pomClient, m_hWSGroup,
  1603. USER_INFORMATION_WORKSET, 0, ppObjPerson, FIRST);
  1604. DebugExitVOID(WBP_PersonHandleFirst);
  1605. }
  1606. //
  1607. // WBP_PersonHandleNext
  1608. //
  1609. STDMETHODIMP_(UINT) WbClient::WBP_PersonHandleNext
  1610. (
  1611. POM_OBJECT pObjPerson,
  1612. POM_OBJECT * ppObjPersonNext
  1613. )
  1614. {
  1615. UINT rc;
  1616. DebugEntry(WBP_PersonHandleNext);
  1617. //
  1618. // Get the handle of the next object in the user information workset.
  1619. //
  1620. rc = OM_ObjectH(m_pomClient,
  1621. m_hWSGroup,
  1622. USER_INFORMATION_WORKSET,
  1623. pObjPerson,
  1624. ppObjPersonNext,
  1625. AFTER);
  1626. if (rc == OM_RC_NO_SUCH_OBJECT)
  1627. {
  1628. rc = WB_RC_NO_SUCH_PERSON;
  1629. }
  1630. else if (rc != 0)
  1631. {
  1632. ERROR_OUT(("OM_ObjectNextH = %d", rc));
  1633. }
  1634. DebugExitDWORD(WBP_PersonHandleNext, rc);
  1635. return(rc);
  1636. }
  1637. //
  1638. // WBP_PersonHandleLocal
  1639. //
  1640. STDMETHODIMP_(void) WbClient::WBP_PersonHandleLocal
  1641. (
  1642. POM_OBJECT * ppObjPerson
  1643. )
  1644. {
  1645. DebugEntry(WBP_PersonHandleLocal);
  1646. *ppObjPerson = m_pObjLocal;
  1647. DebugExitVOID(WBP_PersonHandleLocal);
  1648. }
  1649. //
  1650. // WBP_PersonCountInCall
  1651. //
  1652. STDMETHODIMP_(UINT) WbClient::WBP_PersonCountInCall(void)
  1653. {
  1654. UINT count;
  1655. POM_OBJECT pObj;
  1656. DebugEntry(WBP_PersonCountInCall);
  1657. //
  1658. // Get the count:
  1659. //
  1660. pObj = NULL;
  1661. WBP_PersonHandleFirst(&pObj);
  1662. for (count = 1; ; count++)
  1663. {
  1664. if (WBP_PersonHandleNext(pObj, &pObj) == WB_RC_NO_SUCH_PERSON)
  1665. {
  1666. break;
  1667. }
  1668. }
  1669. DebugExitDWORD(WBP_PersonCountInCall, count);
  1670. return(count);
  1671. }
  1672. //
  1673. // WBP_GetPersonData
  1674. //
  1675. STDMETHODIMP_(UINT) WbClient::WBP_GetPersonData
  1676. (
  1677. POM_OBJECT pObjPerson,
  1678. PWB_PERSON pPerson
  1679. )
  1680. {
  1681. UINT rc;
  1682. DebugEntry(WBP_GetPersonData);
  1683. ASSERT(!IsBadWritePtr(pPerson, sizeof(WB_PERSON)));
  1684. //
  1685. // Get the object.
  1686. //
  1687. rc = wbPersonGet(pObjPerson, pPerson);
  1688. DebugExitDWORD(WBP_GetPersonData, rc);
  1689. return(rc);
  1690. }
  1691. //
  1692. // WBP_SetLocalPersonData
  1693. //
  1694. STDMETHODIMP_(UINT) WbClient::WBP_SetLocalPersonData(PWB_PERSON pPerson)
  1695. {
  1696. UINT rc;
  1697. POM_OBJECTDATA pUserObject;
  1698. DebugEntry(WBP_SetPersonData);
  1699. ASSERT(!IsBadReadPtr(pPerson, sizeof(WB_PERSON)));
  1700. //
  1701. // Allocate a user object
  1702. //
  1703. rc = OM_ObjectAlloc(m_pomClient,
  1704. m_hWSGroup,
  1705. USER_INFORMATION_WORKSET,
  1706. sizeof(WB_PERSON),
  1707. &pUserObject);
  1708. if (rc != 0)
  1709. {
  1710. ERROR_OUT(("OM_ObjectAlloc = %d", rc));
  1711. DC_QUIT;
  1712. }
  1713. //
  1714. // Set the length of the object
  1715. //
  1716. pUserObject->length = sizeof(WB_PERSON);
  1717. //
  1718. // Copy the user information into the ObMan object
  1719. //
  1720. memcpy(pUserObject->data, pPerson, sizeof(WB_PERSON));
  1721. //
  1722. // Replace the user object
  1723. //
  1724. rc = OM_ObjectReplace(m_pomClient,
  1725. m_hWSGroup,
  1726. USER_INFORMATION_WORKSET,
  1727. m_pObjLocal,
  1728. &pUserObject);
  1729. if (rc != 0)
  1730. {
  1731. ERROR_OUT(("OM_ObjectReplace"));
  1732. //
  1733. // Discard the object
  1734. //
  1735. OM_ObjectDiscard(m_pomClient,
  1736. m_hWSGroup,
  1737. USER_INFORMATION_WORKSET,
  1738. &pUserObject);
  1739. DC_QUIT;
  1740. }
  1741. DC_EXIT_POINT:
  1742. //
  1743. // Note that the object has not yet been updated. An
  1744. // OM_OBJECT_UPDATE_IND event will be generated.
  1745. //
  1746. DebugExitDWORD(WBP_SetPersonData, rc);
  1747. return(rc);
  1748. }
  1749. //
  1750. // WBP_PersonUpdateConfirm
  1751. //
  1752. STDMETHODIMP_(void) WbClient::WBP_PersonUpdateConfirm
  1753. (
  1754. POM_OBJECT pObjPerson
  1755. )
  1756. {
  1757. DebugEntry(WBP_PersonUpdateConfirm);
  1758. //
  1759. // Confirm the update to ObMan
  1760. //
  1761. OM_ObjectUpdateConfirm(m_pomClient,
  1762. m_hWSGroup,
  1763. USER_INFORMATION_WORKSET,
  1764. pObjPerson);
  1765. DebugExitVOID(WBP_PersonUpdateConfirm);
  1766. }
  1767. //
  1768. // WBP_PersonReplaceConfirm
  1769. //
  1770. STDMETHODIMP_(void) WbClient::WBP_PersonReplaceConfirm
  1771. (
  1772. POM_OBJECT pObjPerson
  1773. )
  1774. {
  1775. DebugEntry(WBP_PersonReplaceConfirm);
  1776. //
  1777. // Confirm the replace to ObMan
  1778. //
  1779. OM_ObjectReplaceConfirm(m_pomClient,
  1780. m_hWSGroup,
  1781. USER_INFORMATION_WORKSET,
  1782. pObjPerson);
  1783. DebugExitVOID(WBP_PersonReplaceConfirm);
  1784. }
  1785. //
  1786. // WBP_PersonLeftConfirm
  1787. //
  1788. STDMETHODIMP_(void) WbClient::WBP_PersonLeftConfirm
  1789. (
  1790. POM_OBJECT pObjPerson
  1791. )
  1792. {
  1793. DebugEntry(WBP_PersonLeftConfirm);
  1794. //
  1795. // Confirm the update to ObMan
  1796. //
  1797. OM_ObjectDeleteConfirm(m_pomClient,
  1798. m_hWSGroup,
  1799. USER_INFORMATION_WORKSET,
  1800. pObjPerson);
  1801. DebugExitVOID(WBP_PersonLeftConfirm);
  1802. }
  1803. //
  1804. // WBP_SyncPositionGet
  1805. //
  1806. STDMETHODIMP_(UINT) WbClient::WBP_SyncPositionGet
  1807. (
  1808. PWB_SYNC pSync
  1809. )
  1810. {
  1811. UINT result;
  1812. POM_OBJECTDATA pSyncObject = NULL;
  1813. PWB_SYNC_CONTROL pSyncControl = NULL;
  1814. DebugEntry(WBP_SyncPositionGet);
  1815. ASSERT(!IsBadWritePtr(pSync, sizeof(WB_SYNC)));
  1816. //
  1817. // Read the Sync Control object
  1818. //
  1819. result = OM_ObjectRead(m_pomClient,
  1820. m_hWSGroup,
  1821. SYNC_CONTROL_WORKSET,
  1822. m_pObjSyncControl,
  1823. &pSyncObject);
  1824. if (result != 0)
  1825. {
  1826. ERROR_OUT(("Error reading Sync Control Object = %d", result));
  1827. DC_QUIT;
  1828. }
  1829. pSyncControl = (PWB_SYNC_CONTROL) pSyncObject->data;
  1830. //
  1831. // Copy the Sync Person details to the result field
  1832. // NOTE:
  1833. // LiveLan sends a larger object, we need to ignore the stuff past the
  1834. // end.
  1835. //
  1836. if (pSyncControl->sync.length != sizeof(WB_SYNC))
  1837. {
  1838. WARNING_OUT(("WBP_SyncPositionGet (interop): Remote created WB_SYNC of size %d, we expected size %d",
  1839. pSyncControl->sync.length, sizeof(WB_SYNC)));
  1840. }
  1841. memcpy(pSync, &pSyncControl->sync, min(sizeof(WB_SYNC), pSyncControl->sync.length));
  1842. //
  1843. // Release the Sync Control Object
  1844. //
  1845. OM_ObjectRelease(m_pomClient,
  1846. m_hWSGroup,
  1847. SYNC_CONTROL_WORKSET,
  1848. m_pObjSyncControl,
  1849. &pSyncObject);
  1850. DC_EXIT_POINT:
  1851. DebugExitDWORD(WBP_SyncPositionGet, result);
  1852. return(result);
  1853. }
  1854. //
  1855. // WBP_SyncPositionUpdate
  1856. //
  1857. STDMETHODIMP_(UINT) WbClient::WBP_SyncPositionUpdate
  1858. (
  1859. PWB_SYNC pSync
  1860. )
  1861. {
  1862. UINT result;
  1863. POM_OBJECTDATA pSyncObject = NULL;
  1864. PWB_SYNC_CONTROL pSyncControl = NULL;
  1865. DebugEntry(WBP_SyncPositionUpdate);
  1866. ASSERT(!IsBadReadPtr(pSync, sizeof(WB_SYNC)));
  1867. //
  1868. // Write the new sync control object (do not create it)
  1869. //
  1870. result = wbWriteSyncControl(pSync, FALSE);
  1871. DebugExitDWORD(WBP_SyncPositionUpdate, result);
  1872. return(result);
  1873. }
  1874. //
  1875. // WBP_CancelLoad
  1876. //
  1877. STDMETHODIMP_(UINT) WbClient::WBP_CancelLoad(void)
  1878. {
  1879. UINT result = 0;
  1880. DebugEntry(WBP_CancelLoad);
  1881. //
  1882. // Check a load is in progress
  1883. //
  1884. if (m_loadState == LOAD_STATE_EMPTY)
  1885. {
  1886. TRACE_OUT(("request to cancel load, but there is no load in progress"));
  1887. result = WB_RC_NOT_LOADING;
  1888. DC_QUIT;
  1889. }
  1890. TRACE_OUT(("Cancelling load in progress"));
  1891. //
  1892. // Close the file
  1893. //
  1894. if (m_hLoadFile != INVALID_HANDLE_VALUE)
  1895. {
  1896. CloseHandle(m_hLoadFile);
  1897. m_hLoadFile = INVALID_HANDLE_VALUE;
  1898. }
  1899. //
  1900. // reset the load state to show we're no longer loading.
  1901. //
  1902. m_loadState = LOAD_STATE_EMPTY;
  1903. DC_EXIT_POINT:
  1904. DebugExitDWORD(WBP_CancelLoad, result);
  1905. return(result);
  1906. }
  1907. //
  1908. //
  1909. // Name: WBP_ValidateFile
  1910. //
  1911. // Purpose: Validate that a passed filename holds a valid whiteboard file
  1912. //
  1913. // Returns: 0 if successful
  1914. // !0 if an error
  1915. //
  1916. //
  1917. STDMETHODIMP_(UINT) WbClient::WBP_ValidateFile
  1918. (
  1919. LPCSTR pFileName,
  1920. HANDLE * phFile
  1921. )
  1922. {
  1923. UINT result = 0;
  1924. HANDLE hFile;
  1925. WB_FILE_HEADER fileHeader;
  1926. UINT length;
  1927. ULONG cbSizeRead;
  1928. BOOL fileOpen = FALSE;
  1929. DebugEntry(WBP_ValidateFile);
  1930. //
  1931. // Open the file
  1932. //
  1933. hFile = CreateFile(pFileName, GENERIC_READ, 0, NULL,
  1934. OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0);
  1935. if (hFile == INVALID_HANDLE_VALUE)
  1936. {
  1937. WARNING_OUT(("Error opening file, win32 err=%d", GetLastError()));
  1938. result = WB_RC_CREATE_FAILED;
  1939. DC_QUIT;
  1940. }
  1941. //
  1942. // Show that we have opened the file successfully
  1943. //
  1944. fileOpen = TRUE;
  1945. //
  1946. // Read the file header length
  1947. //
  1948. if (! ReadFile(hFile, (void *) &length, sizeof(length), &cbSizeRead, NULL))
  1949. {
  1950. WARNING_OUT(("Error reading file header length, win32 err=%d", GetLastError()));
  1951. result = WB_RC_READ_FAILED;
  1952. DC_QUIT;
  1953. }
  1954. ASSERT(cbSizeRead == sizeof(length));
  1955. if (length != sizeof(fileHeader))
  1956. {
  1957. WARNING_OUT(("Bad file header"));
  1958. result = WB_RC_BAD_FILE_FORMAT;
  1959. DC_QUIT;
  1960. }
  1961. //
  1962. // Read the file header
  1963. //
  1964. if (! ReadFile(hFile, (void *) &fileHeader, sizeof(fileHeader), &cbSizeRead, NULL))
  1965. {
  1966. WARNING_OUT(("Error reading file header, win32 err=%d", GetLastError()));
  1967. result = WB_RC_READ_FAILED;
  1968. DC_QUIT;
  1969. }
  1970. if (cbSizeRead != sizeof(fileHeader))
  1971. {
  1972. WARNING_OUT(("Could not read file header"));
  1973. result = WB_RC_BAD_FILE_FORMAT;
  1974. DC_QUIT;
  1975. }
  1976. //
  1977. // Validate the file header
  1978. //
  1979. if ( (fileHeader.type != TYPE_FILE_HEADER)
  1980. || lstrcmp(fileHeader.functionProfile, WB_FP_NAME))
  1981. {
  1982. WARNING_OUT(("Bad function profile in file header"));
  1983. result = WB_RC_BAD_FILE_FORMAT;
  1984. DC_QUIT;
  1985. }
  1986. DC_EXIT_POINT:
  1987. //
  1988. // Return the handle, if the user needs it.
  1989. //
  1990. if ( (result == 0) && (phFile != NULL))
  1991. {
  1992. TRACE_OUT(("return file handle"));
  1993. *phFile = hFile;
  1994. }
  1995. //
  1996. // Close the file if there has been an error or the caller simply
  1997. // doesnt want the file handle.
  1998. //
  1999. if ( (fileOpen) &&
  2000. ((phFile == NULL) || (result != 0)) )
  2001. {
  2002. CloseHandle(hFile);
  2003. }
  2004. DebugExitDWORD(WBP_ValidateFile, result);
  2005. return(result);
  2006. }
  2007. //
  2008. //
  2009. // Name: wbGraphicLocked
  2010. //
  2011. // Purpose: Test whether a client has a lock on the specified graphic, and
  2012. // if so, return the person handle of the client holding the lock.
  2013. //
  2014. // Returns: TRUE if a client has a lock
  2015. // FALSE otherwise
  2016. //
  2017. //
  2018. BOOL WbClient::wbGraphicLocked
  2019. (
  2020. WB_PAGE_HANDLE hPage,
  2021. WB_GRAPHIC_HANDLE hGraphic,
  2022. POM_OBJECT * ppObjLock
  2023. )
  2024. {
  2025. BOOL result = FALSE;
  2026. UINT rc;
  2027. PWB_GRAPHIC pGraphic = NULL;
  2028. DebugEntry(wbGraphicLocked);
  2029. //
  2030. // Read the object
  2031. //
  2032. if (WBP_GraphicGet(hPage, hGraphic, &pGraphic) != 0)
  2033. {
  2034. DC_QUIT;
  2035. }
  2036. //
  2037. // Look at its lock details
  2038. //
  2039. if (pGraphic->locked != WB_GRAPHIC_LOCK_NONE)
  2040. {
  2041. //
  2042. // The lock flag in the graphic is set
  2043. //
  2044. //
  2045. // Convert the lock user ID in the graphic to a handle
  2046. //
  2047. rc = OM_ObjectIDToPtr(m_pomClient,
  2048. m_hWSGroup,
  2049. USER_INFORMATION_WORKSET,
  2050. pGraphic->lockPersonID,
  2051. ppObjLock);
  2052. if (rc == 0)
  2053. {
  2054. TRACE_OUT(("Graphic is locked"));
  2055. result = TRUE;
  2056. DC_QUIT;
  2057. }
  2058. if (rc != OM_RC_BAD_OBJECT_ID)
  2059. {
  2060. //
  2061. // An error occurred in converting the objectID
  2062. //
  2063. TRACE_OUT(("Error converting object ID to handle"));
  2064. DC_QUIT;
  2065. }
  2066. }
  2067. //
  2068. // The object is not locked (or the lock user has left the call)
  2069. //
  2070. TRACE_OUT(("Graphic is not locked"));
  2071. DC_EXIT_POINT:
  2072. //
  2073. // If the graphic is still held by us, release it
  2074. //
  2075. if (pGraphic != NULL)
  2076. {
  2077. WBP_GraphicRelease(hPage, hGraphic, pGraphic);
  2078. }
  2079. DebugExitBOOL(wbGraphicLocked, result);
  2080. return(result);
  2081. }
  2082. //
  2083. //
  2084. // Name: wbAddLocalUserObject
  2085. //
  2086. // Purpose: Add an object to the user information workset for the local
  2087. // user.
  2088. //
  2089. // Returns: Error code
  2090. //
  2091. //
  2092. UINT WbClient::wbAddLocalUserObject(void)
  2093. {
  2094. UINT rc;
  2095. POM_OBJECTDATA pData;
  2096. PWB_PERSON pUser;
  2097. CM_STATUS cmStatus;
  2098. DebugEntry(wbAddLocalUserObject);
  2099. TRACE_OUT(("Adding the necessary control objects"));
  2100. //
  2101. // Build a user object for this user and write it to the User Information
  2102. // Workset.
  2103. //
  2104. rc = OM_ObjectAlloc(m_pomClient,
  2105. m_hWSGroup,
  2106. USER_INFORMATION_WORKSET,
  2107. sizeof(WB_PERSON),
  2108. &pData);
  2109. if (rc != 0)
  2110. {
  2111. ERROR_OUT(("Error allocating object = %d", rc));
  2112. DC_QUIT;
  2113. }
  2114. pData->length = sizeof(WB_PERSON);
  2115. pUser = (PWB_PERSON) (pData->data);
  2116. //
  2117. // Initialize the contents of the user object for this user
  2118. //
  2119. TRACE_OUT(("Initialising user contents"));
  2120. ZeroMemory(pUser, sizeof(WB_PERSON));
  2121. pUser->currentPage = FIRST_PAGE_WORKSET; // lonchanc: it was 1.
  2122. pUser->synced = FALSE;
  2123. pUser->pointerActive = FALSE;
  2124. pUser->pointerPage = FIRST_PAGE_WORKSET; // lonchanc: it was 1.
  2125. pUser->colorId = (TSHR_UINT16)wbSelectPersonColor();
  2126. //
  2127. // Fill in the Call Manager personID if we are in a call.
  2128. //
  2129. if (CMS_GetStatus(&cmStatus))
  2130. {
  2131. TRACE_OUT(("CMG personID %u", cmStatus.localHandle));
  2132. pUser->cmgPersonID = cmStatus.localHandle;
  2133. }
  2134. else
  2135. {
  2136. pUser->cmgPersonID = 0;
  2137. }
  2138. //
  2139. // Copy the user name into the object:
  2140. //
  2141. lstrcpy(pUser->personName, cmStatus.localName);
  2142. //
  2143. // Copy the person's color into the client's data
  2144. //
  2145. m_colorId = pUser->colorId;
  2146. //
  2147. // Add the object to the User Information Workset, saving the handle of
  2148. // the user object in the client details.
  2149. //
  2150. rc = OM_ObjectAdd(m_pomClient,
  2151. m_hWSGroup,
  2152. USER_INFORMATION_WORKSET,
  2153. &pData,
  2154. WB_PERSON_OBJECT_UPDATE_SIZE,
  2155. &m_pObjLocal,
  2156. LAST);
  2157. if (rc != 0)
  2158. {
  2159. //
  2160. // The add failed, we must discard the object
  2161. //
  2162. OM_ObjectDiscard(m_pomClient,
  2163. m_hWSGroup,
  2164. USER_INFORMATION_WORKSET,
  2165. &pData);
  2166. ERROR_OUT(("Error adding user object = %d", rc));
  2167. DC_QUIT;
  2168. }
  2169. //
  2170. // Save the ID of this user in the client details (for later use in the
  2171. // lock information).
  2172. //
  2173. OM_ObjectPtrToID(m_pomClient,
  2174. m_hWSGroup,
  2175. USER_INFORMATION_WORKSET,
  2176. m_pObjLocal,
  2177. &(m_personID));
  2178. DC_EXIT_POINT:
  2179. DebugExitDWORD(wbAddLocalUserObject, rc);
  2180. return(rc);
  2181. }
  2182. //
  2183. //
  2184. // Name: wbGetEmptyPageHandle
  2185. //
  2186. // Purpose: Return a handle for a page that does not have its workset open.
  2187. //
  2188. // Returns: Handle of free page (or 0 if none exists)
  2189. //
  2190. //
  2191. WB_PAGE_HANDLE WbClient::wbGetEmptyPageHandle(void)
  2192. {
  2193. UINT index;
  2194. WB_PAGE_HANDLE hPage = WB_PAGE_HANDLE_NULL;
  2195. PWB_PAGE_STATE pPageState = m_pageStates;
  2196. //
  2197. // Search the page list for an empty entry
  2198. //
  2199. for (index = 0; index < WB_MAX_PAGES; index++, pPageState++)
  2200. {
  2201. if ( (pPageState->state == PAGE_NOT_IN_USE)
  2202. && (pPageState->subState == PAGE_STATE_EMPTY))
  2203. {
  2204. hPage = PAGE_INDEX_TO_HANDLE(index);
  2205. break;
  2206. }
  2207. }
  2208. return(hPage);
  2209. }
  2210. //
  2211. //
  2212. // Name: wbGetReadyPageHandle
  2213. //
  2214. // Purpose: Return a handle for a page that has its workset open but is not
  2215. // currently in use.
  2216. //
  2217. // Returns: Handle of free page (or 0 if none exists)
  2218. //
  2219. //
  2220. WB_PAGE_HANDLE WbClient::wbGetReadyPageHandle(void)
  2221. {
  2222. UINT index;
  2223. WB_PAGE_HANDLE hPage = WB_PAGE_HANDLE_NULL;
  2224. PWB_PAGE_STATE pPageState = m_pageStates;
  2225. //
  2226. // Search the page list for a ready entry
  2227. //
  2228. for (index = 0; index < WB_MAX_PAGES; index++, pPageState++)
  2229. {
  2230. if ( (pPageState->state == PAGE_NOT_IN_USE)
  2231. && (pPageState->subState == PAGE_STATE_READY))
  2232. {
  2233. hPage = PAGE_INDEX_TO_HANDLE(index);
  2234. break;
  2235. }
  2236. }
  2237. return(hPage);
  2238. }
  2239. //
  2240. //
  2241. // Name: wbPageOrderPageNumber
  2242. //
  2243. // Purpose: Return the number of the specified page.
  2244. // This function performs no validation on its parameters.
  2245. //
  2246. // Returns: None
  2247. //
  2248. //
  2249. UINT WbClient::wbPageOrderPageNumber
  2250. (
  2251. PWB_PAGE_ORDER pPageOrder,
  2252. WB_PAGE_HANDLE hPage
  2253. )
  2254. {
  2255. UINT index;
  2256. POM_WORKSET_ID pPage = pPageOrder->pages;
  2257. DebugEntry(wbPageOrderPageNumber);
  2258. //
  2259. // Search the page order list for the page handle (workset ID)
  2260. //
  2261. for (index = 0; index <= pPageOrder->countPages; index++)
  2262. {
  2263. if (pPage[index] == (OM_WORKSET_ID)hPage)
  2264. {
  2265. DC_QUIT;
  2266. }
  2267. }
  2268. //
  2269. // The page was not found - this is an internal error
  2270. //
  2271. ERROR_OUT(("Page handle not found"));
  2272. //
  2273. // Return the page number starting from 1.
  2274. //
  2275. DC_EXIT_POINT:
  2276. DebugExitDWORD(wbPageOrderPageNumber, index + 1);
  2277. return(index + 1);
  2278. }
  2279. //
  2280. //
  2281. // Name: wbPageOrderPageAdd
  2282. //
  2283. // Purpose: Add a new page to a page order structure. This function expects
  2284. // the parameters to be valid - they must be checked before
  2285. // calling it. It also assumes that there is space in the page
  2286. // list for the new page.
  2287. //
  2288. // Params: pPageOrder - pointer to page list
  2289. // hRefPage - page used as a reference point for the new page
  2290. // hPage - handle of the page to be added
  2291. // where - relative position - before or after hRefPage
  2292. //
  2293. // Returns: None
  2294. //
  2295. //
  2296. void WbClient::wbPageOrderPageAdd
  2297. (
  2298. PWB_PAGE_ORDER pPageOrder,
  2299. WB_PAGE_HANDLE hRefPage,
  2300. WB_PAGE_HANDLE hPage,
  2301. UINT where
  2302. )
  2303. {
  2304. UINT index;
  2305. POM_WORKSET_ID pPage = pPageOrder->pages;
  2306. DebugEntry(wbPageOrderPageAdd);
  2307. //
  2308. // Process according to the add position
  2309. //
  2310. switch(where)
  2311. {
  2312. case PAGE_FIRST:
  2313. index = 0;
  2314. if (pPageOrder->countPages != 0)
  2315. {
  2316. UT_MoveMemory(&pPage[1], &pPage[0], pPageOrder->countPages*sizeof(pPage[0]));
  2317. }
  2318. break;
  2319. case PAGE_LAST:
  2320. index = pPageOrder->countPages;
  2321. break;
  2322. case PAGE_AFTER:
  2323. case PAGE_BEFORE:
  2324. //
  2325. // Make an empty space in the page order list
  2326. //
  2327. index = wbPageOrderPageNumber(pPageOrder, hRefPage);
  2328. if (where == PAGE_BEFORE)
  2329. {
  2330. index--;
  2331. }
  2332. UT_MoveMemory(&pPage[index + 1], &pPage[index],
  2333. (pPageOrder->countPages - index)*sizeof(pPage[0]));
  2334. break;
  2335. default:
  2336. ERROR_OUT(("Bad where parameter"));
  2337. DC_QUIT;
  2338. }
  2339. //
  2340. // Save the new page handle in the list
  2341. //
  2342. pPage[index] = hPage;
  2343. //
  2344. // Show that the extra page is now present
  2345. //
  2346. pPageOrder->countPages += 1;
  2347. DC_EXIT_POINT:
  2348. DebugExitVOID(wbPageOrderPageAdd);
  2349. }
  2350. //
  2351. //
  2352. // Name: wbPageOrderPageDelete
  2353. //
  2354. // Purpose: Remove the specified page from a page order structure. This
  2355. // function expects its the parameters to be valid - they must be
  2356. // checked before calling it.
  2357. //
  2358. // Returns: None
  2359. //
  2360. //
  2361. void WbClient::wbPageOrderPageDelete
  2362. (
  2363. PWB_PAGE_ORDER pPageOrder,
  2364. WB_PAGE_HANDLE hPage
  2365. )
  2366. {
  2367. UINT index;
  2368. POM_WORKSET_ID pPage = pPageOrder->pages;
  2369. DebugEntry(wbPageOrderPageDelete);
  2370. index = wbPageOrderPageNumber(pPageOrder, hPage);
  2371. UT_MoveMemory(&pPage[index - 1],
  2372. &pPage[index],
  2373. (pPageOrder->countPages - index)*sizeof(pPage[0]));
  2374. pPageOrder->countPages -= 1;
  2375. DebugExitVOID(wbPageOrderPageDelete);
  2376. }
  2377. //
  2378. //
  2379. // Name: wbPagesPageAdd
  2380. //
  2381. // Purpose: Add a new page to the internal page list. This function expects
  2382. // the parameters to be valid - they must be checked before
  2383. // calling it. It also assumes that there is space in the page
  2384. // list for the new page.
  2385. //
  2386. // Returns: None
  2387. //
  2388. //
  2389. void WbClient::wbPagesPageAdd
  2390. (
  2391. WB_PAGE_HANDLE hRefPage,
  2392. WB_PAGE_HANDLE hPage,
  2393. UINT where
  2394. )
  2395. {
  2396. PWB_PAGE_STATE pPageState;
  2397. DebugEntry(wbPagesPageAdd);
  2398. //
  2399. // Add the page to the page order structure
  2400. //
  2401. wbPageOrderPageAdd(&(m_pageOrder), hRefPage, hPage, where);
  2402. //
  2403. // Update the page state information
  2404. //
  2405. pPageState = GetPageState(hPage);
  2406. pPageState->state = PAGE_IN_USE;
  2407. pPageState->subState = PAGE_STATE_EMPTY;
  2408. DebugExitVOID(wbPagesPageAdd);
  2409. }
  2410. //
  2411. //
  2412. // Name: wbClientReset
  2413. //
  2414. // Purpose: Reset the client data to a state where the client is not in a
  2415. // call, but is registered with ObMan and has event and exit
  2416. // handlers registered with utilities.
  2417. //
  2418. // Returns: None
  2419. //
  2420. //
  2421. void WbClient::wbClientReset(void)
  2422. {
  2423. UINT index;
  2424. PWB_PAGE_ORDER pPageOrder = &(m_pageOrder);
  2425. PWB_PAGE_STATE pPageState = m_pageStates;
  2426. DebugEntry(wbClientReset);
  2427. //
  2428. // Initialize object handles
  2429. //
  2430. m_hWSGroup = (OM_WSGROUP_HANDLE) NULL;
  2431. m_pObjPageControl = NULL;
  2432. m_pObjSyncControl = NULL;
  2433. m_pObjLocal = NULL;
  2434. m_pObjLock = NULL;
  2435. m_pObjPersonLock = NULL;
  2436. //
  2437. // Initialize the status variables
  2438. //
  2439. m_errorState = ERROR_STATE_EMPTY;
  2440. m_changed = FALSE;
  2441. m_lockState = LOCK_STATE_EMPTY;
  2442. m_lockType = WB_LOCK_TYPE_NONE;
  2443. m_lockRequestType = WB_LOCK_TYPE_NONE;
  2444. m_loadState = LOAD_STATE_EMPTY;
  2445. if (m_hLoadFile != INVALID_HANDLE_VALUE)
  2446. {
  2447. CloseHandle(m_hLoadFile);
  2448. m_hLoadFile = INVALID_HANDLE_VALUE;
  2449. }
  2450. m_countReadyPages = 0;
  2451. //
  2452. // Zero the whole structure
  2453. //
  2454. ZeroMemory(pPageOrder, sizeof(*pPageOrder));
  2455. //
  2456. // Set the object type
  2457. //
  2458. pPageOrder->objectType = TYPE_CONTROL_PAGE_ORDER;
  2459. //
  2460. // Set up the page control elements
  2461. //
  2462. pPageOrder->generationLo = 1;
  2463. pPageOrder->generationHi = 0;
  2464. pPageOrder->countPages = 0;
  2465. //
  2466. // Initialize the page state structures
  2467. //
  2468. for (index = 0; index < WB_MAX_PAGES; index++, pPageState++)
  2469. {
  2470. pPageState->state = PAGE_NOT_IN_USE;
  2471. pPageState->subState = PAGE_STATE_EMPTY;
  2472. }
  2473. DebugExitVOID(wbClientReset);
  2474. }
  2475. //
  2476. //
  2477. // Name: wbOnWsGroupRegisterCon
  2478. //
  2479. // Purpose: Routine processing OM_WSGROUP_REGISTER_CON events.
  2480. //
  2481. // Returns: Error code
  2482. //
  2483. //
  2484. BOOL WbClient::wbOnWsGroupRegisterCon
  2485. (
  2486. UINT_PTR param1,
  2487. UINT_PTR param2
  2488. )
  2489. {
  2490. POM_EVENT_DATA16 pEvent16 = (POM_EVENT_DATA16) &param1;
  2491. POM_EVENT_DATA32 pEvent32 = (POM_EVENT_DATA32) &param2;
  2492. BOOL processed;
  2493. DebugEntry(wbOnWsGroupRegisterCon);
  2494. //
  2495. // Check that this is the event we are expecting
  2496. //
  2497. if (pEvent32->correlator != m_wsgroupCorrelator)
  2498. {
  2499. //
  2500. // We are not expecting this event, this means that it must be for a
  2501. // workset group which we wanted to deregister from (but had not yet
  2502. // received confirmation). So deregister immediately.
  2503. //
  2504. //
  2505. // Check that the return code for the registration is OK
  2506. //
  2507. if (pEvent32->result == 0)
  2508. {
  2509. OM_WSGroupDeregister(m_pomClient, &(pEvent16->hWSGroup));
  2510. }
  2511. processed = FALSE;
  2512. DC_QUIT;
  2513. }
  2514. //
  2515. // Show that we have processed the event
  2516. //
  2517. processed = TRUE;
  2518. //
  2519. // Test for the correct state
  2520. //
  2521. if (m_subState != STATE_REG_PENDING_WSGROUP_CON)
  2522. {
  2523. //
  2524. // We are not in the correct state for this event - this is an internal
  2525. // error.
  2526. //
  2527. ERROR_OUT(("Not in correct state for WSGroupRegisterCon"));
  2528. DC_QUIT;
  2529. }
  2530. //
  2531. // Check that the return code for the registration is OK
  2532. //
  2533. if (pEvent32->result != 0)
  2534. {
  2535. //
  2536. // Registration with the workset group failed - tidy up
  2537. //
  2538. wbError();
  2539. DC_QUIT;
  2540. }
  2541. //
  2542. // Registration with the workset group succeeded
  2543. //
  2544. m_hWSGroup = pEvent16->hWSGroup;
  2545. //
  2546. // Get the clients network ID, used in graphic objects to determine where
  2547. // they are loaded.
  2548. //
  2549. if (!wbGetNetUserID())
  2550. {
  2551. //
  2552. // Tidy up (and post an error event to the client)
  2553. //
  2554. ERROR_OUT(("Failed to get user ID"));
  2555. wbError();
  2556. DC_QUIT;
  2557. }
  2558. //
  2559. // Start opening the worksets. We open them one at a time and wait for
  2560. // the response to avoid flooding the message queue.
  2561. // The user information workset is given high priority. This allows
  2562. // remote pointer movements to travel quickly.
  2563. //
  2564. if (OM_WorksetOpenPReq(m_pomClient,
  2565. m_hWSGroup,
  2566. USER_INFORMATION_WORKSET,
  2567. NET_HIGH_PRIORITY,
  2568. TRUE,
  2569. &(m_worksetOpenCorrelator)) != 0)
  2570. {
  2571. ERROR_OUT(("User Information Workset Open Failed"));
  2572. wbError();
  2573. DC_QUIT;
  2574. }
  2575. //
  2576. // Move to the next state
  2577. //
  2578. m_subState = STATE_REG_PENDING_USER_WORKSET;
  2579. DC_EXIT_POINT:
  2580. DebugExitBOOL(wbOnWsGroupRegisterCon, processed);
  2581. return(processed);
  2582. }
  2583. //
  2584. //
  2585. // Name: wbOnWorksetOpenCon
  2586. //
  2587. // Purpose: Routine processing OM_WORKSET_OPEN_CON events.
  2588. //
  2589. // Returns: Error code
  2590. //
  2591. //
  2592. BOOL WbClient::wbOnWorksetOpenCon
  2593. (
  2594. UINT_PTR param1,
  2595. UINT_PTR param2
  2596. )
  2597. {
  2598. POM_EVENT_DATA16 pEvent16 = (POM_EVENT_DATA16) &param1;
  2599. POM_EVENT_DATA32 pEvent32 = (POM_EVENT_DATA32) &param2;
  2600. BOOL processed = FALSE;
  2601. OM_WORKSET_ID eventWorksetID;
  2602. DebugEntry(wbOnWorksetOpenCon);
  2603. //
  2604. // Process according to the workset ID
  2605. //
  2606. eventWorksetID = pEvent16->worksetID;
  2607. //
  2608. // If the event is for a page workset
  2609. //
  2610. if (eventWorksetID >= FIRST_PAGE_WORKSET)
  2611. {
  2612. //
  2613. // We are opening a page workset
  2614. //
  2615. processed = wbOnPageWorksetOpenCon(param1, param2);
  2616. if (!processed)
  2617. {
  2618. DC_QUIT;
  2619. }
  2620. }
  2621. //
  2622. // We are done if this is a page workset other than the 1st page workset
  2623. //
  2624. if (eventWorksetID > FIRST_PAGE_WORKSET)
  2625. {
  2626. DC_QUIT;
  2627. }
  2628. //
  2629. // Now check if it is one of the control worksets (the first page workset
  2630. // is both a control workset and a page workset).
  2631. //
  2632. if (eventWorksetID != FIRST_PAGE_WORKSET)
  2633. {
  2634. //
  2635. // Check the message correlator
  2636. //
  2637. if (pEvent32->correlator != m_worksetOpenCorrelator)
  2638. {
  2639. TRACE_OUT(("Correlators do not match - quitting"));
  2640. DC_QUIT;
  2641. }
  2642. }
  2643. //
  2644. // We are opening a control workset - process the event
  2645. //
  2646. wbOnControlWorksetOpenCon(param1, param2);
  2647. processed = TRUE;
  2648. DC_EXIT_POINT:
  2649. DebugExitBOOL(wbOnWorksetOpenCon, processed);
  2650. return(processed);
  2651. }
  2652. //
  2653. //
  2654. // Name: wbOnControlWorksetOpenCon
  2655. //
  2656. // Purpose: Routine processing OM_WORKSET_OPEN_CON events for control
  2657. // worksets.
  2658. //
  2659. // Returns: Error code
  2660. //
  2661. //
  2662. void WbClient::wbOnControlWorksetOpenCon
  2663. (
  2664. UINT_PTR param1,
  2665. UINT_PTR param2
  2666. )
  2667. {
  2668. POM_EVENT_DATA16 pEvent16 = (POM_EVENT_DATA16) &param1;
  2669. POM_EVENT_DATA32 pEvent32 = (POM_EVENT_DATA32) &param2;
  2670. UINT rc;
  2671. OM_WORKSET_ID eventId;
  2672. DebugEntry(wbOnControlWorksetOpenCon);
  2673. //
  2674. // Check the return code in the open
  2675. //
  2676. if (pEvent32->result != 0)
  2677. {
  2678. ERROR_OUT(("Error reported on workset open = %d", pEvent32->result));
  2679. wbError();
  2680. DC_QUIT;
  2681. }
  2682. //
  2683. // If we are in registration, we are opening the required worksets -
  2684. // continue the process.
  2685. //
  2686. if (m_state > STATE_REGISTERING)
  2687. {
  2688. ERROR_OUT(("Control workset open con after registration"));
  2689. }
  2690. //
  2691. // Set up for opening the next workset
  2692. //
  2693. eventId = pEvent16->worksetID;
  2694. switch(eventId)
  2695. {
  2696. case USER_INFORMATION_WORKSET:
  2697. //
  2698. // The user information workset is given high priority. This allows
  2699. // remote pointer movements to travel quickly.
  2700. //
  2701. TRACE_OUT(("Opening Page Control workset"));
  2702. rc = OM_WorksetOpenPReq(m_pomClient,
  2703. m_hWSGroup,
  2704. PAGE_CONTROL_WORKSET,
  2705. NET_HIGH_PRIORITY,
  2706. FALSE,
  2707. &(m_worksetOpenCorrelator));
  2708. m_subState = STATE_REG_PENDING_WORKSET_OPEN;
  2709. break;
  2710. case PAGE_CONTROL_WORKSET:
  2711. //
  2712. // The sync control workset is given high priority to allow sync
  2713. // updates to travel quickly.
  2714. //
  2715. TRACE_OUT(("Opening Sync Control workset"));
  2716. rc = OM_WorksetOpenPReq(m_pomClient,
  2717. m_hWSGroup,
  2718. SYNC_CONTROL_WORKSET,
  2719. NET_HIGH_PRIORITY,
  2720. FALSE,
  2721. &(m_worksetOpenCorrelator));
  2722. break;
  2723. case SYNC_CONTROL_WORKSET:
  2724. //
  2725. // Open the first of the page worksets - we must do this to allow us
  2726. // to use it as the only page available if we are the first person in
  2727. // the call.
  2728. //
  2729. TRACE_OUT(("Opening first page workset"));
  2730. rc = wbPageWorksetOpen((WB_PAGE_HANDLE)FIRST_PAGE_WORKSET,
  2731. OPEN_LOCAL);
  2732. break;
  2733. case FIRST_PAGE_WORKSET:
  2734. break;
  2735. default:
  2736. ERROR_OUT(("Bad workset ID"));
  2737. break;
  2738. }
  2739. //
  2740. // Check whether we have just opened another workset
  2741. //
  2742. if (eventId != FIRST_PAGE_WORKSET)
  2743. {
  2744. //
  2745. // Test the return code from the open
  2746. //
  2747. if (rc != 0)
  2748. {
  2749. ERROR_OUT(("Workset open failed = %d", rc));
  2750. wbError();
  2751. }
  2752. DC_QUIT;
  2753. }
  2754. //
  2755. // We have now opened all the control worksets. We now add the required
  2756. // control objects.
  2757. //
  2758. rc = wbAddLocalUserObject();
  2759. if (rc != 0)
  2760. {
  2761. //
  2762. // Stop the join call process, tidy up and send an error message to the
  2763. // client.
  2764. //
  2765. wbError();
  2766. DC_QUIT;
  2767. }
  2768. m_subState = STATE_REG_USER_OBJECT_ADDED;
  2769. TRACE_OUT(("Moved to substate STATE_REG_USER_OBJECT_ADDED"));
  2770. //
  2771. // Check whether the Page Control objects are available yet (they could
  2772. // have been added by another user in the call).
  2773. //
  2774. TRACE_OUT(("%x PAGE WS object, %x SYNC WS object",
  2775. m_pObjPageControl,
  2776. m_pObjSyncControl));
  2777. if ( (m_pObjPageControl == 0) &&
  2778. (m_pObjSyncControl == 0))
  2779. {
  2780. TRACE_OUT(("No control objects - WE MIGHT BE FIRST IN CALL - get lock"));
  2781. //
  2782. // We may be the first user to register - request the lock on the Page
  2783. // Control Workset.
  2784. //
  2785. rc = wbLock(WB_LOCK_TYPE_PAGE_ORDER);
  2786. if (rc != 0)
  2787. {
  2788. ERROR_OUT(("Error from wbLock = %d", rc));
  2789. wbError();
  2790. DC_QUIT;
  2791. }
  2792. //
  2793. // Set the new registration state
  2794. //
  2795. m_subState = STATE_REG_PENDING_LOCK;
  2796. TRACE_OUT(("Moved to substate STATE_REG_PENDING_LOCK"));
  2797. DC_QUIT;
  2798. }
  2799. else
  2800. {
  2801. if (m_pObjSyncControl == 0)
  2802. {
  2803. TRACE_OUT(("Waiting for sync control"));
  2804. m_subState = STATE_REG_PENDING_SYNC_CONTROL;
  2805. DC_QUIT;
  2806. }
  2807. if (m_pObjPageControl == 0)
  2808. {
  2809. TRACE_OUT(("Waiting for page control"));
  2810. m_subState = STATE_REG_PENDING_PAGE_CONTROL;
  2811. DC_QUIT;
  2812. }
  2813. }
  2814. //
  2815. // Complete registration
  2816. //
  2817. TRACE_OUT(("Page Control and Sync Control objects both there."));
  2818. TRACE_OUT(("Registration can be completed"));
  2819. wbOnControlWorksetsReady();
  2820. DC_EXIT_POINT:
  2821. DebugExitVOID(wbOnControlWorksetOpenCon);
  2822. }
  2823. //
  2824. //
  2825. // Name: wbPageWorksetOpen
  2826. //
  2827. // Purpose: Open a page workset
  2828. //
  2829. // Returns: Error code
  2830. //
  2831. //
  2832. UINT WbClient::wbPageWorksetOpen
  2833. (
  2834. WB_PAGE_HANDLE hPage,
  2835. UINT localOrExternal
  2836. )
  2837. {
  2838. UINT result;
  2839. PWB_PAGE_STATE pPageState;
  2840. DebugEntry(wbPageWorksetOpen);
  2841. //
  2842. // Get the page state
  2843. //
  2844. pPageState = GetPageState(hPage);
  2845. ASSERT((pPageState->state == PAGE_NOT_IN_USE));
  2846. ASSERT((pPageState->subState == PAGE_STATE_EMPTY));
  2847. //
  2848. // Open the workset. We allow ObMan to choose the priority, this means
  2849. // that ObMan uses a variable priority scheme allowing small objects to
  2850. // overtake large ones.
  2851. //
  2852. result = OM_WorksetOpenPReq(m_pomClient,
  2853. m_hWSGroup,
  2854. (OM_WORKSET_ID)hPage,
  2855. OM_OBMAN_CHOOSES_PRIORITY,
  2856. FALSE,
  2857. &(pPageState->worksetOpenCorrelator));
  2858. if (result != 0)
  2859. {
  2860. ERROR_OUT(("WorksetOpen failed = %d", result));
  2861. DC_QUIT;
  2862. }
  2863. //
  2864. // Update the page state
  2865. //
  2866. if (localOrExternal == OPEN_LOCAL)
  2867. {
  2868. pPageState->subState = PAGE_STATE_LOCAL_OPEN_CONFIRM;
  2869. TRACE_OUT(("Moved page %d state to PAGE_STATE_PENDING_OPEN_CONFIRM",
  2870. (UINT) hPage));
  2871. }
  2872. else
  2873. {
  2874. pPageState->subState = PAGE_STATE_EXTERNAL_OPEN_CONFIRM;
  2875. TRACE_OUT(("Moved page %d state to PAGE_STATE_PENDING_OPEN_CONFIRM",
  2876. (UINT) hPage));
  2877. }
  2878. DC_EXIT_POINT:
  2879. DebugExitDWORD(wbPageWorksetOpen, result);
  2880. return(result);
  2881. }
  2882. //
  2883. //
  2884. // Name: wbOnPageWorksetOpenCon
  2885. //
  2886. // Purpose: Routine processing OM_WORKSET_OPEN_CON events for page worksets
  2887. //
  2888. // Returns: Error code
  2889. //
  2890. //
  2891. BOOL WbClient::wbOnPageWorksetOpenCon
  2892. (
  2893. UINT_PTR param1,
  2894. UINT_PTR param2
  2895. )
  2896. {
  2897. POM_EVENT_DATA16 pEvent16 = (POM_EVENT_DATA16) &param1;
  2898. POM_EVENT_DATA32 pEvent32 = (POM_EVENT_DATA32) &param2;
  2899. BOOL processed = FALSE;
  2900. OM_WORKSET_ID eventId;
  2901. PWB_PAGE_STATE pPageState;
  2902. WB_PAGE_HANDLE hPage;
  2903. UINT oldState;
  2904. DebugEntry(wbOnPageWorksetOpenCon);
  2905. //
  2906. // Get the page state pointer
  2907. //
  2908. eventId = pEvent16->worksetID;
  2909. hPage = (WB_PAGE_HANDLE)eventId;
  2910. pPageState = GetPageState(hPage);
  2911. //
  2912. // Check the message correlator
  2913. //
  2914. if (pEvent32->correlator != pPageState->worksetOpenCorrelator)
  2915. {
  2916. TRACE_OUT(("Correlators do not match - quitting"));
  2917. DC_QUIT;
  2918. }
  2919. //
  2920. // Show that we have processed this event
  2921. //
  2922. processed = TRUE;
  2923. //
  2924. // Check the return code in the open
  2925. //
  2926. if (pEvent32->result != 0)
  2927. {
  2928. ERROR_OUT(("Error reported on page workset open = %d",
  2929. pEvent32->result));
  2930. pPageState->subState = PAGE_STATE_EMPTY;
  2931. TRACE_OUT(("Moved page %d substate to PAGE_STATE_EMPTY",
  2932. (UINT)hPage));
  2933. DC_QUIT;
  2934. }
  2935. //
  2936. // Update the page state to indicate that the page is now ready for use
  2937. //
  2938. oldState = pPageState->subState;
  2939. pPageState->subState = PAGE_STATE_READY;
  2940. TRACE_OUT(("Moved page %d to substate to PAGE_STATE_READY",
  2941. (UINT)hPage));
  2942. switch (oldState)
  2943. {
  2944. case PAGE_STATE_LOCAL_OPEN_CONFIRM:
  2945. //
  2946. // This workset was opened locally, therefore it is being opened as
  2947. // part of the workset cache. Nothing more to do.
  2948. //
  2949. break;
  2950. case PAGE_STATE_EXTERNAL_OPEN_CONFIRM:
  2951. //
  2952. // This workset was opened as a result of external updates to the
  2953. // Page Control object. We therefore need to add the page to the
  2954. // page list now that the workset is open. We no longer know where
  2955. // the page is to be added - so call the main Page Control update
  2956. // routine again to get all the information.
  2957. //
  2958. wbProcessPageControlChanges();
  2959. break;
  2960. default:
  2961. ERROR_OUT(("Bad page state %d", pPageState->subState));
  2962. break;
  2963. }
  2964. //
  2965. // Increment the number of pages in ready state. This count is never
  2966. // decremented - once a workset is open it stays open.
  2967. //
  2968. m_countReadyPages += 1;
  2969. //
  2970. // If we are in registration and are waiting for the cache of ready
  2971. // pages, we must complete registration now.
  2972. //
  2973. if ( (m_state == STATE_REGISTERING) &&
  2974. (m_subState == STATE_REG_PENDING_READY_PAGES) )
  2975. {
  2976. //
  2977. // If there are enough pages in the cache
  2978. //
  2979. if (wbCheckReadyPages())
  2980. {
  2981. //
  2982. // We have enough ready pages - complete registration
  2983. //
  2984. wbCompleteRegistration();
  2985. DC_QUIT;
  2986. }
  2987. //
  2988. // There are not yet enough pages in the cache. CheckReadyPages will
  2989. // have made a new workset open request, so we will receive another
  2990. // workset open confirm soon.
  2991. //
  2992. DC_QUIT;
  2993. }
  2994. DC_EXIT_POINT:
  2995. DebugExitBOOL(wbOnPageWorksetOpenCon, processed);
  2996. return(processed);
  2997. }
  2998. //
  2999. //
  3000. // Name: wbOnWorksetLockCon
  3001. //
  3002. // Purpose: Routine processing OM_WORKSET_LOCK_CON events.
  3003. //
  3004. // Returns: Error code
  3005. //
  3006. //
  3007. BOOL WbClient::wbOnWorksetLockCon
  3008. (
  3009. UINT_PTR param1,
  3010. UINT_PTR param2
  3011. )
  3012. {
  3013. POM_EVENT_DATA16 pEvent16 = (POM_EVENT_DATA16) &param1;
  3014. POM_EVENT_DATA32 pEvent32 = (POM_EVENT_DATA32) &param2;
  3015. BOOL processed = FALSE;
  3016. UINT rc;
  3017. DebugEntry(wbOnWorksetLockCon);
  3018. //
  3019. // Check the message correlator
  3020. //
  3021. if (pEvent32->correlator != m_lockCorrelator)
  3022. {
  3023. DC_QUIT;
  3024. }
  3025. //
  3026. // The message is for us - set the result to "processed"
  3027. //
  3028. processed = TRUE;
  3029. //
  3030. // Check that the event is for the Page Control Workset (this is the
  3031. // only expected workset).
  3032. //
  3033. if (pEvent16->worksetID != PAGE_CONTROL_WORKSET)
  3034. {
  3035. ERROR_OUT(("Unexpected workset in LockCon = %d",
  3036. pEvent16->worksetID));
  3037. }
  3038. //
  3039. // Process according to the current lock state
  3040. //
  3041. switch (m_lockState)
  3042. {
  3043. //
  3044. // We were waiting for lock confirmation
  3045. //
  3046. case LOCK_STATE_PENDING_LOCK:
  3047. //
  3048. // Check the return code in the event
  3049. //
  3050. if (pEvent32->result != 0)
  3051. {
  3052. TRACE_OUT(("Posting WBP_EVENT_LOCK_FAILED, rc %d",
  3053. pEvent32->result));
  3054. WBP_PostEvent(0, // No delay
  3055. WBP_EVENT_LOCK_FAILED, // Lock request failed
  3056. 0, // No parameters
  3057. 0);
  3058. //
  3059. // The lock failed - update the state. This means that
  3060. // another user has acquired the lock. We expect to get a
  3061. // lock object add indication soon.
  3062. //
  3063. m_lockState = LOCK_STATE_EMPTY;
  3064. TRACE_OUT(("Lock request failed - lock state is now EMPTY"));
  3065. DC_QUIT;
  3066. }
  3067. //
  3068. // Write the lock details to the Page Control Workset
  3069. //
  3070. rc = wbWriteLock();
  3071. if (rc != 0)
  3072. {
  3073. ERROR_OUT(("Unable to write lock details = %d", rc));
  3074. //
  3075. // Tidy up by unlocking the Page Control Workset
  3076. //
  3077. OM_WorksetUnlock(m_pomClient,
  3078. m_hWSGroup,
  3079. PAGE_CONTROL_WORKSET);
  3080. //
  3081. // Tell the client of the failure
  3082. //
  3083. TRACE_OUT(("Posting WBP_EVENT_LOCK_FAILED"));
  3084. WBP_PostEvent(0, // No delay
  3085. WBP_EVENT_LOCK_FAILED, // Lock request failed
  3086. 0, // No parameters
  3087. 0);
  3088. //
  3089. // Update the lock state
  3090. //
  3091. m_lockState = LOCK_STATE_EMPTY;
  3092. TRACE_OUT(("Moved lock state to LOCK_STATE_EMPTY"));
  3093. DC_QUIT;
  3094. }
  3095. //
  3096. // Once we get here the write of the lock object above will
  3097. // trigger an object add event that completes the lock
  3098. // processing.
  3099. //
  3100. m_lockState = LOCK_STATE_PENDING_ADD;
  3101. TRACE_OUT(("Moved lock state to LOCK_STATE_PENDING_ADD"));
  3102. break;
  3103. //
  3104. // The application has cancelled the lock request before it has had
  3105. // time to complete - tidy up.
  3106. //
  3107. case LOCK_STATE_CANCEL_LOCK:
  3108. TRACE_OUT(("LOCK_STATE_CANCEL_LOCK"));
  3109. //
  3110. // If the request failed, just reset the state.
  3111. //
  3112. //
  3113. // The lock was cancelled - unlock the workset if necessary,
  3114. // and notify the front-end of the unlock.
  3115. //
  3116. if (pEvent32->result == 0)
  3117. {
  3118. //
  3119. // We have locked the workset successfully, but in the
  3120. // meantime the front-end has cancelled the lock, so unlock
  3121. // the workset now.
  3122. //
  3123. TRACE_OUT((
  3124. "Lock cancelled before workset locked, so unlock now"));
  3125. OM_WorksetUnlock(m_pomClient,
  3126. m_hWSGroup,
  3127. PAGE_CONTROL_WORKSET);
  3128. }
  3129. m_lockState = LOCK_STATE_EMPTY;
  3130. //
  3131. // Tell the app that we have cancelled the lock.
  3132. //
  3133. TRACE_OUT(("Posting WBP_EVENT_UNLOCKED"));
  3134. WBP_PostEvent(0,
  3135. WBP_EVENT_UNLOCKED,
  3136. 0,
  3137. 0);
  3138. break;
  3139. //
  3140. // Another has got in before us
  3141. //
  3142. case LOCK_STATE_LOCKED_OUT:
  3143. //
  3144. // We have received a lock confirmation and should have been
  3145. // expecting the lock. But we are locked out. This means that
  3146. // another user has got in just before us, acquired the lock
  3147. // and added the lock object. We have processed the add and
  3148. // changed the lock state accordingly. This lock confirmation
  3149. // will therefore normally be a failure. If by some fluke it
  3150. // isn't, then we treat it as a failure for safety.
  3151. //
  3152. if (pEvent32->result == 0)
  3153. {
  3154. ERROR_OUT(("Lock violation"));
  3155. //
  3156. // Tidy up by unlocking the Page Control Workset - leave
  3157. // the state as LOCKED_OUT; we'll clear it on receipt of
  3158. // the unlock (either local, or from the locking user).
  3159. //
  3160. OM_WorksetUnlock(m_pomClient,
  3161. m_hWSGroup,
  3162. PAGE_CONTROL_WORKSET);
  3163. }
  3164. break;
  3165. default:
  3166. ERROR_OUT(("Bad lock state %d", m_lockState));
  3167. break;
  3168. } // Switch on lock state
  3169. DC_EXIT_POINT:
  3170. DebugExitBOOL(wbOnWorksetLockCon, processed);
  3171. return(processed);
  3172. }
  3173. //
  3174. //
  3175. // Name: wbOnWorksetUnlockInd
  3176. //
  3177. // Purpose: Routine processing OM_WORKSET_UNLOCK_IND events.
  3178. //
  3179. // Returns: Error code
  3180. //
  3181. //
  3182. BOOL WbClient::wbOnWorksetUnlockInd
  3183. (
  3184. UINT_PTR param1,
  3185. UINT_PTR param2
  3186. )
  3187. {
  3188. POM_EVENT_DATA16 pEvent16 = (POM_EVENT_DATA16) &param1;
  3189. POM_EVENT_DATA32 pEvent32 = (POM_EVENT_DATA32) &param2;
  3190. BOOL processed = TRUE;
  3191. DebugEntry(wbOnWorksetUnlockInd);
  3192. //
  3193. // We are only interested if the workset id is that of the Page Control
  3194. // Workset.
  3195. //
  3196. if (pEvent16->worksetID != PAGE_CONTROL_WORKSET)
  3197. {
  3198. TRACE_OUT(("Unexpected workset in unlock = %d", pEvent16->worksetID));
  3199. DC_QUIT;
  3200. }
  3201. switch (m_lockState)
  3202. {
  3203. //
  3204. // We had the lock and are waiting to unlock or another user had
  3205. // the lock and has now removed it.
  3206. //
  3207. case LOCK_STATE_LOCKED_OUT:
  3208. //
  3209. // We received the unlock of the workset before the removal of
  3210. // the lock object; we just ignore this, since the deletion of
  3211. // the lock object is our indication that the wb lock is removed.
  3212. //
  3213. TRACE_OUT(("Unlock of page control workset while locked out"));
  3214. break;
  3215. //
  3216. // We are unlocking after an error acquiring the lock or after a
  3217. // user has cancelled alock before we had time to complete it.
  3218. //
  3219. case LOCK_STATE_CANCEL_LOCK:
  3220. //
  3221. // An error occurred in getting the lock - the client has
  3222. // already been informed so we just record the state change.
  3223. //
  3224. m_lockState = LOCK_STATE_EMPTY;
  3225. TRACE_OUT(("Moved lock state to LOCK_STATE_EMPTY"));
  3226. break;
  3227. //
  3228. // We are waiting for the lock - but have got an unlock instead.
  3229. // This could be from another user, or from previous aborted
  3230. // attempts by us to get the lock. We ignore the event and wait
  3231. // for our lock confirmation.
  3232. //
  3233. case LOCK_STATE_PENDING_LOCK:
  3234. TRACE_OUT((
  3235. "Got unlock indication while waiting for lock confirmation"));
  3236. break;
  3237. //
  3238. // We can get an unlock indication without ever having seen the
  3239. // lock object if the lock object was never added (failure at
  3240. // another user) or if ObMan has spoiled the add and delete.
  3241. //
  3242. case LOCK_STATE_EMPTY:
  3243. TRACE_OUT(("Unlock received in LOCK_STATE_EMPTY - ignoring"));
  3244. break;
  3245. //
  3246. // Unlock not expected in this state
  3247. //
  3248. default:
  3249. ERROR_OUT(("Bad lock state %d", m_lockState));
  3250. break;
  3251. }
  3252. DC_EXIT_POINT:
  3253. DebugExitBOOL(wbOnWorksetUnlockInd, processed);
  3254. return(processed);
  3255. }
  3256. //
  3257. //
  3258. // Name: wbOnControlWorksetsReady
  3259. //
  3260. // Purpose: The control worksets have been opened and set up. Continue the
  3261. // registration process by updating the internal page order to
  3262. // ensure that in matches the external order.
  3263. //
  3264. // Returns: Error code
  3265. //
  3266. //
  3267. void WbClient::wbOnControlWorksetsReady(void)
  3268. {
  3269. DebugEntry(wbOnControlWorksetsReady);
  3270. //
  3271. // Read the Page Control object and compare its content to the internal
  3272. // Page Order.
  3273. //
  3274. wbProcessPageControlChanges();
  3275. //
  3276. // Update the state to show that we are waiting for the Page Order
  3277. // Updated event indicating that the internal page order now matches
  3278. // the external order.
  3279. //
  3280. m_subState = STATE_REG_PENDING_PAGE_ORDER;
  3281. TRACE_OUT(("Moved sub state to STATE_REG_PENDING_PAGE_ORDER"));
  3282. DebugExitVOID(wbOnControlWorksetsReady);
  3283. }
  3284. //
  3285. //
  3286. // Name: wbCompleteRegistration
  3287. //
  3288. // Purpose: Perform the final steps in registering a client. These are:
  3289. // post a WB_EVENT_REGISTERED event to the client; check if
  3290. // another user has a lock on the contents or page order, if so,
  3291. // post a WB_EVENT_CONTENTS_LOCKED or WB_EVENT_PAGE_ORDER_LOCKED
  3292. // to the client.
  3293. //
  3294. // Returns: Error code
  3295. //
  3296. //
  3297. void WbClient::wbCompleteRegistration(void)
  3298. {
  3299. DebugEntry(wbCompleteRegistration);
  3300. //
  3301. // Inform the client that we are fully registered
  3302. //
  3303. TRACE_OUT(("Posting WBP_EVENT_REGISTER_OK"));
  3304. WBP_PostEvent(0, // No delay
  3305. WBP_EVENT_JOIN_CALL_OK, // Fully registered
  3306. 0, // No parameters
  3307. 0);
  3308. //
  3309. // Notify the client of the lock status
  3310. //
  3311. wbSendLockNotification();
  3312. //
  3313. // Record that we are now fully registered
  3314. //
  3315. m_state = STATE_IDLE;
  3316. m_subState = STATE_EMPTY;
  3317. TRACE_OUT(("Moved to state STATE_IDLE"));
  3318. DebugExitVOID(wbCompleteRegistration);
  3319. }
  3320. //
  3321. //
  3322. // Name: wbLeaveCall
  3323. //
  3324. // Purpose: Remove a client from a call/workset group
  3325. //
  3326. // Returns: None
  3327. //
  3328. //
  3329. void WbClient::wbLeaveCall(void)
  3330. {
  3331. DebugEntry(wbLeaveCall);
  3332. //
  3333. // If we have not got far enough to have entered a call - leave now
  3334. // (there is nothing to tidy up).
  3335. //
  3336. if (m_state < STATE_REGISTERING)
  3337. {
  3338. DC_QUIT;
  3339. }
  3340. //
  3341. // If we have the lock - delete the lock object (the workset will be
  3342. // unlocked by ObMan when we deregister).
  3343. //
  3344. if (m_lockState == LOCK_STATE_GOT_LOCK)
  3345. {
  3346. TRACE_OUT(("Still got lock - deleting lock object, handle %d",
  3347. m_pObjLock));
  3348. if (OM_ObjectDelete(m_pomClient,
  3349. m_hWSGroup,
  3350. PAGE_CONTROL_WORKSET,
  3351. m_pObjLock) != 0)
  3352. {
  3353. ERROR_OUT(("Error deleting lock object"));
  3354. }
  3355. //
  3356. // If all is well at this point the unlock process will be
  3357. // completed when the object delete ind is received.
  3358. //
  3359. m_lockState = LOCK_STATE_PENDING_DELETE;
  3360. TRACE_OUT(("Moved to state LOCK_STATE_PENDING_DELETE"));
  3361. }
  3362. //
  3363. // Fix up the sub state to indicate that all registration actions have
  3364. // been completed (to ensure that they are all undone).
  3365. //
  3366. if (m_state > STATE_REGISTERING)
  3367. {
  3368. m_subState = STATE_REG_END;
  3369. TRACE_OUT(("Moved to substate STATE_REG_END"));
  3370. }
  3371. //
  3372. // Delete the user object representing the local user from the User
  3373. // Information Workset (if it is present). Note that we are about to
  3374. // deregister from ObMan - this acts as automatic confirmation of the
  3375. // delete request so we do not need to wait for the
  3376. // OM_OBJECT_DELETE_IND event.
  3377. //
  3378. if (m_subState >= STATE_REG_USER_OBJECT_ADDED)
  3379. {
  3380. TRACE_OUT(("Deleting user object"));
  3381. if (OM_ObjectDelete(m_pomClient,
  3382. m_hWSGroup,
  3383. USER_INFORMATION_WORKSET,
  3384. m_pObjLocal) != 0)
  3385. {
  3386. //
  3387. // Trace the error but do not quit - we expect everything to be
  3388. // tidied up when we deregister from ObMan.
  3389. //
  3390. ERROR_OUT(("Error deleting local user object"));
  3391. }
  3392. }
  3393. //
  3394. // If we have already registered with the Workset Group, deregister
  3395. // now. we have not yet received the confirmation, and get it later we
  3396. // will deregister immediately.
  3397. //
  3398. if (m_subState > STATE_REG_PENDING_WSGROUP_CON)
  3399. {
  3400. OM_WSGroupDeregister(m_pomClient, &(m_hWSGroup));
  3401. }
  3402. else
  3403. {
  3404. //
  3405. // We have not yet received the Workset Group Registration
  3406. // confirmation, change the value in the correlator field so that
  3407. // we recognize the fact that we have cancelled registration later.
  3408. //
  3409. m_wsgroupCorrelator--;
  3410. }
  3411. //
  3412. // Reset the handles of objects added during registration
  3413. //
  3414. TRACE_OUT(("Resetting client data"));
  3415. wbClientReset();
  3416. //
  3417. // Set the client state to the appropriate value
  3418. //
  3419. m_state = STATE_STARTED;
  3420. m_subState = STATE_STARTED_START;
  3421. TRACE_OUT(("Moved state to STATE_STARTED"));
  3422. DC_EXIT_POINT:
  3423. DebugExitVOID(wbLeaveCall);
  3424. }
  3425. //
  3426. //
  3427. // Name: wbContentsDelete
  3428. //
  3429. // Purpose: Remove all the current graphics and pages, leaving a single
  3430. // blank page.
  3431. //
  3432. // Returns: None
  3433. //
  3434. //
  3435. void WbClient::wbContentsDelete
  3436. (
  3437. UINT changedFlagAction
  3438. )
  3439. {
  3440. PWB_PAGE_ORDER pPageOrder = &(m_pageOrder);
  3441. PWB_PAGE_STATE pPageState;
  3442. UINT index;
  3443. DebugEntry(wbContentsDelete);
  3444. //
  3445. // Just clear the first page in the list
  3446. //
  3447. wbPageClear(pPageOrder->pages[0], changedFlagAction);
  3448. //
  3449. // If there is only one page left in the list - we're done.
  3450. //
  3451. if (pPageOrder->countPages == 1)
  3452. {
  3453. DC_QUIT;
  3454. }
  3455. //
  3456. // There is more than one page
  3457. //
  3458. //
  3459. // Mark all of the active pages (except the first) as "delete pending"
  3460. //
  3461. for (index = 1; index < pPageOrder->countPages; index++)
  3462. {
  3463. pPageState = GetPageState((pPageOrder->pages)[index]);
  3464. if ((pPageState->state == PAGE_IN_USE) &&
  3465. (pPageState->subState == PAGE_STATE_EMPTY))
  3466. {
  3467. pPageState->subState = PAGE_STATE_LOCAL_DELETE;
  3468. }
  3469. }
  3470. //
  3471. // Write the page control information. The replace event generated by
  3472. // the write will kick off the actual deletion of the pages marked.
  3473. //
  3474. wbWritePageControl(FALSE);
  3475. DC_EXIT_POINT:
  3476. DebugExitVOID(wbContentsDelete);
  3477. }
  3478. //
  3479. //
  3480. // Name: wbStartContentsLoad
  3481. //
  3482. // Purpose: Start the loading of a file (after the contents have been
  3483. // cleared).
  3484. //
  3485. // Returns: Error code
  3486. //
  3487. //
  3488. void WbClient::wbStartContentsLoad(void)
  3489. {
  3490. DebugEntry(wbStartContentsLoad);
  3491. //
  3492. // Specify the first (and only) page handle as the page to load to
  3493. //
  3494. wbPageHandleFromNumber(1, &m_loadPageHandle);
  3495. //
  3496. // Update the load state to show that we are now loading
  3497. //
  3498. m_loadState = LOAD_STATE_LOADING;
  3499. TRACE_OUT(("Moved load state to LOAD_STATE_LOADING"));
  3500. //
  3501. // Load the first page - subsequent pages are chained from this first one
  3502. //
  3503. wbPageLoad();
  3504. DebugExitVOID(wbStartContentsLoad);
  3505. }
  3506. //
  3507. //
  3508. // Name: wbLock
  3509. //
  3510. // Purpose: Request the lock for the Whiteboard contents or the page order
  3511. // generating one of the following events:
  3512. //
  3513. // WB_EVENT_CONTENTS_LOCKED
  3514. // WB_EVENT_CONTENTS_LOCK_FAILED.
  3515. //
  3516. // Returns: Error code
  3517. //
  3518. //
  3519. UINT WbClient::wbLock(WB_LOCK_TYPE lockType)
  3520. {
  3521. UINT result = 0;
  3522. OM_CORRELATOR correlator;
  3523. DebugEntry(wbLock);
  3524. //
  3525. // If we already have the lock we can merely change its status
  3526. //
  3527. if (m_lockState == LOCK_STATE_GOT_LOCK)
  3528. {
  3529. TRACE_OUT(("Already got the lock"));
  3530. m_lockRequestType = lockType;
  3531. result = wbWriteLock();
  3532. DC_QUIT;
  3533. }
  3534. //
  3535. // Request the lock for the Page Control Workset
  3536. //
  3537. result = OM_WorksetLockReq(m_pomClient,
  3538. m_hWSGroup,
  3539. PAGE_CONTROL_WORKSET,
  3540. &correlator);
  3541. if (result != 0)
  3542. {
  3543. ERROR_OUT(("OM_WorksetLockReq failed, result = %d", result));
  3544. DC_QUIT;
  3545. }
  3546. TRACE_OUT(("Requested lock for the Page Control Workset"));
  3547. //
  3548. // Save the lock details
  3549. //
  3550. m_lockState = LOCK_STATE_PENDING_LOCK;
  3551. m_lockCorrelator = correlator;
  3552. m_lockRequestType = lockType;
  3553. TRACE_OUT(("Moved lock state to LOCK_STATE_PENDING_LOCK"));
  3554. TRACE_OUT(("Lock type requested = %d", lockType));
  3555. //
  3556. // We return now, further processing is done when the OM_WORKSET_LOCK_CON
  3557. // event is received.
  3558. //
  3559. DC_EXIT_POINT:
  3560. DebugExitDWORD(wbLock, result);
  3561. return(result);
  3562. }
  3563. //
  3564. //
  3565. // Name: wbUnlock
  3566. //
  3567. // Purpose: Unlock the Contents or Page Order.
  3568. //
  3569. // Returns: Error code
  3570. //
  3571. //
  3572. void WbClient::wbUnlock(void)
  3573. {
  3574. DebugEntry(wbUnlock);
  3575. //
  3576. // Check that we have the lock
  3577. //
  3578. if (m_lockState != LOCK_STATE_GOT_LOCK)
  3579. {
  3580. ERROR_OUT(("Local person doesn't have lock"));
  3581. DC_QUIT;
  3582. }
  3583. //
  3584. // Delete the lock object
  3585. //
  3586. TRACE_OUT(("Delete Lock handle %x", m_pObjLock));
  3587. if (OM_ObjectDelete(m_pomClient,
  3588. m_hWSGroup,
  3589. PAGE_CONTROL_WORKSET,
  3590. m_pObjLock) != 0)
  3591. {
  3592. ERROR_OUT(("Could not delete lock object"));
  3593. DC_QUIT;
  3594. }
  3595. //
  3596. // If all is well at this point the unlock process will be completed when
  3597. // the object delete ind is received.
  3598. //
  3599. m_lockState = LOCK_STATE_PENDING_DELETE;
  3600. TRACE_OUT(("Moved to state LOCK_STATE_PENDING_DELETE"));
  3601. DC_EXIT_POINT:
  3602. DebugExitVOID(wbUnlock);
  3603. }
  3604. //
  3605. //
  3606. // Name: wbObjectSave
  3607. //
  3608. // Purpose: Save a structure to file
  3609. //
  3610. // Returns: Error code
  3611. //
  3612. //
  3613. UINT WbClient::wbObjectSave
  3614. (
  3615. HANDLE hFile,
  3616. LPBYTE pData,
  3617. UINT length
  3618. )
  3619. {
  3620. UINT result = 0;
  3621. ULONG cbSizeWritten;
  3622. DebugEntry(wbObjectSave);
  3623. //
  3624. // Save the length
  3625. //
  3626. if (! WriteFile(hFile, (void *) &length, sizeof(length), &cbSizeWritten, NULL))
  3627. {
  3628. result = WB_RC_WRITE_FAILED;
  3629. ERROR_OUT(("Error writing length to file, win32 err=%d", GetLastError()));
  3630. DC_QUIT;
  3631. }
  3632. ASSERT(cbSizeWritten == sizeof(length));
  3633. //
  3634. // Save the object data
  3635. //
  3636. if (! WriteFile(hFile, pData, length, &cbSizeWritten, NULL))
  3637. {
  3638. result = WB_RC_WRITE_FAILED;
  3639. ERROR_OUT(("Error writing data to file, win32 err=%d", GetLastError()));
  3640. DC_QUIT;
  3641. }
  3642. ASSERT(cbSizeWritten == length);
  3643. DC_EXIT_POINT:
  3644. DebugExitDWORD(wbObjectSave, result);
  3645. return result;
  3646. }
  3647. //
  3648. //
  3649. // Name: wbPageSave
  3650. //
  3651. // Purpose: Save the contents of a single page to file.
  3652. //
  3653. // Returns: Error code
  3654. //
  3655. //
  3656. UINT WbClient::wbPageSave
  3657. (
  3658. WB_PAGE_HANDLE hPage,
  3659. HANDLE hFile
  3660. )
  3661. {
  3662. UINT result = 0;
  3663. UINT rc;
  3664. OM_WORKSET_ID worksetID = (OM_WORKSET_ID)hPage;
  3665. POM_OBJECT pObj;
  3666. POM_OBJECTDATA pData;
  3667. WB_END_OF_PAGE endOfPage;
  3668. DebugEntry(wbPageSave);
  3669. //
  3670. // Get the first object
  3671. //
  3672. result = OM_ObjectH(m_pomClient,
  3673. m_hWSGroup,
  3674. worksetID,
  3675. 0,
  3676. &pObj,
  3677. FIRST);
  3678. if (result == OM_RC_NO_SUCH_OBJECT)
  3679. {
  3680. // This can happen on an empty page, not an error
  3681. TRACE_OUT(("No objects left, quitting with good return"));
  3682. result = 0;
  3683. DC_QUIT;
  3684. }
  3685. if (result != 0)
  3686. {
  3687. ERROR_OUT(("Error getting first object in page"));
  3688. DC_QUIT;
  3689. }
  3690. //
  3691. // Loop through the objects
  3692. //
  3693. for( ; ; )
  3694. {
  3695. //
  3696. // Get a pointer to the object
  3697. //
  3698. result = OM_ObjectRead(m_pomClient,
  3699. m_hWSGroup,
  3700. worksetID,
  3701. pObj,
  3702. &pData);
  3703. if (result != 0)
  3704. {
  3705. ERROR_OUT(("Error reading object = %d", result));
  3706. DC_QUIT;
  3707. }
  3708. //
  3709. // Save the object data
  3710. //
  3711. rc = wbObjectSave(hFile,
  3712. (LPBYTE) pData->data,
  3713. pData->length);
  3714. //
  3715. // The return code is tested after we have released the object because
  3716. // we must always do the release.
  3717. //
  3718. //
  3719. // Release the object
  3720. //
  3721. OM_ObjectRelease(m_pomClient,
  3722. m_hWSGroup,
  3723. worksetID,
  3724. pObj,
  3725. &pData);
  3726. //
  3727. // Now test the write return code
  3728. //
  3729. if (rc != 0)
  3730. {
  3731. result = rc;
  3732. ERROR_OUT(("Error writing object data = %d", result));
  3733. DC_QUIT;
  3734. }
  3735. //
  3736. // Get the next object
  3737. //
  3738. result = OM_ObjectH(m_pomClient,
  3739. m_hWSGroup,
  3740. worksetID,
  3741. pObj,
  3742. &pObj,
  3743. AFTER);
  3744. if (result == OM_RC_NO_SUCH_OBJECT)
  3745. {
  3746. TRACE_OUT(("No objects left, quitting with good return"));
  3747. result = 0;
  3748. DC_QUIT;
  3749. }
  3750. }
  3751. DC_EXIT_POINT:
  3752. //
  3753. // If we have successfully written the page contents, we write an end-of-
  3754. // page marker to the file.
  3755. //
  3756. if (result == 0)
  3757. {
  3758. //
  3759. // Set the end of page object details
  3760. //
  3761. ZeroMemory(&endOfPage, sizeof(endOfPage));
  3762. endOfPage.length = sizeof(endOfPage);
  3763. endOfPage.type = TYPE_END_OF_PAGE;
  3764. //
  3765. // Write the end-of-page object
  3766. //
  3767. result = wbObjectSave(hFile,
  3768. (LPBYTE) &endOfPage,
  3769. sizeof(endOfPage));
  3770. if (result != 0)
  3771. {
  3772. ERROR_OUT(("Error writing end-of-page = %d", result));
  3773. }
  3774. }
  3775. DebugExitDWORD(wbPageSave, result);
  3776. return(result);
  3777. }
  3778. //
  3779. //
  3780. // Name: wbPageLoad
  3781. //
  3782. // Purpose: Load the contents of a single page from file.
  3783. //
  3784. // Returns: Error code
  3785. //
  3786. //
  3787. void WbClient::wbPageLoad(void)
  3788. {
  3789. UINT result = 0;
  3790. UINT type;
  3791. POM_OBJECT pObj;
  3792. POM_OBJECTDATA pData = NULL;
  3793. PWB_GRAPHIC pGraphic = NULL;
  3794. WB_PAGE_HANDLE hPage = m_loadPageHandle;
  3795. WB_PAGE_HANDLE hNewPage;
  3796. UINT postDelay = 0;
  3797. DebugEntry(wbPageLoad);
  3798. TRACE_OUT(("Entered wbPageLoad for page %d", (UINT) hPage));
  3799. //
  3800. // Check the load state - if we're not loading, then quit (can happen if
  3801. // the load is cancelled).
  3802. //
  3803. if (m_loadState == LOAD_STATE_EMPTY)
  3804. {
  3805. TRACE_OUT(("Load has been cancelled - abandoning page load"));
  3806. DC_QUIT;
  3807. }
  3808. //
  3809. // Check that we have a full complement of ready pages before starting
  3810. // the load.
  3811. //
  3812. if (!wbCheckReadyPages())
  3813. {
  3814. //
  3815. // There are not enough pages worksets ready to be used. We exit now
  3816. // to allow the page to be made ready before we continue. We set up a
  3817. // delay on the message that will be used to restart the process to
  3818. // allow the worksets to be opened before we get back in here.
  3819. //
  3820. postDelay = 200;
  3821. DC_QUIT;
  3822. }
  3823. //
  3824. // If we are waiting to add a new page, get the handle of the page we
  3825. // expect to add next here. (We have to do this as ObMan requires that
  3826. // we allocate memory for the object in the correct workset, but we do
  3827. // not want to actually add the page here because we may not need it.)
  3828. //
  3829. if (m_loadState == LOAD_STATE_PENDING_NEW_PAGE)
  3830. {
  3831. hNewPage = wbGetReadyPageHandle();
  3832. //
  3833. // If we cannot get a ready page - we must have run out of pages (we
  3834. // have already done a check on the availability of ready pages above).
  3835. // If we cannot get a new page we continue using the old.
  3836. //
  3837. if (hNewPage != WB_PAGE_HANDLE_NULL)
  3838. {
  3839. hPage = hNewPage;
  3840. }
  3841. }
  3842. //
  3843. // Read the next object
  3844. //
  3845. result = wbObjectLoad(m_hLoadFile,
  3846. (OM_WORKSET_ID)hPage,
  3847. &pGraphic);
  3848. if (result != 0)
  3849. {
  3850. ERROR_OUT(("Error reading object = %d", result));
  3851. DC_QUIT;
  3852. }
  3853. pData = ObjectDataPtrFromGraphic(pGraphic);
  3854. type = pGraphic->type;
  3855. //
  3856. // Process the object according to type
  3857. //
  3858. //
  3859. // End of file marker
  3860. //
  3861. if (type == TYPE_END_OF_FILE)
  3862. {
  3863. //
  3864. // Let the Front End know that the load has completed
  3865. //
  3866. TRACE_OUT(("Posting WBP_EVENT_LOAD_COMPLETE"));
  3867. WBP_PostEvent(
  3868. 0, // No delay
  3869. WBP_EVENT_LOAD_COMPLETE, // Load completed
  3870. 0, // No parameters
  3871. 0);
  3872. //
  3873. // Leave now - the file will be closed below
  3874. //
  3875. DC_QUIT;
  3876. }
  3877. //
  3878. // It is not an end-of file object. So it must be either an end-of page
  3879. // or a graphic object. In either case we may already have flagged the
  3880. // need to add a new page.
  3881. //
  3882. //
  3883. // Add a new page (if necessary)
  3884. //
  3885. if (m_loadState == LOAD_STATE_PENDING_NEW_PAGE)
  3886. {
  3887. //
  3888. // If we could not get a new page handle above leave with an error
  3889. //
  3890. if (hPage == m_loadPageHandle)
  3891. {
  3892. ERROR_OUT(("Run out of pages for load"));
  3893. result = WB_RC_TOO_MANY_PAGES;
  3894. DC_QUIT;
  3895. }
  3896. //
  3897. // Add a new page after the current page. The new page handle is saved
  3898. // in the client details.
  3899. //
  3900. result = wbPageAdd(m_loadPageHandle,
  3901. PAGE_AFTER,
  3902. &(m_loadPageHandle),
  3903. DONT_RESET_CHANGED_FLAG);
  3904. if (result != 0)
  3905. {
  3906. ERROR_OUT(("Failed to add page"));
  3907. DC_QUIT;
  3908. }
  3909. //
  3910. // Check that we got the page handle we expected
  3911. //
  3912. ASSERT((hPage == m_loadPageHandle));
  3913. //
  3914. // Show that we are no longer waiting for a new page
  3915. //
  3916. m_loadState = LOAD_STATE_LOADING;
  3917. }
  3918. //
  3919. // End of page marker
  3920. //
  3921. if (type == TYPE_END_OF_PAGE)
  3922. {
  3923. TRACE_OUT(("End of page object"));
  3924. //
  3925. // Discard the object
  3926. //
  3927. OM_ObjectDiscard(m_pomClient,
  3928. m_hWSGroup,
  3929. (OM_WORKSET_ID)hPage,
  3930. &pData);
  3931. pData = NULL;
  3932. //
  3933. // Set the load state to "pending new page" and leave the routine
  3934. // immediately. The process continues when we return to this routine.
  3935. //
  3936. m_loadState = LOAD_STATE_PENDING_NEW_PAGE;
  3937. //
  3938. // Exit (we post ourselves a message below to get us back into this
  3939. // routine later).
  3940. //
  3941. postDelay = 100;
  3942. DC_QUIT;
  3943. }
  3944. //
  3945. // The object is a standard graphic
  3946. //
  3947. TRACE_OUT(("Graphic object"));
  3948. //
  3949. // Add the object to the page
  3950. //
  3951. result = OM_ObjectAdd(m_pomClient,
  3952. m_hWSGroup,
  3953. (OM_WORKSET_ID)hPage,
  3954. &pData,
  3955. sizeof(WB_GRAPHIC),
  3956. &pObj,
  3957. LAST);
  3958. if (result != 0)
  3959. {
  3960. DC_QUIT;
  3961. }
  3962. //
  3963. // Show that we have finished with the object
  3964. //
  3965. pGraphic = NULL;
  3966. pData = NULL;
  3967. DC_EXIT_POINT:
  3968. //
  3969. // If we still have the object - discard it
  3970. //
  3971. if (pData != NULL)
  3972. {
  3973. TRACE_OUT(("Discarding object"));
  3974. OM_ObjectDiscard(m_pomClient,
  3975. m_hWSGroup,
  3976. (OM_WORKSET_ID)hPage,
  3977. &pData);
  3978. }
  3979. //
  3980. // If an error occurred or we have reached the end-of-file - close the
  3981. // file.
  3982. //
  3983. if ((result != 0) || (type == TYPE_END_OF_FILE))
  3984. {
  3985. CloseHandle(m_hLoadFile);
  3986. m_hLoadFile = INVALID_HANDLE_VALUE;
  3987. //
  3988. // If the final result is an error - post an error message to ourselves
  3989. //
  3990. if (result != 0)
  3991. {
  3992. TRACE_OUT(("Posting WBP_EVENT_LOAD_FAILED"));
  3993. WBP_PostEvent(
  3994. 0, // No delay
  3995. WBP_EVENT_LOAD_FAILED, // Load the next object
  3996. 0, // No parameters
  3997. 0);
  3998. }
  3999. //
  4000. // Record that we are no longer in the load process
  4001. //
  4002. m_loadState = LOAD_STATE_EMPTY;
  4003. TRACE_OUT(("Moved load state to LOAD_STATE_EMPTY"));
  4004. }
  4005. //
  4006. // send a message to load the next page, unless the load has been
  4007. // cancelled
  4008. //
  4009. if (m_loadState != LOAD_STATE_EMPTY)
  4010. {
  4011. //
  4012. // We have not reached the end-of-file and there has been no error.
  4013. // Post a message to ourselves to continue the load process.
  4014. //
  4015. TRACE_OUT(("Posting WBPI_EVENT_LOAD_NEXT"));
  4016. WBP_PostEvent(postDelay, // With delay
  4017. WBPI_EVENT_LOAD_NEXT, // Load the next object
  4018. 0, // No parameters
  4019. 0);
  4020. }
  4021. DebugExitVOID(wbPageLoad);
  4022. }
  4023. //
  4024. //
  4025. // Name: wbObjectLoad
  4026. //
  4027. // Purpose: Load a single object from file.
  4028. //
  4029. // Returns: Error code
  4030. //
  4031. //
  4032. UINT WbClient::wbObjectLoad
  4033. (
  4034. HANDLE hFile,
  4035. WB_PAGE_HANDLE hPage,
  4036. PPWB_GRAPHIC ppGraphic
  4037. )
  4038. {
  4039. UINT result = 0;
  4040. OM_WORKSET_ID worksetID = (OM_WORKSET_ID)hPage;
  4041. UINT length;
  4042. ULONG cbSizeRead;
  4043. POM_OBJECTDATA pData = NULL;
  4044. PWB_GRAPHIC pGraphic = NULL;
  4045. DebugEntry(wbObjectLoad);
  4046. TRACE_OUT(("Entered wbObjectLoad for page %d", (UINT) hPage));
  4047. //
  4048. // Read the next object's length
  4049. //
  4050. if ( (! ReadFile(hFile, (void *) &length, sizeof(length), &cbSizeRead, NULL)) ||
  4051. (cbSizeRead != sizeof(length)) ||
  4052. (length > OM_MAX_OBJECT_SIZE) ||
  4053. (length == 0) )
  4054. {
  4055. //
  4056. // Make sure we return a sensible error.
  4057. //
  4058. ERROR_OUT(("reading object length, win32 err=%d, length=%d", GetLastError(), length));
  4059. result = WB_RC_BAD_FILE_FORMAT;
  4060. DC_QUIT;
  4061. }
  4062. //
  4063. // Allocate memory for the object
  4064. //
  4065. result = OM_ObjectAlloc(m_pomClient,
  4066. m_hWSGroup,
  4067. worksetID,
  4068. length,
  4069. &pData);
  4070. if (result != 0)
  4071. {
  4072. ERROR_OUT(("Error allocating object = %d", result));
  4073. DC_QUIT;
  4074. }
  4075. pData->length = length;
  4076. pGraphic = GraphicPtrFromObjectData(pData);
  4077. //
  4078. // Read the object into memory
  4079. //
  4080. if ( (! ReadFile(hFile, (void *) pGraphic, length, &cbSizeRead, NULL)) ||
  4081. (cbSizeRead != length))
  4082. {
  4083. //
  4084. // Make sure we return a sensible error.
  4085. //
  4086. ERROR_OUT((
  4087. "Reading object from file: win32 err=%d, asked for %d got %d bytes",
  4088. GetLastError(),
  4089. length,
  4090. cbSizeRead));
  4091. result = WB_RC_BAD_FILE_FORMAT;
  4092. DC_QUIT;
  4093. }
  4094. //
  4095. // Validate the object type
  4096. //
  4097. switch (pGraphic->type)
  4098. {
  4099. //
  4100. // Standard type, end-of-page or end-of-file
  4101. //
  4102. case TYPE_END_OF_PAGE:
  4103. case TYPE_END_OF_FILE:
  4104. case TYPE_GRAPHIC_FREEHAND:
  4105. case TYPE_GRAPHIC_LINE:
  4106. case TYPE_GRAPHIC_RECTANGLE:
  4107. case TYPE_GRAPHIC_FILLED_RECTANGLE:
  4108. case TYPE_GRAPHIC_ELLIPSE:
  4109. case TYPE_GRAPHIC_FILLED_ELLIPSE:
  4110. case TYPE_GRAPHIC_TEXT:
  4111. case TYPE_GRAPHIC_DIB:
  4112. break;
  4113. //
  4114. // Unrecognized object type - probably wrong version
  4115. //
  4116. default:
  4117. result = WB_RC_BAD_FILE_FORMAT;
  4118. DC_QUIT;
  4119. break;
  4120. }
  4121. //
  4122. // For graphic objects, set the flag in the object header showing that it
  4123. // was loaded from file. Add our user ID so we know where it came from.
  4124. //
  4125. if ( (pGraphic->type != TYPE_END_OF_FILE) &&
  4126. (pGraphic->type != TYPE_END_OF_PAGE))
  4127. {
  4128. pGraphic->loadedFromFile = TRUE;
  4129. pGraphic->loadingClientID = m_clientNetID;
  4130. }
  4131. *ppGraphic = pGraphic;
  4132. DC_EXIT_POINT:
  4133. //
  4134. // If an error has occurred - discard the object (if we have it)
  4135. //
  4136. if ((result != 0) && (pData != NULL))
  4137. {
  4138. OM_ObjectDiscard(m_pomClient,
  4139. m_hWSGroup,
  4140. worksetID,
  4141. &pData);
  4142. }
  4143. DebugExitDWORD(wbObjectLoad, result);
  4144. return(result);
  4145. }
  4146. //
  4147. //
  4148. // Name: wbPageHandleFromNumber
  4149. //
  4150. // Purpose: Return the handle of a page specified by page number
  4151. //
  4152. // Returns: Error code
  4153. //
  4154. //
  4155. UINT WbClient::wbPageHandleFromNumber
  4156. (
  4157. UINT pageNumber,
  4158. PWB_PAGE_HANDLE phPage
  4159. )
  4160. {
  4161. UINT result = 0;
  4162. WB_PAGE_HANDLE hPage;
  4163. PWB_PAGE_ORDER pPageOrder = &(m_pageOrder);
  4164. DebugEntry(wbPageHandleFromNumber);
  4165. //
  4166. // Validate the requested page number
  4167. //
  4168. if ((pageNumber < 1)|| (pageNumber > WB_MAX_PAGES))
  4169. {
  4170. result = WB_RC_BAD_PAGE_NUMBER;
  4171. DC_QUIT;
  4172. }
  4173. if (pageNumber > pPageOrder->countPages)
  4174. {
  4175. result = WB_RC_NO_SUCH_PAGE;
  4176. DC_QUIT;
  4177. }
  4178. //
  4179. // Get the page handle
  4180. //
  4181. hPage = (pPageOrder->pages)[pageNumber - 1];
  4182. //
  4183. // Check that this page is in use
  4184. //
  4185. if (GetPageState(hPage)->state != PAGE_IN_USE)
  4186. {
  4187. ERROR_OUT(("Page list is bad"));
  4188. }
  4189. //
  4190. // Return the page handle
  4191. //
  4192. *phPage = hPage;
  4193. DC_EXIT_POINT:
  4194. DebugExitDWORD(wbPageHandleFromNumber, result);
  4195. return(result);
  4196. }
  4197. //
  4198. //
  4199. // Name: wbPageClear
  4200. //
  4201. // Purpose: Clear the specified page of all graphic objects
  4202. //
  4203. // Returns: Error code
  4204. //
  4205. //
  4206. UINT WbClient::wbPageClear
  4207. (
  4208. WB_PAGE_HANDLE hPage,
  4209. UINT changedFlagAction
  4210. )
  4211. {
  4212. UINT result = 0;
  4213. DebugEntry(wbPageClear);
  4214. //
  4215. // Show that the contents have changed, if required.
  4216. //
  4217. if (changedFlagAction == RESET_CHANGED_FLAG)
  4218. {
  4219. m_changed = TRUE;
  4220. TRACE_OUT(("Changed flag now TRUE"));
  4221. }
  4222. //
  4223. // Request that the page be cleared
  4224. //
  4225. result = OM_WorksetClear(m_pomClient,
  4226. m_hWSGroup,
  4227. (OM_WORKSET_ID)hPage);
  4228. DebugExitDWORD(wbPageClear, result);
  4229. return(result);
  4230. }
  4231. //
  4232. //
  4233. // Name: wbPageClearConfirm
  4234. //
  4235. // Purpose: Complete the clearing of a page
  4236. //
  4237. // Returns: Error code
  4238. //
  4239. //
  4240. void WbClient::wbPageClearConfirm(WB_PAGE_HANDLE hPage)
  4241. {
  4242. DebugEntry(wbPageClearConfirm);
  4243. //
  4244. // Request that the page be cleared
  4245. //
  4246. OM_WorksetClearConfirm(m_pomClient,
  4247. m_hWSGroup,
  4248. (OM_WORKSET_ID)hPage);
  4249. //
  4250. // Check the load state to see whether we are waiting to load the
  4251. // contents
  4252. //
  4253. if (m_loadState == LOAD_STATE_PENDING_CLEAR)
  4254. {
  4255. //
  4256. // We are waiting to load. If there is only one page available (ie the
  4257. // one that has just been cleared) we are ready to load, otherwise we
  4258. // wait for the page deletes to happen.
  4259. //
  4260. if ((m_pageOrder).countPages == 1)
  4261. {
  4262. //
  4263. // Start the load proper
  4264. //
  4265. wbStartContentsLoad();
  4266. }
  4267. else
  4268. {
  4269. //
  4270. // Move the load state to show that we are waiting for all the pages
  4271. // to be deleted.
  4272. //
  4273. m_loadState = LOAD_STATE_PENDING_DELETE;
  4274. TRACE_OUT(("Moved load state to LOAD_STATE_PENDING_DELETE"));
  4275. }
  4276. }
  4277. DebugExitVOID(wbPageClearConfirm);
  4278. }
  4279. //
  4280. //
  4281. // Name: wbCheckReadyPages
  4282. //
  4283. // Purpose: Check that we have enough worksets open for the local user to
  4284. // use immediately (during page adds).
  4285. //
  4286. // Returns: None
  4287. //
  4288. //
  4289. BOOL WbClient::wbCheckReadyPages(void)
  4290. {
  4291. BOOL bResult = TRUE;
  4292. WB_PAGE_HANDLE hNewPage;
  4293. UINT countPages = m_pageOrder.countPages;
  4294. UINT countReadyPages = m_countReadyPages;
  4295. //
  4296. // If we have opened all the worksets
  4297. //
  4298. if (countReadyPages == WB_MAX_PAGES)
  4299. {
  4300. //
  4301. // Quit there are no more worksets that we can open
  4302. //
  4303. DC_QUIT;
  4304. }
  4305. //
  4306. // If the number of pages in use is getting close to the number of ready
  4307. // pages.
  4308. //
  4309. if ( (countReadyPages >= PREINITIALIZE_PAGES)
  4310. && (countPages <= (countReadyPages - PREINITIALIZE_PAGES)))
  4311. {
  4312. DC_QUIT;
  4313. }
  4314. //
  4315. // If the number of pages ready is less than the required cache size,
  4316. // open another one.
  4317. //
  4318. hNewPage = wbGetEmptyPageHandle();
  4319. if (hNewPage != WB_PAGE_HANDLE_NULL)
  4320. {
  4321. //
  4322. // Open the workset associated with the page
  4323. //
  4324. wbPageWorksetOpen(hNewPage, OPEN_LOCAL);
  4325. }
  4326. bResult = FALSE;
  4327. DC_EXIT_POINT:
  4328. return(bResult);
  4329. }
  4330. //
  4331. //
  4332. // Name: wbPageAdd
  4333. //
  4334. // Purpose: Add a new (blank) page in a specified position
  4335. //
  4336. // Returns: Error code
  4337. //
  4338. //
  4339. UINT WbClient::wbPageAdd
  4340. (
  4341. WB_PAGE_HANDLE hRefPage,
  4342. UINT where,
  4343. PWB_PAGE_HANDLE phPage,
  4344. UINT changedFlagAction
  4345. )
  4346. {
  4347. UINT result = 0;
  4348. WB_PAGE_HANDLE hNewPage;
  4349. DebugEntry(wbPageAdd);
  4350. //
  4351. // Check that there are not too many pages already
  4352. //
  4353. if (m_pageOrder.countPages == WB_MAX_PAGES)
  4354. {
  4355. result = WB_RC_TOO_MANY_PAGES;
  4356. DC_QUIT;
  4357. }
  4358. //
  4359. // Validate the specified reference page
  4360. //
  4361. ASSERT(GetPageState(hRefPage)->state == PAGE_IN_USE);
  4362. //
  4363. // Get a handle for the new page
  4364. //
  4365. hNewPage = wbGetReadyPageHandle();
  4366. //
  4367. // If there are no handles ready we attempt to create one and return a
  4368. // busy indication.
  4369. //
  4370. if (hNewPage == WB_PAGE_HANDLE_NULL)
  4371. {
  4372. result = WB_RC_BUSY;
  4373. DC_QUIT;
  4374. }
  4375. //
  4376. // Make the internal update immediately - this allows the client to
  4377. // reference the new page as soon as this function has returned.
  4378. //
  4379. wbPagesPageAdd(hRefPage, hNewPage, where);
  4380. //
  4381. // Update the Page Control Object
  4382. //
  4383. result = wbWritePageControl(FALSE);
  4384. if (result != 0)
  4385. {
  4386. wbError();
  4387. DC_QUIT;
  4388. }
  4389. //
  4390. // Show that the contents have changed (if required).
  4391. //
  4392. if (changedFlagAction == RESET_CHANGED_FLAG)
  4393. {
  4394. m_changed = TRUE;
  4395. TRACE_OUT(("Changed flag now TRUE"));
  4396. }
  4397. //
  4398. // Return the handle of the new page
  4399. //
  4400. *phPage = hNewPage;
  4401. DC_EXIT_POINT:
  4402. //
  4403. // If we successfully added the page, or could not get a spare page
  4404. // handle, attempt to create a spare one for next time.
  4405. //
  4406. if ((result == 0) || (result == WB_RC_BUSY))
  4407. {
  4408. wbCheckReadyPages();
  4409. }
  4410. DebugExitDWORD(wbPageAdd, result);
  4411. return(result);
  4412. }
  4413. //
  4414. //
  4415. // Name: wbPageMove
  4416. //
  4417. // Purpose: Move a page relative to another page
  4418. //
  4419. // Returns: Error code
  4420. //
  4421. //
  4422. UINT WbClient::wbPageMove
  4423. (
  4424. WB_PAGE_HANDLE hRefPage,
  4425. WB_PAGE_HANDLE hPage,
  4426. UINT where
  4427. )
  4428. {
  4429. UINT result = 0;
  4430. PWB_PAGE_ORDER pPageOrder = &(m_pageOrder);
  4431. DebugEntry(wbPageMove);
  4432. //
  4433. // Extract the page to be moved
  4434. //
  4435. wbPageOrderPageDelete(pPageOrder, hPage);
  4436. //
  4437. // Add it back at its new position
  4438. //
  4439. wbPageOrderPageAdd(pPageOrder, hRefPage, hPage, where);
  4440. //
  4441. // Update the page control object
  4442. //
  4443. result = wbWritePageControl(FALSE);
  4444. if (result != 0)
  4445. {
  4446. wbError();
  4447. DC_QUIT;
  4448. }
  4449. //
  4450. // Show that the contents have changed
  4451. //
  4452. m_changed = TRUE;
  4453. TRACE_OUT(("Changed flag now TRUE"));
  4454. DC_EXIT_POINT:
  4455. DebugExitDWORD(wbPageMove, result);
  4456. return(result);
  4457. }
  4458. //
  4459. //
  4460. // Name: wbPageHandle
  4461. //
  4462. // Purpose: Return a page handle. The page for which the handle is
  4463. // required can be specified relative to another page or as the
  4464. // first/last page.
  4465. //
  4466. // Returns: Error code
  4467. //
  4468. //
  4469. UINT WbClient::wbPageHandle
  4470. (
  4471. WB_PAGE_HANDLE hRefPage,
  4472. UINT where,
  4473. PWB_PAGE_HANDLE phPage
  4474. )
  4475. {
  4476. UINT result = 0;
  4477. UINT pageNumber;
  4478. PWB_PAGE_ORDER pPageOrder = &(m_pageOrder);
  4479. POM_WORKSET_ID pPage = pPageOrder->pages;
  4480. WB_PAGE_HANDLE hPage;
  4481. DebugEntry(wbPageHandle);
  4482. //
  4483. // Check the relative position
  4484. //
  4485. switch (where)
  4486. {
  4487. case PAGE_FIRST:
  4488. hPage = pPage[0];
  4489. break;
  4490. case PAGE_LAST:
  4491. hPage = pPage[pPageOrder->countPages - 1];
  4492. break;
  4493. case PAGE_AFTER:
  4494. case PAGE_BEFORE:
  4495. //
  4496. // Validate the specified reference page
  4497. //
  4498. ASSERT(GetPageState(hRefPage)->state == PAGE_IN_USE);
  4499. //
  4500. // Get the page number of the reference page
  4501. //
  4502. pageNumber = wbPageOrderPageNumber(pPageOrder, hRefPage);
  4503. TRACE_OUT(("Reference page number is %d", pageNumber));
  4504. //
  4505. // Get the page number of the required page
  4506. //
  4507. pageNumber = (UINT)(pageNumber + ((where == PAGE_AFTER) ? 1 : -1));
  4508. TRACE_OUT(("New page number is %d", pageNumber));
  4509. //
  4510. // Check that the new page is valid
  4511. //
  4512. TRACE_OUT(("Number of pages is %d", pPageOrder->countPages));
  4513. if ( (pageNumber < 1)
  4514. || (pageNumber > pPageOrder->countPages))
  4515. {
  4516. TRACE_OUT(("Returning WB_RC_NO_SUCH_PAGE"));
  4517. result = WB_RC_NO_SUCH_PAGE;
  4518. DC_QUIT;
  4519. }
  4520. //
  4521. // Get the handle of the page
  4522. //
  4523. hPage = pPage[pageNumber - 1];
  4524. TRACE_OUT(("Returning handle %d", (UINT) hPage));
  4525. break;
  4526. }
  4527. //
  4528. // Return the page handle
  4529. //
  4530. *phPage = hPage;
  4531. DC_EXIT_POINT:
  4532. DebugExitDWORD(wbPageHandle, result);
  4533. return(result);
  4534. }
  4535. //
  4536. //
  4537. // Name: wbGraphicSelectPrevious
  4538. //
  4539. // Purpose: Return the next graphic object in the specified page whose
  4540. // bounding rectangle contains the specified point. The function
  4541. // starts with the graphic whose handle is given as parameter and
  4542. // will return this graphic if it contains the point.
  4543. //
  4544. // Returns: Error code
  4545. //
  4546. //
  4547. UINT WbClient::wbGraphicSelectPrevious
  4548. (
  4549. WB_PAGE_HANDLE hPage,
  4550. LPPOINT pPoint,
  4551. WB_GRAPHIC_HANDLE hGraphic,
  4552. PWB_GRAPHIC_HANDLE phGraphic
  4553. )
  4554. {
  4555. UINT result = 0;
  4556. OM_WORKSET_ID worksetID = (OM_WORKSET_ID)hPage;
  4557. PWB_GRAPHIC pGraphic;
  4558. POM_OBJECTDATA pData;
  4559. RECT rect;
  4560. DebugEntry(wbGraphicSelectPrevious);
  4561. *phGraphic = (WB_GRAPHIC_HANDLE) NULL;
  4562. //
  4563. // Loop back through the objects starting at the reference point
  4564. //
  4565. do
  4566. {
  4567. //
  4568. // Get the object from ObMan
  4569. //
  4570. result = OM_ObjectRead(m_pomClient,
  4571. m_hWSGroup,
  4572. worksetID,
  4573. hGraphic,
  4574. &pData);
  4575. //
  4576. // Leave the loop if error on read - we do not need to do the release
  4577. //
  4578. if (result != 0)
  4579. {
  4580. DC_QUIT;
  4581. }
  4582. pGraphic = GraphicPtrFromObjectData(pData);
  4583. //
  4584. // Extract the bounding rectangle of the object
  4585. //
  4586. RECT_FROM_TSHR_RECT16(&rect, pGraphic->rectBounds);
  4587. //
  4588. // Release the object
  4589. //
  4590. OM_ObjectRelease(m_pomClient,
  4591. m_hWSGroup,
  4592. worksetID,
  4593. hGraphic,
  4594. &pData);
  4595. //
  4596. // Check whether the point lies in bounds
  4597. //
  4598. if (PtInRect(&rect, *pPoint))
  4599. {
  4600. //
  4601. // Set the result handle
  4602. //
  4603. TRACE_OUT(("Returning graphic handle"));
  4604. *phGraphic = hGraphic;
  4605. DC_QUIT;
  4606. }
  4607. //
  4608. // Get the next object to test
  4609. //
  4610. result = OM_ObjectH(m_pomClient,
  4611. m_hWSGroup,
  4612. worksetID,
  4613. hGraphic,
  4614. &hGraphic,
  4615. BEFORE);
  4616. }
  4617. while (result == 0);
  4618. //
  4619. // Correct the return code (if necessary)
  4620. //
  4621. if (result == OM_RC_NO_SUCH_OBJECT)
  4622. {
  4623. TRACE_OUT(("Returning WB_RC_NO_SUCH_GRAPHIC"));
  4624. result = WB_RC_NO_SUCH_GRAPHIC;
  4625. }
  4626. DC_EXIT_POINT:
  4627. DebugExitDWORD(wbGraphicSelectPrevious, result);
  4628. return(result);
  4629. }
  4630. //
  4631. //
  4632. // Name: wbCoreExitHandler
  4633. //
  4634. // Purpose: Exit handler for the Whiteboard Core. This handler is
  4635. // registered with the Utilities by the WBP_Start call. It is
  4636. // deregistered by the client deregistration process, so it is
  4637. // only called when an abnormal termination occurs.
  4638. //
  4639. // Returns: None
  4640. //
  4641. //
  4642. void CALLBACK wbCoreExitHandler(LPVOID clientData)
  4643. {
  4644. WbClient* pwbClient = (WbClient *)clientData;
  4645. pwbClient->wbExitHandler();
  4646. }
  4647. void WbClient::wbExitHandler(void)
  4648. {
  4649. DebugEntry(wbExitHandler);
  4650. //
  4651. // Leave the current call if there is one, removing any locks etc.
  4652. //
  4653. wbLeaveCall();
  4654. //
  4655. // Dereg from call manager
  4656. //
  4657. if (m_pcmClient != NULL)
  4658. {
  4659. CMS_Deregister(&(m_pcmClient));
  4660. }
  4661. //
  4662. // Dereg exit handler
  4663. //
  4664. if (m_subState >= STATE_START_REGISTERED_EXIT)
  4665. {
  4666. UT_DeregisterExit(m_putTask, wbCoreExitHandler, this);
  4667. }
  4668. //
  4669. // Dereg obman
  4670. //
  4671. if (m_subState >= STATE_START_REGISTERED_OM)
  4672. {
  4673. OM_Deregister(&m_pomClient);
  4674. }
  4675. //
  4676. // Dereg event handler
  4677. //
  4678. if (m_subState >= STATE_START_REGISTERED_EVENT)
  4679. {
  4680. UT_DeregisterEvent(m_putTask, wbCoreEventHandler, this);
  4681. }
  4682. //
  4683. // delete ourself!
  4684. //
  4685. delete this;
  4686. DebugExitVOID(wbExitHandler);
  4687. }
  4688. //
  4689. //
  4690. // Name: wbCoreEventHandler
  4691. //
  4692. // Purpose: Event handler for the Whiteboard Core. This handler is
  4693. // registered with the Utilities by the WBP_Start call.
  4694. //
  4695. // Params: clientData - pointer to the data stored for a client
  4696. // event - event identifier
  4697. // param1 - word event parameter (content depends on event)
  4698. // param2 - long event parameter (content depends on event)
  4699. //
  4700. // Returns: Error code
  4701. //
  4702. //
  4703. BOOL CALLBACK wbCoreEventHandler
  4704. (
  4705. LPVOID clientData,
  4706. UINT event,
  4707. UINT_PTR param1,
  4708. UINT_PTR param2
  4709. )
  4710. {
  4711. WbClient* pwbClient = (WbClient *)clientData;
  4712. return(pwbClient->wbEventHandler(event, param1, param2));
  4713. }
  4714. BOOL WbClient::wbEventHandler
  4715. (
  4716. UINT event,
  4717. UINT_PTR param1,
  4718. UINT_PTR param2
  4719. )
  4720. {
  4721. POM_EVENT_DATA16 pEvent16 = (POM_EVENT_DATA16) &param1;
  4722. POM_EVENT_DATA32 pEvent32 = (POM_EVENT_DATA32) &param2;
  4723. BOOL processed = FALSE;
  4724. DebugEntry(wbEventHandler);
  4725. TRACE_OUT(("event %d, param1 %d, param2 %d", event, param1, param2));
  4726. switch (event)
  4727. {
  4728. //
  4729. // Confirmation that we have registered with a workset group
  4730. //
  4731. case OM_WSGROUP_REGISTER_CON:
  4732. TRACE_OUT(("OM_WSGROUP_REGISTER_CON %x %x",param1,param2));
  4733. processed = wbOnWsGroupRegisterCon(param1, param2);
  4734. break;
  4735. //
  4736. // Confirmation that we have moved a workset group
  4737. //
  4738. case OM_WSGROUP_MOVE_CON:
  4739. TRACE_OUT(("OM_WSGROUP_MOVE_CON %x %x",param1,param2));
  4740. processed = wbOnWsGroupMoveCon(param1, param2);
  4741. break;
  4742. //
  4743. // Our workset group has been moved
  4744. //
  4745. case OM_WSGROUP_MOVE_IND:
  4746. TRACE_OUT(("OM_WSGROUP_MOVE_IND %x %x",param1,param2));
  4747. processed = wbOnWsGroupMoveInd(param1, param2);
  4748. break;
  4749. //
  4750. // A workset has been created - we do nothing
  4751. //
  4752. case OM_WORKSET_NEW_IND:
  4753. TRACE_OUT(("OM_WORKSET_NEW_IND %x %x",param1,param2));
  4754. processed = TRUE;
  4755. break;
  4756. //
  4757. // A workset has been opened
  4758. //
  4759. case OM_WORKSET_OPEN_CON:
  4760. TRACE_OUT(("OM_WORKSET_OPEN_CON %x %x",param1,param2));
  4761. processed = wbOnWorksetOpenCon(param1, param2);
  4762. break;
  4763. //
  4764. // A workset has been locked
  4765. //
  4766. case OM_WORKSET_LOCK_CON:
  4767. TRACE_OUT(("OM_WORKSET_LOCK_CON %x %x",param1,param2));
  4768. processed = wbOnWorksetLockCon(param1, param2);
  4769. break;
  4770. //
  4771. // A workset has been unlocked
  4772. //
  4773. case OM_WORKSET_UNLOCK_IND:
  4774. TRACE_OUT(("OM_WORKSET_UNLOCK_IND %x %x",param1,param2));
  4775. processed = wbOnWorksetUnlockInd(param1, param2);
  4776. break;
  4777. //
  4778. // ObMan has run out of resources
  4779. //
  4780. case OM_OUT_OF_RESOURCES_IND:
  4781. TRACE_OUT(("OM_OUT_OF_RESOURCES_IND %x %x",param1,param2));
  4782. wbError();
  4783. processed = TRUE;
  4784. break;
  4785. //
  4786. // A workset has been cleared
  4787. //
  4788. case OM_WORKSET_CLEAR_IND:
  4789. TRACE_OUT(("OM_WORKSET_CLEAR_IND %x %x",param1,param2));
  4790. processed = wbOnWorksetClearInd(param1, param2);
  4791. break;
  4792. //
  4793. // A new object has been added to a workset
  4794. //
  4795. case OM_OBJECT_ADD_IND:
  4796. TRACE_OUT(("OM_OBJECT_ADD_IND %x %x",param1,param2));
  4797. processed = wbOnObjectAddInd(param1, (POM_OBJECT)param2);
  4798. break;
  4799. //
  4800. // An object has been moved
  4801. //
  4802. case OM_OBJECT_MOVE_IND:
  4803. TRACE_OUT(("OM_OBJECT_MOVE_IND %x %x",param1,param2));
  4804. processed = wbOnObjectMoveInd(param1, param2);
  4805. break;
  4806. //
  4807. // An object has been deleted
  4808. //
  4809. case OM_OBJECT_DELETE_IND:
  4810. TRACE_OUT(("OM_OBJECT_DELETE_IND %x %x",param1,param2));
  4811. processed = wbOnObjectDeleteInd(param1, (POM_OBJECT)param2);
  4812. break;
  4813. //
  4814. // An object has been updated
  4815. //
  4816. case OM_OBJECT_UPDATE_IND:
  4817. TRACE_OUT(("OM_OBJECT_UPDATE_IND %x %x",param1,param2));
  4818. processed = wbOnObjectUpdateInd(param1, (POM_OBJECT)param2);
  4819. break;
  4820. //
  4821. // An object has been updated
  4822. //
  4823. case OM_OBJECT_REPLACE_IND:
  4824. TRACE_OUT(("OM_OBJECT_REPLACE_IND %x %x",param1,param2));
  4825. processed = wbOnObjectReplaceInd(param1, (POM_OBJECT)param2);
  4826. break;
  4827. //
  4828. // Load chaining event
  4829. //
  4830. case WBPI_EVENT_LOAD_NEXT:
  4831. TRACE_OUT(("WBPI_EVENT_LOAD_NEXT"));
  4832. wbPageLoad();
  4833. processed = TRUE;
  4834. break;
  4835. //
  4836. // Whiteboard page clear indication
  4837. //
  4838. case WBP_EVENT_PAGE_CLEAR_IND:
  4839. TRACE_OUT(("WBP_EVENT_PAGE_CLEAR_IND"));
  4840. processed = wbOnWBPPageClearInd((WB_PAGE_HANDLE) param1);
  4841. break;
  4842. //
  4843. // Whiteboard lock notification
  4844. //
  4845. case WBP_EVENT_PAGE_ORDER_LOCKED:
  4846. case WBP_EVENT_CONTENTS_LOCKED:
  4847. TRACE_OUT(("WBP_EVENT_xxx_LOCKED (%#hx) %#hx %#lx",
  4848. event,
  4849. param1,
  4850. param2));
  4851. processed = wbOnWBPLock();
  4852. break;
  4853. //
  4854. // Whiteboard lock failure notification
  4855. //
  4856. case WBP_EVENT_LOCK_FAILED:
  4857. TRACE_OUT(("WBP_EVENT_LOCK_FAILED %x %x",param1,param2));
  4858. processed = wbOnWBPLockFailed();
  4859. break;
  4860. //
  4861. // Whiteboard Unlock notification
  4862. //
  4863. case WBP_EVENT_UNLOCKED:
  4864. TRACE_OUT(("WBP_EVENT_UNLOCKED %x %x",param1,param2));
  4865. processed = wbOnWBPUnlocked();
  4866. break;
  4867. //
  4868. // Whiteboard Page Order Updated notification
  4869. //
  4870. case WBP_EVENT_PAGE_ORDER_UPDATED:
  4871. TRACE_OUT(("WBP_EVENT_PAGE_ORDER_UPDATED %x %x",
  4872. param1,
  4873. param2));
  4874. processed = wbOnWBPPageOrderUpdated();
  4875. break;
  4876. //
  4877. // We are not interested in this event - do nothing
  4878. //
  4879. default:
  4880. TRACE_OUT(("Event ignored"));
  4881. break;
  4882. } // Switch on event type
  4883. DebugExitBOOL(wbEventHandler, processed);
  4884. return(processed);
  4885. }
  4886. //
  4887. // wbJoinCallError
  4888. //
  4889. // This function should be called in STATE_REGISTERING only.
  4890. //
  4891. //
  4892. void WbClient::wbJoinCallError(void)
  4893. {
  4894. DebugEntry(wbJoinCallError);
  4895. ASSERT((m_state == STATE_REGISTERING));
  4896. //
  4897. // Post a registration failed message to the client
  4898. //
  4899. TRACE_OUT(("Posting WBP_EVENT_REGISTER_FAILED"));
  4900. WBP_PostEvent(
  4901. 0, // No delay
  4902. WBP_EVENT_JOIN_CALL_FAILED, // Failure
  4903. 0, // No parameters
  4904. 0);
  4905. //
  4906. // Tidy up after the attempt to join the call
  4907. //
  4908. wbLeaveCall();
  4909. DebugExitVOID(wbJoinCallError);
  4910. }
  4911. //
  4912. // wbError
  4913. //
  4914. void WbClient::wbError(void)
  4915. {
  4916. DebugEntry(wbError);
  4917. //
  4918. // An error has occurred during Core processing. We act according to the
  4919. // current state.
  4920. //
  4921. switch (m_state)
  4922. {
  4923. //
  4924. // If the error has occurred during registration, post a registration
  4925. // failure message to the client and cancel registration.
  4926. //
  4927. case STATE_REGISTERING:
  4928. wbJoinCallError();
  4929. break;
  4930. //
  4931. // If the error occurred during normal running, we tell the client who
  4932. // must deregister.
  4933. //
  4934. case STATE_IDLE:
  4935. //
  4936. // Only take action if we are not already in fatal error state
  4937. //
  4938. if (m_errorState == ERROR_STATE_EMPTY)
  4939. {
  4940. //
  4941. // Post an error message to the client
  4942. //
  4943. TRACE_OUT(("Posting WBP_EVENT_ERROR"));
  4944. WBP_PostEvent(
  4945. 0, // No delay
  4946. WBP_EVENT_ERROR, // Error
  4947. 0, // No parameters
  4948. 0);
  4949. //
  4950. // Record that an error has occurred
  4951. //
  4952. m_errorState = ERROR_STATE_FATAL;
  4953. TRACE_OUT(("Moved error state to ERROR_STATE_FATAL"));
  4954. }
  4955. break;
  4956. //
  4957. // Client is in an unknown state
  4958. //
  4959. default:
  4960. ERROR_OUT(("Bad main state for call"));
  4961. break;
  4962. }
  4963. DebugExitVOID(wbError);
  4964. }
  4965. //
  4966. //
  4967. // Name: wbOnWSGroupMoveCon
  4968. //
  4969. // Purpose: Routine processing OM_WSGROUP_MOVE_CON events.
  4970. //
  4971. //
  4972. BOOL WbClient::wbOnWsGroupMoveCon
  4973. (
  4974. UINT_PTR param1,
  4975. UINT_PTR param2
  4976. )
  4977. {
  4978. POM_EVENT_DATA16 pEvent16 = (POM_EVENT_DATA16) &param1;
  4979. POM_EVENT_DATA32 pEvent32 = (POM_EVENT_DATA32) &param2;
  4980. BOOL processed = FALSE;
  4981. UINT rc;
  4982. BOOL failedToJoin = FALSE;
  4983. DebugEntry(wbOnWsGroupMoveCon);
  4984. //
  4985. // Check that this is the event we are expecting
  4986. //
  4987. if (pEvent32->correlator != m_wsgroupCorrelator)
  4988. {
  4989. DC_QUIT;
  4990. }
  4991. //
  4992. // Show that we have processed the event
  4993. //
  4994. processed = TRUE;
  4995. //
  4996. // Test for the correct state
  4997. //
  4998. if (m_subState != STATE_REG_PENDING_WSGROUP_MOVE)
  4999. {
  5000. //
  5001. // We are not in the correct state for this event - this is an internal
  5002. // error.
  5003. //
  5004. ERROR_OUT(("Wrong state for WSGroupMoveCon"));
  5005. }
  5006. //
  5007. // Check that the return code for the move is OK
  5008. //
  5009. if (pEvent32->result != 0)
  5010. {
  5011. //
  5012. // Moving the workset group failed - post a "join call failed" message
  5013. // to the front-end.
  5014. //
  5015. TRACE_OUT(("WSGroup move failed, result = %d", pEvent32->result));
  5016. failedToJoin = TRUE;
  5017. DC_QUIT;
  5018. }
  5019. //
  5020. // The WSGroupMove has completed successfully. Replace our local user
  5021. // object by deleting the current one (we must have one to get to this
  5022. // point) and adding a new one.
  5023. //
  5024. // The reason we do this is that our existing user object has been moved
  5025. // from the local domain into a call, but since it is in a non-persistent
  5026. // workset, the Obman behaviour for this object when the call ends is
  5027. // undefined. So we replace the object to get a defined behaviour.
  5028. //
  5029. TRACE_OUT(("Deleting local user object"));
  5030. rc = OM_ObjectDelete(m_pomClient,
  5031. m_hWSGroup,
  5032. USER_INFORMATION_WORKSET,
  5033. m_pObjLocal);
  5034. if (rc != 0)
  5035. {
  5036. ERROR_OUT(("Error deleting local user object = %u", rc));
  5037. }
  5038. TRACE_OUT(("Adding new local user object"));
  5039. rc = wbAddLocalUserObject();
  5040. if (rc != 0)
  5041. {
  5042. TRACE_OUT(("Failed to add local user object"));
  5043. failedToJoin = TRUE;
  5044. DC_QUIT;
  5045. }
  5046. //
  5047. // Get the clients network ID, used in graphic objects to determine where
  5048. // they are loaded.
  5049. //
  5050. if (!wbGetNetUserID())
  5051. {
  5052. //
  5053. // Tidy up (and post an error event to the client)
  5054. //
  5055. ERROR_OUT(("Failed to get user ID, rc %u", rc));
  5056. failedToJoin = TRUE;
  5057. DC_QUIT;
  5058. }
  5059. //
  5060. // We added our user object successfully, so now wait for the
  5061. // OBJECT_ADD_IND to arrive.
  5062. //
  5063. m_subState = STATE_REG_PENDING_NEW_USER_OBJECT;
  5064. DC_EXIT_POINT:
  5065. if (failedToJoin)
  5066. {
  5067. //
  5068. // We have failed to join the call, so clean up.
  5069. //
  5070. wbError();
  5071. }
  5072. DebugExitBOOL(wbOnWsGroupMoveCon, processed);
  5073. return(processed);
  5074. }
  5075. //
  5076. //
  5077. // Name: wbOnWSGroupMoveInd
  5078. //
  5079. // Purpose: Routine processing OM_WSGROUP_MOVE_IND events.
  5080. //
  5081. //
  5082. BOOL WbClient::wbOnWsGroupMoveInd
  5083. (
  5084. UINT_PTR param1,
  5085. UINT_PTR callID
  5086. )
  5087. {
  5088. POM_EVENT_DATA16 pEvent16 = (POM_EVENT_DATA16) &param1;
  5089. BOOL processed = TRUE;
  5090. DebugEntry(wbOnWsGroupMoveInd);
  5091. if (callID != OM_NO_CALL)
  5092. {
  5093. TRACE_OUT(("Moved into new call"));
  5094. DC_QUIT;
  5095. }
  5096. //
  5097. // If we are registering, treat it as a failure to join the call,
  5098. // otherwise let the client know about the network failure.
  5099. //
  5100. if (m_state == STATE_REGISTERING)
  5101. {
  5102. TRACE_OUT(("Call went down while registering"));
  5103. wbError();
  5104. DC_QUIT;
  5105. }
  5106. TRACE_OUT(("Posting WBP_EVENT_NETWORK_LOST"));
  5107. WBP_PostEvent(0,
  5108. WBP_EVENT_NETWORK_LOST, // Unlocked
  5109. 0, // No parameters
  5110. 0);
  5111. //
  5112. // Tidy up the User Information workset (the local client is now the
  5113. // only user). Note that since the user information workset it
  5114. // non-persistent, Obman will delete the remote user objects for us.
  5115. //
  5116. //
  5117. // - check we have opened the user workset
  5118. //
  5119. if ( (m_state > STATE_REGISTERING) ||
  5120. (m_subState > STATE_REG_PENDING_USER_WORKSET))
  5121. {
  5122. //
  5123. // Delete the lock object.
  5124. //
  5125. if (m_pObjLock != NULL)
  5126. {
  5127. TRACE_OUT(("Deleting lock object %d", m_pObjLock));
  5128. if (OM_ObjectDelete(m_pomClient,
  5129. m_hWSGroup,
  5130. PAGE_CONTROL_WORKSET,
  5131. m_pObjLock) != 0)
  5132. {
  5133. ERROR_OUT(("Error deleting lock object"));
  5134. }
  5135. if (m_lockState == LOCK_STATE_GOT_LOCK)
  5136. {
  5137. //
  5138. // If all is well at this point the unlock process will be
  5139. // completed when the object delete ind is received.
  5140. //
  5141. m_lockState = LOCK_STATE_PENDING_DELETE;
  5142. TRACE_OUT(("Moved to state LOCK_STATE_PENDING_DELETE"));
  5143. }
  5144. else
  5145. {
  5146. m_lockState = LOCK_STATE_EMPTY;
  5147. TRACE_OUT(("Moved to state LOCK_STATE_EMPTY"));
  5148. }
  5149. }
  5150. }
  5151. DC_EXIT_POINT:
  5152. DebugExitBOOL(wbOnWSGroupMoveInd, processed);
  5153. return(processed);
  5154. }
  5155. //
  5156. //
  5157. // Name: wbOnWorksetClearInd
  5158. //
  5159. // Purpose: Routine processing OM_WORKSET_CLEAR_IND events.
  5160. //
  5161. // Returns: Error code
  5162. //
  5163. //
  5164. BOOL WbClient::wbOnWorksetClearInd
  5165. (
  5166. UINT_PTR param1,
  5167. UINT_PTR param2
  5168. )
  5169. {
  5170. POM_EVENT_DATA16 pEvent16 = (POM_EVENT_DATA16) &param1;
  5171. POM_EVENT_DATA32 pEvent32 = (POM_EVENT_DATA32) &param2;
  5172. BOOL processed = FALSE;
  5173. DebugEntry(wbOnWorksetClearInd);
  5174. //
  5175. // Check that the workset group is ours
  5176. //
  5177. if (pEvent16->hWSGroup != m_hWSGroup)
  5178. {
  5179. ERROR_OUT(("Event for unknown workset group = %d", pEvent16->hWSGroup));
  5180. DC_QUIT;
  5181. }
  5182. //
  5183. // We will process the event
  5184. //
  5185. processed = TRUE;
  5186. //
  5187. // Process the event according to the workset ID
  5188. //
  5189. switch(pEvent16->worksetID)
  5190. {
  5191. //
  5192. // Page Control Workset
  5193. //
  5194. case PAGE_CONTROL_WORKSET:
  5195. ERROR_OUT(("Unexpected clear for Page Control Workset"));
  5196. break;
  5197. //
  5198. // Lock Workset
  5199. //
  5200. case SYNC_CONTROL_WORKSET:
  5201. ERROR_OUT(("Unexpected clear for Sync Control Workset"));
  5202. break;
  5203. //
  5204. // User Information Workset
  5205. //
  5206. case USER_INFORMATION_WORKSET:
  5207. ERROR_OUT(("Unexpected clear for User Information Workset"));
  5208. break;
  5209. //
  5210. // Other (should be a Page Workset)
  5211. //
  5212. default:
  5213. //
  5214. // Tell the client that the page has been cleared - the client must then
  5215. // confirm the clear.
  5216. //
  5217. TRACE_OUT(("Posting WBP_EVENT_PAGE_CLEAR_IND"));
  5218. WBP_PostEvent(
  5219. 0,
  5220. WBP_EVENT_PAGE_CLEAR_IND,
  5221. pEvent16->worksetID,
  5222. 0);
  5223. break;
  5224. }
  5225. DC_EXIT_POINT:
  5226. DebugExitBOOL(wbOnWorksetClearInd, processed);
  5227. return(processed);
  5228. }
  5229. //
  5230. //
  5231. // Name: wbOnWBPPageClearInd
  5232. //
  5233. // Purpose: Routine processing WBP_PAGE_CLEAR_IND events.
  5234. //
  5235. // Returns: Error code
  5236. //
  5237. //
  5238. BOOL WbClient::wbOnWBPPageClearInd(WB_PAGE_HANDLE hPage)
  5239. {
  5240. BOOL processed;
  5241. DebugEntry(wbOnWBPPageClearInd);
  5242. //
  5243. // This routine catches WB_PAGE_CLEAR_IND events posted to the client.
  5244. // Because of the asynchronous nature of page order updates these can
  5245. // sometimes have been sent previously for pages that are now no longer
  5246. // in use. We trap these events here, confirm the clear to ObMan and
  5247. // discard the event.
  5248. //
  5249. if (GetPageState(hPage)->state != PAGE_IN_USE)
  5250. {
  5251. TRACE_OUT(("Page is not in use - confirming workset clear immediately"));
  5252. //
  5253. // Accept the page clear immediately
  5254. //
  5255. wbPageClearConfirm(hPage);
  5256. processed = TRUE;
  5257. }
  5258. else
  5259. {
  5260. //
  5261. // If we get here the page is in use - so we must pass the event on to
  5262. // the client. Resetting the result code of this routine to "not
  5263. // processed" will ask the utilities to pass it on to the next event
  5264. // handler.
  5265. //
  5266. processed = FALSE;
  5267. }
  5268. DebugExitBOOL(wbOnWBPPageClearInd, processed);
  5269. return(processed);
  5270. }
  5271. //
  5272. //
  5273. // Name: wbOnObjectAddInd
  5274. //
  5275. // Purpose: Routine processing OM_OBJECT_ADD_IND events.
  5276. //
  5277. // Returns: Error code
  5278. //
  5279. //
  5280. BOOL WbClient::wbOnObjectAddInd
  5281. (
  5282. UINT_PTR param1,
  5283. POM_OBJECT pObj
  5284. )
  5285. {
  5286. POM_EVENT_DATA16 pEvent16 = (POM_EVENT_DATA16) &param1;
  5287. BOOL processed = FALSE;
  5288. DebugEntry(wbOnObjectAddInd);
  5289. //
  5290. // Check that the workset group is ours
  5291. //
  5292. if (pEvent16->hWSGroup != m_hWSGroup)
  5293. {
  5294. ERROR_OUT(("Event for unknown workset group = %d", pEvent16->hWSGroup));
  5295. DC_QUIT;
  5296. }
  5297. //
  5298. // We will process the event
  5299. //
  5300. processed = TRUE;
  5301. //
  5302. // Process the event according to the workset ID
  5303. //
  5304. switch(pEvent16->worksetID)
  5305. {
  5306. //
  5307. // Page Control Workset
  5308. //
  5309. case PAGE_CONTROL_WORKSET:
  5310. wbOnPageObjectAddInd(pObj);
  5311. break;
  5312. //
  5313. // Sync Control Workset
  5314. //
  5315. case SYNC_CONTROL_WORKSET:
  5316. wbOnSyncObjectAddInd(pObj);
  5317. break;
  5318. //
  5319. // User Information Workset
  5320. //
  5321. case USER_INFORMATION_WORKSET:
  5322. wbOnUserObjectAddInd(pObj);
  5323. break;
  5324. //
  5325. // Other (should be a Page Workset)
  5326. //
  5327. default:
  5328. wbOnGraphicObjectAddInd(pEvent16->worksetID, pObj);
  5329. break;
  5330. }
  5331. DC_EXIT_POINT:
  5332. DebugExitBOOL(wbOnObjectAddInd, processed);
  5333. return(processed);
  5334. }
  5335. //
  5336. //
  5337. // Name: wbGetPageObjectType
  5338. //
  5339. // Purpose: Get the type of an object in the Page Control Workset
  5340. //
  5341. // Returns: Error code
  5342. //
  5343. //
  5344. UINT WbClient::wbGetPageObjectType
  5345. (
  5346. POM_OBJECT pObj,
  5347. UINT * pObjectType
  5348. )
  5349. {
  5350. UINT result;
  5351. POM_OBJECTDATA pData;
  5352. DebugEntry(wbGetPageObjectType);
  5353. //
  5354. // Read the object to get its type
  5355. //
  5356. result = OM_ObjectRead(m_pomClient,
  5357. m_hWSGroup,
  5358. PAGE_CONTROL_WORKSET,
  5359. pObj,
  5360. &pData);
  5361. if (result != 0)
  5362. {
  5363. ERROR_OUT(("Error reading object = %d", result));
  5364. wbError();
  5365. DC_QUIT;
  5366. }
  5367. //
  5368. // The first two bytes of the object data give its type
  5369. //
  5370. *pObjectType = *((TSHR_UINT16 *)pData->data);
  5371. //
  5372. // Release the object
  5373. //
  5374. OM_ObjectRelease(m_pomClient,
  5375. m_hWSGroup,
  5376. PAGE_CONTROL_WORKSET,
  5377. pObj,
  5378. &pData);
  5379. DC_EXIT_POINT:
  5380. DebugExitDWORD(wbGetPageObjectType, result);
  5381. return(result);
  5382. }
  5383. //
  5384. //
  5385. // Name: wbOnPageObjectAddInd
  5386. //
  5387. // Purpose: Routine processing OM_OBJECT_ADD_IND events occurring on the
  5388. // Page Control Workset.
  5389. //
  5390. // Returns: Error code
  5391. //
  5392. //
  5393. void WbClient::wbOnPageObjectAddInd(POM_OBJECT pObj)
  5394. {
  5395. UINT objectType;
  5396. DebugEntry(wbOnPageObjectAddInd);
  5397. //
  5398. // Read the object to get its type
  5399. //
  5400. if (wbGetPageObjectType(pObj, &objectType) != 0)
  5401. {
  5402. DC_QUIT;
  5403. }
  5404. //
  5405. // Act according to the type of object added
  5406. //
  5407. switch (objectType)
  5408. {
  5409. case TYPE_CONTROL_LOCK:
  5410. TRACE_OUT(("It is a lock object"));
  5411. wbReadLock();
  5412. break;
  5413. case TYPE_CONTROL_PAGE_ORDER:
  5414. TRACE_OUT(("It is the Page Control object"));
  5415. wbOnPageControlObjectAddInd(pObj);
  5416. break;
  5417. default:
  5418. ERROR_OUT(("Unknown object type added to Page Control Workset"));
  5419. break;
  5420. }
  5421. DC_EXIT_POINT:
  5422. DebugExitVOID(wbOnPageObjectAddInd);
  5423. }
  5424. //
  5425. //
  5426. // Name: wbOnPageControlObjectAddInd
  5427. //
  5428. // Purpose: Routine processing add of page control object
  5429. //
  5430. // Returns: Error code
  5431. //
  5432. //
  5433. void WbClient::wbOnPageControlObjectAddInd(POM_OBJECT pObj)
  5434. {
  5435. DebugEntry(wbOnPageControlObjectAddInd);
  5436. //
  5437. // We only ever expect to get one of these objects
  5438. //
  5439. if (m_pObjPageControl != 0)
  5440. {
  5441. //
  5442. // Check that this is the same object - the add has been triggered by
  5443. // the workset open but we have already read the contents.
  5444. //
  5445. ASSERT((m_pObjPageControl == pObj));
  5446. }
  5447. //
  5448. // Save the handle of the object
  5449. //
  5450. m_pObjPageControl = pObj;
  5451. TRACE_OUT(("Got Page Control object"));
  5452. //
  5453. // Continue according to the current state
  5454. //
  5455. switch (m_state)
  5456. {
  5457. case STATE_REGISTERING:
  5458. //
  5459. // We now have a Page Control Object - if we are waiting for the
  5460. // object we can now move to the next stage.
  5461. //
  5462. if (m_subState == STATE_REG_PENDING_PAGE_CONTROL)
  5463. {
  5464. //
  5465. // If we have the lock on the Page Control Workset then we are in
  5466. // control of the registration process. We must add the sync
  5467. // control object to the Sync Workset.
  5468. //
  5469. if (m_lockState == LOCK_STATE_GOT_LOCK)
  5470. {
  5471. //
  5472. // Create the Sync Control Object
  5473. //
  5474. if (wbCreateSyncControl() != 0)
  5475. {
  5476. ERROR_OUT(("Error adding Sync Control Object"));
  5477. wbError();
  5478. DC_QUIT;
  5479. }
  5480. }
  5481. //
  5482. // If we do not have the sync control object then wait for it -
  5483. // otherwise we can complete initialisation.
  5484. //
  5485. if (m_pObjSyncControl == 0)
  5486. {
  5487. m_subState = STATE_REG_PENDING_SYNC_CONTROL;
  5488. TRACE_OUT(("Moved substate to STATE_REG_PENDING_SYNC_CONTROL"));
  5489. DC_QUIT;
  5490. }
  5491. else
  5492. {
  5493. //
  5494. // If it is us who has the Page Control Workset locked - release
  5495. // the lock.
  5496. //
  5497. if (m_lockState == LOCK_STATE_GOT_LOCK)
  5498. {
  5499. //
  5500. // Unlock the workset
  5501. //
  5502. wbUnlock();
  5503. //
  5504. // Wait for notification of the lock being released
  5505. //
  5506. TRACE_OUT(("Sub state change %d to %d",
  5507. m_subState, STATE_REG_PENDING_UNLOCK));
  5508. m_subState = STATE_REG_PENDING_UNLOCK;
  5509. }
  5510. else
  5511. {
  5512. TRACE_OUT(("Page Control and Sync Control objects both there."));
  5513. TRACE_OUT(("Registration can be completed"));
  5514. wbOnControlWorksetsReady();
  5515. }
  5516. }
  5517. }
  5518. //
  5519. // In other registration states we are not ready to process the
  5520. // event. It will be dealt with later.
  5521. //
  5522. break;
  5523. case STATE_IDLE:
  5524. //
  5525. // We must already have a Page COntrol Object since we are in idle
  5526. // state. So this is an error. It may have been caused by another
  5527. // client so we just trace it rather than asserting.
  5528. //
  5529. ERROR_OUT(("Unexpected add of Page Control Object in idle state"));
  5530. break;
  5531. default:
  5532. ERROR_OUT(("Bad main state"));
  5533. break;
  5534. }
  5535. DC_EXIT_POINT:
  5536. DebugExitVOID(wbOnPageControlObjectAddInd);
  5537. }
  5538. //
  5539. //
  5540. // Name: wbOnSyncObjectAddInd
  5541. //
  5542. // Purpose: Routine processing OM_OBJECT_ADD_IND events occurring on the
  5543. // Sync Control Workset.
  5544. //
  5545. // Returns: Error code
  5546. //
  5547. //
  5548. void WbClient::wbOnSyncObjectAddInd(POM_OBJECT pObj)
  5549. {
  5550. DebugEntry(wbOnSyncObjectAddInd);
  5551. //
  5552. // We only expect this during registration
  5553. //
  5554. switch(m_state)
  5555. {
  5556. //
  5557. // We are waiting for registration to continue
  5558. //
  5559. case STATE_REGISTERING:
  5560. switch(m_subState)
  5561. {
  5562. //
  5563. // We are waiting for a Sync Control Object
  5564. //
  5565. case STATE_REG_PENDING_SYNC_CONTROL:
  5566. m_pObjSyncControl = pObj;
  5567. //
  5568. // The Sync Control object has been added. We do not need to do
  5569. // anything with it yet.
  5570. //
  5571. //
  5572. // If we already have the page control object then we can
  5573. // complete initilisation, otherwise we have to wait for it.
  5574. //
  5575. if (m_pObjPageControl == 0)
  5576. {
  5577. TRACE_OUT(("Sub state change %d to %d",
  5578. m_subState, STATE_REG_PENDING_PAGE_CONTROL));
  5579. m_subState = STATE_REG_PENDING_PAGE_CONTROL;
  5580. }
  5581. else
  5582. {
  5583. //
  5584. // If it is us who has the Page Control Workset locked -
  5585. // release the lock.
  5586. //
  5587. if (m_lockState == LOCK_STATE_GOT_LOCK)
  5588. {
  5589. //
  5590. // Unlock the workset
  5591. //
  5592. wbUnlock();
  5593. //
  5594. // Wait for notification of the lock being released
  5595. //
  5596. TRACE_OUT(("Sub state change %d to %d",
  5597. m_subState, STATE_REG_PENDING_UNLOCK));
  5598. m_subState = STATE_REG_PENDING_UNLOCK;
  5599. }
  5600. else
  5601. {
  5602. TRACE_OUT(("Page Control and Sync Control objects both there."));
  5603. TRACE_OUT(("Registration can be completed"));
  5604. wbOnControlWorksetsReady();
  5605. }
  5606. }
  5607. break;
  5608. default:
  5609. //
  5610. // Save the handle of the Sync Control Object
  5611. //
  5612. m_pObjSyncControl = pObj;
  5613. break;
  5614. }
  5615. break;
  5616. //
  5617. // We are fully registered and are therefore not expecting an add event
  5618. // on this workset. However, since we are registered we must be
  5619. // satisfied that we have a Sync Control Object - so ignore the error.
  5620. //
  5621. case STATE_IDLE:
  5622. ERROR_OUT(("Sync object add not expected in idle state"));
  5623. break;
  5624. //
  5625. // The client is in an unknown state
  5626. //
  5627. default:
  5628. ERROR_OUT(("Client in unknown state = %d", m_state));
  5629. break;
  5630. }
  5631. DebugExitVOID(wbOnSyncObjectAddInd);
  5632. }
  5633. //
  5634. //
  5635. // Name: wbOnUserObjectAddInd
  5636. //
  5637. // Purpose: A user object has been added to the User Information Workset.
  5638. // Inform the client that a new user has joined the call.
  5639. //
  5640. // Returns: Error code
  5641. //
  5642. //
  5643. void WbClient::wbOnUserObjectAddInd(POM_OBJECT pObj)
  5644. {
  5645. UINT countUsers;
  5646. DebugEntry(wbOnUserObjectAddInd);
  5647. OM_WorksetCountObjects(m_pomClient,
  5648. m_hWSGroup,
  5649. USER_INFORMATION_WORKSET,
  5650. &countUsers);
  5651. TRACE_OUT(("Number of users is now %d", countUsers));
  5652. //
  5653. // Ignore the add indication for our own user.
  5654. //
  5655. if (m_pObjLocal == pObj)
  5656. {
  5657. TRACE_OUT(("Got add of own user object"));
  5658. //
  5659. // If we have the lock (temporarily, with NULL lock owner handle),
  5660. // then we need to update the lock object with our actual handle.
  5661. //
  5662. if ((m_pObjLock != NULL) &&
  5663. (m_lockState == LOCK_STATE_GOT_LOCK))
  5664. {
  5665. TRACE_OUT(("Got the lock - update lock object"));
  5666. wbWriteLock();
  5667. }
  5668. if ((m_state == STATE_REGISTERING) &&
  5669. (m_subState == STATE_REG_PENDING_NEW_USER_OBJECT))
  5670. {
  5671. //
  5672. // We have successfully joined the call.
  5673. //
  5674. TRACE_OUT(("Posting WBP_EVENT_JOIN_CALL_OK"));
  5675. WBP_PostEvent(
  5676. 0, // No delay
  5677. WBP_EVENT_JOIN_CALL_OK, // Unlocked
  5678. 0, // No parameters
  5679. 0);
  5680. //
  5681. // Update the state to show that we are ready for work again
  5682. //
  5683. m_state = STATE_IDLE;
  5684. m_subState = STATE_EMPTY;
  5685. TRACE_OUT(("Moved state back to STATE_IDLE"));
  5686. }
  5687. DC_QUIT;
  5688. }
  5689. //
  5690. // If we have created our user object we must check to see if the new
  5691. // user has usurped our color. If so we may need to change color.
  5692. //
  5693. if (m_pObjLocal != NULL)
  5694. {
  5695. TRACE_OUT(("We have added our user object - check colors"));
  5696. wbCheckPersonColor(pObj);
  5697. }
  5698. //
  5699. // Ignore these events unless we are fully registered
  5700. //
  5701. if (m_state != STATE_IDLE)
  5702. {
  5703. TRACE_OUT(("Ignoring user object add - not fully registered"));
  5704. DC_QUIT;
  5705. }
  5706. //
  5707. // Tell the client that a new user has joined
  5708. //
  5709. TRACE_OUT(("Posting WBP_EVENT_USER_JOINED"));
  5710. WBP_PostEvent(
  5711. 0, // No delay
  5712. WBP_EVENT_PERSON_JOINED, // Event type
  5713. 0, // No short parameter
  5714. (UINT_PTR) pObj); // User object handle
  5715. //
  5716. // Try to read the lock object - we may not have been able to do this
  5717. // yet.
  5718. //
  5719. wbReadLock();
  5720. DC_EXIT_POINT:
  5721. DebugExitVOID(wbOnUserObjectAddInd);
  5722. }
  5723. //
  5724. //
  5725. // Name: wbOnGraphicObjectAddInd
  5726. //
  5727. // Purpose: A graphic object has been added to a page workset.
  5728. // Inform the client that a new graphic has been added.
  5729. //
  5730. // Returns: Error code
  5731. //
  5732. //
  5733. void WbClient::wbOnGraphicObjectAddInd
  5734. (
  5735. OM_WORKSET_ID worksetID,
  5736. POM_OBJECT pObj
  5737. )
  5738. {
  5739. WB_PAGE_HANDLE hPage = (WB_PAGE_HANDLE)worksetID;
  5740. POM_OBJECTDATA pData;
  5741. PWB_GRAPHIC pGraphic;
  5742. UINT result;
  5743. DebugEntry(wbOnGraphicObjectAddInd);
  5744. //
  5745. // NFC, SFR 6450. If this object was loaded from file on this machine,
  5746. // then we dont need to set the "changed flag". Otherwise record that
  5747. // the contents have changed
  5748. //
  5749. //
  5750. // Read the object.
  5751. //
  5752. result = OM_ObjectRead(m_pomClient,
  5753. m_hWSGroup,
  5754. worksetID,
  5755. pObj,
  5756. &pData);
  5757. if (result != 0)
  5758. {
  5759. WARNING_OUT(("OM_ObjectRead (%u) failed, set changed flag anyway ", result));
  5760. m_changed = TRUE;
  5761. TRACE_OUT(("changed flag now TRUE"));
  5762. }
  5763. else
  5764. {
  5765. //
  5766. // Convert the ObMan pointer to a core pointer
  5767. //
  5768. pGraphic = GraphicPtrFromObjectData(pData);
  5769. if ( ! ((pGraphic->loadedFromFile) &&
  5770. (pGraphic->loadingClientID == m_clientNetID)))
  5771. {
  5772. TRACE_OUT(("Not loaded from file locally - Set changed flag on"));
  5773. m_changed = TRUE;
  5774. TRACE_OUT(("Changed flag now TRUE"));
  5775. }
  5776. //
  5777. // Finished with the object, so release it.
  5778. //
  5779. OM_ObjectRelease(m_pomClient,
  5780. m_hWSGroup,
  5781. worksetID,
  5782. pObj,
  5783. &pData);
  5784. }
  5785. //
  5786. // These events are ignored unless we are fully registered (the client
  5787. // can do nothing about them if it is not registered correctly).
  5788. //
  5789. if (m_state != STATE_IDLE)
  5790. {
  5791. TRACE_OUT(("Ignoring add of graphic object - not registered"));
  5792. DC_QUIT;
  5793. }
  5794. //
  5795. // Check that this page is actually in use
  5796. //
  5797. if (GetPageState(hPage)->state != PAGE_IN_USE)
  5798. {
  5799. TRACE_OUT(("Ignoring add to page not in use"));
  5800. DC_QUIT;
  5801. }
  5802. //
  5803. // Inform the client of the object being added
  5804. //
  5805. TRACE_OUT(("Posting WBP_EVENT_GRAPHIC_ADDED"));
  5806. WBP_PostEvent(
  5807. 0, // No delay
  5808. WBP_EVENT_GRAPHIC_ADDED, // Event type
  5809. hPage, //
  5810. (UINT_PTR)pObj); // User object handle
  5811. DC_EXIT_POINT:
  5812. DebugExitVOID(wbOnGraphicObjectAddInd);
  5813. }
  5814. //
  5815. //
  5816. // Name: wbOnObjectMoveInd
  5817. //
  5818. // Purpose: This routine is called whenever OM_OBJECT_MOVE_IND events are
  5819. // received.
  5820. //
  5821. // Returns: Error code
  5822. //
  5823. //
  5824. BOOL WbClient::wbOnObjectMoveInd
  5825. (
  5826. UINT_PTR param1,
  5827. UINT_PTR param2
  5828. )
  5829. {
  5830. POM_EVENT_DATA16 pEvent16 = (POM_EVENT_DATA16) &param1;
  5831. POM_EVENT_DATA32 pEvent32 = (POM_EVENT_DATA32) &param2;
  5832. BOOL processed = FALSE;
  5833. DebugEntry(wbOnObjectMoveInd);
  5834. //
  5835. // Check that the workset group is ours
  5836. //
  5837. if (pEvent16->hWSGroup != m_hWSGroup)
  5838. {
  5839. ERROR_OUT(("Event for unknown workset group = %d", pEvent16->hWSGroup));
  5840. DC_QUIT;
  5841. }
  5842. //
  5843. // We will process the event
  5844. //
  5845. processed = TRUE;
  5846. //
  5847. // Process the event according to the workset ID
  5848. //
  5849. switch(pEvent16->worksetID)
  5850. {
  5851. //
  5852. // Page Control Workset Lock Workset User Information Workset
  5853. //
  5854. case PAGE_CONTROL_WORKSET:
  5855. case SYNC_CONTROL_WORKSET:
  5856. case USER_INFORMATION_WORKSET:
  5857. //
  5858. // Event not expected for these worksets
  5859. //
  5860. ERROR_OUT(("Unexpected for workset %d", (UINT) pEvent16->worksetID));
  5861. break;
  5862. //
  5863. // Other (should be a Page Workset)
  5864. //
  5865. default:
  5866. wbOnGraphicObjectMoveInd(pEvent16->worksetID,
  5867. (POM_OBJECT) param2);
  5868. break;
  5869. }
  5870. DC_EXIT_POINT:
  5871. DebugExitBOOL(wbOnObjectMoveInd, processed);
  5872. return(processed);
  5873. }
  5874. //
  5875. //
  5876. // Name: wbOnGraphicObjectMoveInd
  5877. //
  5878. // Purpose: This routine is called whenever an OM_OBJECT_MOVE_IND is
  5879. // received for a graphic object.
  5880. //
  5881. // Returns: Error code
  5882. //
  5883. //
  5884. void WbClient::wbOnGraphicObjectMoveInd
  5885. (
  5886. OM_WORKSET_ID worksetID,
  5887. POM_OBJECT pObj
  5888. )
  5889. {
  5890. WB_PAGE_HANDLE hPage = (WB_PAGE_HANDLE)worksetID;
  5891. DebugEntry(wbOnGraphicObjectMoveInd);
  5892. //
  5893. // Record that the contents have changed
  5894. //
  5895. m_changed = TRUE;
  5896. //
  5897. // These events are ignored unless we are fully registered (the client
  5898. // can do nothing about them).
  5899. //
  5900. if (m_state != STATE_IDLE)
  5901. {
  5902. TRACE_OUT(("Ignoring move of graphic object before registration"));
  5903. DC_QUIT;
  5904. }
  5905. //
  5906. // Check that this page is actually in use
  5907. //
  5908. if (GetPageState(hPage)->state != PAGE_IN_USE)
  5909. {
  5910. TRACE_OUT(("Ignoring move in page not in use"));
  5911. DC_QUIT;
  5912. }
  5913. //
  5914. // Inform the client of the object being added
  5915. //
  5916. TRACE_OUT(("Posting WBP_EVENT_GRAPHIC_MOVED"));
  5917. WBP_PostEvent(
  5918. 0, // No delay
  5919. WBP_EVENT_GRAPHIC_MOVED, // Event type
  5920. hPage, // Page handle
  5921. (UINT_PTR)pObj); // Object handle
  5922. DC_EXIT_POINT:
  5923. DebugExitVOID(wbOnGraphicObjectMoveInd);
  5924. }
  5925. //
  5926. //
  5927. // Name: wbOnObjectDeleteInd
  5928. //
  5929. // Purpose: This routine is called whenever an OM_OBJECT_DELETE_IND is
  5930. // received.
  5931. //
  5932. // Returns: Error code
  5933. //
  5934. //
  5935. BOOL WbClient::wbOnObjectDeleteInd
  5936. (
  5937. UINT_PTR param1,
  5938. POM_OBJECT pObj
  5939. )
  5940. {
  5941. POM_EVENT_DATA16 pEvent16 = (POM_EVENT_DATA16) &param1;
  5942. BOOL processed = FALSE;
  5943. DebugEntry(wbOnObjectDeleteInd);
  5944. //
  5945. // Check that the workset group is ours
  5946. //
  5947. if (pEvent16->hWSGroup != m_hWSGroup)
  5948. {
  5949. ERROR_OUT(("Event for unknown workset group = %d", pEvent16->hWSGroup));
  5950. DC_QUIT;
  5951. }
  5952. //
  5953. // We will process the event
  5954. //
  5955. processed = TRUE;
  5956. //
  5957. // Process the event according to the workset ID
  5958. //
  5959. switch(pEvent16->worksetID)
  5960. {
  5961. //
  5962. // Page Control Workset
  5963. //
  5964. case PAGE_CONTROL_WORKSET:
  5965. wbOnPageObjectDeleteInd(pObj);
  5966. break;
  5967. //
  5968. // Sync Workset
  5969. //
  5970. case SYNC_CONTROL_WORKSET:
  5971. ERROR_OUT(("Illegal object delete on sync control workset - ignored"));
  5972. //
  5973. // We do not confirm the delete since we do not want to lose the Sync
  5974. // Control Object.
  5975. //
  5976. break;
  5977. //
  5978. // User Information Workset
  5979. //
  5980. case USER_INFORMATION_WORKSET:
  5981. wbOnUserObjectDeleteInd(pObj);
  5982. break;
  5983. //
  5984. // Other (should be a Page Workset)
  5985. //
  5986. default:
  5987. wbOnGraphicObjectDeleteInd(pEvent16->worksetID, pObj);
  5988. break;
  5989. }
  5990. DC_EXIT_POINT:
  5991. DebugExitBOOL(wbOnObjectDeleteInd, processed);
  5992. return(processed);
  5993. }
  5994. //
  5995. //
  5996. // Name: wbOnPageObjectDeleteInd
  5997. //
  5998. // Purpose: This routine is called whenever an OM_OBJECT_DELETE_IND is
  5999. // received for an object in the Page Control Workset.
  6000. //
  6001. // Returns: Error code
  6002. //
  6003. //
  6004. void WbClient::wbOnPageObjectDeleteInd(POM_OBJECT pObj)
  6005. {
  6006. UINT objectType;
  6007. DebugEntry(wbOnPageObjectDeleteInd);
  6008. //
  6009. // Get the type of object that is being deleted
  6010. //
  6011. if (wbGetPageObjectType(pObj, &objectType) != 0)
  6012. {
  6013. DC_QUIT;
  6014. }
  6015. switch(objectType)
  6016. {
  6017. case TYPE_CONTROL_PAGE_ORDER:
  6018. //
  6019. // The object is the Page Control Object - something serious is wrong
  6020. // as this object should never be deleted.
  6021. //
  6022. ERROR_OUT(("Attempt to delete page control object"));
  6023. break;
  6024. case TYPE_CONTROL_LOCK:
  6025. TRACE_OUT(("Lock object being deleted"));
  6026. wbOnLockControlObjectDeleteInd(pObj);
  6027. break;
  6028. default:
  6029. ERROR_OUT(("Bad object type"));
  6030. break;
  6031. }
  6032. DC_EXIT_POINT:
  6033. DebugExitVOID(wbOnPageObjectDeleteInd);
  6034. }
  6035. //
  6036. //
  6037. // Name: wbOnLockControlObjectDeleteInd
  6038. //
  6039. // Purpose: This routine is called whenever an OM_OBJECT_DELETE_IND is
  6040. // received for a lock object in the Page Control Workset.
  6041. //
  6042. // Returns: Error code
  6043. //
  6044. //
  6045. void WbClient::wbOnLockControlObjectDeleteInd(POM_OBJECT pObj
  6046. )
  6047. {
  6048. DebugEntry(wbOnLockControlObjectDeleteInd);
  6049. //
  6050. // Confirm the delete to ObMan
  6051. //
  6052. TRACE_OUT(("Lock handle %x, expecting %x", pObj, m_pObjLock));
  6053. if (pObj != m_pObjLock)
  6054. {
  6055. WARNING_OUT(("Unexpected lock handle %x, expecting %x",
  6056. pObj, m_pObjLock));
  6057. }
  6058. OM_ObjectDeleteConfirm(m_pomClient,
  6059. m_hWSGroup,
  6060. PAGE_CONTROL_WORKSET,
  6061. pObj);
  6062. m_pObjLock = NULL;
  6063. //
  6064. // Process according to the current lock state
  6065. //
  6066. switch(m_lockState)
  6067. {
  6068. case LOCK_STATE_PENDING_DELETE:
  6069. //
  6070. // We are deleting our lock object. We must unlock the
  6071. // workset.
  6072. //
  6073. TRACE_OUT(("Our lock object delete confirmed - unlocking the workset"));
  6074. OM_WorksetUnlock(m_pomClient,
  6075. m_hWSGroup,
  6076. PAGE_CONTROL_WORKSET);
  6077. break;
  6078. case LOCK_STATE_LOCKED_OUT:
  6079. //
  6080. // The user with the lock has deleted the lock object. We treat
  6081. // this as a removal of the whiteboard lock - we reset the
  6082. // state at the end of this function.
  6083. //
  6084. TRACE_OUT(("Remote user's lock object deleted"));
  6085. break;
  6086. case LOCK_STATE_EMPTY:
  6087. //
  6088. // We have just deleted the object at the end of a call to tidy
  6089. // up. Carry on so we reset lockType / pObjPersonLock etc.
  6090. //
  6091. TRACE_OUT(("LOCK_STATE_EMPTY"));
  6092. break;
  6093. case LOCK_STATE_PENDING_LOCK:
  6094. WARNING_OUT(("LOCK_STATE_PENDING_LOCK"));
  6095. //
  6096. // We don't expect to get here. If by some chance we do, then
  6097. // just quit, since we should still get the workset lock con.
  6098. //
  6099. DC_QUIT;
  6100. break;
  6101. default:
  6102. ERROR_OUT(("Bad lock state %d", m_lockState));
  6103. break;
  6104. }
  6105. //
  6106. // The lock object has been deleted, so there is no lock active
  6107. //
  6108. m_lockType = WB_LOCK_TYPE_NONE;
  6109. m_pObjPersonLock = NULL;
  6110. //
  6111. // Record that there is now no lock
  6112. //
  6113. m_lockState = LOCK_STATE_EMPTY;
  6114. TRACE_OUT(("Moved lock state to LOCK_STATE_EMPTY"));
  6115. //
  6116. // Notify the client of the lock status change
  6117. //
  6118. wbSendLockNotification();
  6119. DC_EXIT_POINT:
  6120. DebugExitVOID(wbOnLockControlObjectDeleteInd);
  6121. }
  6122. //
  6123. //
  6124. // Name: wbOnGraphicObjectDeleteInd
  6125. //
  6126. // Purpose: This routine is called whenever an OM_OBJECT_DELETE_IND is
  6127. // received for an object in a page workset.
  6128. //
  6129. // Returns: Error code
  6130. //
  6131. //
  6132. void WbClient::wbOnGraphicObjectDeleteInd
  6133. (
  6134. OM_WORKSET_ID worksetID,
  6135. POM_OBJECT pObj
  6136. )
  6137. {
  6138. WB_PAGE_HANDLE hPage = (WB_PAGE_HANDLE)worksetID;
  6139. BOOL bConfirm = FALSE;
  6140. DebugEntry(wbOnGraphicObjectDeleteInd);
  6141. //
  6142. // Record that the contents have changed
  6143. //
  6144. m_changed = TRUE;
  6145. TRACE_OUT(("Changed flag now TRUE"));
  6146. //
  6147. // These events are handled within the core until the client is ready.
  6148. //
  6149. if (m_state != STATE_IDLE)
  6150. {
  6151. TRACE_OUT(("Delete of graphic object before registration"));
  6152. bConfirm = TRUE;
  6153. }
  6154. //
  6155. // Check that this page is actually in use
  6156. //
  6157. if (GetPageState(hPage)->state != PAGE_IN_USE)
  6158. {
  6159. TRACE_OUT(("Delete in page that is not in use"));
  6160. bConfirm = TRUE;
  6161. }
  6162. //
  6163. // Check whether we are to pass the event on to the client
  6164. //
  6165. if (bConfirm)
  6166. {
  6167. //
  6168. // Confirm the delete to ObMan
  6169. //
  6170. TRACE_OUT(("Confirming delete immediately"));
  6171. OM_ObjectDeleteConfirm(m_pomClient,
  6172. m_hWSGroup,
  6173. worksetID,
  6174. pObj);
  6175. }
  6176. else
  6177. {
  6178. //
  6179. // Inform the client of the object being added
  6180. //
  6181. TRACE_OUT(("Posting WBP_EVENT_GRAPHIC_DELETE_IND"));
  6182. WBP_PostEvent(
  6183. 0, // No delay
  6184. WBP_EVENT_GRAPHIC_DELETE_IND, // Event type
  6185. hPage, // Page handle
  6186. (UINT_PTR)pObj); // Object handle
  6187. }
  6188. DebugExitVOID(wbOnGraphicObjectDeleteInd);
  6189. }
  6190. //
  6191. //
  6192. // Name: wbOnUserObjectDeleteInd
  6193. //
  6194. // Purpose: This routine is called whenever an OM_OBJECT_DELETE_IND is
  6195. // received for an object in the User Information Workset.
  6196. //
  6197. // Returns: Error code
  6198. //
  6199. //
  6200. void WbClient::wbOnUserObjectDeleteInd
  6201. (
  6202. POM_OBJECT pObjPerson
  6203. )
  6204. {
  6205. DebugEntry(wbOnUserObjectDeleteInd);
  6206. //
  6207. // If the user which has been removed had a lock then remove its user
  6208. // handle from the client data. The lock is still there, and will be
  6209. // removed when we get the WORKSET_UNLOCK_IND for the lock workset. This
  6210. // arrives after the user-object delete, because the user workset is of
  6211. // higher priority.
  6212. //
  6213. if (m_pObjPersonLock == pObjPerson)
  6214. {
  6215. m_pObjPersonLock = NULL;
  6216. }
  6217. //
  6218. // These events are ignored unless we are fully registered (the client
  6219. // can do nothing about them).
  6220. //
  6221. if (m_state != STATE_IDLE)
  6222. {
  6223. TRACE_OUT(("Delete of user object before registration - confirming"));
  6224. //
  6225. // Confirm the delete
  6226. //
  6227. OM_ObjectDeleteConfirm(m_pomClient,
  6228. m_hWSGroup,
  6229. USER_INFORMATION_WORKSET,
  6230. pObjPerson);
  6231. //
  6232. // Nothing more to be done
  6233. //
  6234. DC_QUIT;
  6235. }
  6236. //
  6237. // Inform the client of the user leaving
  6238. //
  6239. TRACE_OUT(("Posting WBP_EVENT_USER_LEFT_IND"));
  6240. WBP_PostEvent(
  6241. 0, // No delay
  6242. WBP_EVENT_PERSON_LEFT, // Event type
  6243. 0, // No short parameter
  6244. (UINT_PTR) pObjPerson); // User object handle
  6245. DC_EXIT_POINT:
  6246. DebugExitVOID(wbOnUserObjectDeleteInd);
  6247. }
  6248. //
  6249. //
  6250. // Name: wbOnObjectUpdateInd
  6251. //
  6252. // Purpose: This routine is called whenever an OM_OBJECT_UPDATE_IND is
  6253. // received for an object in a page workset.
  6254. //
  6255. // Returns: Error code
  6256. //
  6257. //
  6258. BOOL WbClient::wbOnObjectUpdateInd
  6259. (
  6260. UINT_PTR param1,
  6261. POM_OBJECT pObj
  6262. )
  6263. {
  6264. POM_EVENT_DATA16 pEvent16 = (POM_EVENT_DATA16) &param1;
  6265. BOOL processed = FALSE;
  6266. DebugEntry(wbOnObjectUpdateInd);
  6267. //
  6268. // Check that the workset group is ours
  6269. //
  6270. if (pEvent16->hWSGroup != m_hWSGroup)
  6271. {
  6272. ERROR_OUT(("Event for unknown workset group = %d", pEvent16->hWSGroup));
  6273. DC_QUIT;
  6274. }
  6275. //
  6276. // We will process the event
  6277. //
  6278. processed = TRUE;
  6279. //
  6280. // Process the event according to the workset ID
  6281. //
  6282. switch(pEvent16->worksetID)
  6283. {
  6284. //
  6285. // Page Control Workset
  6286. //
  6287. case PAGE_CONTROL_WORKSET:
  6288. ERROR_OUT(("Illegal object update on page control workset - ignored"));
  6289. //
  6290. // Updates on the Page Control Object are not allowed - do not
  6291. // confirm it.
  6292. //
  6293. break;
  6294. //
  6295. // Lock Workset
  6296. //
  6297. case SYNC_CONTROL_WORKSET:
  6298. ERROR_OUT(("Illegal object update on sync control workset"));
  6299. //
  6300. // Updates to the Sync Control Object itself are not allowed - do not
  6301. // confirm it.
  6302. //
  6303. break;
  6304. //
  6305. // User Information Workset
  6306. //
  6307. case USER_INFORMATION_WORKSET:
  6308. wbOnUserObjectUpdateInd(pObj);
  6309. break;
  6310. //
  6311. // Other (should be a Page Workset)
  6312. //
  6313. default:
  6314. wbOnGraphicObjectUpdateInd(pEvent16->worksetID, pObj);
  6315. break;
  6316. }
  6317. DC_EXIT_POINT:
  6318. DebugExitBOOL(wbOnObjectUpdateInd, processed);
  6319. return(processed);
  6320. }
  6321. //
  6322. //
  6323. // Name: wbOnUserObjectUpdateInd
  6324. //
  6325. // Purpose: This routine is called whenever an OM_OBJECT_UPDATE_IND is
  6326. // received for an object in the User Information Workset.
  6327. //
  6328. // Returns: Error code
  6329. //
  6330. //
  6331. void WbClient::wbOnUserObjectUpdateInd(POM_OBJECT pObj)
  6332. {
  6333. DebugEntry(wbOnUserObjectUpdateInd);
  6334. //
  6335. // if the updated user object is not the local user's, and we have
  6336. // already added the local user's object, then check the color hasn't
  6337. // changed to clash with the local user's color.
  6338. //
  6339. if ( (m_pObjLocal != pObj)
  6340. && (m_pObjLocal != NULL))
  6341. {
  6342. TRACE_OUT(("Check color of updated user object"));
  6343. wbCheckPersonColor(pObj);
  6344. }
  6345. //
  6346. // Don't inform the front end if we aren't fully registered
  6347. //
  6348. if (m_state != STATE_IDLE)
  6349. {
  6350. TRACE_OUT(("User object updated before registration - confirming"));
  6351. //
  6352. // Confirm the update immediately
  6353. //
  6354. OM_ObjectUpdateConfirm(m_pomClient,
  6355. m_hWSGroup,
  6356. USER_INFORMATION_WORKSET,
  6357. pObj);
  6358. //
  6359. // Nothing more to be done
  6360. //
  6361. DC_QUIT;
  6362. }
  6363. //
  6364. // Tell the client that a user has been updated
  6365. //
  6366. TRACE_OUT(("Posting WBP_EVENT_PERSON_UPDATE_IND"));
  6367. WBP_PostEvent(
  6368. 0, // No delay
  6369. WBP_EVENT_PERSON_UPDATE, // Event type
  6370. 0, // No short parameter
  6371. (UINT_PTR) pObj); // User object handle
  6372. DC_EXIT_POINT:
  6373. DebugExitVOID(wbOnUserObjectUpdateInd);
  6374. }
  6375. //
  6376. //
  6377. // Name: wbOnUserObjectReplaceInd
  6378. //
  6379. // Purpose: This routine is called whenever an OM_OBJECT_REPLACE_IND is
  6380. // received for an object in the User Information Workset.
  6381. //
  6382. //
  6383. // Returns: Error code
  6384. //
  6385. //
  6386. void WbClient::wbOnUserObjectReplaceInd(POM_OBJECT pObj)
  6387. {
  6388. DebugEntry(wbOnUserObjectReplaceInd);
  6389. //
  6390. // if the updated user object is not the local user's, and we have
  6391. // already added the local user's object, then check the color hasn't
  6392. // changed to clash with the local user's color.
  6393. //
  6394. if ( (m_pObjLocal != pObj)
  6395. && (m_pObjLocal != NULL))
  6396. {
  6397. TRACE_OUT(("Check color of updated user object"));
  6398. wbCheckPersonColor(pObj);
  6399. }
  6400. //
  6401. // Don't inform the front end if we aren't fully registered
  6402. //
  6403. if (m_state != STATE_IDLE)
  6404. {
  6405. TRACE_OUT(("User object replaced before registration - confirming"));
  6406. //
  6407. // Confirm the replace immediately
  6408. //
  6409. OM_ObjectReplaceConfirm(m_pomClient,
  6410. m_hWSGroup,
  6411. USER_INFORMATION_WORKSET,
  6412. pObj);
  6413. //
  6414. // Nothing more to be done
  6415. //
  6416. DC_QUIT;
  6417. }
  6418. //
  6419. // Tell the client that a user has been updated
  6420. //
  6421. TRACE_OUT(("Posting WBP_EVENT_PERSON_UPDATE_IND"));
  6422. WBP_PostEvent(
  6423. 0, // No delay
  6424. WBP_EVENT_PERSON_REPLACE, // Event type
  6425. 0, // No short parameter
  6426. (UINT_PTR) pObj); // User object handle
  6427. DC_EXIT_POINT:
  6428. DebugExitVOID(wbOnUserObjectReplaceInd);
  6429. }
  6430. //
  6431. //
  6432. // Name: wbOnGraphicObjectUpdateInd
  6433. //
  6434. // Purpose: This routine is called whenever an OM_OBJECT_UPDATE_IND is
  6435. // received for an object in a page workset.
  6436. //
  6437. // Returns: Error code
  6438. //
  6439. //
  6440. void WbClient::wbOnGraphicObjectUpdateInd
  6441. (
  6442. OM_WORKSET_ID worksetID,
  6443. POM_OBJECT pObj
  6444. )
  6445. {
  6446. WB_PAGE_HANDLE hPage = (WB_PAGE_HANDLE)worksetID;
  6447. BOOL bConfirm = FALSE;
  6448. DebugEntry(wbOnGraphicObjectUpdateInd);
  6449. //
  6450. // Record that the contents have changed
  6451. //
  6452. m_changed = TRUE;
  6453. TRACE_OUT(("Changed flag now TRUE"));
  6454. //
  6455. // These events are handled within the core until the client is ready.
  6456. //
  6457. if (m_state != STATE_IDLE)
  6458. {
  6459. TRACE_OUT(("Update of graphic object before registration"));
  6460. bConfirm = TRUE;
  6461. }
  6462. //
  6463. // Check that this page is actually in use
  6464. //
  6465. if (GetPageState(hPage)->state != PAGE_IN_USE)
  6466. {
  6467. TRACE_OUT(("Update for page that is not in use"));
  6468. bConfirm = TRUE;
  6469. }
  6470. //
  6471. // Check whether we are to confirm the update now or ask the client
  6472. //
  6473. if (bConfirm)
  6474. {
  6475. //
  6476. // Confirm the update immediately
  6477. //
  6478. TRACE_OUT(("Confirming update immediately"));
  6479. OM_ObjectUpdateConfirm(m_pomClient,
  6480. m_hWSGroup,
  6481. worksetID,
  6482. pObj);
  6483. }
  6484. else
  6485. {
  6486. //
  6487. // Inform the client of the object being added
  6488. //
  6489. TRACE_OUT(("Posting WBP_EVENT_GRAPHIC_UPDATE_IND"));
  6490. WBP_PostEvent(
  6491. 0, // No delay
  6492. WBP_EVENT_GRAPHIC_UPDATE_IND, // Event type
  6493. hPage, // Page handle
  6494. (UINT_PTR)pObj); // Object handle
  6495. }
  6496. DebugExitVOID(wbOnGraphicObjectUpdateInd);
  6497. }
  6498. //
  6499. //
  6500. // Name: wbOnObjectReplaceInd
  6501. //
  6502. // Purpose: This routine is called whenever an OM_OBJECT_REPLACE_IND is
  6503. // received.
  6504. //
  6505. // Returns: Error code
  6506. //
  6507. //
  6508. BOOL WbClient::wbOnObjectReplaceInd
  6509. (
  6510. UINT_PTR param1,
  6511. POM_OBJECT pObj
  6512. )
  6513. {
  6514. POM_EVENT_DATA16 pEvent = (POM_EVENT_DATA16) &param1;
  6515. BOOL processed = FALSE;
  6516. DebugEntry(wbOnObjectReplaceInd);
  6517. //
  6518. // Check that the workset group is ours
  6519. //
  6520. if (pEvent->hWSGroup != m_hWSGroup)
  6521. {
  6522. ERROR_OUT(("Event for unknown workset group = %d", pEvent->hWSGroup));
  6523. DC_QUIT;
  6524. }
  6525. //
  6526. // We will process the event
  6527. //
  6528. processed = TRUE;
  6529. //
  6530. // Process the event according to the workset ID
  6531. //
  6532. switch (pEvent->worksetID)
  6533. {
  6534. //
  6535. // Page Control Workset
  6536. //
  6537. case PAGE_CONTROL_WORKSET:
  6538. wbOnPageObjectReplaceInd(pObj);
  6539. break;
  6540. //
  6541. // Lock Workset
  6542. //
  6543. case SYNC_CONTROL_WORKSET:
  6544. wbOnSyncObjectReplaceInd(pObj);
  6545. break;
  6546. //
  6547. // User Information Workset
  6548. //
  6549. case USER_INFORMATION_WORKSET:
  6550. wbOnUserObjectReplaceInd(pObj);
  6551. break;
  6552. //
  6553. // Other (should be a Page Workset)
  6554. //
  6555. default:
  6556. wbOnGraphicObjectReplaceInd(pEvent->worksetID, pObj);
  6557. break;
  6558. }
  6559. DC_EXIT_POINT:
  6560. DebugExitBOOL(wbOnObjectReplaceInd, processed);
  6561. return(processed);
  6562. }
  6563. //
  6564. //
  6565. // Name: wbOnPageObjectReplaceInd
  6566. //
  6567. // Purpose: This routine is called whenever the Page Control object is
  6568. // replaced.
  6569. //
  6570. // Returns: Error code
  6571. //
  6572. //
  6573. void WbClient::wbOnPageObjectReplaceInd(POM_OBJECT pObj)
  6574. {
  6575. UINT objectType;
  6576. DebugEntry(wbOnPageObjectReplaceInd);
  6577. //
  6578. // Confirm the change to ObMan (cannot fail)
  6579. //
  6580. OM_ObjectReplaceConfirm(m_pomClient,
  6581. m_hWSGroup,
  6582. PAGE_CONTROL_WORKSET,
  6583. pObj);
  6584. //
  6585. // Read the object to get its type
  6586. //
  6587. if (wbGetPageObjectType(pObj, &objectType) != 0)
  6588. {
  6589. DC_QUIT;
  6590. }
  6591. //
  6592. // Act according to the type of object added
  6593. //
  6594. switch (objectType)
  6595. {
  6596. case TYPE_CONTROL_LOCK:
  6597. wbReadLock();
  6598. break;
  6599. case TYPE_CONTROL_PAGE_ORDER:
  6600. wbOnPageControlObjectReplaceInd();
  6601. break;
  6602. default:
  6603. ERROR_OUT(("Unknown object type added to Page Control Workset"));
  6604. break;
  6605. }
  6606. DC_EXIT_POINT:
  6607. DebugExitVOID(wbOnPageObjectReplaceInd);
  6608. }
  6609. //
  6610. //
  6611. // Name: wbOnPageControlObjectReplaceInd
  6612. //
  6613. // Purpose: This routine is called whenever the Page Control object is
  6614. // replaced.
  6615. //
  6616. // Returns: Error code
  6617. //
  6618. //
  6619. void WbClient::wbOnPageControlObjectReplaceInd(void)
  6620. {
  6621. DebugEntry(wbOnPageControlObjectReplaceInd);
  6622. //
  6623. // Process according to the current state
  6624. //
  6625. switch (m_state)
  6626. {
  6627. case STATE_REGISTERING:
  6628. //
  6629. // During registration we do nothing - the Page Order is updated
  6630. // explicitly as one of the last registration actions.
  6631. //
  6632. break;
  6633. case STATE_IDLE:
  6634. //
  6635. // When we are fully registered we must send events to the front-end
  6636. // indicating what changes have been made to the page list.
  6637. //
  6638. wbProcessPageControlChanges();
  6639. break;
  6640. default:
  6641. ERROR_OUT(("Bad client major state"));
  6642. break;
  6643. }
  6644. DebugExitVOID(wbOnPageControlObjectReplaceInd);
  6645. }
  6646. //
  6647. //
  6648. // Name: wbProcessPageControlChanges
  6649. //
  6650. // Purpose: This routine is called whenever the Page Control object is
  6651. // replaced in idle state. It reads the new Page Control data
  6652. // and starts the process of informing the client of any changes.
  6653. //
  6654. // Returns: Error code
  6655. //
  6656. //
  6657. void WbClient::wbProcessPageControlChanges(void)
  6658. {
  6659. BYTE toBeMarked[WB_MAX_PAGES];
  6660. UINT indexExternal;
  6661. UINT indexInternal;
  6662. UINT lLengthExternal;
  6663. BOOL addOutstanding = TRUE;
  6664. PWB_PAGE_ORDER pPageOrderExternal;
  6665. PWB_PAGE_ORDER pPageOrderInternal = &(m_pageOrder);
  6666. PWB_PAGE_STATE pPageState;
  6667. POM_WORKSET_ID pPageExternal;
  6668. UINT countPagesExternal;
  6669. POM_OBJECTDATA pData = NULL;
  6670. DebugEntry(wbProcessPageControlChanges);
  6671. //
  6672. // Read the new Page Control Object
  6673. //
  6674. if (OM_ObjectRead(m_pomClient,
  6675. m_hWSGroup,
  6676. PAGE_CONTROL_WORKSET,
  6677. m_pObjPageControl,
  6678. &pData) != 0)
  6679. {
  6680. ERROR_OUT(("Error reading Page Control Object"));
  6681. wbError();
  6682. DC_QUIT;
  6683. }
  6684. //
  6685. // Extract details from the external page order
  6686. //
  6687. lLengthExternal = pData->length;
  6688. pPageOrderExternal = (PWB_PAGE_ORDER) pData->data;
  6689. pPageExternal = pPageOrderExternal->pages;
  6690. countPagesExternal = pPageOrderExternal->countPages;
  6691. //
  6692. // Process existing and newly added pages
  6693. //
  6694. for (indexExternal = 0; indexExternal < countPagesExternal; indexExternal++)
  6695. {
  6696. //
  6697. // Convert the index into the Page Control Object to an index into the
  6698. // internal Page List.
  6699. //
  6700. indexInternal = PAGE_WORKSET_ID_TO_INDEX(pPageExternal[indexExternal]);
  6701. //
  6702. // Test and update the internal page state as necessary
  6703. //
  6704. pPageState = &((m_pageStates)[indexInternal]);
  6705. //
  6706. // If the page is in use locally then we do not need to do anything
  6707. // (the external and internal page lists agree already).
  6708. //
  6709. if (pPageState->state != PAGE_IN_USE)
  6710. {
  6711. switch (pPageState->subState)
  6712. {
  6713. case PAGE_STATE_EMPTY:
  6714. //
  6715. // The page does not yet have a workset open for it - open one
  6716. // now. (But only open one per call to this routine to prevent
  6717. // swamping the message queue. The other outstanding opens will
  6718. // be done when this routine is next called).
  6719. //
  6720. wbPageWorksetOpen(PAGE_INDEX_TO_HANDLE(indexInternal),
  6721. OPEN_EXTERNAL);
  6722. //
  6723. // Leave now - this routine will be called again when the open
  6724. // confirm is received for the workset just opened.
  6725. //
  6726. DC_QUIT;
  6727. break;
  6728. case PAGE_STATE_LOCAL_OPEN_CONFIRM:
  6729. case PAGE_STATE_EXTERNAL_OPEN_CONFIRM:
  6730. case PAGE_STATE_EXTERNAL_ADD:
  6731. //
  6732. // Do nothing - the page is already in the add process
  6733. //
  6734. TRACE_OUT(("Page %d is already pending local add",
  6735. PAGE_INDEX_TO_HANDLE(indexInternal)));
  6736. break;
  6737. case PAGE_STATE_READY:
  6738. //
  6739. // The page workset has been opened previously - we can just mark
  6740. // the page as being in use immediately.
  6741. //
  6742. pPageState->state = PAGE_IN_USE;
  6743. pPageState->subState = PAGE_STATE_EMPTY;
  6744. TRACE_OUT(("Moved page %d state to PAGE_IN_USE",
  6745. (UINT) PAGE_INDEX_TO_HANDLE(indexInternal) ));
  6746. break;
  6747. default:
  6748. ERROR_OUT(("Bad page substate %d", pPageState->subState));
  6749. break;
  6750. }
  6751. }
  6752. }
  6753. //
  6754. // Mark any pages that no longer appear in the Page Control Object as
  6755. // "delete pending" (unless they are already marked).
  6756. //
  6757. FillMemory(toBeMarked, sizeof(toBeMarked), TRUE);
  6758. //
  6759. // Flag which pages should be marked
  6760. //
  6761. for (indexExternal = 0; indexExternal < countPagesExternal; indexExternal++)
  6762. {
  6763. toBeMarked[PAGE_WORKSET_ID_TO_INDEX(pPageExternal[indexExternal])] = 0;
  6764. }
  6765. //
  6766. // Mark them
  6767. //
  6768. for (indexInternal = 0; indexInternal < WB_MAX_PAGES; indexInternal++)
  6769. {
  6770. pPageState = &((m_pageStates)[indexInternal]);
  6771. if ( (toBeMarked[indexInternal] == 1)
  6772. && (pPageState->state == PAGE_IN_USE))
  6773. {
  6774. switch (pPageState->subState)
  6775. {
  6776. case PAGE_STATE_EMPTY:
  6777. //
  6778. // Ask the client for confirmation of the delete
  6779. //
  6780. TRACE_OUT(("Posting WBP_EVENT_PAGE_DELETE_IND"));
  6781. WBP_PostEvent(
  6782. 0, // No delay
  6783. WBP_EVENT_PAGE_DELETE_IND, // Page being deleted
  6784. PAGE_INDEX_TO_HANDLE(indexInternal), // Page handle
  6785. 0);
  6786. //
  6787. // Update the page state
  6788. //
  6789. pPageState->subState = PAGE_STATE_EXTERNAL_DELETE_CONFIRM;
  6790. TRACE_OUT(("Moved page %d substate to PAGE_STATE_EXTERNAL_DELETE_CONFIRM",
  6791. (UINT) PAGE_INDEX_TO_HANDLE(indexInternal) ));
  6792. //
  6793. // Leave now - this routine will be called again when the delete
  6794. // confirm is received for this workset.
  6795. //
  6796. DC_QUIT;
  6797. break;
  6798. case PAGE_STATE_LOCAL_DELETE:
  6799. //
  6800. // Ask the client for confirmation of the delete
  6801. //
  6802. TRACE_OUT(("Posting WBP_EVENT_PAGE_DELETE_IND"));
  6803. WBP_PostEvent(
  6804. 0, // No delay
  6805. WBP_EVENT_PAGE_DELETE_IND, // Page being deleted
  6806. PAGE_INDEX_TO_HANDLE(indexInternal), // Page handle
  6807. 0);
  6808. //
  6809. // Update the page state
  6810. //
  6811. pPageState->subState = PAGE_STATE_LOCAL_DELETE_CONFIRM;
  6812. TRACE_OUT(("Moved page %d substate to PAGE_STATE_LOCAL_DELETE_CONFIRM",
  6813. (UINT) PAGE_INDEX_TO_HANDLE(indexInternal) ));
  6814. //
  6815. // Leave now - this routine will be called again when the delete
  6816. // confirm is received for this workset.
  6817. //
  6818. DC_QUIT;
  6819. break;
  6820. case PAGE_STATE_EXTERNAL_DELETE:
  6821. case PAGE_STATE_EXTERNAL_DELETE_CONFIRM:
  6822. case PAGE_STATE_LOCAL_DELETE_CONFIRM:
  6823. //
  6824. // We are already expecting a delete for this page
  6825. //
  6826. TRACE_OUT(("Page %d is already pending local delete",
  6827. PAGE_INDEX_TO_HANDLE(indexInternal)));
  6828. DC_QUIT;
  6829. break;
  6830. default:
  6831. ERROR_OUT(("Bad page substate %d", pPageState->subState));
  6832. break;
  6833. }
  6834. }
  6835. }
  6836. //
  6837. // There are no deletes or adds outstanding now
  6838. //
  6839. //
  6840. // Copy the new page order to the internal page list
  6841. //
  6842. memcpy(pPageOrderInternal, pPageOrderExternal, lLengthExternal);
  6843. //
  6844. // Inform the client of the change
  6845. //
  6846. TRACE_OUT(("Posting WBP_EVENT_PAGE_ORDER_UPDATED"));
  6847. WBP_PostEvent(
  6848. 0, // No delay
  6849. WBP_EVENT_PAGE_ORDER_UPDATED, // Event number
  6850. 0, // No parameters
  6851. 0);
  6852. //
  6853. // Check the number of pages ready in the cache
  6854. //
  6855. wbCheckReadyPages();
  6856. DC_EXIT_POINT:
  6857. //
  6858. // Release the Page Control Object
  6859. //
  6860. if (pData != NULL)
  6861. {
  6862. OM_ObjectRelease(m_pomClient,
  6863. m_hWSGroup,
  6864. PAGE_CONTROL_WORKSET,
  6865. m_pObjPageControl,
  6866. &pData);
  6867. }
  6868. DebugExitVOID(wbProcessPageControlChanges);
  6869. }
  6870. //
  6871. //
  6872. // Name: wbOnSyncObjectReplaceInd
  6873. //
  6874. // Purpose: This routine is called whenever the Sync Control object is
  6875. // replaced.
  6876. //
  6877. // Returns: Error code
  6878. //
  6879. //
  6880. void WbClient::wbOnSyncObjectReplaceInd(POM_OBJECT pObj)
  6881. {
  6882. POM_OBJECTDATA pSyncObject;
  6883. PWB_SYNC_CONTROL pSyncControl;
  6884. OM_OBJECT_ID syncPersonID;
  6885. DebugEntry(wbOnSyncControlReplaced);
  6886. //
  6887. // Confirm the replace of the object
  6888. //
  6889. OM_ObjectReplaceConfirm(m_pomClient,
  6890. m_hWSGroup,
  6891. SYNC_CONTROL_WORKSET,
  6892. pObj);
  6893. //
  6894. // Read the object and determine whether it was written by this client or
  6895. // another.
  6896. //
  6897. if (OM_ObjectRead(m_pomClient,
  6898. m_hWSGroup,
  6899. SYNC_CONTROL_WORKSET,
  6900. m_pObjSyncControl,
  6901. &pSyncObject) != 0)
  6902. {
  6903. ERROR_OUT(("Error reading Sync Control Object"));
  6904. wbError();
  6905. DC_QUIT;
  6906. }
  6907. pSyncControl = (PWB_SYNC_CONTROL) pSyncObject->data;
  6908. //
  6909. // Get the user ID from the object
  6910. //
  6911. syncPersonID = pSyncControl->personID;
  6912. //
  6913. // Release the Sync Control Object
  6914. //
  6915. OM_ObjectRelease(m_pomClient,
  6916. m_hWSGroup,
  6917. SYNC_CONTROL_WORKSET,
  6918. m_pObjSyncControl,
  6919. &pSyncObject);
  6920. pSyncControl = NULL;
  6921. //
  6922. // If the user ID in the object is not the ID of the current client, we
  6923. // must post a message to the front-end.
  6924. //
  6925. if (memcmp(&syncPersonID,
  6926. &(m_personID),
  6927. sizeof(syncPersonID)) != 0)
  6928. {
  6929. //
  6930. // Post a "sync position updated" event to the front-end
  6931. //
  6932. TRACE_OUT(("Posting WBP_EVENT_SYNC_POSITION_UPDATED"));
  6933. WBP_PostEvent(
  6934. 0,
  6935. WBP_EVENT_SYNC_POSITION_UPDATED,
  6936. 0,
  6937. 0);
  6938. }
  6939. DC_EXIT_POINT:
  6940. DebugExitVOID(wbOnSyncControlReplaced);
  6941. }
  6942. //
  6943. //
  6944. // Name: wbOnGraphicObjectReplaceInd
  6945. //
  6946. // Purpose: This routine is called whenever an OM_OBJECT_REPLACE_IND is
  6947. // received for an object in a page workset.
  6948. //
  6949. // Returns: Error code
  6950. //
  6951. //
  6952. void WbClient::wbOnGraphicObjectReplaceInd
  6953. (
  6954. OM_WORKSET_ID worksetID,
  6955. POM_OBJECT pObj
  6956. )
  6957. {
  6958. WB_PAGE_HANDLE hPage = (WB_PAGE_HANDLE)worksetID;
  6959. BOOL bConfirm = FALSE;
  6960. DebugEntry(wbOnGraphicObjectReplaceInd);
  6961. //
  6962. // Record that the contents have changed
  6963. //
  6964. m_changed = TRUE;
  6965. TRACE_OUT(("Changed flag now TRUE"));
  6966. //
  6967. // These events are handled within the core until the client is ready.
  6968. //
  6969. if (m_state != STATE_IDLE)
  6970. {
  6971. TRACE_OUT(("Replace of graphic object before registration"));
  6972. bConfirm = TRUE;
  6973. }
  6974. //
  6975. // Check that this page is actually in use
  6976. //
  6977. if (GetPageState(hPage)->state != PAGE_IN_USE)
  6978. {
  6979. TRACE_OUT(("Replace in page that is not in use"));
  6980. bConfirm = TRUE;
  6981. }
  6982. //
  6983. // Check whether we are to pass the replace on to the client
  6984. //
  6985. if (bConfirm)
  6986. {
  6987. //
  6988. // Confirm the change to ObMan (cannot fail)
  6989. //
  6990. TRACE_OUT(("Confirming replace immediately"));
  6991. OM_ObjectReplaceConfirm(m_pomClient,
  6992. m_hWSGroup,
  6993. worksetID,
  6994. pObj);
  6995. }
  6996. else
  6997. {
  6998. //
  6999. // Inform the client of the object being added
  7000. //
  7001. TRACE_OUT(("Posting WBP_EVENT_GRAPHIC_REPLACE_IND"));
  7002. WBP_PostEvent(
  7003. 0, // No delay
  7004. WBP_EVENT_GRAPHIC_REPLACE_IND, // Event type
  7005. hPage, // Page handle
  7006. (UINT_PTR)pObj); // Object handle
  7007. }
  7008. DebugExitVOID(wbOnGraphicObjectReplaceInd);
  7009. }
  7010. //
  7011. //
  7012. // Name: wbWritePageControl
  7013. //
  7014. // Purpose: Write the page control information to the Page Control Workset
  7015. // from the copy held in client data. We write only those pages
  7016. // which are marked as being in use (and are not pending delete).
  7017. //
  7018. // Returns: Error code
  7019. //
  7020. //
  7021. UINT WbClient::wbWritePageControl(BOOL create)
  7022. {
  7023. UINT result = 0;
  7024. UINT rc;
  7025. UINT index;
  7026. UINT length;
  7027. PWB_PAGE_ORDER pPageOrderInternal = &(m_pageOrder);
  7028. PWB_PAGE_ORDER pPageOrderExternal;
  7029. WB_PAGE_HANDLE hPage;
  7030. PWB_PAGE_STATE pPageState;
  7031. POM_OBJECT pObj;
  7032. POM_OBJECTDATA pData = NULL;
  7033. UINT generation;
  7034. DebugEntry(wbWritePageControl);
  7035. //
  7036. // Allocate memory for the object.
  7037. //
  7038. length = sizeof(WB_PAGE_ORDER)
  7039. - ( (WB_MAX_PAGES - pPageOrderInternal->countPages)
  7040. * sizeof(OM_WORKSET_ID));
  7041. if (OM_ObjectAlloc(m_pomClient,
  7042. m_hWSGroup,
  7043. PAGE_CONTROL_WORKSET,
  7044. length,
  7045. &pData) != 0)
  7046. {
  7047. ERROR_OUT(("Error allocating object"));
  7048. DC_QUIT;
  7049. }
  7050. pData->length = length;
  7051. //
  7052. // Get a pointer to the page control object itself
  7053. //
  7054. pPageOrderExternal = (PWB_PAGE_ORDER) pData->data;
  7055. //
  7056. // Set the object type
  7057. //
  7058. pPageOrderExternal->objectType = TYPE_CONTROL_PAGE_ORDER;
  7059. //
  7060. // Increment the page list generation number indicating that we have
  7061. // written a new version of the page list.
  7062. //
  7063. generation = MAKELONG(pPageOrderInternal->generationLo,
  7064. pPageOrderInternal->generationHi);
  7065. generation++;
  7066. pPageOrderInternal->generationLo = LOWORD(generation);
  7067. pPageOrderInternal->generationHi = HIWORD(generation);
  7068. //
  7069. // Copy the page control data
  7070. //
  7071. pPageOrderExternal->objectType = TYPE_CONTROL_PAGE_ORDER;
  7072. pPageOrderExternal->generationLo = pPageOrderInternal->generationLo;
  7073. pPageOrderExternal->generationHi = pPageOrderInternal->generationHi;
  7074. pPageOrderExternal->countPages = 0;
  7075. //
  7076. // Loop through the internal page order finding the pages that are in
  7077. // use.
  7078. //
  7079. for (index = 0; index < pPageOrderInternal->countPages; index++)
  7080. {
  7081. //
  7082. // Get the handle of the next page
  7083. //
  7084. hPage = (pPageOrderInternal->pages)[index];
  7085. //
  7086. // Check the page state
  7087. //
  7088. pPageState = GetPageState(hPage);
  7089. if ( (pPageState->state == PAGE_IN_USE)
  7090. && (pPageState->subState == PAGE_STATE_EMPTY))
  7091. {
  7092. //
  7093. // Add the page to the external list
  7094. //
  7095. (pPageOrderExternal->pages)[pPageOrderExternal->countPages] = hPage;
  7096. pPageOrderExternal->countPages++;
  7097. }
  7098. }
  7099. //
  7100. // We expect always to copy at least one page
  7101. //
  7102. ASSERT((pPageOrderExternal->countPages >= 1));
  7103. //
  7104. // Check whether we are creating or replacing the object
  7105. //
  7106. if (create)
  7107. {
  7108. //
  7109. // Add the object to the workset (we never update these objects, so the
  7110. // update length is set to 0).
  7111. //
  7112. rc = OM_ObjectAdd(m_pomClient,
  7113. m_hWSGroup,
  7114. PAGE_CONTROL_WORKSET,
  7115. &pData,
  7116. 0,
  7117. &pObj,
  7118. LAST);
  7119. }
  7120. else
  7121. {
  7122. //
  7123. // Replace the existing object
  7124. //
  7125. TRACE_OUT(("Replacing Page Control Object"));
  7126. rc = OM_ObjectReplace(m_pomClient,
  7127. m_hWSGroup,
  7128. PAGE_CONTROL_WORKSET,
  7129. m_pObjPageControl,
  7130. &pData);
  7131. }
  7132. if (rc != 0)
  7133. {
  7134. //
  7135. // Discard the object - it was not used to replace the existing one
  7136. //
  7137. TRACE_OUT(("Adding Page Control Object"));
  7138. OM_ObjectDiscard(m_pomClient,
  7139. m_hWSGroup,
  7140. PAGE_CONTROL_WORKSET,
  7141. &pData);
  7142. ERROR_OUT(("Error adding/replacing page control object"));
  7143. DC_QUIT;
  7144. }
  7145. DC_EXIT_POINT:
  7146. DebugExitDWORD(wbWritePageControl, result);
  7147. return(result);
  7148. }
  7149. //
  7150. //
  7151. // Name: wbCreateSyncControl
  7152. //
  7153. // Purpose: Create the sync control object
  7154. //
  7155. // Returns: None
  7156. //
  7157. //
  7158. UINT WbClient::wbCreateSyncControl(void)
  7159. {
  7160. UINT result;
  7161. WB_SYNC sync;
  7162. DebugEntry(wbCreateSyncControl);
  7163. //
  7164. // Set the sync information to no page, empty rectangle
  7165. //
  7166. ZeroMemory(&sync, sizeof(WB_SYNC));
  7167. sync.length = WB_SYNC_SIZE;
  7168. sync.currentPage = WB_PAGE_HANDLE_NULL;
  7169. //
  7170. // Write the object
  7171. //
  7172. result = wbWriteSyncControl(&sync, TRUE);
  7173. DebugExitDWORD(wbCreateSyncControl, result);
  7174. return(result);
  7175. }
  7176. //
  7177. //
  7178. // Name: wbWriteSyncControl
  7179. //
  7180. // Purpose: Write the Sync Control object to the Page Control Workset
  7181. //
  7182. // Returns: Error code
  7183. //
  7184. //
  7185. UINT WbClient::wbWriteSyncControl
  7186. (
  7187. PWB_SYNC pSync,
  7188. BOOL create
  7189. )
  7190. {
  7191. UINT result = 0;
  7192. UINT rc;
  7193. POM_OBJECT pObj;
  7194. POM_OBJECTDATA pData = NULL;
  7195. PWB_SYNC_CONTROL pSyncControl;
  7196. DebugEntry(wbWriteSyncControl);
  7197. //
  7198. // Allocate memory for the object.
  7199. //
  7200. rc = OM_ObjectAlloc(m_pomClient,
  7201. m_hWSGroup,
  7202. SYNC_CONTROL_WORKSET,
  7203. WB_SYNC_CONTROL_SIZE,
  7204. &pData);
  7205. if (rc != 0)
  7206. {
  7207. ERROR_OUT(("Error allocating object"));
  7208. DC_QUIT;
  7209. }
  7210. pData->length = WB_SYNC_CONTROL_SIZE;
  7211. //
  7212. // Copy the sync control data from the client information
  7213. //
  7214. pSyncControl = (PWB_SYNC_CONTROL) pData->data;
  7215. pSyncControl->personID = m_personID;
  7216. memcpy(&(pSyncControl->sync), pSync, WB_SYNC_SIZE);
  7217. //
  7218. // Check whether we are creating or replacing the object
  7219. //
  7220. if (create)
  7221. {
  7222. //
  7223. // Add the object to the workset
  7224. //
  7225. rc = OM_ObjectAdd(m_pomClient,
  7226. m_hWSGroup,
  7227. SYNC_CONTROL_WORKSET,
  7228. &pData,
  7229. WB_SYNC_CONTROL_SIZE,
  7230. &pObj,
  7231. LAST);
  7232. //
  7233. // If successful
  7234. //
  7235. if (rc == 0)
  7236. {
  7237. //
  7238. // Save the handle of the sync control object
  7239. //
  7240. m_pObjSyncControl = pObj;
  7241. //
  7242. // Make sure we do not discard the object below
  7243. //
  7244. pData = NULL;
  7245. }
  7246. }
  7247. else
  7248. {
  7249. //
  7250. // Replace the existing object
  7251. //
  7252. rc = OM_ObjectReplace(m_pomClient,
  7253. m_hWSGroup,
  7254. SYNC_CONTROL_WORKSET,
  7255. m_pObjSyncControl,
  7256. &pData);
  7257. //
  7258. // Make sure we do not discard the object below
  7259. //
  7260. pData = NULL;
  7261. }
  7262. DC_EXIT_POINT:
  7263. //
  7264. // If we still have the Sync Control object - discard it
  7265. //
  7266. if (pData != NULL)
  7267. {
  7268. //
  7269. // Discard the object - it was not used to replace the existing one
  7270. //
  7271. OM_ObjectDiscard(m_pomClient,
  7272. m_hWSGroup,
  7273. SYNC_CONTROL_WORKSET,
  7274. &pData);
  7275. }
  7276. //
  7277. // If an error occurred during processing - report it
  7278. //
  7279. if (rc != 0)
  7280. {
  7281. ERROR_OUT(("Error adding/replacing sync control object"));
  7282. wbError();
  7283. DC_QUIT;
  7284. }
  7285. DebugExitDWORD(wbWriteSyncControl, result);
  7286. return(result);
  7287. }
  7288. //
  7289. //
  7290. // Name: wbSelectPersonColor
  7291. //
  7292. // Purpose: Select a color identifier for the local user
  7293. //
  7294. // Returns: Selected color
  7295. //
  7296. //
  7297. UINT WbClient::wbSelectPersonColor(void)
  7298. {
  7299. UINT count = 0;
  7300. UINT result;
  7301. POM_OBJECT pObjUser;
  7302. DebugEntry(wbSelectPersonColor);
  7303. //
  7304. // Select the color according to the order in the workset. See comments
  7305. // in wbCheckPersonColor for further details.
  7306. //
  7307. //
  7308. // start at the first object, search for the position of the local user's
  7309. // user object.
  7310. //
  7311. result = OM_ObjectH(m_pomClient,
  7312. m_hWSGroup,
  7313. USER_INFORMATION_WORKSET,
  7314. 0,
  7315. &pObjUser,
  7316. FIRST);
  7317. while ((result == 0) && (pObjUser != m_pObjLocal))
  7318. {
  7319. count++;
  7320. result = OM_ObjectH(m_pomClient,
  7321. m_hWSGroup,
  7322. USER_INFORMATION_WORKSET,
  7323. pObjUser,
  7324. &pObjUser,
  7325. AFTER);
  7326. }
  7327. if ((result != 0) && (result != OM_RC_NO_SUCH_OBJECT))
  7328. {
  7329. ERROR_OUT(("Unexpected return code from ObMan"));
  7330. }
  7331. DebugExitDWORD(wbSelectPersonColor, count);
  7332. return (count);
  7333. }
  7334. //
  7335. //
  7336. // Name: wbCheckPersonColor
  7337. //
  7338. // Purpose: Check whether a new user has usurped our color. If so we must
  7339. // update our own color.
  7340. //
  7341. // Returns: None
  7342. //
  7343. //
  7344. void WbClient::wbCheckPersonColor
  7345. (
  7346. POM_OBJECT hCheckObject
  7347. )
  7348. {
  7349. POM_OBJECTDATA pCheckObject = NULL;
  7350. PWB_PERSON pUser;
  7351. WB_PERSON user;
  7352. DebugEntry(wbCheckPersonColor);
  7353. //
  7354. // Read the new user information
  7355. //
  7356. if (OM_ObjectRead(m_pomClient,
  7357. m_hWSGroup,
  7358. USER_INFORMATION_WORKSET,
  7359. hCheckObject,
  7360. &pCheckObject) != 0)
  7361. {
  7362. wbError();
  7363. DC_QUIT;
  7364. }
  7365. pUser = (PWB_PERSON) pCheckObject->data;
  7366. //
  7367. // Compare the color identifier in the new user with that of the local
  7368. // user, if they are different there is nothing to do.
  7369. //
  7370. if (pUser->colorId == m_colorId)
  7371. {
  7372. TRACE_OUT(("New user has same color as local user = %d", pUser->colorId));
  7373. //
  7374. // The user color is determined by the order in the workset group of
  7375. // the user objects. The first user has color 0, the second color 1
  7376. // etc.
  7377. //
  7378. // When a user leaves the workset, however, the colors do not change.
  7379. //
  7380. // When a new user joins, it sets its color to its new position, and
  7381. // the others will then be forced to change accordingly. Whenever an
  7382. // object add or update is received where the new remote user color
  7383. // clashes with the local one, it is always the local user's job to
  7384. // change color, since the remote user has selected his new color
  7385. // according to his current position in the workset. The local user
  7386. // can't have the same position (since two users have two distinct user
  7387. // objects, so therefore must have the wrong color.
  7388. //
  7389. //
  7390. // Get the user object for the local user
  7391. //
  7392. if (wbPersonGet(m_pObjLocal, &user) != 0)
  7393. {
  7394. DC_QUIT;
  7395. }
  7396. //
  7397. // Update the color
  7398. //
  7399. TRACE_OUT(("Old color ID for local user is %d", user.colorId));
  7400. user.colorId = (TSHR_UINT16)wbSelectPersonColor();
  7401. TRACE_OUT(("New color ID for local user is %d", user.colorId));
  7402. //
  7403. // Copy the person's color into the client's data
  7404. //
  7405. m_colorId = user.colorId;
  7406. //
  7407. // Write the new user information back
  7408. //
  7409. if (wbPersonUpdate(&user) != 0)
  7410. {
  7411. DC_QUIT;
  7412. }
  7413. }
  7414. DC_EXIT_POINT:
  7415. //
  7416. // If an object has been read, release it now
  7417. //
  7418. if (pCheckObject != NULL)
  7419. {
  7420. OM_ObjectRelease(m_pomClient,
  7421. m_hWSGroup,
  7422. USER_INFORMATION_WORKSET,
  7423. hCheckObject,
  7424. &pCheckObject);
  7425. }
  7426. DebugExitVOID(wbCheckPersonColor);
  7427. }
  7428. //
  7429. //
  7430. // Name: wbWriteLock
  7431. //
  7432. // Purpose: Add a lock object to the Page Control Workset
  7433. //
  7434. // Returns: Error code
  7435. //
  7436. //
  7437. UINT WbClient::wbWriteLock(void)
  7438. {
  7439. UINT result;
  7440. POM_OBJECTDATA pData;
  7441. PWB_LOCK pLock;
  7442. POM_OBJECT pObj;
  7443. DebugEntry(wbWriteLock);
  7444. //
  7445. // Create a lock object
  7446. //
  7447. result = OM_ObjectAlloc(m_pomClient,
  7448. m_hWSGroup,
  7449. PAGE_CONTROL_WORKSET,
  7450. sizeof(WB_LOCK),
  7451. &pData);
  7452. if (result != 0)
  7453. {
  7454. ERROR_OUT(("Unable to allocate lock object = %d", result));
  7455. wbError();
  7456. DC_QUIT;
  7457. }
  7458. pData->length = sizeof(WB_LOCK);
  7459. //
  7460. // Set the lock object fields
  7461. //
  7462. pLock = (PWB_LOCK) pData->data;
  7463. pLock->objectType = TYPE_CONTROL_LOCK;
  7464. pLock->personID = m_personID;
  7465. pLock->lockType = m_lockRequestType;
  7466. //
  7467. // If we already have the lock, then we can just replace the object
  7468. //
  7469. if (m_pObjLock == NULL)
  7470. {
  7471. //
  7472. // Add the lock object to the Workset. The Add indication received
  7473. // by the remote users signals the presence of the lock to them.
  7474. //
  7475. result = OM_ObjectAdd(m_pomClient,
  7476. m_hWSGroup,
  7477. PAGE_CONTROL_WORKSET,
  7478. &pData,
  7479. sizeof(WB_LOCK),
  7480. &pObj,
  7481. LAST);
  7482. }
  7483. else
  7484. {
  7485. //
  7486. // Replace the existing object
  7487. //
  7488. result = OM_ObjectReplace(m_pomClient,
  7489. m_hWSGroup,
  7490. PAGE_CONTROL_WORKSET,
  7491. m_pObjLock,
  7492. &pData);
  7493. }
  7494. if (result != 0)
  7495. {
  7496. //
  7497. // The add or replace failed, we must discard the object
  7498. //
  7499. OM_ObjectDiscard(m_pomClient,
  7500. m_hWSGroup,
  7501. PAGE_CONTROL_WORKSET,
  7502. &pData);
  7503. ERROR_OUT(("Error adding user object"));
  7504. wbError();
  7505. DC_QUIT;
  7506. }
  7507. //
  7508. // Save the handle of the lock object
  7509. //
  7510. TRACE_OUT(("Lock handle was %x, now %x", m_pObjLock, pObj));
  7511. m_pObjLock = pObj;
  7512. DC_EXIT_POINT:
  7513. DebugExitDWORD(wbWriteLock, result);
  7514. return(result);
  7515. }
  7516. //
  7517. //
  7518. // Name: wbReadLock
  7519. //
  7520. // Purpose: Update the lock information stored in the client data after a
  7521. // change in the Lock Object.
  7522. //
  7523. // Returns: Error code
  7524. //
  7525. //
  7526. void WbClient::wbReadLock(void)
  7527. {
  7528. UINT count = 0;
  7529. DebugEntry(wbReadLock);
  7530. //
  7531. // Before we read the lock information we need to ensure that the
  7532. // PAGE_CONTROL_WORKSET and the USER_INFORMATION_WORKSET both contain
  7533. // the objects we need. If either of the objects are missing, quit and
  7534. // wait until we are called again - this function will be called
  7535. // whenever new objects are added to these worksets.
  7536. //
  7537. OM_WorksetCountObjects(m_pomClient,
  7538. m_hWSGroup,
  7539. USER_INFORMATION_WORKSET,
  7540. &count);
  7541. TRACE_OUT(("%d objects in USER_INFORMATION_WORKSET", count));
  7542. if (count == 0)
  7543. {
  7544. TRACE_OUT(("Need to wait for USER_INFO object"));
  7545. DC_QUIT;
  7546. }
  7547. OM_WorksetCountObjects(m_pomClient,
  7548. m_hWSGroup,
  7549. PAGE_CONTROL_WORKSET,
  7550. &count);
  7551. TRACE_OUT(("%d objects in PAGE_CONTROL_WORKSET", count));
  7552. if (count == 0)
  7553. {
  7554. TRACE_OUT(("Need to wait for PAGE_CONTROL object"));
  7555. DC_QUIT;
  7556. }
  7557. TRACE_OUT(("Process lock"));
  7558. wbProcessLockNotification();
  7559. DC_EXIT_POINT:
  7560. DebugExitVOID(wbReadLock);
  7561. }
  7562. //
  7563. //
  7564. // Name: wbProcessLockNotification
  7565. //
  7566. // Purpose:
  7567. //
  7568. // Returns: Error code
  7569. //
  7570. //
  7571. void WbClient::wbProcessLockNotification(void)
  7572. {
  7573. UINT rc = 0;
  7574. POM_OBJECTDATA pData;
  7575. PWB_LOCK pLock;
  7576. WB_LOCK_TYPE lockType;
  7577. POM_OBJECT pObjPersonLock;
  7578. POM_OBJECT pObj;
  7579. POM_OBJECT pObjLock;
  7580. UINT objectType = 0;
  7581. DebugEntry(wbProcessLockNotification);
  7582. //
  7583. // Get the handle of the lock object. We use the last object in the
  7584. // workset to protect against lock objects being left lying around.
  7585. //
  7586. rc = OM_ObjectH(m_pomClient,
  7587. m_hWSGroup,
  7588. PAGE_CONTROL_WORKSET,
  7589. 0,
  7590. &pObj,
  7591. LAST);
  7592. if (rc != 0)
  7593. {
  7594. ERROR_OUT(("Error getting lock object handle = %d", rc));
  7595. wbError();
  7596. DC_QUIT;
  7597. }
  7598. //
  7599. // Check that this is the CONTROL_LOCK object. Quit if it isnt - we
  7600. // will be called again later when the object arrices.
  7601. //
  7602. rc = wbGetPageObjectType(pObj, &objectType);
  7603. if (rc != 0)
  7604. {
  7605. DC_QUIT;
  7606. }
  7607. if (objectType != TYPE_CONTROL_LOCK)
  7608. {
  7609. TRACE_OUT(("not LOCK control object - quit"));
  7610. DC_QUIT;
  7611. }
  7612. //
  7613. // Save the handle of the lock object
  7614. //
  7615. pObjLock = pObj;
  7616. //
  7617. // Read the object
  7618. //
  7619. rc = OM_ObjectRead(m_pomClient,
  7620. m_hWSGroup,
  7621. PAGE_CONTROL_WORKSET,
  7622. pObj,
  7623. &pData);
  7624. if (rc != 0)
  7625. {
  7626. ERROR_OUT(("Error reading lock object %d", rc));
  7627. wbError();
  7628. DC_QUIT;
  7629. }
  7630. pLock = (PWB_LOCK) &(pData->data);
  7631. //
  7632. // Save the lock details
  7633. //
  7634. lockType = (WB_LOCK_TYPE)pLock->lockType;
  7635. TRACE_OUT(("Lock type %d", lockType));
  7636. //
  7637. // Convert the object ID held in the PAGE_CONTROL workset to an object
  7638. // handle.
  7639. //
  7640. rc = OM_ObjectIDToPtr(m_pomClient,
  7641. m_hWSGroup,
  7642. USER_INFORMATION_WORKSET,
  7643. pLock->personID,
  7644. &pObjPersonLock);
  7645. //
  7646. // The return code is checked after the object release to ensure that
  7647. // the object is not held and read again.
  7648. //
  7649. //
  7650. // Release the lock object
  7651. //
  7652. OM_ObjectRelease(m_pomClient,
  7653. m_hWSGroup,
  7654. PAGE_CONTROL_WORKSET,
  7655. pObj,
  7656. &pData);
  7657. //
  7658. // Check the return code from the ID to Handle call
  7659. //
  7660. if (rc == OM_RC_BAD_OBJECT_ID)
  7661. {
  7662. WARNING_OUT(("Unknown ID - wait for next add of user object"));
  7663. DC_QUIT;
  7664. }
  7665. else if (rc != 0)
  7666. {
  7667. ERROR_OUT(("Error (%d) converting lock user ID to handle", rc));
  7668. wbError();
  7669. DC_QUIT;
  7670. }
  7671. //
  7672. // Validate the lock state and details
  7673. //
  7674. switch (m_lockState)
  7675. {
  7676. //
  7677. // In this state we do not actually have the lock, but are waiting
  7678. // for confirmation of an earlier workset-lock request. In this
  7679. // case, we let the front end know that the lock request has failed
  7680. // before sending indication of the lock by the other user.
  7681. //
  7682. case LOCK_STATE_PENDING_LOCK:
  7683. ASSERT((pObjPersonLock != m_pObjLocal));
  7684. m_lockState = LOCK_STATE_LOCKED_OUT;
  7685. TRACE_OUT(("Moved lock state to LOCK_STATE_LOCKED_OUT"));
  7686. WBP_PostEvent(
  7687. 0, // No delay
  7688. WBP_EVENT_LOCK_FAILED, // Lock request failed
  7689. 0, // No parameters
  7690. 0);
  7691. break;
  7692. //
  7693. // In these states we do not have a lock - this must be a new lock
  7694. // from remote user or an update to an old lock.
  7695. //
  7696. case LOCK_STATE_EMPTY:
  7697. case LOCK_STATE_LOCKED_OUT:
  7698. ASSERT((pObjPersonLock != m_pObjLocal));
  7699. //
  7700. // Update the lock state to show that we are now locked out
  7701. //
  7702. m_lockState = LOCK_STATE_LOCKED_OUT;
  7703. TRACE_OUT(("Moved lock state to LOCK_STATE_LOCKED_OUT"));
  7704. break;
  7705. //
  7706. // In these states we have the lock (or are expecting to get it)
  7707. //
  7708. case LOCK_STATE_GOT_LOCK:
  7709. case LOCK_STATE_PENDING_ADD:
  7710. ASSERT((pObjPersonLock == m_pObjLocal));
  7711. //
  7712. // Update the lock state to show that we are now locked out
  7713. //
  7714. m_lockState = LOCK_STATE_GOT_LOCK;
  7715. TRACE_OUT(("Moved lock state to LOCK_STATE_GOT_LOCK"));
  7716. break;
  7717. //
  7718. // The lock request has been cancelled - unlock the WS.
  7719. //
  7720. case LOCK_STATE_CANCEL_LOCK:
  7721. break;
  7722. //
  7723. // In any other state we are not expecting any lock
  7724. //
  7725. default:
  7726. ERROR_OUT(("Not expecting lock object add"));
  7727. break;
  7728. }
  7729. //
  7730. // Save the lock details
  7731. //
  7732. TRACE_OUT(("Lock handle was %x, now %x",
  7733. m_pObjLock, pObjLock));
  7734. m_pObjLock = pObjLock;
  7735. m_lockType = lockType;
  7736. m_pObjPersonLock = pObjPersonLock;
  7737. //
  7738. // If the lock has subsequently been cancelled, unlock the WS.
  7739. //
  7740. if (m_lockState == LOCK_STATE_CANCEL_LOCK)
  7741. {
  7742. TRACE_OUT(("Cancel lock"));
  7743. m_lockState = LOCK_STATE_GOT_LOCK;
  7744. wbUnlock();
  7745. }
  7746. else
  7747. {
  7748. //
  7749. // Inform the client of the lock. The notification will be trapped
  7750. // by the core if the client is not fully registered.
  7751. //
  7752. wbSendLockNotification();
  7753. }
  7754. DC_EXIT_POINT:
  7755. DebugExitVOID(wbProcessLockNotification);
  7756. }
  7757. //
  7758. //
  7759. // Name: wbSendLockNotification
  7760. //
  7761. // Purpose: Post a lock notification to the client. The lock information
  7762. // held in the client memory must be up to date when this function
  7763. // is called.
  7764. //
  7765. // Returns: Error code
  7766. //
  7767. //
  7768. void WbClient::wbSendLockNotification(void)
  7769. {
  7770. UINT result = 0;
  7771. UINT lockEvent;
  7772. DebugEntry(wbSendLockNotification);
  7773. //
  7774. // Check that we are in a valid state for sending a lock notification
  7775. //
  7776. if ( (m_lockState == LOCK_STATE_GOT_LOCK)
  7777. || (m_lockState == LOCK_STATE_LOCKED_OUT)
  7778. || (m_lockState == LOCK_STATE_EMPTY))
  7779. {
  7780. //
  7781. // Verify the lock type
  7782. //
  7783. switch (m_lockType)
  7784. {
  7785. case WB_LOCK_TYPE_CONTENTS:
  7786. TRACE_OUT(("Posting WBP_EVENT_CONTENTS_LOCKED"));
  7787. lockEvent = WBP_EVENT_CONTENTS_LOCKED;
  7788. break;
  7789. case WB_LOCK_TYPE_PAGE_ORDER:
  7790. TRACE_OUT(("Posting WBP_EVENT_PAGE_ORDER_LOCKED"));
  7791. lockEvent = WBP_EVENT_PAGE_ORDER_LOCKED;
  7792. break;
  7793. case WB_LOCK_TYPE_NONE:
  7794. TRACE_OUT(("Posting WBP_EVENT_UNLOCKED"));
  7795. lockEvent = WBP_EVENT_UNLOCKED;
  7796. break;
  7797. default:
  7798. ERROR_OUT(("Bad lock type %d", (UINT) m_lockType));
  7799. DC_QUIT;
  7800. }
  7801. //
  7802. // Tell the client that the lock has been acquired or released
  7803. //
  7804. WBP_PostEvent(
  7805. 0,
  7806. lockEvent,
  7807. 0,
  7808. (UINT_PTR)m_pObjPersonLock);
  7809. TRACE_OUT(("Sent lock notification"));
  7810. }
  7811. DC_EXIT_POINT:
  7812. DebugExitVOID(wbSendLockNotification);
  7813. }
  7814. //
  7815. //
  7816. // Name: wbOnWBPLock
  7817. //
  7818. // Purpose: Process a successful lock acquisitoin
  7819. //
  7820. // Returns: Error code
  7821. //
  7822. //
  7823. BOOL WbClient::wbOnWBPLock(void)
  7824. {
  7825. BOOL processed = TRUE;
  7826. DebugEntry(wbOnWBPLock);
  7827. //
  7828. // If we are registering and have just acquired the lock - we can now
  7829. // continue the registration process.
  7830. //
  7831. //
  7832. // Test the current state
  7833. //
  7834. switch (m_state)
  7835. {
  7836. //
  7837. // We are waiting for registration to continue
  7838. //
  7839. case STATE_REGISTERING:
  7840. //
  7841. // Act on the registration substate
  7842. //
  7843. if (m_subState == STATE_REG_PENDING_LOCK)
  7844. {
  7845. //
  7846. // Check that it is us who now has the lock
  7847. //
  7848. if (m_lockState != LOCK_STATE_GOT_LOCK)
  7849. {
  7850. TRACE_OUT(("It is not us who has the lock"));
  7851. //
  7852. // Another client has acquired the lock - we must wait for them
  7853. // to add the Page Control Object.
  7854. //
  7855. m_subState = STATE_REG_PENDING_PAGE_CONTROL;
  7856. TRACE_OUT(("Moved to substate STATE_REG_PENDING_PAGE_CONTROL"));
  7857. DC_QUIT;
  7858. }
  7859. //
  7860. // We now have the Page Control Workset locked - check for the
  7861. // existence of the Page Control and Sync Control objects. (We
  7862. // have to do this because another client could have locked the
  7863. // workset, added the objects and unlocked the workset just before
  7864. // we requested the lock. The Page Control Object may not have
  7865. // reached us before we requested the lock. Now that we have the
  7866. // lock we are guaranteed to have all objects in the workset so the
  7867. // object add events may have arrived just before the lock
  7868. // confirmation.
  7869. //
  7870. if ( (m_pObjPageControl != 0)
  7871. && (m_pObjSyncControl != 0))
  7872. {
  7873. //
  7874. // Unlock the workset
  7875. //
  7876. wbUnlock();
  7877. //
  7878. // Wait for the unlock to complete
  7879. //
  7880. m_subState = STATE_REG_PENDING_UNLOCK;
  7881. TRACE_OUT(("Moved to substate STATE_REG_PENDING_UNLOCK"));
  7882. DC_QUIT;
  7883. }
  7884. //
  7885. // We are the first in the call - we must add the Page Control
  7886. // Object. (It is possible that another client added the Page
  7887. // Control object and then failed. To cover this we check
  7888. // separately for the Page Control and Sync objects.)
  7889. //
  7890. if (m_pObjPageControl == 0)
  7891. {
  7892. //
  7893. // Add a single page to the page control object using the first
  7894. // page workset (which we always open).
  7895. //
  7896. wbPagesPageAdd(0, FIRST_PAGE_WORKSET,
  7897. PAGE_FIRST);
  7898. //
  7899. // Write the Page Control information
  7900. //
  7901. if (wbWritePageControl(TRUE) != 0)
  7902. {
  7903. ERROR_OUT(("Error adding Page Control Object"));
  7904. wbError();
  7905. DC_QUIT;
  7906. }
  7907. //
  7908. // Update the state to "waiting for Page Control"
  7909. //
  7910. m_subState = STATE_REG_PENDING_PAGE_CONTROL;
  7911. TRACE_OUT(("Moved to substate STATE_REG_PENDING_PAGE_CONTROL"));
  7912. DC_QUIT;
  7913. }
  7914. //
  7915. // The Page Control object is there, so the Sync Control object
  7916. // must not be (we checked above for both being there and would
  7917. // have exited by now if they were).
  7918. //
  7919. ASSERT((m_pObjSyncControl == 0));
  7920. //
  7921. // Create the Sync Control Object.
  7922. //
  7923. if (wbCreateSyncControl() != 0)
  7924. {
  7925. ERROR_OUT(("Error adding Sync Control Object"));
  7926. wbError();
  7927. DC_QUIT;
  7928. }
  7929. //
  7930. // Wait for the Sync Control object to be added
  7931. //
  7932. m_subState = STATE_REG_PENDING_SYNC_CONTROL;
  7933. TRACE_OUT(("Moved substate to STATE_REG_PENDING_SYNC_CONTROL"));
  7934. DC_QUIT;
  7935. }
  7936. break;
  7937. case STATE_IDLE:
  7938. //
  7939. // We are fully registered. The event must be passed on to the
  7940. // front-end
  7941. //
  7942. processed = FALSE;
  7943. break;
  7944. //
  7945. // We are in an unknown state
  7946. //
  7947. default:
  7948. ERROR_OUT(("Bad client major state"));
  7949. break;
  7950. }
  7951. DC_EXIT_POINT:
  7952. DebugExitBOOL(wbOnWBPLock, processed);
  7953. return(processed);
  7954. }
  7955. //
  7956. //
  7957. // Name: wbOnWBPLockFailed
  7958. //
  7959. // Purpose: Process a failed lock acquisition
  7960. //
  7961. // Returns: Error code
  7962. //
  7963. //
  7964. BOOL WbClient::wbOnWBPLockFailed(void)
  7965. {
  7966. BOOL processed = TRUE;
  7967. DebugEntry(wbOnWBPLockFailed);
  7968. //
  7969. // Check the current state
  7970. //
  7971. switch (m_state)
  7972. {
  7973. case STATE_REGISTERING:
  7974. //
  7975. // If we are registering and have just failed to acquire the lock -
  7976. // this is because another user has the lock. If both the page and
  7977. // sync objects have been added, finish registration, otherwise wait
  7978. // for them to be added.
  7979. //
  7980. if ( (m_pObjPageControl != 0) &&
  7981. (m_pObjSyncControl != 0))
  7982. {
  7983. TRACE_OUT(("Page Control and Sync Control objects both there."));
  7984. TRACE_OUT(("Registration can be completed"));
  7985. wbOnControlWorksetsReady();
  7986. DC_QUIT;
  7987. }
  7988. if (m_pObjPageControl == 0)
  7989. {
  7990. TRACE_OUT(("Waiting for page control"));
  7991. m_subState = STATE_REG_PENDING_PAGE_CONTROL;
  7992. DC_QUIT;
  7993. }
  7994. if (m_pObjSyncControl == 0)
  7995. {
  7996. TRACE_OUT(("Waiting for sync control"));
  7997. m_subState = STATE_REG_PENDING_SYNC_CONTROL;
  7998. DC_QUIT;
  7999. }
  8000. break;
  8001. case STATE_IDLE:
  8002. //
  8003. // We are fully registered. The event must be passed on to the
  8004. // front-end
  8005. //
  8006. processed = FALSE;
  8007. break;
  8008. default:
  8009. ERROR_OUT(("Bad main state"));
  8010. break;
  8011. }
  8012. DC_EXIT_POINT:
  8013. DebugExitBOOL(wbOnWBPLockFailed, processed);
  8014. return(processed);
  8015. }
  8016. //
  8017. //
  8018. // Name: wbOnWBPUnlocked
  8019. //
  8020. // Purpose: Process an unlock notification
  8021. //
  8022. // Returns: Error code
  8023. //
  8024. //
  8025. BOOL WbClient::wbOnWBPUnlocked(void)
  8026. {
  8027. BOOL processed = TRUE;
  8028. DebugEntry(wbOnWBPUnlocked);
  8029. //
  8030. // If we are registering and waiting to unlock the Page Control Workset
  8031. // we must complete registration here.
  8032. //
  8033. //
  8034. // Check the current state
  8035. //
  8036. switch (m_state)
  8037. {
  8038. case STATE_REGISTERING:
  8039. //
  8040. // Check whether we are expecting his event
  8041. //
  8042. if(m_subState == STATE_REG_PENDING_UNLOCK)
  8043. {
  8044. //
  8045. // Continue the registration process
  8046. //
  8047. wbOnControlWorksetsReady();
  8048. DC_QUIT;
  8049. }
  8050. //
  8051. // We were not expecting the unlock event
  8052. //
  8053. WARNING_OUT(("Unexpected unlock event"));
  8054. break;
  8055. case STATE_IDLE:
  8056. //
  8057. // We are fully registered. The event must be passed on to the
  8058. // front-end
  8059. //
  8060. processed = FALSE;
  8061. break;
  8062. default:
  8063. ERROR_OUT(("Bad main state"));
  8064. break;
  8065. } // Switch on client state
  8066. DC_EXIT_POINT:
  8067. DebugExitBOOL(wbOnWBPUnlocked, processed);
  8068. return(processed);
  8069. }
  8070. //
  8071. //
  8072. // Name: wbOnWBPPageOrderUpdated
  8073. //
  8074. // Purpose: Process a page order updated notification
  8075. //
  8076. // Returns: Error code
  8077. //
  8078. //
  8079. BOOL WbClient::wbOnWBPPageOrderUpdated(void)
  8080. {
  8081. BOOL processed = FALSE;
  8082. DebugEntry(wbOnWBPPageOrderUpdated);
  8083. //
  8084. // If we are registering and waiting for the Page Order to be brought
  8085. // up-to-date we can now continue registration.
  8086. //
  8087. if (m_state == STATE_REGISTERING)
  8088. {
  8089. //
  8090. // Show that we have processed the event (we do not want to pass it on
  8091. // to the client, they are not yet fully registered and will not be
  8092. // expecting it).
  8093. //
  8094. processed = TRUE;
  8095. //
  8096. // If we have enough pages ready in the cache, we have completed
  8097. // registration. (Otherwise the call to CheckReadyPages will open
  8098. // another page and will complete registration later.)
  8099. //
  8100. if (wbCheckReadyPages())
  8101. {
  8102. wbCompleteRegistration();
  8103. DC_QUIT;
  8104. }
  8105. //
  8106. // We must wait for sufficiently many pages to be ready
  8107. //
  8108. m_subState = STATE_REG_PENDING_READY_PAGES;
  8109. TRACE_OUT(("Moved substate to STATE_REG_PENDING_READY_PAGES"));
  8110. }
  8111. DC_EXIT_POINT:
  8112. DebugExitBOOL(wbOnWBPPageOrderUpdated, processed);
  8113. return(processed);
  8114. }
  8115. //
  8116. //
  8117. // Name: wbPersonGet
  8118. //
  8119. // Purpose: Get user details
  8120. //
  8121. // Returns: Error code
  8122. //
  8123. //
  8124. UINT WbClient::wbPersonGet
  8125. (
  8126. POM_OBJECT pObjUser,
  8127. PWB_PERSON pUser
  8128. )
  8129. {
  8130. UINT result = 0;
  8131. POM_OBJECTDATA pUserObject;
  8132. DebugEntry(wbPersonGet);
  8133. if (pObjUser == m_pObjLocal)
  8134. {
  8135. TRACE_OUT(("Call is for local user details"));
  8136. }
  8137. //
  8138. // Read the object.
  8139. //
  8140. result = OM_ObjectRead(m_pomClient,
  8141. m_hWSGroup,
  8142. USER_INFORMATION_WORKSET,
  8143. pObjUser,
  8144. &pUserObject);
  8145. if (result != 0)
  8146. {
  8147. ERROR_OUT(("OM_ObjectRead = %d", result));
  8148. DC_QUIT;
  8149. }
  8150. //
  8151. // Copy the read user object into the buffer passed
  8152. //
  8153. memcpy(pUser, pUserObject->data, sizeof(WB_PERSON));
  8154. TRACE_OUT(("CMG personID %u", pUser->cmgPersonID));
  8155. //
  8156. // Release the object
  8157. //
  8158. OM_ObjectRelease(m_pomClient,
  8159. m_hWSGroup,
  8160. USER_INFORMATION_WORKSET,
  8161. pObjUser,
  8162. &pUserObject);
  8163. //
  8164. // If the call is for the local user, update the color field to ensure it
  8165. // doesn't get overwritten in a race condition with the front-end (i.e.
  8166. // the front end tries to update the user before the color-change event
  8167. // has been received). The core "knows better" than ObMan what the local
  8168. // user's color is. This is safe because the color field is only ever
  8169. // changed locally.
  8170. //
  8171. if (pObjUser == m_pObjLocal)
  8172. {
  8173. pUser->colorId = (TSHR_UINT16)m_colorId;
  8174. }
  8175. DC_EXIT_POINT:
  8176. DebugExitDWORD(wbPersonGet, result);
  8177. return(result);
  8178. }
  8179. //
  8180. //
  8181. // Name: wbPersonUpdate
  8182. //
  8183. // Purpose: Update the local user object - this is only used by the CORE -
  8184. // the front-end calls WBP_SetPersonData, which does a _replace_.
  8185. //
  8186. // Returns: Error code
  8187. //
  8188. //
  8189. UINT WbClient::wbPersonUpdate(PWB_PERSON pUser)
  8190. {
  8191. UINT result = 0;
  8192. POM_OBJECTDATA pUserObject;
  8193. DebugEntry(wbPersonUpdate);
  8194. //
  8195. // Allocate a user object
  8196. //
  8197. result = OM_ObjectAlloc(m_pomClient,
  8198. m_hWSGroup,
  8199. USER_INFORMATION_WORKSET,
  8200. sizeof(WB_PERSON),
  8201. &pUserObject);
  8202. if (result != 0)
  8203. {
  8204. ERROR_OUT(("OM_ObjectAlloc = %d", result));
  8205. DC_QUIT;
  8206. }
  8207. //
  8208. // Set the length of the object
  8209. //
  8210. pUserObject->length = WB_PERSON_OBJECT_UPDATE_SIZE,
  8211. //
  8212. // Copy the user information into the ObMan object
  8213. //
  8214. memcpy(pUserObject->data, pUser, sizeof(WB_PERSON));
  8215. //
  8216. // Update the object
  8217. //
  8218. result = OM_ObjectUpdate(m_pomClient,
  8219. m_hWSGroup,
  8220. USER_INFORMATION_WORKSET,
  8221. m_pObjLocal,
  8222. &pUserObject);
  8223. if (result != 0)
  8224. {
  8225. ERROR_OUT(("OM_ObjectUpdate = %d", result));
  8226. //
  8227. // Discard the object
  8228. //
  8229. OM_ObjectDiscard(m_pomClient,
  8230. m_hWSGroup,
  8231. USER_INFORMATION_WORKSET,
  8232. &pUserObject);
  8233. DC_QUIT;
  8234. }
  8235. //
  8236. // Note that the object has not yet been updated. An
  8237. // OM_OBJECT_UPDATE_IND event will be generated.
  8238. //
  8239. DC_EXIT_POINT:
  8240. DebugExitDWORD(wbPersonUpdate, result);
  8241. return(result);
  8242. }
  8243. //
  8244. //
  8245. // Name: wbGetNetUserID().
  8246. //
  8247. // Purpose: Get the network user ID for this client
  8248. //
  8249. // Returns:
  8250. //
  8251. //
  8252. BOOL WbClient::wbGetNetUserID(void)
  8253. {
  8254. BOOL result = TRUE;
  8255. UINT rc = 0;
  8256. DebugEntry(wbGetNetUserID);
  8257. rc = OM_GetNetworkUserID(m_pomClient,
  8258. m_hWSGroup,
  8259. &m_clientNetID);
  8260. if (rc != 0)
  8261. {
  8262. if (rc == OM_RC_LOCAL_WSGROUP)
  8263. {
  8264. m_clientNetID = 0;
  8265. }
  8266. else
  8267. {
  8268. result = FALSE;
  8269. }
  8270. }
  8271. DebugExitBOOL(wbGetNetUserID, result);
  8272. return(result);
  8273. }