HICON to CImage - c++

I want to load the icon of an .exe in a CImage object, in order to easily display and save it in a database. My problem is that I have an HICON and I seem to only be able to load/attach an HBITMAP to a CImage object.
SHFILEINFO sfi;
Cimage icon;
DWORD ret = SHGetFileInfo(path, 0, &sfi, sizeof(SHFILEINFO), SHGFI_ICON | SHGFI_SMALLICON | SHGFI_DISPLAYNAME);
if(ret != 0) {
// copy info
hIcon = sfi.hIcon;
if(hIcon != lastHIcon && hIcon != 0) {
// This does not work, needs a HBITMAP instead of a HICON
icon.Attach(hIcon);
}
}
Is there any easy method of doing this, or do I need to render the HICON to a DC first? It just seems to me that there should be a solution that does not require me to be a GDI expert.

Related

How can I get icon of Windows app in CPP?

I'm trying to build an File Manager with in Win32, and I have a problem with the icons. Whenever I trying to get icon that an windows 10 app is associated with it like .png (Photos app), the icon is blank paper. What I'm doing wrong? Thanks in advance and please answer :)
BOOL InitTreeViewImageLists(HWND hwndTV) {
HIMAGELIST himl; // handle to image list
HBITMAP hbmp; // handle to bitmap
// Create the image list.
if ((himl = ImageList_Create(16,
16,
ILC_COLOR16 | ILC_MASK,
3, 0)) == NULL)
return FALSE;
// Add the open file, closed file, and document bitmaps.
HICON hIcon;
SHFILEINFO sfi;
LPCWSTR path = L"C:\\Users\\Shalev\\Desktop\\WhatsApp.lnk";
sfi = GetShellInfo(path);
HICON* iconHandles = new HICON;
hIcon = sfi.hIcon;
cout << hIcon << endl;
g_nOpen = sfi.iIcon;
ImageList_AddIcon(himl, hIcon);
sfi = GetShellInfo(L"C:\\");
hIcon = sfi.hIcon;
g_nClosed = sfi.iIcon;
ImageList_AddIcon(himl, hIcon);
sfi = GetShellInfo(L"C:\\");
hIcon = sfi.hIcon;
g_nDocument = sfi.iIcon;
ImageList_AddIcon(himl, hIcon);
// Associate the image list with the tree-view control.
TreeView_SetImageList(hwndTV, himl, TVSIL_NORMAL);
return TRUE;
}
SHFILEINFO GetShellInfo(LPCWSTR path) {
SHFILEINFO sfi;
SecureZeroMemory(&sfi, sizeof(sfi));
SHGetFileInfo(path, 0, &sfi, sizeof(sfi), SHGFI_SYSICONINDEX | SHGFI_SHELLICONSIZE | SHGFI_ICON | SHGFI_SMALLICON | SHGFI_USEFILEATTRIBUTES);
return sfi;
}
You can use the IShellItemImageFactory interface, something like this:
...
CoInitializeEx(NULL, COINIT_APARTMENTTHREADED); // need this somewhere when your thread begins, not for every call
...
IShellItemImageFactory* factory;
if (SUCCEEDED(SHCreateItemFromParsingName(path, nullptr, IID_PPV_ARGS(&factory))))
{
// the GetImage method defines a required size and multiple flags
// with which you can specify you want the icon only or the thumbnail, etc.
HBITMAP bmp;
if (SUCCEEDED(factory->GetImage(SIZE{ 256, 256 }, SIIGBF_ICONONLY, &bmp)))
{
... // do something with the HBITMAP
DeleteObject(bmp);
}
factory->Release();
}
...
CoUninitialize(); // call this each time you successfully called CoInitializeEx

MFC how to convert PNG with transparent attribute to HBITMAP

I loaded PNG file using GDI+.
My source use HBITMAP so I convert PNG to HBITMAP.
PNG file has a transparent background but HBITMAP has a background.
I want to remove backround from HBITMAP.
I don't really have enough information. This is how I load transparent PNG files:
// Based on afxbutton.cpp's static function ButtonLoadBitmap
HBITMAP __stdcall CMeetingScheduleAssistantApp::ButtonLoadBitmap(UINT uiBmpResId)
{
if (uiBmpResId == 0)
{
return nullptr;
}
LPCTSTR lpszResourceName = MAKEINTRESOURCE(uiBmpResId);
ENSURE(lpszResourceName != nullptr);
HBITMAP hbmp = nullptr;
// Try to load PNG image first:
CPngImage pngImage;
if (pngImage.Load(lpszResourceName))
{
hbmp = (HBITMAP)pngImage.Detach();
}
else
{
HINSTANCE hinstRes = AfxFindResourceHandle(lpszResourceName, RT_BITMAP);
if (hinstRes == nullptr)
{
return nullptr;
}
UINT uiLoadImageFlags = LR_CREATEDIBSECTION | LR_LOADMAP3DCOLORS;
hbmp = (HBITMAP) ::LoadImage(hinstRes, lpszResourceName, IMAGE_BITMAP, 0, 0, uiLoadImageFlags);
}
return hbmp;
}
My code is designed to load a resource but you can adjust it to work with external files.

