Sergio Calderon
Sergio Calderon

Reputation: 867

Is there any WinAPI function to modify the desktop icon size?

Maybe I did not do a good search, but cannot find any WinAPI function to modify the desktop icons size. If there is not, can you suggest a way to achieve that?

Upvotes: 1

Views: 742

Answers (1)

zett42
zett42

Reputation: 27756

Get the IFolderView2 interface of the desktop and call its SetViewModeAndIconSize() method to change the icon size.

The hard thing is how to get the IFolderView2 interface for the desktop. Fortunately, Raymond Chen comes to the rescue. He has an article about manipulating the positions of desktop icons from which we only need the code of his FindDesktopFolderView() function.

I have adapted his code with added error handling. Although this question is tagged "C" I'm using C++ to answer it because C++ is more practical for COM programming.

First the required includes and some helper functions.

#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
{
    HRESULT hr = ::CoInitialize( nullptr );
    CComInit() { ThrowIfFailed( hr, "CoInitialize failed" ); }
    ~CComInit() { ::CoUninitialize(); }
};

Now down to the nitty-gritty, FindDesktopFolderView():

// 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 );
}

Usage Example:

The following example sets the desktop icon size to 16, which is even smaller than what you can achieve through the context menu of the desktop.

You can also have some fun and set the viewMode to something else, say FVM_DETAILS which would switch the desktop into details view. That's not even possible through the regular user interface.

int main()
{
    try
    {
        CComInit coInit;

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

        FOLDERVIEWMODE viewMode = FVM_AUTO;
        int iconSize = 0;
        ThrowIfFailed( 
            spView->GetViewModeAndIconSize( &viewMode, &iconSize ),
            "GetViewModeAndIconSize failed" );
        std::cout << "Current view mode: " << viewMode << ", icon size: " << iconSize << '\n';

        ThrowIfFailed( 
            spView->SetViewModeAndIconSize( viewMode, 16 ),
            "SetViewModeAndIconSize failed" );

        return 0;
    }
    catch( std::system_error const& e )
    {
        std::cout << "ERROR: " << e.what() << ", error code: " << e.code() << "\n";
        return 1;
    }
}

Upvotes: 7

Related Questions