Tutorials and Samples


NetMeeting delivers an open, extensible platform for real-time communications, offering audio, video, and data conferencing functionality. Several tutorials and sample applications that demonstrate some ways to use the NetMeeting SDK are supplied here.

Sample applications can be found in the samples folder of your Nm21sdk folder. The Samples.txt file, also in the Nm21sdk folder, provides information to aid your usage of the samples. To build the samples from Visual C++®, open the project makefile (sample.mak) as a Microsoft VC++ project, and build as usual. The NetMeeting SDK directories must be added to your VC++ environment (select Options from the Tools menu and click the Directories tab).

arrowb.gifUsing the NetMeeting Data Channel

arrowb.gifRemotely Launching Your Program

arrowb.gifILS Extended Attributes

arrowb.gifImplementing Filters in ILS Queries

arrowb.gifNetMeeting Functionality in Web Pages

arrowb.gifCreating a NetMeeting Call Center

Using the NetMeeting Data Channel

The Microsoft® NetMeeting™ COM interface enables programmers to design feature-rich collaborative software. Using the NetMeeting COM interface, developers can create applications that let users work together over local or remote networks. Local instances of the application, running on each person's computer, can communicate with each other using the NetMeeting data channel.

This tutorial demonstrates how to use the NetMeeting data channel, using the Chat sample application (included in the NetMeeting Software Developers Kit) as a working example.

The code in this tutorial has been simplified to highlight the important parts of the Chat application. For more details, see the Chat sample application included in the samples folder of your NetMeeting SDK directory.

arrowb.gifWho Should Use This Tutorial?

arrowb.gifLimitations

arrowb.gifCreating a Data Channel

UpBack to list of Tutorials

Who Should Use This Tutorial?

This tutorial is for developers who want to write a "conferencing-aware application" that uses the NetMeeting data channel to send and receive information.

This tutorial assumes that the reader is familiar with the Microsoft Component Object Model (COM). For more information on COM, see Inside OLE 2 by Kraig Brockschmidt.

UpBack to list of Data Channel topics

Limitations

Once you have written an application that uses the NetMeeting data channel, you may want to ensure that your application is running on each conference member's computer. A separate tutorial, Remotely Launching Your Program, describes how to do this.

UpBack to list of Data Channel topics

Creating a Data Channel

Use the following steps to create a data channel:

  1. Obtain and Initialize a Pointer to an INmManager Object
  2. Obtain a Pointer to an INmConference Object
  3. Create an INmChannelData Interface in the INmConference Object
  4. Create Code to Send and Receive Application-Specific Data

UpBack to list of Data Channel topics

Obtain and Initialize a Pointer to an INmManager Object

The INmManager object is at the top of the NetMeeting COM object hierarchy. Any application that uses the NetMeeting COM object should have code that obtains a pointer to an INmManager object. This pointer enables the program to create its own calls and conferences, to detect the properties of the local system, and many other useful tasks. Once you obtain a pointer to an INmManager object, connect a notification sink to the pointer. This causes you to be notified of the presence of INmConferences and INmCalls. The final step is to initialize the NetMeeting system. Initializing will launch the NetMeeting application.

Note It is important to connect a notification sink to your INmManager object before initializing the NetMeeting application. Reversing the order of these steps may cause you to miss important notifications.

In the following sample code, the INmManager pointer is initialized with data capabilities (NMCH_DATA) only, because this application is not interested in receiving notifications about other types of traffic (such as audio or video).

HRESULT InitManager( void )
{
HRESULT hr;
hr = CoCreateInstance(CLSID_NmManager,
NULL,
CLSCTX_INPROC_SERVER,
IID_INmManager,
(void **)&g_pNmManager);

if( SUCCEEDED( hr ) ) {
g_pManagerNotify = new CManagerNotify();

if( NULL != g_pManagerNotify ) {
hr = g_pManagerNotify->Connect( g_pNmManager );

if( SUCCEEDED( hr ) ) {
ULONG uchCaps = NMCH_DATA;
ULONG uOptions = NM_INIT_NORMAL;
hr = g_pNmManager->Initialize( &uOptions,&uchCaps )
}
}
}
return( hr );
}

UpBack to Creating a Data Channel

Obtain a Pointer to an INmConference Object

The INmConference object enables you to access INmChannels and INmMembers. An active conference is one in which there are two or more computers (each represented by an INmMember pointer), sending and receiving audio, video, files, or data. The INmManager object is notified of existing conferences through its notification sink. When an INmManager pointer is first initialized, or each time a conference is created, the NetMeeting COM object calls your INmManagerNotify::ConferenceCreated method. A conference can be created through the NetMeeting user interface (UI) or through calls to the NetMeeting COM API.

The following code is an example of the INmManagerNotify::ConferenceCreated method you will have to write. As with the preceding function, you will create a pointer to the Conference object, and then connect a notification object to the pointer. This will enable you to receive notifications about the conference.

INmConference *g_pConference = NULL;

