引言
本文主要介紹注冊(cè)表的概念與其相關(guān)根項(xiàng)的功能,以及瀏覽器如何通過連接調(diào)用自定義協(xié)議并與客戶端進(jìn)行數(shù)據(jù)通信。文中講及如何通過C#程序、手動(dòng)修改、安裝項(xiàng)目等不同方式對(duì)ajax方式發(fā)送路徑請(qǐng)求,并在回調(diào)函數(shù)中調(diào)用自定義協(xié)議。
最后一節(jié)還將介紹如何調(diào)用自定義協(xié)議去保持?jǐn)?shù)據(jù)的保密性。
希望本篇文章能對(duì)各位的學(xué)習(xí)研究有所幫助,當(dāng)中有所錯(cuò)漏的地方敬請(qǐng)點(diǎn)評(píng)。
目錄
一、注冊(cè)表的概念
二、以C#程序修改注冊(cè)表
三、在 HKEY_CLASSES_ROOT 中添加自定義協(xié)議
四、通過“安裝項(xiàng)目”方式修改注冊(cè)表
五、自定義協(xié)議的調(diào)用
一、注冊(cè)表的概念
在談及Windows自定義協(xié)議之前,不得不預(yù)先介紹的是注冊(cè)表這個(gè)概念。注冊(cè)表是windows操作系統(tǒng)的一個(gè)核心數(shù)據(jù)庫(kù),其作用是充當(dāng)計(jì)算機(jī)上操作系統(tǒng)和應(yīng)用程序的中央信息儲(chǔ)存庫(kù),用于存放著各種系統(tǒng)級(jí)參數(shù)。它能直接控制著windows的啟動(dòng)、硬件驅(qū)動(dòng)程序的裝載以及一些windows應(yīng)用程序的運(yùn)行。
注冊(cè)表中保存有應(yīng)用程序和資源管理器外殼的初始條件、首選項(xiàng)和卸載數(shù)據(jù)等,聯(lián)網(wǎng)計(jì)算機(jī)的整個(gè)系統(tǒng)的設(shè)置和各種許可,文件擴(kuò)展名與應(yīng)用程序的關(guān)聯(lián),硬件部件的描述、狀態(tài)和屬性,性能記錄和其他底層的系統(tǒng)狀態(tài)信息,以及其他數(shù)據(jù)等。
1.1 打開注冊(cè)表
打開 "windows運(yùn)行",然后輸入regedit或regedt32即可打開注冊(cè)表
1.2 注冊(cè)表結(jié)構(gòu)
注冊(cè)表由鍵、子鍵和值項(xiàng)構(gòu)成,一個(gè)鍵就是分支中的一個(gè)文件夾,而子鍵就是這個(gè)文件夾中的子文件夾,子鍵同樣是一個(gè)鍵。一個(gè)值項(xiàng)則是一個(gè)鍵的當(dāng)前定義,由名稱、數(shù)據(jù)類型以及分配的值組成。一個(gè)鍵可以有一個(gè)或多個(gè)值,每個(gè)值的名稱各不相同,如果一個(gè)值的名稱為空,則該值為該鍵的默認(rèn)值。
HKEY_CLASSES_ROOT 用于控制所有文件的擴(kuò)展和所有可執(zhí)行文件相關(guān)的信息,本章提到的Windows自定義協(xié)議也是在此項(xiàng)中注冊(cè)產(chǎn)生的(在后面章節(jié)將詳細(xì)講述);
HEKY_CURRENT_USER 用于管理系統(tǒng)當(dāng)前的用戶信息,及其應(yīng)用程序的相關(guān)資料,例如:當(dāng)前登錄的用戶信息,包括用戶登錄用戶名和暫存的密碼、當(dāng)前用戶使用的應(yīng)用軟件信息等。用戶登錄時(shí),其信息會(huì)在HEKY_USER表中拷貝到此表中,當(dāng)HEKY_USER表中信息發(fā)生改動(dòng)時(shí),HEKY_CURRENT_USER表中的信息也將隨之改動(dòng);
HKEY_CURRENT_MACHINE 用于存儲(chǔ)控制系統(tǒng)和軟件的信息,當(dāng)中包括網(wǎng)絡(luò)和硬件上所有的軟件設(shè)備信息,比如文件的位置,注冊(cè)和未注冊(cè)的狀態(tài),版本號(hào)等等;比較常用的例如在HKEY_LOCAL_MACHINE\Microsoft\Windows\CurrentVersion\Run下注冊(cè)程序,程序就會(huì)在Windows啟動(dòng)時(shí)自動(dòng)運(yùn)行等等。其實(shí)在HKEY_LOCAL_MACHINE\SOFTWARE\Classes里面就包含了HKEY_CLASSES_ROOT信息,而HKEY_CLASSES_ROOT只是它的一個(gè)鍵值的映射,方便信息管理而已;
HEKY_USER 作用是把缺省用戶和目前登陸用戶的信息輸入到注冊(cè)表編輯器,但它僅被那些配置文件激活的登陸用戶使用。當(dāng)任何在HKEY_CURRENT_USER里的信息發(fā)生改變,HKEY_USERS里面的信息也會(huì)相應(yīng)改動(dòng)。
HKEY_CURRENT_CONFIG 用于存儲(chǔ)當(dāng)前系統(tǒng)的配置方式,例如當(dāng)Windows為同一個(gè)硬件安裝有多種驅(qū)動(dòng)程序時(shí),會(huì)在HEKY_CUREENT_MACHINE中記錄多個(gè)程序信息,而在HEKY_CURRENT_CONFIG中只是存儲(chǔ)默認(rèn)使用的驅(qū)動(dòng)信息,Windows 啟動(dòng)時(shí)會(huì)默認(rèn)按照HEKY_CURRENT_CONFIG中的配置調(diào)用相關(guān)的驅(qū)動(dòng)程序;
回到目錄
二、以C#程序修改注冊(cè)表
微軟建立了Registry、RegistryKey 常用類用于修改Windows 注冊(cè)表中的節(jié)點(diǎn)。
2.1 Registry 類
Registry 主要用作獲取 Windows 注冊(cè)表中的根項(xiàng)的 RegistryKey 對(duì)象,并提供訪問項(xiàng)/值對(duì)的 static 方法。
它有以下幾個(gè)常用的屬性可直接用于獲取HEKY_CUREENT_MACHINE、HKEY_CLASSES_ROOT等幾個(gè)基礎(chǔ)項(xiàng)
屬性 | 說明 |
---|---|
ClassesRoot | 定義文檔的類型(或類)以及與那些類型關(guān)聯(lián)的屬性。 該字段讀取 Windows 注冊(cè)表基項(xiàng) HKEY_CLASSES_ROOT。 |
CurrentConfig | 包含有關(guān)非用戶特定的硬件的配置信息。 該字段讀取 Windows 注冊(cè)表基項(xiàng) HKEY_CURRENT_CONFIG。 |
CurrentUser | 包含有關(guān)當(dāng)前用戶首選項(xiàng)的信息。 該字段讀取 Windows 注冊(cè)表基項(xiàng) HKEY_CURRENT_USER |
DynData | 已過時(shí)。包含動(dòng)態(tài)注冊(cè)表數(shù)據(jù)。 該字段讀取 Windows 注冊(cè)表基項(xiàng) HKEY_DYN_DATA。 |
LocalMachine | 包含本地計(jì)算機(jī)的配置數(shù)據(jù)。 該字段讀取 Windows 注冊(cè)表基項(xiàng) HKEY_LOCAL_MACHINE。 |
PerformanceData | 包含軟件組件的性能信息。 該字段讀取 Windows 注冊(cè)表基項(xiàng) HKEY_PERFORMANCE_DATA。 |
Users | 包含有關(guān)默認(rèn)用戶配置的信息。 該字段讀取 Windows 注冊(cè)表基項(xiàng) HKEY_USERS。 |
Registry屬性表2.1.1
Registry 也提供幾個(gè)常用方法用于獲取或設(shè)置注冊(cè)表中指定名稱的項(xiàng)值。
方法 | 說明 |
---|---|
GetValue (String, String, Object) | 檢索與指定的注冊(cè)表項(xiàng)中的指定名稱關(guān)聯(lián)的值。 如果在指定的項(xiàng)中未找到該名稱,則返回您提供的默認(rèn)值;或者,如果指定的項(xiàng)不存在,則返回 null。 |
SetValue(String, String, Object) | 設(shè)置指定的注冊(cè)表項(xiàng)的指定名稱/值對(duì)。 如果指定的項(xiàng)不存在,則創(chuàng)建該項(xiàng)。 |
SetValue(String, String, Object, RegistryValueKind) | 通過使用指定的注冊(cè)表數(shù)據(jù)類型,設(shè)置該指定的注冊(cè)表項(xiàng)的名稱/值對(duì)。 如果指定的項(xiàng)不存在,則創(chuàng)建該項(xiàng)。 |
Registry方法表2.1.2
2.2 RegistryKey 類
RegistryKey類主要用于管理 Windows 注冊(cè)表中的項(xiàng)級(jí)節(jié)點(diǎn),通過 Registry 類的屬性就可以獲取注冊(cè)表中的根節(jié)點(diǎn)。它包含了以下幾個(gè)常用屬性
屬性 | 說明 |
---|---|
Handle | 獲取一個(gè) SafeRegistryHandle 對(duì)象,該對(duì)象表示當(dāng)前 RegistryKey 對(duì)象封裝的注冊(cè)表項(xiàng)。 |
Name | 檢索項(xiàng)的名稱。 |
SubKeyCount | 檢索當(dāng)前項(xiàng)的子項(xiàng)數(shù)目。 |
ValueCount | 檢索項(xiàng)中值的計(jì)數(shù)。 |
View | 獲取用于創(chuàng)建注冊(cè)表項(xiàng)的視圖。 |
RegistryKey屬性表2.2.1
RegistryKey類的方法比較多,通過CreateSubKey(String)、GetValue(String)、SetValue(String, Object)、DeleteValue(String)等常用方法,就可以實(shí)現(xiàn)對(duì)注冊(cè)表的查詢修改。下面簡(jiǎn)單介紹一下RegistryKey的幾個(gè)常用方法
方法 | 說明 |
---|---|
Close() | 關(guān)閉該項(xiàng),如果該項(xiàng)的內(nèi)容已修改,則將該項(xiàng)刷新到磁盤。 |
CreateSubKey(String) | 創(chuàng)建一個(gè)新子項(xiàng)或打開一個(gè)現(xiàn)有子項(xiàng)以進(jìn)行寫訪問。 |
CreateSubKey(String, RegistryKeyPermissionCheck) | 使用指定的權(quán)限檢查選項(xiàng)創(chuàng)建一個(gè)新子項(xiàng)或打開一個(gè)現(xiàn)有子項(xiàng)以進(jìn)行寫訪問。 |
CreateSubKey(String, RegistryKeyPermissionCheck, RegistryOptions) | 使用指定的權(quán)限檢查和注冊(cè)表選項(xiàng),創(chuàng)建或打開一個(gè)用于寫訪問的子項(xiàng)。 |
CreateSubKey(String, RegistryKeyPermissionCheck, RegistrySecurity) | 使用指定的權(quán)限檢查選項(xiàng)和注冊(cè)表安全性創(chuàng)建一個(gè)新子項(xiàng)或打開一個(gè)現(xiàn)有子項(xiàng)以進(jìn)行寫訪問。 |
CreateSubKey(String, RegistryKeyPermissionCheck, RegistryOptions, RegistrySecurity) | 使用指定的權(quán)限檢查選項(xiàng)、注冊(cè)表選項(xiàng)和注冊(cè)表安全性,創(chuàng)建或打開一個(gè)用于寫訪問的子項(xiàng)。 |
DeleteSubKey(String) | 刪除指定的子項(xiàng)。 |
DeleteSubKey(String, Boolean) | 刪除指定的子項(xiàng),并指定在找不到該子項(xiàng)時(shí)是否引發(fā)異常。 |
DeleteSubKeyTree(String) | 遞歸刪除子項(xiàng)和任何子級(jí)子項(xiàng)。 |
DeleteSubKeyTree(String, Boolean) | 以遞歸方式刪除指定的子項(xiàng)和任何子級(jí)子項(xiàng),并指定在找不到子項(xiàng)時(shí)是否引發(fā)異常。 |
DeleteValue(String) | 從此項(xiàng)中刪除指定值。 |
DeleteValue(String, Boolean) | 從此項(xiàng)中刪除指定的值,并指定在找不到該值時(shí)是否引發(fā)異常。 |
Flush() | 將指定的打開注冊(cè)表項(xiàng)的全部特性寫到注冊(cè)表中。 |
GetSubKeyNames() | 檢索包含所有子項(xiàng)名稱的字符串?dāng)?shù)組。 |
GetValue(String) | 檢索與指定名稱關(guān)聯(lián)的值。 如果注冊(cè)表中不存在名稱/值對(duì),則返回 null。 |
GetValue(String, Object) | 檢索與指定名稱關(guān)聯(lián)的值。 如果未找到名稱,則返回您提供的默認(rèn)值。 |
GetValue(String, Object, RegistryValueOptions) | 檢索與指定的名稱和檢索選項(xiàng)關(guān)聯(lián)的值。 如果未找到名稱,則返回您提供的默認(rèn)值。 |
SetValue(String, Object) | 設(shè)置指定的名稱/值對(duì)。 |
RegistryKey方法表2.2.2
2.3 應(yīng)用實(shí)例
下面先通過幾個(gè)例子,簡(jiǎn)單介紹一下如何通過 Registry、RegistryKey 類修改系統(tǒng)注冊(cè)表。
2.3.1 新建自定義的項(xiàng)
下面應(yīng)用程序?qū)?huì)在注冊(cè)表中新建 MyApplication項(xiàng),并在其子項(xiàng)Path的默認(rèn)值中保存應(yīng)用程序的StartupPath、在AppPath值中保存應(yīng)用程序的UserAppDataPath
static void Main(string[] args) { //獲取Machine根項(xiàng) RegistryKey machine = Registry.LocalMachine; //打開SOFTWARE項(xiàng) RegistryKey software = machine.OpenSubKey("SOFTWARE", true); //新項(xiàng)MyApplication項(xiàng) RegistryKey myApplication = software.CreateSubKey("MyApplication"); RegistryKey subkey = myApplication.CreateSubKey("Path"); //新建鍵值,當(dāng)鍵值名稱為空時(shí),將被設(shè)置為默認(rèn)值 subkey.SetValue(null, Application.StartupPath); subkey.SetValue("AppPath", Application.UserAppDataPath); }
運(yùn)行應(yīng)用程序后,打開"windows運(yùn)行",然后輸入regedit,在注冊(cè)表LocalMachine項(xiàng)中可以查找到新建的MyApplication項(xiàng)
2.3.2 開機(jī)啟動(dòng) “命令提示符”
注冊(cè)表所包含的信息很多,其中在“HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Run”處正是用于Windows開機(jī)啟動(dòng)的程序信息。下面以Windows自帶的“命令提示符”工具為例子,通過修改注冊(cè)表實(shí)現(xiàn)開機(jī)啟動(dòng)。(說明:"命令提示符"的路徑是在“C:\Windows\System32\cmd.exe”)
static void Main(string[] args) { //打開注冊(cè)表子項(xiàng) RegistryKey key = Registry.LocalMachine .OpenSubKey("SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Run", true); //增加開機(jī)啟動(dòng)項(xiàng) key.SetValue("Cmd", "C:\\Windows\\System32\\cmd.exe"); }
修改后可以看到注冊(cè)表中在“HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Run”中會(huì)增加了一個(gè)名為Cmd的鍵
當(dāng)重啟計(jì)算機(jī)時(shí)就會(huì)看到“命令提示符”將自動(dòng)啟動(dòng)
回到目錄
三、在 HKEY_CLASSES_ROOT 中添加自定義協(xié)議
上面的章節(jié)已經(jīng)簡(jiǎn)單介紹如何通過程序操作注冊(cè)表,下面將介紹一下如果通過修改HKEY_CLASSES_ROOT中的項(xiàng),建立自定義協(xié)議。
首先建立一個(gè)應(yīng)用程序MyApplication,寫入簡(jiǎn)單的Hello World測(cè)試代碼
static void Main(string[] args) { Console.WriteLine("Hello World"); Console.ReadKey(); }
手動(dòng)在注冊(cè)表中建立下面的項(xiàng)和鍵:
注意:把 command 鍵值設(shè)置為 "D:\C# Projects\MyApplication.exe" "%1",只要當(dāng)中包含標(biāo)示符“%1”,應(yīng)用程序可以根據(jù)自定義協(xié)議的路徑獲取對(duì)應(yīng)的參數(shù),其使用方式將在下面的章節(jié)再詳細(xì)說明。
簡(jiǎn)單測(cè)試:建立一個(gè)HTML頁面,如入以下代碼。
注意:此連接路徑正是以注冊(cè)表產(chǎn)首項(xiàng)的MyApplication名稱相同。
<html xmlns="http://www.w3.org/1999/xhtml"><head> ......</head> <body> <a href="MyApplication://command">Hello World</a> </body></html>
當(dāng)按下Hello World連接符時(shí),系統(tǒng)就會(huì)調(diào)用自定義協(xié)議MyApplication,啟動(dòng)“D:\C# Projects\MyApplication.exe”
回到目錄
四、通過“安裝項(xiàng)目”方式修改注冊(cè)表
4.1 建立應(yīng)用程序
上面章節(jié)所介紹的只是自定義協(xié)議的簡(jiǎn)單使用方式,然而在做軟件項(xiàng)目的時(shí)候,無論是使用C/S或者B/S方式,自定義協(xié)議都必須實(shí)現(xiàn)在客戶端的自動(dòng)安裝才能使用,因此客戶端的注冊(cè)表設(shè)置只能通過程序進(jìn)行修改。有見及此,微軟早在“安裝項(xiàng)目”中設(shè)置了注冊(cè)表修改功能。下面的章節(jié)將為大家介紹如何通過 Visual Studio 2010 的“安裝項(xiàng)目”,實(shí)現(xiàn)注冊(cè)表的修改。
建立一個(gè)新的MyApplication應(yīng)用程序,輸入以下代碼。
[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) { //獲取輸入?yún)?shù) string data = args[0].Split('&')[1]; //把JSON轉(zhuǎn)換成Person對(duì)象 Person person = GetPerson(data); //數(shù)據(jù)顯示 Console.WriteLine(person.Name + "'s age is:" + person.Age); Console.ReadKey(); } } //數(shù)據(jù)轉(zhuǎn)換 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 添加安裝項(xiàng)目
然后在解決方案里面添加一個(gè)“安裝項(xiàng)目”
右鍵點(diǎn)擊"安裝項(xiàng)目",選擇“視圖-文件系統(tǒng)”后,在應(yīng)用程序文件夾中添加當(dāng)前的“MyApplication”項(xiàng)目。
4.3 修改注冊(cè)表
右鍵點(diǎn)擊"安裝項(xiàng)目",選擇“視圖-注冊(cè)表”后,按照第三節(jié)的例子在HKEY_CLASSES_ROOT上建立多個(gè)必要項(xiàng)。為方法獲取此應(yīng)用程序的安裝路徑,可以在MyApplication項(xiàng)中加入一個(gè)鍵值Path,綁定"[TARGETDIR]",便于系統(tǒng)隨時(shí)能通過此鍵值獲取應(yīng)用程序的安裝路徑。
在“安裝項(xiàng)目”中有多個(gè)可用的綁定值,例如:“[TARGETDIR]”用于綁定應(yīng)用程序的安裝路徑,“[Manufacturer]”用于綁定應(yīng)用程序制造商名稱等等。在command的值中輸入"[TARGETDIR]MyApplication.exe""%1",系統(tǒng)成功安裝后,此值就會(huì)轉(zhuǎn)換成應(yīng)用程序的安裝路徑。例如:MyApplication應(yīng)用程序安裝在"D:\C# Projects"安件夾中,那么注冊(cè)表的command默認(rèn)值就會(huì)變成“D:\C# Projects\MyApplication.exe” “%1”。
4.4 添加安裝自定義操作
在安裝應(yīng)用程序的前后,很多時(shí)候需要做一些必要的操作,例如存儲(chǔ)程序的Path值,為應(yīng)用程序生成一個(gè)sn文件作為標(biāo)識(shí)等等。這時(shí)候就可以通過建立Installer的子類,在安裝的前后的事件進(jìn)行操作。
首先建立新項(xiàng)目InstallComponent,在項(xiàng)目中加入一個(gè)具備RunInstaller特性的類繼承Installer類,RunInstaller特性是作用是用于指示在程序集安裝期間是否調(diào)用該安裝程序。而Installer類是Framework 中所有自定義安裝程序的基類,它具備了以下多個(gè)方法。
方法 | 說明 |
---|---|
Commit | 在派生類中重寫時(shí),完成安裝事務(wù)。 |
Install | 在派生類中被重寫時(shí),執(zhí)行安裝。 |
OnAfterInstall | 引發(fā) AfterInstall 事件。 |
OnAfterRollback | 引發(fā) AfterRollback 事件。 |
OnAfterUninstall | 引發(fā) AfterUninstall 事件。 |
OnBeforeInstall | 引發(fā) BeforeInstall 事件。 |
OnBeforeRollback | 引發(fā) BeforeRollback 事件。 |
OnBeforeUninstall | 引發(fā) BeforeUninstall 事件。 |
OnCommitted | 引發(fā) Committed 事件。 |
OnCommitting | 引發(fā) Committing 事件。 |
Rollback | 在派生類中重寫時(shí),還原計(jì)算機(jī)的安裝前狀態(tài)。 |
Uninstall | 在派生類中重寫時(shí),移除安裝。 |
Installer方法表4.4.1
只要自定義的類型繼承了Installer類并重寫 Install、Commit、Rollback 和 Uninstall 等方法,系統(tǒng)就可以在應(yīng)用程序安裝的多個(gè)不同狀態(tài)下進(jìn)行操作。下面這個(gè)常用例子當(dāng)中,MyInstaller加入了AfterInstall事件的處理方法,在MyApplication應(yīng)用程序安裝完成后,會(huì)根據(jù)注冊(cè)表的Path鍵值獲取應(yīng)用程序的安裝路徑,并在該文件夾內(nèi)加入sn文件。sn文件內(nèi)存儲(chǔ)著一個(gè)GUID,作為該應(yīng)用程序的一個(gè)標(biāo)識(shí)。
[RunInstaller(true)] public partial class MyInstaller : Installer { public MyInstaller() : base() { //綁定完成安裝事件的處理方法 this.AfterInstall += new InstallEventHandler(OnAfterInstall); } /// 加入安裝完成后的處理方法 protected override void OnAfterInstall(object sender, InstallEventArgs e) { CreateSn(); } //在完成安裝后建立一個(gè)sn文件,對(duì)該應(yīng)用程序進(jìn)行標(biāo)識(shí) private void CreateSn() { var regKey = Registry.ClassesRoot.OpenSubKey("MyApplication", true); if (regKey != null) { //根據(jù)注冊(cè)表中的Path鍵值,獲取系統(tǒng)在客戶端的安裝路徑 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 在安裝項(xiàng)目中綁定自定義操作
當(dāng)完成自定義操作的設(shè)定后,回到安裝項(xiàng)目,右鍵點(diǎn)擊"安裝項(xiàng)目",選擇“視圖-文件系統(tǒng)”后,在應(yīng)用程序文件夾中添加自定義操作的“InstallComponent”項(xiàng)目。
然后右鍵點(diǎn)擊"安裝項(xiàng)目",選擇“視圖-自定義操作-添加自定義操作-應(yīng)用程序文件夾”,選擇剛才導(dǎo)入的 “InstallComponent”項(xiàng)目。
把安裝、提交、回滾、卸載等操作都與InstallComponent的MyInstaller類進(jìn)行綁定。
生成安裝項(xiàng)目后,點(diǎn)擊setup應(yīng)用程序進(jìn)行系統(tǒng)安裝,完成安裝后你就會(huì)發(fā)現(xiàn)在注冊(cè)表的HKEY_CLASSES_ROOT下將添加了MyApplication項(xiàng)。而且在該應(yīng)用程序文件夾中會(huì)自動(dòng)增加一個(gè)sn文件,里面將保存著一個(gè)CUID碼。
回到目錄
五、自定義協(xié)議的調(diào)用
5.1 以連接方式調(diào)用
調(diào)用自定義協(xié)議的方式很多,其中最簡(jiǎn)單的就是以連接方式來調(diào)用,好像下面的例子,當(dāng)頁面連接地址為MyApplication://自定義協(xié)議時(shí),系統(tǒng)就會(huì)自動(dòng)到注冊(cè)表查找該協(xié)議,根據(jù)command默認(rèn)項(xiàng)的綁定路徑對(duì)該程序進(jìn)行調(diào)用。并把“MyApplication://command&{'ID':'1','Name':'Rose','Age':'26'}" 路徑名作為static void main(string[] args) 方法中的其中一個(gè)參數(shù)輸入。
觀察第4節(jié)的內(nèi)容,自定義協(xié)議的main方法會(huì)把a(bǔ)rgs[0]參數(shù)按照字符'&'進(jìn)行分組,然后把后面的"{'ID':'1','Name':'Rose','Age':'26'}"JSON字符串轉(zhuǎn)換成Person對(duì)象進(jìn)行顯示。
5.2 動(dòng)態(tài)調(diào)用
回顧前面例子,一直都是運(yùn)用最簡(jiǎn)單的連接方式對(duì)自定義協(xié)議進(jìn)行調(diào)用。然而在現(xiàn)實(shí)的開展過程中,這種方法并不可行,因?yàn)槊看握{(diào)用客戶端的自定義協(xié)議可能需要不同的參數(shù),把參數(shù)直接通過連接路徑來傳輸具有安全性問題。
最簡(jiǎn)單的解決方案是把自定義協(xié)議的路徑在IHttpHandler里面生成,再通過ajax來獲取,在回調(diào)函數(shù)中再調(diào)用此協(xié)議。通過此方法,協(xié)議的路徑不會(huì)以文本的方式存在于客戶端。除非是熟悉開發(fā)人員通過測(cè)試工具進(jìn)行逐步檢索,否則一般人不能通過頁面找到自定義協(xié)議信息。
下面就是一個(gè)以IHttpHandler生成自定義協(xié)議的一個(gè)例子,MyHandler會(huì)根據(jù)url路徑獲取請(qǐng)求對(duì)象的id值,然后進(jìn)行數(shù)據(jù)查詢,并把查詢到的對(duì)象轉(zhuǎn)化為JSON格式。最后把自定義協(xié)議的路徑返回到客戶端。
[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); //根據(jù)id進(jìn)行數(shù)據(jù)查找 foreach (var person in DataSource()) { if (person.ID == id) { //把Person對(duì)象轉(zhuǎn)化為JSON數(shù)據(jù) string json = ConvertToJson(person); //輸出自定義協(xié)議路徑 context.Response.Write(GetUrl(json)); } } } } //獲取自定義協(xié)議路徑 private string GetUrl(string json) { return "MyApplication://command&" + json; } //把Person對(duì)象轉(zhuǎn)化為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); } //模擬數(shù)據(jù)源 private IList<Person> DataSource() { IList<Person> list = new List<Person>(); Person person1 = new Person(1, "Rose", 34); list.Add(person1); ...... return list; } }
客戶端通過ajax把id發(fā)送到MyHandler.ashx進(jìn)行查詢,在回調(diào)函數(shù)中調(diào)用所獲取到的自定義協(xié)議。
如果自定義協(xié)議參數(shù)中具有保密資料的信息還可以通過加密方式進(jìn)行傳遞,好像上面的一個(gè)例子,客戶端可以先把自動(dòng)生成的sn發(fā)送到服務(wù)器進(jìn)行記錄,并與客戶ID進(jìn)行綁定。在請(qǐng)求自定義協(xié)議的路徑時(shí)通過IHttpHandler把相關(guān)的信息通過sn進(jìn)行加密,等到數(shù)據(jù)發(fā)送到客戶端后再進(jìn)行解密。
回到目錄
本章小結(jié)
自定義協(xié)議有著廣泛的應(yīng)用,像QQ、迅雷、淘寶等等這些的常見的應(yīng)用程序都會(huì)使用自定義協(xié)議。特別在大型的企業(yè)系統(tǒng)開發(fā)過程中,C/S、B/S融合開發(fā)的情況很常見,這時(shí)候自定義協(xié)議更發(fā)揮其獨(dú)特的作用。一般在系統(tǒng)自動(dòng)更新,客戶端信息獲取等這些功能上都會(huì)使用自定義協(xié)議進(jìn)行開發(fā)。相對(duì)于ActiveX控件,自定義協(xié)議不會(huì)受到瀏覽器的約束,更能簡(jiǎn)化客戶端與瀏覽器之間的信息傳信。
對(duì) .NET 開發(fā)有興趣的朋友歡迎加入QQ群:230564952 共同探討 !
C#綜合揭秘
通過修改注冊(cè)表建立Windows自定義協(xié)議
Entity Framework 并發(fā)處理詳解
細(xì)說進(jìn)程、應(yīng)用程序域與上下文
細(xì)說多線程(上)
細(xì)說多線程(下)
細(xì)說事務(wù)
深入分析委托與事件
作者:風(fēng)塵浪子
http://www.cnblogs.com/leslies2/p/3727762.html
原創(chuàng)作品,轉(zhuǎn)載時(shí)請(qǐng)注明作者及出處
聯(lián)系客服