Milestone 5: deliver embedded RDP sessions and lifecycle hardening

This commit is contained in:
Keith Smith
2026-03-03 18:59:26 -07:00
parent 230a401386
commit 36006bd4aa
2941 changed files with 724359 additions and 77 deletions

View File

@@ -0,0 +1,16 @@
include(WarnUnmaintained)
warn_unmaintained("windows shadow server subsystem" "-DWITH_SHADOW_SUBSYSTEM=OFF")
add_compile_definitions(WITH_SHADOW_WIN)
add_library(
freerdp-shadow-subsystem-impl STATIC
win_dxgi.c
win_dxgi.h
win_rdp.c
win_rdp.h
win_shadow.c
win_shadow.h
win_wds.c
win_wds.h
)
target_link_libraries(freerdp-shadow-subsystem-impl PRIVATE freerdp-client freerdp winpr)

View File

@@ -0,0 +1,795 @@
/**
* FreeRDP: A Remote Desktop Protocol Implementation
*
* Copyright 2014 Marc-Andre Moreau <marcandre.moreau@gmail.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 <winpr/crt.h>
#include <winpr/print.h>
#include <winpr/library.h>
#include <freerdp/log.h>
#include "win_dxgi.h"
#define TAG SERVER_TAG("shadow.win")
#ifdef WITH_DXGI_1_2
static D3D_DRIVER_TYPE DriverTypes[] = {
D3D_DRIVER_TYPE_HARDWARE,
D3D_DRIVER_TYPE_WARP,
D3D_DRIVER_TYPE_REFERENCE,
};
static UINT NumDriverTypes = ARRAYSIZE(DriverTypes);
static D3D_FEATURE_LEVEL FeatureLevels[] = { D3D_FEATURE_LEVEL_11_0, D3D_FEATURE_LEVEL_10_1,
D3D_FEATURE_LEVEL_10_0, D3D_FEATURE_LEVEL_9_1 };
static UINT NumFeatureLevels = ARRAYSIZE(FeatureLevels);
static HMODULE d3d11_module = nullptr;
typedef HRESULT(WINAPI* fnD3D11CreateDevice)(IDXGIAdapter* pAdapter, D3D_DRIVER_TYPE DriverType,
HMODULE Software, UINT Flags,
CONST D3D_FEATURE_LEVEL* pFeatureLevels,
UINT FeatureLevels, UINT SDKVersion,
ID3D11Device** ppDevice,
D3D_FEATURE_LEVEL* pFeatureLevel,
ID3D11DeviceContext** ppImmediateContext);
static fnD3D11CreateDevice pfnD3D11CreateDevice = nullptr;
#undef DEFINE_GUID
#define INITGUID
#include <initguid.h>
/* d3d11.h GUIDs */
DEFINE_GUID(IID_ID3D11DeviceChild, 0x1841e5c8, 0x16b0, 0x489b, 0xbc, 0xc8, 0x44, 0xcf, 0xb0, 0xd5,
0xde, 0xae);
DEFINE_GUID(IID_ID3D11DepthStencilState, 0x03823efb, 0x8d8f, 0x4e1c, 0x9a, 0xa2, 0xf6, 0x4b, 0xb2,
0xcb, 0xfd, 0xf1);
DEFINE_GUID(IID_ID3D11BlendState, 0x75b68faa, 0x347d, 0x4159, 0x8f, 0x45, 0xa0, 0x64, 0x0f, 0x01,
0xcd, 0x9a);
DEFINE_GUID(IID_ID3D11RasterizerState, 0x9bb4ab81, 0xab1a, 0x4d8f, 0xb5, 0x06, 0xfc, 0x04, 0x20,
0x0b, 0x6e, 0xe7);
DEFINE_GUID(IID_ID3D11Resource, 0xdc8e63f3, 0xd12b, 0x4952, 0xb4, 0x7b, 0x5e, 0x45, 0x02, 0x6a,
0x86, 0x2d);
DEFINE_GUID(IID_ID3D11Buffer, 0x48570b85, 0xd1ee, 0x4fcd, 0xa2, 0x50, 0xeb, 0x35, 0x07, 0x22, 0xb0,
0x37);
DEFINE_GUID(IID_ID3D11Texture1D, 0xf8fb5c27, 0xc6b3, 0x4f75, 0xa4, 0xc8, 0x43, 0x9a, 0xf2, 0xef,
0x56, 0x4c);
DEFINE_GUID(IID_ID3D11Texture2D, 0x6f15aaf2, 0xd208, 0x4e89, 0x9a, 0xb4, 0x48, 0x95, 0x35, 0xd3,
0x4f, 0x9c);
DEFINE_GUID(IID_ID3D11Texture3D, 0x037e866e, 0xf56d, 0x4357, 0xa8, 0xaf, 0x9d, 0xab, 0xbe, 0x6e,
0x25, 0x0e);
DEFINE_GUID(IID_ID3D11View, 0x839d1216, 0xbb2e, 0x412b, 0xb7, 0xf4, 0xa9, 0xdb, 0xeb, 0xe0, 0x8e,
0xd1);
DEFINE_GUID(IID_ID3D11ShaderResourceView, 0xb0e06fe0, 0x8192, 0x4e1a, 0xb1, 0xca, 0x36, 0xd7, 0x41,
0x47, 0x10, 0xb2);
DEFINE_GUID(IID_ID3D11RenderTargetView, 0xdfdba067, 0x0b8d, 0x4865, 0x87, 0x5b, 0xd7, 0xb4, 0x51,
0x6c, 0xc1, 0x64);
DEFINE_GUID(IID_ID3D11DepthStencilView, 0x9fdac92a, 0x1876, 0x48c3, 0xaf, 0xad, 0x25, 0xb9, 0x4f,
0x84, 0xa9, 0xb6);
DEFINE_GUID(IID_ID3D11UnorderedAccessView, 0x28acf509, 0x7f5c, 0x48f6, 0x86, 0x11, 0xf3, 0x16, 0x01,
0x0a, 0x63, 0x80);
DEFINE_GUID(IID_ID3D11VertexShader, 0x3b301d64, 0xd678, 0x4289, 0x88, 0x97, 0x22, 0xf8, 0x92, 0x8b,
0x72, 0xf3);
DEFINE_GUID(IID_ID3D11HullShader, 0x8e5c6061, 0x628a, 0x4c8e, 0x82, 0x64, 0xbb, 0xe4, 0x5c, 0xb3,
0xd5, 0xdd);
DEFINE_GUID(IID_ID3D11DomainShader, 0xf582c508, 0x0f36, 0x490c, 0x99, 0x77, 0x31, 0xee, 0xce, 0x26,
0x8c, 0xfa);
DEFINE_GUID(IID_ID3D11GeometryShader, 0x38325b96, 0xeffb, 0x4022, 0xba, 0x02, 0x2e, 0x79, 0x5b,
0x70, 0x27, 0x5c);
DEFINE_GUID(IID_ID3D11PixelShader, 0xea82e40d, 0x51dc, 0x4f33, 0x93, 0xd4, 0xdb, 0x7c, 0x91, 0x25,
0xae, 0x8c);
DEFINE_GUID(IID_ID3D11ComputeShader, 0x4f5b196e, 0xc2bd, 0x495e, 0xbd, 0x01, 0x1f, 0xde, 0xd3, 0x8e,
0x49, 0x69);
DEFINE_GUID(IID_ID3D11InputLayout, 0xe4819ddc, 0x4cf0, 0x4025, 0xbd, 0x26, 0x5d, 0xe8, 0x2a, 0x3e,
0x07, 0xb7);
DEFINE_GUID(IID_ID3D11SamplerState, 0xda6fea51, 0x564c, 0x4487, 0x98, 0x10, 0xf0, 0xd0, 0xf9, 0xb4,
0xe3, 0xa5);
DEFINE_GUID(IID_ID3D11Asynchronous, 0x4b35d0cd, 0x1e15, 0x4258, 0x9c, 0x98, 0x1b, 0x13, 0x33, 0xf6,
0xdd, 0x3b);
DEFINE_GUID(IID_ID3D11Query, 0xd6c00747, 0x87b7, 0x425e, 0xb8, 0x4d, 0x44, 0xd1, 0x08, 0x56, 0x0a,
0xfd);
DEFINE_GUID(IID_ID3D11Predicate, 0x9eb576dd, 0x9f77, 0x4d86, 0x81, 0xaa, 0x8b, 0xab, 0x5f, 0xe4,
0x90, 0xe2);
DEFINE_GUID(IID_ID3D11Counter, 0x6e8c49fb, 0xa371, 0x4770, 0xb4, 0x40, 0x29, 0x08, 0x60, 0x22, 0xb7,
0x41);
DEFINE_GUID(IID_ID3D11ClassInstance, 0xa6cd7faa, 0xb0b7, 0x4a2f, 0x94, 0x36, 0x86, 0x62, 0xa6, 0x57,
0x97, 0xcb);
DEFINE_GUID(IID_ID3D11ClassLinkage, 0xddf57cba, 0x9543, 0x46e4, 0xa1, 0x2b, 0xf2, 0x07, 0xa0, 0xfe,
0x7f, 0xed);
DEFINE_GUID(IID_ID3D11CommandList, 0xa24bc4d1, 0x769e, 0x43f7, 0x80, 0x13, 0x98, 0xff, 0x56, 0x6c,
0x18, 0xe2);
DEFINE_GUID(IID_ID3D11DeviceContext, 0xc0bfa96c, 0xe089, 0x44fb, 0x8e, 0xaf, 0x26, 0xf8, 0x79, 0x61,
0x90, 0xda);
DEFINE_GUID(IID_ID3D11VideoDecoder, 0x3C9C5B51, 0x995D, 0x48d1, 0x9B, 0x8D, 0xFA, 0x5C, 0xAE, 0xDE,
0xD6, 0x5C);
DEFINE_GUID(IID_ID3D11VideoProcessorEnumerator, 0x31627037, 0x53AB, 0x4200, 0x90, 0x61, 0x05, 0xFA,
0xA9, 0xAB, 0x45, 0xF9);
DEFINE_GUID(IID_ID3D11VideoProcessor, 0x1D7B0652, 0x185F, 0x41c6, 0x85, 0xCE, 0x0C, 0x5B, 0xE3,
0xD4, 0xAE, 0x6C);
DEFINE_GUID(IID_ID3D11AuthenticatedChannel, 0x3015A308, 0xDCBD, 0x47aa, 0xA7, 0x47, 0x19, 0x24,
0x86, 0xD1, 0x4D, 0x4A);
DEFINE_GUID(IID_ID3D11CryptoSession, 0x9B32F9AD, 0xBDCC, 0x40a6, 0xA3, 0x9D, 0xD5, 0xC8, 0x65, 0x84,
0x57, 0x20);
DEFINE_GUID(IID_ID3D11VideoDecoderOutputView, 0xC2931AEA, 0x2A85, 0x4f20, 0x86, 0x0F, 0xFB, 0xA1,
0xFD, 0x25, 0x6E, 0x18);
DEFINE_GUID(IID_ID3D11VideoProcessorInputView, 0x11EC5A5F, 0x51DC, 0x4945, 0xAB, 0x34, 0x6E, 0x8C,
0x21, 0x30, 0x0E, 0xA5);
DEFINE_GUID(IID_ID3D11VideoProcessorOutputView, 0xA048285E, 0x25A9, 0x4527, 0xBD, 0x93, 0xD6, 0x8B,
0x68, 0xC4, 0x42, 0x54);
DEFINE_GUID(IID_ID3D11VideoContext, 0x61F21C45, 0x3C0E, 0x4a74, 0x9C, 0xEA, 0x67, 0x10, 0x0D, 0x9A,
0xD5, 0xE4);
DEFINE_GUID(IID_ID3D11VideoDevice, 0x10EC4D5B, 0x975A, 0x4689, 0xB9, 0xE4, 0xD0, 0xAA, 0xC3, 0x0F,
0xE3, 0x33);
DEFINE_GUID(IID_ID3D11Device, 0xdb6f6ddb, 0xac77, 0x4e88, 0x82, 0x53, 0x81, 0x9d, 0xf9, 0xbb, 0xf1,
0x40);
/* dxgi.h GUIDs */
DEFINE_GUID(IID_IDXGIObject, 0xaec22fb8, 0x76f3, 0x4639, 0x9b, 0xe0, 0x28, 0xeb, 0x43, 0xa6, 0x7a,
0x2e);
DEFINE_GUID(IID_IDXGIDeviceSubObject, 0x3d3e0379, 0xf9de, 0x4d58, 0xbb, 0x6c, 0x18, 0xd6, 0x29,
0x92, 0xf1, 0xa6);
DEFINE_GUID(IID_IDXGIResource, 0x035f3ab4, 0x482e, 0x4e50, 0xb4, 0x1f, 0x8a, 0x7f, 0x8b, 0xd8, 0x96,
0x0b);
DEFINE_GUID(IID_IDXGIKeyedMutex, 0x9d8e1289, 0xd7b3, 0x465f, 0x81, 0x26, 0x25, 0x0e, 0x34, 0x9a,
0xf8, 0x5d);
DEFINE_GUID(IID_IDXGISurface, 0xcafcb56c, 0x6ac3, 0x4889, 0xbf, 0x47, 0x9e, 0x23, 0xbb, 0xd2, 0x60,
0xec);
DEFINE_GUID(IID_IDXGISurface1, 0x4AE63092, 0x6327, 0x4c1b, 0x80, 0xAE, 0xBF, 0xE1, 0x2E, 0xA3, 0x2B,
0x86);
DEFINE_GUID(IID_IDXGIAdapter, 0x2411e7e1, 0x12ac, 0x4ccf, 0xbd, 0x14, 0x97, 0x98, 0xe8, 0x53, 0x4d,
0xc0);
DEFINE_GUID(IID_IDXGIOutput, 0xae02eedb, 0xc735, 0x4690, 0x8d, 0x52, 0x5a, 0x8d, 0xc2, 0x02, 0x13,
0xaa);
DEFINE_GUID(IID_IDXGISwapChain, 0x310d36a0, 0xd2e7, 0x4c0a, 0xaa, 0x04, 0x6a, 0x9d, 0x23, 0xb8,
0x88, 0x6a);
DEFINE_GUID(IID_IDXGIFactory, 0x7b7166ec, 0x21c7, 0x44ae, 0xb2, 0x1a, 0xc9, 0xae, 0x32, 0x1a, 0xe3,
0x69);
DEFINE_GUID(IID_IDXGIDevice, 0x54ec77fa, 0x1377, 0x44e6, 0x8c, 0x32, 0x88, 0xfd, 0x5f, 0x44, 0xc8,
0x4c);
DEFINE_GUID(IID_IDXGIFactory1, 0x770aae78, 0xf26f, 0x4dba, 0xa8, 0x29, 0x25, 0x3c, 0x83, 0xd1, 0xb3,
0x87);
DEFINE_GUID(IID_IDXGIAdapter1, 0x29038f61, 0x3839, 0x4626, 0x91, 0xfd, 0x08, 0x68, 0x79, 0x01, 0x1a,
0x05);
DEFINE_GUID(IID_IDXGIDevice1, 0x77db970f, 0x6276, 0x48ba, 0xba, 0x28, 0x07, 0x01, 0x43, 0xb4, 0x39,
0x2c);
/* dxgi1_2.h GUIDs */
DEFINE_GUID(IID_IDXGIDisplayControl, 0xea9dbf1a, 0xc88e, 0x4486, 0x85, 0x4a, 0x98, 0xaa, 0x01, 0x38,
0xf3, 0x0c);
DEFINE_GUID(IID_IDXGIOutputDuplication, 0x191cfac3, 0xa341, 0x470d, 0xb2, 0x6e, 0xa8, 0x64, 0xf4,
0x28, 0x31, 0x9c);
DEFINE_GUID(IID_IDXGISurface2, 0xaba496dd, 0xb617, 0x4cb8, 0xa8, 0x66, 0xbc, 0x44, 0xd7, 0xeb, 0x1f,
0xa2);
DEFINE_GUID(IID_IDXGIResource1, 0x30961379, 0x4609, 0x4a41, 0x99, 0x8e, 0x54, 0xfe, 0x56, 0x7e,
0xe0, 0xc1);
DEFINE_GUID(IID_IDXGIDevice2, 0x05008617, 0xfbfd, 0x4051, 0xa7, 0x90, 0x14, 0x48, 0x84, 0xb4, 0xf6,
0xa9);
DEFINE_GUID(IID_IDXGISwapChain1, 0x790a45f7, 0x0d42, 0x4876, 0x98, 0x3a, 0x0a, 0x55, 0xcf, 0xe6,
0xf4, 0xaa);
DEFINE_GUID(IID_IDXGIFactory2, 0x50c83a1c, 0xe072, 0x4c48, 0x87, 0xb0, 0x36, 0x30, 0xfa, 0x36, 0xa6,
0xd0);
DEFINE_GUID(IID_IDXGIAdapter2, 0x0AA1AE0A, 0xFA0E, 0x4B84, 0x86, 0x44, 0xE0, 0x5F, 0xF8, 0xE5, 0xAC,
0xB5);
DEFINE_GUID(IID_IDXGIOutput1, 0x00cddea8, 0x939b, 0x4b83, 0xa3, 0x40, 0xa6, 0x85, 0x22, 0x66, 0x66,
0xcc);
const char* GetDxgiErrorString(HRESULT hr)
{
switch (hr)
{
case DXGI_STATUS_OCCLUDED:
return "DXGI_STATUS_OCCLUDED";
case DXGI_STATUS_CLIPPED:
return "DXGI_STATUS_CLIPPED";
case DXGI_STATUS_NO_REDIRECTION:
return "DXGI_STATUS_NO_REDIRECTION";
case DXGI_STATUS_NO_DESKTOP_ACCESS:
return "DXGI_STATUS_NO_DESKTOP_ACCESS";
case DXGI_STATUS_GRAPHICS_VIDPN_SOURCE_IN_USE:
return "DXGI_STATUS_GRAPHICS_VIDPN_SOURCE_IN_USE";
case DXGI_STATUS_MODE_CHANGED:
return "DXGI_STATUS_MODE_CHANGED";
case DXGI_STATUS_MODE_CHANGE_IN_PROGRESS:
return "DXGI_STATUS_MODE_CHANGE_IN_PROGRESS";
case DXGI_ERROR_INVALID_CALL:
return "DXGI_ERROR_INVALID_CALL";
case DXGI_ERROR_NOT_FOUND:
return "DXGI_ERROR_NOT_FOUND";
case DXGI_ERROR_MORE_DATA:
return "DXGI_ERROR_MORE_DATA";
case DXGI_ERROR_UNSUPPORTED:
return "DXGI_ERROR_UNSUPPORTED";
case DXGI_ERROR_DEVICE_REMOVED:
return "DXGI_ERROR_DEVICE_REMOVED";
case DXGI_ERROR_DEVICE_HUNG:
return "DXGI_ERROR_DEVICE_HUNG";
case DXGI_ERROR_DEVICE_RESET:
return "DXGI_ERROR_DEVICE_RESET";
case DXGI_ERROR_WAS_STILL_DRAWING:
return "DXGI_ERROR_WAS_STILL_DRAWING";
case DXGI_ERROR_FRAME_STATISTICS_DISJOINT:
return "DXGI_ERROR_FRAME_STATISTICS_DISJOINT";
case DXGI_ERROR_GRAPHICS_VIDPN_SOURCE_IN_USE:
return "DXGI_ERROR_GRAPHICS_VIDPN_SOURCE_IN_USE";
case DXGI_ERROR_DRIVER_INTERNAL_ERROR:
return "DXGI_ERROR_DRIVER_INTERNAL_ERROR";
case DXGI_ERROR_NONEXCLUSIVE:
return "DXGI_ERROR_NONEXCLUSIVE";
case DXGI_ERROR_NOT_CURRENTLY_AVAILABLE:
return "DXGI_ERROR_NOT_CURRENTLY_AVAILABLE";
case DXGI_ERROR_REMOTE_CLIENT_DISCONNECTED:
return "DXGI_ERROR_REMOTE_CLIENT_DISCONNECTED";
case DXGI_ERROR_REMOTE_OUTOFMEMORY:
return "DXGI_ERROR_REMOTE_OUTOFMEMORY";
case DXGI_ERROR_ACCESS_LOST:
return "DXGI_ERROR_ACCESS_LOST";
case DXGI_ERROR_WAIT_TIMEOUT:
return "DXGI_ERROR_WAIT_TIMEOUT";
case DXGI_ERROR_SESSION_DISCONNECTED:
return "DXGI_ERROR_SESSION_DISCONNECTED";
case DXGI_ERROR_RESTRICT_TO_OUTPUT_STALE:
return "DXGI_ERROR_RESTRICT_TO_OUTPUT_STALE";
case DXGI_ERROR_CANNOT_PROTECT_CONTENT:
return "DXGI_ERROR_CANNOT_PROTECT_CONTENT";
case DXGI_ERROR_ACCESS_DENIED:
return "DXGI_ERROR_ACCESS_DENIED";
case DXGI_ERROR_NAME_ALREADY_EXISTS:
return "DXGI_ERROR_NAME_ALREADY_EXISTS";
case DXGI_ERROR_SDK_COMPONENT_MISSING:
return "DXGI_ERROR_SDK_COMPONENT_MISSING";
case DXGI_STATUS_UNOCCLUDED:
return "DXGI_STATUS_UNOCCLUDED";
case DXGI_STATUS_DDA_WAS_STILL_DRAWING:
return "DXGI_STATUS_DDA_WAS_STILL_DRAWING";
case DXGI_ERROR_MODE_CHANGE_IN_PROGRESS:
return "DXGI_ERROR_MODE_CHANGE_IN_PROGRESS";
case DXGI_DDI_ERR_WASSTILLDRAWING:
return "DXGI_DDI_ERR_WASSTILLDRAWING";
case DXGI_DDI_ERR_UNSUPPORTED:
return "DXGI_DDI_ERR_UNSUPPORTED";
case DXGI_DDI_ERR_NONEXCLUSIVE:
return "DXGI_DDI_ERR_NONEXCLUSIVE";
case 0x80070005:
return "DXGI_ERROR_ACCESS_DENIED";
}
return "DXGI_ERROR_UNKNOWN";
}
static void win_shadow_d3d11_module_init()
{
if (d3d11_module)
return;
d3d11_module = LoadLibraryA("d3d11.dll");
if (!d3d11_module)
return;
pfnD3D11CreateDevice = GetProcAddressAs(d3d11_module, "D3D11CreateDevice", fnD3D11CreateDevice);
}
int win_shadow_dxgi_init_duplication(winShadowSubsystem* subsystem)
{
HRESULT hr;
UINT dTop, i = 0;
IDXGIOutput* pOutput;
DXGI_OUTPUT_DESC outputDesc = WINPR_C_ARRAY_INIT;
DXGI_OUTPUT_DESC* pOutputDesc;
D3D11_TEXTURE2D_DESC textureDesc;
IDXGIDevice* dxgiDevice = nullptr;
IDXGIAdapter* dxgiAdapter = nullptr;
IDXGIOutput* dxgiOutput = nullptr;
IDXGIOutput1* dxgiOutput1 = nullptr;
hr = subsystem->dxgiDevice->lpVtbl->QueryInterface(subsystem->dxgiDevice, &IID_IDXGIDevice,
(void**)&dxgiDevice);
if (FAILED(hr))
{
WLog_ERR(TAG, "ID3D11Device::QueryInterface(IDXGIDevice) failure: %s (0x%08lX)",
GetDxgiErrorString(hr), hr);
return -1;
}
hr = dxgiDevice->lpVtbl->GetParent(dxgiDevice, &IID_IDXGIAdapter, (void**)&dxgiAdapter);
if (dxgiDevice)
{
dxgiDevice->lpVtbl->Release(dxgiDevice);
dxgiDevice = nullptr;
}
if (FAILED(hr))
{
WLog_ERR(TAG, "IDXGIDevice::GetParent(IDXGIAdapter) failure: %s (0x%08lX)",
GetDxgiErrorString(hr), hr);
return -1;
}
pOutput = nullptr;
while (dxgiAdapter->lpVtbl->EnumOutputs(dxgiAdapter, i, &pOutput) != DXGI_ERROR_NOT_FOUND)
{
pOutputDesc = &outputDesc;
hr = pOutput->lpVtbl->GetDesc(pOutput, pOutputDesc);
if (FAILED(hr))
{
WLog_ERR(TAG, "IDXGIOutput::GetDesc failure: %s (0x%08lX)", GetDxgiErrorString(hr), hr);
return -1;
}
if (pOutputDesc->AttachedToDesktop)
dTop = i;
pOutput->lpVtbl->Release(pOutput);
i++;
}
dTop = 0; /* screen id */
hr = dxgiAdapter->lpVtbl->EnumOutputs(dxgiAdapter, dTop, &dxgiOutput);
if (dxgiAdapter)
{
dxgiAdapter->lpVtbl->Release(dxgiAdapter);
dxgiAdapter = nullptr;
}
if (FAILED(hr))
{
WLog_ERR(TAG, "IDXGIAdapter::EnumOutputs failure: %s (0x%08lX)", GetDxgiErrorString(hr),
hr);
return -1;
}
hr = dxgiOutput->lpVtbl->QueryInterface(dxgiOutput, &IID_IDXGIOutput1, (void**)&dxgiOutput1);
if (dxgiOutput)
{
dxgiOutput->lpVtbl->Release(dxgiOutput);
dxgiOutput = nullptr;
}
if (FAILED(hr))
{
WLog_ERR(TAG, "IDXGIOutput::QueryInterface(IDXGIOutput1) failure: %s (0x%08lX)",
GetDxgiErrorString(hr), hr);
return -1;
}
hr = dxgiOutput1->lpVtbl->DuplicateOutput(dxgiOutput1, (IUnknown*)subsystem->dxgiDevice,
&(subsystem->dxgiOutputDuplication));
if (dxgiOutput1)
{
dxgiOutput1->lpVtbl->Release(dxgiOutput1);
dxgiOutput1 = nullptr;
}
if (FAILED(hr))
{
WLog_ERR(TAG, "IDXGIOutput1::DuplicateOutput failure: %s (0x%08lX)", GetDxgiErrorString(hr),
hr);
return -1;
}
textureDesc.Width = subsystem->width;
textureDesc.Height = subsystem->height;
textureDesc.MipLevels = 1;
textureDesc.ArraySize = 1;
textureDesc.Format = DXGI_FORMAT_B8G8R8A8_UNORM;
textureDesc.SampleDesc.Count = 1;
textureDesc.SampleDesc.Quality = 0;
textureDesc.Usage = D3D11_USAGE_STAGING;
textureDesc.BindFlags = 0;
textureDesc.CPUAccessFlags = D3D11_CPU_ACCESS_READ;
textureDesc.MiscFlags = 0;
hr = subsystem->dxgiDevice->lpVtbl->CreateTexture2D(subsystem->dxgiDevice, &textureDesc,
nullptr, &(subsystem->dxgiStage));
if (FAILED(hr))
{
WLog_ERR(TAG, "ID3D11Device::CreateTexture2D failure: %s (0x%08lX)", GetDxgiErrorString(hr),
hr);
return -1;
}
return 1;
}
int win_shadow_dxgi_init(winShadowSubsystem* subsystem)
{
UINT i = 0;
HRESULT hr;
int status;
UINT DriverTypeIndex;
IDXGIDevice* DxgiDevice = nullptr;
IDXGIAdapter* DxgiAdapter = nullptr;
IDXGIOutput* DxgiOutput = nullptr;
IDXGIOutput1* DxgiOutput1 = nullptr;
win_shadow_d3d11_module_init();
if (!pfnD3D11CreateDevice)
return -1;
for (DriverTypeIndex = 0; DriverTypeIndex < NumDriverTypes; ++DriverTypeIndex)
{
hr = pfnD3D11CreateDevice(nullptr, DriverTypes[DriverTypeIndex], nullptr, 0, FeatureLevels,
NumFeatureLevels, D3D11_SDK_VERSION, &(subsystem->dxgiDevice),
&(subsystem->featureLevel), &(subsystem->dxgiDeviceContext));
if (SUCCEEDED(hr))
break;
}
if (FAILED(hr))
{
WLog_ERR(TAG, "D3D11CreateDevice failure: 0x%08lX", hr);
return -1;
}
status = win_shadow_dxgi_init_duplication(subsystem);
return status;
}
int win_shadow_dxgi_uninit(winShadowSubsystem* subsystem)
{
if (subsystem->dxgiStage)
{
subsystem->dxgiStage->lpVtbl->Release(subsystem->dxgiStage);
subsystem->dxgiStage = nullptr;
}
if (subsystem->dxgiDesktopImage)
{
subsystem->dxgiDesktopImage->lpVtbl->Release(subsystem->dxgiDesktopImage);
subsystem->dxgiDesktopImage = nullptr;
}
if (subsystem->dxgiOutputDuplication)
{
subsystem->dxgiOutputDuplication->lpVtbl->Release(subsystem->dxgiOutputDuplication);
subsystem->dxgiOutputDuplication = nullptr;
}
if (subsystem->dxgiDeviceContext)
{
subsystem->dxgiDeviceContext->lpVtbl->Release(subsystem->dxgiDeviceContext);
subsystem->dxgiDeviceContext = nullptr;
}
if (subsystem->dxgiDevice)
{
subsystem->dxgiDevice->lpVtbl->Release(subsystem->dxgiDevice);
subsystem->dxgiDevice = nullptr;
}
return 1;
}
int win_shadow_dxgi_fetch_frame_data(winShadowSubsystem* subsystem, BYTE** ppDstData,
int* pnDstStep, int x, int y, int width, int height)
{
int status;
HRESULT hr;
D3D11_BOX Box;
DXGI_MAPPED_RECT mappedRect;
if ((width * height) < 1)
return 0;
Box.top = x;
Box.left = y;
Box.right = x + width;
Box.bottom = y + height;
Box.front = 0;
Box.back = 1;
subsystem->dxgiDeviceContext->lpVtbl->CopySubresourceRegion(
subsystem->dxgiDeviceContext, (ID3D11Resource*)subsystem->dxgiStage, 0, 0, 0, 0,
(ID3D11Resource*)subsystem->dxgiDesktopImage, 0, &Box);
hr = subsystem->dxgiStage->lpVtbl->QueryInterface(subsystem->dxgiStage, &IID_IDXGISurface,
(void**)&(subsystem->dxgiSurface));
if (FAILED(hr))
{
WLog_ERR(TAG, "ID3D11Texture2D::QueryInterface(IDXGISurface) failure: %s 0x%08lX",
GetDxgiErrorString(hr), hr);
return -1;
}
hr = subsystem->dxgiSurface->lpVtbl->Map(subsystem->dxgiSurface, &mappedRect, DXGI_MAP_READ);
if (FAILED(hr))
{
WLog_ERR(TAG, "IDXGISurface::Map failure: %s 0x%08lX", GetDxgiErrorString(hr), hr);
if (hr == DXGI_ERROR_DEVICE_REMOVED)
{
win_shadow_dxgi_uninit(subsystem);
status = win_shadow_dxgi_init(subsystem);
if (status < 0)
return -1;
return 0;
}
return -1;
}
subsystem->dxgiSurfaceMapped = TRUE;
*ppDstData = mappedRect.pBits;
*pnDstStep = mappedRect.Pitch;
return 1;
}
int win_shadow_dxgi_release_frame_data(winShadowSubsystem* subsystem)
{
if (subsystem->dxgiSurface)
{
if (subsystem->dxgiSurfaceMapped)
{
subsystem->dxgiSurface->lpVtbl->Unmap(subsystem->dxgiSurface);
subsystem->dxgiSurfaceMapped = FALSE;
}
subsystem->dxgiSurface->lpVtbl->Release(subsystem->dxgiSurface);
subsystem->dxgiSurface = nullptr;
}
if (subsystem->dxgiOutputDuplication)
{
if (subsystem->dxgiFrameAcquired)
{
subsystem->dxgiOutputDuplication->lpVtbl->ReleaseFrame(
subsystem->dxgiOutputDuplication);
subsystem->dxgiFrameAcquired = FALSE;
}
}
subsystem->pendingFrames = 0;
return 1;
}
int win_shadow_dxgi_get_next_frame(winShadowSubsystem* subsystem)
{
UINT i = 0;
int status;
HRESULT hr = 0;
UINT timeout = 15;
UINT DataBufferSize = 0;
BYTE* DataBuffer = nullptr;
if (subsystem->dxgiFrameAcquired)
{
win_shadow_dxgi_release_frame_data(subsystem);
}
if (subsystem->dxgiDesktopImage)
{
subsystem->dxgiDesktopImage->lpVtbl->Release(subsystem->dxgiDesktopImage);
subsystem->dxgiDesktopImage = nullptr;
}
hr = subsystem->dxgiOutputDuplication->lpVtbl->AcquireNextFrame(
subsystem->dxgiOutputDuplication, timeout, &(subsystem->dxgiFrameInfo),
&(subsystem->dxgiResource));
if (SUCCEEDED(hr))
{
subsystem->dxgiFrameAcquired = TRUE;
subsystem->pendingFrames = subsystem->dxgiFrameInfo.AccumulatedFrames;
}
if (hr == DXGI_ERROR_WAIT_TIMEOUT)
return 0;
if (FAILED(hr))
{
WLog_ERR(TAG, "IDXGIOutputDuplication::AcquireNextFrame failure: %s (0x%08lX)",
GetDxgiErrorString(hr), hr);
if (hr == DXGI_ERROR_ACCESS_LOST)
{
win_shadow_dxgi_release_frame_data(subsystem);
if (subsystem->dxgiDesktopImage)
{
subsystem->dxgiDesktopImage->lpVtbl->Release(subsystem->dxgiDesktopImage);
subsystem->dxgiDesktopImage = nullptr;
}
if (subsystem->dxgiOutputDuplication)
{
subsystem->dxgiOutputDuplication->lpVtbl->Release(subsystem->dxgiOutputDuplication);
subsystem->dxgiOutputDuplication = nullptr;
}
status = win_shadow_dxgi_init_duplication(subsystem);
if (status < 0)
return -1;
return 0;
}
else if (hr == DXGI_ERROR_INVALID_CALL)
{
win_shadow_dxgi_uninit(subsystem);
status = win_shadow_dxgi_init(subsystem);
if (status < 0)
return -1;
return 0;
}
return -1;
}
hr = subsystem->dxgiResource->lpVtbl->QueryInterface(
subsystem->dxgiResource, &IID_ID3D11Texture2D, (void**)&(subsystem->dxgiDesktopImage));
if (subsystem->dxgiResource)
{
subsystem->dxgiResource->lpVtbl->Release(subsystem->dxgiResource);
subsystem->dxgiResource = nullptr;
}
if (FAILED(hr))
{
WLog_ERR(TAG, "IDXGIResource::QueryInterface(ID3D11Texture2D) failure: %s (0x%08lX)",
GetDxgiErrorString(hr), hr);
return -1;
}
return 1;
}
int win_shadow_dxgi_get_invalid_region(winShadowSubsystem* subsystem)
{
HRESULT hr;
POINT* pSrcPt;
RECT* pDstRect;
RECT* pDirtyRect;
UINT numMoveRects;
UINT numDirtyRects;
UINT UsedBufferSize;
RECTANGLE_16 invalidRect;
UINT MetadataBufferSize;
UINT MoveRectsBufferSize;
UINT DirtyRectsBufferSize;
RECT* pDirtyRectsBuffer;
DXGI_OUTDUPL_MOVE_RECT* pMoveRect;
DXGI_OUTDUPL_MOVE_RECT* pMoveRectBuffer;
rdpShadowSurface* surface = subsystem->server->surface;
if (subsystem->dxgiFrameInfo.AccumulatedFrames == 0)
return 0;
if (subsystem->dxgiFrameInfo.TotalMetadataBufferSize == 0)
return 0;
MetadataBufferSize = subsystem->dxgiFrameInfo.TotalMetadataBufferSize;
if (MetadataBufferSize > subsystem->MetadataBufferSize)
{
subsystem->MetadataBuffer = (BYTE*)realloc(subsystem->MetadataBuffer, MetadataBufferSize);
if (!subsystem->MetadataBuffer)
return -1;
subsystem->MetadataBufferSize = MetadataBufferSize;
}
/* GetFrameMoveRects */
UsedBufferSize = 0;
MoveRectsBufferSize = MetadataBufferSize - UsedBufferSize;
pMoveRectBuffer = (DXGI_OUTDUPL_MOVE_RECT*)&(subsystem->MetadataBuffer[UsedBufferSize]);
hr = subsystem->dxgiOutputDuplication->lpVtbl->GetFrameMoveRects(
subsystem->dxgiOutputDuplication, MoveRectsBufferSize, pMoveRectBuffer,
&MoveRectsBufferSize);
if (FAILED(hr))
{
WLog_ERR(TAG,
"IDXGIOutputDuplication::GetFrameMoveRects failure: %s (0x%08lX) Size: %u Total "
"%u Used: %u",
GetDxgiErrorString(hr), hr, MoveRectsBufferSize, MetadataBufferSize,
UsedBufferSize);
return -1;
}
/* GetFrameDirtyRects */
UsedBufferSize += MoveRectsBufferSize;
DirtyRectsBufferSize = MetadataBufferSize - UsedBufferSize;
pDirtyRectsBuffer = (RECT*)&(subsystem->MetadataBuffer[UsedBufferSize]);
hr = subsystem->dxgiOutputDuplication->lpVtbl->GetFrameDirtyRects(
subsystem->dxgiOutputDuplication, DirtyRectsBufferSize, pDirtyRectsBuffer,
&DirtyRectsBufferSize);
if (FAILED(hr))
{
WLog_ERR(TAG,
"IDXGIOutputDuplication::GetFrameDirtyRects failure: %s (0x%08lX) Size: %u Total "
"%u Used: %u",
GetDxgiErrorString(hr), hr, DirtyRectsBufferSize, MetadataBufferSize,
UsedBufferSize);
return -1;
}
numMoveRects = MoveRectsBufferSize / sizeof(DXGI_OUTDUPL_MOVE_RECT);
for (UINT i = 0; i < numMoveRects; i++)
{
pMoveRect = &pMoveRectBuffer[i];
pSrcPt = &(pMoveRect->SourcePoint);
pDstRect = &(pMoveRect->DestinationRect);
invalidRect.left = (UINT16)pDstRect->left;
invalidRect.top = (UINT16)pDstRect->top;
invalidRect.right = (UINT16)pDstRect->right;
invalidRect.bottom = (UINT16)pDstRect->bottom;
region16_union_rect(&(surface->invalidRegion), &(surface->invalidRegion), &invalidRect);
}
numDirtyRects = DirtyRectsBufferSize / sizeof(RECT);
for (UINT i = 0; i < numDirtyRects; i++)
{
pDirtyRect = &pDirtyRectsBuffer[i];
invalidRect.left = (UINT16)pDirtyRect->left;
invalidRect.top = (UINT16)pDirtyRect->top;
invalidRect.right = (UINT16)pDirtyRect->right;
invalidRect.bottom = (UINT16)pDirtyRect->bottom;
region16_union_rect(&(surface->invalidRegion), &(surface->invalidRegion), &invalidRect);
}
return 1;
}
#endif

