I'm making a library for Delphi to implement Windows 11 toast notifications easier using the interfaces from Winapi.UI.Notifications.
I want to to post custom notifications to the action center using a IToastNotifier to show the notifications and to be able to to receive events for when when the notification is dismissed or activated (clicked on). Thankfully, the IToastNotification has the add_Activated(), add_Dismissed() and add_Failed() methods to register a callback for when those events are triggered.
In C#, it's rather easy to add them, like so:
public void ShowToastNotification()
{
// Construct the toast content with data bound fields
var content = new ToastContentBuilder()
.AddText("Notification title")
.GetToastContent();
// Generate the toast notification
var toast = new ToastNotification(content.GetXml());
toast.Activated += Toast_Activated;
// Show the toast notification to the user
ToastNotificationManager.CreateToastNotifier().Show(toast);
}
private void Toast_Activated(ToastNotification sender, object args)
{
ShowMessageDialog($"Toast activated!");
}
To do the same thing in Delphi, I wrote the following code snippet:
unit Unit1;
interface
uses
Winapi.Windows, Vcl.Forms, Winapi.ui.Notifications,
Winapi.CommonTypes, Winapi.Winrt, Vcl.Dialogs, Winapi.DataRT;
type
TToastActivatedHandler = class(TInterfacedObject, TypedEventHandler_2__IToastNotification__IInspectable)
procedure Invoke(sender: IToastNotification; args: IInspectable); safecall;
end;
TToastDismissHandler = class(TInterfacedObject, TypedEventHandler_2__IToastNotification__IToastDismissedEventArgs)
procedure Invoke(sender: IToastNotification; args: IToastDismissedEventArgs); safecall;
end;
TForm1 = class(TForm)
procedure FormCreate(Sender: TObject);
end;
var
Form1: TForm1;
ActivateHandle: TToastActivatedHandler;
DismissHandle: TToastDismissHandler;
implementation
{$R *.dfm}
procedure TForm1.FormCreate(Sender: TObject);
var
HStr: HSTRING;
S: string;
Instance: IInspectable;
Notifier: IToastNotifier;
begin
// Notification maanger
const xml = '<toast activationType="protocol">'+
' <visual>'+
' <binding template="ToastGeneric">'+
' <text>Hello world!</text>'+
' <text>This is a test notification.</text>'+
' <image src="C:\Windows\System32\@facial-recognition-windows-hello.gif" placement="hero" alt=""/>'+
' </binding>'+
' </visual>'+
'</toast>';
// Create XML
S := 'Windows.Data.Xml.Dom.XmlDocument';
WindowsCreateString(PChar(S), Length(S), HStr);
try
RoActivateInstance(HStr, Instance);
finally
WindowsDeleteString(HStr);
end;
// Load XML
WindowsCreateString(PChar(xml), Length(xml), HStr);
try
(Instance as Xml_Dom_IXmlDocumentIO).LoadXml( HStr );
finally
WindowsDeleteString(HStr);
end;
// Create interfaces
S := 'App.Test';
WindowsCreateString(PChar(S), Length(S), HStr);
try
Notifier := TToastNotificationManager.CreateToastNotifier(HStr);
finally
WindowsDeleteString(HStr);
end;
const Notification = TToastNotification.CreateToastNotification( Instance as Xml_Dom_IXmlDocument );
// Create activator
ActivateHandle := TToastActivatedHandler.Create;
DismissHandle := TToastDismissHandler.Create;
// Prepare
Notification.add_Activated( ActivateHandle );
Notification.add_Dismissed( DismissHandle );
// Show
Notifier.Show( Notification );
end;
{ TToastActivatedHandler2 }
procedure TToastDismissHandler.Invoke(sender: IToastNotification;
args: IToastDismissedEventArgs);
begin
ShowMessage('Toast was dismissed!');
end;
{ TToastActivatedHandler }
procedure TToastActivatedHandler.Invoke(sender: IToastNotification;
args: IInspectable);
begin
ShowMessage('Toast was activated');
end;
end.
The following notification appears:
But the Invoke() method never gets called when I click on the notification, and I'm not sure why. I also tried the add_Dismissed() one, but the same problem occurs for It as well.
I'm completely out of ideas on what to try. There must be a way to have the invoke method called, but I'm unsure on how this may be accomplished.
Note: The unit file is not needed to run the code above, I only took the snippets from It that are needed to show this example. But the full library can be found on GitHub here.
