1431 lines
30 KiB
C++
1431 lines
30 KiB
C++
#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;
|
|
}
|
|
|
|
|
|
|