View File

@@ -0,0 +1,62 @@
/**
* FreeRDP: A Remote Desktop Protocol Implementation
*
* Copyright 2014 Marc-Andre Moreau <marcandre.moreau@gmail.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.
*/
#ifndef FREERDP_SERVER_SHADOW_WIN_DXGI_H
#define FREERDP_SERVER_SHADOW_WIN_DXGI_H
#if _WIN32_WINNT >= 0x0602
//#define WITH_DXGI_1_2 1
#endif
#ifdef WITH_DXGI_1_2
#ifndef CINTERFACE
#define CINTERFACE
#endif
#include <D3D11.h>
#include <dxgi1_2.h>
#endif
#include "win_shadow.h"
#ifdef __cplusplus
extern "C"
{
#endif
#ifdef WITH_DXGI_1_2
WINPR_ATTR_NODISCARD int win_shadow_dxgi_init(winShadowSubsystem* subsystem);
WINPR_ATTR_NODISCARD int win_shadow_dxgi_uninit(winShadowSubsystem* subsystem);
WINPR_ATTR_NODISCARD int win_shadow_dxgi_fetch_frame_data(winShadowSubsystem* subsystem,
BYTE** ppDstData, int* pnDstStep,
int x, int y, int width, int height);
WINPR_ATTR_NODISCARD int win_shadow_dxgi_get_next_frame(winShadowSubsystem* subsystem);
WINPR_ATTR_NODISCARD int win_shadow_dxgi_get_invalid_region(winShadowSubsystem* subsystem);
#endif
#ifdef __cplusplus
}
#endif
#endif /* FREERDP_SERVER_SHADOW_WIN_DXGI_H */

