Windows エクスプローラーに信号を送信して、systray アイコンを更新させることはできますか?

StackOverflow https://stackoverflow.com/questions/74723

質問

この問題はかなり長い間私を悩ませており、本当に迷惑です。

再起動/電源の入れ直し後にログインするたびに、エクスプローラーが表示されるまでに時間がかかります。すべてのサービスが起動するのを待ってからログインする手順を実行しましたが、違いはありません。結果は常に同じです。アプリケーションが起動していても、一部のアイコンが表示されません。

アプリケーションにアイコンを「貼り付ける」コードを少し調べましたが、エクスプローラーがすべてのアイコン情報を再読み取るように実行できる API 呼び出しはありますか?無効化や再描画などのようなものですか?


どうやらジョンが正しかったようですが、それは不可能です。

Bob Dizzle と Mark Ransom のコードに従って、これをビルドしました (Delphi コード)。

procedure Refresh;
var
  hSysTray: THandle;
begin
  hSysTray := GetSystrayHandle;
  SendMessage(hSysTray, WM_PAINT, 0, 0);
end;

function GetSystrayHandle: THandle;
var
  hTray, hNotify, hSysPager: THandle;
begin
  hTray := FindWindow('Shell_TrayWnd', '');
  if hTray = 0 then
  begin
    Result := hTray;
    exit;
  end;

  hNotify := FindWindowEx(hTray, 0, 'TrayNotifyWnd', '');
  if hNotify = 0 then
  begin
    Result := hNotify;
    exit;
  end;

  hSyspager := FindWindowEx(hNotify, 0, 'SysPager', '');
  if hSyspager = 0 then
  begin
    Result := hSyspager;
    exit;
  end;

  Result := FindWindowEx(hSysPager, 0, 'ToolbarWindow32', 'Notification Area');
end;

しかし無駄でした。

私も試してみました

InvalidateRect()
そしてまだショーはありません。

他に何か提案はありますか?

役に立ちましたか?

解決

このブログエントリを見てください。 タスクバーの通知領域を更新する. 。このコードを使用してシステム トレイを更新し、孤立したアイコンを削除していますが、完全に機能します。このブログ エントリは非常に有益で、著者が解決策を見つけるために実行した手順が詳しく説明されています。

#define FW(x,y) FindWindowEx(x, NULL, y, L"")

void RefreshTaskbarNotificationArea()
{
    HWND hNotificationArea;
    RECT r;

    GetClientRect(
        hNotificationArea = FindWindowEx(
            FW(FW(FW(NULL, L"Shell_TrayWnd"), L"TrayNotifyWnd"), L"SysPager"),
            NULL,
            L"ToolbarWindow32",
            // L"Notification Area"), // Windows XP
            L"User Promoted Notification Area"), // Windows 7 and up
        &r);

    for (LONG x = 0; x < r.right; x += 5)
        for (LONG y = 0; y < r.bottom; y += 5)
            SendMessage(
                hNotificationArea,
                WM_MOUSEMOVE,
                0,
                (y << 16) + x);
}

他のヒント

Louis の回答を使用する人にとって重要な 2 つの詳細 (from タスクバーの通知領域を更新する) Windows 7 または Windows 8:

まず、回答が表示に反映されているように、XP では「通知領域」というタイトルのウィンドウは、Windows 7 (実際にはおそらく Vista) 以降では「ユーザー プロモート通知領域」というタイトルになりました。

次に、このコードは現在非表示になっているアイコンを消去しません。これらは別のウィンドウに含まれています。表示されているアイコンを更新するには元のコードを使用し、非表示のアイコンを更新するには次のコードを使用します。

//Hidden icons
GetClientRect(
    hNotificationArea = FindWindowEx(
        FW(NULL, L"NotifyIconOverflowWindow"),
        NULL,
        L"ToolbarWindow32",
        L"Overflow Notification Area"),
    &r);

for (LONG x = 0; x < r.right; x += 5)
    for (LONG y = 0; y < r.bottom; y += 5)
        SendMessage(
            hNotificationArea,
            WM_MOUSEMOVE,
            0,
            (y << 16) + x);

これを実現するために、コードではなくユーティリティを実行するだけで十分な場合は、この更新を使用して単純な exe をビルドしました。 通知領域を更新

システム トレイを更新するには、次のコードを含めます。

public const int WM_PAINT = 0xF;
[DllImport("USER32.DLL")]
public static extern int SendMessage(IntPtr hwnd, int msg, int character,
                                     IntPtr lpsText);

Send WM_PAINT Message to paint System Tray which will refresh it.
SendMessage(traynotifywnd, WM_PAINT, 0, IntPtr.Zero);

私の知る限り、それは不可能です、Gustavo。通知アイコンをシステムトレイに置き、それが正しい状態に保たれるかどうかは各アプリケーションの責任です。

