1

Тема: AHK: TrayTip оставить уведомление

Возможно ли оставить отображение TrayTip на экране и его содержимое в уведомлениях, если скрипт завершился?

По вопросам возмездной помощи пишите на E-Mail: serzh82saratov@mail.ru Telegram: https://t.me/sergiol982
Win10x64 AhkSpy, Hotkey, ClockGui

2

Re: AHK: TrayTip оставить уведомление

TrayTip, видимо, принадлежит Проводнику. И ведёт себя так же, как и иконка скрипта в трее. Если убить процесс скрипта, TrayTip сразу не исчезнет, но при наведении курсора исчезает.

3

Re: AHK: TrayTip оставить уведомление

ypppu пишет:

Если убить процесс скрипта, TrayTip сразу не исчезнет

У меня сразу исчезает в 10ке.

ypppu пишет:

И ведёт себя так же, как и иконка скрипта в трее

Да, забыл, без иконки TrayTipа и нет совсем. Хотя если сразу после TrayTip применить Menu, Tray, NoIcon, то остаётся, но иконка мелькает. Поэтому ещё вопрос - как отобразить TrayTip  без иконки?

По вопросам возмездной помощи пишите на E-Mail: serzh82saratov@mail.ru Telegram: https://t.me/sergiol982
Win10x64 AhkSpy, Hotkey, ClockGui

4

Re: AHK: TrayTip оставить уведомление

Я так понимаю, ты говоришь об уведомлениях. Уведомления остаются после завершения процесса (во всяком случае, в панели уведомлений), но создать уведомление на AHK, думаю, будет затруднительно, это что-то из области UWP.

Разработка AHK-скриптов:
e-mail dfiveg@mail.ru
Telegram jollycoder

5

Re: AHK: TrayTip оставить уведомление

https://github.com/Lexikos/ActiveScript … _Toast.ahk

6

Re: AHK: TrayTip оставить уведомление

Ага, понял, как сделать на чистом AHK. Почему-то думал, что не выйдет.

appID := (A_Is64bitOS ? "{6D809377-6AF0-444b-8957-A3773F02200E}"
                      : "{905E63B6-C1BF-494E-B29C-65B732D3D21A}") . "\AutoHotkey\AutoHotkey.exe"

; https://learn.microsoft.com/en-us/uwp/api/windows.ui.notifications.toasttemplatetype
template := toastImageAndText02 := 1

boldText := "Hello, God!"
regularText := "This is a toast in AHK"

imageFile := A_ScriptDir . "\god.png"
if !FileExist(imageFile)
   UrlDownloadToFile, https://i.imgur.com/GM0mf5w.png, % imageFile

Toast := new ToastNotification(appID, template, [boldText, regularText], imageFile)
Sleep, 1000
MsgBox, 4, % " ", Hide notification?
IfMsgbox, Yes
   Toast.Hide()

class ToastNotification
{
; windows.data.xml.dom.h
; windows.ui.notifications.h
   __New(appID, template, textArr, imageFile := "") {
      if (A_OSVersion ~= "^\D") {
         MsgBox, 48, Class ToastNotification, This class requires Windows 10 or later!
         Return ""
      }
      ToastNotificationManager := this._CreateToastNotificationManager()
      XmlDocument := ToastNotificationManager.GetTemplateContent(template)
      this._SetText(textArr, XmlDocument)
      (imageFile && this._SetImage(imageFile, XmlDocument))
      WrtStr := new WrtString(appID)
      this.ToastNotifier := ToastNotificationManager.CreateToastNotifierWithId(WrtStr.HSTRING)
      this.ToastNotification := this._CreateToastNotification(XmlDocument)
      this.ToastNotifier.Show(this.ToastNotification.ptr)
   }
   
   Hide() {
      this.ToastNotifier.Hide(this.ToastNotification.ptr)
   }
   
   _CreateToastNotificationManager() {
      static IID_IToastNotificationManagerStatics := "{50AC103F-D235-4598-BBEF-98FE4D1A3AD4}"
      VarSetCapacity(CLSID, 16, 0)
      WrtStr := new WrtString("Windows.UI.Notifications.ToastNotificationManager")
      DllCall("Ole32\CLSIDFromString", "WStr", IID_IToastNotificationManagerStatics, "Ptr", &CLSID, "UInt")
      WrtStr.GetFactory(&CLSID, pIToastNotificationManagerStatics)
      Return new IToastNotificationManagerStatics(pIToastNotificationManagerStatics)
   }
   
   _SetText(textArr, XmlDocument) {
      static IID_IXmlNodeSerializer := "{5CC5B382-E6DD-4991-ABEF-06D8D2E7BD0C}"
      XmlNodeList := XmlDocument.GetElementsByTagName((new WrtString("text")).HSTRING)
      Loop % XmlNodeList.get_Length() {
         XmlNode := XmlNodeList.Item(A_Index - 1)
         pXmlNodeSerializer := ComObjQuery(XmlNode.ptr, IID_IXmlNodeSerializer)
         XmlNodeSerializer := new IXmlNodeSerializer(pXmlNodeSerializer)
         XmlNodeSerializer.put_InnerText((new WrtString(textArr[A_Index])).HSTRING)
      }
   }
   
   _SetImage(image, XmlDocument) {
      static IID_IXmlElement := "{2DFB8A1F-6B10-4EF8-9F83-EFCCE8FAEC37}"
      XmlNodeList := XmlDocument.GetElementsByTagName((new WrtString("image")).HSTRING)
      XmlNode := XmlNodeList.Item(0)
      pIXmlElement := ComObjQuery(XmlNode.ptr, IID_IXmlElement)
      XmlElement := new IXmlElement(pIXmlElement)
      WrtStr := new WrtString(image)
      XmlElement.SetAttribute((new WrtString("src")).HSTRING, WrtStr.HSTRING)
   }
   
   _CreateToastNotification(XmlDocument) {
      static IID_IToastNotificationFactory := "{04124B20-82C6-4229-B109-FD9ED4662B53}"
      VarSetCapacity(CLSID, 16, 0)
      WrtStr := new WrtString("Windows.UI.Notifications.ToastNotification")
      DllCall("Ole32\CLSIDFromString", "WStr", IID_IToastNotificationFactory, "Ptr", &CLSID, "UInt")
      WrtStr.GetFactory(&CLSID, pIToastNotificationFactory)
      ToastNotificationFactory := new IToastNotificationFactory(pIToastNotificationFactory)
      Return ToastNotificationFactory.CreateToastNotification(XmlDocument.ptr)
   }
}

class IToastNotificationManagerStatics extends InterfaceBase {
   CreateToastNotifierWithId(hString_appID) {
      hr := DllCall(this.VTable(7), "Ptr", this.ptr, "Ptr", hString_appID, "PtrP", pIToastNotifier)
      this.IsError(A_ThisFunc, hr)
      Return new IToastNotifier(pIToastNotifier)
   }
   GetTemplateContent(ToastTemplateType) {
      hr := DllCall(this.VTable(8), "Ptr", this.ptr, "Int", ToastTemplateType, "PtrP", pIXmlDocument)
      this.IsError(A_ThisFunc, hr)
      Return new IXmlDocument(pIXmlDocument)
   }
}

class IXmlDocument extends InterfaceBase {
   GetElementsByTagName(hString_tagName) {
      hr := DllCall(this.VTable(16), "Ptr", this.ptr, "Ptr", hString_tagName, "PtrP", pIXmlNodeList)
      this.IsError(A_ThisFunc, hr)
      Return new IXmlNodeList(pIXmlNodeList)
   }
}

class IXmlNodeList extends InterfaceBase {
   get_Length() {
      hr := DllCall(this.VTable(6), "Ptr", this.ptr, "UIntP", length)
      this.IsError(A_ThisFunc, hr)
      Return length
   }
   Item(index) {
      hr := DllCall(this.VTable(7), "Ptr", this.ptr, "UInt", index, "PtrP", pIXmlNode)
      this.IsError(A_ThisFunc, hr)
      Return new IXmlNode(pIXmlNode)
   }
}

class IXmlNode extends InterfaceBase {
}

class IXmlNodeSerializer extends InterfaceBase {
   put_InnerText(hString_innerText) {
      hr := DllCall(this.VTable(8), "Ptr", this.ptr, "Ptr", hString_innerText)
      this.IsError(A_ThisFunc, hr)
   }
}

class IXmlElement extends InterfaceBase {
   SetAttribute(hString_attributeName, hString_attributeValue) {
      hr := DllCall(this.VTable(8), "Ptr", this.ptr, "Ptr", hString_attributeName, "Ptr", hString_attributeValue)
      this.IsError(A_ThisFunc, hr)
   }
}

class IToastNotifier extends InterfaceBase {
   Show(pIToastNotification) {
      hr := DllCall(this.VTable(6), "Ptr", this.ptr, "Ptr", pIToastNotification)
      this.IsError(A_ThisFunc, hr)
   }
   Hide(pIToastNotification) {
      hr := DllCall(this.VTable(7), "Ptr", this.ptr, "Ptr", pIToastNotification)
      this.IsError(A_ThisFunc, hr)
   }
}

class IToastNotificationFactory extends InterfaceBase {
   CreateToastNotification(pIXmlDocument) {
      hr := DllCall(this.VTable(6), "Ptr", this.ptr, "Ptr", pIXmlDocument, "PtrP", pIToastNotification)
      this.IsError(A_ThisFunc, hr)
      Return new IToastNotification(pIToastNotification)
   }
}

class IToastNotification extends InterfaceBase {
}

class InterfaceBase {
   __New(ptr) {
      this.ptr := ptr
   }
   __Delete() {
      ObjRelease(this.ptr)
   }
   VTable(idx) {
      Return NumGet(NumGet(this.ptr + 0) + A_PtrSize*idx)
   }
   IsError(method, result, exc := true) {
      if (result = 0)
         Return 0
      error := StrReplace(method, ".", "::") . " failed.`nResult: "
                              . ( result = "" ? "No result" : SysError(Format("{:#x}", result & 0xFFFFFFFF)) )
                              . "`nErrorLevel: " . ErrorLevel
      if !exc
         Return error
      throw error
   }
}

