【轉】C#綜合揭祕——經過修改註冊表創建Windows自定義協議

引言javascript

本文主要介紹註冊表的概念與其相關根項的功能,以及瀏覽器如何經過鏈接調用自定義協議並與客戶端進行數據通訊。文中講及如何經過C#程序、手動修改、安裝項目等不一樣方式對註冊表進行修改。其中經過安裝項目對註冊表進行修改的狀況最爲常見,在通常的應用程序中都會涉及。
當中最爲實用的例子將介紹如何經過"安裝項目"修改註冊表創建自定義協議,在頁面經過ajax方式發送路徑請求,並在回調函數中調用自定義協議。
最後一節還將介紹如何調用自定義協議去保持數據的保密性。
但願本篇文章能對各位的學習研究有所幫助,當中有所錯漏的地方敬請點評。html

 

目錄java

1、註冊表的概念node

2、以C#程序修改註冊表jquery

3、在 HKEY_CLASSES_ROOT 中添加自定義協議ajax

4、經過「安裝項目」方式修改註冊表shell

5、自定義協議的調用數據庫

 

 

 

 

1、註冊表的概念json

在談及Windows自定義協議以前,不得不預先介紹的是註冊表這個概念。註冊表是windows操做系統的一個核心數據庫,其做用是充當計算機上操做系統和應用程序的中央信息儲存庫,用於存放着各類系統級參數。它能直接控制着windows的啓動、硬件驅動程序的裝載以及一些windows應用程序的運行。
註冊表中保存有應用程序和資源管理器外殼的初始條件、首選項和卸載數據等,聯網計算機的整個系統的設置和各類許可,文件擴展名與應用程序的關聯,硬件部件的描述、狀態和屬性,性能記錄和其餘底層的系統狀態信息,以及其餘數據等。windows

1.1 打開註冊表

打開 "windows運行",而後輸入regedit或regedt32便可打開註冊表

 

1.2 註冊表結構

註冊表由鍵、子鍵和值項構成,一個鍵就是分支中的一個文件夾,而子鍵就是這個文件夾中的子文件夾,子鍵一樣是一個鍵。一個值項則是一個鍵的當前定義,由名稱、數據類型以及分配的值組成。一個鍵能夠有一個或多個值,每一個值的名稱各不相同,若是一個值的名稱爲空,則該值爲該鍵的默認值。

HKEY_CLASSES_ROOT 用於控制全部文件的擴展和全部可執行文件相關的信息,本章提到的Windows自定義協議也是在此項中註冊產生的(在後面章節將詳細講述);

HEKY_CURRENT_USER  用於管理系統當前的用戶信息,及其應用程序的相關資料,例如:當前登陸的用戶信息,包括用戶登陸用戶名和暫存的密碼、當前用戶使用的應用軟件信息等。用戶登陸時,其信息會在HEKY_USER表中拷貝到此表中,當HEKY_USER表中信息發生改動時,HEKY_CURRENT_USER表中的信息也將隨之改動;

HKEY_CURRENT_MACHINE  用於存儲控制系統和軟件的信息,當中包括網絡和硬件上全部的軟件設備信息,好比文件的位置,註冊和未註冊的狀態,版本號等等;比較經常使用的例如在HKEY_LOCAL_MACHINE\Microsoft\Windows\CurrentVersion\Run下注冊程序,程序就會在Windows啓動時自動運行等等。其實在HKEY_LOCAL_MACHINE\SOFTWARE\Classes裏面就包含了HKEY_CLASSES_ROOT信息,而HKEY_CLASSES_ROOT只是它的一個鍵值的映射,方便信息管理而已;

HEKY_USER  做用是把缺省用戶和目前登錄用戶的信息輸入到註冊表編輯器,但它僅被那些配置文件激活的登錄用戶使用。當任何在HKEY_CURRENT_USER裏的信息發生改變,HKEY_USERS裏面的信息也會相應改動。

HKEY_CURRENT_CONFIG 用於存儲當前系統的配置方式,例如當Windows爲同一個硬件安裝有多種驅動程序時,會在HEKY_CUREENT_MACHINE中記錄多個程序信息,而在HEKY_CURRENT_CONFIG中只是存儲默認使用的驅動信息,Windows 啓動時會默認按照HEKY_CURRENT_CONFIG中的配置調用相關的驅動程序;

