Source code of Windows XP (NT5)
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.

9787 lines
231 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. }
  2338. //
  2339. // Save the new page handle in the list
  2340. //
  2341. pPage[index] = hPage;
  2342. //
  2343. // Show that the extra page is now present
  2344. //
  2345. pPageOrder->countPages += 1;
  2346. DebugExitVOID(wbPageOrderPageAdd);
  2347. }
  2348. //
  2349. //
  2350. // Name: wbPageOrderPageDelete
  2351. //
  2352. // Purpose: Remove the specified page from a page order structure. This
  2353. // function expects its the parameters to be valid - they must be
  2354. // checked before calling it.
  2355. //
  2356. // Returns: None
  2357. //
  2358. //
  2359. void WbClient::wbPageOrderPageDelete
  2360. (
  2361. PWB_PAGE_ORDER pPageOrder,
  2362. WB_PAGE_HANDLE hPage
  2363. )
  2364. {
  2365. UINT index;
  2366. POM_WORKSET_ID pPage = pPageOrder->pages;
  2367. DebugEntry(wbPageOrderPageDelete);
  2368. index = wbPageOrderPageNumber(pPageOrder, hPage);
  2369. UT_MoveMemory(&pPage[index - 1],
  2370. &pPage[index],
  2371. (pPageOrder->countPages - index)*sizeof(pPage[0]));
  2372. pPageOrder->countPages -= 1;
  2373. DebugExitVOID(wbPageOrderPageDelete);
  2374. }
  2375. //
  2376. //
  2377. // Name: wbPagesPageAdd
  2378. //
  2379. // Purpose: Add a new page to the internal page list. This function expects
  2380. // the parameters to be valid - they must be checked before
  2381. // calling it. It also assumes that there is space in the page
  2382. // list for the new page.
  2383. //
  2384. // Returns: None
  2385. //
  2386. //
  2387. void WbClient::wbPagesPageAdd
  2388. (
  2389. WB_PAGE_HANDLE hRefPage,
  2390. WB_PAGE_HANDLE hPage,
  2391. UINT where
  2392. )
  2393. {
  2394. PWB_PAGE_STATE pPageState;
  2395. DebugEntry(wbPagesPageAdd);
  2396. //
  2397. // Add the page to the page order structure
  2398. //
  2399. wbPageOrderPageAdd(&(m_pageOrder), hRefPage, hPage, where);
  2400. //
  2401. // Update the page state information
  2402. //
  2403. pPageState = GetPageState(hPage);
  2404. pPageState->state = PAGE_IN_USE;
  2405. pPageState->subState = PAGE_STATE_EMPTY;
  2406. DebugExitVOID(wbPagesPageAdd);
  2407. }
  2408. //
  2409. //
  2410. // Name: wbClientReset
  2411. //
  2412. // Purpose: Reset the client data to a state where the client is not in a
  2413. // call, but is registered with ObMan and has event and exit
  2414. // handlers registered with utilities.
  2415. //
  2416. // Returns: None
  2417. //
  2418. //
  2419. void WbClient::wbClientReset(void)
  2420. {
  2421. UINT index;
  2422. PWB_PAGE_ORDER pPageOrder = &(m_pageOrder);
  2423. PWB_PAGE_STATE pPageState = m_pageStates;
  2424. DebugEntry(wbClientReset);
  2425. //
  2426. // Initialize object handles
  2427. //
  2428. m_hWSGroup = (OM_WSGROUP_HANDLE) NULL;
  2429. m_pObjPageControl = NULL;
  2430. m_pObjSyncControl = NULL;
  2431. m_pObjLocal = NULL;
  2432. m_pObjLock = NULL;
  2433. m_pObjPersonLock = NULL;
  2434. //
  2435. // Initialize the status variables
  2436. //
  2437. m_errorState = ERROR_STATE_EMPTY;
  2438. m_changed = FALSE;
  2439. m_lockState = LOCK_STATE_EMPTY;
  2440. m_lockType = WB_LOCK_TYPE_NONE;
  2441. m_lockRequestType = WB_LOCK_TYPE_NONE;
  2442. m_loadState = LOAD_STATE_EMPTY;
  2443. if (m_hLoadFile != INVALID_HANDLE_VALUE)
  2444. {
  2445. CloseHandle(m_hLoadFile);
  2446. m_hLoadFile = INVALID_HANDLE_VALUE;
  2447. }
  2448. m_countReadyPages = 0;
  2449. //
  2450. // Zero the whole structure
  2451. //
  2452. ZeroMemory(pPageOrder, sizeof(*pPageOrder));
  2453. //
  2454. // Set the object type
  2455. //
  2456. pPageOrder->objectType = TYPE_CONTROL_PAGE_ORDER;
  2457. //
  2458. // Set up the page control elements
  2459. //
  2460. pPageOrder->generationLo = 1;
  2461. pPageOrder->generationHi = 0;
  2462. pPageOrder->countPages = 0;
  2463. //
  2464. // Initialize the page state structures
  2465. //
  2466. for (index = 0; index < WB_MAX_PAGES; index++, pPageState++)
  2467. {
  2468. pPageState->state = PAGE_NOT_IN_USE;
  2469. pPageState->subState = PAGE_STATE_EMPTY;
  2470. }
  2471. DebugExitVOID(wbClientReset);
  2472. }
  2473. //
  2474. //
  2475. // Name: wbOnWsGroupRegisterCon
  2476. //
  2477. // Purpose: Routine processing OM_WSGROUP_REGISTER_CON events.
  2478. //
  2479. // Returns: Error code
  2480. //
  2481. //
  2482. BOOL WbClient::wbOnWsGroupRegisterCon
  2483. (
  2484. UINT_PTR param1,
  2485. UINT_PTR param2
  2486. )
  2487. {
  2488. POM_EVENT_DATA16 pEvent16 = (POM_EVENT_DATA16) &param1;
  2489. POM_EVENT_DATA32 pEvent32 = (POM_EVENT_DATA32) &param2;
  2490. BOOL processed;
  2491. DebugEntry(wbOnWsGroupRegisterCon);
  2492. //
  2493. // Check that this is the event we are expecting
  2494. //
  2495. if (pEvent32->correlator != m_wsgroupCorrelator)
  2496. {
  2497. //
  2498. // We are not expecting this event, this means that it must be for a
  2499. // workset group which we wanted to deregister from (but had not yet
  2500. // received confirmation). So deregister immediately.
  2501. //
  2502. //
  2503. // Check that the return code for the registration is OK
  2504. //
  2505. if (pEvent32->result == 0)
  2506. {
  2507. OM_WSGroupDeregister(m_pomClient, &(pEvent16->hWSGroup));
  2508. }
  2509. processed = FALSE;
  2510. DC_QUIT;
  2511. }
  2512. //
  2513. // Show that we have processed the event
  2514. //
  2515. processed = TRUE;
  2516. //
  2517. // Test for the correct state
  2518. //
  2519. if (m_subState != STATE_REG_PENDING_WSGROUP_CON)
  2520. {
  2521. //
  2522. // We are not in the correct state for this event - this is an internal
  2523. // error.
  2524. //
  2525. ERROR_OUT(("Not in correct state for WSGroupRegisterCon"));
  2526. DC_QUIT;
  2527. }
  2528. //
  2529. // Check that the return code for the registration is OK
  2530. //
  2531. if (pEvent32->result != 0)
  2532. {
  2533. //
  2534. // Registration with the workset group failed - tidy up
  2535. //
  2536. wbError();
  2537. DC_QUIT;
  2538. }
  2539. //
  2540. // Registration with the workset group succeeded
  2541. //
  2542. m_hWSGroup = pEvent16->hWSGroup;
  2543. //
  2544. // Get the clients network ID, used in graphic objects to determine where
  2545. // they are loaded.
  2546. //
  2547. if (!wbGetNetUserID())
  2548. {
  2549. //
  2550. // Tidy up (and post an error event to the client)
  2551. //
  2552. ERROR_OUT(("Failed to get user ID"));
  2553. wbError();
  2554. DC_QUIT;
  2555. }
  2556. //
  2557. // Start opening the worksets. We open them one at a time and wait for
  2558. // the response to avoid flooding the message queue.
  2559. // The user information workset is given high priority. This allows
  2560. // remote pointer movements to travel quickly.
  2561. //
  2562. if (OM_WorksetOpenPReq(m_pomClient,
  2563. m_hWSGroup,
  2564. USER_INFORMATION_WORKSET,
  2565. NET_HIGH_PRIORITY,
  2566. TRUE,
  2567. &(m_worksetOpenCorrelator)) != 0)
  2568. {
  2569. ERROR_OUT(("User Information Workset Open Failed"));
  2570. wbError();
  2571. DC_QUIT;
  2572. }
  2573. //
  2574. // Move to the next state
  2575. //
  2576. m_subState = STATE_REG_PENDING_USER_WORKSET;
  2577. DC_EXIT_POINT:
  2578. DebugExitBOOL(wbOnWsGroupRegisterCon, processed);
  2579. return(processed);
  2580. }
  2581. //
  2582. //
  2583. // Name: wbOnWorksetOpenCon
  2584. //
  2585. // Purpose: Routine processing OM_WORKSET_OPEN_CON events.
  2586. //
  2587. // Returns: Error code
  2588. //
  2589. //
  2590. BOOL WbClient::wbOnWorksetOpenCon
  2591. (
  2592. UINT_PTR param1,
  2593. UINT_PTR param2
  2594. )
  2595. {
  2596. POM_EVENT_DATA16 pEvent16 = (POM_EVENT_DATA16) &param1;
  2597. POM_EVENT_DATA32 pEvent32 = (POM_EVENT_DATA32) &param2;
  2598. BOOL processed = FALSE;
  2599. OM_WORKSET_ID eventWorksetID;
  2600. DebugEntry(wbOnWorksetOpenCon);
  2601. //
  2602. // Process according to the workset ID
  2603. //
  2604. eventWorksetID = pEvent16->worksetID;
  2605. //
  2606. // If the event is for a page workset
  2607. //
  2608. if (eventWorksetID >= FIRST_PAGE_WORKSET)
  2609. {
  2610. //
  2611. // We are opening a page workset
  2612. //
  2613. processed = wbOnPageWorksetOpenCon(param1, param2);
  2614. if (!processed)
  2615. {
  2616. DC_QUIT;
  2617. }
  2618. }
  2619. //
  2620. // We are done if this is a page workset other than the 1st page workset
  2621. //
  2622. if (eventWorksetID > FIRST_PAGE_WORKSET)
  2623. {
  2624. DC_QUIT;
  2625. }
  2626. //
  2627. // Now check if it is one of the control worksets (the first page workset
  2628. // is both a control workset and a page workset).
  2629. //
  2630. if (eventWorksetID != FIRST_PAGE_WORKSET)
  2631. {
  2632. //
  2633. // Check the message correlator
  2634. //
  2635. if (pEvent32->correlator != m_worksetOpenCorrelator)
  2636. {
  2637. TRACE_OUT(("Correlators do not match - quitting"));
  2638. DC_QUIT;
  2639. }
  2640. }
  2641. //
  2642. // We are opening a control workset - process the event
  2643. //
  2644. wbOnControlWorksetOpenCon(param1, param2);
  2645. processed = TRUE;
  2646. DC_EXIT_POINT:
  2647. DebugExitBOOL(wbOnWorksetOpenCon, processed);
  2648. return(processed);
  2649. }
  2650. //
  2651. //
  2652. // Name: wbOnControlWorksetOpenCon
  2653. //
  2654. // Purpose: Routine processing OM_WORKSET_OPEN_CON events for control
  2655. // worksets.
  2656. //
  2657. // Returns: Error code
  2658. //
  2659. //
  2660. void WbClient::wbOnControlWorksetOpenCon
  2661. (
  2662. UINT_PTR param1,
  2663. UINT_PTR param2
  2664. )
  2665. {
  2666. POM_EVENT_DATA16 pEvent16 = (POM_EVENT_DATA16) &param1;
  2667. POM_EVENT_DATA32 pEvent32 = (POM_EVENT_DATA32) &param2;
  2668. UINT rc;
  2669. OM_WORKSET_ID eventId;
  2670. DebugEntry(wbOnControlWorksetOpenCon);
  2671. //
  2672. // Check the return code in the open
  2673. //
  2674. if (pEvent32->result != 0)
  2675. {
  2676. ERROR_OUT(("Error reported on workset open = %d", pEvent32->result));
  2677. wbError();
  2678. DC_QUIT;
  2679. }
  2680. //
  2681. // If we are in registration, we are opening the required worksets -
  2682. // continue the process.
  2683. //
  2684. if (m_state > STATE_REGISTERING)
  2685. {
  2686. ERROR_OUT(("Control workset open con after registration"));
  2687. }
  2688. //
  2689. // Set up for opening the next workset
  2690. //
  2691. eventId = pEvent16->worksetID;
  2692. switch(eventId)
  2693. {
  2694. case USER_INFORMATION_WORKSET:
  2695. //
  2696. // The user information workset is given high priority. This allows
  2697. // remote pointer movements to travel quickly.
  2698. //
  2699. TRACE_OUT(("Opening Page Control workset"));
  2700. rc = OM_WorksetOpenPReq(m_pomClient,
  2701. m_hWSGroup,
  2702. PAGE_CONTROL_WORKSET,
  2703. NET_HIGH_PRIORITY,
  2704. FALSE,
  2705. &(m_worksetOpenCorrelator));
  2706. m_subState = STATE_REG_PENDING_WORKSET_OPEN;
  2707. break;
  2708. case PAGE_CONTROL_WORKSET:
  2709. //
  2710. // The sync control workset is given high priority to allow sync
  2711. // updates to travel quickly.
  2712. //
  2713. TRACE_OUT(("Opening Sync Control workset"));
  2714. rc = OM_WorksetOpenPReq(m_pomClient,
  2715. m_hWSGroup,
  2716. SYNC_CONTROL_WORKSET,
  2717. NET_HIGH_PRIORITY,
  2718. FALSE,
  2719. &(m_worksetOpenCorrelator));
  2720. break;
  2721. case SYNC_CONTROL_WORKSET:
  2722. //
  2723. // Open the first of the page worksets - we must do this to allow us
  2724. // to use it as the only page available if we are the first person in
  2725. // the call.
  2726. //
  2727. TRACE_OUT(("Opening first page workset"));
  2728. rc = wbPageWorksetOpen((WB_PAGE_HANDLE)FIRST_PAGE_WORKSET,
  2729. OPEN_LOCAL);
  2730. break;
  2731. case FIRST_PAGE_WORKSET:
  2732. break;
  2733. default:
  2734. ERROR_OUT(("Bad workset ID"));
  2735. break;
  2736. }
  2737. //
  2738. // Check whether we have just opened another workset
  2739. //
  2740. if (eventId != FIRST_PAGE_WORKSET)
  2741. {
  2742. //
  2743. // Test the return code from the open
  2744. //
  2745. if (rc != 0)
  2746. {
  2747. ERROR_OUT(("Workset open failed = %d", rc));
  2748. wbError();
  2749. }
  2750. DC_QUIT;
  2751. }
  2752. //
  2753. // We have now opened all the control worksets. We now add the required
  2754. // control objects.
  2755. //
  2756. rc = wbAddLocalUserObject();
  2757. if (rc != 0)
  2758. {
  2759. //
  2760. // Stop the join call process, tidy up and send an error message to the
  2761. // client.
  2762. //
  2763. wbError();
  2764. DC_QUIT;
  2765. }
  2766. m_subState = STATE_REG_USER_OBJECT_ADDED;
  2767. TRACE_OUT(("Moved to substate STATE_REG_USER_OBJECT_ADDED"));
  2768. //
  2769. // Check whether the Page Control objects are available yet (they could
  2770. // have been added by another user in the call).
  2771. //
  2772. TRACE_OUT(("%x PAGE WS object, %x SYNC WS object",
  2773. m_pObjPageControl,
  2774. m_pObjSyncControl));
  2775. if ( (m_pObjPageControl == 0) &&
  2776. (m_pObjSyncControl == 0))
  2777. {
  2778. TRACE_OUT(("No control objects - WE MIGHT BE FIRST IN CALL - get lock"));
  2779. //
  2780. // We may be the first user to register - request the lock on the Page
  2781. // Control Workset.
  2782. //
  2783. rc = wbLock(WB_LOCK_TYPE_PAGE_ORDER);
  2784. if (rc != 0)
  2785. {
  2786. ERROR_OUT(("Error from wbLock = %d", rc));
  2787. wbError();
  2788. DC_QUIT;
  2789. }
  2790. //
  2791. // Set the new registration state
  2792. //
  2793. m_subState = STATE_REG_PENDING_LOCK;
  2794. TRACE_OUT(("Moved to substate STATE_REG_PENDING_LOCK"));
  2795. DC_QUIT;
  2796. }
  2797. else
  2798. {
  2799. if (m_pObjSyncControl == 0)
  2800. {
  2801. TRACE_OUT(("Waiting for sync control"));
  2802. m_subState = STATE_REG_PENDING_SYNC_CONTROL;
  2803. DC_QUIT;
  2804. }
  2805. if (m_pObjPageControl == 0)
  2806. {
  2807. TRACE_OUT(("Waiting for page control"));
  2808. m_subState = STATE_REG_PENDING_PAGE_CONTROL;
  2809. DC_QUIT;
  2810. }
  2811. }
  2812. //
  2813. // Complete registration
  2814. //
  2815. TRACE_OUT(("Page Control and Sync Control objects both there."));
  2816. TRACE_OUT(("Registration can be completed"));
  2817. wbOnControlWorksetsReady();
  2818. DC_EXIT_POINT:
  2819. DebugExitVOID(wbOnControlWorksetOpenCon);
  2820. }
  2821. //
  2822. //
  2823. // Name: wbPageWorksetOpen
  2824. //
  2825. // Purpose: Open a page workset
  2826. //
  2827. // Returns: Error code
  2828. //
  2829. //
  2830. UINT WbClient::wbPageWorksetOpen
  2831. (
  2832. WB_PAGE_HANDLE hPage,
  2833. UINT localOrExternal
  2834. )
  2835. {
  2836. UINT result;
  2837. PWB_PAGE_STATE pPageState;
  2838. DebugEntry(wbPageWorksetOpen);
  2839. //
  2840. // Get the page state
  2841. //
  2842. pPageState = GetPageState(hPage);
  2843. ASSERT((pPageState->state == PAGE_NOT_IN_USE));
  2844. ASSERT((pPageState->subState == PAGE_STATE_EMPTY));
  2845. //
  2846. // Open the workset. We allow ObMan to choose the priority, this means
  2847. // that ObMan uses a variable priority scheme allowing small objects to
  2848. // overtake large ones.
  2849. //
  2850. result = OM_WorksetOpenPReq(m_pomClient,
  2851. m_hWSGroup,
  2852. (OM_WORKSET_ID)hPage,
  2853. OM_OBMAN_CHOOSES_PRIORITY,
  2854. FALSE,
  2855. &(pPageState->worksetOpenCorrelator));
  2856. if (result != 0)
  2857. {
  2858. ERROR_OUT(("WorksetOpen failed = %d", result));
  2859. DC_QUIT;
  2860. }
  2861. //
  2862. // Update the page state
  2863. //
  2864. if (localOrExternal == OPEN_LOCAL)
  2865. {
  2866. pPageState->subState = PAGE_STATE_LOCAL_OPEN_CONFIRM;
  2867. TRACE_OUT(("Moved page %d state to PAGE_STATE_PENDING_OPEN_CONFIRM",
  2868. (UINT) hPage));
  2869. }
  2870. else
  2871. {
  2872. pPageState->subState = PAGE_STATE_EXTERNAL_OPEN_CONFIRM;
  2873. TRACE_OUT(("Moved page %d state to PAGE_STATE_PENDING_OPEN_CONFIRM",
  2874. (UINT) hPage));
  2875. }
  2876. DC_EXIT_POINT:
  2877. DebugExitDWORD(wbPageWorksetOpen, result);
  2878. return(result);
  2879. }
  2880. //
  2881. //
  2882. // Name: wbOnPageWorksetOpenCon
  2883. //
  2884. // Purpose: Routine processing OM_WORKSET_OPEN_CON events for page worksets
  2885. //
  2886. // Returns: Error code
  2887. //
  2888. //
  2889. BOOL WbClient::wbOnPageWorksetOpenCon
  2890. (
  2891. UINT_PTR param1,
  2892. UINT_PTR param2
  2893. )
  2894. {
  2895. POM_EVENT_DATA16 pEvent16 = (POM_EVENT_DATA16) &param1;
  2896. POM_EVENT_DATA32 pEvent32 = (POM_EVENT_DATA32) &param2;
  2897. BOOL processed = FALSE;
  2898. OM_WORKSET_ID eventId;
  2899. PWB_PAGE_STATE pPageState;
  2900. WB_PAGE_HANDLE hPage;
  2901. UINT oldState;
  2902. DebugEntry(wbOnPageWorksetOpenCon);
  2903. //
  2904. // Get the page state pointer
  2905. //
  2906. eventId = pEvent16->worksetID;
  2907. hPage = (WB_PAGE_HANDLE)eventId;
  2908. pPageState = GetPageState(hPage);
  2909. //
  2910. // Check the message correlator
  2911. //
  2912. if (pEvent32->correlator != pPageState->worksetOpenCorrelator)
  2913. {
  2914. TRACE_OUT(("Correlators do not match - quitting"));
  2915. DC_QUIT;
  2916. }
  2917. //
  2918. // Show that we have processed this event
  2919. //
  2920. processed = TRUE;
  2921. //
  2922. // Check the return code in the open
  2923. //
  2924. if (pEvent32->result != 0)
  2925. {
  2926. ERROR_OUT(("Error reported on page workset open = %d",
  2927. pEvent32->result));
  2928. pPageState->subState = PAGE_STATE_EMPTY;
  2929. TRACE_OUT(("Moved page %d substate to PAGE_STATE_EMPTY",
  2930. (UINT)hPage));
  2931. DC_QUIT;
  2932. }
  2933. //
  2934. // Update the page state to indicate that the page is now ready for use
  2935. //
  2936. oldState = pPageState->subState;
  2937. pPageState->subState = PAGE_STATE_READY;
  2938. TRACE_OUT(("Moved page %d to substate to PAGE_STATE_READY",
  2939. (UINT)hPage));
  2940. switch (oldState)
  2941. {
  2942. case PAGE_STATE_LOCAL_OPEN_CONFIRM:
  2943. //
  2944. // This workset was opened locally, therefore it is being opened as
  2945. // part of the workset cache. Nothing more to do.
  2946. //
  2947. break;
  2948. case PAGE_STATE_EXTERNAL_OPEN_CONFIRM:
  2949. //
  2950. // This workset was opened as a result of external updates to the
  2951. // Page Control object. We therefore need to add the page to the
  2952. // page list now that the workset is open. We no longer know where
  2953. // the page is to be added - so call the main Page Control update
  2954. // routine again to get all the information.
  2955. //
  2956. wbProcessPageControlChanges();
  2957. break;
  2958. default:
  2959. ERROR_OUT(("Bad page state %d", pPageState->subState));
  2960. break;
  2961. }
  2962. //
  2963. // Increment the number of pages in ready state. This count is never
  2964. // decremented - once a workset is open it stays open.
  2965. //
  2966. m_countReadyPages += 1;
  2967. //
  2968. // If we are in registration and are waiting for the cache of ready
  2969. // pages, we must complete registration now.
  2970. //
  2971. if ( (m_state == STATE_REGISTERING) &&
  2972. (m_subState == STATE_REG_PENDING_READY_PAGES) )
  2973. {
  2974. //
  2975. // If there are enough pages in the cache
  2976. //
  2977. if (wbCheckReadyPages())
  2978. {
  2979. //
  2980. // We have enough ready pages - complete registration
  2981. //
  2982. wbCompleteRegistration();
  2983. DC_QUIT;
  2984. }
  2985. //
  2986. // There are not yet enough pages in the cache. CheckReadyPages will
  2987. // have made a new workset open request, so we will receive another
  2988. // workset open confirm soon.
  2989. //
  2990. DC_QUIT;
  2991. }
  2992. DC_EXIT_POINT:
  2993. DebugExitBOOL(wbOnPageWorksetOpenCon, processed);
  2994. return(processed);
  2995. }
  2996. //
  2997. //
  2998. // Name: wbOnWorksetLockCon
  2999. //
  3000. // Purpose: Routine processing OM_WORKSET_LOCK_CON events.
  3001. //
  3002. // Returns: Error code
  3003. //
  3004. //
  3005. BOOL WbClient::wbOnWorksetLockCon
  3006. (
  3007. UINT_PTR param1,
  3008. UINT_PTR param2
  3009. )
  3010. {
  3011. POM_EVENT_DATA16 pEvent16 = (POM_EVENT_DATA16) &param1;
  3012. POM_EVENT_DATA32 pEvent32 = (POM_EVENT_DATA32) &param2;
  3013. BOOL processed = FALSE;
  3014. UINT rc;
  3015. DebugEntry(wbOnWorksetLockCon);
  3016. //
  3017. // Check the message correlator
  3018. //
  3019. if (pEvent32->correlator != m_lockCorrelator)
  3020. {
  3021. DC_QUIT;
  3022. }
  3023. //
  3024. // The message is for us - set the result to "processed"
  3025. //
  3026. processed = TRUE;
  3027. //
  3028. // Check that the event is for the Page Control Workset (this is the
  3029. // only expected workset).
  3030. //
  3031. if (pEvent16->worksetID != PAGE_CONTROL_WORKSET)
  3032. {
  3033. ERROR_OUT(("Unexpected workset in LockCon = %d",
  3034. pEvent16->worksetID));
  3035. }
  3036. //
  3037. // Process according to the current lock state
  3038. //
  3039. switch (m_lockState)
  3040. {
  3041. //
  3042. // We were waiting for lock confirmation
  3043. //
  3044. case LOCK_STATE_PENDING_LOCK:
  3045. //
  3046. // Check the return code in the event
  3047. //
  3048. if (pEvent32->result != 0)
  3049. {
  3050. TRACE_OUT(("Posting WBP_EVENT_LOCK_FAILED, rc %d",
  3051. pEvent32->result));
  3052. WBP_PostEvent(0, // No delay
  3053. WBP_EVENT_LOCK_FAILED, // Lock request failed
  3054. 0, // No parameters
  3055. 0);
  3056. //
  3057. // The lock failed - update the state. This means that
  3058. // another user has acquired the lock. We expect to get a
  3059. // lock object add indication soon.
  3060. //
  3061. m_lockState = LOCK_STATE_EMPTY;
  3062. TRACE_OUT(("Lock request failed - lock state is now EMPTY"));
  3063. DC_QUIT;
  3064. }
  3065. //
  3066. // Write the lock details to the Page Control Workset
  3067. //
  3068. rc = wbWriteLock();
  3069. if (rc != 0)
  3070. {
  3071. ERROR_OUT(("Unable to write lock details = %d", rc));
  3072. //
  3073. // Tidy up by unlocking the Page Control Workset
  3074. //
  3075. OM_WorksetUnlock(m_pomClient,
  3076. m_hWSGroup,
  3077. PAGE_CONTROL_WORKSET);
  3078. //
  3079. // Tell the client of the failure
  3080. //
  3081. TRACE_OUT(("Posting WBP_EVENT_LOCK_FAILED"));
  3082. WBP_PostEvent(0, // No delay
  3083. WBP_EVENT_LOCK_FAILED, // Lock request failed
  3084. 0, // No parameters
  3085. 0);
  3086. //
  3087. // Update the lock state
  3088. //
  3089. m_lockState = LOCK_STATE_EMPTY;
  3090. TRACE_OUT(("Moved lock state to LOCK_STATE_EMPTY"));
  3091. DC_QUIT;
  3092. }
  3093. //
  3094. // Once we get here the write of the lock object above will
  3095. // trigger an object add event that completes the lock
  3096. // processing.
  3097. //
  3098. m_lockState = LOCK_STATE_PENDING_ADD;
  3099. TRACE_OUT(("Moved lock state to LOCK_STATE_PENDING_ADD"));
  3100. break;
  3101. //
  3102. // The application has cancelled the lock request before it has had
  3103. // time to complete - tidy up.
  3104. //
  3105. case LOCK_STATE_CANCEL_LOCK:
  3106. TRACE_OUT(("LOCK_STATE_CANCEL_LOCK"));
  3107. //
  3108. // If the request failed, just reset the state.
  3109. //
  3110. //
  3111. // The lock was cancelled - unlock the workset if necessary,
  3112. // and notify the front-end of the unlock.
  3113. //
  3114. if (pEvent32->result == 0)
  3115. {
  3116. //
  3117. // We have locked the workset successfully, but in the
  3118. // meantime the front-end has cancelled the lock, so unlock
  3119. // the workset now.
  3120. //
  3121. TRACE_OUT((
  3122. "Lock cancelled before workset locked, so unlock now"));
  3123. OM_WorksetUnlock(m_pomClient,
  3124. m_hWSGroup,
  3125. PAGE_CONTROL_WORKSET);
  3126. }
  3127. m_lockState = LOCK_STATE_EMPTY;
  3128. //
  3129. // Tell the app that we have cancelled the lock.
  3130. //
  3131. TRACE_OUT(("Posting WBP_EVENT_UNLOCKED"));
  3132. WBP_PostEvent(0,
  3133. WBP_EVENT_UNLOCKED,
  3134. 0,
  3135. 0);
  3136. break;
  3137. //
  3138. // Another has got in before us
  3139. //
  3140. case LOCK_STATE_LOCKED_OUT:
  3141. //
  3142. // We have received a lock confirmation and should have been
  3143. // expecting the lock. But we are locked out. This means that
  3144. // another user has got in just before us, acquired the lock
  3145. // and added the lock object. We have processed the add and
  3146. // changed the lock state accordingly. This lock confirmation
  3147. // will therefore normally be a failure. If by some fluke it
  3148. // isn't, then we treat it as a failure for safety.
  3149. //
  3150. if (pEvent32->result == 0)
  3151. {
  3152. ERROR_OUT(("Lock violation"));
  3153. //
  3154. // Tidy up by unlocking the Page Control Workset - leave
  3155. // the state as LOCKED_OUT; we'll clear it on receipt of
  3156. // the unlock (either local, or from the locking user).
  3157. //
  3158. OM_WorksetUnlock(m_pomClient,
  3159. m_hWSGroup,
  3160. PAGE_CONTROL_WORKSET);
  3161. }
  3162. break;
  3163. default:
  3164. ERROR_OUT(("Bad lock state %d", m_lockState));
  3165. break;
  3166. } // Switch on lock state
  3167. DC_EXIT_POINT:
  3168. DebugExitBOOL(wbOnWorksetLockCon, processed);
  3169. return(processed);
  3170. }
  3171. //
  3172. //
  3173. // Name: wbOnWorksetUnlockInd
  3174. //
  3175. // Purpose: Routine processing OM_WORKSET_UNLOCK_IND events.
  3176. //
  3177. // Returns: Error code
  3178. //
  3179. //
  3180. BOOL WbClient::wbOnWorksetUnlockInd
  3181. (
  3182. UINT_PTR param1,
  3183. UINT_PTR param2
  3184. )
  3185. {
  3186. POM_EVENT_DATA16 pEvent16 = (POM_EVENT_DATA16) &param1;
  3187. POM_EVENT_DATA32 pEvent32 = (POM_EVENT_DATA32) &param2;
  3188. BOOL processed = TRUE;
  3189. DebugEntry(wbOnWorksetUnlockInd);
  3190. //
  3191. // We are only interested if the workset id is that of the Page Control
  3192. // Workset.
  3193. //
  3194. if (pEvent16->worksetID != PAGE_CONTROL_WORKSET)
  3195. {
  3196. TRACE_OUT(("Unexpected workset in unlock = %d", pEvent16->worksetID));
  3197. DC_QUIT;
  3198. }
  3199. switch (m_lockState)
  3200. {
  3201. //
  3202. // We had the lock and are waiting to unlock or another user had
  3203. // the lock and has now removed it.
  3204. //
  3205. case LOCK_STATE_LOCKED_OUT:
  3206. //
  3207. // We received the unlock of the workset before the removal of
  3208. // the lock object; we just ignore this, since the deletion of
  3209. // the lock object is our indication that the wb lock is removed.
  3210. //
  3211. TRACE_OUT(("Unlock of page control workset while locked out"));
  3212. break;
  3213. //
  3214. // We are unlocking after an error acquiring the lock or after a
  3215. // user has cancelled alock before we had time to complete it.
  3216. //
  3217. case LOCK_STATE_CANCEL_LOCK:
  3218. //
  3219. // An error occurred in getting the lock - the client has
  3220. // already been informed so we just record the state change.
  3221. //
  3222. m_lockState = LOCK_STATE_EMPTY;
  3223. TRACE_OUT(("Moved lock state to LOCK_STATE_EMPTY"));
  3224. break;
  3225. //
  3226. // We are waiting for the lock - but have got an unlock instead.
  3227. // This could be from another user, or from previous aborted
  3228. // attempts by us to get the lock. We ignore the event and wait
  3229. // for our lock confirmation.
  3230. //
  3231. case LOCK_STATE_PENDING_LOCK:
  3232. TRACE_OUT((
  3233. "Got unlock indication while waiting for lock confirmation"));
  3234. break;
  3235. //
  3236. // We can get an unlock indication without ever having seen the
  3237. // lock object if the lock object was never added (failure at
  3238. // another user) or if ObMan has spoiled the add and delete.
  3239. //
  3240. case LOCK_STATE_EMPTY:
  3241. TRACE_OUT(("Unlock received in LOCK_STATE_EMPTY - ignoring"));
  3242. break;
  3243. //
  3244. // Unlock not expected in this state
  3245. //
  3246. default:
  3247. ERROR_OUT(("Bad lock state %d", m_lockState));
  3248. break;
  3249. }
  3250. DC_EXIT_POINT:
  3251. DebugExitBOOL(wbOnWorksetUnlockInd, processed);
  3252. return(processed);
  3253. }
  3254. //
  3255. //
  3256. // Name: wbOnControlWorksetsReady
  3257. //
  3258. // Purpose: The control worksets have been opened and set up. Continue the
  3259. // registration process by updating the internal page order to
  3260. // ensure that in matches the external order.
  3261. //
  3262. // Returns: Error code
  3263. //
  3264. //
  3265. void WbClient::wbOnControlWorksetsReady(void)
  3266. {
  3267. DebugEntry(wbOnControlWorksetsReady);
  3268. //
  3269. // Read the Page Control object and compare its content to the internal
  3270. // Page Order.
  3271. //
  3272. wbProcessPageControlChanges();
  3273. //
  3274. // Update the state to show that we are waiting for the Page Order
  3275. // Updated event indicating that the internal page order now matches
  3276. // the external order.
  3277. //
  3278. m_subState = STATE_REG_PENDING_PAGE_ORDER;
  3279. TRACE_OUT(("Moved sub state to STATE_REG_PENDING_PAGE_ORDER"));
  3280. DebugExitVOID(wbOnControlWorksetsReady);
  3281. }
  3282. //
  3283. //
  3284. // Name: wbCompleteRegistration
  3285. //
  3286. // Purpose: Perform the final steps in registering a client. These are:
  3287. // post a WB_EVENT_REGISTERED event to the client; check if
  3288. // another user has a lock on the contents or page order, if so,
  3289. // post a WB_EVENT_CONTENTS_LOCKED or WB_EVENT_PAGE_ORDER_LOCKED
  3290. // to the client.
  3291. //
  3292. // Returns: Error code
  3293. //
  3294. //
  3295. void WbClient::wbCompleteRegistration(void)
  3296. {
  3297. DebugEntry(wbCompleteRegistration);
  3298. //
  3299. // Inform the client that we are fully registered
  3300. //
  3301. TRACE_OUT(("Posting WBP_EVENT_REGISTER_OK"));
  3302. WBP_PostEvent(0, // No delay
  3303. WBP_EVENT_JOIN_CALL_OK, // Fully registered
  3304. 0, // No parameters
  3305. 0);
  3306. //
  3307. // Notify the client of the lock status
  3308. //
  3309. wbSendLockNotification();
  3310. //
  3311. // Record that we are now fully registered
  3312. //
  3313. m_state = STATE_IDLE;
  3314. m_subState = STATE_EMPTY;
  3315. TRACE_OUT(("Moved to state STATE_IDLE"));
  3316. DebugExitVOID(wbCompleteRegistration);
  3317. }
  3318. //
  3319. //
  3320. // Name: wbLeaveCall
  3321. //
  3322. // Purpose: Remove a client from a call/workset group
  3323. //
  3324. // Returns: None
  3325. //
  3326. //
  3327. void WbClient::wbLeaveCall(void)
  3328. {
  3329. DebugEntry(wbLeaveCall);
  3330. //
  3331. // If we have not got far enough to have entered a call - leave now
  3332. // (there is nothing to tidy up).
  3333. //
  3334. if (m_state < STATE_REGISTERING)
  3335. {
  3336. DC_QUIT;
  3337. }
  3338. //
  3339. // If we have the lock - delete the lock object (the workset will be
  3340. // unlocked by ObMan when we deregister).
  3341. //
  3342. if (m_lockState == LOCK_STATE_GOT_LOCK)
  3343. {
  3344. TRACE_OUT(("Still got lock - deleting lock object, handle %d",
  3345. m_pObjLock));
  3346. if (OM_ObjectDelete(m_pomClient,
  3347. m_hWSGroup,
  3348. PAGE_CONTROL_WORKSET,
  3349. m_pObjLock) != 0)
  3350. {
  3351. ERROR_OUT(("Error deleting lock object"));
  3352. }
  3353. //
  3354. // If all is well at this point the unlock process will be
  3355. // completed when the object delete ind is received.
  3356. //
  3357. m_lockState = LOCK_STATE_PENDING_DELETE;
  3358. TRACE_OUT(("Moved to state LOCK_STATE_PENDING_DELETE"));
  3359. }
  3360. //
  3361. // Fix up the sub state to indicate that all registration actions have
  3362. // been completed (to ensure that they are all undone).
  3363. //
  3364. if (m_state > STATE_REGISTERING)
  3365. {
  3366. m_subState = STATE_REG_END;
  3367. TRACE_OUT(("Moved to substate STATE_REG_END"));
  3368. }
  3369. //
  3370. // Delete the user object representing the local user from the User
  3371. // Information Workset (if it is present). Note that we are about to
  3372. // deregister from ObMan - this acts as automatic confirmation of the
  3373. // delete request so we do not need to wait for the
  3374. // OM_OBJECT_DELETE_IND event.
  3375. //
  3376. if (m_subState >= STATE_REG_USER_OBJECT_ADDED)
  3377. {
  3378. TRACE_OUT(("Deleting user object"));
  3379. if (OM_ObjectDelete(m_pomClient,
  3380. m_hWSGroup,
  3381. USER_INFORMATION_WORKSET,
  3382. m_pObjLocal) != 0)
  3383. {
  3384. //
  3385. // Trace the error but do not quit - we expect everything to be
  3386. // tidied up when we deregister from ObMan.
  3387. //
  3388. ERROR_OUT(("Error deleting local user object"));
  3389. }
  3390. }
  3391. //
  3392. // If we have already registered with the Workset Group, deregister
  3393. // now. we have not yet received the confirmation, and get it later we
  3394. // will deregister immediately.
  3395. //
  3396. if (m_subState > STATE_REG_PENDING_WSGROUP_CON)
  3397. {
  3398. OM_WSGroupDeregister(m_pomClient, &(m_hWSGroup));
  3399. }
  3400. else
  3401. {
  3402. //
  3403. // We have not yet received the Workset Group Registration
  3404. // confirmation, change the value in the correlator field so that
  3405. // we recognize the fact that we have cancelled registration later.
  3406. //
  3407. m_wsgroupCorrelator--;
  3408. }
  3409. //
  3410. // Reset the handles of objects added during registration
  3411. //
  3412. TRACE_OUT(("Resetting client data"));
  3413. wbClientReset();
  3414. //
  3415. // Set the client state to the appropriate value
  3416. //
  3417. m_state = STATE_STARTED;
  3418. m_subState = STATE_STARTED_START;
  3419. TRACE_OUT(("Moved state to STATE_STARTED"));
  3420. DC_EXIT_POINT:
  3421. DebugExitVOID(wbLeaveCall);
  3422. }
  3423. //
  3424. //
  3425. // Name: wbContentsDelete
  3426. //
  3427. // Purpose: Remove all the current graphics and pages, leaving a single
  3428. // blank page.
  3429. //
  3430. // Returns: None
  3431. //
  3432. //
  3433. void WbClient::wbContentsDelete
  3434. (
  3435. UINT changedFlagAction
  3436. )
  3437. {
  3438. PWB_PAGE_ORDER pPageOrder = &(m_pageOrder);
  3439. PWB_PAGE_STATE pPageState;
  3440. UINT index;
  3441. DebugEntry(wbContentsDelete);
  3442. //
  3443. // Just clear the first page in the list
  3444. //
  3445. wbPageClear(pPageOrder->pages[0], changedFlagAction);
  3446. //
  3447. // If there is only one page left in the list - we're done.
  3448. //
  3449. if (pPageOrder->countPages == 1)
  3450. {
  3451. DC_QUIT;
  3452. }
  3453. //
  3454. // There is more than one page
  3455. //
  3456. //
  3457. // Mark all of the active pages (except the first) as "delete pending"
  3458. //
  3459. for (index = 1; index < pPageOrder->countPages; index++)
  3460. {
  3461. pPageState = GetPageState((pPageOrder->pages)[index]);
  3462. if ((pPageState->state == PAGE_IN_USE) &&
  3463. (pPageState->subState == PAGE_STATE_EMPTY))
  3464. {
  3465. pPageState->subState = PAGE_STATE_LOCAL_DELETE;
  3466. }
  3467. }
  3468. //
  3469. // Write the page control information. The replace event generated by
  3470. // the write will kick off the actual deletion of the pages marked.
  3471. //
  3472. wbWritePageControl(FALSE);
  3473. DC_EXIT_POINT:
  3474. DebugExitVOID(wbContentsDelete);
  3475. }
  3476. //
  3477. //
  3478. // Name: wbStartContentsLoad
  3479. //
  3480. // Purpose: Start the loading of a file (after the contents have been
  3481. // cleared).
  3482. //
  3483. // Returns: Error code
  3484. //
  3485. //
  3486. void WbClient::wbStartContentsLoad(void)
  3487. {
  3488. DebugEntry(wbStartContentsLoad);
  3489. //
  3490. // Specify the first (and only) page handle as the page to load to
  3491. //
  3492. wbPageHandleFromNumber(1, &m_loadPageHandle);
  3493. //
  3494. // Update the load state to show that we are now loading
  3495. //
  3496. m_loadState = LOAD_STATE_LOADING;
  3497. TRACE_OUT(("Moved load state to LOAD_STATE_LOADING"));
  3498. //
  3499. // Load the first page - subsequent pages are chained from this first one
  3500. //
  3501. wbPageLoad();
  3502. DebugExitVOID(wbStartContentsLoad);
  3503. }
  3504. //
  3505. //
  3506. // Name: wbLock
  3507. //
  3508. // Purpose: Request the lock for the Whiteboard contents or the page order
  3509. // generating one of the following events:
  3510. //
  3511. // WB_EVENT_CONTENTS_LOCKED
  3512. // WB_EVENT_CONTENTS_LOCK_FAILED.
  3513. //
  3514. // Returns: Error code
  3515. //
  3516. //
  3517. UINT WbClient::wbLock(WB_LOCK_TYPE lockType)
  3518. {
  3519. UINT result = 0;
  3520. OM_CORRELATOR correlator;
  3521. DebugEntry(wbLock);
  3522. //
  3523. // If we already have the lock we can merely change its status
  3524. //
  3525. if (m_lockState == LOCK_STATE_GOT_LOCK)
  3526. {
  3527. TRACE_OUT(("Already got the lock"));
  3528. m_lockRequestType = lockType;
  3529. result = wbWriteLock();
  3530. DC_QUIT;
  3531. }
  3532. //
  3533. // Request the lock for the Page Control Workset
  3534. //
  3535. result = OM_WorksetLockReq(m_pomClient,
  3536. m_hWSGroup,
  3537. PAGE_CONTROL_WORKSET,
  3538. &correlator);
  3539. if (result != 0)
  3540. {
  3541. ERROR_OUT(("OM_WorksetLockReq failed, result = %d", result));
  3542. DC_QUIT;
  3543. }
  3544. TRACE_OUT(("Requested lock for the Page Control Workset"));
  3545. //
  3546. // Save the lock details
  3547. //
  3548. m_lockState = LOCK_STATE_PENDING_LOCK;
  3549. m_lockCorrelator = correlator;
  3550. m_lockRequestType = lockType;
  3551. TRACE_OUT(("Moved lock state to LOCK_STATE_PENDING_LOCK"));
  3552. TRACE_OUT(("Lock type requested = %d", lockType));
  3553. //
  3554. // We return now, further processing is done when the OM_WORKSET_LOCK_CON
  3555. // event is received.
  3556. //
  3557. DC_EXIT_POINT:
  3558. DebugExitDWORD(wbLock, result);
  3559. return(result);
  3560. }
  3561. //
  3562. //
  3563. // Name: wbUnlock
  3564. //
  3565. // Purpose: Unlock the Contents or Page Order.
  3566. //
  3567. // Returns: Error code
  3568. //
  3569. //
  3570. void WbClient::wbUnlock(void)
  3571. {
  3572. DebugEntry(wbUnlock);
  3573. //
  3574. // Check that we have the lock
  3575. //
  3576. if (m_lockState != LOCK_STATE_GOT_LOCK)
  3577. {
  3578. ERROR_OUT(("Local person doesn't have lock"));
  3579. DC_QUIT;
  3580. }
  3581. //
  3582. // Delete the lock object
  3583. //
  3584. TRACE_OUT(("Delete Lock handle %x", m_pObjLock));
  3585. if (OM_ObjectDelete(m_pomClient,
  3586. m_hWSGroup,
  3587. PAGE_CONTROL_WORKSET,
  3588. m_pObjLock) != 0)
  3589. {
  3590. ERROR_OUT(("Could not delete lock object"));
  3591. DC_QUIT;
  3592. }
  3593. //
  3594. // If all is well at this point the unlock process will be completed when
  3595. // the object delete ind is received.
  3596. //
  3597. m_lockState = LOCK_STATE_PENDING_DELETE;
  3598. TRACE_OUT(("Moved to state LOCK_STATE_PENDING_DELETE"));
  3599. DC_EXIT_POINT:
  3600. DebugExitVOID(wbUnlock);
  3601. }
  3602. //
  3603. //
  3604. // Name: wbObjectSave
  3605. //
  3606. // Purpose: Save a structure to file
  3607. //
  3608. // Returns: Error code
  3609. //
  3610. //
  3611. UINT WbClient::wbObjectSave
  3612. (
  3613. HANDLE hFile,
  3614. LPBYTE pData,
  3615. UINT length
  3616. )
  3617. {
  3618. UINT result = 0;
  3619. ULONG cbSizeWritten;
  3620. DebugEntry(wbObjectSave);
  3621. //
  3622. // Save the length
  3623. //
  3624. if (! WriteFile(hFile, (void *) &length, sizeof(length), &cbSizeWritten, NULL))
  3625. {
  3626. result = WB_RC_WRITE_FAILED;
  3627. ERROR_OUT(("Error writing length to file, win32 err=%d", GetLastError()));
  3628. DC_QUIT;
  3629. }
  3630. ASSERT(cbSizeWritten == sizeof(length));
  3631. //
  3632. // Save the object data
  3633. //
  3634. if (! WriteFile(hFile, pData, length, &cbSizeWritten, NULL))
  3635. {
  3636. result = WB_RC_WRITE_FAILED;
  3637. ERROR_OUT(("Error writing data to file, win32 err=%d", GetLastError()));
  3638. DC_QUIT;
  3639. }
  3640. ASSERT(cbSizeWritten == length);
  3641. DC_EXIT_POINT:
  3642. DebugExitDWORD(wbObjectSave, result);
  3643. return result;
  3644. }
  3645. //
  3646. //
  3647. // Name: wbPageSave
  3648. //
  3649. // Purpose: Save the contents of a single page to file.
  3650. //
  3651. // Returns: Error code
  3652. //
  3653. //
  3654. UINT WbClient::wbPageSave
  3655. (
  3656. WB_PAGE_HANDLE hPage,
  3657. HANDLE hFile
  3658. )
  3659. {
  3660. UINT result = 0;
  3661. UINT rc;
  3662. OM_WORKSET_ID worksetID = (OM_WORKSET_ID)hPage;
  3663. POM_OBJECT pObj;
  3664. POM_OBJECTDATA pData;
  3665. WB_END_OF_PAGE endOfPage;
  3666. DebugEntry(wbPageSave);
  3667. //
  3668. // Get the first object
  3669. //
  3670. result = OM_ObjectH(m_pomClient,
  3671. m_hWSGroup,
  3672. worksetID,
  3673. 0,
  3674. &pObj,
  3675. FIRST);
  3676. if (result == OM_RC_NO_SUCH_OBJECT)
  3677. {
  3678. // This can happen on an empty page, not an error
  3679. TRACE_OUT(("No objects left, quitting with good return"));
  3680. result = 0;
  3681. DC_QUIT;
  3682. }
  3683. if (result != 0)
  3684. {
  3685. ERROR_OUT(("Error getting first object in page"));
  3686. DC_QUIT;
  3687. }
  3688. //
  3689. // Loop through the objects
  3690. //
  3691. for( ; ; )
  3692. {
  3693. //
  3694. // Get a pointer to the object
  3695. //
  3696. result = OM_ObjectRead(m_pomClient,
  3697. m_hWSGroup,
  3698. worksetID,
  3699. pObj,
  3700. &pData);
  3701. if (result != 0)
  3702. {
  3703. ERROR_OUT(("Error reading object = %d", result));
  3704. DC_QUIT;
  3705. }
  3706. //
  3707. // Save the object data
  3708. //
  3709. rc = wbObjectSave(hFile,
  3710. (LPBYTE) pData->data,
  3711. pData->length);
  3712. //
  3713. // The return code is tested after we have released the object because
  3714. // we must always do the release.
  3715. //
  3716. //
  3717. // Release the object
  3718. //
  3719. OM_ObjectRelease(m_pomClient,
  3720. m_hWSGroup,
  3721. worksetID,
  3722. pObj,
  3723. &pData);
  3724. //
  3725. // Now test the write return code
  3726. //
  3727. if (rc != 0)
  3728. {
  3729. result = rc;
  3730. ERROR_OUT(("Error writing object data = %d", result));
  3731. DC_QUIT;
  3732. }
  3733. //
  3734. // Get the next object
  3735. //
  3736. result = OM_ObjectH(m_pomClient,
  3737. m_hWSGroup,
  3738. worksetID,
  3739. pObj,
  3740. &pObj,
  3741. AFTER);
  3742. if (result == OM_RC_NO_SUCH_OBJECT)
  3743. {
  3744. TRACE_OUT(("No objects left, quitting with good return"));
  3745. result = 0;
  3746. DC_QUIT;
  3747. }
  3748. }
  3749. DC_EXIT_POINT:
  3750. //
  3751. // If we have successfully written the page contents, we write an end-of-
  3752. // page marker to the file.
  3753. //
  3754. if (result == 0)
  3755. {
  3756. //
  3757. // Set the end of page object details
  3758. //
  3759. ZeroMemory(&endOfPage, sizeof(endOfPage));
  3760. endOfPage.length = sizeof(endOfPage);
  3761. endOfPage.type = TYPE_END_OF_PAGE;
  3762. //
  3763. // Write the end-of-page object
  3764. //
  3765. result = wbObjectSave(hFile,
  3766. (LPBYTE) &endOfPage,
  3767. sizeof(endOfPage));
  3768. if (result != 0)
  3769. {
  3770. ERROR_OUT(("Error writing end-of-page = %d", result));
  3771. }
  3772. }
  3773. DebugExitDWORD(wbPageSave, result);
  3774. return(result);
  3775. }
  3776. //
  3777. //
  3778. // Name: wbPageLoad
  3779. //
  3780. // Purpose: Load the contents of a single page from file.
  3781. //
  3782. // Returns: Error code
  3783. //
  3784. //
  3785. void WbClient::wbPageLoad(void)
  3786. {
  3787. UINT result = 0;
  3788. UINT type;
  3789. POM_OBJECT pObj;
  3790. POM_OBJECTDATA pData = NULL;
  3791. PWB_GRAPHIC pGraphic = NULL;
  3792. WB_PAGE_HANDLE hPage = m_loadPageHandle;
  3793. WB_PAGE_HANDLE hNewPage;
  3794. UINT postDelay = 0;
  3795. DebugEntry(wbPageLoad);
  3796. TRACE_OUT(("Entered wbPageLoad for page %d", (UINT) hPage));
  3797. //
  3798. // Check the load state - if we're not loading, then quit (can happen if
  3799. // the load is cancelled).
  3800. //
  3801. if (m_loadState == LOAD_STATE_EMPTY)
  3802. {
  3803. TRACE_OUT(("Load has been cancelled - abandoning page load"));
  3804. DC_QUIT;
  3805. }
  3806. //
  3807. // Check that we have a full complement of ready pages before starting
  3808. // the load.
  3809. //
  3810. if (!wbCheckReadyPages())
  3811. {
  3812. //
  3813. // There are not enough pages worksets ready to be used. We exit now
  3814. // to allow the page to be made ready before we continue. We set up a
  3815. // delay on the message that will be used to restart the process to
  3816. // allow the worksets to be opened before we get back in here.
  3817. //
  3818. postDelay = 200;
  3819. DC_QUIT;
  3820. }
  3821. //
  3822. // If we are waiting to add a new page, get the handle of the page we
  3823. // expect to add next here. (We have to do this as ObMan requires that
  3824. // we allocate memory for the object in the correct workset, but we do
  3825. // not want to actually add the page here because we may not need it.)
  3826. //
  3827. if (m_loadState == LOAD_STATE_PENDING_NEW_PAGE)
  3828. {
  3829. hNewPage = wbGetReadyPageHandle();
  3830. //
  3831. // If we cannot get a ready page - we must have run out of pages (we
  3832. // have already done a check on the availability of ready pages above).
  3833. // If we cannot get a new page we continue using the old.
  3834. //
  3835. if (hNewPage != WB_PAGE_HANDLE_NULL)
  3836. {
  3837. hPage = hNewPage;
  3838. }
  3839. }
  3840. //
  3841. // Read the next object
  3842. //
  3843. result = wbObjectLoad(m_hLoadFile,
  3844. (OM_WORKSET_ID)hPage,
  3845. &pGraphic);
  3846. if (result != 0)
  3847. {
  3848. ERROR_OUT(("Error reading object = %d", result));
  3849. DC_QUIT;
  3850. }
  3851. pData = ObjectDataPtrFromGraphic(pGraphic);
  3852. type = pGraphic->type;
  3853. //
  3854. // Process the object according to type
  3855. //
  3856. //
  3857. // End of file marker
  3858. //
  3859. if (type == TYPE_END_OF_FILE)
  3860. {
  3861. //
  3862. // Let the Front End know that the load has completed
  3863. //
  3864. TRACE_OUT(("Posting WBP_EVENT_LOAD_COMPLETE"));
  3865. WBP_PostEvent(
  3866. 0, // No delay
  3867. WBP_EVENT_LOAD_COMPLETE, // Load completed
  3868. 0, // No parameters
  3869. 0);
  3870. //
  3871. // Leave now - the file will be closed below
  3872. //
  3873. DC_QUIT;
  3874. }
  3875. //
  3876. // It is not an end-of file object. So it must be either an end-of page
  3877. // or a graphic object. In either case we may already have flagged the
  3878. // need to add a new page.
  3879. //
  3880. //
  3881. // Add a new page (if necessary)
  3882. //
  3883. if (m_loadState == LOAD_STATE_PENDING_NEW_PAGE)
  3884. {
  3885. //
  3886. // If we could not get a new page handle above leave with an error
  3887. //
  3888. if (hPage == m_loadPageHandle)
  3889. {
  3890. ERROR_OUT(("Run out of pages for load"));
  3891. result = WB_RC_TOO_MANY_PAGES;
  3892. DC_QUIT;
  3893. }
  3894. //
  3895. // Add a new page after the current page. The new page handle is saved
  3896. // in the client details.
  3897. //
  3898. result = wbPageAdd(m_loadPageHandle,
  3899. PAGE_AFTER,
  3900. &(m_loadPageHandle),
  3901. DONT_RESET_CHANGED_FLAG);
  3902. if (result != 0)
  3903. {
  3904. ERROR_OUT(("Failed to add page"));
  3905. DC_QUIT;
  3906. }
  3907. //
  3908. // Check that we got the page handle we expected
  3909. //
  3910. ASSERT((hPage == m_loadPageHandle));
  3911. //
  3912. // Show that we are no longer waiting for a new page
  3913. //
  3914. m_loadState = LOAD_STATE_LOADING;
  3915. }
  3916. //
  3917. // End of page marker
  3918. //
  3919. if (type == TYPE_END_OF_PAGE)
  3920. {
  3921. TRACE_OUT(("End of page object"));
  3922. //
  3923. // Discard the object
  3924. //
  3925. OM_ObjectDiscard(m_pomClient,
  3926. m_hWSGroup,
  3927. (OM_WORKSET_ID)hPage,
  3928. &pData);
  3929. pData = NULL;
  3930. //
  3931. // Set the load state to "pending new page" and leave the routine
  3932. // immediately. The process continues when we return to this routine.
  3933. //
  3934. m_loadState = LOAD_STATE_PENDING_NEW_PAGE;
  3935. //
  3936. // Exit (we post ourselves a message below to get us back into this
  3937. // routine later).
  3938. //
  3939. postDelay = 100;
  3940. DC_QUIT;
  3941. }
  3942. //
  3943. // The object is a standard graphic
  3944. //
  3945. TRACE_OUT(("Graphic object"));
  3946. //
  3947. // Add the object to the page
  3948. //
  3949. result = OM_ObjectAdd(m_pomClient,
  3950. m_hWSGroup,
  3951. (OM_WORKSET_ID)hPage,
  3952. &pData,
  3953. sizeof(WB_GRAPHIC),
  3954. &pObj,
  3955. LAST);
  3956. if (result != 0)
  3957. {
  3958. DC_QUIT;
  3959. }
  3960. //
  3961. // Show that we have finished with the object
  3962. //
  3963. pGraphic = NULL;
  3964. pData = NULL;
  3965. DC_EXIT_POINT:
  3966. //
  3967. // If we still have the object - discard it
  3968. //
  3969. if (pData != NULL)
  3970. {
  3971. TRACE_OUT(("Discarding object"));
  3972. OM_ObjectDiscard(m_pomClient,
  3973. m_hWSGroup,
  3974. (OM_WORKSET_ID)hPage,
  3975. &pData);
  3976. }
  3977. //
  3978. // If an error occurred or we have reached the end-of-file - close the
  3979. // file.
  3980. //
  3981. if ((result != 0) || (type == TYPE_END_OF_FILE))
  3982. {
  3983. CloseHandle(m_hLoadFile);
  3984. m_hLoadFile = INVALID_HANDLE_VALUE;
  3985. //
  3986. // If the final result is an error - post an error message to ourselves
  3987. //
  3988. if (result != 0)
  3989. {
  3990. TRACE_OUT(("Posting WBP_EVENT_LOAD_FAILED"));
  3991. WBP_PostEvent(
  3992. 0, // No delay
  3993. WBP_EVENT_LOAD_FAILED, // Load the next object
  3994. 0, // No parameters
  3995. 0);
  3996. }
  3997. //
  3998. // Record that we are no longer in the load process
  3999. //
  4000. m_loadState = LOAD_STATE_EMPTY;
  4001. TRACE_OUT(("Moved load state to LOAD_STATE_EMPTY"));
  4002. }
  4003. //
  4004. // send a message to load the next page, unless the load has been
  4005. // cancelled
  4006. //
  4007. if (m_loadState != LOAD_STATE_EMPTY)
  4008. {
  4009. //
  4010. // We have not reached the end-of-file and there has been no error.
  4011. // Post a message to ourselves to continue the load process.
  4012. //
  4013. TRACE_OUT(("Posting WBPI_EVENT_LOAD_NEXT"));
  4014. WBP_PostEvent(postDelay, // With delay
  4015. WBPI_EVENT_LOAD_NEXT, // Load the next object
  4016. 0, // No parameters
  4017. 0);
  4018. }
  4019. DebugExitVOID(wbPageLoad);
  4020. }
  4021. //
  4022. //
  4023. // Name: wbObjectLoad
  4024. //
  4025. // Purpose: Load a single object from file.
  4026. //
  4027. // Returns: Error code
  4028. //
  4029. //
  4030. UINT WbClient::wbObjectLoad
  4031. (
  4032. HANDLE hFile,
  4033. WB_PAGE_HANDLE hPage,
  4034. PPWB_GRAPHIC ppGraphic
  4035. )
  4036. {
  4037. UINT result = 0;
  4038. OM_WORKSET_ID worksetID = (OM_WORKSET_ID)hPage;
  4039. UINT length;
  4040. ULONG cbSizeRead;
  4041. POM_OBJECTDATA pData = NULL;
  4042. PWB_GRAPHIC pGraphic = NULL;
  4043. DebugEntry(wbObjectLoad);
  4044. TRACE_OUT(("Entered wbObjectLoad for page %d", (UINT) hPage));
  4045. //
  4046. // Read the next object's length
  4047. //
  4048. if ( (! ReadFile(hFile, (void *) &length, sizeof(length), &cbSizeRead, NULL)) ||
  4049. (cbSizeRead != sizeof(length)) ||
  4050. (length > OM_MAX_OBJECT_SIZE) ||
  4051. (length == 0) )
  4052. {
  4053. //
  4054. // Make sure we return a sensible error.
  4055. //
  4056. ERROR_OUT(("reading object length, win32 err=%d, length=%d", GetLastError(), length));
  4057. result = WB_RC_BAD_FILE_FORMAT;
  4058. DC_QUIT;
  4059. }
  4060. //
  4061. // Allocate memory for the object
  4062. //
  4063. result = OM_ObjectAlloc(m_pomClient,
  4064. m_hWSGroup,
  4065. worksetID,
  4066. length,
  4067. &pData);
  4068. if (result != 0)
  4069. {
  4070. ERROR_OUT(("Error allocating object = %d", result));
  4071. DC_QUIT;
  4072. }
  4073. pData->length = length;
  4074. pGraphic = GraphicPtrFromObjectData(pData);
  4075. //
  4076. // Read the object into memory
  4077. //
  4078. if ( (! ReadFile(hFile, (void *) pGraphic, length, &cbSizeRead, NULL)) ||
  4079. (cbSizeRead != length))
  4080. {
  4081. //
  4082. // Make sure we return a sensible error.
  4083. //
  4084. ERROR_OUT((
  4085. "Reading object from file: win32 err=%d, asked for %d got %d bytes",
  4086. GetLastError(),
  4087. length,
  4088. cbSizeRead));
  4089. result = WB_RC_BAD_FILE_FORMAT;
  4090. DC_QUIT;
  4091. }
  4092. //
  4093. // Validate the object type
  4094. //
  4095. switch (pGraphic->type)
  4096. {
  4097. //
  4098. // Standard type, end-of-page or end-of-file
  4099. //
  4100. case TYPE_END_OF_PAGE:
  4101. case TYPE_END_OF_FILE:
  4102. case TYPE_GRAPHIC_FREEHAND:
  4103. case TYPE_GRAPHIC_LINE:
  4104. case TYPE_GRAPHIC_RECTANGLE:
  4105. case TYPE_GRAPHIC_FILLED_RECTANGLE:
  4106. case TYPE_GRAPHIC_ELLIPSE:
  4107. case TYPE_GRAPHIC_FILLED_ELLIPSE:
  4108. case TYPE_GRAPHIC_TEXT:
  4109. case TYPE_GRAPHIC_DIB:
  4110. break;
  4111. //
  4112. // Unrecognized object type - probably wrong version
  4113. //
  4114. default:
  4115. result = WB_RC_BAD_FILE_FORMAT;
  4116. DC_QUIT;
  4117. break;
  4118. }
  4119. //
  4120. // For graphic objects, set the flag in the object header showing that it
  4121. // was loaded from file. Add our user ID so we know where it came from.
  4122. //
  4123. if ( (pGraphic->type != TYPE_END_OF_FILE) &&
  4124. (pGraphic->type != TYPE_END_OF_PAGE))
  4125. {
  4126. pGraphic->loadedFromFile = TRUE;
  4127. pGraphic->loadingClientID = m_clientNetID;
  4128. }
  4129. *ppGraphic = pGraphic;
  4130. DC_EXIT_POINT:
  4131. //
  4132. // If an error has occurred - discard the object (if we have it)
  4133. //
  4134. if ((result != 0) && (pData != NULL))
  4135. {
  4136. OM_ObjectDiscard(m_pomClient,
  4137. m_hWSGroup,
  4138. worksetID,
  4139. &pData);
  4140. }
  4141. DebugExitDWORD(wbObjectLoad, result);
  4142. return(result);
  4143. }
  4144. //
  4145. //
  4146. // Name: wbPageHandleFromNumber
  4147. //
  4148. // Purpose: Return the handle of a page specified by page number
  4149. //
  4150. // Returns: Error code
  4151. //
  4152. //
  4153. UINT WbClient::wbPageHandleFromNumber
  4154. (
  4155. UINT pageNumber,
  4156. PWB_PAGE_HANDLE phPage
  4157. )
  4158. {
  4159. UINT result = 0;
  4160. WB_PAGE_HANDLE hPage;
  4161. PWB_PAGE_ORDER pPageOrder = &(m_pageOrder);
  4162. DebugEntry(wbPageHandleFromNumber);
  4163. //
  4164. // Validate the requested page number
  4165. //
  4166. if ((pageNumber < 1)|| (pageNumber > WB_MAX_PAGES))
  4167. {
  4168. result = WB_RC_BAD_PAGE_NUMBER;
  4169. DC_QUIT;
  4170. }
  4171. if (pageNumber > pPageOrder->countPages)
  4172. {
  4173. result = WB_RC_NO_SUCH_PAGE;
  4174. DC_QUIT;
  4175. }
  4176. //
  4177. // Get the page handle
  4178. //
  4179. hPage = (pPageOrder->pages)[pageNumber - 1];
  4180. //
  4181. // Check that this page is in use
  4182. //
  4183. if (GetPageState(hPage)->state != PAGE_IN_USE)
  4184. {
  4185. ERROR_OUT(("Page list is bad"));
  4186. }
  4187. //
  4188. // Return the page handle
  4189. //
  4190. *phPage = hPage;
  4191. DC_EXIT_POINT:
  4192. DebugExitDWORD(wbPageHandleFromNumber, result);
  4193. return(result);
  4194. }
  4195. //
  4196. //
  4197. // Name: wbPageClear
  4198. //
  4199. // Purpose: Clear the specified page of all graphic objects
  4200. //
  4201. // Returns: Error code
  4202. //
  4203. //
  4204. UINT WbClient::wbPageClear
  4205. (
  4206. WB_PAGE_HANDLE hPage,
  4207. UINT changedFlagAction
  4208. )
  4209. {
  4210. UINT result = 0;
  4211. DebugEntry(wbPageClear);
  4212. //
  4213. // Show that the contents have changed, if required.
  4214. //
  4215. if (changedFlagAction == RESET_CHANGED_FLAG)
  4216. {
  4217. m_changed = TRUE;
  4218. TRACE_OUT(("Changed flag now TRUE"));
  4219. }
  4220. //
  4221. // Request that the page be cleared
  4222. //
  4223. result = OM_WorksetClear(m_pomClient,
  4224. m_hWSGroup,
  4225. (OM_WORKSET_ID)hPage);
  4226. DebugExitDWORD(wbPageClear, result);
  4227. return(result);
  4228. }
  4229. //
  4230. //
  4231. // Name: wbPageClearConfirm
  4232. //
  4233. // Purpose: Complete the clearing of a page
  4234. //
  4235. // Returns: Error code
  4236. //
  4237. //
  4238. void WbClient::wbPageClearConfirm(WB_PAGE_HANDLE hPage)
  4239. {
  4240. DebugEntry(wbPageClearConfirm);
  4241. //
  4242. // Request that the page be cleared
  4243. //
  4244. OM_WorksetClearConfirm(m_pomClient,
  4245. m_hWSGroup,
  4246. (OM_WORKSET_ID)hPage);
  4247. //
  4248. // Check the load state to see whether we are waiting to load the
  4249. // contents
  4250. //
  4251. if (m_loadState == LOAD_STATE_PENDING_CLEAR)
  4252. {
  4253. //
  4254. // We are waiting to load. If there is only one page available (ie the
  4255. // one that has just been cleared) we are ready to load, otherwise we
  4256. // wait for the page deletes to happen.
  4257. //
  4258. if ((m_pageOrder).countPages == 1)
  4259. {
  4260. //
  4261. // Start the load proper
  4262. //
  4263. wbStartContentsLoad();
  4264. }
  4265. else
  4266. {
  4267. //
  4268. // Move the load state to show that we are waiting for all the pages
  4269. // to be deleted.
  4270. //
  4271. m_loadState = LOAD_STATE_PENDING_DELETE;
  4272. TRACE_OUT(("Moved load state to LOAD_STATE_PENDING_DELETE"));
  4273. }
  4274. }
  4275. DebugExitVOID(wbPageClearConfirm);
  4276. }
  4277. //
  4278. //
  4279. // Name: wbCheckReadyPages
  4280. //
  4281. // Purpose: Check that we have enough worksets open for the local user to
  4282. // use immediately (during page adds).
  4283. //
  4284. // Returns: None
  4285. //
  4286. //
  4287. BOOL WbClient::wbCheckReadyPages(void)
  4288. {
  4289. BOOL bResult = TRUE;
  4290. WB_PAGE_HANDLE hNewPage;
  4291. UINT countPages = m_pageOrder.countPages;
  4292. UINT countReadyPages = m_countReadyPages;
  4293. //
  4294. // If we have opened all the worksets
  4295. //
  4296. if (countReadyPages == WB_MAX_PAGES)
  4297. {
  4298. //
  4299. // Quit there are no more worksets that we can open
  4300. //
  4301. DC_QUIT;
  4302. }
  4303. //
  4304. // If the number of pages in use is getting close to the number of ready
  4305. // pages.
  4306. //
  4307. if ( (countReadyPages >= PREINITIALIZE_PAGES)
  4308. && (countPages <= (countReadyPages - PREINITIALIZE_PAGES)))
  4309. {
  4310. DC_QUIT;
  4311. }
  4312. //
  4313. // If the number of pages ready is less than the required cache size,
  4314. // open another one.
  4315. //
  4316. hNewPage = wbGetEmptyPageHandle();
  4317. if (hNewPage != WB_PAGE_HANDLE_NULL)
  4318. {
  4319. //
  4320. // Open the workset associated with the page
  4321. //
  4322. wbPageWorksetOpen(hNewPage, OPEN_LOCAL);
  4323. }
  4324. bResult = FALSE;
  4325. DC_EXIT_POINT:
  4326. return(bResult);
  4327. }
  4328. //
  4329. //
  4330. // Name: wbPageAdd
  4331. //
  4332. // Purpose: Add a new (blank) page in a specified position
  4333. //
  4334. // Returns: Error code
  4335. //
  4336. //
  4337. UINT WbClient::wbPageAdd
  4338. (
  4339. WB_PAGE_HANDLE hRefPage,
  4340. UINT where,
  4341. PWB_PAGE_HANDLE phPage,
  4342. UINT changedFlagAction
  4343. )
  4344. {
  4345. UINT result = 0;
  4346. WB_PAGE_HANDLE hNewPage;
  4347. DebugEntry(wbPageAdd);
  4348. //
  4349. // Check that there are not too many pages already
  4350. //
  4351. if (m_pageOrder.countPages == WB_MAX_PAGES)
  4352. {
  4353. result = WB_RC_TOO_MANY_PAGES;
  4354. DC_QUIT;
  4355. }
  4356. //
  4357. // Validate the specified reference page
  4358. //
  4359. ASSERT(GetPageState(hRefPage)->state == PAGE_IN_USE);
  4360. //
  4361. // Get a handle for the new page
  4362. //
  4363. hNewPage = wbGetReadyPageHandle();
  4364. //
  4365. // If there are no handles ready we attempt to create one and return a
  4366. // busy indication.
  4367. //
  4368. if (hNewPage == WB_PAGE_HANDLE_NULL)
  4369. {
  4370. result = WB_RC_BUSY;
  4371. DC_QUIT;
  4372. }
  4373. //
  4374. // Make the internal update immediately - this allows the client to
  4375. // reference the new page as soon as this function has returned.
  4376. //
  4377. wbPagesPageAdd(hRefPage, hNewPage, where);
  4378. //
  4379. // Update the Page Control Object
  4380. //
  4381. result = wbWritePageControl(FALSE);
  4382. if (result != 0)
  4383. {
  4384. wbError();
  4385. DC_QUIT;
  4386. }
  4387. //
  4388. // Show that the contents have changed (if required).
  4389. //
  4390. if (changedFlagAction == RESET_CHANGED_FLAG)
  4391. {
  4392. m_changed = TRUE;
  4393. TRACE_OUT(("Changed flag now TRUE"));
  4394. }
  4395. //
  4396. // Return the handle of the new page
  4397. //
  4398. *phPage = hNewPage;
  4399. DC_EXIT_POINT:
  4400. //
  4401. // If we successfully added the page, or could not get a spare page
  4402. // handle, attempt to create a spare one for next time.
  4403. //
  4404. if ((result == 0) || (result == WB_RC_BUSY))
  4405. {
  4406. wbCheckReadyPages();
  4407. }
  4408. DebugExitDWORD(wbPageAdd, result);
  4409. return(result);
  4410. }
  4411. //
  4412. //
  4413. // Name: wbPageMove
  4414. //
  4415. // Purpose: Move a page relative to another page
  4416. //
  4417. // Returns: Error code
  4418. //
  4419. //
  4420. UINT WbClient::wbPageMove
  4421. (
  4422. WB_PAGE_HANDLE hRefPage,
  4423. WB_PAGE_HANDLE hPage,
  4424. UINT where
  4425. )
  4426. {
  4427. UINT result = 0;
  4428. PWB_PAGE_ORDER pPageOrder = &(m_pageOrder);
  4429. DebugEntry(wbPageMove);
  4430. //
  4431. // Extract the page to be moved
  4432. //
  4433. wbPageOrderPageDelete(pPageOrder, hPage);
  4434. //
  4435. // Add it back at its new position
  4436. //
  4437. wbPageOrderPageAdd(pPageOrder, hRefPage, hPage, where);
  4438. //
  4439. // Update the page control object
  4440. //
  4441. result = wbWritePageControl(FALSE);
  4442. if (result != 0)
  4443. {
  4444. wbError();
  4445. DC_QUIT;
  4446. }
  4447. //
  4448. // Show that the contents have changed
  4449. //
  4450. m_changed = TRUE;
  4451. TRACE_OUT(("Changed flag now TRUE"));
  4452. DC_EXIT_POINT:
  4453. DebugExitDWORD(wbPageMove, result);
  4454. return(result);
  4455. }
  4456. //
  4457. //
  4458. // Name: wbPageHandle
  4459. //
  4460. // Purpose: Return a page handle. The page for which the handle is
  4461. // required can be specified relative to another page or as the
  4462. // first/last page.
  4463. //
  4464. // Returns: Error code
  4465. //
  4466. //
  4467. UINT WbClient::wbPageHandle
  4468. (
  4469. WB_PAGE_HANDLE hRefPage,
  4470. UINT where,
  4471. PWB_PAGE_HANDLE phPage
  4472. )
  4473. {
  4474. UINT result = 0;
  4475. UINT pageNumber;
  4476. PWB_PAGE_ORDER pPageOrder = &(m_pageOrder);
  4477. POM_WORKSET_ID pPage = pPageOrder->pages;
  4478. WB_PAGE_HANDLE hPage;
  4479. DebugEntry(wbPageHandle);
  4480. //
  4481. // Check the relative position
  4482. //
  4483. switch (where)
  4484. {
  4485. case PAGE_FIRST:
  4486. hPage = pPage[0];
  4487. break;
  4488. case PAGE_LAST:
  4489. hPage = pPage[pPageOrder->countPages - 1];
  4490. break;
  4491. case PAGE_AFTER:
  4492. case PAGE_BEFORE:
  4493. //
  4494. // Validate the specified reference page
  4495. //
  4496. ASSERT(GetPageState(hRefPage)->state == PAGE_IN_USE);
  4497. //
  4498. // Get the page number of the reference page
  4499. //
  4500. pageNumber = wbPageOrderPageNumber(pPageOrder, hRefPage);
  4501. TRACE_OUT(("Reference page number is %d", pageNumber));
  4502. //
  4503. // Get the page number of the required page
  4504. //
  4505. pageNumber = (UINT)(pageNumber + ((where == PAGE_AFTER) ? 1 : -1));
  4506. TRACE_OUT(("New page number is %d", pageNumber));
  4507. //
  4508. // Check that the new page is valid
  4509. //
  4510. TRACE_OUT(("Number of pages is %d", pPageOrder->countPages));
  4511. if ( (pageNumber < 1)
  4512. || (pageNumber > pPageOrder->countPages))
  4513. {
  4514. TRACE_OUT(("Returning WB_RC_NO_SUCH_PAGE"));
  4515. result = WB_RC_NO_SUCH_PAGE;
  4516. DC_QUIT;
  4517. }
  4518. //
  4519. // Get the handle of the page
  4520. //
  4521. hPage = pPage[pageNumber - 1];
  4522. TRACE_OUT(("Returning handle %d", (UINT) hPage));
  4523. break;
  4524. }
  4525. //
  4526. // Return the page handle
  4527. //
  4528. *phPage = hPage;
  4529. DC_EXIT_POINT:
  4530. DebugExitDWORD(wbPageHandle, result);
  4531. return(result);
  4532. }
  4533. //
  4534. //
  4535. // Name: wbGraphicSelectPrevious
  4536. //
  4537. // Purpose: Return the next graphic object in the specified page whose
  4538. // bounding rectangle contains the specified point. The function
  4539. // starts with the graphic whose handle is given as parameter and
  4540. // will return this graphic if it contains the point.
  4541. //
  4542. // Returns: Error code
  4543. //
  4544. //
  4545. UINT WbClient::wbGraphicSelectPrevious
  4546. (
  4547. WB_PAGE_HANDLE hPage,
  4548. LPPOINT pPoint,
  4549. WB_GRAPHIC_HANDLE hGraphic,
  4550. PWB_GRAPHIC_HANDLE phGraphic
  4551. )
  4552. {
  4553. UINT result = 0;
  4554. OM_WORKSET_ID worksetID = (OM_WORKSET_ID)hPage;
  4555. PWB_GRAPHIC pGraphic;
  4556. POM_OBJECTDATA pData;
  4557. RECT rect;
  4558. DebugEntry(wbGraphicSelectPrevious);
  4559. *phGraphic = (WB_GRAPHIC_HANDLE) NULL;
  4560. //
  4561. // Loop back through the objects starting at the reference point
  4562. //
  4563. do
  4564. {
  4565. //
  4566. // Get the object from ObMan
  4567. //
  4568. result = OM_ObjectRead(m_pomClient,
  4569. m_hWSGroup,
  4570. worksetID,
  4571. hGraphic,
  4572. &pData);
  4573. //
  4574. // Leave the loop if error on read - we do not need to do the release
  4575. //
  4576. if (result != 0)
  4577. {
  4578. DC_QUIT;
  4579. }
  4580. pGraphic = GraphicPtrFromObjectData(pData);
  4581. //
  4582. // Extract the bounding rectangle of the object
  4583. //
  4584. RECT_FROM_TSHR_RECT16(&rect, pGraphic->rectBounds);
  4585. //
  4586. // Release the object
  4587. //
  4588. OM_ObjectRelease(m_pomClient,
  4589. m_hWSGroup,
  4590. worksetID,
  4591. hGraphic,
  4592. &pData);
  4593. //
  4594. // Check whether the point lies in bounds
  4595. //
  4596. if (PtInRect(&rect, *pPoint))
  4597. {
  4598. //
  4599. // Set the result handle
  4600. //
  4601. TRACE_OUT(("Returning graphic handle"));
  4602. *phGraphic = hGraphic;
  4603. DC_QUIT;
  4604. }
  4605. //
  4606. // Get the next object to test
  4607. //
  4608. result = OM_ObjectH(m_pomClient,
  4609. m_hWSGroup,
  4610. worksetID,
  4611. hGraphic,
  4612. &hGraphic,
  4613. BEFORE);
  4614. }
  4615. while (result == 0);
  4616. //
  4617. // Correct the return code (if necessary)
  4618. //
  4619. if (result == OM_RC_NO_SUCH_OBJECT)
  4620. {
  4621. TRACE_OUT(("Returning WB_RC_NO_SUCH_GRAPHIC"));
  4622. result = WB_RC_NO_SUCH_GRAPHIC;
  4623. }
  4624. DC_EXIT_POINT:
  4625. DebugExitDWORD(wbGraphicSelectPrevious, result);
  4626. return(result);
  4627. }
  4628. //
  4629. //
  4630. // Name: wbCoreExitHandler
  4631. //
  4632. // Purpose: Exit handler for the Whiteboard Core. This handler is
  4633. // registered with the Utilities by the WBP_Start call. It is
  4634. // deregistered by the client deregistration process, so it is
  4635. // only called when an abnormal termination occurs.
  4636. //
  4637. // Returns: None
  4638. //
  4639. //
  4640. void CALLBACK wbCoreExitHandler(LPVOID clientData)
  4641. {
  4642. WbClient* pwbClient = (WbClient *)clientData;
  4643. pwbClient->wbExitHandler();
  4644. }
  4645. void WbClient::wbExitHandler(void)
  4646. {
  4647. DebugEntry(wbExitHandler);
  4648. //
  4649. // Leave the current call if there is one, removing any locks etc.
  4650. //
  4651. wbLeaveCall();
  4652. //
  4653. // Dereg from call manager
  4654. //
  4655. if (m_pcmClient != NULL)
  4656. {
  4657. CMS_Deregister(&(m_pcmClient));
  4658. }
  4659. //
  4660. // Dereg exit handler
  4661. //
  4662. if (m_subState >= STATE_START_REGISTERED_EXIT)
  4663. {
  4664. UT_DeregisterExit(m_putTask, wbCoreExitHandler, this);
  4665. }
  4666. //
  4667. // Dereg obman
  4668. //
  4669. if (m_subState >= STATE_START_REGISTERED_OM)
  4670. {
  4671. OM_Deregister(&m_pomClient);
  4672. }
  4673. //
  4674. // Dereg event handler
  4675. //
  4676. if (m_subState >= STATE_START_REGISTERED_EVENT)
  4677. {
  4678. UT_DeregisterEvent(m_putTask, wbCoreEventHandler, this);
  4679. }
  4680. //
  4681. // delete ourself!
  4682. //
  4683. delete this;
  4684. DebugExitVOID(wbExitHandler);
  4685. }
  4686. //
  4687. //
  4688. // Name: wbCoreEventHandler
  4689. //
  4690. // Purpose: Event handler for the Whiteboard Core. This handler is
  4691. // registered with the Utilities by the WBP_Start call.
  4692. //
  4693. // Params: clientData - pointer to the data stored for a client
  4694. // event - event identifier
  4695. // param1 - word event parameter (content depends on event)
  4696. // param2 - long event parameter (content depends on event)
  4697. //
  4698. // Returns: Error code
  4699. //
  4700. //
  4701. BOOL CALLBACK wbCoreEventHandler
  4702. (
  4703. LPVOID clientData,
  4704. UINT event,
  4705. UINT_PTR param1,
  4706. UINT_PTR param2
  4707. )
  4708. {
  4709. WbClient* pwbClient = (WbClient *)clientData;
  4710. return(pwbClient->wbEventHandler(event, param1, param2));
  4711. }
  4712. BOOL WbClient::wbEventHandler
  4713. (
  4714. UINT event,
  4715. UINT_PTR param1,
  4716. UINT_PTR param2
  4717. )
  4718. {
  4719. POM_EVENT_DATA16 pEvent16 = (POM_EVENT_DATA16) &param1;
  4720. POM_EVENT_DATA32 pEvent32 = (POM_EVENT_DATA32) &param2;
  4721. BOOL processed = FALSE;
  4722. DebugEntry(wbEventHandler);
  4723. TRACE_OUT(("event %d, param1 %d, param2 %d", event, param1, param2));
  4724. switch (event)
  4725. {
  4726. //
  4727. // Confirmation that we have registered with a workset group
  4728. //
  4729. case OM_WSGROUP_REGISTER_CON:
  4730. TRACE_OUT(("OM_WSGROUP_REGISTER_CON %x %x",param1,param2));
  4731. processed = wbOnWsGroupRegisterCon(param1, param2);
  4732. break;
  4733. //
  4734. // Confirmation that we have moved a workset group
  4735. //
  4736. case OM_WSGROUP_MOVE_CON:
  4737. TRACE_OUT(("OM_WSGROUP_MOVE_CON %x %x",param1,param2));
  4738. processed = wbOnWsGroupMoveCon(param1, param2);
  4739. break;
  4740. //
  4741. // Our workset group has been moved
  4742. //
  4743. case OM_WSGROUP_MOVE_IND:
  4744. TRACE_OUT(("OM_WSGROUP_MOVE_IND %x %x",param1,param2));
  4745. processed = wbOnWsGroupMoveInd(param1, param2);
  4746. break;
  4747. //
  4748. // A workset has been created - we do nothing
  4749. //
  4750. case OM_WORKSET_NEW_IND:
  4751. TRACE_OUT(("OM_WORKSET_NEW_IND %x %x",param1,param2));
  4752. processed = TRUE;
  4753. break;
  4754. //
  4755. // A workset has been opened
  4756. //
  4757. case OM_WORKSET_OPEN_CON:
  4758. TRACE_OUT(("OM_WORKSET_OPEN_CON %x %x",param1,param2));
  4759. processed = wbOnWorksetOpenCon(param1, param2);
  4760. break;
  4761. //
  4762. // A workset has been locked
  4763. //
  4764. case OM_WORKSET_LOCK_CON:
  4765. TRACE_OUT(("OM_WORKSET_LOCK_CON %x %x",param1,param2));
  4766. processed = wbOnWorksetLockCon(param1, param2);
  4767. break;
  4768. //
  4769. // A workset has been unlocked
  4770. //
  4771. case OM_WORKSET_UNLOCK_IND:
  4772. TRACE_OUT(("OM_WORKSET_UNLOCK_IND %x %x",param1,param2));
  4773. processed = wbOnWorksetUnlockInd(param1, param2);
  4774. break;
  4775. //
  4776. // ObMan has run out of resources
  4777. //
  4778. case OM_OUT_OF_RESOURCES_IND:
  4779. TRACE_OUT(("OM_OUT_OF_RESOURCES_IND %x %x",param1,param2));
  4780. wbError();
  4781. processed = TRUE;
  4782. break;
  4783. //
  4784. // A workset has been cleared
  4785. //
  4786. case OM_WORKSET_CLEAR_IND:
  4787. TRACE_OUT(("OM_WORKSET_CLEAR_IND %x %x",param1,param2));
  4788. processed = wbOnWorksetClearInd(param1, param2);
  4789. break;
  4790. //
  4791. // A new object has been added to a workset
  4792. //
  4793. case OM_OBJECT_ADD_IND:
  4794. TRACE_OUT(("OM_OBJECT_ADD_IND %x %x",param1,param2));
  4795. processed = wbOnObjectAddInd(param1, (POM_OBJECT)param2);
  4796. break;
  4797. //
  4798. // An object has been moved
  4799. //
  4800. case OM_OBJECT_MOVE_IND:
  4801. TRACE_OUT(("OM_OBJECT_MOVE_IND %x %x",param1,param2));
  4802. processed = wbOnObjectMoveInd(param1, param2);
  4803. break;
  4804. //
  4805. // An object has been deleted
  4806. //
  4807. case OM_OBJECT_DELETE_IND:
  4808. TRACE_OUT(("OM_OBJECT_DELETE_IND %x %x",param1,param2));
  4809. processed = wbOnObjectDeleteInd(param1, (POM_OBJECT)param2);
  4810. break;
  4811. //
  4812. // An object has been updated
  4813. //
  4814. case OM_OBJECT_UPDATE_IND:
  4815. TRACE_OUT(("OM_OBJECT_UPDATE_IND %x %x",param1,param2));
  4816. processed = wbOnObjectUpdateInd(param1, (POM_OBJECT)param2);
  4817. break;
  4818. //
  4819. // An object has been updated
  4820. //
  4821. case OM_OBJECT_REPLACE_IND:
  4822. TRACE_OUT(("OM_OBJECT_REPLACE_IND %x %x",param1,param2));
  4823. processed = wbOnObjectReplaceInd(param1, (POM_OBJECT)param2);
  4824. break;
  4825. //
  4826. // Load chaining event
  4827. //
  4828. case WBPI_EVENT_LOAD_NEXT:
  4829. TRACE_OUT(("WBPI_EVENT_LOAD_NEXT"));
  4830. wbPageLoad();
  4831. processed = TRUE;
  4832. break;
  4833. //
  4834. // Whiteboard page clear indication
  4835. //
  4836. case WBP_EVENT_PAGE_CLEAR_IND:
  4837. TRACE_OUT(("WBP_EVENT_PAGE_CLEAR_IND"));
  4838. processed = wbOnWBPPageClearInd((WB_PAGE_HANDLE) param1);
  4839. break;
  4840. //
  4841. // Whiteboard lock notification
  4842. //
  4843. case WBP_EVENT_PAGE_ORDER_LOCKED:
  4844. case WBP_EVENT_CONTENTS_LOCKED:
  4845. TRACE_OUT(("WBP_EVENT_xxx_LOCKED (%#hx) %#hx %#lx",
  4846. event,
  4847. param1,
  4848. param2));
  4849. processed = wbOnWBPLock();
  4850. break;
  4851. //
  4852. // Whiteboard lock failure notification
  4853. //
  4854. case WBP_EVENT_LOCK_FAILED:
  4855. TRACE_OUT(("WBP_EVENT_LOCK_FAILED %x %x",param1,param2));
  4856. processed = wbOnWBPLockFailed();
  4857. break;
  4858. //
  4859. // Whiteboard Unlock notification
  4860. //
  4861. case WBP_EVENT_UNLOCKED:
  4862. TRACE_OUT(("WBP_EVENT_UNLOCKED %x %x",param1,param2));
  4863. processed = wbOnWBPUnlocked();
  4864. break;
  4865. //
  4866. // Whiteboard Page Order Updated notification
  4867. //
  4868. case WBP_EVENT_PAGE_ORDER_UPDATED:
  4869. TRACE_OUT(("WBP_EVENT_PAGE_ORDER_UPDATED %x %x",
  4870. param1,
  4871. param2));
  4872. processed = wbOnWBPPageOrderUpdated();
  4873. break;
  4874. //
  4875. // We are not interested in this event - do nothing
  4876. //
  4877. default:
  4878. TRACE_OUT(("Event ignored"));
  4879. break;
  4880. } // Switch on event type
  4881. DebugExitBOOL(wbEventHandler, processed);
  4882. return(processed);
  4883. }
  4884. //
  4885. // wbJoinCallError
  4886. //
  4887. // This function should be called in STATE_REGISTERING only.
  4888. //
  4889. //
  4890. void WbClient::wbJoinCallError(void)
  4891. {
  4892. DebugEntry(wbJoinCallError);
  4893. ASSERT((m_state == STATE_REGISTERING));
  4894. //
  4895. // Post a registration failed message to the client
  4896. //
  4897. TRACE_OUT(("Posting WBP_EVENT_REGISTER_FAILED"));
  4898. WBP_PostEvent(
  4899. 0, // No delay
  4900. WBP_EVENT_JOIN_CALL_FAILED, // Failure
  4901. 0, // No parameters
  4902. 0);
  4903. //
  4904. // Tidy up after the attempt to join the call
  4905. //
  4906. wbLeaveCall();
  4907. DebugExitVOID(wbJoinCallError);
  4908. }
  4909. //
  4910. // wbError
  4911. //
  4912. void WbClient::wbError(void)
  4913. {
  4914. DebugEntry(wbError);
  4915. //
  4916. // An error has occurred during Core processing. We act according to the
  4917. // current state.
  4918. //
  4919. switch (m_state)
  4920. {
  4921. //
  4922. // If the error has occurred during registration, post a registration
  4923. // failure message to the client and cancel registration.
  4924. //
  4925. case STATE_REGISTERING:
  4926. wbJoinCallError();
  4927. break;
  4928. //
  4929. // If the error occurred during normal running, we tell the client who
  4930. // must deregister.
  4931. //
  4932. case STATE_IDLE:
  4933. //
  4934. // Only take action if we are not already in fatal error state
  4935. //
  4936. if (m_errorState == ERROR_STATE_EMPTY)
  4937. {
  4938. //
  4939. // Post an error message to the client
  4940. //
  4941. TRACE_OUT(("Posting WBP_EVENT_ERROR"));
  4942. WBP_PostEvent(
  4943. 0, // No delay
  4944. WBP_EVENT_ERROR, // Error
  4945. 0, // No parameters
  4946. 0);
  4947. //
  4948. // Record that an error has occurred
  4949. //
  4950. m_errorState = ERROR_STATE_FATAL;
  4951. TRACE_OUT(("Moved error state to ERROR_STATE_FATAL"));
  4952. }
  4953. break;
  4954. //
  4955. // Client is in an unknown state
  4956. //
  4957. default:
  4958. ERROR_OUT(("Bad main state for call"));
  4959. break;
  4960. }
  4961. DebugExitVOID(wbError);
  4962. }
  4963. //
  4964. //
  4965. // Name: wbOnWSGroupMoveCon
  4966. //
  4967. // Purpose: Routine processing OM_WSGROUP_MOVE_CON events.
  4968. //
  4969. //
  4970. BOOL WbClient::wbOnWsGroupMoveCon
  4971. (
  4972. UINT_PTR param1,
  4973. UINT_PTR param2
  4974. )
  4975. {
  4976. POM_EVENT_DATA16 pEvent16 = (POM_EVENT_DATA16) &param1;
  4977. POM_EVENT_DATA32 pEvent32 = (POM_EVENT_DATA32) &param2;
  4978. BOOL processed = FALSE;
  4979. UINT rc;
  4980. BOOL failedToJoin = FALSE;
  4981. DebugEntry(wbOnWsGroupMoveCon);
  4982. //
  4983. // Check that this is the event we are expecting
  4984. //
  4985. if (pEvent32->correlator != m_wsgroupCorrelator)
  4986. {
  4987. DC_QUIT;
  4988. }
  4989. //
  4990. // Show that we have processed the event
  4991. //
  4992. processed = TRUE;
  4993. //
  4994. // Test for the correct state
  4995. //
  4996. if (m_subState != STATE_REG_PENDING_WSGROUP_MOVE)
  4997. {
  4998. //
  4999. // We are not in the correct state for this event - this is an internal
  5000. // error.
  5001. //
  5002. ERROR_OUT(("Wrong state for WSGroupMoveCon"));
  5003. }
  5004. //
  5005. // Check that the return code for the move is OK
  5006. //
  5007. if (pEvent32->result != 0)
  5008. {
  5009. //
  5010. // Moving the workset group failed - post a "join call failed" message
  5011. // to the front-end.
  5012. //
  5013. TRACE_OUT(("WSGroup move failed, result = %d", pEvent32->result));
  5014. failedToJoin = TRUE;
  5015. DC_QUIT;
  5016. }
  5017. //
  5018. // The WSGroupMove has completed successfully. Replace our local user
  5019. // object by deleting the current one (we must have one to get to this
  5020. // point) and adding a new one.
  5021. //
  5022. // The reason we do this is that our existing user object has been moved
  5023. // from the local domain into a call, but since it is in a non-persistent
  5024. // workset, the Obman behaviour for this object when the call ends is
  5025. // undefined. So we replace the object to get a defined behaviour.
  5026. //
  5027. TRACE_OUT(("Deleting local user object"));
  5028. rc = OM_ObjectDelete(m_pomClient,
  5029. m_hWSGroup,
  5030. USER_INFORMATION_WORKSET,
  5031. m_pObjLocal);
  5032. if (rc != 0)
  5033. {
  5034. ERROR_OUT(("Error deleting local user object = %u", rc));
  5035. }
  5036. TRACE_OUT(("Adding new local user object"));
  5037. rc = wbAddLocalUserObject();
  5038. if (rc != 0)
  5039. {
  5040. TRACE_OUT(("Failed to add local user object"));
  5041. failedToJoin = TRUE;
  5042. DC_QUIT;
  5043. }
  5044. //
  5045. // Get the clients network ID, used in graphic objects to determine where
  5046. // they are loaded.
  5047. //
  5048. if (!wbGetNetUserID())
  5049. {
  5050. //
  5051. // Tidy up (and post an error event to the client)
  5052. //
  5053. ERROR_OUT(("Failed to get user ID, rc %u", rc));
  5054. failedToJoin = TRUE;
  5055. DC_QUIT;
  5056. }
  5057. //
  5058. // We added our user object successfully, so now wait for the
  5059. // OBJECT_ADD_IND to arrive.
  5060. //
  5061. m_subState = STATE_REG_PENDING_NEW_USER_OBJECT;
  5062. DC_EXIT_POINT:
  5063. if (failedToJoin)
  5064. {
  5065. //
  5066. // We have failed to join the call, so clean up.
  5067. //
  5068. wbError();
  5069. }
  5070. DebugExitBOOL(wbOnWsGroupMoveCon, processed);
  5071. return(processed);
  5072. }
  5073. //
  5074. //
  5075. // Name: wbOnWSGroupMoveInd
  5076. //
  5077. // Purpose: Routine processing OM_WSGROUP_MOVE_IND events.
  5078. //
  5079. //
  5080. BOOL WbClient::wbOnWsGroupMoveInd
  5081. (
  5082. UINT_PTR param1,
  5083. UINT_PTR callID
  5084. )
  5085. {
  5086. POM_EVENT_DATA16 pEvent16 = (POM_EVENT_DATA16) &param1;
  5087. BOOL processed = TRUE;
  5088. DebugEntry(wbOnWsGroupMoveInd);
  5089. if (callID != OM_NO_CALL)
  5090. {
  5091. TRACE_OUT(("Moved into new call"));
  5092. DC_QUIT;
  5093. }
  5094. //
  5095. // If we are registering, treat it as a failure to join the call,
  5096. // otherwise let the client know about the network failure.
  5097. //
  5098. if (m_state == STATE_REGISTERING)
  5099. {
  5100. TRACE_OUT(("Call went down while registering"));
  5101. wbError();
  5102. DC_QUIT;
  5103. }
  5104. TRACE_OUT(("Posting WBP_EVENT_NETWORK_LOST"));
  5105. WBP_PostEvent(0,
  5106. WBP_EVENT_NETWORK_LOST, // Unlocked
  5107. 0, // No parameters
  5108. 0);
  5109. //
  5110. // Tidy up the User Information workset (the local client is now the
  5111. // only user). Note that since the user information workset it
  5112. // non-persistent, Obman will delete the remote user objects for us.
  5113. //
  5114. //
  5115. // - check we have opened the user workset
  5116. //
  5117. if ( (m_state > STATE_REGISTERING) ||
  5118. (m_subState > STATE_REG_PENDING_USER_WORKSET))
  5119. {
  5120. //
  5121. // Delete the lock object.
  5122. //
  5123. if (m_pObjLock != NULL)
  5124. {
  5125. TRACE_OUT(("Deleting lock object %d", m_pObjLock));
  5126. if (OM_ObjectDelete(m_pomClient,
  5127. m_hWSGroup,
  5128. PAGE_CONTROL_WORKSET,
  5129. m_pObjLock) != 0)
  5130. {
  5131. ERROR_OUT(("Error deleting lock object"));
  5132. }
  5133. if (m_lockState == LOCK_STATE_GOT_LOCK)
  5134. {
  5135. //
  5136. // If all is well at this point the unlock process will be
  5137. // completed when the object delete ind is received.
  5138. //
  5139. m_lockState = LOCK_STATE_PENDING_DELETE;
  5140. TRACE_OUT(("Moved to state LOCK_STATE_PENDING_DELETE"));
  5141. }
  5142. else
  5143. {
  5144. m_lockState = LOCK_STATE_EMPTY;
  5145. TRACE_OUT(("Moved to state LOCK_STATE_EMPTY"));
  5146. }
  5147. }
  5148. }
  5149. DC_EXIT_POINT:
  5150. DebugExitBOOL(wbOnWSGroupMoveInd, processed);
  5151. return(processed);
  5152. }
  5153. //
  5154. //
  5155. // Name: wbOnWorksetClearInd
  5156. //
  5157. // Purpose: Routine processing OM_WORKSET_CLEAR_IND events.
  5158. //
  5159. // Returns: Error code
  5160. //
  5161. //
  5162. BOOL WbClient::wbOnWorksetClearInd
  5163. (
  5164. UINT_PTR param1,
  5165. UINT_PTR param2
  5166. )
  5167. {
  5168. POM_EVENT_DATA16 pEvent16 = (POM_EVENT_DATA16) &param1;
  5169. POM_EVENT_DATA32 pEvent32 = (POM_EVENT_DATA32) &param2;
  5170. BOOL processed = FALSE;
  5171. DebugEntry(wbOnWorksetClearInd);
  5172. //
  5173. // Check that the workset group is ours
  5174. //
  5175. if (pEvent16->hWSGroup != m_hWSGroup)
  5176. {
  5177. ERROR_OUT(("Event for unknown workset group = %d", pEvent16->hWSGroup));
  5178. DC_QUIT;
  5179. }
  5180. //
  5181. // We will process the event
  5182. //
  5183. processed = TRUE;
  5184. //
  5185. // Process the event according to the workset ID
  5186. //
  5187. switch(pEvent16->worksetID)
  5188. {
  5189. //
  5190. // Page Control Workset
  5191. //
  5192. case PAGE_CONTROL_WORKSET:
  5193. ERROR_OUT(("Unexpected clear for Page Control Workset"));
  5194. break;
  5195. //
  5196. // Lock Workset
  5197. //
  5198. case SYNC_CONTROL_WORKSET:
  5199. ERROR_OUT(("Unexpected clear for Sync Control Workset"));
  5200. break;
  5201. //
  5202. // User Information Workset
  5203. //
  5204. case USER_INFORMATION_WORKSET:
  5205. ERROR_OUT(("Unexpected clear for User Information Workset"));
  5206. break;
  5207. //
  5208. // Other (should be a Page Workset)
  5209. //
  5210. default:
  5211. //
  5212. // Tell the client that the page has been cleared - the client must then
  5213. // confirm the clear.
  5214. //
  5215. TRACE_OUT(("Posting WBP_EVENT_PAGE_CLEAR_IND"));
  5216. WBP_PostEvent(
  5217. 0,
  5218. WBP_EVENT_PAGE_CLEAR_IND,
  5219. pEvent16->worksetID,
  5220. 0);
  5221. break;
  5222. }
  5223. DC_EXIT_POINT:
  5224. DebugExitBOOL(wbOnWorksetClearInd, processed);
  5225. return(processed);
  5226. }
  5227. //
  5228. //
  5229. // Name: wbOnWBPPageClearInd
  5230. //
  5231. // Purpose: Routine processing WBP_PAGE_CLEAR_IND events.
  5232. //
  5233. // Returns: Error code
  5234. //
  5235. //
  5236. BOOL WbClient::wbOnWBPPageClearInd(WB_PAGE_HANDLE hPage)
  5237. {
  5238. BOOL processed;
  5239. DebugEntry(wbOnWBPPageClearInd);
  5240. //
  5241. // This routine catches WB_PAGE_CLEAR_IND events posted to the client.
  5242. // Because of the asynchronous nature of page order updates these can
  5243. // sometimes have been sent previously for pages that are now no longer
  5244. // in use. We trap these events here, confirm the clear to ObMan and
  5245. // discard the event.
  5246. //
  5247. if (GetPageState(hPage)->state != PAGE_IN_USE)
  5248. {
  5249. TRACE_OUT(("Page is not in use - confirming workset clear immediately"));
  5250. //
  5251. // Accept the page clear immediately
  5252. //
  5253. wbPageClearConfirm(hPage);
  5254. processed = TRUE;
  5255. }
  5256. else
  5257. {
  5258. //
  5259. // If we get here the page is in use - so we must pass the event on to
  5260. // the client. Resetting the result code of this routine to "not
  5261. // processed" will ask the utilities to pass it on to the next event
  5262. // handler.
  5263. //
  5264. processed = FALSE;
  5265. }
  5266. DebugExitBOOL(wbOnWBPPageClearInd, processed);
  5267. return(processed);
  5268. }
  5269. //
  5270. //
  5271. // Name: wbOnObjectAddInd
  5272. //
  5273. // Purpose: Routine processing OM_OBJECT_ADD_IND events.
  5274. //
  5275. // Returns: Error code
  5276. //
  5277. //
  5278. BOOL WbClient::wbOnObjectAddInd
  5279. (
  5280. UINT_PTR param1,
  5281. POM_OBJECT pObj
  5282. )
  5283. {
  5284. POM_EVENT_DATA16 pEvent16 = (POM_EVENT_DATA16) &param1;
  5285. BOOL processed = FALSE;
  5286. DebugEntry(wbOnObjectAddInd);
  5287. //
  5288. // Check that the workset group is ours
  5289. //
  5290. if (pEvent16->hWSGroup != m_hWSGroup)
  5291. {
  5292. ERROR_OUT(("Event for unknown workset group = %d", pEvent16->hWSGroup));
  5293. DC_QUIT;
  5294. }
  5295. //
  5296. // We will process the event
  5297. //
  5298. processed = TRUE;
  5299. //
  5300. // Process the event according to the workset ID
  5301. //
  5302. switch(pEvent16->worksetID)
  5303. {
  5304. //
  5305. // Page Control Workset
  5306. //
  5307. case PAGE_CONTROL_WORKSET:
  5308. wbOnPageObjectAddInd(pObj);
  5309. break;
  5310. //
  5311. // Sync Control Workset
  5312. //
  5313. case SYNC_CONTROL_WORKSET:
  5314. wbOnSyncObjectAddInd(pObj);
  5315. break;
  5316. //
  5317. // User Information Workset
  5318. //
  5319. case USER_INFORMATION_WORKSET:
  5320. wbOnUserObjectAddInd(pObj);
  5321. break;
  5322. //
  5323. // Other (should be a Page Workset)
  5324. //
  5325. default:
  5326. wbOnGraphicObjectAddInd(pEvent16->worksetID, pObj);
  5327. break;
  5328. }
  5329. DC_EXIT_POINT:
  5330. DebugExitBOOL(wbOnObjectAddInd, processed);
  5331. return(processed);
  5332. }
  5333. //
  5334. //
  5335. // Name: wbGetPageObjectType
  5336. //
  5337. // Purpose: Get the type of an object in the Page Control Workset
  5338. //
  5339. // Returns: Error code
  5340. //
  5341. //
  5342. UINT WbClient::wbGetPageObjectType
  5343. (
  5344. POM_OBJECT pObj,
  5345. UINT * pObjectType
  5346. )
  5347. {
  5348. UINT result;
  5349. POM_OBJECTDATA pData;
  5350. DebugEntry(wbGetPageObjectType);
  5351. //
  5352. // Read the object to get its type
  5353. //
  5354. result = OM_ObjectRead(m_pomClient,
  5355. m_hWSGroup,
  5356. PAGE_CONTROL_WORKSET,
  5357. pObj,
  5358. &pData);
  5359. if (result != 0)
  5360. {
  5361. ERROR_OUT(("Error reading object = %d", result));
  5362. wbError();
  5363. DC_QUIT;
  5364. }
  5365. //
  5366. // The first two bytes of the object data give its type
  5367. //
  5368. *pObjectType = *((TSHR_UINT16 *)pData->data);
  5369. //
  5370. // Release the object
  5371. //
  5372. OM_ObjectRelease(m_pomClient,
  5373. m_hWSGroup,
  5374. PAGE_CONTROL_WORKSET,
  5375. pObj,
  5376. &pData);
  5377. DC_EXIT_POINT:
  5378. DebugExitDWORD(wbGetPageObjectType, result);
  5379. return(result);
  5380. }
  5381. //
  5382. //
  5383. // Name: wbOnPageObjectAddInd
  5384. //
  5385. // Purpose: Routine processing OM_OBJECT_ADD_IND events occurring on the
  5386. // Page Control Workset.
  5387. //
  5388. // Returns: Error code
  5389. //
  5390. //
  5391. void WbClient::wbOnPageObjectAddInd(POM_OBJECT pObj)
  5392. {
  5393. UINT objectType;
  5394. DebugEntry(wbOnPageObjectAddInd);
  5395. //
  5396. // Read the object to get its type
  5397. //
  5398. if (wbGetPageObjectType(pObj, &objectType) != 0)
  5399. {
  5400. DC_QUIT;
  5401. }
  5402. //
  5403. // Act according to the type of object added
  5404. //
  5405. switch (objectType)
  5406. {
  5407. case TYPE_CONTROL_LOCK:
  5408. TRACE_OUT(("It is a lock object"));
  5409. wbReadLock();
  5410. break;
  5411. case TYPE_CONTROL_PAGE_ORDER:
  5412. TRACE_OUT(("It is the Page Control object"));
  5413. wbOnPageControlObjectAddInd(pObj);
  5414. break;
  5415. default:
  5416. ERROR_OUT(("Unknown object type added to Page Control Workset"));
  5417. break;
  5418. }
  5419. DC_EXIT_POINT:
  5420. DebugExitVOID(wbOnPageObjectAddInd);
  5421. }
  5422. //
  5423. //
  5424. // Name: wbOnPageControlObjectAddInd
  5425. //
  5426. // Purpose: Routine processing add of page control object
  5427. //
  5428. // Returns: Error code
  5429. //
  5430. //
  5431. void WbClient::wbOnPageControlObjectAddInd(POM_OBJECT pObj)
  5432. {
  5433. DebugEntry(wbOnPageControlObjectAddInd);
  5434. //
  5435. // We only ever expect to get one of these objects
  5436. //
  5437. if (m_pObjPageControl != 0)
  5438. {
  5439. //
  5440. // Check that this is the same object - the add has been triggered by
  5441. // the workset open but we have already read the contents.
  5442. //
  5443. ASSERT((m_pObjPageControl == pObj));
  5444. }
  5445. //
  5446. // Save the handle of the object
  5447. //
  5448. m_pObjPageControl = pObj;
  5449. TRACE_OUT(("Got Page Control object"));
  5450. //
  5451. // Continue according to the current state
  5452. //
  5453. switch (m_state)
  5454. {
  5455. case STATE_REGISTERING:
  5456. //
  5457. // We now have a Page Control Object - if we are waiting for the
  5458. // object we can now move to the next stage.
  5459. //
  5460. if (m_subState == STATE_REG_PENDING_PAGE_CONTROL)
  5461. {
  5462. //
  5463. // If we have the lock on the Page Control Workset then we are in
  5464. // control of the registration process. We must add the sync
  5465. // control object to the Sync Workset.
  5466. //
  5467. if (m_lockState == LOCK_STATE_GOT_LOCK)
  5468. {
  5469. //
  5470. // Create the Sync Control Object
  5471. //
  5472. if (wbCreateSyncControl() != 0)
  5473. {
  5474. ERROR_OUT(("Error adding Sync Control Object"));
  5475. wbError();
  5476. DC_QUIT;
  5477. }
  5478. }
  5479. //
  5480. // If we do not have the sync control object then wait for it -
  5481. // otherwise we can complete initialisation.
  5482. //
  5483. if (m_pObjSyncControl == 0)
  5484. {
  5485. m_subState = STATE_REG_PENDING_SYNC_CONTROL;
  5486. TRACE_OUT(("Moved substate to STATE_REG_PENDING_SYNC_CONTROL"));
  5487. DC_QUIT;
  5488. }
  5489. else
  5490. {
  5491. //
  5492. // If it is us who has the Page Control Workset locked - release
  5493. // the lock.
  5494. //
  5495. if (m_lockState == LOCK_STATE_GOT_LOCK)
  5496. {
  5497. //
  5498. // Unlock the workset
  5499. //
  5500. wbUnlock();
  5501. //
  5502. // Wait for notification of the lock being released
  5503. //
  5504. TRACE_OUT(("Sub state change %d to %d",
  5505. m_subState, STATE_REG_PENDING_UNLOCK));
  5506. m_subState = STATE_REG_PENDING_UNLOCK;
  5507. }
  5508. else
  5509. {
  5510. TRACE_OUT(("Page Control and Sync Control objects both there."));
  5511. TRACE_OUT(("Registration can be completed"));
  5512. wbOnControlWorksetsReady();
  5513. }
  5514. }
  5515. }
  5516. //
  5517. // In other registration states we are not ready to process the
  5518. // event. It will be dealt with later.
  5519. //
  5520. break;
  5521. case STATE_IDLE:
  5522. //
  5523. // We must already have a Page COntrol Object since we are in idle
  5524. // state. So this is an error. It may have been caused by another
  5525. // client so we just trace it rather than asserting.
  5526. //
  5527. ERROR_OUT(("Unexpected add of Page Control Object in idle state"));
  5528. break;
  5529. default:
  5530. ERROR_OUT(("Bad main state"));
  5531. break;
  5532. }
  5533. DC_EXIT_POINT:
  5534. DebugExitVOID(wbOnPageControlObjectAddInd);
  5535. }
  5536. //
  5537. //
  5538. // Name: wbOnSyncObjectAddInd
  5539. //
  5540. // Purpose: Routine processing OM_OBJECT_ADD_IND events occurring on the
  5541. // Sync Control Workset.
  5542. //
  5543. // Returns: Error code
  5544. //
  5545. //
  5546. void WbClient::wbOnSyncObjectAddInd(POM_OBJECT pObj)
  5547. {
  5548. DebugEntry(wbOnSyncObjectAddInd);
  5549. //
  5550. // We only expect this during registration
  5551. //
  5552. switch(m_state)
  5553. {
  5554. //
  5555. // We are waiting for registration to continue
  5556. //
  5557. case STATE_REGISTERING:
  5558. switch(m_subState)
  5559. {
  5560. //
  5561. // We are waiting for a Sync Control Object
  5562. //
  5563. case STATE_REG_PENDING_SYNC_CONTROL:
  5564. m_pObjSyncControl = pObj;
  5565. //
  5566. // The Sync Control object has been added. We do not need to do
  5567. // anything with it yet.
  5568. //
  5569. //
  5570. // If we already have the page control object then we can
  5571. // complete initilisation, otherwise we have to wait for it.
  5572. //
  5573. if (m_pObjPageControl == 0)
  5574. {
  5575. TRACE_OUT(("Sub state change %d to %d",
  5576. m_subState, STATE_REG_PENDING_PAGE_CONTROL));
  5577. m_subState = STATE_REG_PENDING_PAGE_CONTROL;
  5578. }
  5579. else
  5580. {
  5581. //
  5582. // If it is us who has the Page Control Workset locked -
  5583. // release the lock.
  5584. //
  5585. if (m_lockState == LOCK_STATE_GOT_LOCK)
  5586. {
  5587. //
  5588. // Unlock the workset
  5589. //
  5590. wbUnlock();
  5591. //
  5592. // Wait for notification of the lock being released
  5593. //
  5594. TRACE_OUT(("Sub state change %d to %d",
  5595. m_subState, STATE_REG_PENDING_UNLOCK));
  5596. m_subState = STATE_REG_PENDING_UNLOCK;
  5597. }
  5598. else
  5599. {
  5600. TRACE_OUT(("Page Control and Sync Control objects both there."));
  5601. TRACE_OUT(("Registration can be completed"));
  5602. wbOnControlWorksetsReady();
  5603. }
  5604. }
  5605. break;
  5606. default:
  5607. //
  5608. // Save the handle of the Sync Control Object
  5609. //
  5610. m_pObjSyncControl = pObj;
  5611. break;
  5612. }
  5613. break;
  5614. //
  5615. // We are fully registered and are therefore not expecting an add event
  5616. // on this workset. However, since we are registered we must be
  5617. // satisfied that we have a Sync Control Object - so ignore the error.
  5618. //
  5619. case STATE_IDLE:
  5620. ERROR_OUT(("Sync object add not expected in idle state"));
  5621. break;
  5622. //
  5623. // The client is in an unknown state
  5624. //
  5625. default:
  5626. ERROR_OUT(("Client in unknown state = %d", m_state));
  5627. break;
  5628. }
  5629. DebugExitVOID(wbOnSyncObjectAddInd);
  5630. }
  5631. //
  5632. //
  5633. // Name: wbOnUserObjectAddInd
  5634. //
  5635. // Purpose: A user object has been added to the User Information Workset.
  5636. // Inform the client that a new user has joined the call.
  5637. //
  5638. // Returns: Error code
  5639. //
  5640. //
  5641. void WbClient::wbOnUserObjectAddInd(POM_OBJECT pObj)
  5642. {
  5643. UINT countUsers;
  5644. DebugEntry(wbOnUserObjectAddInd);
  5645. OM_WorksetCountObjects(m_pomClient,
  5646. m_hWSGroup,
  5647. USER_INFORMATION_WORKSET,
  5648. &countUsers);
  5649. TRACE_OUT(("Number of users is now %d", countUsers));
  5650. //
  5651. // Ignore the add indication for our own user.
  5652. //
  5653. if (m_pObjLocal == pObj)
  5654. {
  5655. TRACE_OUT(("Got add of own user object"));
  5656. //
  5657. // If we have the lock (temporarily, with NULL lock owner handle),
  5658. // then we need to update the lock object with our actual handle.
  5659. //
  5660. if ((m_pObjLock != NULL) &&
  5661. (m_lockState == LOCK_STATE_GOT_LOCK))
  5662. {
  5663. TRACE_OUT(("Got the lock - update lock object"));
  5664. wbWriteLock();
  5665. }
  5666. if ((m_state == STATE_REGISTERING) &&
  5667. (m_subState == STATE_REG_PENDING_NEW_USER_OBJECT))
  5668. {
  5669. //
  5670. // We have successfully joined the call.
  5671. //
  5672. TRACE_OUT(("Posting WBP_EVENT_JOIN_CALL_OK"));
  5673. WBP_PostEvent(
  5674. 0, // No delay
  5675. WBP_EVENT_JOIN_CALL_OK, // Unlocked
  5676. 0, // No parameters
  5677. 0);
  5678. //
  5679. // Update the state to show that we are ready for work again
  5680. //
  5681. m_state = STATE_IDLE;
  5682. m_subState = STATE_EMPTY;
  5683. TRACE_OUT(("Moved state back to STATE_IDLE"));
  5684. }
  5685. DC_QUIT;
  5686. }
  5687. //
  5688. // If we have created our user object we must check to see if the new
  5689. // user has usurped our color. If so we may need to change color.
  5690. //
  5691. if (m_pObjLocal != NULL)
  5692. {
  5693. TRACE_OUT(("We have added our user object - check colors"));
  5694. wbCheckPersonColor(pObj);
  5695. }
  5696. //
  5697. // Ignore these events unless we are fully registered
  5698. //
  5699. if (m_state != STATE_IDLE)
  5700. {
  5701. TRACE_OUT(("Ignoring user object add - not fully registered"));
  5702. DC_QUIT;
  5703. }
  5704. //
  5705. // Tell the client that a new user has joined
  5706. //
  5707. TRACE_OUT(("Posting WBP_EVENT_USER_JOINED"));
  5708. WBP_PostEvent(
  5709. 0, // No delay
  5710. WBP_EVENT_PERSON_JOINED, // Event type
  5711. 0, // No short parameter
  5712. (UINT_PTR) pObj); // User object handle
  5713. //
  5714. // Try to read the lock object - we may not have been able to do this
  5715. // yet.
  5716. //
  5717. wbReadLock();
  5718. DC_EXIT_POINT:
  5719. DebugExitVOID(wbOnUserObjectAddInd);
  5720. }
  5721. //
  5722. //
  5723. // Name: wbOnGraphicObjectAddInd
  5724. //
  5725. // Purpose: A graphic object has been added to a page workset.
  5726. // Inform the client that a new graphic has been added.
  5727. //
  5728. // Returns: Error code
  5729. //
  5730. //
  5731. void WbClient::wbOnGraphicObjectAddInd
  5732. (
  5733. OM_WORKSET_ID worksetID,
  5734. POM_OBJECT pObj
  5735. )
  5736. {
  5737. WB_PAGE_HANDLE hPage = (WB_PAGE_HANDLE)worksetID;
  5738. POM_OBJECTDATA pData;
  5739. PWB_GRAPHIC pGraphic;
  5740. UINT result;
  5741. DebugEntry(wbOnGraphicObjectAddInd);
  5742. //
  5743. // NFC, SFR 6450. If this object was loaded from file on this machine,
  5744. // then we dont need to set the "changed flag". Otherwise record that
  5745. // the contents have changed
  5746. //
  5747. //
  5748. // Read the object.
  5749. //
  5750. result = OM_ObjectRead(m_pomClient,
  5751. m_hWSGroup,
  5752. worksetID,
  5753. pObj,
  5754. &pData);
  5755. if (result != 0)
  5756. {
  5757. WARNING_OUT(("OM_ObjectRead (%u) failed, set changed flag anyway ", result));
  5758. m_changed = TRUE;
  5759. TRACE_OUT(("changed flag now TRUE"));
  5760. }
  5761. else
  5762. {
  5763. //
  5764. // Convert the ObMan pointer to a core pointer
  5765. //
  5766. pGraphic = GraphicPtrFromObjectData(pData);
  5767. if ( ! ((pGraphic->loadedFromFile) &&
  5768. (pGraphic->loadingClientID == m_clientNetID)))
  5769. {
  5770. TRACE_OUT(("Not loaded from file locally - Set changed flag on"));
  5771. m_changed = TRUE;
  5772. TRACE_OUT(("Changed flag now TRUE"));
  5773. }
  5774. //
  5775. // Finished with the object, so release it.
  5776. //
  5777. OM_ObjectRelease(m_pomClient,
  5778. m_hWSGroup,
  5779. worksetID,
  5780. pObj,
  5781. &pData);
  5782. }
  5783. //
  5784. // These events are ignored unless we are fully registered (the client
  5785. // can do nothing about them if it is not registered correctly).
  5786. //
  5787. if (m_state != STATE_IDLE)
  5788. {
  5789. TRACE_OUT(("Ignoring add of graphic object - not registered"));
  5790. DC_QUIT;
  5791. }
  5792. //
  5793. // Check that this page is actually in use
  5794. //
  5795. if (GetPageState(hPage)->state != PAGE_IN_USE)
  5796. {
  5797. TRACE_OUT(("Ignoring add to page not in use"));
  5798. DC_QUIT;
  5799. }
  5800. //
  5801. // Inform the client of the object being added
  5802. //
  5803. TRACE_OUT(("Posting WBP_EVENT_GRAPHIC_ADDED"));
  5804. WBP_PostEvent(
  5805. 0, // No delay
  5806. WBP_EVENT_GRAPHIC_ADDED, // Event type
  5807. hPage, //
  5808. (UINT_PTR)pObj); // User object handle
  5809. DC_EXIT_POINT:
  5810. DebugExitVOID(wbOnGraphicObjectAddInd);
  5811. }
  5812. //
  5813. //
  5814. // Name: wbOnObjectMoveInd
  5815. //
  5816. // Purpose: This routine is called whenever OM_OBJECT_MOVE_IND events are
  5817. // received.
  5818. //
  5819. // Returns: Error code
  5820. //
  5821. //
  5822. BOOL WbClient::wbOnObjectMoveInd
  5823. (
  5824. UINT_PTR param1,
  5825. UINT_PTR param2
  5826. )
  5827. {
  5828. POM_EVENT_DATA16 pEvent16 = (POM_EVENT_DATA16) &param1;
  5829. POM_EVENT_DATA32 pEvent32 = (POM_EVENT_DATA32) &param2;
  5830. BOOL processed = FALSE;
  5831. DebugEntry(wbOnObjectMoveInd);
  5832. //
  5833. // Check that the workset group is ours
  5834. //
  5835. if (pEvent16->hWSGroup != m_hWSGroup)
  5836. {
  5837. ERROR_OUT(("Event for unknown workset group = %d", pEvent16->hWSGroup));
  5838. DC_QUIT;
  5839. }
  5840. //
  5841. // We will process the event
  5842. //
  5843. processed = TRUE;
  5844. //
  5845. // Process the event according to the workset ID
  5846. //
  5847. switch(pEvent16->worksetID)
  5848. {
  5849. //
  5850. // Page Control Workset Lock Workset User Information Workset
  5851. //
  5852. case PAGE_CONTROL_WORKSET:
  5853. case SYNC_CONTROL_WORKSET:
  5854. case USER_INFORMATION_WORKSET:
  5855. //
  5856. // Event not expected for these worksets
  5857. //
  5858. ERROR_OUT(("Unexpected for workset %d", (UINT) pEvent16->worksetID));
  5859. break;
  5860. //
  5861. // Other (should be a Page Workset)
  5862. //
  5863. default:
  5864. wbOnGraphicObjectMoveInd(pEvent16->worksetID,
  5865. (POM_OBJECT) param2);
  5866. break;
  5867. }
  5868. DC_EXIT_POINT:
  5869. DebugExitBOOL(wbOnObjectMoveInd, processed);
  5870. return(processed);
  5871. }
  5872. //
  5873. //
  5874. // Name: wbOnGraphicObjectMoveInd
  5875. //
  5876. // Purpose: This routine is called whenever an OM_OBJECT_MOVE_IND is
  5877. // received for a graphic object.
  5878. //
  5879. // Returns: Error code
  5880. //
  5881. //
  5882. void WbClient::wbOnGraphicObjectMoveInd
  5883. (
  5884. OM_WORKSET_ID worksetID,
  5885. POM_OBJECT pObj
  5886. )
  5887. {
  5888. WB_PAGE_HANDLE hPage = (WB_PAGE_HANDLE)worksetID;
  5889. DebugEntry(wbOnGraphicObjectMoveInd);
  5890. //
  5891. // Record that the contents have changed
  5892. //
  5893. m_changed = TRUE;
  5894. //
  5895. // These events are ignored unless we are fully registered (the client
  5896. // can do nothing about them).
  5897. //
  5898. if (m_state != STATE_IDLE)
  5899. {
  5900. TRACE_OUT(("Ignoring move of graphic object before registration"));
  5901. DC_QUIT;
  5902. }
  5903. //
  5904. // Check that this page is actually in use
  5905. //
  5906. if (GetPageState(hPage)->state != PAGE_IN_USE)
  5907. {
  5908. TRACE_OUT(("Ignoring move in page not in use"));
  5909. DC_QUIT;
  5910. }
  5911. //
  5912. // Inform the client of the object being added
  5913. //
  5914. TRACE_OUT(("Posting WBP_EVENT_GRAPHIC_MOVED"));
  5915. WBP_PostEvent(
  5916. 0, // No delay
  5917. WBP_EVENT_GRAPHIC_MOVED, // Event type
  5918. hPage, // Page handle
  5919. (UINT_PTR)pObj); // Object handle
  5920. DC_EXIT_POINT:
  5921. DebugExitVOID(wbOnGraphicObjectMoveInd);
  5922. }
  5923. //
  5924. //
  5925. // Name: wbOnObjectDeleteInd
  5926. //
  5927. // Purpose: This routine is called whenever an OM_OBJECT_DELETE_IND is
  5928. // received.
  5929. //
  5930. // Returns: Error code
  5931. //
  5932. //
  5933. BOOL WbClient::wbOnObjectDeleteInd
  5934. (
  5935. UINT_PTR param1,
  5936. POM_OBJECT pObj
  5937. )
  5938. {
  5939. POM_EVENT_DATA16 pEvent16 = (POM_EVENT_DATA16) &param1;
  5940. BOOL processed = FALSE;
  5941. DebugEntry(wbOnObjectDeleteInd);
  5942. //
  5943. // Check that the workset group is ours
  5944. //
  5945. if (pEvent16->hWSGroup != m_hWSGroup)
  5946. {
  5947. ERROR_OUT(("Event for unknown workset group = %d", pEvent16->hWSGroup));
  5948. DC_QUIT;
  5949. }
  5950. //
  5951. // We will process the event
  5952. //
  5953. processed = TRUE;
  5954. //
  5955. // Process the event according to the workset ID
  5956. //
  5957. switch(pEvent16->worksetID)
  5958. {
  5959. //
  5960. // Page Control Workset
  5961. //
  5962. case PAGE_CONTROL_WORKSET:
  5963. wbOnPageObjectDeleteInd(pObj);
  5964. break;
  5965. //
  5966. // Sync Workset
  5967. //
  5968. case SYNC_CONTROL_WORKSET:
  5969. ERROR_OUT(("Illegal object delete on sync control workset - ignored"));
  5970. //
  5971. // We do not confirm the delete since we do not want to lose the Sync
  5972. // Control Object.
  5973. //
  5974. break;
  5975. //
  5976. // User Information Workset
  5977. //
  5978. case USER_INFORMATION_WORKSET:
  5979. wbOnUserObjectDeleteInd(pObj);
  5980. break;
  5981. //
  5982. // Other (should be a Page Workset)
  5983. //
  5984. default:
  5985. wbOnGraphicObjectDeleteInd(pEvent16->worksetID, pObj);
  5986. break;
  5987. }
  5988. DC_EXIT_POINT:
  5989. DebugExitBOOL(wbOnObjectDeleteInd, processed);
  5990. return(processed);
  5991. }
  5992. //
  5993. //
  5994. // Name: wbOnPageObjectDeleteInd
  5995. //
  5996. // Purpose: This routine is called whenever an OM_OBJECT_DELETE_IND is
  5997. // received for an object in the Page Control Workset.
  5998. //
  5999. // Returns: Error code
  6000. //
  6001. //
  6002. void WbClient::wbOnPageObjectDeleteInd(POM_OBJECT pObj)
  6003. {
  6004. UINT objectType;
  6005. DebugEntry(wbOnPageObjectDeleteInd);
  6006. //
  6007. // Get the type of object that is being deleted
  6008. //
  6009. if (wbGetPageObjectType(pObj, &objectType) != 0)
  6010. {
  6011. DC_QUIT;
  6012. }
  6013. switch(objectType)
  6014. {
  6015. case TYPE_CONTROL_PAGE_ORDER:
  6016. //
  6017. // The object is the Page Control Object - something serious is wrong
  6018. // as this object should never be deleted.
  6019. //
  6020. ERROR_OUT(("Attempt to delete page control object"));
  6021. break;
  6022. case TYPE_CONTROL_LOCK:
  6023. TRACE_OUT(("Lock object being deleted"));
  6024. wbOnLockControlObjectDeleteInd(pObj);
  6025. break;
  6026. default:
  6027. ERROR_OUT(("Bad object type"));
  6028. break;
  6029. }
  6030. DC_EXIT_POINT:
  6031. DebugExitVOID(wbOnPageObjectDeleteInd);
  6032. }
  6033. //
  6034. //
  6035. // Name: wbOnLockControlObjectDeleteInd
  6036. //
  6037. // Purpose: This routine is called whenever an OM_OBJECT_DELETE_IND is
  6038. // received for a lock object in the Page Control Workset.
  6039. //
  6040. // Returns: Error code
  6041. //
  6042. //
  6043. void WbClient::wbOnLockControlObjectDeleteInd(POM_OBJECT pObj
  6044. )
  6045. {
  6046. DebugEntry(wbOnLockControlObjectDeleteInd);
  6047. //
  6048. // Confirm the delete to ObMan
  6049. //
  6050. TRACE_OUT(("Lock handle %x, expecting %x", pObj, m_pObjLock));
  6051. if (pObj != m_pObjLock)
  6052. {
  6053. WARNING_OUT(("Unexpected lock handle %x, expecting %x",
  6054. pObj, m_pObjLock));
  6055. }
  6056. OM_ObjectDeleteConfirm(m_pomClient,
  6057. m_hWSGroup,
  6058. PAGE_CONTROL_WORKSET,
  6059. pObj);
  6060. m_pObjLock = NULL;
  6061. //
  6062. // Process according to the current lock state
  6063. //
  6064. switch(m_lockState)
  6065. {
  6066. case LOCK_STATE_PENDING_DELETE:
  6067. //
  6068. // We are deleting our lock object. We must unlock the
  6069. // workset.
  6070. //
  6071. TRACE_OUT(("Our lock object delete confirmed - unlocking the workset"));
  6072. OM_WorksetUnlock(m_pomClient,
  6073. m_hWSGroup,
  6074. PAGE_CONTROL_WORKSET);
  6075. break;
  6076. case LOCK_STATE_LOCKED_OUT:
  6077. //
  6078. // The user with the lock has deleted the lock object. We treat
  6079. // this as a removal of the whiteboard lock - we reset the
  6080. // state at the end of this function.
  6081. //
  6082. TRACE_OUT(("Remote user's lock object deleted"));
  6083. break;
  6084. case LOCK_STATE_EMPTY:
  6085. //
  6086. // We have just deleted the object at the end of a call to tidy
  6087. // up. Carry on so we reset lockType / pObjPersonLock etc.
  6088. //
  6089. TRACE_OUT(("LOCK_STATE_EMPTY"));
  6090. break;
  6091. case LOCK_STATE_PENDING_LOCK:
  6092. WARNING_OUT(("LOCK_STATE_PENDING_LOCK"));
  6093. //
  6094. // We don't expect to get here. If by some chance we do, then
  6095. // just quit, since we should still get the workset lock con.
  6096. //
  6097. DC_QUIT;
  6098. break;
  6099. default:
  6100. ERROR_OUT(("Bad lock state %d", m_lockState));
  6101. break;
  6102. }
  6103. //
  6104. // The lock object has been deleted, so there is no lock active
  6105. //
  6106. m_lockType = WB_LOCK_TYPE_NONE;
  6107. m_pObjPersonLock = NULL;
  6108. //
  6109. // Record that there is now no lock
  6110. //
  6111. m_lockState = LOCK_STATE_EMPTY;
  6112. TRACE_OUT(("Moved lock state to LOCK_STATE_EMPTY"));
  6113. //
  6114. // Notify the client of the lock status change
  6115. //
  6116. wbSendLockNotification();
  6117. DC_EXIT_POINT:
  6118. DebugExitVOID(wbOnLockControlObjectDeleteInd);
  6119. }
  6120. //
  6121. //
  6122. // Name: wbOnGraphicObjectDeleteInd
  6123. //
  6124. // Purpose: This routine is called whenever an OM_OBJECT_DELETE_IND is
  6125. // received for an object in a page workset.
  6126. //
  6127. // Returns: Error code
  6128. //
  6129. //
  6130. void WbClient::wbOnGraphicObjectDeleteInd
  6131. (
  6132. OM_WORKSET_ID worksetID,
  6133. POM_OBJECT pObj
  6134. )
  6135. {
  6136. WB_PAGE_HANDLE hPage = (WB_PAGE_HANDLE)worksetID;
  6137. BOOL bConfirm = FALSE;
  6138. DebugEntry(wbOnGraphicObjectDeleteInd);
  6139. //
  6140. // Record that the contents have changed
  6141. //
  6142. m_changed = TRUE;
  6143. TRACE_OUT(("Changed flag now TRUE"));
  6144. //
  6145. // These events are handled within the core until the client is ready.
  6146. //
  6147. if (m_state != STATE_IDLE)
  6148. {
  6149. TRACE_OUT(("Delete of graphic object before registration"));
  6150. bConfirm = TRUE;
  6151. }
  6152. //
  6153. // Check that this page is actually in use
  6154. //
  6155. if (GetPageState(hPage)->state != PAGE_IN_USE)
  6156. {
  6157. TRACE_OUT(("Delete in page that is not in use"));
  6158. bConfirm = TRUE;
  6159. }
  6160. //
  6161. // Check whether we are to pass the event on to the client
  6162. //
  6163. if (bConfirm)
  6164. {
  6165. //
  6166. // Confirm the delete to ObMan
  6167. //
  6168. TRACE_OUT(("Confirming delete immediately"));
  6169. OM_ObjectDeleteConfirm(m_pomClient,
  6170. m_hWSGroup,
  6171. worksetID,
  6172. pObj);
  6173. }
  6174. else
  6175. {
  6176. //
  6177. // Inform the client of the object being added
  6178. //
  6179. TRACE_OUT(("Posting WBP_EVENT_GRAPHIC_DELETE_IND"));
  6180. WBP_PostEvent(
  6181. 0, // No delay
  6182. WBP_EVENT_GRAPHIC_DELETE_IND, // Event type
  6183. hPage, // Page handle
  6184. (UINT_PTR)pObj); // Object handle
  6185. }
  6186. DebugExitVOID(wbOnGraphicObjectDeleteInd);
  6187. }
  6188. //
  6189. //
  6190. // Name: wbOnUserObjectDeleteInd
  6191. //
  6192. // Purpose: This routine is called whenever an OM_OBJECT_DELETE_IND is
  6193. // received for an object in the User Information Workset.
  6194. //
  6195. // Returns: Error code
  6196. //
  6197. //
  6198. void WbClient::wbOnUserObjectDeleteInd
  6199. (
  6200. POM_OBJECT pObjPerson
  6201. )
  6202. {
  6203. DebugEntry(wbOnUserObjectDeleteInd);
  6204. //
  6205. // If the user which has been removed had a lock then remove its user
  6206. // handle from the client data. The lock is still there, and will be
  6207. // removed when we get the WORKSET_UNLOCK_IND for the lock workset. This
  6208. // arrives after the user-object delete, because the user workset is of
  6209. // higher priority.
  6210. //
  6211. if (m_pObjPersonLock == pObjPerson)
  6212. {
  6213. m_pObjPersonLock = NULL;
  6214. }
  6215. //
  6216. // These events are ignored unless we are fully registered (the client
  6217. // can do nothing about them).
  6218. //
  6219. if (m_state != STATE_IDLE)
  6220. {
  6221. TRACE_OUT(("Delete of user object before registration - confirming"));
  6222. //
  6223. // Confirm the delete
  6224. //
  6225. OM_ObjectDeleteConfirm(m_pomClient,
  6226. m_hWSGroup,
  6227. USER_INFORMATION_WORKSET,
  6228. pObjPerson);
  6229. //
  6230. // Nothing more to be done
  6231. //
  6232. DC_QUIT;
  6233. }
  6234. //
  6235. // Inform the client of the user leaving
  6236. //
  6237. TRACE_OUT(("Posting WBP_EVENT_USER_LEFT_IND"));
  6238. WBP_PostEvent(
  6239. 0, // No delay
  6240. WBP_EVENT_PERSON_LEFT, // Event type
  6241. 0, // No short parameter
  6242. (UINT_PTR) pObjPerson); // User object handle
  6243. DC_EXIT_POINT:
  6244. DebugExitVOID(wbOnUserObjectDeleteInd);
  6245. }
  6246. //
  6247. //
  6248. // Name: wbOnObjectUpdateInd
  6249. //
  6250. // Purpose: This routine is called whenever an OM_OBJECT_UPDATE_IND is
  6251. // received for an object in a page workset.
  6252. //
  6253. // Returns: Error code
  6254. //
  6255. //
  6256. BOOL WbClient::wbOnObjectUpdateInd
  6257. (
  6258. UINT_PTR param1,
  6259. POM_OBJECT pObj
  6260. )
  6261. {
  6262. POM_EVENT_DATA16 pEvent16 = (POM_EVENT_DATA16) &param1;
  6263. BOOL processed = FALSE;
  6264. DebugEntry(wbOnObjectUpdateInd);
  6265. //
  6266. // Check that the workset group is ours
  6267. //
  6268. if (pEvent16->hWSGroup != m_hWSGroup)
  6269. {
  6270. ERROR_OUT(("Event for unknown workset group = %d", pEvent16->hWSGroup));
  6271. DC_QUIT;
  6272. }
  6273. //
  6274. // We will process the event
  6275. //
  6276. processed = TRUE;
  6277. //
  6278. // Process the event according to the workset ID
  6279. //
  6280. switch(pEvent16->worksetID)
  6281. {
  6282. //
  6283. // Page Control Workset
  6284. //
  6285. case PAGE_CONTROL_WORKSET:
  6286. ERROR_OUT(("Illegal object update on page control workset - ignored"));
  6287. //
  6288. // Updates on the Page Control Object are not allowed - do not
  6289. // confirm it.
  6290. //
  6291. break;
  6292. //
  6293. // Lock Workset
  6294. //
  6295. case SYNC_CONTROL_WORKSET:
  6296. ERROR_OUT(("Illegal object update on sync control workset"));
  6297. //
  6298. // Updates to the Sync Control Object itself are not allowed - do not
  6299. // confirm it.
  6300. //
  6301. break;
  6302. //
  6303. // User Information Workset
  6304. //
  6305. case USER_INFORMATION_WORKSET:
  6306. wbOnUserObjectUpdateInd(pObj);
  6307. break;
  6308. //
  6309. // Other (should be a Page Workset)
  6310. //
  6311. default:
  6312. wbOnGraphicObjectUpdateInd(pEvent16->worksetID, pObj);
  6313. break;
  6314. }
  6315. DC_EXIT_POINT:
  6316. DebugExitBOOL(wbOnObjectUpdateInd, processed);
  6317. return(processed);
  6318. }
  6319. //
  6320. //
  6321. // Name: wbOnUserObjectUpdateInd
  6322. //
  6323. // Purpose: This routine is called whenever an OM_OBJECT_UPDATE_IND is
  6324. // received for an object in the User Information Workset.
  6325. //
  6326. // Returns: Error code
  6327. //
  6328. //
  6329. void WbClient::wbOnUserObjectUpdateInd(POM_OBJECT pObj)
  6330. {
  6331. DebugEntry(wbOnUserObjectUpdateInd);
  6332. //
  6333. // if the updated user object is not the local user's, and we have
  6334. // already added the local user's object, then check the color hasn't
  6335. // changed to clash with the local user's color.
  6336. //
  6337. if ( (m_pObjLocal != pObj)
  6338. && (m_pObjLocal != NULL))
  6339. {
  6340. TRACE_OUT(("Check color of updated user object"));
  6341. wbCheckPersonColor(pObj);
  6342. }
  6343. //
  6344. // Don't inform the front end if we aren't fully registered
  6345. //
  6346. if (m_state != STATE_IDLE)
  6347. {
  6348. TRACE_OUT(("User object updated before registration - confirming"));
  6349. //
  6350. // Confirm the update immediately
  6351. //
  6352. OM_ObjectUpdateConfirm(m_pomClient,
  6353. m_hWSGroup,
  6354. USER_INFORMATION_WORKSET,
  6355. pObj);
  6356. //
  6357. // Nothing more to be done
  6358. //
  6359. DC_QUIT;
  6360. }
  6361. //
  6362. // Tell the client that a user has been updated
  6363. //
  6364. TRACE_OUT(("Posting WBP_EVENT_PERSON_UPDATE_IND"));
  6365. WBP_PostEvent(
  6366. 0, // No delay
  6367. WBP_EVENT_PERSON_UPDATE, // Event type
  6368. 0, // No short parameter
  6369. (UINT_PTR) pObj); // User object handle
  6370. DC_EXIT_POINT:
  6371. DebugExitVOID(wbOnUserObjectUpdateInd);
  6372. }
  6373. //
  6374. //
  6375. // Name: wbOnUserObjectReplaceInd
  6376. //
  6377. // Purpose: This routine is called whenever an OM_OBJECT_REPLACE_IND is
  6378. // received for an object in the User Information Workset.
  6379. //
  6380. //
  6381. // Returns: Error code
  6382. //
  6383. //
  6384. void WbClient::wbOnUserObjectReplaceInd(POM_OBJECT pObj)
  6385. {
  6386. DebugEntry(wbOnUserObjectReplaceInd);
  6387. //
  6388. // if the updated user object is not the local user's, and we have
  6389. // already added the local user's object, then check the color hasn't
  6390. // changed to clash with the local user's color.
  6391. //
  6392. if ( (m_pObjLocal != pObj)
  6393. && (m_pObjLocal != NULL))
  6394. {
  6395. TRACE_OUT(("Check color of updated user object"));
  6396. wbCheckPersonColor(pObj);
  6397. }
  6398. //
  6399. // Don't inform the front end if we aren't fully registered
  6400. //
  6401. if (m_state != STATE_IDLE)
  6402. {
  6403. TRACE_OUT(("User object replaced before registration - confirming"));
  6404. //
  6405. // Confirm the replace immediately
  6406. //
  6407. OM_ObjectReplaceConfirm(m_pomClient,
  6408. m_hWSGroup,
  6409. USER_INFORMATION_WORKSET,
  6410. pObj);
  6411. //
  6412. // Nothing more to be done
  6413. //
  6414. DC_QUIT;
  6415. }
  6416. //
  6417. // Tell the client that a user has been updated
  6418. //
  6419. TRACE_OUT(("Posting WBP_EVENT_PERSON_UPDATE_IND"));
  6420. WBP_PostEvent(
  6421. 0, // No delay
  6422. WBP_EVENT_PERSON_REPLACE, // Event type
  6423. 0, // No short parameter
  6424. (UINT_PTR) pObj); // User object handle
  6425. DC_EXIT_POINT:
  6426. DebugExitVOID(wbOnUserObjectReplaceInd);
  6427. }
  6428. //
  6429. //
  6430. // Name: wbOnGraphicObjectUpdateInd
  6431. //
  6432. // Purpose: This routine is called whenever an OM_OBJECT_UPDATE_IND is
  6433. // received for an object in a page workset.
  6434. //
  6435. // Returns: Error code
  6436. //
  6437. //
  6438. void WbClient::wbOnGraphicObjectUpdateInd
  6439. (
  6440. OM_WORKSET_ID worksetID,
  6441. POM_OBJECT pObj
  6442. )
  6443. {
  6444. WB_PAGE_HANDLE hPage = (WB_PAGE_HANDLE)worksetID;
  6445. BOOL bConfirm = FALSE;
  6446. DebugEntry(wbOnGraphicObjectUpdateInd);
  6447. //
  6448. // Record that the contents have changed
  6449. //
  6450. m_changed = TRUE;
  6451. TRACE_OUT(("Changed flag now TRUE"));
  6452. //
  6453. // These events are handled within the core until the client is ready.
  6454. //
  6455. if (m_state != STATE_IDLE)
  6456. {
  6457. TRACE_OUT(("Update of graphic object before registration"));
  6458. bConfirm = TRUE;
  6459. }
  6460. //
  6461. // Check that this page is actually in use
  6462. //
  6463. if (GetPageState(hPage)->state != PAGE_IN_USE)
  6464. {
  6465. TRACE_OUT(("Update for page that is not in use"));
  6466. bConfirm = TRUE;
  6467. }
  6468. //
  6469. // Check whether we are to confirm the update now or ask the client
  6470. //
  6471. if (bConfirm)
  6472. {
  6473. //
  6474. // Confirm the update immediately
  6475. //
  6476. TRACE_OUT(("Confirming update immediately"));
  6477. OM_ObjectUpdateConfirm(m_pomClient,
  6478. m_hWSGroup,
  6479. worksetID,
  6480. pObj);
  6481. }
  6482. else
  6483. {
  6484. //
  6485. // Inform the client of the object being added
  6486. //
  6487. TRACE_OUT(("Posting WBP_EVENT_GRAPHIC_UPDATE_IND"));
  6488. WBP_PostEvent(
  6489. 0, // No delay
  6490. WBP_EVENT_GRAPHIC_UPDATE_IND, // Event type
  6491. hPage, // Page handle
  6492. (UINT_PTR)pObj); // Object handle
  6493. }
  6494. DebugExitVOID(wbOnGraphicObjectUpdateInd);
  6495. }
  6496. //
  6497. //
  6498. // Name: wbOnObjectReplaceInd
  6499. //
  6500. // Purpose: This routine is called whenever an OM_OBJECT_REPLACE_IND is
  6501. // received.
  6502. //
  6503. // Returns: Error code
  6504. //
  6505. //
  6506. BOOL WbClient::wbOnObjectReplaceInd
  6507. (
  6508. UINT_PTR param1,
  6509. POM_OBJECT pObj
  6510. )
  6511. {
  6512. POM_EVENT_DATA16 pEvent = (POM_EVENT_DATA16) &param1;
  6513. BOOL processed = FALSE;
  6514. DebugEntry(wbOnObjectReplaceInd);
  6515. //
  6516. // Check that the workset group is ours
  6517. //
  6518. if (pEvent->hWSGroup != m_hWSGroup)
  6519. {
  6520. ERROR_OUT(("Event for unknown workset group = %d", pEvent->hWSGroup));
  6521. DC_QUIT;
  6522. }
  6523. //
  6524. // We will process the event
  6525. //
  6526. processed = TRUE;
  6527. //
  6528. // Process the event according to the workset ID
  6529. //
  6530. switch (pEvent->worksetID)
  6531. {
  6532. //
  6533. // Page Control Workset
  6534. //
  6535. case PAGE_CONTROL_WORKSET:
  6536. wbOnPageObjectReplaceInd(pObj);
  6537. break;
  6538. //
  6539. // Lock Workset
  6540. //
  6541. case SYNC_CONTROL_WORKSET:
  6542. wbOnSyncObjectReplaceInd(pObj);
  6543. break;
  6544. //
  6545. // User Information Workset
  6546. //
  6547. case USER_INFORMATION_WORKSET:
  6548. wbOnUserObjectReplaceInd(pObj);
  6549. break;
  6550. //
  6551. // Other (should be a Page Workset)
  6552. //
  6553. default:
  6554. wbOnGraphicObjectReplaceInd(pEvent->worksetID, pObj);
  6555. break;
  6556. }
  6557. DC_EXIT_POINT:
  6558. DebugExitBOOL(wbOnObjectReplaceInd, processed);
  6559. return(processed);
  6560. }
  6561. //
  6562. //
  6563. // Name: wbOnPageObjectReplaceInd
  6564. //
  6565. // Purpose: This routine is called whenever the Page Control object is
  6566. // replaced.
  6567. //
  6568. // Returns: Error code
  6569. //
  6570. //
  6571. void WbClient::wbOnPageObjectReplaceInd(POM_OBJECT pObj)
  6572. {
  6573. UINT objectType;
  6574. DebugEntry(wbOnPageObjectReplaceInd);
  6575. //
  6576. // Confirm the change to ObMan (cannot fail)
  6577. //
  6578. OM_ObjectReplaceConfirm(m_pomClient,
  6579. m_hWSGroup,
  6580. PAGE_CONTROL_WORKSET,
  6581. pObj);
  6582. //
  6583. // Read the object to get its type
  6584. //
  6585. if (wbGetPageObjectType(pObj, &objectType) != 0)
  6586. {
  6587. DC_QUIT;
  6588. }
  6589. //
  6590. // Act according to the type of object added
  6591. //
  6592. switch (objectType)
  6593. {
  6594. case TYPE_CONTROL_LOCK:
  6595. wbReadLock();
  6596. break;
  6597. case TYPE_CONTROL_PAGE_ORDER:
  6598. wbOnPageControlObjectReplaceInd();
  6599. break;
  6600. default:
  6601. ERROR_OUT(("Unknown object type added to Page Control Workset"));
  6602. break;
  6603. }
  6604. DC_EXIT_POINT:
  6605. DebugExitVOID(wbOnPageObjectReplaceInd);
  6606. }
  6607. //
  6608. //
  6609. // Name: wbOnPageControlObjectReplaceInd
  6610. //
  6611. // Purpose: This routine is called whenever the Page Control object is
  6612. // replaced.
  6613. //
  6614. // Returns: Error code
  6615. //
  6616. //
  6617. void WbClient::wbOnPageControlObjectReplaceInd(void)
  6618. {
  6619. DebugEntry(wbOnPageControlObjectReplaceInd);
  6620. //
  6621. // Process according to the current state
  6622. //
  6623. switch (m_state)
  6624. {
  6625. case STATE_REGISTERING:
  6626. //
  6627. // During registration we do nothing - the Page Order is updated
  6628. // explicitly as one of the last registration actions.
  6629. //
  6630. break;
  6631. case STATE_IDLE:
  6632. //
  6633. // When we are fully registered we must send events to the front-end
  6634. // indicating what changes have been made to the page list.
  6635. //
  6636. wbProcessPageControlChanges();
  6637. break;
  6638. default:
  6639. ERROR_OUT(("Bad client major state"));
  6640. break;
  6641. }
  6642. DebugExitVOID(wbOnPageControlObjectReplaceInd);
  6643. }
  6644. //
  6645. //
  6646. // Name: wbProcessPageControlChanges
  6647. //
  6648. // Purpose: This routine is called whenever the Page Control object is
  6649. // replaced in idle state. It reads the new Page Control data
  6650. // and starts the process of informing the client of any changes.
  6651. //
  6652. // Returns: Error code
  6653. //
  6654. //
  6655. void WbClient::wbProcessPageControlChanges(void)
  6656. {
  6657. BYTE toBeMarked[WB_MAX_PAGES];
  6658. UINT indexExternal;
  6659. UINT indexInternal;
  6660. UINT lLengthExternal;
  6661. BOOL addOutstanding = TRUE;
  6662. PWB_PAGE_ORDER pPageOrderExternal;
  6663. PWB_PAGE_ORDER pPageOrderInternal = &(m_pageOrder);
  6664. PWB_PAGE_STATE pPageState;
  6665. POM_WORKSET_ID pPageExternal;
  6666. UINT countPagesExternal;
  6667. POM_OBJECTDATA pData = NULL;
  6668. DebugEntry(wbProcessPageControlChanges);
  6669. //
  6670. // Read the new Page Control Object
  6671. //
  6672. if (OM_ObjectRead(m_pomClient,
  6673. m_hWSGroup,
  6674. PAGE_CONTROL_WORKSET,
  6675. m_pObjPageControl,
  6676. &pData) != 0)
  6677. {
  6678. ERROR_OUT(("Error reading Page Control Object"));
  6679. wbError();
  6680. DC_QUIT;
  6681. }
  6682. //
  6683. // Extract details from the external page order
  6684. //
  6685. lLengthExternal = pData->length;
  6686. pPageOrderExternal = (PWB_PAGE_ORDER) pData->data;
  6687. pPageExternal = pPageOrderExternal->pages;
  6688. countPagesExternal = pPageOrderExternal->countPages;
  6689. //
  6690. // Process existing and newly added pages
  6691. //
  6692. for (indexExternal = 0; indexExternal < countPagesExternal; indexExternal++)
  6693. {
  6694. //
  6695. // Convert the index into the Page Control Object to an index into the
  6696. // internal Page List.
  6697. //
  6698. indexInternal = PAGE_WORKSET_ID_TO_INDEX(pPageExternal[indexExternal]);
  6699. //
  6700. // Test and update the internal page state as necessary
  6701. //
  6702. pPageState = &((m_pageStates)[indexInternal]);
  6703. //
  6704. // If the page is in use locally then we do not need to do anything
  6705. // (the external and internal page lists agree already).
  6706. //
  6707. if (pPageState->state != PAGE_IN_USE)
  6708. {
  6709. switch (pPageState->subState)
  6710. {
  6711. case PAGE_STATE_EMPTY:
  6712. //
  6713. // The page does not yet have a workset open for it - open one
  6714. // now. (But only open one per call to this routine to prevent
  6715. // swamping the message queue. The other outstanding opens will
  6716. // be done when this routine is next called).
  6717. //
  6718. wbPageWorksetOpen(PAGE_INDEX_TO_HANDLE(indexInternal),
  6719. OPEN_EXTERNAL);
  6720. //
  6721. // Leave now - this routine will be called again when the open
  6722. // confirm is received for the workset just opened.
  6723. //
  6724. DC_QUIT;
  6725. break;
  6726. case PAGE_STATE_LOCAL_OPEN_CONFIRM:
  6727. case PAGE_STATE_EXTERNAL_OPEN_CONFIRM:
  6728. case PAGE_STATE_EXTERNAL_ADD:
  6729. //
  6730. // Do nothing - the page is already in the add process
  6731. //
  6732. TRACE_OUT(("Page %d is already pending local add",
  6733. PAGE_INDEX_TO_HANDLE(indexInternal)));
  6734. break;
  6735. case PAGE_STATE_READY:
  6736. //
  6737. // The page workset has been opened previously - we can just mark
  6738. // the page as being in use immediately.
  6739. //
  6740. pPageState->state = PAGE_IN_USE;
  6741. pPageState->subState = PAGE_STATE_EMPTY;
  6742. TRACE_OUT(("Moved page %d state to PAGE_IN_USE",
  6743. (UINT) PAGE_INDEX_TO_HANDLE(indexInternal) ));
  6744. break;
  6745. default:
  6746. ERROR_OUT(("Bad page substate %d", pPageState->subState));
  6747. break;
  6748. }
  6749. }
  6750. }
  6751. //
  6752. // Mark any pages that no longer appear in the Page Control Object as
  6753. // "delete pending" (unless they are already marked).
  6754. //
  6755. FillMemory(toBeMarked, sizeof(toBeMarked), TRUE);
  6756. //
  6757. // Flag which pages should be marked
  6758. //
  6759. for (indexExternal = 0; indexExternal < countPagesExternal; indexExternal++)
  6760. {
  6761. toBeMarked[PAGE_WORKSET_ID_TO_INDEX(pPageExternal[indexExternal])] = 0;
  6762. }
  6763. //
  6764. // Mark them
  6765. //
  6766. for (indexInternal = 0; indexInternal < WB_MAX_PAGES; indexInternal++)
  6767. {
  6768. pPageState = &((m_pageStates)[indexInternal]);
  6769. if ( (toBeMarked[indexInternal] == 1)
  6770. && (pPageState->state == PAGE_IN_USE))
  6771. {
  6772. switch (pPageState->subState)
  6773. {
  6774. case PAGE_STATE_EMPTY:
  6775. //
  6776. // Ask the client for confirmation of the delete
  6777. //
  6778. TRACE_OUT(("Posting WBP_EVENT_PAGE_DELETE_IND"));
  6779. WBP_PostEvent(
  6780. 0, // No delay
  6781. WBP_EVENT_PAGE_DELETE_IND, // Page being deleted
  6782. PAGE_INDEX_TO_HANDLE(indexInternal), // Page handle
  6783. 0);
  6784. //
  6785. // Update the page state
  6786. //
  6787. pPageState->subState = PAGE_STATE_EXTERNAL_DELETE_CONFIRM;
  6788. TRACE_OUT(("Moved page %d substate to PAGE_STATE_EXTERNAL_DELETE_CONFIRM",
  6789. (UINT) PAGE_INDEX_TO_HANDLE(indexInternal) ));
  6790. //
  6791. // Leave now - this routine will be called again when the delete
  6792. // confirm is received for this workset.
  6793. //
  6794. DC_QUIT;
  6795. break;
  6796. case PAGE_STATE_LOCAL_DELETE:
  6797. //
  6798. // Ask the client for confirmation of the delete
  6799. //
  6800. TRACE_OUT(("Posting WBP_EVENT_PAGE_DELETE_IND"));
  6801. WBP_PostEvent(
  6802. 0, // No delay
  6803. WBP_EVENT_PAGE_DELETE_IND, // Page being deleted
  6804. PAGE_INDEX_TO_HANDLE(indexInternal), // Page handle
  6805. 0);
  6806. //
  6807. // Update the page state
  6808. //
  6809. pPageState->subState = PAGE_STATE_LOCAL_DELETE_CONFIRM;
  6810. TRACE_OUT(("Moved page %d substate to PAGE_STATE_LOCAL_DELETE_CONFIRM",
  6811. (UINT) PAGE_INDEX_TO_HANDLE(indexInternal) ));
  6812. //
  6813. // Leave now - this routine will be called again when the delete
  6814. // confirm is received for this workset.
  6815. //
  6816. DC_QUIT;
  6817. break;
  6818. case PAGE_STATE_EXTERNAL_DELETE:
  6819. case PAGE_STATE_EXTERNAL_DELETE_CONFIRM:
  6820. case PAGE_STATE_LOCAL_DELETE_CONFIRM:
  6821. //
  6822. // We are already expecting a delete for this page
  6823. //
  6824. TRACE_OUT(("Page %d is already pending local delete",
  6825. PAGE_INDEX_TO_HANDLE(indexInternal)));
  6826. DC_QUIT;
  6827. break;
  6828. default:
  6829. ERROR_OUT(("Bad page substate %d", pPageState->subState));
  6830. break;
  6831. }
  6832. }
  6833. }
  6834. //
  6835. // There are no deletes or adds outstanding now
  6836. //
  6837. //
  6838. // Copy the new page order to the internal page list
  6839. //
  6840. memcpy(pPageOrderInternal, pPageOrderExternal, lLengthExternal);
  6841. //
  6842. // Inform the client of the change
  6843. //
  6844. TRACE_OUT(("Posting WBP_EVENT_PAGE_ORDER_UPDATED"));
  6845. WBP_PostEvent(
  6846. 0, // No delay
  6847. WBP_EVENT_PAGE_ORDER_UPDATED, // Event number
  6848. 0, // No parameters
  6849. 0);
  6850. //
  6851. // Check the number of pages ready in the cache
  6852. //
  6853. wbCheckReadyPages();
  6854. DC_EXIT_POINT:
  6855. //
  6856. // Release the Page Control Object
  6857. //
  6858. if (pData != NULL)
  6859. {
  6860. OM_ObjectRelease(m_pomClient,
  6861. m_hWSGroup,
  6862. PAGE_CONTROL_WORKSET,
  6863. m_pObjPageControl,
  6864. &pData);
  6865. }
  6866. DebugExitVOID(wbProcessPageControlChanges);
  6867. }
  6868. //
  6869. //
  6870. // Name: wbOnSyncObjectReplaceInd
  6871. //
  6872. // Purpose: This routine is called whenever the Sync Control object is
  6873. // replaced.
  6874. //
  6875. // Returns: Error code
  6876. //
  6877. //
  6878. void WbClient::wbOnSyncObjectReplaceInd(POM_OBJECT pObj)
  6879. {
  6880. POM_OBJECTDATA pSyncObject;
  6881. PWB_SYNC_CONTROL pSyncControl;
  6882. OM_OBJECT_ID syncPersonID;
  6883. DebugEntry(wbOnSyncControlReplaced);
  6884. //
  6885. // Confirm the replace of the object
  6886. //
  6887. OM_ObjectReplaceConfirm(m_pomClient,
  6888. m_hWSGroup,
  6889. SYNC_CONTROL_WORKSET,
  6890. pObj);
  6891. //
  6892. // Read the object and determine whether it was written by this client or
  6893. // another.
  6894. //
  6895. if (OM_ObjectRead(m_pomClient,
  6896. m_hWSGroup,
  6897. SYNC_CONTROL_WORKSET,
  6898. m_pObjSyncControl,
  6899. &pSyncObject) != 0)
  6900. {
  6901. ERROR_OUT(("Error reading Sync Control Object"));
  6902. wbError();
  6903. DC_QUIT;
  6904. }
  6905. pSyncControl = (PWB_SYNC_CONTROL) pSyncObject->data;
  6906. //
  6907. // Get the user ID from the object
  6908. //
  6909. syncPersonID = pSyncControl->personID;
  6910. //
  6911. // Release the Sync Control Object
  6912. //
  6913. OM_ObjectRelease(m_pomClient,
  6914. m_hWSGroup,
  6915. SYNC_CONTROL_WORKSET,
  6916. m_pObjSyncControl,
  6917. &pSyncObject);
  6918. pSyncControl = NULL;
  6919. //
  6920. // If the user ID in the object is not the ID of the current client, we
  6921. // must post a message to the front-end.
  6922. //
  6923. if (memcmp(&syncPersonID,
  6924. &(m_personID),
  6925. sizeof(syncPersonID)) != 0)
  6926. {
  6927. //
  6928. // Post a "sync position updated" event to the front-end
  6929. //
  6930. TRACE_OUT(("Posting WBP_EVENT_SYNC_POSITION_UPDATED"));
  6931. WBP_PostEvent(
  6932. 0,
  6933. WBP_EVENT_SYNC_POSITION_UPDATED,
  6934. 0,
  6935. 0);
  6936. }
  6937. DC_EXIT_POINT:
  6938. DebugExitVOID(wbOnSyncControlReplaced);
  6939. }
  6940. //
  6941. //
  6942. // Name: wbOnGraphicObjectReplaceInd
  6943. //
  6944. // Purpose: This routine is called whenever an OM_OBJECT_REPLACE_IND is
  6945. // received for an object in a page workset.
  6946. //
  6947. // Returns: Error code
  6948. //
  6949. //
  6950. void WbClient::wbOnGraphicObjectReplaceInd
  6951. (
  6952. OM_WORKSET_ID worksetID,
  6953. POM_OBJECT pObj
  6954. )
  6955. {
  6956. WB_PAGE_HANDLE hPage = (WB_PAGE_HANDLE)worksetID;
  6957. BOOL bConfirm = FALSE;
  6958. DebugEntry(wbOnGraphicObjectReplaceInd);
  6959. //
  6960. // Record that the contents have changed
  6961. //
  6962. m_changed = TRUE;
  6963. TRACE_OUT(("Changed flag now TRUE"));
  6964. //
  6965. // These events are handled within the core until the client is ready.
  6966. //
  6967. if (m_state != STATE_IDLE)
  6968. {
  6969. TRACE_OUT(("Replace of graphic object before registration"));
  6970. bConfirm = TRUE;
  6971. }
  6972. //
  6973. // Check that this page is actually in use
  6974. //
  6975. if (GetPageState(hPage)->state != PAGE_IN_USE)
  6976. {
  6977. TRACE_OUT(("Replace in page that is not in use"));
  6978. bConfirm = TRUE;
  6979. }
  6980. //
  6981. // Check whether we are to pass the replace on to the client
  6982. //
  6983. if (bConfirm)
  6984. {
  6985. //
  6986. // Confirm the change to ObMan (cannot fail)
  6987. //
  6988. TRACE_OUT(("Confirming replace immediately"));
  6989. OM_ObjectReplaceConfirm(m_pomClient,
  6990. m_hWSGroup,
  6991. worksetID,
  6992. pObj);
  6993. }
  6994. else
  6995. {
  6996. //
  6997. // Inform the client of the object being added
  6998. //
  6999. TRACE_OUT(("Posting WBP_EVENT_GRAPHIC_REPLACE_IND"));
  7000. WBP_PostEvent(
  7001. 0, // No delay
  7002. WBP_EVENT_GRAPHIC_REPLACE_IND, // Event type
  7003. hPage, // Page handle
  7004. (UINT_PTR)pObj); // Object handle
  7005. }
  7006. DebugExitVOID(wbOnGraphicObjectReplaceInd);
  7007. }
  7008. //
  7009. //
  7010. // Name: wbWritePageControl
  7011. //
  7012. // Purpose: Write the page control information to the Page Control Workset
  7013. // from the copy held in client data. We write only those pages
  7014. // which are marked as being in use (and are not pending delete).
  7015. //
  7016. // Returns: Error code
  7017. //
  7018. //
  7019. UINT WbClient::wbWritePageControl(BOOL create)
  7020. {
  7021. UINT result = 0;
  7022. UINT rc;
  7023. UINT index;
  7024. UINT length;
  7025. PWB_PAGE_ORDER pPageOrderInternal = &(m_pageOrder);
  7026. PWB_PAGE_ORDER pPageOrderExternal;
  7027. WB_PAGE_HANDLE hPage;
  7028. PWB_PAGE_STATE pPageState;
  7029. POM_OBJECT pObj;
  7030. POM_OBJECTDATA pData = NULL;
  7031. UINT generation;
  7032. DebugEntry(wbWritePageControl);
  7033. //
  7034. // Allocate memory for the object.
  7035. //
  7036. length = sizeof(WB_PAGE_ORDER)
  7037. - ( (WB_MAX_PAGES - pPageOrderInternal->countPages)
  7038. * sizeof(OM_WORKSET_ID));
  7039. if (OM_ObjectAlloc(m_pomClient,
  7040. m_hWSGroup,
  7041. PAGE_CONTROL_WORKSET,
  7042. length,
  7043. &pData) != 0)
  7044. {
  7045. ERROR_OUT(("Error allocating object"));
  7046. DC_QUIT;
  7047. }
  7048. pData->length = length;
  7049. //
  7050. // Get a pointer to the page control object itself
  7051. //
  7052. pPageOrderExternal = (PWB_PAGE_ORDER) pData->data;
  7053. //
  7054. // Set the object type
  7055. //
  7056. pPageOrderExternal->objectType = TYPE_CONTROL_PAGE_ORDER;
  7057. //
  7058. // Increment the page list generation number indicating that we have
  7059. // written a new version of the page list.
  7060. //
  7061. generation = MAKELONG(pPageOrderInternal->generationLo,
  7062. pPageOrderInternal->generationHi);
  7063. generation++;
  7064. pPageOrderInternal->generationLo = LOWORD(generation);
  7065. pPageOrderInternal->generationHi = HIWORD(generation);
  7066. //
  7067. // Copy the page control data
  7068. //
  7069. pPageOrderExternal->objectType = TYPE_CONTROL_PAGE_ORDER;
  7070. pPageOrderExternal->generationLo = pPageOrderInternal->generationLo;
  7071. pPageOrderExternal->generationHi = pPageOrderInternal->generationHi;
  7072. pPageOrderExternal->countPages = 0;
  7073. //
  7074. // Loop through the internal page order finding the pages that are in
  7075. // use.
  7076. //
  7077. for (index = 0; index < pPageOrderInternal->countPages; index++)
  7078. {
  7079. //
  7080. // Get the handle of the next page
  7081. //
  7082. hPage = (pPageOrderInternal->pages)[index];
  7083. //
  7084. // Check the page state
  7085. //
  7086. pPageState = GetPageState(hPage);
  7087. if ( (pPageState->state == PAGE_IN_USE)
  7088. && (pPageState->subState == PAGE_STATE_EMPTY))
  7089. {
  7090. //
  7091. // Add the page to the external list
  7092. //
  7093. (pPageOrderExternal->pages)[pPageOrderExternal->countPages] = hPage;
  7094. pPageOrderExternal->countPages++;
  7095. }
  7096. }
  7097. //
  7098. // We expect always to copy at least one page
  7099. //
  7100. ASSERT((pPageOrderExternal->countPages >= 1));
  7101. //
  7102. // Check whether we are creating or replacing the object
  7103. //
  7104. if (create)
  7105. {
  7106. //
  7107. // Add the object to the workset (we never update these objects, so the
  7108. // update length is set to 0).
  7109. //
  7110. rc = OM_ObjectAdd(m_pomClient,
  7111. m_hWSGroup,
  7112. PAGE_CONTROL_WORKSET,
  7113. &pData,
  7114. 0,
  7115. &pObj,
  7116. LAST);
  7117. }
  7118. else
  7119. {
  7120. //
  7121. // Replace the existing object
  7122. //
  7123. TRACE_OUT(("Replacing Page Control Object"));
  7124. rc = OM_ObjectReplace(m_pomClient,
  7125. m_hWSGroup,
  7126. PAGE_CONTROL_WORKSET,
  7127. m_pObjPageControl,
  7128. &pData);
  7129. }
  7130. if (rc != 0)
  7131. {
  7132. //
  7133. // Discard the object - it was not used to replace the existing one
  7134. //
  7135. TRACE_OUT(("Adding Page Control Object"));
  7136. OM_ObjectDiscard(m_pomClient,
  7137. m_hWSGroup,
  7138. PAGE_CONTROL_WORKSET,
  7139. &pData);
  7140. ERROR_OUT(("Error adding/replacing page control object"));
  7141. DC_QUIT;
  7142. }
  7143. DC_EXIT_POINT:
  7144. DebugExitDWORD(wbWritePageControl, result);
  7145. return(result);
  7146. }
  7147. //
  7148. //
  7149. // Name: wbCreateSyncControl
  7150. //
  7151. // Purpose: Create the sync control object
  7152. //
  7153. // Returns: None
  7154. //
  7155. //
  7156. UINT WbClient::wbCreateSyncControl(void)
  7157. {
  7158. UINT result;
  7159. WB_SYNC sync;
  7160. DebugEntry(wbCreateSyncControl);
  7161. //
  7162. // Set the sync information to no page, empty rectangle
  7163. //
  7164. ZeroMemory(&sync, sizeof(WB_SYNC));
  7165. sync.length = WB_SYNC_SIZE;
  7166. sync.currentPage = WB_PAGE_HANDLE_NULL;
  7167. //
  7168. // Write the object
  7169. //
  7170. result = wbWriteSyncControl(&sync, TRUE);
  7171. DebugExitDWORD(wbCreateSyncControl, result);
  7172. return(result);
  7173. }
  7174. //
  7175. //
  7176. // Name: wbWriteSyncControl
  7177. //
  7178. // Purpose: Write the Sync Control object to the Page Control Workset
  7179. //
  7180. // Returns: Error code
  7181. //
  7182. //
  7183. UINT WbClient::wbWriteSyncControl
  7184. (
  7185. PWB_SYNC pSync,
  7186. BOOL create
  7187. )
  7188. {
  7189. UINT result = 0;
  7190. UINT rc;
  7191. POM_OBJECT pObj;
  7192. POM_OBJECTDATA pData = NULL;
  7193. PWB_SYNC_CONTROL pSyncControl;
  7194. DebugEntry(wbWriteSyncControl);
  7195. //
  7196. // Allocate memory for the object.
  7197. //
  7198. rc = OM_ObjectAlloc(m_pomClient,
  7199. m_hWSGroup,
  7200. SYNC_CONTROL_WORKSET,
  7201. WB_SYNC_CONTROL_SIZE,
  7202. &pData);
  7203. if (rc != 0)
  7204. {
  7205. ERROR_OUT(("Error allocating object"));
  7206. DC_QUIT;
  7207. }
  7208. pData->length = WB_SYNC_CONTROL_SIZE;
  7209. //
  7210. // Copy the sync control data from the client information
  7211. //
  7212. pSyncControl = (PWB_SYNC_CONTROL) pData->data;
  7213. pSyncControl->personID = m_personID;
  7214. memcpy(&(pSyncControl->sync), pSync, WB_SYNC_SIZE);
  7215. //
  7216. // Check whether we are creating or replacing the object
  7217. //
  7218. if (create)
  7219. {
  7220. //
  7221. // Add the object to the workset
  7222. //
  7223. rc = OM_ObjectAdd(m_pomClient,
  7224. m_hWSGroup,
  7225. SYNC_CONTROL_WORKSET,
  7226. &pData,
  7227. WB_SYNC_CONTROL_SIZE,
  7228. &pObj,
  7229. LAST);
  7230. //
  7231. // If successful
  7232. //
  7233. if (rc == 0)
  7234. {
  7235. //
  7236. // Save the handle of the sync control object
  7237. //
  7238. m_pObjSyncControl = pObj;
  7239. //
  7240. // Make sure we do not discard the object below
  7241. //
  7242. pData = NULL;
  7243. }
  7244. }
  7245. else
  7246. {
  7247. //
  7248. // Replace the existing object
  7249. //
  7250. rc = OM_ObjectReplace(m_pomClient,
  7251. m_hWSGroup,
  7252. SYNC_CONTROL_WORKSET,
  7253. m_pObjSyncControl,
  7254. &pData);
  7255. //
  7256. // Make sure we do not discard the object below
  7257. //
  7258. pData = NULL;
  7259. }
  7260. DC_EXIT_POINT:
  7261. //
  7262. // If we still have the Sync Control object - discard it
  7263. //
  7264. if (pData != NULL)
  7265. {
  7266. //
  7267. // Discard the object - it was not used to replace the existing one
  7268. //
  7269. OM_ObjectDiscard(m_pomClient,
  7270. m_hWSGroup,
  7271. SYNC_CONTROL_WORKSET,
  7272. &pData);
  7273. }
  7274. //
  7275. // If an error occurred during processing - report it
  7276. //
  7277. if (rc != 0)
  7278. {
  7279. ERROR_OUT(("Error adding/replacing sync control object"));
  7280. wbError();
  7281. DC_QUIT;
  7282. }
  7283. DebugExitDWORD(wbWriteSyncControl, result);
  7284. return(result);
  7285. }
  7286. //
  7287. //
  7288. // Name: wbSelectPersonColor
  7289. //
  7290. // Purpose: Select a color identifier for the local user
  7291. //
  7292. // Returns: Selected color
  7293. //
  7294. //
  7295. UINT WbClient::wbSelectPersonColor(void)
  7296. {
  7297. UINT count = 0;
  7298. UINT result;
  7299. POM_OBJECT pObjUser;
  7300. DebugEntry(wbSelectPersonColor);
  7301. //
  7302. // Select the color according to the order in the workset. See comments
  7303. // in wbCheckPersonColor for further details.
  7304. //
  7305. //
  7306. // start at the first object, search for the position of the local user's
  7307. // user object.
  7308. //
  7309. result = OM_ObjectH(m_pomClient,
  7310. m_hWSGroup,
  7311. USER_INFORMATION_WORKSET,
  7312. 0,
  7313. &pObjUser,
  7314. FIRST);
  7315. while ((result == 0) && (pObjUser != m_pObjLocal))
  7316. {
  7317. count++;
  7318. result = OM_ObjectH(m_pomClient,
  7319. m_hWSGroup,
  7320. USER_INFORMATION_WORKSET,
  7321. pObjUser,
  7322. &pObjUser,
  7323. AFTER);
  7324. }
  7325. if ((result != 0) && (result != OM_RC_NO_SUCH_OBJECT))
  7326. {
  7327. ERROR_OUT(("Unexpected return code from ObMan"));
  7328. }
  7329. DebugExitDWORD(wbSelectPersonColor, count);
  7330. return (count);
  7331. }
  7332. //
  7333. //
  7334. // Name: wbCheckPersonColor
  7335. //
  7336. // Purpose: Check whether a new user has usurped our color. If so we must
  7337. // update our own color.
  7338. //
  7339. // Returns: None
  7340. //
  7341. //
  7342. void WbClient::wbCheckPersonColor
  7343. (
  7344. POM_OBJECT hCheckObject
  7345. )
  7346. {
  7347. POM_OBJECTDATA pCheckObject = NULL;
  7348. PWB_PERSON pUser;
  7349. WB_PERSON user;
  7350. DebugEntry(wbCheckPersonColor);
  7351. //
  7352. // Read the new user information
  7353. //
  7354. if (OM_ObjectRead(m_pomClient,
  7355. m_hWSGroup,
  7356. USER_INFORMATION_WORKSET,
  7357. hCheckObject,
  7358. &pCheckObject) != 0)
  7359. {
  7360. wbError();
  7361. DC_QUIT;
  7362. }
  7363. pUser = (PWB_PERSON) pCheckObject->data;
  7364. //
  7365. // Compare the color identifier in the new user with that of the local
  7366. // user, if they are different there is nothing to do.
  7367. //
  7368. if (pUser->colorId == m_colorId)
  7369. {
  7370. TRACE_OUT(("New user has same color as local user = %d", pUser->colorId));
  7371. //
  7372. // The user color is determined by the order in the workset group of
  7373. // the user objects. The first user has color 0, the second color 1
  7374. // etc.
  7375. //
  7376. // When a user leaves the workset, however, the colors do not change.
  7377. //
  7378. // When a new user joins, it sets its color to its new position, and
  7379. // the others will then be forced to change accordingly. Whenever an
  7380. // object add or update is received where the new remote user color
  7381. // clashes with the local one, it is always the local user's job to
  7382. // change color, since the remote user has selected his new color
  7383. // according to his current position in the workset. The local user
  7384. // can't have the same position (since two users have two distinct user
  7385. // objects, so therefore must have the wrong color.
  7386. //
  7387. //
  7388. // Get the user object for the local user
  7389. //
  7390. if (wbPersonGet(m_pObjLocal, &user) != 0)
  7391. {
  7392. DC_QUIT;
  7393. }
  7394. //
  7395. // Update the color
  7396. //
  7397. TRACE_OUT(("Old color ID for local user is %d", user.colorId));
  7398. user.colorId = (TSHR_UINT16)wbSelectPersonColor();
  7399. TRACE_OUT(("New color ID for local user is %d", user.colorId));
  7400. //
  7401. // Copy the person's color into the client's data
  7402. //
  7403. m_colorId = user.colorId;
  7404. //
  7405. // Write the new user information back
  7406. //
  7407. if (wbPersonUpdate(&user) != 0)
  7408. {
  7409. DC_QUIT;
  7410. }
  7411. }
  7412. DC_EXIT_POINT:
  7413. //
  7414. // If an object has been read, release it now
  7415. //
  7416. if (pCheckObject != NULL)
  7417. {
  7418. OM_ObjectRelease(m_pomClient,
  7419. m_hWSGroup,
  7420. USER_INFORMATION_WORKSET,
  7421. hCheckObject,
  7422. &pCheckObject);
  7423. }
  7424. DebugExitVOID(wbCheckPersonColor);
  7425. }
  7426. //
  7427. //
  7428. // Name: wbWriteLock
  7429. //
  7430. // Purpose: Add a lock object to the Page Control Workset
  7431. //
  7432. // Returns: Error code
  7433. //
  7434. //
  7435. UINT WbClient::wbWriteLock(void)
  7436. {
  7437. UINT result;
  7438. POM_OBJECTDATA pData;
  7439. PWB_LOCK pLock;
  7440. POM_OBJECT pObj;
  7441. DebugEntry(wbWriteLock);
  7442. //
  7443. // Create a lock object
  7444. //
  7445. result = OM_ObjectAlloc(m_pomClient,
  7446. m_hWSGroup,
  7447. PAGE_CONTROL_WORKSET,
  7448. sizeof(WB_LOCK),
  7449. &pData);
  7450. if (result != 0)
  7451. {
  7452. ERROR_OUT(("Unable to allocate lock object = %d", result));
  7453. wbError();
  7454. DC_QUIT;
  7455. }
  7456. pData->length = sizeof(WB_LOCK);
  7457. //
  7458. // Set the lock object fields
  7459. //
  7460. pLock = (PWB_LOCK) pData->data;
  7461. pLock->objectType = TYPE_CONTROL_LOCK;
  7462. pLock->personID = m_personID;
  7463. pLock->lockType = m_lockRequestType;
  7464. //
  7465. // If we already have the lock, then we can just replace the object
  7466. //
  7467. if (m_pObjLock == NULL)
  7468. {
  7469. //
  7470. // Add the lock object to the Workset. The Add indication received
  7471. // by the remote users signals the presence of the lock to them.
  7472. //
  7473. result = OM_ObjectAdd(m_pomClient,
  7474. m_hWSGroup,
  7475. PAGE_CONTROL_WORKSET,
  7476. &pData,
  7477. sizeof(WB_LOCK),
  7478. &pObj,
  7479. LAST);
  7480. }
  7481. else
  7482. {
  7483. //
  7484. // Replace the existing object
  7485. //
  7486. result = OM_ObjectReplace(m_pomClient,
  7487. m_hWSGroup,
  7488. PAGE_CONTROL_WORKSET,
  7489. m_pObjLock,
  7490. &pData);
  7491. }
  7492. if (result != 0)
  7493. {
  7494. //
  7495. // The add or replace failed, we must discard the object
  7496. //
  7497. OM_ObjectDiscard(m_pomClient,
  7498. m_hWSGroup,
  7499. PAGE_CONTROL_WORKSET,
  7500. &pData);
  7501. ERROR_OUT(("Error adding user object"));
  7502. wbError();
  7503. DC_QUIT;
  7504. }
  7505. //
  7506. // Save the handle of the lock object
  7507. //
  7508. TRACE_OUT(("Lock handle was %x, now %x", m_pObjLock, pObj));
  7509. m_pObjLock = pObj;
  7510. DC_EXIT_POINT:
  7511. DebugExitDWORD(wbWriteLock, result);
  7512. return(result);
  7513. }
  7514. //
  7515. //
  7516. // Name: wbReadLock
  7517. //
  7518. // Purpose: Update the lock information stored in the client data after a
  7519. // change in the Lock Object.
  7520. //
  7521. // Returns: Error code
  7522. //
  7523. //
  7524. void WbClient::wbReadLock(void)
  7525. {
  7526. UINT count = 0;
  7527. DebugEntry(wbReadLock);
  7528. //
  7529. // Before we read the lock information we need to ensure that the
  7530. // PAGE_CONTROL_WORKSET and the USER_INFORMATION_WORKSET both contain
  7531. // the objects we need. If either of the objects are missing, quit and
  7532. // wait until we are called again - this function will be called
  7533. // whenever new objects are added to these worksets.
  7534. //
  7535. OM_WorksetCountObjects(m_pomClient,
  7536. m_hWSGroup,
  7537. USER_INFORMATION_WORKSET,
  7538. &count);
  7539. TRACE_OUT(("%d objects in USER_INFORMATION_WORKSET", count));
  7540. if (count == 0)
  7541. {
  7542. TRACE_OUT(("Need to wait for USER_INFO object"));
  7543. DC_QUIT;
  7544. }
  7545. OM_WorksetCountObjects(m_pomClient,
  7546. m_hWSGroup,
  7547. PAGE_CONTROL_WORKSET,
  7548. &count);
  7549. TRACE_OUT(("%d objects in PAGE_CONTROL_WORKSET", count));
  7550. if (count == 0)
  7551. {
  7552. TRACE_OUT(("Need to wait for PAGE_CONTROL object"));
  7553. DC_QUIT;
  7554. }
  7555. TRACE_OUT(("Process lock"));
  7556. wbProcessLockNotification();
  7557. DC_EXIT_POINT:
  7558. DebugExitVOID(wbReadLock);
  7559. }
  7560. //
  7561. //
  7562. // Name: wbProcessLockNotification
  7563. //
  7564. // Purpose:
  7565. //
  7566. // Returns: Error code
  7567. //
  7568. //
  7569. void WbClient::wbProcessLockNotification(void)
  7570. {
  7571. UINT rc = 0;
  7572. POM_OBJECTDATA pData;
  7573. PWB_LOCK pLock;
  7574. WB_LOCK_TYPE lockType;
  7575. POM_OBJECT pObjPersonLock;
  7576. POM_OBJECT pObj;
  7577. POM_OBJECT pObjLock;
  7578. UINT objectType = 0;
  7579. DebugEntry(wbProcessLockNotification);
  7580. //
  7581. // Get the handle of the lock object. We use the last object in the
  7582. // workset to protect against lock objects being left lying around.
  7583. //
  7584. rc = OM_ObjectH(m_pomClient,
  7585. m_hWSGroup,
  7586. PAGE_CONTROL_WORKSET,
  7587. 0,
  7588. &pObj,
  7589. LAST);
  7590. if (rc != 0)
  7591. {
  7592. ERROR_OUT(("Error getting lock object handle = %d", rc));
  7593. wbError();
  7594. DC_QUIT;
  7595. }
  7596. //
  7597. // Check that this is the CONTROL_LOCK object. Quit if it isnt - we
  7598. // will be called again later when the object arrices.
  7599. //
  7600. rc = wbGetPageObjectType(pObj, &objectType);
  7601. if (rc != 0)
  7602. {
  7603. DC_QUIT;
  7604. }
  7605. if (objectType != TYPE_CONTROL_LOCK)
  7606. {
  7607. TRACE_OUT(("not LOCK control object - quit"));
  7608. DC_QUIT;
  7609. }
  7610. //
  7611. // Save the handle of the lock object
  7612. //
  7613. pObjLock = pObj;
  7614. //
  7615. // Read the object
  7616. //
  7617. rc = OM_ObjectRead(m_pomClient,
  7618. m_hWSGroup,
  7619. PAGE_CONTROL_WORKSET,
  7620. pObj,
  7621. &pData);
  7622. if (rc != 0)
  7623. {
  7624. ERROR_OUT(("Error reading lock object %d", rc));
  7625. wbError();
  7626. DC_QUIT;
  7627. }
  7628. pLock = (PWB_LOCK) &(pData->data);
  7629. //
  7630. // Save the lock details
  7631. //
  7632. lockType = (WB_LOCK_TYPE)pLock->lockType;
  7633. TRACE_OUT(("Lock type %d", lockType));
  7634. //
  7635. // Convert the object ID held in the PAGE_CONTROL workset to an object
  7636. // handle.
  7637. //
  7638. rc = OM_ObjectIDToPtr(m_pomClient,
  7639. m_hWSGroup,
  7640. USER_INFORMATION_WORKSET,
  7641. pLock->personID,
  7642. &pObjPersonLock);
  7643. //
  7644. // The return code is checked after the object release to ensure that
  7645. // the object is not held and read again.
  7646. //
  7647. //
  7648. // Release the lock object
  7649. //
  7650. OM_ObjectRelease(m_pomClient,
  7651. m_hWSGroup,
  7652. PAGE_CONTROL_WORKSET,
  7653. pObj,
  7654. &pData);
  7655. //
  7656. // Check the return code from the ID to Handle call
  7657. //
  7658. if (rc == OM_RC_BAD_OBJECT_ID)
  7659. {
  7660. WARNING_OUT(("Unknown ID - wait for next add of user object"));
  7661. DC_QUIT;
  7662. }
  7663. else if (rc != 0)
  7664. {
  7665. ERROR_OUT(("Error (%d) converting lock user ID to handle", rc));
  7666. wbError();
  7667. DC_QUIT;
  7668. }
  7669. //
  7670. // Validate the lock state and details
  7671. //
  7672. switch (m_lockState)
  7673. {
  7674. //
  7675. // In this state we do not actually have the lock, but are waiting
  7676. // for confirmation of an earlier workset-lock request. In this
  7677. // case, we let the front end know that the lock request has failed
  7678. // before sending indication of the lock by the other user.
  7679. //
  7680. case LOCK_STATE_PENDING_LOCK:
  7681. ASSERT((pObjPersonLock != m_pObjLocal));
  7682. m_lockState = LOCK_STATE_LOCKED_OUT;
  7683. TRACE_OUT(("Moved lock state to LOCK_STATE_LOCKED_OUT"));
  7684. WBP_PostEvent(
  7685. 0, // No delay
  7686. WBP_EVENT_LOCK_FAILED, // Lock request failed
  7687. 0, // No parameters
  7688. 0);
  7689. break;
  7690. //
  7691. // In these states we do not have a lock - this must be a new lock
  7692. // from remote user or an update to an old lock.
  7693. //
  7694. case LOCK_STATE_EMPTY:
  7695. case LOCK_STATE_LOCKED_OUT:
  7696. ASSERT((pObjPersonLock != m_pObjLocal));
  7697. //
  7698. // Update the lock state to show that we are now locked out
  7699. //
  7700. m_lockState = LOCK_STATE_LOCKED_OUT;
  7701. TRACE_OUT(("Moved lock state to LOCK_STATE_LOCKED_OUT"));
  7702. break;
  7703. //
  7704. // In these states we have the lock (or are expecting to get it)
  7705. //
  7706. case LOCK_STATE_GOT_LOCK:
  7707. case LOCK_STATE_PENDING_ADD:
  7708. ASSERT((pObjPersonLock == m_pObjLocal));
  7709. //
  7710. // Update the lock state to show that we are now locked out
  7711. //
  7712. m_lockState = LOCK_STATE_GOT_LOCK;
  7713. TRACE_OUT(("Moved lock state to LOCK_STATE_GOT_LOCK"));
  7714. break;
  7715. //
  7716. // The lock request has been cancelled - unlock the WS.
  7717. //
  7718. case LOCK_STATE_CANCEL_LOCK:
  7719. break;
  7720. //
  7721. // In any other state we are not expecting any lock
  7722. //
  7723. default:
  7724. ERROR_OUT(("Not expecting lock object add"));
  7725. break;
  7726. }
  7727. //
  7728. // Save the lock details
  7729. //
  7730. TRACE_OUT(("Lock handle was %x, now %x",
  7731. m_pObjLock, pObjLock));
  7732. m_pObjLock = pObjLock;
  7733. m_lockType = lockType;
  7734. m_pObjPersonLock = pObjPersonLock;
  7735. //
  7736. // If the lock has subsequently been cancelled, unlock the WS.
  7737. //
  7738. if (m_lockState == LOCK_STATE_CANCEL_LOCK)
  7739. {
  7740. TRACE_OUT(("Cancel lock"));
  7741. m_lockState = LOCK_STATE_GOT_LOCK;
  7742. wbUnlock();
  7743. }
  7744. else
  7745. {
  7746. //
  7747. // Inform the client of the lock. The notification will be trapped
  7748. // by the core if the client is not fully registered.
  7749. //
  7750. wbSendLockNotification();
  7751. }
  7752. DC_EXIT_POINT:
  7753. DebugExitVOID(wbProcessLockNotification);
  7754. }
  7755. //
  7756. //
  7757. // Name: wbSendLockNotification
  7758. //
  7759. // Purpose: Post a lock notification to the client. The lock information
  7760. // held in the client memory must be up to date when this function
  7761. // is called.
  7762. //
  7763. // Returns: Error code
  7764. //
  7765. //
  7766. void WbClient::wbSendLockNotification(void)
  7767. {
  7768. UINT result = 0;
  7769. UINT lockEvent;
  7770. DebugEntry(wbSendLockNotification);
  7771. //
  7772. // Check that we are in a valid state for sending a lock notification
  7773. //
  7774. if ( (m_lockState == LOCK_STATE_GOT_LOCK)
  7775. || (m_lockState == LOCK_STATE_LOCKED_OUT)
  7776. || (m_lockState == LOCK_STATE_EMPTY))
  7777. {
  7778. //
  7779. // Verify the lock type
  7780. //
  7781. switch (m_lockType)
  7782. {
  7783. case WB_LOCK_TYPE_CONTENTS:
  7784. TRACE_OUT(("Posting WBP_EVENT_CONTENTS_LOCKED"));
  7785. lockEvent = WBP_EVENT_CONTENTS_LOCKED;
  7786. break;
  7787. case WB_LOCK_TYPE_PAGE_ORDER:
  7788. TRACE_OUT(("Posting WBP_EVENT_PAGE_ORDER_LOCKED"));
  7789. lockEvent = WBP_EVENT_PAGE_ORDER_LOCKED;
  7790. break;
  7791. case WB_LOCK_TYPE_NONE:
  7792. TRACE_OUT(("Posting WBP_EVENT_UNLOCKED"));
  7793. lockEvent = WBP_EVENT_UNLOCKED;
  7794. break;
  7795. default:
  7796. ERROR_OUT(("Bad lock type %d", (UINT) m_lockType));
  7797. break;
  7798. }
  7799. //
  7800. // Tell the client that the lock has been acquired or released
  7801. //
  7802. WBP_PostEvent(
  7803. 0,
  7804. lockEvent,
  7805. 0,
  7806. (UINT_PTR)m_pObjPersonLock);
  7807. TRACE_OUT(("Sent lock notification"));
  7808. }
  7809. DebugExitVOID(wbSendLockNotification);
  7810. }
  7811. //
  7812. //
  7813. // Name: wbOnWBPLock
  7814. //
  7815. // Purpose: Process a successful lock acquisitoin
  7816. //
  7817. // Returns: Error code
  7818. //
  7819. //
  7820. BOOL WbClient::wbOnWBPLock(void)
  7821. {
  7822. BOOL processed = TRUE;
  7823. DebugEntry(wbOnWBPLock);
  7824. //
  7825. // If we are registering and have just acquired the lock - we can now
  7826. // continue the registration process.
  7827. //
  7828. //
  7829. // Test the current state
  7830. //
  7831. switch (m_state)
  7832. {
  7833. //
  7834. // We are waiting for registration to continue
  7835. //
  7836. case STATE_REGISTERING:
  7837. //
  7838. // Act on the registration substate
  7839. //
  7840. if (m_subState == STATE_REG_PENDING_LOCK)
  7841. {
  7842. //
  7843. // Check that it is us who now has the lock
  7844. //
  7845. if (m_lockState != LOCK_STATE_GOT_LOCK)
  7846. {
  7847. TRACE_OUT(("It is not us who has the lock"));
  7848. //
  7849. // Another client has acquired the lock - we must wait for them
  7850. // to add the Page Control Object.
  7851. //
  7852. m_subState = STATE_REG_PENDING_PAGE_CONTROL;
  7853. TRACE_OUT(("Moved to substate STATE_REG_PENDING_PAGE_CONTROL"));
  7854. DC_QUIT;
  7855. }
  7856. //
  7857. // We now have the Page Control Workset locked - check for the
  7858. // existence of the Page Control and Sync Control objects. (We
  7859. // have to do this because another client could have locked the
  7860. // workset, added the objects and unlocked the workset just before
  7861. // we requested the lock. The Page Control Object may not have
  7862. // reached us before we requested the lock. Now that we have the
  7863. // lock we are guaranteed to have all objects in the workset so the
  7864. // object add events may have arrived just before the lock
  7865. // confirmation.
  7866. //
  7867. if ( (m_pObjPageControl != 0)
  7868. && (m_pObjSyncControl != 0))
  7869. {
  7870. //
  7871. // Unlock the workset
  7872. //
  7873. wbUnlock();
  7874. //
  7875. // Wait for the unlock to complete
  7876. //
  7877. m_subState = STATE_REG_PENDING_UNLOCK;
  7878. TRACE_OUT(("Moved to substate STATE_REG_PENDING_UNLOCK"));
  7879. DC_QUIT;
  7880. }
  7881. //
  7882. // We are the first in the call - we must add the Page Control
  7883. // Object. (It is possible that another client added the Page
  7884. // Control object and then failed. To cover this we check
  7885. // separately for the Page Control and Sync objects.)
  7886. //
  7887. if (m_pObjPageControl == 0)
  7888. {
  7889. //
  7890. // Add a single page to the page control object using the first
  7891. // page workset (which we always open).
  7892. //
  7893. wbPagesPageAdd(0, FIRST_PAGE_WORKSET,
  7894. PAGE_FIRST);
  7895. //
  7896. // Write the Page Control information
  7897. //
  7898. if (wbWritePageControl(TRUE) != 0)
  7899. {
  7900. ERROR_OUT(("Error adding Page Control Object"));
  7901. wbError();
  7902. DC_QUIT;
  7903. }
  7904. //
  7905. // Update the state to "waiting for Page Control"
  7906. //
  7907. m_subState = STATE_REG_PENDING_PAGE_CONTROL;
  7908. TRACE_OUT(("Moved to substate STATE_REG_PENDING_PAGE_CONTROL"));
  7909. DC_QUIT;
  7910. }
  7911. //
  7912. // The Page Control object is there, so the Sync Control object
  7913. // must not be (we checked above for both being there and would
  7914. // have exited by now if they were).
  7915. //
  7916. ASSERT((m_pObjSyncControl == 0));
  7917. //
  7918. // Create the Sync Control Object.
  7919. //
  7920. if (wbCreateSyncControl() != 0)
  7921. {
  7922. ERROR_OUT(("Error adding Sync Control Object"));
  7923. wbError();
  7924. DC_QUIT;
  7925. }
  7926. //
  7927. // Wait for the Sync Control object to be added
  7928. //
  7929. m_subState = STATE_REG_PENDING_SYNC_CONTROL;
  7930. TRACE_OUT(("Moved substate to STATE_REG_PENDING_SYNC_CONTROL"));
  7931. DC_QUIT;
  7932. }
  7933. break;
  7934. case STATE_IDLE:
  7935. //
  7936. // We are fully registered. The event must be passed on to the
  7937. // front-end
  7938. //
  7939. processed = FALSE;
  7940. break;
  7941. //
  7942. // We are in an unknown state
  7943. //
  7944. default:
  7945. ERROR_OUT(("Bad client major state"));
  7946. break;
  7947. }
  7948. DC_EXIT_POINT:
  7949. DebugExitBOOL(wbOnWBPLock, processed);
  7950. return(processed);
  7951. }
  7952. //
  7953. //
  7954. // Name: wbOnWBPLockFailed
  7955. //
  7956. // Purpose: Process a failed lock acquisition
  7957. //
  7958. // Returns: Error code
  7959. //
  7960. //
  7961. BOOL WbClient::wbOnWBPLockFailed(void)
  7962. {
  7963. BOOL processed = TRUE;
  7964. DebugEntry(wbOnWBPLockFailed);
  7965. //
  7966. // Check the current state
  7967. //
  7968. switch (m_state)
  7969. {
  7970. case STATE_REGISTERING:
  7971. //
  7972. // If we are registering and have just failed to acquire the lock -
  7973. // this is because another user has the lock. If both the page and
  7974. // sync objects have been added, finish registration, otherwise wait
  7975. // for them to be added.
  7976. //
  7977. if ( (m_pObjPageControl != 0) &&
  7978. (m_pObjSyncControl != 0))
  7979. {
  7980. TRACE_OUT(("Page Control and Sync Control objects both there."));
  7981. TRACE_OUT(("Registration can be completed"));
  7982. wbOnControlWorksetsReady();
  7983. DC_QUIT;
  7984. }
  7985. if (m_pObjPageControl == 0)
  7986. {
  7987. TRACE_OUT(("Waiting for page control"));
  7988. m_subState = STATE_REG_PENDING_PAGE_CONTROL;
  7989. DC_QUIT;
  7990. }
  7991. if (m_pObjSyncControl == 0)
  7992. {
  7993. TRACE_OUT(("Waiting for sync control"));
  7994. m_subState = STATE_REG_PENDING_SYNC_CONTROL;
  7995. DC_QUIT;
  7996. }
  7997. break;
  7998. case STATE_IDLE:
  7999. //
  8000. // We are fully registered. The event must be passed on to the
  8001. // front-end
  8002. //
  8003. processed = FALSE;
  8004. break;
  8005. default:
  8006. ERROR_OUT(("Bad main state"));
  8007. break;
  8008. }
  8009. DC_EXIT_POINT:
  8010. DebugExitBOOL(wbOnWBPLockFailed, processed);
  8011. return(processed);
  8012. }
  8013. //
  8014. //
  8015. // Name: wbOnWBPUnlocked
  8016. //
  8017. // Purpose: Process an unlock notification
  8018. //
  8019. // Returns: Error code
  8020. //
  8021. //
  8022. BOOL WbClient::wbOnWBPUnlocked(void)
  8023. {
  8024. BOOL processed = TRUE;
  8025. DebugEntry(wbOnWBPUnlocked);
  8026. //
  8027. // If we are registering and waiting to unlock the Page Control Workset
  8028. // we must complete registration here.
  8029. //
  8030. //
  8031. // Check the current state
  8032. //
  8033. switch (m_state)
  8034. {
  8035. case STATE_REGISTERING:
  8036. //
  8037. // Check whether we are expecting his event
  8038. //
  8039. if(m_subState == STATE_REG_PENDING_UNLOCK)
  8040. {
  8041. //
  8042. // Continue the registration process
  8043. //
  8044. wbOnControlWorksetsReady();
  8045. DC_QUIT;
  8046. }
  8047. //
  8048. // We were not expecting the unlock event
  8049. //
  8050. WARNING_OUT(("Unexpected unlock event"));
  8051. break;
  8052. case STATE_IDLE:
  8053. //
  8054. // We are fully registered. The event must be passed on to the
  8055. // front-end
  8056. //
  8057. processed = FALSE;
  8058. break;
  8059. default:
  8060. ERROR_OUT(("Bad main state"));
  8061. break;
  8062. } // Switch on client state
  8063. DC_EXIT_POINT:
  8064. DebugExitBOOL(wbOnWBPUnlocked, processed);
  8065. return(processed);
  8066. }
  8067. //
  8068. //
  8069. // Name: wbOnWBPPageOrderUpdated
  8070. //
  8071. // Purpose: Process a page order updated notification
  8072. //
  8073. // Returns: Error code
  8074. //
  8075. //
  8076. BOOL WbClient::wbOnWBPPageOrderUpdated(void)
  8077. {
  8078. BOOL processed = FALSE;
  8079. DebugEntry(wbOnWBPPageOrderUpdated);
  8080. //
  8081. // If we are registering and waiting for the Page Order to be brought
  8082. // up-to-date we can now continue registration.
  8083. //
  8084. if (m_state == STATE_REGISTERING)
  8085. {
  8086. //
  8087. // Show that we have processed the event (we do not want to pass it on
  8088. // to the client, they are not yet fully registered and will not be
  8089. // expecting it).
  8090. //
  8091. processed = TRUE;
  8092. //
  8093. // If we have enough pages ready in the cache, we have completed
  8094. // registration. (Otherwise the call to CheckReadyPages will open
  8095. // another page and will complete registration later.)
  8096. //
  8097. if (wbCheckReadyPages())
  8098. {
  8099. wbCompleteRegistration();
  8100. DC_QUIT;
  8101. }
  8102. //
  8103. // We must wait for sufficiently many pages to be ready
  8104. //
  8105. m_subState = STATE_REG_PENDING_READY_PAGES;
  8106. TRACE_OUT(("Moved substate to STATE_REG_PENDING_READY_PAGES"));
  8107. }
  8108. DC_EXIT_POINT:
  8109. DebugExitBOOL(wbOnWBPPageOrderUpdated, processed);
  8110. return(processed);
  8111. }
  8112. //
  8113. //
  8114. // Name: wbPersonGet
  8115. //
  8116. // Purpose: Get user details
  8117. //
  8118. // Returns: Error code
  8119. //
  8120. //
  8121. UINT WbClient::wbPersonGet
  8122. (
  8123. POM_OBJECT pObjUser,
  8124. PWB_PERSON pUser
  8125. )
  8126. {
  8127. UINT result = 0;
  8128. POM_OBJECTDATA pUserObject;
  8129. DebugEntry(wbPersonGet);
  8130. if (pObjUser == m_pObjLocal)
  8131. {
  8132. TRACE_OUT(("Call is for local user details"));
  8133. }
  8134. //
  8135. // Read the object.
  8136. //
  8137. result = OM_ObjectRead(m_pomClient,
  8138. m_hWSGroup,
  8139. USER_INFORMATION_WORKSET,
  8140. pObjUser,
  8141. &pUserObject);
  8142. if (result != 0)
  8143. {
  8144. ERROR_OUT(("OM_ObjectRead = %d", result));
  8145. DC_QUIT;
  8146. }
  8147. //
  8148. // Copy the read user object into the buffer passed
  8149. //
  8150. memcpy(pUser, pUserObject->data, sizeof(WB_PERSON));
  8151. TRACE_OUT(("CMG personID %u", pUser->cmgPersonID));
  8152. //
  8153. // Release the object
  8154. //
  8155. OM_ObjectRelease(m_pomClient,
  8156. m_hWSGroup,
  8157. USER_INFORMATION_WORKSET,
  8158. pObjUser,
  8159. &pUserObject);
  8160. //
  8161. // If the call is for the local user, update the color field to ensure it
  8162. // doesn't get overwritten in a race condition with the front-end (i.e.
  8163. // the front end tries to update the user before the color-change event
  8164. // has been received). The core "knows better" than ObMan what the local
  8165. // user's color is. This is safe because the color field is only ever
  8166. // changed locally.
  8167. //
  8168. if (pObjUser == m_pObjLocal)
  8169. {
  8170. pUser->colorId = (TSHR_UINT16)m_colorId;
  8171. }
  8172. DC_EXIT_POINT:
  8173. DebugExitDWORD(wbPersonGet, result);
  8174. return(result);
  8175. }
  8176. //
  8177. //
  8178. // Name: wbPersonUpdate
  8179. //
  8180. // Purpose: Update the local user object - this is only used by the CORE -
  8181. // the front-end calls WBP_SetPersonData, which does a _replace_.
  8182. //
  8183. // Returns: Error code
  8184. //
  8185. //
  8186. UINT WbClient::wbPersonUpdate(PWB_PERSON pUser)
  8187. {
  8188. UINT result = 0;
  8189. POM_OBJECTDATA pUserObject;
  8190. DebugEntry(wbPersonUpdate);
  8191. //
  8192. // Allocate a user object
  8193. //
  8194. result = OM_ObjectAlloc(m_pomClient,
  8195. m_hWSGroup,
  8196. USER_INFORMATION_WORKSET,
  8197. sizeof(WB_PERSON),
  8198. &pUserObject);
  8199. if (result != 0)
  8200. {
  8201. ERROR_OUT(("OM_ObjectAlloc = %d", result));
  8202. DC_QUIT;
  8203. }
  8204. //
  8205. // Set the length of the object
  8206. //
  8207. pUserObject->length = WB_PERSON_OBJECT_UPDATE_SIZE,
  8208. //
  8209. // Copy the user information into the ObMan object
  8210. //
  8211. memcpy(pUserObject->data, pUser, sizeof(WB_PERSON));
  8212. //
  8213. // Update the object
  8214. //
  8215. result = OM_ObjectUpdate(m_pomClient,
  8216. m_hWSGroup,
  8217. USER_INFORMATION_WORKSET,
  8218. m_pObjLocal,
  8219. &pUserObject);
  8220. if (result != 0)
  8221. {
  8222. ERROR_OUT(("OM_ObjectUpdate = %d", result));
  8223. //
  8224. // Discard the object
  8225. //
  8226. OM_ObjectDiscard(m_pomClient,
  8227. m_hWSGroup,
  8228. USER_INFORMATION_WORKSET,
  8229. &pUserObject);
  8230. DC_QUIT;
  8231. }
  8232. //
  8233. // Note that the object has not yet been updated. An
  8234. // OM_OBJECT_UPDATE_IND event will be generated.
  8235. //
  8236. DC_EXIT_POINT:
  8237. DebugExitDWORD(wbPersonUpdate, result);
  8238. return(result);
  8239. }
  8240. //
  8241. //
  8242. // Name: wbGetNetUserID().
  8243. //
  8244. // Purpose: Get the network user ID for this client
  8245. //
  8246. // Returns:
  8247. //
  8248. //
  8249. BOOL WbClient::wbGetNetUserID(void)
  8250. {
  8251. BOOL result = TRUE;
  8252. UINT rc = 0;
  8253. DebugEntry(wbGetNetUserID);
  8254. rc = OM_GetNetworkUserID(m_pomClient,
  8255. m_hWSGroup,
  8256. &m_clientNetID);
  8257. if (rc != 0)
  8258. {
  8259. if (rc == OM_RC_LOCAL_WSGROUP)
  8260. {
  8261. m_clientNetID = 0;
  8262. }
  8263. else
  8264. {
  8265. result = FALSE;
  8266. }
  8267. }
  8268. DebugExitBOOL(wbGetNetUserID, result);
  8269. return(result);
  8270. }