class WrtString {
   __New(string, isHandle := false) {
      if isHandle
         this.HSTRING := string
      else {
         DllCall("Combase\WindowsCreateString", "WStr", string, "UInt", StrLen(string), "PtrP", HSTRING)
         this.HSTRING := HSTRING
      }
   }
   __Delete() {
      DllCall("Combase\WindowsDeleteString", "Ptr", this.HSTRING)
   }
   GetText() {
      pBuff := DllCall("Combase\WindowsGetStringRawBuffer", "Ptr", this.HSTRING, "UIntP", len, "Ptr")
      Return StrGet(pBuff, len, "UTF-16")
   }
   GetFactory(riid, ByRef pInterface) {
      hr := DllCall("Combase\RoGetActivationFactory", "Ptr", this.HSTRING, "Ptr", riid, "PtrP", pInterface)
      if (hr != 0)
         throw SysError(hr)
   }
}

SysError(errorNum = "") {
   static flags := (FORMAT_MESSAGE_ALLOCATE_BUFFER := 0x100) | (FORMAT_MESSAGE_FROM_SYSTEM := 0x1000)
   (errorNum = "" && errorNum := A_LastError)
   DllCall("FormatMessage", "UInt", flags, "UInt", 0, "UInt", errorNum, "UInt", 0, "PtrP", pBuff, "UInt", 512, "Str", "")
   Return (str := StrGet(pBuff)) ? str : ErrorNum
}
Разработка AHK-скриптов:
e-mail dfiveg@mail.ru
Telegram jollycoder

7

Re: AHK: TrayTip оставить уведомление

Здесь интересный проект от Lexikos:
https://github.com/Lexikos/winrt.ahk

8

Re: AHK: TrayTip оставить уведомление

Он хочет превратить AHK в "серьёзный" язык программирования. К сожалению, вряд ли будет востребовано.

Разработка AHK-скриптов:
e-mail dfiveg@mail.ru
Telegram jollycoder

9

Re: AHK: TrayTip оставить уведомление

teadrinker пишет:

Ага, понял, как сделать на чистом AHK. Почему-то думал, что не выйдет.

Супер!
А appID что такое? Почему в класс не поместил, и что такое "\AutoHotkey\AutoHotkey.exe", оно не будет работать без установленного AutoHotkey.exe?

По вопросам возмездной помощи пишите на E-Mail: serzh82saratov@mail.ru Telegram: https://t.me/sergiol982
Win10x64 AhkSpy, Hotkey, ClockGui

10

Re: AHK: TrayTip оставить уведомление

; Для Windows 10.0.16299 (и, возможно, более ранних или более поздних версий) AppID
; должно идентифицировать приложение, имеющее ярлык на начальном экране, в противном случае
; уведомление не будет отображаться. AppID для настольных приложений, кажется,
; путь к исполняемому файлу с заменой системных/известных папок на идентификаторы GUID.
; Если это не сработает, можно использовать команду PowerShell Get-StartApps для
; получить список AppID в системе.
; Это предполагает, что AutoHotkey установлен по умолчанию:
toast_appid := ( A_Is64bitOS ? " {6D809377-6AF0-444b-8957-A3773F02200E} "
                            : " {905e63b6-c1bf-494e-b29c-65b732d3d21a} " )
    . " \AutoHotkey\AutoHotkey.exe "

Ссылку Malcev увидел.

в противном случае
; уведомление не будет отображаться

Написал там просто белиберду, и всё равно работает.

По вопросам возмездной помощи пишите на E-Mail: serzh82saratov@mail.ru Telegram: https://t.me/sergiol982
Win10x64 AhkSpy, Hotkey, ClockGui

11

Re: AHK: TrayTip оставить уведомление

Я пробовал A_AhkPath писать, тогда там полный путь отображается.

Разработка AHK-скриптов:
e-mail dfiveg@mail.ru
Telegram jollycoder

12

Re: AHK: TrayTip оставить уведомление

можно использовать команду PowerShell Get-StartApps для
; получить список AppID в системе

А это можно сделать, чтобы свой ехешник с иконкой выводить, или оно всё равно только для установленных в системе работает?

По вопросам возмездной помощи пишите на E-Mail: serzh82saratov@mail.ru Telegram: https://t.me/sergiol982
Win10x64 AhkSpy, Hotkey, ClockGui

13

Re: AHK: TrayTip оставить уведомление

Думаю, только для установленных. Я пока не экспериментировал.

Разработка AHK-скриптов:
e-mail dfiveg@mail.ru
Telegram jollycoder

14

Re: AHK: TrayTip оставить уведомление

Нормальная штука, по идее там же есть ещё ссылка где то, на то что надо запустить, если кликнул по уведомлению.

По вопросам возмездной помощи пишите на E-Mail: serzh82saratov@mail.ru Telegram: https://t.me/sergiol982
Win10x64 AhkSpy, Hotkey, ClockGui

15

Re: AHK: TrayTip оставить уведомление

Да, надо отлавливать ToastNotification.Activated Event:
https://learn.microsoft.com/en-us/uwp/a … inrt-22621

16

Re: AHK: TrayTip оставить уведомление

Пока не пойму, как его регистрировать. Вижу, что у IToastNotification есть метод add_Activated:

    HRESULT (STDMETHODCALLTYPE* add_Activated)(__x_ABI_CWindows_CUI_CNotifications_CIToastNotification* This,
        __FITypedEventHandler_2_Windows__CUI__CNotifications__CToastNotification_IInspectable* handler,
        EventRegistrationToken* token);

Дальше тёмный лес. Так понимаю, нужно имплементировать ITypedEventHandler (какой его формат?). EventRegistrationToken тоже загадка.
upd:

teadrinker пишет:

какой его формат?

Формат, скорее всего IInspectable + Invoke.

Разработка AHK-скриптов:
e-mail dfiveg@mail.ru
Telegram jollycoder

17

Re: AHK: TrayTip оставить уведомление

Я думаю вот он:

MIDL_INTERFACE("E3BF92F3-C197-436F-8265-0625824F8DAC")

https://github.com/wmliang/wdk-10/blob/ … ns.h#L5180
А токен возвращается, полагаю, чтобы указать его если понадобится убрать подписку на уведомления.
Кстати, на js пример уже есть:
https://www.autohotkey.com/boards/viewt … 81#p222881

18

Re: AHK: TrayTip оставить уведомление

Malcev пишет:

Я думаю вот он

Вряд ли. Это интерфейс с аргументами, нам нужен метод Invoke().

Malcev пишет:

на js пример уже есть

Не сгодится, там через addEventListener, такого метода у IToastNotification нет.

Разработка AHK-скриптов:
e-mail dfiveg@mail.ru
Telegram jollycoder

19

Re: AHK: TrayTip оставить уведомление

В windows.data.xml.dom.h тоже такого нет.

Разработка AHK-скриптов:
e-mail dfiveg@mail.ru
Telegram jollycoder

20

Re: AHK: TrayTip оставить уведомление

Ну да, это ж для джаваскрипт.

teadrinker пишет:

Вряд ли. Это интерфейс с аргументами, нам нужен метод Invoke().

Да, точно, invoke, только Iunknown + Invoke.
Можешь посмотреть, я его тут использовал:
http://forum.script-coding.com/viewtopic.php?id=16743

21

Re: AHK: TrayTip оставить уведомление

Попробую.

Разработка AHK-скриптов:
e-mail dfiveg@mail.ru
Telegram jollycoder

22 (изменено: teadrinker, 2022-12-15 23:42:36)

Re: AHK: TrayTip оставить уведомление

Вышло:

#Persistent
appID := (A_Is64bitOS ? "{6D809377-6AF0-444b-8957-A3773F02200E}"
                      : "{905E63B6-C1BF-494E-B29C-65B732D3D21A}") . "\AutoHotkey\AutoHotkey.exe"

; https://learn.microsoft.com/en-us/uwp/api/windows.ui.notifications.toasttemplatetype
template := toastImageAndText02 := 1

boldText := "Hello, God!"
regularText := "This is a toast in AHK"

imageFile := A_ScriptDir . "\god.png"
if !FileExist(imageFile)
   UrlDownloadToFile, https://i.imgur.com/GM0mf5w.png, % imageFile

Toast := new ToastNotification(appID, template, [boldText, regularText], imageFile, Func("OnActivated"))
/*
Sleep, 1000
MsgBox, 4, % " ", Hide notification?
IfMsgbox, Yes
   Toast.Hide()
*/
OnActivated() {
   MsgBox, activated!
}

class ToastNotification
{
; windows.data.xml.dom.h
; windows.ui.notifications.h
   __New(appID, template, textArr, imageFile := "", userFunc := "") {
      if (A_OSVersion ~= "^\D") {
         MsgBox, 48, Class ToastNotification, This class requires Windows 10 or later!
         Return ""
      }
      ToastNotificationManager := this._CreateToastNotificationManager()
      XmlDocument := ToastNotificationManager.GetTemplateContent(template)
      this._SetText(textArr, XmlDocument)
      (imageFile && this._SetImage(imageFile, XmlDocument))
      WrtStr := new WrtString(appID)
      this.ToastNotifier := ToastNotificationManager.CreateToastNotifierWithId(WrtStr.HSTRING)
      this.ToastNotification := this._CreateToastNotification(XmlDocument)
      (userFunc && this._CreateEventHandler(userFunc))
      this.ToastNotifier.Show(this.ToastNotification.ptr)
   }
   
   Hide() {
      this.ToastNotifier.Hide(this.ToastNotification.ptr)
   }
   
   _CreateToastNotificationManager() {
      static IID_IToastNotificationManagerStatics := "{50AC103F-D235-4598-BBEF-98FE4D1A3AD4}"
      WrtStr := new WrtString("Windows.UI.Notifications.ToastNotificationManager")
      WrtStr.GetFactory(CLSIDFromString(IID_IToastNotificationManagerStatics, _), pIToastNotificationManagerStatics)
      Return new IToastNotificationManagerStatics(pIToastNotificationManagerStatics)
   }
   
   _SetText(textArr, XmlDocument) {
      static IID_IXmlNodeSerializer := "{5CC5B382-E6DD-4991-ABEF-06D8D2E7BD0C}"
      XmlNodeList := XmlDocument.GetElementsByTagName((new WrtString("text")).HSTRING)
      Loop % XmlNodeList.get_Length() {
         XmlNode := XmlNodeList.Item(A_Index - 1)
         pXmlNodeSerializer := ComObjQuery(XmlNode.ptr, IID_IXmlNodeSerializer)
         XmlNodeSerializer := new IXmlNodeSerializer(pXmlNodeSerializer)
         XmlNodeSerializer.put_InnerText((new WrtString(textArr[A_Index])).HSTRING)
      }
   }
   
