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 Read More...

2008-12-13

DOM 还是 SAX

选择 DOM 还是选择 SAX,这取决于下面几个因素:

  • 应用程序的目的:如果打算对数据作出更改并将它输出为 XML,那么在大多数情况下,DOM 是适当的选择。并不是说使用 SAX 就不能更改数据,但是该过程要复杂得多,因为您必须对数据的一份拷贝而不是对数据本身作出更改。
  • 数据容量: 对于大型文件,SAX 是更好的选择。
  • 数据将如何使用:如果只有数据中的少量部分会被使用,那么使用 SAX 来将该部分数据提取到应用程序中可能更好。 另一方面,如果您知道自己以后会回头引用已处理过的大量信息,那么 SAX 也许不是恰当的选择。
  • 对速度的需要: SAX 实现通常要比 DOM 实现更快。
SAX 和 DOM 不是相互排斥的,记住这点很重要。您可以使用 DOM 来创建 SAX 事件流,也可以使用 SAX 来创建 DOM 树。事实上,用于创建 DOM 树的大多数解析器实际上都使用 SAX 来完成这个任务!

參考:
http://www.ibm.com/developerworks/cn/views/xml/tutorials.jsp?cv_doc_id=84979

//EOF Read More...

2008-12-11

網頁互動游戲 Stargate Origin

網頁 Stargate Origin
是一個網頁游戲,主要是造東西然后再造東西,還有掠奪別人的東西…… 比較無聊。

昨天申請了個帳號,今天登錄發現被掠奪一空了 -_-||||

//EOF Read More...

2008-12-10

struts 配置文件中元素的順序

今天才發現原來 struts 配置文件中元素之間的順序是有要求的。

controller 放在 message-resources 之前會報錯,雖然程序能夠正常運行,但在加載的時候會報一個“配置文件解析錯誤”。

看來順序還是不能變~

//EOF Read More...

一个怪异都梦

昨天晚上做了个梦,大致是这样的:

似乎是在急匆匆的赶夜路,夜空非常的清明,奇怪的是空中找不到月亮,但是空中有三颗很亮的星,看起来有两颗在一等星或一等星以上,另一颗大概是二等星,由于这三颗星的亮度太大,其它星基本看不到。虽然我移动的很快,但仍然感觉得到三颗星都在移动,而且是不规则的运动轨迹,想停下来仔细看看,但发现停不下来──哦~ 原来我躺在一个敞篷的运输车厢里,旁边还挤着其他一些穿着和我一样的人。

飞星!飞星!
以上情节与《三体》中的场景很象吧?很奇怪我怎么会做这样的梦,《三体》我看过少说也有一两年了,怎么会在这时候梦到就奇怪了。
不过也不一定就是“飞星”,人造天体/飞行器具 也说不定,还有可能是导弹的尾焰……

大概在这里,就迷迷糊糊的醒来了,之后似乎又迷迷糊糊的睡着了……
总体来说昨晚的睡眠质量特差,断断续续的醒来又迷迷糊糊的睡去,这样往复不断,之后似乎也做了些梦,但都记不得了~~。

这个梦给我印象最深的就是 夜空 ,夜空非常的清明,稀稀的伴着几朵薄薄的云彩。这样的夜空已经很久没有看到过了,至少在我现在住的地方是看不到的。记得最接近的就是我上湘大时的图书馆前坪看到过比较接近的夜空──那是在图书馆还没实行亮化工程前,实行亮化之后也看不到了。

不知道要待到何时才能再次在现实中看到这样的夜空?我希望能在我住的地方仰头就能看到这样的夜空 :)

//EOF Read More...

2008-12-07

ASP.NET TreeView check childs/parents

給 ASP.NET 的 TreeView 寫了一個掛件,主要功能就是在 TreeView 是 ShowCheckBox 模式的時候,當勾選某個節點時能自動的勾選這個節點相關的所有父節點,以及勾選、反勾選這個節點的所有子節點。

功能很簡單純 javascript 實現:

/*************************************************************************
 * change the tree view node's child nodes check-state, when check
 * this node.
 *
 *   NOTE: for ASP.NET TreeView
 *
 * @author h_Davy
 * @version 2008-12-5
 *************************************************************************/

/**
 * check the tree node's childs with this checkbox's stats
 *
 * @param chk   the check box element
 *
 * @private
 */
function _checkTreeChilds(chk)
{
    var childId = chk.id.replace('CheckBox', 'Nodes');
    var child = document.getElementById(childId);
    if (child) {
        var chks = child.getElementsByTagName('input');
        for (var i in chks) {
            if (chks[i].type == "checkbox") {
                chks[i].checked = chk.checked;
            }
        }
    }
}

/**
 * find out the checkbox-node's parent node's checkbox id
 *
 * @param chk       the check box element
 * @param treeView  the treeView element
 *
 * @return  the parent node checkbox id
 *
 * @private
 */
function _findTreeParentId(chk, treeView)
{
    if (!chk) return null;
    var tmpElm = chk.parentNode;
    for(;;) {
        if (tmpElm.tagName == "TABLE") {
            return tmpElm.parentNode.id.replace('Nodes', 'CheckBox');
        } else {
        // go up to find out the parent node, until touch the treeview
            tmpElm = tmpElm.parentNode;
            if (tmpElm == treeView) return null;
        }
    }
    return null;
}

/**
 * check the tree node's parent w this checkbox is checked
 *
 * @param chk   the check box element
 * @param treeView  the treeView element
 *
 * @private
 */
function _checkTreeParent(chk, treeView)
{
    if (!chk.checked) return;
    var tmpChk;
    var parentId = _findTreeParentId(chk);
    for(;;) {
        if (!parentId) return;
        if (chk.checked) {
            tmpChk = document.getElementById(parentId);
            if (!tmpChk || tmpChk == treeView) return;
            tmpChk.checked = true;
        }
        parentId = _findTreeParentId(tmpChk, treeView);
    }
}

/**
 * use this bind to a tree view
 *
 * @param id    the tree view's id (NOTE: it's the HTML node id, not .NET page server id)
 */
function bindCheckEvent(id) {
    var treeView = document.getElementById(id);
    var chks = treeView.getElementsByTagName('input');
    for(var i in chks) {
        if (chks[i].type == "checkbox") {
            chks[i].onclick = function() {
                _checkTreeChilds(this);
                _checkTreeParent(this, treeView);
            };
        }
    }
}

// -- EOF --

使用方法,在要使用的頁面導入以上代碼后,在頁面結尾處加上:
<script type="text/javascript">

bindCheckEvent('TreeView1');
// 這里的 'TreeView1' 就是那個TreeView的ID
// !!!注意:這里的ID指的是最終生成的HTML頁面中的ID,
//                 如果你的TreeView是在某個使用了模板頁的內容頁里面的話,
//                 就有可能是 'ctl00_ContentPlaceHolder1_TreeView1' 了。

</script>

//EOF Read More...