回到目錄

 

2、以C#程序修改註冊表

微軟創建了Registry、RegistryKey 經常使用類用於修改Windows 註冊表中的節點。

2.1 Registry 類

Registry 主要用做獲取 Windows 註冊表中的根項的 RegistryKey 對象,並提供訪問項/值對的 static 方法。
它有如下幾個經常使用的屬性可直接用於獲取HEKY_CUREENT_MACHINE、HKEY_CLASSES_ROOT等幾個基礎項

屬性 說明
ClassesRoot 定義文檔的類型(或類)以及與那些類型關聯的屬性。 該字段讀取 Windows 註冊表基項 HKEY_CLASSES_ROOT。
CurrentConfig 包含有關非用戶特定的硬件的配置信息。 該字段讀取 Windows 註冊表基項 HKEY_CURRENT_CONFIG。
CurrentUser 包含有關當前用戶首選項的信息。 該字段讀取 Windows 註冊表基項 HKEY_CURRENT_USER
DynData 已過期包含動態註冊表數據。 該字段讀取 Windows 註冊表基項 HKEY_DYN_DATA。
LocalMachine 包含本地計算機的配置數據。 該字段讀取 Windows 註冊表基項 HKEY_LOCAL_MACHINE。
PerformanceData 包含軟件組件的性能信息。 該字段讀取 Windows 註冊表基項 HKEY_PERFORMANCE_DATA。
Users 包含有關默認用戶配置的信息。 該字段讀取 Windows 註冊表基項 HKEY_USERS。

Registry屬性表2.1.1

 

Registry 也提供幾個經常使用方法用於獲取或設置註冊表中指定名稱的項值。

方法 說明
GetValue (String, String, Object) 檢索與指定的註冊表項中的指定名稱關聯的值。  若是在指定的項中未找到該名稱,則返回您提供的默認值;或者,若是指定的項不存在,則返回 null。    
SetValue(String, String, Object)   設置指定的註冊表項的指定名稱/值對。  若是指定的項不存在,則建立該項。    
SetValue(String, String, Object, RegistryValueKind)   經過使用指定的註冊表數據類型,設置該指定的註冊表項的名稱/值對。  若是指定的項不存在,則建立該項。    

Registry方法表2.1.2

 

2.2 RegistryKey 類

RegistryKey類主要用於管理 Windows 註冊表中的項級節點,經過 Registry 類的屬性就能夠獲取註冊表中的根節點。它包含了如下幾個經常使用屬性   

屬性 說明
Handle 獲取一個 SafeRegistryHandle 對象,該對象表示當前 RegistryKey 對象封裝的註冊表項。
Name 檢索項的名稱。
SubKeyCount 檢索當前項的子項數目。
ValueCount 檢索項中值的計數。
View 獲取用於建立註冊表項的視圖。

RegistryKey屬性表2.2.1

 

RegistryKey類的方法比較多,經過CreateSubKey(String)、GetValue(String)、SetValue(String, Object)、DeleteValue(String)等經常使用方法,就能夠實現對註冊表的查詢修改。下面簡單介紹一下RegistryKey的幾個經常使用方法   

方法 說明
Close() 關閉該項,若是該項的內容已修改,則將該項刷新到磁盤。
CreateSubKey(String) 建立一個新子項或打開一個現有子項以進行寫訪問。
CreateSubKey(String, RegistryKeyPermissionCheck) 使用指定的權限檢查選項建立一個新子項或打開一個現有子項以進行寫訪問。
CreateSubKey(String, RegistryKeyPermissionCheck, RegistryOptions) 使用指定的權限檢查和註冊表選項,建立或打開一個用於寫訪問的子項。
CreateSubKey(String, RegistryKeyPermissionCheck, RegistrySecurity) 使用指定的權限檢查選項和註冊表安全性建立一個新子項或打開一個現有子項以進行寫訪問。
CreateSubKey(String, RegistryKeyPermissionCheck, RegistryOptions, RegistrySecurity) 使用指定的權限檢查選項、註冊表選項和註冊表安全性,建立或打開一個用於寫訪問的子項。
DeleteSubKey(String) 刪除指定的子項。
DeleteSubKey(String, Boolean) 刪除指定的子項,並指定在找不到該子項時是否引起異常。
DeleteSubKeyTree(String) 遞歸刪除子項和任何子級子項。
DeleteSubKeyTree(String, Boolean) 以遞歸方式刪除指定的子項和任何子級子項,並指定在找不到子項時是否引起異常。
DeleteValue(String) 今後項中刪除指定值。
DeleteValue(String, Boolean) 今後項中刪除指定的值,並指定在找不到該值時是否引起異常。
Flush() 將指定的打開註冊表項的所有特性寫到註冊表中。
GetSubKeyNames() 檢索包含全部子項名稱的字符串數組。
GetValue(String) 檢索與指定名稱關聯的值。  若是註冊表中不存在名稱/值對,則返回 null。 
GetValue(String, Object) 檢索與指定名稱關聯的值。  若是未找到名稱,則返回您提供的默認值。 
GetValue(String, Object, RegistryValueOptions) 檢索與指定的名稱和檢索選項關聯的值。  若是未找到名稱,則返回您提供的默認值。 
SetValue(String, Object) 設置指定的名稱/值對。