   _SetImage(image, XmlDocument) {
      static IID_IXmlElement := "{2DFB8A1F-6B10-4EF8-9F83-EFCCE8FAEC37}"
      XmlNodeList := XmlDocument.GetElementsByTagName((new WrtString("image")).HSTRING)
      XmlNode := XmlNodeList.Item(0)
      pIXmlElement := ComObjQuery(XmlNode.ptr, IID_IXmlElement)
      XmlElement := new IXmlElement(pIXmlElement)
      WrtStr := new WrtString(image)
      XmlElement.SetAttribute((new WrtString("src")).HSTRING, WrtStr.HSTRING)
   }
   
   _CreateToastNotification(XmlDocument) {
      static IID_IToastNotificationFactory := "{04124B20-82C6-4229-B109-FD9ED4662B53}"
      WrtStr := new WrtString("Windows.UI.Notifications.ToastNotification")
      WrtStr.GetFactory(CLSIDFromString(IID_IToastNotificationFactory, _), pIToastNotificationFactory)
      ToastNotificationFactory := new IToastNotificationFactory(pIToastNotificationFactory)
      Return ToastNotificationFactory.CreateToastNotification(XmlDocument.ptr)
   }
   
   _CreateEventHandler(userFunc) {
      this.handler := new ITypedEventHandler(userFunc)
      this.SetCapacity("eventRegistrationToken", 8)
      this.pEventRegistrationToken := this.GetAddress("eventRegistrationToken")
      this.ToastNotification.add_Activated(this.handler.ptr, this.pEventRegistrationToken)
   }
   
   __Delete() {
      this.ToastNotification.remove_Activated(this.pEventRegistrationToken)
   }
}

class IToastNotificationManagerStatics extends InterfaceBase {
   CreateToastNotifierWithId(hString_appID) {
      hr := DllCall(this.VTable(7), "Ptr", this.ptr, "Ptr", hString_appID, "PtrP", pIToastNotifier)
      this.IsError(A_ThisFunc, hr)
      Return new IToastNotifier(pIToastNotifier)
   }
   GetTemplateContent(ToastTemplateType) {
      hr := DllCall(this.VTable(8), "Ptr", this.ptr, "Int", ToastTemplateType, "PtrP", pIXmlDocument)
      this.IsError(A_ThisFunc, hr)
      Return new IXmlDocument(pIXmlDocument)
   }
}

class IXmlDocument extends InterfaceBase {
   GetElementsByTagName(hString_tagName) {
      hr := DllCall(this.VTable(16), "Ptr", this.ptr, "Ptr", hString_tagName, "PtrP", pIXmlNodeList)
      this.IsError(A_ThisFunc, hr)
      Return new IXmlNodeList(pIXmlNodeList)
   }
}

class IXmlNodeList extends InterfaceBase {
   get_Length() {
      hr := DllCall(this.VTable(6), "Ptr", this.ptr, "UIntP", length)
      this.IsError(A_ThisFunc, hr)
      Return length
   }
   Item(index) {
      hr := DllCall(this.VTable(7), "Ptr", this.ptr, "UInt", index, "PtrP", pIXmlNode)
      this.IsError(A_ThisFunc, hr)
      Return new IXmlNode(pIXmlNode)
   }
}

class IXmlNode extends InterfaceBase {
}

class IXmlNodeSerializer extends InterfaceBase {
   put_InnerText(hString_innerText) {
      hr := DllCall(this.VTable(8), "Ptr", this.ptr, "Ptr", hString_innerText)
      this.IsError(A_ThisFunc, hr)
   }
}

class IXmlElement extends InterfaceBase {
   SetAttribute(hString_attributeName, hString_attributeValue) {
      hr := DllCall(this.VTable(8), "Ptr", this.ptr, "Ptr", hString_attributeName, "Ptr", hString_attributeValue)
      this.IsError(A_ThisFunc, hr)
   }
}

class IToastNotifier extends InterfaceBase {
   Show(pIToastNotification) {
      hr := DllCall(this.VTable(6), "Ptr", this.ptr, "Ptr", pIToastNotification)
      this.IsError(A_ThisFunc, hr)
   }
   Hide(pIToastNotification) {
      hr := DllCall(this.VTable(7), "Ptr", this.ptr, "Ptr", pIToastNotification)
      this.IsError(A_ThisFunc, hr)
   }
}

class IToastNotificationFactory extends InterfaceBase {
   CreateToastNotification(pIXmlDocument) {
      hr := DllCall(this.VTable(6), "Ptr", this.ptr, "Ptr", pIXmlDocument, "PtrP", pIToastNotification)
      this.IsError(A_ThisFunc, hr)
      Return new IToastNotification(pIToastNotification)
   }
}

class IToastNotification extends InterfaceBase {
   add_Activated(pTypedEventHandler, pEventRegistrationToken) {
      hr := DllCall(this.VTable(11), "Ptr", this.ptr, "Ptr", pTypedEventHandler, "Ptr", pEventRegistrationToken)
      this.IsError(A_ThisFunc, hr)
   }
   remove_Activated(pEventRegistrationToken) {
      hr := DllCall(this.VTable(12), "Ptr", this.ptr, "Ptr", pEventRegistrationToken)
      this.IsError(A_ThisFunc, hr)
   }
}

class InterfaceBase {
   __New(ptr) {
      this.ptr := ptr
   }
   __Delete() {
      ObjRelease(this.ptr)
   }
   VTable(idx) {
      Return NumGet(NumGet(this.ptr + 0) + A_PtrSize*idx)
   }
   IsError(method, result, exc := true) {
      if (result = 0)
         Return 0
      error := StrReplace(method, ".", "::") . " failed.`nResult: "
                              . ( result = "" ? "No result" : SysError(Format("{:#x}", result & 0xFFFFFFFF)) )
                              . "`nErrorLevel: " . ErrorLevel
      if !exc
         Return error
      throw error
   }
}

class WrtString {
   __New(string, isHandle := false) {
      if isHandle
         this.HSTRING := string
      else {
         DllCall("Combase\WindowsCreateString", "WStr", string, "UInt", StrLen(string), "PtrP", HSTRING)
         this.HSTRING := HSTRING
      }
   }
   __Delete() {
      DllCall("Combase\WindowsDeleteString", "Ptr", this.HSTRING)
   }
   GetText() {
      pBuff := DllCall("Combase\WindowsGetStringRawBuffer", "Ptr", this.HSTRING, "UIntP", len, "Ptr")
      Return StrGet(pBuff, len, "UTF-16")
   }
   GetFactory(riid, ByRef pInterface) {
      hr := DllCall("Combase\RoGetActivationFactory", "Ptr", this.HSTRING, "Ptr", riid, "PtrP", pInterface)
      if (hr != 0)
         throw SysError(hr)
   }
}

class ITypedEventHandler {
   __New(UserFunc) {
      this.Implement(UserFunc)
   }
   
   Implement(UserFunc) {
      static Methods := [ {name: "QueryInterface", paramCount: 3}
                        , {name: "AddRef"        , paramCount: 1}
                        , {name: "Release"       , paramCount: 1}
                        , {name: "Invoke"        , paramCount: 3} ]

      this.SetCapacity("vtable", A_PtrSize*(Methods.Count() + 1))
      pVtable := this.GetAddress("vtable")
      this.SetCapacity("IUnknown", A_PtrSize)
      NumPut(pVtable, this.ptr := this.GetAddress("IUnknown"))
      
      this.Info := {refOffset: A_PtrSize * Methods.Count(), UserFunc: UserFunc}
      this.EventInst := new this.Events(this.Info)
      this.Callbacks := []
      for k, v in Methods {
         Callback := new BoundFuncCallback( ObjBindMethod(this.EventInst, v.name), v.paramCount, "Fast" )
         NumPut(Callback.addr, pVtable + A_PtrSize*(k - 1))
         this.Callbacks.Push(Callback)
      }
      NumPut(0, pVtable + this.Info.refOffset)
   }
   
   __Delete() {
      this.Delete("Callbacks")
      this.SetCapacity("vtable", 0), this.Delete("vtable")
      this.Delete("EventInst")
   }
   
   class Events {
      __New(Info) {
         this.Info := Info
      }
      
      QueryInterface(pITypedEventHandler, riid, ppvObject) {
         static IID_IUnknown := "{00000000-0000-0000-C000-000000000046}"
              , IID          := "{AB54DE2D-97D9-5528-B6AD-105AFE156530}"
              , E_NOINTERFACE := 0x80004002, S_OK := 0, _, __
              , p1 := CLSIDFromString(IID_IUnknown,  _)
              , p2 := CLSIDFromString(IID         , __)
              
         if !( DllCall("Ole32\IsEqualGUID", "Ptr", riid, "Ptr", p1)
            || DllCall("Ole32\IsEqualGUID", "Ptr", riid, "Ptr", p2) )
         { ; if riid doesn't match IID_IUnknown nor IID
            NumPut(0, ppvObject + 0)
            Return E_NOINTERFACE
         }
         else {
            NumPut(pITypedEventHandler, ppvObject + 0)
            DllCall(NumGet(NumGet(ppvObject + 0) + A_PtrSize), "Ptr", ppvObject)
            Return S_OK
         }
      }
      
      AddRef(pITypedEventHandler) {
         refOffset := NumGet(pITypedEventHandler + 0) + this.Info.refOffset
         NumPut(refCount := NumGet(refOffset + 0, "UInt") + 1, refOffset, "UInt")
         Return refCount
      }
      
      Release(pITypedEventHandler) {
         refOffset := NumGet(pITypedEventHandler + 0) + this.Info.refOffset
         NumPut(refCount := NumGet(refOffset + 0, "UInt") - 1, refOffset, "UInt")
         Return refCount
      }
   
      Invoke(pITypedEventHandler, sender, args) {
         timer := this.Info.UserFunc
         SetTimer, % timer, -10
      }
   }
}

