SetIcon bug

  • Thread starter Thread starter Rajko
  • Start date Start date
R

Rajko

I found possible bug with set icon.
I'm not sure but I don't think this is supposed to work like this.

Program uses large instead of small icons.
Please tell me is it known bug or maybe I missed something.

If it is a bug I made document how to make it happen. So I'll send it to
someone who can verify it.

Thanks, Rajko.
 
I found possible bug with set icon.
I'm not sure but I don't think this is supposed to work like this.

Program uses large instead of small icons.
Please tell me is it known bug or maybe I missed something.

If it is a bug I made document how to make it happen. So I'll send it to
someone who can verify it.

Why don't you post a minimal code snippet here that illustrates how to
reproduce this issue?

Dave
 
OK. This one is quite simple.
Since I tested behaviour, I created following results of my test:
I hope you can read html (red is possible error).
BTW I don't have all Windows updates because I had problem with Windows(including sasser).
SetIcon(); --> I avoided this function because :
_AFXWIN_INLINE HICON CWnd::SetIcon(HICON hIcon, BOOL bBigIcon)
{ ASSERT(::IsWindow(m_hWnd)); return (HICON)::SendMessage(m_hWnd, WM_SETICON, bBigIcon, (LPARAM)hIcon); }
)

I used: "SendMessage(WM_SETICON, ...);" = SM

Resources: 3 separate files with resource ids: IDI_ICONS(for small - list and details), IDI_ICONL(for large - icons), IDI_ICONX(for xlarge - tiles and thumbinals)

S=small, L=large, X=xlarge

App icon Windows Explorer (list view ctrl)
Function calls top-left(=small) Alt+Tab(=large) Small(16x16) Large(32x32) XLarge(48x48)
SM + ICON_SMALL + IDI_ICONS
S NULL S S S
SM + ICON_SMALL + IDI_ICONL L NULL S S S
SM + ICON_SMALL + IDI_ICONX X NULL S S S
SM + ICON_BIG + IDI_ICONS
S S S S S
SM + ICON_BIG + IDI_ICONL L L S S S
SM + ICON_BIG + IDI_ICONX X X S S S
SM + ICON_SMALL + IDI_ICONS
SM + ICON_SMALL + IDI_ICONL
SM + ICON_SMALL + IDI_ICONX

X X S S S
SM + ICON_BIG + IDI_ICONS
SM + ICON_BIG + IDI_ICONL
SM + ICON_BIG + IDI_ICONX
X X S S S

Resources: 1 ico file with icon sizes 32x32, 16x16, 48x48, Id = IDI_ICONALL

App icon Windows Explorer (list view)
Function calls top-left(=small) Alt+Tab(=large) Small(16x16) Large(32x32) XLarge(48x48)
SM + ICON_SMALL + IDI_ICONALL L NULL S L X
SM + ICON_BIG + IDI_ICONALL S L S L X
SM + ICON_SMALL + IDI_ICONALL
SM + ICON_BIG + IDI_ICONALL
L L S L X
SM + ICON_BIG + IDI_ICONALL
SM + ICON_SMALL + IDI_ICONALL
L L S L X

This is how it looked like over here:

