PDA

View Full Version : Extracting larger icons



MisterIKS
29th April 2010, 16:03
Hi everyone,

I'm trying to extract program icons out of exe-files. This works using the following Qt function with the path of my exe-file saved in filePath:


QFileInfo *info = new QFileInfo(filePath);
QFileIconProvider *provider = new QFileIconProvider();
image = new QImage(provider->icon(*info).pixmap(128,128).toImage());

My problem is, that this function only extracts the smallest iocn the file containst, usually 32 x 32 pixels. Most of todays software provides icons in higher resolution up to 256 x 256, but I can't see a way to set this neither in QFileInfo nor in QFileIconProvider. I found another possibility using the windows API with the function ExtractIconEx:


HICON smallIcon, bigIcon;
WCHAR path;
filePath.toWCharArray(&path);
ExtractIconEx(&path,0,&smallIcon,&bigIcon,1);
image = new QImage(QPixmap::fromWinHICON(bigIcon).toImage());

The compiler does't show any errors, but the QImage keeps empty. I hope anybody could help me with extracting larger program-icons out of exe-file. I've tried it in another forum before, but I didn't get any answer at all, so QtCenter appears to have much more promise.

MisterIKS
2nd May 2010, 16:09
Huh, no answers either...

I still believe, that theres a way to do this, and I hope that theres somebody out there who knows the way, please don't fail me. Just a hint how it could possibly work, just so that I can go on trying.

squidge
2nd May 2010, 16:55
I don't know about a Qt way (it seems to only return a single icon, either the small or the big depending on which is available), but on Windows you can get the icon via SHGetFileInfo() and then use the convertHIconToPixmap function in qpixmap_win.cpp (which has a big fat warning at the top of the file, so you need to either copy the code and be GPL licensed or write your own version).

MisterIKS
3rd May 2010, 05:30
Thanks, that's worth a try! I'll come back as soon as I had time to try it.

MisterIKS
5th May 2010, 16:06
I've now tried using SHGetFileInfo() the following way:


LPCTSTR path = (LPCTSTR)filePath.toStdString().c_str();
SHFILEINFO fileInfo = {0};
SHGetFileInfo(path,-1,&fileInfo,sizeof(fileInfo),SHGFI_ICON | SHGFI_LARGEICON);

*pixmap = QPixmap::fromWinHICON(fileInfo.hIcon);

That's the way I would think it should work, but it doesn't. The code onse again compiles error-less but as soon as debugger runs through the function I get SIGSEGV, operating system signal inside of QPixmap::fromHIcon().
I didn't quite get, what you meant with
so you need to either copy the code and be GPL licensed or write your own version. Any further advice?

Thanks a lot!

squidge
5th May 2010, 22:25
Since you are using Qt you should be passing a unicode string to SHGetFileInfo, not a LPCTSTR:


SHGetFileInfo(QDir::toNativeSeparators(fileName).u tf16(), ...

Secondly, I prefer to grab a handle to the system icon list and then use SYSICONINDEX param to SHGetFileInfo(), but it's your choice.

MisterIKS
6th May 2010, 05:27
Thanks for your reply, but the code you suggested doesn't seem to work. SHGetFileInfo(), as MSDN says, requires LPCTSTR/ const char*, but your code produces const ushort*:

QDir::toNativeSeparators(filePath).utf16()
These are not compatible and a direct cast won't work either. I really don't know what to do, as just about any modern application wich does a such task is capable of extracting larger icons, I'd never thought that it could be that difficult. :confused:

squidge
6th May 2010, 08:13
If you are using Qt, then you will be using the Unicode libraries, so SHGetFileInfo will be aliased to SHGetFileInfoW, which although the prototype will be LPCTSTR, you can (and should) use a Unicode string provided by utf16()

Let me dig out an example from one of my apps... [structure and error checking removed]



HIMAGELIST ImageList;
HICON WinIcon;

ImageList = (HIMAGELIST) SHGetFileInfo((const WCHAR *)QDir::toNativeSeparators(ee->filePath).utf16(), 0, &FileInfo, sizeof(SHFILEINFO), SHGFI_LARGEICON|SHGFI_SYSICONINDEX);

WinIcon = ImageList_GetIcon(ImageList, FileInfo.iIcon, ILD_NORMAL);

MisterIKS
6th May 2010, 16:08
Thank you so much for that example, I'm confident of it to work fine, but sorry for getting on your nerves, but what do I need to include in order to get this to work? I Included "windows.h" which works fine for SHFILEINFO and HICON but doesn't provide HIMAGELIST.I've googled for it and the second result was this thread itself.

I'm looking forward to finally getting this to work after endless weeks of trying :D Once again, thank you!

squidge
6th May 2010, 17:32
Try CommCtrl.h

MisterIKS
7th May 2010, 11:58
The output window throughs out the following error:

undefined reference to `ImageList_GetIcon@12`
collect2: ld returned 1 exit status

I've neither seen the first line, nor the second line in this context. "windows.h" and "commctrl.h" are included, I can't see a solution...

MTW
3rd November 2010, 14:35
Hi, I am having the same problem. But I know that the WinAPI Method
SHGetImageList() could do the job. The problem I have is that SHGetImageList is not found in my QtCreator although I include "shellapi.h" which is required according to msdn. Does anybody has some hints for me to get this function working?

squidge
3rd November 2010, 18:55
SHGetImageList is part of Windows SDK 'shellapi.h' header file. Last time I looked it was not supported in MinGW version of 'shellapi.h'.

MTW
3rd November 2010, 19:38
Ok, as mingw is opensource is there any way to include this function into the mingw 'shellapi.h' version?

squidge
3rd November 2010, 22:09
Depends if MinGW has a linker library for it. Why not copy the definition from the WinSDK and see?

Or perhaps a newer/different version of MinGW already has the function?

ChrisW67
3rd November 2010, 22:39
HICON smallIcon, bigIcon;
WCHAR path;
filePath.toWCharArray(&path);
ExtractIconEx(&path,0,&smallIcon,&bigIcon,1);
image = new QImage(QPixmap::fromWinHICON(bigIcon).toImage());


This looks wrong. Your path variable is a single WCHAR (i.e. a single wide char) and not a pointer to an array of them. From the docs of QString::toWCharArray()

int QString::toWCharArray ( wchar_t * array ) const
Fills the array with the data contained in this QString object. The array is encoded in utf16 on platforms where wchar_t is 2 bytes wide (e.g. windows) and in ucs4 on platforms where wchar_t is 4 bytes wide (most Unix systems).

array has to be allocated by the caller and contain enough space to hold the complete string (allocating the array with the same length as the string is always sufficient).

returns the actual length of the string in array.

Note: This function does not append a null character to the array.

I have not tried this (Windows code goes poorly on Linux) but something like:

HICON smallIcon, bigIcon;
WCHAR path[1024];
// ^^^^^ there is probably some actual size limit you can use
// or you can dynamically allocate the right number based on the filePath string length
int numChars = filePath.toWCharArray(path);
path[numChars] = '\0'; // make sure of Nul termination
ExtractIconEx(path,0,&smallIcon,&bigIcon,1);
image = new QImage(QPixmap::fromWinHICON(bigIcon).toImage());

is probably closer.