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.

1430 lines
30 KiB

  1. #include "precomp.h"
  2. #include <initguid.h>
  3. #include <service.h>
  4. #include <nmmkcert.h>
  5. //
  6. // SERVER.CPP
  7. // Created 4/19/2000 LauraBu
  8. //
  9. // Sample server-side app for remote desktop sharing
  10. // - Holds a conference (secure)
  11. // - Shares the desktop out when somebody calls in
  12. // - Gives control of the shared desktop to the remote
  13. //
  14. // Depending on options turned on/off in the dialog we
  15. // - automatically accepts new callers into the call
  16. // OR
  17. // prompts user to accept
  18. // - automatically gives control of the shared desktop to the
  19. // caller
  20. // OR
  21. // waits for caller to request control
  22. //
  23. // Globals
  24. HINSTANCE g_hInst;
  25. HWND g_hwndMain;
  26. INmManager * g_pMgr;
  27. INmConference * g_pConf;
  28. IAppSharing * g_pAS;
  29. BOOL g_fUnattended;
  30. BOOL g_fSecurity;
  31. CMgrNotify * g_pMgrNotify;
  32. CConfNotify * g_pConfNotify;
  33. UINT g_cPeopleInConf;
  34. UINT g_cPeopleInShare;
  35. INmChannelData * g_pPrivateChannel;
  36. CNmDataNotify * g_pDataNotify;
  37. #ifdef DEBUG
  38. enum
  39. {
  40. ZONE_CORE = BASE_ZONE_INDEX,
  41. };
  42. #define MLZ_FILE_ZONE ZONE_CORE
  43. static PTCHAR c_apszDbgZones[] =
  44. {
  45. TEXT("Server"),
  46. DEFAULT_ZONES
  47. TEXT("Core"),
  48. };
  49. #endif // DEBUG
  50. //
  51. // Main entry point
  52. //
  53. void __cdecl main(int argc, char **argv)
  54. {
  55. MSG msg;
  56. #ifdef _DEBUG
  57. MLZ_DbgInit((PSTR *)&c_apszDbgZones[0],
  58. (sizeof(c_apszDbgZones) / sizeof(c_apszDbgZones[0])) - 1);
  59. #endif
  60. g_hInst = ::GetModuleHandle(NULL);
  61. if (!InitServer())
  62. {
  63. goto Cleanup;
  64. }
  65. // Main message loop
  66. while (GetMessage(&msg, NULL, 0, 0))
  67. {
  68. if (!g_hwndMain || !IsDialogMessage(g_hwndMain, &msg))
  69. {
  70. TranslateMessage(&msg);
  71. DispatchMessage(&msg);
  72. }
  73. }
  74. Cleanup:
  75. TermServer();
  76. #ifdef DEBUG
  77. MLZ_DbgDeInit();
  78. #endif // DEBUG
  79. ExitProcess(0);
  80. }
  81. //
  82. // InitServer()
  83. //
  84. // Create the demo modeless dialog and initialize T.120 etc.
  85. //
  86. BOOL InitServer(void)
  87. {
  88. CoInitialize(NULL);
  89. if (CreateDialogParam(g_hInst, MAKEINTRESOURCE(IDD_SERVERUI),
  90. NULL, ServerDlgProc, 0) == NULL)
  91. {
  92. ERROR_OUT(("CreateDialog of IDD_SERVERUI failed"));
  93. return FALSE;
  94. }
  95. ShowWindow(g_hwndMain, SW_SHOW);
  96. UpdateWindow(g_hwndMain);
  97. return TRUE;
  98. }
  99. //
  100. // TermServer()
  101. //
  102. // Destroy the font demo modeless dialog and shutdown
  103. //
  104. void TermServer(void)
  105. {
  106. DeactivateServer();
  107. if (g_hwndMain)
  108. {
  109. DestroyWindow(g_hwndMain);
  110. g_hwndMain = NULL;
  111. }
  112. CoUninitialize();
  113. }
  114. //
  115. // ActivateServer()
  116. //
  117. BOOL ActivateServer(void)
  118. {
  119. HRESULT hr;
  120. HCERTSTORE hStore;
  121. PCCERT_CONTEXT pCertContext = NULL;
  122. //
  123. // Initialize the calling/conf stuff
  124. //
  125. //
  126. // Get NmManager object from RDCALL
  127. //
  128. hr = CreateNmManager(&g_pMgr);
  129. if (FAILED(hr))
  130. {
  131. ERROR_OUT(("CreateNmManager failed with error 0x%08x", hr));
  132. return FALSE;
  133. }
  134. //
  135. // Register our notification objects with NmManager so we can
  136. // find out about calls and people in the conference
  137. //
  138. g_pMgrNotify = new CMgrNotify();
  139. if (!g_pMgrNotify)
  140. {
  141. ERROR_OUT(("new CMgrNotify() failed"));
  142. return FALSE;
  143. }
  144. hr = g_pMgrNotify->Connect(g_pMgr);
  145. if (FAILED(hr))
  146. {
  147. ERROR_OUT(("Connect to INmManager failed with error 0x%08x", hr));
  148. return FALSE;
  149. }
  150. //
  151. // Set up our credentials
  152. //
  153. //
  154. // SALEM BUGBUG
  155. // Currently am using the NetMeeting certificate. You will want to
  156. // provide your own cert/credentials for real.
  157. //
  158. // Open the NetMeeting user certificate store.
  159. hStore = CertOpenStore(CERT_STORE_PROV_SYSTEM,
  160. X509_ASN_ENCODING, 0, CERT_SYSTEM_STORE_CURRENT_USER,
  161. WSZNMSTORE);
  162. if ( NULL != hStore )
  163. {
  164. // Check the store for any certificate
  165. pCertContext = CertFindCertificateInStore(hStore,
  166. X509_ASN_ENCODING, 0, CERT_FIND_ANY, NULL, NULL);
  167. CertCloseStore( hStore, 0);
  168. }
  169. if ( NULL == pCertContext )
  170. {
  171. WARNING_OUT(("No server context cert found!"));
  172. }
  173. //
  174. // Initialize calling with our name, properties, credentials
  175. //
  176. TCHAR szComputerName[MAX_PATH+1];
  177. DWORD dwComputerNameLength = sizeof(szComputerName) / sizeof(szComputerName[0]);
  178. if (!GetComputerName(szComputerName, &dwComputerNameLength))
  179. {
  180. ERROR_OUT(("GetComputerName failed"));
  181. lstrcpy(szComputerName, "<UNKNOWN>");
  182. }
  183. hr = g_pMgr->Initialize(BSTRING(szComputerName), (DWORD_PTR)pCertContext,
  184. DEFAULT_LISTEN_PORT, NMMANAGER_SERVER);
  185. if (pCertContext)
  186. {
  187. CertFreeCertificateContext(pCertContext);
  188. }
  189. if (FAILED(hr))
  190. {
  191. ERROR_OUT(("INmManager Initialize failed with error 0x%08x", hr));
  192. return FALSE;
  193. }
  194. //
  195. // Create and hold a conference
  196. //
  197. TCHAR szConfName[MAX_PATH];
  198. ::LoadString(g_hInst, IDS_CONFERENCE_TITLE, szConfName, CCHMAX(szConfName));
  199. BSTRING bstrConfName(szConfName);
  200. hr = g_pMgr->CreateConference(&g_pConf, bstrConfName, NULL, g_fSecurity);
  201. if (FAILED(hr))
  202. {
  203. ERROR_OUT(("CreateConference failed with error 0x%08x", hr));
  204. return FALSE;
  205. }
  206. ASSERT(g_pConf);
  207. // Connect to the conference object
  208. ASSERT(NULL == g_pConfNotify);
  209. g_pConfNotify = new CConfNotify();
  210. if (NULL == g_pConfNotify)
  211. {
  212. ERROR_OUT(("failed to new CConfNotify"));
  213. hr = E_OUTOFMEMORY;
  214. }
  215. else
  216. {
  217. hr = g_pConfNotify->Connect(g_pConf);
  218. if (FAILED(hr))
  219. {
  220. ERROR_OUT(("Failed to connect to g_pConfNotify"));
  221. g_pConfNotify->Release();
  222. g_pConfNotify = NULL;
  223. }
  224. }
  225. hr = g_pConf->Host();
  226. if (FAILED(hr))
  227. {
  228. ERROR_OUT(("Host conference failed with error 0x%08x", hr));
  229. return FALSE;
  230. }
  231. return TRUE;
  232. }
  233. //
  234. // DeactivateServer()
  235. //
  236. void DeactivateServer(void)
  237. {
  238. //
  239. // Release the AppSharing interface
  240. //
  241. if (g_pAS)
  242. {
  243. g_pAS->AllowControl(FALSE);
  244. g_pAS->UnshareDesktop();
  245. g_pAS->Release();
  246. g_pAS = NULL;
  247. g_cPeopleInShare = 0;
  248. }
  249. //
  250. // Release our private data channel
  251. //
  252. DeactivatePrivateChannel();
  253. //
  254. // Leave the conference
  255. //
  256. if (g_pConf)
  257. {
  258. g_pConf->Leave();
  259. if (g_hwndMain)
  260. {
  261. ::SendDlgItemMessage(g_hwndMain, IDC_ROSTER, LB_RESETCONTENT, 0, 0);
  262. }
  263. }
  264. //
  265. // Disconnect from the conference if there is one currently,
  266. // to stop getting notifications
  267. //
  268. if (g_pConfNotify)
  269. {
  270. g_pConfNotify->Disconnect();
  271. g_pConfNotify->Release();
  272. g_pConfNotify = NULL;
  273. }
  274. //
  275. // Release the NmConference interface
  276. //
  277. if (g_pConf)
  278. {
  279. g_pConf->Release();
  280. g_pConf = NULL;
  281. }
  282. g_cPeopleInConf = 0;
  283. //
  284. // Sleep for a second so T.120 cn clean up
  285. //
  286. Sleep(1000);
  287. //
  288. // Disconnect from NmManager to stop getting notifications
  289. //
  290. if (g_pMgrNotify)
  291. {
  292. g_pMgrNotify->Disconnect();
  293. g_pMgrNotify->Release();
  294. g_pMgrNotify = NULL;
  295. }
  296. //
  297. // Let go of the NmManager interface. We need to sleep a bit first
  298. // though.
  299. //
  300. if (g_pMgr)
  301. {
  302. g_pMgr->Release();
  303. g_pMgr = NULL;
  304. }
  305. }
  306. //
  307. // ActivatePrivateChannel()
  308. //
  309. BOOL ActivatePrivateChannel(void)
  310. {
  311. HRESULT hr;
  312. ASSERT(g_pConf);
  313. hr = g_pConf->CreateDataChannel(&g_pPrivateChannel,
  314. GUID_SAMPLEDATA);
  315. if (!SUCCEEDED(hr))
  316. {
  317. ERROR_OUT(("CreateDataChannel failed with error 0x%08x", hr));
  318. return FALSE;
  319. }
  320. g_pDataNotify = new CNmDataNotify();
  321. if (!g_pDataNotify)
  322. {
  323. ERROR_OUT(("new CNmDataNotify failed"));
  324. return FALSE;
  325. }
  326. hr = g_pDataNotify->Connect(g_pPrivateChannel);
  327. if (FAILED(hr))
  328. {
  329. ERROR_OUT(("Connect to g_pPrivateChannel failed with error 0x%08x", hr));
  330. return FALSE;
  331. }
  332. return S_OK;
  333. }
  334. //
  335. // DeactivatePrivateChannel()
  336. //
  337. void DeactivatePrivateChannel(void)
  338. {
  339. if (g_pDataNotify)
  340. {
  341. g_pDataNotify->Disconnect();
  342. g_pDataNotify->Release();
  343. g_pDataNotify = NULL;
  344. }
  345. if (g_pPrivateChannel)
  346. {
  347. g_pPrivateChannel->Release();
  348. g_pPrivateChannel = NULL;
  349. }
  350. }
  351. //
  352. // ServerDlgProc()
  353. //
  354. // Server demo modeless dialog handler
  355. //
  356. BOOL CALLBACK ServerDlgProc
  357. (
  358. HWND hwnd,
  359. UINT uMsg,
  360. WPARAM wParam,
  361. LPARAM lParam
  362. )
  363. {
  364. BOOL rc = TRUE;
  365. switch (uMsg)
  366. {
  367. case WM_INITDIALOG:
  368. {
  369. g_hwndMain = hwnd;
  370. break;
  371. }
  372. case WM_CLOSE:
  373. {
  374. DestroyWindow(hwnd);
  375. break;
  376. }
  377. case WM_DESTROY:
  378. {
  379. g_hwndMain = NULL;
  380. PostQuitMessage(0);
  381. break;
  382. }
  383. case WM_COMMAND:
  384. {
  385. switch (GET_WM_COMMAND_ID(wParam, lParam))
  386. {
  387. case IDC_ACTIVATE:
  388. {
  389. if (ActivateServer())
  390. {
  391. TCHAR szText[MAX_PATH];
  392. ::SetWindowLong(GetDlgItem(hwnd, IDC_ACTIVATE), GWL_ID, IDC_DEACTIVATE);
  393. // Change the button to deactivate
  394. ::CheckDlgButton(hwnd, IDC_DEACTIVATE, TRUE);
  395. ::LoadString(g_hInst, IDS_DEACTIVATE, szText, CCHMAX(szText));
  396. ::SetDlgItemText(hwnd, IDC_DEACTIVATE, szText);
  397. }
  398. else
  399. {
  400. DeactivateServer();
  401. }
  402. break;
  403. }
  404. case IDC_DEACTIVATE:
  405. {
  406. TCHAR szText[MAX_PATH];
  407. DeactivateServer();
  408. ::SetWindowLong(GetDlgItem(hwnd, IDC_DEACTIVATE), GWL_ID, IDC_ACTIVATE);
  409. // Change the button to activate
  410. ::CheckDlgButton(hwnd, IDC_ACTIVATE, FALSE);
  411. ::LoadString(g_hInst, IDS_ACTIVATE, szText, CCHMAX(szText));
  412. ::SetDlgItemText(hwnd, IDC_ACTIVATE, szText);
  413. break;
  414. }
  415. case IDC_UNATTENDED:
  416. {
  417. g_fUnattended = ::IsDlgButtonChecked(hwnd, IDC_UNATTENDED);
  418. break;
  419. }
  420. case IDC_SECURITY:
  421. {
  422. g_fSecurity = ::IsDlgButtonChecked(hwnd, IDC_SECURITY);
  423. break;
  424. }
  425. case IDC_LOADAS:
  426. {
  427. HRESULT hr;
  428. ASSERT(!g_pAS);
  429. hr = CreateASObject(g_pMgrNotify, (g_fUnattended ?
  430. AS_UNATTENDED : 0), &g_pAS);
  431. if (FAILED(hr))
  432. {
  433. ERROR_OUT(("CreateASObject failed"));
  434. }
  435. break;
  436. }
  437. case IDC_UNLOADAS:
  438. {
  439. if (g_pAS)
  440. {
  441. g_pAS->AllowControl(FALSE);
  442. g_pAS->UnshareDesktop();
  443. g_pAS->Release();
  444. g_pAS = NULL;
  445. g_cPeopleInShare = 0;
  446. }
  447. break;
  448. }
  449. case IDC_SENDBUTTON:
  450. {
  451. SendPrivateData();
  452. break;
  453. }
  454. default:
  455. break;
  456. }
  457. break;
  458. }
  459. default:
  460. {
  461. rc = FALSE;
  462. break;
  463. }
  464. }
  465. return rc;
  466. }
  467. CMgrNotify::CMgrNotify() : RefCount(), CNotify()
  468. {
  469. TRACE_OUT(("CMgrNotify created"));
  470. }
  471. CMgrNotify::~CMgrNotify()
  472. {
  473. TRACE_OUT(("CMgrNotify destroyed"));
  474. }
  475. ///////////////////////////
  476. // CMgrNotify:IUnknown
  477. ULONG STDMETHODCALLTYPE CMgrNotify::AddRef(void)
  478. {
  479. return RefCount::AddRef();
  480. }
  481. ULONG STDMETHODCALLTYPE CMgrNotify::Release(void)
  482. {
  483. return RefCount::Release();
  484. }
  485. HRESULT STDMETHODCALLTYPE CMgrNotify::QueryInterface(REFIID riid, PVOID *ppvObject)
  486. {
  487. HRESULT hr = S_OK;
  488. TRACE_OUT(("CMgrNotify QI'd"));
  489. if (riid == IID_IUnknown || riid == IID_INmManagerNotify)
  490. {
  491. *ppvObject = (INmManagerNotify *)this;
  492. }
  493. else
  494. {
  495. hr = E_NOINTERFACE;
  496. *ppvObject = NULL;
  497. }
  498. if (S_OK == hr)
  499. {
  500. AddRef();
  501. }
  502. return hr;
  503. }
  504. ////////////////////////////
  505. // CMgrNotify:ICNotify
  506. HRESULT STDMETHODCALLTYPE CMgrNotify::Connect(IUnknown *pUnk)
  507. {
  508. TRACE_OUT(("CMgrNotify::Connect"));
  509. return CNotify::Connect(pUnk, IID_INmManagerNotify, (INmManagerNotify *)this);
  510. }
  511. HRESULT STDMETHODCALLTYPE CMgrNotify::Disconnect(void)
  512. {
  513. TRACE_OUT(("CMgrNotify::Disconnect"));
  514. return CNotify::Disconnect();
  515. }
  516. //////////////////////////////////
  517. // CMgrNotify:INmManagerNotify
  518. HRESULT STDMETHODCALLTYPE CMgrNotify::NmUI(CONFN confn)
  519. {
  520. TRACE_OUT(("CMgrNotify::NmUI"));
  521. return S_OK;
  522. }
  523. HRESULT STDMETHODCALLTYPE CMgrNotify::CallCreated(INmCall *pNmCall)
  524. {
  525. new CCallNotify(pNmCall);
  526. TRACE_OUT(("CMgrNotify::CallCreated"));
  527. return S_OK;
  528. }
  529. HRESULT STDMETHODCALLTYPE CMgrNotify::ConferenceCreated(INmConference *pConference)
  530. {
  531. g_cPeopleInConf = 0;
  532. g_cPeopleInShare = 0;
  533. ASSERT(pConference);
  534. pConference->AddRef();
  535. return S_OK;
  536. }
  537. // CMgrNotify::IAppSharingNotify
  538. HRESULT STDMETHODCALLTYPE CMgrNotify::OnReadyToShare(BOOL fReady)
  539. {
  540. HRESULT hr = S_OK;
  541. TRACE_OUT(("CMgrNotify::OnReadyToShare"));
  542. if (g_pAS)
  543. {
  544. //
  545. // Share out the desktop
  546. //
  547. hr = g_pAS->ShareDesktop();
  548. if (FAILED(hr))
  549. {
  550. ERROR_OUT(("OnReadyToShare: sharing desktop failed: %x",hr));
  551. }
  552. }
  553. return hr;
  554. }
  555. HRESULT STDMETHODCALLTYPE CMgrNotify::OnShareStarted()
  556. {
  557. TRACE_OUT(("CMgrNotify::OnShareStarted"));
  558. return S_OK;
  559. }
  560. HRESULT STDMETHODCALLTYPE CMgrNotify::OnSharingStarted()
  561. {
  562. HRESULT hr = S_OK;
  563. TRACE_OUT(("CMgrNotify::OnSharingStarted"));
  564. if (g_pAS)
  565. {
  566. //
  567. // Allow control
  568. //
  569. hr = g_pAS->AllowControl ( TRUE );
  570. if (FAILED(hr))
  571. {
  572. ERROR_OUT(("OnSharingStarted: allowing control failed: %x",hr));
  573. }
  574. }
  575. return hr;
  576. }
  577. HRESULT STDMETHODCALLTYPE CMgrNotify::OnShareEnded()
  578. {
  579. TRACE_OUT(("CMgrNotify::OnShareEnded"));
  580. return S_OK;
  581. }
  582. HRESULT STDMETHODCALLTYPE CMgrNotify::OnPersonJoined(IAS_GCC_ID gccID)
  583. {
  584. TRACE_OUT(("CMgrNotify::OnPersonJoined"));
  585. ASSERT(g_pAS);
  586. ASSERT(g_cPeopleInShare >= 0);
  587. g_cPeopleInShare++;
  588. if ((g_cPeopleInShare == 2) && g_fUnattended)
  589. {
  590. HRESULT hr;
  591. //
  592. // Once we are no longer alone in the share, invite the remote party to
  593. // take control of us.
  594. //
  595. ASSERT(g_pAS);
  596. //
  597. // Give control to the remote party
  598. //
  599. hr = g_pAS->GiveControl(gccID);
  600. if (FAILED(hr))
  601. {
  602. ERROR_OUT(("OnPersonJoined: GiveControl to %d failed: %x",
  603. gccID, hr));
  604. }
  605. }
  606. return S_OK;
  607. }
  608. HRESULT STDMETHODCALLTYPE CMgrNotify::OnPersonLeft(IAS_GCC_ID gccID)
  609. {
  610. TRACE_OUT(("CMgrNotify::OnPersonLeft"));
  611. ASSERT(g_pAS);
  612. g_cPeopleInShare--;
  613. ASSERT(g_cPeopleInShare >= 0);
  614. return S_OK;
  615. }
  616. HRESULT STDMETHODCALLTYPE CMgrNotify::OnStartInControl(IAS_GCC_ID gccID)
  617. {
  618. TRACE_OUT(("CMgrNotify::OnStartInControl"));
  619. return S_OK;
  620. }
  621. HRESULT STDMETHODCALLTYPE CMgrNotify::OnStopInControl(IAS_GCC_ID gccID)
  622. {
  623. TRACE_OUT(("CMgrNotify::OnStopInControl"));
  624. return S_OK;
  625. }
  626. HRESULT STDMETHODCALLTYPE CMgrNotify::OnControllable(BOOL fControllable)
  627. {
  628. TRACE_OUT(("CMgrNotify::OnControllable"));
  629. return S_OK;
  630. }
  631. HRESULT STDMETHODCALLTYPE CMgrNotify::OnStartControlled(IAS_GCC_ID gccID)
  632. {
  633. TRACE_OUT(("CMgrNotify::OnStartControlled"));
  634. return S_OK;
  635. }
  636. HRESULT STDMETHODCALLTYPE CMgrNotify::OnStopControlled(IAS_GCC_ID gccID)
  637. {
  638. TRACE_OUT(("CMgrNotify::OnStopControlled"));
  639. return S_OK;
  640. }
  641. //////////////////////////////////////////////////////////////////////////
  642. // C C N F N O T I F Y
  643. CConfNotify::CConfNotify() : RefCount(), CNotify()
  644. {
  645. TRACE_OUT(("CConfNotify created"));
  646. }
  647. CConfNotify::~CConfNotify()
  648. {
  649. TRACE_OUT(("CConfNotify destroyed"));
  650. }
  651. ///////////////////////////
  652. // CConfNotify:IUknown
  653. ULONG STDMETHODCALLTYPE CConfNotify::AddRef(void)
  654. {
  655. TRACE_OUT(("CConfNotify::AddRef"));
  656. return RefCount::AddRef();
  657. }
  658. ULONG STDMETHODCALLTYPE CConfNotify::Release(void)
  659. {
  660. TRACE_OUT(("CConfNotify::Release"));
  661. return RefCount::Release();
  662. }
  663. HRESULT STDMETHODCALLTYPE CConfNotify::QueryInterface(REFIID riid, PVOID *ppvObject)
  664. {
  665. HRESULT hr = S_OK;
  666. TRACE_OUT(("CConfNotify::QueryInterface"));
  667. if (riid == IID_IUnknown)
  668. {
  669. TRACE_OUT(("CConfNotify::QueryInterface IID_IUnknown"));
  670. *ppvObject = (IUnknown *)this;
  671. }
  672. else if (riid == IID_INmConferenceNotify)
  673. {
  674. TRACE_OUT(("CConfNotify::QueryInterface IID_INmConferenceNotify"));
  675. *ppvObject = (INmConferenceNotify *)this;
  676. }
  677. else
  678. {
  679. WARNING_OUT(("CConfNotify::QueryInterface bogus"));
  680. hr = E_NOINTERFACE;
  681. *ppvObject = NULL;
  682. }
  683. if (S_OK == hr)
  684. {
  685. AddRef();
  686. }
  687. return hr;
  688. }
  689. ////////////////////////////
  690. // CConfNotify:ICNotify
  691. HRESULT STDMETHODCALLTYPE CConfNotify::Connect(IUnknown *pUnk)
  692. {
  693. TRACE_OUT(("CConfNotify::Connect"));
  694. return CNotify::Connect(pUnk,IID_INmConferenceNotify,(IUnknown *)this);
  695. }
  696. HRESULT STDMETHODCALLTYPE CConfNotify::Disconnect(void)
  697. {
  698. TRACE_OUT(("CConfNotify::Disconnect"));
  699. return CNotify::Disconnect();
  700. }
  701. //////////////////////////////////
  702. // CConfNotify:IConfNotify
  703. HRESULT STDMETHODCALLTYPE CConfNotify::NmUI(CONFN uNotify)
  704. {
  705. TRACE_OUT(("CConfNotify::NmUI"));
  706. TRACE_OUT(("NmUI called."));
  707. return S_OK;
  708. }
  709. HRESULT STDMETHODCALLTYPE CConfNotify::StateChanged(NM_CONFERENCE_STATE uState)
  710. {
  711. TRACE_OUT(("CConfNotify::StateChanged"));
  712. if (NULL == g_pConf)
  713. return S_OK; // weird
  714. switch (uState)
  715. {
  716. case NM_CONFERENCE_ACTIVE:
  717. break;
  718. case NM_CONFERENCE_INITIALIZING:
  719. break; // can't do anything just yet
  720. case NM_CONFERENCE_WAITING:
  721. break;
  722. case NM_CONFERENCE_IDLE:
  723. break;
  724. }
  725. return S_OK;
  726. }
  727. HRESULT STDMETHODCALLTYPE CConfNotify::MemberChanged(NM_MEMBER_NOTIFY uNotify, INmMember *pMember)
  728. {
  729. HRESULT hr;
  730. switch (uNotify)
  731. {
  732. case NM_MEMBER_ADDED:
  733. {
  734. TRACE_OUT(("CConfNotify::MemberChanged() Member added"));
  735. ASSERT( g_cPeopleInConf >= 0 );
  736. g_cPeopleInConf++;
  737. //
  738. // Add to our roster
  739. //
  740. ULONG id = 0;
  741. BSTR bstrName;
  742. pMember->GetID(&id);
  743. hr = pMember->GetName(&bstrName);
  744. if (FAILED(hr))
  745. {
  746. ERROR_OUT(("GetName of member failed"));
  747. }
  748. else
  749. {
  750. CSTRING string(bstrName);
  751. TCHAR szName[MAX_PATH];
  752. wsprintf(szName, "%s - %d", (LPCSTR)string, id);
  753. ::SendDlgItemMessage(g_hwndMain, IDC_ROSTER, LB_ADDSTRING,
  754. (WPARAM)-1, (LPARAM)szName);
  755. SysFreeString(bstrName);
  756. }
  757. //
  758. // Once we are no longer alone in the conference, share the desktop
  759. // and allow control:
  760. //
  761. if (1 == g_cPeopleInConf)
  762. {
  763. ActivatePrivateChannel();
  764. }
  765. else if (2 == g_cPeopleInConf)
  766. {
  767. TRACE_OUT(("%d parties in conf, Sharing the desktop",
  768. g_cPeopleInConf));
  769. PostMessage(g_hwndMain, WM_COMMAND, IDC_LOADAS, 0);
  770. }
  771. break;
  772. }
  773. case NM_MEMBER_REMOVED:
  774. {
  775. TRACE_OUT(("CConfNotify::MemberChanged() Member removed"));
  776. g_cPeopleInConf--;
  777. ASSERT( g_cPeopleInConf >= 0 );
  778. if (0 == g_cPeopleInConf)
  779. {
  780. DeactivatePrivateChannel();
  781. }
  782. else if (1 == g_cPeopleInConf)
  783. {
  784. TRACE_OUT(("%d parties in conf, Unsharing the desktop",
  785. g_cPeopleInConf));
  786. //
  787. // Release app sharing
  788. //
  789. PostMessage(g_hwndMain, WM_COMMAND, IDC_UNLOADAS, 0);
  790. }
  791. //
  792. // Remove from our roster
  793. //
  794. ULONG id = 0;
  795. BSTR bstrName;
  796. pMember->GetID(&id);
  797. hr = pMember->GetName(&bstrName);
  798. if (FAILED(hr))
  799. {
  800. ERROR_OUT(("GetName of member failed"));
  801. }
  802. else
  803. {
  804. CSTRING string(bstrName);
  805. TCHAR szName[MAX_PATH];
  806. int iItem;
  807. wsprintf(szName, "%s - %d", (LPCSTR)string, id);
  808. iItem = ::SendDlgItemMessage(g_hwndMain, IDC_ROSTER,
  809. LB_FINDSTRING, 0, (LPARAM)szName);
  810. if (iItem != -1)
  811. {
  812. ::SendDlgItemMessage(g_hwndMain, IDC_ROSTER, LB_DELETESTRING,
  813. iItem, 0);
  814. }
  815. SysFreeString(bstrName);
  816. }
  817. break;
  818. }
  819. case NM_MEMBER_UPDATED:
  820. {
  821. TRACE_OUT(("CConfNotify::MemberChanged() Member updated"));
  822. break;
  823. }
  824. default:
  825. break;
  826. }
  827. return hr;
  828. }
  829. CCallNotify::CCallNotify(INmCall * pNmCall) :
  830. m_pCall (pNmCall),
  831. m_pszName (NULL),
  832. m_fSelectedConference (FALSE),
  833. m_pos (NULL),
  834. m_cRef (1),
  835. m_dwCookie (0)
  836. {
  837. HRESULT hr;
  838. TRACE_OUT(("CCallNotify: Created %08X (INmCall=%08X)", this, pNmCall));
  839. ASSERT(NULL != m_pCall);
  840. m_pCall->AddRef();
  841. // Get the display name
  842. BSTR bstr;
  843. hr = m_pCall->GetAddress(&bstr);
  844. if (SUCCEEDED(hr))
  845. {
  846. hr = BSTR_to_LPTSTR(&m_pszName, bstr);
  847. SysFreeString(bstr);
  848. }
  849. if (FEmptySz(m_pszName))
  850. {
  851. // Default to "another person" if no name available in the call data
  852. m_pszName = TEXT("Somebody");
  853. }
  854. // These should never change
  855. m_fIncoming = (m_pCall->IsIncoming() == S_OK);
  856. m_dwTick = ::GetTickCount();
  857. Update();
  858. NmAdvise(m_pCall, this, IID_INmCallNotify, &m_dwCookie);
  859. }
  860. VOID CCallNotify::RemoveCall(void)
  861. {
  862. NmUnadvise(m_pCall, IID_INmCallNotify, m_dwCookie);
  863. }
  864. CCallNotify::~CCallNotify()
  865. {
  866. delete m_pszName;
  867. ASSERT(NULL != m_pCall);
  868. m_pCall->Release();
  869. }
  870. // IUnknown methods
  871. STDMETHODIMP_(ULONG) CCallNotify::AddRef(void)
  872. {
  873. return ++m_cRef;
  874. }
  875. STDMETHODIMP_(ULONG) CCallNotify::Release(void)
  876. {
  877. ASSERT(m_cRef > 0);
  878. if (m_cRef > 0)
  879. {
  880. m_cRef--;
  881. }
  882. ULONG cRef = m_cRef;
  883. if (0 == cRef)
  884. {
  885. delete this;
  886. }
  887. return cRef;
  888. }
  889. STDMETHODIMP CCallNotify::QueryInterface(REFIID riid, PVOID *ppv)
  890. {
  891. HRESULT hr = S_OK;
  892. if ((riid == IID_INmCallNotify) || (riid == IID_IUnknown))
  893. {
  894. *ppv = (INmCallNotify *)this;
  895. }
  896. else
  897. {
  898. hr = E_NOINTERFACE;
  899. *ppv = NULL;
  900. }
  901. if (S_OK == hr)
  902. {
  903. AddRef();
  904. }
  905. return hr;
  906. }
  907. // INmCallNotify methods
  908. STDMETHODIMP CCallNotify::NmUI(CONFN uNotify)
  909. {
  910. return S_OK;
  911. }
  912. STDMETHODIMP CCallNotify::StateChanged(NM_CALL_STATE uState)
  913. {
  914. // REVIEW: This check should be done outside of this routine
  915. if (uState == m_State)
  916. {
  917. // Don't bother the UI when nothing changes!
  918. return S_OK;
  919. }
  920. Update();
  921. return S_OK;
  922. }
  923. STDMETHODIMP CCallNotify::Failed(ULONG uError)
  924. {
  925. return S_OK;
  926. }
  927. STDMETHODIMP CCallNotify::Accepted(INmConference *pConference)
  928. {
  929. return S_OK;
  930. }
  931. // INmCallNotify2 methods
  932. STDMETHODIMP CCallNotify::CallError(UINT cns)
  933. {
  934. return S_OK;
  935. }
  936. STDMETHODIMP CCallNotify::RemoteConference(BOOL fMCU, BSTR *pwszConfNames, BSTR *pbstrConfToJoin)
  937. {
  938. return S_OK;
  939. }
  940. STDMETHODIMP CCallNotify::RemotePassword(BSTR bstrConference, BSTR *pbstrPassword, BYTE *pb, DWORD cb)
  941. {
  942. return S_OK;
  943. }
  944. /* U P D A T E */
  945. /*-------------------------------------------------------------------------
  946. %%Function: Update
  947. Update the cached information about the call
  948. -------------------------------------------------------------------------*/
  949. VOID CCallNotify::Update(void)
  950. {
  951. m_pCall->GetState(&m_State);
  952. // TRACE_OUT(("CCall: New State=%0d for call=%08X", m_State, this));
  953. switch (m_State)
  954. {
  955. case NM_CALL_ACCEPTED:
  956. case NM_CALL_REJECTED:
  957. case NM_CALL_CANCELED:
  958. {
  959. RemoveCall();
  960. Release();
  961. break;
  962. }
  963. case NM_CALL_RING:
  964. {
  965. m_pCall->Accept();
  966. break;
  967. }
  968. default:
  969. ERROR_OUT(("CCall::Update: Unknown state %08X", m_State));
  970. case NM_CALL_INVALID:
  971. case NM_CALL_INIT:
  972. case NM_CALL_SEARCH:
  973. case NM_CALL_WAIT:
  974. break;
  975. }
  976. }
  977. //
  978. // SendPrivateData()
  979. //
  980. void SendPrivateData(void)
  981. {
  982. LPSTR szData = NULL;
  983. UINT cbData;
  984. HRESULT hr;
  985. if (!g_pPrivateChannel)
  986. {
  987. ERROR_OUT(("Can't send private data - no channel object"));
  988. return;
  989. }
  990. cbData = ::SendDlgItemMessage(g_hwndMain, IDC_PRIVATESEND,
  991. WM_GETTEXTLENGTH, 0, 0);
  992. if (!cbData)
  993. {
  994. WARNING_OUT(("SendPrivateData - nothing to send"));
  995. return;
  996. }
  997. cbData++;
  998. szData = new char[cbData];
  999. if (!szData)
  1000. {
  1001. ERROR_OUT(("SendPrivateData - unable to allocate buffer"));
  1002. return;
  1003. }
  1004. szData[cbData-1] = 0;
  1005. ::SendDlgItemMessage(g_hwndMain, IDC_PRIVATESEND, WM_GETTEXT,
  1006. cbData, (LPARAM)szData);
  1007. //
  1008. // Now send the data
  1009. //
  1010. hr = g_pPrivateChannel->SendData(NULL, cbData, (LPBYTE)szData,
  1011. DATA_MEDIUM_PRIORITY | DATA_NORMAL_SEND);
  1012. if (FAILED(hr))
  1013. {
  1014. ERROR_OUT(("SendPrivateData - SendData failed"));
  1015. }
  1016. delete szData;
  1017. }
  1018. //
  1019. // CNmDataNotify
  1020. //
  1021. ULONG STDMETHODCALLTYPE CNmDataNotify::AddRef(void)
  1022. {
  1023. TRACE_OUT(("CNmDataNotify::AddRef"));
  1024. return RefCount::AddRef();
  1025. }
  1026. ULONG STDMETHODCALLTYPE CNmDataNotify::Release(void)
  1027. {
  1028. TRACE_OUT(("CNmDataNotify::Release"));
  1029. return RefCount::Release();
  1030. }
  1031. HRESULT STDMETHODCALLTYPE CNmDataNotify::QueryInterface(REFIID riid, PVOID *ppvObject)
  1032. {
  1033. HRESULT hr = S_OK;
  1034. TRACE_OUT(("CNmDataNotify::QueryInterface"));
  1035. if (riid == IID_IUnknown)
  1036. {
  1037. TRACE_OUT(("CNmDataNotify::QueryInterface IID_IUnknown"));
  1038. *ppvObject = (IUnknown *)this;
  1039. }
  1040. else if (riid == IID_INmChannelDataNotify)
  1041. {
  1042. TRACE_OUT(("CNmDataNotify::QueryInterface IID_INmChannelDataNotify"));
  1043. *ppvObject = (INmChannelDataNotify *)this;
  1044. }
  1045. else
  1046. {
  1047. WARNING_OUT(("CNmDataNotify::QueryInterface bogus"));
  1048. hr = E_NOINTERFACE;
  1049. *ppvObject = NULL;
  1050. }
  1051. if (S_OK == hr)
  1052. {
  1053. AddRef();
  1054. }
  1055. return hr;
  1056. }
  1057. ////////////////////////////
  1058. // CNmDataNotify:ICNotify
  1059. HRESULT STDMETHODCALLTYPE CNmDataNotify::Connect(IUnknown *pUnk)
  1060. {
  1061. TRACE_OUT(("CNmDataNotify::Connect"));
  1062. return CNotify::Connect(pUnk,IID_INmChannelDataNotify,(IUnknown *)this);
  1063. }
  1064. HRESULT STDMETHODCALLTYPE CNmDataNotify::Disconnect(void)
  1065. {
  1066. TRACE_OUT(("CNmDataNotify::Disconnect"));
  1067. return CNotify::Disconnect();
  1068. }
  1069. HRESULT STDMETHODCALLTYPE CNmDataNotify::NmUI(CONFN uNotify)
  1070. {
  1071. TRACE_OUT(("CNmDataNotify::NmUI"));
  1072. return S_OK;
  1073. }
  1074. HRESULT STDMETHODCALLTYPE CNmDataNotify::MemberChanged(NM_MEMBER_NOTIFY uNotify, INmMember *pMember)
  1075. {
  1076. TRACE_OUT(("CNmDataNotify::MemberChanged"));
  1077. return S_OK;
  1078. }
  1079. HRESULT STDMETHODCALLTYPE CNmDataNotify::DataSent
  1080. (
  1081. INmMember * pMember,
  1082. ULONG uSize,
  1083. LPBYTE pvBuffer
  1084. )
  1085. {
  1086. TRACE_OUT(("CNmDataNotify::DataSent"));
  1087. return S_OK;
  1088. }
  1089. HRESULT STDMETHODCALLTYPE CNmDataNotify::DataReceived
  1090. (
  1091. INmMember * pMember,
  1092. ULONG uSize,
  1093. LPBYTE pvBuffer,
  1094. ULONG dwFlags
  1095. )
  1096. {
  1097. HRESULT hr;
  1098. TRACE_OUT(("CNmDataNotify::DataReceived"));
  1099. //
  1100. // Get the member's name, and add the data + name to the received
  1101. // edit field.
  1102. //
  1103. if (pMember)
  1104. {
  1105. BSTR bstrName;
  1106. hr = pMember->GetName(&bstrName);
  1107. if (SUCCEEDED(hr))
  1108. {
  1109. UINT cch;
  1110. char szName[MAX_PATH];
  1111. cch = SysStringLen(bstrName);
  1112. WideCharToMultiByte(CP_ACP, 0, bstrName, -1, szName, cch+1, NULL, NULL);
  1113. SysFreeString(bstrName);
  1114. lstrcat(szName, ": ");
  1115. ::SendDlgItemMessage(g_hwndMain, IDC_PRIVATERECV, EM_REPLACESEL,
  1116. FALSE, (LPARAM)szName);
  1117. }
  1118. }
  1119. //
  1120. // Add data to the end of the edit field
  1121. //
  1122. ::SendDlgItemMessage(g_hwndMain, IDC_PRIVATERECV, EM_REPLACESEL,
  1123. FALSE, (LPARAM)pvBuffer);
  1124. //
  1125. // Add carriage return to end of edit field
  1126. //
  1127. ::SendDlgItemMessage(g_hwndMain, IDC_PRIVATERECV, EM_REPLACESEL,
  1128. FALSE, (LPARAM)"\r\n");
  1129. return S_OK;
  1130. }
  1131. HRESULT STDMETHODCALLTYPE CNmDataNotify::AllocateHandleConfirm
  1132. (
  1133. ULONG handle_value,
  1134. ULONG chandles
  1135. )
  1136. {
  1137. TRACE_OUT(("CNmDataNotify::AllocateHandleConfirm"));
  1138. return S_OK;
  1139. }