Related
Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 2 years ago.
Improve this question
I tried to follow the example found:
Capturing an image from a minimized window
My code:
#include <iostream>
#include <string>
#include <windows.h>
#include <gdiplus.h>
#pragma comment(lib, "gdiplus.lib")
#pragma warning(disable : 4996)
using namespace std;
using namespace Gdiplus;
int GetEncoderClsid(LPCWSTR format, CLSID* pClsid)
{
unsigned int num = 0, size = 0;
GetImageEncodersSize(&num, &size);
if (size == 0) return -1;
ImageCodecInfo* pImageCodecInfo = (ImageCodecInfo*)(malloc(size));
if (pImageCodecInfo == NULL) return -1;
GetImageEncoders(num, size, pImageCodecInfo);
for (unsigned int j = 0; j < num; ++j) {
if (wcscmp(pImageCodecInfo[j].MimeType, format) == 0) {
*pClsid = pImageCodecInfo[j].Clsid;
free(pImageCodecInfo);
return j;
}
}
free(pImageCodecInfo);
return -1;
}
int SaveScreenshot(string filename, ULONG uQuality, HWND hwnd) // by Napalm
{
ULONG_PTR gdiplusToken;
GdiplusStartupInput gdiplusStartupInput;
GdiplusStartup(&gdiplusToken, &gdiplusStartupInput, NULL);
HWND hMyWnd = hwnd;
//HWND hMyWnd = GetDesktopWindow();
RECT r;
int w, h;
HDC dc, hdcCapture;
int nBPP, nCapture, iRes;
LPBYTE lpCapture;
CLSID imageCLSID;
Bitmap* pScreenShot;
// get the area of my application's window
GetWindowRect(hMyWnd, &r);
dc = GetWindowDC(hMyWnd); // GetDC(hMyWnd) ;
w = r.right - r.left;
h = r.bottom - r.top;
nBPP = GetDeviceCaps(dc, BITSPIXEL);
hdcCapture = CreateCompatibleDC(dc);
// create the buffer for the screenshot
BITMAPINFO bmiCapture = { sizeof(BITMAPINFOHEADER), w, -h, 1, nBPP, BI_RGB, 0, 0, 0, 0, 0, };
// create a container and take the screenshot
HBITMAP hbmCapture = CreateDIBSection(dc, &bmiCapture, DIB_PAL_COLORS, (LPVOID*)&lpCapture, NULL, 0);
// failed to take it
if (!hbmCapture) {
DeleteDC(hdcCapture);
DeleteDC(dc);
GdiplusShutdown(gdiplusToken);
printf("failed to take the screenshot. err: %d\n", GetLastError());
return 0;
}
// copy the screenshot buffer
nCapture = SaveDC(hdcCapture);
SelectObject(hdcCapture, hbmCapture);
BitBlt(hdcCapture, 0, 0, w, h, dc, 0, 0, SRCCOPY);
RestoreDC(hdcCapture, nCapture);
DeleteDC(hdcCapture);
DeleteDC(dc);
// save the buffer to a file
pScreenShot = new Bitmap(hbmCapture, (HPALETTE)NULL);
EncoderParameters encoderParams;
encoderParams.Count = 1;
encoderParams.Parameter[0].NumberOfValues = 1;
encoderParams.Parameter[0].Guid = EncoderQuality;
encoderParams.Parameter[0].Type = EncoderParameterValueTypeLong;
encoderParams.Parameter[0].Value = &uQuality;
GetEncoderClsid(L"image/jpeg", &imageCLSID);
wchar_t* lpszFilename = new wchar_t[filename.length() + 1];
mbstowcs(lpszFilename, filename.c_str(), filename.length() + 1);
iRes = (pScreenShot->Save(lpszFilename, &imageCLSID, &encoderParams) == Ok);
delete pScreenShot;
DeleteObject(hbmCapture);
GdiplusShutdown(gdiplusToken);
return iRes;
}
int main() {
HWND hWnd;
hWnd = FindWindowA(NULL, "txt.txt - Bloco de Notas");
WINDOWPLACEMENT wp = { 0 };
wp.length = sizeof(WINDOWPLACEMENT);
GetWindowPlacement(hWnd, &wp);
ANIMATIONINFO ai = { 0 };
bool restoreAnimated = false;
if (wp.showCmd == SW_SHOWMINIMIZED)
{
ai.cbSize = sizeof(ANIMATIONINFO);
SystemParametersInfo(SPI_GETANIMATION, sizeof(ANIMATIONINFO), &ai, 0);
if (ai.iMinAnimate != 0)
{
ai.iMinAnimate = 0;
SystemParametersInfo(SPI_SETANIMATION, sizeof(ANIMATIONINFO), &ai, 0);
restoreAnimated = true;
}
// optionally move the window off-screen, or
// apply alpha using SetLayeredWindowAttributes()...
ShowWindow(hWnd, SW_SHOWNOACTIVATE);
}
// capture as needed ...
string path = "C:\\Users\\CAIO\\Desktop\\screenshot.jpg";
ULONG quality = 100;
SaveScreenshot(path, quality, hWnd);
if (wp.showCmd == SW_SHOWMINIMIZED)
{
SetWindowPlacement(hWnd, &wp);
// optionally remove alpha using SetLayeredWindowAttributes()...
if (restoreAnimated)
{
ai.iMinAnimate = 1;
SystemParametersInfo(SPI_SETANIMATION, sizeof(ANIMATIONINFO), &ai, 0);
}
}
return 0;
}
In her code there's restoreAnimation = true; and if (restoreAnimation) did he mean restoreAnimated?
With the code above it still shown the window for a sec, also the captured image is all black (maybe captured while minimized) or is not captured properly.
https://youtu.be/8b1wXxtaXsY?t=9
Sec 8 and 9 from the video you can see the window is being shown on the screen.
Suggestions?
did he mean restoreAnimated?
I think yes.
This code from #Remy only disables the animation effects when minimizing and restoring, the window will still be displayed for a short time when restoring. As the answer pointed out, you can use SetLayeredWindowAttributes to make the window nearly completely transparent(It should be noted that using SetLayeredWindowAttributes needs to ensure that hwnd has WS_EX_LAYERED style.) and then you will not see the window, but the operating system will.
In addition, the problem of incomplete window capture is because the window is not drawn completely, call UpdateWindow after ShowWindow works for me, it will send a WM_PAINT message to the window.
bool restoreAnimated = false;
BYTE Alph = 0;
LONG_PTR exstyle = 0;
if (wp.showCmd == SW_SHOWMINIMIZED)
{
ai.cbSize = sizeof(ANIMATIONINFO);
SystemParametersInfo(SPI_GETANIMATION, sizeof(ANIMATIONINFO), &ai, 0);
if (ai.iMinAnimate != 0)
{
ai.iMinAnimate = 0;
SystemParametersInfo(SPI_SETANIMATION, sizeof(ANIMATIONINFO), &ai, 0);
restoreAnimated = true;
}
// optionally move the window off-screen, or
// apply alpha using SetLayeredWindowAttributes()...
exstyle = GetWindowLongPtr(hWnd, GWL_EXSTYLE);
SetWindowLongPtr(hWnd, GWL_EXSTYLE, exstyle | WS_EX_LAYERED);
DWORD flag;
BOOL ret = GetLayeredWindowAttributes(hWnd, 0, &Alph, 0);
SetLayeredWindowAttributes(hWnd, 0, 1, LWA_ALPHA);
ShowWindow(hWnd, SW_SHOWNOACTIVATE);
UpdateWindow(hWnd);
}
// capture as needed ...
string path = "C:\\Users\\name\\Desktop\\screenshot.jpg";
ULONG quality = 100;
SaveScreenshot(path, quality, hWnd);
if (wp.showCmd == SW_SHOWMINIMIZED)
{
SetWindowPlacement(hWnd, &wp);
// optionally remove alpha using SetLayeredWindowAttributes()...
SetLayeredWindowAttributes(hWnd, 0, Alph, LWA_ALPHA);
SetWindowLongPtr(hWnd, GWL_EXSTYLE, exstyle);
if (restoreAnimated)
{
ai.iMinAnimate = 1;
SystemParametersInfo(SPI_SETANIMATION, sizeof(ANIMATIONINFO), &ai, 0);
}
}
I'm using Objective Grid and wanted to have a grid cell control that can show an icon and text. So I took RogueWave's example (https://rwkbp.makekb.com/entry/466/) and modified it as below.
Initially the text renders correctly, but if I do anything in the grid that refreshes the relevant cell, the text disappears. If I update the whole grid, or even refresh the cell by dragging it off screen and back again, the text reappears - until it disappears again. Seems like a paint or InvalidateRect problem - but I can't figure out how to fix it. Any ideas?
Thanks!
//------------------------------------------------------------------------------
void CGXIconControl::Draw(CDC* pDC, CRect rect, ROWCOL nRow, ROWCOL nCol, const CGXStyle& style, const CGXStyle* pStandardStyle)
//------------------------------------------------------------------------------
{
BOOL b;
ASSERT(pDC != NULL && pDC->IsKindOf(RUNTIME_CLASS(CDC)));
// ASSERTION-> Invalid Device Context ->END
ASSERT(nRow <= Grid()->GetRowCount() && nCol <= Grid()->GetColCount());
// ASSERTION-> Cell coordinates out of range ->END
ASSERT_VALID(pDC);
DrawBackground(pDC, rect, style);
pDC->SetBkMode(TRANSPARENT);
if (rect.right <= rect.left || rect.Width() <= 1 || rect.Height() <= 1)
{
return;
}
CString str = style.GetIncludeValue() ? style.GetValue() : _T("");
CString sTxtBefore = _T("");
CString sTxtAfter = _T("");
int nHAlign = style.GetHorizontalAlignment();
int nVAlign = style.GetVerticalAlignment();
// Save these value to restore them when done drawing
COLORREF crOldTextColor = pDC->GetTextColor();
COLORREF crOldBkColor = pDC->GetBkColor();
if (!style.GetEnabled())
{
pDC->SetTextColor(::GetSysColor(COLOR_GRAYTEXT));
}
CBrush Brush;
Brush.CreateSolidBrush(style.GetEnabled() ? ::GetSysColor(COLOR_WINDOWTEXT) : ::GetSysColor(COLOR_GRAYTEXT));
LOGBRUSH lBrush = { 0 };
Brush.GetLogBrush(&lBrush);
CBrush* pOldBrush = (CBrush*)pDC->SelectStockObject(NULL_BRUSH);
CPen linePen;
linePen.CreatePen(PS_SOLID, 1, &lBrush);
CPen* pOldPen = pDC->SelectObject(&linePen);
// Set font bold if necessary
CFont* pCurfont = pDC->GetCurrentFont();
LOGFONT lf;
CFont font;
if (pCurfont)
{
pCurfont->GetLogFont(&lf);
}
if (style.GetFont().GetBold())
{
lf.lfWeight = FW_BOLD;
}
font.CreateFontIndirect(&lf);
CFont* pOldFont = pDC->SelectObject(&font);
int nIcoStart = str.Find(_T("#ICO"));
if (nIcoStart == -1)
{
// We didn't find an icon indicator, so just draw the text
pDC->DrawText(str, rect, DT_SINGLELINE|nHAlign|nVAlign);
}
else
{
sTxtBefore = str.Left(nIcoStart);
CSize szBefore = pDC->GetTextExtent(sTxtBefore);
int nIconEnd = str.Find(_T(")"), nIcoStart);
CString strIDResource = str.Mid(nIcoStart + 5, nIconEnd - (nIcoStart + 5));
UINT nIDResource = _ttoi(strIDResource);
// Load the highest bit-depth available
HICON hIcon = NULL;
hIcon = LoadResourceIcon(nIDResource, m_nIconSize, m_nIconSize, 32);
hIcon == NULL ? LoadResourceIcon(nIDResource, m_nIconSize, m_nIconSize, 24) : NULL;
hIcon == NULL ? LoadResourceIcon(nIDResource, m_nIconSize, m_nIconSize, 16) : NULL;
hIcon == NULL ? LoadResourceIcon(nIDResource, m_nIconSize, m_nIconSize, 8) : NULL;
sTxtAfter = str.Right(str.GetLength() - nIconEnd - 1);
CSize szAfter = pDC->GetTextExtent(sTxtAfter);
CRect rectCell = CGXControl::GetCellRect(nRow, nCol, rect, &style);
CRect rectBefore = rectCell;
CRect rectAfter = rectCell;
int nTotalWidth = szBefore.cx + m_nIconSize + szAfter.cx;
// Calculate positions
int nTop, nLeft;
switch (nHAlign)
{
case DT_LEFT:
{
rectBefore.right = rectBefore.left + szBefore.cx;
nLeft = rectBefore.right;
rectAfter.left = nLeft + m_nIconSize;
rectAfter.right = rectAfter.left + szAfter.cx;
} break;
case DT_CENTER:
{
rectBefore.left = (rectCell.right - rectCell.Width() / 2) - nTotalWidth / 2;
rectBefore.right = rectBefore.left + szBefore.cx;
nLeft = rectBefore.right;
rectAfter.left = nLeft + m_nIconSize;
rectAfter.right = rectAfter.left + szAfter.cx;
} break;
case DT_RIGHT:
{
// Work from the right
rectAfter.right = rectCell.right;
rectAfter.left = rectAfter.right - szAfter.cx;
nLeft = rectAfter.left - m_nIconSize;
rectBefore.right = nLeft;
rectBefore.left = rectBefore.right - szBefore.cx;
} break;
}
switch (nVAlign)
{
case DT_TOP:
nTop = rectCell.top;
break;
case DT_VCENTER:
nTop = rectCell.top + (rectCell.Height() / 2 - m_nIconSize / 2);
break;
case DT_BOTTOM:
nTop = rectCell.bottom - m_nIconSize;
break;
}
if (!sTxtBefore.IsEmpty())
{
pDC->DrawText(sTxtBefore, rectBefore, DT_SINGLELINE|nHAlign|nVAlign);
}
b = ::DrawIconEx(pDC->m_hDC, nLeft, nTop, hIcon, m_nIconSize, m_nIconSize, 0, NULL, DI_NORMAL);
b = ::DestroyIcon(hIcon);
if (!sTxtAfter.IsEmpty())
{
pDC->DrawText(sTxtAfter, rectAfter, DT_SINGLELINE|nHAlign|nVAlign);
}
}
// Reset original values
pDC->SetTextColor(crOldTextColor);
pDC->SetBkColor(crOldBkColor);
pDC->SelectObject(pOldBrush);
pDC->SelectObject(pOldPen);
pDC->SelectObject(pOldFont);
// Child Controls: spin-buttons, hotspot, combobox btn, ...
CGXControl::Draw(pDC, rect, nRow, nCol, style, pStandardStyle);
}
I am attempting to load an icon from a third party executable for use in SDL_SetWindowIcon.
Based on some debugging, I believe I am loading the icon correctly, but I don't seem to be populating the SDL_Surface correctly.
Here's what I'm trying currently:
//attempts to load an icon resource from the specified assembly
//uses rcName if provided, or rcId (as an int resource id) if rcName is null
//if successful, convert and set it as SDL's window icon
void LoadIconFrom(std::string assembly, int rcId, const char* rcName) {
//get a module handle for the target assembly
HMODULE hModule = LoadLibrary(assembly.c_str());
if (hModule == NULL) {
ShowError((std::string("Icon Error ") + std::to_string(GetLastError())).c_str(), "hModule is null!");
return;
}
//get a handle for the desired icon
HICON hIcon = NULL;
if (rcName == NULL) {
hIcon = LoadIcon(hModule, MAKEINTRESOURCE(rcId));
}
else {
hIcon = LoadIcon(hModule, rcName);
}
if (hIcon == NULL) {
ShowError((std::string("Icon Error ") + std::to_string(GetLastError())).c_str(), "hIcon is null!");
return;
}
//load some info regarding the selected icon, make sure it has bitmap data
ICONINFO ii;
if (!GetIconInfo(hIcon, &ii)) {
ShowError((std::string("Icon Error ") + std::to_string(GetLastError())).c_str(), "IconInfo is null!");
return;
}
if (!ii.hbmColor) {
ShowError("Icon Error", "Icon does not have bitmap data!");
return;
}
//attempt to determine the size of the icon
int iWidth, iHeight;
BITMAP bm;
if (!GetObject(ii.hbmColor, sizeof(bm), &bm)) {
ShowError("Icon Error", "Could not read bitmap data!");
return;
}
iWidth = bm.bmWidth;
iHeight = bm.bmHeight;
//ShowError("Icon Win!!!",(std::string("Loaded icon of size: ") + std::to_string(iWidth) + "x" + std::to_string(iHeight)).c_str());
icon = SDL_CreateRGBSurface(SDL_SWSURFACE, bm.bmWidth, bm.bmHeight, bm.bmBitsPixel, 0x000000FF, 0x0000FF00, 0x00FF0000, 0xFF000000);
Uint8 * bits = NULL;
Uint8 * temp = NULL;
bits = new Uint8[bm.bmWidthBytes*bm.bmHeight];
temp = new Uint8[bm.bmWidthBytes*bm.bmHeight];
memcpy(temp, bm.bmBits, bm.bmWidthBytes*bm.bmHeight);
Uint8 *ptemp;
Uint8 *pbits = bits;
for (int j = bm.bmHeight - 1; j >= 0; j--)
{
ptemp = temp + j * bm.bmWidthBytes;
for (int x = 0; x < bm.bmWidthBytes; x++)
{
*pbits = *ptemp;
pbits++;
ptemp++;
}
}
if (SDL_MUSTLOCK(icon)) SDL_LockSurface(icon);
memcpy(icon->pixels, bits, bm.bmWidthBytes*bm.bmHeight);
if (SDL_MUSTLOCK(icon)) SDL_UnlockSurface(icon);
delete[] bits;
delete[] temp;
SDL_SetWindowIcon(mainWindow, icon);
}
It crashes at SDL_SetWindowIcon. The last bit is supposed to flip the image over, which I believe to be required from examples I've found. Removing that part doesn't seem to have any effect.
If I don't modify "bits" at all, and leave it empty, the program doesn't crash but I get a blank icon.
What am I missing here?
Edit: I have also tried CreateRGBSurfaceFrom, which seems to have identical behaviour - either blank on a blank array or crashes if there's any data in it.
Edit 2: "icon" is an SDL_Surface*, declared elsewhere.
Edit 3: Using SDL 2.0.7.
Edit 4: FIXED CODE :
//attempts to load an icon resource from the specified assembly
//uses rcName if provided, or rcId (as an int resource id) if rcName is null
//if successful, convert and set it as SDL's window icon
void LoadIconFrom(std::string assembly, int rcId, const char* rcName) {
//todo: make error throwing here only happen in debug, while
//release should just continue on its merry way, iconless
//get a module handle for the target assembly
HMODULE hModule = LoadLibrary(assembly.c_str());
if (hModule == NULL) {
ShowError((std::string("Icon Error ") + std::to_string(GetLastError())).c_str(), "hModule is null!");
return;
}
//get a handle for the desired icon
HICON hIcon = NULL;
if (rcName == NULL) {
hIcon = LoadIcon(hModule, MAKEINTRESOURCE(rcId));
}
else {
hIcon = LoadIcon(hModule, rcName);
}
if (hIcon == NULL) {
ShowError((std::string("Icon Error ") + std::to_string(GetLastError())).c_str(), "hIcon is null!");
return;
}
//load some info regarding the selected icon, make sure it has bitmap data
ICONINFO ii;
if (!GetIconInfo(hIcon, &ii)) {
ShowError((std::string("Icon Error ") + std::to_string(GetLastError())).c_str(), "IconInfo is null!");
return;
}
if (!ii.hbmColor) {
ShowError("Icon Error", "Icon does not have bitmap data!");
return;
}
BITMAP bm;
if (!GetObject(ii.hbmColor, sizeof(bm), &bm)) {
ShowError("Icon Error", "Bitmap data does not exist!");
return;
}
HBITMAP hbitmap = (HBITMAP)CopyImage(ii.hbmColor, IMAGE_BITMAP, bm.bmWidth, bm.bmHeight, LR_CREATEDIBSECTION);
if (!GetObject(hbitmap, sizeof(BITMAP), &bm)) {
ShowError("Icon Error", "Could not read bitmap data!");
return;
}
// Verify that the data we have obtained is a 32bpp bitmap with color info
if (bm.bmBitsPixel != 32) {
ShowError("Icon Error", "Bitmap data not in a 32bpp format!");
return;
}
if (bm.bmBits == NULL) {
ShowError("Icon Error", "Extracted bitmap data is null!");
return;
}
// Create an SDL surface - note the mask varies by platform endian-ness
int rmask = 0x00FF0000;
int gmask = 0x0000FF00;
int bmask = 0x000000FF;
int amask = 0xFF000000;
icon = SDL_CreateRGBSurface(SDL_SWSURFACE, bm.bmWidth, bm.bmHeight, bm.bmBitsPixel, rmask, gmask, bmask, amask);
if (icon == NULL) {
ShowError("Icon Error", (std::string("SDL surface creation failed: ") + SDL_GetError()).c_str());
return;
}
// Re-orient the bytes to flip the image vertically
Uint8 * bits = NULL;
Uint8 * temp = NULL;
bits = new Uint8[bm.bmWidthBytes*bm.bmHeight];
temp = new Uint8[bm.bmWidthBytes*bm.bmHeight];
memcpy(temp, bm.bmBits, bm.bmWidthBytes*bm.bmHeight);
Uint8 *ptemp;
Uint8 *pbits = bits;
for (int j = bm.bmHeight - 1; j >= 0; j--)
{
ptemp = temp + j * bm.bmWidthBytes;
for (int x = 0; x < bm.bmWidthBytes; x++)
{
*pbits = *ptemp;
pbits++;
ptemp++;
}
}
// Copy the formatted bits to the surface
if (SDL_MUSTLOCK(icon)) SDL_LockSurface(icon);
memcpy(icon->pixels, bits, bm.bmWidthBytes*bm.bmHeight);
if (SDL_MUSTLOCK(icon)) SDL_UnlockSurface(icon);
// Set the window icon to the loaded surface
SDL_SetWindowIcon(mainWindow, icon);
// Cleanup
delete[] bits;
delete[] temp;
DeleteObject(hbitmap);
SDL_FreeSurface(icon);
}
Thank you to everyone who helped. I appreciate it. (If I'm missing anything in error testing or cleanup, please feel free to point it out and I'll update.)
bm.bmBits in your code, obtained from HICON, is most likely NULL. Use CopyImage with LR_CREATEDIBSECTION to access bmBits
HBITMAP hbitmap = (HBITMAP)CopyImage(ii.hbmColor, IMAGE_BITMAP,
bm.bmWidth, bm.bmHeight, LR_CREATEDIBSECTION);
BITMAP bm2;
GetObject(hbitmap, sizeof(BITMAP), &bm2);
...
DeleteObject(hbitmap);
Check bm2.bmBitsPixel to make sure it's 32-bit. Check bm2.bmBits to make sure it is not NULL.
void LoadIconFrom(std::string assembly, int rcId, const char* rcName)
{
...
ICONINFO ii;
GetIconInfo(hicon, &ii);
BITMAP bm;
GetObject(ii.hbmColor, sizeof(bm), &bm);
HBITMAP hbitmap = (HBITMAP)CopyImage(ii.hbmColor, IMAGE_BITMAP,
bm.bmWidth, bm.bmHeight, LR_CREATEDIBSECTION);
GetObject(hbitmap, sizeof(BITMAP), &bm);
if (bm.bmBitsPixel != 32) {error(); ...}
if (bm.bmBits == NULL) {error(); ...}
...
icon = SDL_CreateRGBSurface(SDL_SWSURFACE, bm.bmWidth, bm.bmHeight,
bm.bmBitsPixel, rmask, gmask, bmask, amask);
//copy bits upside down
if(SDL_MUSTLOCK(icon)) SDL_LockSurface(icon);
int wb = bm.bmWidthBytes;
BYTE* bits = icon->pixels;
BYTE* src = (BYTE*)bm.bmBits;
for(int j = 0; j < bm.bmHeight; j++)
memcpy(bits + j * wb, src + (bm.bmHeight - j - 1) * wb, wb);
if(SDL_MUSTLOCK(icon)) SDL_UnlockSurface(icon);
SDL_SetWindowIcon(mainWindow, icon);
// Cleanup
SDL_FreeSurface(icon);
DeleteObject(hbitmap);
}
I need help with rendering CRichEditCtrl content with transparent background on graphical context which is displayed on screen and printed as well.
Now I have following code, which is working good except transparency issues:
CRichEditCtrl ctrl; // my CRichEditCtrl
CDC *dc; // - my graphical context
dc->SetBkMode(TRANSPARENT);
dc->DPtoHIMETRIC(&targetSize);
CRect cHiMetricRect( 0, 0, origSize.cx*factor,origSize.cy*factor);
CRect cTwipsRect( 0, 0, (TWIPS_INCH * targetSize.cx + HIMETRIC_INCH / 2) / HIMETRIC_INCH, (TWIPS_INCH * targetSize.cy + HIMETRIC_INCH / 2) / HIMETRIC_INCH);
CMetaFileDC metaFile;
metaFile.CreateEnhanced( dc, NULL, cHiMetricRect, NULL );
metaFile.SetBkMode(TRANSPARENT);
metaFile.SetAttribDC( dc->m_hDC );
FORMATRANGE stFR;
stFR.hdcTarget = stFR.hdc = metaFile.m_hDC;
stFR.rcPage = stFR.rc = cTwipsRect;
stFR.chrg.cpMin = 0;
stFR.chrg.cpMax = -1;
ctrl.FormatRange( &stFR, TRUE);
ctrl.FormatRange( NULL, TRUE);
HENHMETAFILE hMetaFile = metaFile.CloseEnhanced();
dc->PlayMetaFile(hMetaFile,&cr);
DeleteEnhMetaFile(hMetaFile);
I need to render this text with transparency because there are already things drawn on my DC.
I tried to search web for any help about metafiles and transparency but found nothing adequate. I will be thankful for any kind of help.
I'm not very sure about MetaFiles, but I've done something similar with EMFs with straight WinAPI which does work -- call EnumEnhMetaFile instead of PlayMetaFile, like:
BOOL bFirstTime = TRUE;
EnumEnhMetaFile(hDC, m_hEmf, (ENHMFENUMPROC)EmfEnumProc_Play_TranspBackground, &bFirstTime, &rc);
where the EnumProc is defined as
int CALLBACK EmfEnumProc_Play_TranspBackground(HDC hDC, LPHANDLETABLE lpHTable, LPENHMETARECORD lpEMFR, int nObj, LPARAM lpData)
{ BOOL bOK;
if (lpEMFR->iType == EMR_SETBKMODE)
{ EMRSETBKMODE* lpEMRBkMode = (EMRSETBKMODE*) lpEMFR;
if (lpEMRBkMode->iMode == OPAQUE)
{ EMRSETBKMODE EmrBkMode;
EmrBkMode.emr.iType = EMR_SETBKMODE;
EmrBkMode.emr.nSize = (sizeof(EmrBkMode) % 4 == 0 ? sizeof(EmrBkMode) : (((sizeof(EmrBkMode) / 4) + 1) * 4));
EmrBkMode.iMode = TRANSPARENT;
bOK = PlayEnhMetaFileRecord(hDC, lpHTable, (LPENHMETARECORD)&EmrBkMode, (UINT)nObj);
return bOK;
}
}
bOK = PlayEnhMetaFileRecord(hDC, lpHTable, lpEMFR, (UINT)nObj);
if (lpEMFR->iType == EMR_HEADER)
{ BOOL* pbFirstTime = (BOOL*)lpData;
if (*pbFirstTime)
{ EMRSETBKMODE EmrBkMode;
EmrBkMode.emr.iType = EMR_SETBKMODE;
EmrBkMode.emr.nSize = (sizeof(EmrBkMode) % 4 == 0 ? sizeof(EmrBkMode) : (((sizeof(EmrBkMode) / 4) + 1) * 4));
EmrBkMode.iMode = TRANSPARENT;
PlayEnhMetaFileRecord(hDC, lpHTable, (LPENHMETARECORD)&EmrBkMode, (UINT)nObj);
*pbFirstTime = FALSE;
}
}
return bOK;
}
I used EnumEnhMetaFile function:
EnumEnhMetaFile(dc->m_hDC, hMetaFile, myMetafileProc, NULL, rect );
Then I used callback procedure that retrives each record of metafile:
int metafileProc( HDC hDC, HANDLETABLE *lpHTable, const ENHMETARECORD *lpEMFR, int nObj, LPARAM lpData) {
if ( lpEMFR->iType == EMR_EXTTEXTOUTW ) {
COLORREF_STRUCT *c = (COLORREF_STRUCT *)&(lastBgColor);
EMR_EXTTEXTOUTW_STRUCT *s = (EMR_EXTTEXTOUTW_STRUCT *)lpEMFR;
s->textStruct.options = 0x00;
if ( bgColorFlag ) {
bgColorFlag = false;
renderRect( hDC, s->textStruct.rect, c );
}
PlayEnhMetaFileRecord( hDC, lpHTable, lpEMFR, nObj );
} else if ( lpEMFR->iType == EMR_SETBKCOLOR ) {
BYTE *ptr = (BYTE*)lpEMFR;
COLORREF temp = *((COLORREF*)(ptr+8));
if ( temp != 0xFFFFFF ) {
lastBgColor = temp;
bgColorFlag = true;
}
}
return 1;
}
where renderRect( hDC, s->textStruct.rect, c ) is function which draws transparent background in c color. I have to zero options flag for text becouse there was different behaviour in Windows XP and Windows 7 and 8 - after that everything works ok. Thanks for help. Best regards.
Currently I have the following function to attempt to get the character widths for specific characters in a string. It returns the same values for a font regardless of point size. I know this is in logical units. What multiplier do I need to take into account to get it out of logical units and into pixels?
Thanks!
double Utils::GetFormattedCharWidth(char theChar, Gdiplus::Font* pFont, RectF& rectArc, Graphics& graphics)
{
double textWidth = 0;
HDC hdc = NULL;
DWORD outLine = 0; //= GetLastError();
hdc = graphics.GetHDC();
outLine = GetLastError();
LPINT lpBuffer = new int;
/*ABC *abc = new ABC[256];
for(int iCon = 0; iCon < 256; iCon++)
{
(&abc[iCon])->abcA = 0;
(&abc[iCon])->abcB = 0;
(&abc[iCon])->abcC = 0;
}*/
DWORD dSize = 0;
SetMapMode(hdc,MM_TEXT);
HGDIOBJ hOldFont = SelectObject(hdc, pFont);
outLine = GetLastError();
//outLine = GetLastError();
//DWORD d = GetGlyphOutline(hdc, theChar, GGO_METRICS, lpg, dSize, lpvBuffer, LPM);
DWORD d = GetCharWidth32(hdc, theChar, theChar, lpBuffer);
//lpABC = (LPABC)GlobalAllocPtr( GHND, 256*sizeof(ABC) );
//d = GetCharABCWidthsA(hdc, 0, 255, abc);
outLine = GetLastError();
//DWORD d = GetCharABCWidthsA(hdc, theChar, theChar, abc);
int iExtraSpacing = GetTextCharacterExtra(hdc);
outLine = GetLastError();
graphics.ReleaseHDC(hdc);
textWidth = (double)(*lpBuffer) ;
//delete abc;
delete lpBuffer;
graphics.ReleaseHDC(hdc);
return textWidth + iExtraSpacing;
}
New code for Mark using Measure String.
double Utils::GetFormattedCharWidth(char theChar, Gdiplus::Font* pFont, RectF& rectArc, Graphics& graphics)
{
double textWidth = 0;
char charBuff[4];
memset(&charBuff, 0, 4);
charBuff[0] = theChar;
RectF rectTemp;
WCHAR* pChar = (WCHAR*)charBuff;
graphics.MeasureString(pChar, 1, pFont, rectArc, &rectTemp);
textWidth = rectTemp.Width;
return textWidth;
}
You're trying to select a GDI+ Font into a GDI DC. I'm pretty sure that's not going to work. You need a GDI handle to the font.