View File

@@ -0,0 +1,440 @@
/**
* FreeRDP: A Remote Desktop Protocol Implementation
*
* Copyright 2014 Marc-Andre Moreau <marcandre.moreau@gmail.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 <winpr/crt.h>
#include <winpr/assert.h>
#include <winpr/print.h>
#include <winpr/assert.h>
#include <freerdp/log.h>
#include "win_rdp.h"
#define TAG SERVER_TAG("shadow.win")
static void shw_OnChannelConnectedEventHandler(void* context, const ChannelConnectedEventArgs* e)
{
shwContext* shw = (shwContext*)context;
WINPR_ASSERT(e);
WLog_INFO(TAG, "OnChannelConnected: %s", e->name);
}
static void shw_OnChannelDisconnectedEventHandler(void* context,
const ChannelDisconnectedEventArgs* e)
{
shwContext* shw = (shwContext*)context;
WINPR_ASSERT(e);
WLog_INFO(TAG, "OnChannelDisconnected: %s", e->name);
}
static BOOL shw_begin_paint(rdpContext* context)
{
shwContext* shw;
rdpGdi* gdi;
WINPR_ASSERT(context);
gdi = context->gdi;
WINPR_ASSERT(gdi);
shw = (shwContext*)context;
gdi->primary->hdc->hwnd->invalid->null = TRUE;
gdi->primary->hdc->hwnd->ninvalid = 0;
return TRUE;
}
static BOOL shw_end_paint(rdpContext* context)
{
int ninvalid;
HGDI_RGN cinvalid;
RECTANGLE_16 invalidRect;
rdpGdi* gdi = context->gdi;
shwContext* shw = (shwContext*)context;
winShadowSubsystem* subsystem = shw->subsystem;
rdpShadowSurface* surface = subsystem->base.server->surface;
ninvalid = gdi->primary->hdc->hwnd->ninvalid;
cinvalid = gdi->primary->hdc->hwnd->cinvalid;
for (int index = 0; index < ninvalid; index++)
{
invalidRect.left = cinvalid[index].x;
invalidRect.top = cinvalid[index].y;
invalidRect.right = cinvalid[index].x + cinvalid[index].w;
invalidRect.bottom = cinvalid[index].y + cinvalid[index].h;
region16_union_rect(&(surface->invalidRegion), &(surface->invalidRegion), &invalidRect);
}
(void)SetEvent(subsystem->RdpUpdateEnterEvent);
(void)WaitForSingleObject(subsystem->RdpUpdateLeaveEvent, INFINITE);
(void)ResetEvent(subsystem->RdpUpdateLeaveEvent);
return TRUE;
}
BOOL shw_desktop_resize(rdpContext* context)
{
WLog_WARN(TAG, "Desktop resizing not implemented!");
return TRUE;
}
static BOOL shw_surface_frame_marker(rdpContext* context,
const SURFACE_FRAME_MARKER* surfaceFrameMarker)
{
shwContext* shw = (shwContext*)context;
return TRUE;
}
static BOOL shw_authenticate(freerdp* instance, char** username, char** password, char** domain)
{
WLog_WARN(TAG, "Authentication not implemented, access granted to everyone!");
return TRUE;
}
static int shw_verify_x509_certificate(freerdp* instance, const BYTE* data, size_t length,
const char* hostname, UINT16 port, DWORD flags)
{
WLog_WARN(TAG, "Certificate checks not implemented, access granted to everyone!");
return 1;
}
static void shw_OnConnectionResultEventHandler(void* context, const ConnectionResultEventArgs* e)
{
shwContext* shw = (shwContext*)context;
WINPR_ASSERT(e);
WLog_INFO(TAG, "OnConnectionResult: %d", e->result);
}
static BOOL shw_pre_connect(freerdp* instance)
{
shwContext* shw;
rdpContext* context = instance->context;
shw = (shwContext*)context;
PubSub_SubscribeConnectionResult(context->pubSub, shw_OnConnectionResultEventHandler);
PubSub_SubscribeChannelConnected(context->pubSub, shw_OnChannelConnectedEventHandler);
PubSub_SubscribeChannelDisconnected(context->pubSub, shw_OnChannelDisconnectedEventHandler);
return TRUE;
}
static BOOL shw_post_connect(freerdp* instance)
{
rdpGdi* gdi;
shwContext* shw;
rdpUpdate* update;
rdpSettings* settings;
WINPR_ASSERT(instance);
shw = (shwContext*)instance->context;
WINPR_ASSERT(shw);
update = instance->context->update;
WINPR_ASSERT(update);
settings = instance->context->settings;
WINPR_ASSERT(settings);
if (!gdi_init(instance, PIXEL_FORMAT_BGRX32))
return FALSE;
gdi = instance->context->gdi;
update->BeginPaint = shw_begin_paint;
update->EndPaint = shw_end_paint;
update->DesktopResize = shw_desktop_resize;
update->SurfaceFrameMarker = shw_surface_frame_marker;
return TRUE;
}
static DWORD WINAPI shw_client_thread(LPVOID arg)
{
int index;
BOOL bSuccess;
shwContext* shw;
rdpContext* context;
rdpChannels* channels;
freerdp* instance = (freerdp*)arg;
WINPR_ASSERT(instance);
context = (rdpContext*)instance->context;
WINPR_ASSERT(context);
shw = (shwContext*)context;
bSuccess = freerdp_connect(instance);
WLog_INFO(TAG, "freerdp_connect: %d", bSuccess);
if (!bSuccess)
{
ExitThread(0);
return 0;
}
channels = context->channels;
WINPR_ASSERT(channels);
while (1)
{
DWORD status;
HANDLE handles[MAXIMUM_WAIT_OBJECTS] = WINPR_C_ARRAY_INIT;
DWORD count = freerdp_get_event_handles(instance->context, handles, ARRAYSIZE(handles));
if ((count == 0) || (count == MAXIMUM_WAIT_OBJECTS))
{
WLog_ERR(TAG, "Failed to get FreeRDP event handles");
break;
}
handles[count++] = freerdp_channels_get_event_handle(instance);
if (MsgWaitForMultipleObjects(count, handles, FALSE, 1000, QS_ALLINPUT) == WAIT_FAILED)
{
WLog_ERR(TAG, "MsgWaitForMultipleObjects failure: 0x%08lX", GetLastError());
break;
}
if (!freerdp_check_fds(instance))
{
WLog_ERR(TAG, "Failed to check FreeRDP file descriptor");
break;
}
if (freerdp_shall_disconnect_context(instance->context))
{
break;
}
if (!freerdp_channels_check_fds(channels, instance))
{
WLog_ERR(TAG, "Failed to check channels file descriptor");
break;
}
}
freerdp_free(instance);
ExitThread(0);
return 0;
}
/**
* Client Interface
*/
static BOOL shw_freerdp_client_global_init(void)
{
return TRUE;
}
static void shw_freerdp_client_global_uninit(void)
{
}
static int shw_freerdp_client_start(rdpContext* context)
{
shwContext* shw;
freerdp* instance = context->instance;
shw = (shwContext*)context;
if (!(shw->common.thread = CreateThread(nullptr, 0, shw_client_thread, instance, 0, nullptr)))
{
WLog_ERR(TAG, "Failed to create thread");
return -1;
}
return 0;
}
static int shw_freerdp_client_stop(rdpContext* context)
{
shwContext* shw = (shwContext*)context;
(void)SetEvent(shw->StopEvent);
return 0;
}
static BOOL shw_freerdp_client_new(freerdp* instance, rdpContext* context)
{
shwContext* shw;
rdpSettings* settings;
WINPR_ASSERT(instance);
WINPR_ASSERT(context);
shw = (shwContext*)instance->context;
WINPR_ASSERT(shw);
if (!(shw->StopEvent = CreateEvent(nullptr, TRUE, FALSE, nullptr)))
return FALSE;
instance->LoadChannels = freerdp_client_load_channels;
instance->PreConnect = shw_pre_connect;
instance->PostConnect = shw_post_connect;
instance->Authenticate = shw_authenticate;
instance->VerifyX509Certificate = shw_verify_x509_certificate;
settings = context->settings;
WINPR_ASSERT(settings);
shw->settings = settings;
if (!freerdp_settings_set_bool(settings, FreeRDP_AsyncChannels, FALSE))
return FALSE;
if (!freerdp_settings_set_bool(settings, FreeRDP_AsyncUpdate, FALSE))
return FALSE;
if (!freerdp_settings_set_bool(settings, FreeRDP_IgnoreCertificate, TRUE))
return FALSE;
if (!freerdp_settings_set_bool(settings, FreeRDP_ExternalCertificateManagement, TRUE))
return FALSE;
if (!freerdp_settings_set_bool(settings, FreeRDP_RdpSecurity, TRUE))
return FALSE;
if (!freerdp_settings_set_bool(settings, FreeRDP_TlsSecurity, TRUE))
return FALSE;
if (!freerdp_settings_set_bool(settings, FreeRDP_NlaSecurity, FALSE))
return FALSE;
if (!freerdp_settings_set_bool(settings, FreeRDP_BitmapCacheEnabled, FALSE))
return FALSE;
if (!freerdp_settings_set_bool(settings, FreeRDP_BitmapCacheV3Enabled, FALSE))
return FALSE;
if (!freerdp_settings_set_bool(settings, FreeRDP_OffscreenSupportLevel, FALSE))
return FALSE;
if (!freerdp_settings_set_uint32(settings, FreeRDP_GlyphSupportLevel, GLYPH_SUPPORT_NONE))
return FALSE;
if (!freerdp_settings_set_bool(settings, FreeRDP_BrushSupportLevel, FALSE))
return FALSE;
ZeroMemory(freerdp_settings_get_pointer_writable(settings, FreeRDP_OrderSupport), 32);
if (!freerdp_settings_set_bool(settings, FreeRDP_FrameMarkerCommandEnabled, TRUE))
return FALSE;
if (!freerdp_settings_set_bool(settings, FreeRDP_SurfaceFrameMarkerEnabled, TRUE))
return FALSE;
if (!freerdp_settings_set_bool(settings, FreeRDP_AltSecFrameMarkerSupport, TRUE))
return FALSE;
if (!freerdp_settings_set_uint32(settings, FreeRDP_ColorDepth, 32))
return FALSE;
if (!freerdp_settings_set_bool(settings, FreeRDP_NSCodec, TRUE))
return FALSE;
if (!freerdp_settings_set_bool(settings, FreeRDP_RemoteFxCodec, TRUE))
return FALSE;
if (!freerdp_settings_set_bool(settings, FreeRDP_FastPathInput, TRUE))
return FALSE;
if (!freerdp_settings_set_bool(settings, FreeRDP_FastPathOutput, TRUE))
return FALSE;
if (!freerdp_settings_set_bool(settings, FreeRDP_LargePointerFlag, TRUE))
return FALSE;
if (!freerdp_settings_set_bool(settings, FreeRDP_CompressionEnabled, FALSE))
return FALSE;
if (!freerdp_settings_set_bool(settings, FreeRDP_AutoReconnectionEnabled, FALSE))
return FALSE;
if (!freerdp_settings_set_bool(settings, FreeRDP_NetworkAutoDetect, FALSE))
return FALSE;
if (!freerdp_settings_set_bool(settings, FreeRDP_SupportHeartbeatPdu, FALSE))
return FALSE;
if (!freerdp_settings_set_bool(settings, FreeRDP_SupportMultitransport, FALSE))
return FALSE;
if (!freerdp_settings_set_uint32(settings, FreeRDP_ConnectionType, CONNECTION_TYPE_LAN))
return FALSE;
if (!freerdp_settings_set_bool(settings, FreeRDP_AllowFontSmoothing, TRUE))
return FALSE;
if (!freerdp_settings_set_bool(settings, FreeRDP_AllowDesktopComposition, TRUE))
return FALSE;
if (!freerdp_settings_set_bool(settings, FreeRDP_DisableWallpaper, FALSE))
return FALSE;
if (!freerdp_settings_set_bool(settings, FreeRDP_DisableFullWindowDrag, TRUE))
return FALSE;
if (!freerdp_settings_set_bool(settings, FreeRDP_DisableMenuAnims, TRUE))
return FALSE;
if (!freerdp_settings_set_bool(settings, FreeRDP_DisableThemes, FALSE))
return FALSE;
if (!freerdp_settings_set_bool(settings, FreeRDP_DeviceRedirection, TRUE))
return FALSE;
if (!freerdp_settings_set_bool(settings, FreeRDP_RedirectClipboard, TRUE))
return FALSE;
if (!freerdp_settings_set_bool(settings, FreeRDP_SupportDynamicChannels, TRUE))
return FALSE;
return TRUE;
}
static void shw_freerdp_client_free(freerdp* instance, rdpContext* context)
{
shwContext* shw = (shwContext*)instance->context;
}
int shw_RdpClientEntry(RDP_CLIENT_ENTRY_POINTS* pEntryPoints)
{
pEntryPoints->Version = 1;
pEntryPoints->Size = sizeof(RDP_CLIENT_ENTRY_POINTS_V1);
pEntryPoints->settings = nullptr;
pEntryPoints->ContextSize = sizeof(shwContext);
pEntryPoints->GlobalInit = shw_freerdp_client_global_init;
pEntryPoints->GlobalUninit = shw_freerdp_client_global_uninit;
pEntryPoints->ClientNew = shw_freerdp_client_new;
pEntryPoints->ClientFree = shw_freerdp_client_free;
pEntryPoints->ClientStart = shw_freerdp_client_start;
pEntryPoints->ClientStop = shw_freerdp_client_stop;
return 0;
}
int win_shadow_rdp_init(winShadowSubsystem* subsystem)
{
rdpContext* context;
RDP_CLIENT_ENTRY_POINTS clientEntryPoints = WINPR_C_ARRAY_INIT;
clientEntryPoints.Size = sizeof(RDP_CLIENT_ENTRY_POINTS);
clientEntryPoints.Version = RDP_CLIENT_INTERFACE_VERSION;
shw_RdpClientEntry(&clientEntryPoints);
if (!(subsystem->RdpUpdateEnterEvent = CreateEvent(nullptr, TRUE, FALSE, nullptr)))
goto fail_enter_event;
if (!(subsystem->RdpUpdateLeaveEvent = CreateEvent(nullptr, TRUE, FALSE, nullptr)))
goto fail_leave_event;
if (!(context = freerdp_client_context_new(&clientEntryPoints)))
goto fail_context;
subsystem->shw = (shwContext*)context;
subsystem->shw->settings = context->settings;
subsystem->shw->subsystem = subsystem;
return 1;
fail_context:
(void)CloseHandle(subsystem->RdpUpdateLeaveEvent);
fail_leave_event:
(void)CloseHandle(subsystem->RdpUpdateEnterEvent);
fail_enter_event:
return -1;
}
int win_shadow_rdp_start(winShadowSubsystem* subsystem)
{
int status;
shwContext* shw = subsystem->shw;
rdpContext* context = (rdpContext*)shw;
status = freerdp_client_start(context);
return status;
}
int win_shadow_rdp_stop(winShadowSubsystem* subsystem)
{
int status;
shwContext* shw = subsystem->shw;
rdpContext* context = (rdpContext*)shw;
status = freerdp_client_stop(context);
return status;
}
int win_shadow_rdp_uninit(winShadowSubsystem* subsystem)
{
win_shadow_rdp_stop(subsystem);
return 1;
}

