People Near Me (PNM) is a new feature of Windows Vista, and provides a standard set of APIs that allow one to write applications that can interact and collaborate with other users on the local subnet. PNM provides four key services—Discover, Interact, Collaborate, Publish—that enable a user to share objects and applications, subscribe to events, and send invites for others to join. This section covers in detail only the Discover and Interact services of PNM.
Discover
Internally, PNM uses Web discovery to publish various details, such as name, computer name, IP address, port, and so on. A user is not signed in automatically; instead, a user signs in via the Control Panel. After having done so, a user can choose the option to sign in automatically whenever Windows starts.
Figure 2 and Figure 3 show the PNM icon when a user is signed in and signed out, respectively.
Figure 2. PNM, signed in
Figure 3. PNM, signed out
As shown in Figure 4, the Settings tab of PNM allows a user to sign in and out of PNR and change settings, such as the friendly name that others will see, which profile of users one would want to accept invitations from, and so on.
Figure 4. People Near Me options
A significant portion of the PNM functionality is provided by a static class that is called PeerCollaboration and can be found in the System.Net.PeerToPeer.Collaboration namespace. This class allows you to interact with the collaboration infrastructure, which enables one to sign in, sign out, register and unregister applications, and so on. PeerCollaboration has a static method that is called SignIn and with which one can sign in to the collaboration infrastructure, as shown in Listing 21. Note that you must have IPv6 installed for this to work; otherwise, you will get a PeerToPeerException that shows the message, “The sign-in succeeded, but there are no IPv6 addresses available at this time.”
Each PNM is represented by the PeerNearMe class, which exposes all of the details for a peer, such as the endpoints at which they can be reached, nickname, whether they are online, and so on. After you have signed in, you can try to find any peers that are within the PNM infrastructure via the GetPeersNearMe method. This returns a collection of PeerNearMe that represents the peers who are signed-in in the same local subnet.
PeerCollaboration.SignIn(PeerScope.All);
PeerNearMeCollection peers = PeerCollaboration.GetPeersNearMe();
Console.WriteLine("{0} peers found.", peers.Count);
Listing 21. Sign in to collaboration
Contacts
The other option for discovering people is to search in the Windows Address Book (WAB). The entries that are saved in the WAB are called as Contacts and enable interaction beyond the local subnet. The WAB is a new feature of Windows Vista. You can find the WAB saved as “Contacts”; it is usually stored in C:\Users\<user-name>\Contacts.
The WAB features are exposed via a class that is called ContactManager and can be retrieved via the PeerCollaboration class. The ContactManager class exposes a method that is called GetContacts and returns a collection of PeerContacts that are available in the signed-in scope, as shown in the following snippet:
ContactManager contactMgr = PeerCollaboration.ContactManager;
PeerContactCollection contacts = contactMgr.GetContacts();
You can add a found peer to your address book by using the AddToContactManager() method on the PeerContact. If that peer already exists as a contact, you will get a PeerToPeerException that shows the message, “Peer collaboration add contact failed. Contact already exists in contact manager.”
Listing 22 shows the code and the output when there is one more peer called “Amit2” on the subnet. Figure 5 shows what the contact looks like when it is added to the WAB.
PeerNearMeCollection peers = PeerCollaboration.GetPeersNearMe();
Console.WriteLine("{0} peers found.", peers.Count);
foreach (PeerNearMe peer in peers)
{
PeerContact contact = peer.AddToContactManager();
Console.WriteLine("Peer {0} is online:{1} with {2} endpoints", peer.Nickname, peer.IsOnline, peer.PeerEndPoints.Count);
}
1 peers found.
1: Peer Amit2 is online:True with 1 endpoints
Listing 22. Peers found on the subnet
Figure 5. Contact added to Windows Address Book
Interact
To interact with another peer by using some application (typically, a line-of-business (LOB) application), the same application must be installed on both of the computers—in other words, on yours and on the peer with whom you are planning to interact. Furthermore, this application must be installed on both the computers with the same GUID and must be registered with the peer-collaboration infrastructure as one of the applications that is available for interaction. To find the endpoint at which an application can be reached, you can use the EndPoint property of the PeerNearMe class. This property returns an IPEndPoint object.
The invitation that a user sends to a peer to launch a certain application contains an XML payload and is sent over a secure connection. The XML payload consists of the following:
-
A unique GUID that identifies the application
-
A user-defined message that is displayed to the peer who receives the invitation
-
Additional data that essentially is a placeholder in which to put any blob of data that the target application might expect (for example, the endpoint details of the peer who sends the invitation)
Figure 6 shows an example of what the invitation looks like on the target computer when one is inviting to launch Windows Meeting Space. This request is from an unknown peer. (If this were from a known contact—that is, part of WAB—the request would look like what is shown in Figure 8.)
Figure 6. Unknown-peer invitation
Clicking the View button shows the details of the invitation that is shown in Figure 7. If you accept the invitation, the application will launch. At this point, the peer infrastructure is no longer part of the process; instead, the applications that are on both ends are communicating by using regular communication protocols, such as TCP, HTTP, and so on.
Figure 7. Unknown Windows Meeting Space invitation details
The GetLocalRegisteredApplications method on the PeerCollaboration class returns a collection of type PeerApplications that represents all of the applications that are registered on the local computer. By default, this method returns the applications that are registered for all users; however, if you want to restrict that to the logged-on user, you can use the overloaded method that accepts a PeerApplicationRegisterationType.
Listing 23 shows a sample listing of the applications. It is this list of applications that is available for a peer to use.
PeerApplicationCollection apps = PeerCollaboration.GetLocalRegisteredApplications();
int i = 1;
Console.WriteLine("{0} Applications Found:", apps.Count);
foreach (PeerApplication someApp in apps)
{
Console.WriteLine("\t{0}: ID:{1}", i, someApp.Id);
Console.WriteLine("\t\tDesc:{0}", someApp.Description);
Console.WriteLine("\t\tPath:{0}", someApp.Path);
Console.WriteLine("\t\tArguments:{0}", someApp.CommandLineArgs);
}
Listing 23. Iterating through all available peer applications
You use the Invite() method on the PeerNearMe class to invite a selected peer to launch the application. This method takes three parameters: the application that is to be launched, a message for the user, and some data (as shown in Listing 24). The data parameter is specific for each application; based on its implementation, only the application knows what to expect. In many cases, it would contain your endpoint address, so that the application knows the address to which to “talk back.” The Invite() method returns a PeerInvitationReponse and can be one of the following options:
-
Declined
-
Accepted
-
Expired
PeerInvitationResponse response = peer.Invite(myApp, "Want to work on this P2P article together?", null);
if (response.PeerInvitationResponseType != PeerInvitationResponseType.Accepted)
MessageBox.Show(peer.Nickname + " declined the request.");
Listing 24. Inviting a peer to launch an application
Figure 8 shows an invitation from a trusted contact to launch Windows Meeting Space. Clicking on the View button shows you the details of the invitation that is shown in Figure 9.
Figure 8. Known-peer invitation
Figure 9. Known Windows Meeting Space invitation details
Creating Your PeerApplication
A PeerApplication can be any application that can run on Windows. The only difference between a regular application and a peer application is that the latter is registered as available on the P2P infrastructure. Typically, an application is registered during the installation process.
Registering a new application manually or programmatically is fairly straightforward. The first step is to create a new instance of the PeerApplication class, and the second step is to register that instance on the P2P infrastructure. We need a unique ID (represented by a GUID) to identify this application. This ID must be the same on all of the computers on which this application will be installed and is used to identify the application that is to be launched on the target computer.
In addition to the path of the executable and a human-readable description, we also must assign a scope to the application. Typically, this scope is dictated by the design of the application and what it is supposed to be doing.
Listing 25 shows an example of creating a new PeerApplication that configures Microsoft Notepad to be available as part of the P2P infrastructure.
PeerApplication myApplication = new PeerApplication();
myApplication.Description = "My Test Application";
myApplication.Id = new Guid("B0C29122-398A-4416-8AA7-0A8A9AE82B23");
myApplication.Path = @"c:\windows\notepad.exe";
myApplication.PeerScope = PeerScope.All;
Listing 25. Creating a new PeerApplication
The third step is to register the application on the P2P infrastructure by using the RegisterApplication method on the PeerCollaboration class. This accepts two parameters: the application that you want to register, and the scope of the users for which the application is available (that is, the currently logged-on user or All Users). A PeerToPeerException is thrown if the registration fails.
PeerCollaboration.RegisterApplication(myApplication, PeerApplicationRegistrationType.CurrentUser);
The same application can be registered many times, as long as a unique ID is associated with each registration. For example, Listing 26 shows a sample output of all of the locally registered peer applications. Note that we have Notepad registered twice, with two different IDs.
3 Applications Found:
1: ID:81facd1e-c761-4330-b56c-a7286a3424aa
Desc:Amit Test Application
Path:c:\windows\notepad.exe
Arguments:
1: ID:b0c29122-398a-4416-8aa7-0a8a9ae82b23
Desc:Amit Test Application
Path:c:\windows\notepad.exe
Arguments:
1: ID:153999c2-cec7-4233-8599-819dc4840a0c
Desc:Windows Meeting Space
Path:C:\Program Files\Windows Collaboration\WinCollab.exe
Arguments:/e
Listing 26. Sample output of locally registered applications
If you are trying to register an application that will be available for All Users, the process that is executing this requires administrator privileges, because this writes to the registry. If you don’t run this with elevated privileges, the registration will fail and throw a PeerToPeerException that shows the message, “Peer collaboration register application failed.” However, if you examine the inner exception, you see the more meaningful message of “Access Denied.” Of course, if you have User Account Control (UAC) switched off, you already are running with administrator privileges, and the registration will succeed.
PeerCollaboration.RegisterApplication(myApplication, PeerApplicationRegistrationType.AllUsers);
As mentioned earlier, an application that is designed to be invoked over a peer infrastructure (such as Windows Meeting Space) typically would be registered during the installation process of that application. If you want to register this manually or if you are creating the setup (for example, by using the Setup and Deployment project in Microsoft Visual Studio or WiX), you must create an entry in the following Windows registry hives, depending on the scope. If the application is available for All Users, you must register it in the HKLM hive. If the application is available only for the current user, you must use the HKCU hive.
-
HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\PeerNet\AppInvite\MyApplications
-
HKEY_CURRENT_USER\Software\Microsoft\Windows NT\CurrentVersion\PeerNet\AppInvite\MyApplications
Each application is a new key that consists of the application’s ID and the structure, as shown in the following snippet and in Figure 10:
"CommandLineArgs"=""
"PublicationScope"=dword:00000002
"Filename"="C:\\Windows\\notepad.exe"
"Description"="Some App"
Figure 10. Registry details of an application registered on the peer infrastructure
If you accidentally use the same ID for two different applications, each of which is in a different scope (that is, Local User and All Users), the application that is found in Local User takes precedence. For example, if the 81facd1e-c761-4330-b56c-a7286a3424aa key is used to register both Notepad and UltraEdit in the All Users and Current User scopes, respectively, when iterating through the available list of registered applications, you will find only the reference to UltraEdit, because that takes precedence over the reference to Notepad.
If you tried to register an application by using an existing ID in the same scope, you will get an exception that says that the application was already registered. Also, if the application on the target system was not found (for example, there might be a typing error in the path of the executable), you will get an “Unable to start the program” error message, as shown in Figure 11.
Figure 11. Peer application not found
If your peer application needs some metadata at startup—such as how is it launched, or to read any initial data such as any LOB-specific details or endpoint details, and so on—you must use the ApplicationLaunchInfo method on the PeerCollaboration class to get those details. One of the parameters on the Invite() method (shown in Listing 24) accepts this metadata and passes it through. Listing 27 shows an example of this.
PeerApplicationLaunchInfo launchInfo = PeerCollaboration.ApplicationLaunchInfo;
if (launchInfo != null)
{
StringBuilder s = new StringBuilder();
s.Append("Message:" + launchInfo.Message + Environment.NewLine);
s.Append("PeerApplication:" + launchInfo.PeerApplication.ToString() + Environment.NewLine);
s.Append("Peer Contact:" + launchInfo.PeerContact.ToString() + Environment.NewLine);
s.Append(launchInfo.ToString());
MessageBox.Show(s.ToString());
}
Listing 27. Finding out application-launch details
If you want to “respect” the context of a peer and get its presence information, based on which you want to make some business decision (such as to initiate a session with another peer, if it is busy), use the LocalPresenceInfo property that is exposed by the PeerCollaboration class. This returns an object of type PeerPresenceInfo that exposes the PeerPresenceStatus enumeration.