SelectObject returns NULL with hbitmap created in constructor

I have a bitmap class that has a load function for loading the bitmap from either file path or resource ID. This part works fine.
void GtBitmap::Load()
{
LPTSTR szFileName;
szFileName = (LPTSTR)m_strPath.c_str();
// Check for valid .BMP file path
if (m_strPath.size() > 0)
{
// Open .BMP file
m_pFile = fopen(m_strPath.c_str(), ("rb"));
if (m_pFile != NULL)
{
m_hBitmap = (HBITMAP)LoadImage (GetModuleHandle(NULL), szFileName, IMAGE_BITMAP, 0, 0, LR_SHARED | LR_LOADFROMFILE);
GetObject(m_hBitmap, sizeof(m_bmap), &m_bmap);
int i = 1;
}
}
else if (m_intResourceID != 0)
{
m_hBitmap = (HBITMAP)LoadImage(GetModuleHandle(NULL), MAKEINTRESOURCE(m_intResourceID), IMAGE_BITMAP, 0, 0, LR_SHARED);
GetObject(m_hBitmap, sizeof(m_bmap), &m_bmap);
int i = 1;
}
}
However, when I try to render it in my code block, the SelectObject returns null. Here is the code for that section of the painter class.
void GtPainterGDI::GtDrawBitmap(GtRectI & target, GtBitmap & bitmap, bool blnOffset)
{
GtCanvas topCv = m_arrCanvas.back();
HDC hdcMem = CreateCompatibleDC(topCv.m_hdcParent);
HBITMAP hbmOld = (HBITMAP)SelectObject(hdcMem, bitmap.m_hBitmap);
DWORD lastError = GetLastError();
bool success = BitBlt(hdcMem, target.GetLeft(), target.GetTop(),
target.Width(), target.Height(), hdcMem, 0, 0, SRCCOPY);
SelectObject(hdcMem, bitmap.m_hBitmap);
DeleteDC(hdcMem);
};
The SelectObject() returns null and the image is not drawn. I can only get the image to show up if I use a LoadImage() in that paint function. However I don't want to load the image every time I want to paint. I should be able to load the image once in the Load function or constructor of the bitmap, then use the handle in the paint function.
If anyone could please provide an example of loading an image in a constructor and then painting it elsewhere in the codes WM_PAINT or equivalent painting function I would appreciate it. The code is a new version of the GT graphical user interface library. I plan on posting a new version on codeproject in the next few days or so. I have to do some cleanup first...
Thanks in advance.
HINSTANCE parameter in LoadImage should be NULL when loading the image from file. Use GetModuleHandle(NULL) only when loading from resource.
m_hBitmap = (HBITMAP)LoadImage(NULL, m_strPath.c_str(),
IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE);
if (!m_hBitmap)
{
//report error
}
Also LR_SHARED is not necessary here.
When testing for file's exist, you can use std::ifstream. Example:
#include <fstream>
...
bool test = std::ifstream(m_strPath).good();
This will test for file and close the file handle right away.
Make sure to select hbmOld before deleting hdcMem:
HBITMAP hbmOld = (HBITMAP)SelectObject(hdcMem, bitmap.m_hBitmap);
BitBlt(...)
//SelectObject(hdcMem, bitmap.m_hBitmap); <<= remove this
SelectObject(hdcMem, hbmOld);
DeleteDC(hdcMem);

Load BMP from file by using MFC

