Click here to Skip to main content
15,884,099 members
Articles / Hosted Services / Serverless
Article

Peer Collaboration - People Near Me

Rate me:
Please Sign up or sign in to vote.
4.22/5 (7 votes)
18 Apr 20069 min read 56.8K   678   24   8
An introduction to Microsoft's Peer-to-Peer Collaboration technology in Windows Vista.

Background

This article introduces Microsoft's new peer-to-peer Collaboration technology in Windows Vista. Collaboration enables a new generation of serverless applications, and provides:

  • automatic discovery of peers,
  • automatic update of a peer's presence and availability,
  • management of contacts and invitations, and
  • discovery and matching of application capabilities.

Naming and Discovery

Peer Name Resolution Protocol (PNRP) is a serverless DNS that exists in today's versions of Windows. It's used by peer-to-peer applications to register their presence and discover other peers on the local network or Internet. PNRP capabilities are vast, however, it relies heavily on functioning IPv6 infrastructure and IPv4 to IPv6 tunneling. Windows Vista includes new improvements in this area, but is the topic for another article.

To simplify discover on a subnet, Microsoft has added the People Near Me functionality to Windows Vista. Applications must Sign-In to alert others of their presence and capabilities. Once signed in, an application can publish data to indicate what applications are installed or running on the local computer, or what data is needed to launch an application. Applications can also use the underlying collaboration API to enumerate other peers on the subnet and discover their application capabilities. People Near Me provides a simple way for a user to discover people in the same office or meeting room to create ad-hoc, real-time work groups to share resources and data. It remains to be seen if this functionality will be available in a future Windows XP service pack.

Contacts

Once you have discovered someone with whom you want to have collaboration over time, you can save them as a contact. The Collaboration API includes methods to manage contacts discovered on the subnet and store them in the Windows Address Book (WAB). It also provides APIs to create invitations to collaborate using a common, registered application. Finally, APIs are provided to monitor a contact's presence similar to the way a contact's status can be monitored in an Instant Messenger application.

Application Capabilities

An application can use the collaboration APIs during installation to register its capabilities and/or parameters needed to launch an application. Other users with the same application installed or running can discover and use this information to collaborate.

This new functionality combined with existing peer-to-peer graphing and grouping technology will allow developers to create new and innovative applications.

Introduction

Microsoft's entire Peer-to-Peer technology is exposed through the latest Platform SDK as C/C++ API calls. However, the code in this article shows these APIs being used from .NET managed code using C#. The sample application includes a PeerCollab class that implements the SignIn and SignOut methods to control the presence of People Near Me on the local subnet. Also, delegates are provided to show changes in the presence of other People Near Me on the same subnet. While the PeerCollab class hides the details of using Microsoft's peer-to-peer collaboration APIs (in order to simplify the programming model), the flow of unmanaged calls is outlined below.

Startup

Before any other peer-to-peer collaboration APIs can be called, PeerCollabStartup must be called to initialize the service. Likewise, PeerCollabShutdown must be called before the application exits. To ensure this occurs, a static singleton class is provided. The PeerCollab class includes a reference to guarantee that the singleton is created before any other collaboration APIs are used. As a result, you don't have to remember to do this. The following code shows the singleton class:

C#
sealed class PeerCollabService
{
  private PeerCollabService()
  {
    uint hr = PeerCollabNative.PeerCollabStartup(1);
    if (hr != 0) throw new PeerCollabException(hr);
  }
  ~PeerCollabService()
  {
     PeerCollabNative.PeerCollabShutdown();
  }
  public static readonly PeerCollabService 
         Instance = new PeerCollabService();
}

The PeerCollab Class

The purpose of the PeerCollab class is to expose all the peer-to-peer collaboration functionality. However, the code download at the beginning of this article only implements the ability to sign-in, sign-out, display People Near Me, and handle events to monitor People Near Me as they come and go on the local subnet.

The PeerCollab class constructor requires requires no parameters. In order for your application to publish its presence, it must call the SignIn method.

SignIn

The SignIn method takes a parameter that determines how your presence can be monitored:

  • NearMe allows other applications on the same subnet to discover and monitor your presence.
  • Internet allows other contacts to monitor your presence.
  • All allows both subnet and internet users to monitor your presence.
  • None prevents others from seeing your application.

Note that the sample application only demonstrates the NearMe option. The following code shows how the SignIn method calls the underlying PeerCollabSignin API:

C#
public void SignIn(PeerSignInOption Options)
{
  uint hr = 
   PeerCollabNative.PeerCollabSignin(IntPtr.Zero, 
   Options);
  if (hr != 0) throw new PeerCollabException(hr);

  RegisterForEvents();
}

