如何在 C++ 中使用 Windows API 隐藏桌面图标?

Posted

技术标签:

【中文标题】如何在 C++ 中使用 Windows API 隐藏桌面图标?【英文标题】:How to hide Desktop icons with Windows API in C++? 【发布时间】:2018-11-14 23:37:11 【问题描述】:

我找到的答案链接到fHideIcon,但我在 Microsoft 的这些链接页面上收到 404 错误。

我也试过了:

SHELLSTATE ss;
SecureZeroMemory(&ss, sizeof(ss));
SHGetSetSettings(&ss, SSF_HIDEICONS, TRUE);

但这没有用。 有谁知道怎么做?

【问题讨论】:

MS 肯定不像以前那样维护其 winapi C++ 文档了。 @Christopher 以前好吗? 从 1998 年到 2003 年“更好”。至少链接有效。 MSDN 已经将其文档从 msdn.microsoft.com 迁移到 docs.microsoft.com 上的新格式已经有一段时间了,而且很多事情都在破解(链接断开、文本不完整等) .这太可怕了。恕我直言,旧文档没有任何问题,他们应该不理会它。 @rem:虽然我同意文档的当前状态是一个非常重要的回归,但实际上 移动它的原因。完成后,我们最终将有办法提交和公开跟踪文档缺陷。 【参考方案1】:

以下使用官方 shell API 的方法有点复杂,但即使在 Windows 10 下也可以使用。

步骤:

    获取桌面的IFolderView2接口(从Windows Vista开始支持)。 使用FWF_NOICONS 调用IFolderView2::SetCurrentFolderFlags() 以获取dwMaskdwFlags 参数。

标志的效果立即可见。无需重新启动计算机或“explorer.exe”。该标志在注销或重新启动后仍然存在。

棘手的是第 1 步)。 Raymond Chen 在他的文章 "Manipulating the positions of desktop icons" 中展示了 C++ 代码,特别是在他的 FindDesktopFolderView() 函数中。

这是一个控制台应用程序形式的完整示例。它基于 Raymond Chen 的代码。该程序每次运行时都会切换桌面图标的可见性。

代码已在 Windows 10 Version 1803 下测试。

“库”代码:

#include <ShlObj.h>     // Shell API
#include <atlcomcli.h>  // CComPtr & Co.
#include <string> 
#include <iostream> 
#include <system_error>

// Throw a std::system_error if the HRESULT indicates failure.
template< typename T >
void ThrowIfFailed( HRESULT hr, T&& msg )

    if( FAILED( hr ) )
        throw std::system_error hr, std::system_category(), std::forward<T>( msg ) ;


// RAII wrapper to initialize/uninitialize COM
struct CComInit

    CComInit()  ThrowIfFailed( ::CoInitialize( nullptr ), "CoInitialize failed" ); 
    ~CComInit()  ::CoUninitialize(); 
    CComInit( CComInit const& ) = delete;
    CComInit& operator=( CComInit const& ) = delete;
;

// Query an interface from the desktop shell view.
void FindDesktopFolderView( REFIID riid, void **ppv, std::string const& interfaceName )

    CComPtr<IShellWindows> spShellWindows;
    ThrowIfFailed( 
        spShellWindows.CoCreateInstance( CLSID_ShellWindows ),
        "Failed to create IShellWindows instance" );

    CComVariant vtLoc( CSIDL_DESKTOP );
    CComVariant vtEmpty;
    long lhwnd;
    CComPtr<IDispatch> spdisp;
    ThrowIfFailed( 
        spShellWindows->FindWindowSW(
            &vtLoc, &vtEmpty, SWC_DESKTOP, &lhwnd, SWFO_NEEDDISPATCH, &spdisp ),
        "Failed to find desktop window" );

    CComQIPtr<IServiceProvider> spProv( spdisp );
    if( ! spProv )
        ThrowIfFailed( E_NOINTERFACE, "Failed to get IServiceProvider interface for desktop" );

    CComPtr<IShellBrowser> spBrowser;
    ThrowIfFailed( 
        spProv->QueryService( SID_STopLevelBrowser, IID_PPV_ARGS( &spBrowser ) ),
        "Failed to get IShellBrowser for desktop" );

    CComPtr<IShellView> spView;
    ThrowIfFailed( 
        spBrowser->QueryActiveShellView( &spView ),
        "Failed to query IShellView for desktop" );

    ThrowIfFailed( 
        spView->QueryInterface( riid, ppv ),
        "Could not query desktop IShellView for interface " + interfaceName );

