程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> .NET網頁編程 >> .NET實例教程 >> 關於二次啟動的一些探討

關於二次啟動的一些探討

編輯:.NET實例教程

        二次啟動,這個名詞恐怕做過產品的都會了解吧。由於二次啟動程序,會產生許多的問題(這一般是根據程序的質量而言的),例如:對共享資源的操作、界面的更新顯示等等。

        一般的產品(至少是我現在參與過的),都或多或少要求進行程序二次啟動的防止,實際的對策各種各樣,這裡只對於實際工作中遇到的一個比較典型的問題進行分析,找出其解決辦法。

        我們是做鬼子外包程序的“大”公司,因此很多顯示、處理式樣是由鬼子決定的。對於二次啟動防止,鬼子的要求是(這裡指的程序是指能最小化的有顯示界面的窗口程序):如果程序已經在用戶A下啟動,

        1、在用戶A下,再次啟動本程序,將程序置前顯示(即顯示在所有窗口最上面);
        2、在用戶B下,再次啟動本程序,彈出二次啟動防止對話框(因為在用戶A下已經啟動過啦);

        第二種情況下如何顯示實際是挺復雜的,不過不是這篇所討論的重點。這裡主要討論第一種情況下該如何完成相應的功能。

        這裡還要分為更為詳細的情況(由於我們應客戶的要求,在Vista下開發,所以提到的都是Vista下的操作。XP下也有類似的操作,不過是否會產生同樣的現象,沒驗證過,:-D ):

        1、首次直接啟動程序,第二次也直接啟動程序(這其中,可能已經通過切換,將程序顯示在其它窗口後面,下面也存在同樣情況,不再贅述);
        2、首次直接啟動程序,將程序最小化,第二次也直接啟動程序;
        3、首次直接啟動程序,第二次提升權限啟動程序;
        4、首次直接啟動程序,將程序最小化,第二次提升權限啟動程序;
        5、首次提升權限啟動程序,第二次直接啟動程序;
        6、首次提升權限啟動程序,將程序最小化,第二次直接啟動程序;
        7、首次提升權限啟動程序,第二次也提升權限啟動程序;
        8、首次提升權限啟動程序,將程序最小化,第二次也提升權限啟動程序;

        應該就這些吧,是不是感覺很啰嗦?俺也很無奈,誰讓現實情況就這樣呢,因為這些不同的情況,才會引出本文的。

        產品是由Visual C# 2005開發的(實際跟版本關系不大,因為使用到的類和方法好像在.net Framework 1.0中也支持,沒仔細查過),使用的都是.Net Framework中提供的類和方法(當然還有一個WinAPI——SetForegroundWindow,用來將窗口置前顯示的,就不多描述了,可以查看MSDN),互斥量Mutex。基本邏輯是這樣的:進入程序後,創建一個命名互斥量。如果互斥量不存在,正常啟動程序;如果互斥量已存在,獲取窗口句柄,將窗口置前顯示。

        說實話,這個邏輯基本上是沒什麼問題的。不過由於.Net Framework的局限性,以及Vista比較討厭的安全性,導致上面提到的第6種情況會無法做到,即將最小化的窗口再顯示出來。

        問題出在哪裡呢?仔細調查發現是下面兩種原因所導致的:

        1、Vista新的安全措施要求低權限用戶不能向高權限用戶發消息,實際上就是高權限用戶一般接收不到低權限用戶發出來的消息;
        2、.Net Framework在創建互斥量等內核對象時,不能指定對象的安全性。

        第一種原因,是系統為了增強安全性所做的必要的措施,看來我們是無法更改了(除非我們能說動MS,要不然就做病毒吧),只好在第二種原因上想辦法。而.net Framework又不支持,只好使用WinAPI了(感想:.net Framework所封裝的類雖然易用,不過還是WinAPI強大啊,好多功能是.Net Framework中沒有的)。更改後的程序啟動邏輯為(必要的清理資源工作就不敘述了):

        1、進入程序後創建全局命名互斥量(mutex);
        2、如果互斥量已存在,發送一個事件(event),退出程序;
        3、使用GetLastError得到的錯誤不是ERROR_FILE_NOT_FOUND,退出;
        4、創建全局命名互斥量;
        5、創建具有指定安全屬性的事件(event),並創建將窗口置前顯示的等待線程;——注意:這裡是解決問題的關鍵!!!
        6、正常啟動程序。

        既然關鍵在於創建具有指定安全性的事件,那麼該如何創建呢?具體代碼如下:

 



SECURITY_ATTRIBUTES sa;
SECURITY_DESCRIPTOR sd;

if ( InitializeSecurityDescriptor(&sd, SECURITY_DESCRIPTOR_REVISION))
...{
    if ( SetSecurityDescriptorDacl(&sd, TRUE, NULL, FALSE))
    ...{
        sa.nLength = sizeof(SECURITY_ATTRIBUTES);
        sa.lpSecurityDescriptor = &sd;
        sa.bInheritHandle = TRUE;
    }
    else
    ...{
        return FALSE;
    }
}
else
...{
    return FALSE;
}

......

const TCHAR tcEventName[] = _T("Global\ShowSelfWindow");
HANDLE hWaitHandle = CreateEvent(&sa, FALSE, FALSE, tcEventName);

 

        Ok啦,由於創建的事件具有sa的安全屬性(所有用戶均可訪問),因此上面提到的第6種情況已經順利解決。


  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved