Community
cancel
Showing results for 
Search instead for 
Did you mean: 
Highlighted
Beginner
105 Views

SetConsoleIcon problems in Windows 10

Jump to solution

I have a console application and I change its icon at runtime. It has been working well so far, in Windows 7, 8 and 10. However, it stopped working after one of the recent updates of Windows 10 (I do not know which was it was and I do not have any possibility to use an older version of Windows 10).

This is how I change the icon in the code:

      subroutine changeConsoleWindowIcon ( )
      
      use ifwin
      
      interface
        function SetConsoleIcon ( hIcon )
        use ifwinty
        integer(BOOL) :: SetConsoleIcon
        integer(DWORD) :: hIcon
        !dec$ attributes default, stdcall :: SetConsoleIcon
        end function
      end interface
      
      integer,parameter :: IDI_ICON_MYAPP=101
      integer(kind=HANDLE) :: hModule, hLib
      integer :: hMainIcon, lRet
      pointer ( SetConsoleF1, SetConsoleIcon )
      
      
      hLib = LoadLibrary ( 'Kernel32.dll'C )
      SetConsoleF1 = GetProcAddress ( hLib, 'SetConsoleIcon'C )
      hModule = GetModuleHandle(0)
      hMainIcon = LoadIcon ( hModule, MAKEINTRESOURCE(IDI_ICON_MYAPP) )
      lRet = SetConsoleIcon ( hMainIcon )
      lRet = FreeLibrary ( hLib )
      
      return
      end subroutine changeConsoleWindowIcon

This works well in Windows 7. In Windows 10, it also works, in cases when I run the executable by double clicking it in the Windows Explorer or any file manager. If I run the command line and run my application from it, or if I run my application as a new process from another (dialog-based, C++) application, the console icon is not changed.

I checked the return value from the call to SetConsoleIcon (by writing its value to the console window) and it is 0 in all above mentioned cases.

I apologize this is not much of a Fortran question; I wonder if anyone here could at least point me in a direction leading to resolving this problem. Goggling this found one note that SetConsoleIcon might have been removed from Kernel32.dll...

Thank you in advance for any tips.

0 Kudos

Accepted Solutions
Highlighted
New Contributor II
105 Views

Here is the code:

  PROGRAM cd
  USE IFWIN, ONLY : LRESULT, fWPARAM, HANDLE , NULL, GetModuleHandle, LoadIcon, &
                    GetConsoleWindow, SendMessage, WM_SETICON, ICON_BIG, ICON_SMALL
  IMPLICIT none
!
  INTEGER(KIND=HANDLE)  :: hInstance, hConsole, hIcon
  INTEGER(KIND=LRESULT) :: result