View File

@@ -0,0 +1,56 @@
/**
* FreeRDP: A Remote Desktop Protocol Implementation
*
* Copyright 2014 Marc-Andre Moreau <marcandre.moreau@gmail.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.
*/
#ifndef FREERDP_SERVER_SHADOW_WIN_RDP_H
#define FREERDP_SERVER_SHADOW_WIN_RDP_H
#include <freerdp/addin.h>
#include <freerdp/gdi/gdi.h>
#include <freerdp/client/cmdline.h>
#include <freerdp/channels/channels.h>
typedef struct shw_context shwContext;
#include "win_shadow.h"
struct shw_context
{
rdpClientContext common;
HANDLE StopEvent;
freerdp* instance;
rdpSettings* settings;
winShadowSubsystem* subsystem;
};
#ifdef __cplusplus
extern "C"
{
#endif
WINPR_ATTR_NODISCARD int win_shadow_rdp_init(winShadowSubsystem* subsystem);
WINPR_ATTR_NODISCARD int win_shadow_rdp_uninit(winShadowSubsystem* subsystem);
WINPR_ATTR_NODISCARD int win_shadow_rdp_start(winShadowSubsystem* subsystem);
WINPR_ATTR_NODISCARD int win_shadow_rdp_stop(winShadowSubsystem* subsystem);
#ifdef __cplusplus
}
#endif
#endif /* FREERDP_SERVER_SHADOW_WIN_RDP_H */