class BoundFuncCallback
{
   __New(BoundFuncObj, paramCount, options := "") {
      this.pInfo := Object( {BoundObj: BoundFuncObj, paramCount: paramCount} )
      this.addr := RegisterCallback(this.__Class . "._Callback", options, paramCount, this.pInfo)
   }
   __Delete() {
      ObjRelease(this.pInfo)
      DllCall("GlobalFree", "Ptr", this.addr, "Ptr")
   }
   _Callback(Params*) {
      Info := Object(A_EventInfo), Args := []
      Loop % Info.paramCount
         Args.Push( NumGet(Params + A_PtrSize*(A_Index - 2)) )
      Return Info.BoundObj.Call(Args*)
   }
}

CLSIDFromString(IID, ByRef CLSID) {
   VarSetCapacity(CLSID, 16, 0)
   if res := DllCall("ole32\CLSIDFromString", "WStr", IID, "Ptr", &CLSID, "UInt")
      throw Exception("CLSIDFromString failed. Error: " . Format("{:#x}", res))
   Return &CLSID
}

SysError(errorNum = "") {
   static flags := (FORMAT_MESSAGE_ALLOCATE_BUFFER := 0x100) | (FORMAT_MESSAGE_FROM_SYSTEM := 0x1000)
   (errorNum = "" && errorNum := A_LastError)
   DllCall("FormatMessage", "UInt", flags, "UInt", 0, "UInt", errorNum, "UInt", 0, "PtrP", pBuff, "UInt", 512, "Str", "")
   Return (str := StrGet(pBuff)) ? str : ErrorNum
}

Правда, работает только если активировать, пока не скрылось, из панели уведомлений уже не хочет.

Разработка AHK-скриптов:
e-mail dfiveg@mail.ru
Telegram jollycoder

23

Re: AHK: TrayTip оставить уведомление

Для работы из панели управлений, наверное, надо как-то так:
https://learn.microsoft.com/en-us/windo … other-apps

24

Re: AHK: TrayTip оставить уведомление

У-у-у...
Там что-то заморочное.

Step 1: Register your app in the registry
Step 2: Set up your COM activator

Разработка AHK-скриптов:
e-mail dfiveg@mail.ru
Telegram jollycoder

25

Re: AHK: TrayTip оставить уведомление

Добавил ещё remove_Activated().

Разработка AHK-скриптов:
e-mail dfiveg@mail.ru
Telegram jollycoder

26 (изменено: Malcev, 2022-12-16 17:51:32)

Re: AHK: TrayTip оставить уведомление

teadrinker пишет:

У-у-у...
Там что-то заморочное.

Как-то так должно работать:

#persistent
OnExit, Exit
CustomActivator := "{A5A8F02C-A117-47FF-8A91-2DBEC37A645B}"
RegRead, OutputVar, HKEY_CURRENT_USER\SOFTWARE\Classes\AppUserModelId\{6D809377-6AF0-444B-8957-A3773F02200E}\AutoHotkey\AutoHotkey.exe, CustomActivator
if (OutputVar != CustomActivator)
   RegWrite, REG_EXPAND_SZ, HKEY_CURRENT_USER\SOFTWARE\Classes\AppUserModelId\{6D809377-6AF0-444B-8957-A3773F02200E}\AutoHotkey\AutoHotkey.exe, CustomActivator, % CustomActivator

VarSetCapacity(INotificationActivationCallback, A_PtrSize*6, 0)
NumPut(&INotificationActivationCallback + A_PtrSize, INotificationActivationCallback)
nParams := 3115
Loop, Parse, nParams
   NumPut(RegisterCallback("INotificationActivationCallback", "", A_LoopField, A_Index-1), INotificationActivationCallback, A_PtrSize*A_Index)

VarSetCapacity(IClassFactory, A_PtrSize*7, 0)
NumPut(&IClassFactory + A_PtrSize, IClassFactory)
nParams := 31142
Loop, Parse, nParams
   NumPut(RegisterCallback("IClassFactory", "", A_LoopField, A_Index-1), IClassFactory, A_PtrSize*A_Index)

NumPut(&IClassFactory, INotificationActivationCallback, A_PtrSize*5)
NumPut(&INotificationActivationCallback, IClassFactory, A_PtrSize*6)
VarSetCapacity(GUID, 16)
DllCall("ole32\CLSIDFromString", "wstr", CustomActivator, "ptr", &GUID)
DllCall("ole32\CoRegisterClassObject", "ptr", &GUID, "ptr", &INotificationActivationCallback, "uint", CLSCTX_LOCAL_SERVER := 4, "uint", REGCLS_MULTIPLEUSE := 1, "uint*", Register)
return

Exit:
DllCall("ole32\CoRevokeClassObject", "uint", Register)
ExitApp


IClassFactory(this, punk="", riid="", ppobj="")
{
   hResult := 0
   if (A_EventInfo = 3)
      NumPut(NumGet(this+A_PtrSize*6), ppobj+0)
   else if (A_EventInfo = 0)
      hResult := DllCall(NumGet(NumGet(this+A_PtrSize*6)+A_PtrSize), "ptr", NumGet(this+A_PtrSize*6), "ptr", punk, "ptr", riid)
   return hResult
}

INotificationActivationCallback(this, appUserModelId="", invokedArgs="", data="", count="")
{
   hResult := 0
   if (A_EventInfo = 3)
      msgbox pressed
   else if (A_EventInfo = 0)
   {
      VarSetCapacity(sGuid, 78)
      DllCall("ole32\StringFromGUID2", "ptr", appUserModelId, "ptr", &sGuid, "int", 39)
      IID := StrGet(&sGuid, "UTF-16")
      if InStr("{53E31837-6600-4A81-9395-75CFFE746F94}{00000000-0000-0000-C000-000000000046}", IID)   ; IID_INotificationActivationCallback or IID_IUnknown
         NumPut(this, invokedArgs+0)
      else if (IID = "{00000001-0000-0000-C000-000000000046}")   ; IID_IClassFactory
         NumPut(NumGet(this+A_PtrSize*5), invokedArgs+0)
      else
         hResult := 0x80004002
   }
   return hResult
}

27

Re: AHK: TrayTip оставить уведомление

Ага, спасибо, уже тоже нашёл: How to register a COM class in memory?

Разработка AHK-скриптов:
e-mail dfiveg@mail.ru
Telegram jollycoder

28

Re: AHK: TrayTip оставить уведомление

Не так всё просто оказалось. Во-первых, в эту ветку реестра можно писать только от админа, во-вторых, наличие слешей в названии ключа не допускается. Непонятно, какой appID тогда писать.

Разработка AHK-скриптов:
e-mail dfiveg@mail.ru
Telegram jollycoder

29

Re: AHK: TrayTip оставить уведомление

Так мой код создает нужный ключ.

30

Re: AHK: TrayTip оставить уведомление

Нет, у меня он создаёт иерархию ключей.

Разработка AHK-скриптов:
e-mail dfiveg@mail.ru
Telegram jollycoder

31

Re: AHK: TrayTip оставить уведомление

Это и есть нужный ключ.

32

Re: AHK: TrayTip оставить уведомление

И работает?

Разработка AHK-скриптов:
e-mail dfiveg@mail.ru
Telegram jollycoder

33

Re: AHK: TrayTip оставить уведомление

У меня да, а у тебя нет?

34

Re: AHK: TrayTip оставить уведомление

Не сработало, но может ошибся где-то, еще позже проверю.
У меня при запущенном скрипта от админа вообще не захотел метод Show работать.

Разработка AHK-скриптов:
e-mail dfiveg@mail.ru
Telegram jollycoder

35

Re: AHK: TrayTip оставить уведомление

Я этот скрипт отдельно запускал.

36

Re: AHK: TrayTip оставить уведомление

Я тоже так пробовал, но не было реакции.

Разработка AHK-скриптов:
e-mail dfiveg@mail.ru
Telegram jollycoder

37

Re: AHK: TrayTip оставить уведомление

Проверил. Запускать скрипт надо от обычного пользователя.

38

Re: AHK: TrayTip оставить уведомление

Да, сейчас тоже проверил. Работает! Но в реестр не получится писать не от админа. То-есть, это отдельно нужно делать.

Разработка AHK-скриптов:
e-mail dfiveg@mail.ru
Telegram jollycoder

39

Re: AHK: TrayTip оставить уведомление

Не обязательно.
Можно в HKEY_CURRENT_USER писать.
Подправил код.

40

Re: AHK: TrayTip оставить уведомление

Ага, отлично, работает! Объединю в одно целое.

Разработка AHK-скриптов:
e-mail dfiveg@mail.ru
Telegram jollycoder

41

Re: AHK: TrayTip оставить уведомление

Но теперь основной скрипт как-то странно стал работать. То создаёт сразу несколько уведомлений в панели уведомлений, то не показывает всплывающее уведомление.

Разработка AHK-скриптов:
e-mail dfiveg@mail.ru
Telegram jollycoder

42

Re: AHK: TrayTip оставить уведомление

Я вот так проверял - вроде работает.

#persistent
OnExit, Exit
CustomActivator := "{A5A8F02C-A117-47FF-8A91-2DBEC37A645B}"
RegRead, OutputVar, HKEY_CURRENT_USER\SOFTWARE\Classes\AppUserModelId\{6D809377-6AF0-444B-8957-A3773F02200E}\AutoHotkey\AutoHotkey.exe, CustomActivator
if (OutputVar != CustomActivator)
   RegWrite, REG_EXPAND_SZ, HKEY_CURRENT_USER\SOFTWARE\Classes\AppUserModelId\{6D809377-6AF0-444B-8957-A3773F02200E}\AutoHotkey\AutoHotkey.exe, CustomActivator, % CustomActivator

VarSetCapacity(INotificationActivationCallback, A_PtrSize*6, 0)
NumPut(&INotificationActivationCallback + A_PtrSize, INotificationActivationCallback)
nParams := 3115
Loop, Parse, nParams
   NumPut(RegisterCallback("INotificationActivationCallback", "", A_LoopField, A_Index-1), INotificationActivationCallback, A_PtrSize*A_Index)

VarSetCapacity(IClassFactory, A_PtrSize*7, 0)
NumPut(&IClassFactory + A_PtrSize, IClassFactory)
nParams := 31142
Loop, Parse, nParams
   NumPut(RegisterCallback("IClassFactory", "", A_LoopField, A_Index-1), IClassFactory, A_PtrSize*A_Index)