Note that according to Microsoft's documentation, the first parameter is supposed to take a HWND handle to a parent window. at the time of writing this article using the February 2006 CTP of Windows Vista, this parameter cannot be used from .NET. The purpose of this parameter is to display the "acknowledge privacy" window. Until you acknowledge the privacy statement, the current Windows account cannot sign-in to People Near Me, and the sample application will log a PEER_E_PRIVACY_DECLINED exception. Under Control Panel, Network and Internet, click on the People Near Me applet. The first time you do this, you should be presented with a window to acknowledge the privacy statement.

Once Microsoft supports the HWND parameter from .NET, the "acknowledge privacy" window should appear for the sample application rather than immediately throwing an exception.

SignOut

The SignOut method supports the same options as the SignIn method, and allows partial or complete change of presence. The following code shows how the SignOut method calls the underlying PeerCollabSignout API.

C#
public void SignOut(PeerSignInOption Options)
{
  uint hr = PeerCollabNative.PeerCollabSignout(Options);
  if (hr != 0) throw new PeerCollabException(hr);

  UnregisterForEvents();
}

Note that signing in or out affects all other peer-to-peer collaboration applications running under the current Windows account. If you are planning to use collaboration from a service, you should consider creating a separate, distinct account for your service.

Status

Use the Status property at any time to determine the current application's sign-in status. The following code shows how the Status property calls the underlying PeerCollabGetSigninOptions API.

C#
public PeerSignInOption Status
{
  get
  {
    PeerSignInOption Options;
    uint hr = PeerCollabNative.PeerCollabGetSigninOptions(out Options);
    if (hr != 0) throw new PeerCollabException(hr);
    return Options;
  }
}

People Near Me Collection

Once your application is signed in, you can use the PeopleNearMe property to enumerate the People Near Me on the same subnet.

C#
public PeopleNearMeCollection PeopleNearMe
{
  get { return new PeopleNearMeCollection(); }
}

This property returns a PeopleNearMeCollection collection. The collection implements the IEnumerable interface. The Reset method of this interface calls the underlying PeerCollabEnumPeopleNearMe API to retrieve the current list of People Near Me on the same subnet.

C#
public void IEnumerable.Reset()
{
  uint hr;
  if (hPeerEnum != IntPtr.Zero)
  {
    hr = PeerCollabNative.PeerEndEnumeration(hPeerEnum);
    if (hr != 0) throw new PeerCollabException(hr);
    hPeerEnum = IntPtr.Zero;
  }

  hr = PeerCollabNative.PeerCollabEnumPeopleNearMe(out hPeerEnum);
  if (hr != 0) throw new PeerCollabException(hr);

  uint count;
  hr = PeerCollabNative.PeerGetItemCount(hPeerEnum, out count);
  if (hr != 0) throw new PeerCollabException(hr);

  this.count = (int)count;
  index = -1;
}

Events

The Collaboration API allows an application to register and receive events when other applications' presence or capabilities change. The following code shows how the internal RegisterForEvents method uses the PeerCollabRegisterEvent method to register for events.

