BOOL CImageList::Replace( int nImage, CBitmap* pbmImage, CBitmap* pbmMask ) - winapi

I have an imagelist.
For some operations I am extracting toolbar images and replacing the image in the imagelist using
BOOL CImageList::Replace( int nImage, CBitmap* pbmImage, CBitmap* pbmMask );
I need to apply mask color RGB(255,0,255) while replacing.
ICONINFO iconinfo;
GetIconInfo(hIcon, &iconinfo);
HBITMAP hBitmap = iconinfo.hbmColor;
m_imgListSingle.Replace(0,CBitmap::FromHandle(hBitmap),???)
I dont know what I need to pass for third argument for CImageList Replace function.

There is no way to use the Replace function with a mask color directly.
You may succeed in using the following sequence:
Use the CImageList::Add method with the appropriate mask color
Use CImageList::GetImageInfo to extract the bitmaps that got created by the Add command
Use the CImageList::Replace method with the extracted bitmaps
use the CImageList::Delete method to delete the newly created image.
Dont't forget to free the bitmaps you retrieved by CImageList::GetImageInfo

Related

GDI: Original DC bitmap changes, and can't restore

I'm seeing an issue where I could not re-select the original bitmap on a DC, causing a memory leak. The pointer to the original bitmap stayed the same throughout the program, but the data (from CBitmap::GetBitmap) changes from monochrome to something else. I don't know when the bitmap actually changes, but something in the system is causing it.
CBitmap* cMyClass::mpOldBitmap;
CDC cMyClass::mCanvasDc;
CBitmap cMyClass::mCanvasBmp;
void cMyClass::Init()
{
// One-time initialization
CDC* pDc = GetDC();
mCanvasDc.CreateCompatibleDC(pDc);
mCanvasBmp.CreateCompatibleBitmap(pDc, 10, 10);
mpOldBitmap = mCanvasDc.SelectObject(&mCanvasBmp);
ReleaseDC(pDc);
BITMAP bitmap;
mpOldBitmap->GetBitmap(&bitmap); // A monochrome bitmap, as expected.
}
void cMyClass::Recreate(int newW, int newH)
{
// 1. Delete existing bitmap:
if (mpOldBitmap)
{
BITMAP bitmap;
mpOldBitmap->GetBitmap(&bitmap); // This is no longer the monochrome bitmap. It is 8bpp, with random size.
CBitmap* pCurrBmp = mCanvasDc.SelectObject(mpOldBitmap); // This fails (NULL). I can't de-select my bitmap.
mCanvasBmp.DeleteObject(); // This fails too, causing memory leak. Actually, it fails in CE6, but not in Win32. Regardless, both platforms will have a memory leak.
}
// 2. Recreate the bitmap with new size:
{
CDC* pDc = GetDC();
mCanvasBmp.CreateCompatibleBitmap(pDc, newW, newH);
ReleaseDC(pDc);
}
// 3. Finalize
mpOldBitmap = mCanvasDc.SelectObject(&mCanvasBmp);
}
Any known scenarios where this can happen?
Any debugging tips to break when the bitmap data changes?
Note: In code, I mentioned "this fails". I remove the assert on the returned values to make the code readable.
Edit: The solution that I am using to fix it is to use CDC:SaveDC and CDC::RestoreDC instead of stashing the pointer. The memory leak went away, and every GDI call passed. But I am still curious why the original code leaked. The pointer to the default bitmap, as far as I know, should be a default monochrome bitmap that is probably global in GDI world
Let's see the code from OP.
mpOldBitmap = mCanvasDc.SelectObject(mCanvasBmp);
Because mCanvasBmp is a CBitmap object (not a pointer to CBitmap), first is called the HGDIOBJ operator, then CDC::SelectObject(HGDIOBJ) which returns HGDIOBJ and not CBitmap*. This should give a conversion compiler error. If cast the returned value to CBitmap* is also wrong.
The correct way to get rid of problem is to pass a pointer.
mpOldBitmap = mCanvasDc.SelectObject(& mCanvasBmp);
This case will be called CDC::SelectObject(CBitmap* pBitmap) which returns a CBitmap*.
// I hope it's pretty clear. :)

