Skip to main content
The context is the central state object for an RDP client session. Every piece of connection state — settings, channels, GDI surface, input, update callbacks — lives on or is reachable from the context. FreeRDP provides two related types:
TypePurpose
rdpContextCore context embedded in every session
rdpClientContextExtended context for client-side use; embeds rdpContext

Lifecycle

1

Fill in entry points

Populate an RDP_CLIENT_ENTRY_POINTS struct with the sizes and callbacks for your client.
RDP_CLIENT_ENTRY_POINTS ep = { 0 };
ep.Version     = RDP_CLIENT_INTERFACE_VERSION;
ep.Size        = sizeof(RDP_CLIENT_ENTRY_POINTS_V1);
ep.ContextSize = sizeof(MyContext);   /* your extended context size */
ep.ClientNew   = my_client_new;
ep.ClientFree  = my_client_free;
ep.ClientStart = my_client_start;
ep.ClientStop  = my_client_stop;
2

Allocate the context

freerdp_client_context_new() allocates the context using the size specified in ep.ContextSize, calls global init, then calls ClientNew.
rdpContext* context = freerdp_client_context_new(&ep);
if (!context)
    return -1;
3

Use the context

Access context->settings, context->instance, etc. to configure and drive the session.
4

Free the context

freerdp_client_context_free() calls ClientFree, tears down channels, and releases all memory.
freerdp_client_context_free(context);
If you are not using the higher-level freerdp_client_context_new() wrapper, you can allocate a bare freerdp instance with freerdp_new(), set instance->ContextSize, and then call freerdp_context_new() / freerdp_context_free() directly. The client-common wrapper is recommended for new code.

rdpContext Fields

The rdpContext struct is defined in include/freerdp/freerdp.h. Its key members are:
instance
freerdp*
Back-pointer to the owning freerdp (rdp_freerdp) instance. Set by freerdp_context_new(). Use this to reach instance-level callbacks from context callbacks.
settings
rdpSettings*
Pointer to the RDP settings for this session. Owned by the internal rdpRdp object; do not free separately. Use the freerdp_settings_* accessor functions to read and write values.
channels
rdpChannels*
Virtual channel manager. Used internally to route channel data; clients typically interact with it through channel plug-in callbacks.
input
rdpInput*
Input interface. Send keyboard, mouse, and touch events to the remote server through this. Owned by rdpRdp.
update
rdpUpdate*
Update/display interface. Register BeginPaint, EndPaint, DesktopResize callbacks here in PostConnect.
gdi
rdpGdi*
GDI (graphics device interface) state. Allocated by gdi_init() during PostConnect; freed by gdi_free() during PostDisconnect.
cache
rdpCache*
Bitmap/glyph/pointer cache. Managed internally.
graphics
rdpGraphics*
Graphics registration (bitmap/pointer/glyph codecs). Managed internally.
pubSub
wPubSub*
Publish/subscribe bus. Use PubSub_SubscribeChannelConnected and PubSub_SubscribeChannelDisconnected here in PreConnect to react to dynamic channel events.
log
wLog*
WLog logger associated with this context.
LastError
UINT32
Last error code recorded on this context. Use freerdp_get_last_error() to read it.

rdpClientContext Fields

rdpClientContext (defined in include/freerdp/client.h) embeds rdpContext as its first member and adds client-specific fields:
context
rdpContext
Must be the first field. The embedded base context. Cast between rdpContext* and rdpClientContext* freely.
thread
HANDLE
Handle to the client thread created by freerdp_client_start().
lastX / lastY
INT32
Last known mouse cursor position (client coordinates).
mouse_grabbed
BOOL
Whether the local mouse is currently captured/grabbed by the RDP window.
contacts
FreeRDP_TouchContact[10]
Active touch contacts (up to FREERDP_MAX_TOUCH_CONTACTS = 10). Updated by freerdp_client_handle_touch().
pens
FreeRDP_PenDevice[10]
Active pen devices (up to FREERDP_MAX_PEN_DEVICES = 10). Updated by freerdp_client_handle_pen().

Context Extension Pattern

The idiomatic FreeRDP pattern for carrying application-specific data is to embed rdpClientContext as the first member of your own struct, then tell FreeRDP about the larger size via ep.ContextSize.
/* 1. Declare your extended context */
typedef struct
{
    rdpClientContext common;  /* MUST be first */

    /* Your custom fields below */
    MyWindow* window;
    MyAudioSink* audio;
    BOOL fullscreen;
} MyContext;

/* 2. Register the size */
RDP_CLIENT_ENTRY_POINTS ep = { 0 };
ep.ContextSize = sizeof(MyContext);
ep.ClientNew   = my_client_new;
ep.ClientFree  = my_client_free;
/* ... other fields ... */

/* 3. Cast in callbacks */
static BOOL my_client_new(freerdp* instance, rdpContext* context)
{
    MyContext* my = (MyContext*)context;  /* safe: MyContext starts with rdpContext */

    my->fullscreen = FALSE;
    my->window     = my_window_create();
    if (!my->window)
        return FALSE;

    instance->PreConnect  = my_pre_connect;
    instance->PostConnect = my_post_connect;
    instance->PostDisconnect = my_post_disconnect;
    return TRUE;
}

static void my_client_free(freerdp* instance, rdpContext* context)
{
    MyContext* my = (MyContext*)context;
    my_window_destroy(my->window);
}

ClientNew / ClientFree Callbacks

These callbacks are set on RDP_CLIENT_ENTRY_POINTS and called by FreeRDP during context allocation and deallocation:

Common Client Functions

/* Allocate a context from entry points */
rdpContext* freerdp_client_context_new(const RDP_CLIENT_ENTRY_POINTS* pEntryPoints);

/* Free a context */
void freerdp_client_context_free(rdpContext* context);

/* Start/stop the built-in client thread */
int freerdp_client_start(rdpContext* context);
int freerdp_client_stop(rdpContext* context);

/* Retrieve the freerdp instance from a context */
freerdp* freerdp_client_get_instance(rdpContext* context);

/* Retrieve the client thread handle */
HANDLE freerdp_client_get_thread(rdpContext* context);

Full Example

#include <freerdp/freerdp.h>
#include <freerdp/client.h>

typedef struct {
    rdpClientContext common;  /* MUST be first */
    int custom_value;
} MyContext;

static BOOL my_client_new(freerdp* instance, rdpContext* context)
{
    MyContext* my = (MyContext*)context;
    my->custom_value = 42;
    instance->PreConnect     = my_pre_connect;
    instance->PostConnect    = my_post_connect;
    instance->PostDisconnect = my_post_disconnect;
    return TRUE;
}

static void my_client_free(freerdp* instance, rdpContext* context)
{
    /* nothing to free in this minimal example */
    (void)instance;
    (void)context;
}

static int my_client_start(rdpContext* context) { return 0; }
static int my_client_stop(rdpContext* context)  { return 0; }

int main(int argc, char* argv[])
{
    RDP_CLIENT_ENTRY_POINTS ep = { 0 };
    ep.Version     = RDP_CLIENT_INTERFACE_VERSION;
    ep.Size        = sizeof(RDP_CLIENT_ENTRY_POINTS_V1);
    ep.ContextSize = sizeof(MyContext);
    ep.ClientNew   = my_client_new;
    ep.ClientFree  = my_client_free;
    ep.ClientStart = my_client_start;
    ep.ClientStop  = my_client_stop;

    rdpContext* context = freerdp_client_context_new(&ep);
    if (!context)
        return 1;

    /* parse args, connect, run event loop ... */

    freerdp_client_context_free(context);
    return 0;
}