C#
private void RegisterForEvents()
{
  if (hPeerEvent != IntPtr.Zero) return; // already registered

  AutoResetEvent sendEvent = new AutoResetEvent(false);
  Handle = ThreadPool.RegisterWaitForSingleObject(sendEvent, 
           new WaitOrTimerCallback(PeerEventWorker), null, -1, false);

  PEER_COLLAB_EVENT_REGISTRATION[] info = 
  {
    new PEER_COLLAB_EVENT_REGISTRATION(
        PEER_COLLAB_EVENT_TYPE.PEER_EVENT_WATCHLIST_CHANGED),
    new PEER_COLLAB_EVENT_REGISTRATION(
        PEER_COLLAB_EVENT_TYPE.PEER_EVENT_ENDPOINT_CHANGED),
    new PEER_COLLAB_EVENT_REGISTRATION(
        PEER_COLLAB_EVENT_TYPE.PEER_EVENT_ENDPOINT_PRESENCE_CHANGED),
    new PEER_COLLAB_EVENT_REGISTRATION(
        PEER_COLLAB_EVENT_TYPE.PEER_EVENT_ENDPOINT_APPLICATION_CHANGED),
    new PEER_COLLAB_EVENT_REGISTRATION(
        PEER_COLLAB_EVENT_TYPE.PEER_EVENT_ENDPOINT_OBJECT_CHANGED),
    new PEER_COLLAB_EVENT_REGISTRATION(
        PEER_COLLAB_EVENT_TYPE.PEER_EVENT_MY_ENDPOINT_CHANGED),
    new PEER_COLLAB_EVENT_REGISTRATION(
        PEER_COLLAB_EVENT_TYPE.PEER_EVENT_MY_PRESENCE_CHANGED),
    new PEER_COLLAB_EVENT_REGISTRATION(
        PEER_COLLAB_EVENT_TYPE.PEER_EVENT_MY_APPLICATION_CHANGED),
    new PEER_COLLAB_EVENT_REGISTRATION(
        PEER_COLLAB_EVENT_TYPE.PEER_EVENT_MY_OBJECT_CHANGED),
    new PEER_COLLAB_EVENT_REGISTRATION(
        PEER_COLLAB_EVENT_TYPE.PEER_EVENT_PEOPLE_NEAR_ME_CHANGED),
    new PEER_COLLAB_EVENT_REGISTRATION(
        PEER_COLLAB_EVENT_TYPE.PEER_EVENT_REQUEST_STATUS_CHANGED)
  };

  int size = Marshal.SizeOf(info[0]);
  IntPtr infoptr = Marshal.AllocCoTaskMem(info.Length*size);

  int offset = 0;
  foreach (PEER_COLLAB_EVENT_REGISTRATION item in info)
  {
    Marshal.StructureToPtr(item, (IntPtr)(infoptr.ToInt32()+offset), false);
    offset += size;
  }
  uint result = PeerCollabNative.PeerCollabRegisterEvent(sendEvent.Handle, 
                info.Length, infoptr, out hPeerEvent);
  if (result != 0) Marshal.ThrowExceptionForHR((int)result);
}

The PEER_COLLAB_EVENT_REGISTRATION data structure includes a field indicating the type of event to monitor. An array of these data structures can be passed to the register method. Much of the code above takes care of marshalling this data structure into a block of unmanaged memory.

The WaitOrTimerCallback represents a callback method that is executed when something changes in the Collab. RegisterWaitForSingleObject registers this delegate with the default thread pool using an infinite timeout. Finally, the event handle and data structure is passed to PeerCollabRegisterEvent.

The following code shows how the worker thread handles incoming events.

C#
private void PeerEventWorker(object xdata, bool timedOut)
{
  while (true)
  {
    IntPtr evptr;
    uint result = 
         PeerCollabNative.PeerCollabGetEventData(hPeerEvent, out evptr);
    if (result == PeerCollabNative.PEER_S_NO_EVENT_DATA || 
                  evptr == IntPtr.Zero)
        break;
    if (result != 0) Marshal.ThrowExceptionForHR((int)result);

    PEER_COLLAB_EVENT_DATA data = 
        (PEER_COLLAB_EVENT_DATA)Marshal.PtrToStructure(evptr, 
        typeof(PEER_COLLAB_EVENT_DATA));
    IntPtr dataptr = (IntPtr)(evptr.ToInt32() + 
        Marshal.SizeOf(typeof(PEER_COLLAB_EVENT_DATA)));

    switch (data.eventType)
    {
      case PEER_COLLAB_EVENT_TYPE.PEER_EVENT_REQUEST_STATUS_CHANGED:
        HandleEventRequestStatusChanged(dataptr);
        break;
      //...
    }
    PeerCollabNative.PeerFreeData(evptr);
  }
}

The PeerCollabGetEventData method is called to get each event. The loop ensures that all events are proceeded until PEER_S_NO_EVENT_DATA is returned indicating no further events. Each event data structure is marshaled, and a switch statement is used to handle each event type.

Event Types

While there are 11 types of events, this sample application only implements the PeopleNearMeChanged and RequestStatusChanged events. Future articles will demonstrate how the other events are typically used.

The PeopleNearMeChanged event fires when a collaboration application's presence on the same subnet changes. Three types of changes can occur:

  • Added occurs when a local or remote application signs into People Near Me (serverless presence).
  • Updated occurs when a local or remote application changes its User Information (name or picture).
  • Deleted occurs when a remote application signs out of People Near Me, or the local Windows account signs out.

The RequestStatusChanged event fires when the status of an endpoint raises an error. It's unclear when and how this event should be used.

Using the Sample Application

The sample application only runs on Windows Vista. It automatically signs you into People Near Me, and shows you whether others on the same subnet are signed in too. The top list shows you the nick names of those who are signed in. The following code shows how this is done:

