c# - 如何检测 Windows 开始菜单/开始屏幕何时打开?

标签 c# c++ windows callback startmenu

如何为 Windows 开始菜单(或 Windows 8 开始屏幕)打开设置事件处理程序或回调?

或者,至少,如何检查开始菜单当前是否打开?

我更喜欢使用 C# 解决此问题,但也非常感谢使用 C++ 解决方案。

最佳答案

显然,开始屏幕可见性回调/事件不适用于桌面应用程序(请参阅下面的 out-#if 代码),但简单的轮询效果很好。

#include <algorithm>        // std::swap
#include <functional>       // std::function
#include <iostream>
#include <stdlib.h>         // EXIT_FAILURE, EXIT_SUCCESS
#include <stdexcept>        // std::runtime_error, std::exception
#include <system_error>     // std::system_error
#include <string>           // std::string
using namespace std;

#include <conio.h>          // _kbhit

#undef UNICODE
#define UNICODE
#include <windows.h>
#include <shobjidl.h>       // IAppVisibilityEvents

auto fail( string const& message, int code = 0 )
    -> bool
{ throw system_error( code, system_category(), message ); }

class On_block_exit
{
private:
    function<void()>    f_;
public:
    ~On_block_exit() { f_(); }
    On_block_exit( function<void()> f ): f_( f ) {}
};

enum Success { success };

auto operator>>( HRESULT const hr, Success const )
    -> bool
{ ::SetLastError( hr );  return SUCCEEDED( hr ); }

template< class Interface >
class Com_ptr
{
private:
    Interface*  p_;
public:
    Interface* pointer() const { return p_; }
    Interface* operator->() const { return p_; }

    void** as_out_arg()
    {
        *this = Com_ptr();
        return reinterpret_cast<void**>( &p_ );
    }

    friend
    void swap( Com_ptr& a, Com_ptr& b ) throw()
    { swap( a.p_, b.p_ ); }

    void operator=( Com_ptr rhs ) { swap( *this, rhs ); }

    ~Com_ptr() { if( p_ ) { p_->Release(); } }

    Com_ptr( Interface* const p = nullptr ): p_( p ) {}

    Com_ptr( Com_ptr const& other )
        : p_( other.p_ )
    { if( p_ ) { p_->AddRef(); } }
};

auto is_startscreen_shown( Com_ptr<IAppVisibility> p_app_visibility )
    -> bool
{
    BOOL    result;
    p_app_visibility->IsLauncherVisible( &result )
        >> success
        || fail( "IAppVisibility::IsLauncherVisible", ::GetLastError() );
    return !!result;
}

template< class Base >
struct With_dummy_iunknown_
    : Base
{
    ULONG __stdcall AddRef() override { return 0; }

    ULONG __stdcall Release() override { return 0; }

    HRESULT __stdcall QueryInterface( REFIID riid, void **ppvObject ) override
    {
        if( riid == IID_IUnknown )
        {
            *ppvObject = this;
            return S_OK;
        }
        return E_NOINTERFACE;
    }
};

void cpp_main()
{
    ::CoInitialize( nullptr )
        >> success
        || fail( "CoInitialize", ::GetLastError() );

    Com_ptr<IAppVisibility> p_app_visibility;

    ::CoCreateInstance(
        CLSID_AppVisibility, nullptr, CLSCTX_ALL, IID_IAppVisibility, p_app_visibility.as_out_arg()
        ) >> success
        || fail( "CoCreateInstance CLSID_AppVisibility IID_IAppVisibility", ::GetLastError() );

    cout << "Press the 'Any' key to quit." << endl;
    bool was_shown = false; bool first_iteration = true; int n = 0;
    for( ;; )
    {
        if( _kbhit() ) { break; }

        bool const is_shown = is_startscreen_shown( p_app_visibility );
        if( first_iteration || is_shown != was_shown )
        {
            cout << n << ": ";
            if( is_shown )
            {
                cout << "Currently showing the start screen" << endl;
            }
            else
            {
                cout << "Currently showing normal desktop or app." << endl;
            }
            ++n;
        }
        first_iteration = false;
        was_shown = is_shown;
        Sleep( 50 );
    }

#if 0
    struct Events: IAppVisibilityEvents
    {
        HRESULT __stdcall AppVisibilityOnMonitorChanged(
            HMONITOR                monitor_handle,
            MONITOR_APP_VISIBILITY  previous_mode,
            MONITOR_APP_VISIBILITY  current_mode
            ) override
        { return S_OK; }

        HRESULT __stdcall LauncherVisibilityChange(
            BOOL is_now_visible
            ) override
        {
            cout
                << (!!is_now_visible? "Showing the start screen" : "Hiding start screen, showing desktop/app")
                << endl;
            return S_OK;
        }
    };

    With_dummy_iunknown_<Events> events;
    DWORD cookie = 1;
    p_app_visibility->Advise( &events, &cookie )
        >> success
        || fail( "IAppVisibility::Advise", ::GetLastError() );
    On_block_exit unadvise( [=](){ p_app_visibility->Unadvise( cookie ); } );

    ::MessageBox( 0, L"Press OK to quit.", L"Watching...", MB_SETFOREGROUND );
#endif
}

auto main()
    -> int
{
    try
    {
        cpp_main();
        return EXIT_SUCCESS;
    }
    catch( system_error const& x )
    {
        cerr << "!" << x.what() << " (code " << x.code().value() << ")" << endl;
    }
    catch( exception const& x )
    {
        cerr << "!" << x.what() << endl;
    }
    return EXIT_FAILURE;
}

关于c# - 如何检测 Windows 开始菜单/开始屏幕何时打开?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/22085746/

相关文章:

c# - 无法跨 AppDomains 传递 GCHandle

c++ - 如何在不等待的情况下使用 future ?

c++ - 如何直接从构造函数结束 C++ 代码?

c# - 开发文件存储 Web 应用程序

c# - 在 azure 中发布网站时,未发布已编辑的页面

c# - 我可以通过 ajax 关闭监视器并获得响应吗?

c# - 让存储在 Session 中的数据保持事件状态

c++ - 为什么## aka 标记粘贴运算符不适用于 C 和 C++ 中的注释?

windows - Powershell脚本协助请

windows - 启动应用程序(如果已安装)或重定向以下载 - Windows