Figure 1   NetMeeting Objects and Interfaces

Object Name
Interface
Connection Point
Description
Conference Manager
INmManager
INmManagerNotify
Manager of the overall conferencing system.
Call
INmCall
INmCallNotify
Monitors and controls an incoming or outgoing call.
Conference
INmConference
INmConferenceNotify
Manages an instance of a conference.
Channel
INmChannel
INmChannelNotify
Base object for all the channels. A conduit for a specific type of media (application sharing, audio, data, file transfer, and video).
Audio Channel
INmChannelAudio
INmChannelAudioNotify
A conduit for audio-type media.
Video Channel
INmChannelVideo
INmChannelVideoNotify
A conduit for video-type media.
File Transfer Channel
INmChannelFt
INmChannelFtNotify
Manager of file transfer activity.
Application Sharing Channel
INmChannelAppShare
INmChannelAppShareNotify
Manager of shared applications.
Data Channel
INmChannelData
INmChannelDataNotify
A conduit for sending and receiving data between conference participants.
Local System
INmSysInfo

Information about the local user and local computer.
Member
INmMember

A participant in a conference.


Figure 4   CNMManager


class CNMManager
{
// Attributes
    protected:
        //NetMeeting Interface pointer
        CComPtr<INmManager> m_pManager;
        //Connection point cookie
        DWORD m_dwManagerCookie;

// Implementation
    public:
        CNMManager ();
        ~CNMManager ();
// Initializes the conferencing system and sets up the
// connection point
        HRESULT Initialize (ULONG uchCaps = NMCH_ALL, 
                            ULONG uOptions = NM_INIT_CONTROL);

        //Connection point support functions
void OnNmUI();
        HRESULT OnConferenceCreated(INmConference * pIConference);
        HRESULT OnCallCreated(INmCall* pICall);

        //Wrapper routines
        HRESULT CreateConference(BSTR bstrName,
                                 BSTR bstrPassword = NULL,
                                 ULONG uchCaps = NMCH_ALL);
        HRESULT CreateCall(NM_ADDR_TYPE uType, 
                           BSTR bstrAddr,
                           INmConference * pConference = NULL);
};


Figure 5   CNMManagerEventSink


class CNMManagerEventSink : 
    public CComObjectRoot,
    public INmManagerNotify
{
// Construction
public:
    CNMManagerEventSink();

// Attributes
protected:
    CNMManager* m_pManager;

// Operations
public:

    BEGIN_COM_MAP(CNMManagerEventSink)
        COM_INTERFACE_ENTRY(INmManagerNotify)
    END_COM_MAP()

// Implementation
public:
    virtual ~CNMManagerEventSink();
    void Initialize (CNMManager* pManager)
    {m_pManager = pManager;}

    // INmManagerNotify
    STDMETHOD(NmUI)(CONFN uNotify);
    STDMETHOD(ConferenceCreated)(INmConference *pConference);
    STDMETHOD(CallCreated)(INmCall *pCall);
};


Figure 6   CNMManager Initialization


HRESULT CNMManager::Initialize (ULONG uchCaps,    ULONG uOptions)
{
    HRESULT hr = E_FAIL;

ATLTRACE( "CNMManager::Initialize\n" );

    // Create a conference manager instance
hr = CoCreateInstance(CLSID_NmManager, NULL, CLSCTX_ALL,
                      IID_INmManager, (void**)&m_pManager);
    _ASSERTE(m_pManager != NULL);
    if (FAILED(hr))
    {
            //Error handling
    }
    else
    {
        //establish the connection point
        CComObject<CNMManagerEventSink>* pSink;
        CComObject<CNMManagerEventSink>::CreateInstance(&pSink);
        pSink->Initialize (this);
        AtlAdvise(m_pManager, pSink->GetUnknown(), 
                  IID_INmManagerNotify, &m_dwManagerCookie);

        // Initialize the data
        hr = m_pManager->Initialize(&uOptions, &uchCaps);
    }

    return hr;
}


Figure 7   NetMeeting Control Options