NumPut(&IClassFactory, INotificationActivationCallback, A_PtrSize*5)
NumPut(&INotificationActivationCallback, IClassFactory, A_PtrSize*6)
VarSetCapacity(GUID, 16)
DllCall("ole32\CLSIDFromString", "wstr", CustomActivator, "ptr", &GUID)
DllCall("ole32\CoRegisterClassObject", "ptr", &GUID, "ptr", &INotificationActivationCallback, "uint", CLSCTX_LOCAL_SERVER := 4, "uint", REGCLS_MULTIPLEUSE := 1, "uint*", Register)
return

f11::
appID := (A_Is64bitOS ? "{6D809377-6AF0-444b-8957-A3773F02200E}"
                      : "{905E63B6-C1BF-494E-B29C-65B732D3D21A}") . "\AutoHotkey\AutoHotkey.exe"

; https://learn.microsoft.com/en-us/uwp/api/windows.ui.notifications.toasttemplatetype
template := toastImageAndText02 := 1

boldText := "Hello, God!"
regularText := "This is a toast in AHK"

imageFile := A_ScriptDir . "\god.png"
if !FileExist(imageFile)
   UrlDownloadToFile, https://i.imgur.com/GM0mf5w.png, % imageFile

Toast := new ToastNotification(appID, template, [boldText, regularText], imageFile, Func("OnActivated"))
/*
Sleep, 1000
MsgBox, 4, % " ", Hide notification?
IfMsgbox, Yes
   Toast.Hide()
*/
OnActivated() {
   MsgBox, activated!
}
return

Exit:
DllCall("ole32\CoRevokeClassObject", "uint", Register)
ExitApp


IClassFactory(this, punk="", riid="", ppobj="")
{
   hResult := 0
   if (A_EventInfo = 3)
      NumPut(NumGet(this+A_PtrSize*6), ppobj+0)
   else if (A_EventInfo = 0)
      hResult := DllCall(NumGet(NumGet(this+A_PtrSize*6)+A_PtrSize), "ptr", NumGet(this+A_PtrSize*6), "ptr", punk, "ptr", riid)
   return hResult
}

INotificationActivationCallback(this, appUserModelId="", invokedArgs="", data="", count="")
{
   hResult := 0
   if (A_EventInfo = 3)
      msgbox pressed
   else if (A_EventInfo = 0)
   {
      VarSetCapacity(sGuid, 78)
      DllCall("ole32\StringFromGUID2", "ptr", appUserModelId, "ptr", &sGuid, "int", 39)
      IID := StrGet(&sGuid, "UTF-16")
      if InStr("{53E31837-6600-4A81-9395-75CFFE746F94}{00000000-0000-0000-C000-000000000046}", IID)   ; IID_INotificationActivationCallback or IID_IUnknown
         NumPut(this, invokedArgs+0)
      else if (IID = "{00000001-0000-0000-C000-000000000046}")   ; IID_IClassFactory
         NumPut(NumGet(this+A_PtrSize*5), invokedArgs+0)
      else
         hResult := 0x80004002
   }
   return hResult
}




class ToastNotification
{
; windows.data.xml.dom.h
; windows.ui.notifications.h
   __New(appID, template, textArr, imageFile := "", userFunc := "") {
      if (A_OSVersion ~= "^\D") {
         MsgBox, 48, Class ToastNotification, This class requires Windows 10 or later!
         Return ""
      }
      ToastNotificationManager := this._CreateToastNotificationManager()
      XmlDocument := ToastNotificationManager.GetTemplateContent(template)
      this._SetText(textArr, XmlDocument)
      (imageFile && this._SetImage(imageFile, XmlDocument))
      WrtStr := new WrtString(appID)
      this.ToastNotifier := ToastNotificationManager.CreateToastNotifierWithId(WrtStr.HSTRING)
      this.ToastNotification := this._CreateToastNotification(XmlDocument)
      (userFunc && this._CreateEventHandler(userFunc))
      this.ToastNotifier.Show(this.ToastNotification.ptr)
   }
   
   Hide() {
      this.ToastNotifier.Hide(this.ToastNotification.ptr)
   }
   
   _CreateToastNotificationManager() {
      static IID_IToastNotificationManagerStatics := "{50AC103F-D235-4598-BBEF-98FE4D1A3AD4}"
      WrtStr := new WrtString("Windows.UI.Notifications.ToastNotificationManager")
      WrtStr.GetFactory(CLSIDFromString(IID_IToastNotificationManagerStatics, _), pIToastNotificationManagerStatics)
      Return new IToastNotificationManagerStatics(pIToastNotificationManagerStatics)
   }
   
   _SetText(textArr, XmlDocument) {
      static IID_IXmlNodeSerializer := "{5CC5B382-E6DD-4991-ABEF-06D8D2E7BD0C}"
      XmlNodeList := XmlDocument.GetElementsByTagName((new WrtString("text")).HSTRING)
      Loop % XmlNodeList.get_Length() {
         XmlNode := XmlNodeList.Item(A_Index - 1)
         pXmlNodeSerializer := ComObjQuery(XmlNode.ptr, IID_IXmlNodeSerializer)
         XmlNodeSerializer := new IXmlNodeSerializer(pXmlNodeSerializer)
         XmlNodeSerializer.put_InnerText((new WrtString(textArr[A_Index])).HSTRING)
      }
   }
   
   _SetImage(image, XmlDocument) {
      static IID_IXmlElement := "{2DFB8A1F-6B10-4EF8-9F83-EFCCE8FAEC37}"
      XmlNodeList := XmlDocument.GetElementsByTagName((new WrtString("image")).HSTRING)
      XmlNode := XmlNodeList.Item(0)
      pIXmlElement := ComObjQuery(XmlNode.ptr, IID_IXmlElement)
      XmlElement := new IXmlElement(pIXmlElement)
      WrtStr := new WrtString(image)
      XmlElement.SetAttribute((new WrtString("src")).HSTRING, WrtStr.HSTRING)
   }
   
   _CreateToastNotification(XmlDocument) {
      static IID_IToastNotificationFactory := "{04124B20-82C6-4229-B109-FD9ED4662B53}"
      WrtStr := new WrtString("Windows.UI.Notifications.ToastNotification")
      WrtStr.GetFactory(CLSIDFromString(IID_IToastNotificationFactory, _), pIToastNotificationFactory)
      ToastNotificationFactory := new IToastNotificationFactory(pIToastNotificationFactory)
      Return ToastNotificationFactory.CreateToastNotification(XmlDocument.ptr)
   }
   
   _CreateEventHandler(userFunc) {
      this.handler := new ITypedEventHandler(userFunc)
      this.SetCapacity("eventRegistrationToken", 8)
      this.pEventRegistrationToken := this.GetAddress("eventRegistrationToken")
      this.ToastNotification.add_Activated(this.handler.ptr, this.pEventRegistrationToken)
   }
   
   __Delete() {
      this.ToastNotification.remove_Activated(this.pEventRegistrationToken)
   }
}

class IToastNotificationManagerStatics extends InterfaceBase {
   CreateToastNotifierWithId(hString_appID) {
      hr := DllCall(this.VTable(7), "Ptr", this.ptr, "Ptr", hString_appID, "PtrP", pIToastNotifier)
      this.IsError(A_ThisFunc, hr)
      Return new IToastNotifier(pIToastNotifier)
   }
   GetTemplateContent(ToastTemplateType) {
      hr := DllCall(this.VTable(8), "Ptr", this.ptr, "Int", ToastTemplateType, "PtrP", pIXmlDocument)
      this.IsError(A_ThisFunc, hr)
      Return new IXmlDocument(pIXmlDocument)
   }
}

class IXmlDocument extends InterfaceBase {
   GetElementsByTagName(hString_tagName) {
      hr := DllCall(this.VTable(16), "Ptr", this.ptr, "Ptr", hString_tagName, "PtrP", pIXmlNodeList)
      this.IsError(A_ThisFunc, hr)
      Return new IXmlNodeList(pIXmlNodeList)
   }
}

class IXmlNodeList extends InterfaceBase {
   get_Length() {
      hr := DllCall(this.VTable(6), "Ptr", this.ptr, "UIntP", length)
      this.IsError(A_ThisFunc, hr)
      Return length
   }
   Item(index) {
      hr := DllCall(this.VTable(7), "Ptr", this.ptr, "UInt", index, "PtrP", pIXmlNode)
      this.IsError(A_ThisFunc, hr)
      Return new IXmlNode(pIXmlNode)
   }
}

class IXmlNode extends InterfaceBase {
}

class IXmlNodeSerializer extends InterfaceBase {
   put_InnerText(hString_innerText) {
      hr := DllCall(this.VTable(8), "Ptr", this.ptr, "Ptr", hString_innerText)
      this.IsError(A_ThisFunc, hr)
   }
}

class IXmlElement extends InterfaceBase {
   SetAttribute(hString_attributeName, hString_attributeValue) {
      hr := DllCall(this.VTable(8), "Ptr", this.ptr, "Ptr", hString_attributeName, "Ptr", hString_attributeValue)
      this.IsError(A_ThisFunc, hr)
   }
}

class IToastNotifier extends InterfaceBase {
   Show(pIToastNotification) {
      hr := DllCall(this.VTable(6), "Ptr", this.ptr, "Ptr", pIToastNotification)
      this.IsError(A_ThisFunc, hr)
   }
   Hide(pIToastNotification) {
      hr := DllCall(this.VTable(7), "Ptr", this.ptr, "Ptr", pIToastNotification)
      this.IsError(A_ThisFunc, hr)
   }
}

class IToastNotificationFactory extends InterfaceBase {
   CreateToastNotification(pIXmlDocument) {
      hr := DllCall(this.VTable(6), "Ptr", this.ptr, "Ptr", pIXmlDocument, "PtrP", pIToastNotification)
      this.IsError(A_ThisFunc, hr)
      Return new IToastNotification(pIToastNotification)
   }
}

class IToastNotification extends InterfaceBase {
   add_Activated(pTypedEventHandler, pEventRegistrationToken) {
      hr := DllCall(this.VTable(11), "Ptr", this.ptr, "Ptr", pTypedEventHandler, "Ptr", pEventRegistrationToken)
      this.IsError(A_ThisFunc, hr)
   }
   remove_Activated(pEventRegistrationToken) {
      hr := DllCall(this.VTable(12), "Ptr", this.ptr, "Ptr", pEventRegistrationToken)
      this.IsError(A_ThisFunc, hr)
   }
}

