Detecting When Screen Is Locked

Detect screen lock - FMX in Win32

Use WTSRegisterSessionNotification() to register an HWND to receive WTS_SESSION_(UN)LOCK notifications via the WM_WTSSESSION_CHANGE window message.

You can use FMX's FormToHWND() function to obtain your Form's HWND. However, FireMonkey controls, including Forms, do not have an overridable WndProc() method to process window messages, like VCL does, so you will have to use the Win32 API's SetWindowLongPtr() or SetWindowSubclass() function (see Subclassing Controls on MSDN) to receive the WM_WTSSESSION_CHANGE window message:

class TMyForm : public TForm
{
...
#ifdef _Windows
private:
bool MonitoringWTS;
static LRESULT CALLBACK SubclassWndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam, UINT_PTR uIdSubclass, DWORD_PTR dwRefData);
protected:
virtual void __fastcall CreateHandle();
#endif
...
};

#ifdef _Windows

#include <FMX.Platform.Win.hpp>
#include <commctrl.h>
#include <wtsapi32.h>

void __fastcall TMyForm::CreateHandle()
{
MonitoringWTS = false;

TForm::CreateHandle();

// depending on which version of C++Builder you are using...
HWND hWnd = FormToHWND(this);
//HWND hWnd = WindowHandleToPlatform(Handle)->Wnd;
//HWND hWnd = FmxHandleToHWND(Handle);

if (!SetWindowSubclass(hWnd, &SubclassWndProc, 1, reinterpret_cast<DWORD_PTR>(this)))
throw Exception(_D("Could not subclass window"));

MonitoringWTS = WTSRegisterSessionNotification(hWnd, NOTIFY_FOR_THIS_SESSION);
if (!MonitoringWTS)
RaiseLastOSError();
}

LRESULT CALLBACK TMyForm::SubclassWndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam, UINT_PTR uIdSubclass, DWORD_PTR dwRefData)
{
switch (uMsg)
{
case WM_NCDESTROY:
{
WTSUnRegisterSessionNotification(hWnd);
reinterpret_cast<TMyForm*>(dwRefData)->MonitoringWTS = false;

RemoveWindowSubclass(hWnd, &SubclassWndProc, uIdSubclass);
break;
}

case WM_WTSSESSION_CHANGE:
{
TMyForm *pThis = reinterpret_cast<TMyForm*>(dwRefData);

switch (wParam)
{
case WTS_SESSION_LOCK:
// do something ...
break;

case WTS_SESSION_UNLOCK:
// do something ...
break;
}

return 0;
}
}

return DefSubclassProc(hWnd, uMsg, wParam, lParam);
}

#endif

Alternatively, you can use the RTL's AllocateHWnd() function to create a hidden HWND and provide it with a custom WndProc() method:

class TMyForm : public TForm
{
...
#ifdef _Windows
private:
HWND WndForWTS;
bool MonitoringWTS;
void __fastcall WndProcForWTS(TMessage &Message);
public:
__fastcall TMyForm(TComponent *Owner);
__fastcall ~TMyForm();
#endif
...
};

#ifdef _Windows

#include <wtsapi32.h>

__fastcall TMyForm::TMyForm(TComponent *Owner)
: TForm(Owner)
{
WndForWTS = AllocateHWnd(&WndProcForWTS);

MonitoringWTS = WTSRegisterSessionNotification(WndForWTS, NOTIFY_FOR_THIS_SESSION);
if (!MonitoringWTS)
{
int err = GetLastError();
DeallocateHWnd(WndForWTS);
RaiseLastOSError(err);
}
}

__fastcall ~TMyForm();
{
DeallocateHWnd(WndForWTS);
}

void __fastcall TMyForm::WndProcForWTS(TMessage &Message)
{
switch (Message.Msg)
{
case WM_NCDESTROY:
{
if (MonitoringWTS)
{
WTSUnRegisterSessionNotification(WndForWTS);
MonitoringWTS = false;
}
WndForWTS = NULL;
break;
}

case WM_WTSSESSION_CHANGE:
{
switch (Message.WParam)
{
case WTS_SESSION_LOCK:
// do something ...
break;

case WTS_SESSION_UNLOCK:
// do something ...
break;
}

return;
}
}

Message.Result = DefWindowProc(WndForWTS, Message.Msg, Message.WParam, Message.LParam);
}

#endif

How to detect desktop is locked in javascript

In your javascript it is not possible to detect if the OS UI has locked. The browser sand box prevents this kind of access to OS resources for security reasons. You would need to write a browser plugin to do this.

Detect when user locks/unlocks screen in Windows 7 with Delphi

Your code does not work because you did not implement it correctly.

You are not declaring WTSRegisterSessionNotification() and WTSUnRegisterSessionNotification() correctly.

Also, you are not accounting for the possibility of the VCL ever recreating the Form's window dynamically during the Form object's lifetime. So, even if WTSRegisterSessionNotification() were successful, you can lose your registration and not realize it.

Try this instead:

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.

That being said, consider writing the code to not rely on the VCL's window recreation behavior. You can allocate a dedicated window for monitoring the session changes:

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.


Related Topics



Leave a reply



Submit