Value
Description
NM_INIT_NORMAL
NetMeeting user interface will be visible.
NM_INIT_CONTROL
NetMeeting UI will not be visible. You will control the UI in the application.
NM_INIT_NO_LAUNCH
NetMeeting will not be started if it isn't already running.


Figure 8   Notification Support


HRESULT CNMManager::OnConferenceCreated(INmConference * pIConference)
{
    ATLTRACE( "CNMManager::OnConferenceCreated\n" );
    if (NULL != pIConference)
    {
        m_pConference = new CNMConference(pIConference);
        m_pConference->Initialize();
    }
    return S_OK;
}

HRESULT CNMManager::OnCallCreated(INmCall* pICall)
{
    ATLTRACE( "CNMManager::OnCallCreated\n" );
    if (NULL != pICall)
    {
        m_pCall = new CNMCall(pICall);
        m_pCall->Initialize();
    }
    return S_OK;
}


Figure 9   CNMConference


using namespace std;

class CNMConference
{
// Attributes
    protected:
        CComPtr<INmConference> m_pConference;
        DWORD m_dwConferenceCookie;
        CNMAppShare* m_pChannelAppShare;
        vector <CNMChannelVideo*> m_pChannelVideoVector;
        //Other Channels go here.

// Implementation
    public:
        CNMConference (INmConference* pConference);
        ~CNMConference ();
        void Initialize ();
        CNMAppShare* GetAppShareChannel()
        {return m_pChannelAppShare;}
        CNMChannelVideo* GetVideoChannel(BOOL bIncoming = TRUE);
        //Other channel access functions go here

        //Notification support functions
void OnNmUI();
        void OnStateChanged();
        void OnMemberChanged();

        //Channel management support functions
        HRESULT OnAddChannel(INmChannel* pIChannel);
        HRESULT OnRemoveChannel(INmChannel* pIChannel);
        HRESULT OnUpdateChannel(INmChannel* pIChannel);

        //Application Remote launching support.
        HRESULT LaunchRemote(GUID* pguidApp);
};


Figure 10   CNMConferenceEventSink


class CNMConferenceEventSink : 
    public CComObjectRoot,
    public INmConferenceNotify
{
// Construction
public:
    CNMConferenceEventSink();

// Attributes
protected:
    CNMConference* m_pConference;

// Operations
public:

    BEGIN_COM_MAP(CNMConferenceEventSink)
        COM_INTERFACE_ENTRY(INmConferenceNotify)
    END_COM_MAP()

// Implementation
public:
    virtual ~CNMConferenceEventSink();
    
//Interface Manager pointer for call back.
    void Initialize (CNMConference* pConference)
    {m_pConference = pConference;}

    // INmConferenceNotify
    STDMETHOD(NmUI)(CONFN uNotify);
    STDMETHOD(StateChanged)(NM_CONFERENCE_STATE uState);
    STDMETHOD(MemberChanged)(NM_MEMBER_NOTIFY uNotify,
                             INmMember *pfMember);
    STDMETHOD(ChannelChanged)(NM_CHANNEL_NOTIFY uNotify,
                              INmChannel *pChannel);
};


Figure 11   CNMConference Destructor


CNMConference::~CNMConference ()
{
ATLTRACE( "CNMConference::~CNMConference\n" );
    
    int nIndex = 0;
    int nSize = m_pChannelVideoVector.size();

//Clean-up all of the channel information 
if (NULL != m_pChannelAppShare)
     delete m_pChannelAppShare;

for (nIndex = 0; nIndex < nSize; nIndex++)
{
     delete m_pChannelVideoVector.at(nIndex);
}
m_pChannelVideoVector.clear();
    
//Release the sink
    AtlUnadvise(m_pConference, 
                IID_INmConferenceNotify, 
                m_dwConferenceCookie);

}


Figure 12   ChannelChanged


HRESULT CNMConferenceEventSink::ChannelChanged(
    NM_CHANNEL_NOTIFY uNotify, 
    INmChannel *pChannel)
{
    ATLTRACE( "CNMConferenceEventSink::ChannelChanged\n");
    HRESULT hr = E_FAIL;
    If (NULL != pConference)
{
    switch (uNotify)
    {
    case NM_CHANNEL_ADDED:
        hr = m_pConference->OnAddChannel(pChannel);
        break;
    case NM_CHANNEL_REMOVED:
        hr = m_pConference->OnRemoveChannel(pChannel);
        break;
    case NM_CHANNEL_UPDATED:
        hr = m_pConference->OnUpdateChannel(pChannel);
        break;
    }
}
    return hr;
}