class InterfaceBase {
   __New(ptr) {
      this.ptr := ptr
   }
   __Delete() {
      ObjRelease(this.ptr)
   }
   VTable(idx) {
      Return NumGet(NumGet(this.ptr + 0) + A_PtrSize*idx)
   }
   IsError(method, result, exc := true) {
      if (result = 0)
         Return 0
      error := StrReplace(method, ".", "::") . " failed.`nResult: "
                              . ( result = "" ? "No result" : SysError(Format("{:#x}", result & 0xFFFFFFFF)) )
                              . "`nErrorLevel: " . ErrorLevel
      if !exc
         Return error
      throw error
   }
}

class WrtString {
   __New(string, isHandle := false) {
      if isHandle
         this.HSTRING := string
      else {
         DllCall("Combase\WindowsCreateString", "WStr", string, "UInt", StrLen(string), "PtrP", HSTRING)
         this.HSTRING := HSTRING
      }
   }
   __Delete() {
      DllCall("Combase\WindowsDeleteString", "Ptr", this.HSTRING)
   }
   GetText() {
      pBuff := DllCall("Combase\WindowsGetStringRawBuffer", "Ptr", this.HSTRING, "UIntP", len, "Ptr")
      Return StrGet(pBuff, len, "UTF-16")
   }
   GetFactory(riid, ByRef pInterface) {
      hr := DllCall("Combase\RoGetActivationFactory", "Ptr", this.HSTRING, "Ptr", riid, "PtrP", pInterface)
      if (hr != 0)
         throw SysError(hr)
   }
}

class ITypedEventHandler {
   __New(UserFunc) {
      this.Implement(UserFunc)
   }
   
   Implement(UserFunc) {
      static Methods := [ {name: "QueryInterface", paramCount: 3}
                        , {name: "AddRef"        , paramCount: 1}
                        , {name: "Release"       , paramCount: 1}
                        , {name: "Invoke"        , paramCount: 3} ]

      this.SetCapacity("vtable", A_PtrSize*(Methods.Count() + 1))
      pVtable := this.GetAddress("vtable")
      this.SetCapacity("IUnknown", A_PtrSize)
      NumPut(pVtable, this.ptr := this.GetAddress("IUnknown"))
      
      this.Info := {refOffset: A_PtrSize * Methods.Count(), UserFunc: UserFunc}
      this.EventInst := new this.Events(this.Info)
      this.Callbacks := []
      for k, v in Methods {
         Callback := new BoundFuncCallback( ObjBindMethod(this.EventInst, v.name), v.paramCount, "Fast" )
         NumPut(Callback.addr, pVtable + A_PtrSize*(k - 1))
         this.Callbacks.Push(Callback)
      }
      NumPut(0, pVtable + this.Info.refOffset)
   }
   
   __Delete() {
      this.Delete("Callbacks")
      this.SetCapacity("vtable", 0), this.Delete("vtable")
      this.Delete("EventInst")
   }
   
   class Events {
      __New(Info) {
         this.Info := Info
      }
      
      QueryInterface(pITypedEventHandler, riid, ppvObject) {
         static IID_IUnknown := "{00000000-0000-0000-C000-000000000046}"
              , IID          := "{AB54DE2D-97D9-5528-B6AD-105AFE156530}"
              , E_NOINTERFACE := 0x80004002, S_OK := 0, _, __
              , p1 := CLSIDFromString(IID_IUnknown,  _)
              , p2 := CLSIDFromString(IID         , __)
              
         if !( DllCall("Ole32\IsEqualGUID", "Ptr", riid, "Ptr", p1)
            || DllCall("Ole32\IsEqualGUID", "Ptr", riid, "Ptr", p2) )
         { ; if riid doesn't match IID_IUnknown nor IID
            NumPut(0, ppvObject + 0)
            Return E_NOINTERFACE
         }
         else {
            NumPut(pITypedEventHandler, ppvObject + 0)
            DllCall(NumGet(NumGet(ppvObject + 0) + A_PtrSize), "Ptr", ppvObject)
            Return S_OK
         }
      }
      
      AddRef(pITypedEventHandler) {
         refOffset := NumGet(pITypedEventHandler + 0) + this.Info.refOffset
         NumPut(refCount := NumGet(refOffset + 0, "UInt") + 1, refOffset, "UInt")
         Return refCount
      }
      
      Release(pITypedEventHandler) {
         refOffset := NumGet(pITypedEventHandler + 0) + this.Info.refOffset
         NumPut(refCount := NumGet(refOffset + 0, "UInt") - 1, refOffset, "UInt")
         Return refCount
      }
   
      Invoke(pITypedEventHandler, sender, args) {
         timer := this.Info.UserFunc
         SetTimer, % timer, -10
      }
   }
}

class BoundFuncCallback
{
   __New(BoundFuncObj, paramCount, options := "") {
      this.pInfo := Object( {BoundObj: BoundFuncObj, paramCount: paramCount} )
      this.addr := RegisterCallback(this.__Class . "._Callback", options, paramCount, this.pInfo)
   }
   __Delete() {
      ObjRelease(this.pInfo)
      DllCall("GlobalFree", "Ptr", this.addr, "Ptr")
   }
   _Callback(Params*) {
      Info := Object(A_EventInfo), Args := []
      Loop % Info.paramCount
         Args.Push( NumGet(Params + A_PtrSize*(A_Index - 2)) )
      Return Info.BoundObj.Call(Args*)
   }
}

CLSIDFromString(IID, ByRef CLSID) {
   VarSetCapacity(CLSID, 16, 0)
   if res := DllCall("ole32\CLSIDFromString", "WStr", IID, "Ptr", &CLSID, "UInt")
      throw Exception("CLSIDFromString failed. Error: " . Format("{:#x}", res))
   Return &CLSID
}

SysError(errorNum = "") {
   static flags := (FORMAT_MESSAGE_ALLOCATE_BUFFER := 0x100) | (FORMAT_MESSAGE_FROM_SYSTEM := 0x1000)
   (errorNum = "" && errorNum := A_LastError)
   DllCall("FormatMessage", "UInt", flags, "UInt", 0, "UInt", errorNum, "UInt", 0, "PtrP", pBuff, "UInt", 512, "Str", "")
   Return (str := StrGet(pBuff)) ? str : ErrorNum
}

43

Re: AHK: TrayTip оставить уведомление

А ты удалил ранее созданный ключ от админа? И ещё перезагрузиться надо на всякий случай.

Разработка AHK-скриптов:
e-mail dfiveg@mail.ru
Telegram jollycoder

44

Re: AHK: TrayTip оставить уведомление

Последний код у меня создаёт два уведомления в панели. Это после удаления всех ранее созданных ключей и перезагрузки.

Разработка AHK-скриптов:
e-mail dfiveg@mail.ru
Telegram jollycoder

45

Re: AHK: TrayTip оставить уведомление

После перезагрузки скрипта теперь нормально. Надо ещё потестировать. Возможно какие-то проблемы возникают, если одновременно создавать ключ и показывать уведомление.

Разработка AHK-скриптов:
e-mail dfiveg@mail.ru
Telegram jollycoder

46

Re: AHK: TrayTip оставить уведомление

Точно что-то кривовато работает. Сейчас очистил панель уведомлений, удалил ключ из реестра, перезагрузился, запустил скрипт, первый раз сработал корректно. Перезагрузил скрипт — больше не показывает всплывающих уведомлений.

Разработка AHK-скриптов:
e-mail dfiveg@mail.ru
Telegram jollycoder

47

Re: AHK: TrayTip оставить уведомление

У меня такого не наблюдается.
По идее на показ уведомления COM activator влиять не должен.

48

Re: AHK: TrayTip оставить уведомление

Проверил ещё раз. После нескольких перезагрузок скрипт опять перестаёт показывать всплывающие уведомления. В панели уведомлений появляются, на клик реагируют. Может, конечно, у меня в системе какой-то косяк. Но изначальный скрипт всегда нормально работал.

Разработка AHK-скриптов:
e-mail dfiveg@mail.ru
Telegram jollycoder

49

Re: AHK: TrayTip оставить уведомление

Кажется, запись в реестре всё-таки на что-то влияет.

Разработка AHK-скриптов:
e-mail dfiveg@mail.ru
Telegram jollycoder

50

Re: AHK: TrayTip оставить уведомление

Единственное, что пока приходит в голову это:

The Activate method is called on a separte thread from your main thread.

https://learn.microsoft.com/en-us/windo … activation
Поэтому можно попробовать заменить RegisterCallback на RegisterSyncCallback.

51

Re: AHK: TrayTip оставить уведомление

Попробую, но вряд ли в этом проблема. Если удалить ключ из реестра, первый скрипт работает без проблем. Думаю, просто не совсем корректная запись в реестре, у меня других таких нет.

Разработка AHK-скриптов:
e-mail dfiveg@mail.ru
Telegram jollycoder

52

Re: AHK: TrayTip оставить уведомление

А если есть запись в реестре, то код из 6 поста тоже не срабатывает?

53

Re: AHK: TrayTip оставить уведомление

Просто, если бы была проблема в реестре, то, наверное, вообще бы не работало, а не время от времени.

54

Re: AHK: TrayTip оставить уведомление

Из 6 поста так же не показывает всплывающее уведомление, только в панели уведомлений появляется. Вроде было, что один раз сработал, но когда не сработал, то уже и не работает дальше.

Разработка AHK-скриптов:
e-mail dfiveg@mail.ru
Telegram jollycoder

55

Re: AHK: TrayTip оставить уведомление

Вроде, когда от админа писалось, тогда работало нормально. Но может, просто не успел поймать.

Разработка AHK-скриптов:
e-mail dfiveg@mail.ru
Telegram jollycoder

56

Re: AHK: TrayTip оставить уведомление

Заменил на обычный одноуровневый ключ — работает без проблем, но appID не отображается. Пробовал заменить обратные слеши на прямые.

Разработка AHK-скриптов:
e-mail dfiveg@mail.ru
Telegram jollycoder

57

Re: AHK: TrayTip оставить уведомление

