How to detect when the Windows start menu / start screen opens?

久未见 提交于 2019-12-02 07:14:28

问题


How to setup an event-handler or callback for the Windows start menu (or Windows 8 start screen) opening?

Or, at least, how to check if the start menu is currently open?

I prefer a solution for this problem in C#, but a solution in C++ is also greatly appreciated.


回答1:


Apparently the start screen visibility callback/event thing doesn't work for a desktop app (see the out-#ifed code below), but simple polling works nicely.

#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;
}


来源:https://stackoverflow.com/questions/22085746/how-to-detect-when-the-windows-start-menu-start-screen-opens

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!