View File

@@ -0,0 +1,562 @@
/**
* FreeRDP: A Remote Desktop Protocol Implementation
*
* Copyright 2011-2014 Marc-Andre Moreau <marcandre.moreau@gmail.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 <windows.h>
#include <winpr/crt.h>
#include <winpr/synch.h>
#include <winpr/sysinfo.h>
#include <freerdp/log.h>
#include <freerdp/codec/color.h>
#include <freerdp/codec/region.h>
#include <freerdp/server/server-common.h>
#include "win_shadow.h"
#define TAG SERVER_TAG("shadow.win")
/* https://docs.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-mouse_event
* does not mention this flag is only supported if building for _WIN32_WINNT >= 0x0600
*/
#ifndef MOUSEEVENTF_HWHEEL
#define MOUSEEVENTF_HWHEEL 0x1000
#endif
static BOOL win_shadow_input_synchronize_event(rdpShadowSubsystem* subsystem,
rdpShadowClient* client, UINT32 flags)
{
WLog_WARN(TAG, "TODO: Implement!");
return TRUE;
}
static BOOL win_shadow_input_keyboard_event(rdpShadowSubsystem* subsystem, rdpShadowClient* client,
UINT16 flags, UINT8 code)
{
UINT rc;
INPUT event;
event.type = INPUT_KEYBOARD;
event.ki.wVk = 0;
event.ki.wScan = code;
event.ki.dwFlags = KEYEVENTF_SCANCODE;
event.ki.dwExtraInfo = 0;
event.ki.time = 0;
if (flags & KBD_FLAGS_RELEASE)
event.ki.dwFlags |= KEYEVENTF_KEYUP;
if (flags & KBD_FLAGS_EXTENDED)
event.ki.dwFlags |= KEYEVENTF_EXTENDEDKEY;
rc = SendInput(1, &event, sizeof(INPUT));
if (rc == 0)
return FALSE;
return TRUE;
}
static BOOL win_shadow_input_unicode_keyboard_event(rdpShadowSubsystem* subsystem,
rdpShadowClient* client, UINT16 flags,
UINT16 code)
{
UINT rc;
INPUT event;
event.type = INPUT_KEYBOARD;
event.ki.wVk = 0;
event.ki.wScan = code;
event.ki.dwFlags = KEYEVENTF_UNICODE;
event.ki.dwExtraInfo = 0;
event.ki.time = 0;
if (flags & KBD_FLAGS_RELEASE)
event.ki.dwFlags |= KEYEVENTF_KEYUP;
rc = SendInput(1, &event, sizeof(INPUT));
if (rc == 0)
return FALSE;
return TRUE;
}
static BOOL win_shadow_input_mouse_event(rdpShadowSubsystem* subsystem, rdpShadowClient* client,
UINT16 flags, UINT16 x, UINT16 y)
{
UINT rc = 1;
INPUT event = WINPR_C_ARRAY_INIT;
float width;
float height;
event.type = INPUT_MOUSE;
if (flags & (PTR_FLAGS_WHEEL | PTR_FLAGS_HWHEEL))
{
if (flags & PTR_FLAGS_WHEEL)
event.mi.dwFlags = MOUSEEVENTF_WHEEL;
else
event.mi.dwFlags = MOUSEEVENTF_HWHEEL;
event.mi.mouseData = flags & WheelRotationMask;
if (flags & PTR_FLAGS_WHEEL_NEGATIVE)
event.mi.mouseData *= -1;
rc = SendInput(1, &event, sizeof(INPUT));
/* The build target is a system that did not support MOUSEEVENTF_HWHEEL
* but it may run on newer systems supporting it.
* Ignore the return value in these cases.
*/
#if (_WIN32_WINNT < 0x0600)
if (flags & PTR_FLAGS_HWHEEL)
rc = 1;
#endif
}
else
{
width = (float)GetSystemMetrics(SM_CXSCREEN);
height = (float)GetSystemMetrics(SM_CYSCREEN);
event.mi.dx = (LONG)((float)x * (65535.0f / width));
event.mi.dy = (LONG)((float)y * (65535.0f / height));
event.mi.dwFlags = MOUSEEVENTF_ABSOLUTE;
if (flags & PTR_FLAGS_MOVE)
{
event.mi.dwFlags |= MOUSEEVENTF_MOVE;
rc = SendInput(1, &event, sizeof(INPUT));
if (rc == 0)
return FALSE;
}
event.mi.dwFlags = MOUSEEVENTF_ABSOLUTE;
if (flags & PTR_FLAGS_BUTTON1)
{
if (flags & PTR_FLAGS_DOWN)
event.mi.dwFlags |= MOUSEEVENTF_LEFTDOWN;
else
event.mi.dwFlags |= MOUSEEVENTF_LEFTUP;
rc = SendInput(1, &event, sizeof(INPUT));
}
else if (flags & PTR_FLAGS_BUTTON2)
{
if (flags & PTR_FLAGS_DOWN)
event.mi.dwFlags |= MOUSEEVENTF_RIGHTDOWN;
else
event.mi.dwFlags |= MOUSEEVENTF_RIGHTUP;
rc = SendInput(1, &event, sizeof(INPUT));
}
else if (flags & PTR_FLAGS_BUTTON3)
{
if (flags & PTR_FLAGS_DOWN)
event.mi.dwFlags |= MOUSEEVENTF_MIDDLEDOWN;
else
event.mi.dwFlags |= MOUSEEVENTF_MIDDLEUP;
rc = SendInput(1, &event, sizeof(INPUT));
}
}
if (rc == 0)
return FALSE;
return TRUE;
}
static BOOL win_shadow_input_extended_mouse_event(rdpShadowSubsystem* subsystem,
rdpShadowClient* client, UINT16 flags, UINT16 x,
UINT16 y)
{
UINT rc = 1;
INPUT event = WINPR_C_ARRAY_INIT;
float width;
float height;
if ((flags & PTR_XFLAGS_BUTTON1) || (flags & PTR_XFLAGS_BUTTON2))
{
event.type = INPUT_MOUSE;
if (flags & PTR_FLAGS_MOVE)
{
width = (float)GetSystemMetrics(SM_CXSCREEN);
height = (float)GetSystemMetrics(SM_CYSCREEN);
event.mi.dx = (LONG)((float)x * (65535.0f / width));
event.mi.dy = (LONG)((float)y * (65535.0f / height));
event.mi.dwFlags = MOUSEEVENTF_ABSOLUTE | MOUSEEVENTF_MOVE;
rc = SendInput(1, &event, sizeof(INPUT));
if (rc == 0)
return FALSE;
}
event.mi.dx = event.mi.dy = event.mi.dwFlags = 0;
if (flags & PTR_XFLAGS_DOWN)
event.mi.dwFlags |= MOUSEEVENTF_XDOWN;
else
event.mi.dwFlags |= MOUSEEVENTF_XUP;
if (flags & PTR_XFLAGS_BUTTON1)
event.mi.mouseData = XBUTTON1;
else if (flags & PTR_XFLAGS_BUTTON2)
event.mi.mouseData = XBUTTON2;
rc = SendInput(1, &event, sizeof(INPUT));
}
if (rc == 0)
return FALSE;
return TRUE;
}
static int win_shadow_invalidate_region(winShadowSubsystem* subsystem, int x, int y, int width,
int height)
{
rdpShadowServer* server;
rdpShadowSurface* surface;
RECTANGLE_16 invalidRect;
server = subsystem->base.server;
surface = server->surface;
invalidRect.left = x;
invalidRect.top = y;
invalidRect.right = x + width;
invalidRect.bottom = y + height;
EnterCriticalSection(&(surface->lock));
region16_union_rect(&(surface->invalidRegion), &(surface->invalidRegion), &invalidRect);
LeaveCriticalSection(&(surface->lock));
return 1;
}
static int win_shadow_surface_copy(winShadowSubsystem* subsystem)
{
int x, y;
int width;
int height;
int count;
int status = 1;
int nDstStep = 0;
DWORD DstFormat;
BYTE* pDstData = nullptr;
rdpShadowServer* server;
rdpShadowSurface* surface;
RECTANGLE_16 surfaceRect;
RECTANGLE_16 invalidRect;
const RECTANGLE_16* extents;
server = subsystem->base.server;
surface = server->surface;
if (ArrayList_Count(server->clients) < 1)
return 1;
surfaceRect.left = surface->x;
surfaceRect.top = surface->y;
surfaceRect.right = surface->x + surface->width;
surfaceRect.bottom = surface->y + surface->height;
region16_intersect_rect(&(surface->invalidRegion), &(surface->invalidRegion), &surfaceRect);
if (region16_is_empty(&(surface->invalidRegion)))
return 1;
extents = region16_extents(&(surface->invalidRegion));
CopyMemory(&invalidRect, extents, sizeof(RECTANGLE_16));
shadow_capture_align_clip_rect(&invalidRect, &surfaceRect);
x = invalidRect.left;
y = invalidRect.top;
width = invalidRect.right - invalidRect.left;
height = invalidRect.bottom - invalidRect.top;
if (0)
{
x = 0;
y = 0;
width = surface->width;
height = surface->height;
}
WLog_INFO(TAG, "SurfaceCopy x: %d y: %d width: %d height: %d right: %d bottom: %d", x, y, width,
height, x + width, y + height);
#if defined(WITH_WDS_API)
{
rdpGdi* gdi;
shwContext* shw;
rdpContext* context;
WINPR_ASSERT(subsystem);
shw = subsystem->shw;
WINPR_ASSERT(shw);
context = &shw->common.context;
WINPR_ASSERT(context);
gdi = context->gdi;
WINPR_ASSERT(gdi);
pDstData = gdi->primary_buffer;
nDstStep = gdi->width * 4;
DstFormat = gdi->dstFormat;
}
#elif defined(WITH_DXGI_1_2)
DstFormat = PIXEL_FORMAT_BGRX32;
status = win_shadow_dxgi_fetch_frame_data(subsystem, &pDstData, &nDstStep, x, y, width, height);
#endif
if (status <= 0)
return status;
if (!freerdp_image_copy_no_overlap(surface->data, surface->format, surface->scanline, x, y,
width, height, pDstData, DstFormat, nDstStep, x, y, nullptr,
FREERDP_FLIP_NONE))
return ERROR_INTERNAL_ERROR;
ArrayList_Lock(server->clients);
count = ArrayList_Count(server->clients);
shadow_subsystem_frame_update(&subsystem->base);
ArrayList_Unlock(server->clients);
region16_clear(&(surface->invalidRegion));
return 1;
}
#if defined(WITH_WDS_API)
static DWORD WINAPI win_shadow_subsystem_thread(LPVOID arg)
{
winShadowSubsystem* subsystem = (winShadowSubsystem*)arg;
DWORD status;
DWORD nCount;
HANDLE events[32];
HANDLE StopEvent;
StopEvent = subsystem->base.server->StopEvent;
nCount = 0;
events[nCount++] = StopEvent;
events[nCount++] = subsystem->RdpUpdateEnterEvent;
while (1)
{
status = WaitForMultipleObjects(nCount, events, FALSE, INFINITE);
if (WaitForSingleObject(StopEvent, 0) == WAIT_OBJECT_0)
{
break;
}
if (WaitForSingleObject(subsystem->RdpUpdateEnterEvent, 0) == WAIT_OBJECT_0)
{
win_shadow_surface_copy(subsystem);
(void)ResetEvent(subsystem->RdpUpdateEnterEvent);
(void)SetEvent(subsystem->RdpUpdateLeaveEvent);
}
}
ExitThread(0);
return 0;
}
#elif defined(WITH_DXGI_1_2)
static DWORD WINAPI win_shadow_subsystem_thread(LPVOID arg)
{
winShadowSubsystem* subsystem = (winShadowSubsystem*)arg;
int fps;
DWORD status;
DWORD nCount;
UINT64 cTime;
DWORD dwTimeout;
DWORD dwInterval;
UINT64 frameTime;
HANDLE events[32];
HANDLE StopEvent;
StopEvent = subsystem->server->StopEvent;
nCount = 0;
events[nCount++] = StopEvent;
fps = 16;
dwInterval = 1000 / fps;
frameTime = GetTickCount64() + dwInterval;
while (1)
{
dwTimeout = INFINITE;
cTime = GetTickCount64();
dwTimeout = (DWORD)((cTime > frameTime) ? 0 : frameTime - cTime);
status = WaitForMultipleObjects(nCount, events, FALSE, dwTimeout);
if (WaitForSingleObject(StopEvent, 0) == WAIT_OBJECT_0)
{
break;
}
if ((status == WAIT_TIMEOUT) || (GetTickCount64() > frameTime))
{
int dxgi_status;
dxgi_status = win_shadow_dxgi_get_next_frame(subsystem);
if (dxgi_status > 0)
dxgi_status = win_shadow_dxgi_get_invalid_region(subsystem);
if (dxgi_status > 0)
win_shadow_surface_copy(subsystem);
dwInterval = 1000 / fps;
frameTime += dwInterval;
}
}
ExitThread(0);
return 0;
}
#endif
static UINT32 win_shadow_enum_monitors(MONITOR_DEF* monitors, UINT32 maxMonitors)
{
HDC hdc;
int index;
int desktopWidth;
int desktopHeight;
DWORD iDevNum = 0;
int numMonitors = 0;
MONITOR_DEF* monitor;
DISPLAY_DEVICE displayDevice = WINPR_C_ARRAY_INIT;
displayDevice.cb = sizeof(DISPLAY_DEVICE);
if (EnumDisplayDevices(nullptr, iDevNum, &displayDevice, 0))
{
hdc = CreateDC(displayDevice.DeviceName, nullptr, nullptr, nullptr);
desktopWidth = GetDeviceCaps(hdc, HORZRES);
desktopHeight = GetDeviceCaps(hdc, VERTRES);
index = 0;
numMonitors = 1;
monitor = &monitors[index];
monitor->left = 0;
monitor->top = 0;
monitor->right = desktopWidth;
monitor->bottom = desktopHeight;
monitor->flags = 1;
DeleteDC(hdc);
}
return numMonitors;
}
static int win_shadow_subsystem_init(rdpShadowSubsystem* arg)
{
winShadowSubsystem* subsystem = (winShadowSubsystem*)arg;
int status;
MONITOR_DEF* virtualScreen;
subsystem->base.numMonitors = win_shadow_enum_monitors(subsystem->base.monitors, 16);
#if defined(WITH_WDS_API)
status = win_shadow_wds_init(subsystem);
#elif defined(WITH_DXGI_1_2)
status = win_shadow_dxgi_init(subsystem);
#endif
virtualScreen = &(subsystem->base.virtualScreen);
virtualScreen->left = 0;
virtualScreen->top = 0;
virtualScreen->right = subsystem->width;
virtualScreen->bottom = subsystem->height;
virtualScreen->flags = 1;
WLog_INFO(TAG, "width: %d height: %d", subsystem->width, subsystem->height);
return 1;
}
static int win_shadow_subsystem_uninit(rdpShadowSubsystem* arg)
{
winShadowSubsystem* subsystem = (winShadowSubsystem*)arg;
if (!subsystem)
return -1;
#if defined(WITH_WDS_API)
win_shadow_wds_uninit(subsystem);
#elif defined(WITH_DXGI_1_2)
win_shadow_dxgi_uninit(subsystem);
#endif
return 1;
}
static int win_shadow_subsystem_start(rdpShadowSubsystem* arg)
{
winShadowSubsystem* subsystem = (winShadowSubsystem*)arg;
HANDLE thread;
if (!subsystem)
return -1;
if (!(thread =
CreateThread(nullptr, 0, win_shadow_subsystem_thread, (void*)subsystem, 0, nullptr)))
{
WLog_ERR(TAG, "Failed to create thread");
return -1;
}
return 1;
}
static int win_shadow_subsystem_stop(rdpShadowSubsystem* arg)
{
winShadowSubsystem* subsystem = (winShadowSubsystem*)arg;
if (!subsystem)
return -1;
return 1;
}
static void win_shadow_subsystem_free(rdpShadowSubsystem* arg)
{
winShadowSubsystem* subsystem = (winShadowSubsystem*)arg;
if (!subsystem)
return;
win_shadow_subsystem_uninit(arg);
free(subsystem);
}
static rdpShadowSubsystem* win_shadow_subsystem_new(void)
{
winShadowSubsystem* subsystem;
subsystem = (winShadowSubsystem*)calloc(1, sizeof(winShadowSubsystem));
if (!subsystem)
return nullptr;
subsystem->base.SynchronizeEvent = win_shadow_input_synchronize_event;
subsystem->base.KeyboardEvent = win_shadow_input_keyboard_event;
subsystem->base.UnicodeKeyboardEvent = win_shadow_input_unicode_keyboard_event;
subsystem->base.MouseEvent = win_shadow_input_mouse_event;
subsystem->base.ExtendedMouseEvent = win_shadow_input_extended_mouse_event;
return &subsystem->base;
}
FREERDP_API const char* ShadowSubsystemName(void)
{
return "Win";
}
FREERDP_API int ShadowSubsystemEntry(RDP_SHADOW_ENTRY_POINTS* pEntryPoints)
{
const char name[] = "windows shadow subsystem";
const char* arg[] = { name };
freerdp_server_warn_unmaintained(ARRAYSIZE(arg), arg);
pEntryPoints->New = win_shadow_subsystem_new;
pEntryPoints->Free = win_shadow_subsystem_free;
pEntryPoints->Init = win_shadow_subsystem_init;
pEntryPoints->Uninit = win_shadow_subsystem_uninit;
pEntryPoints->Start = win_shadow_subsystem_start;
pEntryPoints->Stop = win_shadow_subsystem_stop;
pEntryPoints->EnumMonitors = win_shadow_enum_monitors;
return 1;
}