Figure 13   Channel Manipulation


HRESULT CNMConference::OnAddChannel(INmChannel* pIChannel)
{
    ATLTRACE( "CNMConference::OnAddChannel\n");
    
    HRESULT hr = E_FAIL;
    ULONG uChannel = NMCH_DATA;

    hr = pIChannel->GetNmch(&uChannel);
    if (SUCCEEDED(hr))
    {
        switch (uChannel)
        {
        ...
        case NMCH_SHARE:
            m_pChannelAppShare = new CNMAppShare (pIChannel);
            m_pChannelAppShare->Initialize();
            break;
        case NMCH_VIDEO:
            {
                CNMChannelVideo* pChannelVideo = 
                    new CNMChannelVideo (pIChannel);
                pChannelVideo->Initialize();
                m_pChannelVideoVector.push_back(pChannelVideo);
            }    
break;
        }
    }
    return hr;
}

//===================================================================

HRESULT CNMConference::OnRemoveChannel(INmChannel* pIChannel)
{
    ATLTRACE( "CNMConference::OnRemoveChannel\n");

    HRESULT hr = E_FAIL;
    ULONG uChannel = NMCH_DATA;

    hr = pIChannel->GetNmch(&uChannel);
    if (SUCCEEDED(hr))
    {
        switch (uChannel)
        {
        ...
        case NMCH_SHARE:
            if ((NULL != m_pChannelAppShare)
            && (S_OK == m_pChannelAppShare->GetInterface()
                ->IsSameAs(pChannel)))
            {
                delete m_pChannelAppShare;
                m_pChannelAppShare = NULL;
            }
            break;
        case NMCH_VIDEO:
        {
    int nIndex = 0;
    int nSize = m_pChannelVideoVector.size();
                CNMChannelVideo* pChannelVideo = NULL;

                for (nIndex = 0; nIndex < nSize; nIndex++)
                {
                    pChannelVideo =
                         m_pChannelVideoVector.at(nIndex);
                    if ((NULL != pChannelVideo) && 
                        pChannelVideo->GetInterface()
                        ->IsSameAs(pIChannel))
                    {
                        delete pChannelVideo;
                        pChannelVideo = NULL;
                        m_pChannelVideoVector.erase(
                            m_pChannelVideoVector.begin() 
                            + nIndex);
                        break;
                    }
                }
            }            
break;
        }
    }
    return hr;
}


Figure 14   CNMAppShare


class CNMAppShare
{
// Attributes
    protected:
        CComPtr< INmChannelAppShare > m_pAppShare;
        DWORD m_dwAppShareCookie;

// Implementation
    public:
        CNMAppShare (INmChannel* pAppShare);
        ~CNMAppShare ();
        HRESULT Initialize ();
        INmChannelAppShare* GetInterface()
        {return m_pAppShare;}
        HRESULT OnNmUI();
        HRESULT OnMemberChanged();
        HRESULT OnStateChanged();
        HRESULT SetAppShareState(HWND hWnd, NM_SHAPP_STATE uState);
        HRESULT SetState(NM_SHARE_STATE uState)
{ m_pAppShare->SetState(uState);}
};


Figure 15   SetState Levels

Value
Description
NM_SHARE_COLLABORATING
All the conference members can work in all applications the local user has shared.
NM_SHARE_IN_CONTROL
Gives the local user control of the cursor. If the user is working alone, this will also grant others permission to take control of this shared application.
NM_SHARE_WORKING_ALONE
The local user is working alone. Other conference members can see applications that the local user has shared, but they cannot work in them.


Figure 16   SetAppShareState Method