I try to load a bmp to my MFC Picture Control.
void CMFCAppDlg::OnBnClickedButtonload()
{
CFileDialog dlg(TRUE);
int result=dlg.DoModal();
if(result==IDOK)
{
MyBmpFile::Instance() -> setPath (dlg.GetPathName());
UpdateData(FALSE);
}
HANDLE hBitmap = LoadImage(0, MyBmpFile::Instance() -> getPath(), IMAGE_BITMAP,0,0,LR_LOADFROMFILE);
CBitmap m_bitmap;
m_bitmap.Attach((HBITMAP)hBitmap);
CDC dc, *pDC;
BITMAP bmp;
m_bitmap.LoadBitmapW(IDB_BITMAP);
m_bitmap.GetBitmap(&bmp);
pDC = this->GetDC();
dc.CreateCompatibleDC(pDC);
dc.SelectObject(m_bitmap);
pDC->BitBlt(200, 200, bmp.bmWidth, bmp.bmHeight, &dc,0 , 0, SRCCOPY);
m_bitmap.DeleteObject();
m_bitmap.Detach();
}
This code returns me an error after I select an item in dialog box. Problem is with LoadImage() it returns NULL. But actually I dont know what im doing wrong with that.
Ok, I used CImage to draw this bmp, anyway i did not solve the problem with LoadImage(). I try to make it in static way like: L"D:\\e.bmp" or _T("D:\\e.bmp") but even there problem is the same as before.
void CMFCAppDlg::OnBnClickedButtonload()
{
CFileDialog dlg(TRUE);
int result=dlg.DoModal();
if(result==IDOK)
{
MyBmpFile::Instance() -> setPath (dlg.GetPathName());
UpdateData(FALSE);
}
CImage image;
image.Load( MyBmpFile::Instance() ->getPath() );
CDC dc, *pDC;
pDC = this->GetDC();
dc.CreateCompatibleDC(pDC);
image.Draw(pDC -> GetSafeHdc(),0,0);
}
Following may be of help:
INSTANCE hInst = AfxGetInstanceHandle();
HBITMAP hBmp = (HBITMAP)LoadImage(hInst, L"path\to\file.bmp", IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE);
Couple of things to check:
Are you using 1-byte or 2-byte characters. Use the L macro for the latter.
Is the path to your file correctly specified (e.g. could be relative to where the program happens to run from)
Can you load the file manually as a bitmap as in the example below?
Code to load a file manually as a bitmap:
CFile file;
if (file.Open(L"C:\\Tmp\\Example.bmp", CFile::modeRead))
{
// Read file header
BITMAPFILEHEADER bmfHeader;
if (file.Read((LPSTR) &bmfHeader, sizeof(bmfHeader)) == sizeof(bmfHeader))
{
// File type should be 'BM'
if (bmfHeader.bfType == ((WORD)('M' << 8)| 'B'))
{
BITMAPINFOHEADER bmiHeader;
if (file.Read((LPSTR) &bmiHeader, sizeof(bmiHeader)) == sizeof(bmiHeader))
{
int width = bmiHeader.biWidth;
int height = bmiHeader.biHeight;
}
}
}
file.Close();
}

Images in ListControl are not Clear in MFC SDI application

I am working on one MFC/SDI project Where I am using CListView as a default View.
But the thing is, I have applied ImageList to the CListCtrl
but these Images are not clearly displayed.
As shown in the picture below.
Below is the code for creating new image List.
Creating ImageList where m_ImgList is a member of CImageList.
if(m_ImgList->m_hImageList == NULL || m_ImgList->DeleteImageList() == TRUE)
{
m_ImgList->Create(16,16, ILC_COLOR,0, 1);
}
Then I am creating images by using BLOB data from database.
Here, pByte is BYTE* to hold BLOB Data.
HGLOBAL hGlobal = ::GlobalAlloc(GMEM_MOVEABLE, nbytes+5);
LPVOID pV = GlobalLock(hGlobal);
memcpy(pV, pByte, nbytes);
GlobalUnlock(hGlobal);
LPSTREAM pstm = NULL;
HRESULT hr = CreateStreamOnHGlobal(hGlobal, TRUE, &pstm);
CImage image;
image.Load(pstm);
if (image == NULL)
{
image.Load(NILIMAGE);
}
CPaintDC dc(this);
CDC pMDC;
pMDC.CreateCompatibleDC(&dc);
CBitmap pb;
pb.CreateCompatibleBitmap(&dc, iNewWidth, iNewHeight);
CBitmap *pob = (CBitmap*)pMDC.SelectObject(&pb);
image.StretchBlt(pMDC.m_hDC,0, 0, iNewWidth, iNewHeight,
0, 0, image.GetWidth(), image.GetHeight(), SRCCOPY);
pMDC.SelectObject(pob);
Adding images to the image list
if((m_ImgList->Add(&pb, RGB(0,0,0)))== -1)
{
_T("undone");
}
if(hGlobal != NULL)
::GlobalFree(hGlobal);
Can anyone tell me how can I do that?
Thank you in Advance.
and Sorry for bad English.