Heres the code:
HRESULT DisplayPrintPropertySheet(HWND hWnd)
{
HRESULT hResult;
PRINTDLGEX pdx = {0};
LPPRINTPAGERANGE pPageRanges = NULL;
DWORD dwBytesWritten = 0L;
// Allocate an array of PRINTPAGERANGE structures.
pPageRanges = (LPPRINTPAGERANGE) GlobalAlloc(GPTR, 10 * sizeof(PRINTPAGERANGE));
if (!pPageRanges)
return E_OUTOFMEMORY;
// Initialize the PRINTDLGEX structure.
pdx.lStructSize = sizeof(PRINTDLGEX);
pdx.hwndOwner = hWnd;
pdx.hDevMode = NULL;
pdx.hDevNames = NULL;
pdx.hDC = NULL;
pdx.Flags = PD_RETURNDC | PD_COLLATE;
pdx.Flags2 = 0;
pdx.ExclusionFlags = 0;
pdx.nPageRanges = 0;
pdx.nMaxPageRanges = 10;
pdx.lpPageRanges = pPageRanges;
pdx.nMinPage = 1;
pdx.nMaxPage = 1000;
pdx.nCopies = 1;
pdx.hInstance = 0;
pdx.lpPrintTemplateName = NULL;
pdx.lpCallback = NULL;
pdx.nPropertyPages = 0;
pdx.lphPropertyPages = NULL;
pdx.nStartPage = START_PAGE_GENERAL;
pdx.dwResultAction = 0;
// Invoke the Print property sheet.
hResult = PrintDlgEx(&pdx);
if ((hResult == S_OK) && pdx.dwResultAction == PD_RESULT_PRINT)
{ //2976 // 3876 //210 //273
cout << "HORZRES: " << GetDeviceCaps(pdx.hDC,PHYSICALWIDTH)/GetDeviceCaps(pdx.hDC,LOGPIXELSX) << endl;
cout << "VERTRES : " <<GetDeviceCaps(pdx.hDC,PHYSICALHEIGHT)/GetDeviceCaps(pdx.hDC,LOGPIXELSY) << endl;
DOCINFO di = {0};
di.cbSize = sizeof(DOCINFO);
di.lpszDocName = _T("Scribble Printout");
di.lpszOutput = (LPTSTR) NULL;
di.lpszDatatype = "RAW";
di.fwType = 0;
StartDoc(pdx.hDC, &di);
StartPage(pdx.hDC);``
etMapMode(pdx.hDC, MM_HIENGLISH);
RECT rc;
rc.top = -1000;
rc.left = 500;
rc.right = 8000;
rc.bottom = -11000;
DrawText(pdx.hDC,"Legal Action Was Threatened",-1,&rc,DT_WORDBREAK);
EndPage(pdx.hDC);
EndDoc(pdx.hDC);
}
if (pdx.hDevMode != NULL)
GlobalFree(pdx.hDevMode);
if (pdx.hDevNames != NULL)
GlobalFree(pdx.hDevNames);
if (pdx.lpPageRanges != NULL)
GlobalFree(pPageRanges);
if (pdx.hDC != NULL)
DeleteDC(pdx.hDC);
return hResult;
}
The problem seems to be with DrawText.
This is what it's displaying via .xps:
Related
I use the following function to get the name of the connected WiFi connection. The function is called repeatedly every 4 seconds to monitor connection changes. But after a while, the function no longer works as before, and fails returning false.
bool GetConnectedConnectionsName(wstring connection_names[50], int& number)
{
HANDLE h_client = NULL;
DWORD dwMaxClient = 2;
DWORD dwCurVersion = 0;
DWORD result = 0;
DWORD dwRetVal = 0;
int iRet = 0;
WCHAR GuidString[39] = { 0 };
unsigned int i, j, k;
PWLAN_INTERFACE_INFO_LIST p_if_list = NULL;
PWLAN_INTERFACE_INFO p_if_info = NULL;
PWLAN_AVAILABLE_NETWORK_LIST p_bss_list = NULL;
PWLAN_AVAILABLE_NETWORK p_bss_entry = NULL;
int iRSSI = 0;
result = WlanOpenHandle(dwMaxClient, NULL, &dwCurVersion, &h_client);
if (result != ERROR_SUCCESS)
{
if (p_bss_list != NULL)
WlanFreeMemory(p_bss_list);
if (p_if_list != NULL)
WlanFreeMemory(p_if_list);
return false;
}
result = WlanEnumInterfaces(h_client, NULL, &p_if_list);
if (result != ERROR_SUCCESS)
{
if (p_bss_list != NULL)
WlanFreeMemory(p_bss_list);
if (p_if_list != NULL)
WlanFreeMemory(p_if_list);
return false;
}
for (i = 0; i < (int)p_if_list->dwNumberOfItems; i++)
{
p_if_info = (WLAN_INTERFACE_INFO*)&p_if_list->InterfaceInfo[i];
result = WlanGetAvailableNetworkList(h_client,
&p_if_info->InterfaceGuid,
0,
NULL,
&p_bss_list);
if (result != ERROR_SUCCESS)
{
if (p_bss_list != NULL)
WlanFreeMemory(p_bss_list);
if (p_if_list != NULL)
WlanFreeMemory(p_if_list);
return false;
}
else
{
number = 0;
for (j = 0; j < p_bss_list->dwNumberOfItems; j++)
{
p_bss_entry = (WLAN_AVAILABLE_NETWORK*)&p_bss_list->Network[j];
if (p_bss_entry->dwFlags && (p_bss_entry->dwFlags & WLAN_AVAILABLE_NETWORK_CONNECTED))
{
connection_names[number] = wstring(p_bss_entry->strProfileName);
number++;
}
}
}
}
if (p_bss_list != NULL)
WlanFreeMemory(p_bss_list);
if (p_if_list != NULL)
WlanFreeMemory(p_if_list);
return true;
}
What's wrong, and how can I solve the problem?
Good afternoon.
I am trying to write a program that will display pixels for me from the desktop, but I get an E_INVALIDARG error in the Map function.
Below I have attached my function and indicated with a comment where I got this error. I also inserted the D3D11_CREATE_DEVICE_DEBUG flag in the D3D11CreateDevice function, but it doesn't output anything. Please help.
BYTE* GetImageData()
{
if (pDupTex2D != NULL)
{
printf("Tap1\n");
/*
D3D11_TEXTURE2D_DESC description;
pDupTex2D->GetDesc(&description);
description.BindFlags = 0;
description.CPUAccessFlags = D3D11_CPU_ACCESS_READ | D3D11_CPU_ACCESS_WRITE;
description.Usage = D3D11_USAGE_STAGING;
description.Format = DXGI_FORMAT_B8G8R8A8_UNORM;*/
D3D11_TEXTURE2D_DESC Desc;
//Desc.Width = 3440;
//Desc.Height = 1440;
Desc.Format = DXGI_FORMAT_B8G8R8A8_UNORM;
Desc.Usage = D3D11_USAGE_STAGING;
Desc.BindFlags = 0;
Desc.CPUAccessFlags = D3D11_CPU_ACCESS_READ | D3D11_CPU_ACCESS_WRITE;
pDupTex2D->GetDesc(&Desc);
ID3D11Texture2D *texTemp = NULL;
HRESULT hr = pD3DDev->CreateTexture2D(&Desc, NULL, &texTemp);
std::cout << std::hex<<hr << std::endl;
if (FAILED(hr))
{
if (texTemp)
{
texTemp->Release();
texTemp = NULL;
}
return NULL;
}
printf("Tap2\n");
pCtx->CopyResource(texTemp, pDupTex2D);
D3D11_MAPPED_SUBRESOURCE mapped;
unsigned int subresource = D3D11CalcSubresource(0, 0, 0);
hr = pCtx->Map(texTemp, subresource, D3D11_MAP_READ_WRITE, 0, &mapped); // ERROR ===================================
std::cout << std::hex << hr << std::endl;
if (FAILED(hr))
{
texTemp->Release();
texTemp = NULL;
return NULL;
}
printf("Tap3\n");
unsigned char* captureData = new unsigned char[Desc.Width * Desc.Height * 4];
RtlZeroMemory(captureData, Desc.Width * Desc.Height * 4);
const int pitch = mapped.RowPitch;
unsigned char* source = static_cast<unsigned char*>(mapped.pData);
unsigned char* dest = captureData;
for (int i = 0; i < Desc.Height; i++) {
memcpy(captureData, source, Desc.Width * 4);
source += pitch;
captureData += Desc.Width * 4;
}
for (int i = 0; i < Desc.Width * Desc.Height * 4; i++) {
printf("h");
std::cout << "Pixel[%d] = %x\n" << i << dest[i] << std::endl;
}
pCtx->Unmap(texTemp, 0);
return dest;
}
else {
return NULL;
}
}
I am developing a game engine using DX11. My problem is that I am getting a read access violation because vertexShaderBuffer was nullptr.
bool TerrainShaderClass::InitializeShader(ID3D11Device* device, HWND hwnd, LPCSTR vsFileName, LPCSTR psFileName)
{
HRESULT result;
ID3D10Blob* errorMessage = nullptr;
ID3D10Blob* vertexShaderBuffer = nullptr;
ID3D10Blob* pixelShaderBuffer = nullptr;
D3D11_INPUT_ELEMENT_DESC polygonLayout[3];
unsigned int numElements;
D3D11_SAMPLER_DESC samplerDesc;
D3D11_BUFFER_DESC matrixBufferDesc;
D3D11_BUFFER_DESC lightBufferDesc;
result = D3DX11CompileFromFile(vsFileName, NULL, NULL, "TerrainVertexShader", "vs_5_0", D3D10_SHADER_ENABLE_STRICTNESS, 0, NULL,
&vertexShaderBuffer, &errorMessage, NULL);
if (FAILED(result))
{
if (errorMessage)
{
OutputShaderErrorMessage(errorMessage, hwnd, vsFileName);
}
else
{
MessageBox(hwnd, vsFileName, "Missing Shader File", MB_OK);
}
return false;
}
result = D3DX11CompileFromFile(psFileName, NULL, NULL, "TerrainPixelShader", "ps_5_0", D3D10_SHADER_ENABLE_STRICTNESS, 0, NULL,
&pixelShaderBuffer, &errorMessage, NULL);
if (FAILED(result))
{
if (errorMessage)
{
OutputShaderErrorMessage(errorMessage, hwnd, psFileName);
}
else
{
MessageBox(hwnd, psFileName, "Missing Shader File", MB_OK);
}
return false;
}
result = device->CreateVertexShader(vertexShaderBuffer->GetBufferPointer(), vertexShaderBuffer->GetBufferSize(), NULL,
&m_vertexShader);
if (FAILED(result))
{
return false;
}
result = device->CreatePixelShader(pixelShaderBuffer->GetBufferPointer(), pixelShaderBuffer->GetBufferSize(), NULL,
&m_pixelShader);
if (FAILED(result))
{
return false;
}
// This setup needs to match the VertexType stucture in the ModelClass and in the shader.
polygonLayout[0].SemanticName = "POSITION";
polygonLayout[0].SemanticIndex = 0;
polygonLayout[0].Format = DXGI_FORMAT_R32G32B32_FLOAT;
polygonLayout[0].InputSlot = 0;
polygonLayout[0].AlignedByteOffset = 0;
polygonLayout[0].InputSlotClass = D3D11_INPUT_PER_VERTEX_DATA;
polygonLayout[0].InstanceDataStepRate = 0;
polygonLayout[1].SemanticName = "TEXCOORD";
polygonLayout[1].SemanticIndex = 0;
polygonLayout[1].Format = DXGI_FORMAT_R32G32_FLOAT;
polygonLayout[1].InputSlot = 0;
polygonLayout[1].AlignedByteOffset = D3D11_APPEND_ALIGNED_ELEMENT;
polygonLayout[1].InputSlotClass = D3D11_INPUT_PER_VERTEX_DATA;
polygonLayout[1].InstanceDataStepRate = 0;
polygonLayout[2].SemanticName = "NORMAL";
polygonLayout[2].SemanticIndex = 0;
polygonLayout[2].Format = DXGI_FORMAT_R32G32B32_FLOAT;
polygonLayout[2].InputSlot = 0;
polygonLayout[2].AlignedByteOffset = D3D11_APPEND_ALIGNED_ELEMENT;
polygonLayout[2].InputSlotClass = D3D11_INPUT_PER_VERTEX_DATA;
polygonLayout[2].InstanceDataStepRate = 0;
polygonLayout[3].SemanticName = "COLOR";
polygonLayout[3].SemanticIndex = 0;
polygonLayout[3].Format = DXGI_FORMAT_R32G32B32_FLOAT;
polygonLayout[3].InputSlot = 0;
polygonLayout[3].AlignedByteOffset = D3D11_APPEND_ALIGNED_ELEMENT;
polygonLayout[3].InputSlotClass = D3D11_INPUT_PER_VERTEX_DATA;
polygonLayout[3].InstanceDataStepRate = 0;
numElements = sizeof(polygonLayout) / sizeof(polygonLayout[0]);
result = device->CreateInputLayout(polygonLayout, numElements, vertexShaderBuffer->GetBufferPointer(),
vertexShaderBuffer->GetBufferSize(), &m_layout);
if (FAILED(result))
{
return false;
}
vertexShaderBuffer->Release();
vertexShaderBuffer = nullptr;
pixelShaderBuffer->Release();
pixelShaderBuffer = nullptr;
//Continues
When the code reaches polygonLayout[3].InputSlotClass = D3D11_INPUT_PER_VERTEX_DATA;, the buffer is set as normal. But after that line ( polygonLayout[3].InstanceDataStepRate = 0;) the value goes null for no appearant reason, with the
result = device->CreateInputLayout(polygonLayout, numElements, vertexShaderBuffer->GetBufferPointer(),
vertexShaderBuffer->GetBufferSize(), &m_layout);
line throwing the exception.
I tried searching online with no results. Any help is much appreciated. Thanks in advance.
polygonLayout array contains only 3 items so when you fill polygonLayout[3] you are producing buffer overrun and face Undefined Behavior (potentially corrupting other variables stored on the stack). It would be a good idea to 1) make it contain 4 items; 2) use array wrapper with (debug) indexing check:
::std::array<D3D11_INPUT_ELEMENT_DESC, 4> polygonLayout;
I'm trying to share an array of structs containing 2 dynamic arrays using shared memory to use the structs in another process. So far I can share an array of structs but these do not contain dynamic arrays yet. Any help on completing this problem would be great.
Expected:
typedef struct {
int id;
int type;
int count;
int[] values;
int[] settings;
} Entry;
Current code:
typedef struct {
int id;
int type;
int count;
} Entry;
BOOL DumpEntries(TCHAR* memName) {
int size = entries.size() * sizeof(Entry) + sizeof(DWORD);
::hMapObject = CreateFileMapping(INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE, 0, size, memName);
if (::hMapObject == NULL) {
return FALSE;
}
::vMapData = MapViewOfFile(::hMapObject, FILE_MAP_ALL_ACCESS, 0, 0, size);
if (::vMapData == NULL) {
CloseHandle(::hMapObject);
return FALSE;
}
(*(DWORD*)::vMapData) = entries.size();
Entry* eArray = (Entry*)(((DWORD*)::vMapData) + 1);
for(int i = entries.size() - 1; i >= 0; i--) eArray[i] = entries.at(i);
UnmapViewOfFile(::vMapData);
return TRUE;
}
BOOL ReadEntries(TCHAR* memName, Entry** entries, DWORD &number_of_entries) {
HANDLE hMapFile = OpenFileMapping(FILE_MAP_ALL_ACCESS, FALSE, memName);
if (hMapFile == NULL) {
return FALSE;
}
DWORD *num_entries = (DWORD*)MapViewOfFile(hMapFile, FILE_MAP_ALL_ACCESS, 0, 0, 0);
if (num_entries == NULL) {
CloseHandle(hMapFile);
return FALSE;
}
number_of_entries = *num_entries;
if(number_of_entries == 0)
{
// special case: when no entries was found in buffer
*entries = NULL;
return true;
}
Entry* tmpEntries = (Entry*)(num_entries + 1);
*entries = new Entry[*num_entries];
for (UINT i = 0; i < *num_entries; i++) {
(*entries)[i] = tmpEntries[i];
}
UnmapViewOfFile(num_entries);
CloseHandle(hMapFile);
return TRUE;
}
You can't pass pointers across process boundaries, so you can't store pointers inside the struct items that you put in the shared memory. What you can do is allocate the shared memory block itself to be large enough to hold all of the array data, and then use offsets to access the various arrays as needed, eg:
typedef struct
{
int id;
int type;
int count;
int *values;
int *settings;
} Entry;
#pragma pack(push, 1)
typedef struct
{
int id;
int type;
int count;
DWORD values_offset;
DWORD values_count; // if different than 'int count'
DWORD settings_offset;
DWORD settings_count; // if different than 'int count'
} SharedMemEntry;
#pragma pack(pop)
BOOL DumpEntries(TCHAR* memName)
{
DWORD NumValues = 0;
DWORD NumSettings = 0;
// or whatever your container actually is...
for(std::vector<Entry>::reverse_iterator iter = entries.rbegin();
iter != entries.rend(); ++iter)
{
Entry &e = *iter;
// or whatever you have to do to calculate how many
// integers are in the values[] and settings[] arrays...
//
NumValues += e.count;
NumSettings += e.count;
}
DWORD memsize = sizeof(DWORD) +
(entries.size() * sizeof(SharedMemEntry)) +
(sizeof(int) * NumValues) +
(sizeof(int) * NumSettings);
if (hMapObject != NULL)
CloseHandle(hMapObject);
hMapObject = CreateFileMapping(INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE, 0, memsize, memName);
if (hMapObject == NULL) {
return FALSE;
}
BYTE *vMapData = (BYTE*) MapViewOfFile(hMapObject, FILE_MAP_WRITE, 0, 0, memsize);
if (vMapData == NULL) {
CloseHandle(hMapObject);
hMapObject = NULL;
return FALSE;
}
DWORD *pEntryCount = (DWORD*) vMapData;
*pEntryCount = entries.size();
SharedMemEntry* pEntries = (SharedMemEntry*) (pEntryCount + 1);
int *pValues = (int*) (pEntries + entries.size());
int *pSettings = (int*) (pValues + NumValues);
// or whatever your container actually is...
for(std::vector<Entry>::reverse_iterator iter = entries.rbegin();
iter != entries.rend(); ++iter)
{
Entry &e = *iter;
SharedMemEntry &eEntry = *pEntries++;
eEntry.id = e.id;
eEntry.type = e.type;
eEntry.count = e.count;
eEntry.values_offset = ((BYTE*)pValues - vMapData);
eEntry.values_count = e.count; // or whatever you need...
for(DWORD k = 0; k < eEntry.values_count; ++k) {
*pValues++ = e.values[k];
}
eEntry.settings_offset = ((BYTE*)pSettings - vMapData);
eEntry.settings_count = e.count; // or whatever you need...
for(DWORD k = 0; k < eEntry.settings_count; ++k) {
*pSettings++ = e.settings[k];
}
}
UnmapViewOfFile(vMapData);
return TRUE;
}
BOOL ReadEntries(TCHAR* memName, Entry** entries, DWORD &num_entries)
{
HANDLE hMapFile = OpenFileMapping(FILE_MAP_READ, FALSE, memName);
if (hMapFile == NULL) {
return FALSE;
}
BYTE *vMapData = (BYTE*) MapViewOfFile(hMapFile, FILE_MAP_READ, 0, 0, 0);
if (vMapData == NULL) {
CloseHandle(hMapFile);
return FALSE;
}
DWORD *pEntryCount = (DWORD*) vMapData;
num_entries = *pEntryCount;
if (num_entries == 0)
{
// special case: when no entries was found in buffer
*entries = NULL;
}
else
{
SharedMemEntry *pEntries = (SharedMemEntry*) (pEntryCount + 1);
*entries = new Entry[num_entries];
for (DWORD i = 0; i < num_entries; ++i)
{
Entry &e = (*entries)[i];
SharedMemEntry &eEntry = pEntries[i];
e.id = eEntry.id;
e.type = eEntry.type;
e.count = eEntry.count;
e.values = new int[eEntry.values_count];
e.settings = new int[eEntry.settings_count];
int *pValues = (int*) (vMapData + eEntry.values_offset);
for(DWORD j = 0; j < eEntry.values_count; ++j) {
e.values[j] = pValues[j];
}
int *pSettings = (int*) (vMapData + eEntry.settings_offset);
for(DWORD j = 0; j < eEntry.settings_count; ++j) {
e.settings[j] = pSettings[j];
}
}
}
UnmapViewOfFile(vMapData);
CloseHandle(hMapFile);
return TRUE;
}
Alternatively, you should consider automating the memory management and loops instead of doing everything manually:
typedef struct
{
int id;
int type;
int count;
std::vector<int> values;
std::vector<int> settings;
} Entry;
#pragma pack(push, 1)
typedef struct
{
int id;
int type;
int count;
DWORD values_offset;
DWORD values_count; // if different than 'int count'
DWORD settings_offset;
DWORD settings_count; // if different than 'int count'
} SharedMemEntry;
#pragma pack(pop)
BOOL DumpEntries(TCHAR* memName)
{
DWORD NumValues = 0;
DWORD NumSettings = 0;
// or whatever your container actually is...
for(std::vector<Entry>::reverse_iterator iter = entries.rbegin();
iter != entries.rend(); ++iter)
{
Entry &e = *iter;
NumValues += e.values.size();
NumSettings += e.settings.size();
}
DWORD memsize = sizeof(DWORD) +
(entries.size() * sizeof(SharedMemEntry)) +
(sizeof(int) * NumValues) +
(sizeof(int) * NumSettings);
if (hMapObject != NULL)
CloseHandle(hMapObject);
hMapObject = CreateFileMapping(INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE, 0, memsize, memName);
if (!hMapObject) {
return FALSE;
}
std::unique_ptr<void, decltype(&UnmapViewOfFile)> uMapData( MapViewOfFile(hMapObject, FILE_MAP_WRITE, 0, 0, memsize), &UnmapViewOfFile );
BYTE *vMapData = (BYTE*) uMapData.get();
if (!vMapData) {
CloseHandle(hMapObject);
hMapObject = NULL;
return FALSE;
}
DWORD *pEntryCount = (DWORD*) vMapData;
*pEntryCount = entries.size();
SharedMemEntry* pEntries = (SharedMemEntry*) (pEntryCount + 1);
int *pValues = (int*) (pEntries + entries.size());
int *pSettings = (int*) (pValues + NumValues);
// or whatever your container actually is...
for(std::vector<Entry>::reverse_iterator iter = entries.rbegin();
iter != entries.rend(); ++iter)
{
Entry &e = *iter;
SharedMemEntry &eEntry = *pEntries++;
eEntry.id = e.id;
eEntry.type = e.type;
eEntry.count = e.count;
eEntry.values_offset = ((BYTE*)pValues - vMapData);
eEntry.values_count = e.values.size();
pValues = std::copy(e.values.begin(), e.values.end(), pValues);
eEntry.settings_offset = ((BYTE*)pSettings - vMapData);
eEntry.settings_count = e.settings.size();
pSettings = std::copy(e.settings.begin(), e.settings.end(), pSettings);
}
return TRUE;
}
// or whatever container type you want...
BOOL ReadEntries(TCHAR* memName, std::vector<Entry> &entries)
{
entries.clear();
std::unique_ptr<std::remove_pointer<HANDLE>::type, decltype(&CloseHandle)> uMapFile( OpenFileMapping(FILE_MAP_READ, FALSE, memName), &CloseHandle );
HANDLE hMapFile = uMapFile.get();
if (!hMapFile) {
return FALSE;
}
std::unique_ptr<void, decltype(&UnmapViewOfFile)> uMapData( MapViewOfFile(hMapFile, FILE_MAP_READ, 0, 0, 0), &UnmapViewOfFile );
BYTE *vMapData = (BYTE*) uMapData.get();
if (!vMapData) {
return FALSE;
}
DWORD *pEntryCount = (DWORD*) vMapData;
DWORD num_entries = *pEntryCount;
if (num_entries != 0)
{
entries.resize(num_entries);
SharedMemEntry *pEntries = (SharedMemEntry*) (pEntryCount + 1);
for (DWORD i = 0; i < num_entries; ++i)
{
Entry &e = entries[i];
SharedMemEntry &eEntry = pEntries[i];
e.id = eEntry.id;
e.type = eEntry.type;
e.count = eEntry.count;
e.values.reserve(eEntry.values_count);
e.settings.reserve(eEntry.settings_count);
int *pValues = (int*) (vMapData + eEntry.values_offset);
std::copy(pValues, pValues + eEntry.values_count, std::back_inserter(e.values));
int *pSettings = (int*) (vMapData + eEntry.settings_offset);
std::copy(pSettings, pSettings + eEntry.settings_count, std::back_inserter(e.settings));
}
}
return TRUE;
}
Either way, make sure you provide some kind of synchronization between DumpEntries() and ReadEntries(), such as with shared events from CreateEvent(), so that ReadEntries() does not try to read from the memory while DumpEntries() is still writing to it, and vice versa.
I have created procedures to save window screenshot to file. It works for PNG and BMP, but not for JPG (and GIF).
Here is code for capturing HBITMAP:
HBITMAP Signature::getScreenHBITMAP() {
// get screen rectangle
RECT windowRect;
GetWindowRect(getMainWnd(), &windowRect);
// bitmap dimensions
int bitmap_dx = windowRect.right - windowRect.left;
int bitmap_dy = windowRect.bottom - windowRect.top;
// create bitmap info header
BITMAPINFOHEADER infoHeader;
infoHeader.biSize = sizeof(infoHeader);
infoHeader.biWidth = bitmap_dx;
infoHeader.biHeight = bitmap_dy;
infoHeader.biPlanes = 1;
infoHeader.biBitCount = 24;
infoHeader.biCompression = BI_RGB;
infoHeader.biSizeImage = 0;
infoHeader.biXPelsPerMeter = 0;
infoHeader.biYPelsPerMeter = 0;
infoHeader.biClrUsed = 0;
infoHeader.biClrImportant = 0;
// dibsection information
BITMAPINFO info;
info.bmiHeader = infoHeader;
HDC winDC = GetWindowDC(getMainWnd());
HDC memDC = CreateCompatibleDC(winDC);
BYTE* memory = 0;
HBITMAP bitmap = CreateDIBSection(winDC, &info, DIB_RGB_COLORS, (void**)&memory, 0, 0);
SelectObject(memDC, bitmap);
// Copies screen upside down (as it is already upside down) - if need normal layout, change to BitBlt function call
StretchBlt(memDC, 0, 0, bitmap_dx, bitmap_dy, winDC, 0, bitmap_dy, bitmap_dx, bitmap_dy * -1, SRCCOPY);
DeleteDC(memDC);
ReleaseDC(getMainWnd(), winDC);
return bitmap;
}
And here is code for image saving:
HRESULT Imaging_SaveToFile(HBITMAP handle, LPTSTR filename, LPCTSTR format){
HRESULT res;
res = CoInitializeEx(NULL, COINIT_MULTITHREADED);
if ((res == S_OK) || (res == S_FALSE)) {
IImagingFactory* factory=NULL;
if (CoCreateInstance(CLSID_ImagingFactory, NULL, CLSCTX_INPROC_SERVER, IID_IImagingFactory, (void**)&factory) == S_OK) {
UINT count;
ImageCodecInfo* imageCodecInfo=NULL;
if (factory->GetInstalledEncoders(&count, &imageCodecInfo) == S_OK) {
// Get the particular encoder to use
LPTSTR formatString;
if (wcscmp(format, L"png") == 0) {
formatString = _T("image/png");
} else if (wcscmp(format, L"jpg") == 0) {
formatString = _T("image/jpeg");
} else if (wcscmp(format, L"gif") == 0) {
formatString = _T("image/gif");
} else if (wcscmp(format, L"bmp") == 0) {
formatString = _T("image/bmp");
} else {
CoUninitialize();
return S_FALSE;
}
CLSID encoderClassId;
if (count == 0) {
CoUninitialize();
return S_FALSE;
}
for(int i=0; i < (int)count; i++) {
if (wcscmp(imageCodecInfo[i].MimeType, formatString) == 0) {
encoderClassId= imageCodecInfo[i].Clsid;
free(imageCodecInfo);
break;
} else {
continue;
}
CoUninitialize();
return S_FALSE;
}
IImageEncoder* imageEncoder=NULL;
if (factory->CreateImageEncoderToFile(&encoderClassId, filename, &imageEncoder) == S_OK) {
IImageSink* imageSink = NULL;
res = imageEncoder->GetEncodeSink(&imageSink);
if (res != S_OK) {
CoUninitialize();
return res;
}
BITMAP bm;
GetObject (handle, sizeof(BITMAP), &bm);
ImageInfo* imageInfo = new ImageInfo();
imageInfo->Width = bm.bmWidth;
imageInfo->Height = bm.bmHeight;
imageInfo->RawDataFormat = IMGFMT_MEMORYBMP; //ImageFormatMemoryBMP;
imageInfo->Flags |= SinkFlagsTopDown | SinkFlagsFullWidth;
// Get pixel format from hBitmap
PixelFormatID pixelFormat;
int numColors = 0;
switch (bm.bmBitsPixel) {
case 1: {
pixelFormat = PixelFormat1bppIndexed;
numColors = 1;
break;
}
case 4: {
pixelFormat = PixelFormat4bppIndexed;
numColors = 16;
break;
}
case 8: {
pixelFormat = PixelFormat8bppIndexed;
numColors = 256;
break;
}
case 24: {
pixelFormat = PixelFormat24bppRGB;
break;
}
default: {
pixelFormat = PixelFormat32bppARGB;
numColors = 3; // according to MSDN 16 and 32 bpp numColors should be 3
break;
}
}
imageInfo->PixelFormat = pixelFormat;
if (pixelFormat == PixelFormat32bppARGB) imageInfo->Flags |= SinkFlagsHasAlpha;
res = imageSink->BeginSink(imageInfo, NULL);
if (res != S_OK) {
CoUninitialize();
return res;
}
ColorPalette* palette = NULL;
if (numColors > 0) {
palette = (ColorPalette*)malloc(sizeof(ColorPalette) + (numColors - 1) * sizeof(ARGB));
palette->Count = numColors;
for (int i=0; i<numColors; i++) {
int rgb = i*64;
int red = rgb & 0x00FF;
int green = (rgb >> 8) & 0x00FF;
int blue = (rgb >> 16) & 0x00FF;
palette->Entries[i] = MAKEARGB(0, red, green, blue);
}
} else {
palette = (ColorPalette*)malloc(sizeof(ColorPalette));
palette->Count = 0;
if (pixelFormat == PixelFormat32bppARGB) palette->Flags = PALFLAG_HASALPHA;
}
res = imageSink->SetPalette(palette);
if (res != S_OK) {
CoUninitialize();
return res;
}
BitmapData* bmData = new BitmapData();
bmData->Height = bm.bmHeight;
bmData->Width = bm.bmWidth;
bmData->Scan0 = bm.bmBits;
bmData->PixelFormat = pixelFormat;
UINT bitsPerLine = imageInfo->Width * bm.bmBitsPixel;
UINT bitAlignment = sizeof(LONG) * 8;
UINT bitStride = bitAlignment * (bitsPerLine / bitAlignment); // The image buffer is always padded to LONG boundaries
if ((bitsPerLine % bitAlignment) != 0) bitStride += bitAlignment; // Add a bit more for the leftover values
bmData->Stride = (bitStride / 8);
RECT rect;
rect.top = 0;
rect.bottom = bm.bmHeight;
rect.left = 0;
rect.right = bm.bmWidth;
res = imageSink->PushPixelData(&rect, bmData, TRUE);
if (res != S_OK) {
CoUninitialize();
return res;
}
res = imageSink->EndSink(S_OK);
if (res != S_OK) {
CoUninitialize();
return res;
}
imageSink->Release();
res = imageEncoder->TerminateEncoder();
if (res != S_OK) {
CoUninitialize();
return res;
}
}
}
}
CoUninitialize();
} else {
return res;
}
return res;
}
I used code from Koders.com as an example and tried to follow MSDN description of image encoding when modified this example.
Found also that others have similar issue, but with no answer:
social.msdn.microsoft.com/Forums/en-US/windowsmobiledev/thread/1c368cc1-cc5b-419e-a7d2-2a39c90ae83d/
groups.google.com/group/microsoft.public.windowsce.embedded.vc/browse_thread/thread/8cd67e16ac29627b/9242e82721c48ace?hl=hu&pli=1
I also found solution which uses GDI+ wrapper:
www.ernzo.com/LibGdiplus.aspx
www.codeproject.com/KB/windows/gdiplusandwinmobile.aspx
But I cannot use this GDI+ lib. Also I do not need whole GDI+. Tried to create similar saving procedure like in this wrapper, but with no success.
EDIT
Here is fixed and working solution (Thanks PhilMY for answer):
HRESULT Imaging_SaveToFile(HBITMAP handle, LPTSTR filename, LPCTSTR format){
HRESULT res;
res = CoInitializeEx(NULL, COINIT_MULTITHREADED);
if ((res == S_OK) || (res == S_FALSE)) {
IImagingFactory* factory=NULL;
if (CoCreateInstance(CLSID_ImagingFactory, NULL, CLSCTX_INPROC_SERVER, IID_IImagingFactory, (void**)&factory) == S_OK) {
UINT count;
ImageCodecInfo* imageCodecInfo=NULL;
if (factory->GetInstalledEncoders(&count, &imageCodecInfo) == S_OK) {
// Get the particular encoder to use
LPTSTR formatString;
if (wcscmp(format, L"png") == 0) {
formatString = _T("image/png");
} else if (wcscmp(format, L"jpg") == 0) {
formatString = _T("image/jpeg");
} else if (wcscmp(format, L"gif") == 0) {
formatString = _T("image/gif");
} else if (wcscmp(format, L"bmp") == 0) {
formatString = _T("image/bmp");
} else {
CoUninitialize();
return S_FALSE;
}
CLSID encoderClassId;
if (count == 0) {
CoUninitialize();
return S_FALSE;
}
for(int i=0; i < (int)count; i++) {
if (wcscmp(imageCodecInfo[i].MimeType, formatString) == 0) {
encoderClassId= imageCodecInfo[i].Clsid;
free(imageCodecInfo);
break;
} else {
continue;
}
CoUninitialize();
return S_FALSE;
}
IImageEncoder* imageEncoder=NULL;
if (factory->CreateImageEncoderToFile(&encoderClassId, filename, &imageEncoder) == S_OK) {
IImageSink* imageSink = NULL;
res = imageEncoder->GetEncodeSink(&imageSink);
if (res != S_OK) {
CoUninitialize();
return res;
}
BITMAP bm;
GetObject (handle, sizeof(BITMAP), &bm);
PixelFormatID pixelFormat;
switch (bm.bmBitsPixel) {
case 1: {
pixelFormat = PixelFormat1bppIndexed;
break;
}
case 4: {
pixelFormat = PixelFormat4bppIndexed;
break;
}
case 8: {
pixelFormat = PixelFormat8bppIndexed;
break;
}
case 24: {
pixelFormat = PixelFormat24bppRGB;
break;
}
default: {
pixelFormat = PixelFormat32bppARGB;
break;
}
}
BitmapData* bmData = new BitmapData();
bmData->Height = bm.bmHeight;
bmData->Width = bm.bmWidth;
bmData->Scan0 = bm.bmBits;
bmData->PixelFormat = pixelFormat;
UINT bitsPerLine = bm.bmWidth * bm.bmBitsPixel;
UINT bitAlignment = sizeof(LONG) * 8;
UINT bitStride = bitAlignment * (bitsPerLine / bitAlignment); // The image buffer is always padded to LONG boundaries
if ((bitsPerLine % bitAlignment) != 0) bitStride += bitAlignment; // Add a bit more for the leftover values
bmData->Stride = (bitStride / 8);
IBitmapImage* pBitmap;
factory->CreateBitmapFromBuffer(bmData, &pBitmap);
IImage* pImage;
pBitmap->QueryInterface(IID_IImage, (void**)&pImage);
res = pImage->PushIntoSink(imageSink);
if (res != S_OK) {
CoUninitialize();
return res;
}
pBitmap->Release();
pImage->Release();
imageSink->Release();
imageEncoder->TerminateEncoder();
imageEncoder->Release();
}
}
}
CoUninitialize();
} else {
return res;
}
return res;
}
I have some similar code that worked for JPEGs on WinCE 6.0.
The main differences are:
I check ImageCodecInfo::FormatID against ImageFormatJPEG to match an encoder
I call SetEncoderParameters to set ENCODER_QUALITY
I copy the source bitmap into an IBitmapImage then use IImage::PushIntoSink