如何检测用户何时在
Windows 7中锁定/解锁屏幕?
我发现this question有一个C#的答案,但我想在Delphi 2009中使用它.我猜有一些Windows消息(如these)可以完成这项工作.这是我试过的代码,但它不起作用:
const NOTIFY_FOR_ALL_SESSIONS = 1; {$EXTERNALSYM NOTIFY_FOR_ALL_SESSIONS} NOTIFY_FOR_THIS_SESSION = 0; {$EXTERNALSYM NOTIFY_FOR_THIS_SESSION} type TfrmAlisson = class(TForm) lbl2: TLabel; procedure FormCreate(Sender: TObject); procedure FormDestroy(Sender: TObject); public FLockedCount: Integer; procedure WndProc(var Message: TMessage); override; function WTSRegisterSessionNotification(hWnd: HWND; dwFlags: DWORD): bool; stdcall; function WTSUnRegisterSessionNotification(hWND: HWND): bool; stdcall; end; implementation uses // my impl uses here procedure TfrmAlisson.FormCreate(Sender: TObject); begin if (WTSRegisterSessionNotification(Handle,NOTIFY_FOR_THIS_SESSION)) then ShowMessage('Nice') else begin lastError := GetLastError; ShowMessage(SysErrorMessage(lastError)); end; end; procedure TfrmAlisson.FormDestroy(Sender: TObject); begin WTSUnRegisterSessionNotification(Handle); end; procedure TfrmAlisson.WndProc(var Message: TMessage); begin case Message.Msg of WM_WTSSESSION_CHANGE: begin if Message.wParam = WTS_SESSION_LOCK then begin Inc(FLockedCount); end; if Message.wParam = WTS_SESSION_UNLOCK then begin lbl2.Caption := 'Session was locked ' + IntToStr(FLockedCount) + ' times.'; end; end; end; inherited; end; function TfrmAlisson.WTSRegisterSessionNotification(hWnd: HWND; dwFlags: DWORD): bool; external 'wtsapi32.dll' Name 'WTSRegisterSessionNotification'; function TfrmAlisson.WTSUnRegisterSessionNotification(hWND: HWND): bool; external 'wtsapi32.dll' Name 'WTSUnRegisterSessionNotification';
执行FormCreate时,WTSRegisterSessionNotification返回false,最后一次操作系统错误返回Invalid Parameter.
解决方法
您的代码无效,因为您没有正确实现它.
您没有正确声明WTSRegisterSessionNotification()和WTSUnRegisterSessionNotification().
此外,您没有考虑VCL在Form对象的生命周期中动态重新创建窗体窗口的可能性.因此,即使WTSRegisterSessionNotification()成功,您也可能会丢失注册而无法实现.
试试这个:
interface uses ...; type TfrmAlisson = class(TForm) lbl2: TLabel; protected procedure CreateWnd; override; procedure DestroyWindowHandle; override; procedure WndProc(var Message: TMessage); override; public LockedCount: Integer; end; implementation const NOTIFY_FOR_THIS_SESSION = $0; NOTIFY_FOR_ALL_SESSIONS = $1; function WTSRegisterSessionNotification(hWnd: HWND; dwFlags: DWORD): Boolean; stdcall; external 'wtsapi32.dll' name 'WTSRegisterSessionNotification'; function WTSUnRegisterSessionNotification(hWnd: HWND): Boolean; stdcall; external 'wtsapi32.dll' name 'WTSUnRegisterSessionNotification'; procedure TfrmAlisson.CreateWnd; begin inherited; if not WTSRegisterSessionNotification(Handle,NOTIFY_FOR_THIS_SESSION) then RaiseLastOSError; end; procedure TfrmAlisson.DestroyWindowHandle; begin WTSUnRegisterSessionNotification(Handle); inherited; end; procedure TfrmAlisson.WndProc(var Message: TMessage); begin if Message.Msg = WM_WTSSESSION_CHANGE then begin case Message.wParam of WTS_SESSION_LOCK: begin Inc(LockedCount); end; WTS_SESSION_UNLOCK: begin lbl2.Caption := Format('Session was locked %d times.',[LockedCount]); end; end; end; inherited; end; end.
话虽这么说,考虑编写代码不依赖于VCL的窗口娱乐行为.您可以分配一个专用窗口来监视会话更改:
interface uses ...; type TfrmAlisson = class(TForm) lbl2: TLabel; procedure FormCreate(Sender: TObject); procedure FormDestroy(Sender: TObject); private SessionWnd: HWND; procedure SessionWndProc(var Message: TMessage); public LockedCount: Integer; end; implementation const NOTIFY_FOR_THIS_SESSION = $0; NOTIFY_FOR_ALL_SESSIONS = $1; function WTSRegisterSessionNotification(hWnd: HWND; dwFlags: DWORD): Boolean; stdcall; external 'wtsapi32.dll' name 'WTSRegisterSessionNotification'; function WTSUnRegisterSessionNotification(hWnd: HWND): Boolean; stdcall; external 'wtsapi32.dll' name 'WTSUnRegisterSessionNotification'; procedure TfrmAlisson.FormCreate(Sender: TObject); begin SessionWnd := AllocateHWnd(SessionWndProc); if not WTSRegisterSessionNotification(SessionWnd,NOTIFY_FOR_THIS_SESSION) then RaiseLastOSError; end; procedure TfrmAlisson.FormDestroy(Sender: TObject); begin if SessionWnd <> 0 then begin WTSUnRegisterSessionNotification(SessionWnd); DeallocateHWnd(SessionWnd); end; end; procedure TfrmAlisson.SessionWndProc(var Message: TMessage); begin if Message.Msg = WM_WTSSESSION_CHANGE then begin case Message.wParam of WTS_SESSION_LOCK: begin Inc(LockedCount); end; WTS_SESSION_UNLOCK: begin lbl2.Caption := Format('Session was locked %d times.',[LockedCount]); end; end; end; Message.Result := DefWindowProc(SessionWnd,Message.Msg,Message.WParam,Message.LParam); end; end.