Click here to Skip to main content
Click here to Skip to main content

Windows Desktop Sharing with RDP in Vista: Add a Professional Interactive Help System to your Applications

, 2 Oct 2008
Rate this:
Please Sign up or sign in to vote.
Use of the RDP API in simple classes

1.jpg

2.jpg

Introduction

Windows Vista introduced a powerful Remote Desktop Management API which is relatively unknown. This article will present an easy way to use it, in order to provide professional level help in your Vista applications.

A generic implementaton of this technique is presented in this article and is featured in my "Turbo Remote" experimental application.

Requirements

  • Windows Vista or later (if you find any way to run it on XP, tell me!). Admin rights are NOT required.
  • Knowledge of COM basics and ActiveX controls.

API Reference

The API reference is provided from Microsoft here.

Contents

  • RDP.H / RDP.CPP code for server/client implementation
  • Helpers AX.CPP and AX.H, my AX control which describes how to use an ActiveX control)
  • Test projects to demonstrate the functionality
  • Solutions / VCPROJ files for all the stuff

Features

  • Easy API
  • Allows both direct and reverse connections
  • Easy manipulation of the IRDP* classes
  • Works in x86/x64

Classes

  • RAS:: BASERDP, base for SERVER and CLIENT
  • RAS :: SERVER, implements a server
  • RAS :: CLIENT, implements a client
  • RAS :: ATTENDEE, implements an attendee
  • RAS :: CHANNEL, implements a virtual channel
  • RAS :: S_INVITATION, implements an invitation

BaseRDP

BaseRDP is a class that has common code for both server and client, like channels, data transmission, events, etc. Some useful member functions are here:

 class BASERDP
 {
 ...
 public:
   void SetWindowNotification(HWND,UINT);
   // Sends the specified message to the specified window before and after an event
   // occurs. The wParam contains the dispid of the notification
   // and the lParam the DISPPARAMS* passed (if sent before the event is processed,
   // in which case you can return 1 to prevent default processing), or NULL 
   // (if sent after the event has been processed). 
   
   void SetDataNotification(void (*)(CHANNEL*,ATTENDEE*,char*,int,void*),void*);
   // Sets a callback function to be notified when data is received at a
   // specified channel, from a specified attendee.
   // It contains the data, the size, and a custom parameter.

   void AssignChannelToAttendees(CHANNEL* c,vector<ATTENDEE*>& AssignAtts);
   // Sets the list of attendees that will send/receive data from a channel
   
   virtual CHANNEL* CreateVirtualChannel(const wchar_t* n,bool Compressed,int Priority);
   // Creates a virtual channel with the specified name, 
   // compression flag and priority (CHANNEL_PRIORITY_* flags)
   virtual HRESULT SendData(CHANNEL* C,char* d,int sz,
       bool Unc = false,vector<ATTENDEE*>* List = 0);
   // Sends data through a channel to the attendee list. If List is 0, it
   // is sent to all attendees configured previously with AssignChannelToAttendees
   virtual void OnReceiveData(CHANNEL* C,ATTENDEE* A,char* d,int sz);
   // This function calls the callback registered with SetDataNotification()

   vector<CHANNEL>& GetChannels();
   // Returns the channel list
   vector<ATTENDEE>& GetAttendees();
   // Returns the attendee list
 };

Server Implementation