C#
private void Form_Load(object sender, System.EventArgs e)
{
  collab = new PeerCollab();
  collab.RequestStatusChanged += new 
    Peer.Collaboration.PeerCollab.RequestStatusChangedHandler(
    collab_RequestStatusChanged);
  collab.PeopleNearMeChanged += new 
    PeerCollab.PeopleNearMeChangedHandler(
    collab_PeopleNearMeChanged);

  try
  {
    collab.SignIn(PeerSignInOption.NearMe);

    foreach (PeopleNearMe pnm in collab.PeopleNearMe)
    {
      listBox1.Items.Add(pnm);
    }

    LogMessage(@"SignIn", "Completed");
  }
  catch (PeerCollabException ex)
  {
    LogMessage(@"SignIn", ex.Message);
  }
}

Click on a name to see more information about each application signed into People Near Me. The bottom list contains a log of events or error messages that occur while the application is running.

If you only have one Windows Vista computer, use the Switch User feature to login as multiple users. Each user account has its own People Near Me presence on the subnet. You only need to start the sample application under one account. Under the other accounts, open Control Panel and use People Near Me to sign-in. You will notice a new icon appears in the system tray:

  • indicates you are signed in to People Near Me.
  • indicates you are signed out.

Right click on these icons to change the presence or your account or one of the other accounts. Also, right click and select Properties to change the User Information nickname. Changing the name will result in an Updated event being logged by the sample application. The following code shows how the sample application handles the PeopleNearMeChanged event.

C#
void collab_PeopleNearMeChanged(object sender, 
     PeerCollabPNMChangedEventArgs e)
{
  if (e.PeopleNearMe == null) // its me
  {
    switch (e.Action)   
    {
    case PeerChangeType.Deleted:
      LogMessage(@"SignOut", "Me");
      RefreshPeopleNearMe();
      break;
    case PeerChangeType.Added:
      LogMessage(@"SignIn", "Me");
      break;
    case PeerChangeType.Updated:
      LogMessage(@"Update", "Me");
      break;
    }
  }
  else
  {
    switch (e.Action) // its someone else
    {
    case PeerChangeType.Added:
      LogMessage(@"SignIn", e.PeopleNearMe.NickName);
      AddPeopleNearMe(e.PeopleNearMe);
      break;
    case PeerChangeType.Deleted:
      // the event does not indicate who was deleted,
      // so we are forced to refresh
      LogMessage(@"SignOut", "Someone Near Me");
      RefreshPeopleNearMe();
      break;
    case PeerChangeType.Updated:
      LogMessage(@"Update", e.PeopleNearMe.NickName);
      RefreshPeopleNearMe();
      break;
    }
  }
}

If the PeopleNearMe property is null, the event is a change to the local Windows account, otherwise, it's for another account (could be local or remote). For the Deleted action, the event does not include the specific People Near Me reference. As a result, the sample application refreshes its list by enumerating the PeopleNearMe again. This behavior may change by the time Windows Vista is released.

Point of Interest

You can monitor my ongoing progress while writing about peer-to-peer collaboration, by visiting my blog.

Links to Resources

I have found the following resources to be very useful in understanding peer-to-peer collaboration:

Conclusion

I hope you have found this article interesting. I'll be writing more articles to describe the other features of Peer-to-Peer Collaboration in the coming weeks and months.

If you have suggestions for other topics, please leave a comment. Finally, a big thanks to all those who have been voting.

History

  • Initial revision.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here


Written By
Web Developer
Canada Canada
Adrian Moore is the Development Manager for the SCADA Vision system developed by ABB Inc in Calgary, Alberta.

He has been interested in compilers, parsers, real-time database systems and peer-to-peer solutions since the early 90's. In his spare time, he is currently working on a SQL parser for querying .NET DataSets (http://www.queryadataset.com).

Adrian is a Microsoft MVP for Windows Networking.

