2008-12-31

替換Windows的Desktop時,如何獲取應用程序注冊的圖標?

今天整理硬盤的時候發現這個,放上來算了,希望對需要的人有幫助。
是以前寫的一個東西——曾經覺得 Windows 的 Desktop 太難看了,所以打算自己寫一個。其它的沒啥子主要是些 GDI+ 的操作。
中間遇到的最大問題是如何獲得應用程序對 TrayNotifyIcon 的注冊。關于這個問題曾經 debug 了 explorer.exe ,才得出以下方法:(Windows XP)

1、如何接收應用程序的注冊圖標通知:
自己實現一個Window注冊Class為"Shell_TrayWnd"(Windows界面中的控件元素都可看作Window——所以叫做 Windows 嘛~~),其下一個子窗口(控件)注冊Class為"TrayNotifyWnd"。
在注冊Class為"Shell_TrayWnd"的窗口中可處理 WM_COPYDATA 消息:
此時 lParam 為 PCOPYDATASTRUCT pcds
(pcds->dwData == 1) 時表示是一個通知消息
此時的 pcds->lpData 結構如下:
(這是我自己定義的一個結構,不知道MSDN是否有這樣的結構,反正我是沒找到,所以自定義了個)

// the struct for WM_COPYDATA to "Shell_TrayWnd"
typedef struct _NOTIFY_MSG_DATA {
 DWORD dwUnknow;  // ??? I don't know what's this ?
 DWORD dwNotifyCode; // NIM_ADD, NIM_DELETE, NIM_MODIFY, ...
 NOTIFYICONDATA nid; // 這里就是應用程序注冊圖標時的數據了
 bool operator== (const _NOTIFY_MSG_DATA& nmd) const
 {
  return nid.hWnd == nmd.nid.hWnd;
 };
} NOTIFY_MSG_DATA, *PNOTIFY_MSG_DATA;
子窗口注冊Class為"TrayNotifyWnd"主要是想和 explorer.exe 保持一致罷了,接收消息的實質上是"Shell_TrayWnd"。

另外,要注意的是:
if (pnid->uFlags & NIF_ICON) // pnid為上面的NOTIFYICONDATA的指針
{
 // Some applications destroy the icon immediately after completing the
 // NIM_ADD/MODIFY message, so we have to make a copy of it.
 if (hIcon)
  ::DestroyIcon(hIcon);
 hIcon = (HICON) ::CopyIcon(pnid->hIcon);

 bChanged = true;
}
某些程序在注冊圖標后會 destory 這個 hIcon ,所以最好是自己拷貝一份——要不然也會出現某些得到的圖標莫名其妙不見了的情況。

2、explorer.exe 出異常中途結束后重啟,得到被終結之前的圖標。
(在XP之前的Win版本中是會丟失的——失去之前注冊的程序圖標)
XP 中主要在以下注冊表項目中,以二進制方式存儲:
[HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Explorer\TrayNotify]
IconStreams 当前项目
PastIconsStream 过去的项目
存儲的數據格式如何,自己dump一下就知道了 :)


嗯……其它的就沒有什么好多說的了,基本上就是一些 GDI+ 操作了。

哦!還有就是 explorer.exe 除了桌面外,還充當文件管理器等其它的作用,所以要替換它的話除了繪制桌面還要做其它方面的準備,或者那些方面的替代品。

差不多就是這些了,以上!

//EOF

1 comments:

Davy Hawk said...

這個算是年終總結吧 :P