即使在应用关闭后,有没有办法使OnReceiveLocalNotification(TNotificationCenter)正常工作?

时间:2019-01-10 14:03:51

标签: delphi notificationcenter

我的应用程序有一些任务需要在后台运行。我使用任务计划程序在需要任务时运行应用程序,并在任务完成后自行关闭。到目前为止,一切都很好。

任务可能要花一些时间才能完成,因此我在任务开始和结束时都会向操作中心发送通知。对于第一个,我没有问题,但是在第二个通知中,我想在用户单击日志文件时打开一个日志文件。

操作中心显示两个通知,但是单击通知时日志文件不会打开。我猜是因为该应用程序已经关闭。

到目前为止,我尝试了以下方法。

uses
  System.SysUtils, System.Classes, System.Notification,
  System.Generics.Collections;

type
  TActionCenter = class(TDataModule)
    NotificationCenter: TNotificationCenter;
    procedure NotificationCenterReceiveLocalNotification(Sender: TObject;
      ANotification: TNotification);
  strict private
    FNotifications: TDictionary<string, TOnReceiveLocalNotification>;
  public
    class procedure AppRegister(const ACompanyName: string);
    procedure AfterConstruction; override;
    procedure BeforeDestruction; override;
    procedure SendNotification(const ATitle, AMessage: string); overload;
    procedure SendNotification(const ATitle, AMessage: string; AOnClick: TOnReceiveLocalNotification); overload;
  end;

var
  _ActionCenter: TActionCenter;

...

uses
  System.Hash, System.Win.Registry, Winapi.Windows;

procedure TActionCenter.AfterConstruction;
begin
  inherited;
  FNotifications := TDictionary<string, TOnReceiveLocalNotification>.Create;
end;

class procedure TActionCenter.AppRegister(const ACompanyName: string);
const
  ActionCenterKey = 'SOFTWARE\Microsoft\Windows\CurrentVersion\Notifications\Settings\';
var
  ApplicationKey: string;
  Registry: TRegistry;
begin
  ApplicationKey := ACompanyName + '.DesktopToasts.' + THashBobJenkins.GetHashString(ParamStr(0));
  Registry := TRegistry.Create;
  try
    Registry.RootKey := HKEY_CURRENT_USER;
    if not Registry.KeyExists(ActionCenterKey + ApplicationKey) then
    begin
      Registry.Access := KEY_WRITE;
      if Registry.OpenKey(ActionCenterKey + ApplicationKey, True) then
        Registry.WriteInteger('ShowInActionCenter', 1);
    end;
  finally
    Registry.Free;
  end;
end;

procedure TActionCenter.BeforeDestruction;
begin
  inherited;
  FNotifications.Free;
end;

procedure TActionCenter.NotificationCenterReceiveLocalNotification(
  Sender: TObject; ANotification: TNotification);
var
  Pair: TPair<string, TOnReceiveLocalNotification>;
begin
  Pair := FNotifications.ExtractPair(ANotification.Name);
  if Assigned(Pair.Value) then
    Pair.Value(Sender, ANotification);
end;

procedure TActionCenter.SendNotification(const ATitle, AMessage: string);
begin
  SendNotification(ATitle, AMessage, nil);
end;

procedure TActionCenter.SendNotification(const ATitle, AMessage: string;
  AOnClick: TOnReceiveLocalNotification);
var
  Notification: TNotification;
begin
  Notification := NotificationCenter.CreateNotification;
  try
    Notification.Name := TGUID.NewGuid.ToString;
    Notification.Title := ATitle;
    Notification.AlertBody := AMessage;
    FNotifications.Add(Notification.Name, AOnClick);
    NotificationCenter.PresentNotification(Notification);
  finally
    Notification.Free;
  end;
end;

initialization
  TActionCenter.AppRegister('MyCompanyName');
  _ActionCenter := TActionCenter.Create(nil);

finalization
  _ActionCenter.Free;

...

uses
  Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants,
  System.Classes, Vcl.Graphics, Vcl.Controls, Vcl.Forms, Vcl.Dialogs,
  Vcl.StdCtrls, ActionCenter.Classes;

type
  TMain = class(TForm)
    Send: TButton;
    procedure SendClick(Sender: TObject);
  strict private
    procedure NotificationClick1(ASender: TObject; ANotification: TNotification);
    procedure NotificationClick2(ASender: TObject; ANotification: TNotification);
    procedure NotificationClick3(ASender: TObject; ANotification: TNotification);
    procedure OpenLog(FileName: TFileName);
  end;

....

uses
  Winapi.ShellAPI;

procedure TMain.NotificationClick1(ASender: TObject; ANotification: TNotification);
begin
  OpenLog('C:\First.txt');
end;

procedure TMain.NotificationClick2(ASender: TObject; ANotification: TNotification);
begin
  OpenLog('C:\Second.txt');
end;

procedure TMain.NotificationClick3(ASender: TObject; ANotification: TNotification);
begin
  OpenLog('C:\Third.txt');
end;

procedure TMain.OpenLog(FileName: TFileName);
var
  Handle: THandle;
begin
  Handle := GetStdHandle(STD_INPUT_HANDLE);
  ShellExecute(Handle, nil, PChar(FileName), nil, nil, SW_SHOWNORMAL);
end;

有没有办法做到这一点?即使在应用关闭后,OnReceiveLocalNotification事件是否仍然有效?

1 个答案:

答案 0 :(得分:0)

我解决了用TTrayIcon和OnBaloonClick替换TNotificationCenter和OnReceiveLocalNotification的问题。似乎TTrayIcon通知使应用程序运行了几秒钟。这不是完美的解决方案,但到目前为止已经足够。