如何使用ToastGeneric在德尔福创建Toast通知

如何使用ToastGeneric在德尔福创建Toast通知

问题描述:

我使用delphi在桌面上开发。我想用ToastGeneric类型通知创建吐司通知 LToastFactory.CreateToastNotification(LXMLTemplate);如何使用ToastGeneric在德尔福创建Toast通知

另外,我使用的是XML作为 https://docs.microsoft.com/en-us/windows/uwp/controls-and-patterns/tiles-and-notifications-adaptive-interactive-toasts

我的问题是如何让德尔福接受这个XML,我还没有找到一种方法来该字符串转换成Xml_Dom_IXmlDocument类型。

我有同样的问题。

我的目标是使用toastGeneric创建一个来自Delphi的Toast通知。但是,我找不到任何通过操纵xml来实现此功能的语言示例 - 所有示例都使用不可从Delphi访问的类。

我的解决方案是创建一个标准模板,然后使用自定义模板所需的xml覆盖该标准模板中的xml。下面是一些应该给你这个想法的Delphi代码。这是一个完整的控制台应用。此代码在Delphi 10.2东京编译。早期版本可能需要进行一些调整。你会对OverwriteToastTemplateXML功能感兴趣。

我的代码是围绕在马可·坎的博客张贴在这里的最后注释的参考标准敬酒模板例如:http://blog.marcocantu.com/blog/2015-june-windows10-notifications-vcl-winrt.html

注意,在我的XML到“英雄”的形象JPG文件的参考。要使通知充分发挥作用,请确保您在c:\ notifications \ hero.jpg上有jpg,或者在xml中注释掉该行。

除了将XML字符串转换为自定义的Toast模板外,代码还将Toast模板转换回字符串,这对调试很有用 - 这是ToastTemplateToString函数。这些是我对原始示例的主要功能修改。出于我自己的理解,我也改变了示例代码的结构,以便可变范围以及每行代码与其他代码的关系也更加明显。

让我知道这是否适合你 - 我发现吐司通知是德尔福的辛苦工作!

干杯

史蒂夫

program ConsoleNotifier; 

{$APPTYPE CONSOLE} 

{$R *.res} 

uses 
    System.SysUtils, 

    // Required to create the Toast Notification 
    WinAPI.WinRT, 
    WinAPI.DataRT, 
    WinAPI.UI.Notifications, 
    WinAPI.ActiveX, 
    WinAPI.CommonTypes, 

    // Required for creating the Desktop Shell Link 
    WinAPI.PropKey, 
    WinAPI.PropSys, 
    WinAPI.ShlObj, 
    System.Win.ComObj, 
    Windows 
    ; 

function CreateDesktopShellLink(const TargetName: string): Boolean; 

    function GetStartMenuFolder: string; 
    var 
    Buffer: array [0 .. MAX_PATH - 1] of Char; 
    begin 
    Result := ''; 
    GetEnvironmentVariable(PChar('APPDATA'), Buffer, MAX_PATH - 1); 
    Result := Buffer + '\Microsoft\Windows\Start Menu\Programs\Desktop Delphi Toasts App.lnk'; 
    end; 

var 
    IObject: IUnknown; 
    ISLink: IShellLink; 
    IPFile: IPersistFile; 
    LinkName: string; 

    LStore: WinAPI.PropSys.IPropertyStore; 
    LValue: TPropVariant; 
begin 
    Result := False; 

    IObject := CreateComObject(CLSID_ShellLink); 
    ISLink := IObject as IShellLink; 
    IPFile := IObject as IPersistFile; 
    LStore := IObject as WinAPI.PropSys.IPropertyStore; 

    with ISLink 
    do begin 
    SetPath(PChar(ParamStr(0))); 
    end; 
    ISLink.SetArguments(PChar('')); 

    if Succeeded(InitPropVariantFromStringAsVector(PWideChar('Delphi.DesktopNotification.Sample'), LValue)) 
    then begin 
    if Succeeded(LStore.SetValue(PKEY_AppUserModel_ID, LValue)) 
    then LStore.Commit; 
    end; 

    LinkName := GetStartMenuFolder; 

    if not FileExists(LinkName) 
    then 
    if IPFile.Save(PWideChar(LinkName), True) = S_OK 
    then Result := True; 
end; 

function HStr(Value:String): HString; 
begin 
    if NOT Succeeded(
    WindowsCreateString(PWideChar(Value), Length(Value), Result) 
) 
    then raise Exception.CreateFmt('Unable to create HString for %s', [ Value ]); 