RegistryKey方法表2.2.2

 

2.3 應用實例

下面先經過幾個例子,簡單介紹一下如何經過 Registry、RegistryKey 類修改系統註冊表。

2.3.1 新建自定義的項

下面應用程序將會在註冊表中新建 MyApplication項,並在其子項Path的默認值中保存應用程序的StartupPath、在AppPath值中保存應用程序的UserAppDataPath

複製代碼
        static void Main(string[] args)
        {
            //獲取Machine根項
            RegistryKey machine = Registry.LocalMachine;
            //打開SOFTWARE項
            RegistryKey software = machine.OpenSubKey("SOFTWARE", true);
            //新項MyApplication項
            RegistryKey myApplication = software.CreateSubKey("MyApplication");
            RegistryKey subkey = myApplication.CreateSubKey("Path");
            //新建鍵值,當鍵值名稱爲空時,將被設置爲默認值
            subkey.SetValue(null, Application.StartupPath);
            subkey.SetValue("AppPath", Application.UserAppDataPath);
        }
複製代碼

運行應用程序後,打開"windows運行",而後輸入regedit,在註冊表LocalMachine項中能夠查找到新建的MyApplication項

 

2.3.2 開機啓動 「命令提示符」

註冊表所包含的信息不少,其中在「HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Run」處正是用於Windows開機啓動的程序信息。下面以Windows自帶的「命令提示符」工具爲例子,經過修改註冊表實現開機啓動。(說明:"命令提示符"的路徑是在「C:\Windows\System32\cmd.exe」)

複製代碼
      static void Main(string[] args)
        {
            //打開註冊表子項
            RegistryKey key = Registry.LocalMachine
                .OpenSubKey("SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Run", true);
            //增長開機啓動項
            key.SetValue("Cmd", "C:\\Windows\\System32\\cmd.exe");
        }
複製代碼

修改後能夠看到註冊表中在「HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Run」中會增長了一個名爲Cmd的鍵

當重啓計算機時就會看到「命令提示符」將自動啓動

 

回到目錄

 

3、在 HKEY_CLASSES_ROOT 中添加自定義協議

上面的章節已經簡單介紹如何經過程序操做註冊表,下面將介紹一下若是經過修改HKEY_CLASSES_ROOT中的項,創建自定義協議。
首先創建一個應用程序MyApplication,寫入簡單的Hello World測試代碼

   static void Main(string[] args)
        {
            Console.WriteLine("Hello World");
            Console.ReadKey();
        }

手動在註冊表中創建下面的項和鍵:

  • 一、在HKEY_CLASSES_ROOT下添加項MyApplication.
  • 二、修改MyApplication項下的默認值輸入"URL:(可爲空)"。
  • 三、在MyApplication項下再添加一個鍵值"URL Protocol"。(必要健,不然在IE瀏覽器中可能沒法運行)
  • 四、在MyApplication項下新建項"shell"
  • 五、在shell項下新建項"open"
  • 六、在open項下新建項"command"
  • 七、修改command項的默認鍵值爲MyApplication應用程序的路徑 "D:\C# Projects\MyApplication.exe" "%1"

注意:把 command 鍵值設置爲 "D:\C# Projects\MyApplication.exe" "%1",只要當中包含標示符「%1」,應用程序能夠根據自定義協議的路徑獲取對應的參數,其使用方式將在下面的章節再詳細說明。