The server is the application that shares the session. An application, some windows, or an entire desktop can be shared. The steps are:

  • Configure parameters and start the server.
  • Set the notification to receive events if you want to handle them manually (if you don't set a notification, there are default handlers).
  • Create an invitation ticket and (optionally) a password.
  • Send this ticket and password to the recipient in your own way.
// Create the server
RAS:: SERVER s;
// Set or retrieve connection parameters - Type (AF_INET or AF_INET6),
//        Port, Driver type (dynamic or static), Color (8/16/24 bit)
s.SetConnectionParameters(AF_INET,3389,true,24);
// Start the Server
s.Open();
// Set the shared region if desired
RECT rc = {0};
rc.right = GetSystemMetrics(SM_CXFULLSCREEN);
rc.bottom = GetSystemMetrics(SM_CYFULLSCREEN);
s->SetDesktopRegion(rc);
// Create Invitation, specifying the max number  of viewers (1)
s.Invite(0,L”password”,L"group",1);

If you wish to connect to the client instead of accepting connections (that might be needed if your PC is behind an IPv4 NAT, for example), you can use SERVER::ReverseOpen. The ticket you must pass to that function must have been created by the client and transported to you through an external interface.

The S_INVITATION* from SERVER::Invite() can be used to expire the invitation with S_INVITATION::Revoke().

Once you have viewers connected, you can use the ATTENDEE class.

 class ATTENDEE 
 {
  ...
 public:
  void SetControl(int x);
  // Sets the control for an attendee (CTRL_LEVEL_NONE,CTRL_LEVEL_VIEW,
      CTRL_LEVEL_INTERACTIVE);
  wstring& GetNane();
  // Gets the attendee's friendly name
  int GetID();
  // Gets the attendee's ID, assigned by the API.
  HRESULT Kill();
  // Disconnects the attendee
  int GetProtocol();
  wstring GetLocalIP(); 
  wstring GetPeerIP(); 
  long GetLocalPort(); 
  long GetPeerPort(); 
  // Returns TCP/IP information for the attendee };

Client Implementation

The client application is a viewer that connects to the sharer. The steps are:

  • Get the ticket from an external interface.
  • Create the client, either by passing 0 to the constructor, in which case. it creates it with CoCreateInstance, or by passing an IUnknown* to it if you ever manage to create it with OleCreate.
  • If you plan to accept connections to the client, call CLIENT:: SetReverseConnectionParameters, taking the invitation ticket (generated by the server). You must give the new connection string to the server by an external method.
  • If you plan to connect directly, call Connect() using the ticket and password.
// Create the client
RAS::CLIENT* c = new RAS::CLIENT(a);
// Use your own ActiveX container here; I use AX
TCHAR Ticket[1000] = {0};
TCHAR Pwd[1000] = {0};
if (Reverse)
{
	wstring s = ReversalString;
	wstring y = c->SetReverseConnectionParameters(s.c_str(),
	            _T("hello"),_T(""));
	SendToServerSomeHow(y.c_str());
}
else
{
	wstring wTicket = GetTicketSomeHow();
	wstring Password = GetPasswordSomeHow();
	c->Connect(Ticket.c_str(),L"A Client",Pwd.c_str());
}

Virtual Channels

The CHANNEL class implements a virtual channel (a way to share binary data between clients). You must call BASERDP::CreateVirtualChannel with the same name from both the server and clients, so as to establish a communication channel between them. The channel is distinguished by its name.

BASERDP::CreateVirtualChannel must be called before any connection has occurred. It is not possible to create virtual channels after connections have been established.

In order to set which attendees will receive data from a channel, you must call SERVER::AssignChannelToAttendees.

After that, you can call BASERDP::SendData() with the selected channel, the binary data and its size.

The implementation ensures that the data is sent and received in a proper way, and also if the data is delayed, it keeps a queue to resend them, either to all or to specified attendees.

The data comes to BASERDP::OnReceiveData(), which calls your callback.

Sharable Applications and Region

You can limit the shared region of the desktop by calling SERVER :: SetDesktopRegion(const RECT& rc).

You can limit the number of applications shared by calling:

SERVER :: ShareOnlyTheseApplications(vector<int>& pids,bool X)

The vector is an array of the process id of the applications you want to be shared, and X is true.

If X is false, all applications are shared no matter what pids contain.

You can get the list of sharable applications, their names and their status by calling:

SERVER :: GetShareableApplications
	(vector<int>& pids,vector<wstring>& names,vector<int>& ST);

Interesting Stuff

  • The Viewer must be created with CoCreateInstance() and not OleCreate().
  • The COM state must be in a single threading mode (CoInitializeEx(0, COINIT_APARTMENTTHREADED) in both the server and the client implementations). This would cost me some hours of debugging.
  • Virtual channels must be created before any connection is established.

To Do

  • Implementation of more server and client events

History

  • 29-9-2008 - Implementation of data callbacks, more member functions.
  • 26-9-2008 - Implementation of Virtual Channels, some bug fixes and Implementation of Sharable Applications
  • 24-9-2008 - First post

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

Share

About the Author

Michael Chourdakis
Engineer
Greece Greece
I'm working in C++, PHP , Flash and DSP Programming, currently experimenting with Windows 7 technologies and professional audio applications.
 
I 've a PhD in Digital Signal Processing.
 
My home page: http://www.michaelchourdakis.com

Comments and Discussions

 
QuestionGetting graphics stream buffer from RDPViewer PinmemberVCSharp00712-Feb-13 2:28 
AnswerRe: Getting graphics stream buffer from RDPViewer PinmemberMichael Chourdakis12-Feb-13 3:19 
GeneralRe: Getting graphics stream buffer from RDPViewer PinmemberVCSharp00712-Feb-13 16:40 
GeneralRe: Getting graphics stream buffer from RDPViewer PinmemberMichael Chourdakis12-Feb-13 20:03 
QuestionI am trying to run Source code in VS2012 but its not allowing me to convert PinmemberMember 216961512-Feb-13 1:41 
AnswerRe: I am trying to run Source code in VS2012 but its not allowing me to convert PinmemberMichael Chourdakis12-Feb-13 3:18 
Questioni want to learn something about ras Pinmemberlirunjinnew25-Dec-12 1:52 
QuestionUsage on two computers PinmemberMartin vanPutten30-May-12 11:08 
AnswerRe: Usage on two computers Pinmemberhuntime30-May-12 15:51 
GeneralRe: Usage on two computers PinmemberMartin vanPutten31-May-12 2:39 
Questionrdp proxy Pinmemberhuntime21-May-12 16:09 
AnswerRe: rdp proxy Pinmemberhuntime30-May-12 15:52 
QuestionGreat article... PinmemberMember 470367327-Feb-12 13:16 
AnswerRe: Great article... PinmemberMichael Chourdakis6-Mar-12 10:58 
GeneralRe: Great article... PinmemberMember 47036737-Mar-12 10:57 
GeneralRe: Great article... PinmemberMichael Chourdakis7-Mar-12 11:02 
QuestionBug in code? PinmemberAndrew Brock8-Dec-09 18:14 
AnswerRe: Bug in code? Pinmembermichael_zurich16-Nov-10 11:22 
GeneralRe: Bug in code? PinmemberMichael Chourdakis17-Nov-10 10:38 
GeneralRe: Bug in code? PinmemberMichael Chourdakis25-Sep-11 10:08 
QuestionDoes this window desktop sharing API uses any IE security settings PinmemberMember 430193921-Oct-09 5:16 
AnswerRe: Does this window desktop sharing API uses any IE security settings PinmemberMichael Chourdakis21-Oct-09 6:28 
GeneralWindows XP Pinmembertopena15-Apr-09 7:33 
GeneralRe: Windows XP PinmemberMichael Chourdakis15-Apr-09 8:38 
Generalrdp plugin dll in activex control PinmemberAlexander Shilonosov9-Oct-08 22:00 

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

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

| Advertise | Privacy | Mobile
Web01 | 2.8.140827.1 | Last Updated 2 Oct 2008
Article Copyright 2008 by Michael Chourdakis
Everything else Copyright © CodeProject, 1999-2014
Terms of Service
Layout: fixed | fluid