How to compute the actual height of the text in a static control

My simple Win32 DialogBox contains two static text controls (IDC_STATIC_TITLE and IDC_STATIC_SECONDARY), here's what it looks like in the resource editor:
At run time, the text first string is updated dynamically. Also, the font of the that text string is replaced such that it's bigger than the IDC_STATIC_SECONDARY string below it. The resulting text string might span a single line, two lines, or more.
I want the other static control holding the secondary text to be placed directly underneath the title string at run time. However, my resulting attempt to re-position this control in the WM_INITDIALOG callback isn't working very well. The second string is overlapping the first. I thought I could use DrawText with DT_CALCRECT to compute the height of the primary text string and then move the secondary text string based on the result. My code is coming up a bit short as seen here:
DrawText returns a RECT with coordinates {top=42 bottom=74 left=19 right=461} Subtracting bottom from top is "32". That seems a little short. I suspect I'm not invoking the API correctly and/or an issue with the different mappings between logical and pixel units.
Here's the relevant ATL code. The CMainWindow class just inherits from ATL's CDialogImpl class.
CMainWindow::CMainWindow():
_titleFont(NULL),
_secondaryFont(NULL)
{
LOGFONT logfont = {};
logfont.lfHeight = 30;
_titleFont = CreateFontIndirect(&logfont);
}
LRESULT CMainWindow::OnInitDialog(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
{
CString strTitle;
RECT rectDrawText = {}, rectTitle={}, rectSecondary={};
CWindow wndTitle = GetDlgItem(IDC_STATIC_TITLE);
CWindow wndSecondary = GetDlgItem(IDC_STATIC_SECONDARY);
this->GetDlgItemText(IDC_STATIC_TITLE, strTitle);
wndTitle.SetFont(_titleFont); // font created with Create
wndTitle.GetWindowRect(&rectTitle);
wndSecondary.GetWindowRect(&rectSecondary);
ScreenToClient(&rectTitle);
ScreenToClient(&rectSecondary);
rectDrawText = rectTitle;
DrawText(wndTitle.GetDC(), strTitle, strTitle.GetLength(), &rectDrawText, DT_CALCRECT|DT_WORDBREAK); // compute the actual size of the text
UINT height = rectSecondary.bottom - rectSecondary.top; // get the original height of the secondary text control
rectSecondary.top = rectDrawText.bottom; // position it to be directly below the bottom of the title control
rectSecondary.bottom = rectSecondary.top + height; // add the height back
wndSecondary.MoveWindow(&rectSecondary);
return 0;
}
What am I doing wrong?
Despite what its name may make it sound like, wndTitle.GetDC() doesn't return some pointer/reference that's part of the CWindow and that's the same every call. Instead, it retrieves a brand new device context for the window each time. (It's basically a thin wrapper for the GetDC() Windows API call, right down to returning an HDC instead of the MFC equivalent.)
This device context, despite being associated with the window, is loaded with default parameters, including the default font (which IIRC is that old "System" font from the 16-bit days (most of this screenshot)).
So what you need to do is:
Call wndTitle.GetDC() to get the HDC.
Call SelectObject() to select the correct window font in (you can use WM_GETFONT to get this; not sure if MFC has a wrapper function for it), saving the return value, the previous font, for step 4
Call DrawText()
Call SelectObject() to select the previous font back in
Call wndTitle.ReleaseDC() to state that you are finished using the HDC
More details are on the MSDN page for CWindow::GetDC().

load a ttf font with the Windows API