Comments and Discussions

 
GeneralVista 64 Pin
Matt Newman19-Feb-07 11:21
Matt Newman19-Feb-07 11:21 
GeneralRunning demo under Windows XP Pin
Andrew Houghton2-Feb-07 8:09
Andrew Houghton2-Feb-07 8:09 
Is it possible to run this demo under Windows XP Professional? I have installed .NET 3.0 Framework and installed the P2P networking facilities in Add and Remove programs, but I get an application error when I try to run it Frown | :(

See the end of this message for details on invoking
just-in-time (JIT) debugging instead of this dialog box.

************** Exception Text **************
System.TypeInitializationException: The type initializer for 'Peer.Collaboration.PeerCollab' threw an exception. ---> System.TypeInitializationException: The type initializer for 'Peer.Collaboration.PeerCollabService' threw an exception. ---> System.EntryPointNotFoundException: Unable to find an entry point named 'PeerCollabStartup' in DLL 'p2p.dll'.
at Peer.Collaboration.PeerCollabNative.PeerCollabStartup(Int16 wVersionRequested)
at Peer.Collaboration.PeerCollabService..ctor()
at Peer.Collaboration.PeerCollabService..cctor()
--- End of inner exception stack trace ---
at Peer.Collaboration.PeerCollab..cctor()
--- End of inner exception stack trace ---
at Peer.Collaboration.PeerCollab..ctor()
at article_src.Form.Form_Load(Object sender, EventArgs e)
at System.Windows.Forms.Form.OnLoad(EventArgs e)
at System.Windows.Forms.Form.OnCreateControl()
at System.Windows.Forms.Control.CreateControl(Boolean fIgnoreVisible)
at System.Windows.Forms.Control.CreateControl()
at System.Windows.Forms.Control.WmShowWindow(Message& m)
at System.Windows.Forms.Control.WndProc(Message& m)
at System.Windows.Forms.ScrollableControl.WndProc(Message& m)
at System.Windows.Forms.ContainerControl.WndProc(Message& m)
at System.Windows.Forms.Form.WmShowWindow(Message& m)
at System.Windows.Forms.Form.WndProc(Message& m)
at System.Windows.Forms.Control.ControlNativeWindow.OnMessage(Message& m)
at System.Windows.Forms.Control.ControlNativeWindow.WndProc(Message& m)
at System.Windows.Forms.NativeWindow.Callback(IntPtr hWnd, Int32 msg, IntPtr wparam, IntPtr lparam)


************** Loaded Assemblies **************
mscorlib
Assembly Version: 2.0.0.0
Win32 Version: 2.0.50727.42 (RTM.050727-4200)
CodeBase: file:///D:/WINDOWS/Microsoft.NET/Framework/v2.0.50727/mscorlib.dll
----------------------------------------
PeerCollab
Assembly Version: 1.0.2297.13610
Win32 Version: 1.0.2297.13610
CodeBase: file:///F:/Vocabularies/Favorites/Development/Vista/People%20Near%20Me/PeerCollab.exe
----------------------------------------
System.Windows.Forms
Assembly Version: 2.0.0.0
Win32 Version: 2.0.50727.42 (RTM.050727-4200)
CodeBase: file:///D:/WINDOWS/assembly/GAC_MSIL/System.Windows.Forms/2.0.0.0__b77a5c561934e089/System.Windows.Forms.dll
----------------------------------------
System
Assembly Version: 2.0.0.0
Win32 Version: 2.0.50727.42 (RTM.050727-4200)
CodeBase: file:///D:/WINDOWS/assembly/GAC_MSIL/System/2.0.0.0__b77a5c561934e089/System.dll
----------------------------------------
System.Drawing
Assembly Version: 2.0.0.0
Win32 Version: 2.0.50727.42 (RTM.050727-4200)
CodeBase: file:///D:/WINDOWS/assembly/GAC_MSIL/System.Drawing/2.0.0.0__b03f5f7f11d50a3a/System.Drawing.dll
----------------------------------------
System.Configuration
Assembly Version: 2.0.0.0
Win32 Version: 2.0.50727.42 (RTM.050727-4200)
CodeBase: file:///D:/WINDOWS/assembly/GAC_MSIL/System.Configuration/2.0.0.0__b03f5f7f11d50a3a/System.Configuration.dll
----------------------------------------
System.Xml
Assembly Version: 2.0.0.0
Win32 Version: 2.0.50727.42 (RTM.050727-4200)
CodeBase: file:///D:/WINDOWS/assembly/GAC_MSIL/System.Xml/2.0.0.0__b77a5c561934e089/System.Xml.dll
----------------------------------------

GeneralRe: Running demo under Windows XP Pin
matrix10121-Mar-08 1:54
matrix10121-Mar-08 1:54 
GeneralRe: Running demo under Windows XP Pin
TheNakedPirate27-Apr-08 13:26
TheNakedPirate27-Apr-08 13:26 
AnswerRe: Running demo under Windows XP Pin
sumantamca6-Sep-08 2:44
sumantamca6-Sep-08 2:44 
GeneralGot my 5 Pin
Vanarion8-May-06 1:30
Vanarion8-May-06 1:30 
GeneralRe: Got my 5 Pin
Adrian_Moore8-May-06 2:34
Adrian_Moore8-May-06 2:34 
AnswerRe: Got my 5 Pin
Vanarion10-May-06 2:13
Vanarion10-May-06 2:13 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.