<?xml version="1.0" encoding="UTF-8" ?>
<?xml-stylesheet type="text/xsl" href="http://blogs.msdn.com/utility/FeedStylesheets/rss.xsl" media="screen"?><rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/" xmlns:wfw="http://wellformedweb.org/CommentAPI/"><channel><title>Terminal Services Team Blog : API</title><link>http://blogs.msdn.com/ts/archive/tags/API/default.aspx</link><description>Tags: API</description><dc:language>en-US</dc:language><generator>CommunityServer 2.1 SP1 (Build: 61025.2)</generator><item><title>TS Session Broker Extensibility (Part 2)</title><link>http://blogs.msdn.com/ts/archive/2008/09/25/ts-session-broker-extensibility-part-2.aspx</link><pubDate>Thu, 25 Sep 2008 18:41:52 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:8965389</guid><dc:creator>termserv</dc:creator><slash:comments>7</slash:comments><comments>http://blogs.msdn.com/ts/comments/8965389.aspx</comments><wfw:commentRss>http://blogs.msdn.com/ts/commentrss.aspx?PostID=8965389</wfw:commentRss><description>&lt;p&gt;&lt;/p&gt;  &lt;p&gt;&lt;font size="2"&gt;In a previous blog post, Christa gave a high level explanation of the extensibility points we introduced to Session Broker (SB) in Windows Server 2008. In this post, we will dive a bit deeper to see how we can use SB Extensibility to build our own load balancing logic.&lt;/font&gt;&lt;/p&gt;  &lt;p&gt;&lt;font size="2"&gt;As Christa mentioned, when a new incoming connection is received by a terminal server, the terminal server contacts the SB for directions on where to redirect this new user. To answer this question, the SB must go through its load balancing logic. Our implementation of this logic consists of:&lt;/font&gt;&lt;/p&gt;  &lt;ol&gt;   &lt;li&gt;&lt;font size="2"&gt;The SB looking through its database and picking the terminal server with the least number of sessions. (This is a slight simplification as the SB takes some other factors into account, but for now it is safe to ignore them for this discussion.) &lt;/font&gt;&lt;/li&gt;    &lt;li&gt;&lt;font size="2"&gt;The SB then returns that information to the terminal server to which the user initially connected. &lt;/font&gt;&lt;/li&gt;    &lt;li&gt;&lt;font size="2"&gt;The terminal server uses the returned data to execute the actual redirection. &lt;/font&gt;&lt;/li&gt; &lt;/ol&gt;  &lt;p&gt;&lt;font size="2"&gt;Since the debut of Windows Server 2008, we’ve received some feedback regarding SB load balancing logic, labeling it too simplistic. While this may or may not be the case, with the extensibility points we’ve provided, you can fully replace the SB load logic with your own to load balance based on what might be important to you in your organization.&lt;/font&gt;&lt;/p&gt;  &lt;p&gt;&lt;font size="2"&gt;To implement your own load balancing logic and make use of these extensibility points, you will have to construct a COM server which implements the &lt;/font&gt;&lt;a href="http://msdn.microsoft.com/en-us/library/cc644955(VS.85).aspx"&gt;&lt;font size="2"&gt;IWTSSBPlugin&lt;/font&gt;&lt;/a&gt;&lt;font size="2"&gt; interface. This COM server (which I’ll refer to as an “extensibility plug-in”) will be called by the SB for passive notifications as well as requests to make load balancing decisions.&lt;/font&gt;&lt;/p&gt;  &lt;p&gt;&lt;font size="2"&gt;The &lt;/font&gt;&lt;a href="http://msdn.microsoft.com/en-us/library/cc644955(VS.85).aspx"&gt;&lt;font size="2"&gt;IWTSSBPlugin&lt;/font&gt;&lt;/a&gt;&lt;font size="2"&gt; interface has five methods which SB calls at different points. We will temporarily ignore &lt;/font&gt;&lt;a href="http://msdn.microsoft.com/en-us/library/cc644958(VS.85).aspx"&gt;&lt;font size="2"&gt;WTSSBX_GetUserExternalSession&lt;/font&gt;&lt;/a&gt;&lt;font size="2"&gt; and revisit it in a later blog post.&lt;/font&gt;&lt;/p&gt;  &lt;p&gt;&lt;font size="2"&gt;Let’s quickly review the four methods and when SB calls them:&lt;/font&gt;&lt;/p&gt;  &lt;p&gt;&lt;font size="2"&gt;· &lt;/font&gt;&lt;a href="http://msdn.microsoft.com/en-us/library/cc644956(VS.85).aspx"&gt;&lt;font size="2"&gt;Initialize&lt;/font&gt;&lt;/a&gt;&lt;font size="2"&gt; – called by SB when the SB service starts to allow the plug-in to do its initialization.&lt;/font&gt;&lt;/p&gt;  &lt;p&gt;&lt;font size="2"&gt;· &lt;/font&gt;&lt;a href="http://msdn.microsoft.com/en-us/library/cc644961(VS.85).aspx"&gt;&lt;font size="2"&gt;Terminated&lt;/font&gt;&lt;/a&gt;&lt;font size="2"&gt; – called by SB when the SB service shuts down to allow the plug-in to do its termination cleanup.&lt;/font&gt;&lt;/p&gt;  &lt;p&gt;&lt;font size="2"&gt;· &lt;/font&gt;&lt;a href="http://msdn.microsoft.com/en-us/library/cc644957(VS.85).aspx"&gt;&lt;font size="2"&gt;WTSSBX_GetMostSuitableServer&lt;/font&gt;&lt;/a&gt;&lt;font size="2"&gt; – called by SB when a load balancing decision needs to be made. We can use this method to override the SB’s default load balancing logic.&lt;/font&gt;&lt;/p&gt;  &lt;p&gt;&lt;font size="2"&gt;· &lt;/font&gt;&lt;a href="http://msdn.microsoft.com/en-us/library/cc644959(VS.85).aspx"&gt;&lt;font size="2"&gt;WTSSBX_MachineChangeNotification&lt;/font&gt;&lt;/a&gt;&lt;font size="2"&gt; – called by SB when a change occurs in one of the servers in the farm. We can use this method to get information on new terminal servers that have joined or left the farm.&lt;/font&gt;&lt;/p&gt;  &lt;p&gt;&lt;font size="2"&gt;· &lt;/font&gt;&lt;a href="http://msdn.microsoft.com/en-us/library/cc644960(VS.85).aspx"&gt;&lt;font size="2"&gt;WTSSBX_SessionChangeNotification&lt;/font&gt;&lt;/a&gt;&lt;font size="2"&gt; – called by SB when a change occurs in a session on a terminal server that is part of the farm. We can use this method to detect session state changes (such as when a user disconnects from his session).&lt;/font&gt;&lt;/p&gt;  &lt;p&gt;&lt;font size="2"&gt;The order in which these methods are called depends on what is happening in the farm. Let’s first look at the machine notifications:&lt;/font&gt;&lt;/p&gt;  &lt;p&gt;&lt;font size="2"&gt;When a server joins a farm the following notifications are called on the plug-in in the following order:&lt;/font&gt;&lt;/p&gt;  &lt;ol&gt;   &lt;li&gt;&lt;a href="http://msdn.microsoft.com/en-us/library/cc644959(VS.85).aspx"&gt;&lt;font size="2"&gt;WTSSBX_MachineChangeNotification&lt;/font&gt;&lt;/a&gt;&lt;font size="2"&gt; is called with &lt;/font&gt;&lt;a href="http://msdn.microsoft.com/en-us/library/cc644968(VS.85).aspx"&gt;&lt;font size="2"&gt;WTSSBX_NOTIFICATION_TYPE&lt;/font&gt;&lt;/a&gt;&lt;font size="2"&gt; set to WTSSBX_NOTIFICATION_ADDED. This notification also provides the unique Machine ID which SB will use to identify this terminal server in all subsequent calls to the plug-in. &lt;/font&gt;&lt;/li&gt;    &lt;li&gt;&lt;a href="http://msdn.microsoft.com/en-us/library/cc644960(VS.85).aspx"&gt;&lt;font size="2"&gt;WTSSBX_SessionChangeNotification&lt;/font&gt;&lt;/a&gt;&lt;font size="2"&gt; is called with &lt;/font&gt;&lt;a href="http://msdn.microsoft.com/en-us/library/cc644968(VS.85).aspx"&gt;&lt;font size="2"&gt;WTSSBX_NOTIFICATION_TYPE&lt;/font&gt;&lt;/a&gt;&lt;font size="2"&gt; set to WTSSBX_NOTIFICATION_RESYNC. This notification reports the state of the sessions already existing on the terminal server joining the SB. &lt;/font&gt;&lt;/li&gt;    &lt;li&gt;&lt;a href="http://msdn.microsoft.com/en-us/library/cc644959(VS.85).aspx"&gt;&lt;font size="2"&gt;WTSSBX_MachineChangeNotification&lt;/font&gt;&lt;/a&gt;&lt;font size="2"&gt; is called with &lt;/font&gt;&lt;a href="http://msdn.microsoft.com/en-us/library/cc644968(VS.85).aspx"&gt;&lt;font size="2"&gt;WTSSBX_NOTIFICATION_TYPE&lt;/font&gt;&lt;/a&gt;&lt;font size="2"&gt; set to WTSSBX_NOTIFICATION_CHANGED. This notifies the plug-in that the terminal server is now part of the farm and is ready for incoming connections. &lt;/font&gt;&lt;/li&gt; &lt;/ol&gt;  &lt;p&gt;&lt;font size="2"&gt;Similarly, when a server leaves the farm &lt;/font&gt;&lt;a href="http://msdn.microsoft.com/en-us/library/cc644959(VS.85).aspx"&gt;&lt;font size="2"&gt;WTSSBX_MachineChangeNotification&lt;/font&gt;&lt;/a&gt;&lt;font size="2"&gt; is called with &lt;/font&gt;&lt;a href="http://msdn.microsoft.com/en-us/library/cc644968(VS.85).aspx"&gt;&lt;font size="2"&gt;WTSSBX_NOTIFICATION_TYPE&lt;/font&gt;&lt;/a&gt;&lt;font size="2"&gt; set to WTSSBX_NOTIFICATION_REMOVED.&lt;/font&gt;&lt;/p&gt;  &lt;p&gt;&lt;font size="2"&gt;The session notifications are also quite simple:&lt;/font&gt;&lt;/p&gt;  &lt;ul&gt;   &lt;li&gt;&lt;font size="2"&gt;When a user connects to a terminal server in the farm, a &lt;/font&gt;&lt;a href="http://msdn.microsoft.com/en-us/library/cc644960(VS.85).aspx"&gt;&lt;font size="2"&gt;WTSSBX_SessionChangeNotification&lt;/font&gt;&lt;/a&gt;&lt;font size="2"&gt; is called with &lt;/font&gt;&lt;a href="http://msdn.microsoft.com/en-us/library/cc644968(VS.85).aspx"&gt;&lt;font size="2"&gt;WTSSBX_NOTIFICATION_TYPE&lt;/font&gt;&lt;/a&gt;&lt;font size="2"&gt; set to WTSSBX_NOTIFICATION_ADDED. &lt;/font&gt;&lt;/li&gt;    &lt;li&gt;&lt;font size="2"&gt;Similarly, when a user logs off a session WTSSBX_NOTIFICATION_REMOVED is used. &lt;/font&gt;&lt;/li&gt;    &lt;li&gt;&lt;font size="2"&gt;Session state changes are called through &lt;/font&gt;&lt;a href="http://msdn.microsoft.com/en-us/library/cc644960(VS.85).aspx"&gt;&lt;font size="2"&gt;WTSSBX_SessionChangeNotification&lt;/font&gt;&lt;/a&gt;&lt;font size="2"&gt; with &lt;/font&gt;&lt;a href="http://msdn.microsoft.com/en-us/library/cc644968(VS.85).aspx"&gt;&lt;font size="2"&gt;WTSSBX_NOTIFICATION_TYPE&lt;/font&gt;&lt;/a&gt;&lt;font size="2"&gt; set to WTSSBX_NOTIFICATION_CHANGED. &lt;/font&gt;&lt;/li&gt; &lt;/ul&gt;  &lt;p&gt;&lt;font size="2"&gt;These notifications provide the plug-in with enough information to make load balancing decisions.&lt;/font&gt;&lt;/p&gt;  &lt;p&gt;&lt;font size="2"&gt;The actual decisions are communicated to the SB via the &lt;/font&gt;&lt;a href="http://msdn.microsoft.com/en-us/library/cc644957(VS.85).aspx"&gt;&lt;font size="2"&gt;WTSSBX_GetMostSuitableServer&lt;/font&gt;&lt;/a&gt;&lt;font size="2"&gt; method. Let’s look back at the original explanation of how the SB load balancing logic is invoked to see where in that process &lt;/font&gt;&lt;a href="http://msdn.microsoft.com/en-us/library/cc644957(VS.85).aspx"&gt;&lt;font size="2"&gt;WTSSBX_GetMostSuitableServer&lt;/font&gt;&lt;/a&gt;&lt;font size="2"&gt; is called.&lt;/font&gt;&lt;/p&gt;  &lt;p&gt;&lt;font size="2"&gt;When a new connection comes to a terminal server, the server asks the SB to provide the Machine ID of the terminal server which has an existing session for the user. The SB queries its database and if no such session exists, the SB uses its standard load balancing logic to determine a Machine ID to which the user should be redirected. At this point, instead of returning this ID to the terminal server, the SB calls into the plug-in via the &lt;/font&gt;&lt;a href="http://msdn.microsoft.com/en-us/library/cc644957(VS.85).aspx"&gt;&lt;font size="2"&gt;WTSSBX_GetMostSuitableServer&lt;/font&gt;&lt;/a&gt;&lt;font size="2"&gt; method and passes the Machine ID it has just calculated as one of the parameters. The plug-in can then change this parameter to redirect to a different terminal server than the one originally intended. &lt;/font&gt;&lt;/p&gt;  &lt;p&gt;&lt;font size="2"&gt;So we see that by returning a different Machine ID in response to a &lt;/font&gt;&lt;a href="http://msdn.microsoft.com/en-us/library/cc644957(VS.85).aspx"&gt;&lt;font size="2"&gt;WTSSBX_GetMostSuitableServer&lt;/font&gt;&lt;/a&gt;&lt;font size="2"&gt; method call, we can override the default SB load balancing logic and provide our own.&lt;/font&gt;&lt;/p&gt;  &lt;p&gt;&lt;font size="2"&gt;In the next blog post, I will provide some design guidelines on how to construct your plug-in as well as an example of a plug-in that does resource-based load balancing.&lt;/font&gt;&lt;/p&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=8965389" width="1" height="1"&gt;</description><category domain="http://blogs.msdn.com/ts/archive/tags/API/default.aspx">API</category><category domain="http://blogs.msdn.com/ts/archive/tags/Session+Broker/default.aspx">Session Broker</category><category domain="http://blogs.msdn.com/ts/archive/tags/Author_3A00_+Roman+Porter/default.aspx">Author: Roman Porter</category></item><item><title>How To: Extend the TS Session Broker to Support VDI (Part 1)</title><link>http://blogs.msdn.com/ts/archive/2008/08/12/how-to-extend-the-ts-session-broker-to-support-vdi-part-1.aspx</link><pubDate>Wed, 13 Aug 2008 04:09:25 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:8855803</guid><dc:creator>termserv</dc:creator><slash:comments>11</slash:comments><comments>http://blogs.msdn.com/ts/comments/8855803.aspx</comments><wfw:commentRss>http://blogs.msdn.com/ts/commentrss.aspx?PostID=8855803</wfw:commentRss><description>&lt;p&gt;Terminal Services is both a collection of features and a platform for the TS team&amp;#8217;s independent software vendor (ISV) partners. As a platform, we want to make sure that our components can be easily extended to support our partners&amp;#8217; vision of what Terminal Services can do&amp;#8212;and we want to be sure that people know about those extensibility points.&lt;/p&gt;  &lt;p&gt;One of the new Terminal Services roles in Windows Server 2008 is the TS Session Broker, responsible for routing incoming connections to the right terminal server. When the TS Session Broker gets an incoming connection, it checks first to see if that user has an existing session on a terminal server in the farm. If they do, then the connection goes to that terminal server. If they don&amp;#8217;t, then the Session Broker will redirect to the terminal server with the lowest number of sessions. (The TS Session Broker supports redirection to Windows Server 2003 terminal server sessions, but the Win2K3 terminal servers can&amp;#8217;t participate in load balancing.) In &lt;a href="http://blogs.msdn.com/ts/archive/2008/03/14/instantaneous-session-broker-redirection-leveraging-credssp.aspx"&gt;another blog entry&lt;/a&gt;, we&amp;#8217;ve explained how CredSSP can even speed the redirection process to terminal servers.&lt;/p&gt;  &lt;p&gt;But what about destinations, such as virtual desktops, blade PCs, or even PCs? While the built-in functionality of the TS Session Broker in WS08 only supports routing connections to terminal server sessions, we&amp;#8217;ve created a set of APIs that ISVs can use to create connection brokers for other kinds of devices. Basically, these APIs allow you to lobotomize the TS Session Broker and replace its brain&amp;#8212;its brokering mechanism&amp;#8212;with a new plug-in. This plug-in can contain a new set of rules that support redirection to other types of destinations. It can also provide different means of deciding the best target for new connections, such as load balancing rules based on server resources or login time.&lt;/p&gt;  &lt;p&gt;ISVs can extend the capabilities of TS Session Broker through the IWTSSBPlugin interface. This interface includes several benefits:&lt;/p&gt;  &lt;p&gt;&amp;#183; It doesn&amp;#8217;t need an agent on the client or terminal server to support connection brokering, so there&amp;#8217;s never anything to update.&lt;/p&gt;  &lt;p&gt;&amp;#183; Plug-ins using this interface can easily interact with other Terminal Services role services, such as Terminal Services Gateway (TS Gateway) and rely on information from TS Session Broker about session and computer states (available through WMI).&lt;/p&gt;  &lt;p&gt;&amp;#183; The plug-ins can manage connections with client or server devices that support RDP 5.2 or later. &lt;/p&gt;  &lt;p&gt;The IWTSSBPlugin interface can:&lt;/p&gt;  &lt;p&gt;&amp;#183; Return the ID of the server to which TS Session Broker should direct the incoming connection.&lt;/p&gt;  &lt;p&gt;&amp;#183; Direct an incoming connection to an external computing resource.&lt;/p&gt;  &lt;p&gt;&amp;#183; Notify the plug-in that a change occurred in the server environment.&lt;/p&gt;  &lt;p&gt;&amp;#183; Notify the plug-in that a change, such as a logon, logoff, disconnect, or reconnect, occurred in a user session.&lt;/p&gt;  &lt;p&gt;You can learn more about the methods for the IWTSSBPlugin interface at &lt;a href="http://msdn.microsoft.com/en-us/library/cc644955(VS.85).aspx"&gt;http://msdn.microsoft.com/en-us/library/cc644955(VS.85).aspx&lt;/a&gt; and Roman Porter will include some code samples in a follow-up blog entry.&lt;/p&gt;  &lt;p&gt;Finally, here&amp;#8217;s a question to everyone reading this: When it comes to Terminal Services as a platform, what other extensibility points would you find useful?&lt;/p&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=8855803" width="1" height="1"&gt;</description><category domain="http://blogs.msdn.com/ts/archive/tags/API/default.aspx">API</category><category domain="http://blogs.msdn.com/ts/archive/tags/Session+Broker/default.aspx">Session Broker</category><category domain="http://blogs.msdn.com/ts/archive/tags/Author_3A00_+Christa+Anderson/default.aspx">Author: Christa Anderson</category></item><item><title>Dynamic Virtual Channels</title><link>http://blogs.msdn.com/ts/archive/2007/09/20/dynamic-virtual-channels.aspx</link><pubDate>Thu, 20 Sep 2007 17:02:00 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:5014781</guid><dc:creator>termserv</dc:creator><slash:comments>3</slash:comments><comments>http://blogs.msdn.com/ts/comments/5014781.aspx</comments><wfw:commentRss>http://blogs.msdn.com/ts/commentrss.aspx?PostID=5014781</wfw:commentRss><description>&lt;P mce_keep="true"&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;An important goal of the Terminal Services (TS) team is to provide a product that can easily be extended by third parties to better meet their needs.&amp;nbsp; While TS has always supported virtual channels, they had their limitations, including the limited number of channels and the difficulty involved in writing virtual channel applications.&amp;nbsp; For the 6.1 version of the client, and Windows Vista SP1 or Windows Server 2008 on the server side, Dynamic Virtual Channels (DVCs) can be used. DVCs address the limitations of the old virtual channels.&amp;nbsp; This article outlines the basics of DVCs and shows how to write a complete DVC application and client plug-in to add basic file transfer support to Terminal Services. 
&lt;H3&gt;DVC Basics&lt;/H3&gt;
&lt;H4&gt;What are Virtual Channels?&lt;/H4&gt;
&lt;P&gt;Virtual channels are bi-directional connection streams provided through the RDP protocol. Virtual channels allow third parties to establish a data pipe between the TS client and server to extend the functionality of the Remote Desktop Protocol (RDP). Examples of extra functionality provided through virtual channels are cross-TS-connection clipboard, drive, printer and smart card redirection. There are two types of virtual channels: static and dynamic. Due to the limitations of static virtual channels referenced above, dynamic virtual channels are the preferred way to extend TS functionality. 
&lt;H4&gt;Client and Server DVC components&lt;/H4&gt;
&lt;P&gt;On the TS client side the DVC is handled through a TS client plug-in. This plug-in is a COM object, whose registered CLSID is passed to the TS client through the registry (see the attached sample). The COM object must implement the &lt;A href="http://msdn2.microsoft.com/en-us/library/bb540865.aspx" mce_href="http://msdn2.microsoft.com/en-us/library/bb540865.aspx"&gt;IWTSPlugin&lt;/A&gt; interface. On the server side any arbitrary component running in the current session can use the WTS API to establish the DVC connection, as well as send and receive data. 
&lt;H4&gt;Channel Initialization and Usage&lt;/H4&gt;
&lt;H5&gt;Client Side&lt;/H5&gt;
&lt;P&gt;1) The TS client loads the DVC plug-ins from the registry: 
&lt;P&gt;&lt;FONT face="Courier New" size=2&gt;HKCU\Software\Microsoft\Terminal Server Client\Default\AddIns&lt;/FONT&gt; 
&lt;P&gt;2) The TS client invokes the Initialize() method on &lt;A href="http://msdn2.microsoft.com/en-us/library/bb540865.aspx" mce_href="http://msdn2.microsoft.com/en-us/library/bb540865.aspx"&gt;IWTSPlugin&lt;/A&gt;; and passes an &lt;A href="http://msdn2.microsoft.com/en-us/library/bb540874.aspx" mce_href="http://msdn2.microsoft.com/en-us/library/bb540874.aspx"&gt;IWTSVirtualChannelManager&lt;/A&gt; 
&lt;P&gt;&lt;FONT face="Courier New" size=2&gt;HRESULT CTsClientPlgn::Initialize(&lt;/FONT&gt; 
&lt;BLOCKQUOTE&gt;
&lt;P&gt;&lt;FONT face="Courier New" size=2&gt;IWTSVirtualChannelManager *pChannelMgr&lt;/FONT&gt;&lt;/P&gt;&lt;/BLOCKQUOTE&gt;
&lt;P&gt;&lt;FONT face="Courier New" size=2&gt;)&lt;/FONT&gt; 
&lt;P&gt;3) During initialization, or at any arbitrary point, the plug-in is expected to use the &lt;A href="http://msdn2.microsoft.com/en-us/library/bb540874.aspx" mce_href="http://msdn2.microsoft.com/en-us/library/bb540874.aspx"&gt;IWTSVirtualChannelManager&lt;/A&gt; to create a connection listener and pass an &lt;A href="http://msdn2.microsoft.com/en-us/library/bb540862.aspx" mce_href="http://msdn2.microsoft.com/en-us/library/bb540862.aspx"&gt;IWTSListenerCallback&lt;/A&gt; 
&lt;P&gt;&lt;FONT face="Courier New" size=2&gt;hr = pChannelMgr-&amp;gt;CreateListener(TSTELE_CHANNEL_NAME,&lt;/FONT&gt; 
&lt;BLOCKQUOTE&gt;
&lt;P&gt;&lt;FONT face="Courier New" size=2&gt;0,&lt;/FONT&gt;&lt;/P&gt;&lt;/BLOCKQUOTE&gt;
&lt;BLOCKQUOTE&gt;
&lt;P&gt;&lt;FONT face="Courier New" size=2&gt;pListenerCallback,&lt;/FONT&gt;&lt;/P&gt;&lt;/BLOCKQUOTE&gt;
&lt;BLOCKQUOTE&gt;
&lt;P&gt;&lt;FONT face="Courier New" size=2&gt;&amp;amp;pListener);&lt;/FONT&gt;&lt;/P&gt;&lt;/BLOCKQUOTE&gt;
&lt;P&gt;4) &lt;A href="http://msdn2.microsoft.com/en-us/library/bb540862.aspx" mce_href="http://msdn2.microsoft.com/en-us/library/bb540862.aspx"&gt;IWTSListenerCallback&lt;/A&gt; is notified of connection requests on the channel; &lt;A href="http://msdn2.microsoft.com/en-us/library/bb540862.aspx" mce_href="http://msdn2.microsoft.com/en-us/library/bb540862.aspx"&gt;IWTSListenerCallback&lt;/A&gt; receives an &lt;A href="http://msdn2.microsoft.com/en-us/library/bb540870.aspx" mce_href="http://msdn2.microsoft.com/en-us/library/bb540870.aspx"&gt;IWTSVirtualChannel&lt;/A&gt; for every new connection and returns a corresponding &lt;A href="http://msdn2.microsoft.com/en-us/library/bb540870.aspx" mce_href="http://msdn2.microsoft.com/en-us/library/bb540870.aspx"&gt;IWTSVirtualChannelCallback&lt;/A&gt; 
&lt;P&gt;&lt;FONT face="Courier New" size=2&gt;HRESULT CTsListenerCallback::OnNewChannelConnection(&lt;/FONT&gt; 
&lt;BLOCKQUOTE&gt;
&lt;P&gt;&lt;FONT face="Courier New" size=2&gt;IWTSVirtualChannel *pChannel,&lt;/FONT&gt;&lt;/P&gt;&lt;/BLOCKQUOTE&gt;
&lt;BLOCKQUOTE&gt;
&lt;P&gt;&lt;FONT face="Courier New" size=2&gt;BSTR data,&lt;/FONT&gt;&lt;/P&gt;&lt;/BLOCKQUOTE&gt;
&lt;BLOCKQUOTE&gt;
&lt;P&gt;&lt;FONT face="Courier New" size=2&gt;BOOL *pbAccept,&lt;/FONT&gt;&lt;/P&gt;&lt;/BLOCKQUOTE&gt;
&lt;BLOCKQUOTE&gt;
&lt;P&gt;&lt;FONT face="Courier New" size=2&gt;IWTSVirtualChannelCallback **ppCallback )&lt;/FONT&gt;&lt;/P&gt;&lt;/BLOCKQUOTE&gt;
&lt;P&gt;&lt;FONT face="Courier New" size=2&gt;{&lt;/FONT&gt; 
&lt;BLOCKQUOTE&gt;
&lt;P&gt;&lt;FONT face="Courier New" size=2&gt;*pbAccept = TRUE;&lt;/FONT&gt;&lt;/P&gt;&lt;/BLOCKQUOTE&gt;
&lt;BLOCKQUOTE&gt;
&lt;P&gt;&lt;FONT face="Courier New" size=2&gt;_pChannelCallback-&amp;gt;AddRef();&lt;/FONT&gt;&lt;/P&gt;&lt;/BLOCKQUOTE&gt;
&lt;BLOCKQUOTE&gt;
&lt;P&gt;&lt;FONT face="Courier New" size=2&gt;*ppCallback = _pChannelCallback;&lt;/FONT&gt;&lt;/P&gt;&lt;/BLOCKQUOTE&gt;
&lt;BLOCKQUOTE&gt;
&lt;P&gt;&lt;FONT face="Courier New" size=2&gt;pChannel-&amp;gt;AddRef();&lt;/FONT&gt;&lt;/P&gt;&lt;/BLOCKQUOTE&gt;
&lt;BLOCKQUOTE&gt;
&lt;P&gt;&lt;FONT face="Courier New" size=2&gt;_pChannel = pChannel;&lt;/FONT&gt;&lt;/P&gt;&lt;/BLOCKQUOTE&gt;
&lt;P&gt;5) The plug-in uses the &lt;A href="http://msdn2.microsoft.com/en-us/library/bb540870.aspx" mce_href="http://msdn2.microsoft.com/en-us/library/bb540870.aspx"&gt;IWTSVirtualChannel&lt;/A&gt; to write to and close the channel 
&lt;P&gt;&lt;FONT face=cour size=2&gt;hr = _pChannel-&amp;gt;Write(sizeof(HRESULT), (PBYTE) &amp;amp;hr, NULL);&lt;/FONT&gt; 
&lt;P&gt;&lt;FONT face=cour size=2&gt;hr = _pChannel-&amp;gt;Close();&lt;/FONT&gt; 
&lt;P&gt;6) The plug-in receives incoming data and channel close notifications on the &lt;A href="http://msdn2.microsoft.com/en-us/library/bb540870.aspx" mce_href="http://msdn2.microsoft.com/en-us/library/bb540870.aspx"&gt;IWTSVirtualChannelCallback&lt;/A&gt; 
&lt;P&gt;&lt;FONT face="Courier New" size=2&gt;HRESULT CTsChannelCallback::OnDataReceived(&lt;/FONT&gt; 
&lt;BLOCKQUOTE&gt;
&lt;P&gt;&lt;FONT face="Courier New" size=2&gt;ULONG cbSize,&lt;/FONT&gt;&lt;/P&gt;&lt;/BLOCKQUOTE&gt;
&lt;BLOCKQUOTE&gt;
&lt;P&gt;&lt;FONT face="Courier New" size=2&gt;BYTE *pBuffer&lt;/FONT&gt;&lt;/P&gt;&lt;/BLOCKQUOTE&gt;
&lt;P&gt;&lt;FONT face="Courier New" size=2&gt;);&lt;/FONT&gt; 
&lt;P&gt;&lt;FONT face="Courier New" size=2&gt;HRESULT CTsChannelCallback::OnClose();&lt;/FONT&gt; 
&lt;H5&gt;Server Side &lt;/H5&gt;
&lt;P&gt;1) An application issues a &lt;A href="http://msdn2.microsoft.com/en-us/library/bb540882.aspx" mce_href="http://msdn2.microsoft.com/en-us/library/bb540882.aspx"&gt;WTSVirtualChannelOpenEx&lt;/A&gt; with the WTS_CHANNEL_OPTION_DYNAMIC flag to establish the DVC connection. 
&lt;P&gt;&lt;FONT face="Courier New" size=2&gt;hWTSHandle = WTSVirtualChannelOpenEx(&lt;/FONT&gt; 
&lt;BLOCKQUOTE&gt;
&lt;P&gt;&lt;FONT face="Courier New" size=2&gt;WTS_CURRENT_SESSION,&lt;/FONT&gt;&lt;/P&gt;&lt;/BLOCKQUOTE&gt;
&lt;BLOCKQUOTE&gt;
&lt;P&gt;&lt;FONT face="Courier New" size=2&gt;TSTELE_CHANNEL_NAME,&lt;/FONT&gt;&lt;/P&gt;&lt;/BLOCKQUOTE&gt;
&lt;BLOCKQUOTE&gt;
&lt;P&gt;&lt;FONT face="Courier New" size=2&gt;WTS_CHANNEL_OPTION_DYNAMIC);&lt;/FONT&gt;&lt;/P&gt;&lt;/BLOCKQUOTE&gt;
&lt;P&gt;2) Using the WTS handle received from the previous call a &lt;A href="http://msdn2.microsoft.com/en-us/library/aa383852.aspx" mce_href="http://msdn2.microsoft.com/en-us/library/aa383852.aspx"&gt;WTSVirtualChannelQuery&lt;/A&gt; is used to get a read/write file handle for the channel 
&lt;P&gt;&lt;B&gt;NOTE:&lt;/B&gt; DuplicateHandle() is needed to be able to access the channel after freeing hWTSHandle (i.e. calling WTSVirtualChannelClose()). The output handle from DuplicateHandle() needs to be closed using CloseHandle(). 
&lt;P&gt;&lt;FONT face="Courier New" size=2&gt;BOOL bSucc = WTSVirtualChannelQuery(&lt;/FONT&gt; 
&lt;BLOCKQUOTE&gt;
&lt;P&gt;&lt;FONT face="Courier New" size=2&gt;hWTSHandle,&lt;/FONT&gt;&lt;/P&gt;&lt;/BLOCKQUOTE&gt;
&lt;BLOCKQUOTE&gt;
&lt;P&gt;&lt;FONT face="Courier New" size=2&gt;WTSVirtualFileHandle,&lt;/FONT&gt;&lt;/P&gt;&lt;/BLOCKQUOTE&gt;
&lt;BLOCKQUOTE&gt;
&lt;P&gt;&lt;FONT face="Courier New" size=2&gt;&amp;amp;vcFileHandlePtr,&lt;/FONT&gt;&lt;/P&gt;&lt;/BLOCKQUOTE&gt;
&lt;BLOCKQUOTE&gt;
&lt;P&gt;&lt;FONT face="Courier New" size=2&gt;&amp;amp;len);&lt;/FONT&gt;&lt;/P&gt;&lt;/BLOCKQUOTE&gt;
&lt;P&gt;&lt;FONT face="Courier New" size=2&gt;...&lt;/FONT&gt; 
&lt;BLOCKQUOTE&gt;
&lt;P&gt;&lt;FONT face="Courier New" size=2&gt;HANDLE hWTSFileHandle = *(HANDLE *)vcFileHandlePtr;&lt;/FONT&gt;&lt;/P&gt;&lt;/BLOCKQUOTE&gt;
&lt;P&gt;&lt;FONT face="Courier New" size=2&gt;...&lt;/FONT&gt; 
&lt;BLOCKQUOTE&gt;
&lt;P&gt;&lt;FONT face="Courier New" size=2&gt;bSucc = DuplicateHandle(&lt;/FONT&gt;&lt;/P&gt;&lt;/BLOCKQUOTE&gt;
&lt;BLOCKQUOTE&gt;
&lt;P&gt;&lt;FONT face="Courier New" size=2&gt;GetCurrentProcess(),&lt;/FONT&gt;&lt;/P&gt;&lt;/BLOCKQUOTE&gt;
&lt;BLOCKQUOTE&gt;
&lt;P&gt;&lt;FONT face="Courier New" size=2&gt;hWTSFileHandle,&lt;/FONT&gt;&lt;/P&gt;&lt;/BLOCKQUOTE&gt;
&lt;BLOCKQUOTE&gt;
&lt;P&gt;&lt;FONT face="Courier New" size=2&gt;GetCurrentProcess(),&lt;/FONT&gt;&lt;/P&gt;&lt;/BLOCKQUOTE&gt;
&lt;BLOCKQUOTE&gt;
&lt;P&gt;&lt;FONT face="Courier New" size=2&gt;&amp;amp;_hDVC,&lt;/FONT&gt;&lt;/P&gt;&lt;/BLOCKQUOTE&gt;
&lt;BLOCKQUOTE&gt;
&lt;P&gt;&lt;FONT face="Courier New" size=2&gt;0,&lt;/FONT&gt;&lt;/P&gt;&lt;/BLOCKQUOTE&gt;
&lt;BLOCKQUOTE&gt;
&lt;P&gt;&lt;FONT face="Courier New" size=2&gt;FALSE,&lt;/FONT&gt;&lt;/P&gt;&lt;/BLOCKQUOTE&gt;
&lt;BLOCKQUOTE&gt;
&lt;P&gt;&lt;FONT face="Courier New" size=2&gt;DUPLICATE_SAME_ACCESS);&lt;/FONT&gt;&lt;/P&gt;&lt;/BLOCKQUOTE&gt;
&lt;P&gt;3) Overlapped ReadFile() and WriteFile() calls are issued on the channel file handle 
&lt;P&gt;&lt;FONT face="Courier New" size=2&gt;bRet = ReadFile(_hDVC, ReadBuf, CHANNEL_PDU_LENGTH, &amp;amp;BytesRead, &amp;amp;ovr);&lt;/FONT&gt; 
&lt;P&gt;&lt;FONT face="Courier New" size=2&gt;bRet = WriteFile(_hDVC, pPacket, RequiredLen, &amp;amp;BytesWrit, &amp;amp;ovr);&lt;/FONT&gt; 
&lt;P&gt;4) To close the connection the channel file handle is closed 
&lt;P&gt;&lt;FONT face="Courier New" size=2&gt;CloseHandle(_hDVC);&lt;/FONT&gt; 
&lt;H3&gt;Sample: TS-Teleport&lt;/H3&gt;
&lt;P&gt;TS-Teleport is a sample application to demonstrate the end to end use of the DVC APIs. It implements a simple protocol to transport files from the TS server session to the desktop of the client machine. It does not rely on similar TS functionality like drive redirection. 
&lt;P&gt;&lt;A href="http://blogs.msdn.com/blogfiles/ts/WindowsLiveWriter/DynamicVirtualChannels_D610/dvc_1.png" atomicselection="true" mce_href="http://blogs.msdn.com/blogfiles/ts/WindowsLiveWriter/DynamicVirtualChannels_D610/dvc_1.png"&gt;&lt;IMG style="WIDTH: 605px; HEIGHT: 178px" height=226 alt=dvc src="http://blogs.msdn.com/blogfiles/ts/WindowsLiveWriter/DynamicVirtualChannels_D610/dvc_thumb_1.png" width=686 mce_src="http://blogs.msdn.com/blogfiles/ts/WindowsLiveWriter/DynamicVirtualChannels_D610/dvc_thumb_1.png"&gt;&lt;/A&gt; 
&lt;P&gt;The server component is a shell extension that adds an “RDP Client Desktop” entry to the “Send To” context menu. Upon receiving the list of highlighted files which the user elected to “Send to the RDP Client Desktop”, the shell extension opens the DVC and streams the files through. Upon receiving the file names and data, the client component creates those files and directories on the desktop. 
&lt;P&gt;The server sends a series of state dependent requests to the client by writing on the DVC and for each request it reads the status through a DVC read. Requests are start and end pairs for files and directories and data packets for file data. 
&lt;H4&gt;Sample Files and Instructions&lt;/H4&gt;
&lt;P&gt;Please follow the link below to access sample files and instructions, including source code and installation how-to. 
&lt;P&gt;&lt;A title=http://blogs.msdn.com/ts/pages/ts-teleport-sample-instructions.aspx href="http://blogs.msdn.com/ts/pages/ts-teleport-sample-instructions.aspx" mce_href="http://blogs.msdn.com/ts/pages/ts-teleport-sample-instructions.aspx"&gt;http://blogs.msdn.com/ts/pages/ts-teleport-sample-instructions.aspx&lt;/A&gt; 
&lt;P&gt;&lt;I&gt;Author: Ahmed Tolba (SDE TS Devices Team)&lt;/I&gt; 
&lt;P&gt;&lt;I&gt;Credits: Eric Holk, Zardosht Kasheff, Josh Rosenberg and the rest of the TS Devices Team&lt;/I&gt;&lt;/P&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=5014781" width="1" height="1"&gt;</description><category domain="http://blogs.msdn.com/ts/archive/tags/API/default.aspx">API</category><category domain="http://blogs.msdn.com/ts/archive/tags/Author_3A00_+Ahmed+Tolba/default.aspx">Author: Ahmed Tolba</category><category domain="http://blogs.msdn.com/ts/archive/tags/Virtual+Channels/default.aspx">Virtual Channels</category></item><item><title>Writing a Desktop Sharing Application</title><link>http://blogs.msdn.com/ts/archive/2007/03/23/writing-a-desktop-sharing-application.aspx</link><pubDate>Fri, 23 Mar 2007 19:37:00 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:1938884</guid><dc:creator>termserv</dc:creator><slash:comments>71</slash:comments><comments>http://blogs.msdn.com/ts/comments/1938884.aspx</comments><wfw:commentRss>http://blogs.msdn.com/ts/commentrss.aspx?PostID=1938884</wfw:commentRss><description>&amp;nbsp; 
&lt;P&gt;Windows Desktop Sharing (WDS) API provides a rich set of API to share your complete desktop or just individual applications. Below is a step-by-step guide to write a sharing application. I have chosen C#/.Net to make things simpler and we will be using Visual Studio 2005 as the IDE.&lt;/P&gt;
&lt;P&gt;&lt;STRONG&gt;Windows Desktop Sharing API Introduction:&lt;/STRONG&gt;&lt;/P&gt;
&lt;P&gt;Windows Desktop Sharing API allows a Windows Desktop Session to be shared across multiple viewers. More information on the API can be found on MSDN at &lt;A href="http://msdn2.microsoft.com/en-us/library/aa373852.aspx" mce_href="http://msdn2.microsoft.com/en-us/library/aa373852.aspx"&gt;http://msdn2.microsoft.com/en-us/library/aa373852.aspx&lt;/A&gt;. You could also refer to the &lt;A href="http://blogs.msdn.com/ts/archive/2007/03/08/windows-desktop-sharing-api.aspx" mce_href="http://blogs.msdn.com/ts/archive/2007/03/08/windows-desktop-sharing-api.aspx"&gt;Windows Desktop Sharing API Introduction&lt;/A&gt; blog. Windows Meeting Space &amp;amp; Remote Assistance use WDS API for collaboration and assistance scenarios. Similarly, you can write applications to achieve your sharing, collaboration, assistance, administration and deployment scenarios.&amp;nbsp; &lt;/P&gt;
&lt;P&gt;&lt;STRONG&gt;Object Model of the API:&lt;/STRONG&gt; API currently is published as an in-proc COM DLL (RdpEncom.dll) and is available in Vista. There are 2 primary objects that can be created: &lt;/P&gt;
&lt;UL&gt;
&lt;LI&gt;1. IRDPSRAPISharingSession - COM object that enables sharing of desktop &lt;/LI&gt;
&lt;LI&gt;2. IRDPSRAPIViewer - ActiveX control that can be embedded into a host window for viewing the sharing session.&lt;/LI&gt;&lt;/UL&gt;
&lt;P&gt;Other objects can be created or queried from these 2 primary objects. There is also an event sink interface (IRDPSessionEvents) that the API would use to report events to the application. Applications should sink appropriate events as needed. &lt;/P&gt;
&lt;P&gt;&lt;STRONG&gt;Desktop Sharing Application:&lt;/STRONG&gt; Writing a desktop sharing application involves writing 2 different applications - one for sharing and the other for viewing.&amp;nbsp; These 2 applications can be written as one application working in different modes similar to Windows Meeting Space.&lt;/P&gt;
&lt;P&gt;&lt;STRONG&gt;Sharer Application:&lt;/STRONG&gt; You can choose to create either a console based application or windows based application. It is nice to have a GUI interface to control the viewers, start/stop sharing etc., so let's build a windows application. To create a sharer application you will need to first add a reference to RdpComApi 1.0 Type Library (rdpencom.dll in %windows%\system32 directory) to your project. &lt;/P&gt;
&lt;P&gt;&lt;STRONG&gt;Starting the sharing Session: &lt;/STRONG&gt;To start the sharer, first create an instance of RdpSession Class and then subscribe to the events published by the WDS API. For this you will need to declare an event handler of the corresponding delegate signature. Here is an example of declaring and defining an event handler: &lt;/P&gt;
&lt;P&gt;
&lt;TABLE class="" cellSpacing=0 cellPadding=0 width="100%"&gt;
&lt;TBODY&gt;
&lt;TR&gt;
&lt;TD class=""&gt;
&lt;P&gt;private void OnAttendeeConnected(object pObjAttendee)&lt;/P&gt;
&lt;P&gt;{&lt;/P&gt;
&lt;BLOCKQUOTE&gt;
&lt;P&gt;IRDPSRAPIAttendee pAttendee = pObjAttendee as IRDPSRAPIAttendee;&lt;/P&gt;&lt;/BLOCKQUOTE&gt;
&lt;BLOCKQUOTE&gt;
&lt;P&gt;pAttendee.ControlLevel = CTRL_LEVEL.CTRL_LEVEL_VIEW;&lt;/P&gt;&lt;/BLOCKQUOTE&gt;
&lt;BLOCKQUOTE&gt;
&lt;P&gt;LogTextBox.Text += ("Attendee Connected: " + pAttendee.RemoteName + Environment.NewLine);&lt;/P&gt;&lt;/BLOCKQUOTE&gt;
&lt;P&gt;}&lt;/P&gt;
&lt;P&gt;&lt;I&gt;&lt;/I&gt;&amp;nbsp;&lt;/P&gt;&lt;/TD&gt;&lt;/TR&gt;&lt;/TBODY&gt;&lt;/TABLE&gt;&lt;/P&gt;
&lt;P&gt;Above is the event handler for the delegate: &lt;/P&gt;
&lt;P&gt;&lt;B&gt;void&lt;/B&gt; &lt;B&gt;_IRDPSessionEvents_OnAttendeeConnectedEventHandler&lt;/B&gt;(&lt;B&gt;&lt;U&gt;object&lt;/U&gt;&lt;/B&gt; &lt;I&gt;pAttendee&lt;/I&gt;);&lt;/P&gt;
&lt;P mce_keep="true"&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;This event is fired by the API when an attendee connects to the sharing session and will pass in the attendee instance to the event handler. Use that attendee instance to query information and also to set control level of the attendee. Control levels define the level of information that an attendee gets. In this implementation of event handler, attendee is given view control which means that attendee can only see the sharing session but cannot interact with it. We also print out some message to a text box so that the user who is running the sharing app can see the status of attendees connecting and disconnecting. Similarly we add event handlers for attendee disconnected and control level change requests. &lt;/P&gt;
&lt;P&gt;After subscribing to the events that we are interested in, start the sharing session by calling Open() method on the RdpSession object.&amp;nbsp; &lt;/P&gt;
&lt;P&gt;
&lt;TABLE class="" cellSpacing=0 cellPadding=0 width="100%"&gt;
&lt;TBODY&gt;
&lt;TR&gt;
&lt;TD class=""&gt;
&lt;P&gt;// Create a new RdpSession instance&lt;/P&gt;
&lt;P&gt;m_pRdpSession = new RDPSession();&lt;/P&gt;
&lt;P mce_keep="true"&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;// Subscribe to events&lt;/P&gt;
&lt;P&gt;m_pRdpSession.OnAttendeeConnected += new _IRDPSessionEvents_OnAttendeeConnectedEventHandler(OnAttendeeConnected);&lt;/P&gt;
&lt;P&gt;m_pRdpSession.OnAttendeeDisconnected += new _IRDPSessionEvents_OnAttendeeDisconnectedEventHandler(OnAttendeeDisconnected);&lt;/P&gt;
&lt;P&gt;m_pRdpSession.OnControlLevelChangeRequest += new _IRDPSessionEvents_OnControlLevelChangeRequestEventHandler(OnControlLevelChangeRequest);&lt;/P&gt;
&lt;P mce_keep="true"&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;// Start the Sharing Session&lt;/P&gt;
&lt;P&gt;m_pRdpSession.Open();&lt;/P&gt;
&lt;P mce_keep="true"&gt;LogTextBox.Text += "Presentation Started. Your Desktop is being shared." + Environment.NewLine;&lt;/P&gt;
&lt;P&gt;&lt;I&gt;&lt;/I&gt;&amp;nbsp;&lt;/P&gt;&lt;/TD&gt;&lt;/TR&gt;&lt;/TBODY&gt;&lt;/TABLE&gt;&lt;/P&gt;
&lt;P&gt;&lt;STRONG&gt;Creating an Invitation: &lt;/STRONG&gt;Create an invitation that can be sent to attendees so that they can use the invitation to connect to the sharing session. The invitation can be sent to the attendees using any mechanism desired. For example, Remote assistance allows to save the invitation and send it by email or to send through IM. Windows Meeting space uses "People Near Me" feature to identify and then send the invitations. In this implementation, let's take a simple approach and save it to a file. Here is the corresponding code:&lt;/P&gt;
&lt;P&gt;// Create invitation. &lt;/P&gt;
&lt;P&gt;IRDPSRAPIInvitation pInvitation = m_pRdpSession.Invitations.CreateInvitation("WinPresenter","PresentationGroup","",5);&lt;/P&gt;
&lt;P&gt;string invitationString = pInvitation.ConnectionString;&lt;/P&gt;
&lt;P&gt;// Save Connection String to File&lt;/P&gt;
&lt;P&gt;WriteToFile(invitationString);&lt;/P&gt;
&lt;P&gt;&lt;STRONG&gt;&lt;/STRONG&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;&lt;STRONG&gt;Stopping the Sharing Session: &lt;/STRONG&gt;To stop the sharing session, call close method on the RdpSession class instance. Here is the code:&lt;/P&gt;
&lt;P&gt;
&lt;TABLE class="" cellSpacing=0 cellPadding=0 width="100%"&gt;
&lt;TBODY&gt;
&lt;TR&gt;
&lt;TD class=""&gt;
&lt;P&gt;m_pRdpSession.Close();&lt;/P&gt;
&lt;P&gt;LogTextBox.Text += "Presentation Stopped." + Environment.NewLine;&lt;/P&gt;
&lt;P&gt;Marshal.ReleaseComObject(m_pRdpSession);&lt;/P&gt;
&lt;P&gt;m_pRdpSession = null;&lt;/P&gt;
&lt;P&gt;&lt;I&gt;&lt;/I&gt;&amp;nbsp;&lt;/P&gt;&lt;/TD&gt;&lt;/TR&gt;&lt;/TBODY&gt;&lt;/TABLE&gt;You may notice that I am calling ReleaseComObject. Reason being that once Close() is called then that RdpSession class instance cannot be used anymore. We will need to create another instance of RdpSession class to restart sharing. &lt;/P&gt;
&lt;P&gt;&lt;STRONG&gt;Viewer Application:&lt;/STRONG&gt; You will need to create a windows application and then add RdpViewer Class as an ActiveX control. &lt;A href="http://msdn2.microsoft.com/en-us/library/aa984238(vs.71).aspx" mce_href="http://msdn2.microsoft.com/en-us/library/aa984238(vs.71).aspx"&gt;Adding ActiveX controls to Windows Forms&lt;/A&gt; is a good resource to learn about adding ActiveX controls in Visual Studio IDE. Visual Studio will create an instance of AxRdpViewer and you can resize the ActiveX control to fit to your needs on the Windows Form. You can also choose to create this ActiveX control dynamically and place it in the host Form.&lt;/P&gt;
&lt;P&gt;
&lt;TABLE class="" cellSpacing=0 cellPadding=0 width="100%"&gt;
&lt;TBODY&gt;
&lt;TR&gt;
&lt;TD class=""&gt;
&lt;P mce_keep="true"&gt;&amp;nbsp;&lt;/P&gt;&lt;/TD&gt;&lt;/TR&gt;&lt;/TBODY&gt;&lt;/TABLE&gt;&lt;STRONG&gt;Connecting to the Sharing Session: &lt;/STRONG&gt;First subscribe to the events that you are interested in. The easiest way in Visual Studio to add event handlers to an event is to click on the Events lightning bolt in the property browser of ActiveX control, then double-click on any events you wish to handle. An empty method signature and the appropriate event hooking and unhooking code are then emitted for you. &amp;nbsp;Subscribe to OnConnectionEstablished, OnConnectionTerminated, OnConnectionFailed and OnError events at a minimum so that you can report status and errors, if there are any. Here is some code for OnError event handler method:&lt;/P&gt;
&lt;P&gt;private void OnError(object sender, _IRDPSessionEvents_OnErrorEvent e)&lt;/P&gt;
&lt;P&gt;{&lt;/P&gt;
&lt;BLOCKQUOTE&gt;
&lt;P&gt;int ErrorCode = (int)e.errorInfo;&lt;/P&gt;&lt;/BLOCKQUOTE&gt;
&lt;BLOCKQUOTE&gt;
&lt;P&gt;LogTextBox.Text += ("Error 0x" + ErrorCode.ToString("X") + Environment.NewLine);&lt;/P&gt;&lt;/BLOCKQUOTE&gt;
&lt;P&gt;}&lt;I&gt;&lt;/I&gt;&lt;/P&gt;
&lt;P&gt;To connect to the Sharing Session, you will need an invitation. Since we saved the invitation created in the Sharing Application as a file, let's just read the file into a string. Then call Connect method with the invitation file. Please note that we are passing empty string as password. Since we created the invitation on the sharing application with empty string as the password this would work. This is not advised if you are writing a commercial application because anyone can connect to your Sharing Session if they can get hold of the invitation. &lt;/P&gt;
&lt;P&gt;Here is the code to connect to the Sharing Session:&lt;/P&gt;
&lt;P&gt;
&lt;TABLE class="" cellSpacing=0 cellPadding=0 width="100%"&gt;
&lt;TBODY&gt;
&lt;TR&gt;
&lt;TD class=""&gt;
&lt;P&gt;string ConnectionString = ReadFromFile();&lt;/P&gt;
&lt;P&gt;if (ConnectionString != null)&lt;/P&gt;
&lt;P&gt;{&lt;/P&gt;
&lt;BLOCKQUOTE&gt;
&lt;P&gt;pRdpViewer.Connect(ConnectionString, "Viewer1", "");&lt;/P&gt;&lt;/BLOCKQUOTE&gt;
&lt;P&gt;}&lt;/P&gt;&lt;/TD&gt;&lt;/TR&gt;&lt;/TBODY&gt;&lt;/TABLE&gt;&lt;/P&gt;
&lt;P&gt;Once the connection is succesfully established with sharing session, API will fire OnConnectionEstablished event or OnConnectionFailed event if the connection fails.&lt;/P&gt;
&lt;P&gt;
&lt;TABLE class="" cellSpacing=0 cellPadding=0 width="100%"&gt;
&lt;TBODY&gt;
&lt;TR&gt;
&lt;TD class=""&gt;
&lt;P mce_keep="true"&gt;&amp;nbsp;&lt;/P&gt;&lt;/TD&gt;&lt;/TR&gt;&lt;/TBODY&gt;&lt;/TABLE&gt;&lt;STRONG&gt;Disconnecting from the Sharing Session: &lt;/STRONG&gt;To disconnect from the sharing session, call Disconnect method on the AxRdpViewer class instance. Here is the code:&lt;/P&gt;
&lt;P&gt;pRdpViewer.Disconnect();&lt;/P&gt;
&lt;P mce_keep="true"&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;API will fire OnConnectionTerminated event once the viewer is disconnected from the sharing session.&lt;/P&gt;
&lt;P&gt;&lt;STRONG&gt;Wrapping up:&lt;/STRONG&gt;&lt;/P&gt;
&lt;P&gt;This is all you need to do to share your desktop. Obviously you will need to do much more if you want to have control on who is connected, display a nice GUI for attendee information, kick attendees etc. This will give you a good start and explore the API provided by WDS API to achieve your other scenarios.&lt;/P&gt;
&lt;P&gt;&lt;STRONG&gt;Sample Application:&lt;/STRONG&gt;&lt;/P&gt;
&lt;P&gt;WinPresenter is a sample Desktop Sharing Suite of applications encompassing both Sharing and Viewing application. You should be able to find source code including the snippets above. I left out error checking, printing messages to user etc., so please modify it to your needs. &lt;/P&gt;
&lt;P&gt;&lt;STRONG&gt;Usage of Sample Applications: &lt;/STRONG&gt;&lt;/P&gt;
&lt;P&gt;Sharer Application: Run winsharer.exe. Invitation file will be saved to the current directory with file name inv.xml&lt;/P&gt;
&lt;P&gt;Viewer application: Run winviewer.exe %path to invitation file%. Either specify the directory where you have run the winsharer or copy inv.xml to some other location and specify the path. If there is no path specified it will try to read inv.xml from the current directory.&lt;/P&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=1938884" width="1" height="1"&gt;</description><enclosure url="http://blogs.msdn.com/ts/attachment/1938884.ashx" length="22179" type="application/x-zip-compressed" /><category domain="http://blogs.msdn.com/ts/archive/tags/Collaboration/default.aspx">Collaboration</category><category domain="http://blogs.msdn.com/ts/archive/tags/Desktop+Sharing/default.aspx">Desktop Sharing</category><category domain="http://blogs.msdn.com/ts/archive/tags/API/default.aspx">API</category><category domain="http://blogs.msdn.com/ts/archive/tags/Author_3A00_+Seenu+Neerudu/default.aspx">Author: Seenu Neerudu</category></item><item><title>Windows Desktop Sharing API</title><link>http://blogs.msdn.com/ts/archive/2007/03/08/windows-desktop-sharing-api.aspx</link><pubDate>Thu, 08 Mar 2007 19:07:00 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:1838554</guid><dc:creator>termserv</dc:creator><slash:comments>14</slash:comments><comments>http://blogs.msdn.com/ts/comments/1838554.aspx</comments><wfw:commentRss>http://blogs.msdn.com/ts/commentrss.aspx?PostID=1838554</wfw:commentRss><description>&lt;P&gt;&lt;B&gt;Windows Desktop Sharing API Basics&lt;/B&gt;&lt;/P&gt;
&lt;P&gt;Microsoft &lt;A class="" href="http://www.microsoft.com/windowsserver2003/technologies/terminalservices/default.mspx" mce_href="http://www.microsoft.com/windowsserver2003/technologies/terminalservices/default.mspx"&gt;Terminal Services&lt;/A&gt; provides a public &lt;A href="http://msdn2.microsoft.com/en-us/library/aa373852.aspx"&gt;"Windows Desktop Sharing API"&lt;/A&gt; based on RDP to enable customers to write custom collaboration solutions in &lt;A href="http://www.microsoft.com/windows/products/windowsvista/default.mspx"&gt;Windows Vista&lt;/A&gt;. These API's are available on all the SKU's starting with Windows Vista Home Basics. You can write a customized collaboration application that can do either or all kinds of sharing including desktop, application and region. &amp;nbsp;Useful MSDN documentation of these API's is available at:&lt;/P&gt;
&lt;P mce_keep="true"&gt;&lt;A href="http://msdn2.microsoft.com/en-us/library/aa373852.aspx"&gt;http://msdn2.microsoft.com/en-us/library/aa373852.aspx&lt;/A&gt;&lt;/P&gt;
&lt;P mce_keep="true"&gt;&lt;B&gt;Highlights:&lt;/B&gt;&lt;/P&gt;
&lt;P&gt;Windows desktop sharing is a multi-party screen sharing technology in Windows Vista, wherein a local desktop can be transmitted over an RDP connection without creating an additional session. &lt;/P&gt;
&lt;UL&gt;
&lt;LI&gt;a) &lt;I&gt;Connectivity: &lt;/I&gt;Windows Desktop Sharing does support connectivity to intelligent appliances, wireless devices and PC's in uPnP framework and also teredo tunneling to provide connectivity to IPV6 machines behind IPV4 NAT's.&lt;/LI&gt;
&lt;LI&gt;b) &lt;I&gt;&lt;A href="http://msdn2.microsoft.com/en-us/library/aa373312.aspx"&gt;Reverse Connect&lt;/A&gt;&lt;/I&gt;: It is an interesting feature, where sharer can connect to the viewer if viewer cannot reach the sharer via direct connect. For example, the viewer may not be able to connect to the sharer because of network address translation (NAT). &lt;/LI&gt;
&lt;LI&gt;c) &lt;I&gt;&lt;A href="http://msdn2.microsoft.com/en-us/library/aa373295.aspx"&gt;Authentication&lt;/A&gt;&lt;/I&gt;: API supports creating &lt;A href="http://msdn2.microsoft.com/en-us/library/aa373294.aspx"&gt;tickets/ invitations&lt;/A&gt; on the sharer side that can be routed by the API consumer application or IM's to the viewers.&lt;/LI&gt;
&lt;LI&gt;&lt;I&gt;d) &lt;/I&gt;&lt;I&gt;Sharing Modes: &lt;/I&gt;API supports sharing &lt;A href="http://msdn2.microsoft.com/en-us/library/aa373267.aspx"&gt;desktop&lt;/A&gt;, &lt;A href="http://msdn2.microsoft.com/en-us/library/aa373267.aspx"&gt;application&lt;/A&gt; or a &lt;A href="http://msdn2.microsoft.com/en-us/library/aa373319.aspx"&gt;region&lt;/A&gt;.&lt;/LI&gt;
&lt;LI&gt;e) &lt;I&gt;&lt;A href="http://msdn2.microsoft.com/en-us/library/aa373357.aspx"&gt;Control Modes&lt;/A&gt;:&lt;/I&gt; Sharer always has full control of his desktop/ application/region. Each viewer can be tuned to no-view/view or interactive control. &lt;A href="http://msdn2.microsoft.com/en-us/library/aa373288.aspx"&gt;Sharer controls the control level&lt;/A&gt; for each viewer and viewers can request promotion in control level to sharer.&lt;/LI&gt;
&lt;LI&gt;f) &lt;I&gt;&lt;A href="http://msdn2.microsoft.com/en-us/library/aa373358.aspx"&gt;Smart sizing&lt;/A&gt;&lt;/I&gt;: Smart sizing is well-supported and is a client/ viewer option that can be turned on and off.&lt;/LI&gt;
&lt;LI&gt;g) &lt;I&gt;&lt;A href="http://msdn2.microsoft.com/en-us/library/aa373361.aspx"&gt;Virtual channels&lt;/A&gt;: &lt;/I&gt;Virtual channels can be used to exchange other data like documents, application data, chat messages etc.&lt;/LI&gt;&lt;/UL&gt;
&lt;P&gt;&lt;B&gt;Microsoft Collaboration Solutions&lt;/B&gt;&lt;B&gt;:&lt;/B&gt;&lt;/P&gt;
&lt;P&gt;&lt;A href="http://www.microsoft.com/windows/products/windowsvista/features/details/meetingspace.mspx"&gt;"Windows Meeting Space"&lt;/A&gt; and &lt;A href="http://www.microsoft.com/windowsvista/features/foreveryone/remoteassistance.mspx"&gt;"Remote Assistance"&lt;/A&gt; in Windows Vista are based on these public API's -&lt;/P&gt;
&lt;UL&gt;
&lt;LI&gt;a) &lt;A href="http://www.microsoft.com/windowsvista/features/foreveryone/remoteassistance.mspx"&gt;Remote Assistance&lt;/A&gt;: Remote assistance is 1:1 sharing mechanism wherein the helper (expert) can get to see and control novice's desktop. Application and region sharing is not exposed via RA in Windows Vista.&lt;/LI&gt;
&lt;LI&gt;b) &lt;A href="http://www.microsoft.com/windows/products/windowsvista/features/details/meetingspace.mspx"&gt;Windows Meeting Space&lt;/A&gt;: Windows Meeting Space is a peer-to-peer application that enables multiple users to conduct virtual meeting. Participants can share their desktop, documents and applications, exchange notes, give presentations by connecting to a network projector. Network projector in this scenario is a intelligent device in uPnP framework that plays a role of viewer.&lt;/LI&gt;&lt;/UL&gt;
&lt;P&gt;&lt;B&gt;API support versus perceived limitations in Windows Meeting Space&lt;/B&gt;&lt;B&gt;:&lt;/B&gt;&lt;B&gt;&lt;/B&gt;&lt;/P&gt;
&lt;UL&gt;
&lt;LI&gt;a) &lt;I&gt;Multi-monitor remoting&lt;/I&gt; - In Windows Meeting Space the sharer does not allow sharing of both or the secondary monitor in multi-monitor arrangement. However, the API allows you to attach the appropriate region of the composite monitor and hence it can be flexible enough to share any particular monitor, if needed. It could get very interesting with more than 2 monitors.&lt;/LI&gt;
&lt;LI&gt;b) &lt;I&gt;Easy Switching among &lt;A href="http://msdn2.microsoft.com/en-us/library/aa373267.aspx"&gt;desktop/ application sharing&lt;/A&gt; &lt;/I&gt;- "Windows Meeting Space" doesn't allow flexible switching between desktop and application sharing. You need to select either one of them. To switch you need to restart the session (Meeting Space session). The API allows you to switch between various sharing methods without closing the session.&lt;/LI&gt;
&lt;LI&gt;c) &lt;I&gt;&lt;A href="http://msdn2.microsoft.com/en-us/library/aa373267.aspx"&gt;Application Sharing&lt;/A&gt; (minimize-&amp;gt;on-screen) &lt;/I&gt;- In "Windows Meeting Space" when the viewer has the control of the sharer's application and viewer minimizes the application then he/she doesn't have a way to work on that application further (until sharer clicks on the taskbar on the minimized application). The API does provide a way for the viewer to bring back the minimized application on desktop. Hence a better user experience can be provided on the viewer side.&lt;/LI&gt;&lt;/UL&gt;
&lt;P&gt;&lt;B&gt;Frequently Asked Questions:&lt;/B&gt;&lt;/P&gt;
&lt;OL&gt;
&lt;LI&gt;&lt;I&gt;What is the behavior with DWM?&lt;BR&gt;&lt;/I&gt;Windows desktop sharing API turns off "Desktop Windows Manager/ DWM" on the sharer's machine when the desktop/ application sharing is active. &lt;I&gt;&amp;nbsp;&lt;/I&gt;&lt;/LI&gt;
&lt;LI&gt;&lt;I&gt;What is the behavior when "Secure Desktop" pops up while sharing?&lt;BR&gt;&lt;/I&gt;"Pause screen- Black screen with two bars(indicating pause) at lower right" is remoted when secure desktop (UAC prompts) is up on sharer's machine, when sharing process is run as a non-system process. Also, the pause screen is shown if sharer opts to suspend graphics encoding for some reason via &lt;A href="http://msdn2.microsoft.com/en-us/library/aa373316.aspx"&gt;IRDPSRAPISharingSession::Pause&lt;/A&gt;. &lt;/LI&gt;
&lt;LI&gt;&lt;EM&gt;Why does the remoted screen refresh for all connected clients whenever a new viewer joins the session?&lt;BR&gt;&lt;/EM&gt;The protocol tries to make sure that the graphics updates sent to all the connected viewers are synchronized. To do so, it needs to refresh the graphics stream for each previously connected client.&lt;/LI&gt;
&lt;LI&gt;&lt;I&gt;Why does sharer's monitor flash while sharing? Is there anything that I can do to avoid multiple set of DWM on/off flashes, typically in 1:M scenarios?&lt;BR&gt;&lt;/I&gt;Currently, the protocol does not support remoting glass so it turns DWM off while sharing. Turning DWM off/ on causes a flash on the sharer's monitor [only in case if DWM was on]. You cannot entirely avoid on/off flash but you can avoid multiple on/off flashes. &amp;nbsp;Depending on your preference you can select dynamic/ static loading of mirror driver. In static mode, sharer will load mirror driver [&amp;amp; turn DWM off if it is on] only once when it puts a session in &lt;A href="http://msdn2.microsoft.com/en-us/library/aa373315.aspx"&gt;active state&lt;/A&gt; and unload mirror driver [&amp;amp; turns DWM on if it was on earlier] only once when it puts session in &lt;A href="http://msdn2.microsoft.com/en-us/library/aa373310.aspx"&gt;inactive state&lt;/A&gt;. So, in static mirror driver load mode you won't see multiple set of DWM on/off flashes. However, note that in static mirror driver load DWM/ glass will be turned off even if there are no clients connected. In dynamic mirror driver load mode DWM/ glass is turned off only when there is at least one connected client and is turned on whenever there are no connected clients. There is a property DrvConAttach that you can set via &lt;A href="http://msdn2.microsoft.com/en-us/library/aa373305.aspx"&gt;IRDPSRAPISessionProperties&lt;/A&gt; to control this behavior. &lt;/LI&gt;
&lt;LI&gt;&lt;I&gt;Can multiple viewers have simultaneous control of sharer's desktop/ application?&lt;BR&gt;&lt;/I&gt;Yes. &lt;A href="http://msdn2.microsoft.com/en-us/library/aa373288.aspx"&gt;Sharer can permit each viewer a none, view only OR interactive&lt;/A&gt; control. Of course, viewers input (mouse movements/ keyboard input) will only be directed to sharer's machine when viewer has interactive control and the active X control has focus.&lt;/LI&gt;
&lt;LI&gt;&lt;I&gt;Can you force sharer or viewer[in reverse connect scenario] to use particular port/ protocol for listening for connection and communication? &lt;BR&gt;&lt;/I&gt;Yes. You can use &lt;A href="http://msdn2.microsoft.com/en-us/library/aa373305.aspx"&gt;IRDPSRAPISessionProperties&lt;/A&gt; property - PortId and PortProtocol to use specific port and protocol.&lt;/LI&gt;
&lt;LI&gt;&lt;EM&gt;Why does requesting color depth change from the viewer via &lt;/EM&gt;&lt;A href="http://msdn2.microsoft.com/en-us/library/aa373356.aspx"&gt;&lt;EM&gt;IRDPSRAPIViewer::RequestColorDepthChange&lt;/EM&gt;&lt;/A&gt;&lt;EM&gt; fail?&lt;BR&gt;&lt;/EM&gt;Currently, protocol does not allow viewer to request/ control the color depth change. Only the sharer can control the color depth via put property &lt;A href="http://msdn2.microsoft.com/en-us/library/aa373311.aspx"&gt;IRDPSRAPISharingSession::put_ColorDepth.&lt;/A&gt; IRDPSRAPIViewer::RequestColorDepthChange returns E_NOTIMPL in the current release.&lt;/LI&gt;
&lt;LI&gt;&lt;EM&gt;Does the API support clipboard?&lt;BR&gt;&lt;/EM&gt;No. Windows Desktop Sharing API doesn't provide automatic text/ file clipboard solution yet. This might be a good proposal for new feature in future versions.&lt;/LI&gt;
&lt;LI&gt;&lt;I&gt;Does the API support Audio/ Multi&lt;/I&gt;-&lt;EM&gt;media&lt;/EM&gt;?&lt;BR&gt;No audio can be redirected to and fro from viewers/ sharer via "Windows Desktop Sharing API". This might be a good proposal for new feature in future versions.&lt;/LI&gt;&lt;/OL&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=1838554" width="1" height="1"&gt;</description><category domain="http://blogs.msdn.com/ts/archive/tags/Collaboration/default.aspx">Collaboration</category><category domain="http://blogs.msdn.com/ts/archive/tags/Desktop+Sharing/default.aspx">Desktop Sharing</category><category domain="http://blogs.msdn.com/ts/archive/tags/API/default.aspx">API</category><category domain="http://blogs.msdn.com/ts/archive/tags/Author_3A00_+Mayur+Jagtap/default.aspx">Author: Mayur Jagtap</category></item></channel></rss>