shadow: improve DXGI 1.2 error checking

This commit is contained in:
Marc-André Moreau 2014-07-18 17:26:21 -04:00
parent eae6efd23f
commit c45ddc783e
7 changed files with 410 additions and 170 deletions

View File

@ -55,6 +55,7 @@ typedef int (*pfnShadowSubsystemStop)(rdpShadowSubsystem* subsystem);
typedef void (*pfnShadowSubsystemFree)(rdpShadowSubsystem* subsystem); typedef void (*pfnShadowSubsystemFree)(rdpShadowSubsystem* subsystem);
typedef int (*pfnShadowSurfaceCopy)(rdpShadowSubsystem* subsystem); typedef int (*pfnShadowSurfaceCopy)(rdpShadowSubsystem* subsystem);
typedef int (*pfnShadowSurfaceUpdate)(rdpShadowSubsystem* subsystem, REGION16* region);
typedef int (*pfnShadowSynchronizeEvent)(rdpShadowSubsystem* subsystem, UINT32 flags); typedef int (*pfnShadowSynchronizeEvent)(rdpShadowSubsystem* subsystem, UINT32 flags);
typedef int (*pfnShadowKeyboardEvent)(rdpShadowSubsystem* subsystem, UINT16 flags, UINT16 code); typedef int (*pfnShadowKeyboardEvent)(rdpShadowSubsystem* subsystem, UINT16 flags, UINT16 code);
@ -72,8 +73,11 @@ struct rdp_shadow_client
BOOL mayView; BOOL mayView;
BOOL mayInteract; BOOL mayInteract;
HANDLE StopEvent; HANDLE StopEvent;
CRITICAL_SECTION lock;
REGION16 invalidRegion;
rdpShadowServer* server; rdpShadowServer* server;
rdpShadowSurface* lobby; rdpShadowSurface* lobby;
rdpShadowEncoder* encoder;
HANDLE vcm; HANDLE vcm;
EncomspServerContext* encomsp; EncomspServerContext* encomsp;
@ -85,15 +89,18 @@ struct rdp_shadow_server
void* ext; void* ext;
HANDLE thread; HANDLE thread;
HANDLE StopEvent; HANDLE StopEvent;
wArrayList* clients;
rdpShadowScreen* screen; rdpShadowScreen* screen;
rdpShadowSurface* surface; rdpShadowSurface* surface;
rdpShadowEncoder* encoder;
rdpShadowSubsystem* subsystem; rdpShadowSubsystem* subsystem;
DWORD port; DWORD port;
BOOL mayView; BOOL mayView;
BOOL mayInteract; BOOL mayInteract;
char* ConfigPath; char* ConfigPath;
char* CertificateFile;
char* PrivateKeyFile;
CRITICAL_SECTION lock;
freerdp_listener* listener; freerdp_listener* listener;
pfnShadowCreateSubsystem CreateSubsystem; pfnShadowCreateSubsystem CreateSubsystem;
}; };
@ -103,6 +110,7 @@ struct rdp_shadow_server
int monitorCount; \ int monitorCount; \
MONITOR_DEF monitors[16]; \ MONITOR_DEF monitors[16]; \
MONITOR_DEF virtualScreen; \ MONITOR_DEF virtualScreen; \
REGION16 invalidRegion; \
\ \
pfnShadowSubsystemInit Init; \ pfnShadowSubsystemInit Init; \
pfnShadowSubsystemUninit Uninit; \ pfnShadowSubsystemUninit Uninit; \
@ -111,6 +119,7 @@ struct rdp_shadow_server
pfnShadowSubsystemFree Free; \ pfnShadowSubsystemFree Free; \
\ \
pfnShadowSurfaceCopy SurfaceCopy; \ pfnShadowSurfaceCopy SurfaceCopy; \
pfnShadowSurfaceUpdate SurfaceUpdate; \
\ \
pfnShadowSynchronizeEvent SynchronizeEvent; \ pfnShadowSynchronizeEvent SynchronizeEvent; \
pfnShadowKeyboardEvent KeyboardEvent; \ pfnShadowKeyboardEvent KeyboardEvent; \

View File

