Тема: AHK: TrayTip оставить уведомление
Возможно ли оставить отображение TrayTip на экране и его содержимое в уведомлениях, если скрипт завершился?
Win10x64 AhkSpy, Hotkey, ClockGui
Вы не вошли. Пожалуйста, войдите или зарегистрируйтесь.
Страницы 1
Чтобы отправить ответ, вы должны войти или зарегистрироваться
Возможно ли оставить отображение TrayTip на экране и его содержимое в уведомлениях, если скрипт завершился?
TrayTip, видимо, принадлежит Проводнику. И ведёт себя так же, как и иконка скрипта в трее. Если убить процесс скрипта, TrayTip сразу не исчезнет, но при наведении курсора исчезает.
Если убить процесс скрипта, TrayTip сразу не исчезнет
У меня сразу исчезает в 10ке.
И ведёт себя так же, как и иконка скрипта в трее
Да, забыл, без иконки TrayTipа и нет совсем. Хотя если сразу после TrayTip применить Menu, Tray, NoIcon, то остаётся, но иконка мелькает. Поэтому ещё вопрос - как отобразить TrayTip без иконки?
Я так понимаю, ты говоришь об уведомлениях. Уведомления остаются после завершения процесса (во всяком случае, в панели уведомлений), но создать уведомление на AHK, думаю, будет затруднительно, это что-то из области UWP.
Ага, понял, как сделать на чистом 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
}
Здесь интересный проект от Lexikos:
https://github.com/Lexikos/winrt.ahk
Он хочет превратить AHK в "серьёзный" язык программирования. К сожалению, вряд ли будет востребовано.
Ага, понял, как сделать на чистом AHK. Почему-то думал, что не выйдет.
Супер!
А appID что такое? Почему в класс не поместил, и что такое "\AutoHotkey\AutoHotkey.exe", оно не будет работать без установленного AutoHotkey.exe?
; Для 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 увидел.
в противном случае
; уведомление не будет отображаться
Написал там просто белиберду, и всё равно работает.
Я пробовал A_AhkPath писать, тогда там полный путь отображается.
можно использовать команду PowerShell Get-StartApps для
; получить список AppID в системе
А это можно сделать, чтобы свой ехешник с иконкой выводить, или оно всё равно только для установленных в системе работает?
Думаю, только для установленных. Я пока не экспериментировал.
Нормальная штука, по идее там же есть ещё ссылка где то, на то что надо запустить, если кликнул по уведомлению.
Да, надо отлавливать ToastNotification.Activated Event:
https://learn.microsoft.com/en-us/uwp/a … inrt-22621
Пока не пойму, как его регистрировать. Вижу, что у 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:
какой его формат?
Формат, скорее всего IInspectable + Invoke.
Я думаю вот он:
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
Я думаю вот он
Вряд ли. Это интерфейс с аргументами, нам нужен метод Invoke().
на js пример уже есть
Не сгодится, там через addEventListener, такого метода у IToastNotification нет.
В windows.data.xml.dom.h тоже такого нет.
Ну да, это ж для джаваскрипт.
Вряд ли. Это интерфейс с аргументами, нам нужен метод Invoke().
Да, точно, invoke, только Iunknown + Invoke.
Можешь посмотреть, я его тут использовал:
http://forum.script-coding.com/viewtopic.php?id=16743
Попробую.
Вышло:
#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
}
Правда, работает только если активировать, пока не скрылось, из панели уведомлений уже не хочет.
Для работы из панели управлений, наверное, надо как-то так:
https://learn.microsoft.com/en-us/windo … other-apps
У-у-у...
Там что-то заморочное.
Step 1: Register your app in the registry
Step 2: Set up your COM activator
Добавил ещё remove_Activated().
У-у-у...
Там что-то заморочное.
Как-то так должно работать:
#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
}
Ага, спасибо, уже тоже нашёл: How to register a COM class in memory?
Не так всё просто оказалось. Во-первых, в эту ветку реестра можно писать только от админа, во-вторых, наличие слешей в названии ключа не допускается. Непонятно, какой appID тогда писать.
Так мой код создает нужный ключ.
Нет, у меня он создаёт иерархию ключей.
Это и есть нужный ключ.
И работает?
У меня да, а у тебя нет?
Не сработало, но может ошибся где-то, еще позже проверю.
У меня при запущенном скрипта от админа вообще не захотел метод Show работать.
Я этот скрипт отдельно запускал.
Я тоже так пробовал, но не было реакции.
Проверил. Запускать скрипт надо от обычного пользователя.
Да, сейчас тоже проверил. Работает! Но в реестр не получится писать не от админа. То-есть, это отдельно нужно делать.
Не обязательно.
Можно в HKEY_CURRENT_USER писать.
Подправил код.
Ага, отлично, работает! Объединю в одно целое.
Но теперь основной скрипт как-то странно стал работать. То создаёт сразу несколько уведомлений в панели уведомлений, то не показывает всплывающее уведомление.
Я вот так проверял - вроде работает.
#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
}
А ты удалил ранее созданный ключ от админа? И ещё перезагрузиться надо на всякий случай.
Последний код у меня создаёт два уведомления в панели. Это после удаления всех ранее созданных ключей и перезагрузки.
После перезагрузки скрипта теперь нормально. Надо ещё потестировать. Возможно какие-то проблемы возникают, если одновременно создавать ключ и показывать уведомление.
Точно что-то кривовато работает. Сейчас очистил панель уведомлений, удалил ключ из реестра, перезагрузился, запустил скрипт, первый раз сработал корректно. Перезагрузил скрипт — больше не показывает всплывающих уведомлений.
У меня такого не наблюдается.
По идее на показ уведомления COM activator влиять не должен.
Проверил ещё раз. После нескольких перезагрузок скрипт опять перестаёт показывать всплывающие уведомления. В панели уведомлений появляются, на клик реагируют. Может, конечно, у меня в системе какой-то косяк. Но изначальный скрипт всегда нормально работал.
Кажется, запись в реестре всё-таки на что-то влияет.
Единственное, что пока приходит в голову это:
The Activate method is called on a separte thread from your main thread.
https://learn.microsoft.com/en-us/windo … activation
Поэтому можно попробовать заменить RegisterCallback на RegisterSyncCallback.
Попробую, но вряд ли в этом проблема. Если удалить ключ из реестра, первый скрипт работает без проблем. Думаю, просто не совсем корректная запись в реестре, у меня других таких нет.
А если есть запись в реестре, то код из 6 поста тоже не срабатывает?
Просто, если бы была проблема в реестре, то, наверное, вообще бы не работало, а не время от времени.
Из 6 поста так же не показывает всплывающее уведомление, только в панели уведомлений появляется. Вроде было, что один раз сработал, но когда не сработал, то уже и не работает дальше.
Вроде, когда от админа писалось, тогда работало нормально. Но может, просто не успел поймать.
Заменил на обычный одноуровневый ключ — работает без проблем, но appID не отображается. Пробовал заменить обратные слеши на прямые.
Теперь всё заработало, чудеса! Наверно, какой-то глюк был.
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)
вроде не используется?
Да, я тоже заметил.
Но там, где я скрипт взял, автор прописал (хотя там тоже не вызывается):
https://www.autohotkey.com/board/topic/ … ntry154605
Идея "сокращённой" реализации интерфейсов, конечно, прикольная. Но я, наверно, всё же расшифрую.
Собрал, вроде работает:
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
}
Ничего себе вы накопали!
Собрал, вроде работает:
Я правильно понял что MsgBox, activated! должен быть при клике по уведомлению? У меня ничего не происходит.
Только что проверил на всякий случай на Windows 10 последний скрипт, у меня работает. Перед проверкой удалял все ранее созданные ключи в реестре и перезагружался. Проверь, создался ли у тебя в ветке реестра HKEY_CURRENT_USER\Software\Classes\AppUserModelId новый раздел {6D809377-6AF0-444B-8957-A3773F02200E}. Посмотри, работает ли этот вариант.
HKEY_CURRENT_USER\Software\Classes\AppUserModelId новый раздел {6D809377-6AF0-444B-8957-A3773F02200E}.
Раздел такой есть, вариант по ссылке тоже MsgBox не выдаёт. Мне надо удалить в реестре и перезагрузится?
Попробуй.
Попробовал, MsgBox после клика не появляется.
Страницы 1
Чтобы отправить ответ, вы должны войти или зарегистрироваться