Handling strings in threads seems to be very unstable, so a mutex is used.
The code below seems to work well, but more tests are required.
Edit: The code slightly modified.
Code: Select all
EnableExplicit
; Sending toast notifications from desktop apps
; https://docs.microsoft.com/en-us/previous-versions/windows/apps/hh779727(v=win.10)
;
; Generally, sending a toast notification from a desktop app is the same as sending it from a Windows Store app. However, you should be aware of these differences and requirements:
;
; - The app must have a shortcut installed (though not necessarily pinned) to the Start screen or in the Apps view
; - The shortcut must have an AppUserModelID
; - Desktop apps cannot schedule a toast
; - All toasts raised by desktop apps are the same system-defined color
; - Desktop apps cannot use web images
; - Desktop app notifications will not appear on the lock screen
; How to enable desktop toast notifications through an AppUserModelID
; https://docs.microsoft.com/en-us/previous-versions/windows/desktop/legacy/hh802762(v=vs.85)
; Application User Model IDs (AppUserModelIDs)
; https://docs.microsoft.com/en-us/windows/win32/shell/appids
;This is the AppUserModelId of an application from the Start menu.
;If you don't supply a valid entry here, the toast will have no icon.
#App_ID = "MyCompany.TestApp.TestSubProduct"
; Unique CLSID of your app.
#App_CLSID = "{394391cf-093b-4cb1-895b-5505ee760cc2}"
;Set a name to be used as the shortcut file(.lnk) name and the toast notification title.
#App_Name = "My Toast Notification Test App"
;- For debugging.
#DebugMode = 1
#EditorGadget = 2
#App_DebugEvent_NewDebugString = #PB_Event_FirstCustomValue
#App_DebugEventType_Value = #PB_EventType_FirstCustomValue
CompilerIf #PB_Compiler_Debugger
;CompilerError "Turn OFF debugger. "
CompilerEndIf
CompilerIf Not #PB_Compiler_Thread
CompilerError "Turn ON thread-safe. "
CompilerEndIf
CompilerIf #DebugMode
Global MutexStringSync
CompilerIf Not Defined(EditorGadget, #PB_Constant)
CompilerError "#EditorGadget NOT defined. "
CompilerEndIf
Macro mDebugOutput(String)
CompilerIf Not Defined(___string_buffer___, #PB_Variable)
Define ___string_buffer___
CompilerEndIf
LockMutex(MutexStringSync)
___string_buffer___ = AllocateMemory(StringByteLength(String) + SizeOf(Character))
PokeS(___string_buffer___, String)
PostEvent(#App_DebugEvent_NewDebugString, 0, 0, #App_DebugEventType_Value, ___string_buffer___)
___string_buffer___ = 0
UnlockMutex(MutexStringSync)
EndMacro
Procedure ShowDebugString()
Protected String.s, *buffer = EventData()
If *buffer
LockMutex(MutexStringSync)
String = PeekS(*buffer)
If String
If IsGadget(#EditorGadget)
AddGadgetItem(#EditorGadget, -1, FormatDate("%hh:%ii:%ss", Date()) + " | " + String)
PostMessage_(GadgetID(#EditorGadget), #EM_SCROLL, #SB_PAGEDOWN, 0)
EndIf
EndIf
FreeMemory(*buffer)
UnlockMutex(MutexStringSync)
EndIf
EndProcedure
CompilerElse
Macro mDebugOutput(String)
EndMacro
Macro ShowDebugString()
EndMacro
CompilerEndIf
;- Constants.
#SHCNE_ASSOCCHANGED = $8000000
#SHCNF_IDLIST = 0
#SHCNE_ALLEVENTS = $7FFFFFFF
#SHCNF_FLUSH = $1000
#SHREGSET_FORCE_HKCU = 2
#REGCLS_SINGLEUSE = 0 ;class object only generates one instance
#REGCLS_MULTIPLEUSE = 1 ;same class object genereates multiple inst. and local automatically goes into inproc tbl.
#REGCLS_MULTI_SEPARATE = 2 ;multiple use, but separate control over each context.
#REGCLS_SUSPENDED = 4 ;register is as suspended, will be activated when app calls CoResumeClassObjects
#REGCLS_SURROGATE = 8 ;must be used when a surrogate process is registering a class object that will be loaded in the surrogate
#CLSCTX_INPROC_SERVER = $1
#CLSCTX_INPROC_HANDLER = $2
#CLSCTX_LOCAL_SERVER = $4
#CLSCTX_INPROC_SERVER16 = $8
#CLSCTX_REMOTE_SERVER = $10
#CLSCTX_INPROC_HANDLER16 = $20
#CLSCTX_RESERVED1 = $40
#CLSCTX_RESERVED2 = $80
#CLSCTX_RESERVED3 = $100
#CLSCTX_RESERVED4 = $200
#CLSCTX_NO_CODE_DOWNLOAD = $400
#CLSCTX_RESERVED5 = $800
#CLSCTX_NO_CUSTOM_MARSHAL = $1000
#CLSCTX_ENABLE_CODE_DOWNLOAD = $2000
#CLSCTX_NO_FAILURE_LOG = $4000
#CLSCTX_DISABLE_AAA = $8000
#CLSCTX_ENABLE_AAA = $10000
#CLSCTX_FROM_DEFAULT_CONTEXT = $20000
#CLSCTX_ACTIVATE_X86_SERVER = $40000
#CLSCTX_ACTIVATE_32_BIT_SERVER = #CLSCTX_ACTIVATE_X86_SERVER
#CLSCTX_ACTIVATE_64_BIT_SERVER = $80000
#CLSCTX_ENABLE_CLOAKING = $100000
#CLSCTX_APPCONTAINER = $400000
#CLSCTX_ACTIVATE_AAA_AS_IU = $800000
#CLSCTX_RESERVED6 = $1000000
#CLSCTX_ACTIVATE_ARM32_SERVER = $2000000
#CLSCTX_PS_DLL = $80000000
#RO_INIT_MULTITHREADED = 1
#RuntimeClass_Windows_Data_Xml_Dom_XmlDocument = "Windows.Data.Xml.Dom.XmlDocument"
#RuntimeClass_Windows_UI_Notifications_ToastNotificationManager = "Windows.UI.Notifications.ToastNotificationManager"
#RuntimeClass_Windows_UI_Notifications_ToastNotification = "Windows.UI.Notifications.ToastNotification"
Enumeration ;__x_ABI_CWindows_CUI_CNotifications_CToastDismissalReason
#ToastDismissalReason_UserCanceled
#ToastDismissalReason_ApplicationHidden
#ToastDismissalReason_TimedOut
EndEnumeration
;__x_ABI_CWindows_CFoundation_CPropertyType
#PropertyType_Empty = 0
#PropertyType_UInt8 = 1
#PropertyType_Int16 = 2
#PropertyType_UInt16 = 3
#PropertyType_Int32 = 4
#PropertyType_UInt32 = 5
#PropertyType_Int64 = 6
#PropertyType_UInt64 = 7
#PropertyType_Single = 8
#PropertyType_Double = 9
#PropertyType_Char16 = 10
#PropertyType_Boolean = 11
#PropertyType_String = 12
#PropertyType_Inspectable = 13
#PropertyType_DateTime = 14
#PropertyType_TimeSpan = 15
#PropertyType_Guid = 16
#PropertyType_Point = 17
#PropertyType_Size = 18
#PropertyType_Rect = 19
#PropertyType_OtherType = 20
#PropertyType_UInt8Array = 1025
#PropertyType_Int16Array = 1026
#PropertyType_UInt16Array = 1027
#PropertyType_Int32Array = 1028
#PropertyType_UInt32Array = 1029
#PropertyType_Int64Array = 1030
#PropertyType_UInt64Array = 1031
#PropertyType_SingleArray = 1032
#PropertyType_DoubleArray = 1033
#PropertyType_Char16Array = 1034
#PropertyType_BooleanArray = 1035
#PropertyType_StringArray = 1036
#PropertyType_InspectableArray = 1037
#PropertyType_DateTimeArray = 1038
#PropertyType_TimeSpanArray = 1039
#PropertyType_GuidArray = 1040
#PropertyType_PointArray = 1041
#PropertyType_SizeArray = 1042
#PropertyType_RectArray = 1043
#PropertyType_OtherTypeArray = 1044
;- Interfaces.
;{
;winrt\inspectable.h
Interface IInspectable Extends IUnknown
GetIids(*iidCount, *iids)
GetRuntimeClassName(*className)
GetTrustLevel(*trustLevel)
EndInterface
;winrt\Windows.Data.Xml.Dom.h
Interface __x_ABI_CWindows_CData_CXml_CDom_CIXmlDocument Extends IInspectable
get_Doctype(*value)
get_Implementation(*value)
get_DocumentElement(*value)
CreateElement(tagName, *newElement)
CreateDocumentFragment(*newDocumentFragment)
CreateTextNode(hStringData, *newTextNode)
CreateComment(hStringData, *newComment)
CreateProcessingInstruction(target, hStringData, *newProcessingInstruction)
CreateAttribute(name, *newAttribute)
CreateEntityReference(name, *newEntityReference)
GetElementsByTagName(tagName, *elements)
CreateCDataSection(hStringData, *newCDataSection)
get_DocumentUri(*value)
CreateAttributeNS(*namespaceUri, qualifiedName, *newAttribute)
CreateElementNS(*namespaceUri, qualifiedName, *newElement)
GetElementById(elementId, *element)
ImportNode(*node, deep, *newNode)
EndInterface
Interface __x_ABI_CWindows_CData_CXml_CDom_CIXmlElement Extends IInspectable
get_TagName(*value)
GetAttribute(attributeName, *attributeValue)
SetAttribute(attributeName, attributeValue)
RemoveAttribute(attributeName)
GetAttributeNode(attributeName, *attributeNode)
SetAttributeNode(*newAttribute, *previousAttribute)
RemoveAttributeNode(*attributeNode, *removedAttribute)
GetElementsByTagName(tagName, *elements)
SetAttributeNS(*namespaceUri, qualifiedName, value)
GetAttributeNS(*namespaceUri, localName, *value)
RemoveAttributeNS(*namespaceUri, localName)
SetAttributeNodeNS(*newAttribute, *previousAttribute)
GetAttributeNodeNS(*namespaceUri, localName, *previousAttribute)
EndInterface
Interface __x_ABI_CWindows_CData_CXml_CDom_CIXmlNodeList Extends IInspectable
get_Length(*value)
Item(index, *node)
EndInterface
Interface __x_ABI_CWindows_CData_CXml_CDom_CIXmlNode Extends IInspectable
get_NodeValue(*value)
put_NodeValue(*value)
get_NodeType(*value)
get_NodeName(*value)
get_ParentNode(*value)
get_ChildNodes(*value)
get_FirstChild(*value)
get_LastChild(*value)
get_PreviousSibling(*value)
get_NextSibling(*value)
get_Attributes(*value)
HasChildNodes(*value)
get_OwnerDocument(*value)
InsertBefore(*newChild, *referenceChild, *insertedChild)
ReplaceChild(*newChild, *referenceChild, *previousChild)
RemoveChild(*childNode, *removedChild)
AppendChild(*newChild, *appendedChild)
CloneNode(deep, *newNode)
get_NamespaceUri(*value)
get_LocalName(*value)
get_Prefix(*value)
Normalize()
put_Prefix(*value)
EndInterface
Interface __x_ABI_CWindows_CData_CXml_CDom_CIXmlDocumentIO Extends IInspectable
LoadXML(xml)
LoadXmlWithSettings(xml, *loadSettings)
SaveToFileAsync(*file, *asyncInfo)
EndInterface
Macro __x_ABI_CWindows_CFoundation_CCollections_CIPropertySet
IInspectable
EndMacro
;winrt\windows.foundation.h
Interface __FIIterable_1___FIKeyValuePair_2_HSTRING_IInspectable Extends IInspectable
First(*result)
EndInterface
Interface __FIIterator_1___FIKeyValuePair_2_HSTRING_IInspectable Extends IInspectable
get_Current(*result)
get_HasCurrent(*result)
MoveNext(*result)
GetMany(itemsLength, *items, *result)
EndInterface
Interface __FIKeyValuePair_2_HSTRING_IInspectable Extends IInspectable
get_Key(*result)
get_Value(*result)
EndInterface
Interface __x_ABI_CWindows_CFoundation_CIPropertyValue Extends IInspectable
get_Type(*value)
get_IsNumericScalar(*value)
GetUInt8(*value)
GetInt16(*value)
GetUInt16(*value)
GetInt32(*value)
GetUInt32(*value)
GetInt64(*value)
GetUInt64(*value)
GetSingle(*value)
GetDouble(*value)
GetChar16(*value)
GetBoolean(*value)
GetString(*value)
GetGuid(*value)
GetDateTime(*value)
GetTimeSpan(*value)
GetPoint(*value)
GetSize(*value)
GetRect(*value)
GetUInt8Array(*valueLength, *value)
GetInt16Array(*valueLength, *value)
GetUInt16Array(*valueLength, *value)
GetInt32Array(*valueLength, *value)
GetUInt32Array(*valueLength, *value)
GetInt64Array(*valueLength, *value)
GetUInt64Array(*valueLength, *value)
GetSingleArray(*valueLength, *value)
GetDoubleArray(*valueLength, *value)
GetChar16Array(*valueLength, *value)
GetBooleanArray(*valueLength, *value)
GetStringArray(*valueLength, *value)
GetInspectableArray(*valueLength, *value)
GetGuidArray(*valueLength, *value)
GetDateTimeArray(*valueLength, *value)
GetTimeSpanArray(*valueLength, *value)
GetPointArray(*valueLength, *value)
GetSizeArray(*valueLength, *value)
GetRectArray(*valueLength, *value)
EndInterface
;winrt\windows.ui.notifications.h
Interface __x_ABI_CWindows_CUI_CNotifications_CIToastNotificationManagerStatics Extends IInspectable
CreateToastNotifier(*result)
CreateToastNotifierWithId(applicationId, *result)
GetTemplateContent(type, *result)
EndInterface
Interface __x_ABI_CWindows_CUI_CNotifications_CIToastNotifier Extends IInspectable
Show(*notification)
Hide(*notification)
get_Setting(*value)
AddToSchedule(*scheduledToast)
RemoveFromSchedule(*scheduledToast)
GetScheduledToastNotifications(*result)
EndInterface
Interface __x_ABI_CWindows_CUI_CNotifications_CIToastNotificationFactory Extends IInspectable
CreateToastNotification(*content, *value)
EndInterface
Interface __x_ABI_CWindows_CUI_CNotifications_CIToastNotification Extends IInspectable
get_Content(*value)
put_ExpirationTime(*value)
get_ExpirationTime(*value)
add_Dismissed(*handler, *token)
remove_Dismissed(token.q)
add_Activated(*handler, *token)
remove_Activated(token.q)
add_Failed(*handler, *token)
remove_Failed(token.q)
EndInterface
; Interface __FITypedEventHandler_2_Windows__CUI__CNotifications__CToastNotification_IInspectable Extends IUnknown
; Invoke(*sender, *args)
; EndInterface
; Interface __FITypedEventHandler_2_Windows__CUI__CNotifications__CToastNotification_Windows__CUI__CNotifications__CToastDismissedEventArgs Extends IUnknown
; Invoke(*sender, *args)
; EndInterface
; Interface __FITypedEventHandler_2_Windows__CUI__CNotifications__CToastNotification_Windows__CUI__CNotifications__CToastFailedEventArgs Extends IUnknown
; Invoke(*sender, *args)
; EndInterface
Interface ITypedEventHandler_2_ToastEventArgs Extends IUnknown
Invoke(*sender, *args)
EndInterface
;um\NotificationActivationCallback.h
Interface INotificationActivationCallback Extends IUnknown
Activate(*appUserModelId, *invokedArgs, *data, count)
EndInterface
;um\propsys.h
Interface IPropertyStore Extends IUnknown
GetCount(*cProps)
GetAt(iProp, *pkey)
GetValue(key, *pv)
SetValue(key, propvar)
Commit()
EndInterface
;um\objidl.h
Interface IPersistFileW Extends IUnknown
GetClassID(*pClassID)
IsDirty()
Load(pszFileName.s, dwMode)
Save(pszFileName.s, fRemember)
SaveCompleted(pszFileName.s)
GetCurFile(*ppszFileName)
EndInterface
;um\ShObjIdl_core.h
Interface IShellLink Extends IUnknown ;IShellLinkW
GetPath(*pszFile, cch, *pfd, fFlags)
GetIDList(*ppidl)
SetIDList(pidl)
GetDescription(*pszName, cch)
SetDescription(pszName.s)
GetWorkingDirectory(*pszDir, cch)
SetWorkingDirectory(pszDir.s)
GetArguments(*pszArgs, cch)
SetArguments(pszArgs.s)
GetHotkey(*pwHotkey)
SetHotkey(wHotkey)
GetShowCmd(*piShowCmd)
SetShowCmd(iShowCmd)
GetIconLocation(*pszIconPath, cch, *piIcon)
SetIconLocation(pszIconPath.s, iIcon)
SetRelativePath(pszPathRel.s, dwReserved)
Resolve(hwnd, fFlags)
SetPath(pszFile.s)
EndInterface
;winrt\windows.ui.notifications.h
Interface __x_ABI_CWindows_CUI_CNotifications_CIToastActivatedEventArgs2 Extends IInspectable
get_UserInput(*value)
EndInterface
;winrt\windows.ui.notifications.h
Interface __x_ABI_CWindows_CUI_CNotifications_CIToastActivatedEventArgs Extends IInspectable
get_Arguments(*value)
EndInterface
Interface __x_ABI_CWindows_CUI_CNotifications_CIToastDismissedEventArgs Extends IInspectable
get_Reason(*value)
EndInterface
Interface __x_ABI_CWindows_CUI_CNotifications_CIToastFailedEventArgs Extends IInspectable
get_ErrorCode(*value)
EndInterface
;}
;- Structures.
; https://www.purebasic.fr/english/viewtopic.php?p=489813&#p489813
Structure PROPVARIANT_CLIPDATA
cbSize.l
ulClipFmt.l
*pClipData.BYTE
EndStructure
Structure PROPVARIANT_BSTRBLOB
cbSize.l
*pData.BYTE
EndStructure
Structure PROPVARIANT_BLOB
cbSize.l
*pBlobData.BYTE
EndStructure
Structure PROPVARIANT_VERSIONEDSTREAM
guidVersion.GUID
*pStream.IStream
EndStructure
Structure PROPVARIANT_CAC
cElems.l
*pElems.BYTE
EndStructure
Structure PROPVARIANT_CAUB
cElems.l
*pElems.BYTE
EndStructure
Structure PROPVARIANT_CAI
cElems.l
*pElems.WORD
EndStructure
Structure PROPVARIANT_CAUI
cElems.l
*pElems.WORD
EndStructure
Structure PROPVARIANT_CAL
cElems.l
*pElems.LONG
EndStructure
Structure PROPVARIANT_CAUL
cElems.l
*pElems.LONG
EndStructure
Structure PROPVARIANT_CAFLT
cElems.l
*pElems.FLOAT
EndStructure
Structure PROPVARIANT_CADBL
cElems.l
*pElems.DOUBLE
EndStructure
Structure PROPVARIANT_CACY
cElems.l
*pElems.QUAD
EndStructure
Structure PROPVARIANT_CADATE
cElems.l
*pElems.DOUBLE
EndStructure
Structure PROPVARIANT_CABSTR
cElems.l
*pElems.INTEGER
EndStructure
Structure PROPVARIANT_CABSTRBLOB
cElems.l
*pElems.PROPVARIANT_BSTRBLOB
EndStructure
Structure PROPVARIANT_CABOOL
cElems.l
*pElems.WORD
EndStructure
Structure PROPVARIANT_CASCODE
cElems.l
*pElems.LONG
EndStructure
Structure PROPVARIANT_CAPROPVARIANT
cElems.l
*pElems.PROPVARIANT
EndStructure
Structure PROPVARIANT_CAH
cElems.l
*pElems.QUAD
EndStructure
Structure PROPVARIANT_CAUH
cElems.l
*pElems.QUAD
EndStructure
Structure PROPVARIANT_CALPSTR
cElems.l
*pElems.INTEGER
EndStructure
Structure PROPVARIANT_CALPWSTR
cElems.l
*pElems.INTEGER
EndStructure
Structure PROPVARIANT_CAFILETIME
cElems.l
*pElems.FILETIME
EndStructure
Structure PROPVARIANT_CACLIPDATA
cElems.l
*pElems.PROPVARIANT_CLIPDATA
EndStructure
Structure PROPVARIANT_CACLSID
cElems.l
*pElems.CLSID
EndStructure
; https://docs.microsoft.com/en-us/windows/win32/api/propidl/ns-propidl-propvariant
Structure PROPVARIANT Align #PB_Structure_AlignC ;x64 24 bytes // x86 16 bytes.
vt.w
wReserved1.w
wReserved2.w
wReserved3.w
StructureUnion
cVal.b
bVal.b
iVal.w
uiVal.w
lVal.l
ulVal.l
intVal.l
uintVal.l
hVal.q
uhVal.q
fltVal.f
dblVal.d
boolVal.w
scode.l
cyVal.q
date.d
filetime.FILETIME
*puuid.CLSID
*pclipdata.PROPVARIANT_CLIPDATA
bstrVal.i
bstrblobVal.PROPVARIANT_BSTRBLOB
blob.PROPVARIANT_BLOB
*pszVal
*pwszVal
*punkVal.IUnknown
*pdispVal.IDispatch
*pStream.IStream
*pStorage.IStorage
*pVersionedStream.PROPVARIANT_VERSIONEDSTREAM
*parray.SAFEARRAY
cac.PROPVARIANT_CAC
caub.PROPVARIANT_CAUB
cai.PROPVARIANT_CAI
caui.PROPVARIANT_CAUI
cal.PROPVARIANT_CAL
caul.PROPVARIANT_CAUL
cah.PROPVARIANT_CAH
cauh.PROPVARIANT_CAUH
caflt.PROPVARIANT_CAFLT
cadbl.PROPVARIANT_CADBL
cabool.PROPVARIANT_CABOOL
cascode.PROPVARIANT_CASCODE
cacy.PROPVARIANT_CACY
cadate.PROPVARIANT_CADATE
cafiletime.PROPVARIANT_CAFILETIME
cauuid.PROPVARIANT_CACLSID
caclipdata.PROPVARIANT_CACLIPDATA
cabstr.PROPVARIANT_CABSTR
cabstrblob.PROPVARIANT_CABSTRBLOB
calpstr.PROPVARIANT_CALPSTR
calpwstr.PROPVARIANT_CALPWSTR
capropvar.PROPVARIANT_CAPROPVARIANT
*pcVal.BYTE
*pbVal.BYTE
*piVal.WORD
*puiVal.WORD
*plVal.LONG
*pulVal.LONG
*pintVal.LONG
*puintVal.LONG
*pfltVal.FLOAT
*pdblVal.DOUBLE
*pboolVal.WORD
*pdecVal.VARIANT_DECIMAL
*pscode.LONG
*pcyVal.QUAD
*pdate.DOUBLE
*pbstrVal.INTEGER
*ppunkVal.INTEGER
*ppdispVal.INTEGER
*pparray.INTEGER
*pvarVal.PROPVARIANT
EndStructureUnion
EndStructure
;winrt\hstring.h
Structure HSTRING
unused.i
EndStructure
Structure HSTRING_HEADER
StructureUnion
*Reserved1
CompilerIf #PB_Compiler_Processor = #PB_Processor_x64
Reserved2.c[24]
CompilerElse
Reserved2.c[20]
CompilerEndIf
EndStructureUnion
EndStructure
;winrt\EventToken.h
Structure EventRegistrationToken
value.q
EndStructure
;um\NotificationActivationCallback.h
Structure NOTIFICATION_USER_INPUT_DATA
*pKey
*pValue
EndStructure
;shared\wtypes.h
Structure PROPERTYKEY
fmtid.GUID
pid.l
EndStructure
Structure STRUC_IUnknownBase
*pVtbl
lRefCount.l
lDismissCount.l
*pActivatedHandler.STRUC_IUnknownBase
*pDismissedHandler.STRUC_IUnknownBase
*pFailedHandler.STRUC_IUnknownBase
hEventExitThread.i
EndStructure
Structure STRUC_IUnknownVtbl Extends STRUC_IUnknownBase
*pQueryInterface
*pAddRef
*pRelease
EndStructure
Structure STRUC_IClassFactoryVtbl Extends STRUC_IUnknownVtbl
*pCreateInstance
*pLockServer
EndStructure
Structure STRUC_INotificationActivationCallbackVtbl Extends STRUC_IUnknownVtbl
*pActivate
EndStructure
Structure STRUC_ToastEventHandler Extends STRUC_IUnknownVtbl
*pInvoke
EndStructure
;- Global variables.
Global MutexStringSync
Global hEventAllThreadExit
Global LibComBase
Global *NotificationActivationCallback.STRUC_INotificationActivationCallbackVtbl
Global *ClassFactory.STRUC_IClassFactoryVtbl
;- Prototypes.
Prototype ptRoInitialize(initType)
Global RoInitialize.ptRoInitialize
Prototype ptRoUninitialize()
Global RoUninitialize.ptRoUninitialize
Prototype ptRoGetActivationFactory(activatableClassId, iid, *factory)
Global RoGetActivationFactory.ptRoGetActivationFactory
Prototype ptWindowsCreateStringReference(sourceString.s, length.l, *hstringHeader, *string)
Global WindowsCreateStringReference.ptWindowsCreateStringReference
Prototype ptRoActivateInstance(activatableClassId, *instance)
Global RoActivateInstance.ptRoActivateInstance
Prototype ptWindowsGetStringRawBuffer(string, *length)
Global WindowsGetStringRawBuffer.ptWindowsGetStringRawBuffer
Prototype ptWindowsDeleteString(string)
Global WindowsDeleteString.ptWindowsDeleteString
Procedure InitLibraries()
LibComBase = OpenLibrary(#PB_Any, "combase.dll")
If LibComBase = 0 : ProcedureReturn 0 : EndIf
RoInitialize = GetFunction(LibComBase, "RoInitialize")
RoUninitialize = GetFunction(LibComBase, "RoUninitialize")
WindowsCreateStringReference = GetFunction(LibComBase, "WindowsCreateStringReference")
RoActivateInstance = GetFunction(LibComBase, "RoActivateInstance")
RoGetActivationFactory = GetFunction(LibComBase, "RoGetActivationFactory")
WindowsGetStringRawBuffer = GetFunction(LibComBase, "WindowsGetStringRawBuffer")
WindowsDeleteString = GetFunction(LibComBase, "WindowsDeleteString")
If RoInitialize = 0 Or
RoUninitialize = 0 Or
WindowsCreateStringReference = 0 Or
RoActivateInstance = 0 Or
RoGetActivationFactory = 0 Or
WindowsGetStringRawBuffer = 0 Or
WindowsDeleteString = 0
ProcedureReturn 0
EndIf
ProcedureReturn 1
EndProcedure
Procedure CloseLibraries()
If LibComBase : CloseLibrary(LibComBase) : EndIf
EndProcedure
Procedure.s GetStringFromHString(HString)
Protected Result.s, *buffer, iLen
If HString
*buffer = WindowsGetStringRawBuffer(HString, @iLen)
If *buffer
Result = PeekS(*buffer, iLen)
EndIf
WindowsDeleteString(HString)
EndIf
ProcedureReturn Result
EndProcedure
Procedure.l IUnknown_AddRef(*this.STRUC_IUnknownBase)
*this\lRefCount + 1
ProcedureReturn *this\lRefCount
EndProcedure
Procedure.l IUnknown_Release(*this.STRUC_IUnknownBase)
*this\lRefCount - 1
;No need to call FreeMemory.
ProcedureReturn *this\lRefCount
EndProcedure
Procedure.l INotificationActivationCallback_QueryInterface(*this.STRUC_IUnknownBase, *riid.IID, *ppvObject.Integer)
If *ppvObject And *riid
If CompareMemory(*riid, ?IID_IUnknown, SizeOf(IID)) Or CompareMemory(*riid, ?IID_INotificationActivationCallback, SizeOf(IID))
*this\lRefCount + 1
*ppvObject\i = *this
Else
*ppvObject\i = 0
ProcedureReturn #E_NOINTERFACE
EndIf
Else
ProcedureReturn #E_POINTER
EndIf
ProcedureReturn #S_OK
EndProcedure
Procedure.l INotificationActivationCallback_Activate(*this, *appUserModelId, *invokedArgs, *data.NOTIFICATION_USER_INPUT_DATA, Count)
Protected i
Protected sAppUserModelId.s, sInvokedArgs.s, sKey.s, sValue.s
mDebugOutput("----------------------------------------------------------")
mDebugOutput("*** NotificationActivationCallback")
If *appUserModelId
LockMutex(MutexStringSync)
sAppUserModelId = PeekS(*appUserModelId)
UnlockMutex(MutexStringSync)
mDebugOutput("AppUserModelId: " + sAppUserModelId)
EndIf
If *invokedArgs
LockMutex(MutexStringSync)
sInvokedArgs = PeekS(*invokedArgs)
UnlockMutex(MutexStringSync)
mDebugOutput("InvokedArgs: " + sInvokedArgs)
EndIf
mDebugOutput("Data count: " + Str(Count))
If *data
For i = 0 To Count - 1
LockMutex(MutexStringSync)
If *data\pKey
sKey = PeekS(*data\pKey)
EndIf
If *data\pValue
sValue = PeekS(*data\pValue)
EndIf
UnlockMutex(MutexStringSync)
mDebugOutput("Data: Key= " + sKey + " // Value= " + sValue)
*data + SizeOf(NOTIFICATION_USER_INPUT_DATA)
Next
EndIf
mDebugOutput("----------------------------------------------------------")
ProcedureReturn #S_OK
EndProcedure
Procedure.l IClassFactory_QueryInterface(*this.STRUC_IUnknownBase, *riid.IID, *ppvObject.Integer)
If *riid And *ppvObject
If CompareMemory(*riid, ?IID_IUnknown, SizeOf(IID)) Or CompareMemory(*riid, ?IID_IClassFactory, SizeOf(IID))
*this\lRefCount + 1
*ppvObject\i = *this
ElseIf CompareMemory(*riid, ?IID_INotificationActivationCallback, SizeOf(IID))
*NotificationActivationCallback\lRefCount + 1
*ppvObject\i = *NotificationActivationCallback
Else
*ppvObject\i = 0
ProcedureReturn #E_NOINTERFACE
EndIf
Else
ProcedureReturn #E_POINTER
EndIf
ProcedureReturn #S_OK
EndProcedure
Procedure.l IClassFactory_CreateInstance(*this, *pUnkOuter.IUnknown, *riid.IID, *ppvObject.Integer)
Protected ClassFactory.IClassFactory = *ClassFactory
;mDebugOutput("IClassFactory_CreateInstance")
If *riid = 0 Or *ppvObject = 0
ProcedureReturn #E_INVALIDARG
EndIf
If *pUnkOuter
*ppvObject\i = 0
ProcedureReturn #CLASS_E_NOAGGREGATION
EndIf
ProcedureReturn ClassFactory\QueryInterface(*riid, *ppvObject)
EndProcedure
Procedure.l IClassFactory_LockServer(*this, fLock)
;mDebugOutput("IClassFactory_LockServer")
ProcedureReturn #E_UNEXPECTED
EndProcedure
Procedure.l ToastEventHandler_QueryInterface(*this.STRUC_IUnknownBase, *riid.IID, *ppvObject.Integer)
If *ppvObject And *riid
If CompareMemory(*riid, ?IID_IUnknown, SizeOf(IID))
*this\lRefCount + 1
*ppvObject\i = *this
ElseIf CompareMemory(*riid, ?IID_DesktopToastActivatedEventHandler, SizeOf(IID))
*this\pActivatedHandler\lRefCount + 1
*ppvObject\i = *this\pActivatedHandler
ElseIf CompareMemory(*riid, ?IID_DesktopToastDismissedEventHandler, SizeOf(IID))
*this\pDismissedHandler\lRefCount + 1
*ppvObject\i = *this\pDismissedHandler
ElseIf CompareMemory(*riid, ?IID_DesktopToastFailedEventHandler, SizeOf(IID))
*this\pFailedHandler\lRefCount + 1
*ppvObject\i = *this\pFailedHandler
Else
*ppvObject\i = 0
ProcedureReturn #E_NOINTERFACE
EndIf
Else
ProcedureReturn #E_POINTER
EndIf
ProcedureReturn #S_OK
EndProcedure
Procedure.l ActivatedEventHandler_Invoke(*this.STRUC_IUnknownBase, *sender.__x_ABI_CWindows_CUI_CNotifications_CIToastNotification, *args.__x_ABI_CWindows_CUI_CNotifications_CIToastActivatedEventArgs)
Protected r, hstring, Type
Protected *args2.__x_ABI_CWindows_CUI_CNotifications_CIToastActivatedEventArgs2
Protected *ui.IInspectable
Protected *iterable.__FIIterable_1___FIKeyValuePair_2_HSTRING_IInspectable
Protected *iterator.__FIIterator_1___FIKeyValuePair_2_HSTRING_IInspectable
Protected *KeyValuePair.__FIKeyValuePair_2_HSTRING_IInspectable
Protected *value.IInspectable
Protected *pv.__x_ABI_CWindows_CFoundation_CIPropertyValue
Protected sArguments.s, sKey.s, sValue.s
If *args = 0 : ProcedureReturn #E_POINTER : EndIf
mDebugOutput("----------------------------------------------------------")
mDebugOutput("*** Toast notification event: Activated")
If *args\get_Arguments(@hstring) = #S_OK
LockMutex(MutexStringSync)
sArguments = GetStringFromHString(hstring)
UnlockMutex(MutexStringSync)
mDebugOutput("Arguments: " + sArguments)
EndIf
r = *args\QueryInterface(?IID_IToastActivatedEventArgs2, @*args2)
If r <> #S_OK Or *args2 = 0 : Goto _Proc_Exit : EndIf
r = *args2\get_UserInput(@*ui)
If r <> #S_OK Or *ui = 0 : Goto _Proc_Exit : EndIf
r = *ui\QueryInterface(?IID___FIIterable_1___FIKeyValuePair_2_HSTRING_IInspectable, @*iterable)
If r <> #S_OK Or *iterable = 0 : Goto _Proc_Exit : EndIf
r = *iterable\First(@*iterator)
If r <> #S_OK Or *iterator = 0 : Goto _Proc_Exit : EndIf
r = *iterator\get_Current(@*KeyValuePair)
If r <> #S_OK Or *KeyValuePair = 0 : Goto _Proc_Exit : EndIf
If *KeyValuePair\get_Key(@hstring) = 0
LockMutex(MutexStringSync)
sKey = GetStringFromHString(hstring)
UnlockMutex(MutexStringSync)
mDebugOutput("Key: " + sKey)
EndIf
r = *KeyValuePair\get_Value(@*value)
If r <> #S_OK Or *value = 0 : Goto _Proc_Exit : EndIf
r = *value\QueryInterface(?IID_IPropertyValue, @*pv)
If r <> #S_OK Or *pv = 0 : Goto _Proc_Exit : EndIf
r = *pv\get_Type(@Type)
If r <> #S_OK : Goto _Proc_Exit : EndIf
If Type = #PropertyType_String
If *pv\GetString(@hstring) = #S_OK
LockMutex(MutexStringSync)
sValue = GetStringFromHString(hstring)
UnlockMutex(MutexStringSync)
mDebugOutput("Value: " + sValue)
EndIf
EndIf
_Proc_Exit:
If *pv : *pv\Release() : EndIf
If *value : *value\Release() : EndIf
If *KeyValuePair : *KeyValuePair\Release() : EndIf
If *iterator : *iterator\Release() : EndIf
If *iterable : *iterable\Release() : EndIf
If *ui : *ui\Release() : EndIf
If *args2 : *args2\Release() : EndIf
mDebugOutput("----------------------------------------------------------")
If *this\hEventExitThread
SetEvent_(*this\hEventExitThread)
EndIf
ProcedureReturn #S_OK
EndProcedure
Procedure.l DismissedEventHandler_Invoke(*this.STRUC_IUnknownBase, *sender.__x_ABI_CWindows_CUI_CNotifications_CIToastNotification, *args.__x_ABI_CWindows_CUI_CNotifications_CIToastDismissedEventArgs)
Protected ReasonCode
If *args = 0 : ProcedureReturn #E_POINTER : EndIf
mDebugOutput("----------------------------------------------------------")
mDebugOutput("*** Toast notification event: Dismissed")
If *args\get_Reason(@ReasonCode) = #S_OK
Select ReasonCode
Case #ToastDismissalReason_UserCanceled
mDebugOutput("Reason: UserCanceled. The user dismissed the toast.")
Case #ToastDismissalReason_ApplicationHidden
mDebugOutput("Reason: ApplicationHidden. The application hid the toast using ToastNotifier\Hide().")
Case #ToastDismissalReason_TimedOut
mDebugOutput("Reason: TimedOut. The toast has expired.")
Default
mDebugOutput("Unknown Reason code: " + Str(ReasonCode))
EndSelect
EndIf
mDebugOutput("----------------------------------------------------------")
If *this\lDismissCount > 0
If *this\hEventExitThread
SetEvent_(*this\hEventExitThread)
EndIf
Else
*this\lDismissCount + 1
EndIf
ProcedureReturn #S_OK
EndProcedure
Procedure.l FailedEventHandler_Invoke(*this.STRUC_IUnknownBase, *sender.__x_ABI_CWindows_CUI_CNotifications_CIToastNotification, *args.__x_ABI_CWindows_CUI_CNotifications_CIToastFailedEventArgs)
Protected Result.l
If *args = 0 : ProcedureReturn #E_POINTER : EndIf
mDebugOutput("----------------------------------------------------------")
mDebugOutput("*** Toast notification event: Failed")
If *args\get_ErrorCode(@Result) = #S_OK
mDebugOutput("HRESULT code: " + Hex(Result))
EndIf
mDebugOutput("----------------------------------------------------------")
If *this\hEventExitThread
SetEvent_(*this\hEventExitThread)
EndIf
ProcedureReturn #S_OK
EndProcedure
Procedure InitInterfaces()
*NotificationActivationCallback = AllocateMemory(SizeOf(STRUC_INotificationActivationCallbackVtbl))
If *NotificationActivationCallback = 0 : ProcedureReturn 0 : EndIf
*ClassFactory = AllocateMemory(SizeOf(STRUC_IClassFactoryVtbl))
If *ClassFactory = 0 : ProcedureReturn 0 : EndIf
With *ClassFactory
\pVtbl = *ClassFactory + OffsetOf(STRUC_IClassFactoryVtbl\pQueryInterface)
\pQueryInterface = @IClassFactory_QueryInterface()
\pAddRef = @IUnknown_AddRef()
\pRelease = @IUnknown_Release()
\pCreateInstance = @IClassFactory_CreateInstance()
\pLockServer = @IClassFactory_LockServer()
EndWith
With *NotificationActivationCallback
\pVtbl = *NotificationActivationCallback + OffsetOf(STRUC_INotificationActivationCallbackVtbl\pQueryInterface)
\pQueryInterface = @INotificationActivationCallback_QueryInterface()
\pAddRef = @IUnknown_AddRef()
\pRelease = @IUnknown_Release()
\pActivate = @INotificationActivationCallback_Activate()
EndWith
ProcedureReturn 1
EndProcedure
Procedure InitPropVariantFromString(String.s, *ppropvar.PROPVARIANT)
Protected ByteCount, Result
If *ppropvar = 0 : ProcedureReturn #E_INVALIDARG : EndIf
If String = ""
Result = #E_INVALIDARG
EndIf
ByteCount = StringByteLength(String) + SizeOf(Character)
*ppropvar\pwszVal = CoTaskMemAlloc_(ByteCount)
If *ppropvar\pwszVal
CopyMemory(@String, *ppropvar\pwszVal, ByteCount)
*ppropvar\vt = #VT_LPWSTR
Result = #S_OK
Else
Result = #E_OUTOFMEMORY
EndIf
If Result <> #S_OK
FillMemory(*ppropvar, SizeOf(PROPVARIANT), 0)
EndIf
ProcedureReturn Result
EndProcedure
Procedure InstallShortcut(sShortcutFile.s)
Protected sExePath.s = #DOUBLEQUOTE$ + ProgramFilename() + #DOUBLEQUOTE$
Protected *ShellLink.IShellLink
Protected *PropertyStore.IPropertyStore
Protected *PersistFile.IPersistFileW
Protected AppIdPropVar.PROPVARIANT
Protected AppCLSID.CLSID, Result
If sShortcutFile = "" : ProcedureReturn #E_INVALIDARG : EndIf
Result = CoCreateInstance_(?CLSID_ShellLink, 0, #CLSCTX_INPROC_SERVER, ?IID_IShellLinkW, @*ShellLink)
If Result <> #S_OK : ProcedureReturn Result : EndIf
If *ShellLink = 0 : ProcedureReturn #E_NOINTERFACE : EndIf
Result = *ShellLink\SetPath(sExePath)
If Result <> #S_OK : Goto _Proc_Exit : EndIf
; *ShellLink\SetArguments(Arguments$)
; *ShellLink\SetWorkingDirectory(WorkingDirectory$)
; *ShellLink\SetDescription(Description$)
; *ShellLink\SetShowCmd(ShowCommand)
; *ShellLink\SetHotkey(HotKey)
; *ShellLink\SetIconLocation(IconFile$, IconIndex)
Result = *ShellLink\QueryInterface(?IID_IPropertyStore, @*PropertyStore)
If Result <> #S_OK : Goto _Proc_Exit : EndIf
If *PropertyStore = 0 : Result = #E_NOINTERFACE : Goto _Proc_Exit : EndIf
Result = InitPropVariantFromString(#App_ID, @AppIdPropVar)
If Result <> #S_OK : Goto _Proc_Exit : EndIf
Result = *PropertyStore\SetValue(?PKEY_AppUserModel_ID, AppIdPropVar)
If Result <> #S_OK : Goto _Proc_Exit : EndIf
If AppIdPropVar\pwszVal
AppIdPropVar\vt = 0
CoTaskMemFree_(AppIdPropVar\pwszVal)
EndIf
AppIdPropVar\vt = #VT_CLSID
CLSIDFromString_(#App_CLSID, AppCLSID)
AppIdPropVar\puuid = @AppCLSID
Result = *PropertyStore\SetValue(?PKEY_AppUserModel_ToastActivatorCLSID, AppIdPropVar)
If Result <> #S_OK : Goto _Proc_Exit : EndIf
Result = *ShellLink\QueryInterface(?IID_IPersistFileW, @*PersistFile)
If Result <> #S_OK : Goto _Proc_Exit : EndIf
If *PersistFile = 0 : Result = #E_NOINTERFACE : Goto _Proc_Exit : EndIf
Result = *PersistFile\Save(sShortcutFile, 1)
SHChangeNotify_(#SHCNE_ASSOCCHANGED, #SHCNF_IDLIST, 0, 0)
_Proc_Exit:
If *PersistFile : *PersistFile\Release() : EndIf
If *PropertyStore : *PropertyStore\Release() : EndIf
If *ShellLink : *ShellLink\Release() : EndIf
ProcedureReturn Result
EndProcedure
Procedure CreateXmlDocumentFromString(xmlString.s, *idoc.Integer)
Protected Result = #E_FAIL
Protected *doc.__x_ABI_CWindows_CData_CXml_CDom_CIXmlDocument
Protected *docIO.__x_ABI_CWindows_CData_CXml_CDom_CIXmlDocumentIO
Protected *pInspectable.IInspectable
Protected header_IXmlDocumentHString.HSTRING_HEADER, *IXmlDocumentHString.HSTRING
Protected header_XmlString.HSTRING_HEADER, *XmlString.HSTRING
Result = WindowsCreateStringReference(#RuntimeClass_Windows_Data_Xml_Dom_XmlDocument, Len(#RuntimeClass_Windows_Data_Xml_Dom_XmlDocument), @header_IXmlDocumentHString, @*IXmlDocumentHString)
If Result <> #S_OK : ProcedureReturn Result : EndIf
If *IXmlDocumentHString = 0 : ProcedureReturn #E_POINTER : EndIf
Result = RoActivateInstance(*IXmlDocumentHString, @*pInspectable)
If Result <> #S_OK : ProcedureReturn Result : EndIf
If *pInspectable = 0 : ProcedureReturn #E_NOINTERFACE : EndIf
Result = *pInspectable\QueryInterface(?IID_IXmlDocument, @*doc)
If Result <> #S_OK : Goto _Proc_Exit : EndIf
If *doc = 0 : Result = #E_NOINTERFACE : Goto _Proc_Exit : EndIf
Result = *doc\QueryInterface(?IID_IXmlDocumentIO, @*docIO)
If Result <> #S_OK : Goto _Proc_Exit : EndIf
If *docIO = 0 : Result = #E_NOINTERFACE : Goto _Proc_Exit : EndIf
Result = WindowsCreateStringReference(xmlString, Len(xmlString), @header_XmlString, @*XmlString)
If Result <> #S_OK : Goto _Proc_Exit : EndIf
If *XmlString = 0 : Result = #E_POINTER : Goto _Proc_Exit : EndIf
Result = *docIO\LoadXML(*XmlString)
_Proc_Exit:
If Result = #S_OK
*idoc\i = *doc
Else
If *doc : *doc\Release() : EndIf
EndIf
If *docIO : *docIO\Release() : EndIf
If *pInspectable : *pInspectable\Release() : EndIf
ProcedureReturn Result
EndProcedure
Procedure ShowMsg(*xml)
Protected Result, xml.s
Protected header_AppIdHString.HSTRING_HEADER, *AppIdHString.HSTRING
Protected header_ToastNotificationManagerHString.HSTRING_HEADER, *ToastNotificationManagerHString.HSTRING
Protected header_ToastNotificationHString.HSTRING_HEADER, *ToastNotificationHString.HSTRING
Protected *inputXml.__x_ABI_CWindows_CData_CXml_CDom_CIXmlDocument
Protected *toastStatics.__x_ABI_CWindows_CUI_CNotifications_CIToastNotificationManagerStatics
Protected *notifier.__x_ABI_CWindows_CUI_CNotifications_CIToastNotifier
Protected *notifFactory.__x_ABI_CWindows_CUI_CNotifications_CIToastNotificationFactory
Protected *toast.__x_ABI_CWindows_CUI_CNotifications_CIToastNotification
Protected ActivatedToken.EventRegistrationToken, DismissedToken.EventRegistrationToken, FailedToken.EventRegistrationToken
Protected *DismissedEventHandler.STRUC_ToastEventHandler
Protected *ActivatedEventHandler.STRUC_ToastEventHandler
Protected *FailedEventHandler.STRUC_ToastEventHandler
Protected Dim hEventThreadExit.i(1), hEventThreadExit
If *xml
LockMutex(MutexStringSync)
xml = PeekS(*xml)
FreeMemory(*xml)
UnlockMutex(MutexStringSync)
Else
ProcedureReturn
EndIf
If RoInitialize(#RO_INIT_MULTITHREADED) <> #S_OK : ProcedureReturn : EndIf
If WindowsCreateStringReference(#App_ID, Len(#App_ID), @header_AppIdHString, @*AppIdHString) <> #S_OK : Goto _Proc_Exit : EndIf
If *AppIdHString = 0 : Goto _Proc_Exit : EndIf
If CreateXmlDocumentFromString(xml, @*inputXml) <> #S_OK : Goto _Proc_Exit : EndIf
If *inputXml = 0 : Goto _Proc_Exit : EndIf
If WindowsCreateStringReference(#RuntimeClass_Windows_UI_Notifications_ToastNotificationManager, Len(#RuntimeClass_Windows_UI_Notifications_ToastNotificationManager),
@header_ToastNotificationManagerHString, @*ToastNotificationManagerHString) <> #S_OK : Goto _Proc_Exit : EndIf
If *ToastNotificationManagerHString = 0 : Goto _Proc_Exit : EndIf
If RoGetActivationFactory(*ToastNotificationManagerHString, ?IID_IToastNotificationManagerStatics, @*toastStatics) <> #S_OK : Goto _Proc_Exit : EndIf
If *toastStatics = 0 : Goto _Proc_Exit : EndIf
If *toastStatics\CreateToastNotifierWithId(*AppIdHString, @*notifier) <> #S_OK : Goto _Proc_Exit : EndIf
If *notifier = 0 : Goto _Proc_Exit : EndIf
If WindowsCreateStringReference(#RuntimeClass_Windows_UI_Notifications_ToastNotification, Len(#RuntimeClass_Windows_UI_Notifications_ToastNotification),
@header_ToastNotificationHString, @*ToastNotificationHString) <> #S_OK : Goto _Proc_Exit : EndIf
If *ToastNotificationHString = 0 : Goto _Proc_Exit : EndIf
If RoGetActivationFactory(*ToastNotificationHString, ?IID_IToastNotificationFactory, @*notifFactory) <> #S_OK : Goto _Proc_Exit : EndIf
If *notifFactory = 0 : Goto _Proc_Exit : EndIf
If *notifFactory\CreateToastNotification(*inputXml, @*toast) <> #S_OK : Goto _Proc_Exit : EndIf
If *toast = 0 : Goto _Proc_Exit : EndIf
*ActivatedEventHandler = AllocateMemory(SizeOf(STRUC_ToastEventHandler))
*DismissedEventHandler = AllocateMemory(SizeOf(STRUC_ToastEventHandler))
*FailedEventHandler = AllocateMemory(SizeOf(STRUC_ToastEventHandler))
If *ActivatedEventHandler = 0 Or *DismissedEventHandler = 0 Or *FailedEventHandler = 0 : Goto _Proc_Exit : EndIf
hEventThreadExit = CreateEvent_(0, 0, 0, 0)
If hEventThreadExit = 0 : Goto _Proc_Exit : EndIf
hEventThreadExit(0) = hEventAllThreadExit
hEventThreadExit(1) = hEventThreadExit
With *ActivatedEventHandler
\pVtbl = *ActivatedEventHandler + OffsetOf(STRUC_ToastEventHandler\pQueryInterface)
\pActivatedHandler = *ActivatedEventHandler
\pDismissedHandler = *DismissedEventHandler
\pFailedHandler = *FailedEventHandler
\hEventExitThread = hEventThreadExit
\pQueryInterface = @ToastEventHandler_QueryInterface()
\pAddRef = @IUnknown_AddRef()
\pRelease = @IUnknown_Release()
\pInvoke = @ActivatedEventHandler_Invoke()
EndWith
With *DismissedEventHandler
\pVtbl = *DismissedEventHandler + OffsetOf(STRUC_ToastEventHandler\pQueryInterface)
\pActivatedHandler = *ActivatedEventHandler
\pDismissedHandler = *DismissedEventHandler
\pFailedHandler = *FailedEventHandler
\hEventExitThread = hEventThreadExit
\pQueryInterface = @ToastEventHandler_QueryInterface()
\pAddRef = @IUnknown_AddRef()
\pRelease = @IUnknown_Release()
\pInvoke = @DismissedEventHandler_Invoke()
EndWith
With *FailedEventHandler
\pVtbl = *FailedEventHandler + OffsetOf(STRUC_ToastEventHandler\pQueryInterface)
\pActivatedHandler = *ActivatedEventHandler
\pDismissedHandler = *DismissedEventHandler
\pFailedHandler = *FailedEventHandler
\pQueryInterface = @ToastEventHandler_QueryInterface()
\pAddRef = @IUnknown_AddRef()
\pRelease = @IUnknown_Release()
\pInvoke = @FailedEventHandler_Invoke()
EndWith
If *toast\add_Activated(*ActivatedEventHandler, @ActivatedToken) <> #S_OK : Goto _Proc_Exit : EndIf
If *toast\add_Dismissed(*DismissedEventHandler, @DismissedToken) <> #S_OK : Goto _Proc_Exit : EndIf
If *toast\add_Failed(*FailedEventHandler, @FailedToken) <> #S_OK : Goto _Proc_Exit : EndIf
Result = *notifier\Show(*toast)
If Result = #S_OK
Result = WaitForMultipleObjects_(2, @hEventThreadExit(), 0, #INFINITE)
If Result - #WAIT_OBJECT_0 = 1
Sleep_(2000)
EndIf
EndIf
_Proc_Exit:
If *toast
If ActivatedToken\value
*toast\remove_Activated(ActivatedToken\value)
EndIf
If DismissedToken\value
*toast\remove_Dismissed(DismissedToken\value)
EndIf
If FailedToken\value
*toast\remove_Failed(FailedToken\value)
EndIf
EndIf
If *toast : *toast\Release() : EndIf
If *notifFactory : *notifFactory\Release() : EndIf
If *notifier : *notifier\Release() : EndIf
If *toastStatics : *toastStatics\Release() : EndIf
If *inputXml : *inputXml\Release() : EndIf
If *ActivatedEventHandler : FreeMemory(*ActivatedEventHandler) : EndIf
If *DismissedEventHandler : FreeMemory(*DismissedEventHandler) : EndIf
If *FailedEventHandler : FreeMemory(*FailedEventHandler) : EndIf
If hEventThreadExit : CloseHandle_(hEventThreadExit) : EndIf
RoUninitialize()
EndProcedure
Procedure CreateToastNotificationThread(xml.s, List Threads.i())
Protected *xml, Result
LockMutex(MutexStringSync)
If xml
If AddElement(Threads())
*xml = AllocateMemory(StringByteLength(xml) + SizeOf(Character))
If *xml
PokeS(*xml, xml)
Threads() = CreateThread(@ShowMsg(), *xml)
If IsThread(Threads())
Result = 1
Else
DeleteElement(Threads())
EndIf
EndIf
EndIf
EndIf
UnlockMutex(MutexStringSync)
ProcedureReturn Result
EndProcedure
Define lRegister, CLSID.CLSID, sLinkFile.s
Define xml.s, e
NewList Threads.i()
xml = ~"<toast duration='short'>" +
~" <visual>" +
~" <binding template='ToastGeneric'>" +
~" <text>Test Notification</text>" +
~" <text>blah blah blah...</text>" +
~" </binding>" +
~" </visual>" +
~" <actions>" +
~" <input id='MyMessageInput' type='text' title='Message' placeHolderContent='Enter a message' defaultInput='Toast Notification Test' />" +
~" <action activationType='foreground' arguments='QuickReply' content='Submit' />" +
~" <action activationType='foreground' arguments='Cancel' content='Cancel' />" +
~" </actions>" +
~"</toast>"
If OSVersion() < #PB_OS_Windows_10
MessageRequester("Warning", "Windows 10 or later is required.")
End
EndIf
If InitInterfaces() = 0
End
EndIf
If InitLibraries() = 0
End
EndIf
MutexStringSync = CreateMutex()
If MutexStringSync = 0
End
EndIf
hEventAllThreadExit = CreateEvent_(0, 1, 0, 0)
If hEventAllThreadExit = 0
End
EndIf
CoInitialize_(0)
sLinkFile = GetEnvironmentVariable("APPDATA")
If sLinkFile
sLinkFile + "\Microsoft\Windows\Start Menu\Programs\" + #App_Name + ".lnk"
If FileSize(sLinkFile) = -1
If InstallShortcut(sLinkFile) <> #S_OK
Goto Quit
EndIf
EndIf
EndIf
;SHChangeNotify_(#SHCNE_ASSOCCHANGED, #SHCNF_FLUSH, 0, 0)
SHChangeNotify_(#SHCNE_ALLEVENTS, #SHCNF_FLUSH, 0, 0)
SendMessageTimeout_(#HWND_BROADCAST, #WM_SETTINGCHANGE, 0, 0, #SMTO_ABORTIFHUNG, 5000, 0)
MessageRequester("", "Wait a few seconds for the setting to be reflected in the system.")
If CLSIDFromString_(#App_CLSID, @CLSID) <> #NOERROR
Goto Quit
EndIf
If CoRegisterClassObject_(CLSID, *ClassFactory, #CLSCTX_LOCAL_SERVER, #REGCLS_MULTIPLEUSE, @lRegister) <> #S_OK
Goto Quit
EndIf
If OpenWindow(0, 0, 0, 600, 650, "Toast Test", #PB_Window_SystemMenu | #PB_Window_ScreenCentered)
ButtonGadget(0, 10, 2, 200, 25, "Show message")
ButtonGadget(1, 390, 2, 200, 25, "Clear")
EditorGadget(#EditorGadget, 0, 30, 600, 620, #PB_Editor_ReadOnly)
mDebugOutput(ProgramFilename())
Repeat
e = WaitWindowEvent()
If e = #PB_Event_Gadget
Select EventGadget()
Case 0
CreateToastNotificationThread(xml, Threads())
Case 1
ClearGadgetItems(#EditorGadget)
EndSelect
EndIf
If e = #App_DebugEvent_NewDebugString And EventType() = #App_DebugEventType_Value
ShowDebugString()
EndIf
Until e = #PB_Event_CloseWindow
CloseWindow(0)
SetEvent_(hEventAllThreadExit)
ForEach Threads()
If IsThread(Threads())
WaitThread(Threads(), 5000)
EndIf
Next
EndIf
Quit:
;delete .lnk file.
If FileSize(sLinkFile) >= 0
DeleteFile(sLinkFile)
EndIf
If hEventAllThreadExit : CloseHandle_(hEventAllThreadExit) : EndIf
CloseLibraries()
If lRegister
CoRevokeClassObject_(lRegister)
EndIf
CoUninitialize_()
DataSection
CLSID_ShellLink:
;00021401-0000-0000-C000-000000000046
Data.l $00021401
Data.w $0000, $0000
Data.b $C0, $00, $00, $00, $00, $00, $00, $46
;UUIDs obtained from <windows.ui.notifications.h>
;ABI.Windows.UI.Notifications.IToastNotificationManagerStatics
;50ac103f-d235-4598-bbef-98fe4d1a3ad4
IID_IToastNotificationManagerStatics:
Data.l $50ac103f
Data.w $d235, $4598
Data.b $bb, $ef, $98, $fe, $4d, $1a, $3a, $d4
;ABI.Windows.Notifications.IToastNotificationFactory
;04124b20-82c6-4229-b109-fd9ed4662b53
IID_IToastNotificationFactory:
Data.l $04124b20
Data.w $82c6, $4229
Data.b $b1, $09, $fd, $9e, $d4, $66, $2b, $53
;UUIDs obtained from <windows.data.xml.dom.h>
;ABI.Windows.Data.Xml.Dom.IXmlDocument
;f7f3a506-1e87-42d6-bcfb-b8c809fa5494
IID_IXmlDocument:
Data.l $f7f3a506
Data.w $1e87, $42d6
Data.b $bc, $fb, $b8, $c8, $09, $fa, $54, $94
;ABI.Windows.Data.Xml.Dom.IXmlDocumentIO
;6cd0e74e-ee65-4489-9ebf-ca43e87ba637
IID_IXmlDocumentIO:
Data.l $6cd0e74e
Data.w $ee65, $4489
Data.b $9e, $bf, $ca, $43, $e8, $7b, $a6, $37
IID_INotificationActivationCallback:
;53E31837-6600-4A81-9395-75CFFE746F94
Data.l $53E31837
Data.w $6600, $4A81
Data.b $93, $95, $75, $CF, $FE, $74, $6F, $94
IID_IShellLinkW:
;000214F9-0000-0000-C000-000000000046
Data.l $000214F9
Data.w $0000, $0000
Data.b $C0, $00, $00, $00, $00, $00, $00, $46
IID_IPersistFileW:
;0000010b-0000-0000-C000-000000000046
Data.l $0000010b
Data.w $0000, $0000
Data.b $C0, $00, $00, $00, $00, $00, $00, $46
IID_IPropertyStore:
;886d8eeb-8cf2-4446-8d02-cdba1dbdcf99
Data.l $886d8eeb
Data.w $8cf2, $4446
Data.b $8d, $02, $cd, $ba, $1d, $bd, $cf, $99
IID_IUnknown:
Data.l $00000000
Data.w $0000, $0000
Data.b $C0, $00, $00, $00, $00, $00, $00, $46
IID_IToastActivatedEventArgs2:
;ab7da512-cc61-568e-81be-304ac31038fa
Data.l $ab7da512
Data.w $cc61, $568e
Data.b $81, $be, $30, $4a, $c3, $10, $38, $fa
IID_IToastActivatedEventArgs:
;E3BF92F3-C197-436F-8265-0625824F8DAC
Data.l $E3BF92F3
Data.w $C197, $436F
Data.b $82, $65, $06, $25, $82, $4F, $8D, $AC
IID_IToastFailedEventArgs:
;35176862-cfd4-44f8-ad64-f500fd896c3b
Data.l $35176862
Data.w $cfd4, $44f8
Data.b $ad, $64, $f5, $00, $fd, $89, $6c, $3b
IID_IToastDismissedEventArgs:
;3f89d935-d9cb-4538-a0f0-ffe7659938f8
Data.l $3f89d935
Data.w $d9cb, $4538
Data.b $a0, $f0, $ff, $e7, $65, $99, $38, $f8
IID___FIIterable_1___FIKeyValuePair_2_HSTRING_IInspectable:
;fe2f3d47-5d47-5499-8374-430c7cda0204
Data.l $fe2f3d47
Data.w $5d47, $5499
Data.b $83, $74, $43, $0c, $7c, $da, $02, $04
IID_IPropertyValue:
;4bd682dd-7554-40e9-9a9b-82654ede7e62
Data.l $4bd682dd
Data.w $7554, $40e9
Data.b $9a, $9b, $82, $65, $4e, $de, $7e, $62
IID_DesktopToastActivatedEventHandler:
;ab54de2d-97d9-5528-b6ad-105afe156530
Data.l $ab54de2d
Data.w $97d9, $5528
Data.b $b6, $ad, $10, $5a, $fe, $15, $65, $30
IID_DesktopToastDismissedEventHandler:
;61c2402f-0ed0-5a18-ab69-59f4aa99a368
Data.l $61c2402f
Data.w $0ed0, $5a18
Data.b $ab, $69, $59, $f4, $aa, $99, $a3, $68
IID_DesktopToastFailedEventHandler:
;95e3e803-c969-5e3a-9753-ea2ad22a9a33
Data.l $95e3e803
Data.w $c969, $5e3a
Data.b $97, $53, $ea, $2a, $d2, $2a, $9a, $33
IID_IClassFactory:
Data.l $00000001
Data.w $0000, $0000
Data.b $C0, $0, $0, $0, $0, $0, $0, $46
;PROPERTYKEY structures
;propkey.h
PKEY_AppUserModel_ID:
; { { 0x9F4C2855, 0x9F79, 0x4B39, 0xA8, 0xD0, 0xE1, 0xD4, 0x2D, 0xE1, 0xD5, 0xF3 }, 5 }
Data.l $9F4C2855
Data.w $9F79, $4B39
Data.b $A8, $D0, $E1, $D4, $2D, $E1, $D5, $F3
Data.l 5
PKEY_AppUserModel_ToastActivatorCLSID:
; { { 0x9F4C2855, 0x9F79, 0x4B39, 0xA8, 0xD0, 0xE1, 0xD4, 0x2D, 0xE1, 0xD5, 0xF3 }, 26 }
Data.l $9F4C2855
Data.w $9F79, $4B39
Data.b $A8, $D0, $E1, $D4, $2D, $E1, $D5, $F3
Data.l 26
EndDataSection