@ -136,6 +136,87 @@ DEFINE_GUID(IID_IDXGIFactory2, 0x50c83a1c, 0xe072, 0x4c48, 0x87, 0xb0, 0x36, 0x3
DEFINE_GUID(IID_IDXGIAdapter2, 0x0AA1AE0A, 0xFA0E, 0x4B84, 0x86, 0x44, 0xE0, 0x5F, 0xF8, 0xE5, 0xAC, 0xB5); 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); 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";
}
return "DXGI_ERROR_UNKNOWN";
}
static void win_shadow_d3d11_module_init() static void win_shadow_d3d11_module_init()
{ {
if (d3d11_module) if (d3d11_module)
@ -155,39 +236,55 @@ int win_shadow_dxgi_init_duplication(winShadowSubsystem* subsystem)
UINT dTop, i = 0; UINT dTop, i = 0;
IDXGIOutput* pOutput; IDXGIOutput* pOutput;
DXGI_OUTPUT_DESC outputDesc; DXGI_OUTPUT_DESC outputDesc;
DXGI_OUTPUT_DESC* pOutputDesc;
D3D11_TEXTURE2D_DESC textureDesc; D3D11_TEXTURE2D_DESC textureDesc;
IDXGIDevice* DxgiDevice = NULL; IDXGIDevice* dxgiDevice = NULL;
IDXGIAdapter* DxgiAdapter = NULL; IDXGIAdapter* dxgiAdapter = NULL;
IDXGIOutput* DxgiOutput = NULL; IDXGIOutput* dxgiOutput = NULL;
IDXGIOutput1* DxgiOutput1 = NULL; IDXGIOutput1* dxgiOutput1 = NULL;
hr = subsystem->dxgiDevice->lpVtbl->QueryInterface(subsystem->dxgiDevice, hr = subsystem->dxgiDevice->lpVtbl->QueryInterface(subsystem->dxgiDevice,
&IID_IDXGIDevice, (void**) &DxgiDevice); &IID_IDXGIDevice, (void**) &dxgiDevice);
if (FAILED(hr)) if (FAILED(hr))
{
fprintf(stderr, "ID3D11Device::QueryInterface(IDXGIDevice) failure: %s (0x%04X)\n",
GetDxgiErrorString(hr), hr);
return -1; return -1;
}
hr = DxgiDevice->lpVtbl->GetParent(DxgiDevice, &IID_IDXGIAdapter, (void**) &DxgiAdapter); hr = dxgiDevice->lpVtbl->GetParent(dxgiDevice, &IID_IDXGIAdapter, (void**) &dxgiAdapter);
DxgiDevice->lpVtbl->Release(DxgiDevice); if (dxgiDevice)
DxgiDevice = NULL; {
dxgiDevice->lpVtbl->Release(dxgiDevice);
dxgiDevice = NULL;
}
if (FAILED(hr)) if (FAILED(hr))
{
fprintf(stderr, "IDXGIDevice::GetParent(IDXGIAdapter) failure: %s (0x%04X)\n",
GetDxgiErrorString(hr), hr);
return -1; return -1;
}
pOutput = NULL; pOutput = NULL;
ZeroMemory(&outputDesc, sizeof(outputDesc)); ZeroMemory(&outputDesc, sizeof(outputDesc));
while (DxgiAdapter->lpVtbl->EnumOutputs(DxgiAdapter, i, &pOutput) != DXGI_ERROR_NOT_FOUND) while (dxgiAdapter->lpVtbl->EnumOutputs(dxgiAdapter, i, &pOutput) != DXGI_ERROR_NOT_FOUND)
{ {
DXGI_OUTPUT_DESC* pDesc = &outputDesc; pOutputDesc = &outputDesc;
hr = pOutput->lpVtbl->GetDesc(pOutput, pDesc); hr = pOutput->lpVtbl->GetDesc(pOutput, pOutputDesc);
if (FAILED(hr)) if (FAILED(hr))
{
fprintf(stderr, "IDXGIOutput::GetDesc failure: %s (0x%04X)\n",
GetDxgiErrorString(hr), hr);
return -1; return -1;
}
if (pDesc->AttachedToDesktop) if (pOutputDesc->AttachedToDesktop)
dTop = i; dTop = i;
pOutput->lpVtbl->Release(pOutput); pOutput->lpVtbl->Release(pOutput);
@ -196,30 +293,51 @@ int win_shadow_dxgi_init_duplication(winShadowSubsystem* subsystem)
dTop = 0; /* screen id */ dTop = 0; /* screen id */
hr = DxgiAdapter->lpVtbl->EnumOutputs(DxgiAdapter, dTop, &DxgiOutput); hr = dxgiAdapter->lpVtbl->EnumOutputs(dxgiAdapter, dTop, &dxgiOutput);
DxgiAdapter->lpVtbl->Release(DxgiAdapter); if (dxgiAdapter)
DxgiAdapter = NULL; {
dxgiAdapter->lpVtbl->Release(dxgiAdapter);
dxgiAdapter = NULL;
}
if (FAILED(hr)) if (FAILED(hr))
{
fprintf(stderr, "IDXGIAdapter::EnumOutputs failure: %s (0x%04X)\n",
GetDxgiErrorString(hr), hr);
return -1; return -1;
}
hr = DxgiOutput->lpVtbl->QueryInterface(DxgiOutput, &IID_IDXGIOutput1, (void**) &DxgiOutput1); hr = dxgiOutput->lpVtbl->QueryInterface(dxgiOutput, &IID_IDXGIOutput1, (void**) &dxgiOutput1);
DxgiOutput->lpVtbl->Release(DxgiOutput); if (dxgiOutput)
DxgiOutput = NULL; {
dxgiOutput->lpVtbl->Release(dxgiOutput);
dxgiOutput = NULL;
}
if (FAILED(hr)) if (FAILED(hr))
{
fprintf(stderr, "IDXGIOutput::QueryInterface(IDXGIOutput1) failure: %s (0x%04X)\n",
GetDxgiErrorString(hr), hr);
return -1; return -1;
}
hr = DxgiOutput1->lpVtbl->DuplicateOutput(DxgiOutput1, (IUnknown*) subsystem->dxgiDevice, hr = dxgiOutput1->lpVtbl->DuplicateOutput(dxgiOutput1, (IUnknown*) subsystem->dxgiDevice,
&(subsystem->dxgiOutputDuplication)); &(subsystem->dxgiOutputDuplication));
DxgiOutput1->lpVtbl->Release(DxgiOutput1); if (dxgiOutput1)
DxgiOutput1 = NULL; {
dxgiOutput1->lpVtbl->Release(dxgiOutput1);
dxgiOutput1 = NULL;
}
if (FAILED(hr)) if (FAILED(hr))
{
fprintf(stderr, "IDXGIOutput1::DuplicateOutput failure: %s (0x%04X)\n",
GetDxgiErrorString(hr), hr);
return -1; return -1;
}
textureDesc.Width = subsystem->width; textureDesc.Width = subsystem->width;
textureDesc.Height = subsystem->height; textureDesc.Height = subsystem->height;
@ -237,7 +355,11 @@ int win_shadow_dxgi_init_duplication(winShadowSubsystem* subsystem)
&textureDesc, NULL, &(subsystem->dxgiStage)); &textureDesc, NULL, &(subsystem->dxgiStage));
if (FAILED(hr)) if (FAILED(hr))
{
fprintf(stderr, "ID3D11Device::CreateTexture2D failure: %s (0x%04X)\n",
GetDxgiErrorString(hr), hr);
return -1; return -1;
}
return 1; return 1;
} }
@ -268,7 +390,10 @@ int win_shadow_dxgi_init(winShadowSubsystem* subsystem)
} }
if (FAILED(hr)) if (FAILED(hr))
{
fprintf(stderr, "D3D11CreateDevice failure: 0x%04X\n", hr);
return -1; return -1;
}
win_shadow_dxgi_init_duplication(subsystem); win_shadow_dxgi_init_duplication(subsystem);
@ -317,6 +442,9 @@ int win_shadow_dxgi_fetch_frame_data(winShadowSubsystem* subsystem,
D3D11_BOX Box; D3D11_BOX Box;
DXGI_MAPPED_RECT mappedRect; DXGI_MAPPED_RECT mappedRect;
if ((width * height) < 1)
return 1;
Box.top = x; Box.top = x;
Box.left = y; Box.left = y;
Box.right = x + width; Box.right = x + width;
@ -331,12 +459,22 @@ int win_shadow_dxgi_fetch_frame_data(winShadowSubsystem* subsystem,
&IID_IDXGISurface, (void**) &(subsystem->dxgiSurface)); &IID_IDXGISurface, (void**) &(subsystem->dxgiSurface));
if (FAILED(hr)) if (FAILED(hr))
{
fprintf(stderr, "ID3D11Texture2D::QueryInterface(IDXGISurface) failure: %s 0x%04X\n",
GetDxgiErrorString(hr), hr);
return -1; return -1;
}
hr = subsystem->dxgiSurface->lpVtbl->Map(subsystem->dxgiSurface, &mappedRect, DXGI_MAP_READ); hr = subsystem->dxgiSurface->lpVtbl->Map(subsystem->dxgiSurface, &mappedRect, DXGI_MAP_READ);
if (FAILED(hr)) if (FAILED(hr))
{
fprintf(stderr, "IDXGISurface::Map failure: %s 0x%04X\n",
GetDxgiErrorString(hr), hr);
return -1; return -1;
}
subsystem->dxgiSurfaceMapped = TRUE;
*ppDstData = mappedRect.pBits; *ppDstData = mappedRect.pBits;
*pnDstStep = mappedRect.Pitch; *pnDstStep = mappedRect.Pitch;
@ -346,22 +484,26 @@ int win_shadow_dxgi_fetch_frame_data(winShadowSubsystem* subsystem,
int win_shadow_dxgi_release_frame_data(winShadowSubsystem* subsystem) int win_shadow_dxgi_release_frame_data(winShadowSubsystem* subsystem)
{ {
HRESULT hr;
if (subsystem->dxgiSurface) if (subsystem->dxgiSurface)
{
if (subsystem->dxgiSurfaceMapped)
{ {
subsystem->dxgiSurface->lpVtbl->Unmap(subsystem->dxgiSurface); subsystem->dxgiSurface->lpVtbl->Unmap(subsystem->dxgiSurface);
subsystem->dxgiSurfaceMapped = FALSE;
}
subsystem->dxgiSurface->lpVtbl->Release(subsystem->dxgiSurface); subsystem->dxgiSurface->lpVtbl->Release(subsystem->dxgiSurface);
subsystem->dxgiSurface = NULL; subsystem->dxgiSurface = NULL;
} }
hr = subsystem->dxgiOutputDuplication->lpVtbl->ReleaseFrame(subsystem->dxgiOutputDuplication); if (subsystem->dxgiFrameAcquired)
{
subsystem->dxgiOutputDuplication->lpVtbl->ReleaseFrame(subsystem->dxgiOutputDuplication);
subsystem->dxgiFrameAcquired = FALSE;
}
subsystem->pendingFrames = 0; subsystem->pendingFrames = 0;
if (FAILED(hr))
return -1;
return 1; return 1;
} }
@ -373,7 +515,7 @@ int win_shadow_dxgi_get_next_frame(winShadowSubsystem* subsystem)
UINT DataBufferSize = 0; UINT DataBufferSize = 0;
BYTE* DataBuffer = NULL; BYTE* DataBuffer = NULL;
if (subsystem->pendingFrames > 0) if (subsystem->dxgiFrameAcquired)
{ {
win_shadow_dxgi_release_frame_data(subsystem); win_shadow_dxgi_release_frame_data(subsystem);
} }
@ -387,11 +529,20 @@ int win_shadow_dxgi_get_next_frame(winShadowSubsystem* subsystem)
hr = subsystem->dxgiOutputDuplication->lpVtbl->AcquireNextFrame(subsystem->dxgiOutputDuplication, hr = subsystem->dxgiOutputDuplication->lpVtbl->AcquireNextFrame(subsystem->dxgiOutputDuplication,
0, &(subsystem->dxgiFrameInfo), &(subsystem->dxgiResource)); 0, &(subsystem->dxgiFrameInfo), &(subsystem->dxgiResource));
if (SUCCEEDED(hr))
{
subsystem->dxgiFrameAcquired = TRUE;
subsystem->pendingFrames = subsystem->dxgiFrameInfo.AccumulatedFrames;
}
if (hr == DXGI_ERROR_WAIT_TIMEOUT) if (hr == DXGI_ERROR_WAIT_TIMEOUT)
return 0; return 0;
if (FAILED(hr)) if (FAILED(hr))
{ {
fprintf(stderr, "IDXGIOutputDuplication::AcquireNextFrame failure: %s (0x%04X)\n",
GetDxgiErrorString(hr), hr);
if (hr == DXGI_ERROR_ACCESS_LOST) if (hr == DXGI_ERROR_ACCESS_LOST)
{ {
if (subsystem->dxgiDesktopImage) if (subsystem->dxgiDesktopImage)
@ -413,33 +564,23 @@ int win_shadow_dxgi_get_next_frame(winShadowSubsystem* subsystem)
return 0; return 0;
} }
else
{
hr = subsystem->dxgiOutputDuplication->lpVtbl->ReleaseFrame(subsystem->dxgiOutputDuplication);
if (FAILED(hr))
return -1;
return -1; return -1;
} }
}
hr = subsystem->dxgiResource->lpVtbl->QueryInterface(subsystem->dxgiResource, hr = subsystem->dxgiResource->lpVtbl->QueryInterface(subsystem->dxgiResource,
&IID_ID3D11Texture2D, (void**) &(subsystem->dxgiDesktopImage)); &IID_ID3D11Texture2D, (void**) &(subsystem->dxgiDesktopImage));
if (subsystem->dxgiResource)
{
subsystem->dxgiResource->lpVtbl->Release(subsystem->dxgiResource); subsystem->dxgiResource->lpVtbl->Release(subsystem->dxgiResource);
subsystem->dxgiResource = NULL; subsystem->dxgiResource = NULL;
}
if (FAILED(hr)) if (FAILED(hr))
return -1;
subsystem->pendingFrames = subsystem->dxgiFrameInfo.AccumulatedFrames;
if (subsystem->pendingFrames == 0)
{ {
hr = subsystem->dxgiOutputDuplication->lpVtbl->ReleaseFrame(subsystem->dxgiOutputDuplication); fprintf(stderr, "IDXGIResource::QueryInterface(ID3D11Texture2D) failure: %s (0x%04X)\n",
GetDxgiErrorString(hr), hr);
if (FAILED(hr))
return -1; return -1;
} }
@ -456,21 +597,13 @@ int win_shadow_dxgi_get_invalid_region(winShadowSubsystem* subsystem)
UINT numMoveRects; UINT numMoveRects;
UINT numDirtyRects; UINT numDirtyRects;
UINT UsedBufferSize; UINT UsedBufferSize;
rdpShadowServer* server;
rdpShadowScreen* screen;
RECTANGLE_16 invalidRect; RECTANGLE_16 invalidRect;
UINT MetadataBufferSize; UINT MetadataBufferSize;
UINT MoveRectsBufferSize; UINT MoveRectsBufferSize;
UINT DirtyRectsBufferSize; UINT DirtyRectsBufferSize;
UINT PointerShapeBufferSize;
RECT* pDirtyRectsBuffer; RECT* pDirtyRectsBuffer;
void* pPointerShapeBuffer;
DXGI_OUTDUPL_MOVE_RECT* pMoveRect; DXGI_OUTDUPL_MOVE_RECT* pMoveRect;
DXGI_OUTDUPL_MOVE_RECT* pMoveRectBuffer; DXGI_OUTDUPL_MOVE_RECT* pMoveRectBuffer;
DXGI_OUTDUPL_POINTER_SHAPE_INFO PointerShapeInfo;
server = subsystem->server;
screen = server->screen;
if (subsystem->dxgiFrameInfo.AccumulatedFrames == 0) if (subsystem->dxgiFrameInfo.AccumulatedFrames == 0)
return 0; return 0;
@ -501,7 +634,11 @@ int win_shadow_dxgi_get_invalid_region(winShadowSubsystem* subsystem)
MoveRectsBufferSize, pMoveRectBuffer, &MoveRectsBufferSize); MoveRectsBufferSize, pMoveRectBuffer, &MoveRectsBufferSize);
if (FAILED(hr)) if (FAILED(hr))
{
fprintf(stderr, "IDXGIOutputDuplication::GetFrameMoveRects failure: %s (0x%04X) Size: %d Total %d Used: %d\n",
GetDxgiErrorString(hr), hr, MoveRectsBufferSize, MetadataBufferSize, UsedBufferSize);
return -1; return -1;
}
/* GetFrameDirtyRects */ /* GetFrameDirtyRects */
@ -514,22 +651,11 @@ int win_shadow_dxgi_get_invalid_region(winShadowSubsystem* subsystem)
DirtyRectsBufferSize, pDirtyRectsBuffer, &DirtyRectsBufferSize); DirtyRectsBufferSize, pDirtyRectsBuffer, &DirtyRectsBufferSize);
if (FAILED(hr)) if (FAILED(hr))
{
fprintf(stderr, "IDXGIOutputDuplication::GetFrameDirtyRects failure: %s (0x%04X) Size: %d Total %d Used: %d\n",
GetDxgiErrorString(hr), hr, DirtyRectsBufferSize, MetadataBufferSize, UsedBufferSize);
return -1; return -1;
}
/* GetFramePointerShape */
UsedBufferSize += MoveRectsBufferSize;
PointerShapeBufferSize = MetadataBufferSize - UsedBufferSize;
pPointerShapeBuffer = (void*) &(subsystem->MetadataBuffer[UsedBufferSize]);
hr = subsystem->dxgiOutputDuplication->lpVtbl->GetFramePointerShape(subsystem->dxgiOutputDuplication,
PointerShapeBufferSize, pPointerShapeBuffer, &PointerShapeBufferSize, &PointerShapeInfo);
if (FAILED(hr))
return -1;
EnterCriticalSection(&(screen->lock));
numMoveRects = MoveRectsBufferSize / sizeof(DXGI_OUTDUPL_MOVE_RECT); numMoveRects = MoveRectsBufferSize / sizeof(DXGI_OUTDUPL_MOVE_RECT);
@ -544,7 +670,7 @@ int win_shadow_dxgi_get_invalid_region(winShadowSubsystem* subsystem)
invalidRect.right = (UINT16) pDstRect->right; invalidRect.right = (UINT16) pDstRect->right;
invalidRect.bottom = (UINT16) pDstRect->bottom; invalidRect.bottom = (UINT16) pDstRect->bottom;
region16_union_rect(&(screen->invalidRegion), &(screen->invalidRegion), &invalidRect); region16_union_rect(&(subsystem->invalidRegion), &(subsystem->invalidRegion), &invalidRect);
} }
numDirtyRects = DirtyRectsBufferSize / sizeof(RECT); numDirtyRects = DirtyRectsBufferSize / sizeof(RECT);
@ -558,11 +684,9 @@ int win_shadow_dxgi_get_invalid_region(winShadowSubsystem* subsystem)
invalidRect.right = (UINT16) pDirtyRect->right; invalidRect.right = (UINT16) pDirtyRect->right;
invalidRect.bottom = (UINT16) pDirtyRect->bottom; invalidRect.bottom = (UINT16) pDirtyRect->bottom;
region16_union_rect(&(screen->invalidRegion), &(screen->invalidRegion), &invalidRect); region16_union_rect(&(subsystem->invalidRegion), &(subsystem->invalidRegion), &invalidRect);
} }
LeaveCriticalSection(&(screen->lock));
return 1; return 1;
} }
@ -747,7 +871,6 @@ int win_shadow_surface_copy(winShadowSubsystem* subsystem)
int status; int status;
int nDstStep = 0; int nDstStep = 0;
BYTE* pDstData = NULL; BYTE* pDstData = NULL;
rdpShadowScreen* screen;
rdpShadowServer* server; rdpShadowServer* server;
rdpShadowSurface* surface; rdpShadowSurface* surface;
RECTANGLE_16 surfaceRect; RECTANGLE_16 surfaceRect;
@ -755,7 +878,6 @@ int win_shadow_surface_copy(winShadowSubsystem* subsystem)
server = subsystem->server; server = subsystem->server;
surface = server->surface; surface = server->surface;
screen = server->screen;
surfaceRect.left = surface->x; surfaceRect.left = surface->x;
surfaceRect.top = surface->y; surfaceRect.top = surface->y;
@ -763,7 +885,8 @@ int win_shadow_surface_copy(winShadowSubsystem* subsystem)
surfaceRect.bottom = surface->y + surface->height; surfaceRect.bottom = surface->y + surface->height;
region16_clear(&(surface->invalidRegion)); region16_clear(&(surface->invalidRegion));
region16_intersect_rect(&(surface->invalidRegion), &(screen->invalidRegion), &surfaceRect); region16_copy(&(surface->invalidRegion), &(subsystem->invalidRegion));
region16_intersect_rect(&(surface->invalidRegion), &(surface->invalidRegion), &surfaceRect);
if (region16_is_empty(&(surface->invalidRegion))) if (region16_is_empty(&(surface->invalidRegion)))
return 1; return 1;
@ -775,7 +898,7 @@ int win_shadow_surface_copy(winShadowSubsystem* subsystem)
width = extents->right - extents->left; width = extents->right - extents->left;
height = extents->bottom - extents->top; height = extents->bottom - extents->top;
printf("x: %d y: %d width: %d height: %d right: %d bottom: %d\n", printf("SurfaceCopy x: %d y: %d width: %d height: %d right: %d bottom: %d\n",
x, y, width, height, x + width, y + height); x, y, width, height, x + width, y + height);
status = win_shadow_dxgi_fetch_frame_data(subsystem, &pDstData, &nDstStep, x, y, width, height); status = win_shadow_dxgi_fetch_frame_data(subsystem, &pDstData, &nDstStep, x, y, width, height);
@ -783,10 +906,14 @@ int win_shadow_surface_copy(winShadowSubsystem* subsystem)
if (status < 0) if (status < 0)
return -1; return -1;
EnterCriticalSection(&(surface->lock));
freerdp_image_copy(surface->data, PIXEL_FORMAT_XRGB32, freerdp_image_copy(surface->data, PIXEL_FORMAT_XRGB32,
surface->scanline, x - surface->x, y - surface->y, width, height, surface->scanline, x - surface->x, y - surface->y, width, height,
pDstData, PIXEL_FORMAT_XRGB32, nDstStep, x, y); pDstData, PIXEL_FORMAT_XRGB32, nDstStep, x, y);
LeaveCriticalSection(&(surface->lock));
return 1; return 1;
} }
@ -832,14 +959,16 @@ void* win_shadow_subsystem_thread(winShadowSubsystem* subsystem)
#ifdef WITH_DXGI_1_2 #ifdef WITH_DXGI_1_2
int dxgi_status; int dxgi_status;
//win_shadow_invalidate_region(subsystem, 0, 0, subsystem->width, subsystem->height);
dxgi_status = win_shadow_dxgi_get_next_frame(subsystem); dxgi_status = win_shadow_dxgi_get_next_frame(subsystem);
if (subsystem->pendingFrames > 0)
{
dxgi_status = win_shadow_dxgi_get_invalid_region(subsystem); dxgi_status = win_shadow_dxgi_get_invalid_region(subsystem);
win_shadow_surface_copy(subsystem);
win_shadow_invalidate_region(subsystem, 0, 0, subsystem->width, subsystem->height); if (subsystem->SurfaceUpdate)
} subsystem->SurfaceUpdate((rdpShadowSubsystem*) subsystem, &(subsystem->invalidRegion));
region16_clear(&(subsystem->invalidRegion));
#endif #endif
dwInterval = 1000 / fps; dwInterval = 1000 / fps;
@ -941,6 +1070,8 @@ void win_shadow_subsystem_free(winShadowSubsystem* subsystem)
win_shadow_subsystem_uninit(subsystem); win_shadow_subsystem_uninit(subsystem);
region16_uninit(&(subsystem->invalidRegion));
free(subsystem); free(subsystem);
} }
@ -955,6 +1086,8 @@ winShadowSubsystem* win_shadow_subsystem_new(rdpShadowServer* server)
subsystem->server = server; subsystem->server = server;
region16_init(&(subsystem->invalidRegion));
subsystem->Init = (pfnShadowSubsystemInit) win_shadow_subsystem_init; subsystem->Init = (pfnShadowSubsystemInit) win_shadow_subsystem_init;
subsystem->Uninit = (pfnShadowSubsystemInit) win_shadow_subsystem_uninit; subsystem->Uninit = (pfnShadowSubsystemInit) win_shadow_subsystem_uninit;
subsystem->Start = (pfnShadowSubsystemStart) win_shadow_subsystem_start; subsystem->Start = (pfnShadowSubsystemStart) win_shadow_subsystem_start;