簡單測試:創建一個HTML頁面,如入如下代碼。
注意:此鏈接路徑正是以註冊表產首項的MyApplication名稱相同。

複製代碼
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
  ......
</head>
 <body>
     <a href="MyApplication://command">Hello World</a>
   </body>
</html>
複製代碼

當按下Hello World鏈接符時,系統就會調用自定義協議MyApplication,啓動「D:\C# Projects\MyApplication.exe」

 

回到目錄

4、經過「安裝項目」方式修改註冊表

4.1 創建應用程序

上面章節所介紹的只是自定義協議的簡單使用方式,然而在作軟件項目的時候,不管是使用C/S或者B/S方式,自定義協議都必須實如今客戶端的自動安裝才能使用,所以客戶端的註冊表設置只能經過程序進行修改。有見及此,微軟早在「安裝項目」中設置了註冊表修改功能。下面的章節將爲你們介紹如何經過 Visual Studio 2010 的「安裝項目」,實現註冊表的修改。
創建一個新的MyApplication應用程序,輸入如下代碼。

複製代碼
    [DataContract]
    public class Person
    {
        [DataMember]
        public int ID;
        [DataMember]
        public string Name;
        [DataMember]
        public int Age;
    }

    class Program
    {
        static void Main(string[] args)
        {
            if (args != null)
            {
                //獲取輸入參數
                string data = args[0].Split('&')[1];
                //把JSON轉換成Person對象
                Person person = GetPerson(data);
                //數據顯示
                Console.WriteLine(person.Name + "'s age is:" + person.Age);
                Console.ReadKey();
            }
        }

        //數據轉換
        static Person GetPerson(string data)
        {
            DataContractJsonSerializer serializer = new 
                DataContractJsonSerializer(typeof(Person));
            MemoryStream stream = new MemoryStream(Encoding.Unicode.GetBytes(data));
            Person person = (Person)serializer.ReadObject(stream);
            stream.Close();
            return person;
        }
    }
複製代碼

 

4.2 添加安裝項目

而後在解決方案裏面添加一個「安裝項目」

右鍵點擊"安裝項目",選擇「視圖-文件系統」後,在應用程序文件夾中添加當前的「MyApplication」項目。

 

4.3 修改註冊表

右鍵點擊"安裝項目",選擇「視圖-註冊表」後,按照第三節的例子在HKEY_CLASSES_ROOT上創建多個必要項。爲方法獲取此應用程序的安裝路徑,能夠在MyApplication項中加入一個鍵值Path,綁定"[TARGETDIR]",便於系統隨時能經過此鍵值獲取應用程序的安裝路徑。

在「安裝項目」中有多個可用的綁定值,例如:「[TARGETDIR]」用於綁定應用程序的安裝路徑,「[Manufacturer]」用於綁定應用程序製造商名稱等等。在command的值中輸入"[TARGETDIR]MyApplication.exe""%1",系統成功安裝後,此值就會轉換成應用程序的安裝路徑。例如:MyApplication應用程序安裝在"D:\C# Projects"安件夾中,那麼註冊表的command默認值就會變成「D:\C# Projects\MyApplication.exe」 「%1」。

 

4.4 添加安裝自定義操做

在安裝應用程序的先後,不少時候須要作一些必要的操做,例如存儲程序的Path值,爲應用程序生成一個sn文件做爲標識等等。這時候就能夠經過創建Installer的子類,在安裝的先後的事件進行操做。
首先創建新項目InstallComponent,在項目中加入一個具有RunInstaller特性的類繼承Installer類,RunInstaller特性是做用是用於指示在程序集安裝期間是否調用該安裝程序。而Installer類是Framework 中全部自定義安裝程序的基類,它具有了如下多個方法。    

方法 說明
Commit 在派生類中重寫時,完成安裝事務。
Install 在派生類中被重寫時,執行安裝。
OnAfterInstall 引起 AfterInstall 事件。
OnAfterRollback 引起 AfterRollback 事件。
OnAfterUninstall 引起 AfterUninstall 事件。
OnBeforeInstall 引起 BeforeInstall 事件。
OnBeforeRollback 引起 BeforeRollback 事件。
OnBeforeUninstall 引起 BeforeUninstall 事件。
OnCommitted 引起 Committed 事件。
OnCommitting 引起 Committing 事件。
Rollback 在派生類中重寫時,還原計算機的安裝前狀態。
Uninstall 在派生類中重寫時,移除安裝。