使用上述代码切换桌面图标的示例:

void ToggleDesktopIcons()

    CComPtr<IFolderView2> spView;
    FindDesktopFolderView( IID_PPV_ARGS(&spView), "IFolderView2" );

    DWORD flags = 0;
    ThrowIfFailed( 
        spView->GetCurrentFolderFlags( &flags ), 
        "GetCurrentFolderFlags failed" );
    ThrowIfFailed( 
        spView->SetCurrentFolderFlags( FWF_NOICONS, flags ^ FWF_NOICONS ),
        "SetCurrentFolderFlags failed" );


int wmain(int argc, wchar_t **argv)

    try
    
        CComInit init;

        ToggleDesktopIcons();

        std::cout << "Desktop icons have been toggled.\n";
    
    catch( std::system_error const& e )
    
        std::cout << "ERROR: " << e.what() << ", error code: " << e.code() << "\n";
        return 1;
    

    return 0;

【讨论】:

【参考方案2】:

第三个参数不是改变设置,是选择SHGetSetSettings()行为。

FALSE 将获取当前设置的值并将其存储在 ss 中,TRUE 将设置的值设置为 ss 中的值。

所以基本上你必须做ss.fHideIcons = TRUE 然后调用SHGetSetSettings(&amp;ss, SSF_HIDEICONS, TRUE) 来设置它。

我知道,这很奇怪,但另一方面,它允许您同时更改多个设置,因为SSF_* 是位掩码。

【讨论】:

除非那行不通...我认为ss.fHideIcons与OP所希望的含义不同 @PaulSanders 好吧,希望您在 将内存归零之后执行ss.fHideIcons = TRUE,否则它的工作将被撤消。 @PaulSanders 嗯...是的,我刚刚在这里测试过,我的图标闪烁,但仅此而已。有趣的是,当您实际将设置更改为与以前不同的值时,它们只会闪烁,无论我是要隐藏还是显示图标。如果我在 Windows 资源管理器上下文菜单中手动隐藏它们,它也不会显示图标。我不知道,也许这是 Windows 10 的错误?您使用的是哪个 Windows 版本? 我试过这个,不幸的是,它不起作用。 @peter 的回答虽然有效。 @Havenard 哦,好吧,你知道 MS:向后兼容是王道。【参考方案3】:

以下似乎有效(改编自https://***.com/a/6403014/5743288):

#include <windows.h>

int main ()

    HWND hProgman = FindWindowW (L"Progman", L"Program Manager");
    HWND hChild = GetWindow (hProgman, GW_CHILD);
    ShowWindow (hChild, SW_HIDE);
    Sleep (2000);
    ShowWindow (hChild, SW_SHOW);

请注意:此方法不受 Microsoft 支持,并且无法在桌面上单击鼠标右键。

【讨论】:

@peter 谢谢!是的,我找到了那个链接,但我不知道如何让它在 C++ 中工作。你能解释一下这是如何工作的吗?我不明白。 @Adam 是的,这正是我所说的方法,我只是不确定它是否适用于不同版本的 Windows。天啊,我记得在 Windows 98 上这样做... @adam 正如我链接到的帖子所解释的,它隐藏了承载所有桌面图标的父窗口。希望 MS 不会破坏这一点。 Shell 有一个公共 API。不要在没有明确将其标记为不受支持的情况下根据实施细节分发解决方案。 可能还需要注意,这将失去右键单击桌面的能力。

以上是关于如何在 C++ 中使用 Windows API 隐藏桌面图标?的主要内容,如果未能解决你的问题,请参考以下文章

如何使用 Windows 运行时使用 C# 实现 C++ API?

使用 windows api 和 C++,我如何从硬盘驱动器加载 exe 并在自己的线程中运行它?

如何使用 C++ 在 Windows 中获取硬件信息?

Windows C++ API:如何将整个二进制文件读入缓冲区?

如何使用 C++ 在 Windows 中创建守护线程?

为啥 c++ 中的分号似乎隐式处理错误? [tldr:他们没有]