Hi , I want to figure out why msgbox dosn't use "custom icon" but GUI objects can use it?
I use it TraySetIcon
this normal msgbox()
.
.
.
this small custom GUI()
Why Msgbox dosn't use "TraySetIcon"? Topic is solved
Why Msgbox dosn't use "TraySetIcon"?
Re: Why Msgbox dosn't use "TraySetIcon"?
I'm guessing that it's just how Windows implements its MsgBox to be an "independent" sort of dialog window.
Re: Why Msgbox dosn't use "TraySetIcon"? Topic is solved
I'm not sure if there's a better way, but here's a trick for now.
You could try using WM_SETICON with Msgbox, but I haven't attempted it yet because it seems like Msgbox needs to be created first before it can be changed.
The reason is probably, as @mikeyww mentioned, because MessageBox is part of the Win32 API. Since MessageBox is a commonly used form not only in AHK but also in other places, I don't think it can be fully customized to suit the user's taste.
You could try using WM_SETICON with Msgbox, but I haven't attempted it yet because it seems like Msgbox needs to be created first before it can be changed.
The reason is probably, as @mikeyww mentioned, because MessageBox is part of the Win32 API. Since MessageBox is a commonly used form not only in AHK but also in other places, I don't think it can be fully customized to suit the user's taste.
Code: Select all
#Requires AutoHotkey v2.0
#SingleInstance Force
download("http://autohotkey.com/favicon.ico", A_Temp "/autohotkey_favicon.ico")
traySetIcon(A_Temp "/autohotkey_favicon.ico")
F5:: {
msgboxWithTrayIcon("Hello, World!")
}
MsgboxWithTrayIcon(text?, title?, options?) { ; ahk2.0
myGui := gui("+LastFound +OwnDialogs")
winSetTransparent(0)
myGui.show()
result := msgbox(text?, title?, options?)
myGui.destroy()
return result
}
- English is not my native language. Please forgive any awkward expressions.
- 영어는 제 모국어가 아닙니다. 어색한 표현이 있어도 양해해 주세요.
Re: Why Msgbox dosn't use "TraySetIcon"?
Oh I see so that's why , many thanks <3
oh great function I thought I need to build a whole custom Msgbox function , many thanks <3Seven0528 wrote: I'm not sure if there's a better way, but here's a trick for now.
You could try using WM_SETICON with Msgbox, but I haven't attempted it yet because it seems like Msgbox needs to be created first before it can be changed.
The reason is probably, as @mikeyww mentioned, because MessageBox is part of the Win32 API. Since MessageBox is a commonly used form not only in AHK but also in other places, I don't think it can be fully customized to suit the user's taste.Code: Select all
#Requires AutoHotkey v2.0 #SingleInstance Force download("http://autohotkey.com/favicon.ico", A_Temp "/autohotkey_favicon.ico") traySetIcon(A_Temp "/autohotkey_favicon.ico") F5:: { msgboxWithTrayIcon("Hello, World!") } MsgboxWithTrayIcon(text?, title?, options?) { ; ahk2.0 myGui := gui("+LastFound +OwnDialogs") winSetTransparent(0) myGui.show() result := msgbox(text?, title?, options?) myGui.destroy() return result }
Re: Why Msgbox dosn't use "TraySetIcon"?
UPDATE: I may have been a little confused on what was the original goal here. The code I've provided below is for adding the script's Icon to the titlebar of the MsgBox and not to the Window's Taskbar, however it will add the icon to BOTH. I also noticed some potential poor image quality when using this with an uncompiled script. If I found out what's causing that I'll update the code here.
UPDATE #2: Worked out why the image quality was happening and updated the options for LoadPicture, also updated default values for the iconFile and iconNumber parameters so that it will now take into consideration if TraySetIcon() has been used.
We actually just went through this process in the AHK discord last night and this morning. Here is the current solution we have in place, which works very well.
Once you include this function into your script, you can call it like a normal MsgBox and you'll have your script's icon added to the titleBar.
For compiled scripts, if you omit the iconFile and iconNumber parameters, it will use the first icon in the .exe and for uncompiled scripts, you'll need to make sure pass the filepath to the icon you want to use in the iconFile parameter.
UPDATE #2: Worked out why the image quality was happening and updated the options for LoadPicture, also updated default values for the iconFile and iconNumber parameters so that it will now take into consideration if TraySetIcon() has been used.
We actually just went through this process in the AHK discord last night and this morning. Here is the current solution we have in place, which works very well.
Code: Select all
MsgBoxEx(text?, title?, options?, iconFile := A_IconFile ? A_IconFile : A_AhkPath, iconNumber := A_IconNumber ? A_IconNumber : 1) {
winTitle := Format("{1} ahk_class #32770", title?)
OnMessage(0x0044, SetTitleBarIcon)
result := MsgBox(text?, title?, options?)
return result
SetTitleBarIcon(*) {
DetectHiddenWindows(true)
DetectHiddenText(true)
iconHandle := LoadPicture(iconFile, "w24 h24 Icon" iconNumber, &HandleType)
SendMessage(WM_SETICON := 0x0080, 0, iconHandle, control?, winTitle, text ?? "Press OK to continue.")
OnMessage(0x0044, SetTitleBarIcon, 0)
DetectHiddenWindows(false)
DetectHiddenText(false)
}
}
Code: Select all
MsgBoxEx("Do you like my new Icon?", "Success Message")
Re: Why Msgbox dosn't use "TraySetIcon"?
Code: Select all
#Requires AutoHotkey v2.0
#SingleInstance Force
suspend(true)
if (!fileExist(iconFileName:=A_Temp "/autohotkey_favicon.ico"))
download("http://autohotkey.com/favicon.ico", iconFileName)
traySetIcon(iconFileName)
suspend(false)
;-----------------------
F2::msgbox("Hello, World!")
F3::msgbox("Hello, World!",,0x1000)
F6::msgboxWithIcon("Hello, World!")
F7::msgboxWithIcon("Hello, World!",,0x1000)
F12:: {
hIconSmall:=loadPicture("Shell32.dll", "Icon55", &_)
hIconBig:=loadPicture("explorer.exe", "Icon22", &_)
msgboxWithIcon("Hello, World!",,0x1000,hIconSmall,hIconBig)
for hIcon in [&hIconSmall, &hIconBig]
dllCall("User32.dll\DestroyIcon", "Ptr",%hIcon%)
}
;-----------------------
MsgboxWithIcon(text?, title?, options?, hIconSmall?, hIconBig?) { ; ahk2.0
WM_COMMNOTIFY(*) {
static WM_SETICON:=0x0080, ICON_BIG:=1, ICON_SMALL:=0
,WTA_NONCLIENT:=1, WTNCA_NODRAWCAPTION:=0x00000001, WTNCA_NODRAWICON:=0x00000002, WTNCA_NOSYSMENU:=0x00000004, WTNCA_NOMIRRORHELP:=0x00000008
winCaption:=(title??A_ScriptName) " ahk_class #32770"
if (!hWnd:=format("{2}", prevDHW:=detectHiddenWindows(true), winExist(winCaption), detectHiddenWindows(prevDHW)))
return
if (hIconSmall)
dllCall("User32.dll\SendMessage", "Ptr",hWnd, "UInt",WM_SETICON, "UPtr",ICON_SMALL, "Ptr",hIconSmall, "Ptr")
if (hIconBig)
dllCall("User32.dll\SendMessage", "Ptr",hWnd, "UInt",WM_SETICON, "UPtr",ICON_BIG, "Ptr",hIconBig, "Ptr")
if (hIconSmall||hIconBig) && (!draySystemIcon) {
eAttribute:=WTA_NONCLIENT
pvAttribute:=buffer(cbAttribute:=8,0), dwFlags:= dwMask:= 0
dwFlags|=WTNCA_NODRAWICON|WTNCA_NOSYSMENU ,numPut("UInt",dwFlags,pvAttribute,0)
dwMask|=WTNCA_NODRAWICON|WTNCA_NOSYSMENU ,numPut("UInt",dwMask,pvAttribute,4)
dllCall("UxTheme.dll\SetWindowThemeAttribute", "Ptr",hwnd, "Int",eAttribute, "Ptr",pvAttribute.Ptr, "UInt",cbAttribute, "Int")
}
}
onApplicationExit(*) {
for hIcon in destroyIconList
dllCall("User32.dll\DestroyIcon", "Ptr",hIcon)
}
static IMAGE_ICON:=1, MB_SYSTEMMODAL:=0x00001000
destroyIconList:=[], onExit(onApplicationExit)
,fileName:=(A_IconFile?A_IconFile:A_AhkPath), iconIndex:=(A_IconNumber?A_IconNumber:1)
if (!isSet(hIconSmall)) {
for cIcon in [256,128,64,48,32,16] {
if (!dllCall("User32.dll\PrivateExtractIcons", "Str",fileName, "Int",iconIndex-1, "Int",cIcon, "Int",cIcon, "Ptr*",&hIconSmall:=0, "UPtr*",0, "UInt",1, "UInt",IMAGE_ICON, "UInt"))
continue
destroyIconList.push(hIconSmall)
if (!isSet(hIconBig))
hIconBig:=hIconSmall
break
}
}
if (!isSet(hIconBig)) {
for cIcon in [256,128,64,48,32,16] {
if (!dllCall("User32.dll\PrivateExtractIcons", "Str",fileName, "Int",iconIndex-1, "Int",cIcon, "Int",cIcon, "Ptr*",&hIconBig:=0, "UPtr*",0, "UInt",1, "UInt",IMAGE_ICON, "UInt"))
continue
destroyIconList.push(hIconBig)
break
}
}
if (!hIconSmall && !hIconBig)
return msgBox(text?, title?, options?)
draySystemIcon:=false
loop Parse, (options??""), A_Space A_Tab {
if (A_LoopField~="D)^(?:[[:digit:]]+|(0[Xx][[:xdigit:]]+))$" && A_LoopField&MB_SYSTEMMODAL)
draySystemIcon:=true
} until (draySystemIcon)
result:=format("{2}"
,onMessage(0x0044,WM_COMMNOTIFY,-1)
,msgBox(text?, title?, options?)
,onMessage(0x0044,WM_COMMNOTIFY,0))
onExit(onApplicationExit,false)
for hIcon in destroyIconList
dllCall("User32.dll\DestroyIcon", "Ptr",hIcon)
return result
}
- English is not my native language. Please forgive any awkward expressions.
- 영어는 제 모국어가 아닙니다. 어색한 표현이 있어도 양해해 주세요.
Re: Why Msgbox dosn't use "TraySetIcon"?
Thanks to much for you effort, I have noticed it will pick the 32*32 icon version instead of 256*256?Panaku wrote: ↑15 Apr 2024, 13:45UPDATE: I may have been a little confused on what was the original goal here. The code I've provided below is for adding the script's Icon to the titlebar of the MsgBox and not to the Window's Taskbar, however it will add the icon to BOTH. I also noticed some potential poor image quality when using this with an uncompiled script. If I found out what's causing that I'll update the code here.
UPDATE #2: Worked out why the image quality was happening and updated the options for LoadPicture, also updated default values for the iconFile and iconNumber parameters so that it will now take into consideration if TraySetIcon() has been used.
We actually just went through this process in the AHK discord last night and this morning. Here is the current solution we have in place, which works very well.Once you include this function into your script, you can call it like a normal MsgBox and you'll have your script's icon added to the titleBar.Code: Select all
MsgBoxEx(text?, title?, options?, iconFile := A_IconFile ? A_IconFile : A_AhkPath, iconNumber := A_IconNumber ? A_IconNumber : 1) { winTitle := Format("{1} ahk_class #32770", title?) OnMessage(0x0044, SetTitleBarIcon) result := MsgBox(text?, title?, options?) return result SetTitleBarIcon(*) { DetectHiddenWindows(true) DetectHiddenText(true) iconHandle := LoadPicture(iconFile, "w24 h24 Icon" iconNumber, &HandleType) SendMessage(WM_SETICON := 0x0080, 0, iconHandle, control?, winTitle, text ?? "Press OK to continue.") OnMessage(0x0044, SetTitleBarIcon, 0) DetectHiddenWindows(false) DetectHiddenText(false) } }
For compiled scripts, if you omit the iconFile and iconNumber parameters, it will use the first icon in the .exe and for uncompiled scripts, you'll need to make sure pass the filepath to the icon you want to use in the iconFile parameter.Code: Select all
MsgBoxEx("Do you like my new Icon?", "Success Message")
this is my icon file
https://github.com/xmaxrayx/Steam-games-wallpapers-finder/blob/main/Asissts/steam%20wallpapers%20finders.ico Update: I have notice if I used icon file that has only one image it wont change but if there multi-image in one Icon it will pick the 32*32.
idk if my icon file wasn't done right.
Last edited by xMaxrayx on 16 Apr 2024, 05:40, edited 1 time in total.
Re: Why Msgbox dosn't use "TraySetIcon"?
Seven0528 wrote: ↑15 Apr 2024, 17:0820240416_074213.png
20240416_074225.png
20240416_074236.pngYou should delete all the unused hIcons by using DestroyIcon.Code: Select all
#Requires AutoHotkey v2.0 #SingleInstance Force suspend(true) if (!fileExist(iconFileName:=A_Temp "/autohotkey_favicon.ico")) download("http://autohotkey.com/favicon.ico", iconFileName) traySetIcon(iconFileName) suspend(false) ;----------------------- F2::msgbox("Hello, World!") F3::msgbox("Hello, World!",,0x1000) F6::msgboxWithIcon("Hello, World!") F7::msgboxWithIcon("Hello, World!",,0x1000) F12:: { hIconSmall:=loadPicture("Shell32.dll", "Icon55", &_) hIconBig:=loadPicture("explorer.exe", "Icon22", &_) msgboxWithIcon("Hello, World!",,0x1000,hIconSmall,hIconBig) for hIcon in [&hIconSmall, &hIconBig] dllCall("User32.dll\DestroyIcon", "Ptr",%hIcon%) } ;----------------------- MsgboxWithIcon(text?, title?, options?, hIconSmall?, hIconBig?) { ; ahk2.0 WM_COMMNOTIFY(*) { static WM_SETICON:=0x0080, ICON_BIG:=1, ICON_SMALL:=0 ,WTA_NONCLIENT:=1, WTNCA_NODRAWCAPTION:=0x00000001, WTNCA_NODRAWICON:=0x00000002, WTNCA_NOSYSMENU:=0x00000004, WTNCA_NOMIRRORHELP:=0x00000008 winCaption:=(title??A_ScriptName) " ahk_class #32770" if (!hWnd:=format("{2}", prevDHW:=detectHiddenWindows(true), winExist(winCaption), detectHiddenWindows(prevDHW))) return if (hIconSmall) dllCall("User32.dll\SendMessage", "Ptr",hWnd, "UInt",WM_SETICON, "UPtr",ICON_SMALL, "Ptr",hIconSmall, "Ptr") if (hIconBig) dllCall("User32.dll\SendMessage", "Ptr",hWnd, "UInt",WM_SETICON, "UPtr",ICON_BIG, "Ptr",hIconBig, "Ptr") if (hIconSmall||hIconBig) && (!draySystemIcon) { eAttribute:=WTA_NONCLIENT pvAttribute:=buffer(cbAttribute:=8,0), dwFlags:= dwMask:= 0 dwFlags|=WTNCA_NODRAWICON|WTNCA_NOSYSMENU ,numPut("UInt",dwFlags,pvAttribute,0) dwMask|=WTNCA_NODRAWICON|WTNCA_NOSYSMENU ,numPut("UInt",dwMask,pvAttribute,4) dllCall("UxTheme.dll\SetWindowThemeAttribute", "Ptr",hwnd, "Int",eAttribute, "Ptr",pvAttribute.Ptr, "UInt",cbAttribute, "Int") } } onApplicationExit(*) { for hIcon in destroyIconList dllCall("User32.dll\DestroyIcon", "Ptr",hIcon) } static IMAGE_ICON:=1, MB_SYSTEMMODAL:=0x00001000 destroyIconList:=[], onExit(onApplicationExit) ,fileName:=(A_IconFile?A_IconFile:A_AhkPath), iconIndex:=(A_IconNumber?A_IconNumber:1) if (!isSet(hIconSmall)) { for cIcon in [256,128,64,48,32,16] { if (!dllCall("User32.dll\PrivateExtractIcons", "Str",fileName, "Int",iconIndex-1, "Int",cIcon, "Int",cIcon, "Ptr*",&hIconSmall:=0, "UPtr*",0, "UInt",1, "UInt",IMAGE_ICON, "UInt")) continue destroyIconList.push(hIconSmall) if (!isSet(hIconBig)) hIconBig:=hIconSmall break } } if (!isSet(hIconBig)) { for cIcon in [256,128,64,48,32,16] { if (!dllCall("User32.dll\PrivateExtractIcons", "Str",fileName, "Int",iconIndex-1, "Int",cIcon, "Int",cIcon, "Ptr*",&hIconBig:=0, "UPtr*",0, "UInt",1, "UInt",IMAGE_ICON, "UInt")) continue destroyIconList.push(hIconBig) break } } if (!hIconSmall && !hIconBig) return msgBox(text?, title?, options?) draySystemIcon:=false loop Parse, (options??""), A_Space A_Tab { if (A_LoopField~="D)^(?:[[:digit:]]+|(0[Xx][[:xdigit:]]+))$" && A_LoopField&MB_SYSTEMMODAL) draySystemIcon:=true } until (draySystemIcon) result:=format("{2}" ,onMessage(0x0044,WM_COMMNOTIFY,-1) ,msgBox(text?, title?, options?) ,onMessage(0x0044,WM_COMMNOTIFY,0)) onExit(onApplicationExit,false) for hIcon in destroyIconList dllCall("User32.dll\DestroyIcon", "Ptr",hIcon) return result }
Thank you so much
win11 64bit
- *F3 doesn't display the Icon
*F7 show on Taskbar only (lower than 256
*F6 shows on both msgbox and tashbar (lower than 256)
*F12 looks interesting xd
Re: Why Msgbox dosn't use "TraySetIcon"?
so seems if you want higher res ICON you need to use custom GUI object? because windows msgbox doesn't support it.
Re: Why Msgbox dosn't use "TraySetIcon"?
Personally, I believe that directly FileInstalling the ICO file and then obtaining the hIcon corresponding to size 256 would be a better approach. Referring to the PrivateExtractIcons part in the code I provided earlier might be helpful.
I don't have much experience using LoadPicture, so I find it difficult to advise on that function.
To be honest, I don't prefer this method either, so I use the method of converting a Base64-encoded string hardcoded using CryptStringToBinary and CreateIconFromResourceEx to obtain hIcon. However, I only have code corresponding to AHK v1, so it's difficult to share.
There's a thread here titled "Convert Base64PNG_to_HICON to v2" that someone else has written,
so if you're interested, you might want to take a look at it.
I don't have much experience using LoadPicture, so I find it difficult to advise on that function.
To be honest, I don't prefer this method either, so I use the method of converting a Base64-encoded string hardcoded using CryptStringToBinary and CreateIconFromResourceEx to obtain hIcon. However, I only have code corresponding to AHK v1, so it's difficult to share.
There's a thread here titled "Convert Base64PNG_to_HICON to v2" that someone else has written,
so if you're interested, you might want to take a look at it.
- English is not my native language. Please forgive any awkward expressions.
- 영어는 제 모국어가 아닙니다. 어색한 표현이 있어도 양해해 주세요.
Re: Why Msgbox dosn't use "TraySetIcon"?
So, I'm not sure there is a need for doing all of the DllCalls to load the different resolutions of the icons. The SendMessage() call lets us control which resolution is used by defining the width and height when we use LoadPicture. We've made some adjustments to the function that I posted yesterday, including working out a way to override the base MsgBox function to use our custom function instead.
The following code has a few new things compared to the code from yesterday.
1. It now using your system's settings for determining what the icon size should be for titlebar and the taskbar. This can result in different resolution versions being used for each icon.
2. It overrides the default MsgBox() function. Now anytime you use that function, it will add the icons to it automatically.
Now, if you want to force the MsgBox to use a different resolution icon, then you can force that change by changing the width and height values in the LoadPicture() calls.
Note: Forcing a larger resolution icon may affect quality, as you're still squishing the larger icon down into a smaller space.
The benefit to the above code is that now all your MsgBoxes in this script will have icons added based off of either the icon used when you compiled the script or the icon used during TraySetIcon(), but you can also use a different icon for specific MsgBoxes by calling MsgBoxEx directly.
The only thing different about calling MsgBoxEx directly, is that now we have to pass the MsgBox function as the first parameter. I found this setup to be ideal because now I don't have to call a custom function everytime I want to add an Icon to my MsgBoxes. If you don't want to override the base MsgBox function and would prefer to call the custom function manually, then you can just use the following code.
The following code has a few new things compared to the code from yesterday.
1. It now using your system's settings for determining what the icon size should be for titlebar and the taskbar. This can result in different resolution versions being used for each icon.
2. It overrides the default MsgBox() function. Now anytime you use that function, it will add the icons to it automatically.
Code: Select all
#Requires AutoHotkey v2+
TraySetIcon("MyIcon.ico")
MsgBox.Native := MsgBox.Call
MsgBox.DefineProp("Call", {Call: MsgBoxEx})
MsgBoxEx(this, Text?, Title?, Options?, IconFile := A_IconFile ? A_IconFile : A_AhkPath, IconNumber := A_IconNumber ? A_IconNumber : 1) {
WinTitle := (title ?? A_ScriptName) " ahk_class #32770"
OnMessage(0x0044, WM_NOTIFY_MSGBOXEX)
result := this.Native(text?, title?, options?)
return result
WM_NOTIFY_MSGBOXEX(*) {
static ICON_BIG := 1, ICON_SMALL := 0, SM_CXICON := SysGet(11), SM_CYICON := SysGet(12), SM_CXSMICON := SysGet(49), SM_CYSMICON := SysGet(50), WM_SETICON := 0x0080
hICON_BIG := LoadPicture(IconFile, "w" SM_CXICON " h" SM_CYICON " Icon" IconNumber, &HandleType)
hICON_SMALL := LoadPicture(IconFile, "w" SM_CXSMICON " h" SM_CYSMICON " Icon" IconNumber, &HandleType)
DetectHiddenWindows(True)
SendMessage(WM_SETICON, ICON_BIG, hICON_BIG, Control?, WinTitle, Text ?? "Press OK to continue.")
SendMessage(WM_SETICON, ICON_SMALL, hICON_SMALL, Control?, WinTitle, Text ?? "Press Ok to continue.")
DetectHiddenWindows(False)
OnMessage(0x0044, WM_NOTIFY_MSGBOXEX, 0)
}
}
MsgBox("Test")
Note: Forcing a larger resolution icon may affect quality, as you're still squishing the larger icon down into a smaller space.
Code: Select all
hICON_BIG := LoadPicture(IconFile, "w256 h256 Icon" IconNumber, &HandleType)
hICON_SMALL := LoadPicture(IconFile, "w256 h256 Icon" IconNumber, &HandleType)
Code: Select all
MsgBoxEx(MsgBox, "test",,, "shell32.dll", 54)
Code: Select all
#Requires AutoHotkey v2+
TraySetIcon("MyIcon.ico")
MsgBoxEx(Text?, Title?, Options?, IconFile := A_IconFile ? A_IconFile : A_AhkPath, IconNumber := A_IconNumber ? A_IconNumber : 1) {
WinTitle := (title ?? A_ScriptName) " ahk_class #32770"
OnMessage(0x0044, WM_NOTIFY_MSGBOXEX)
result := MsgBox(text?, title?, options?)
return result
WM_NOTIFY_MSGBOXEX(*) {
static ICON_BIG := 1, ICON_SMALL := 0, SM_CXICON := SysGet(11), SM_CYICON := SysGet(12), SM_CXSMICON := SysGet(49), SM_CYSMICON := SysGet(50), WM_SETICON := 0x0080
hICON_BIG := LoadPicture(IconFile, "w" SM_CXICON " h" SM_CYICON " Icon" IconNumber, &HandleType)
hICON_SMALL := LoadPicture(IconFile, "w" SM_CXSMICON " h" SM_CYSMICON " Icon" IconNumber, &HandleType)
DetectHiddenWindows(True)
SendMessage(WM_SETICON, ICON_BIG, hICON_BIG, Control?, WinTitle, Text ?? "Press OK to continue.")
SendMessage(WM_SETICON, ICON_SMALL, hICON_SMALL, Control?, WinTitle, Text ?? "Press Ok to continue.")
DetectHiddenWindows(False)
OnMessage(0x0044, WM_NOTIFY_MSGBOXEX, 0)
}
}
MsgBoxEx("Test")
Re: Why Msgbox dosn't use "TraySetIcon"?
@Panaku
Certainly, to clarify, my preference for using PrivateExtractIcons instead of LoadPicture is simply because it's more familiar to me personally. I'm not asserting that the former is better. More than anything, our codes do slightly different things. Your code is more user-friendly, while mine is more friendly to me. (I tend to prefer handling hIcons directly.)
It was meant to demonstrate that code can be written in this way, not to claim superiority over your code.
Actually, I don't know how the built-in LoadPicture is implemented in practice. However, from the information in the official reference, it seems that if an hIcon is created through LoadPicture, it should also be destroyed using DestroyIcon.
https://www.autohotkey.com/docs/v2/lib/LoadPicture.htm#Remarks
Certainly, to clarify, my preference for using PrivateExtractIcons instead of LoadPicture is simply because it's more familiar to me personally. I'm not asserting that the former is better. More than anything, our codes do slightly different things. Your code is more user-friendly, while mine is more friendly to me. (I tend to prefer handling hIcons directly.)
It was meant to demonstrate that code can be written in this way, not to claim superiority over your code.
However, one thing is clear, as I mentioned earlier, there is still a slight issue with the code you provided. If hIcon is made a local variable, it must be destroyed using DestroyIcon. That's the point I wanted to address.It is only necessary to call DestroyIcon for icons and cursors created with the following functions: CreateIconFromResourceEx (if called without the LR_SHARED flag), CreateIconIndirect, and CopyIcon. Do not use this function to destroy a shared icon. A shared icon is valid as long as the module from which it was loaded remains in memory. The following functions obtain a shared icon.
LoadIcon
LoadImage (if you use the LR_SHARED flag)
CopyImage (if you use the LR_COPYRETURNORG flag and the hImage parameter is a shared icon)
CreateIconFromResource
CreateIconFromResourceEx (if you use the LR_SHARED flag)
Actually, I don't know how the built-in LoadPicture is implemented in practice. However, from the information in the official reference, it seems that if an hIcon is created through LoadPicture, it should also be destroyed using DestroyIcon.
https://www.autohotkey.com/docs/v2/lib/LoadPicture.htm#Remarks
Code: Select all
if (not OutImageType) ; IMAGE_BITMAP (0) or the OutImageType parameter was omitted.
DllCall("DeleteObject", "ptr", Handle)
else if (OutImageType = 1) ; IMAGE_ICON
DllCall("DestroyIcon", "ptr", Handle)
else if (OutImageType = 2) ; IMAGE_CURSOR
DllCall("DestroyCursor", "ptr", Handle)
Last edited by Seven0528 on 16 Apr 2024, 19:40, edited 2 times in total.
- English is not my native language. Please forgive any awkward expressions.
- 영어는 제 모국어가 아닙니다. 어색한 표현이 있어도 양해해 주세요.
Re: Why Msgbox dosn't use "TraySetIcon"?
Anyway, using SysGet to retrieve the icon size seems like a really good idea. It's another thing I'm learning along the way! Thank you.
Code: Select all
MsgboxWithIcon(text?, title?, options?, hIconSmall?, hIconBig?) { ; ahk2.0
WM_COMMNOTIFY(*) {
static WM_SETICON:=0x0080, ICON_BIG:=1, ICON_SMALL:=0
,WTA_NONCLIENT:=1, WTNCA_NODRAWCAPTION:=0x00000001, WTNCA_NODRAWICON:=0x00000002, WTNCA_NOSYSMENU:=0x00000004, WTNCA_NOMIRRORHELP:=0x00000008
winCaption:=(title??A_ScriptName) " ahk_class #32770"
if (!hWnd:=format("{2}", prevDHW:=detectHiddenWindows(true), winExist(winCaption), detectHiddenWindows(prevDHW)))
return
if (hIconSmall)
dllCall("User32.dll\SendMessage", "Ptr",hWnd, "UInt",WM_SETICON, "UPtr",ICON_SMALL, "Ptr",hIconSmall, "Ptr")
if (hIconBig)
dllCall("User32.dll\SendMessage", "Ptr",hWnd, "UInt",WM_SETICON, "UPtr",ICON_BIG, "Ptr",hIconBig, "Ptr")
if (hIconSmall||hIconBig) && (!drawSystemIcon) {
eAttribute:=WTA_NONCLIENT
pvAttribute:=buffer(cbAttribute:=8,0), dwFlags:= dwMask:= 0
dwFlags|=WTNCA_NODRAWICON|WTNCA_NOSYSMENU ,numPut("UInt",dwFlags,pvAttribute,0)
dwMask|=WTNCA_NODRAWICON|WTNCA_NOSYSMENU ,numPut("UInt",dwMask,pvAttribute,4)
dllCall("UxTheme.dll\SetWindowThemeAttribute", "Ptr",hwnd, "Int",eAttribute, "Ptr",pvAttribute.Ptr, "UInt",cbAttribute, "Int")
}
}
onApplicationExit(*) {
for hIcon in destroyIconList
dllCall("User32.dll\DestroyIcon", "Ptr",hIcon)
}
static IMAGE_ICON:=1, MB_SYSTEMMODAL:=0x00001000
destroyIconList:=[], onExit(onApplicationExit)
,fileName:=(A_IconFile?A_IconFile:A_AhkPath), iconIndex:=(A_IconNumber?A_IconNumber:1)
if (!isSet(hIconSmall)) {
if (dllCall("User32.dll\PrivateExtractIcons", "Str",fileName, "Int",iconIndex-1, "Int",SM_CXSMICON:=sysGet(49), "Int",SM_CYSMICON:=sysGet(50), "Ptr*",&hIconSmall:=0, "UPtr*",0, "UInt",1, "UInt",IMAGE_ICON, "UInt")) {
for cIcon in [256,128,64,48,32,16] {
if (dllCall("User32.dll\PrivateExtractIcons", "Str",fileName, "Int",iconIndex-1, "Int",cIcon, "Int",cIcon, "Ptr*",&hIconSmall:=0, "UPtr*",0, "UInt",1, "UInt",IMAGE_ICON, "UInt"))
break
}
}
if (hIconSmall)
destroyIconList.push(hIconSmall)
}
if (!isSet(hIconBig)) {
if (dllCall("User32.dll\PrivateExtractIcons", "Str",fileName, "Int",iconIndex-1, "Int",SM_CXICON:=sysGet(11), "Int",SM_CYICON:=sysGet(12), "Ptr*",&hIconBig:=0, "UPtr*",0, "UInt",1, "UInt",IMAGE_ICON, "UInt")) {
for cIcon in [256,128,64,48,32,16] {
if (dllCall("User32.dll\PrivateExtractIcons", "Str",fileName, "Int",iconIndex-1, "Int",cIcon, "Int",cIcon, "Ptr*",&hIconBig:=0, "UPtr*",0, "UInt",1, "UInt",IMAGE_ICON, "UInt"))
break
}
}
if (hIconBig)
destroyIconList.push(hIconBig)
}
if (!hIconSmall && !hIconBig)
return msgBox(text?, title?, options?)
drawSystemIcon:=false
loop Parse, (options??""), A_Space A_Tab {
if (A_LoopField~="D)^(?:[[:digit:]]+|(0[Xx][[:xdigit:]]+))$" && A_LoopField&MB_SYSTEMMODAL)
drawSystemIcon:=true
} until (drawSystemIcon)
result:=format("{2}"
,onMessage(0x0044,WM_COMMNOTIFY,-1)
,msgBox(text?, title?, options?)
,onMessage(0x0044,WM_COMMNOTIFY,0))
onExit(onApplicationExit,false)
for hIcon in destroyIconList
dllCall("User32.dll\DestroyIcon", "Ptr",hIcon)
return result
}
Last edited by Seven0528 on 17 Apr 2024, 06:40, edited 1 time in total.
- English is not my native language. Please forgive any awkward expressions.
- 영어는 제 모국어가 아닙니다. 어색한 표현이 있어도 양해해 주세요.
Re: Why Msgbox dosn't use "TraySetIcon"?
@Seven0528, thanks for pointing out that bit in the documentation for LoadPicture(). Ran some leak tests and was noticing some performance issues after about 1600 MsgBox() calls, so we've tweaked the function yet again, now deleting the handles right after they've been applied and are now no longer needed.
Code: Select all
MsgBox.Native := MsgBox.Call
MsgBox.DefineProp("Call", {Call: MsgBoxEx})
MsgBoxEx(this, Text?, Title?, Options?, IconFile := A_IconFile ? A_IconFile : A_AhkPath, IconNumber := A_IconNumber ? A_IconNumber : 1) {
WinTitle := (title ?? A_ScriptName) " ahk_class #32770"
OnMessage(0x0044, WM_NOTIFY_MSGBOXEX)
result := this.Native(text?, title?, options?)
return result
WM_NOTIFY_MSGBOXEX(*) {
static ICON_BIG := 1, ICON_SMALL := 0, SM_CXICON := SysGet(11), SM_CYICON := SysGet(12), SM_CXSMICON := SysGet(49), SM_CYSMICON := SysGet(50), WM_SETICON := 0x0080
hICON_BIG := LoadPicture(IconFile, "w" SM_CXICON " h" SM_CYICON " Icon" IconNumber, &HandleType)
hICON_SMALL := LoadPicture(IconFile, "w" SM_CXSMICON " h" SM_CYSMICON " Icon" IconNumber, &HandleType)
DetectHiddenWindows(True)
SendMessage(WM_SETICON, ICON_BIG, hICON_BIG, Control?, WinTitle, Text ?? "Press OK to continue.")
SendMessage(WM_SETICON, ICON_SMALL, hICON_SMALL, Control?, WinTitle, Text ?? "Press Ok to continue.")
DetectHiddenWindows(False)
OnMessage(0x0044, WM_NOTIFY_MSGBOXEX, 0)
SetTimer((*) => DllCall("DestroyIcon", "ptr", hICON_BIG), -100)
SetTimer((*) => DllCall("DestroyIcon", "ptr", hICON_SMALL), -100)
}
}
Who is online
Users browsing this forum: CraigM and 61 guests