BOOL CTestDlgIconDlg::OnInitDialog() {
CDialog::OnInitDialog();
....
SendMessage(WM_SETICON, ICON_BIG, (LPARAM)AfxGetApp()->LoadIcon(IDI_ICONALL));
SendMessage(WM_SETICON, ICON_SMALL, (LPARAM)AfxGetApp()->LoadIcon(IDI_ICONALL));
....


--------------------------------------------------------------------------------

MFC Library Reference

CWnd::SetIcon
Call this member function to set the handle to a specific icon, as identified by hIcon.

HICON SetIcon(
HICON hIcon,
BOOL bBigIcon
);Parameters
hIcon
A handle to a previous icon.
bBigIcon
Specifies a 32 pixel by 32 pixel icon if TRUE; specifies a 16 pixel by 16 pixel icon if FALSE.
Return Value
A handle to an icon.

Remarks
When the window class is registered, it selects an icon.

Example
See the example for CWnd::GetSystemMenu.

See Also
CWnd Overview | Class Members | Hierarchy Chart | GetIcon



--------------------------------------------------------------------------------

Send feedback on this topic to Microsoft

© Microsoft Corporation. All rights reserved.


--------------------------------------------------------------------------------

--------------------------------------------------------------------------------

--------------------------------------------------------------------------------



WM_SETICON Message

--------------------------------------------------------------------------------

An application sends the WM_SETICON message to associate a new large or small icon with a window. The system displays the large icon in the ALT+TAB dialog box, and the small icon in the window caption.

Syntax


To send this message, call the SendMessage function as follows.
lResult = SendMessage( // returns LRESULT in lResult (HWND) hWndControl, // handle to destination control (UINT) WM_SETICON, // message ID (WPARAM) wParam, // = (WPARAM) () wParam; (LPARAM) lParam // = (LPARAM) () lParam; ); Parameters

wParam
Specifies the type of icon to be set. This parameter can be one of the following values.
ICON_BIG
Set the large icon for the window.
ICON_SMALL
Set the small icon for the window.
lParam
Handle to the new large or small icon. If this parameter is NULL, the icon indicated by wParamis removed.
Return Value

The return value is a handle to the previous large or small icon, depending on the value of wParam. It is NULL if the window previously had no icon of the type indicated by wParam.


Remarks

The DefWindowProc function returns a handle to the previous large or small icon associated with the window, depending on the value of wParam.

Message Information

Header Declared in Winuser.h, include Windows.h
Minimum operating systems Windows 95, Windows NT 4.0

See Also

Windows Overview, DefWindowProc, WM_GETICON

--------------------------------------------------------------------------------

© 2003 Microsoft Corporation. All rights reserved.
 
Since I tested behaviour, I created following results of my test:
I hope you can read html (red is possible error).

No HTML here thanks.
Resources: 3 separate files with resource ids: IDI_ICONS(for small - list and details), IDI_ICONL(for large - icons), IDI_ICONX(for xlarge - tiles and thumbinals)
S=small, L=large, X=xlarge
App icon Windows Explorer (list view ctrl)
Function calls top-left(=small) Alt+Tab(=large) Small(16x16) Large(32x32) XLarge(48x48)
SM + ICON_SMALL + IDI_ICONS
snip

I'm afraid I've not got the faintest idea what you're trying to tell
us in that lot.
SendMessage(WM_SETICON, ICON_BIG, (LPARAM)AfxGetApp()->LoadIcon(IDI_ICONALL));
SendMessage(WM_SETICON, ICON_SMALL, (LPARAM)AfxGetApp()->LoadIcon(IDI_ICONALL));

Use LoadImage rather than LoadIcon. LoadIcon only loads icons of size
SM_CXICON, SM_CYICON.

Dave
 
Ok, I messed up with HTML.
HTML doc basically said that i tested behaviour of SetIcon();
BTW LoadIcon from recource works fine.
And I found something strange.
First some background:
There are 3 types of icons in XP: small, large, dont know the name so I'll
call it xlarge.
Usage: small = app icon in topleft corner of the window (16x16)
large = app icon which appears on Alt+Tab action
xlarge = app icon which appears in Windows Explorer on Thumbinal view or
Tiles view.
This was needed for debugging.

It work fine for most cases, except one:
When I used (from CDialog):
SendMessage(WM_SETICON, ICON_SMALL, IDI_ICONALL);
IDI_ICONALL is recource icon with all three types of icon (small, large and
xlarge).

What happen is:
small app icon is resized and set to large icon
and
large app icon is NULL

but if I use: SendMessage(WM_SETICON, ICON_BIG, IDI_ICONALL);
small = small and large = large that is OK!

if I combine thesse two:
SendMessage(WM_SETICON, ICON_SMALL, IDI_ICONALL);
SendMessage(WM_SETICON, ICON_BIG, IDI_ICONALL);
or
SendMessage(WM_SETICON, ICON_BIG, IDI_ICONALL);
SendMessage(WM_SETICON, ICON_SMALL, IDI_ICONALL);
order isn't important.
I always get:
small = large
large = large

and it should be:
small = small
large = large


Rajko.



David Lowndes said:
No HTML here thanks.
and details), IDI_ICONL(for large - icons), IDI_ICONX(for xlarge - tiles and
thumbinals)
 
It work fine for most cases, except one:
When I used (from CDialog):
SendMessage(WM_SETICON, ICON_SMALL, IDI_ICONALL);
IDI_ICONALL is recource icon with all three types of icon (small, large and
xlarge).

But the WM_SETICON message requires a handle to an icon - not the
resource ID, so nothing you've written makes much sense. This is not
code that will work - so what exactly are you doing?

Are you using LoadIcon rather than LoadImage in your code somewhere?

Dave
 
Rajko said:
Ok, I messed up with HTML.
HTML doc basically said that i tested behaviour of SetIcon();
BTW LoadIcon from recource works fine.

As Dave said, LoadIcon only loads the SM_CXICON/SM_CYICON sized icon.
And I found something strange.
First some background:
There are 3 types of icons in XP: small, large, dont know the name so I'll
call it xlarge.
Usage: small = app icon in topleft corner of the window (16x16)
large = app icon which appears on Alt+Tab action
xlarge = app icon which appears in Windows Explorer on Thumbinal view or
Tiles view.
This was needed for debugging.

I'm not certain that WM_SETICON has any influence over explorer view icons.
It work fine for most cases, except one:
When I used (from CDialog):
SendMessage(WM_SETICON, ICON_SMALL, IDI_ICONALL);
IDI_ICONALL is recource icon with all three types of icon (small, large and
xlarge).

What happen is:
small app icon is resized and set to large icon
and
large app icon is NULL

WM_SETICON/ICON_SMALL only sets the window's small icon.
but if I use: SendMessage(WM_SETICON, ICON_BIG, IDI_ICONALL);
small = small and large = large that is OK!

WM_SETICON/ICON_BIG can set both the large and small icon -- if the small
icon has not been specifically set. On XP at any rate, the DefWindowProc
WM_SETICON handler first attempts to use CopyImage on the large icon handle
with the LR_COPYFROMRESOURCE flag, and if that fails it will just use the
large icon handle and shrink it.
if I combine thesse two:
SendMessage(WM_SETICON, ICON_SMALL, IDI_ICONALL);
SendMessage(WM_SETICON, ICON_BIG, IDI_ICONALL);
or
SendMessage(WM_SETICON, ICON_BIG, IDI_ICONALL);
SendMessage(WM_SETICON, ICON_SMALL, IDI_ICONALL);
order isn't important.
I always get:
small = large
large = large

In your first case, you specifically set the small icon so the DWP handler
will not attempt to insinuate its own notion of small icon when you then set
the large icon. In your second, you specifically set the small icon to the
large icon after DWP has done its small icon thing. In both cases you are
using the SM_CXICON/SM_CYICON sized icon obtained via LoadIcon to set the
small icon.
and it should be:
small = small
large = large

Not if you specifically set the small icon to the SM_CXICON/SM_CYICON sized
icon obtained via LoadIcon.
 
Of course, it doesn't work.
I was thinking that you cought line from html. But I was thinking too much.
:-)