View File

@@ -0,0 +1,89 @@
/**
* FreeRDP: A Remote Desktop Protocol Implementation
*
* Copyright 2011-2014 Marc-Andre Moreau <marcandre.moreau@gmail.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.
*/
#ifndef FREERDP_SERVER_SHADOW_WIN_H
#define FREERDP_SERVER_SHADOW_WIN_H
#include <freerdp/assistance.h>
#include <freerdp/server/shadow.h>
typedef struct win_shadow_subsystem winShadowSubsystem;
#include <winpr/crt.h>
#include <winpr/synch.h>
#include <winpr/thread.h>
#include <winpr/stream.h>
#include <winpr/collections.h>
#include "win_rdp.h"
#include "win_wds.h"
#include "win_dxgi.h"
struct win_shadow_subsystem
{
rdpShadowSubsystem base;
int bpp;
int width;
int height;
#ifdef WITH_WDS_API
HWND hWnd;
shwContext* shw;
HANDLE RdpUpdateEnterEvent;
HANDLE RdpUpdateLeaveEvent;
rdpAssistanceFile* pAssistanceFile;
_IRDPSessionEvents* pSessionEvents;
IRDPSRAPISharingSession* pSharingSession;
IRDPSRAPIInvitation* pInvitation;
IRDPSRAPIInvitationManager* pInvitationMgr;
IRDPSRAPISessionProperties* pSessionProperties;
IRDPSRAPIVirtualChannelManager* pVirtualChannelMgr;
IRDPSRAPIApplicationFilter* pApplicationFilter;
IRDPSRAPIAttendeeManager* pAttendeeMgr;
#endif
#ifdef WITH_DXGI_1_2
UINT pendingFrames;
BYTE* MetadataBuffer;
UINT MetadataBufferSize;
BOOL dxgiSurfaceMapped;
BOOL dxgiFrameAcquired;
ID3D11Device* dxgiDevice;
IDXGISurface* dxgiSurface;
ID3D11Texture2D* dxgiStage;
IDXGIResource* dxgiResource;
D3D_FEATURE_LEVEL featureLevel;
ID3D11Texture2D* dxgiDesktopImage;
DXGI_OUTDUPL_FRAME_INFO dxgiFrameInfo;
ID3D11DeviceContext* dxgiDeviceContext;
IDXGIOutputDuplication* dxgiOutputDuplication;
#endif
};
#ifdef __cplusplus
extern "C"
{
#endif
#ifdef __cplusplus
}
#endif
#endif /* FREERDP_SERVER_SHADOW_WIN_H */

View File