HRESULT CNMAppShare::SetAppShareState(HWND hWnd, NM_SHAPP_STATE uState)
{
    ATLTRACE( "CNMAppShare::SetAppShareState\n");
    
    HRESULT hr = E_FAIL;
    HWND hWndApp = NULL;
    IEnumNmSharableApp * pEnum = NULL;
    INmSharableApp * pApp = NULL;

    if (NULL != m_pAppShare)
    {
        hr = m_pAppShare->EnumSharableApp(&pEnum);
        if (FAILED(hr))
        {
            for ( ; ; )
            {
                hr = pEnum->Next(1, &pApp, NULL);
                if (SUCCEEDED(hr))
                {
                    pApp->GetHwnd(&hWndApp);
                    if (hWndApp == hWnd)
                    {
                        hr = pApp->SetState(uState);
                        pApp->Release();
                        break;
                    }
                    pApp->Release();
                }
                else
                    break;
            }
        }
        pEnum->Release();
    }
    return hr;
}


Figure 17   CNMAppShareEventSink


class CNMAppShareEventSink : 
    public CComObjectRoot,
    public INmChannelAppShareNotify
{
// Construction
public:
    CNMAppShareEventSink();

// Attributes
protected:
    CNMAppShare* m_pAppShare;

// Operations
public:

    BEGIN_COM_MAP(CNMAppShareEventSink)
        COM_INTERFACE_ENTRY(INmChannelAppShareNotify)
    END_COM_MAP()

// Implementation
public:
    virtual ~CNMAppShareEventSink();
    void Initialize (CNMAppShare* pAppShare)
    {m_pAppShare = pAppShare;}

    // INmChannelAppShareNotify
    STDMETHOD(NmUI)(CONFN uNotify);
    STDMETHOD(MemberChanged)(NM_MEMBER_NOTIFY uNotify, 
                             INmMember * pMember);
    STDMETHOD(StateChanged)(NM_SHAPP_STATE uNotify, 
                            INmSharableApp *pApp);
};


Figure 18   GetVideoChannel Method


CNMChannelVideo* CNMConference::GetVideoChannel(BOOL bIncoming)
{
    int nIndex = 0;
    int nSize = m_pChannelVideoVector.size();
    CNMChannelVideo* pChannelVideo = NULL;

    for (nIndex; nIndex < nSize; nIndex++)
    {
        pChannelVideo = m_pChannelVideoVector.at(nIndex);
        if ((NULL != pChannelVideo) && 
            (pChannelVideo->IsIncoming() == bIncoming))
        {
            break;
        }
    }
    return pChannelVideo;
}


Figure 19   Video Channel Properties

uID Value
Description
wLow
wHigh
NM_VIDPROP_PAUSE
Pauses/resumes the video
0 or 1

NM_VIDPROP_WINDOW_AUTO_SIZE
Sets the window size as a percentage of the image size
0 to 400%

NM_VIDPROP_WINDOW_SIZE
Sets the window size
Desired width
Desired height
NM_VIDPROP_WINDOW_TOP_MOST
Sets the window as the topmost window
0 or 1

NM_VIDPROP_WINDOW_POSITION
Sets the window position
Desired x-coordinate value
Desired y-coordinate value
NM_VIDPROP_WINDOW_VISIBLE
Sets the window visible
0 or 1

NM_VIDPROP_IMAGE_PREFERRED_SIZE
Sets the image size
NM_VIDEO_SMALL, NM_VIDEO_MEDIUM, or NM_VIDEO_LARGE

NM_VIDPROP_IMAGE_QUALITY
Sets the image quality
0 to 31

NM_VIDPROP_CAMERA_DIALOG
Sets the dialog used by the capture device
NM_VIDEO_FORMAT_ DIALOG or NM_VIDEO_ SOURCE_DIALOG


Figure 20   ShareMe Method


void CNMDemoDoc::OnToolsShareMe() 
{
CNMAppShare * pAppShare = m_pManager->GetCurrentConference()
   ->GetAppShareChannel();
    if (m_bShared)
    {
pAppShare->SetAppShareState(AfxGetMainWnd()->m_hWnd, 
                            NM_SHAPP_NOT_SHARED);
        m_bShared = FALSE;
    }
    else
    {
        m_bShared = TRUE;
pAppShare->SetAppShareState(AfxGetMainWnd()->m_hWnd, 
                            NM_SHAPP_SHARED);
    }
}