HRESULT STDMETHODCALLTYPE
CManagerNotify::ConferenceCreated( INmConference *pConference )
{
HRESULT hr = E_FAIL;

pConference->AddRef();
g_pConference = pConference;
g_pConferenceNotify = new CConferenceNotify();

if( NULL != g_pConferenceNotify ) {
hr = g_pConferenceNotify->Connect( g_pConference );
}
return( hr );
}

UpBack to Creating a Data Channel

Create an INmChannelData Interface in the INmConference Object

INmChannelData is the interface through which application-specific data is transmitted and received. A data channel is created with a GUID (globally unique identifier). Programs can use a data channel to transmit information only if both members have created a data channel using the same GUID.

The following code creates a data channel for a program that can communicate with the NetMeeting Chat application. It first creates a data channel, then connects the channel to a notification sink so that notification about the channel can be received.

// Local Application Guid :
// {D29A8C50-774F-11d0-8B1D-00A0C91BC90E}
const GUID g_guidApp =
{ 0xd29a8c51, 0x774f, 0x11d0,
{ 0x8b, 0x1d, 0x0, 0xa0, 0xc9, 0x1b, 0xc9, 0xe} };

INmChannelData *g_pChannelData = NULL;

HRESULT CreateChatChannel(void)
{
HRESULT hr;
hr = g_pConference->CreateDataChannel(
&g_pChannelData, g_guidApp);

if (S_OK == hr) {
g_pDataChanNotify = new CChannelDataNotify();

if( NULL != g_pDataChanNotify ) {
hr = g_pDataChanNotify->Connect(g_pChannelData);
}
}
return hr;
}

For more information about creating and using GUIDs, see Inside OLE, Second Edition.

UpBack to Creating a Data Channel

Create Code to Send and Receive Application-Specific Data

Sending data is accomplished through INmChannelData::SendData. Data is received by your INmChannelDataNotify::DataReceived method.

The INmChannelDataNotify::DataReceived method is called by the NetMeeting COM object whenever data is received.

The following sample code sends and receives normal, null-terminated text strings.