時々、explorer.exe がクラッシュすると、特定のアイコンが再表示されないことに気づくことがあります。これは、プロセスがクラッシュしたためではなく、単に、explorer.exe の新しいインスタンスが開始されたときに、アプリケーションがシステムトレイに通知アイコンを配置しなかっただけです。上。繰り返しますが、責任を負うのはアプリケーションです。

良いニュースがなくてごめんなさい!

この問題については昨年も記事で取り上げましたが、 コードアホリック ウェブログの次のタイトルの記事 [Delphi] SysTray の更新.

私の解決策は、Delphi ActiveX/COM DLL です。ダウンロード リンクはまだ機能します (ただし、どれくらい長く機能するかはわかりません) プラグ 会員資格は失効しています。)

次の C++ コードを使用して、トレイ ウィンドウのウィンドウ ハンドルを取得します。 注記: これは Windows XP でのみテストされています。

HWND FindSystemTrayIcons(void)
{
    // the system tray icons are contained in a specific window hierarchy;
    // use the Spy++ utility to see the chain
    HWND hwndTray = ::FindWindow("Shell_TrayWnd", "");
    if (hwndTray == NULL)
        return NULL;
    HWND hwndNotifyWnd = ::FindWindowEx(hwndTray, NULL, "TrayNotifyWnd", "");
    if (hwndNotifyWnd == NULL)
        return NULL;
    HWND hwndSysPager = ::FindWindowEx(hwndNotifyWnd, NULL, "SysPager", "");
    if (hwndSysPager == NULL)
        return NULL;
    return ::FindWindowEx(hwndSysPager, NULL, "ToolbarWindow32", "Notification Area");
}

@Skip R、およびこれをCで実行したい他の人は、このコードがWindows 10 64ビット上の最近(最新)のmingwでコンパイルされて検証されています(ただし、mingw 32ビットパッケージがインストールされています)。これはWindows XPで動作するようです/ 2003 では、古い通知領域のアイコンが削除されます。

次のように Chocolatey 経由で mingw をインストールしました。

choco install mingw --x86 --force --params "/exception:sjlj"

(私のシステムでは、コンパイラーがここにインストールされていたため、状況は異なる場合があります。

C:\ProgramData\chocolatey\lib\mingw\tools\install\mingw32\bin\gcc.exe

そして簡単な

gcc refresh_notification_area.c

Windows 2003 (32 ビット) で発生していた古い通知領域アイコンの問題を解決する a.exe が生成されました。

上記の @Stephen Klancher から改変されたコードは次のとおりです (これは Windows XP/2003 でのみ動作する可能性があることに注意してください。これは私の目的を達成しました)。

#include <windows.h>

#define FW(x,y) FindWindowEx(x, NULL, y, "")

int main ()
{

    HWND hNotificationArea;
    RECT r;

    //WinXP
    // technique found at:
    // https://stackoverflow.com/questions/74723/can-you-send-a-signal-to-windows-explorer-to-make-it-refresh-the-systray-icons#18038441
    GetClientRect(
        hNotificationArea = FindWindowEx(
            FW(FW(FW(NULL, "Shell_TrayWnd"), "TrayNotifyWnd"), "SysPager"),
            NULL,
            "ToolbarWindow32",
            "Notification Area"),
        &r);

    for (LONG x = 0; x < r.right; x += 5)
        for (LONG y = 0; y < r.bottom; y += 5)
            SendMessage(
                hNotificationArea,
                WM_MOUSEMOVE,
                0,
                (y << 16) + x);

  return 0;

}

何度も試した結果、次の 3 つの点を知っておく必要があることがわかりました。

  • 非表示のトレイ ウィンドウの親は、 NotifyIconOverflowWindow, 、以外 Shell_TrayWnd.
  • 使用すべきではありません caption のパラメータ FindWindowEx これらは Windows OS の多くの言語バージョンであるため、必ずしも同じタイトルであるとは限りません。
  • 使用 spy++ Visual Studio を使用して、必要なものを見つけたり、確認したりできます。

そこで、@Stephen Klancher と @Louis Davis のコードを変更しました。ありがとうございます。

次のコードは私にとってはうまくいきました。

#define FW(x,y) FindWindowEx(x, NULL, y, L"")
void RefreshTaskbarNotificationArea()
{
    HWND hNotificationArea;
    RECT r;
    GetClientRect(hNotificationArea = FindWindowEx(FW(NULL, L"NotifyIconOverflowWindow"), NULL, L"ToolbarWindow32", NULL), &r);
    for (LONG x = 0; x < r.right; x += 5)
    {
        for (LONG y = 0; y < r.bottom; y += 5)
        {
            SendMessage(hNotificationArea, WM_MOUSEMOVE, 0, (y << 16) + x);
        }
    }
}
ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top