windows-nt/Source/XPSP1/NT/termsrv/remdsk/rds/samples/server/server.cpp

1431 lines
30 KiB
C++
Raw Permalink Normal View History

2020-09-26 03:20:57 -05:00
#include "precomp.h"
#include <initguid.h>
#include <service.h>
#include <nmmkcert.h>
//
// SERVER.CPP
// Created 4/19/2000 LauraBu
//
// Sample server-side app for remote desktop sharing
// - Holds a conference (secure)
// - Shares the desktop out when somebody calls in
// - Gives control of the shared desktop to the remote
//
// Depending on options turned on/off in the dialog we
// - automatically accepts new callers into the call
// OR
// prompts user to accept
// - automatically gives control of the shared desktop to the
// caller
// OR
// waits for caller to request control
//
// Globals
HINSTANCE g_hInst;
HWND g_hwndMain;
INmManager * g_pMgr;
INmConference * g_pConf;
IAppSharing * g_pAS;
BOOL g_fUnattended;
BOOL g_fSecurity;
CMgrNotify * g_pMgrNotify;
CConfNotify * g_pConfNotify;
UINT g_cPeopleInConf;
UINT g_cPeopleInShare;
INmChannelData * g_pPrivateChannel;
CNmDataNotify * g_pDataNotify;
#ifdef DEBUG
enum
{
ZONE_CORE = BASE_ZONE_INDEX,
};
#define MLZ_FILE_ZONE ZONE_CORE
static PTCHAR c_apszDbgZones[] =
{
TEXT("Server"),
DEFAULT_ZONES
TEXT("Core"),
};
#endif // DEBUG
//
// Main entry point
//
void __cdecl main(int argc, char **argv)
{
MSG msg;
#ifdef _DEBUG
MLZ_DbgInit((PSTR *)&c_apszDbgZones[0],
(sizeof(c_apszDbgZones) / sizeof(c_apszDbgZones[0])) - 1);
#endif
g_hInst = ::GetModuleHandle(NULL);
if (!InitServer())
{
goto Cleanup;
}
// Main message loop
while (GetMessage(&msg, NULL, 0, 0))
{
if (!g_hwndMain || !IsDialogMessage(g_hwndMain, &msg))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
Cleanup:
TermServer();
#ifdef DEBUG
MLZ_DbgDeInit();
#endif // DEBUG
ExitProcess(0);
}
//
// InitServer()
//
// Create the demo modeless dialog and initialize T.120 etc.
//
BOOL InitServer(void)
{
CoInitialize(NULL);
if (CreateDialogParam(g_hInst, MAKEINTRESOURCE(IDD_SERVERUI),
NULL, ServerDlgProc, 0) == NULL)
{
ERROR_OUT(("CreateDialog of IDD_SERVERUI failed"));
return FALSE;
}
ShowWindow(g_hwndMain, SW_SHOW);
UpdateWindow(g_hwndMain);
return TRUE;
}
//
// TermServer()
//
// Destroy the font demo modeless dialog and shutdown
//
void TermServer(void)
{
DeactivateServer();
if (g_hwndMain)
{
DestroyWindow(g_hwndMain);
g_hwndMain = NULL;
}
CoUninitialize();
}
//
// ActivateServer()
//
BOOL ActivateServer(void)
{
HRESULT hr;
HCERTSTORE hStore;
PCCERT_CONTEXT pCertContext = NULL;
//
// Initialize the calling/conf stuff
//
//
// Get NmManager object from RDCALL
//
hr = CreateNmManager(&g_pMgr);
if (FAILED(hr))
{
ERROR_OUT(("CreateNmManager failed with error 0x%08x", hr));
return FALSE;
}
//
// Register our notification objects with NmManager so we can
// find out about calls and people in the conference
//
g_pMgrNotify = new CMgrNotify();
if (!g_pMgrNotify)
{
ERROR_OUT(("new CMgrNotify() failed"));
return FALSE;
}
hr = g_pMgrNotify->Connect(g_pMgr);
if (FAILED(hr))
{
ERROR_OUT(("Connect to INmManager failed with error 0x%08x", hr));
return FALSE;
}
//
// Set up our credentials
//
//
// SALEM BUGBUG
// Currently am using the NetMeeting certificate. You will want to
// provide your own cert/credentials for real.
//
// Open the NetMeeting user certificate store.
hStore = CertOpenStore(CERT_STORE_PROV_SYSTEM,
X509_ASN_ENCODING, 0, CERT_SYSTEM_STORE_CURRENT_USER,
WSZNMSTORE);
if ( NULL != hStore )
{
// Check the store for any certificate
pCertContext = CertFindCertificateInStore(hStore,
X509_ASN_ENCODING, 0, CERT_FIND_ANY, NULL, NULL);
CertCloseStore( hStore, 0);
}
if ( NULL == pCertContext )
{
WARNING_OUT(("No server context cert found!"));
}
//
// Initialize calling with our name, properties, credentials
//
TCHAR szComputerName[MAX_PATH+1];
DWORD dwComputerNameLength = sizeof(szComputerName) / sizeof(szComputerName[0]);
if (!GetComputerName(szComputerName, &dwComputerNameLength))
{
ERROR_OUT(("GetComputerName failed"));
lstrcpy(szComputerName, "<UNKNOWN>");
}
hr = g_pMgr->Initialize(BSTRING(szComputerName), (DWORD_PTR)pCertContext,
DEFAULT_LISTEN_PORT, NMMANAGER_SERVER);
if (pCertContext)
{
CertFreeCertificateContext(pCertContext);
}
if (FAILED(hr))
{
ERROR_OUT(("INmManager Initialize failed with error 0x%08x", hr));
return FALSE;
}
//
// Create and hold a conference
//
TCHAR szConfName[MAX_PATH];
::LoadString(g_hInst, IDS_CONFERENCE_TITLE, szConfName, CCHMAX(szConfName));
BSTRING bstrConfName(szConfName);
hr = g_pMgr->CreateConference(&g_pConf, bstrConfName, NULL, g_fSecurity);
if (FAILED(hr))
{
ERROR_OUT(("CreateConference failed with error 0x%08x", hr));
return FALSE;
}
ASSERT(g_pConf);
// Connect to the conference object
ASSERT(NULL == g_pConfNotify);
g_pConfNotify = new CConfNotify();
if (NULL == g_pConfNotify)
{
ERROR_OUT(("failed to new CConfNotify"));
hr = E_OUTOFMEMORY;
}
else
{
hr = g_pConfNotify->Connect(g_pConf);
if (FAILED(hr))
{
ERROR_OUT(("Failed to connect to g_pConfNotify"));
g_pConfNotify->Release();
g_pConfNotify = NULL;
}
}
hr = g_pConf->Host();
if (FAILED(hr))
{
ERROR_OUT(("Host conference failed with error 0x%08x", hr));
return FALSE;
}
return TRUE;
}
//
// DeactivateServer()
//
void DeactivateServer(void)
{
//
// Release the AppSharing interface
//
if (g_pAS)
{
g_pAS->AllowControl(FALSE);
g_pAS->UnshareDesktop();
g_pAS->Release();
g_pAS = NULL;
g_cPeopleInShare = 0;
}
//
// Release our private data channel
//
DeactivatePrivateChannel();
//
// Leave the conference
//
if (g_pConf)
{
g_pConf->Leave();
if (g_hwndMain)
{
::SendDlgItemMessage(g_hwndMain, IDC_ROSTER, LB_RESETCONTENT, 0, 0);
}
}
//
// Disconnect from the conference if there is one currently,
// to stop getting notifications
//
if (g_pConfNotify)
{
g_pConfNotify->Disconnect();
g_pConfNotify->Release();
g_pConfNotify = NULL;
}
//
// Release the NmConference interface
//
if (g_pConf)
{
g_pConf->Release();
g_pConf = NULL;
}
g_cPeopleInConf = 0;
//
// Sleep for a second so T.120 cn clean up
//
Sleep(1000);
//
// Disconnect from NmManager to stop getting notifications
//
if (g_pMgrNotify)
{
g_pMgrNotify->Disconnect();
g_pMgrNotify->Release();
g_pMgrNotify = NULL;
}
//
// Let go of the NmManager interface. We need to sleep a bit first
// though.
//
if (g_pMgr)
{
g_pMgr->Release();
g_pMgr = NULL;
}
}
//
// ActivatePrivateChannel()
//
BOOL ActivatePrivateChannel(void)
{
HRESULT hr;
ASSERT(g_pConf);
hr = g_pConf->CreateDataChannel(&g_pPrivateChannel,
GUID_SAMPLEDATA);
if (!SUCCEEDED(hr))
{
ERROR_OUT(("CreateDataChannel failed with error 0x%08x", hr));
return FALSE;
}
g_pDataNotify = new CNmDataNotify();
if (!g_pDataNotify)
{
ERROR_OUT(("new CNmDataNotify failed"));
return FALSE;
}
hr = g_pDataNotify->Connect(g_pPrivateChannel);
if (FAILED(hr))
{
ERROR_OUT(("Connect to g_pPrivateChannel failed with error 0x%08x", hr));
return FALSE;
}
return S_OK;
}
//
// DeactivatePrivateChannel()
//
void DeactivatePrivateChannel(void)
{
if (g_pDataNotify)
{
g_pDataNotify->Disconnect();
g_pDataNotify->Release();
g_pDataNotify = NULL;
}
if (g_pPrivateChannel)
{
g_pPrivateChannel->Release();
g_pPrivateChannel = NULL;
}
}
//
// ServerDlgProc()
//
// Server demo modeless dialog handler
//
BOOL CALLBACK ServerDlgProc
(
HWND hwnd,
UINT uMsg,
WPARAM wParam,
LPARAM lParam
)
{
BOOL rc = TRUE;
switch (uMsg)
{
case WM_INITDIALOG:
{
g_hwndMain = hwnd;
break;
}
case WM_CLOSE:
{
DestroyWindow(hwnd);
break;
}
case WM_DESTROY:
{
g_hwndMain = NULL;
PostQuitMessage(0);
break;
}
case WM_COMMAND:
{
switch (GET_WM_COMMAND_ID(wParam, lParam))
{
case IDC_ACTIVATE:
{
if (ActivateServer())
{
TCHAR szText[MAX_PATH];
::SetWindowLong(GetDlgItem(hwnd, IDC_ACTIVATE), GWL_ID, IDC_DEACTIVATE);
// Change the button to deactivate
::CheckDlgButton(hwnd, IDC_DEACTIVATE, TRUE);
::LoadString(g_hInst, IDS_DEACTIVATE, szText, CCHMAX(szText));
::SetDlgItemText(hwnd, IDC_DEACTIVATE, szText);
}
else
{
DeactivateServer();
}
break;
}
case IDC_DEACTIVATE:
{
TCHAR szText[MAX_PATH];
DeactivateServer();
::SetWindowLong(GetDlgItem(hwnd, IDC_DEACTIVATE), GWL_ID, IDC_ACTIVATE);
// Change the button to activate
::CheckDlgButton(hwnd, IDC_ACTIVATE, FALSE);
::LoadString(g_hInst, IDS_ACTIVATE, szText, CCHMAX(szText));
::SetDlgItemText(hwnd, IDC_ACTIVATE, szText);
break;
}
case IDC_UNATTENDED:
{
g_fUnattended = ::IsDlgButtonChecked(hwnd, IDC_UNATTENDED);
break;
}
case IDC_SECURITY:
{
g_fSecurity = ::IsDlgButtonChecked(hwnd, IDC_SECURITY);
break;
}
case IDC_LOADAS:
{
HRESULT hr;
ASSERT(!g_pAS);
hr = CreateASObject(g_pMgrNotify, (g_fUnattended ?
AS_UNATTENDED : 0), &g_pAS);
if (FAILED(hr))
{
ERROR_OUT(("CreateASObject failed"));
}
break;
}
case IDC_UNLOADAS:
{
if (g_pAS)
{
g_pAS->AllowControl(FALSE);
g_pAS->UnshareDesktop();
g_pAS->Release();
g_pAS = NULL;
g_cPeopleInShare = 0;
}
break;
}
case IDC_SENDBUTTON:
{
SendPrivateData();
break;
}
default:
break;
}
break;
}
default:
{
rc = FALSE;
break;
}
}
return rc;
}
CMgrNotify::CMgrNotify() : RefCount(), CNotify()
{
TRACE_OUT(("CMgrNotify created"));
}
CMgrNotify::~CMgrNotify()
{
TRACE_OUT(("CMgrNotify destroyed"));
}
///////////////////////////
// CMgrNotify:IUnknown
ULONG STDMETHODCALLTYPE CMgrNotify::AddRef(void)
{
return RefCount::AddRef();
}
ULONG STDMETHODCALLTYPE CMgrNotify::Release(void)
{
return RefCount::Release();
}
HRESULT STDMETHODCALLTYPE CMgrNotify::QueryInterface(REFIID riid, PVOID *ppvObject)
{
HRESULT hr = S_OK;
TRACE_OUT(("CMgrNotify QI'd"));
if (riid == IID_IUnknown || riid == IID_INmManagerNotify)
{
*ppvObject = (INmManagerNotify *)this;
}
else
{
hr = E_NOINTERFACE;
*ppvObject = NULL;
}
if (S_OK == hr)
{
AddRef();
}
return hr;
}
////////////////////////////
// CMgrNotify:ICNotify
HRESULT STDMETHODCALLTYPE CMgrNotify::Connect(IUnknown *pUnk)
{
TRACE_OUT(("CMgrNotify::Connect"));
return CNotify::Connect(pUnk, IID_INmManagerNotify, (INmManagerNotify *)this);
}
HRESULT STDMETHODCALLTYPE CMgrNotify::Disconnect(void)
{
TRACE_OUT(("CMgrNotify::Disconnect"));
return CNotify::Disconnect();
}
//////////////////////////////////
// CMgrNotify:INmManagerNotify
HRESULT STDMETHODCALLTYPE CMgrNotify::NmUI(CONFN confn)
{
TRACE_OUT(("CMgrNotify::NmUI"));
return S_OK;
}
HRESULT STDMETHODCALLTYPE CMgrNotify::CallCreated(INmCall *pNmCall)
{
new CCallNotify(pNmCall);
TRACE_OUT(("CMgrNotify::CallCreated"));
return S_OK;
}
HRESULT STDMETHODCALLTYPE CMgrNotify::ConferenceCreated(INmConference *pConference)
{
g_cPeopleInConf = 0;
g_cPeopleInShare = 0;
ASSERT(pConference);
pConference->AddRef();
return S_OK;
}
// CMgrNotify::IAppSharingNotify
HRESULT STDMETHODCALLTYPE CMgrNotify::OnReadyToShare(BOOL fReady)
{
HRESULT hr = S_OK;
TRACE_OUT(("CMgrNotify::OnReadyToShare"));
if (g_pAS)
{
//
// Share out the desktop
//
hr = g_pAS->ShareDesktop();
if (FAILED(hr))
{
ERROR_OUT(("OnReadyToShare: sharing desktop failed: %x",hr));
}
}
return hr;
}
HRESULT STDMETHODCALLTYPE CMgrNotify::OnShareStarted()
{
TRACE_OUT(("CMgrNotify::OnShareStarted"));
return S_OK;
}
HRESULT STDMETHODCALLTYPE CMgrNotify::OnSharingStarted()
{
HRESULT hr = S_OK;
TRACE_OUT(("CMgrNotify::OnSharingStarted"));
if (g_pAS)
{
//
// Allow control
//
hr = g_pAS->AllowControl ( TRUE );
if (FAILED(hr))
{
ERROR_OUT(("OnSharingStarted: allowing control failed: %x",hr));
}
}
return hr;
}
HRESULT STDMETHODCALLTYPE CMgrNotify::OnShareEnded()
{
TRACE_OUT(("CMgrNotify::OnShareEnded"));
return S_OK;
}
HRESULT STDMETHODCALLTYPE CMgrNotify::OnPersonJoined(IAS_GCC_ID gccID)
{
TRACE_OUT(("CMgrNotify::OnPersonJoined"));
ASSERT(g_pAS);
ASSERT(g_cPeopleInShare >= 0);
g_cPeopleInShare++;
if ((g_cPeopleInShare == 2) && g_fUnattended)
{
HRESULT hr;
//
// Once we are no longer alone in the share, invite the remote party to
// take control of us.
//
ASSERT(g_pAS);
//
// Give control to the remote party
//
hr = g_pAS->GiveControl(gccID);
if (FAILED(hr))
{
ERROR_OUT(("OnPersonJoined: GiveControl to %d failed: %x",
gccID, hr));
}
}
return S_OK;
}
HRESULT STDMETHODCALLTYPE CMgrNotify::OnPersonLeft(IAS_GCC_ID gccID)
{
TRACE_OUT(("CMgrNotify::OnPersonLeft"));
ASSERT(g_pAS);
g_cPeopleInShare--;
ASSERT(g_cPeopleInShare >= 0);
return S_OK;
}
HRESULT STDMETHODCALLTYPE CMgrNotify::OnStartInControl(IAS_GCC_ID gccID)
{
TRACE_OUT(("CMgrNotify::OnStartInControl"));
return S_OK;
}
HRESULT STDMETHODCALLTYPE CMgrNotify::OnStopInControl(IAS_GCC_ID gccID)
{
TRACE_OUT(("CMgrNotify::OnStopInControl"));
return S_OK;
}
HRESULT STDMETHODCALLTYPE CMgrNotify::OnControllable(BOOL fControllable)
{
TRACE_OUT(("CMgrNotify::OnControllable"));
return S_OK;
}
HRESULT STDMETHODCALLTYPE CMgrNotify::OnStartControlled(IAS_GCC_ID gccID)
{
TRACE_OUT(("CMgrNotify::OnStartControlled"));
return S_OK;
}
HRESULT STDMETHODCALLTYPE CMgrNotify::OnStopControlled(IAS_GCC_ID gccID)
{
TRACE_OUT(("CMgrNotify::OnStopControlled"));
return S_OK;
}
//////////////////////////////////////////////////////////////////////////
// C C N F N O T I F Y
CConfNotify::CConfNotify() : RefCount(), CNotify()
{
TRACE_OUT(("CConfNotify created"));
}
CConfNotify::~CConfNotify()
{
TRACE_OUT(("CConfNotify destroyed"));
}
///////////////////////////
// CConfNotify:IUknown
ULONG STDMETHODCALLTYPE CConfNotify::AddRef(void)
{
TRACE_OUT(("CConfNotify::AddRef"));
return RefCount::AddRef();
}
ULONG STDMETHODCALLTYPE CConfNotify::Release(void)
{
TRACE_OUT(("CConfNotify::Release"));
return RefCount::Release();
}
HRESULT STDMETHODCALLTYPE CConfNotify::QueryInterface(REFIID riid, PVOID *ppvObject)
{
HRESULT hr = S_OK;
TRACE_OUT(("CConfNotify::QueryInterface"));
if (riid == IID_IUnknown)
{
TRACE_OUT(("CConfNotify::QueryInterface IID_IUnknown"));
*ppvObject = (IUnknown *)this;
}
else if (riid == IID_INmConferenceNotify)
{
TRACE_OUT(("CConfNotify::QueryInterface IID_INmConferenceNotify"));
*ppvObject = (INmConferenceNotify *)this;
}
else
{
WARNING_OUT(("CConfNotify::QueryInterface bogus"));
hr = E_NOINTERFACE;
*ppvObject = NULL;
}
if (S_OK == hr)
{
AddRef();
}
return hr;
}
////////////////////////////
// CConfNotify:ICNotify
HRESULT STDMETHODCALLTYPE CConfNotify::Connect(IUnknown *pUnk)
{
TRACE_OUT(("CConfNotify::Connect"));
return CNotify::Connect(pUnk,IID_INmConferenceNotify,(IUnknown *)this);
}
HRESULT STDMETHODCALLTYPE CConfNotify::Disconnect(void)
{
TRACE_OUT(("CConfNotify::Disconnect"));
return CNotify::Disconnect();
}
//////////////////////////////////
// CConfNotify:IConfNotify
HRESULT STDMETHODCALLTYPE CConfNotify::NmUI(CONFN uNotify)
{
TRACE_OUT(("CConfNotify::NmUI"));
TRACE_OUT(("NmUI called."));
return S_OK;
}
HRESULT STDMETHODCALLTYPE CConfNotify::StateChanged(NM_CONFERENCE_STATE uState)
{
TRACE_OUT(("CConfNotify::StateChanged"));
if (NULL == g_pConf)
return S_OK; // weird
switch (uState)
{
case NM_CONFERENCE_ACTIVE:
break;
case NM_CONFERENCE_INITIALIZING:
break; // can't do anything just yet
case NM_CONFERENCE_WAITING:
break;
case NM_CONFERENCE_IDLE:
break;
}
return S_OK;
}
HRESULT STDMETHODCALLTYPE CConfNotify::MemberChanged(NM_MEMBER_NOTIFY uNotify, INmMember *pMember)
{
HRESULT hr;
switch (uNotify)
{
case NM_MEMBER_ADDED:
{
TRACE_OUT(("CConfNotify::MemberChanged() Member added"));
ASSERT( g_cPeopleInConf >= 0 );
g_cPeopleInConf++;
//
// Add to our roster
//
ULONG id = 0;
BSTR bstrName;
pMember->GetID(&id);
hr = pMember->GetName(&bstrName);
if (FAILED(hr))
{
ERROR_OUT(("GetName of member failed"));
}
else
{
CSTRING string(bstrName);
TCHAR szName[MAX_PATH];
wsprintf(szName, "%s - %d", (LPCSTR)string, id);
::SendDlgItemMessage(g_hwndMain, IDC_ROSTER, LB_ADDSTRING,
(WPARAM)-1, (LPARAM)szName);
SysFreeString(bstrName);
}
//
// Once we are no longer alone in the conference, share the desktop
// and allow control:
//
if (1 == g_cPeopleInConf)
{
ActivatePrivateChannel();
}
else if (2 == g_cPeopleInConf)
{
TRACE_OUT(("%d parties in conf, Sharing the desktop",
g_cPeopleInConf));
PostMessage(g_hwndMain, WM_COMMAND, IDC_LOADAS, 0);
}
break;
}
case NM_MEMBER_REMOVED:
{
TRACE_OUT(("CConfNotify::MemberChanged() Member removed"));
g_cPeopleInConf--;
ASSERT( g_cPeopleInConf >= 0 );
if (0 == g_cPeopleInConf)
{
DeactivatePrivateChannel();
}
else if (1 == g_cPeopleInConf)
{
TRACE_OUT(("%d parties in conf, Unsharing the desktop",
g_cPeopleInConf));
//
// Release app sharing
//
PostMessage(g_hwndMain, WM_COMMAND, IDC_UNLOADAS, 0);
}
//
// Remove from our roster
//
ULONG id = 0;
BSTR bstrName;
pMember->GetID(&id);
hr = pMember->GetName(&bstrName);
if (FAILED(hr))
{
ERROR_OUT(("GetName of member failed"));
}
else
{
CSTRING string(bstrName);
TCHAR szName[MAX_PATH];
int iItem;
wsprintf(szName, "%s - %d", (LPCSTR)string, id);
iItem = ::SendDlgItemMessage(g_hwndMain, IDC_ROSTER,
LB_FINDSTRING, 0, (LPARAM)szName);
if (iItem != -1)
{
::SendDlgItemMessage(g_hwndMain, IDC_ROSTER, LB_DELETESTRING,
iItem, 0);
}
SysFreeString(bstrName);
}
break;
}
case NM_MEMBER_UPDATED:
{
TRACE_OUT(("CConfNotify::MemberChanged() Member updated"));
break;
}
default:
break;
}
return hr;
}
CCallNotify::CCallNotify(INmCall * pNmCall) :
m_pCall (pNmCall),
m_pszName (NULL),
m_fSelectedConference (FALSE),
m_pos (NULL),
m_cRef (1),
m_dwCookie (0)
{
HRESULT hr;
TRACE_OUT(("CCallNotify: Created %08X (INmCall=%08X)", this, pNmCall));
ASSERT(NULL != m_pCall);
m_pCall->AddRef();
// Get the display name
BSTR bstr;
hr = m_pCall->GetAddress(&bstr);
if (SUCCEEDED(hr))
{
hr = BSTR_to_LPTSTR(&m_pszName, bstr);
SysFreeString(bstr);
}
if (FEmptySz(m_pszName))
{
// Default to "another person" if no name available in the call data
m_pszName = TEXT("Somebody");
}
// These should never change
m_fIncoming = (m_pCall->IsIncoming() == S_OK);
m_dwTick = ::GetTickCount();
Update();
NmAdvise(m_pCall, this, IID_INmCallNotify, &m_dwCookie);
}
VOID CCallNotify::RemoveCall(void)
{
NmUnadvise(m_pCall, IID_INmCallNotify, m_dwCookie);
}
CCallNotify::~CCallNotify()
{
delete m_pszName;
ASSERT(NULL != m_pCall);
m_pCall->Release();
}
// IUnknown methods
STDMETHODIMP_(ULONG) CCallNotify::AddRef(void)
{
return ++m_cRef;
}
STDMETHODIMP_(ULONG) CCallNotify::Release(void)
{
ASSERT(m_cRef > 0);
if (m_cRef > 0)
{
m_cRef--;
}
ULONG cRef = m_cRef;
if (0 == cRef)
{
delete this;
}
return cRef;
}
STDMETHODIMP CCallNotify::QueryInterface(REFIID riid, PVOID *ppv)
{
HRESULT hr = S_OK;
if ((riid == IID_INmCallNotify) || (riid == IID_IUnknown))
{
*ppv = (INmCallNotify *)this;
}
else
{
hr = E_NOINTERFACE;
*ppv = NULL;
}
if (S_OK == hr)
{
AddRef();
}
return hr;
}
// INmCallNotify methods
STDMETHODIMP CCallNotify::NmUI(CONFN uNotify)
{
return S_OK;
}
STDMETHODIMP CCallNotify::StateChanged(NM_CALL_STATE uState)
{
// REVIEW: This check should be done outside of this routine
if (uState == m_State)
{
// Don't bother the UI when nothing changes!
return S_OK;
}
Update();
return S_OK;
}
STDMETHODIMP CCallNotify::Failed(ULONG uError)
{
return S_OK;
}
STDMETHODIMP CCallNotify::Accepted(INmConference *pConference)
{
return S_OK;
}
// INmCallNotify2 methods
STDMETHODIMP CCallNotify::CallError(UINT cns)
{
return S_OK;
}
STDMETHODIMP CCallNotify::RemoteConference(BOOL fMCU, BSTR *pwszConfNames, BSTR *pbstrConfToJoin)
{
return S_OK;
}
STDMETHODIMP CCallNotify::RemotePassword(BSTR bstrConference, BSTR *pbstrPassword, BYTE *pb, DWORD cb)
{
return S_OK;
}
/* U P D A T E */
/*-------------------------------------------------------------------------
%%Function: Update
Update the cached information about the call
-------------------------------------------------------------------------*/
VOID CCallNotify::Update(void)
{
m_pCall->GetState(&m_State);
// TRACE_OUT(("CCall: New State=%0d for call=%08X", m_State, this));
switch (m_State)
{
case NM_CALL_ACCEPTED:
case NM_CALL_REJECTED:
case NM_CALL_CANCELED:
{
RemoveCall();
Release();
break;
}
case NM_CALL_RING:
{
m_pCall->Accept();
break;
}
default:
ERROR_OUT(("CCall::Update: Unknown state %08X", m_State));
case NM_CALL_INVALID:
case NM_CALL_INIT:
case NM_CALL_SEARCH:
case NM_CALL_WAIT:
break;
}
}
//
// SendPrivateData()
//
void SendPrivateData(void)
{
LPSTR szData = NULL;
UINT cbData;
HRESULT hr;
if (!g_pPrivateChannel)
{
ERROR_OUT(("Can't send private data - no channel object"));
return;
}
cbData = ::SendDlgItemMessage(g_hwndMain, IDC_PRIVATESEND,
WM_GETTEXTLENGTH, 0, 0);
if (!cbData)
{
WARNING_OUT(("SendPrivateData - nothing to send"));
return;
}
cbData++;
szData = new char[cbData];
if (!szData)
{
ERROR_OUT(("SendPrivateData - unable to allocate buffer"));
return;
}
szData[cbData-1] = 0;
::SendDlgItemMessage(g_hwndMain, IDC_PRIVATESEND, WM_GETTEXT,
cbData, (LPARAM)szData);
//
// Now send the data
//
hr = g_pPrivateChannel->SendData(NULL, cbData, (LPBYTE)szData,
DATA_MEDIUM_PRIORITY | DATA_NORMAL_SEND);
if (FAILED(hr))
{
ERROR_OUT(("SendPrivateData - SendData failed"));
}
delete szData;
}
//
// CNmDataNotify
//
ULONG STDMETHODCALLTYPE CNmDataNotify::AddRef(void)
{
TRACE_OUT(("CNmDataNotify::AddRef"));
return RefCount::AddRef();
}
ULONG STDMETHODCALLTYPE CNmDataNotify::Release(void)
{
TRACE_OUT(("CNmDataNotify::Release"));
return RefCount::Release();
}
HRESULT STDMETHODCALLTYPE CNmDataNotify::QueryInterface(REFIID riid, PVOID *ppvObject)
{
HRESULT hr = S_OK;
TRACE_OUT(("CNmDataNotify::QueryInterface"));
if (riid == IID_IUnknown)
{
TRACE_OUT(("CNmDataNotify::QueryInterface IID_IUnknown"));
*ppvObject = (IUnknown *)this;
}
else if (riid == IID_INmChannelDataNotify)
{
TRACE_OUT(("CNmDataNotify::QueryInterface IID_INmChannelDataNotify"));
*ppvObject = (INmChannelDataNotify *)this;
}
else
{
WARNING_OUT(("CNmDataNotify::QueryInterface bogus"));
hr = E_NOINTERFACE;
*ppvObject = NULL;
}
if (S_OK == hr)
{
AddRef();
}
return hr;
}
////////////////////////////
// CNmDataNotify:ICNotify
HRESULT STDMETHODCALLTYPE CNmDataNotify::Connect(IUnknown *pUnk)
{
TRACE_OUT(("CNmDataNotify::Connect"));
return CNotify::Connect(pUnk,IID_INmChannelDataNotify,(IUnknown *)this);
}
HRESULT STDMETHODCALLTYPE CNmDataNotify::Disconnect(void)
{
TRACE_OUT(("CNmDataNotify::Disconnect"));
return CNotify::Disconnect();
}
HRESULT STDMETHODCALLTYPE CNmDataNotify::NmUI(CONFN uNotify)
{
TRACE_OUT(("CNmDataNotify::NmUI"));
return S_OK;
}
HRESULT STDMETHODCALLTYPE CNmDataNotify::MemberChanged(NM_MEMBER_NOTIFY uNotify, INmMember *pMember)
{
TRACE_OUT(("CNmDataNotify::MemberChanged"));
return S_OK;
}
HRESULT STDMETHODCALLTYPE CNmDataNotify::DataSent
(
INmMember * pMember,
ULONG uSize,
LPBYTE pvBuffer
)
{
TRACE_OUT(("CNmDataNotify::DataSent"));
return S_OK;
}
HRESULT STDMETHODCALLTYPE CNmDataNotify::DataReceived
(
INmMember * pMember,
ULONG uSize,
LPBYTE pvBuffer,
ULONG dwFlags
)
{
HRESULT hr;
TRACE_OUT(("CNmDataNotify::DataReceived"));
//
// Get the member's name, and add the data + name to the received
// edit field.
//
if (pMember)
{
BSTR bstrName;
hr = pMember->GetName(&bstrName);
if (SUCCEEDED(hr))
{
UINT cch;
char szName[MAX_PATH];
cch = SysStringLen(bstrName);
WideCharToMultiByte(CP_ACP, 0, bstrName, -1, szName, cch+1, NULL, NULL);
SysFreeString(bstrName);
lstrcat(szName, ": ");
::SendDlgItemMessage(g_hwndMain, IDC_PRIVATERECV, EM_REPLACESEL,
FALSE, (LPARAM)szName);
}
}
//
// Add data to the end of the edit field
//
::SendDlgItemMessage(g_hwndMain, IDC_PRIVATERECV, EM_REPLACESEL,
FALSE, (LPARAM)pvBuffer);
//
// Add carriage return to end of edit field
//
::SendDlgItemMessage(g_hwndMain, IDC_PRIVATERECV, EM_REPLACESEL,
FALSE, (LPARAM)"\r\n");
return S_OK;
}
HRESULT STDMETHODCALLTYPE CNmDataNotify::AllocateHandleConfirm
(
ULONG handle_value,
ULONG chandles
)
{
TRACE_OUT(("CNmDataNotify::AllocateHandleConfirm"));
return S_OK;
}