View File

@ -56,6 +56,8 @@ struct win_shadow_subsystem
UINT pendingFrames; UINT pendingFrames;
BYTE* MetadataBuffer; BYTE* MetadataBuffer;
UINT MetadataBufferSize; UINT MetadataBufferSize;
BOOL dxgiSurfaceMapped;
BOOL dxgiFrameAcquired;
ID3D11Device* dxgiDevice; ID3D11Device* dxgiDevice;
IDXGISurface* dxgiSurface; IDXGISurface* dxgiSurface;
ID3D11Texture2D* dxgiStage; ID3D11Texture2D* dxgiStage;

View File

@ -27,69 +27,8 @@
#include <winpr/thread.h> #include <winpr/thread.h>
#include <winpr/sysinfo.h> #include <winpr/sysinfo.h>
#include <winpr/tools/makecert.h>
#include "shadow.h" #include "shadow.h"
static const char* makecert_argv[6] =
{
"makecert",
"-rdp",
"-live",
"-silent",
"-y", "5"
};
static int makecert_argc = (sizeof(makecert_argv) / sizeof(char*));
int shadow_generate_certificate(rdpShadowClient* client)
{
char* filepath;
rdpContext* context;
rdpSettings* settings;
MAKECERT_CONTEXT* makecert;
rdpShadowServer* server = client->server;
context = (rdpContext*) client;
settings = context->settings;
if (!PathFileExistsA(server->ConfigPath))
CreateDirectoryA(server->ConfigPath, 0);
filepath = GetCombinedPath(server->ConfigPath, "shadow");
if (!filepath)
return -1;
if (!PathFileExistsA(filepath))
CreateDirectoryA(filepath, 0);
settings->CertificateFile = GetCombinedPath(filepath, "shadow.crt");
settings->PrivateKeyFile = GetCombinedPath(filepath, "shadow.key");
if ((!PathFileExistsA(settings->CertificateFile)) ||
(!PathFileExistsA(settings->PrivateKeyFile)))
{
makecert = makecert_context_new();
makecert_context_process(makecert, makecert_argc, (char**) makecert_argv);
makecert_context_set_output_file_name(makecert, "shadow");
if (!PathFileExistsA(settings->CertificateFile))
makecert_context_output_certificate_file(makecert, filepath);
if (!PathFileExistsA(settings->PrivateKeyFile))
makecert_context_output_private_key_file(makecert, filepath);
makecert_context_free(makecert);
}
free(filepath);
return 1;
}
void shadow_client_context_new(freerdp_peer* peer, rdpShadowClient* client) void shadow_client_context_new(freerdp_peer* peer, rdpShadowClient* client)
{ {
rdpSettings* settings; rdpSettings* settings;
@ -110,19 +49,36 @@ void shadow_client_context_new(freerdp_peer* peer, rdpShadowClient* client)
settings->TlsSecurity = TRUE; settings->TlsSecurity = TRUE;
settings->NlaSecurity = FALSE; settings->NlaSecurity = FALSE;
shadow_generate_certificate(client); settings->CertificateFile = _strdup(server->CertificateFile);
settings->PrivateKeyFile = _strdup(server->PrivateKeyFile);
client->inLobby = TRUE; client->inLobby = TRUE;
client->mayView = server->mayView; client->mayView = server->mayView;
client->mayInteract = server->mayInteract; client->mayInteract = server->mayInteract;
InitializeCriticalSectionAndSpinCount(&(client->lock), 4000);
region16_init(&(client->invalidRegion));
client->vcm = WTSOpenServerA((LPSTR) peer->context); client->vcm = WTSOpenServerA((LPSTR) peer->context);
client->StopEvent = CreateEvent(NULL, TRUE, FALSE, NULL); client->StopEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
client->encoder = shadow_encoder_new(server);
ArrayList_Add(server->clients, (void*) client);
} }
void shadow_client_context_free(freerdp_peer* peer, rdpShadowClient* client) void shadow_client_context_free(freerdp_peer* peer, rdpShadowClient* client)
{ {
rdpShadowServer* server = client->server;
ArrayList_Remove(server->clients, (void*) client);
DeleteCriticalSection(&(client->lock));
region16_uninit(&(client->invalidRegion));
WTSCloseServer((HANDLE) client->vcm); WTSCloseServer((HANDLE) client->vcm);
CloseHandle(client->StopEvent); CloseHandle(client->StopEvent);
@ -132,6 +88,12 @@ void shadow_client_context_free(freerdp_peer* peer, rdpShadowClient* client)
shadow_surface_free(client->lobby); shadow_surface_free(client->lobby);
client->lobby = NULL; client->lobby = NULL;
} }
if (client->encoder)
{
shadow_encoder_free(client->encoder);
client->encoder = NULL;
}
} }
BOOL shadow_client_capabilities(freerdp_peer* peer) BOOL shadow_client_capabilities(freerdp_peer* peer)
@ -189,7 +151,7 @@ BOOL shadow_client_activate(freerdp_peer* peer)
client->activated = TRUE; client->activated = TRUE;
client->inLobby = client->mayView ? FALSE : TRUE; client->inLobby = client->mayView ? FALSE : TRUE;
shadow_encoder_reset(client->server->encoder); shadow_encoder_reset(client->encoder);
return TRUE; return TRUE;
} }
@ -199,7 +161,7 @@ void shadow_client_surface_frame_acknowledge(rdpShadowClient* client, UINT32 fra
SURFACE_FRAME* frame; SURFACE_FRAME* frame;
wListDictionary* frameList; wListDictionary* frameList;
frameList = client->server->encoder->frameList; frameList = client->encoder->frameList;
frame = (SURFACE_FRAME*) ListDictionary_GetItemValue(frameList, (void*) (size_t) frameId); frame = (SURFACE_FRAME*) ListDictionary_GetItemValue(frameList, (void*) (size_t) frameId);
if (frame) if (frame)
@ -248,7 +210,7 @@ int shadow_client_send_surface_bits(rdpShadowClient* client, rdpShadowSurface* s
settings = context->settings; settings = context->settings;
server = client->server; server = client->server;
encoder = server->encoder; encoder = client->encoder;
pSrcData = surface->data; pSrcData = surface->data;
nSrcStep = surface->scanline; nSrcStep = surface->scanline;
@ -336,8 +298,6 @@ int shadow_client_send_surface_bits(rdpShadowClient* client, rdpShadowSurface* s
free(messages); free(messages);
} }
region16_clear(&(surface->invalidRegion));
if (encoder->frameAck) if (encoder->frameAck)
{ {
shadow_client_send_surface_frame_marker(client, SURFACECMD_FRAMEACTION_END, frameId); shadow_client_send_surface_frame_marker(client, SURFACECMD_FRAMEACTION_END, frameId);
@ -372,7 +332,7 @@ int shadow_client_send_bitmap_update(rdpShadowClient* client, rdpShadowSurface*
settings = context->settings; settings = context->settings;
server = client->server; server = client->server;
encoder = server->encoder; encoder = client->encoder;
pSrcData = surface->data; pSrcData = surface->data;
nSrcStep = surface->scanline; nSrcStep = surface->scanline;
@ -562,27 +522,39 @@ int shadow_client_send_surface_update(rdpShadowClient* client)
rdpShadowServer* server; rdpShadowServer* server;
rdpShadowSurface* surface; rdpShadowSurface* surface;
rdpShadowEncoder* encoder; rdpShadowEncoder* encoder;
REGION16 invalidRegion;
RECTANGLE_16 surfaceRect; RECTANGLE_16 surfaceRect;
const RECTANGLE_16* extents; const RECTANGLE_16* extents;
context = (rdpContext*) client; context = (rdpContext*) client;
settings = context->settings; settings = context->settings;
server = client->server; server = client->server;
encoder = server->encoder; encoder = client->encoder;
surface = client->inLobby ? client->lobby : server->surface; surface = client->inLobby ? client->lobby : server->surface;
EnterCriticalSection(&(client->lock));
region16_init(&invalidRegion);
region16_copy(&invalidRegion, &(client->invalidRegion));
region16_clear(&(client->invalidRegion));
LeaveCriticalSection(&(client->lock));
surfaceRect.left = surface->x; surfaceRect.left = surface->x;
surfaceRect.top = surface->y; surfaceRect.top = surface->y;
surfaceRect.right = surface->x + surface->width; surfaceRect.right = surface->x + surface->width;
surfaceRect.bottom = surface->y + surface->height; surfaceRect.bottom = surface->y + surface->height;
region16_intersect_rect(&(surface->invalidRegion), &(surface->invalidRegion), &surfaceRect); region16_intersect_rect(&invalidRegion, &invalidRegion, &surfaceRect);
if (region16_is_empty(&(surface->invalidRegion))) if (region16_is_empty(&invalidRegion))
{
region16_uninit(&invalidRegion);
return 1; return 1;
}
extents = region16_extents(&(surface->invalidRegion)); extents = region16_extents(&invalidRegion);
nXSrc = extents->left - surface->x; nXSrc = extents->left - surface->x;
nYSrc = extents->top - surface->y; nYSrc = extents->top - surface->y;
@ -608,9 +580,31 @@ int shadow_client_send_surface_update(rdpShadowClient* client)
status = shadow_client_send_bitmap_update(client, surface, nXSrc, nYSrc, nWidth, nHeight); status = shadow_client_send_bitmap_update(client, surface, nXSrc, nYSrc, nWidth, nHeight);
} }
region16_uninit(&invalidRegion);
return status; return status;
} }
int shadow_client_surface_update(rdpShadowClient* client, REGION16* region)
{
int index;
int numRects = 0;
const RECTANGLE_16* rects;
EnterCriticalSection(&(client->lock));
rects = region16_rects(region, &numRects);
for (index = 0; index < numRects; index++)
{
region16_union_rect(&(client->invalidRegion), &(client->invalidRegion), &rects[index]);
}
LeaveCriticalSection(&(client->lock));
return 1;
}
void* shadow_client_thread(rdpShadowClient* client) void* shadow_client_thread(rdpShadowClient* client)
{ {
int fps; int fps;
@ -633,7 +627,7 @@ void* shadow_client_thread(rdpShadowClient* client)
server = client->server; server = client->server;
screen = server->screen; screen = server->screen;
encoder = server->encoder; encoder = client->encoder;
subsystem = server->subsystem; subsystem = server->subsystem;
peer = ((rdpContext*) client)->peer; peer = ((rdpContext*) client)->peer;

View File

@ -25,6 +25,7 @@
extern "C" { extern "C" {
#endif #endif
int shadow_client_surface_update(rdpShadowClient* client, REGION16* region);
void shadow_client_accepted(freerdp_listener* instance, freerdp_peer* client); void shadow_client_accepted(freerdp_listener* instance, freerdp_peer* client);
#ifdef __cplusplus #ifdef __cplusplus

View File

@ -83,7 +83,7 @@ static int encomsp_change_participant_control_level(EncomspServerContext* contex
if (inLobby != client->inLobby) if (inLobby != client->inLobby)
{ {
shadow_encoder_reset(client->server->encoder); shadow_encoder_reset(client->encoder);
client->inLobby = inLobby; client->inLobby = inLobby;
} }

View File

@ -27,6 +27,8 @@
#include <freerdp/version.h> #include <freerdp/version.h>
#include <winpr/tools/makecert.h>
#ifndef _WIN32 #ifndef _WIN32
#include <sys/select.h> #include <sys/select.h>
#include <sys/signal.h> #include <sys/signal.h>
@ -226,6 +228,32 @@ int shadow_server_parse_command_line(rdpShadowServer* server, int argc, char** a
return status; return status;
} }
int shadow_server_surface_update(rdpShadowSubsystem* subsystem, REGION16* region)
{
int index;
int count;
wArrayList* clients;
rdpShadowServer* server;
rdpShadowClient* client;
server = subsystem->server;
clients = server->clients;
ArrayList_Lock(clients);
count = ArrayList_Count(clients);
for (index = 0; index < count; index++)
{
client = ArrayList_GetItem(clients, index);
shadow_client_surface_update(client, region);
}
ArrayList_Unlock(clients);
return 1;
}
void* shadow_server_thread(rdpShadowServer* server) void* shadow_server_thread(rdpShadowServer* server)
{ {
DWORD status; DWORD status;
@ -317,6 +345,59 @@ int shadow_server_stop(rdpShadowServer* server)
return 0; return 0;
} }
int shadow_server_init_certificate(rdpShadowServer* server)
{
char* filepath;
MAKECERT_CONTEXT* makecert;
const char* makecert_argv[6] =
{
"makecert",
"-rdp",
"-live",
"-silent",
"-y", "5"
};
int makecert_argc = (sizeof(makecert_argv) / sizeof(char*));
if (!PathFileExistsA(server->ConfigPath))
CreateDirectoryA(server->ConfigPath, 0);
filepath = GetCombinedPath(server->ConfigPath, "shadow");
if (!filepath)
return -1;
if (!PathFileExistsA(filepath))
CreateDirectoryA(filepath, 0);
server->CertificateFile = GetCombinedPath(filepath, "shadow.crt");
server->PrivateKeyFile = GetCombinedPath(filepath, "shadow.key");
if ((!PathFileExistsA(server->CertificateFile)) ||
(!PathFileExistsA(server->PrivateKeyFile)))
{
makecert = makecert_context_new();
makecert_context_process(makecert, makecert_argc, (char**) makecert_argv);
makecert_context_set_output_file_name(makecert, "shadow");
if (!PathFileExistsA(server->CertificateFile))
makecert_context_output_certificate_file(makecert, filepath);
if (!PathFileExistsA(server->PrivateKeyFile))
makecert_context_output_private_key_file(makecert, filepath);
makecert_context_free(makecert);
}
free(filepath);
return 1;
}
int shadow_server_init(rdpShadowServer* server) int shadow_server_init(rdpShadowServer* server)
{ {
int status; int status;
@ -325,6 +406,11 @@ int shadow_server_init(rdpShadowServer* server)
server->StopEvent = CreateEvent(NULL, TRUE, FALSE, NULL); server->StopEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
status = shadow_server_init_certificate(server);
if (status < 0)
return -1;
server->listener = freerdp_listener_new(); server->listener = freerdp_listener_new();
if (!server->listener) if (!server->listener)
@ -351,6 +437,8 @@ int shadow_server_init(rdpShadowServer* server)
if (!server->subsystem) if (!server->subsystem)
return -1; return -1;
server->subsystem->SurfaceUpdate = shadow_server_surface_update;
if (server->subsystem->Init) if (server->subsystem->Init)
{ {
status = server->subsystem->Init(server->subsystem); status = server->subsystem->Init(server->subsystem);
@ -364,11 +452,6 @@ int shadow_server_init(rdpShadowServer* server)
if (!server->screen) if (!server->screen)
return -1; return -1;
server->encoder = shadow_encoder_new(server);
if (!server->encoder)
return -1;
return 1; return 1;
} }
@ -382,18 +465,24 @@ int shadow_server_uninit(rdpShadowServer* server)
server->listener = NULL; server->listener = NULL;
} }
if (server->encoder)
{
shadow_encoder_free(server->encoder);
server->encoder = NULL;
}
if (server->subsystem) if (server->subsystem)
{ {
server->subsystem->Free(server->subsystem); server->subsystem->Free(server->subsystem);
server->subsystem = NULL; server->subsystem = NULL;
} }
if (server->CertificateFile)
{
free(server->CertificateFile);
server->CertificateFile = NULL;
}
if (server->PrivateKeyFile)
{
free(server->PrivateKeyFile);
server->PrivateKeyFile = NULL;
}
return 1; return 1;
} }
@ -417,6 +506,10 @@ rdpShadowServer* shadow_server_new()
if (!server->ConfigPath) if (!server->ConfigPath)
server->ConfigPath = GetKnownSubPath(KNOWN_PATH_XDG_CONFIG_HOME, "freerdp"); server->ConfigPath = GetKnownSubPath(KNOWN_PATH_XDG_CONFIG_HOME, "freerdp");
InitializeCriticalSectionAndSpinCount(&(server->lock), 4000);
server->clients = ArrayList_New(TRUE);
return server; return server;
} }
@ -425,6 +518,14 @@ void shadow_server_free(rdpShadowServer* server)
if (!server) if (!server)
return; return;
DeleteCriticalSection(&(server->lock));
if (server->clients)
{
ArrayList_Free(server->clients);
server->clients = NULL;
}
shadow_server_uninit(server); shadow_server_uninit(server);
free(server); free(server);