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
Related
I'm 'casting' the screen of window1 to window2 using the WINAPI DwmRegisterThumbnail
but as soon I set the window2 child of another window the image disappears.
After reading the docs I found this mention:
Setting the destination window handle to anything other than a
top-level window type will result in a return value of E_INVALIDARG.
HWND dest = (HWND)this->winId();
HWND source = ...
hr = DwmRegisterThumbnail(dest, source, &thumbnail_id);
DWORD err = GetLastError();
qDebug() << "hr: " << hr;
if (SUCCEEDED(hr) && NULL != thumbnail_id)
{
prop.dwFlags = DWM_TNP_RECTDESTINATION | DWM_TNP_RECTSOURCE | DWM_TNP_OPACITY
| DWM_TNP_VISIBLE | DWM_TNP_SOURCECLIENTAREAONLY;
prop.rcSource = { 0, 0, 1200, 600 };
prop.rcDestination = { 0, 0, 1200, 600 };
prop.opacity = 255;
prop.fVisible = TRUE;
prop.fSourceClientAreaOnly = FALSE;
hr = DwmUpdateThumbnailProperties(thumbnail_id, &prop);
qDebug() << "hr: " << hr;
}
I also tried using a QDockWidget but the image is visible only when the widget is not docked to the MainWindow, as soon I dock the widget, the image disappears, sad.
There's something else I could try to be able to 'cast' the image to a child window?
or maybe another winapi I could use?
I have two fonts which are used by my Windows C++ app (Ubuntu, Roboto Regular and Roboto Thin) and I have tried to install them with AddFontResource and AddFontResourceEx but it does not work in the latest Anniversary Edition of Windows 10 and also in Windows Server 2008 and 2012.
The font does not get installed. So I have created my Font Installation C++ class.
In my C++ / VSNET2015 function I do the following:
Copy the .TTF font files in C:\Windows\Fonts
Add the .TTF font files to HKEY_LOCAL_MACHINE\Software\Microsoft\Windows NT\CurrentVersion\Fonts FontName (TrueType) - FontFile.ttf
Call AddFontResource(FontFileName)
Send WM_FONTCHANGE message.
The fonts get installed and works every time, but is working until I restart Windows then it doesn't. The font files are there and the registry entries are ok also the fonts show in the Windows Fonts Explorer, but it cannot be used in my application and the fonts cannot be deleted from Windows Fonts Explorer because the fonts are in use (with the app closed).
/**********************************************************************/
BOOL CInstallFont::InstallFont(CString strFontName, CString strFontFileName, BOOL bRegular)
{
m_strFontName = strFontName;
m_strFontFileName = strFontFileName;
if (IsFontInstalled() == TRUE)
if (CanCreateFont(strFontName)) // try to create the font and if successful, then don't install it again
return TRUE;
/*****************************************************/
/* Copy Font to Windows\Fonts folder */
/*****************************************************/
CPathW pwSrc;
CPathW pwDest;
CString strTmp, strTmp2;
FolderUtils f;
CString strFontsFolder = _T("");
f.GetSpecialFolder(CSIDL_FONTS, strFontsFolder);
strTmp2 = theApp.m_strAppFolder;
pwSrc.Combine(strTmp2, strFontFileName);
pwDest.Combine(strFontsFolder, strFontFileName);
BOOL bRet=CopyFile(pwSrc, pwDest, TRUE);
if (bRet == FALSE)
{
strTmp = _T("Error: Cannot copy font file ");
strTmp += strFontFileName;
AfxMessageBox(strTmp, MB_ICONEXCLAMATION);
}
/*****************************************************/
/* Add Font to Registry */
/*****************************************************/
CRegKey reg;
LONG lRet=0;
lRet = reg.Open(HKEY_LOCAL_MACHINE, _T("SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Fonts"), KEY_READ | KEY_WRITE);
if (lRet == ERROR_SUCCESS)
{
CString strFullFontName = strFontName;
strFullFontName += _T(" (TrueType)");
reg.SetStringValue(strFullFontName, strFontFileName); // For OpenType fonts you need to change the value here
}
reg.Close();
/*****************************************************/
//AddFontResource(strFontFileName);
SendMessage(HWND_BROADCAST, WM_FONTCHANGE, 0, 0);
return TRUE;
}
/**********************************************************************/
int CALLBACK CInstallFont::EnumFontFamExProc(ENUMLOGFONTEX* /*lpelfe*/, NEWTEXTMETRICEX* /*lpntme*/, int /*FontType*/, LPARAM lParam)
{
LPARAM* l = (LPARAM*)lParam;
*l = TRUE;
return TRUE;
}
/**********************************************************************/
/* Test to see if the font can be created */
BOOL CInstallFont::CanCreateFont(CString strFontName)
{
CFont font;
BOOL bRet=font.CreateFont(
16, // nHeight
0, // nWidth
0, // nEscapement
0, // nOrientation
FW_NORMAL, // nWeight
FALSE, // bItalic
FALSE, // bUnderline
0, // cStrikeOut
DEFAULT_CHARSET, // nCharSet
OUT_DEFAULT_PRECIS, // nOutPrecision
CLIP_DEFAULT_PRECIS, // nClipPrecision
ANTIALIASED_QUALITY, // nQuality
DEFAULT_PITCH | FF_SWISS, // nPitchAndFamily
strFontName); // lpszFacename
font.DeleteObject();
return bRet;
}
/**********************************************************************/
BOOL CInstallFont::IsFontInstalled()
{
// Get the screen DC
CDC dc;
if (!dc.CreateCompatibleDC(NULL))
{
return false;
}
LOGFONT lf = { 0 };
// Any character set will do
lf.lfCharSet = DEFAULT_CHARSET;
// Set the facename to check for
wcscpy_s(lf.lfFaceName, m_strFontName.GetLength()*2, (LPCTSTR)m_strFontName);
LPARAM lParam = 0;
// Enumerate fonts
::EnumFontFamiliesEx(dc.GetSafeHdc(), &lf, (FONTENUMPROC)EnumFontFamExProc, (LPARAM)&lParam, 0);
return lParam ? TRUE : FALSE;
}
I call the function with the following parameters
CInstallFont instFont;
instFont.InstallFont(_T("Roboto Light"), _T("Roboto-Light.ttf"));
instFont.InstallFont(_T("Roboto Thin"), _T("Roboto-Thin.ttf"));
instFont.InstallFont(_T("Roboto Regular"), _T("Roboto-Regular.ttf"));
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);
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();
}
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.