This article may contain URLs that were valid when originally published, but now link to sites or pages that no longer exist. To maintain the flow of the article, we've left these URLs in the text, but disabled the links.
|
Make the Internet Your Office with NetMeeting
Suresh G. Nair |
Microsoft NetMeeting lets users collaborate with audio, video, whiteboard, and application sharing. And now you can add its features to your Weblication! |
Download the code (6KB)
I've burned a lot of time playing around with the Internet Client SDK. I was particularly astounded when I got to the NetMeeting® section. The power NetMeeting can add to applications and the simplicity of its object model are amazing. The NetMeeting 2.1 SDK has made phenomenal improvements from the previous version with the introduction of a component object model.
I'll show you how to use NetMeeting COM-based objects to add NetMeeting functionality to your own applications. I'll analyze the NetMeeting object model and establish a generic approach for supporting NetMeeting functionality using its objects. Then I'll take a closer look at some of the key NetMeeting objects and how to use the generic approach to develop an ActiveX® Template Library (ATL)-based NetMeeting wrapper. This ATL wrapper will help add NetMeeting functionality to your applications with minimal effort. Finally, I will illustrate how to use the generic wrapper to add application sharing, audio, video, and remote-launching conferencing capabilities to other applications.
Overview
Setting Up the Sample Application
|
|
Add .\$(InputName).h as the output file name. During the build process initiated by this custom build command, the MIDL compiler will generate the files imsconf2.h and imsconf2.c. Edit stdafx.h so it includes the file imsconf2.h. Choose Project | Add to Project | Files and add imsconf2.c into the project. A warning dialog will appear, saying that the file does not exist. Select Yes to ignore this, because the file will be created during the first build. Once you have completed these steps, the project will be ready to use all of the NetMeeting objects.
NetMeeting Objects
|
Figure 2: Object Interaction |
To make life a little easier, you can implement an object instance manager that will manage the object's interface pointer and connection with the sink and wrap any of the calls to the object's interface. The overall object interaction is illustrated in Figure 2. Thus for every connectable object that has to be supported in the application, you need an object instance manager that will have a pointer to the NetMeeting object's interface, the connection point cookie to manage the sink connection, and function support for the connection point notifications. The corresponding sink interface will have a pointer to the object instance manager to pass on the information the sink gets through notifications from the server. The beauty of this object model
is that once you understand the basic structure, most of
the NetMeeting support in the application can be done in almost no time.
Two NetMeeting connectable objects are key. The Conference Manager object manages the entire conferencing system, while the Conference object provides the context within which all the channels exist. To provide any of the NetMeeting functionality in an application, you must do at least two things: create and manage an instance of the Conference Manager object and implement its connection point, and manage instances of the Conference object and implement its connection point. Let's take a detailed look at these objects.
The Conference Manager Object
|
Figure 3: The Conference Manager |
The Conference Manager object will notify the application using the connection point sink interface, INmManagerNotify, whenever a conference or call is initiated or when a conference change occurs. Following the general approach, the object interface manager class, CNMManager, encapsulates the INmManager interface, as shown in Figure 4. This code uses the smart pointer CComPtr to manage the NetMeeting interface. The connection point sink will be managed through the smart pointer's cookie. Implemented this way, the only data that you need to store in the application to use the CNMManager object is a pointer to its instance. The object instance manager and the connection point sink implementation go hand in hand.
Before looking at the methods of CNMManager, let's take a quick look at the sink interface. The Conference Manager sink, INmManagerNotify, requires that you implement three notifications: NmUI, ConferenceCreated, and CallCreated. All of these event handlers in the sink objects must return S_OK to the sink source. The connection point sink implementation CNMManagerEventSink (see Figure 5) is a typical ATL sink interface, with the exception of the Initialize method to set the pointer to the interface manager, CNMManager. Let's examine the actual implementation of some of the important CNMManager methods. First and foremost is CNMManager::Initialize, shown in Figure 6. This method creates the INmManager instance, sets up the connection point, decides which channels from the conferencing system will be supported, and establishes the level of control that the application needs on NetMeeting. The first parameter, uchCaps, has a default value of NMCH_ALL, meaning the program should allow all the applications to access all the channels that NetMeeting supports. Depending on an application's needs, you can choose any combination of the channels that you want to provide to the user. For example, you can have application-sharing channels only (NMCH_SHARE), or video and audio channels only (NMCH_VIDEO | NMCH_AUDIO). The value of the second parameter, uOptions, determines the level of control that the program will have over the NetMeeting UI and execution. It can take one of the three values shown in Figure 7. CNMManager sets the uOptions parameter to NM_INIT_CONTROL by default, indicating that the application will provide a custom user interface for NetMeeting. Note that the only information about the sink that you need to store is the cookie that uniquely identifies the connection. In the CNMManager destructor, the stored cookie value is used to remove the connection and destroy the sink instance: |
|
In the destructor, you don't have to do anything with the INmManager interface pointer, m_pManager. The CComPtr smart pointer will take care of the reference count management and release the memory for you.
As I mentioned earlier, NetMeeting objects will notify the sink whenever specific events occur. One such notification is common to all the NetMeeting objects: NmUI. The server sends a NmUI notification to the sink whenever a change occurs that might require notification to be displayed to the user. Two other events can be fired from the Conference Manager. ConferenceCreated is sent when a Conference object is created. It can be either auto-created by the system because of an incoming call or created by the application by calling INmManager::CreateConference.CallCreated is sent when a Call object is created. It can be sent as a result of an incoming call or an outgoing call placed by calling INmManager::CreateCall. To provide a common access point to the NetMeeting objects that are created, the server will send pointers to the objects as parameters when firing these notifications. When the application gets the notifications, it should initialize the object interface managers and set up the connection points for these connectable objects. Generally, the sink should pass the notification information to the object interface manager. The Conference Manager notification support functions CNMManager::OnConferenceCreated and CNMManager:: OnCallCreated will create the corresponding object interface manager instances and initialize them (see Figure 8). After setting up the notification routines like this, the only task the two create routines, CNMManager::CreateConference and CNMManager::CreateCall, will have to perform is to turn around and call the corresponding functions in the INmManager interface through the pointer m_pManager.
The Conference Object
|
|
As in the case of the Conference Manager, the stored cookie value is used to remove the sink connection and destroy
the sink instance in the CNMConference destructor, as shown in Figure 11. The destructor will release all the channels before removing the sink connection, and finally the INmConference interface will be released by the smart pointer destructor.
Channel Management and Channels
The Application-sharing Channel
|
|
INmChannelAppShare contains two important methods: SetState and SetAppShareState. SetState lets the user set the level of control each conference member has on an application the user has shared on their local machine. The three supported levels are listed in Figure 15. The main window handle of the CNMAppShare::SetAppShareState method (see Figure 16) allows any local application to be shared among the conference members. m_pAppShare->EnumSharableApp returns a list of applications in the local system that can be shared, each represented by an instance of the Application object. The Application object exposes the INmSharableApp interface, which can be used to identify the application and manage its sharing state.
The application Sharing Channel object sends two notification messages apart from NmUI through its connection point sink interface, INmChannelAppShareNotify. The StateChanged notification is sent when a shareable application on the local computer becomes shared or is no longer being shared, while the MemberChanged notification indicates that a member of the application-sharing channel was added, removed, or updated. The connection point sink CNMAppShareEventSink, shown in Figure 17, implements the INmChannelAppShareNotify interface. Just like the Conference object's Initialize method, the CNMAppShare::Initialize method will set up the connection with connection point sink interface, and the destructor will use the cookie value to release the connection. The StateChanged and NmUI notifications can be used to update the application-sharing status on the UI.
The Video Channel
Launching a Remote Application
|
|
In the SetNmApp call, IID_NMDEMOGUID is the application's GUID, bstrPath is the file specification for the application, and bstrDir is the current drive and directory for the application.
The third parameter to the SetNmApp call is the actual command line to execute, allowing you to pass arguments to the application if necessary. If this parameter is NULL, the value of the second parameter bstrPath will be used to execute the application. With the application installed and registered for conferencing on all the participating systems, all you need to do to launch it remotely is call CNMConference::LaunchRemote. This function, shown below, can launch the application on all of the conference members' systems or a selected member's system. |
|
In this call, the second parameter, pMember, can be used to specify a single conference member if you want to launch the application only on that member's system. If it is set to NULL, the application will be launched on all conference members' systems.
Using the ATL Wrapper in an Application
|
|
Once the system is initialized, you can create a conference with all of the NetMeeting channel support with two lines of code: |
|
Now the application can call the members and participants it wants in this conference using CNMManager::CreateCall. Once the conference is active, it will auto-create all the channels in the application, and in the process instantiate all the necessary support classes. With this infrastructure in place, adding a ShareMe button to auto-share the application among the conference participants can be as simple as adding the message handler shown in Figure 20.
Within the active conference, the application can be remotely launched on all the participants' systems with the command |
|
where GetAppGuid will return the application's GUID. The following code segment will position the incoming video channel window on the left-hand side of the application, halfway from the top, and will make it visible: |
|
Conclusion
|
|