OK, code(just this one line):
SendMessage(WM_SETICON, ICON_BIG,
(LPARAM)AfxGetApp()->LoadIcon(ICON_RESOURCE));

Int the rest of message you substitute all icon resources like this
#define ICON_RESOURCE (LPARAM)AfxGetApp()->LoadIcon(ICON_RESOURCE)
:-)
The Rest of message stands.

Rajko.
 
So, to conclude:
I got resource IDI_ALL_ICONS (this resource have all icons: 16x16, 32x32,
48x48)
And I use:
HICON someIcon = AfxGetApp()->LoadIcon(IDI_ALL_ICONS);

and then I use it in following way:

SendMessage(WM_SETICON, ICON_SMALL, (LPARAM)someIcon);
it will use Handle to icon and set SMALL icon to LARGE icon because LoadIcon
loaded SM_CXICON x SM_CYICON which is large icon.

But when I use it this way:
SendMessage(WM_SETICON, ICON_BIG, (LPARAM)someIcon);
it will use the SAME HANDLE and it will set (small to small) and (large to
large).
Well, guys I don't know about you, but this does not make any sense to me.
I mean this is the same approach to setting icons and the same handle, so
why can SendMessage be so smart to set small icon to small icon when it can
be done (SendMessage did it with ICON_BIG);

