Extending Remote Desktop Protocol (RDP) is one of those areas where the documentation technically explains everything, but the real-world picture can still be difficult to piece together.
At its core, the concept is straightforward: an RDP plugin consists of two cooperating components:
- A client-side component running alongside the RDP client (mstsc.exe or Windows App)
- A server-side component running inside the remote session
When a user connects through RDP, the client component is loaded by the RDP client and advertises one or more virtual channels. Applications inside the remote session can open those channels and exchange data with the client over the same RDP connection.
RDP defines two types of virtual channels:
- Static virtual channels (SVC) — the original model with several limitations
- Dynamic virtual channels (DVC) — the modern model used by most current RDP features
Static channels are still supported on Windows. However, they are not supported in Windows 365 or Azure Virtual Desktop and have several architectural constraints that make them unsuitable for new development.
Modern extensions rely on dynamic virtual channels, which allow channels to be created and closed dynamically during an active session. This mechanism powers many core RDP capabilities, including graphics, clipboard synchronization, audio redirection, device forwarding, and diagnostics.
Dynamic virtual channels in practice
Dynamic virtual channels have existed since Windows Vista and have been available to third-party developers for nearly two decades. During that time, hundreds of third-party plugins have been built using DVCs — from media optimization stacks for communication platforms, to advanced device redirection, monitoring agents, and internal enterprise integrations.
Despite this widespread use, practical end-to-end examples have remained surprisingly rare. The only official reference sample, TS Teleport, was published in 2007. While it demonstrates the concept, it uses old development patterns, tooling, and deployment approaches that make it difficult to apply directly to modern projects.
A modern sample repository
To address this gap, we are releasing a sample repository demonstrating how to build RDP plugins using modern tools and development patterns.
https://github.com/microsoft/rdp-dvc-plugin-samples
What you get
- Working client plugins and in-session server implementations across multiple languages
- Examples of plugin activation models (LocalServer32, InprocServer32, directentrypoint)
- Lifecycle guidance (connect, disconnect, reconnect) and a shared baseline protocol for validation
The goal is to provide practical, end-to-end examples that developers and IT professionals can use as a starting point when building real-world RDP integrations.
Core concepts used in this article
RDP Client: Any RDP client that implements loading third-party plugins – It could be built-in Remote Desktop Client (mstsc.exe) on Windows 11 or Windows Server, Windows App or any other application that is using Remote Desktop ActiveX.
RDP Server: A Windows 11 or Windows Server endpoint you connect to via RDP (including Azure Virtual Desktop/Windows 365 scenarios), where the server-side app runs inside the remote session and opens the DVC via the WTS APIs.
What is a dynamic virtual channel?
A dynamic virtual channel (DVC) is a virtual channel created and managed dynamically during a live RDP session. Both sides agree on a channel name, which is the only address required.
The client side is implemented as a COM object (IWTSPlugin) loaded by the RDP client.
The server side is a normal Windows application running inside the RDP session that uses the Windows Terminal Services (WTS) API to open the channel and exchange data.
Under the hood, DVCs are multiplexed over the RDP transport.
Overview of a RDP plugin architecture
A diagram displaying simplified interaction between RDP plugin components
What is the Repository?
Simple samples
Start with the Simple samples. Each one implements the same ping/echo protocol: the server sends a message with a sequence number, timestamp, and 5 KB payload; the client plugin echoes it back; the server logs round-trip time. That is the baseline.
Seven languages — C++, .NET 8, .NET Framework 4.8, Go, Rust, Python, and Electron — all using LocalServer32 activation, all sharing the same channel name and wire format. Any client plugin can talk to any server binary. Each client side executable accepts /register and /unregister flags to manage its own registry entries under HKCU (HKEY_CURRENT_USER) — no elevation required.
The Simple samples deliberately leave out session reconnection, render hints, and alternative activation models.
Advanced samples
The Advanced samples are the ones to read once the Simple sample works. They implement: reconnects, different activation models, and rarely used render interfaces. They cover all three activation models in both C++ and .NET 8, sharing a single rdp-plugin-common library across the three client projects, so you can see exactly what differs between activation models without duplicating everything else.
Activation models
RDP Client loads DVC plugins at startup via a well-known registry key under HKCU|HKLM\SOFTWARE\Microsoft\Terminal Server Client\Default\AddIns\. The Name value under that key determines how the plugin is activated:
|
Model |
How RDP Client activates |
Stability |
|
LocalServer32 (out-of-process EXE) |
CoCreateInstance → COM Service Control Manager (SCM) launches the EXE |
Crash in the plugin does not take down mstsc |
|
InprocServer32 (in-process Dynamic-Link Library (DLL)) |
CoCreateInstance → COM loads the DLL into mstsc |
Crash or heap corruption affects the RDP client |
|
Direct exported entrypoint |
LoadLibraryEx + resolves VirtualChannelGetInstance |
Same in-proc risk; no COM registration needed |
If you are building a plugin, start with LocalServer32 unless you have a specific reason not to. It isolates the plugin process, makes debugging straightforward, and means a crash in your code does not take down the user's RDP client.
How registration works
Plugins are registered under:
HKCU\SOFTWARE\Microsoft\Terminal Server Client\Default\AddIns\SampleRdpPlugin
Example:
Name = "{D9B80669-C06A-4BD1-9CB1-3B7168C9E3A3}"
This CLSID maps to the COM registration:
HKCU\Software\Classes\CLSID\{D9B80669-C06A-4BD1-9CB1-3B7168C9E3A3}\LocalServer32
(Default) = "C:\path\to\rdp-plugin.exe"
Process Lifetime (LocalServer32)
Each RDP connection causes mstsc.exe to call CoCreateInstance.
Depending on how the server is implemented, this may:
- Reuse an existing process via CoRegisterClassObject
- Launch a new process instance
Getting started
Requirements
Client and server must run supported versions of Windows 11 or Windows Server 2019 or later. You can use either built-in mstsc.exe, or Windows 365/Azure Virtual Desktop
Install required tools
- Open a PowerShell window.
Install Git and Visual Studio Code:
winget install Git.Git
winget install vscode
Restart the PowerShell window if necessary.
- Clone the repository
mkdir C:\sources
cd C:\sources
git clone https://github.com/microsoft/rdp-dvc-plugin-samples.git
cd rdp-dvc-plugin-samples
- Build a sample
Navigate to a language under the simple folder.
Example:
cd simple\dotnet
Each language directory contains a build.ps1 script that can be used to required build tools:
.\build.ps1 -Install
This step only needs to be performed once.
Restart PowerShell if required.
Build the sample:
.\build.ps1
- Run the sample
On the client machine:
rdp-plugin.exe /register
This registers the plugin. Start the plugin or let the RDP client launch it automatically when a connection is established.
Connect to the RDP server, note the plugin output window logs
On the server machine:
Copy the server binary and run it inside the RDP session.
You should see ping/echo output in both consoles, confirming that the DVC channel is functioning.
If the plugin does not load, the most common causes are:
- Missing registry registration
- Running the plugin elevated while the RDP client is not
See TROUBLESHOOTING.md for the full checklist.
Conclusion
Dynamic virtual channels are one of the most powerful extensibility points in the Remote Desktop Protocol stack. Whether the goal is device redirection, custom signaling, telemetry, or entirely new client capabilities, DVCs provide a flexible and well-integrated mechanism to extend the RDP experience.
If you are new to DVC development, start with the official documentation to understand the protocol model and API surface:
https://learn.microsoft.com/en-us/windows/win32/termserv/dynamic-virtual-channels
Then explore the sample repository to see complete, working implementations across multiple languages and activation models:
https://github.com/microsoft/rdp-dvc-plugin-samples
Clone the repository, run the simple samples to validate your environment, and then use the advanced samples as a foundation for building production-ready RDP plugins.
Continue the conversation. Find best practices. Bookmark the Windows Tech Community, then follow us on LinkedIn or @MSWindowsITPro for updates. Looking for support? Visit Windows on Microsoft Q&A.