end; 

function ToastTemplateToString(Const Template:Xml_Dom_IXmlDocument): String; 

    function HStringToString(Src: HSTRING): String; 
    var 
    c: Cardinal; 
    begin 
    c := WindowsGetStringLen(Src); 
    Result := WindowsGetStringRawBuffer(Src, @c); 
    end; 

begin 
    Result := HStringToString(
    (Template.DocumentElement as Xml_Dom_IXmlNodeSerializer).GetXml 
); 
end; 

function GetFactory(Const Name:String; Const GUID:String): IInspectable; 
var 
    FactoryHString : HString; 
    FactoryGUID : TGUID; 
begin 
    FactoryHString := HStr(Name); 
    try 
    FactoryGUID := TGUID.Create(GUID); 

    if NOT Succeeded(
     RoGetActivationFactory(FactoryHString, FactoryGUID, Result) 
    ) 
    then raise Exception.CreateFmt('Error creating factory: %s %s', [ Name, GUID ]); 
    finally 
    WindowsDeleteString(FactoryHString); 
    end; 
end; 

procedure OverwriteToastTemplateXML(Const Template: Xml_Dom_IXmlDocument; Const XML:String); 
var 
    hXML: HSTRING; 
begin 
    hXML := HStr(XML); 
    try 
    (Template as Xml_Dom_IXmlDocumentIO).LoadXml(hXML); 
    finally 
    WindowsDeleteString(hXML); 
    end; 
end; 

procedure SteveNotification(Const AppID:String; Const XML:String); 
var 
    ToastNotificationManagerStatics : IToastNotificationManagerStatics; 
    ToastTemplate     : Xml_Dom_IXmlDocument; 
    LToastNotification    : IToastNotification; 
    ToastNotificationManagerFactory : IInspectable; 
    ToastNotificationFactory  : IInspectable; 
    hAppID       : HString; 
begin 
    ToastNotificationManagerFactory := GetFactory(sToastNotificationManager, '{50AC103F-D235-4598-BBEF-98FE4D1A3AD4}'); 
    ToastNotificationManagerStatics := IToastNotificationManagerStatics(ToastNotificationManagerFactory); 
    ToastTemplate := ToastNotificationManagerStatics.GetTemplateContent(ToastTemplateType.ToastText01); 

    OverwriteToastTemplateXML(ToastTemplate, XML); 

    WriteLn('XML: ', ToastTemplateToString(ToastTemplate)); 

    ToastNotificationFactory := GetFactory(SToastNotification, '{04124B20-82C6-4229-B109-FD9ED4662B53}'); 

    LToastNotification := IToastNotificationFactory(ToastNotificationFactory).CreateToastNotification(ToastTemplate); 

    hAppID := HStr(AppID); 
    try 
    ToastNotificationManagerStatics 
    .CreateToastNotifier(hAppID) 
    .Show(LToastNotification); 
    finally 
    WindowsDeleteString(hAppID); 
    end; 
end; 

Const 
    AppID = 'My Application ID'; 
    XML = '<toast activationType="protocol" launch="http://www.ecutek.com" >' 
     + ' <visual>' 
     + ' <binding template="ToastGeneric">' 
     + '  <text>Body Text ABC</text>' 
     + '  <text>More Text</text>' 
     + '  <image placement="hero" src="file:///c:\notifications\hero.jpg"/>' 
     + ' </binding>' 
     + ' </visual>' 
     + ' <actions>' 
     + ' <action content="Open Google" activationType="protocol" arguments="http://www.google.com" />' 
     + ' </actions>' 
     + '</toast>'; 

var 
    c : char; 
begin 
    try 
    if TOSVersion.Major < 10 
    then raise Exception.Create('Windows 10 Required'); 

    RoInitialize(RO_INIT_MULTITHREADED); 

    CreateDesktopShellLink(ParamStr(0)); 

    SteveNotification(AppID, XML); 

    // Wait for a KeyPress 
    Read(c); write(c); 
    except 
    on E: Exception do 
     Writeln(E.ClassName, ': ', E.Message); 
    end; 
end. 
+0

这看起来很有前途,但遗憾的是没有与柏林工作。单步执行代码,调用成功并且不会生成错误。我注意到控制台应用程序没有在Windows中注册为通知发送者。是否有一段代码需要这样做? – lowrider