dynamic channels: mutualize things for listeners and plugins
The same code is copied in all dynamic channels to create a plugin, have a listener, and manage the channel lifecycle. This patch does a mutualization effort so that channels only have to code things that are specific to them.
This commit is contained in:
parent
ffcb25a925
commit
3478051f15
@ -41,13 +41,10 @@
|
|||||||
typedef struct AINPUT_PLUGIN_ AINPUT_PLUGIN;
|
typedef struct AINPUT_PLUGIN_ AINPUT_PLUGIN;
|
||||||
struct AINPUT_PLUGIN_
|
struct AINPUT_PLUGIN_
|
||||||
{
|
{
|
||||||
IWTSPlugin iface;
|
GENERIC_DYNVC_PLUGIN base;
|
||||||
|
AInputClientContext* context;
|
||||||
GENERIC_LISTENER_CALLBACK* listener_callback;
|
|
||||||
IWTSListener* listener;
|
|
||||||
UINT32 MajorVersion;
|
UINT32 MajorVersion;
|
||||||
UINT32 MinorVersion;
|
UINT32 MinorVersion;
|
||||||
BOOL initialized;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -101,7 +98,6 @@ static UINT ainput_send_input_event(AInputClientContext* context, UINT64 flags,
|
|||||||
time = GetTickCount64();
|
time = GetTickCount64();
|
||||||
ainput = (AINPUT_PLUGIN*)context->handle;
|
ainput = (AINPUT_PLUGIN*)context->handle;
|
||||||
WINPR_ASSERT(ainput);
|
WINPR_ASSERT(ainput);
|
||||||
WINPR_ASSERT(ainput->listener_callback);
|
|
||||||
|
|
||||||
if (ainput->MajorVersion != AINPUT_VERSION_MAJOR)
|
if (ainput->MajorVersion != AINPUT_VERSION_MAJOR)
|
||||||
{
|
{
|
||||||
@ -109,7 +105,7 @@ static UINT ainput_send_input_event(AInputClientContext* context, UINT64 flags,
|
|||||||
ainput->MajorVersion, ainput->MinorVersion);
|
ainput->MajorVersion, ainput->MinorVersion);
|
||||||
return CHANNEL_RC_UNSUPPORTED_VERSION;
|
return CHANNEL_RC_UNSUPPORTED_VERSION;
|
||||||
}
|
}
|
||||||
callback = ainput->listener_callback->channel_callback;
|
callback = ainput->base.listener_callback->channel_callback;
|
||||||
WINPR_ASSERT(callback);
|
WINPR_ASSERT(callback);
|
||||||
|
|
||||||
{
|
{
|
||||||
@ -149,104 +145,30 @@ static UINT ainput_on_close(IWTSVirtualChannelCallback* pChannelCallback)
|
|||||||
return CHANNEL_RC_OK;
|
return CHANNEL_RC_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
static UINT init_plugin_cb(GENERIC_DYNVC_PLUGIN* base, rdpContext* rcontext, rdpSettings* settings)
|
||||||
* Function description
|
|
||||||
*
|
|
||||||
* @return 0 on success, otherwise a Win32 error code
|
|
||||||
*/
|
|
||||||
static UINT ainput_on_new_channel_connection(IWTSListenerCallback* pListenerCallback,
|
|
||||||
IWTSVirtualChannel* pChannel, BYTE* Data,
|
|
||||||
BOOL* pbAccept,
|
|
||||||
IWTSVirtualChannelCallback** ppCallback)
|
|
||||||
{
|
{
|
||||||
GENERIC_CHANNEL_CALLBACK* callback;
|
AINPUT_PLUGIN* ainput = (AINPUT_PLUGIN*)base;
|
||||||
GENERIC_LISTENER_CALLBACK* listener_callback = (GENERIC_LISTENER_CALLBACK*)pListenerCallback;
|
AInputClientContext* context = (AInputClientContext*)calloc(1, sizeof(AInputClientContext));
|
||||||
|
if (!context)
|
||||||
WINPR_ASSERT(listener_callback);
|
|
||||||
WINPR_UNUSED(Data);
|
|
||||||
WINPR_UNUSED(pbAccept);
|
|
||||||
|
|
||||||
callback = (GENERIC_CHANNEL_CALLBACK*)calloc(1, sizeof(GENERIC_CHANNEL_CALLBACK));
|
|
||||||
|
|
||||||
if (!callback)
|
|
||||||
{
|
|
||||||
WLog_ERR(TAG, "calloc failed!");
|
|
||||||
return CHANNEL_RC_NO_MEMORY;
|
return CHANNEL_RC_NO_MEMORY;
|
||||||
}
|
|
||||||
|
|
||||||
callback->iface.OnDataReceived = ainput_on_data_received;
|
context->handle = (void*)base;
|
||||||
callback->iface.OnClose = ainput_on_close;
|
context->AInputSendInputEvent = ainput_send_input_event;
|
||||||
callback->plugin = listener_callback->plugin;
|
|
||||||
callback->channel_mgr = listener_callback->channel_mgr;
|
|
||||||
callback->channel = pChannel;
|
|
||||||
listener_callback->channel_callback = callback;
|
|
||||||
|
|
||||||
*ppCallback = &callback->iface;
|
|
||||||
|
|
||||||
|
ainput->context = context;
|
||||||
|
ainput->base.iface.pInterface = context;
|
||||||
return CHANNEL_RC_OK;
|
return CHANNEL_RC_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
static void terminate_plugin_cb(GENERIC_DYNVC_PLUGIN* base)
|
||||||
* Function description
|
|
||||||
*
|
|
||||||
* @return 0 on success, otherwise a Win32 error code
|
|
||||||
*/
|
|
||||||
static UINT ainput_plugin_initialize(IWTSPlugin* pPlugin, IWTSVirtualChannelManager* pChannelMgr)
|
|
||||||
{
|
{
|
||||||
UINT status;
|
AINPUT_PLUGIN* ainput = (AINPUT_PLUGIN*)base;
|
||||||
AINPUT_PLUGIN* ainput = (AINPUT_PLUGIN*)pPlugin;
|
free(ainput->context);
|
||||||
|
|
||||||
WINPR_ASSERT(ainput);
|
|
||||||
|
|
||||||
if (ainput->initialized)
|
|
||||||
{
|
|
||||||
WLog_ERR(TAG, "[%s] channel initialized twice, aborting", AINPUT_DVC_CHANNEL_NAME);
|
|
||||||
return ERROR_INVALID_DATA;
|
|
||||||
}
|
|
||||||
ainput->listener_callback =
|
|
||||||
(GENERIC_LISTENER_CALLBACK*)calloc(1, sizeof(GENERIC_LISTENER_CALLBACK));
|
|
||||||
|
|
||||||
if (!ainput->listener_callback)
|
|
||||||
{
|
|
||||||
WLog_ERR(TAG, "calloc failed!");
|
|
||||||
return CHANNEL_RC_NO_MEMORY;
|
|
||||||
}
|
|
||||||
|
|
||||||
ainput->listener_callback->iface.OnNewChannelConnection = ainput_on_new_channel_connection;
|
|
||||||
ainput->listener_callback->plugin = pPlugin;
|
|
||||||
ainput->listener_callback->channel_mgr = pChannelMgr;
|
|
||||||
|
|
||||||
status = pChannelMgr->CreateListener(pChannelMgr, AINPUT_DVC_CHANNEL_NAME, 0,
|
|
||||||
&ainput->listener_callback->iface, &ainput->listener);
|
|
||||||
|
|
||||||
ainput->listener->pInterface = ainput->iface.pInterface;
|
|
||||||
ainput->initialized = status == CHANNEL_RC_OK;
|
|
||||||
return status;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
static const IWTSVirtualChannelCallback ainput_functions = { ainput_on_data_received,
|
||||||
* Function description
|
NULL, /* Open */
|
||||||
*
|
ainput_on_close };
|
||||||
* @return 0 on success, otherwise a Win32 error code
|
|
||||||
*/
|
|
||||||
static UINT ainput_plugin_terminated(IWTSPlugin* pPlugin)
|
|
||||||
{
|
|
||||||
AINPUT_PLUGIN* ainput = (AINPUT_PLUGIN*)pPlugin;
|
|
||||||
if (ainput && ainput->listener_callback)
|
|
||||||
{
|
|
||||||
IWTSVirtualChannelManager* mgr = ainput->listener_callback->channel_mgr;
|
|
||||||
if (mgr)
|
|
||||||
IFCALL(mgr->DestroyListener, mgr, ainput->listener);
|
|
||||||
}
|
|
||||||
if (ainput)
|
|
||||||
{
|
|
||||||
free(ainput->listener_callback);
|
|
||||||
free(ainput->iface.pInterface);
|
|
||||||
}
|
|
||||||
free(ainput);
|
|
||||||
|
|
||||||
return CHANNEL_RC_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Function description
|
* Function description
|
||||||
@ -255,32 +177,7 @@ static UINT ainput_plugin_terminated(IWTSPlugin* pPlugin)
|
|||||||
*/
|
*/
|
||||||
UINT ainput_DVCPluginEntry(IDRDYNVC_ENTRY_POINTS* pEntryPoints)
|
UINT ainput_DVCPluginEntry(IDRDYNVC_ENTRY_POINTS* pEntryPoints)
|
||||||
{
|
{
|
||||||
UINT status = CHANNEL_RC_OK;
|
return freerdp_generic_DVCPluginEntry(pEntryPoints, TAG, AINPUT_DVC_CHANNEL_NAME,
|
||||||
AINPUT_PLUGIN* ainput = (AINPUT_PLUGIN*)pEntryPoints->GetPlugin(pEntryPoints, "ainput");
|
sizeof(AINPUT_PLUGIN), sizeof(GENERIC_CHANNEL_CALLBACK),
|
||||||
|
&ainput_functions, init_plugin_cb, terminate_plugin_cb);
|
||||||
if (!ainput)
|
|
||||||
{
|
|
||||||
AInputClientContext* context = (AInputClientContext*)calloc(1, sizeof(AInputClientContext));
|
|
||||||
ainput = (AINPUT_PLUGIN*)calloc(1, sizeof(AINPUT_PLUGIN));
|
|
||||||
|
|
||||||
if (!ainput || !context)
|
|
||||||
{
|
|
||||||
free(context);
|
|
||||||
free(ainput);
|
|
||||||
|
|
||||||
WLog_ERR(TAG, "calloc failed!");
|
|
||||||
return CHANNEL_RC_NO_MEMORY;
|
|
||||||
}
|
|
||||||
|
|
||||||
ainput->iface.Initialize = ainput_plugin_initialize;
|
|
||||||
ainput->iface.Terminated = ainput_plugin_terminated;
|
|
||||||
|
|
||||||
context->handle = (void*)ainput;
|
|
||||||
context->AInputSendInputEvent = ainput_send_input_event;
|
|
||||||
ainput->iface.pInterface = (void*)context;
|
|
||||||
|
|
||||||
status = pEntryPoints->RegisterPlugin(pEntryPoints, AINPUT_CHANNEL_NAME, &ainput->iface);
|
|
||||||
}
|
|
||||||
|
|
||||||
return status;
|
|
||||||
}
|
}
|
||||||
|
@ -22,7 +22,8 @@ set(${MODULE_PREFIX}_SRCS
|
|||||||
${CMAKE_CURRENT_BINARY_DIR}/tables.c
|
${CMAKE_CURRENT_BINARY_DIR}/tables.c
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/tables.h
|
${CMAKE_CURRENT_SOURCE_DIR}/tables.h
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/addin.c
|
${CMAKE_CURRENT_SOURCE_DIR}/addin.c
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/addin.h)
|
${CMAKE_CURRENT_SOURCE_DIR}/addin.h
|
||||||
|
${CMAKE_CURRENT_SOURCE_DIR}/generic_dynvc.c)
|
||||||
|
|
||||||
if(CHANNEL_STATIC_CLIENT_ENTRIES)
|
if(CHANNEL_STATIC_CLIENT_ENTRIES)
|
||||||
list(REMOVE_DUPLICATES CHANNEL_STATIC_CLIENT_ENTRIES)
|
list(REMOVE_DUPLICATES CHANNEL_STATIC_CLIENT_ENTRIES)
|
||||||
|
209
channels/client/generic_dynvc.c
Normal file
209
channels/client/generic_dynvc.c
Normal file
@ -0,0 +1,209 @@
|
|||||||
|
/**
|
||||||
|
* FreeRDP: A Remote Desktop Protocol Implementation
|
||||||
|
* Dynamic channel
|
||||||
|
*
|
||||||
|
* Copyright 2022 David Fort <contact@hardening-consulting.com>
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <freerdp/config.h>
|
||||||
|
#include <freerdp/log.h>
|
||||||
|
#include <freerdp/client/channels.h>
|
||||||
|
|
||||||
|
#define TAG FREERDP_TAG("genericdynvc")
|
||||||
|
|
||||||
|
static UINT generic_on_new_channel_connection(IWTSListenerCallback* pListenerCallback,
|
||||||
|
IWTSVirtualChannel* pChannel, BYTE* Data,
|
||||||
|
BOOL* pbAccept,
|
||||||
|
IWTSVirtualChannelCallback** ppCallback)
|
||||||
|
{
|
||||||
|
GENERIC_CHANNEL_CALLBACK* callback;
|
||||||
|
GENERIC_DYNVC_PLUGIN* plugin;
|
||||||
|
GENERIC_LISTENER_CALLBACK* listener_callback = (GENERIC_LISTENER_CALLBACK*)pListenerCallback;
|
||||||
|
|
||||||
|
if (!listener_callback || !listener_callback->plugin)
|
||||||
|
return ERROR_INTERNAL_ERROR;
|
||||||
|
|
||||||
|
plugin = (GENERIC_DYNVC_PLUGIN*)listener_callback->plugin;
|
||||||
|
WLog_Print(plugin->log, WLOG_TRACE, "...");
|
||||||
|
|
||||||
|
callback = (GENERIC_CHANNEL_CALLBACK*)calloc(1, plugin->channelCallbackSize);
|
||||||
|
if (!callback)
|
||||||
|
{
|
||||||
|
WLog_Print(plugin->log, WLOG_ERROR, "calloc failed!");
|
||||||
|
return CHANNEL_RC_NO_MEMORY;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* implant configured channel callbacks */
|
||||||
|
callback->iface = *plugin->channel_callbacks;
|
||||||
|
|
||||||
|
callback->plugin = listener_callback->plugin;
|
||||||
|
callback->channel_mgr = listener_callback->channel_mgr;
|
||||||
|
callback->channel = pChannel;
|
||||||
|
|
||||||
|
listener_callback->channel_callback = callback;
|
||||||
|
*ppCallback = (IWTSVirtualChannelCallback*)callback;
|
||||||
|
return CHANNEL_RC_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
static UINT generic_dynvc_plugin_initialize(IWTSPlugin* pPlugin,
|
||||||
|
IWTSVirtualChannelManager* pChannelMgr)
|
||||||
|
{
|
||||||
|
UINT rc;
|
||||||
|
GENERIC_LISTENER_CALLBACK* listener_callback;
|
||||||
|
GENERIC_DYNVC_PLUGIN* plugin = (GENERIC_DYNVC_PLUGIN*)pPlugin;
|
||||||
|
|
||||||
|
if (!plugin)
|
||||||
|
return CHANNEL_RC_BAD_CHANNEL_HANDLE;
|
||||||
|
|
||||||
|
if (!pChannelMgr)
|
||||||
|
return ERROR_INVALID_PARAMETER;
|
||||||
|
|
||||||
|
if (plugin->initialized)
|
||||||
|
{
|
||||||
|
WLog_ERR(TAG, "[%s] channel initialized twice, aborting", plugin->dynvc_name);
|
||||||
|
return ERROR_INVALID_DATA;
|
||||||
|
}
|
||||||
|
|
||||||
|
WLog_Print(plugin->log, WLOG_TRACE, "...");
|
||||||
|
listener_callback = (GENERIC_LISTENER_CALLBACK*)calloc(1, sizeof(GENERIC_LISTENER_CALLBACK));
|
||||||
|
if (!listener_callback)
|
||||||
|
{
|
||||||
|
WLog_Print(plugin->log, WLOG_ERROR, "calloc failed!");
|
||||||
|
return CHANNEL_RC_NO_MEMORY;
|
||||||
|
}
|
||||||
|
|
||||||
|
plugin->listener_callback = listener_callback;
|
||||||
|
listener_callback->iface.OnNewChannelConnection = generic_on_new_channel_connection;
|
||||||
|
listener_callback->plugin = pPlugin;
|
||||||
|
listener_callback->channel_mgr = pChannelMgr;
|
||||||
|
rc = pChannelMgr->CreateListener(pChannelMgr, plugin->dynvc_name, 0, &listener_callback->iface,
|
||||||
|
&plugin->listener);
|
||||||
|
|
||||||
|
plugin->listener->pInterface = plugin->iface.pInterface;
|
||||||
|
plugin->initialized = (rc == CHANNEL_RC_OK);
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
static UINT generic_plugin_terminated(IWTSPlugin* pPlugin)
|
||||||
|
{
|
||||||
|
GENERIC_DYNVC_PLUGIN* plugin = (GENERIC_DYNVC_PLUGIN*)pPlugin;
|
||||||
|
UINT error = CHANNEL_RC_OK;
|
||||||
|
|
||||||
|
if (!plugin)
|
||||||
|
return CHANNEL_RC_BAD_CHANNEL_HANDLE;
|
||||||
|
|
||||||
|
WLog_Print(plugin->log, WLOG_TRACE, "...");
|
||||||
|
|
||||||
|
if (plugin->terminatePluginFn)
|
||||||
|
plugin->terminatePluginFn(plugin);
|
||||||
|
|
||||||
|
if (plugin->listener_callback)
|
||||||
|
{
|
||||||
|
IWTSVirtualChannelManager* mgr = plugin->listener_callback->channel_mgr;
|
||||||
|
if (mgr)
|
||||||
|
IFCALL(mgr->DestroyListener, mgr, plugin->listener);
|
||||||
|
}
|
||||||
|
|
||||||
|
free(plugin->listener_callback);
|
||||||
|
free(plugin->dynvc_name);
|
||||||
|
free(plugin);
|
||||||
|
return error;
|
||||||
|
}
|
||||||
|
|
||||||
|
static UINT generic_dynvc_plugin_attached(IWTSPlugin* pPlugin)
|
||||||
|
{
|
||||||
|
GENERIC_DYNVC_PLUGIN* pluginn = (GENERIC_DYNVC_PLUGIN*)pPlugin;
|
||||||
|
UINT error = CHANNEL_RC_OK;
|
||||||
|
|
||||||
|
if (!pluginn)
|
||||||
|
return CHANNEL_RC_BAD_CHANNEL_HANDLE;
|
||||||
|
|
||||||
|
pluginn->attached = TRUE;
|
||||||
|
return error;
|
||||||
|
}
|
||||||
|
|
||||||
|
static UINT generic_dynvc_plugin_detached(IWTSPlugin* pPlugin)
|
||||||
|
{
|
||||||
|
GENERIC_DYNVC_PLUGIN* plugin = (GENERIC_DYNVC_PLUGIN*)pPlugin;
|
||||||
|
UINT error = CHANNEL_RC_OK;
|
||||||
|
|
||||||
|
if (!plugin)
|
||||||
|
return CHANNEL_RC_BAD_CHANNEL_HANDLE;
|
||||||
|
|
||||||
|
plugin->attached = FALSE;
|
||||||
|
return error;
|
||||||
|
}
|
||||||
|
|
||||||
|
UINT freerdp_generic_DVCPluginEntry(IDRDYNVC_ENTRY_POINTS* pEntryPoints, const char* logTag,
|
||||||
|
const char* name, size_t pluginSize, size_t channelCallbackSize,
|
||||||
|
const IWTSVirtualChannelCallback* channel_callbacks,
|
||||||
|
DYNVC_PLUGIN_INIT_FN initPluginFn,
|
||||||
|
DYNVC_PLUGIN_TERMINATE_FN terminatePluginFn)
|
||||||
|
{
|
||||||
|
GENERIC_DYNVC_PLUGIN* plugin;
|
||||||
|
UINT error = CHANNEL_RC_INITIALIZATION_ERROR;
|
||||||
|
|
||||||
|
WINPR_ASSERT(pEntryPoints);
|
||||||
|
WINPR_ASSERT(pEntryPoints->GetPlugin);
|
||||||
|
WINPR_ASSERT(logTag);
|
||||||
|
WINPR_ASSERT(name);
|
||||||
|
WINPR_ASSERT(pluginSize >= sizeof(*plugin));
|
||||||
|
WINPR_ASSERT(channelCallbackSize >= sizeof(GENERIC_CHANNEL_CALLBACK));
|
||||||
|
|
||||||
|
plugin = (GENERIC_DYNVC_PLUGIN*)pEntryPoints->GetPlugin(pEntryPoints, name);
|
||||||
|
if (plugin != NULL)
|
||||||
|
return CHANNEL_RC_ALREADY_INITIALIZED;
|
||||||
|
|
||||||
|
plugin = (GENERIC_DYNVC_PLUGIN*)calloc(1, pluginSize);
|
||||||
|
if (!plugin)
|
||||||
|
{
|
||||||
|
WLog_ERR(TAG, "calloc failed!");
|
||||||
|
return CHANNEL_RC_NO_MEMORY;
|
||||||
|
}
|
||||||
|
|
||||||
|
plugin->log = WLog_Get(logTag);
|
||||||
|
plugin->attached = TRUE;
|
||||||
|
plugin->channel_callbacks = channel_callbacks;
|
||||||
|
plugin->channelCallbackSize = channelCallbackSize;
|
||||||
|
plugin->iface.Initialize = generic_dynvc_plugin_initialize;
|
||||||
|
plugin->iface.Connected = NULL;
|
||||||
|
plugin->iface.Disconnected = NULL;
|
||||||
|
plugin->iface.Terminated = generic_plugin_terminated;
|
||||||
|
plugin->iface.Attached = generic_dynvc_plugin_attached;
|
||||||
|
plugin->iface.Detached = generic_dynvc_plugin_detached;
|
||||||
|
plugin->terminatePluginFn = terminatePluginFn;
|
||||||
|
|
||||||
|
if (initPluginFn)
|
||||||
|
{
|
||||||
|
rdpSettings* settings = pEntryPoints->GetRdpSettings(pEntryPoints);
|
||||||
|
rdpContext* context = pEntryPoints->GetRdpContext(pEntryPoints);
|
||||||
|
|
||||||
|
error = initPluginFn(plugin, context, settings);
|
||||||
|
if (error != CHANNEL_RC_OK)
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
|
||||||
|
plugin->dynvc_name = _strdup(name);
|
||||||
|
if (!plugin->dynvc_name)
|
||||||
|
goto error;
|
||||||
|
|
||||||
|
error = pEntryPoints->RegisterPlugin(pEntryPoints, name, &plugin->iface);
|
||||||
|
if (error == CHANNEL_RC_OK)
|
||||||
|
return error;
|
||||||
|
|
||||||
|
error:
|
||||||
|
generic_plugin_terminated(&plugin->iface);
|
||||||
|
return error;
|
||||||
|
}
|
@ -44,15 +44,12 @@
|
|||||||
|
|
||||||
typedef struct
|
typedef struct
|
||||||
{
|
{
|
||||||
IWTSPlugin iface;
|
GENERIC_DYNVC_PLUGIN base;
|
||||||
|
|
||||||
IWTSListener* listener;
|
|
||||||
GENERIC_LISTENER_CALLBACK* listener_callback;
|
|
||||||
|
|
||||||
|
DispClientContext* context;
|
||||||
UINT32 MaxNumMonitors;
|
UINT32 MaxNumMonitors;
|
||||||
UINT32 MaxMonitorAreaFactorA;
|
UINT32 MaxMonitorAreaFactorA;
|
||||||
UINT32 MaxMonitorAreaFactorB;
|
UINT32 MaxMonitorAreaFactorB;
|
||||||
BOOL initialized;
|
|
||||||
} DISP_PLUGIN;
|
} DISP_PLUGIN;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -167,7 +164,7 @@ static UINT disp_recv_display_control_caps_pdu(GENERIC_CHANNEL_CALLBACK* callbac
|
|||||||
disp = (DISP_PLUGIN*)callback->plugin;
|
disp = (DISP_PLUGIN*)callback->plugin;
|
||||||
WINPR_ASSERT(disp);
|
WINPR_ASSERT(disp);
|
||||||
|
|
||||||
context = (DispClientContext*)disp->iface.pInterface;
|
context = disp->context;
|
||||||
WINPR_ASSERT(context);
|
WINPR_ASSERT(context);
|
||||||
|
|
||||||
if (!Stream_CheckAndLogRequiredLength(TAG, s, 12))
|
if (!Stream_CheckAndLogRequiredLength(TAG, s, 12))
|
||||||
@ -245,103 +242,6 @@ static UINT disp_on_close(IWTSVirtualChannelCallback* pChannelCallback)
|
|||||||
return CHANNEL_RC_OK;
|
return CHANNEL_RC_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Function description
|
|
||||||
*
|
|
||||||
* @return 0 on success, otherwise a Win32 error code
|
|
||||||
*/
|
|
||||||
static UINT disp_on_new_channel_connection(IWTSListenerCallback* pListenerCallback,
|
|
||||||
IWTSVirtualChannel* pChannel, BYTE* Data, BOOL* pbAccept,
|
|
||||||
IWTSVirtualChannelCallback** ppCallback)
|
|
||||||
{
|
|
||||||
GENERIC_CHANNEL_CALLBACK* callback;
|
|
||||||
GENERIC_LISTENER_CALLBACK* listener_callback = (GENERIC_LISTENER_CALLBACK*)pListenerCallback;
|
|
||||||
|
|
||||||
WINPR_ASSERT(listener_callback);
|
|
||||||
WINPR_ASSERT(pChannel);
|
|
||||||
WINPR_ASSERT(pbAccept);
|
|
||||||
WINPR_ASSERT(ppCallback);
|
|
||||||
|
|
||||||
callback = (GENERIC_CHANNEL_CALLBACK*)calloc(1, sizeof(GENERIC_CHANNEL_CALLBACK));
|
|
||||||
|
|
||||||
if (!callback)
|
|
||||||
{
|
|
||||||
WLog_ERR(TAG, "calloc failed!");
|
|
||||||
return CHANNEL_RC_NO_MEMORY;
|
|
||||||
}
|
|
||||||
|
|
||||||
callback->iface.OnDataReceived = disp_on_data_received;
|
|
||||||
callback->iface.OnClose = disp_on_close;
|
|
||||||
callback->plugin = listener_callback->plugin;
|
|
||||||
callback->channel_mgr = listener_callback->channel_mgr;
|
|
||||||
callback->channel = pChannel;
|
|
||||||
listener_callback->channel_callback = callback;
|
|
||||||
*ppCallback = (IWTSVirtualChannelCallback*)callback;
|
|
||||||
return CHANNEL_RC_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Function description
|
|
||||||
*
|
|
||||||
* @return 0 on success, otherwise a Win32 error code
|
|
||||||
*/
|
|
||||||
static UINT disp_plugin_initialize(IWTSPlugin* pPlugin, IWTSVirtualChannelManager* pChannelMgr)
|
|
||||||
{
|
|
||||||
UINT status;
|
|
||||||
DISP_PLUGIN* disp = (DISP_PLUGIN*)pPlugin;
|
|
||||||
|
|
||||||
WINPR_ASSERT(disp);
|
|
||||||
WINPR_ASSERT(pChannelMgr);
|
|
||||||
|
|
||||||
if (disp->initialized)
|
|
||||||
{
|
|
||||||
WLog_ERR(TAG, "[%s] channel initialized twice, aborting", DISP_DVC_CHANNEL_NAME);
|
|
||||||
return ERROR_INVALID_DATA;
|
|
||||||
}
|
|
||||||
disp->listener_callback =
|
|
||||||
(GENERIC_LISTENER_CALLBACK*)calloc(1, sizeof(GENERIC_LISTENER_CALLBACK));
|
|
||||||
|
|
||||||
if (!disp->listener_callback)
|
|
||||||
{
|
|
||||||
WLog_ERR(TAG, "calloc failed!");
|
|
||||||
return CHANNEL_RC_NO_MEMORY;
|
|
||||||
}
|
|
||||||
|
|
||||||
disp->listener_callback->iface.OnNewChannelConnection = disp_on_new_channel_connection;
|
|
||||||
disp->listener_callback->plugin = pPlugin;
|
|
||||||
disp->listener_callback->channel_mgr = pChannelMgr;
|
|
||||||
status = pChannelMgr->CreateListener(pChannelMgr, DISP_DVC_CHANNEL_NAME, 0,
|
|
||||||
&disp->listener_callback->iface, &(disp->listener));
|
|
||||||
disp->listener->pInterface = disp->iface.pInterface;
|
|
||||||
|
|
||||||
disp->initialized = status == CHANNEL_RC_OK;
|
|
||||||
return status;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Function description
|
|
||||||
*
|
|
||||||
* @return 0 on success, otherwise a Win32 error code
|
|
||||||
*/
|
|
||||||
static UINT disp_plugin_terminated(IWTSPlugin* pPlugin)
|
|
||||||
{
|
|
||||||
DISP_PLUGIN* disp = (DISP_PLUGIN*)pPlugin;
|
|
||||||
|
|
||||||
WINPR_ASSERT(disp);
|
|
||||||
|
|
||||||
if (disp->listener_callback)
|
|
||||||
{
|
|
||||||
IWTSVirtualChannelManager* mgr = disp->listener_callback->channel_mgr;
|
|
||||||
if (mgr)
|
|
||||||
IFCALL(mgr->DestroyListener, mgr, disp->listener);
|
|
||||||
free(disp->listener_callback);
|
|
||||||
}
|
|
||||||
|
|
||||||
free(disp->iface.pInterface);
|
|
||||||
free(pPlugin);
|
|
||||||
return CHANNEL_RC_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Channel Client Interface
|
* Channel Client Interface
|
||||||
*/
|
*/
|
||||||
@ -362,11 +262,54 @@ static UINT disp_send_monitor_layout(DispClientContext* context, UINT32 NumMonit
|
|||||||
disp = (DISP_PLUGIN*)context->handle;
|
disp = (DISP_PLUGIN*)context->handle;
|
||||||
WINPR_ASSERT(disp);
|
WINPR_ASSERT(disp);
|
||||||
|
|
||||||
callback = disp->listener_callback->channel_callback;
|
callback = disp->base.listener_callback->channel_callback;
|
||||||
|
|
||||||
return disp_send_display_control_monitor_layout_pdu(callback, NumMonitors, Monitors);
|
return disp_send_display_control_monitor_layout_pdu(callback, NumMonitors, Monitors);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Function description
|
||||||
|
*
|
||||||
|
* @return 0 on success, otherwise a Win32 error code
|
||||||
|
*/
|
||||||
|
static UINT disp_plugin_initialize(GENERIC_DYNVC_PLUGIN* base, rdpContext* rcontext,
|
||||||
|
rdpSettings* settings)
|
||||||
|
{
|
||||||
|
DispClientContext* context;
|
||||||
|
DISP_PLUGIN* disp = (DISP_PLUGIN*)base;
|
||||||
|
|
||||||
|
WINPR_ASSERT(disp);
|
||||||
|
disp->MaxNumMonitors = 16;
|
||||||
|
disp->MaxMonitorAreaFactorA = 8192;
|
||||||
|
disp->MaxMonitorAreaFactorB = 8192;
|
||||||
|
|
||||||
|
context = (DispClientContext*)calloc(1, sizeof(*disp));
|
||||||
|
if (!context)
|
||||||
|
{
|
||||||
|
WLog_Print(base->log, WLOG_ERROR, "unable to allocate DispClientContext");
|
||||||
|
return CHANNEL_RC_NO_MEMORY;
|
||||||
|
}
|
||||||
|
|
||||||
|
context->handle = (void*)disp;
|
||||||
|
context->SendMonitorLayout = disp_send_monitor_layout;
|
||||||
|
|
||||||
|
disp->base.iface.pInterface = disp->context = context;
|
||||||
|
|
||||||
|
return CHANNEL_RC_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void disp_plugin_terminated(GENERIC_DYNVC_PLUGIN* base)
|
||||||
|
{
|
||||||
|
DISP_PLUGIN* disp = (DISP_PLUGIN*)base;
|
||||||
|
|
||||||
|
WINPR_ASSERT(disp);
|
||||||
|
|
||||||
|
free(disp->context);
|
||||||
|
}
|
||||||
|
|
||||||
|
static const IWTSVirtualChannelCallback disp_callbacks = { disp_on_data_received, NULL, /* Open */
|
||||||
|
disp_on_close };
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Function description
|
* Function description
|
||||||
*
|
*
|
||||||
@ -374,50 +317,8 @@ static UINT disp_send_monitor_layout(DispClientContext* context, UINT32 NumMonit
|
|||||||
*/
|
*/
|
||||||
UINT disp_DVCPluginEntry(IDRDYNVC_ENTRY_POINTS* pEntryPoints)
|
UINT disp_DVCPluginEntry(IDRDYNVC_ENTRY_POINTS* pEntryPoints)
|
||||||
{
|
{
|
||||||
UINT error = CHANNEL_RC_OK;
|
return freerdp_generic_DVCPluginEntry(pEntryPoints, TAG, DISP_DVC_CHANNEL_NAME,
|
||||||
DISP_PLUGIN* disp;
|
sizeof(DISP_PLUGIN), sizeof(GENERIC_CHANNEL_CALLBACK),
|
||||||
DispClientContext* context;
|
&disp_callbacks, disp_plugin_initialize,
|
||||||
|
disp_plugin_terminated);
|
||||||
WINPR_ASSERT(pEntryPoints);
|
|
||||||
|
|
||||||
disp = (DISP_PLUGIN*)pEntryPoints->GetPlugin(pEntryPoints, DISP_CHANNEL_NAME);
|
|
||||||
|
|
||||||
if (!disp)
|
|
||||||
{
|
|
||||||
disp = (DISP_PLUGIN*)calloc(1, sizeof(DISP_PLUGIN));
|
|
||||||
|
|
||||||
if (!disp)
|
|
||||||
{
|
|
||||||
WLog_ERR(TAG, "calloc failed!");
|
|
||||||
return CHANNEL_RC_NO_MEMORY;
|
|
||||||
}
|
|
||||||
|
|
||||||
disp->iface.Initialize = disp_plugin_initialize;
|
|
||||||
disp->iface.Connected = NULL;
|
|
||||||
disp->iface.Disconnected = NULL;
|
|
||||||
disp->iface.Terminated = disp_plugin_terminated;
|
|
||||||
disp->MaxNumMonitors = 16;
|
|
||||||
disp->MaxMonitorAreaFactorA = 8192;
|
|
||||||
disp->MaxMonitorAreaFactorB = 8192;
|
|
||||||
context = (DispClientContext*)calloc(1, sizeof(DispClientContext));
|
|
||||||
|
|
||||||
if (!context)
|
|
||||||
{
|
|
||||||
WLog_ERR(TAG, "calloc failed!");
|
|
||||||
free(disp);
|
|
||||||
return CHANNEL_RC_NO_MEMORY;
|
|
||||||
}
|
|
||||||
|
|
||||||
context->handle = (void*)disp;
|
|
||||||
context->SendMonitorLayout = disp_send_monitor_layout;
|
|
||||||
disp->iface.pInterface = (void*)context;
|
|
||||||
error = pEntryPoints->RegisterPlugin(pEntryPoints, DISP_CHANNEL_NAME, &disp->iface);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
WLog_ERR(TAG, "could not get disp Plugin.");
|
|
||||||
return CHANNEL_RC_BAD_CHANNEL;
|
|
||||||
}
|
|
||||||
|
|
||||||
return error;
|
|
||||||
}
|
}
|
||||||
|
@ -34,14 +34,9 @@
|
|||||||
|
|
||||||
#define TAG CHANNELS_TAG("echo.client")
|
#define TAG CHANNELS_TAG("echo.client")
|
||||||
|
|
||||||
|
|
||||||
typedef struct
|
typedef struct
|
||||||
{
|
{
|
||||||
IWTSPlugin iface;
|
GENERIC_DYNVC_PLUGIN baseDynPlugin;
|
||||||
|
|
||||||
GENERIC_LISTENER_CALLBACK* listener_callback;
|
|
||||||
IWTSListener* listener;
|
|
||||||
BOOL initialized;
|
|
||||||
} ECHO_PLUGIN;
|
} ECHO_PLUGIN;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -66,95 +61,15 @@ static UINT echo_on_data_received(IWTSVirtualChannelCallback* pChannelCallback,
|
|||||||
*/
|
*/
|
||||||
static UINT echo_on_close(IWTSVirtualChannelCallback* pChannelCallback)
|
static UINT echo_on_close(IWTSVirtualChannelCallback* pChannelCallback)
|
||||||
{
|
{
|
||||||
GENERIC_CHANNEL_CALLBACK* callback = (GENERIC_CHANNEL_CALLBACK*)pChannelCallback;
|
GENERIC_CHANNEL_CALLBACK* callback = (GENERIC_CHANNEL_CALLBACK*)pChannelCallback;
|
||||||
|
|
||||||
free(callback);
|
free(callback);
|
||||||
|
|
||||||
return CHANNEL_RC_OK;
|
return CHANNEL_RC_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
static const IWTSVirtualChannelCallback echo_callbacks = { echo_on_data_received, NULL, /* Open */
|
||||||
* Function description
|
echo_on_close };
|
||||||
*
|
|
||||||
* @return 0 on success, otherwise a Win32 error code
|
|
||||||
*/
|
|
||||||
static UINT echo_on_new_channel_connection(IWTSListenerCallback* pListenerCallback,
|
|
||||||
IWTSVirtualChannel* pChannel, BYTE* Data, BOOL* pbAccept,
|
|
||||||
IWTSVirtualChannelCallback** ppCallback)
|
|
||||||
{
|
|
||||||
GENERIC_CHANNEL_CALLBACK* callback;
|
|
||||||
GENERIC_LISTENER_CALLBACK* listener_callback = (GENERIC_LISTENER_CALLBACK*)pListenerCallback;
|
|
||||||
|
|
||||||
callback = (GENERIC_CHANNEL_CALLBACK*)calloc(1, sizeof(GENERIC_CHANNEL_CALLBACK));
|
|
||||||
|
|
||||||
if (!callback)
|
|
||||||
{
|
|
||||||
WLog_ERR(TAG, "calloc failed!");
|
|
||||||
return CHANNEL_RC_NO_MEMORY;
|
|
||||||
}
|
|
||||||
|
|
||||||
callback->iface.OnDataReceived = echo_on_data_received;
|
|
||||||
callback->iface.OnClose = echo_on_close;
|
|
||||||
callback->plugin = listener_callback->plugin;
|
|
||||||
callback->channel_mgr = listener_callback->channel_mgr;
|
|
||||||
callback->channel = pChannel;
|
|
||||||
|
|
||||||
*ppCallback = (IWTSVirtualChannelCallback*)callback;
|
|
||||||
|
|
||||||
return CHANNEL_RC_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Function description
|
|
||||||
*
|
|
||||||
* @return 0 on success, otherwise a Win32 error code
|
|
||||||
*/
|
|
||||||
static UINT echo_plugin_initialize(IWTSPlugin* pPlugin, IWTSVirtualChannelManager* pChannelMgr)
|
|
||||||
{
|
|
||||||
UINT status;
|
|
||||||
ECHO_PLUGIN* echo = (ECHO_PLUGIN*)pPlugin;
|
|
||||||
if (echo->initialized)
|
|
||||||
{
|
|
||||||
WLog_ERR(TAG, "[%s] channel initialized twice, aborting", ECHO_DVC_CHANNEL_NAME);
|
|
||||||
return ERROR_INVALID_DATA;
|
|
||||||
}
|
|
||||||
echo->listener_callback = (GENERIC_LISTENER_CALLBACK*)calloc(1, sizeof(GENERIC_LISTENER_CALLBACK));
|
|
||||||
|
|
||||||
if (!echo->listener_callback)
|
|
||||||
{
|
|
||||||
WLog_ERR(TAG, "calloc failed!");
|
|
||||||
return CHANNEL_RC_NO_MEMORY;
|
|
||||||
}
|
|
||||||
|
|
||||||
echo->listener_callback->iface.OnNewChannelConnection = echo_on_new_channel_connection;
|
|
||||||
echo->listener_callback->plugin = pPlugin;
|
|
||||||
echo->listener_callback->channel_mgr = pChannelMgr;
|
|
||||||
|
|
||||||
status = pChannelMgr->CreateListener(pChannelMgr, ECHO_DVC_CHANNEL_NAME, 0,
|
|
||||||
&echo->listener_callback->iface, &echo->listener);
|
|
||||||
|
|
||||||
echo->initialized = status == CHANNEL_RC_OK;
|
|
||||||
return status;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Function description
|
|
||||||
*
|
|
||||||
* @return 0 on success, otherwise a Win32 error code
|
|
||||||
*/
|
|
||||||
static UINT echo_plugin_terminated(IWTSPlugin* pPlugin)
|
|
||||||
{
|
|
||||||
ECHO_PLUGIN* echo = (ECHO_PLUGIN*)pPlugin;
|
|
||||||
if (echo && echo->listener_callback)
|
|
||||||
{
|
|
||||||
IWTSVirtualChannelManager* mgr = echo->listener_callback->channel_mgr;
|
|
||||||
if (mgr)
|
|
||||||
IFCALL(mgr->DestroyListener, mgr, echo->listener);
|
|
||||||
}
|
|
||||||
free(echo);
|
|
||||||
|
|
||||||
return CHANNEL_RC_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Function description
|
* Function description
|
||||||
@ -163,28 +78,7 @@ static UINT echo_plugin_terminated(IWTSPlugin* pPlugin)
|
|||||||
*/
|
*/
|
||||||
UINT echo_DVCPluginEntry(IDRDYNVC_ENTRY_POINTS* pEntryPoints)
|
UINT echo_DVCPluginEntry(IDRDYNVC_ENTRY_POINTS* pEntryPoints)
|
||||||
{
|
{
|
||||||
UINT status = CHANNEL_RC_OK;
|
return freerdp_generic_DVCPluginEntry(pEntryPoints, TAG, ECHO_DVC_CHANNEL_NAME,
|
||||||
ECHO_PLUGIN* echo;
|
sizeof(ECHO_PLUGIN), sizeof(GENERIC_CHANNEL_CALLBACK),
|
||||||
|
&echo_callbacks, NULL, NULL);
|
||||||
echo = (ECHO_PLUGIN*)pEntryPoints->GetPlugin(pEntryPoints, "echo");
|
|
||||||
|
|
||||||
if (!echo)
|
|
||||||
{
|
|
||||||
echo = (ECHO_PLUGIN*)calloc(1, sizeof(ECHO_PLUGIN));
|
|
||||||
|
|
||||||
if (!echo)
|
|
||||||
{
|
|
||||||
WLog_ERR(TAG, "calloc failed!");
|
|
||||||
return CHANNEL_RC_NO_MEMORY;
|
|
||||||
}
|
|
||||||
|
|
||||||
echo->iface.Initialize = echo_plugin_initialize;
|
|
||||||
echo->iface.Connected = NULL;
|
|
||||||
echo->iface.Disconnected = NULL;
|
|
||||||
echo->iface.Terminated = echo_plugin_terminated;
|
|
||||||
|
|
||||||
status = pEntryPoints->RegisterPlugin(pEntryPoints, "echo", &echo->iface);
|
|
||||||
}
|
|
||||||
|
|
||||||
return status;
|
|
||||||
}
|
}
|
||||||
|
@ -41,13 +41,8 @@
|
|||||||
|
|
||||||
typedef struct
|
typedef struct
|
||||||
{
|
{
|
||||||
IWTSPlugin iface;
|
GENERIC_DYNVC_PLUGIN base;
|
||||||
|
|
||||||
IWTSListener* listener;
|
|
||||||
GENERIC_LISTENER_CALLBACK* listener_callback;
|
|
||||||
|
|
||||||
GeometryClientContext* context;
|
GeometryClientContext* context;
|
||||||
BOOL initialized;
|
|
||||||
} GEOMETRY_PLUGIN;
|
} GEOMETRY_PLUGIN;
|
||||||
|
|
||||||
static UINT32 mappedGeometryHash(const void* v)
|
static UINT32 mappedGeometryHash(const void* v)
|
||||||
@ -68,7 +63,7 @@ static void freerdp_rgndata_reset(FREERDP_RGNDATA* data)
|
|||||||
data->nRectCount = 0;
|
data->nRectCount = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static UINT32 geometry_read_RGNDATA(wStream* s, UINT32 len, FREERDP_RGNDATA* rgndata)
|
static UINT32 geometry_read_RGNDATA(wLog* logger, wStream* s, UINT32 len, FREERDP_RGNDATA* rgndata)
|
||||||
{
|
{
|
||||||
UINT32 dwSize, iType;
|
UINT32 dwSize, iType;
|
||||||
INT32 right, bottom;
|
INT32 right, bottom;
|
||||||
@ -76,7 +71,7 @@ static UINT32 geometry_read_RGNDATA(wStream* s, UINT32 len, FREERDP_RGNDATA* rgn
|
|||||||
|
|
||||||
if (len < 32)
|
if (len < 32)
|
||||||
{
|
{
|
||||||
WLog_ERR(TAG, "invalid RGNDATA");
|
WLog_Print(logger, WLOG_ERROR, "invalid RGNDATA");
|
||||||
return ERROR_INVALID_DATA;
|
return ERROR_INVALID_DATA;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -84,7 +79,7 @@ static UINT32 geometry_read_RGNDATA(wStream* s, UINT32 len, FREERDP_RGNDATA* rgn
|
|||||||
|
|
||||||
if (dwSize != 32)
|
if (dwSize != 32)
|
||||||
{
|
{
|
||||||
WLog_ERR(TAG, "invalid RGNDATA dwSize");
|
WLog_Print(logger, WLOG_ERROR, "invalid RGNDATA dwSize");
|
||||||
return ERROR_INVALID_DATA;
|
return ERROR_INVALID_DATA;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -92,7 +87,7 @@ static UINT32 geometry_read_RGNDATA(wStream* s, UINT32 len, FREERDP_RGNDATA* rgn
|
|||||||
|
|
||||||
if (iType != RDH_RECTANGLE)
|
if (iType != RDH_RECTANGLE)
|
||||||
{
|
{
|
||||||
WLog_ERR(TAG, "iType %" PRIu32 " for RGNDATA is not supported", iType);
|
WLog_Print(logger, WLOG_ERROR, "iType %" PRIu32 " for RGNDATA is not supported", iType);
|
||||||
return ERROR_UNSUPPORTED_TYPE;
|
return ERROR_UNSUPPORTED_TYPE;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -116,7 +111,7 @@ static UINT32 geometry_read_RGNDATA(wStream* s, UINT32 len, FREERDP_RGNDATA* rgn
|
|||||||
|
|
||||||
if (len / (4 * 4) < rgndata->nRectCount)
|
if (len / (4 * 4) < rgndata->nRectCount)
|
||||||
{
|
{
|
||||||
WLog_ERR(TAG, "not enough data for region rectangles");
|
WLog_Print(logger, WLOG_ERROR, "not enough data for region rectangles");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (rgndata->nRectCount)
|
if (rgndata->nRectCount)
|
||||||
@ -126,7 +121,8 @@ static UINT32 geometry_read_RGNDATA(wStream* s, UINT32 len, FREERDP_RGNDATA* rgn
|
|||||||
|
|
||||||
if (!tmp)
|
if (!tmp)
|
||||||
{
|
{
|
||||||
WLog_ERR(TAG, "unable to allocate memory for %" PRIu32 " RECTs", rgndata->nRectCount);
|
WLog_Print(logger, WLOG_ERROR, "unable to allocate memory for %" PRIu32 " RECTs",
|
||||||
|
rgndata->nRectCount);
|
||||||
return CHANNEL_RC_NO_MEMORY;
|
return CHANNEL_RC_NO_MEMORY;
|
||||||
}
|
}
|
||||||
rgndata->rects = tmp;
|
rgndata->rects = tmp;
|
||||||
@ -165,11 +161,13 @@ static UINT geometry_recv_pdu(GENERIC_CHANNEL_CALLBACK* callback, wStream* s)
|
|||||||
GEOMETRY_PLUGIN* geometry;
|
GEOMETRY_PLUGIN* geometry;
|
||||||
GeometryClientContext* context;
|
GeometryClientContext* context;
|
||||||
UINT ret = CHANNEL_RC_OK;
|
UINT ret = CHANNEL_RC_OK;
|
||||||
UINT32 version, updateType, geometryType;
|
UINT32 updateType, geometryType;
|
||||||
UINT64 id;
|
UINT64 id;
|
||||||
|
wLog* logger;
|
||||||
|
|
||||||
geometry = (GEOMETRY_PLUGIN*)callback->plugin;
|
geometry = (GEOMETRY_PLUGIN*)callback->plugin;
|
||||||
context = (GeometryClientContext*)geometry->iface.pInterface;
|
logger = geometry->base.log;
|
||||||
|
context = (GeometryClientContext*)geometry->base.iface.pInterface;
|
||||||
|
|
||||||
if (!Stream_CheckAndLogRequiredLength(TAG, s, 4))
|
if (!Stream_CheckAndLogRequiredLength(TAG, s, 4))
|
||||||
return ERROR_INVALID_DATA;
|
return ERROR_INVALID_DATA;
|
||||||
@ -178,11 +176,11 @@ static UINT geometry_recv_pdu(GENERIC_CHANNEL_CALLBACK* callback, wStream* s)
|
|||||||
|
|
||||||
if (length < 73 || !Stream_CheckAndLogRequiredLength(TAG, s, (length - 4)))
|
if (length < 73 || !Stream_CheckAndLogRequiredLength(TAG, s, (length - 4)))
|
||||||
{
|
{
|
||||||
WLog_ERR(TAG, "invalid packet length");
|
WLog_Print(logger, WLOG_ERROR, "invalid packet length");
|
||||||
return ERROR_INVALID_DATA;
|
return ERROR_INVALID_DATA;
|
||||||
}
|
}
|
||||||
|
|
||||||
Stream_Read_UINT32(s, version);
|
Stream_Read_UINT32(s, context->remoteVersion);
|
||||||
Stream_Read_UINT64(s, id);
|
Stream_Read_UINT64(s, id);
|
||||||
Stream_Read_UINT32(s, updateType);
|
Stream_Read_UINT32(s, updateType);
|
||||||
Stream_Seek_UINT32(s); /* flags */
|
Stream_Seek_UINT32(s); /* flags */
|
||||||
@ -193,18 +191,19 @@ static UINT geometry_recv_pdu(GENERIC_CHANNEL_CALLBACK* callback, wStream* s)
|
|||||||
{
|
{
|
||||||
if (!mappedGeometry)
|
if (!mappedGeometry)
|
||||||
{
|
{
|
||||||
WLog_ERR(TAG, "geometry 0x%" PRIx64 " not found here, ignoring clear command", id);
|
WLog_Print(logger, WLOG_ERROR,
|
||||||
|
"geometry 0x%" PRIx64 " not found here, ignoring clear command", id);
|
||||||
return CHANNEL_RC_OK;
|
return CHANNEL_RC_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
WLog_DBG(TAG, "clearing geometry 0x%" PRIx64 "", id);
|
WLog_Print(logger, WLOG_DEBUG, "clearing geometry 0x%" PRIx64 "", id);
|
||||||
|
|
||||||
if (mappedGeometry->MappedGeometryClear &&
|
if (mappedGeometry->MappedGeometryClear &&
|
||||||
!mappedGeometry->MappedGeometryClear(mappedGeometry))
|
!mappedGeometry->MappedGeometryClear(mappedGeometry))
|
||||||
return ERROR_INTERNAL_ERROR;
|
return ERROR_INTERNAL_ERROR;
|
||||||
|
|
||||||
if (!HashTable_Remove(context->geometries, &id))
|
if (!HashTable_Remove(context->geometries, &id))
|
||||||
WLog_ERR(TAG, "geometry not removed from geometries");
|
WLog_Print(logger, WLOG_ERROR, "geometry not removed from geometries");
|
||||||
}
|
}
|
||||||
else if (updateType == GEOMETRY_UPDATE)
|
else if (updateType == GEOMETRY_UPDATE)
|
||||||
{
|
{
|
||||||
@ -213,7 +212,7 @@ static UINT geometry_recv_pdu(GENERIC_CHANNEL_CALLBACK* callback, wStream* s)
|
|||||||
if (!mappedGeometry)
|
if (!mappedGeometry)
|
||||||
{
|
{
|
||||||
newOne = TRUE;
|
newOne = TRUE;
|
||||||
WLog_DBG(TAG, "creating geometry 0x%" PRIx64 "", id);
|
WLog_Print(logger, WLOG_DEBUG, "creating geometry 0x%" PRIx64 "", id);
|
||||||
mappedGeometry = calloc(1, sizeof(MAPPED_GEOMETRY));
|
mappedGeometry = calloc(1, sizeof(MAPPED_GEOMETRY));
|
||||||
if (!mappedGeometry)
|
if (!mappedGeometry)
|
||||||
return CHANNEL_RC_NO_MEMORY;
|
return CHANNEL_RC_NO_MEMORY;
|
||||||
@ -224,14 +223,15 @@ static UINT geometry_recv_pdu(GENERIC_CHANNEL_CALLBACK* callback, wStream* s)
|
|||||||
if (!HashTable_Insert(context->geometries, &(mappedGeometry->mappingId),
|
if (!HashTable_Insert(context->geometries, &(mappedGeometry->mappingId),
|
||||||
mappedGeometry))
|
mappedGeometry))
|
||||||
{
|
{
|
||||||
WLog_ERR(TAG, "unable to register geometry 0x%" PRIx64 " in the table", id);
|
WLog_Print(logger, WLOG_ERROR,
|
||||||
|
"unable to register geometry 0x%" PRIx64 " in the table", id);
|
||||||
free(mappedGeometry);
|
free(mappedGeometry);
|
||||||
return CHANNEL_RC_NO_MEMORY;
|
return CHANNEL_RC_NO_MEMORY;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
WLog_DBG(TAG, "updating geometry 0x%" PRIx64 "", id);
|
WLog_Print(logger, WLOG_DEBUG, "updating geometry 0x%" PRIx64 "", id);
|
||||||
}
|
}
|
||||||
|
|
||||||
Stream_Read_UINT64(s, mappedGeometry->topLevelId);
|
Stream_Read_UINT64(s, mappedGeometry->topLevelId);
|
||||||
@ -247,6 +247,9 @@ static UINT geometry_recv_pdu(GENERIC_CHANNEL_CALLBACK* callback, wStream* s)
|
|||||||
Stream_Read_INT32(s, mappedGeometry->topLevelBottom);
|
Stream_Read_INT32(s, mappedGeometry->topLevelBottom);
|
||||||
|
|
||||||
Stream_Read_UINT32(s, geometryType);
|
Stream_Read_UINT32(s, geometryType);
|
||||||
|
if (geometryType != 0x02)
|
||||||
|
WLog_Print(logger, WLOG_DEBUG, "geometryType should be set to 0x02 and is 0x%" PRIx32,
|
||||||
|
geometryType);
|
||||||
|
|
||||||
Stream_Read_UINT32(s, cbGeometryBuffer);
|
Stream_Read_UINT32(s, cbGeometryBuffer);
|
||||||
if (!Stream_CheckAndLogRequiredLength(TAG, s, cbGeometryBuffer))
|
if (!Stream_CheckAndLogRequiredLength(TAG, s, cbGeometryBuffer))
|
||||||
@ -254,7 +257,7 @@ static UINT geometry_recv_pdu(GENERIC_CHANNEL_CALLBACK* callback, wStream* s)
|
|||||||
|
|
||||||
if (cbGeometryBuffer)
|
if (cbGeometryBuffer)
|
||||||
{
|
{
|
||||||
ret = geometry_read_RGNDATA(s, cbGeometryBuffer, &mappedGeometry->geometry);
|
ret = geometry_read_RGNDATA(logger, s, cbGeometryBuffer, &mappedGeometry->geometry);
|
||||||
if (ret != CHANNEL_RC_OK)
|
if (ret != CHANNEL_RC_OK)
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
@ -268,7 +271,7 @@ static UINT geometry_recv_pdu(GENERIC_CHANNEL_CALLBACK* callback, wStream* s)
|
|||||||
if (context->MappedGeometryAdded &&
|
if (context->MappedGeometryAdded &&
|
||||||
!context->MappedGeometryAdded(context, mappedGeometry))
|
!context->MappedGeometryAdded(context, mappedGeometry))
|
||||||
{
|
{
|
||||||
WLog_ERR(TAG, "geometry added callback failed");
|
WLog_Print(logger, WLOG_ERROR, "geometry added callback failed");
|
||||||
ret = ERROR_INTERNAL_ERROR;
|
ret = ERROR_INTERNAL_ERROR;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -277,14 +280,14 @@ static UINT geometry_recv_pdu(GENERIC_CHANNEL_CALLBACK* callback, wStream* s)
|
|||||||
if (mappedGeometry->MappedGeometryUpdate &&
|
if (mappedGeometry->MappedGeometryUpdate &&
|
||||||
!mappedGeometry->MappedGeometryUpdate(mappedGeometry))
|
!mappedGeometry->MappedGeometryUpdate(mappedGeometry))
|
||||||
{
|
{
|
||||||
WLog_ERR(TAG, "geometry update callback failed");
|
WLog_Print(logger, WLOG_ERROR, "geometry update callback failed");
|
||||||
ret = ERROR_INTERNAL_ERROR;
|
ret = ERROR_INTERNAL_ERROR;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
WLog_ERR(TAG, "unknown updateType=%" PRIu32 "", updateType);
|
WLog_Print(logger, WLOG_ERROR, "unknown updateType=%" PRIu32 "", updateType);
|
||||||
ret = CHANNEL_RC_OK;
|
ret = CHANNEL_RC_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -313,101 +316,6 @@ static UINT geometry_on_close(IWTSVirtualChannelCallback* pChannelCallback)
|
|||||||
return CHANNEL_RC_OK;
|
return CHANNEL_RC_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Function description
|
|
||||||
*
|
|
||||||
* @return 0 on success, otherwise a Win32 error code
|
|
||||||
*/
|
|
||||||
static UINT geometry_on_new_channel_connection(IWTSListenerCallback* pListenerCallback,
|
|
||||||
IWTSVirtualChannel* pChannel, BYTE* Data,
|
|
||||||
BOOL* pbAccept,
|
|
||||||
IWTSVirtualChannelCallback** ppCallback)
|
|
||||||
{
|
|
||||||
GENERIC_CHANNEL_CALLBACK* callback;
|
|
||||||
GENERIC_LISTENER_CALLBACK* listener_callback = (GENERIC_LISTENER_CALLBACK*)pListenerCallback;
|
|
||||||
|
|
||||||
WINPR_UNUSED(Data);
|
|
||||||
WINPR_UNUSED(pbAccept);
|
|
||||||
|
|
||||||
callback = (GENERIC_CHANNEL_CALLBACK*)calloc(1, sizeof(GENERIC_CHANNEL_CALLBACK));
|
|
||||||
|
|
||||||
if (!callback)
|
|
||||||
{
|
|
||||||
WLog_ERR(TAG, "calloc failed!");
|
|
||||||
return CHANNEL_RC_NO_MEMORY;
|
|
||||||
}
|
|
||||||
|
|
||||||
callback->iface.OnDataReceived = geometry_on_data_received;
|
|
||||||
callback->iface.OnClose = geometry_on_close;
|
|
||||||
callback->plugin = listener_callback->plugin;
|
|
||||||
callback->channel_mgr = listener_callback->channel_mgr;
|
|
||||||
callback->channel = pChannel;
|
|
||||||
listener_callback->channel_callback = callback;
|
|
||||||
*ppCallback = (IWTSVirtualChannelCallback*)callback;
|
|
||||||
return CHANNEL_RC_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Function description
|
|
||||||
*
|
|
||||||
* @return 0 on success, otherwise a Win32 error code
|
|
||||||
*/
|
|
||||||
static UINT geometry_plugin_initialize(IWTSPlugin* pPlugin, IWTSVirtualChannelManager* pChannelMgr)
|
|
||||||
{
|
|
||||||
UINT status;
|
|
||||||
GEOMETRY_PLUGIN* geometry = (GEOMETRY_PLUGIN*)pPlugin;
|
|
||||||
if (geometry->initialized)
|
|
||||||
{
|
|
||||||
WLog_ERR(TAG, "[%s] channel initialized twice, aborting", GEOMETRY_DVC_CHANNEL_NAME);
|
|
||||||
return ERROR_INVALID_DATA;
|
|
||||||
}
|
|
||||||
geometry->listener_callback =
|
|
||||||
(GENERIC_LISTENER_CALLBACK*)calloc(1, sizeof(GENERIC_LISTENER_CALLBACK));
|
|
||||||
|
|
||||||
if (!geometry->listener_callback)
|
|
||||||
{
|
|
||||||
WLog_ERR(TAG, "calloc failed!");
|
|
||||||
return CHANNEL_RC_NO_MEMORY;
|
|
||||||
}
|
|
||||||
|
|
||||||
geometry->listener_callback->iface.OnNewChannelConnection = geometry_on_new_channel_connection;
|
|
||||||
geometry->listener_callback->plugin = pPlugin;
|
|
||||||
geometry->listener_callback->channel_mgr = pChannelMgr;
|
|
||||||
status =
|
|
||||||
pChannelMgr->CreateListener(pChannelMgr, GEOMETRY_DVC_CHANNEL_NAME, 0,
|
|
||||||
&geometry->listener_callback->iface, &(geometry->listener));
|
|
||||||
geometry->listener->pInterface = geometry->iface.pInterface;
|
|
||||||
|
|
||||||
geometry->initialized = status == CHANNEL_RC_OK;
|
|
||||||
return status;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Function description
|
|
||||||
*
|
|
||||||
* @return 0 on success, otherwise a Win32 error code
|
|
||||||
*/
|
|
||||||
static UINT geometry_plugin_terminated(IWTSPlugin* pPlugin)
|
|
||||||
{
|
|
||||||
GEOMETRY_PLUGIN* geometry = (GEOMETRY_PLUGIN*)pPlugin;
|
|
||||||
GeometryClientContext* context = (GeometryClientContext*)geometry->iface.pInterface;
|
|
||||||
|
|
||||||
if (geometry && geometry->listener_callback)
|
|
||||||
{
|
|
||||||
IWTSVirtualChannelManager* mgr = geometry->listener_callback->channel_mgr;
|
|
||||||
if (mgr)
|
|
||||||
IFCALL(mgr->DestroyListener, mgr, geometry->listener);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (context)
|
|
||||||
HashTable_Free(context->geometries);
|
|
||||||
|
|
||||||
free(geometry->listener_callback);
|
|
||||||
free(geometry->iface.pInterface);
|
|
||||||
free(pPlugin);
|
|
||||||
return CHANNEL_RC_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void mappedGeometryUnref_void(void* arg)
|
static void mappedGeometryUnref_void(void* arg)
|
||||||
{
|
{
|
||||||
MAPPED_GEOMETRY* g = (MAPPED_GEOMETRY*)arg;
|
MAPPED_GEOMETRY* g = (MAPPED_GEOMETRY*)arg;
|
||||||
@ -418,6 +326,59 @@ static void mappedGeometryUnref_void(void* arg)
|
|||||||
* Channel Client Interface
|
* Channel Client Interface
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
static const IWTSVirtualChannelCallback geometry_callbacks = { geometry_on_data_received,
|
||||||
|
NULL, /* Open */
|
||||||
|
geometry_on_close };
|
||||||
|
|
||||||
|
static UINT init_plugin_cb(GENERIC_DYNVC_PLUGIN* base, rdpContext* rcontext, rdpSettings* settings)
|
||||||
|
{
|
||||||
|
GeometryClientContext* context;
|
||||||
|
GEOMETRY_PLUGIN* geometry = (GEOMETRY_PLUGIN*)base;
|
||||||
|
|
||||||
|
WINPR_ASSERT(base);
|
||||||
|
WINPR_UNUSED(settings);
|
||||||
|
|
||||||
|
context = (GeometryClientContext*)calloc(1, sizeof(GeometryClientContext));
|
||||||
|
if (!context)
|
||||||
|
{
|
||||||
|
WLog_Print(base->log, WLOG_ERROR, "calloc failed!");
|
||||||
|
return CHANNEL_RC_NO_MEMORY;
|
||||||
|
}
|
||||||
|
|
||||||
|
context->geometries = HashTable_New(FALSE);
|
||||||
|
if (!context->geometries)
|
||||||
|
{
|
||||||
|
WLog_Print(base->log, WLOG_ERROR, "unable to allocate geometries");
|
||||||
|
free(context);
|
||||||
|
return CHANNEL_RC_NO_MEMORY;
|
||||||
|
}
|
||||||
|
|
||||||
|
HashTable_SetHashFunction(context->geometries, mappedGeometryHash);
|
||||||
|
{
|
||||||
|
wObject* obj = HashTable_KeyObject(context->geometries);
|
||||||
|
obj->fnObjectEquals = mappedGeometryKeyCompare;
|
||||||
|
}
|
||||||
|
{
|
||||||
|
wObject* obj = HashTable_ValueObject(context->geometries);
|
||||||
|
obj->fnObjectFree = mappedGeometryUnref_void;
|
||||||
|
}
|
||||||
|
context->handle = (void*)geometry;
|
||||||
|
|
||||||
|
geometry->context = context;
|
||||||
|
geometry->base.iface.pInterface = (void*)context;
|
||||||
|
|
||||||
|
return CHANNEL_RC_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void terminate_plugin_cb(GENERIC_DYNVC_PLUGIN* base)
|
||||||
|
{
|
||||||
|
GEOMETRY_PLUGIN* geometry = (GEOMETRY_PLUGIN*)base;
|
||||||
|
|
||||||
|
if (geometry->context)
|
||||||
|
HashTable_Free(geometry->context->geometries);
|
||||||
|
free(geometry->context);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Function description
|
* Function description
|
||||||
*
|
*
|
||||||
@ -425,58 +386,7 @@ static void mappedGeometryUnref_void(void* arg)
|
|||||||
*/
|
*/
|
||||||
UINT geometry_DVCPluginEntry(IDRDYNVC_ENTRY_POINTS* pEntryPoints)
|
UINT geometry_DVCPluginEntry(IDRDYNVC_ENTRY_POINTS* pEntryPoints)
|
||||||
{
|
{
|
||||||
UINT error = CHANNEL_RC_OK;
|
return freerdp_generic_DVCPluginEntry(pEntryPoints, TAG, GEOMETRY_DVC_CHANNEL_NAME,
|
||||||
GEOMETRY_PLUGIN* geometry;
|
sizeof(GEOMETRY_PLUGIN), sizeof(GENERIC_CHANNEL_CALLBACK),
|
||||||
GeometryClientContext* context;
|
&geometry_callbacks, init_plugin_cb, terminate_plugin_cb);
|
||||||
geometry = (GEOMETRY_PLUGIN*)pEntryPoints->GetPlugin(pEntryPoints, "geometry");
|
|
||||||
|
|
||||||
if (!geometry)
|
|
||||||
{
|
|
||||||
geometry = (GEOMETRY_PLUGIN*)calloc(1, sizeof(GEOMETRY_PLUGIN));
|
|
||||||
|
|
||||||
if (!geometry)
|
|
||||||
{
|
|
||||||
WLog_ERR(TAG, "calloc failed!");
|
|
||||||
return CHANNEL_RC_NO_MEMORY;
|
|
||||||
}
|
|
||||||
|
|
||||||
geometry->iface.Initialize = geometry_plugin_initialize;
|
|
||||||
geometry->iface.Connected = NULL;
|
|
||||||
geometry->iface.Disconnected = NULL;
|
|
||||||
geometry->iface.Terminated = geometry_plugin_terminated;
|
|
||||||
context = (GeometryClientContext*)calloc(1, sizeof(GeometryClientContext));
|
|
||||||
|
|
||||||
if (!context)
|
|
||||||
{
|
|
||||||
WLog_ERR(TAG, "calloc failed!");
|
|
||||||
goto error_context;
|
|
||||||
}
|
|
||||||
|
|
||||||
context->geometries = HashTable_New(FALSE);
|
|
||||||
HashTable_SetHashFunction(context->geometries, mappedGeometryHash);
|
|
||||||
{
|
|
||||||
wObject* obj = HashTable_KeyObject(context->geometries);
|
|
||||||
obj->fnObjectEquals = mappedGeometryKeyCompare;
|
|
||||||
}
|
|
||||||
{
|
|
||||||
wObject* obj = HashTable_ValueObject(context->geometries);
|
|
||||||
obj->fnObjectFree = mappedGeometryUnref_void;
|
|
||||||
}
|
|
||||||
|
|
||||||
context->handle = (void*)geometry;
|
|
||||||
geometry->iface.pInterface = (void*)context;
|
|
||||||
geometry->context = context;
|
|
||||||
error = pEntryPoints->RegisterPlugin(pEntryPoints, "geometry", &geometry->iface);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
WLog_ERR(TAG, "could not get geometry Plugin.");
|
|
||||||
return CHANNEL_RC_BAD_CHANNEL;
|
|
||||||
}
|
|
||||||
|
|
||||||
return error;
|
|
||||||
|
|
||||||
error_context:
|
|
||||||
free(geometry);
|
|
||||||
return CHANNEL_RC_NO_MEMORY;
|
|
||||||
}
|
}
|
||||||
|
@ -66,10 +66,7 @@
|
|||||||
|
|
||||||
typedef struct
|
typedef struct
|
||||||
{
|
{
|
||||||
IWTSPlugin iface;
|
GENERIC_DYNVC_PLUGIN base;
|
||||||
|
|
||||||
IWTSListener* listener;
|
|
||||||
GENERIC_LISTENER_CALLBACK* listener_callback;
|
|
||||||
|
|
||||||
RdpeiClientContext* context;
|
RdpeiClientContext* context;
|
||||||
|
|
||||||
@ -87,7 +84,6 @@ typedef struct
|
|||||||
|
|
||||||
CRITICAL_SECTION lock;
|
CRITICAL_SECTION lock;
|
||||||
rdpContext* rdpcontext;
|
rdpContext* rdpcontext;
|
||||||
BOOL initialized;
|
|
||||||
HANDLE thread;
|
HANDLE thread;
|
||||||
HANDLE event;
|
HANDLE event;
|
||||||
} RDPEI_PLUGIN;
|
} RDPEI_PLUGIN;
|
||||||
@ -343,14 +339,14 @@ static UINT rdpei_send_pen_frame(RdpeiClientContext* context, RDPINPUT_PEN_FRAME
|
|||||||
if (!context)
|
if (!context)
|
||||||
return ERROR_INTERNAL_ERROR;
|
return ERROR_INTERNAL_ERROR;
|
||||||
rdpei = (RDPEI_PLUGIN*)context->handle;
|
rdpei = (RDPEI_PLUGIN*)context->handle;
|
||||||
if (!rdpei || !rdpei->listener_callback)
|
if (!rdpei || !rdpei->base.listener_callback)
|
||||||
return ERROR_INTERNAL_ERROR;
|
return ERROR_INTERNAL_ERROR;
|
||||||
if (!rdpei || !rdpei->rdpcontext)
|
if (!rdpei || !rdpei->rdpcontext)
|
||||||
return ERROR_INTERNAL_ERROR;
|
return ERROR_INTERNAL_ERROR;
|
||||||
if (freerdp_settings_get_bool(rdpei->rdpcontext->settings, FreeRDP_SuspendInput))
|
if (freerdp_settings_get_bool(rdpei->rdpcontext->settings, FreeRDP_SuspendInput))
|
||||||
return CHANNEL_RC_OK;
|
return CHANNEL_RC_OK;
|
||||||
|
|
||||||
callback = rdpei->listener_callback->channel_callback;
|
callback = rdpei->base.listener_callback->channel_callback;
|
||||||
/* Just ignore the event if the channel is not connected */
|
/* Just ignore the event if the channel is not connected */
|
||||||
if (!callback)
|
if (!callback)
|
||||||
return CHANNEL_RC_OK;
|
return CHANNEL_RC_OK;
|
||||||
@ -444,7 +440,7 @@ static DWORD WINAPI rdpei_periodic_update(LPVOID arg)
|
|||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
context = (RdpeiClientContext*)rdpei->iface.pInterface;
|
context = rdpei->context;
|
||||||
|
|
||||||
if (!context)
|
if (!context)
|
||||||
{
|
{
|
||||||
@ -452,7 +448,7 @@ static DWORD WINAPI rdpei_periodic_update(LPVOID arg)
|
|||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
while (rdpei->initialized)
|
while (rdpei->base.initialized)
|
||||||
{
|
{
|
||||||
status = WaitForSingleObject(rdpei->event, 20);
|
status = WaitForSingleObject(rdpei->event, 20);
|
||||||
|
|
||||||
@ -794,8 +790,10 @@ static UINT rdpei_recv_pdu(GENERIC_CHANNEL_CALLBACK* callback, wStream* s)
|
|||||||
UINT16 eventId;
|
UINT16 eventId;
|
||||||
UINT32 pduLength;
|
UINT32 pduLength;
|
||||||
UINT error;
|
UINT error;
|
||||||
|
|
||||||
if (!s)
|
if (!s)
|
||||||
return ERROR_INTERNAL_ERROR;
|
return ERROR_INTERNAL_ERROR;
|
||||||
|
|
||||||
if (!Stream_CheckAndLogRequiredLength(TAG, s, 6))
|
if (!Stream_CheckAndLogRequiredLength(TAG, s, 6))
|
||||||
return ERROR_INVALID_DATA;
|
return ERROR_INVALID_DATA;
|
||||||
|
|
||||||
@ -870,142 +868,16 @@ static UINT rdpei_on_close(IWTSVirtualChannelCallback* pChannelCallback)
|
|||||||
if (callback)
|
if (callback)
|
||||||
{
|
{
|
||||||
RDPEI_PLUGIN* rdpei = (RDPEI_PLUGIN*)callback->plugin;
|
RDPEI_PLUGIN* rdpei = (RDPEI_PLUGIN*)callback->plugin;
|
||||||
if (rdpei && rdpei->listener_callback)
|
if (rdpei && rdpei->base.listener_callback)
|
||||||
{
|
{
|
||||||
if (rdpei->listener_callback->channel_callback == callback)
|
if (rdpei->base.listener_callback->channel_callback == callback)
|
||||||
rdpei->listener_callback->channel_callback = NULL;
|
rdpei->base.listener_callback->channel_callback = NULL;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
free(callback);
|
free(callback);
|
||||||
return CHANNEL_RC_OK;
|
return CHANNEL_RC_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Function description
|
|
||||||
*
|
|
||||||
* @return 0 on success, otherwise a Win32 error code
|
|
||||||
*/
|
|
||||||
static UINT rdpei_on_new_channel_connection(IWTSListenerCallback* pListenerCallback,
|
|
||||||
IWTSVirtualChannel* pChannel, BYTE* Data,
|
|
||||||
BOOL* pbAccept, IWTSVirtualChannelCallback** ppCallback)
|
|
||||||
{
|
|
||||||
GENERIC_CHANNEL_CALLBACK* callback;
|
|
||||||
GENERIC_LISTENER_CALLBACK* listener_callback = (GENERIC_LISTENER_CALLBACK*)pListenerCallback;
|
|
||||||
if (!listener_callback)
|
|
||||||
return ERROR_INTERNAL_ERROR;
|
|
||||||
callback = (GENERIC_CHANNEL_CALLBACK*)calloc(1, sizeof(GENERIC_CHANNEL_CALLBACK));
|
|
||||||
|
|
||||||
WINPR_UNUSED(Data);
|
|
||||||
WINPR_UNUSED(pbAccept);
|
|
||||||
|
|
||||||
if (!callback)
|
|
||||||
{
|
|
||||||
WLog_ERR(TAG, "calloc failed!");
|
|
||||||
return CHANNEL_RC_NO_MEMORY;
|
|
||||||
}
|
|
||||||
|
|
||||||
callback->iface.OnDataReceived = rdpei_on_data_received;
|
|
||||||
callback->iface.OnClose = rdpei_on_close;
|
|
||||||
callback->plugin = listener_callback->plugin;
|
|
||||||
callback->channel_mgr = listener_callback->channel_mgr;
|
|
||||||
callback->channel = pChannel;
|
|
||||||
listener_callback->channel_callback = callback;
|
|
||||||
*ppCallback = (IWTSVirtualChannelCallback*)callback;
|
|
||||||
return CHANNEL_RC_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Function description
|
|
||||||
*
|
|
||||||
* @return 0 on success, otherwise a Win32 error code
|
|
||||||
*/
|
|
||||||
static UINT rdpei_plugin_terminated(IWTSPlugin* pPlugin)
|
|
||||||
{
|
|
||||||
RDPEI_PLUGIN* rdpei = (RDPEI_PLUGIN*)pPlugin;
|
|
||||||
|
|
||||||
if (!pPlugin)
|
|
||||||
return ERROR_INVALID_PARAMETER;
|
|
||||||
|
|
||||||
if (rdpei)
|
|
||||||
{
|
|
||||||
IWTSVirtualChannelManager* mgr = NULL;
|
|
||||||
|
|
||||||
rdpei->initialized = FALSE;
|
|
||||||
if (rdpei->event)
|
|
||||||
SetEvent(rdpei->event);
|
|
||||||
|
|
||||||
if (rdpei->thread)
|
|
||||||
{
|
|
||||||
WaitForSingleObject(rdpei->thread, INFINITE);
|
|
||||||
CloseHandle(rdpei->thread);
|
|
||||||
}
|
|
||||||
if (rdpei->event)
|
|
||||||
CloseHandle(rdpei->event);
|
|
||||||
|
|
||||||
if (rdpei->listener_callback)
|
|
||||||
mgr = rdpei->listener_callback->channel_mgr;
|
|
||||||
|
|
||||||
if (mgr)
|
|
||||||
IFCALL(mgr->DestroyListener, mgr, rdpei->listener);
|
|
||||||
}
|
|
||||||
DeleteCriticalSection(&rdpei->lock);
|
|
||||||
free(rdpei->listener_callback);
|
|
||||||
free(rdpei->context);
|
|
||||||
free(rdpei);
|
|
||||||
return CHANNEL_RC_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Function description
|
|
||||||
*
|
|
||||||
* @return 0 on success, otherwise a Win32 error code
|
|
||||||
*/
|
|
||||||
static UINT rdpei_plugin_initialize(IWTSPlugin* pPlugin, IWTSVirtualChannelManager* pChannelMgr)
|
|
||||||
{
|
|
||||||
UINT error;
|
|
||||||
RDPEI_PLUGIN* rdpei = (RDPEI_PLUGIN*)pPlugin;
|
|
||||||
|
|
||||||
if (rdpei->initialized)
|
|
||||||
{
|
|
||||||
WLog_ERR(TAG, "[%s] channel initialized twice, aborting", RDPEI_DVC_CHANNEL_NAME);
|
|
||||||
return ERROR_INVALID_DATA;
|
|
||||||
}
|
|
||||||
rdpei->listener_callback =
|
|
||||||
(GENERIC_LISTENER_CALLBACK*)calloc(1, sizeof(GENERIC_LISTENER_CALLBACK));
|
|
||||||
|
|
||||||
if (!rdpei->listener_callback)
|
|
||||||
{
|
|
||||||
WLog_ERR(TAG, "calloc failed!");
|
|
||||||
return CHANNEL_RC_NO_MEMORY;
|
|
||||||
}
|
|
||||||
|
|
||||||
rdpei->listener_callback->iface.OnNewChannelConnection = rdpei_on_new_channel_connection;
|
|
||||||
rdpei->listener_callback->plugin = pPlugin;
|
|
||||||
rdpei->listener_callback->channel_mgr = pChannelMgr;
|
|
||||||
|
|
||||||
if ((error = pChannelMgr->CreateListener(pChannelMgr, RDPEI_DVC_CHANNEL_NAME, 0,
|
|
||||||
&rdpei->listener_callback->iface, &(rdpei->listener))))
|
|
||||||
{
|
|
||||||
WLog_ERR(TAG, "ChannelMgr->CreateListener failed with error %" PRIu32 "!", error);
|
|
||||||
goto error_out;
|
|
||||||
}
|
|
||||||
|
|
||||||
rdpei->listener->pInterface = rdpei->iface.pInterface;
|
|
||||||
|
|
||||||
InitializeCriticalSection(&rdpei->lock);
|
|
||||||
rdpei->event = CreateEventA(NULL, TRUE, FALSE, NULL);
|
|
||||||
if (!rdpei->event)
|
|
||||||
goto error_out;
|
|
||||||
rdpei->thread = CreateThread(NULL, 0, rdpei_periodic_update, rdpei, 0, NULL);
|
|
||||||
if (!rdpei->thread)
|
|
||||||
goto error_out;
|
|
||||||
rdpei->initialized = TRUE;
|
|
||||||
return error;
|
|
||||||
error_out:
|
|
||||||
rdpei_plugin_terminated(pPlugin);
|
|
||||||
return error;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Channel Client Interface
|
* Channel Client Interface
|
||||||
*/
|
*/
|
||||||
@ -1040,7 +912,7 @@ UINT rdpei_send_frame(RdpeiClientContext* context, RDPINPUT_TOUCH_FRAME* frame)
|
|||||||
GENERIC_CHANNEL_CALLBACK* callback;
|
GENERIC_CHANNEL_CALLBACK* callback;
|
||||||
UINT error;
|
UINT error;
|
||||||
|
|
||||||
callback = rdpei->listener_callback->channel_callback;
|
callback = rdpei->base.listener_callback->channel_callback;
|
||||||
|
|
||||||
/* Just ignore the event if the channel is not connected */
|
/* Just ignore the event if the channel is not connected */
|
||||||
if (!callback)
|
if (!callback)
|
||||||
@ -1437,6 +1309,91 @@ static UINT rdpei_pen_raw_event(RdpeiClientContext* context, INT32 externalId, U
|
|||||||
return error;
|
return error;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static UINT init_plugin_cb(GENERIC_DYNVC_PLUGIN* base, rdpContext* rcontext, rdpSettings* settings)
|
||||||
|
{
|
||||||
|
RdpeiClientContext* context;
|
||||||
|
RDPEI_PLUGIN* rdpei = (RDPEI_PLUGIN*)base;
|
||||||
|
|
||||||
|
WINPR_ASSERT(base);
|
||||||
|
WINPR_UNUSED(settings);
|
||||||
|
|
||||||
|
rdpei->version = RDPINPUT_PROTOCOL_V300;
|
||||||
|
rdpei->currentFrameTime = 0;
|
||||||
|
rdpei->previousFrameTime = 0;
|
||||||
|
rdpei->maxTouchContacts = MAX_CONTACTS;
|
||||||
|
rdpei->maxPenContacts = MAX_PEN_CONTACTS;
|
||||||
|
rdpei->rdpcontext = rcontext;
|
||||||
|
|
||||||
|
InitializeCriticalSection(&rdpei->lock);
|
||||||
|
rdpei->event = CreateEventA(NULL, TRUE, FALSE, NULL);
|
||||||
|
if (!rdpei->event)
|
||||||
|
{
|
||||||
|
WLog_ERR(TAG, "calloc failed!");
|
||||||
|
return CHANNEL_RC_NO_MEMORY;
|
||||||
|
}
|
||||||
|
|
||||||
|
context = (RdpeiClientContext*)calloc(1, sizeof(*context));
|
||||||
|
if (!context)
|
||||||
|
{
|
||||||
|
WLog_ERR(TAG, "calloc failed!");
|
||||||
|
return CHANNEL_RC_NO_MEMORY;
|
||||||
|
}
|
||||||
|
|
||||||
|
context->clientFeaturesMask = UINT32_MAX;
|
||||||
|
context->handle = (void*)rdpei;
|
||||||
|
context->GetVersion = rdpei_get_version;
|
||||||
|
context->GetFeatures = rdpei_get_features;
|
||||||
|
context->AddContact = rdpei_add_contact;
|
||||||
|
context->TouchBegin = rdpei_touch_begin;
|
||||||
|
context->TouchUpdate = rdpei_touch_update;
|
||||||
|
context->TouchEnd = rdpei_touch_end;
|
||||||
|
context->TouchCancel = rdpei_touch_cancel;
|
||||||
|
context->TouchRawEvent = rdpei_touch_raw_event;
|
||||||
|
context->AddPen = rdpei_add_pen;
|
||||||
|
context->PenBegin = rdpei_pen_begin;
|
||||||
|
context->PenUpdate = rdpei_pen_update;
|
||||||
|
context->PenEnd = rdpei_pen_end;
|
||||||
|
context->PenCancel = rdpei_pen_cancel;
|
||||||
|
context->PenRawEvent = rdpei_pen_raw_event;
|
||||||
|
|
||||||
|
rdpei->context = context;
|
||||||
|
rdpei->base.iface.pInterface = (void*)context;
|
||||||
|
|
||||||
|
rdpei->thread = CreateThread(NULL, 0, rdpei_periodic_update, rdpei, 0, NULL);
|
||||||
|
if (!rdpei->thread)
|
||||||
|
{
|
||||||
|
WLog_ERR(TAG, "calloc failed!");
|
||||||
|
return CHANNEL_RC_NO_MEMORY;
|
||||||
|
}
|
||||||
|
|
||||||
|
return CHANNEL_RC_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void terminate_plugin_cb(GENERIC_DYNVC_PLUGIN* base)
|
||||||
|
{
|
||||||
|
RDPEI_PLUGIN* rdpei = (RDPEI_PLUGIN*)base;
|
||||||
|
WINPR_ASSERT(rdpei);
|
||||||
|
|
||||||
|
if (rdpei->event)
|
||||||
|
SetEvent(rdpei->event);
|
||||||
|
|
||||||
|
if (rdpei->thread)
|
||||||
|
{
|
||||||
|
WaitForSingleObject(rdpei->thread, INFINITE);
|
||||||
|
CloseHandle(rdpei->thread);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (rdpei->event)
|
||||||
|
CloseHandle(rdpei->event);
|
||||||
|
|
||||||
|
DeleteCriticalSection(&rdpei->lock);
|
||||||
|
free(rdpei->context);
|
||||||
|
}
|
||||||
|
|
||||||
|
static const IWTSVirtualChannelCallback geometry_callbacks = { rdpei_on_data_received,
|
||||||
|
NULL, /* Open */
|
||||||
|
rdpei_on_close };
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Function description
|
* Function description
|
||||||
*
|
*
|
||||||
@ -1444,71 +1401,7 @@ static UINT rdpei_pen_raw_event(RdpeiClientContext* context, INT32 externalId, U
|
|||||||
*/
|
*/
|
||||||
UINT rdpei_DVCPluginEntry(IDRDYNVC_ENTRY_POINTS* pEntryPoints)
|
UINT rdpei_DVCPluginEntry(IDRDYNVC_ENTRY_POINTS* pEntryPoints)
|
||||||
{
|
{
|
||||||
UINT error;
|
return freerdp_generic_DVCPluginEntry(pEntryPoints, TAG, RDPEI_DVC_CHANNEL_NAME,
|
||||||
RDPEI_PLUGIN* rdpei = NULL;
|
sizeof(RDPEI_PLUGIN), sizeof(GENERIC_CHANNEL_CALLBACK),
|
||||||
RdpeiClientContext* context = NULL;
|
&geometry_callbacks, init_plugin_cb, terminate_plugin_cb);
|
||||||
rdpei = (RDPEI_PLUGIN*)pEntryPoints->GetPlugin(pEntryPoints, "rdpei");
|
|
||||||
|
|
||||||
if (!rdpei)
|
|
||||||
{
|
|
||||||
rdpei = (RDPEI_PLUGIN*)calloc(1, sizeof(RDPEI_PLUGIN));
|
|
||||||
|
|
||||||
if (!rdpei)
|
|
||||||
{
|
|
||||||
WLog_ERR(TAG, "calloc failed!");
|
|
||||||
return CHANNEL_RC_NO_MEMORY;
|
|
||||||
}
|
|
||||||
|
|
||||||
rdpei->iface.Initialize = rdpei_plugin_initialize;
|
|
||||||
rdpei->iface.Connected = NULL;
|
|
||||||
rdpei->iface.Disconnected = NULL;
|
|
||||||
rdpei->iface.Terminated = rdpei_plugin_terminated;
|
|
||||||
rdpei->version = RDPINPUT_PROTOCOL_V300;
|
|
||||||
rdpei->currentFrameTime = 0;
|
|
||||||
rdpei->previousFrameTime = 0;
|
|
||||||
rdpei->maxTouchContacts = MAX_CONTACTS;
|
|
||||||
rdpei->maxPenContacts = MAX_PEN_CONTACTS;
|
|
||||||
rdpei->rdpcontext = pEntryPoints->GetRdpContext(pEntryPoints);
|
|
||||||
|
|
||||||
context = (RdpeiClientContext*)calloc(1, sizeof(RdpeiClientContext));
|
|
||||||
|
|
||||||
if (!context)
|
|
||||||
{
|
|
||||||
WLog_ERR(TAG, "calloc failed!");
|
|
||||||
error = CHANNEL_RC_NO_MEMORY;
|
|
||||||
goto error_out;
|
|
||||||
}
|
|
||||||
|
|
||||||
context->clientFeaturesMask = UINT32_MAX;
|
|
||||||
context->handle = (void*)rdpei;
|
|
||||||
context->GetVersion = rdpei_get_version;
|
|
||||||
context->GetFeatures = rdpei_get_features;
|
|
||||||
context->AddContact = rdpei_add_contact;
|
|
||||||
context->TouchBegin = rdpei_touch_begin;
|
|
||||||
context->TouchUpdate = rdpei_touch_update;
|
|
||||||
context->TouchEnd = rdpei_touch_end;
|
|
||||||
context->TouchCancel = rdpei_touch_cancel;
|
|
||||||
context->TouchRawEvent = rdpei_touch_raw_event;
|
|
||||||
context->AddPen = rdpei_add_pen;
|
|
||||||
context->PenBegin = rdpei_pen_begin;
|
|
||||||
context->PenUpdate = rdpei_pen_update;
|
|
||||||
context->PenEnd = rdpei_pen_end;
|
|
||||||
context->PenCancel = rdpei_pen_cancel;
|
|
||||||
context->PenRawEvent = rdpei_pen_raw_event;
|
|
||||||
|
|
||||||
rdpei->context = context;
|
|
||||||
rdpei->iface.pInterface = (void*)context;
|
|
||||||
|
|
||||||
if ((error = pEntryPoints->RegisterPlugin(pEntryPoints, "rdpei", &rdpei->iface)))
|
|
||||||
{
|
|
||||||
WLog_ERR(TAG, "EntryPoints->RegisterPlugin failed with error %" PRIu32 "!", error);
|
|
||||||
error = CHANNEL_RC_NO_MEMORY;
|
|
||||||
goto error_out;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return CHANNEL_RC_OK;
|
|
||||||
error_out:
|
|
||||||
rdpei_plugin_terminated(&rdpei->iface);
|
|
||||||
return error;
|
|
||||||
}
|
}
|
||||||
|
@ -128,7 +128,7 @@ static UINT rdpgfx_decode_AVC420(RDPGFX_PLUGIN* gfx, RDPGFX_SURFACE_COMMAND* cmd
|
|||||||
UINT error;
|
UINT error;
|
||||||
wStream* s;
|
wStream* s;
|
||||||
RDPGFX_AVC420_BITMAP_STREAM h264;
|
RDPGFX_AVC420_BITMAP_STREAM h264;
|
||||||
RdpgfxClientContext* context = (RdpgfxClientContext*)gfx->iface.pInterface;
|
RdpgfxClientContext* context = gfx->context;
|
||||||
s = Stream_New(cmd->data, cmd->length);
|
s = Stream_New(cmd->data, cmd->length);
|
||||||
|
|
||||||
if (!s)
|
if (!s)
|
||||||
@ -173,7 +173,7 @@ static UINT rdpgfx_decode_AVC444(RDPGFX_PLUGIN* gfx, RDPGFX_SURFACE_COMMAND* cmd
|
|||||||
size_t pos1, pos2;
|
size_t pos1, pos2;
|
||||||
wStream* s;
|
wStream* s;
|
||||||
RDPGFX_AVC444_BITMAP_STREAM h264 = { 0 };
|
RDPGFX_AVC444_BITMAP_STREAM h264 = { 0 };
|
||||||
RdpgfxClientContext* context = (RdpgfxClientContext*)gfx->iface.pInterface;
|
RdpgfxClientContext* context = gfx->context;
|
||||||
s = Stream_New(cmd->data, cmd->length);
|
s = Stream_New(cmd->data, cmd->length);
|
||||||
|
|
||||||
if (!s)
|
if (!s)
|
||||||
@ -259,7 +259,7 @@ fail:
|
|||||||
UINT rdpgfx_decode(RDPGFX_PLUGIN* gfx, RDPGFX_SURFACE_COMMAND* cmd)
|
UINT rdpgfx_decode(RDPGFX_PLUGIN* gfx, RDPGFX_SURFACE_COMMAND* cmd)
|
||||||
{
|
{
|
||||||
UINT error = CHANNEL_RC_OK;
|
UINT error = CHANNEL_RC_OK;
|
||||||
RdpgfxClientContext* context = (RdpgfxClientContext*)gfx->iface.pInterface;
|
RdpgfxClientContext* context = gfx->context;
|
||||||
PROFILER_ENTER(context->SurfaceProfiler)
|
PROFILER_ENTER(context->SurfaceProfiler)
|
||||||
|
|
||||||
switch (cmd->codecId)
|
switch (cmd->codecId)
|
||||||
|
@ -115,10 +115,10 @@ static UINT rdpgfx_send_caps_advertise_pdu(RdpgfxClientContext* context,
|
|||||||
|
|
||||||
gfx = (RDPGFX_PLUGIN*)context->handle;
|
gfx = (RDPGFX_PLUGIN*)context->handle;
|
||||||
|
|
||||||
if (!gfx || !gfx->listener_callback)
|
if (!gfx || !gfx->base.listener_callback)
|
||||||
return ERROR_BAD_ARGUMENTS;
|
return ERROR_BAD_ARGUMENTS;
|
||||||
|
|
||||||
callback = gfx->listener_callback->channel_callback;
|
callback = gfx->base.listener_callback->channel_callback;
|
||||||
|
|
||||||
header.flags = 0;
|
header.flags = 0;
|
||||||
header.cmdId = RDPGFX_CMDID_CAPSADVERTISE;
|
header.cmdId = RDPGFX_CMDID_CAPSADVERTISE;
|
||||||
@ -205,7 +205,7 @@ static UINT rdpgfx_send_supported_caps(GENERIC_CHANNEL_CALLBACK* callback)
|
|||||||
if (!gfx)
|
if (!gfx)
|
||||||
return ERROR_BAD_CONFIGURATION;
|
return ERROR_BAD_CONFIGURATION;
|
||||||
|
|
||||||
context = (RdpgfxClientContext*)gfx->iface.pInterface;
|
context = gfx->context;
|
||||||
|
|
||||||
if (!context)
|
if (!context)
|
||||||
return ERROR_BAD_CONFIGURATION;
|
return ERROR_BAD_CONFIGURATION;
|
||||||
@ -365,8 +365,10 @@ static UINT rdpgfx_recv_caps_confirm_pdu(GENERIC_CHANNEL_CALLBACK* callback, wSt
|
|||||||
RDPGFX_CAPS_CONFIRM_PDU pdu = { 0 };
|
RDPGFX_CAPS_CONFIRM_PDU pdu = { 0 };
|
||||||
WINPR_ASSERT(callback);
|
WINPR_ASSERT(callback);
|
||||||
RDPGFX_PLUGIN* gfx = (RDPGFX_PLUGIN*)callback->plugin;
|
RDPGFX_PLUGIN* gfx = (RDPGFX_PLUGIN*)callback->plugin;
|
||||||
|
|
||||||
WINPR_ASSERT(gfx);
|
WINPR_ASSERT(gfx);
|
||||||
RdpgfxClientContext* context = (RdpgfxClientContext*)gfx->iface.pInterface;
|
RdpgfxClientContext* context = gfx->context;
|
||||||
|
|
||||||
pdu.capsSet = &capsSet;
|
pdu.capsSet = &capsSet;
|
||||||
|
|
||||||
if (!Stream_CheckAndLogRequiredLength(TAG, s, 12))
|
if (!Stream_CheckAndLogRequiredLength(TAG, s, 12))
|
||||||
@ -404,10 +406,10 @@ static UINT rdpgfx_send_frame_acknowledge_pdu(RdpgfxClientContext* context,
|
|||||||
|
|
||||||
gfx = (RDPGFX_PLUGIN*)context->handle;
|
gfx = (RDPGFX_PLUGIN*)context->handle;
|
||||||
|
|
||||||
if (!gfx || !gfx->listener_callback)
|
if (!gfx || !gfx->base.listener_callback)
|
||||||
return ERROR_BAD_CONFIGURATION;
|
return ERROR_BAD_CONFIGURATION;
|
||||||
|
|
||||||
callback = gfx->listener_callback->channel_callback;
|
callback = gfx->base.listener_callback->channel_callback;
|
||||||
|
|
||||||
if (!callback)
|
if (!callback)
|
||||||
return ERROR_BAD_CONFIGURATION;
|
return ERROR_BAD_CONFIGURATION;
|
||||||
@ -460,10 +462,10 @@ static UINT rdpgfx_send_qoe_frame_acknowledge_pdu(RdpgfxClientContext* context,
|
|||||||
|
|
||||||
gfx = (RDPGFX_PLUGIN*)context->handle;
|
gfx = (RDPGFX_PLUGIN*)context->handle;
|
||||||
|
|
||||||
if (!gfx || !gfx->listener_callback)
|
if (!gfx || !gfx->base.listener_callback)
|
||||||
return ERROR_BAD_CONFIGURATION;
|
return ERROR_BAD_CONFIGURATION;
|
||||||
|
|
||||||
callback = gfx->listener_callback->channel_callback;
|
callback = gfx->base.listener_callback->channel_callback;
|
||||||
|
|
||||||
if (!callback)
|
if (!callback)
|
||||||
return ERROR_BAD_CONFIGURATION;
|
return ERROR_BAD_CONFIGURATION;
|
||||||
@ -506,8 +508,10 @@ static UINT rdpgfx_recv_reset_graphics_pdu(GENERIC_CHANNEL_CALLBACK* callback, w
|
|||||||
WINPR_ASSERT(callback);
|
WINPR_ASSERT(callback);
|
||||||
|
|
||||||
RDPGFX_PLUGIN* gfx = (RDPGFX_PLUGIN*)callback->plugin;
|
RDPGFX_PLUGIN* gfx = (RDPGFX_PLUGIN*)callback->plugin;
|
||||||
|
|
||||||
WINPR_ASSERT(gfx);
|
WINPR_ASSERT(gfx);
|
||||||
RdpgfxClientContext* context = (RdpgfxClientContext*)gfx->iface.pInterface;
|
|
||||||
|
RdpgfxClientContext* context = gfx->context;
|
||||||
UINT error = CHANNEL_RC_OK;
|
UINT error = CHANNEL_RC_OK;
|
||||||
GraphicsResetEventArgs graphicsReset = { 0 };
|
GraphicsResetEventArgs graphicsReset = { 0 };
|
||||||
|
|
||||||
@ -592,7 +596,7 @@ static UINT rdpgfx_recv_evict_cache_entry_pdu(GENERIC_CHANNEL_CALLBACK* callback
|
|||||||
WINPR_ASSERT(callback);
|
WINPR_ASSERT(callback);
|
||||||
RDPGFX_PLUGIN* gfx = (RDPGFX_PLUGIN*)callback->plugin;
|
RDPGFX_PLUGIN* gfx = (RDPGFX_PLUGIN*)callback->plugin;
|
||||||
WINPR_ASSERT(gfx);
|
WINPR_ASSERT(gfx);
|
||||||
RdpgfxClientContext* context = (RdpgfxClientContext*)gfx->iface.pInterface;
|
RdpgfxClientContext* context = gfx->context;
|
||||||
UINT error = CHANNEL_RC_OK;
|
UINT error = CHANNEL_RC_OK;
|
||||||
|
|
||||||
if (!Stream_CheckAndLogRequiredLength(TAG, s, 2))
|
if (!Stream_CheckAndLogRequiredLength(TAG, s, 2))
|
||||||
@ -707,7 +711,7 @@ static UINT rdpgfx_save_persistent_cache(RDPGFX_PLUGIN* gfx)
|
|||||||
WINPR_ASSERT(gfx);
|
WINPR_ASSERT(gfx);
|
||||||
WINPR_ASSERT(gfx->rdpcontext);
|
WINPR_ASSERT(gfx->rdpcontext);
|
||||||
rdpSettings* settings = gfx->rdpcontext->settings;
|
rdpSettings* settings = gfx->rdpcontext->settings;
|
||||||
RdpgfxClientContext* context = (RdpgfxClientContext*)gfx->iface.pInterface;
|
RdpgfxClientContext* context = gfx->context;
|
||||||
|
|
||||||
WINPR_ASSERT(context);
|
WINPR_ASSERT(context);
|
||||||
WINPR_ASSERT(settings);
|
WINPR_ASSERT(settings);
|
||||||
@ -774,10 +778,10 @@ static UINT rdpgfx_send_cache_import_offer_pdu(RdpgfxClientContext* context,
|
|||||||
|
|
||||||
gfx = (RDPGFX_PLUGIN*)context->handle;
|
gfx = (RDPGFX_PLUGIN*)context->handle;
|
||||||
|
|
||||||
if (!gfx || !gfx->listener_callback)
|
if (!gfx || !gfx->base.listener_callback)
|
||||||
return ERROR_BAD_CONFIGURATION;
|
return ERROR_BAD_CONFIGURATION;
|
||||||
|
|
||||||
callback = gfx->listener_callback->channel_callback;
|
callback = gfx->base.listener_callback->channel_callback;
|
||||||
|
|
||||||
if (!callback)
|
if (!callback)
|
||||||
return ERROR_BAD_CONFIGURATION;
|
return ERROR_BAD_CONFIGURATION;
|
||||||
@ -839,7 +843,7 @@ static UINT rdpgfx_send_cache_offer(RDPGFX_PLUGIN* gfx)
|
|||||||
WINPR_ASSERT(gfx);
|
WINPR_ASSERT(gfx);
|
||||||
WINPR_ASSERT(gfx->rdpcontext);
|
WINPR_ASSERT(gfx->rdpcontext);
|
||||||
|
|
||||||
RdpgfxClientContext* context = (RdpgfxClientContext*)gfx->iface.pInterface;
|
RdpgfxClientContext* context = gfx->context;
|
||||||
rdpSettings* settings = gfx->rdpcontext->settings;
|
rdpSettings* settings = gfx->rdpcontext->settings;
|
||||||
|
|
||||||
if (!settings->BitmapCachePersistEnabled)
|
if (!settings->BitmapCachePersistEnabled)
|
||||||
@ -923,7 +927,7 @@ static UINT rdpgfx_load_cache_import_reply(RDPGFX_PLUGIN* gfx, RDPGFX_CACHE_IMPO
|
|||||||
WINPR_ASSERT(gfx);
|
WINPR_ASSERT(gfx);
|
||||||
WINPR_ASSERT(gfx->rdpcontext);
|
WINPR_ASSERT(gfx->rdpcontext);
|
||||||
rdpSettings* settings = gfx->rdpcontext->settings;
|
rdpSettings* settings = gfx->rdpcontext->settings;
|
||||||
RdpgfxClientContext* context = (RdpgfxClientContext*)gfx->iface.pInterface;
|
RdpgfxClientContext* context = gfx->context;
|
||||||
|
|
||||||
WINPR_ASSERT(settings);
|
WINPR_ASSERT(settings);
|
||||||
WINPR_ASSERT(reply);
|
WINPR_ASSERT(reply);
|
||||||
@ -990,7 +994,7 @@ static UINT rdpgfx_recv_cache_import_reply_pdu(GENERIC_CHANNEL_CALLBACK* callbac
|
|||||||
WINPR_ASSERT(callback);
|
WINPR_ASSERT(callback);
|
||||||
RDPGFX_PLUGIN* gfx = (RDPGFX_PLUGIN*)callback->plugin;
|
RDPGFX_PLUGIN* gfx = (RDPGFX_PLUGIN*)callback->plugin;
|
||||||
WINPR_ASSERT(gfx);
|
WINPR_ASSERT(gfx);
|
||||||
RdpgfxClientContext* context = (RdpgfxClientContext*)gfx->iface.pInterface;
|
RdpgfxClientContext* context = gfx->context;
|
||||||
UINT error = CHANNEL_RC_OK;
|
UINT error = CHANNEL_RC_OK;
|
||||||
|
|
||||||
if (!Stream_CheckAndLogRequiredLength(TAG, s, 2))
|
if (!Stream_CheckAndLogRequiredLength(TAG, s, 2))
|
||||||
@ -1044,7 +1048,7 @@ static UINT rdpgfx_recv_create_surface_pdu(GENERIC_CHANNEL_CALLBACK* callback, w
|
|||||||
WINPR_ASSERT(callback);
|
WINPR_ASSERT(callback);
|
||||||
RDPGFX_PLUGIN* gfx = (RDPGFX_PLUGIN*)callback->plugin;
|
RDPGFX_PLUGIN* gfx = (RDPGFX_PLUGIN*)callback->plugin;
|
||||||
WINPR_ASSERT(gfx);
|
WINPR_ASSERT(gfx);
|
||||||
RdpgfxClientContext* context = (RdpgfxClientContext*)gfx->iface.pInterface;
|
RdpgfxClientContext* context = gfx->context;
|
||||||
UINT error = CHANNEL_RC_OK;
|
UINT error = CHANNEL_RC_OK;
|
||||||
|
|
||||||
if (!Stream_CheckAndLogRequiredLength(TAG, s, 7))
|
if (!Stream_CheckAndLogRequiredLength(TAG, s, 7))
|
||||||
@ -1082,7 +1086,7 @@ static UINT rdpgfx_recv_delete_surface_pdu(GENERIC_CHANNEL_CALLBACK* callback, w
|
|||||||
WINPR_ASSERT(callback);
|
WINPR_ASSERT(callback);
|
||||||
RDPGFX_PLUGIN* gfx = (RDPGFX_PLUGIN*)callback->plugin;
|
RDPGFX_PLUGIN* gfx = (RDPGFX_PLUGIN*)callback->plugin;
|
||||||
WINPR_ASSERT(gfx);
|
WINPR_ASSERT(gfx);
|
||||||
RdpgfxClientContext* context = (RdpgfxClientContext*)gfx->iface.pInterface;
|
RdpgfxClientContext* context = gfx->context;
|
||||||
UINT error = CHANNEL_RC_OK;
|
UINT error = CHANNEL_RC_OK;
|
||||||
|
|
||||||
if (!Stream_CheckAndLogRequiredLength(TAG, s, 2))
|
if (!Stream_CheckAndLogRequiredLength(TAG, s, 2))
|
||||||
@ -1114,7 +1118,7 @@ static UINT rdpgfx_recv_start_frame_pdu(GENERIC_CHANNEL_CALLBACK* callback, wStr
|
|||||||
WINPR_ASSERT(callback);
|
WINPR_ASSERT(callback);
|
||||||
RDPGFX_PLUGIN* gfx = (RDPGFX_PLUGIN*)callback->plugin;
|
RDPGFX_PLUGIN* gfx = (RDPGFX_PLUGIN*)callback->plugin;
|
||||||
WINPR_ASSERT(gfx);
|
WINPR_ASSERT(gfx);
|
||||||
RdpgfxClientContext* context = (RdpgfxClientContext*)gfx->iface.pInterface;
|
RdpgfxClientContext* context = gfx->context;
|
||||||
UINT error = CHANNEL_RC_OK;
|
UINT error = CHANNEL_RC_OK;
|
||||||
|
|
||||||
if (!Stream_CheckAndLogRequiredLength(TAG, s, RDPGFX_START_FRAME_PDU_SIZE))
|
if (!Stream_CheckAndLogRequiredLength(TAG, s, RDPGFX_START_FRAME_PDU_SIZE))
|
||||||
@ -1151,7 +1155,7 @@ static UINT rdpgfx_recv_end_frame_pdu(GENERIC_CHANNEL_CALLBACK* callback, wStrea
|
|||||||
WINPR_ASSERT(callback);
|
WINPR_ASSERT(callback);
|
||||||
RDPGFX_PLUGIN* gfx = (RDPGFX_PLUGIN*)callback->plugin;
|
RDPGFX_PLUGIN* gfx = (RDPGFX_PLUGIN*)callback->plugin;
|
||||||
WINPR_ASSERT(gfx);
|
WINPR_ASSERT(gfx);
|
||||||
RdpgfxClientContext* context = (RdpgfxClientContext*)gfx->iface.pInterface;
|
RdpgfxClientContext* context = gfx->context;
|
||||||
UINT error = CHANNEL_RC_OK;
|
UINT error = CHANNEL_RC_OK;
|
||||||
|
|
||||||
if (!Stream_CheckAndLogRequiredLength(TAG, s, RDPGFX_END_FRAME_PDU_SIZE))
|
if (!Stream_CheckAndLogRequiredLength(TAG, s, RDPGFX_END_FRAME_PDU_SIZE))
|
||||||
@ -1340,7 +1344,7 @@ static UINT rdpgfx_recv_wire_to_surface_2_pdu(GENERIC_CHANNEL_CALLBACK* callback
|
|||||||
WINPR_ASSERT(callback);
|
WINPR_ASSERT(callback);
|
||||||
RDPGFX_PLUGIN* gfx = (RDPGFX_PLUGIN*)callback->plugin;
|
RDPGFX_PLUGIN* gfx = (RDPGFX_PLUGIN*)callback->plugin;
|
||||||
WINPR_ASSERT(gfx);
|
WINPR_ASSERT(gfx);
|
||||||
RdpgfxClientContext* context = (RdpgfxClientContext*)gfx->iface.pInterface;
|
RdpgfxClientContext* context = gfx->context;
|
||||||
UINT error = CHANNEL_RC_OK;
|
UINT error = CHANNEL_RC_OK;
|
||||||
|
|
||||||
if (!Stream_CheckAndLogRequiredLength(TAG, s, RDPGFX_WIRE_TO_SURFACE_PDU_2_SIZE))
|
if (!Stream_CheckAndLogRequiredLength(TAG, s, RDPGFX_WIRE_TO_SURFACE_PDU_2_SIZE))
|
||||||
@ -1412,7 +1416,7 @@ static UINT rdpgfx_recv_delete_encoding_context_pdu(GENERIC_CHANNEL_CALLBACK* ca
|
|||||||
WINPR_ASSERT(callback);
|
WINPR_ASSERT(callback);
|
||||||
RDPGFX_PLUGIN* gfx = (RDPGFX_PLUGIN*)callback->plugin;
|
RDPGFX_PLUGIN* gfx = (RDPGFX_PLUGIN*)callback->plugin;
|
||||||
WINPR_ASSERT(gfx);
|
WINPR_ASSERT(gfx);
|
||||||
RdpgfxClientContext* context = (RdpgfxClientContext*)gfx->iface.pInterface;
|
RdpgfxClientContext* context = gfx->context;
|
||||||
UINT error = CHANNEL_RC_OK;
|
UINT error = CHANNEL_RC_OK;
|
||||||
|
|
||||||
if (!Stream_CheckAndLogRequiredLength(TAG, s, 6))
|
if (!Stream_CheckAndLogRequiredLength(TAG, s, 6))
|
||||||
@ -1450,7 +1454,7 @@ static UINT rdpgfx_recv_solid_fill_pdu(GENERIC_CHANNEL_CALLBACK* callback, wStre
|
|||||||
WINPR_ASSERT(callback);
|
WINPR_ASSERT(callback);
|
||||||
RDPGFX_PLUGIN* gfx = (RDPGFX_PLUGIN*)callback->plugin;
|
RDPGFX_PLUGIN* gfx = (RDPGFX_PLUGIN*)callback->plugin;
|
||||||
WINPR_ASSERT(gfx);
|
WINPR_ASSERT(gfx);
|
||||||
RdpgfxClientContext* context = (RdpgfxClientContext*)gfx->iface.pInterface;
|
RdpgfxClientContext* context = gfx->context;
|
||||||
UINT error;
|
UINT error;
|
||||||
|
|
||||||
if (!Stream_CheckAndLogRequiredLength(TAG, s, 8))
|
if (!Stream_CheckAndLogRequiredLength(TAG, s, 8))
|
||||||
@ -1519,7 +1523,7 @@ static UINT rdpgfx_recv_surface_to_surface_pdu(GENERIC_CHANNEL_CALLBACK* callbac
|
|||||||
WINPR_ASSERT(callback);
|
WINPR_ASSERT(callback);
|
||||||
RDPGFX_PLUGIN* gfx = (RDPGFX_PLUGIN*)callback->plugin;
|
RDPGFX_PLUGIN* gfx = (RDPGFX_PLUGIN*)callback->plugin;
|
||||||
WINPR_ASSERT(gfx);
|
WINPR_ASSERT(gfx);
|
||||||
RdpgfxClientContext* context = (RdpgfxClientContext*)gfx->iface.pInterface;
|
RdpgfxClientContext* context = gfx->context;
|
||||||
UINT error;
|
UINT error;
|
||||||
|
|
||||||
if (!Stream_CheckAndLogRequiredLength(TAG, s, 14))
|
if (!Stream_CheckAndLogRequiredLength(TAG, s, 14))
|
||||||
@ -1591,8 +1595,9 @@ static UINT rdpgfx_recv_surface_to_cache_pdu(GENERIC_CHANNEL_CALLBACK* callback,
|
|||||||
RDPGFX_SURFACE_TO_CACHE_PDU pdu = { 0 };
|
RDPGFX_SURFACE_TO_CACHE_PDU pdu = { 0 };
|
||||||
WINPR_ASSERT(callback);
|
WINPR_ASSERT(callback);
|
||||||
RDPGFX_PLUGIN* gfx = (RDPGFX_PLUGIN*)callback->plugin;
|
RDPGFX_PLUGIN* gfx = (RDPGFX_PLUGIN*)callback->plugin;
|
||||||
|
|
||||||
WINPR_ASSERT(gfx);
|
WINPR_ASSERT(gfx);
|
||||||
RdpgfxClientContext* context = (RdpgfxClientContext*)gfx->iface.pInterface;
|
RdpgfxClientContext* context = gfx->context;
|
||||||
UINT error;
|
UINT error;
|
||||||
|
|
||||||
if (!Stream_CheckAndLogRequiredLength(TAG, s, 20))
|
if (!Stream_CheckAndLogRequiredLength(TAG, s, 20))
|
||||||
@ -1642,7 +1647,7 @@ static UINT rdpgfx_recv_cache_to_surface_pdu(GENERIC_CHANNEL_CALLBACK* callback,
|
|||||||
RDPGFX_PLUGIN* gfx = (RDPGFX_PLUGIN*)callback->plugin;
|
RDPGFX_PLUGIN* gfx = (RDPGFX_PLUGIN*)callback->plugin;
|
||||||
|
|
||||||
WINPR_ASSERT(gfx);
|
WINPR_ASSERT(gfx);
|
||||||
RdpgfxClientContext* context = (RdpgfxClientContext*)gfx->iface.pInterface;
|
RdpgfxClientContext* context = gfx->context;
|
||||||
UINT error = CHANNEL_RC_OK;
|
UINT error = CHANNEL_RC_OK;
|
||||||
|
|
||||||
if (!Stream_CheckAndLogRequiredLength(TAG, s, 6))
|
if (!Stream_CheckAndLogRequiredLength(TAG, s, 6))
|
||||||
@ -1704,8 +1709,9 @@ static UINT rdpgfx_recv_map_surface_to_output_pdu(GENERIC_CHANNEL_CALLBACK* call
|
|||||||
RDPGFX_MAP_SURFACE_TO_OUTPUT_PDU pdu = { 0 };
|
RDPGFX_MAP_SURFACE_TO_OUTPUT_PDU pdu = { 0 };
|
||||||
WINPR_ASSERT(callback);
|
WINPR_ASSERT(callback);
|
||||||
RDPGFX_PLUGIN* gfx = (RDPGFX_PLUGIN*)callback->plugin;
|
RDPGFX_PLUGIN* gfx = (RDPGFX_PLUGIN*)callback->plugin;
|
||||||
|
|
||||||
WINPR_ASSERT(gfx);
|
WINPR_ASSERT(gfx);
|
||||||
RdpgfxClientContext* context = (RdpgfxClientContext*)gfx->iface.pInterface;
|
RdpgfxClientContext* context = gfx->context;
|
||||||
UINT error = CHANNEL_RC_OK;
|
UINT error = CHANNEL_RC_OK;
|
||||||
|
|
||||||
if (!Stream_CheckAndLogRequiredLength(TAG, s, 12))
|
if (!Stream_CheckAndLogRequiredLength(TAG, s, 12))
|
||||||
@ -1738,8 +1744,9 @@ static UINT rdpgfx_recv_map_surface_to_scaled_output_pdu(GENERIC_CHANNEL_CALLBAC
|
|||||||
RDPGFX_MAP_SURFACE_TO_SCALED_OUTPUT_PDU pdu = { 0 };
|
RDPGFX_MAP_SURFACE_TO_SCALED_OUTPUT_PDU pdu = { 0 };
|
||||||
WINPR_ASSERT(callback);
|
WINPR_ASSERT(callback);
|
||||||
RDPGFX_PLUGIN* gfx = (RDPGFX_PLUGIN*)callback->plugin;
|
RDPGFX_PLUGIN* gfx = (RDPGFX_PLUGIN*)callback->plugin;
|
||||||
|
|
||||||
WINPR_ASSERT(gfx);
|
WINPR_ASSERT(gfx);
|
||||||
RdpgfxClientContext* context = (RdpgfxClientContext*)gfx->iface.pInterface;
|
RdpgfxClientContext* context = gfx->context;
|
||||||
UINT error = CHANNEL_RC_OK;
|
UINT error = CHANNEL_RC_OK;
|
||||||
|
|
||||||
if (!Stream_CheckAndLogRequiredLength(TAG, s, 20))
|
if (!Stream_CheckAndLogRequiredLength(TAG, s, 20))
|
||||||
@ -1779,8 +1786,9 @@ static UINT rdpgfx_recv_map_surface_to_window_pdu(GENERIC_CHANNEL_CALLBACK* call
|
|||||||
RDPGFX_MAP_SURFACE_TO_WINDOW_PDU pdu = { 0 };
|
RDPGFX_MAP_SURFACE_TO_WINDOW_PDU pdu = { 0 };
|
||||||
WINPR_ASSERT(callback);
|
WINPR_ASSERT(callback);
|
||||||
RDPGFX_PLUGIN* gfx = (RDPGFX_PLUGIN*)callback->plugin;
|
RDPGFX_PLUGIN* gfx = (RDPGFX_PLUGIN*)callback->plugin;
|
||||||
|
|
||||||
WINPR_ASSERT(gfx);
|
WINPR_ASSERT(gfx);
|
||||||
RdpgfxClientContext* context = (RdpgfxClientContext*)gfx->iface.pInterface;
|
RdpgfxClientContext* context = gfx->context;
|
||||||
UINT error = CHANNEL_RC_OK;
|
UINT error = CHANNEL_RC_OK;
|
||||||
|
|
||||||
if (!Stream_CheckAndLogRequiredLength(TAG, s, 18))
|
if (!Stream_CheckAndLogRequiredLength(TAG, s, 18))
|
||||||
@ -1814,7 +1822,7 @@ static UINT rdpgfx_recv_map_surface_to_scaled_window_pdu(GENERIC_CHANNEL_CALLBAC
|
|||||||
WINPR_ASSERT(callback);
|
WINPR_ASSERT(callback);
|
||||||
RDPGFX_PLUGIN* gfx = (RDPGFX_PLUGIN*)callback->plugin;
|
RDPGFX_PLUGIN* gfx = (RDPGFX_PLUGIN*)callback->plugin;
|
||||||
WINPR_ASSERT(gfx);
|
WINPR_ASSERT(gfx);
|
||||||
RdpgfxClientContext* context = (RdpgfxClientContext*)gfx->iface.pInterface;
|
RdpgfxClientContext* context = gfx->context;
|
||||||
UINT error = CHANNEL_RC_OK;
|
UINT error = CHANNEL_RC_OK;
|
||||||
|
|
||||||
if (!Stream_CheckAndLogRequiredLength(TAG, s, 26))
|
if (!Stream_CheckAndLogRequiredLength(TAG, s, 26))
|
||||||
@ -2109,7 +2117,7 @@ static UINT rdpgfx_on_open(IWTSVirtualChannelCallback* pChannelCallback)
|
|||||||
WINPR_ASSERT(callback);
|
WINPR_ASSERT(callback);
|
||||||
RDPGFX_PLUGIN* gfx = (RDPGFX_PLUGIN*)callback->plugin;
|
RDPGFX_PLUGIN* gfx = (RDPGFX_PLUGIN*)callback->plugin;
|
||||||
WINPR_ASSERT(gfx);
|
WINPR_ASSERT(gfx);
|
||||||
RdpgfxClientContext* context = (RdpgfxClientContext*)gfx->iface.pInterface;
|
RdpgfxClientContext* context = gfx->context;
|
||||||
UINT error = CHANNEL_RC_OK;
|
UINT error = CHANNEL_RC_OK;
|
||||||
BOOL do_caps_advertise = TRUE;
|
BOOL do_caps_advertise = TRUE;
|
||||||
gfx->sendFrameAcks = TRUE;
|
gfx->sendFrameAcks = TRUE;
|
||||||
@ -2140,9 +2148,11 @@ static UINT rdpgfx_on_close(IWTSVirtualChannelCallback* pChannelCallback)
|
|||||||
GENERIC_CHANNEL_CALLBACK* callback = (GENERIC_CHANNEL_CALLBACK*)pChannelCallback;
|
GENERIC_CHANNEL_CALLBACK* callback = (GENERIC_CHANNEL_CALLBACK*)pChannelCallback;
|
||||||
WINPR_ASSERT(callback);
|
WINPR_ASSERT(callback);
|
||||||
RDPGFX_PLUGIN* gfx = (RDPGFX_PLUGIN*)callback->plugin;
|
RDPGFX_PLUGIN* gfx = (RDPGFX_PLUGIN*)callback->plugin;
|
||||||
|
|
||||||
if (!gfx)
|
if (!gfx)
|
||||||
goto fail;
|
goto fail;
|
||||||
RdpgfxClientContext* context = (RdpgfxClientContext*)gfx->iface.pInterface;
|
|
||||||
|
RdpgfxClientContext* context = gfx->context;
|
||||||
|
|
||||||
DEBUG_RDPGFX(gfx->log, "OnClose");
|
DEBUG_RDPGFX(gfx->log, "OnClose");
|
||||||
error = rdpgfx_save_persistent_cache(gfx);
|
error = rdpgfx_save_persistent_cache(gfx);
|
||||||
@ -2170,102 +2180,14 @@ fail:
|
|||||||
return CHANNEL_RC_OK;
|
return CHANNEL_RC_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
static void terminate_plugin_cb(GENERIC_DYNVC_PLUGIN* base)
|
||||||
* Function description
|
|
||||||
*
|
|
||||||
* @return 0 on success, otherwise a Win32 error code
|
|
||||||
*/
|
|
||||||
static UINT rdpgfx_on_new_channel_connection(IWTSListenerCallback* pListenerCallback,
|
|
||||||
IWTSVirtualChannel* pChannel, BYTE* Data,
|
|
||||||
BOOL* pbAccept,
|
|
||||||
IWTSVirtualChannelCallback** ppCallback)
|
|
||||||
{
|
{
|
||||||
GENERIC_CHANNEL_CALLBACK* callback;
|
RDPGFX_PLUGIN* gfx = (RDPGFX_PLUGIN*)base;
|
||||||
GENERIC_LISTENER_CALLBACK* listener_callback = (GENERIC_LISTENER_CALLBACK*)pListenerCallback;
|
|
||||||
|
|
||||||
WINPR_ASSERT(listener_callback);
|
|
||||||
WINPR_ASSERT(pChannel);
|
|
||||||
WINPR_ASSERT(ppCallback);
|
|
||||||
|
|
||||||
callback = (GENERIC_CHANNEL_CALLBACK*)calloc(1, sizeof(GENERIC_CHANNEL_CALLBACK));
|
|
||||||
|
|
||||||
if (!callback)
|
|
||||||
{
|
|
||||||
WLog_ERR(TAG, "calloc failed!");
|
|
||||||
return CHANNEL_RC_NO_MEMORY;
|
|
||||||
}
|
|
||||||
|
|
||||||
callback->iface.OnDataReceived = rdpgfx_on_data_received;
|
|
||||||
callback->iface.OnOpen = rdpgfx_on_open;
|
|
||||||
callback->iface.OnClose = rdpgfx_on_close;
|
|
||||||
callback->plugin = listener_callback->plugin;
|
|
||||||
callback->channel_mgr = listener_callback->channel_mgr;
|
|
||||||
callback->channel = pChannel;
|
|
||||||
listener_callback->channel_callback = callback;
|
|
||||||
*ppCallback = &callback->iface;
|
|
||||||
return CHANNEL_RC_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Function description
|
|
||||||
*
|
|
||||||
* @return 0 on success, otherwise a Win32 error code
|
|
||||||
*/
|
|
||||||
static UINT rdpgfx_plugin_initialize(IWTSPlugin* pPlugin, IWTSVirtualChannelManager* pChannelMgr)
|
|
||||||
{
|
|
||||||
UINT error;
|
|
||||||
RDPGFX_PLUGIN* gfx = (RDPGFX_PLUGIN*)pPlugin;
|
|
||||||
|
|
||||||
WINPR_ASSERT(gfx);
|
WINPR_ASSERT(gfx);
|
||||||
WINPR_ASSERT(pChannelMgr);
|
RdpgfxClientContext* context = gfx->context;
|
||||||
|
|
||||||
if (gfx->initialized)
|
|
||||||
{
|
|
||||||
WLog_ERR(TAG, "[%s] channel initialized twice, aborting", RDPGFX_DVC_CHANNEL_NAME);
|
|
||||||
return ERROR_INVALID_DATA;
|
|
||||||
}
|
|
||||||
gfx->listener_callback =
|
|
||||||
(GENERIC_LISTENER_CALLBACK*)calloc(1, sizeof(GENERIC_LISTENER_CALLBACK));
|
|
||||||
|
|
||||||
if (!gfx->listener_callback)
|
|
||||||
{
|
|
||||||
WLog_Print(gfx->log, WLOG_ERROR, "calloc failed!");
|
|
||||||
return CHANNEL_RC_NO_MEMORY;
|
|
||||||
}
|
|
||||||
|
|
||||||
gfx->listener_callback->iface.OnNewChannelConnection = rdpgfx_on_new_channel_connection;
|
|
||||||
gfx->listener_callback->plugin = pPlugin;
|
|
||||||
gfx->listener_callback->channel_mgr = pChannelMgr;
|
|
||||||
|
|
||||||
WINPR_ASSERT(pChannelMgr->CreateListener);
|
|
||||||
error = pChannelMgr->CreateListener(pChannelMgr, RDPGFX_DVC_CHANNEL_NAME, 0,
|
|
||||||
&gfx->listener_callback->iface, &(gfx->listener));
|
|
||||||
gfx->listener->pInterface = gfx->iface.pInterface;
|
|
||||||
DEBUG_RDPGFX(gfx->log, "Initialize");
|
|
||||||
|
|
||||||
gfx->initialized = error == CHANNEL_RC_OK;
|
|
||||||
return error;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Function description
|
|
||||||
*
|
|
||||||
* @return 0 on success, otherwise a Win32 error code
|
|
||||||
*/
|
|
||||||
static UINT rdpgfx_plugin_terminated(IWTSPlugin* pPlugin)
|
|
||||||
{
|
|
||||||
RDPGFX_PLUGIN* gfx = (RDPGFX_PLUGIN*)pPlugin;
|
|
||||||
WINPR_ASSERT(gfx);
|
|
||||||
RdpgfxClientContext* context = (RdpgfxClientContext*)gfx->iface.pInterface;
|
|
||||||
DEBUG_RDPGFX(gfx->log, "Terminated");
|
DEBUG_RDPGFX(gfx->log, "Terminated");
|
||||||
if (gfx && gfx->listener_callback)
|
|
||||||
{
|
|
||||||
IWTSVirtualChannelManager* mgr = gfx->listener_callback->channel_mgr;
|
|
||||||
if (mgr)
|
|
||||||
IFCALL(mgr->DestroyListener, mgr, gfx->listener);
|
|
||||||
}
|
|
||||||
rdpgfx_client_context_free(context);
|
rdpgfx_client_context_free(context);
|
||||||
return CHANNEL_RC_OK;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -2390,49 +2312,41 @@ static void* rdpgfx_get_cache_slot_data(RdpgfxClientContext* context, UINT16 cac
|
|||||||
return pData;
|
return pData;
|
||||||
}
|
}
|
||||||
|
|
||||||
RdpgfxClientContext* rdpgfx_client_context_new(rdpContext* rdpcontext)
|
static UINT init_plugin_cb(GENERIC_DYNVC_PLUGIN* base, rdpContext* rcontext, rdpSettings* settings)
|
||||||
{
|
{
|
||||||
RDPGFX_PLUGIN* gfx;
|
|
||||||
RdpgfxClientContext* context;
|
RdpgfxClientContext* context;
|
||||||
|
RDPGFX_PLUGIN* gfx = (RDPGFX_PLUGIN*)base;
|
||||||
|
|
||||||
WINPR_ASSERT(rdpcontext);
|
WINPR_ASSERT(base);
|
||||||
|
gfx->rdpcontext = rcontext;
|
||||||
|
|
||||||
gfx = (RDPGFX_PLUGIN*)calloc(1, sizeof(RDPGFX_PLUGIN));
|
|
||||||
|
|
||||||
if (!gfx)
|
|
||||||
{
|
|
||||||
WLog_ERR(TAG, "calloc failed!");
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
gfx->log = WLog_Get(TAG);
|
|
||||||
|
|
||||||
if (!gfx->log)
|
|
||||||
{
|
|
||||||
free(gfx);
|
|
||||||
WLog_ERR(TAG, "Failed to acquire reference to WLog %s", TAG);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
gfx->rdpcontext = rdpcontext;
|
|
||||||
gfx->SurfaceTable = HashTable_New(TRUE);
|
gfx->SurfaceTable = HashTable_New(TRUE);
|
||||||
|
|
||||||
if (!gfx->SurfaceTable)
|
if (!gfx->SurfaceTable)
|
||||||
{
|
{
|
||||||
free(gfx);
|
WLog_ERR(TAG, "HashTable_New for surfaces failed !");
|
||||||
WLog_ERR(TAG, "HashTable_New failed!");
|
return CHANNEL_RC_NO_MEMORY;
|
||||||
return NULL;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
gfx->MaxCacheSlots =
|
gfx->MaxCacheSlots =
|
||||||
freerdp_settings_get_bool(gfx->rdpcontext->settings, FreeRDP_GfxSmallCache) ? 4096 : 25600;
|
freerdp_settings_get_bool(gfx->rdpcontext->settings, FreeRDP_GfxSmallCache) ? 4096 : 25600;
|
||||||
context = (RdpgfxClientContext*)calloc(1, sizeof(RdpgfxClientContext));
|
|
||||||
|
|
||||||
|
context = (RdpgfxClientContext*)calloc(1, sizeof(RdpgfxClientContext));
|
||||||
if (!context)
|
if (!context)
|
||||||
{
|
{
|
||||||
free(gfx);
|
WLog_ERR(TAG, "context calloc failed!");
|
||||||
WLog_ERR(TAG, "calloc failed!");
|
HashTable_Free(gfx->SurfaceTable);
|
||||||
return NULL;
|
gfx->SurfaceTable = NULL;
|
||||||
|
return CHANNEL_RC_NO_MEMORY;
|
||||||
|
}
|
||||||
|
|
||||||
|
gfx->zgfx = zgfx_context_new(FALSE);
|
||||||
|
if (!gfx->zgfx)
|
||||||
|
{
|
||||||
|
WLog_ERR(TAG, "zgfx_context_new failed!");
|
||||||
|
HashTable_Free(gfx->SurfaceTable);
|
||||||
|
gfx->SurfaceTable = NULL;
|
||||||
|
free(context);
|
||||||
|
return CHANNEL_RC_NO_MEMORY;
|
||||||
}
|
}
|
||||||
|
|
||||||
context->handle = (void*)gfx;
|
context->handle = (void*)gfx;
|
||||||
@ -2446,18 +2360,9 @@ RdpgfxClientContext* rdpgfx_client_context_new(rdpContext* rdpcontext)
|
|||||||
context->CacheImportOffer = rdpgfx_send_cache_import_offer_pdu;
|
context->CacheImportOffer = rdpgfx_send_cache_import_offer_pdu;
|
||||||
context->QoeFrameAcknowledge = rdpgfx_send_qoe_frame_acknowledge_pdu;
|
context->QoeFrameAcknowledge = rdpgfx_send_qoe_frame_acknowledge_pdu;
|
||||||
|
|
||||||
gfx->iface.pInterface = (void*)context;
|
gfx->base.iface.pInterface = (void*)context;
|
||||||
gfx->zgfx = zgfx_context_new(FALSE);
|
gfx->context = context;
|
||||||
|
return CHANNEL_RC_OK;
|
||||||
if (!gfx->zgfx)
|
|
||||||
{
|
|
||||||
free(gfx);
|
|
||||||
free(context);
|
|
||||||
WLog_ERR(TAG, "zgfx_context_new failed!");
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
return context;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void rdpgfx_client_context_free(RdpgfxClientContext* context)
|
void rdpgfx_client_context_free(RdpgfxClientContext* context)
|
||||||
@ -2473,12 +2378,6 @@ void rdpgfx_client_context_free(RdpgfxClientContext* context)
|
|||||||
free_surfaces(context, gfx->SurfaceTable);
|
free_surfaces(context, gfx->SurfaceTable);
|
||||||
evict_cache_slots(context, gfx->MaxCacheSlots, gfx->CacheSlots);
|
evict_cache_slots(context, gfx->MaxCacheSlots, gfx->CacheSlots);
|
||||||
|
|
||||||
if (gfx->listener_callback)
|
|
||||||
{
|
|
||||||
free(gfx->listener_callback);
|
|
||||||
gfx->listener_callback = NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (gfx->zgfx)
|
if (gfx->zgfx)
|
||||||
{
|
{
|
||||||
zgfx_context_free(gfx->zgfx);
|
zgfx_context_free(gfx->zgfx);
|
||||||
@ -2487,9 +2386,11 @@ void rdpgfx_client_context_free(RdpgfxClientContext* context)
|
|||||||
|
|
||||||
HashTable_Free(gfx->SurfaceTable);
|
HashTable_Free(gfx->SurfaceTable);
|
||||||
free(context);
|
free(context);
|
||||||
free(gfx);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static const IWTSVirtualChannelCallback rdpgfx_callbacks = { rdpgfx_on_data_received,
|
||||||
|
rdpgfx_on_open, rdpgfx_on_close };
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Function description
|
* Function description
|
||||||
*
|
*
|
||||||
@ -2497,36 +2398,7 @@ void rdpgfx_client_context_free(RdpgfxClientContext* context)
|
|||||||
*/
|
*/
|
||||||
UINT rdpgfx_DVCPluginEntry(IDRDYNVC_ENTRY_POINTS* pEntryPoints)
|
UINT rdpgfx_DVCPluginEntry(IDRDYNVC_ENTRY_POINTS* pEntryPoints)
|
||||||
{
|
{
|
||||||
UINT error = CHANNEL_RC_OK;
|
return freerdp_generic_DVCPluginEntry(pEntryPoints, TAG, RDPGFX_DVC_CHANNEL_NAME,
|
||||||
RDPGFX_PLUGIN* gfx;
|
sizeof(RDPGFX_PLUGIN), sizeof(GENERIC_CHANNEL_CALLBACK),
|
||||||
RdpgfxClientContext* context;
|
&rdpgfx_callbacks, init_plugin_cb, terminate_plugin_cb);
|
||||||
|
|
||||||
WINPR_ASSERT(pEntryPoints);
|
|
||||||
WINPR_ASSERT(pEntryPoints->GetPlugin);
|
|
||||||
|
|
||||||
gfx = (RDPGFX_PLUGIN*)pEntryPoints->GetPlugin(pEntryPoints, "rdpgfx");
|
|
||||||
|
|
||||||
if (!gfx)
|
|
||||||
{
|
|
||||||
WINPR_ASSERT(pEntryPoints->GetRdpContext);
|
|
||||||
context = rdpgfx_client_context_new(pEntryPoints->GetRdpContext(pEntryPoints));
|
|
||||||
|
|
||||||
if (!context)
|
|
||||||
{
|
|
||||||
WLog_ERR(TAG, "rdpgfx_client_context_new failed!");
|
|
||||||
return CHANNEL_RC_NO_MEMORY;
|
|
||||||
}
|
|
||||||
|
|
||||||
gfx = (RDPGFX_PLUGIN*)context->handle;
|
|
||||||
|
|
||||||
gfx->iface.Initialize = rdpgfx_plugin_initialize;
|
|
||||||
gfx->iface.Connected = NULL;
|
|
||||||
gfx->iface.Disconnected = NULL;
|
|
||||||
gfx->iface.Terminated = rdpgfx_plugin_terminated;
|
|
||||||
|
|
||||||
WINPR_ASSERT(pEntryPoints->RegisterPlugin);
|
|
||||||
error = pEntryPoints->RegisterPlugin(pEntryPoints, "rdpgfx", &gfx->iface);
|
|
||||||
}
|
|
||||||
|
|
||||||
return error;
|
|
||||||
}
|
}
|
||||||
|
@ -36,10 +36,7 @@
|
|||||||
|
|
||||||
typedef struct
|
typedef struct
|
||||||
{
|
{
|
||||||
IWTSPlugin iface;
|
GENERIC_DYNVC_PLUGIN base;
|
||||||
|
|
||||||
IWTSListener* listener;
|
|
||||||
GENERIC_LISTENER_CALLBACK* listener_callback;
|
|
||||||
|
|
||||||
ZGFX_CONTEXT* zgfx;
|
ZGFX_CONTEXT* zgfx;
|
||||||
UINT32 UnacknowledgedFrames;
|
UINT32 UnacknowledgedFrames;
|
||||||
@ -58,7 +55,7 @@ typedef struct
|
|||||||
|
|
||||||
wLog* log;
|
wLog* log;
|
||||||
RDPGFX_CAPSET ConnectionCaps;
|
RDPGFX_CAPSET ConnectionCaps;
|
||||||
BOOL initialized;
|
RdpgfxClientContext* context;
|
||||||
} RDPGFX_PLUGIN;
|
} RDPGFX_PLUGIN;
|
||||||
|
|
||||||
#endif /* FREERDP_CHANNEL_RDPGFX_CLIENT_MAIN_H */
|
#endif /* FREERDP_CHANNEL_RDPGFX_CLIENT_MAIN_H */
|
||||||
|
@ -41,6 +41,25 @@ typedef struct
|
|||||||
GENERIC_CHANNEL_CALLBACK* channel_callback;
|
GENERIC_CHANNEL_CALLBACK* channel_callback;
|
||||||
} GENERIC_LISTENER_CALLBACK;
|
} GENERIC_LISTENER_CALLBACK;
|
||||||
|
|
||||||
|
typedef struct GENERIC_DYNVC_PLUGIN GENERIC_DYNVC_PLUGIN;
|
||||||
|
typedef UINT (*DYNVC_PLUGIN_INIT_FN)(GENERIC_DYNVC_PLUGIN* plugin, rdpContext* context,
|
||||||
|
rdpSettings* settings);
|
||||||
|
typedef void (*DYNVC_PLUGIN_TERMINATE_FN)(GENERIC_DYNVC_PLUGIN* plugin);
|
||||||
|
|
||||||
|
struct GENERIC_DYNVC_PLUGIN
|
||||||
|
{
|
||||||
|
IWTSPlugin iface;
|
||||||
|
GENERIC_LISTENER_CALLBACK* listener_callback;
|
||||||
|
IWTSListener* listener;
|
||||||
|
BOOL attached;
|
||||||
|
BOOL initialized;
|
||||||
|
wLog* log;
|
||||||
|
char* dynvc_name;
|
||||||
|
size_t channelCallbackSize;
|
||||||
|
const IWTSVirtualChannelCallback* channel_callbacks;
|
||||||
|
DYNVC_PLUGIN_TERMINATE_FN terminatePluginFn;
|
||||||
|
};
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
extern "C"
|
extern "C"
|
||||||
{
|
{
|
||||||
@ -57,6 +76,13 @@ extern "C"
|
|||||||
LPCSTR lpType, DWORD dwFlags);
|
LPCSTR lpType, DWORD dwFlags);
|
||||||
FREERDP_API void freerdp_channels_addin_list_free(FREERDP_ADDIN** ppAddins);
|
FREERDP_API void freerdp_channels_addin_list_free(FREERDP_ADDIN** ppAddins);
|
||||||
|
|
||||||
|
FREERDP_API BOOL freerdp_initialize_generic_dynvc_plugin(GENERIC_DYNVC_PLUGIN* plugin);
|
||||||
|
FREERDP_API UINT freerdp_generic_DVCPluginEntry(
|
||||||
|
IDRDYNVC_ENTRY_POINTS* pEntryPoints, const char* logTag, const char* name,
|
||||||
|
size_t pluginSize, size_t channelCallbackSize,
|
||||||
|
const IWTSVirtualChannelCallback* channel_callbacks, DYNVC_PLUGIN_INIT_FN initPluginFn,
|
||||||
|
DYNVC_PLUGIN_TERMINATE_FN terminatePluginFn);
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
@ -57,6 +57,7 @@ struct s_geometry_client_context
|
|||||||
void* custom;
|
void* custom;
|
||||||
|
|
||||||
pcMappedGeometryAdded MappedGeometryAdded;
|
pcMappedGeometryAdded MappedGeometryAdded;
|
||||||
|
UINT32 remoteVersion;
|
||||||
};
|
};
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
|
Loading…
Reference in New Issue
Block a user