It really confused me because framework initally create CDialog class with
calls:
SetIcon(hIco, FALSE) // small
SetIcon(hIco, TRUE) // big
in OnInitDialog and after this allways:
small = large
large = large

as we concluded.


Rajko.

PS There is no consistency with this tipe of defining functions. It can
easilly lead to mistakes. This one is just icon but ...
You got it?
jep

PS BTW Even if you can explain it, I call this a bug. (with consistency)
 
One more remark.
ATL Library Reference
CWindow::SetIcon

Doesn't mention any of this and it should.
Only:
Remarks
SetIcon sends a WM_SETICON message to the window

I did not considder this as See also link just info for message handlers.


BTW I hope you dont think I'm pain in the ass, and hair splitter. :-)))

Thanks guys, Rajko
 
Rajko said:
So, to conclude:
I got resource IDI_ALL_ICONS (this resource have all icons: 16x16, 32x32,
48x48)
And I use:
HICON someIcon = AfxGetApp()->LoadIcon(IDI_ALL_ICONS);

and then I use it in following way:

SendMessage(WM_SETICON, ICON_SMALL, (LPARAM)someIcon);
it will use Handle to icon and set SMALL icon to LARGE icon because LoadIcon
loaded SM_CXICON x SM_CYICON which is large icon.
Correct.


But when I use it this way:
SendMessage(WM_SETICON, ICON_BIG, (LPARAM)someIcon);
it will use the SAME HANDLE and it will set (small to small) and (large to
large).
Correct.

Well, guys I don't know about you, but this does not make any sense to me.
I mean this is the same approach to setting icons and the same handle, so
why can SendMessage be so smart to set small icon to small icon when it can
be done (SendMessage did it with ICON_BIG);

It really confused me because framework initally create CDialog class with
calls:
SetIcon(hIco, FALSE) // small
SetIcon(hIco, TRUE) // big
in OnInitDialog and after this allways:
small = large
large = large

I've never been impressed by the way the Wizard generated CDialog app does
this using LoadIcon, and is the first thing I fix.
PS There is no consistency with this tipe of defining functions. It can
easilly lead to mistakes. This one is just icon but ...
You got it?

Don't hate me, but I'm not sure I do. What function? What mistake?
jep

PS BTW Even if you can explain it, I call this a bug. (with consistency)

It still may or may not make sense, but I'll try. First, see the 'Class
Icons' subtopic at this URL...

http://msdn.microsoft.com/library/d...rface/windowing/windowclasses/aboutwindow.asp

....wherein it describes WM_SETICON as a way to, "override the large or small
class icon for a particular window". So, if you think of WM_SETICON as an
extension of the hIcon and hIconSm members of WNDCLASSEX -- then it is
consistant with and works the same way these members are documented...

"If an application sets the hIcon and hIconSm members of the WNDCLASSEX
structure to NULL, the system uses the default application icon as the large
and small class icons for the window class. If you specify a large class
icon but not a small one, the system creates a small class icon based on the
large one. However, if you specify a small class icon but not a large one,
the system uses the default application icon as the large class icon and the
specified icon as the small class icon".

If you also consider that WNDCLASSEX and hIconSm are a Win95 extension of
the Win3.x WNDCLASS, and backward compatibility with pre 9x apps or apps
ported from preexisting code -- apps that don't know about or have yet to
consider the addition of hIconSm, then it does seemingly make sense that the
OS would go about giving them one that is the best match/compromise for the
large one. And the CopyImage/LR_COPYFROMRESOURCE scheme seems a really good
solution to my mind.

So I call it a help not a hurt, and a feature not a bug.
 
Rajko said:
One more remark.
ATL Library Reference
CWindow::SetIcon

