【问题标题】:Detect screen lock - FMX in Win32检测屏幕锁定 - Win32 中的 FMX
【发布时间】:2019-05-03 17:41:07
【问题描述】:

我希望我的应用程序在屏幕锁定时运行一些代码(Win 7 和 10)。当用户锁定屏幕时,我的应用程序也可能在后台。

有人指出我正确的方向吗?

谢谢你, 接力人

【问题讨论】:

    标签: firemonkey c++builder


    【解决方案1】:

    使用WTSRegisterSessionNotification() 注册HWND 以通过WM_WTSSESSION_CHANGE 窗口消息接收WTS_SESSION_(UN)LOCK 通知。

    您可以使用 FMX 的FormToHWND() 函数来获取您的表单的HWND。但是,FireMonkey 控件(包括 Forms)没有可覆盖的 WndProc() 方法来处理窗口消息,就像 VCL 一样,因此您必须使用 Win32 API 的 SetWindowLongPtr()SetWindowSubclass() 函数(请参阅 MSDN 上的 Subclassing Controls ) 接收WM_WTSSESSION_CHANGE 窗口消息:

    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
    

    或者,您可以使用 RTL 的 AllocateHWnd() 函数创建隐藏的 HWND 并为其提供自定义 WndProc() 方法:

    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
    

    【讨论】:

    • 我找到了这个example,但我不知道如何实现它。我在这里是个蹒跚学步的孩子。
    • Remy - 有没有例子可以告诉我如何做到这一点?我找到了这个链接 (bcbjournal.org/articles/vol2/9807/…) 但我无法让它在东京 10.3.2 工作。我猜它太旧/过时了,我不知道如何适应它。
    • Remy,我创建了一个新的 FMX 项目,并尝试了您的第一种方法。我把第一个块放在 Unit1.h 中,第二个放在 Unit1.cpp 中。我将 TmyForm 更改为 TForm1。当我运行它时,我得到“E2268 Call to undefined function 'FormToHWND'。
    • @relayman357 您使用的是哪个版本的 C++Builder?你从来没有这么说过。 FormToHWND() 需要 XE5+,并在 FMX.Platform.Win.hpp 中声明。如果您的版本没有FormToHWND() ,请改用FmxHandleToHWND()WindowHandleToPlatform()。我更新了我的答案以显示他们
    • @relayman357 FormToHWND() 肯定存在于 10.2 Tokyo 中。尝试完全限定其命名空间(以防DELPHIHEADER_NO_IMPLICIT_NAMESPACE_USE生效):HWND hWnd = Fmx::Platform::Win::FormToHWND(this);至于XE5,我指的是C++Builder XE5,它是东京10.2之前的6个版本(XE5为released in 2013)。跨度>
    猜你喜欢
    • 1970-01-01
    • 2016-03-30
    • 1970-01-01
    • 2016-08-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多