Теперь всё заработало, чудеса! Наверно, какой-то глюк был.

Malcev пишет:
IClassFactory(this, punk="", riid="", ppobj="")
{
   hResult := 0
   if (A_EventInfo = 3)
      NumPut(NumGet(this+A_PtrSize*6), ppobj+0)
   else if (A_EventInfo = 0)
      hResult := DllCall(NumGet(NumGet(this+A_PtrSize*6)+A_PtrSize), "ptr", NumGet(this+A_PtrSize*6), "ptr", punk, "ptr", riid)
   return hResult
}

А вот это

 else if (A_EventInfo = 0)
      hResult := DllCall(NumGet(NumGet(this+A_PtrSize*6)+A_PtrSize), "ptr", NumGet(this+A_PtrSize*6), "ptr", punk, "ptr", riid)

вроде не используется?

Разработка AHK-скриптов:
e-mail dfiveg@mail.ru
Telegram jollycoder

58

Re: AHK: TrayTip оставить уведомление

Да, я тоже заметил.
Но там, где я скрипт взял, автор прописал (хотя там тоже не вызывается):
https://www.autohotkey.com/board/topic/ … ntry154605

59

Re: AHK: TrayTip оставить уведомление

Идея "сокращённой" реализации интерфейсов, конечно, прикольная. Но я, наверно, всё же расшифрую.

Разработка AHK-скриптов:
e-mail dfiveg@mail.ru
Telegram jollycoder

60 (изменено: teadrinker, 2022-12-21 19:03:12)

Re: AHK: TrayTip оставить уведомление

Собрал, вроде работает:

appID := (A_Is64bitOS ? "{6D809377-6AF0-444b-8957-A3773F02200E}"
                      : "{905E63B6-C1BF-494E-B29C-65B732D3D21A}") . "\AutoHotkey\AutoHotkey.exe"

; https://learn.microsoft.com/en-us/uwp/api/windows.ui.notifications.toasttemplatetype
template := toastImageAndText02 := 1

boldText := "Hello, God!"
regularText := "This is a toast in AHK"

imageFile := A_ScriptDir . "\god.png"
if !FileExist(imageFile)
   UrlDownloadToFile, https://i.imgur.com/GM0mf5w.png, % imageFile

F11::
   Toast := new ToastNotification(appID, template, [boldText, regularText], imageFile, Func("OnActivated"))
   /*
   Sleep, 1000
   MsgBox, 4, % " ", Hide notification?
   IfMsgbox, Yes
      Toast.Hide()
   */
Return

OnActivated() {
   MsgBox, activated!
}

class ToastNotification
{
; windows.data.xml.dom.h
; windows.ui.notifications.h
   __New(appID, template, textArr, imageFile := "", userFunc := "") {
      if (A_OSVersion ~= "^\D") {
         MsgBox, 48, Class ToastNotification, This class requires Windows 10 or later!
         Return ""
      }
      ToastNotificationManager := this._CreateToastNotificationManager()
      XmlDocument := ToastNotificationManager.GetTemplateContent(template)
      this._SetText(textArr, XmlDocument)
      (imageFile && this._SetImage(imageFile, XmlDocument))
      WrtStr := new WrtString(appID)
      this.ToastNotifier := ToastNotificationManager.CreateToastNotifierWithId(WrtStr.HSTRING)
      this.ToastNotification := this._CreateToastNotification(XmlDocument)
      if (userFunc && !ToastNotification.ActivationCallbackCreated) {
         CreateNotificationActivationCallback(appID, userFunc)
         ToastNotification.ActivationCallbackCreated := true
      }
      this.ToastNotifier.Show(this.ToastNotification.ptr)
   }
   
   Hide() {
      this.ToastNotifier.Hide(this.ToastNotification.ptr)
   }
   
   _CreateToastNotificationManager() {
      static IID_IToastNotificationManagerStatics := "{50AC103F-D235-4598-BBEF-98FE4D1A3AD4}"
      WrtStr := new WrtString("Windows.UI.Notifications.ToastNotificationManager")
      WrtStr.GetFactory(CLSIDFromString(IID_IToastNotificationManagerStatics, _), pIToastNotificationManagerStatics)
      Return new IToastNotificationManagerStatics(pIToastNotificationManagerStatics)
   }
   
   _SetText(textArr, XmlDocument) {
      static IID_IXmlNodeSerializer := "{5CC5B382-E6DD-4991-ABEF-06D8D2E7BD0C}"
      XmlNodeList := XmlDocument.GetElementsByTagName((new WrtString("text")).HSTRING)
      Loop % XmlNodeList.get_Length() {
         XmlNode := XmlNodeList.Item(A_Index - 1)
         pXmlNodeSerializer := ComObjQuery(XmlNode.ptr, IID_IXmlNodeSerializer)
         XmlNodeSerializer := new IXmlNodeSerializer(pXmlNodeSerializer)
         XmlNodeSerializer.put_InnerText((new WrtString(textArr[A_Index])).HSTRING)
      }
   }
   
   _SetImage(image, XmlDocument) {
      static IID_IXmlElement := "{2DFB8A1F-6B10-4EF8-9F83-EFCCE8FAEC37}"
      XmlNodeList := XmlDocument.GetElementsByTagName((new WrtString("image")).HSTRING)
      XmlNode := XmlNodeList.Item(0)
      pIXmlElement := ComObjQuery(XmlNode.ptr, IID_IXmlElement)
      XmlElement := new IXmlElement(pIXmlElement)
      WrtStr := new WrtString(image)
      XmlElement.SetAttribute((new WrtString("src")).HSTRING, WrtStr.HSTRING)
   }
   
   _CreateToastNotification(XmlDocument) {
      static IID_IToastNotificationFactory := "{04124B20-82C6-4229-B109-FD9ED4662B53}"
      WrtStr := new WrtString("Windows.UI.Notifications.ToastNotification")
      WrtStr.GetFactory(CLSIDFromString(IID_IToastNotificationFactory, _), pIToastNotificationFactory)
      ToastNotificationFactory := new IToastNotificationFactory(pIToastNotificationFactory)
      Return ToastNotificationFactory.CreateToastNotification(XmlDocument.ptr)
   }
}

class IToastNotificationManagerStatics extends InterfaceBase {
   CreateToastNotifierWithId(hString_appID) {
      hr := DllCall(this.VTable(7), "Ptr", this.ptr, "Ptr", hString_appID, "PtrP", pIToastNotifier)
      this.IsError(A_ThisFunc, hr)
      Return new IToastNotifier(pIToastNotifier)
   }
   GetTemplateContent(ToastTemplateType) {
      hr := DllCall(this.VTable(8), "Ptr", this.ptr, "Int", ToastTemplateType, "PtrP", pIXmlDocument)
      this.IsError(A_ThisFunc, hr)
      Return new IXmlDocument(pIXmlDocument)
   }
}

class IXmlDocument extends InterfaceBase {
   GetElementsByTagName(hString_tagName) {
      hr := DllCall(this.VTable(16), "Ptr", this.ptr, "Ptr", hString_tagName, "PtrP", pIXmlNodeList)
      this.IsError(A_ThisFunc, hr)
      Return new IXmlNodeList(pIXmlNodeList)
   }
}

class IXmlNodeList extends InterfaceBase {
   get_Length() {
      hr := DllCall(this.VTable(6), "Ptr", this.ptr, "UIntP", length)
      this.IsError(A_ThisFunc, hr)
      Return length
   }
   Item(index) {
      hr := DllCall(this.VTable(7), "Ptr", this.ptr, "UInt", index, "PtrP", pIXmlNode)
      this.IsError(A_ThisFunc, hr)
      Return new IXmlNode(pIXmlNode)
   }
}

class IXmlNode extends InterfaceBase {
}

class IXmlNodeSerializer extends InterfaceBase {
   put_InnerText(hString_innerText) {
      hr := DllCall(this.VTable(8), "Ptr", this.ptr, "Ptr", hString_innerText)
      this.IsError(A_ThisFunc, hr)
   }
}

class IXmlElement extends InterfaceBase {
   SetAttribute(hString_attributeName, hString_attributeValue) {
      hr := DllCall(this.VTable(8), "Ptr", this.ptr, "Ptr", hString_attributeName, "Ptr", hString_attributeValue)
      this.IsError(A_ThisFunc, hr)
   }
}

class IToastNotifier extends InterfaceBase {
   Show(pIToastNotification) {
      hr := DllCall(this.VTable(6), "Ptr", this.ptr, "Ptr", pIToastNotification)
      this.IsError(A_ThisFunc, hr)
   }
   Hide(pIToastNotification) {
      hr := DllCall(this.VTable(7), "Ptr", this.ptr, "Ptr", pIToastNotification)
      this.IsError(A_ThisFunc, hr)
   }
}

class IToastNotificationFactory extends InterfaceBase {
   CreateToastNotification(pIXmlDocument) {
      hr := DllCall(this.VTable(6), "Ptr", this.ptr, "Ptr", pIXmlDocument, "PtrP", pIToastNotification)
      this.IsError(A_ThisFunc, hr)
      Return new IToastNotification(pIToastNotification)
   }
}

class IToastNotification extends InterfaceBase {
}

class InterfaceBase {
   __New(ptr) {
      this.ptr := ptr
   }
   __Delete() {
      ObjRelease(this.ptr)
   }
   VTable(idx) {
      Return NumGet(NumGet(this.ptr + 0) + A_PtrSize*idx)
   }
   IsError(method, result, exc := true) {
      if (result = 0)
         Return 0
      error := StrReplace(method, ".", "::") . " failed.`nResult: "
                              . ( result = "" ? "No result" : SysError(Format("{:#x}", result & 0xFFFFFFFF)) )
                              . "`nErrorLevel: " . ErrorLevel
      if !exc
         Return error
      throw error
   }
}

class WrtString {
   __New(string, isHandle := false) {
      if isHandle
         this.HSTRING := string
      else {
         DllCall("Combase\WindowsCreateString", "WStr", string, "UInt", StrLen(string), "PtrP", HSTRING)
         this.HSTRING := HSTRING
      }
   }
   __Delete() {
      DllCall("Combase\WindowsDeleteString", "Ptr", this.HSTRING)
   }
   GetText() {
      pBuff := DllCall("Combase\WindowsGetStringRawBuffer", "Ptr", this.HSTRING, "UIntP", len, "Ptr")
      Return StrGet(pBuff, len, "UTF-16")
   }
   GetFactory(riid, ByRef pInterface) {
      hr := DllCall("Combase\RoGetActivationFactory", "Ptr", this.HSTRING, "Ptr", riid, "PtrP", pInterface)
      if (hr != 0)
         throw SysError(hr)
   }
}

