2
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

Windowsのごみ箱アイコンの変化を検知する

Last updated at Posted at 2021-04-25

ごみ箱の ITEMIDLIST を取得

# include <ShlObj.h>

LPITEMIDLIST pidlBitBucket;
SHGetSpecialFolderLocation(nullptr, CSIDL_BITBUCKET, &pidlBitBucket);

SHGetSpecialFolderLocation function (shlobj_core.h) - Win32 apps | Microsoft Docs

シェルの変更通知に登録

# define WM_SHCHANGENOTIFY (WM_APP + 1)

SHChangeNotifyEntry changeNotifyEntry = { 0 };
changeNotifyEntry.fRecursive = FALSE;
changeNotifyEntry.pidl = pidlBitBucket;

ULONG ulID = SHChangeNotifyRegister(
    hWnd,
    (SHCNRF_ShellLevel | SHCNRF_NewDelivery),
    SHCNE_UPDATEIMAGE,
    WM_SHCHANGENOTIFY,
    1,
    &changeNotifyEntry);

SHChangeNotifyRegister function (shlobj_core.h) - Win32 apps | Microsoft Docs
SHChangeNotifyRegisterの第3引数(fEvents)にSHCNE_UPDATEIMAGEを渡すと、アイコンの変更が通知されます。

Window メッセージ を処理

LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
    switch (message) {
        case WM_SHCHANGENOTIFY:
            LPITEMIDLIST* ppidl;
            LONG lEvent;
            HANDLE hLock = SHChangeNotification_Lock((HANDLE)wParam, (DWORD)lParam, &ppidl, &lEvent);
        
            if (!hLock) {
                break;
            }

            if (lEvent == SHCNE_UPDATEIMAGE) {
                AnalyzeIcon();
            }

            SHChangeNotification_Unlock(hLock);
            break;

        ...
    }

    return 0;
}

SHChangeNotification_Lock function (shlobj_core.h) - Win32 apps | Microsoft Docs
SHChangeNotification_Unlock function (shlobj_core.h) - Win32 apps | Microsoft Docs

ごみ箱のアイコンを取得

# include <shellapi.h>

void AnalyzeIcon()
{
    SHFILEINFO shFileInfo = { 0 };

    if (SUCCEEDED(SHGetFileInfo(
        (LPCTSTR)pidlBitBucket,
        -1,
        &shFileInfo,
        sizeof(shFileInfo),
        (SHGFI_PIDL | SHGFI_ICON)))) {
        HICON hIcon = shFileInfo.hIcon;
        // アイコンを使う処理
        ...

        if (hIcon) {
            DestroyIcon(hIcon);
        }
    }
}

SHGetFileInfoA function (shellapi.h) - Win32 apps | Microsoft Docs
SHGetFileInfoの第1引数(pszPath)にITEMIDLISTのポインタ、第5引数にSHGFI_PIDLを渡すのがポイント。
取得したアイコンのハンドルは破棄が必要。

サンプル

# include <ShlObj.h>
# include <shellapi.h>
# define WM_SHCHANGENOTIFY (WM_APP + 1)

LPITEMIDLIST g_pidlBitBucket = nullptr;
ULONG g_ulID = 0;

LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
    switch (message) {
        case WM_CREATE:
            CoInitialize(nullptr);

            {
                SHChangeNotifyEntry changeNotifyEntry = { 0 };
                changeNotifyEntry.fRecursive = FALSE;
                changeNotifyEntry.pidl = g_pidlBitBucket;

                g_ulID = SHChangeNotifyRegister(
                    hWnd,
                    (SHCNRF_ShellLevel | SHCNRF_NewDelivery),
                    SHCNE_UPDATEIMAGE,
                    WM_SHCHANGENOTIFY,
                    1,
                    &changeNotifyEntry);

                if (!g_ulID) {
                    break;
                }
            }

            break;

        case WM_DESTROY:
            SHChangeNotifyDeregister(g_ulID);

            if (g_pidlBitBucket) {
                CoTaskMemFree(g_pidlBitBucket);
            }

            CoUninitialize();
            PostQuitMessage(0);
            break;

        case WM_SHCHANGENOTIFY:
        {
            LPITEMIDLIST* ppidl;
            LONG lEvent;
            HANDLE hLock = SHChangeNotification_Lock((HANDLE)wParam, (DWORD)lParam, &ppidl, &lEvent);

            if (!hLock) {
                break;
            }

            if (lEvent == SHCNE_UPDATEIMAGE) {
                AnalyzeIcon();
            }

            SHChangeNotification_Unlock(hLock);
        }

        break;

        default:
            return DefWindowProc(hWnd, message, wParam, lParam);
    }

    return 0;
}

余談

.NETではshell32.dllを参照に追加するだけで、こんなコードが書けます。

using Shell32;
using System;

static class Program
{
    static void Main()
    {
        Shell shell = new Shell();
        // ShellSpecialFolderConstants::ssfBITBUCKET: 10
        Folder bitBucketFolder = shell.NameSpace(10);

        foreach (FolderItem2 item in bitBucketFolder.Items())
        {
            Console.WriteLine(item.Name);
        }
    }
}

Windows Shell - Win32 apps | Microsoft Docs

追記

IShellFolderは使用しないので、説明を削除しました。
(ごみ箱の中身を検証する時に使用します)

2
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?