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.

1388 lines
28 KiB

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