class INotificationActivationCallback {
   Implement(UserFunc) {
      static MethodList := [ {name: "QueryInterface", paramCount: 3}
                           , {name: "AddRef"        , paramCount: 1}
                           , {name: "Release"       , paramCount: 1}
                           , {name: "Activate"      , paramCount: 5} ]

      this.SetCapacity("vtable", MethodList.Count()*A_PtrSize)
      pVtable := this.GetAddress("vtable")
      this.SetCapacity("IUnknown", A_PtrSize)
      NumPut(pVtable, this.pIUnknown := this.GetAddress("IUnknown"))
      this.Methods.UserFunc := UserFunc
      this.Callbacks := []
      for k, method in MethodList {
         Callback := new BoundFuncCallback( ObjBindMethod(this.Methods, method.name), method.paramCount, "Fast" )
         NumPut(Callback.addr, pVtable + A_PtrSize*(k - 1))
         this.Callbacks.Push(Callback)
      }
   }
   
   __Delete() {
      this.Delete("Callbacks")
      this.SetCapacity("vtable", 0)
      this.Delete("vtable")
   }
   
   class Methods {
      QueryInterface(pINotificationActivationCallback, riid, ppvObject) {
         static IID_IUnknown                        := "{00000000-0000-0000-C000-000000000046}"
              , IID_IClassFactory                   := "{00000001-0000-0000-C000-000000000046}"
              , IID_INotificationActivationCallback := "{53E31837-6600-4A81-9395-75CFFE746F94}"
              , E_NOINTERFACE := 0x80004002, S_OK := 0, _, __, ___
              , p1 := CLSIDFromString(IID_IUnknown                       ,   _)
              , p2 := CLSIDFromString(IID_INotificationActivationCallback,  __)
              , p3 := CLSIDFromString(IID_IClassFactory                  , ___)
              
         hResult := S_OK 
         if DllCall("Ole32\IsEqualGUID", "Ptr", riid, "Ptr", p1) || DllCall("Ole32\IsEqualGUID", "Ptr", riid, "Ptr", p2)
            NumPut(pINotificationActivationCallback, ppvObject + 0)
         else if DllCall("Ole32\IsEqualGUID", "Ptr", riid, "Ptr", p3)
            NumPut(this.pIClassFactory, ppvObject + 0)
         else
         { ; if riid doesn't match IID_IUnknown nor IID_INotificationActivationCallback nor IID_IClassFactory
            NumPut(0, ppvObject + 0)
            hResult := E_NOINTERFACE
         }
         Return hResult
      }
      
      AddRef(pINotificationActivationCallback) {
         Return E_NOTIMPL := 0x80004001
      }
      
      Release(pINotificationActivationCallback) {
         Return E_NOTIMPL := 0x80004001
      }
   
      Activate(pINotificationActivationCallback, appUserModelId, invokedArgs, pData, count) {
         timer := this.UserFunc
         SetTimer, % timer, -10
      }
   }
}

class IClassFactory
{
   Implement(pUnkOuter) {
      static MethodList := [ {name: "QueryInterface", paramCount: 3}
                           , {name: "AddRef"        , paramCount: 1}
                           , {name: "Release"       , paramCount: 1}
                           , {name: "CreateInstance", paramCount: 4}
                           , {name: "LockServer"    , paramCount: 2} ]

      this.SetCapacity("vtable", MethodList.Count()*A_PtrSize)
      pVtable := this.GetAddress("vtable")
      this.SetCapacity("IUnknown", A_PtrSize)
      NumPut(pVtable, this.pIUnknown := this.GetAddress("IUnknown"))
      
      this.Methods.pUnkOuter := pUnkOuter
      this.Callbacks := []
      for k, method in MethodList {
         Callback := new BoundFuncCallback( ObjBindMethod(this.Methods, method.name), method.paramCount, "Fast" )
         NumPut(Callback.addr, pVtable + A_PtrSize*(k - 1))
         this.Callbacks.Push(Callback)
      }
   }
   
   __Delete() {
      this.Delete("Callbacks")
      this.SetCapacity("vtable", 0)
      this.Delete("vtable")
   }
   
   class Methods {
      QueryInterface(pIClassFactory, riid, ppvObject) {
         Return E_NOTIMPL := 0x80004001
      }
      
      AddRef(pIClassFactory) {
         Return E_NOTIMPL := 0x80004001
      }
      
      Release(pIClassFactory) {
         Return E_NOTIMPL := 0x80004001
      }
   
      CreateInstance(pIClassFactory, pUnkOuter, riid, ppvObject) {
         NumPut(this.pUnkOuter, ppvObject + 0)
         Return S_OK := 0
      }
      
      LockServer(pIClassFactory, fLock) {
         Return E_NOTIMPL := 0x80004001
      }
   }
}

class BoundFuncCallback
{
   __New(BoundFuncObj, paramCount, options := "") {
      this.pInfo := Object( {BoundObj: BoundFuncObj, paramCount: paramCount} )
      this.addr := RegisterCallback(this.__Class . "._Callback", options, paramCount, this.pInfo)
   }
   __Delete() {
      ObjRelease(this.pInfo)
      DllCall("GlobalFree", "Ptr", this.addr, "Ptr")
   }
   _Callback(Params*) {
      Info := Object(A_EventInfo), Args := []
      Loop % Info.paramCount
         Args.Push( NumGet(Params + A_PtrSize*(A_Index - 2)) )
      Return Info.BoundObj.Call(Args*)
   }
}

CreateNotificationActivationCallback(appID, userFunc) {
   static CLSCTX_LOCAL_SERVER := 4, REGCLS_MULTIPLEUSE := 1
        , CustomActivator := "{A5A8F02C-A117-47FF-8A91-2DBEC37A645B}"
        
   regKey := "HKCU\Software\Classes\AppUserModelId\" . appID
   RegRead, guid, % regKey, CustomActivator
   if (guid != CustomActivator)
      RegWrite, REG_SZ, % regKey, CustomActivator, % CustomActivator
   
   INotificationActivationCallback.Implement(userFunc)
   IClassFactory.Implement(INotificationActivationCallback.pIUnknown)
   INotificationActivationCallback.Methods.pIClassFactory := IClassFactory.pIUnknown
   
   DllCall("Ole32\CoRegisterClassObject", "Ptr", CLSIDFromString(CustomActivator, _)
                                        , "Ptr", INotificationActivationCallback.pIUnknown
                                        , "UInt", CLSCTX_LOCAL_SERVER, "UInt", REGCLS_MULTIPLEUSE, "UIntP", Register)
   OnExit(Func("RevokeClassObject").Bind(Register))
}

RevokeClassObject(Register) {
   DllCall("Ole32\CoRevokeClassObject", "UInt", Register)
}

CLSIDFromString(IID, ByRef CLSID) {
   VarSetCapacity(CLSID, 16, 0)
   if res := DllCall("ole32\CLSIDFromString", "WStr", IID, "Ptr", &CLSID, "UInt")
      throw Exception("CLSIDFromString failed. Error: " . Format("{:#x}", res))
   Return &CLSID
}

SysError(errorNum = "") {
   static flags := (FORMAT_MESSAGE_ALLOCATE_BUFFER := 0x100) | (FORMAT_MESSAGE_FROM_SYSTEM := 0x1000)
   (errorNum = "" && errorNum := A_LastError)
   DllCall("FormatMessage", "UInt", flags, "UInt", 0, "UInt", errorNum, "UInt", 0, "PtrP", pBuff, "UInt", 512, "Str", "")
   Return (str := StrGet(pBuff)) ? str : ErrorNum
}
Разработка AHK-скриптов:
e-mail dfiveg@mail.ru
Telegram jollycoder

61

Re: AHK: TrayTip оставить уведомление

Ничего себе вы накопали!

По вопросам возмездной помощи пишите на E-Mail: serzh82saratov@mail.ru Telegram: https://t.me/sergiol982
Win10x64 AhkSpy, Hotkey, ClockGui

62

Re: AHK: TrayTip оставить уведомление

teadrinker пишет:

Собрал, вроде работает:

Я правильно понял что MsgBox, activated! должен быть при клике по уведомлению? У меня ничего не происходит.

По вопросам возмездной помощи пишите на E-Mail: serzh82saratov@mail.ru Telegram: https://t.me/sergiol982
Win10x64 AhkSpy, Hotkey, ClockGui

63

Re: AHK: TrayTip оставить уведомление

Только что проверил на всякий случай на Windows 10 последний скрипт, у меня работает. Перед проверкой удалял все ранее созданные ключи в реестре и перезагружался. Проверь, создался ли у тебя в ветке реестра HKEY_CURRENT_USER\Software\Classes\AppUserModelId новый раздел {6D809377-6AF0-444B-8957-A3773F02200E}. Посмотри, работает ли этот вариант.

Разработка AHK-скриптов:
e-mail dfiveg@mail.ru
Telegram jollycoder

64

Re: AHK: TrayTip оставить уведомление

teadrinker пишет:

HKEY_CURRENT_USER\Software\Classes\AppUserModelId новый раздел {6D809377-6AF0-444B-8957-A3773F02200E}.

Раздел такой есть, вариант по ссылке тоже MsgBox не выдаёт. Мне надо удалить в реестре и перезагрузится?

По вопросам возмездной помощи пишите на E-Mail: serzh82saratov@mail.ru Telegram: https://t.me/sergiol982
Win10x64 AhkSpy, Hotkey, ClockGui

65

Re: AHK: TrayTip оставить уведомление

Попробуй.

Разработка AHK-скриптов:
e-mail dfiveg@mail.ru
Telegram jollycoder

66

Re: AHK: TrayTip оставить уведомление

Попробовал, MsgBox после клика не появляется.

По вопросам возмездной помощи пишите на E-Mail: serzh82saratov@mail.ru Telegram: https://t.me/sergiol982
Win10x64 AhkSpy, Hotkey, ClockGui