diff --git a/channels/audin/client/audin_main.c b/channels/audin/client/audin_main.c index 6306af8d6..5f0005e89 100644 --- a/channels/audin/client/audin_main.c +++ b/channels/audin/client/audin_main.c @@ -91,6 +91,7 @@ struct _AUDIN_PLUGIN IAudinDevice* device; rdpContext* rdpcontext; + BOOL attached; }; static BOOL audin_process_addin_args(AUDIN_PLUGIN* audin, ADDIN_ARGV* args); @@ -106,11 +107,8 @@ static UINT audin_process_version(IWTSVirtualChannelCallback* pChannelCallback, wStream* out; UINT32 Version; AUDIN_CHANNEL_CALLBACK* callback = (AUDIN_CHANNEL_CALLBACK*) pChannelCallback; - Stream_Read_UINT32(s, Version); - DEBUG_DVC("Version=%"PRIu32"", Version); - out = Stream_New(NULL, 5); if (!out) @@ -121,9 +119,9 @@ static UINT audin_process_version(IWTSVirtualChannelCallback* pChannelCallback, Stream_Write_UINT8(out, MSG_SNDIN_VERSION); Stream_Write_UINT32(out, Version); - error = callback->channel->Write(callback->channel, (UINT32) Stream_GetPosition(out), Stream_Buffer(out), NULL); + error = callback->channel->Write(callback->channel, (UINT32) Stream_GetPosition(out), + Stream_Buffer(out), NULL); Stream_Free(out, TRUE); - return error; } @@ -136,7 +134,6 @@ static UINT audin_send_incoming_data_pdu(IWTSVirtualChannelCallback* pChannelCal { BYTE out_data[1]; AUDIN_CHANNEL_CALLBACK* callback = (AUDIN_CHANNEL_CALLBACK*) pChannelCallback; - out_data[0] = MSG_SNDIN_DATA_INCOMING; return callback->channel->Write(callback->channel, 1, out_data, NULL); } @@ -157,17 +154,18 @@ static UINT audin_process_formats(IWTSVirtualChannelCallback* pChannelCallback, UINT32 NumFormats; audinFormat format; UINT32 cbSizeFormatsPacket; - Stream_Read_UINT32(s, NumFormats); DEBUG_DVC("NumFormats %"PRIu32"", NumFormats); + if ((NumFormats < 1) || (NumFormats > 1000)) { WLog_ERR(TAG, "bad NumFormats %"PRIu32"", NumFormats); return ERROR_INVALID_DATA; } - Stream_Seek_UINT32(s); /* cbSizeFormatsPacket */ + Stream_Seek_UINT32(s); /* cbSizeFormatsPacket */ callback->formats = (audinFormat*) calloc(1, NumFormats * sizeof(audinFormat)); + if (!callback->formats) { WLog_ERR(TAG, "calloc failed!"); @@ -198,24 +196,26 @@ static UINT audin_process_formats(IWTSVirtualChannelCallback* pChannelCallback, Stream_Read_UINT16(s, format.cbSize); format.data = Stream_Pointer(s); Stream_Seek(s, format.cbSize); - DEBUG_DVC("wFormatTag=%"PRIu16" nChannels=%"PRIu16" nSamplesPerSec=%"PRIu32" " - "nBlockAlign=%"PRIu16" wBitsPerSample=%"PRIu16" cbSize=%"PRIu16"", - format.wFormatTag, format.nChannels, format.nSamplesPerSec, - format.nBlockAlign, format.wBitsPerSample, format.cbSize); + "nBlockAlign=%"PRIu16" wBitsPerSample=%"PRIu16" cbSize=%"PRIu16"", + format.wFormatTag, format.nChannels, format.nSamplesPerSec, + format.nBlockAlign, format.wBitsPerSample, format.cbSize); if (audin->fixed_format > 0 && audin->fixed_format != format.wFormatTag) continue; + if (audin->fixed_channel > 0 && audin->fixed_channel != format.nChannels) continue; + if (audin->fixed_rate > 0 && audin->fixed_rate != format.nSamplesPerSec) continue; + if (audin->device && audin->device->FormatSupported(audin->device, &format)) { DEBUG_DVC("format ok"); - /* Store the agreed format in the corresponding index */ callback->formats[callback->formats_count++] = format; + /* Put the format to output buffer */ if (!Stream_EnsureRemainingCapacity(out, 18 + format.cbSize)) { @@ -224,7 +224,6 @@ static UINT audin_process_formats(IWTSVirtualChannelCallback* pChannelCallback, goto out; } - Stream_Write(out, fm, 18 + format.cbSize); } } @@ -237,20 +236,19 @@ static UINT audin_process_formats(IWTSVirtualChannelCallback* pChannelCallback, cbSizeFormatsPacket = (UINT32) Stream_GetPosition(out); Stream_SetPosition(out, 0); - Stream_Write_UINT8(out, MSG_SNDIN_FORMATS); /* Header (1 byte) */ Stream_Write_UINT32(out, callback->formats_count); /* NumFormats (4 bytes) */ Stream_Write_UINT32(out, cbSizeFormatsPacket); /* cbSizeFormatsPacket (4 bytes) */ - error = callback->channel->Write(callback->channel, cbSizeFormatsPacket, Stream_Buffer(out), NULL); out: + if (error != CHANNEL_RC_OK) { free(callback->formats); callback->formats = NULL; } - Stream_Free(out, TRUE); + Stream_Free(out, TRUE); return error; } @@ -259,12 +257,12 @@ out: * * @return 0 on success, otherwise a Win32 error code */ -static UINT audin_send_format_change_pdu(IWTSVirtualChannelCallback* pChannelCallback, UINT32 NewFormat) +static UINT audin_send_format_change_pdu(IWTSVirtualChannelCallback* pChannelCallback, + UINT32 NewFormat) { UINT error; wStream* out; AUDIN_CHANNEL_CALLBACK* callback = (AUDIN_CHANNEL_CALLBACK*) pChannelCallback; - out = Stream_New(NULL, 5); if (!out) @@ -277,7 +275,6 @@ static UINT audin_send_format_change_pdu(IWTSVirtualChannelCallback* pChannelCal Stream_Write_UINT32(out, NewFormat); error = callback->channel->Write(callback->channel, 5, Stream_Buffer(out), NULL); Stream_Free(out, TRUE); - return error; } @@ -291,7 +288,6 @@ static UINT audin_send_open_reply_pdu(IWTSVirtualChannelCallback* pChannelCallba UINT error; wStream* out; AUDIN_CHANNEL_CALLBACK* callback = (AUDIN_CHANNEL_CALLBACK*) pChannelCallback; - out = Stream_New(NULL, 5); if (!out) @@ -304,7 +300,6 @@ static UINT audin_send_open_reply_pdu(IWTSVirtualChannelCallback* pChannelCallba Stream_Write_UINT32(out, Result); error = callback->channel->Write(callback->channel, 5, Stream_Buffer(out), NULL); Stream_Free(out, TRUE); - return error; } @@ -335,9 +330,9 @@ static UINT audin_receive_wave_data(const BYTE* data, int size, void* user_data) Stream_Write_UINT8(out, MSG_SNDIN_DATA); Stream_Write(out, data, size); - error = callback->channel->Write(callback->channel, (UINT32) Stream_GetPosition(out), Stream_Buffer(out), NULL); + error = callback->channel->Write(callback->channel, (UINT32) Stream_GetPosition(out), + Stream_Buffer(out), NULL); Stream_Free(out, TRUE); - return error; } @@ -354,30 +349,32 @@ static UINT audin_process_open(IWTSVirtualChannelCallback* pChannelCallback, wSt UINT32 initialFormat; UINT32 FramesPerPacket; UINT error = CHANNEL_RC_OK; - Stream_Read_UINT32(s, FramesPerPacket); Stream_Read_UINT32(s, initialFormat); - DEBUG_DVC("FramesPerPacket=%"PRIu32" initialFormat=%"PRIu32"", - FramesPerPacket, initialFormat); + FramesPerPacket, initialFormat); if (initialFormat >= (UINT32) callback->formats_count) { WLog_ERR(TAG, "invalid format index %"PRIu32" (total %d)", - initialFormat, callback->formats_count); + initialFormat, callback->formats_count); return ERROR_INVALID_DATA; } format = &callback->formats[initialFormat]; + if (audin->device) { IFCALLRET(audin->device->SetFormat, error, audin->device, format, FramesPerPacket); + if (error != CHANNEL_RC_OK) { WLog_ERR(TAG, "SetFormat failed with errorcode %"PRIu32"", error); return error; } + IFCALLRET(audin->device->Open, error, audin->device, audin_receive_wave_data, callback); + if (error != CHANNEL_RC_OK) { WLog_ERR(TAG, "Open failed with errorcode %"PRIu32"", error); @@ -405,19 +402,17 @@ static UINT audin_process_open(IWTSVirtualChannelCallback* pChannelCallback, wSt static UINT audin_process_format_change(IWTSVirtualChannelCallback* pChannelCallback, wStream* s) { AUDIN_CHANNEL_CALLBACK* callback = (AUDIN_CHANNEL_CALLBACK*) pChannelCallback; - AUDIN_PLUGIN * audin = (AUDIN_PLUGIN*) callback->plugin; + AUDIN_PLUGIN* audin = (AUDIN_PLUGIN*) callback->plugin; UINT32 NewFormat; audinFormat* format; UINT error = CHANNEL_RC_OK; - Stream_Read_UINT32(s, NewFormat); - DEBUG_DVC("NewFormat=%"PRIu32"", NewFormat); if (NewFormat >= (UINT32) callback->formats_count) { WLog_ERR(TAG, "invalid format index %"PRIu32" (total %d)", - NewFormat, callback->formats_count); + NewFormat, callback->formats_count); return ERROR_INVALID_DATA; } @@ -426,18 +421,23 @@ static UINT audin_process_format_change(IWTSVirtualChannelCallback* pChannelCall if (audin->device) { IFCALLRET(audin->device->Close, error, audin->device); + if (error != CHANNEL_RC_OK) { WLog_ERR(TAG, "Close failed with errorcode %"PRIu32"", error); return error; } + IFCALLRET(audin->device->SetFormat, error, audin->device, format, 0); + if (error != CHANNEL_RC_OK) { WLog_ERR(TAG, "SetFormat failed with errorcode %"PRIu32"", error); return error; } + IFCALLRET(audin->device->Open, error, audin->device, audin_receive_wave_data, callback); + if (error != CHANNEL_RC_OK) { WLog_ERR(TAG, "Open failed with errorcode %"PRIu32"", error); @@ -456,13 +456,11 @@ static UINT audin_process_format_change(IWTSVirtualChannelCallback* pChannelCall * * @return 0 on success, otherwise a Win32 error code */ -static UINT audin_on_data_received(IWTSVirtualChannelCallback* pChannelCallback, wStream *data) +static UINT audin_on_data_received(IWTSVirtualChannelCallback* pChannelCallback, wStream* data) { UINT error; BYTE MessageId; - Stream_Read_UINT8(data, MessageId); - DEBUG_DVC("MessageId=0x%02"PRIx8"", MessageId); switch (MessageId) @@ -502,19 +500,18 @@ static UINT audin_on_close(IWTSVirtualChannelCallback* pChannelCallback) AUDIN_CHANNEL_CALLBACK* callback = (AUDIN_CHANNEL_CALLBACK*) pChannelCallback; AUDIN_PLUGIN* audin = (AUDIN_PLUGIN*) callback->plugin; UINT error = CHANNEL_RC_OK; - DEBUG_DVC("..."); if (audin->device) { IFCALLRET(audin->device->Close, error, audin->device); + if (error != CHANNEL_RC_OK) WLog_ERR(TAG, "Close failed with errorcode %"PRIu32"", error); } free(callback->formats); free(callback); - return error; } @@ -524,15 +521,14 @@ static UINT audin_on_close(IWTSVirtualChannelCallback* pChannelCallback) * @return 0 on success, otherwise a Win32 error code */ static UINT audin_on_new_channel_connection(IWTSListenerCallback* pListenerCallback, - IWTSVirtualChannel* pChannel, BYTE* Data, BOOL* pbAccept, - IWTSVirtualChannelCallback** ppCallback) + IWTSVirtualChannel* pChannel, BYTE* Data, BOOL* pbAccept, + IWTSVirtualChannelCallback** ppCallback) { AUDIN_CHANNEL_CALLBACK* callback; AUDIN_LISTENER_CALLBACK* listener_callback = (AUDIN_LISTENER_CALLBACK*) pListenerCallback; - DEBUG_DVC("..."); - callback = (AUDIN_CHANNEL_CALLBACK*) calloc(1, sizeof(AUDIN_CHANNEL_CALLBACK)); + if (!callback) { WLog_ERR(TAG, "calloc failed!"); @@ -544,9 +540,7 @@ static UINT audin_on_new_channel_connection(IWTSListenerCallback* pListenerCallb callback->plugin = listener_callback->plugin; callback->channel_mgr = listener_callback->channel_mgr; callback->channel = pChannel; - *ppCallback = (IWTSVirtualChannelCallback*) callback; - return CHANNEL_RC_OK; } @@ -558,10 +552,9 @@ static UINT audin_on_new_channel_connection(IWTSListenerCallback* pListenerCallb static UINT audin_plugin_initialize(IWTSPlugin* pPlugin, IWTSVirtualChannelManager* pChannelMgr) { AUDIN_PLUGIN* audin = (AUDIN_PLUGIN*) pPlugin; - DEBUG_DVC("..."); - audin->listener_callback = (AUDIN_LISTENER_CALLBACK*) calloc(1, sizeof(AUDIN_LISTENER_CALLBACK)); + if (!audin->listener_callback) { WLog_ERR(TAG, "calloc failed!"); @@ -571,9 +564,8 @@ static UINT audin_plugin_initialize(IWTSPlugin* pPlugin, IWTSVirtualChannelManag audin->listener_callback->iface.OnNewChannelConnection = audin_on_new_channel_connection; audin->listener_callback->plugin = pPlugin; audin->listener_callback->channel_mgr = pChannelMgr; - return pChannelMgr->CreateListener(pChannelMgr, "AUDIO_INPUT", 0, - (IWTSListenerCallback*) audin->listener_callback, NULL); + (IWTSListenerCallback*) audin->listener_callback, NULL); } /** @@ -585,32 +577,54 @@ static UINT audin_plugin_terminated(IWTSPlugin* pPlugin) { AUDIN_PLUGIN* audin = (AUDIN_PLUGIN*) pPlugin; UINT error = CHANNEL_RC_OK; - DEBUG_DVC("..."); if (audin->device) { IFCALLRET(audin->device->Free, error, audin->device); + if (error != CHANNEL_RC_OK) { WLog_ERR(TAG, "Free failed with errorcode %"PRIu32"", error); // dont stop on error } + audin->device = NULL; } free(audin->subsystem); audin->subsystem = NULL; - free(audin->device_name); audin->device_name = NULL; - free(audin->listener_callback); free(audin); - return CHANNEL_RC_OK; } +static UINT audin_plugin_attached(IWTSPlugin* pPlugin) +{ + AUDIN_PLUGIN* audin = (AUDIN_PLUGIN*) pPlugin; + UINT error = CHANNEL_RC_OK; + + if (!audin) + return CHANNEL_RC_BAD_CHANNEL_HANDLE; + + audin->attached = TRUE; + return error; +} + +static UINT audin_plugin_detached(IWTSPlugin* pPlugin) +{ + AUDIN_PLUGIN* audin = (AUDIN_PLUGIN*) pPlugin; + UINT error = CHANNEL_RC_OK; + + if (!audin) + return CHANNEL_RC_BAD_CHANNEL_HANDLE; + + audin->attached = FALSE; + return error; +} + /** * Function description * @@ -627,7 +641,6 @@ static UINT audin_register_device_plugin(IWTSPlugin* pPlugin, IAudinDevice* devi } DEBUG_DVC("device registered."); - audin->device = device; return CHANNEL_RC_OK; } @@ -647,11 +660,13 @@ static UINT audin_load_device_plugin(IWTSPlugin* pPlugin, const char* name, ADDI if (!audin_process_addin_args(audin, args)) return CHANNEL_RC_INITIALIZATION_ERROR; - entry = (PFREERDP_AUDIN_DEVICE_ENTRY) freerdp_load_channel_addin_entry("audin", (LPSTR) name, NULL, 0); + entry = (PFREERDP_AUDIN_DEVICE_ENTRY) freerdp_load_channel_addin_entry("audin", (LPSTR) name, NULL, + 0); if (entry == NULL) { - WLog_ERR(TAG, "freerdp_load_channel_addin_entry did not return any function pointers for %s ", name); + WLog_ERR(TAG, "freerdp_load_channel_addin_entry did not return any function pointers for %s ", + name); return ERROR_INVALID_FUNCTION; } @@ -679,11 +694,13 @@ static UINT audin_set_subsystem(AUDIN_PLUGIN* audin, char* subsystem) { free(audin->subsystem); audin->subsystem = _strdup(subsystem); + if (!audin->subsystem) { WLog_ERR(TAG, "_strdup failed!"); return ERROR_NOT_ENOUGH_MEMORY; } + return CHANNEL_RC_OK; } @@ -696,11 +713,13 @@ static UINT audin_set_device_name(AUDIN_PLUGIN* audin, char* device_name) { free(audin->device_name); audin->device_name = _strdup(device_name); + if (!audin->device_name) { WLog_ERR(TAG, "_strdup failed!"); return ERROR_NOT_ENOUGH_MEMORY; } + return CHANNEL_RC_OK; } @@ -725,9 +744,9 @@ BOOL audin_process_addin_args(AUDIN_PLUGIN* audin, ADDIN_ARGV* args) return TRUE; flags = COMMAND_LINE_SIGIL_NONE | COMMAND_LINE_SEPARATOR_COLON | COMMAND_LINE_IGN_UNKNOWN_KEYWORD; - status = CommandLineParseArgumentsA(args->argc, (const char**) args->argv, - audin_args, flags, audin, NULL, NULL); + audin_args, flags, audin, NULL, NULL); + if (status != 0) return FALSE; @@ -739,7 +758,6 @@ BOOL audin_process_addin_args(AUDIN_PLUGIN* audin, ADDIN_ARGV* args) continue; CommandLineSwitchStart(arg) - CommandLineSwitchCase(arg, "sys") { if ((error = audin_set_subsystem(audin, arg->Value))) @@ -770,9 +788,7 @@ BOOL audin_process_addin_args(AUDIN_PLUGIN* audin, ADDIN_ARGV* args) } CommandLineSwitchDefault(arg) { - } - CommandLineSwitchEnd(arg) } while ((arg = CommandLineFindNextArgumentA(arg)) != NULL); @@ -795,10 +811,9 @@ UINT DVCPluginEntry(IDRDYNVC_ENTRY_POINTS* pEntryPoints) { struct SubsystemEntry { - char *subsystem; - char *device; + char* subsystem; + char* device; }; - UINT error = CHANNEL_RC_INITIALIZATION_ERROR; ADDIN_ARGV* args; AUDIN_PLUGIN* audin; @@ -822,31 +837,34 @@ UINT DVCPluginEntry(IDRDYNVC_ENTRY_POINTS* pEntryPoints) #if defined(WITH_MACAUDIO) {"mac", "default"}, #endif - {NULL,NULL} + {NULL, NULL} }; - struct SubsystemEntry *entry = &entries[0]; - + struct SubsystemEntry* entry = &entries[0]; assert(pEntryPoints); assert(pEntryPoints->GetPlugin); - audin = (AUDIN_PLUGIN*) pEntryPoints->GetPlugin(pEntryPoints, "audin"); + if (audin != NULL) return CHANNEL_RC_ALREADY_INITIALIZED; audin = (AUDIN_PLUGIN*) calloc(1, sizeof(AUDIN_PLUGIN)); + if (!audin) { WLog_ERR(TAG, "calloc failed!"); return CHANNEL_RC_NO_MEMORY; } + audin->attached = TRUE; audin->iface.Initialize = audin_plugin_initialize; audin->iface.Connected = NULL; audin->iface.Disconnected = NULL; audin->iface.Terminated = audin_plugin_terminated; - + audin->iface.Attached = audin_plugin_attached; + audin->iface.Detached = audin_plugin_detached; args = pEntryPoints->GetPluginData(pEntryPoints); - audin->rdpcontext = ((freerdp*)((rdpSettings*) pEntryPoints->GetRdpSettings(pEntryPoints))->instance)->context; + audin->rdpcontext = ((freerdp*)((rdpSettings*) pEntryPoints->GetRdpSettings( + pEntryPoints))->instance)->context; if (args) { @@ -859,7 +877,7 @@ UINT DVCPluginEntry(IDRDYNVC_ENTRY_POINTS* pEntryPoints) if ((error = audin_load_device_plugin((IWTSPlugin*) audin, audin->subsystem, args))) { WLog_ERR(TAG, "audin_load_device_plugin %s failed with error %"PRIu32"!", - audin->subsystem, error); + audin->subsystem, error); goto out; } } @@ -870,17 +888,17 @@ UINT DVCPluginEntry(IDRDYNVC_ENTRY_POINTS* pEntryPoints) if ((error = audin_set_subsystem(audin, entry->subsystem))) { WLog_ERR(TAG, "audin_set_subsystem for %s failed with error %"PRIu32"!", - entry->subsystem, error); + entry->subsystem, error); } else if ((error = audin_set_device_name(audin, entry->device))) { WLog_ERR(TAG, "audin_set_device_name for %s failed with error %"PRIu32"!", - entry->subsystem, error); + entry->subsystem, error); } else if ((error = audin_load_device_plugin((IWTSPlugin*) audin, audin->subsystem, args))) { WLog_ERR(TAG, "audin_load_device_plugin %s failed with error %"PRIu32"!", - entry->subsystem, error); + entry->subsystem, error); } entry++; @@ -891,8 +909,8 @@ UINT DVCPluginEntry(IDRDYNVC_ENTRY_POINTS* pEntryPoints) WLog_ERR(TAG, "no sound device."); error = pEntryPoints->RegisterPlugin(pEntryPoints, "audin", (IWTSPlugin*) audin); - out: + if (error != CHANNEL_RC_OK) audin_plugin_terminated((IWTSPlugin*)audin); diff --git a/channels/drdynvc/client/drdynvc_main.c b/channels/drdynvc/client/drdynvc_main.c index 252ec24cb..18754baae 100644 --- a/channels/drdynvc/client/drdynvc_main.c +++ b/channels/drdynvc/client/drdynvc_main.c @@ -706,7 +706,8 @@ static UINT drdynvc_send(drdynvcPlugin* drdynvc, wStream* s) if (status != CHANNEL_RC_OK) { Stream_Free(s, TRUE); - WLog_ERR(TAG, "VirtualChannelWriteEx failed with %s [%08"PRIX32"]", WTSErrorToString(status), status); + WLog_ERR(TAG, "VirtualChannelWriteEx failed with %s [%08"PRIX32"]", WTSErrorToString(status), + status); } return status; @@ -1073,7 +1074,7 @@ static UINT drdynvc_order_recv(drdynvcPlugin* drdynvc, wStream* s) Cmd = (value & 0xf0) >> 4; Sp = (value & 0x0c) >> 2; cbChId = (value & 0x03) >> 0; - WLog_DBG(TAG, "order_recv: Cmd=0x%x, Sp=%d cbChId=%d", Cmd, Sp,cbChId); + WLog_DBG(TAG, "order_recv: Cmd=0x%x, Sp=%d cbChId=%d", Cmd, Sp, cbChId); switch (Cmd) { @@ -1379,6 +1380,64 @@ static UINT drdynvc_virtual_channel_event_terminated(drdynvcPlugin* drdynvc) return CHANNEL_RC_OK; } +static UINT drdynvc_virtual_channel_event_attached(drdynvcPlugin* drdynvc) +{ + int i; + DVCMAN* dvcman; + + if (!drdynvc) + return CHANNEL_RC_BAD_CHANNEL_HANDLE; + + dvcman = (DVCMAN*) drdynvc->channel_mgr; + + if (!dvcman) + return CHANNEL_RC_BAD_CHANNEL_HANDLE; + + for (i = 0; i < dvcman->num_plugins; i++) + { + UINT error; + IWTSPlugin* pPlugin = dvcman->plugins[i]; + + if (pPlugin->Attached) + if ((error = pPlugin->Attached(pPlugin))) + { + WLog_ERR(TAG, "Attach failed with error %"PRIu32"!", error); + return error; + } + } + + return CHANNEL_RC_OK; +} + +static UINT drdynvc_virtual_channel_event_detached(drdynvcPlugin* drdynvc) +{ + int i; + DVCMAN* dvcman; + + if (!drdynvc) + return CHANNEL_RC_BAD_CHANNEL_HANDLE; + + dvcman = (DVCMAN*) drdynvc->channel_mgr; + + if (!dvcman) + return CHANNEL_RC_BAD_CHANNEL_HANDLE; + + for (i = 0; i < dvcman->num_plugins; i++) + { + UINT error; + IWTSPlugin* pPlugin = dvcman->plugins[i]; + + if (pPlugin->Detached) + if ((error = pPlugin->Detached(pPlugin))) + { + WLog_ERR(TAG, "Detach failed with error %"PRIu32"!", error); + return error; + } + } + + return CHANNEL_RC_OK; +} + static VOID VCAPITYPE drdynvc_virtual_channel_init_event_ex(LPVOID lpUserParam, LPVOID pInitHandle, UINT event, LPVOID pData, UINT dataLength) { @@ -1410,6 +1469,21 @@ static VOID VCAPITYPE drdynvc_virtual_channel_init_event_ex(LPVOID lpUserParam, WLog_ERR(TAG, "drdynvc_virtual_channel_event_terminated failed with error %"PRIu32"", error); break; + + case CHANNEL_EVENT_ATTACHED: + if ((error = drdynvc_virtual_channel_event_attached(drdynvc))) + WLog_ERR(TAG, "drdynvc_virtual_channel_event_attached failed with error %"PRIu32"", error); + + break; + + case CHANNEL_EVENT_DETACHED: + if ((error = drdynvc_virtual_channel_event_detached(drdynvc))) + WLog_ERR(TAG, "drdynvc_virtual_channel_event_detached failed with error %"PRIu32"", error); + + break; + + default: + break; } if (error && drdynvc->rdpcontext) diff --git a/channels/rail/client/rail_main.c b/channels/rail/client/rail_main.c index 38db6acd7..dae8242e8 100644 --- a/channels/rail/client/rail_main.c +++ b/channels/rail/client/rail_main.c @@ -742,6 +742,11 @@ static VOID VCAPITYPE rail_virtual_channel_init_event_ex(LPVOID lpUserParam, LPV case CHANNEL_EVENT_TERMINATED: rail_virtual_channel_event_terminated(rail); break; + + case CHANNEL_EVENT_ATTACHED: + case CHANNEL_EVENT_DETACHED: + default: + break; } if (error && rail->rdpcontext) diff --git a/channels/rdpdr/client/rdpdr_main.c b/channels/rdpdr/client/rdpdr_main.c index 18d20e713..d3c9448fd 100644 --- a/channels/rdpdr/client/rdpdr_main.c +++ b/channels/rdpdr/client/rdpdr_main.c @@ -1738,9 +1738,10 @@ static VOID VCAPITYPE rdpdr_virtual_channel_init_event_ex(LPVOID lpUserParam, LP rdpdr_virtual_channel_event_terminated(rdpdr); break; + case CHANNEL_EVENT_ATTACHED: + case CHANNEL_EVENT_DETACHED: default: WLog_ERR(TAG, "unknown event %"PRIu32"!", event); - error = ERROR_INVALID_DATA; break; } diff --git a/channels/rdpsnd/client/rdpsnd_main.c b/channels/rdpsnd/client/rdpsnd_main.c index 1fdaf6910..7a22d720b 100644 --- a/channels/rdpsnd/client/rdpsnd_main.c +++ b/channels/rdpsnd/client/rdpsnd_main.c @@ -74,6 +74,8 @@ struct rdpsnd_plugin AUDIO_FORMAT* ClientFormats; UINT16 NumberOfClientFormats; + BOOL attached; + BOOL expectingWave; BYTE waveData[4]; UINT16 waveDataSize; @@ -741,6 +743,9 @@ static UINT rdpsnd_recv_pdu(rdpsndPlugin* rdpsnd, wStream* s) Stream_Seek_UINT8(s); /* bPad */ Stream_Read_UINT16(s, BodySize); + if (!rdpsnd->attached) + goto out; + //WLog_ERR(TAG, "msgType %"PRIu8" BodySize %"PRIu16"", msgType, BodySize); switch (msgType) @@ -1445,6 +1450,17 @@ static VOID VCAPITYPE rdpsnd_virtual_channel_init_event_ex(LPVOID lpUserParam, L rdpsnd_virtual_channel_event_terminated(plugin); plugin = NULL; break; + + case CHANNEL_EVENT_ATTACHED: + plugin->attached = TRUE; + break; + + case CHANNEL_EVENT_DETACHED: + plugin->attached = FALSE; + break; + + default: + break; } if (error && plugin && plugin->rdpcontext) @@ -1474,6 +1490,7 @@ BOOL VCAPITYPE VirtualChannelEntryEx(PCHANNEL_ENTRY_POINTS pEntryPoints, PVOID p return FALSE; } + rdpsnd->attached = TRUE; #if !defined(_WIN32) && !defined(ANDROID) { sigset_t mask; @@ -1497,9 +1514,7 @@ BOOL VCAPITYPE VirtualChannelEntryEx(PCHANNEL_ENTRY_POINTS pEntryPoints, PVOID p rdpsnd->log = WLog_Get("com.freerdp.channels.rdpsnd.client"); CopyMemory(&(rdpsnd->channelEntryPoints), pEntryPoints, sizeof(CHANNEL_ENTRY_POINTS_FREERDP_EX)); - rdpsnd->InitHandle = pInitHandle; - rc = rdpsnd->channelEntryPoints.pVirtualChannelInitEx(rdpsnd, NULL, pInitHandle, &rdpsnd->channelDef, 1, VIRTUAL_CHANNEL_VERSION_WIN2000, rdpsnd_virtual_channel_init_event_ex); diff --git a/channels/remdesk/client/remdesk_main.c b/channels/remdesk/client/remdesk_main.c index c59f671a7..c7d95f7ca 100644 --- a/channels/remdesk/client/remdesk_main.c +++ b/channels/remdesk/client/remdesk_main.c @@ -1015,6 +1015,11 @@ static VOID VCAPITYPE remdesk_virtual_channel_init_event_ex(LPVOID lpUserParam, case CHANNEL_EVENT_TERMINATED: remdesk_virtual_channel_event_terminated(remdesk); break; + + case CHANNEL_EVENT_ATTACHED: + case CHANNEL_EVENT_DETACHED: + default: + break; } if (error && remdesk->rdpcontext) diff --git a/include/freerdp/client/drdynvc.h b/include/freerdp/client/drdynvc.h index 89d172340..1bccd6462 100644 --- a/include/freerdp/client/drdynvc.h +++ b/include/freerdp/client/drdynvc.h @@ -29,8 +29,14 @@ typedef struct _drdynvc_client_context DrdynvcClientContext; typedef int (*pcDrdynvcGetVersion)(DrdynvcClientContext* context); -typedef UINT (*pcDrdynvcOnChannelConnected)(DrdynvcClientContext* context, const char* name, void* pInterface); -typedef UINT (*pcDrdynvcOnChannelDisconnected)(DrdynvcClientContext* context, const char* name, void* pInterface); +typedef UINT(*pcDrdynvcOnChannelConnected)(DrdynvcClientContext* context, const char* name, + void* pInterface); +typedef UINT(*pcDrdynvcOnChannelDisconnected)(DrdynvcClientContext* context, const char* name, + void* pInterface); +typedef UINT(*pcDrdynvcOnChannelAttached)(DrdynvcClientContext* context, const char* name, + void* pInterface); +typedef UINT(*pcDrdynvcOnChannelDetached)(DrdynvcClientContext* context, const char* name, + void* pInterface); struct _drdynvc_client_context { @@ -40,6 +46,8 @@ struct _drdynvc_client_context pcDrdynvcGetVersion GetVersion; pcDrdynvcOnChannelConnected OnChannelConnected; pcDrdynvcOnChannelDisconnected OnChannelDisconnected; + pcDrdynvcOnChannelAttached OnChannelAttached; + pcDrdynvcOnChannelDetached OnChannelDetached; }; #endif /* FREERDP_CHANNEL_CLIENT_DRDYNVC_H */ diff --git a/include/freerdp/dvc.h b/include/freerdp/dvc.h index 0cea12d9a..44bff5143 100644 --- a/include/freerdp/dvc.h +++ b/include/freerdp/dvc.h @@ -67,97 +67,101 @@ typedef struct _IWTSVirtualChannelCallback IWTSVirtualChannelCallback; struct _IWTSListener { /* Retrieves the listener-specific configuration. */ - UINT (*GetConfiguration)(IWTSListener *pListener, - void **ppPropertyBag); + UINT(*GetConfiguration)(IWTSListener* pListener, + void** ppPropertyBag); - void *pInterface; + void* pInterface; }; struct _IWTSVirtualChannel { /* Starts a write request on the channel. */ - UINT (*Write)(IWTSVirtualChannel *pChannel, - ULONG cbSize, - const BYTE *pBuffer, - void *pReserved); + UINT(*Write)(IWTSVirtualChannel* pChannel, + ULONG cbSize, + const BYTE* pBuffer, + void* pReserved); /* Closes the channel. */ - UINT (*Close)(IWTSVirtualChannel *pChannel); + UINT(*Close)(IWTSVirtualChannel* pChannel); }; struct _IWTSVirtualChannelManager { /* Returns an instance of a listener object that listens on a specific endpoint, or creates a static channel. */ - UINT (*CreateListener)(IWTSVirtualChannelManager *pChannelMgr, - const char *pszChannelName, - ULONG ulFlags, - IWTSListenerCallback *pListenerCallback, - IWTSListener **ppListener); + UINT(*CreateListener)(IWTSVirtualChannelManager* pChannelMgr, + const char* pszChannelName, + ULONG ulFlags, + IWTSListenerCallback* pListenerCallback, + IWTSListener** ppListener); /* Find the channel or ID to send data to a specific endpoint. */ - UINT32(*GetChannelId)(IWTSVirtualChannel *channel); - IWTSVirtualChannel *(*FindChannelById)(IWTSVirtualChannelManager *pChannelMgr, - UINT32 ChannelId); + UINT32(*GetChannelId)(IWTSVirtualChannel* channel); + IWTSVirtualChannel* (*FindChannelById)(IWTSVirtualChannelManager* pChannelMgr, + UINT32 ChannelId); }; struct _IWTSPlugin { /* Used for the first call that is made from the client to the plug-in. */ - UINT (*Initialize)(IWTSPlugin *pPlugin, - IWTSVirtualChannelManager *pChannelMgr); + UINT(*Initialize)(IWTSPlugin* pPlugin, + IWTSVirtualChannelManager* pChannelMgr); /* Notifies the plug-in that the Remote Desktop Connection (RDC) client has successfully connected to the Remote Desktop Session Host (RD Session Host) server. */ - UINT (*Connected)(IWTSPlugin *pPlugin); + UINT(*Connected)(IWTSPlugin* pPlugin); /* Notifies the plug-in that the Remote Desktop Connection (RDC) client has disconnected from the RD Session Host server. */ - UINT (*Disconnected)(IWTSPlugin *pPlugin, - DWORD dwDisconnectCode); + UINT(*Disconnected)(IWTSPlugin* pPlugin, + DWORD dwDisconnectCode); /* Notifies the plug-in that the Remote Desktop Connection (RDC) client has terminated. */ - UINT (*Terminated)(IWTSPlugin *pPlugin); + UINT(*Terminated)(IWTSPlugin* pPlugin); + + UINT(*Attached)(IWTSPlugin* pPlugin); + + UINT(*Detached)(IWTSPlugin* pPlugin); /* Extended */ - void *pInterface; + void* pInterface; }; struct _IWTSListenerCallback { /* Accepts or denies a connection request for an incoming connection to the associated listener. */ - UINT (*OnNewChannelConnection)(IWTSListenerCallback *pListenerCallback, - IWTSVirtualChannel *pChannel, - BYTE *Data, - BOOL *pbAccept, - IWTSVirtualChannelCallback **ppCallback); + UINT(*OnNewChannelConnection)(IWTSListenerCallback* pListenerCallback, + IWTSVirtualChannel* pChannel, + BYTE* Data, + BOOL* pbAccept, + IWTSVirtualChannelCallback** ppCallback); }; struct _IWTSVirtualChannelCallback { /* Notifies the user about data that is being received. */ - UINT (*OnDataReceived) (IWTSVirtualChannelCallback* pChannelCallback, wStream* data); + UINT(*OnDataReceived)(IWTSVirtualChannelCallback* pChannelCallback, wStream* data); /* Notifies the user that the channel has been opened. */ - UINT (*OnOpen) (IWTSVirtualChannelCallback* pChannelCallback); + UINT(*OnOpen)(IWTSVirtualChannelCallback* pChannelCallback); /* Notifies the user that the channel has been closed. */ - UINT (*OnClose) (IWTSVirtualChannelCallback* pChannelCallback); + UINT(*OnClose)(IWTSVirtualChannelCallback* pChannelCallback); }; /* The DVC Plugin entry points */ typedef struct _IDRDYNVC_ENTRY_POINTS IDRDYNVC_ENTRY_POINTS; struct _IDRDYNVC_ENTRY_POINTS { - UINT (*RegisterPlugin)(IDRDYNVC_ENTRY_POINTS *pEntryPoints, - const char *name, IWTSPlugin *pPlugin); - IWTSPlugin *(*GetPlugin)(IDRDYNVC_ENTRY_POINTS *pEntryPoints, - const char *name); + UINT(*RegisterPlugin)(IDRDYNVC_ENTRY_POINTS* pEntryPoints, + const char* name, IWTSPlugin* pPlugin); + IWTSPlugin* (*GetPlugin)(IDRDYNVC_ENTRY_POINTS* pEntryPoints, + const char* name); ADDIN_ARGV* (*GetPluginData)(IDRDYNVC_ENTRY_POINTS* pEntryPoints); void* (*GetRdpSettings)(IDRDYNVC_ENTRY_POINTS* pEntryPoints); }; -typedef UINT (*PDVC_PLUGIN_ENTRY)(IDRDYNVC_ENTRY_POINTS *); +typedef UINT(*PDVC_PLUGIN_ENTRY)(IDRDYNVC_ENTRY_POINTS*); -void *get_callback_by_name(const char *name, void **context); -void add_callback_by_name(const char *name, void *fkt, void *context); -void remove_callback_by_name(const char *name, void *context); +void* get_callback_by_name(const char* name, void** context); +void add_callback_by_name(const char* name, void* fkt, void* context); +void remove_callback_by_name(const char* name, void* context); #endif /* FREERDP_DVC_H */ diff --git a/include/freerdp/event.h b/include/freerdp/event.h index fbe5e8507..30f5c0386 100644 --- a/include/freerdp/event.h +++ b/include/freerdp/event.h @@ -34,60 +34,70 @@ extern "C" { #define FREERDP_WINDOW_STATE_ACTIVE 4 DEFINE_EVENT_BEGIN(WindowStateChange) - int state; +int state; DEFINE_EVENT_END(WindowStateChange) DEFINE_EVENT_BEGIN(ResizeWindow) - int width; - int height; +int width; +int height; DEFINE_EVENT_END(ResizeWindow) DEFINE_EVENT_BEGIN(PanningChange) - int dx; - int dy; +int dx; +int dy; DEFINE_EVENT_END(PanningChange) DEFINE_EVENT_BEGIN(ZoomingChange) - int dx; - int dy; +int dx; +int dy; DEFINE_EVENT_END(ZoomingChange) DEFINE_EVENT_BEGIN(LocalResizeWindow) - int width; - int height; +int width; +int height; DEFINE_EVENT_END(LocalResizeWindow) DEFINE_EVENT_BEGIN(EmbedWindow) - BOOL embed; - void* handle; +BOOL embed; +void* handle; DEFINE_EVENT_END(EmbedWindow) DEFINE_EVENT_BEGIN(ErrorInfo) - UINT32 code; +UINT32 code; DEFINE_EVENT_END(ErrorInfo) DEFINE_EVENT_BEGIN(Terminate) - int code; +int code; DEFINE_EVENT_END(Terminate) DEFINE_EVENT_BEGIN(ConnectionResult) - int result; +int result; DEFINE_EVENT_END(ConnectionResult) DEFINE_EVENT_BEGIN(ChannelConnected) - const char* name; - void* pInterface; +const char* name; +void* pInterface; DEFINE_EVENT_END(ChannelConnected) DEFINE_EVENT_BEGIN(ChannelDisconnected) - const char* name; - void* pInterface; +const char* name; +void* pInterface; DEFINE_EVENT_END(ChannelDisconnected) +DEFINE_EVENT_BEGIN(ChannelAttached) +const char* name; +void* pInterface; +DEFINE_EVENT_END(ChannelAttached) + +DEFINE_EVENT_BEGIN(ChannelDetached) +const char* name; +void* pInterface; +DEFINE_EVENT_END(ChannelDetached) + DEFINE_EVENT_BEGIN(MouseEvent) - UINT16 flags; - UINT16 x; - UINT16 y; +UINT16 flags; +UINT16 x; +UINT16 y; DEFINE_EVENT_END(MouseEvent) #ifdef __cplusplus diff --git a/include/freerdp/freerdp.h b/include/freerdp/freerdp.h index 4abe1fb47..f6e5c61e2 100644 --- a/include/freerdp/freerdp.h +++ b/include/freerdp/freerdp.h @@ -307,13 +307,22 @@ FREERDP_API BOOL freerdp_shall_disconnect(freerdp* instance); FREERDP_API BOOL freerdp_disconnect(freerdp* instance); FREERDP_API BOOL freerdp_reconnect(freerdp* instance); -FREERDP_API UINT freerdp_channel_add_init_handle_data(rdpChannelHandles* handles, void* pInitHandle, void* pUserData); -FREERDP_API void* freerdp_channel_get_init_handle_data(rdpChannelHandles* handles, void* pInitHandle); -FREERDP_API void freerdp_channel_remove_init_handle_data(rdpChannelHandles* handles, void* pInitHandle); +FREERDP_API UINT freerdp_channel_add_init_handle_data(rdpChannelHandles* handles, void* pInitHandle, + void* pUserData); +FREERDP_API void* freerdp_channel_get_init_handle_data(rdpChannelHandles* handles, + void* pInitHandle); +FREERDP_API void freerdp_channel_remove_init_handle_data(rdpChannelHandles* handles, + void* pInitHandle); -FREERDP_API UINT freerdp_channel_add_open_handle_data(rdpChannelHandles* handles, DWORD openHandle, void* pUserData); -FREERDP_API void* freerdp_channel_get_open_handle_data(rdpChannelHandles* handles, DWORD openHandle); -FREERDP_API void freerdp_channel_remove_open_handle_data(rdpChannelHandles* handles, DWORD openHandle); +FREERDP_API UINT freerdp_channel_add_open_handle_data(rdpChannelHandles* handles, DWORD openHandle, + void* pUserData); +FREERDP_API void* freerdp_channel_get_open_handle_data(rdpChannelHandles* handles, + DWORD openHandle); +FREERDP_API void freerdp_channel_remove_open_handle_data(rdpChannelHandles* handles, + DWORD openHandle); + +FREERDP_API UINT freerdp_channels_attach(freerdp* instance); +FREERDP_API UINT freerdp_channels_detach(freerdp* instance); FREERDP_API BOOL freerdp_get_fds(freerdp* instance, void** rfds, int* rcount, void** wfds, int* wcount); diff --git a/libfreerdp/core/client.c b/libfreerdp/core/client.c index cdc2e7fb4..21c84bd43 100644 --- a/libfreerdp/core/client.c +++ b/libfreerdp/core/client.c @@ -182,6 +182,36 @@ static UINT freerdp_drdynvc_on_channel_disconnected(DrdynvcClientContext* return status; } +static UINT freerdp_drdynvc_on_channel_attached(DrdynvcClientContext* + context, + const char* name, void* pInterface) +{ + UINT status = CHANNEL_RC_OK; + ChannelAttachedEventArgs e; + rdpChannels* channels = (rdpChannels*) context->custom; + freerdp* instance = channels->instance; + EventArgsInit(&e, "freerdp"); + e.name = name; + e.pInterface = pInterface; + PubSub_OnChannelAttached(instance->context->pubSub, instance->context, &e); + return status; +} + +static UINT freerdp_drdynvc_on_channel_detached(DrdynvcClientContext* + context, + const char* name, void* pInterface) +{ + UINT status = CHANNEL_RC_OK; + ChannelDetachedEventArgs e; + rdpChannels* channels = (rdpChannels*) context->custom; + freerdp* instance = channels->instance; + EventArgsInit(&e, "freerdp"); + e.name = name; + e.pInterface = pInterface; + PubSub_OnChannelDetached(instance->context->pubSub, instance->context, &e); + return status; +} + /** * go through and inform all the libraries that we are initialized * called only from main thread @@ -214,6 +244,122 @@ UINT freerdp_channels_pre_connect(rdpChannels* channels, freerdp* instance) return error; } +UINT freerdp_channels_attach(freerdp* instance) +{ + UINT error = CHANNEL_RC_OK; + int index; + char* name = NULL; + char* hostname; + int hostnameLength; + rdpChannels* channels; + CHANNEL_CLIENT_DATA* pChannelClientData; + channels = instance->context->channels; + channels->connected = 1; + hostname = instance->settings->ServerHostname; + hostnameLength = (int) strlen(hostname); + + for (index = 0; index < channels->clientDataCount; index++) + { + ChannelConnectedEventArgs e; + CHANNEL_OPEN_DATA* pChannelOpenData = NULL; + pChannelClientData = &channels->clientDataList[index]; + + if (pChannelClientData->pChannelInitEventProc) + { + pChannelClientData->pChannelInitEventProc( + pChannelClientData->pInitHandle, CHANNEL_EVENT_ATTACHED, hostname, hostnameLength); + } + else if (pChannelClientData->pChannelInitEventProcEx) + { + pChannelClientData->pChannelInitEventProcEx(pChannelClientData->lpUserParam, + pChannelClientData->pInitHandle, CHANNEL_EVENT_ATTACHED, hostname, hostnameLength); + } + + if (getChannelError(instance->context) != CHANNEL_RC_OK) + goto fail; + + pChannelOpenData = &channels->openDataList[index]; + name = (char*) malloc(9); + + if (!name) + { + error = CHANNEL_RC_NO_MEMORY; + goto fail; + } + + CopyMemory(name, pChannelOpenData->name, 8); + name[8] = '\0'; + EventArgsInit(&e, "freerdp"); + e.name = name; + e.pInterface = pChannelOpenData->pInterface; + PubSub_OnChannelAttached(instance->context->pubSub, instance->context, &e); + free(name); + name = NULL; + } + +fail: + free(name); + return error; +} + +UINT freerdp_channels_detach(freerdp* instance) +{ + UINT error = CHANNEL_RC_OK; + int index; + char* name = NULL; + char* hostname; + int hostnameLength; + rdpChannels* channels; + CHANNEL_CLIENT_DATA* pChannelClientData; + channels = instance->context->channels; + channels->connected = 1; + hostname = instance->settings->ServerHostname; + hostnameLength = (int) strlen(hostname); + + for (index = 0; index < channels->clientDataCount; index++) + { + ChannelConnectedEventArgs e; + CHANNEL_OPEN_DATA* pChannelOpenData; + pChannelClientData = &channels->clientDataList[index]; + + if (pChannelClientData->pChannelInitEventProc) + { + pChannelClientData->pChannelInitEventProc( + pChannelClientData->pInitHandle, CHANNEL_EVENT_DETACHED, hostname, hostnameLength); + } + else if (pChannelClientData->pChannelInitEventProcEx) + { + pChannelClientData->pChannelInitEventProcEx(pChannelClientData->lpUserParam, + pChannelClientData->pInitHandle, CHANNEL_EVENT_DETACHED, hostname, hostnameLength); + } + + if (getChannelError(instance->context) != CHANNEL_RC_OK) + goto fail; + + pChannelOpenData = &channels->openDataList[index]; + name = (char*) malloc(9); + + if (!name) + { + error = CHANNEL_RC_NO_MEMORY; + goto fail; + } + + CopyMemory(name, pChannelOpenData->name, 8); + name[8] = '\0'; + EventArgsInit(&e, "freerdp"); + e.name = name; + e.pInterface = pChannelOpenData->pInterface; + PubSub_OnChannelDetached(instance->context->pubSub, instance->context, &e); + free(name); + name = NULL; + } + +fail: + free(name); + return error; +} + /** * go through and inform all the libraries that we are connected * this will tell the libraries that its ok to call MyVirtualChannelOpen @@ -234,7 +380,7 @@ UINT freerdp_channels_post_connect(rdpChannels* channels, freerdp* instance) for (index = 0; index < channels->clientDataCount; index++) { ChannelConnectedEventArgs e; - CHANNEL_OPEN_DATA* pChannelOpenData = NULL; + CHANNEL_OPEN_DATA* pChannelOpenData; pChannelClientData = &channels->clientDataList[index]; if (pChannelClientData->pChannelInitEventProc) @@ -279,6 +425,8 @@ UINT freerdp_channels_post_connect(rdpChannels* channels, freerdp* instance) channels->drdynvc->OnChannelConnected = freerdp_drdynvc_on_channel_connected; channels->drdynvc->OnChannelDisconnected = freerdp_drdynvc_on_channel_disconnected; + channels->drdynvc->OnChannelAttached = freerdp_drdynvc_on_channel_attached; + channels->drdynvc->OnChannelDetached = freerdp_drdynvc_on_channel_detached; } fail: diff --git a/winpr/include/winpr/wtsapi.h b/winpr/include/winpr/wtsapi.h index aa4b90936..eb546be31 100644 --- a/winpr/include/winpr/wtsapi.h +++ b/winpr/include/winpr/wtsapi.h @@ -133,6 +133,8 @@ typedef CHANNEL_INIT_EVENT_EX_FN* PCHANNEL_INIT_EVENT_EX_FN; #define CHANNEL_EVENT_TERMINATED 4 #define CHANNEL_EVENT_REMOTE_CONTROL_START 5 #define CHANNEL_EVENT_REMOTE_CONTROL_STOP 6 +#define CHANNEL_EVENT_ATTACHED 7 +#define CHANNEL_EVENT_DETACHED 8 #define CHANNEL_EVENT_DATA_RECEIVED 10 #define CHANNEL_EVENT_WRITE_COMPLETE 11 #define CHANNEL_EVENT_WRITE_CANCELLED 12