Installer方法表4.4.1

只要自定義的類型繼承了Installer類並重寫 Install、Commit、Rollback 和 Uninstall 等方法,系統就能夠在應用程序安裝的多個不一樣狀態下進行操做。下面這個經常使用例子當中,MyInstaller加入了AfterInstall事件的處理方法,在MyApplication應用程序安裝完成後,會根據註冊表的Path鍵值獲取應用程序的安裝路徑,並在該文件夾內加入sn文件。sn文件內存儲着一個GUID,做爲該應用程序的一個標識。

複製代碼
   [RunInstaller(true)]
    public partial class MyInstaller : Installer
    {
        public MyInstaller()
            : base()
        {
        //綁定完成安裝事件的處理方法
            this.AfterInstall += new InstallEventHandler(OnAfterInstall);
        }

        /// 加入安裝完成後的處理方法
        protected override void OnAfterInstall(object sender, InstallEventArgs e)
        {
            CreateSn();
        }

      //在完成安裝後創建一個sn文件,對該應用程序進行標識
        private void CreateSn()
        {
            var regKey = Registry.ClassesRoot.OpenSubKey("MyApplication", true);
            if (regKey != null)
            {
                //根據註冊表中的Path鍵值,獲取系統在客戶端的安裝路徑
                string path = regKey.GetValue("Path").ToString();
            //創建sn文件
                string snPath = path + "sn";
                StreamWriter writer = new StreamWriter(snPath, true, Encoding.Unicode);
                writer.Write(Guid.NewGuid().ToString());
                writer.Close();
            }
        }

        /// 重寫安裝過程方法
        public override void Install(IDictionary stateSaver)
        {
            base.Install(stateSaver);
        }

        /// 重寫卸載方法
        public override void Uninstall(IDictionary savedState)
        {
            base.Uninstall(savedState);
        }

        /// 重寫回滾方法
        public override void Rollback(IDictionary savedState)
        {
            base.Rollback(savedState);
        }

        //重寫提交方法
        public override void Commit(IDictionary savedState)
        {
            base.Commit(savedState);
        }
    }
複製代碼

 

4.5 在安裝項目中綁定自定義操做

當完成自定義操做的設定後,回到安裝項目,右鍵點擊"安裝項目",選擇「視圖-文件系統」後,在應用程序文件夾中添加自定義操做的「InstallComponent」項目。

而後右鍵點擊"安裝項目",選擇「視圖-自定義操做-添加自定義操做-應用程序文件夾」,選擇剛纔導入的 「InstallComponent」項目。

把安裝、提交、回滾、卸載等操做都與InstallComponent的MyInstaller類進行綁定。

 

生成安裝項目後,點擊setup應用程序進行系統安裝,完成安裝後你就會發如今註冊表的HKEY_CLASSES_ROOT下將添加了MyApplication項。並且在該應用程序文件夾中會自動增長一個sn文件,裏面將保存着一個CUID碼。

回到目錄

 

5、自定義協議的調用

5.1 以鏈接方式調用

調用自定義協議的方式不少,其中最簡單的就是以鏈接方式來調用,好像下面的例子,當頁面鏈接地址爲MyApplication://自定義協議時,系統就會自動到註冊表查找該協議,根據command默認項的綁定路徑對該程序進行調用。並把「MyApplication://command&{'ID':'1','Name':'Rose','Age':'26'}" 路徑名做爲static void main(string[] args) 方法中的其中一個參數輸入。

複製代碼
<body>
   <script  type="text/javascript">
    window.onload = function () {
        var link = "MyApplication://command&{'ID':'1','Name':'Rose','Age':'26'}";
        location.href = link;
    }
   </script>
</body>
複製代碼

觀察第4節的內容,自定義協議的main方法會把args[0]參數按照字符'&'進行分組,而後把後面的"{'ID':'1','Name':'Rose','Age':'26'}"JSON字符串轉換成Person對象進行顯示。

 

5.2 動態調用

