|
|
|
|
@@ -68,6 +68,9 @@ void BreakSink(int s)
|
|
|
|
|
if (agentHost != NULL) { MeshAgent_Stop(agentHost); }
|
|
|
|
|
}
|
|
|
|
|
#endif
|
|
|
|
|
#include <d3d11.h>
|
|
|
|
|
#include <dxgi.h>
|
|
|
|
|
#include <dxgi1_2.h>
|
|
|
|
|
|
|
|
|
|
#if defined(_LINKVM) && defined(__APPLE__)
|
|
|
|
|
extern void* kvm_server_mainloop(void *parm);
|
|
|
|
|
@@ -79,6 +82,246 @@ ILibTransport_DoneState kvm_serviceWriteSink(char *buffer, int bufferLen, void *
|
|
|
|
|
}
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
typedef int(*GdipLoadImageFromStream_func)(IStream* stream, void **image);
|
|
|
|
|
typedef int(*GdiplusStartup_func)(ULONG_PTR *token, void *input, void *output);
|
|
|
|
|
typedef int(*GdipSaveImageToStream_func)(void *image, IStream* stream, void* clsidEncoder, void* encoderParams);
|
|
|
|
|
typedef int(*GetImageEncodersSize_func)(UINT *numEncoders, UINT *size);
|
|
|
|
|
typedef int(*GetImageEncoders_func)(UINT numEncoders, UINT size, void *encoders);
|
|
|
|
|
|
|
|
|
|
GetImageEncoders_func _GetImageEncoders = NULL;
|
|
|
|
|
GetImageEncodersSize_func _GetImageEncodersSize = NULL;
|
|
|
|
|
GdipLoadImageFromStream_func _GdipLoadImageFromStream = NULL;
|
|
|
|
|
GdiplusStartup_func _GdiplusStartup = NULL;
|
|
|
|
|
GdipSaveImageToStream_func _GdipSaveImageToStream = NULL;
|
|
|
|
|
|
|
|
|
|
typedef HRESULT(*D3D11CreateDevice_func)(void *pAdapter, int DriverType, HMODULE Software, UINT Flags, int *pFeatureLevels, UINT FeatureLevels, UINT SDKVersion, void **ppDevice, UINT *pFeatureLevel, void **context);
|
|
|
|
|
typedef HRESULT(*GetParent_func)(void *self, void* iid, void **ppParent);
|
|
|
|
|
typedef ULONG(*Release_func)(void *self);
|
|
|
|
|
typedef UINT(*D3D11CalcSubresource_func)(UINT MipSlice, UINT ArraySlice, UINT MipLevels);
|
|
|
|
|
|
|
|
|
|
UINT defaultCompressionLevel = 50;
|
|
|
|
|
DWORD tilebuffersize = 0;
|
|
|
|
|
LPVOID tilebuffer = NULL;
|
|
|
|
|
int SCALED_WIDTH, SCREEN_WIDTH;
|
|
|
|
|
int SCALED_HEIGHT, SCREEN_HEIGHT;
|
|
|
|
|
|
|
|
|
|
extern void __jpeghelp2(void *x);
|
|
|
|
|
// Used to obtain the GUID for the image encoder.
|
|
|
|
|
int GetEncoderClsid(const WCHAR* format, CLSID* pClsid)
|
|
|
|
|
{
|
|
|
|
|
unsigned int num = 0, size = 0;
|
|
|
|
|
char* pImageCodecInfo = NULL;
|
|
|
|
|
|
|
|
|
|
_GetImageEncodersSize(&num, &size);
|
|
|
|
|
if (size == 0) return -1;
|
|
|
|
|
|
|
|
|
|
if ((pImageCodecInfo = (char*)(malloc(size))) == NULL) return -1;
|
|
|
|
|
_GetImageEncoders(num, size, (void*)pImageCodecInfo);
|
|
|
|
|
|
|
|
|
|
for (unsigned int j = 0; j < num; ++j)
|
|
|
|
|
{
|
|
|
|
|
WCHAR *tmp = ((WCHAR**)(pImageCodecInfo + (104 * j) + 64))[0];
|
|
|
|
|
if (wcsncmp(tmp, format, size) == 0)
|
|
|
|
|
{
|
|
|
|
|
*pClsid = ((CLSID*)(pImageCodecInfo + (104 * j)))[0];
|
|
|
|
|
free(pImageCodecInfo);
|
|
|
|
|
return j;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
free(pImageCodecInfo);
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Adjusts the screen size(width or height) to be exactly divisible by TILE_WIDTH
|
|
|
|
|
int adjust_screen_size(int pixles)
|
|
|
|
|
{
|
|
|
|
|
int extra = pixles % 32; // Assuming tile width and height will remain the same.
|
|
|
|
|
if (extra != 0) return pixles + 32 - extra;
|
|
|
|
|
return pixles;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Creates a BITMAPINFO object with required width and height
|
|
|
|
|
BITMAPINFO _get_bmp_info(int width, int height, int PIXEL_SIZE)
|
|
|
|
|
{
|
|
|
|
|
BITMAPINFO bmpInfo;
|
|
|
|
|
|
|
|
|
|
ZeroMemory(&bmpInfo, sizeof(BITMAPINFO));
|
|
|
|
|
bmpInfo.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
|
|
|
|
|
bmpInfo.bmiHeader.biBitCount = (WORD)(PIXEL_SIZE * 8);
|
|
|
|
|
bmpInfo.bmiHeader.biSize = 40;
|
|
|
|
|
bmpInfo.bmiHeader.biHeight = height;
|
|
|
|
|
bmpInfo.bmiHeader.biWidth = width;
|
|
|
|
|
bmpInfo.bmiHeader.biSizeImage = height * width * PIXEL_SIZE;
|
|
|
|
|
bmpInfo.bmiHeader.biPlanes = 1;
|
|
|
|
|
|
|
|
|
|
return bmpInfo;
|
|
|
|
|
}
|
|
|
|
|
// Extracts the required tile buffer from the desktop buffer
|
|
|
|
|
int _get_tile_buffer(int x, int y, int PIXEL_SIZE, void **buffer, void *desktop, int tilewidth, int tileheight)
|
|
|
|
|
{
|
|
|
|
|
void *target = *buffer;
|
|
|
|
|
for (int height = adjust_screen_size(SCALED_HEIGHT) - y - tileheight; height < adjust_screen_size(SCALED_HEIGHT) - y; height++)
|
|
|
|
|
{
|
|
|
|
|
memcpy_s(target, tilebuffersize, (const void *)((unsigned char *)desktop + (((height * adjust_screen_size(SCALED_WIDTH)) + x) * PIXEL_SIZE)), (size_t)(tilewidth * PIXEL_SIZE));
|
|
|
|
|
target = (void *)((unsigned char *)target + tilewidth * PIXEL_SIZE);
|
|
|
|
|
}
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int _calc_opt_compr_send(int x, int y, int PIXEL_SIZE, int captureWidth, int captureHeight, void* desktop, void ** buffer, int64_t *bufferSize)
|
|
|
|
|
{
|
|
|
|
|
BITMAPINFO bmpInfo;
|
|
|
|
|
LARGE_INTEGER Offset;
|
|
|
|
|
BITMAPFILEHEADER bmpFileHeader;
|
|
|
|
|
*buffer = NULL;
|
|
|
|
|
*bufferSize = 0;
|
|
|
|
|
|
|
|
|
|
// Get the bmpInfo structure
|
|
|
|
|
bmpInfo = _get_bmp_info(captureWidth, captureHeight, PIXEL_SIZE);
|
|
|
|
|
|
|
|
|
|
// Make sure a tile buffer is available. Most of the time, this is skipped.
|
|
|
|
|
if (tilebuffersize != bmpInfo.bmiHeader.biSizeImage)
|
|
|
|
|
{
|
|
|
|
|
if (tilebuffer != NULL) free(tilebuffer);
|
|
|
|
|
tilebuffersize = bmpInfo.bmiHeader.biSizeImage;
|
|
|
|
|
if ((tilebuffer = malloc(tilebuffersize)) == NULL) return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Get the final coalesced tile
|
|
|
|
|
_get_tile_buffer(x, y, PIXEL_SIZE, &tilebuffer, desktop, captureWidth, captureHeight);
|
|
|
|
|
|
|
|
|
|
bmpFileHeader.bfReserved1 = 0;
|
|
|
|
|
bmpFileHeader.bfReserved2 = 0;
|
|
|
|
|
bmpFileHeader.bfSize = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER) + bmpInfo.bmiHeader.biSizeImage;
|
|
|
|
|
bmpFileHeader.bfType = 'MB';
|
|
|
|
|
bmpFileHeader.bfOffBits = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER);
|
|
|
|
|
|
|
|
|
|
// Construct stream object.
|
|
|
|
|
IStream* bmpStream = NULL;
|
|
|
|
|
if (CreateStreamOnHGlobal(NULL, TRUE, (LPSTREAM*)&bmpStream) != S_OK)
|
|
|
|
|
{
|
|
|
|
|
ILibCriticalLog(NULL, __FILE__, __LINE__, 252, GetLastError());
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Write entire contents of the source BMP into this stream.
|
|
|
|
|
bmpStream->lpVtbl->Write(bmpStream, &bmpFileHeader, sizeof(BITMAPFILEHEADER), NULL);
|
|
|
|
|
bmpStream->lpVtbl->Write(bmpStream, &bmpInfo, sizeof(BITMAPINFOHEADER), NULL);
|
|
|
|
|
bmpStream->lpVtbl->Write(bmpStream, tilebuffer, bmpInfo.bmiHeader.biSizeImage, NULL);
|
|
|
|
|
|
|
|
|
|
// Move the stream pointer to the beginning of the stream.
|
|
|
|
|
Offset.QuadPart = 0;
|
|
|
|
|
if (bmpStream->lpVtbl->Seek(bmpStream, Offset, STREAM_SEEK_SET, NULL) != S_OK)
|
|
|
|
|
{
|
|
|
|
|
bmpStream->lpVtbl->Release(bmpStream);
|
|
|
|
|
ILibCriticalLog(NULL, __FILE__, __LINE__, 252, GetLastError());
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Construct GDI+ Image object from the BMP stream.
|
|
|
|
|
void *DIBImage;
|
|
|
|
|
_GdipLoadImageFromStream(bmpStream, &DIBImage);
|
|
|
|
|
|
|
|
|
|
// Create stream to receive the encoded JPEG.
|
|
|
|
|
IStream* jpegStream = NULL;
|
|
|
|
|
if (CreateStreamOnHGlobal(NULL, TRUE, (LPSTREAM*)&jpegStream) != S_OK)
|
|
|
|
|
{
|
|
|
|
|
//delete DIBImage;
|
|
|
|
|
bmpStream->lpVtbl->Release(bmpStream);
|
|
|
|
|
ILibCriticalLog(NULL, __FILE__, __LINE__, 252, GetLastError());
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
CLSID encoderClsid;
|
|
|
|
|
GetEncoderClsid(L"image/jpeg", &encoderClsid);
|
|
|
|
|
|
|
|
|
|
char encparms[40];
|
|
|
|
|
((uint32_t*)encparms)[0] = 1; // EncoderParameters::Count
|
|
|
|
|
util_hexToBuf("B5E45B1D4AFA2D459CDD5DB35105E7EB", 32, encparms + 8); // EncoderParameter::Guid
|
|
|
|
|
((uint32_t*)(24 + encparms))[0] = 1; // EncoderParameter::NumberOfValues
|
|
|
|
|
((uint32_t*)(28 + encparms))[0] = 4; // EncoderParameter::Type
|
|
|
|
|
((void**)(32 + encparms))[0] = (void*)&defaultCompressionLevel; // EncoderParameter::Value
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Save image stream into the stream object.
|
|
|
|
|
int SaveStatus = _GdipSaveImageToStream(DIBImage, jpegStream, &encoderClsid, (void*)encparms);
|
|
|
|
|
if (SaveStatus != S_OK)
|
|
|
|
|
{
|
|
|
|
|
//delete DIBImage;
|
|
|
|
|
bmpStream->lpVtbl->Release(bmpStream);
|
|
|
|
|
jpegStream->lpVtbl->Release(jpegStream);
|
|
|
|
|
ILibCriticalLog(NULL, __FILE__, __LINE__, 252, GetLastError());
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Get the size of the output stream
|
|
|
|
|
ULARGE_INTEGER Size;
|
|
|
|
|
Offset.QuadPart = 0;
|
|
|
|
|
if (jpegStream->lpVtbl->Seek(jpegStream, Offset, STREAM_SEEK_END, &Size) != S_OK)
|
|
|
|
|
{
|
|
|
|
|
//delete DIBImage;
|
|
|
|
|
bmpStream->lpVtbl->Release(bmpStream);
|
|
|
|
|
jpegStream->lpVtbl->Release(jpegStream);
|
|
|
|
|
ILibCriticalLog(NULL, __FILE__, __LINE__, 252, GetLastError());
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Move the image stream's pointer to its beginning.
|
|
|
|
|
Offset.QuadPart = 0;
|
|
|
|
|
if (jpegStream->lpVtbl->Seek(jpegStream, Offset, STREAM_SEEK_SET, NULL) != S_OK)
|
|
|
|
|
{
|
|
|
|
|
//delete DIBImage;
|
|
|
|
|
bmpStream->lpVtbl->Release(bmpStream);
|
|
|
|
|
jpegStream->lpVtbl->Release(jpegStream);
|
|
|
|
|
ILibCriticalLog(NULL, __FILE__, __LINE__, 252, GetLastError());
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Check if the tile is too large to send
|
|
|
|
|
DWORD jpegSize = (DWORD)Size.QuadPart;
|
|
|
|
|
|
|
|
|
|
// Save the image stream in memory.
|
|
|
|
|
char* Tile = (char*)ILibMemory_Allocate(jpegSize > 65500 ? (jpegSize + 16) : (jpegSize + 8), 0, NULL, NULL);
|
|
|
|
|
if (jpegStream->lpVtbl->Read(jpegStream, Tile + (jpegSize > 65500 ? 16 : 8), jpegSize, NULL) != S_OK)
|
|
|
|
|
{
|
|
|
|
|
//delete DIBImage;
|
|
|
|
|
free(Tile);
|
|
|
|
|
bmpStream->lpVtbl->Release(bmpStream);
|
|
|
|
|
jpegStream->lpVtbl->Release(jpegStream);
|
|
|
|
|
ILibCriticalLog(NULL, __FILE__, __LINE__, 252, GetLastError());
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Cleanup
|
|
|
|
|
//delete DIBImage;
|
|
|
|
|
bmpStream->lpVtbl->Release(bmpStream);
|
|
|
|
|
jpegStream->lpVtbl->Release(jpegStream);
|
|
|
|
|
|
|
|
|
|
*buffer = (unsigned char*)Tile;
|
|
|
|
|
*bufferSize = jpegSize + (jpegSize > 65500 ? 16 : 8);
|
|
|
|
|
|
|
|
|
|
//// Place the header
|
|
|
|
|
//if (jpegSize > 65500)
|
|
|
|
|
//{
|
|
|
|
|
// ((unsigned short*)*buffer)[0] = (unsigned short)htons((unsigned short)MNG_JUMBO); // Write the type
|
|
|
|
|
// ((unsigned short*)*buffer)[1] = (unsigned short)htons((unsigned short)8); // Write the size
|
|
|
|
|
// ((unsigned int*)*buffer)[1] = (unsigned int)htonl(jpegSize + 8); // Size of the Next Packet
|
|
|
|
|
// ((unsigned short*)*buffer)[4] = (unsigned short)htons((unsigned short)MNG_KVM_PICTURE); // Write the type
|
|
|
|
|
// ((unsigned short*)*buffer)[5] = 0; // RESERVED
|
|
|
|
|
// ((unsigned short*)*buffer)[6] = (unsigned short)htons((unsigned short)x); // X position
|
|
|
|
|
// ((unsigned short*)*buffer)[7] = (unsigned short)htons((unsigned short)y); // Y position
|
|
|
|
|
//}
|
|
|
|
|
//else
|
|
|
|
|
//{
|
|
|
|
|
// ((unsigned short*)*buffer)[0] = (unsigned short)htons((unsigned short)MNG_KVM_PICTURE); // Write the type
|
|
|
|
|
// ((unsigned short*)*buffer)[1] = (unsigned short)htons((unsigned short)*bufferSize); // Write the size
|
|
|
|
|
// ((unsigned short*)*buffer)[2] = (unsigned short)htons((unsigned short)x); // X position
|
|
|
|
|
// ((unsigned short*)*buffer)[3] = (unsigned short)htons((unsigned short)y); // Y position
|
|
|
|
|
//}
|
|
|
|
|
//return 0;
|
|
|
|
|
}
|
|
|
|
|
extern void __jpeghelp(void *x);
|
|
|
|
|
#ifdef WIN32
|
|
|
|
|
#define wmain_free(argv) for(argvi=0;argvi<(int)(ILibMemory_Size(argv)/sizeof(void*));++argvi){ILibMemory_Free(argv[argvi]);}ILibMemory_Free(argv);
|
|
|
|
|
int wmain(int argc, char **wargv)
|
|
|
|
|
@@ -95,6 +338,269 @@ int main(int argc, char **argv)
|
|
|
|
|
int integratedJavaScriptLen = 0;
|
|
|
|
|
int retCode = 0;
|
|
|
|
|
int capabilities = 0;
|
|
|
|
|
|
|
|
|
|
CLSID encoderClsid;
|
|
|
|
|
HRESULT hr;
|
|
|
|
|
HMODULE GDIP = LoadLibraryExW(L"Gdiplus.dll", NULL, LOAD_LIBRARY_SEARCH_SYSTEM32);
|
|
|
|
|
void *gdiptoken = NULL;
|
|
|
|
|
char gdipinput[24] = { 0 };
|
|
|
|
|
((int*)gdipinput)[0] = 1;
|
|
|
|
|
|
|
|
|
|
_GdipLoadImageFromStream = (GdipLoadImageFromStream_func)GetProcAddress(GDIP, "GdipLoadImageFromStream");
|
|
|
|
|
_GdiplusStartup = (GdiplusStartup_func)GetProcAddress(GDIP, "GdiplusStartup");
|
|
|
|
|
_GdipSaveImageToStream = (GdipSaveImageToStream_func)GetProcAddress(GDIP, "GdipSaveImageToStream");
|
|
|
|
|
_GetImageEncodersSize = (GetImageEncodersSize_func)GetProcAddress(GDIP, "GdipGetImageEncodersSize");
|
|
|
|
|
_GetImageEncoders = (GetImageEncoders_func)GetProcAddress(GDIP, "GdipGetImageEncoders");
|
|
|
|
|
_GdiplusStartup(&gdiptoken, gdipinput, NULL);
|
|
|
|
|
|
|
|
|
|
util_hexToBuf("B5E45B1D4AFA2D459CDD5DB35105E7EB", 32, ILibScratchPad);
|
|
|
|
|
|
|
|
|
|
GUID G;
|
|
|
|
|
util_hexToBuf("B5E45B1D4AFA2D459CDD5DB35105E7EB", 32, &G);
|
|
|
|
|
|
|
|
|
|
char encparms[40];
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
//EncoderParameters::Count = > 0
|
|
|
|
|
//EncoderParameters::Parameter = > 8
|
|
|
|
|
//EncoderParameter::Guid = > 0
|
|
|
|
|
//EncoderParameter::NumberOfValues = > 16
|
|
|
|
|
//EncoderParameter::Type = > 20
|
|
|
|
|
//EncoderParameter::Value = > 24
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
HMODULE D3D = LoadLibraryExW(L"D3D11.dll", NULL, LOAD_LIBRARY_SEARCH_SYSTEM32);
|
|
|
|
|
D3D11CreateDevice_func func = (D3D11CreateDevice_func)GetProcAddress(D3D, "D3D11CreateDevice");
|
|
|
|
|
D3D11CalcSubresource_func func2 = (D3D11CalcSubresource_func)GetProcAddress(D3D, "D3D11CalcSubresource");
|
|
|
|
|
|
|
|
|
|
void *lDevice = NULL;
|
|
|
|
|
int lFeatureLevel = 0;
|
|
|
|
|
ID3D11DeviceContext *lImmediateContext = NULL;
|
|
|
|
|
|
|
|
|
|
IID iid;
|
|
|
|
|
hr = IIDFromString(L"{54ec77fa-1377-44e6-8c32-88fd5f44c84c}", &iid);
|
|
|
|
|
|
|
|
|
|
// Create device
|
|
|
|
|
UINT gNumDriverTypes = 1;
|
|
|
|
|
for (UINT DriverTypeIndex = 0; DriverTypeIndex < gNumDriverTypes; ++DriverTypeIndex)
|
|
|
|
|
{
|
|
|
|
|
hr = func(NULL, D3D_DRIVER_TYPE_HARDWARE, NULL, 0, NULL, 0, D3D11_SDK_VERSION, &lDevice, &lFeatureLevel, &lImmediateContext);
|
|
|
|
|
|
|
|
|
|
if (SUCCEEDED(hr))
|
|
|
|
|
{
|
|
|
|
|
// Device creation success, no need to loop anymore
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
((ID3D11Device*)lDevice)->lpVtbl->Release(lDevice);
|
|
|
|
|
((ID3D11DeviceContext*)lImmediateContext)->lpVtbl->Release(lImmediateContext);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Get DXGI device
|
|
|
|
|
IDXGIDevice *lDxgiDevice;
|
|
|
|
|
hr = ((ID3D11Device*)lDevice)->lpVtbl->QueryInterface(lDevice, &iid, &lDxgiDevice);
|
|
|
|
|
|
|
|
|
|
// Get DXGI adapter
|
|
|
|
|
GetParent_func fnc = (GetParent_func)((void**)((void**)lDxgiDevice)[0])[6]; // GetParent
|
|
|
|
|
IID adapteriid;
|
|
|
|
|
void *adapter = NULL;
|
|
|
|
|
IIDFromString(L"{2411e7e1-12ac-4ccf-bd14-9798e8534dc0}", &adapteriid);
|
|
|
|
|
hr = fnc(lDxgiDevice, &adapteriid, &adapter);
|
|
|
|
|
|
|
|
|
|
((Release_func)((void**)((void**)lDxgiDevice)[0])[2])(lDxgiDevice); // Release
|
|
|
|
|
UINT Output = 0;
|
|
|
|
|
IDXGIOutput *lDxgiOutput = NULL;
|
|
|
|
|
hr = ((IDXGIAdapter*)adapter)->lpVtbl->EnumOutputs(adapter, Output, &lDxgiOutput); // Get output
|
|
|
|
|
((IDXGIAdapter*)adapter)->lpVtbl->Release(adapter);
|
|
|
|
|
|
|
|
|
|
DXGI_OUTPUT_DESC outdesc;
|
|
|
|
|
hr = lDxgiOutput->lpVtbl->GetDesc(lDxgiOutput, &outdesc);
|
|
|
|
|
|
|
|
|
|
IID output1IID;
|
|
|
|
|
IDXGIOutput1 *output1 = NULL;
|
|
|
|
|
IIDFromString(L"{00cddea8-939b-4b83-a340-a685226666cc}", &output1IID);
|
|
|
|
|
hr = lDxgiOutput->lpVtbl->QueryInterface(lDxgiOutput, &output1IID, &output1);
|
|
|
|
|
|
|
|
|
|
lDxgiOutput->lpVtbl->Release(lDxgiOutput);
|
|
|
|
|
|
|
|
|
|
IDXGIOutputDuplication *lDeskDupl = NULL;
|
|
|
|
|
|
|
|
|
|
// Create desktop duplication
|
|
|
|
|
hr = output1->lpVtbl->DuplicateOutput(output1, lDevice, &lDeskDupl);
|
|
|
|
|
lDxgiOutput->lpVtbl->Release(lDxgiOutput);
|
|
|
|
|
|
|
|
|
|
// Create GUI drawing texture
|
|
|
|
|
DXGI_OUTDUPL_DESC lOutputDuplDesc;
|
|
|
|
|
lDeskDupl->lpVtbl->GetDesc(lDeskDupl, &lOutputDuplDesc);
|
|
|
|
|
|
|
|
|
|
D3D11_TEXTURE2D_DESC desc;
|
|
|
|
|
ID3D11Texture2D *lGDIImage = NULL;
|
|
|
|
|
ID3D11Texture2D *lDestImage = NULL;
|
|
|
|
|
ID3D11Texture2D *lAcquiredDesktopImage = NULL;
|
|
|
|
|
|
|
|
|
|
desc.Width = lOutputDuplDesc.ModeDesc.Width;
|
|
|
|
|
desc.Height = lOutputDuplDesc.ModeDesc.Height;
|
|
|
|
|
desc.Format = lOutputDuplDesc.ModeDesc.Format;
|
|
|
|
|
desc.ArraySize = 1;
|
|
|
|
|
desc.BindFlags = D3D11_BIND_RENDER_TARGET;
|
|
|
|
|
desc.MiscFlags = D3D11_RESOURCE_MISC_GDI_COMPATIBLE;
|
|
|
|
|
desc.SampleDesc.Count = 1;
|
|
|
|
|
desc.SampleDesc.Quality = 0;
|
|
|
|
|
desc.MipLevels = 1;
|
|
|
|
|
desc.CPUAccessFlags = 0;
|
|
|
|
|
desc.Usage = D3D11_USAGE_DEFAULT;
|
|
|
|
|
hr = ((ID3D11Device*)lDevice)->lpVtbl->CreateTexture2D(lDevice, &desc, NULL, &lGDIImage);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Create CPU access texture
|
|
|
|
|
desc.Width = lOutputDuplDesc.ModeDesc.Width;
|
|
|
|
|
desc.Height = lOutputDuplDesc.ModeDesc.Height;
|
|
|
|
|
desc.Format = lOutputDuplDesc.ModeDesc.Format;
|
|
|
|
|
desc.ArraySize = 1;
|
|
|
|
|
desc.BindFlags = 0;
|
|
|
|
|
desc.MiscFlags = 0;
|
|
|
|
|
desc.SampleDesc.Count = 1;
|
|
|
|
|
desc.SampleDesc.Quality = 0;
|
|
|
|
|
desc.MipLevels = 1;
|
|
|
|
|
desc.CPUAccessFlags = D3D11_CPU_ACCESS_READ | D3D11_CPU_ACCESS_WRITE;
|
|
|
|
|
desc.Usage = D3D11_USAGE_STAGING;
|
|
|
|
|
hr = ((ID3D11Device*)lDevice)->lpVtbl->CreateTexture2D(lDevice, &desc, NULL, &lDestImage);
|
|
|
|
|
|
|
|
|
|
IDXGIResource *lDesktopResource;
|
|
|
|
|
DXGI_OUTDUPL_FRAME_INFO lFrameInfo;
|
|
|
|
|
int lTryCount = 4;
|
|
|
|
|
|
|
|
|
|
do
|
|
|
|
|
{
|
|
|
|
|
|
|
|
|
|
Sleep(100);
|
|
|
|
|
|
|
|
|
|
// Get new frame
|
|
|
|
|
hr = lDeskDupl->lpVtbl->AcquireNextFrame(
|
|
|
|
|
lDeskDupl,
|
|
|
|
|
250,
|
|
|
|
|
&lFrameInfo,
|
|
|
|
|
&lDesktopResource);
|
|
|
|
|
|
|
|
|
|
if (SUCCEEDED(hr))
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
if (hr == DXGI_ERROR_WAIT_TIMEOUT)
|
|
|
|
|
{
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
else if (FAILED(hr))
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
} while (--lTryCount > 0);
|
|
|
|
|
|
|
|
|
|
IID ID3D11Texture2D_IID;
|
|
|
|
|
IIDFromString(L"{6f15aaf2-d208-4e89-9ab4-489535d34f9c}", &ID3D11Texture2D_IID);
|
|
|
|
|
hr = lDesktopResource->lpVtbl->QueryInterface(lDesktopResource, &ID3D11Texture2D_IID, &lAcquiredDesktopImage);
|
|
|
|
|
lDesktopResource->lpVtbl->Release(lDesktopResource);
|
|
|
|
|
|
|
|
|
|
// Copy image into GDI drawing texture
|
|
|
|
|
lImmediateContext->lpVtbl->CopyResource(lImmediateContext, lGDIImage, lAcquiredDesktopImage);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Draw cursor image into GDI drawing texture
|
|
|
|
|
IID IDXGISurface1_IID;
|
|
|
|
|
IIDFromString(L"{4AE63092-6327-4c1b-80AE-BFE12EA32B86}", &IDXGISurface1_IID);
|
|
|
|
|
IDXGISurface1 *lIDXGISurface1 = NULL;
|
|
|
|
|
hr = lGDIImage->lpVtbl->QueryInterface(lGDIImage, &IDXGISurface1_IID, &lIDXGISurface1);
|
|
|
|
|
|
|
|
|
|
CURSORINFO lCursorInfo = { 0 };
|
|
|
|
|
lCursorInfo.cbSize = sizeof(lCursorInfo);
|
|
|
|
|
|
|
|
|
|
if (GetCursorInfo(&lCursorInfo) == TRUE)
|
|
|
|
|
{
|
|
|
|
|
if (lCursorInfo.flags == CURSOR_SHOWING)
|
|
|
|
|
{
|
|
|
|
|
POINT lCursorPosition = lCursorInfo.ptScreenPos;
|
|
|
|
|
DWORD lCursorSize = lCursorInfo.cbSize;
|
|
|
|
|
HDC lHDC;
|
|
|
|
|
|
|
|
|
|
lIDXGISurface1->lpVtbl->GetDC(lIDXGISurface1, FALSE, &lHDC);
|
|
|
|
|
|
|
|
|
|
DrawIconEx(
|
|
|
|
|
lHDC,
|
|
|
|
|
lCursorPosition.x,
|
|
|
|
|
lCursorPosition.y,
|
|
|
|
|
lCursorInfo.hCursor,
|
|
|
|
|
0,
|
|
|
|
|
0,
|
|
|
|
|
0,
|
|
|
|
|
0,
|
|
|
|
|
DI_NORMAL | DI_DEFAULTSIZE);
|
|
|
|
|
|
|
|
|
|
lIDXGISurface1->lpVtbl->ReleaseDC(lIDXGISurface1, NULL);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Copy image into CPU access texture
|
|
|
|
|
lImmediateContext->lpVtbl->CopyResource(lImmediateContext, lDestImage, lGDIImage);
|
|
|
|
|
|
|
|
|
|
// Copy from CPU access texture to bitmap buffer
|
|
|
|
|
D3D11_MAPPED_SUBRESOURCE resource;
|
|
|
|
|
UINT subresource = 0;
|
|
|
|
|
lImmediateContext->lpVtbl->Map(lImmediateContext, lDestImage, subresource, D3D11_MAP_READ_WRITE, 0, &resource);
|
|
|
|
|
|
|
|
|
|
BITMAPINFO lBmpInfo;
|
|
|
|
|
ZeroMemory(&lBmpInfo, sizeof(BITMAPINFO));
|
|
|
|
|
lBmpInfo.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
|
|
|
|
|
lBmpInfo.bmiHeader.biBitCount = 32;
|
|
|
|
|
lBmpInfo.bmiHeader.biCompression = BI_RGB;
|
|
|
|
|
lBmpInfo.bmiHeader.biWidth = lOutputDuplDesc.ModeDesc.Width;
|
|
|
|
|
lBmpInfo.bmiHeader.biHeight = lOutputDuplDesc.ModeDesc.Height;
|
|
|
|
|
lBmpInfo.bmiHeader.biPlanes = 1;
|
|
|
|
|
lBmpInfo.bmiHeader.biSizeImage = lOutputDuplDesc.ModeDesc.Width * lOutputDuplDesc.ModeDesc.Height * 4;
|
|
|
|
|
|
|
|
|
|
BYTE* pBuf;
|
|
|
|
|
ILibMemory_AllocateRaw(pBuf, lBmpInfo.bmiHeader.biSizeImage);
|
|
|
|
|
UINT lBmpRowPitch = lOutputDuplDesc.ModeDesc.Width * 4;
|
|
|
|
|
BYTE* sptr = (BYTE*)resource.pData;
|
|
|
|
|
BYTE* dptr = pBuf + lBmpInfo.bmiHeader.biSizeImage - lBmpRowPitch;
|
|
|
|
|
UINT lRowPitch = ((lBmpRowPitch < resource.RowPitch) ? lBmpRowPitch : resource.RowPitch);
|
|
|
|
|
|
|
|
|
|
for (size_t h = 0; h < lOutputDuplDesc.ModeDesc.Height; ++h)
|
|
|
|
|
{
|
|
|
|
|
memcpy_s(dptr, lBmpRowPitch, sptr, lRowPitch);
|
|
|
|
|
sptr += resource.RowPitch;
|
|
|
|
|
dptr -= lBmpRowPitch;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
char *desk = NULL;
|
|
|
|
|
int64_t deskSize = 0;
|
|
|
|
|
int vv = _calc_opt_compr_send(0, 0, 4, lOutputDuplDesc.ModeDesc.Width, lOutputDuplDesc.ModeDesc.Height, pBuf, &desk, &deskSize);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Save bitmap buffer into the file ScreenShot.bmp
|
|
|
|
|
FILE* lfile = NULL;
|
|
|
|
|
errno_t lerr = _wfopen_s(&lfile, L"C:\\TEST\\KVM.bmp", L"wb");
|
|
|
|
|
|
|
|
|
|
if (lfile != NULL)
|
|
|
|
|
{
|
|
|
|
|
|
|
|
|
|
BITMAPFILEHEADER bmpFileHeader;
|
|
|
|
|
|
|
|
|
|
bmpFileHeader.bfReserved1 = 0;
|
|
|
|
|
bmpFileHeader.bfReserved2 = 0;
|
|
|
|
|
bmpFileHeader.bfSize = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER) + lBmpInfo.bmiHeader.biSizeImage;
|
|
|
|
|
bmpFileHeader.bfType = 'MB';
|
|
|
|
|
bmpFileHeader.bfOffBits = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER);
|
|
|
|
|
|
|
|
|
|
fwrite(&bmpFileHeader, sizeof(BITMAPFILEHEADER), 1, lfile);
|
|
|
|
|
fwrite(&lBmpInfo.bmiHeader, sizeof(BITMAPINFOHEADER), 1, lfile);
|
|
|
|
|
fwrite(pBuf, lBmpInfo.bmiHeader.biSizeImage, 1, lfile);
|
|
|
|
|
|
|
|
|
|
fclose(lfile);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#ifdef WIN32
|
|
|
|
|
int argvi, argvsz;
|
|
|
|
|
|