HRESULT SendText(LPTSTR psz)
{
HRESULT hr;
ULONG cb = lstrlen(psz);

if ((0 == cb) || (NULL == g_pChannelData)
|| (S_OK != g_pChannelData->IsActive()) {
return S_FALSE; // data channel not available
}

INmMember *pMember = GetSelectedMember();
cb++; // include final null
hr = g_pChannelData->SendData(pMember, cb, psz, 0);
return hr;
}

HRESULT STDMETHODCALLTYPE CChannelDataNotify::DataReceived(INmMember *pMember, ULONG uSize, LPBYTE pb, ULONG dwFlags)
{
LPTSTR psz;
psz = (LPTSTR) pb;
DisplayMsg(psz, pMember, dwFlags);
return S_OK;
}

UpBack to Creating a Data Channel

UpBack to list of Data Channel topics

Remotely Launching Your Program

You've written an application that uses the Microsoft® NetMeeting™ data channel to send information between the people in a conference. How do you ensure that your application is running on everyone's computer? This tutorial shows you!

The NetMeeting COM interface enables programmers to quickly and easily design feature-rich, collaborative software. Using the NetMeeting COM interface, developers can create applications that enable users to work together over local or remote networks. To support this, your software may need to ensure that your application is running on another computer, or to cause another computer to launch a copy of your application. This tutorial provides a tour through the hierarchy of the NetMeeting COM interface and demonstrates how to launch copies of your programs on a remote computer. This is accomplished with a call to INmConference::LaunchRemote and several other important methods.

arrowb.gifWho Should Use This Tutorial?

arrowb.gifLimitations

arrowb.gifLaunchRemote and the Registry

arrowb.gifSetting and Getting Information for Remote Applications

arrowb.gifLaunching a Remote Application

UpBack to list of Tutorials

Who Should Use This Tutorial?

This tutorial is for developers who want to learn how to launch applications on a remote computer.

This tutorial assumes that the developer has the ability to create and manage conferences and calls.

This tutorial assumes that the reader is familiar with the Microsoft Component Object Model (COM). For more information on COM, see Inside OLE 2 by Kraig Brockschmidt.

UpBack to list of Remote Launch topics

Limitations

To launch an application on a remote computer:

UpBack to list of Remote Launch topics

LaunchRemote and the Registry

Registry keys for programs that can be remotely launched with NetMeeting are stored in:

HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Conferencing\Applications

Under the Applications key is one key for each program which can be launched remotely . This folder must be named with your application's globally unique identifier (GUID). The keys are described in the following section, Setting and Getting Information for Remote Applications.

The following example shows the registry keys for the NetMeeting Chat program.

HKEY_LOCAL_MACHINE\
SOFTWARE\
Microsoft\
Conferencing\
Applications\
{340F3A60-7067-11D0-A041-444553540000}
Directory "C:\Program Files\NetMeeting"
Path "C:\Program Files\NetMeeting\cb32.exe"

UpBack to list of Remote Launch topics

Setting and Getting Information for Remote Applications

Applications that can be launched remotely can be entered into the registry in any manner. However, the best and most convenient way to register an application is with the INmSysInfo::SetNmApp method. SetNmApp takes four parameters, which are used to register the application with the system. Its complement function, INmSysInfo::GetNmApp, passes the first parameter as an "in" parameter, and the last three as "out" parameters to be filled in by the INmSysInfo interface. Using SetNmApp is preferred to modifying the registry directly because it will continue to work even if the registry keys are moved in a future release of NetMeeting.

The following table describes the parameters you need to provide.

Parameter Usage/Meaning Registry key
REFGUID rguid This GUID identifies the application and is needed when calling LaunchRemote. Each application to be launched remotely should have one GUID that can be used to register with any computer. For more information about creating and using GUIDs, see Inside OLE, Second Edition. In the registry, the value of rguid is the folder name of the entry for this application.
BSTR bstrApplication The full path and file name of the module that will be started when there is an incoming request to launch the application associated with the rguid parameter. If the bstrApplication parameter is NULL, the module name must be the first white-space-delimited token in the bstrCommandLine string. This parameter is reflected in the registry as the Path registry key under the rguid folder.
BSTR bstrCommandLine Specifies the command line to execute. If this parameter is NULL, the function uses the string pointed to by bstrApplication as the command line. This parameter is reflected in the registry as the CmdLine registry key under the rguid folder.
BSTR bstrDirectory Specifies the current drive and directory for the child process. The string must be a full path and file name that includes a drive letter. If this parameter is NULL, the new process is created with the same current drive and directory as the calling process. This parameter is reflected in the registry as the Directory registry key under the rguid folder.

Code Sample

The following code sample demonstrates how to use the SetNmApp method to add your application's keys to the registry. It also demonstrates the use of the GetNmApp method to read these values.

HRESULT hr;
INmManager *pManager;
INmSysInfo *pSysInfo;

// Add code to retrieve and initialize pManager
// and pSysInfo

BSTR bstrApp, bstrCom, bstrDir;
LPTSTR_to_BSTR( &bstrApp, "C:\RemoteDemo\Demo.exe" );
LPTSTR_to_BSTR( &bstrCom, "C:\RemoteDemo\Demo Arg1 Arg2" );
LPTSTR_to_BSTR( &bstrDir, "C:\RemoteDemo" );

hr = pSysInfo->SetNmApp(
IID_APPGUID, // a predefined GUID for this App
bstrApp, // Full path and file name
bstrCom, // Path and file with command-line args
bstrDir ); // The working directory to use

if( SUCCEEDED( hr ) ) {
MessageBox( NULL,
"We set this app as remote launchable",
NULL,
MB_OK );
} else {
MessageBox( NULL,
"We did not set this app as launchable",
NULL,
MB_OK );
}

SysFreeString( bstrApp );
SysFreeString( bstrCom );
SysFreeString( bstrDir );

hr = pSysInfo->GetNmApp(
IID_APPGUID, // GUID for the app we want to know about
&bstrApp, // the three BSTR parameters will
// be filled with info
&bstrCom, // retrieved from the registry
&bstrDir );

if( SUCCEEDED( hr ) ) {
// do something with the BSTR parameters that have been filled
}

UpBack to list of Remote Launch topics

Launching a Remote Application

Applications are launched remotely through a call to INmConference::LaunchRemote. LaunchRemote can be used to start an application for a specific member of a conference or for all members of the conference.

LaunchRemote uses an application GUID to uniquely identify which application to launch. The application must already be properly registered in the registry of the remote computer, as described in the preceding section. Because one call to LaunchRemote may send out the same GUID to many computers, it is important that you register your application with the same GUID on every computer.

The following is a more detailed description of the required parameters:

REFGUID rguid
rguid is the GUID in the registry associated with the application being launched.
INmMember *pMember
pMember is a pointer to the member on whose computer the application should be launched. Using a NULL pMember instructs NetMeeting to start the application on every conference member's computer.

LaunchRemote returns an HRESULT that indicates whether or not the request to launch was successfully processed. It does not guarantee the remote instance of the application was started.

Code Sample

The following code sample demonstrates how to use LaunchRemote to launch your application on remote computers.

HRESULT hr;
INmConference *pConf;
IEnumNmMember *pEnum;
BOOL fLaunchOnEverybody;

// Add code to create a conference with members in pConf
// ...

if( fLaunchOnEverybody ) {

// Call LaunchRemote on all members of a conference
hr = pConf->LaunchRemote(
IID_APPGUID, // GUID for the app to be launched
NULL ); // call everyone in conference
} else {

// Call particular members
hr = pConf->EnumMember( &pEnum );

if( SUCCEDED( hr ) ) {
INmMember *pMem;
ULONG uFetched;

while( SUCCEEDED( pEnum->Next( 1, &pMem, &uFetched ) {

if( IWantToLaunchOn( pMem ) ) {
hr = LaunchRemote( IID_APPGUID,pMem );

if( FAILED( hr ) ) {
// There was a problem with the launch request
}
}
}
}
// Could not enumerate members
}

UpBack to list of Remote Launch topics

ILS Extended Attributes

The Microsoft® Internet Locator Server (ILS) enables users of a collaborative software program (a game or conferencing package, for example) to locate other users running the same or compatible software and connect to them. To appear in a list of users, each person must log on to the ILS. The ILS tracks each logged-on person as a User object. Each User object has several standard attributes, including first name, last name, e-mail name, and country. In addition, an application can create extended attributes for its users and perform queries on these attributes. This tutorial demonstrates how to create and retrieve these extended attributes.

arrowb.gifWho Should Use This Tutorial?

arrowb.gifLimitations

arrowb.gifThe Client Side

arrowb.gifThe Server Side

UpBack to list of Tutorials

Who Should Use This Tutorial?

This tutorial is for developers and Web page authors who want to add extended attributes to ILS User objects and perform searches based on their custom extended attributes.

There are two ways to set/get extended attributes for a user:

This tutorial assumes that the reader is familiar with the Microsoft Component Object Model (COM). For more information on COM, see Inside OLE 2 by Kraig Brockschmidt.

UpBack to list of Extended Attributes topics

Limitations

With ILS Server 1.0, all extended attribute names must be numerical text strings of type BSTR. This means you cannot create an attribute named "Player's Real Name." Instead, you must create a numbered attribute (for example, 605 or 574). Extended attributes should have numbers higher than 400. The table in the following section enumerates attribute names currently used by NetMeeting.

Extended attributes are application specific, so AppFoo's attribute named 605 will not collide with AppBar's attribute named 605. For this reason, all searches based on extended attributes must include the application identifier.

NetMeeting uses the application identifier "ms-netmeeting". If your application uses this application identifier, you must choose extended attributes that do not collide with those used by NetMeeting.

UpBack to list of Extended Attributes topics

The Client Side

NetMeeting uses extended attributes to indicate that an ILS user is in a call, whether or not the user has audio/video capabilities, and the self-declared "category" of user. The NetMeeting user interface also supports searching for users based on these attributes.

UpBack to list of Extended Attributes topics

Extended Attributes Used by NetMeeting 2.1

The following extended attributes are used by NetMeeting.

Attribute
"name"
Description Possible values
400 In-call indicator "0","1"
501 Ability to send audio "0","1"
503 Ability to send video "0","1"
600 User category "1" = Personal
"2" = Business
"4" = Adult

UpBack to list of Client Side topics

Setting Attributes

Extended attributes are set through the IIlsUser::SetExtendedAttribute method. This method takes two parameters—the name of the extended attribute and the value. Both are of type BSTR.

ILS treats the attribute names as a MAPI property tag and uses the PROP_TAG macro to encode the name before setting the attribute. You must perform the same encoding when retrieving a NetMeeting extended attribute so the names will match.

For example, to set a user's status to be "currently in a call", use the following:

DWORD dwAtt = PROP_TAG(PT_STRING8, 400);
wsprintf(szName, TEXT("%lu"), dwAtt);

LPTSTR_to_BSTR( szName, bstrName);
LPTSTR_to_BSTR( "1", bstrValue); // set user to be in a call

IIlsUser::SetExtendedAttribute (bstrName, bstrValue);
IIlsUser::Update()

Note The implementation of the LPTSTR_to_BSTR macro has been left as an exercise for the reader.

UpBack to list of Client Side topics

Retrieving Attributes

Calling IIlsUser::GetExtendedAttribute or IIlsUser::GetAllExtendedAttributes does not trigger a server query. All the desired user attribute names must be specified when the user object is obtained from the server. Subsequent calls to GetExtendedAttribute or GetAllExtendedAttributes will provide you with the attribute values.

To retrieve a user object with extended attributes, you must create an Attribute object with the proper names and pass this object to the IIlsMain::GetUser or IIlsMain::EnumUsers method as shown in the following code:

LPTSTR_to_BSTR(&bstrEmpty, ""); 

// in a call
wsprintf(szProperty, TEXT("%lu"), PROP_TAG(PT_STRING8, 400));

LPTSTR_to_BSTR(&bstrName, szProperty);
hr = pAttrib->SetAttribute(bstrName, bstrEmpty);

// user type
wsprintf(szProperty, TEXT("%lu"), PROP_TAG(PT_STRING8, 600));

LPTSTR_to_BSTR(&bstrName, szProperty);
hr = pAttrib->SetAttribute(bstrName, bstrEmpty);

// Now that the attributes object is configured,
// get the user objects
hr = pIls->EnumUsers (pServer, pFilter, pAttrib, NULL, &uReqID);

After the User object with the specified extended attributes is retrieved from the server, getting the value for just one attribute is easily done by calling IIlsUser::GetExtendedAttribute, as shown in the following code:

DWORD dwAtt = PROP_TAG(PT_STRING8, 501);
wsprintf(szName, TEXT("%lu"), dwAtt);
LPTSTR_to_BSTR( szName, bstrName);
pUser->GetExtendedAttribute (bstrName, &bstrValue);

As previously stated, the User object must have been retrieved from the server with this attribute name specified.

Multiple attribute values can be returned by creating an Attribute object with the desired names and calling IIlsUser::GetAllExtendedAttributes. When the call to GetAllExtendedAttributes returns, the Attribute object will contain the correct values for the named attributes. Again, the User object should have been retrieved from the server with the extended attributes specified.

LPTSTR_to_BSTR(&bstrEmpty, "");   

// in a call
wsprintf(szProperty, TEXT("%lu"), PROP_TAG(PT_STRING8, 400));

LPTSTR_to_BSTR(&bstrName, szProperty);
hr = pAttrib->SetAttribute(bstrName, bstrEmpty);

// user type
wsprintf(szProperty, TEXT("%lu"), PROP_TAG(PT_STRING8, 600));

LPTSTR_to_BSTR(&bstrName, szProperty);
hr = pAttrib->SetAttribute(bstrName, bstrEmpty);

//... set up other attributes here...
hr = pUser->GetAllExtendedAttributes(&pAttrib);

UpBack to list of Client Side topics

UpBack to list of Extended Attributes topics

The Server Side

This tutorial addresses how to author ILS-enabled ASP (Active Server Page) pages for use with applications developed using the ILS interfaces provided in the NetMeeting 2.1 SDK. You can create users and query users on the server using ASP objects. For more information and a general overview, see the Microsoft Active Server Pages Web site.

Normally, to access extended attributes using the ASP pages, a Web author can specify the attribute by querying the attribute named "ilstNNNN", where NNNN is the attribute number. However, due to a known problem with ILS Server 1.0, if you want to access an extended attribute that your application has set through the ILS API, you will need to add 0x8000 (32768 decimal) to the attribute number and then prefix it with the string "ilst." For example, to access an attribute named 601, you should refer to the attribute as "ilst33369" in the ASP code. This pertains only to cases where you are using ASP to access extended attributes that were created through the ILS client API. If you are both creating and retrieving the attributes through ASP, you do not need to perform this manipulation.

The following code assumes that an ILS Server object called "ils" has been created according to the instructions in the ILS documentation, and a User object called "testuser" already exists.

' Define the NM extended attribute names here
strAudio = "ilst33269" ' 501
strVideo = "ilst33271" ' 503
strIncall = "ilst33168" ' 400
strUserType = "ilst33368" ' 600

' Set the extended attribute values
UserType = 2 ' Business user
Audio = 1 ' Audio capable
InCall = 0 ' Not currently in a call
Video = 1 ' Video capable
App = "ms-netmeeting" ' App name

' Build the string of values to modify for the application.
' modop=0 because extended attributes are application specific.
NMInfo = "cna=testuser" & _
"&modop=0" & _
"&obj=rtperson" & _
"&appid=" & App & _
"&appmime=text/iuls" & _
"&protid=h323" & _
"&protmime=text/h323" & _
"&" & strVideo & "=" & Video & _
"&" & strIncall & "=" & Incall & _
"&" & strAudio & "=" & Audio & _
"&" & strUserType & "=" & UserType

' The actual call to modify the user
modifyperson = ils.modify(NMInfo)

Retrieving users based on an extended attribute is fairly easy. Simply search for all user IDs where the specified attribute has the correct value. To find all users on the ILS who list themselves as business users, use the following query:

' Build the string to specify the search criteria.
fndstr = "obj=rtperson" & "&maxreq=0" & _
"&appid=" & App & "&cna=*" & _
"&" & strUserType & "=" & UserType

' The actual call to find the users
ils.find(fndstr)

UpBack to list of Extended Attributes topics

Implementing Filters in ILS Queries

As the popularity and usage of ILS servers increases, it will become even more important to limit the amount of information returned from an ILS server query. The Microsoft® Internet Locator Server (ILS) COM interfaces support the use of filters to restrict the amount of data returned from such a query. This tutorial demonstrates the procedure for constructing a custom filter that will allow your application to quickly locate a particular subset of users on the server.

arrowb.gifWho Should Use This Tutorial?

arrowb.gifLimitations

arrowb.gifFilter Objects

arrowb.gifCreating a Filter Object

arrowb.gifCreating Simple Filters

arrowb.gifCreating Composite Filters

UpBack to list of Tutorials

Who Should Use This Tutorial?

This tutorial is for developers who wish to define ILS query filter strings in order to target a particular user or group of users on a server. Filters can also be applied to protocols belonging to a given user.

Before referencing this tutorial, developers should read the ILS Extended Attributes tutorial.

This tutorial assumes that the reader is familiar with the Microsoft® Component Object Model (COM). For more information on COM, see Inside OLE 2 by Kraig Brockschmidt.

UpBack to list of Implementing Filters topics

Limitations

Both standard and extended attributes can be used in filtering. Attributes must be referenced by their index value—not by actual text names (see the ILS Extended Attributes tutorial). Standard attribute indices can be found in the ILS_STDATTR_* definitions in the Ils.idl file. Extended attribute indices must be defined by the user.

All filter attribute values can use the wildcard character, * , to indicate they should match any string. However, ILS server version 1.0 does not support substring matching. Versions beyond 1.0 allow you to search for partial strings. For example, using a filter created from the string "($1=*)&($5=woo*)" will return all identifiers for users whose last names begin with "woo".

For versions 1.x of the ILS server, the only filter operations supported for composite filters is AND. The rest of the composite filter operations will be discussed in this document for future reference.

UpBack to list of Implementing Filters topics

Filter Objects

A filter is either a simple filter or a composite filter. A simple filter is one that directly relates an attribute name and its target attribute value. A composite filter consists of either two or more simple filters or other composite filters.

For example, the following filter pseudo-code will find all the people who are living in Redmond, WA, and running NetMeeting or any other H323-based application. Also, these people will have the last name 'Doe' but not have the first name 'John'. In this example, composite filter A consists of four subfilters: B, C, F, and H.


Composite filter A (AND)
{
Simple filter B (lastname=Doe)
Composite filter C (OR)
{
Simple filter D (appname=ms-netmeeting)
Simple filter E (protid=h323)
}
Composite filter F (NOT)
{
Simple filter G (firstname=John)
}
Simple filter H (city=Redmond,WA)
}

The filter representation is based on LDAP filter design. However, the ILS filter interface cannot simply accept an LDAP filter string. There are two reasons:

  1. The application does not know the names of predefined attributes in the user objects, application objects, and protocol objects.
  2. The application does not have the knowledge of the (client and/or server) representation of non-clear-text attribute values.

The corresponding LDAP filter string of the preceding filter pseudo-code will look like:


(&(userid=*)(&(lastname=Doe)
(|(appid=ms-netmeeting)(protid=h323))
(!(firstname=John))(city=Redmond,WA)))

UpBack to list of Implementing Filters topics

Creating a Filter Object

There are two ways to create a filter object:

The IIlsMain::CreateFilter is prototyped as follows:


HRESULT IIlsMain::CreateFilter(
[in] ILS_FILTER_TYPE FilterType;
[in] ILS_FILTER_OP FilterOp;
[out] IIlsFilter **ppFilter);

The IIlsMain::StringToFilter is prototyped as follows:


HRESULT IIlsMain::StringToFilter(
[in] BSTR bstrFilterString,
[out] IIlsFilter **ppFilter);

This method takes a regular expression filter string and converts it to a filter object (either composite or simple). For the filter in the previous example, the regular expression would look like:

$1=* & $5=Doe & ($10=ms-netmeeting | $13=h323) & $4!=John & $6=Redmond, WA

The application can also add parentheses around relations for clarity, such as:

($1=*)&(($5=Doe) & (($10=ms-netmeeting) | ($13=h323)) & ($4!=John) & ($6=Redmond, WA))

In this example, $1 indicates the user identifier attribute, $5 is last name, $10 is application identifier, $13 is protocol identifier, $4 is first name, and $6 is city name. The standard attributes are indexed because the application does not know the actual attribute names in the server. All the indices are defined as type ILS_STD_ATTR_NAME. Values of standard attributes are defined in the Ils.idl file and are also listed in the IIlsUser::SetStandardAttribute method description.

All search strings must include ($1="pattern") to inform the server we are interested in receiving user information. Most filters will use a pattern of ($1=*) to return all users whose attributes match the remainder of the filter string.

UpBack to list of Implementing Filters topics

Creating Simple Filters

The following methods are used to set the attributes of a simple filter once it has been created. All simple filters are comprised of name-value pairs, and both must be set for every simple filter.


HRESULT IIlsFilter::SetStandardAttributeName(
[in] ILS_STD_ATTR_NAME usrStdAttr);

SetStandardAttributeName sets a standard attribute name. The names are ILS_STD_ATTR_NAME indices.


HRESULT IIlsFilter::SetExtendedAttributeName(
[in] BSTR bstrAnyAttrname);

SetExtendedAttributeName sets an arbitrary attribute name. This must also be a numerical index. See the ILS Extended Attributes tutorial for more information.


HRESULT IIlsFilter::SetAttributeValue(
[in] BSTR bstrAttrValue);

SetAttributeValue sets a target attribute value. All values are of type BSTR.

The following code demonstrates how to create a simple filter and use it to locate users with the last name "Johnson".


// Create the simple filter object.
hr = CreateFilter(ILS_FITLERTYPE_SIMPLE, ILS_FILTEROP_EQUAL, &pFilter);
if(SUCCEEDED(hr)
{
// Set the filter name.
hr = pFilter->SetStandardAttributeName(ILS_STDATTR_LAST_NAME);

if(SUCCEEDED(hr)
{
// Set the filter value.
LPTSTR_to_BSTR(&bstrLastName, "Johnson");
hr=pFilter->SetStandardAttributeValue( bstrLastName );
...

// Use the filter we have created to enumerate users.
hr = EnumUsers(pServer, pFilter, NULL, NULL, &uReqID);
...
}
}

UpBack to list of Implementing Filters topics

Creating Composite Filters

The following methods are used in creating composite filters.


HRESULT IIlsFilter::AddSubFilter (
[in] IIlsFilter *pFilter );

AddSubFilter appends a filter to the list of subfilters in a composite filter. The order of subfilters is not important.


HRESULT IIlsFilter::RemoveSubFilter (
[in] IIlsFilter *pFilter );

RemoveSubFilter removes the specified filter from the list of subfilters in a composite filter.


HRESULT IIlsFilter::GetCount (
[out] ULONG *pcElements );

GetCount counts the number of subfilters in a given composite filter.

The following code sample creates a composite filter that can be used to search for an ILS user named "Joe Johnson".


// Create the first simple filter object.
hr = CreateFilter(
ILS_FILTERTYPE_SIMPLE,
ILS_FILTEROP_EQUAL,
&pFilterOne);

if(SUCCEEDED(hr))
{
// Set the filter name.
hr = pFilterOne->SetStandardAttributeName(
ILS_STDATTR_LAST_NAME);
if(SUCCEEDED(hr))
{
// Set the filter value.
LPTSTR_to_BSTR(&bstrLastName, "Johnson");
hr=pFilterOne->SetStandardAttributeValue( bstrLastName );
...
}
}

// Create the second simple filter object.
hr = CreateFilter(
ILS_FILTERTYPE_SIMPLE,
ILS_FILTEROP_EQUAL,
&pFilterTwo);

if(SUCCEEDED(hr))
{
// Set the filter name.
hr = pFilterTwo->SetStandardAttributeName(
ILS_STDATTR_FIRST_NAME);

if(SUCCEEDED(hr))
{
// Set the filter value.
LPTSTR_to_BSTR(&bstrFirstName, "Joe*");
hr=pFilterTwo->SetStandardAttributeValue(
bstrFirstName );
...
}
}

// Create the composite filter object.
hr = CreateFilter(
ILS_FILTERTYPE_COMPOSITE,
ILS_FILTEROP_AND,
&pFilterComp);

if(SUCCEEDED(hr))
{
// Add the subfilters to the composite filter.
hr = pFilterComp->AddSubFilter(pFilterOne);
// Note - Check for success here.

hr = pFilterComp->AddSubFilter(pFilterTwo);
// Note - Check for success here.
}

// Use the filter we have created to enumerate users.
hr = EnumUsers(
pServer,
pFilterComp,
NULL, NULL,
&uReqID);

The preceding example is a long and complicated process for building a filter. However, such a process would allow an application to implement ad hoc filters through its own UI.

The equivalent filter can be created using the StringToFilter method as follows:


// Create the string.
LPTSTR szFilter[] =
"(%lu = *) & (%lu = %s) & (%lu = %s)";

wsprintf(
szFilter,
ILS_STDATTR_USER_ID,
ILS_STDATTR_FIRST_NAME,
"Joe",
ILS_STDATTR_LAST_NAME,
"Johnson");

// Convert the string.
LPTSTR_to_BSTR(&bstrFilter, szFilter);
hr = StringToFilter(bstrFilter, &pFilter)

// Use the filter we have created to enumerate users.
hr = EnumUsers(
pServer,
pFilter,
NULL, NULL,
&uReqID);

UpBack to list of Implementing Filters topics

NetMeeting Functionality in Web Pages

The Vbocx.htm sample HTML file demonstrates just how easy it is to add Microsoft® NetMeeting™ functionality to your own Web pages. It utilizes the ActiveX™ control, Xmsconf.ocx, which is installed as part of NetMeeting. This sample demonstrates use of the control with Visual Basic® Scripting Edition (VBScript).

Some parts of this sample expect to be communicating with another instance of this sample on the remote computers. To fully exercise the sample, you should be running Vbocx.htm on every computer in the conference.

Using the VBOCX Sample

To use the VBOCX sample, simply click the link below. When the page is loaded, several edit controls and buttons will be displayed.

BulletVbocx.htm sample Web page

To initiate a conference, type the user ID of the remote computer you want to call in the User Name control in the upper left and click the Call button.

Note The user ID is set through the NetMeeting interface from the Tools menu.

To leave a conference, click the Leave button. The conference will end and the connection to all remote computers will be dropped.

The Refresh button will rewrite the current list of shareable applications on the system to the Conference Log window.

The Member Roster window displays the first and last names of everyone currently in the conference. Again, this information is set through the NetMeeting Tools menu.

The Conference Log window displays the current state of the conference, messages received, and the list of shareable applications. This window fills up fast but does not automatically scroll. You might need to adjust the scroll bar to see the latest information.

Transferring files between conference participants is accomplished by entering the fully qualified file name into the File To Transfer window and clicking the Send File button.

The Received Text and Transmitted Text windows, and the Send Data button, comprise a limited chat functionality. Simply enter the data to send into the Transmitted Text window and click the Send Data button. The text will be sent to all conference participants and will appear in the Received Text window.

Application sharing is performed by entering the name of the application into the Application To Share window and clicking the Share App button. Clicking the Unshare App button halts application sharing. The name of the application must exactly match one from the list of shareable applications on the system. This list is displayed when the Refresh button is clicked.

Notes

UpBack to list of Tutorials

Creating a NetMeeting Call Center

Help desks, customer service centers, and other service offerings that allow customers to ask questions or place orders can benefit from the addition of online NetMeeting functionality. Such a solution would allow you to route each caller to the best qualified representative based on the caller's question.

This tutorial explains how to set up a call center using NetMeeting and the NetMeeting Software Developers Kit.

arrowb.gifWho Should Use This Tutorial?

arrowb.gifLimitations

arrowb.gifCreating A Call Center

UpBack to list of Tutorials

Who Should Use This Tutorial?

This tutorial is for developers who want to build a help desk or customer service offering using NetMeeting.

This tutorial assumes that the reader is familiar with the Microsoft® Component Object Model (COM). For more information on COM, see Inside OLE 2 by Kraig Brockschmidt.

This tutorial also assumes that the reader is familiar with tools and techniques used to author Web pages. For more information about Web page authoring, see the Microsoft Internet Client SDK. The complete Internet Client SDK is available for free download at the Internet Client SDK site.

UpBack to Creating a NetMeeting Call Center

Limitations

This tutorial provides background information necessary to integrate NetMeeting calls with customer service solutions. It does not discuss how to integrate NetMeeting with specific customer service solutions you may be using.

UpBack to Creating a NetMeeting Call Center

Creating A Call Center

There are several ways to set up a NetMeeting call center.

What does the end user see?

If you choose to implement the last option from the list in the previous section, these are the steps the end user will follow:

  1. Click a link to the call center or service offering on your Web page.
  2. Fill in a form that requests information like the customer's name and the reason for the call. Some information, such as the return ILS address your representative will call, can be detected and provided by an application you write.
  3. Click a Submit button. This sends the information in the form to an application that you write. Your application determines how to route the call according to the information in the form.
  4. Wait for the return call. A Web page will appear to explain that a customer service representative will call back shortly.
  5. The customer receives a call from your customer service representative.

What does the customer service representative see?

Your customer service representative sees the customer's description of why he or she is calling, any other relevant information, and a Call-Back button to initiate a return NetMeeting call to the customer. The customer service representative gathers any information relevant to the customer's question and presses the Call-Back button. Pressing this button launches NetMeeting, if necessary, and returns the call.

How does it work?

You write Active Server Pages that gather the requisite information from the user. (Visit the Microsoft Active Server Pages Web site for more information.)

You can use the NetMeeting COM method to detect the customer's system information and automatically provide some of the fields. Following is a snippet from the NetMeeting documentation for this method.


HRESULT GetProperty(
[in] NM_SYSPROP uProp,
[out] BSTR *pbstrName);

When called with the corresponding uProp, this method can return the following types of information (in the pbstrName parameter), which can be automatically entered into the fields on the Active Server Page.
NM_SYSPROP_EMAIL_NAME Customer's e-mail name.
NM_SYSPROP_RESOLVE_NAME ILS name that your customer service representative can use to call the customer back.
NM_SYSPROP_SERVER_NAME Name of the ILS server used by the customer.
NM_SYSPROP_FIRST_NAME User's first name.
NM_SYSPROP_LAST_NAME User'a last name.
NM_SYSPROP_USER_CITY City.
NM_SYSPROP_USER_COMMENTS User comments.
NM_SYSPROP_USER_COUNTRY Country (two-letter country codes).
NM_SYSPROP_USER_NAME User's full name (first and last).
NM_SYSPROP_USER_CATEGORY Can be one of the following:
NM_CATEGORY_PERSONAL
NM_CATEGORY_BUSINESS
NM_CATEGORY_ADULT
NM_SYSPROP_INSTALL_DIRECTORY Directory in which NetMeeting is installed.
NM_SYSPROP_IS_RUNNING Determines if Conf.exe is running (pbstrName will return 0 if it is not running, or 1 if it is running.
NM_SYSPROP_IN_CONFERENCE Determines if the local system is currently in a conference (pbstrName will return 0 if it is not in a conference, or 1 if it is in a conference).

When the user clicks the Submit button, your Active Server Page should send all the information the user has entered as well as the information detected by INmSysInfo::GetProperty.

Each of your customer service representatives should log onto a designated ILS server. You can write code that queries the server for available customer service representatives and assigns the incoming service request to the appropriate customer service representative. The ILS Extended Attributes tutorial contains information about setting and retrieving attributes of users logged onto an ILS server.

Once your application has chosen a customer service representative to whom the call will be routed, you can display information on his or her screen about the customer and the customer's request. You can include a button or HTML link that enables the customer service representative to initiate a NetMeeting call to the customer.

To include an HTML link, you can use the callto: protocol handler. A callto: link will work on any computer that has Microsoft® Internet Explorer and NetMeeting installed. Use one of the following formats to create a NetMeeting call link on your Web page:

Format Example
callto:DNS name callto:machine2.test.com
callto:IP address callto:157.55.22.31
callto:e-mail address callto:user@test.com
callto:server name/e-mail address callto:uls4.microsoft.com/user@test.com

For example, if John Smith wanted to embed a link in his Web page so that other people could call him, he would add the following HTML tag:


Call me using NetMeeting at
<A HREF="callto:uls.microsoft.com/jsmith@somedomain.com>
uls.microsoft.com/jsmith@somedomain.com</A>

To include a call button in an application, use the INmManager::CreateCall method to place a call to the user at the address the user provided on the Web-based form.


HRESULT CreateCall(
[out] INmCall **ppCall,
[in] NM_CALL_TYPE callType,
[in] NM_ADDR_TYPE uType,
[in] BSTR bstrAddr,
[in] INmConference * pConference);

UpBack to Creating a NetMeeting Call Center

Last Updated: November 1, 1997
© 1997 Microsoft Corporation. All rights reserved. Terms of Use.