With CreateFont one can specify font name and a bunch of other properties. However, what if I have a font.ttf file, and I want that particular font to be loaded by windows? How do I specify that specific file to be used?
I'm pretty sure you can't. All requests for fonts go through the font mapper, and it picks out the font file that comes the closest to meeting the specifications you've given. Though I'm not sure it even does in reality, it could at least theoretically use (for example) data from two entirely separate font files to create one logical font.
It's admittedly rather indirect, but you could utilize GDI interop with DWrite when running on Windows 7+.
#include <Windows.h>
#include <WindowsX.h>
#include <DWrite.h>
...
// Make the font file visible to GDI.
AddFontResourceEx(fontFileName, FR_PRIVATE, 0);
if (SUCCEEDED(GetLogFontFromFileName(fontFileName, &logFont)))
{
logFont.lfHeight = -long(desiredPpem);
HFONT hf = CreateFontIndirect(&logFont);
HFONT oldFont = SelectFont(hdc, hf);
...
// Do stuff...
...
SelectFont(hdc, oldFont);
}
RemoveFontResource(fontFileName);
....
HRESULT GetLogFontFromFileName(_In_z_ wchar const* fontFileName, _Out_ LOGFONT* logFont)
{
// DWrite objects
ComPtr<IDWriteFactory> dwriteFactory;
ComPtr<IDWriteFontFace> fontFace;
ComPtr<IDWriteFontFile> fontFile;
ComPtr<IDWriteGdiInterop> gdiInterop;
// Set up our DWrite factory and interop interface.
IFR(DWriteCreateFactory(
DWRITE_FACTORY_TYPE_SHARED,
__uuidof(IDWriteFactory),
reinterpret_cast<IUnknown**>(&dwriteFactory)
);
IFR(g_dwriteFactory->GetGdiInterop(&gdiInterop));
// Open the file and determine the font type.
IFR(g_dwriteFactory->CreateFontFileReference(fontFileName, nullptr, &fontFile));
BOOL isSupportedFontType = false;
DWRITE_FONT_FILE_TYPE fontFileType;
DWRITE_FONT_FACE_TYPE fontFaceType;
UINT32 numberOfFaces = 0;
IFR(fontFile->Analyze(&isSupportedFontType, &fontFileType, &fontFaceType, &numberOfFaces));
if (!isSupportedFontType)
return DWRITE_E_FILEFORMAT;
// Set up a font face from the array of font files (just one)
ComPtr<IDWriteFontFile> fontFileArray[] = {fontFile};
IFR(g_dwriteFactory->CreateFontFace(
fontFaceType,
ARRAYSIZE(fontFileArray), // file count
&fontFileArray[0], // or GetAddressOf if WRL ComPtr
0, // faceIndex
DWRITE_FONT_SIMULATIONS_NONE,
&fontFace
);
// Get the necessary logical font information.
IFR(gdiInterop->ConvertFontFaceToLOGFONT(fontFace, OUT logFont));
return S_OK;
}
Where IFR is just a failure macro that returns on a FAILED HRESULT, and ComPtr is a helper smart pointer class (substitute with your own, or ATL CComPtr, WinRT ComPtr, VS2013 _com_ptr_t...).
One possibility is to EnumFonts(), save the results. Then add your private font with AddFontResourceEx(), and EnumFonts() again, the difference is what you added. Note that TTF and bitmap fonts enumerate differently, but for this test, that shouldn't matter.
If you were using bitmap fonts, they could be easily parsed (.FNT and .FON). TTF you'd likely have to build (or borrow, as another commenter suggested FreeType) a parser to pull the "name" table out of the TTF file.
That seems like a lot of work for a font you're controlling or supplying with your app.
We use AddFontResourceEx() to add a private font, but since we control the font we're adding, we just hardcode the fontname passed to CreateFontIndirect() to match.
If you dont care about installing the font you can do so with AddFontResource then you can fetch the relationship between the physical .TTF and it logical/family name by looking at the mappings in HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Fonts.
I mentioned PrivateFontCollection in my comment because I thought you wanted to do this temporarily; you can load a TTF into a PFC with PrivateFontCollection::AddFontFile, fetch back the new FontFamily object from the collection & examime GetFamilyName. (I've done similar with the .net implementation of this but not the raw API)

Qt4: QAbstractTableModel Drag and Drop w/o MIME

I have a class which inherits QAbstractTableModel, and holds some complex structs in a QMap. The QVariant data(QModelIndex index, ...) method just returns an enum which describes how a custom item delegate should draw the contents of a cell. I would like to implement drag and drop functionality in this model so that users can reorder these structs in the QMap, but can't quite figure our how Qt would like me to do this. All I need is to see the source and destination indices of the drag/drop operation and I can take care of the rest, but the closest thing I've found in QAbstractItemModel is the dropMimeData() function. DropMimeData() doesn't give me the source index and requires me to convert the data into some MIME type (plaintext, etc.), which it is definitely not. I can hack my way through this by creating a QMimeData that just contains the source index, but I would like to really learn to use Qt as it's meant to be used, and I feel like I'm missing something. Any thoughts?
Just to help clarify a bit, the application is an animation program which acts sort of like Adobe Flash. The class which inherits QAbstractTableModel has a QMap<int, FrameState> (with struct FrameState{QPointF pos; bool visible;}) to hold keyframes. This state of this QMap is what I would like to display and have users edit. I draw a green circle if there is a visible key frame, a red circle if there is an invisible keyframe, a line if the previous keyframe was visible, and nothing if the previous keyframe was invisible. I would like users to be able to drag the keyframes around to change their QMap key.
Thanks!
You can use the views dragEnterEvent to get the indices that were selected initially:
void DropTreeView::dragEnterEvent(QDragEnterEvent *event)
{
QTreeView::dragEnterEvent(event);
const QItemSelectionModel * sm = selectionModel();
if (!sm)
return;
dragStartIndicies = sm->selectedIndexes();
}
You'll need to use the mime-types for the drag and drop, but C++ Qt provides a nice way to do that using QDataStream:
QMimeData *YourModel::mimeData( const QModelIndexList &indexes ) const
{
QByteArray encodedData;
QDataStream stream( &encodedData, QIODevice::WriteOnly );
stream << yourQMap /* OR almost any Qt data structure */;
QMimeData *mData = new QMimeData();
mData->setData( YOUR_MIME_TYPE, encodedData );
return mData;
}
On the receiving end, you can get your data structure (i.e. QMap if that's what you want to use) back out of the QDataStream:
QByteArray encodedData = yourMimeData->data( YOUR_MIME_TYPE );
QDataStream stream( &encodedData, QIODevice::ReadOnly );
QMap decodedMap;
stream >> decodedMap;

How to Create a Bitmap Programmatically?

I'd like to create programmatically a random X height and Y width bitmap file.
The content, for me, is irrelevant. It could be all white, empty. What is important is the dimension.
How to do it using Windows API?
You wish to create a Bitmap File using the windows API? There is no specific helper for this. a BMP file however is very simple:
Write out a BITMAPFILEHEADER struct.
Write out a BITMAPINFO struct.
Write out an array of bytes, enough to hold the format and dimensions described in the BITMAPINFO struct.
The MSDN has an Article with sample code demonstrating how.
I suppose you have Microsoft .NET 2.0 Framework installed. (1.1 is also usable).
Using Notepad, create test.cs file with this code:
namespace test
{
class Program
{
static void Main(string[] args)
{
if (args.Length == 3)
new System.Drawing.Bitmap(System.Convert.ToInt32(args[0]), System.Convert.ToInt32(args[1]))
.Save(args[2] + ".bmp", System.Drawing.Imaging.ImageFormat.Bmp);
else
System.Console.WriteLine("Usage: test.exe 100 200 filename");
}
}
}
Then create test.cmd file with this code:
#echo off
%windir%\Microsoft.NET\Framework\v2.0.50727\csc.exe /t:exe test.cs
Execute test.cmd
Execute text.exe
In .Net you can just new up a Bitmap object:
Image myImage = new Bitmap(width, height);
GDI+ includes commands to load/save BMP images in C++. This sample code shows how to load and save images: Converting a BMP Image to a PNG Image. The Bitmap class also has a ctor that takes a width, a height and a pixel format to create empty images.
If you really insist on making an image with windows API,you should use Gdi32.dll
In C# just call
Import dll file into your assembly, so you can use external methods in
DllImport["Gdi32.dll"]
HBITMAP CreateCompatibleBitmap(
HDC hdc,
int nWidth,
int nHeight
);
Then call Bitmap class from this Bitmap like
Bitmap bmp = Bitmap.FromHbitmap( nameOfBitmap );
bmp.Save("C:\NewImage.jpg");
There is an example in msdn page here

Resources