!
  hInstance = GetModuleHandle(NULL)
  hIcon     = LoadIcon(hInstance, "MY_ICON"//CHAR(0))
!
  hConsole = GetConsoleWindow()
  result = SendMessage(hConsole, WM_SETICON, INT(ICON_SMALL,KIND=fWPARAM), hIcon)
  result = SendMessage(hConsole, WM_SETICON, INT(ICON_BIG,KIND=fWPARAM),   hIcon)
!
  END PROGRAM cd

Be sure you have a resource file where you define the name of the icon resource, i.e. "MY_ICON". Note that the ICOM_SMALL is for the icon in the console itself and ICON_BIG for the icon in the task bar. The latter, however, does not work in this example. In a window applications where a console is created, it works fine.

 

View solution in original post

0 Kudos
11 Replies
Highlighted
New Contributor II
105 Views

Irina,

I met the same problem. In the mean time I found another, much more simple, solution. Try as follows:

hConsole = GetConsoleWindow()

iResult = SendMessage(hConsole, WM_SETICON, ICON_BIG, hMainIcon)

iResult = SendMessage(hConsole, WM_SETICON, ICON_SMALL, hMainIcon)

 

For me it works fine!

Robert

0 Kudos
Highlighted
Beginner
105 Views

Could you please post the complete code? I appreciate your idea, but I am not able to finish your snippet to make things work. :-[

0 Kudos
Highlighted
New Contributor II
106 Views

Here is the code:

  PROGRAM cd
  USE IFWIN, ONLY : LRESULT, fWPARAM, HANDLE , NULL, GetModuleHandle, LoadIcon, &
                    GetConsoleWindow, SendMessage, WM_SETICON, ICON_BIG, ICON_SMALL
  IMPLICIT none
!
  INTEGER(KIND=HANDLE)  :: hInstance, hConsole, hIcon
  INTEGER(KIND=LRESULT) :: result
!
  hInstance = GetModuleHandle(NULL)
  hIcon     = LoadIcon(hInstance, "MY_ICON"//CHAR(0))
!
  hConsole = GetConsoleWindow()
  result = SendMessage(hConsole, WM_SETICON, INT(ICON_SMALL,KIND=fWPARAM), hIcon)
  result = SendMessage(hConsole, WM_SETICON, INT(ICON_BIG,KIND=fWPARAM),   hIcon)
!
  END PROGRAM cd

Be sure you have a resource file where you define the name of the icon resource, i.e. "MY_ICON". Note that the ICOM_SMALL is for the icon in the console itself and ICON_BIG for the icon in the task bar. The latter, however, does not work in this example. In a window applications where a console is created, it works fine.

 

View solution in original post

0 Kudos
Highlighted
Beginner
105 Views

Robert, thank you for posting the complete code. While testing it, I encountered several interesting things and difficulties:

  • In IPS 2016, Update 4, "GetConsoleWindow" is an unresolved external.
  • In IPS 2017, Update 2, "GetConsoleWindow" compiles well, but I had to change the call to LoadIcon to MAKEINTRESOURCE(MY_ICON) instead of "MY_ICON"//CHAR(0) to work as required.

Icon is now changed even in Windows 10; thank you very much again!

Finally, it is interesting to see that SendMessage returns 0 in Windows 7, while it return a nonzero value in Windows 10.

0 Kudos
Highlighted
Valued Contributor III
105 Views

@robert, thanks for the useful tip.

0 Kudos
Highlighted
New Contributor II
105 Views

Jirina,

thanks for letting me know. I cannot comment on the unresolved external referewnce. According to MS GetConsoleWindow is valid since Windows XP. Maybe Intel added it somewhat later??

On the icon resource: you have a choice: if the resource is known by its name only, so not by a numerical value, you can use the LoadIcon function call only with a nul-terminated string as the second argument. If you have a resource known by a numerical value, you MUST use that value by calling LoadIcon with a 32 bit integer as the second argument of which the high order word must be zero. I presume you used the second method. I assumed a resource with name so used the first method.

The return value of the Sendmessage is, according to the specs, the handle to the previous console icon. If there was not such an icon, it will retrurn NULL.

Robert

 

0 Kudos
Highlighted
Black Belt Retired Employee
105 Views

GetConsoleWindow is defined by kernel32.lib which comes from Microsoft. Intel doesn't touch this. It could be that you declared it incorrectly. What was the exact error message? 

0 Kudos
Highlighted
Beginner
105 Views

Robert, thank you for your kind and detailed explanation.

Steve, this is what I have in my code:

      use ifwin
      integer(kind=HANDLE) :: hInstance
      hInstance = GetModuleHandle ( NULL )

Compiling this in IPS XE 2016, Update 4 issues warning #6717: This name has not been given an explicit type.   [GETCONSOLEWINDOW]

Linking then issues error LNK2019: unresolved external symbol GETCONSOLEWINDOW referenced in function CONSOLEWINDOW_mp_CHANGECONSOLEWINDOWICON    window.obj

 

 

0 Kudos
Highlighted
105 Views

I don't want to sound like I'm making a silly statement, but that code snippet doesn't even have the string "getconsolewindow" in it (lowercase, uppercase, or mixed case)

In your real code, make sure that you "use kernel32" as well as "ifwinty".  That will add the declaration and make sure the correct library is linked against.

              --Lorri

0 Kudos
Highlighted
Black Belt Retired Employee
105 Views

IFWIN includes KERNEL32 and IFWINTY. Most likely the declaration of that routine was missing from module KERNEL32 (looking at the current source I see it is one I added with BIND(C), but I am not sure when it was added.) If it was missing when you compiled, you get the Intel Fortran defaults which are not correct for this routine and hence the link error.

0 Kudos
Highlighted
Beginner
105 Views

Lorri, I am very sorry for the mistake I made when posting the code snippet. It contained GetModuleHandle instead of GetConsoleWindow. The right snippet is

use ifwin
integer(kind=HANDLE) :: hInstance
hInstance = GetConsoleWindow( NULL )

I think using IFWIN should be sufficient, as Steve explained, because the code snippet works well in IPS XE 2017 Update 2, but not in IPS XE 2016 Update 4. I think the declaration of the routine has been added recently, making it work in IPS XE 2017 Update 2.

Thank you for your quick and kind support.

0 Kudos