Doesn't mention any of this and it should.
Only:
Remarks
SetIcon sends a WM_SETICON message to the window

I did not considder this as See also link just info for message handlers.


BTW I hope you dont think I'm pain in the ass, and hair splitter. :-)))

I'm on your side in this, but MS documentation has always worked this way,
and if anything appears to be moving in the opposite direction. Programming
for Windows is at least 30% reading and researching about programming for
windows. Always follow the links, always search the subtopics, always look
for kb articles that might apply, always read between the lines. Some of the
best -- and sometimes even critical, documentation appears in the least
obvious places. :)
 
Jap, Jeff I couldn agree more.
I hate to bother others with things that could be obvious if done as our
vision.

But on the other hand it's groving and ever changing documentation and it
can not be as perfect as we wish.

I wish just to be little more compact. I mean when they discover something
like this why not link it in main doc.

Thx, Rajko.
 
I see you wrote quite a explanation. Thanks a lot, you realy invested some
effort.
I appreciate this. And officially recomend you as helpful.
I'll look at it as soon as I can, I'm playing with user-interface threads.
After that this is first thing i'll do.

Thanks a lot Jeff, Rajko.

PS You and David were very helpful.
 
Yes, I got it.
I thought that could be something like this.
It it compatibility at question over here and the one from Win 3.x. Wow.
One of mine assumptions was that code from as early as Win 3.x was
depricated in .NET.
I was mistaking.


Can I ask you something else?
I was playing with user-interface threads and I didn't have any expirience
with Windows MFC threads.
For creation I used :

CMRenameThread *pTipThread = new
CMRenameThread(RUNTIME_CLASS(CMRenameTips));
pTipThread->StartIdle();
m_ChildThreads.Add(pTipThread);

for implementation:

BOOL CMRenameThread::InitInstance() {
if (m_pClass != NULL) {
CObject *pObject = m_pClass->CreateObject();

CDialog *pDlg = NULL;
if (pObject->IsKindOf(RUNTIME_CLASS(CMRenameTips))) {
pDlg = (CMRenameTips *)pObject;
((CMRenameTips *)pDlg)->RunningInThread();
}
if (pObject->IsKindOf(RUNTIME_CLASS(CMRenameOptions))) {
pDlg = (CMRenameOptions *)pObject;
((CMRenameOptions *)pDlg)->RunningInThread();
}
if (pObject->IsKindOf(RUNTIME_CLASS(CMRenameCascadingMenu))) {
pDlg = (CMRenameCascadingMenu *)pObject;
((CMRenameCascadingMenu *)pDlg)->RunningInThread();
}
if (pObject->IsKindOf(RUNTIME_CLASS(CMRenameAbout))) {
pDlg = (CMRenameAbout *)pObject;
((CMRenameAbout *)pDlg)->RunningInThread();
}

if (pDlg != NULL) {
CWnd wndDesktop;
wndDesktop.Attach(::GetDesktopWindow());

m_pMainWnd = pDlg;
m_pActiveWnd = pDlg;
m_pMainWnd->ShowWindow(SW_SHOW);
// Invalidate window so entire client area is redrawn when UpdateWindow is
called
m_pMainWnd->Invalidate();
// Update Window to cause View to redraw
m_pMainWnd->UpdateWindow();

wndDesktop.Detach();
}
}

return TRUE; // TRUE = modal, FALSE = worker thread
}


int CMRenameThread::ExitInstance() {
SetThreadPriority(THREAD_PRIORITY_ABOVE_NORMAL);

if (m_pMainWnd != NULL) {
m_pMainWnd->DestroyWindow();
m_pMainWnd = NULL;
}

return CWinThread::ExitInstance();
}


and for premature ending of thread from main dialog I used:

void CMRenameDialog::OnClose() {
for (int i=0; i < m_ChildThreads.GetSize(); i++) {
m_ChildThreads->PostThreadMessage(WM_QUIT, 0, 0);
}
m_ChildThreads.RemoveAll();

CDialog::OnClose();
}

I found many ways on internet how to end thread but this one i like the
most:

Tell me what you think, please.

Thx, Rajko.
 
Back
Top