回顧前面例子,一直都是運用最簡單的鏈接方式對自定義協議進行調用。然而在現實的開展過程當中,這種方法並不可行,由於每次調用客戶端的自定義協議可能須要不一樣的參數,把參數直接經過鏈接路徑來傳輸具備安全性問題。
最簡單的解決方案是把自定義協議的路徑在IHttpHandler裏面生成,再經過ajax來獲取,在回調函數中再調用此協議。經過此方法,協議的路徑不會以文本的方式存在於客戶端。除非是熟悉開發人員經過測試工具進行逐步檢索,不然通常人不能經過頁面找到自定義協議信息。
下面就是一個以IHttpHandler生成自定義協議的一個例子,MyHandler會根據url路徑獲取請求對象的id值,而後進行數據查詢,並把查詢到的對象轉化爲JSON格式。最後把自定義協議的路徑返回到客戶端。

複製代碼
    [DataContract]
    public class Person
    {
        public Person(int id, string name, int age)
        {
            ID = id;
            Name = name;
            Age = age;
        }

        [DataMember]
        public int ID;
        [DataMember]
        public string Name;
        [DataMember]
        public int Age;
    }

   public class MyHandler : IHttpHandler
    {
        public bool IsReusable
        {
            get { return true; }
        }

        public void ProcessRequest(HttpContext context)
        {
            //經過QueryString獲取id
            string data = context.Request.QueryString["id"];
            if (data != null)
            {
                int id = int.Parse(data);
                //根據id進行數據查找
                foreach (var person in DataSource())
                {
                    if (person.ID == id)
                    {
                        //把Person對象轉化爲JSON數據
                        string json = ConvertToJson(person);
                        //輸出自定義協議路徑
                        context.Response.Write(GetUrl(json));
                    }
                }
            }
        }

        //獲取自定義協議路徑
        private string GetUrl(string json)
        {
            return "MyApplication://command&" + json;
        }

        //把Person對象轉化爲JSON
        private string ConvertToJson(Person person)
        {
            DataContractJsonSerializer serializer = new
                DataContractJsonSerializer(typeof(Person));
            MemoryStream stream = new MemoryStream();
            serializer.WriteObject(stream, person);
            byte[] bytes = stream.ToArray();
            stream.Close();
            return Encoding.ASCII.GetString(bytes);
        }

        //模擬數據源
        private IList<Person> DataSource()
        {
            IList<Person> list = new List<Person>();
            Person person1 = new Person(1, "Rose", 34);
            list.Add(person1);
            ......
            return list;
        }
    }
複製代碼

客戶端經過ajax把id發送到MyHandler.ashx進行查詢,在回調函數中調用所獲取到的自定義協議。
若是自定義協議參數中具備保密資料的信息還能夠經過加密方式進行傳遞,好像上面的一個例子,客戶端能夠先把自動生成的sn發送到服務器進行記錄,並與客戶ID進行綁定。在請求自定義協議的路徑時經過IHttpHandler把相關的信息經過sn進行加密,等到數據發送到客戶端後再進行解密。

複製代碼
<head>
    <title></title>
    <script src="Scripts/jquery-1.8.2.min.js" type="text/javascript"></script>
</head>
<body>
   <a name="send" id="send" href="#">GetPerson</a>
   <script type="text/javascript">
       $(function () {
           $('#send').click(function () {
               $.ajax({
                   type: "GET",
                   url: "MyHandler.ashx?id=1",
                   data: null,
                   dataType: null,
                   success: function (data) {
                       location.href = data;
                   }
               });
           });
       });
   </script>
</body>
</html>
複製代碼

回到目錄 

 

本章小結

自定義協議有着普遍的應用,像QQ、迅雷、淘寶等等這些的常見的應用程序都會使用自定義協議。特別在大型的企業系統開發過程當中,C/S、B/S融合開發的狀況很常見,這時候自定義協議更發揮其獨特的做用。通常在系統自動更新,客戶端信息獲取等這些功能上都會使用自定義協議進行開發。相對於ActiveX控件,自定義協議不會受到瀏覽器的約束,更能簡化客戶端與瀏覽器之間的信息傳信。

對 .NET 開發有興趣的朋友歡迎加入QQ羣:230564952 共同探討 !

 

C#綜合揭祕

經過修改註冊表創建Windows自定義協議
Entity Framework 併發處理詳解 
細說進程、應用程序域與上下文 
細說多線程(上) 
細說多線程(下)
細說事務 
深刻分析委託與事件

 

from:http://www.cnblogs.com/leslies2/p/3727762.html

相關文章
相關標籤/搜索