@@ -0,0 +1,855 @@
/**
* FreeRDP: A Remote Desktop Protocol Implementation
*
* Copyright 2014 Marc-Andre Moreau <marcandre.moreau@gmail.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 <winpr/crt.h>
#include <winpr/print.h>
#include <freerdp/log.h>
#include "win_rdp.h"
#include "win_wds.h"
/**
* Windows Desktop Sharing API:
* http://blogs.msdn.com/b/rds/archive/2007/03/08/windows-desktop-sharing-api.aspx
*
* Windows Desktop Sharing Interfaces:
* http://msdn.microsoft.com/en-us/library/aa373871%28v=vs.85%29.aspx
*
* Offer Remote Assistance Sample C:
* http://msdn.microsoft.com/en-us/library/ms811079.aspx#remoteassistanceapi_topic2b
*
* Remote Assistance in XP: Programmatically establish an RDP session:
* http://www.codeproject.com/Articles/29939/Remote-Assistance-in-XP-Programmatically-establish
*/
#undef DEFINE_GUID
#define INITGUID
#include <initguid.h>
#include <freerdp/assistance.h>
#define TAG SERVER_TAG("shadow.win")
DEFINE_GUID(CLSID_RDPSession, 0x9B78F0E6, 0x3E05, 0x4A5B, 0xB2, 0xE8, 0xE7, 0x43, 0xA8, 0x95, 0x6B,
0x65);
DEFINE_GUID(DIID__IRDPSessionEvents, 0x98a97042, 0x6698, 0x40e9, 0x8e, 0xfd, 0xb3, 0x20, 0x09, 0x90,
0x00, 0x4b);
DEFINE_GUID(IID_IRDPSRAPISharingSession, 0xeeb20886, 0xe470, 0x4cf6, 0x84, 0x2b, 0x27, 0x39, 0xc0,
0xec, 0x5c, 0xfb);
DEFINE_GUID(IID_IRDPSRAPIAttendee, 0xec0671b3, 0x1b78, 0x4b80, 0xa4, 0x64, 0x91, 0x32, 0x24, 0x75,
0x43, 0xe3);
DEFINE_GUID(IID_IRDPSRAPIAttendeeManager, 0xba3a37e8, 0x33da, 0x4749, 0x8d, 0xa0, 0x07, 0xfa, 0x34,
0xda, 0x79, 0x44);
DEFINE_GUID(IID_IRDPSRAPISessionProperties, 0x339b24f2, 0x9bc0, 0x4f16, 0x9a, 0xac, 0xf1, 0x65,
0x43, 0x3d, 0x13, 0xd4);
DEFINE_GUID(CLSID_RDPSRAPIApplicationFilter, 0xe35ace89, 0xc7e8, 0x427e, 0xa4, 0xf9, 0xb9, 0xda,
0x07, 0x28, 0x26, 0xbd);
DEFINE_GUID(CLSID_RDPSRAPIInvitationManager, 0x53d9c9db, 0x75ab, 0x4271, 0x94, 0x8a, 0x4c, 0x4e,
0xb3, 0x6a, 0x8f, 0x2b);
static ULONG Shadow_IRDPSessionEvents_RefCount = 0;
const char* GetRDPSessionEventString(DISPID id)
{
switch (id)
{
case DISPID_RDPSRAPI_EVENT_ON_ATTENDEE_CONNECTED:
return "OnAttendeeConnected";
break;
case DISPID_RDPSRAPI_EVENT_ON_ATTENDEE_DISCONNECTED:
return "OnAttendeeDisconnected";
break;
case DISPID_RDPSRAPI_EVENT_ON_ATTENDEE_UPDATE:
return "OnAttendeeUpdate";
break;
case DISPID_RDPSRAPI_EVENT_ON_ERROR:
return "OnError";
break;
case DISPID_RDPSRAPI_EVENT_ON_VIEWER_CONNECTED:
return "OnConnectionEstablished";
break;
case DISPID_RDPSRAPI_EVENT_ON_VIEWER_DISCONNECTED:
return "OnConnectionTerminated";
break;
case DISPID_RDPSRAPI_EVENT_ON_VIEWER_AUTHENTICATED:
return "OnConnectionAuthenticated";
break;
case DISPID_RDPSRAPI_EVENT_ON_VIEWER_CONNECTFAILED:
return "OnConnectionFailed";
break;
case DISPID_RDPSRAPI_EVENT_ON_CTRLLEVEL_CHANGE_REQUEST:
return "OnControlLevelChangeRequest";
break;
case DISPID_RDPSRAPI_EVENT_ON_GRAPHICS_STREAM_PAUSED:
return "OnGraphicsStreamPaused";
break;
case DISPID_RDPSRAPI_EVENT_ON_GRAPHICS_STREAM_RESUMED:
return "OnGraphicsStreamResumed";
break;
case DISPID_RDPSRAPI_EVENT_ON_VIRTUAL_CHANNEL_JOIN:
return "OnChannelJoin";
break;
case DISPID_RDPSRAPI_EVENT_ON_VIRTUAL_CHANNEL_LEAVE:
return "OnChannelLeave";
break;
case DISPID_RDPSRAPI_EVENT_ON_VIRTUAL_CHANNEL_DATARECEIVED:
return "OnChannelDataReceived";
break;
case DISPID_RDPSRAPI_EVENT_ON_VIRTUAL_CHANNEL_SENDCOMPLETED:
return "OnChannelDataSent";
break;
case DISPID_RDPSRAPI_EVENT_ON_APPLICATION_OPEN:
return "OnApplicationOpen";
break;
case DISPID_RDPSRAPI_EVENT_ON_APPLICATION_CLOSE:
return "OnApplicationClose";
break;
case DISPID_RDPSRAPI_EVENT_ON_APPLICATION_UPDATE:
return "OnApplicationUpdate";
break;
case DISPID_RDPSRAPI_EVENT_ON_WINDOW_OPEN:
return "OnWindowOpen";
break;
case DISPID_RDPSRAPI_EVENT_ON_WINDOW_CLOSE:
return "OnWindowClose";
break;
case DISPID_RDPSRAPI_EVENT_ON_WINDOW_UPDATE:
return "OnWindowUpdate";
break;
case DISPID_RDPSRAPI_EVENT_ON_APPFILTER_UPDATE:
return "OnAppFilterUpdate";
break;
case DISPID_RDPSRAPI_EVENT_ON_SHARED_RECT_CHANGED:
return "OnSharedRectChanged";
break;
case DISPID_RDPSRAPI_EVENT_ON_FOCUSRELEASED:
return "OnFocusReleased";
break;
case DISPID_RDPSRAPI_EVENT_ON_SHARED_DESKTOP_SETTINGS_CHANGED:
return "OnSharedDesktopSettingsChanged";
break;
case DISPID_RDPAPI_EVENT_ON_BOUNDING_RECT_CHANGED:
return "OnViewingSizeChanged";
break;
}
return "OnUnknown";
}
static HRESULT STDMETHODCALLTYPE
Shadow_IRDPSessionEvents_QueryInterface(__RPC__in _IRDPSessionEvents* This,
/* [in] */ __RPC__in REFIID riid,
/* [annotation][iid_is][out] */
_COM_Outptr_ void** ppvObject)
{
*ppvObject = nullptr;
if (IsEqualIID(riid, &DIID__IRDPSessionEvents) || IsEqualIID(riid, &IID_IDispatch) ||
IsEqualIID(riid, &IID_IUnknown))
{
*ppvObject = This;
}
if (!(*ppvObject))
return E_NOINTERFACE;
This->lpVtbl->AddRef(This);
return S_OK;
}
static ULONG STDMETHODCALLTYPE Shadow_IRDPSessionEvents_AddRef(__RPC__in _IRDPSessionEvents* This)
{
Shadow_IRDPSessionEvents_RefCount++;
return Shadow_IRDPSessionEvents_RefCount;
}
static ULONG STDMETHODCALLTYPE Shadow_IRDPSessionEvents_Release(__RPC__in _IRDPSessionEvents* This)
{
if (!Shadow_IRDPSessionEvents_RefCount)
return 0;
Shadow_IRDPSessionEvents_RefCount--;
return Shadow_IRDPSessionEvents_RefCount;
}
static HRESULT STDMETHODCALLTYPE
Shadow_IRDPSessionEvents_GetTypeInfoCount(__RPC__in _IRDPSessionEvents* This,
/* [out] */ __RPC__out UINT* pctinfo)
{
WLog_INFO(TAG, "Shadow_IRDPSessionEvents_GetTypeInfoCount");
*pctinfo = 1;
return S_OK;
}
static HRESULT STDMETHODCALLTYPE
Shadow_IRDPSessionEvents_GetTypeInfo(__RPC__in _IRDPSessionEvents* This,
/* [in] */ UINT iTInfo,
/* [in] */ LCID lcid,
/* [out] */ __RPC__deref_out_opt ITypeInfo** ppTInfo)
{
WLog_INFO(TAG, "Shadow_IRDPSessionEvents_GetTypeInfo");
return E_NOTIMPL;
}
static HRESULT STDMETHODCALLTYPE Shadow_IRDPSessionEvents_GetIDsOfNames(
__RPC__in _IRDPSessionEvents* This,
/* [in] */ __RPC__in REFIID riid,
/* [size_is][in] */ __RPC__in_ecount_full(cNames) LPOLESTR* rgszNames,
/* [range][in] */ __RPC__in_range(0, 16384) UINT cNames,
/* [in] */ LCID lcid,
/* [size_is][out] */ __RPC__out_ecount_full(cNames) DISPID* rgDispId)
{
WLog_INFO(TAG, "Shadow_IRDPSessionEvents_GetIDsOfNames");
return E_NOTIMPL;
}
static HRESULT STDMETHODCALLTYPE Shadow_IRDPSessionEvents_Invoke(_IRDPSessionEvents* This,
/* [annotation][in] */
_In_ DISPID dispIdMember,
/* [annotation][in] */
_In_ REFIID riid,
/* [annotation][in] */
_In_ LCID lcid,
/* [annotation][in] */
_In_ WORD wFlags,
/* [annotation][out][in] */
_In_ DISPPARAMS* pDispParams,
/* [annotation][out] */
_Out_opt_ VARIANT* pVarResult,
/* [annotation][out] */
_Out_opt_ EXCEPINFO* pExcepInfo,
/* [annotation][out] */
_Out_opt_ UINT* puArgErr)
{
HRESULT hr;
VARIANT vr;
UINT uArgErr;
WLog_INFO(TAG, "%s (%ld)", GetRDPSessionEventString(dispIdMember), dispIdMember);
switch (dispIdMember)
{
case DISPID_RDPSRAPI_EVENT_ON_ATTENDEE_CONNECTED:
{
int level;
IDispatch* pDispatch;
IRDPSRAPIAttendee* pAttendee;
vr.vt = VT_DISPATCH;
vr.pdispVal = nullptr;
hr = DispGetParam(pDispParams, 0, VT_DISPATCH, &vr, &uArgErr);
if (FAILED(hr))
{
WLog_ERR(TAG, "%s DispGetParam(0, VT_DISPATCH) failure: 0x%08lX",
GetRDPSessionEventString(dispIdMember), hr);
return hr;
}
pDispatch = vr.pdispVal;
hr = pDispatch->lpVtbl->QueryInterface(pDispatch, &IID_IRDPSRAPIAttendee,
(void**)&pAttendee);
if (FAILED(hr))
{
WLog_INFO(TAG, "%s IDispatch::QueryInterface(IRDPSRAPIAttendee) failure: 0x%08lX",
GetRDPSessionEventString(dispIdMember), hr);
return hr;
}
level = CTRL_LEVEL_VIEW;
// level = CTRL_LEVEL_INTERACTIVE;
hr = pAttendee->lpVtbl->put_ControlLevel(pAttendee, level);
if (FAILED(hr))
{
WLog_INFO(TAG, "%s IRDPSRAPIAttendee::put_ControlLevel() failure: 0x%08lX",
GetRDPSessionEventString(dispIdMember), hr);
return hr;
}
pAttendee->lpVtbl->Release(pAttendee);
}
break;
case DISPID_RDPSRAPI_EVENT_ON_ATTENDEE_DISCONNECTED:
break;
case DISPID_RDPSRAPI_EVENT_ON_ATTENDEE_UPDATE:
break;
case DISPID_RDPSRAPI_EVENT_ON_ERROR:
break;
case DISPID_RDPSRAPI_EVENT_ON_VIEWER_CONNECTED:
break;
case DISPID_RDPSRAPI_EVENT_ON_VIEWER_DISCONNECTED:
break;
case DISPID_RDPSRAPI_EVENT_ON_VIEWER_AUTHENTICATED:
break;
case DISPID_RDPSRAPI_EVENT_ON_VIEWER_CONNECTFAILED:
break;
case DISPID_RDPSRAPI_EVENT_ON_CTRLLEVEL_CHANGE_REQUEST:
{
int level;
IDispatch* pDispatch;
IRDPSRAPIAttendee* pAttendee;
vr.vt = VT_INT;
vr.pdispVal = nullptr;
hr = DispGetParam(pDispParams, 1, VT_INT, &vr, &uArgErr);
if (FAILED(hr))
{
WLog_INFO(TAG, "%s DispGetParam(1, VT_INT) failure: 0x%08lX",
GetRDPSessionEventString(dispIdMember), hr);
return hr;
}
level = vr.intVal;
vr.vt = VT_DISPATCH;
vr.pdispVal = nullptr;
hr = DispGetParam(pDispParams, 0, VT_DISPATCH, &vr, &uArgErr);
if (FAILED(hr))
{
WLog_ERR(TAG, "%s DispGetParam(0, VT_DISPATCH) failure: 0x%08lX",
GetRDPSessionEventString(dispIdMember), hr);
return hr;
}
pDispatch = vr.pdispVal;
hr = pDispatch->lpVtbl->QueryInterface(pDispatch, &IID_IRDPSRAPIAttendee,
(void**)&pAttendee);
if (FAILED(hr))
{
WLog_INFO(TAG, "%s IDispatch::QueryInterface(IRDPSRAPIAttendee) failure: 0x%08lX",
GetRDPSessionEventString(dispIdMember), hr);
return hr;
}
hr = pAttendee->lpVtbl->put_ControlLevel(pAttendee, level);
if (FAILED(hr))
{
WLog_INFO(TAG, "%s IRDPSRAPIAttendee::put_ControlLevel() failure: 0x%08lX",
GetRDPSessionEventString(dispIdMember), hr);
return hr;
}
pAttendee->lpVtbl->Release(pAttendee);
}
break;
case DISPID_RDPSRAPI_EVENT_ON_GRAPHICS_STREAM_PAUSED:
break;
case DISPID_RDPSRAPI_EVENT_ON_GRAPHICS_STREAM_RESUMED:
break;
case DISPID_RDPSRAPI_EVENT_ON_VIRTUAL_CHANNEL_JOIN:
break;
case DISPID_RDPSRAPI_EVENT_ON_VIRTUAL_CHANNEL_LEAVE:
break;
case DISPID_RDPSRAPI_EVENT_ON_VIRTUAL_CHANNEL_DATARECEIVED:
break;
case DISPID_RDPSRAPI_EVENT_ON_VIRTUAL_CHANNEL_SENDCOMPLETED:
break;
case DISPID_RDPSRAPI_EVENT_ON_APPLICATION_OPEN:
break;
case DISPID_RDPSRAPI_EVENT_ON_APPLICATION_CLOSE:
break;
case DISPID_RDPSRAPI_EVENT_ON_APPLICATION_UPDATE:
break;
case DISPID_RDPSRAPI_EVENT_ON_WINDOW_OPEN:
break;
case DISPID_RDPSRAPI_EVENT_ON_WINDOW_CLOSE:
break;
case DISPID_RDPSRAPI_EVENT_ON_WINDOW_UPDATE:
break;
case DISPID_RDPSRAPI_EVENT_ON_APPFILTER_UPDATE:
break;
case DISPID_RDPSRAPI_EVENT_ON_SHARED_RECT_CHANGED:
break;
case DISPID_RDPSRAPI_EVENT_ON_FOCUSRELEASED:
break;
case DISPID_RDPSRAPI_EVENT_ON_SHARED_DESKTOP_SETTINGS_CHANGED:
break;
case DISPID_RDPAPI_EVENT_ON_BOUNDING_RECT_CHANGED:
break;
}
return S_OK;
}
static _IRDPSessionEventsVtbl Shadow_IRDPSessionEventsVtbl = {
/* IUnknown */
Shadow_IRDPSessionEvents_QueryInterface, Shadow_IRDPSessionEvents_AddRef,
Shadow_IRDPSessionEvents_Release,
/* IDispatch */
Shadow_IRDPSessionEvents_GetTypeInfoCount, Shadow_IRDPSessionEvents_GetTypeInfo,
Shadow_IRDPSessionEvents_GetIDsOfNames, Shadow_IRDPSessionEvents_Invoke
};
static _IRDPSessionEvents Shadow_IRDPSessionEvents = { &Shadow_IRDPSessionEventsVtbl };
static LRESULT CALLBACK ShadowWndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
switch (uMsg)
{
case WM_CLOSE:
DestroyWindow(hwnd);
break;
case WM_DESTROY:
PostQuitMessage(0);
break;
default:
return DefWindowProc(hwnd, uMsg, wParam, lParam);
break;
}
return 0;
}
int win_shadow_wds_wnd_init(winShadowSubsystem* subsystem)
{
HMODULE hModule;
HINSTANCE hInstance;
WNDCLASSEX wndClassEx = WINPR_C_ARRAY_INIT;
hModule = GetModuleHandle(nullptr);
wndClassEx.cbSize = sizeof(WNDCLASSEX);
wndClassEx.style = 0;
wndClassEx.lpfnWndProc = ShadowWndProc;
wndClassEx.cbClsExtra = 0;
wndClassEx.cbWndExtra = 0;
wndClassEx.hInstance = hModule;
wndClassEx.hIcon = nullptr;
wndClassEx.hCursor = nullptr;
wndClassEx.hbrBackground = nullptr;
wndClassEx.lpszMenuName = _T("ShadowWndMenu");
wndClassEx.lpszClassName = _T("ShadowWndClass");
wndClassEx.hIconSm = nullptr;
if (!RegisterClassEx(&wndClassEx))
{
WLog_ERR(TAG, "RegisterClassEx failure");
return -1;
}
hInstance = wndClassEx.hInstance;
subsystem->hWnd = CreateWindowEx(0, wndClassEx.lpszClassName, 0, 0, 0, 0, 0, 0, HWND_MESSAGE, 0,
hInstance, nullptr);
if (!subsystem->hWnd)
{
WLog_INFO(TAG, "CreateWindowEx failure");
return -1;
}
return 1;
}
int win_shadow_wds_init(winShadowSubsystem* subsystem)
{
int status = -1;
long left = 0;
long top = 0;
long right = 0;
long bottom = 0;
BSTR bstrAuthString = nullptr;
BSTR bstrGroupName = nullptr;
BSTR bstrPassword = nullptr;
BSTR bstrPropertyName = nullptr;
VARIANT varPropertyValue;
rdpAssistanceFile* file = nullptr;
IConnectionPoint* pCP = nullptr;
IConnectionPointContainer* pCPC = nullptr;
win_shadow_wds_wnd_init(subsystem);
HRESULT hr = OleInitialize(nullptr);
if (FAILED(hr))
{
WLog_ERR(TAG, "OleInitialize() failure");
return -1;
}
hr = CoInitializeEx(nullptr, COINIT_APARTMENTTHREADED);
if (FAILED(hr))
{
WLog_ERR(TAG, "CoInitialize() failure");
return -1;
}
hr = CoCreateInstance(&CLSID_RDPSession, nullptr, CLSCTX_ALL, &IID_IRDPSRAPISharingSession,
(void**)&(subsystem->pSharingSession));
if (FAILED(hr))
{
WLog_ERR(TAG, "CoCreateInstance(IRDPSRAPISharingSession) failure: 0x%08lX", hr);
return -1;
}
IUnknown* pUnknown = (IUnknown*)subsystem->pSharingSession;
hr = pUnknown->lpVtbl->QueryInterface(pUnknown, &IID_IConnectionPointContainer, (void**)&pCPC);
if (FAILED(hr))
{
WLog_ERR(TAG, "QueryInterface(IID_IConnectionPointContainer) failure: 0x%08lX", hr);
return -1;
}
pCPC->lpVtbl->FindConnectionPoint(pCPC, &DIID__IRDPSessionEvents, &pCP);
if (FAILED(hr))
{
WLog_ERR(
TAG,
"IConnectionPointContainer::FindConnectionPoint(_IRDPSessionEvents) failure: 0x%08lX",
hr);
return -1;
}
DWORD dwCookie = 0;
subsystem->pSessionEvents = &Shadow_IRDPSessionEvents;
subsystem->pSessionEvents->lpVtbl->AddRef(subsystem->pSessionEvents);
hr = pCP->lpVtbl->Advise(pCP, (IUnknown*)subsystem->pSessionEvents, &dwCookie);
if (FAILED(hr))
{
WLog_ERR(TAG, "IConnectionPoint::Advise(Shadow_IRDPSessionEvents) failure: 0x%08lX", hr);
return -1;
}
hr = subsystem->pSharingSession->lpVtbl->put_ColorDepth(subsystem->pSharingSession, 32);
if (FAILED(hr))
{
WLog_ERR(TAG, "IRDPSRAPISharingSession::put_ColorDepth() failure: 0x%08lX", hr);
return -1;
}
hr = subsystem->pSharingSession->lpVtbl->GetDesktopSharedRect(subsystem->pSharingSession, &left,
&top, &right, &bottom);
if (FAILED(hr))
{
WLog_ERR(TAG, "IRDPSRAPISharingSession::GetDesktopSharedRect() failure: 0x%08lX", hr);
return -1;
}
long width = right - left;
long height = bottom - top;
WLog_INFO(
TAG,
"GetDesktopSharedRect(): left: %ld top: %ld right: %ld bottom: %ld width: %ld height: %ld",
left, top, right, bottom, width, height);
hr = subsystem->pSharingSession->lpVtbl->get_VirtualChannelManager(
subsystem->pSharingSession, &(subsystem->pVirtualChannelMgr));
if (FAILED(hr))
{
WLog_ERR(TAG, "IRDPSRAPISharingSession::get_VirtualChannelManager() failure: 0x%08lX", hr);
return -1;
}
hr = subsystem->pSharingSession->lpVtbl->get_ApplicationFilter(
subsystem->pSharingSession, &(subsystem->pApplicationFilter));
if (FAILED(hr))
{
WLog_ERR(TAG, "IRDPSRAPISharingSession::get_ApplicationFilter() failure: 0x%08lX", hr);
return -1;
}
hr = subsystem->pSharingSession->lpVtbl->get_Attendees(subsystem->pSharingSession,
&(subsystem->pAttendeeMgr));
if (FAILED(hr))
{
WLog_ERR(TAG, "IRDPSRAPISharingSession::get_Attendees() failure: 0x%08lX", hr);
return -1;
}
hr = subsystem->pSharingSession->lpVtbl->get_Properties(subsystem->pSharingSession,
&(subsystem->pSessionProperties));
if (FAILED(hr))
{
WLog_ERR(TAG, "IRDPSRAPISharingSession::get_Properties() failure: 0x%08lX", hr);
return -1;
}
bstrPropertyName = SysAllocString(L"PortId");
varPropertyValue.vt = VT_I4;
varPropertyValue.intVal = 40000;
hr = subsystem->pSessionProperties->lpVtbl->put_Property(subsystem->pSessionProperties,
bstrPropertyName, varPropertyValue);
SysFreeString(bstrPropertyName);
if (FAILED(hr))
{
WLog_ERR(TAG, "IRDPSRAPISessionProperties::put_Property(PortId) failure: 0x%08lX", hr);
return -1;
}
bstrPropertyName = SysAllocString(L"DrvConAttach");
varPropertyValue.vt = VT_BOOL;
varPropertyValue.boolVal = VARIANT_TRUE;
hr = subsystem->pSessionProperties->lpVtbl->put_Property(subsystem->pSessionProperties,
bstrPropertyName, varPropertyValue);
SysFreeString(bstrPropertyName);
if (FAILED(hr))
{
WLog_ERR(TAG, "IRDPSRAPISessionProperties::put_Property(DrvConAttach) failure: 0x%08lX",
hr);
return -1;
}
bstrPropertyName = SysAllocString(L"PortProtocol");
varPropertyValue.vt = VT_I4;
// varPropertyValue.intVal = 0; // AF_UNSPEC
varPropertyValue.intVal = 2; // AF_INET
// varPropertyValue.intVal = 23; // AF_INET6
hr = subsystem->pSessionProperties->lpVtbl->put_Property(subsystem->pSessionProperties,
bstrPropertyName, varPropertyValue);
SysFreeString(bstrPropertyName);
if (FAILED(hr))
{
WLog_ERR(TAG, "IRDPSRAPISessionProperties::put_Property(PortProtocol) failure: 0x%08lX",
hr);
return -1;
}
hr = subsystem->pSharingSession->lpVtbl->Open(subsystem->pSharingSession);
if (FAILED(hr))
{
WLog_ERR(TAG, "IRDPSRAPISharingSession::Open() failure: 0x%08lX", hr);
return -1;
}
hr = subsystem->pSharingSession->lpVtbl->get_Invitations(subsystem->pSharingSession,
&(subsystem->pInvitationMgr));
if (FAILED(hr))
{
WLog_ERR(TAG, "IRDPSRAPISharingSession::get_Invitations() failure");
return -1;
}
bstrAuthString = SysAllocString(L"Shadow");
bstrGroupName = SysAllocString(L"ShadowGroup");
bstrPassword = SysAllocString(L"Shadow123!");
hr = subsystem->pInvitationMgr->lpVtbl->CreateInvitation(
subsystem->pInvitationMgr, bstrAuthString, bstrGroupName, bstrPassword, 5,
&(subsystem->pInvitation));
SysFreeString(bstrAuthString);
SysFreeString(bstrGroupName);
SysFreeString(bstrPassword);
if (FAILED(hr))
{
WLog_ERR(TAG, "IRDPSRAPIInvitationManager::CreateInvitation() failure: 0x%08lX", hr);
return -1;
}
file = subsystem->pAssistanceFile = freerdp_assistance_file_new();
if (!file)
{
WLog_ERR(TAG, "freerdp_assistance_file_new() failed");
return -1;
}
{
int status2 = -1;
char* ConnectionString2;
BSTR bstrConnectionString;
hr = subsystem->pInvitation->lpVtbl->get_ConnectionString(subsystem->pInvitation,
&bstrConnectionString);
if (FAILED(hr))
{
WLog_ERR(TAG, "IRDPSRAPIInvitation::get_ConnectionString() failure: 0x%08lX", hr);
return -1;
}
ConnectionString2 = ConvertWCharToUtf8Alloc(bstrConnectionString, nullptr);
SysFreeString(bstrConnectionString);
status2 = freerdp_assistance_set_connection_string2(file, ConnectionString2, "Shadow123!");
free(ConnectionString2);
if ((!ConnectionString2) || (status2 < 1))
{
WLog_ERR(TAG, "failed to convert connection string");
return -1;
}
}
freerdp_assistance_print_file(file, WLog_Get(TAG), WLOG_INFO);
status = win_shadow_rdp_init(subsystem);
if (status < 0)
{
WLog_ERR(TAG, "win_shadow_rdp_init() failure: %d", status);
return status;
}
rdpSettings* settings = subsystem->shw->settings;
if (!freerdp_assistance_populate_settings_from_assistance_file(file, settings))
return -1;
if (!freerdp_settings_set_string(settings, FreeRDP_Domain, "RDP"))
return -1;
if (!freerdp_settings_set_string(settings, FreeRDP_Username, "Shadow"))
return -1;
if (!freerdp_settings_set_bool(settings, FreeRDP_AutoLogonEnabled, TRUE))
return -1;
if (!freerdp_settings_set_uint32(settings, FreeRDP_DesktopWidth, width))
return -1;
if (!freerdp_settings_set_uint32(settings, FreeRDP_DesktopHeight, height))
return -1;
status = win_shadow_rdp_start(subsystem);
if (status < 0)
{
WLog_ERR(TAG, "win_shadow_rdp_start() failure: %d", status);
return status;
}
return 1;
}
int win_shadow_wds_uninit(winShadowSubsystem* subsystem)
{
if (subsystem->pSharingSession)
{
subsystem->pSharingSession->lpVtbl->Close(subsystem->pSharingSession);
subsystem->pSharingSession->lpVtbl->Release(subsystem->pSharingSession);
subsystem->pSharingSession = nullptr;
}
if (subsystem->pVirtualChannelMgr)
{
subsystem->pVirtualChannelMgr->lpVtbl->Release(subsystem->pVirtualChannelMgr);
subsystem->pVirtualChannelMgr = nullptr;
}
if (subsystem->pApplicationFilter)
{
subsystem->pApplicationFilter->lpVtbl->Release(subsystem->pApplicationFilter);
subsystem->pApplicationFilter = nullptr;
}
if (subsystem->pAttendeeMgr)
{
subsystem->pAttendeeMgr->lpVtbl->Release(subsystem->pAttendeeMgr);
subsystem->pAttendeeMgr = nullptr;
}
if (subsystem->pSessionProperties)
{
subsystem->pSessionProperties->lpVtbl->Release(subsystem->pSessionProperties);
subsystem->pSessionProperties = nullptr;
}
if (subsystem->pInvitationMgr)
{
subsystem->pInvitationMgr->lpVtbl->Release(subsystem->pInvitationMgr);
subsystem->pInvitationMgr = nullptr;
}
if (subsystem->pInvitation)
{
subsystem->pInvitation->lpVtbl->Release(subsystem->pInvitation);
subsystem->pInvitation = nullptr;
}
if (subsystem->pAssistanceFile)
{
freerdp_assistance_file_free(subsystem->pAssistanceFile);
subsystem->pAssistanceFile = nullptr;
}
if (subsystem->hWnd)
{
DestroyWindow(subsystem->hWnd);
subsystem->hWnd = nullptr;
}
if (subsystem->shw)
{
win_shadow_rdp_uninit(subsystem);
subsystem->shw = nullptr;
}
return 1;
}

View File

@@ -0,0 +1,48 @@
/**
* FreeRDP: A Remote Desktop Protocol Implementation
*
* Copyright 2014 Marc-Andre Moreau <marcandre.moreau@gmail.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.
*/
#ifndef FREERDP_SERVER_SHADOW_WIN_WDS_H
#define FREERDP_SERVER_SHADOW_WIN_WDS_H
#define WITH_WDS_API 1
#ifndef CINTERFACE
#define CINTERFACE
#endif
#include <rdpencomapi.h>
#ifndef DISPID_RDPAPI_EVENT_ON_BOUNDING_RECT_CHANGED
#define DISPID_RDPAPI_EVENT_ON_BOUNDING_RECT_CHANGED 340
#endif
#include "win_shadow.h"
#ifdef __cplusplus
extern "C"
{
#endif
WINPR_ATTR_NODISCARD int win_shadow_wds_init(winShadowSubsystem* subsystem);
WINPR_ATTR_NODISCARD int win_shadow_wds_uninit(winShadowSubsystem* subsystem);
#ifdef __cplusplus
}
#endif
#endif /* FREERDP_SERVER_SHADOW_WIN_WDS_H */