很多軟件安裝以后都會在IE瀏覽器的工具欄上添加一個自己的啟動按鈕,只要點擊該按鈕就可以啟動自己的程序,比較典型的軟件有網(wǎng)絡(luò)螞蟻、金山詞霸、網(wǎng)際快車(FlashGet)等等。如圖1所示,”FlashGet“按鈕就是”網(wǎng)際快車“安裝之后添加的按鈕,這個按鈕能方便用戶啟動程序,而不用從開始菜單中啟動應(yīng)用程序,節(jié)省了很多時間。
這么好的功能,我們的程序當(dāng)然也應(yīng)該有!需要說明的是,IE4.0以下的版本并不支持該功能,直到IE5.0發(fā)布,才使該項技術(shù)大眾化。那么怎么實現(xiàn)這個功能呢?下面讓我們分析一下技術(shù)原理。IE啟動的時候,它會去讀取Windows注冊表中相應(yīng)的數(shù)據(jù),如果該鍵值下面有數(shù)據(jù)并且是正確的,那么它將正確的顯示出來。如果沒有數(shù)據(jù)或者有數(shù)據(jù)但數(shù)據(jù)是非法的,那么他將不以理會。所以,實現(xiàn)該功能并不需要復(fù)雜的技術(shù),僅僅是處理注冊表而已!
下面我們先看看這些有用的數(shù)據(jù)到底寫在什么地方。運(yùn)行RegEdit程序,打開HKEY_LOCAL_MACHINE SOFTWAREMicrosoftInternet ExplorerExtensions主鍵,并找到{D6E814A0-E0C5-11d4-8D29-0050BA6940E3}子鍵。該子鍵的具體含義我先不作解釋,后文中將詳細(xì)介紹。圖2就是FlashGet在IE工具欄上顯示按鈕的奧秘所在其中,是顯示在按鈕上的文字,”FlashGet“就是顯示在IE工具欄按鈕上的文本。
是一個GUID,標(biāo)明FlashGet的類。
按鈕默認(rèn)是否可見,我們當(dāng)然希望按鈕可見了,所以取值為”Yes“.
可執(zhí)行文件的路徑及其文件名,即當(dāng)點擊按鈕時,要執(zhí)行的文件。
顧名思義,就是當(dāng)鼠標(biāo)移動在該按鈕上的時候所顯示的圖標(biāo),我們應(yīng)該有這個經(jīng)驗,就是當(dāng)鼠標(biāo)移動到圖標(biāo)上的時候,圖標(biāo)的顏色會發(fā)生變化,就是這個意思。
就是按鈕所顯示的圖標(biāo)。當(dāng)鼠標(biāo)沒有移動上去的時候?qū)@示圖標(biāo)。
是菜單在狀態(tài)條的提示。
與按鈕相應(yīng)的”工具“菜單里的菜單項名稱。
在動手用VC++來完成這些工作之前,我們先來介紹一些預(yù)備知識一、上文中我們曾經(jīng)提到過GUID.GUID(Globally Unique IDentifier),全球標(biāo)識符,是一個128位的隨機(jī)數(shù),是通過計算機(jī)的網(wǎng)卡和計算機(jī)的時間來共同產(chǎn)生的,所以幾乎不會產(chǎn)生重復(fù)數(shù)。從理論上講,如果一臺機(jī)器上每秒產(chǎn)生10,000,000個GUID,那么也可以保證3240年以上不重復(fù)。既然是隨機(jī)數(shù),當(dāng)然就不能保證絕對無重復(fù),但我們已經(jīng)可以看出,如果要重復(fù)的話,那概率是多么的??!
手工構(gòu)造這么一個128的隨機(jī)數(shù)是相當(dāng)麻煩的,所以VC++提供了兩個工具來產(chǎn)生GUID.一個是UUIDGen.exe,這是一個命令行程序,所以我并不喜歡。另一個是GUIDGen.exe(如圖3所示,你可以在Visual Studio安裝目錄的CommonTools中找到),該程序是一個基于對話框的程序,用它來產(chǎn)生GUID十分方便,所以我非常愛用它而不用UUIDGen.Exe.
VC中的注冊表操作函數(shù)主要要用到的注冊表操作函數(shù)有RegCreateKeyEx()、RegSetValueEx()和RegOpenKeyEx()等。RegCreateKeyEx()的作用是創(chuàng)建一個鍵值,如果該鍵值存在的話,那么則打開它。RegSetValueEx()的作用是對某個特定的鍵值進(jìn)行賦值。RegOpenKeyEx()的作用是打開一個鍵值。具體的函數(shù)參數(shù)請參考MSDN,這里就不再贅述了。
下面我們以一個SDI為例演示函數(shù)的使用,為了與下文統(tǒng)一起來,請把它建立在”C:Test“.假設(shè)我們已經(jīng)建立一個SDI應(yīng)用程序Test并給CTestView添加了一個成員函數(shù)WriteReg().我們將在該函數(shù)中實現(xiàn)在IE瀏覽器的工具菜單上和IE的上下文菜單中添加我們的菜單,并實現(xiàn)響應(yīng)菜單消息。在實現(xiàn)該函數(shù)之前,我們先用GUIDGen產(chǎn)生兩個GUID:{32204547-1C47-11d5-A413-00A00CC191CF}和{1FBA04EE-3024-11d2-8F1F-0000F87ABD16}.
該函數(shù)的主要內(nèi)容如下建立上下文菜單, lpSubKey, 0, ”“, REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL, &phkResult,, ”我們自己的上下文菜單(&W)“, REG_SZ, keyValue,建立工具菜單, lpSubKey, 0, ”“, REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS,NULL,&phkResult,, lpSubKey, 0, KEY_ALL_ACCESS,, ”CLSID“, 0, REG_SZ, (const unsigned char *)((LPCSTR)type),, ”MenuText“, 0, REG_SZ, (const unsigned char *)((LPCSTR)type),我們自己的測試程序, ”MenuStatusBar“, 0, REG_SZ, (const unsigned char *)((LPCSTR)type),, ”Exec“, 0, REG_SZ, (const unsigned char *)((LPCSTR)type),工具欄按鈕, ”ButtonText“, 0, REG_SZ, (const unsigned char *)((LPCSTR)type),,, ”Icon“, 0, REG_SZ, (const unsigned char *)((LPCSTR)type),,, ”HotIcon“, 0, REG_SZ, (const unsigned char *)((LPCSTR)type),, ”Default Visible“, 0, REG_SZ, (const unsigned char *)((LPCSTR)type),代碼中我們還用到了一個GetAppPath()函數(shù),該函數(shù)將返回應(yīng)用程序的路徑,pathtemp,函數(shù)已經(jīng)寫好了,我們只要在程序適當(dāng)?shù)牡胤秸{(diào)用函數(shù)WriteReg()就可以了,例如在CTestView::PreCreateWindow()中?,F(xiàn)在啟動IE,你會發(fā)現(xiàn)IE中有三個地方已經(jīng)有所不同了,如圖4、圖5、圖6所示試試點擊”MyTest“按鈕或者”工具“菜單上的”MyTest“項看看,我們剛才編寫的MyTest.exe是不是自動執(zhí)行了?
那么上下文菜單怎樣執(zhí)行呢?從我們的程序中可以看出,我們是把它與一個。htm文件”MySelf.htm“相關(guān)聯(lián)了,即點擊上下文菜單中的”我們自己的上下文菜單“項,IE將會打開MYSelf.htm文件并執(zhí)行其內(nèi)容。
現(xiàn)在讓我們回想使用網(wǎng)絡(luò)螞蟻的情形:右擊一個文件的URL,選擇”Down by NetAnt“上下文菜單項,IE就會打開網(wǎng)絡(luò)螞蟻并開始下載。那么這個功能是怎么實現(xiàn)的呢?
如果用過3721網(wǎng)址軟件的話,它也會在IE的上下文菜單中添加自己的菜單”訪問3721網(wǎng)站“,只要點擊該菜單,就會打開瀏覽器,進(jìn)入3721網(wǎng)站,這又是怎么實現(xiàn)的呢?
其實,兩種功能都是通過那個htm文件來實現(xiàn)的,只是那個htm文件的內(nèi)容不一樣罷了。下面我們就來揭開這層神秘的面紗。我們先看看3721中文網(wǎng)址,它相對比較簡單。實現(xiàn)點擊上下文菜單并打開一個固定的主頁地址是很簡單的,如果你對HTML語言和Script稍有了解的話,閱讀下面MySelf.Htm的代碼就會非常輕松當(dāng)我們點擊”我們自己的上下文菜單“的時候,IE就會自動打開清華大學(xué)的主頁,非常簡單的幾句語句就解決大問題。事實上確實如此,有些問題沒有認(rèn)清本質(zhì)的時候我們會覺得它很神奇,我們一旦弄清楚了,就覺得很簡單了,是不是?
下面要講的是怎樣實現(xiàn)網(wǎng)絡(luò)螞蟻的功能。不要誤會,我們并不是要實現(xiàn)網(wǎng)絡(luò)螞蟻下載的功能,我們只是實現(xiàn)網(wǎng)絡(luò)螞蟻的啟動功能,即通過點擊”我們自己的上下文菜單“啟動我們的Test程序而已。如果你對COM一點都不知道的話,先去看看這方面的書籍,下面的內(nèi)容會簡單一些。如果暫時不懂COM的話也沒有關(guān)系,我會一步步講的,只要按照我講的步驟操作同樣可以成功。
首先我們建立一個很簡單的COM組件。打開VC++開發(fā)環(huán)境并新建一個工程AddIEFun,Location選擇”C:AddIEFun“,工程的類型是MFC AppWizard(dll),完畢以后點擊OK按鈕。在”Step 1 of 1“對話框中選中Automation(自動化)選項,因為要讓組件支持腳本訪問的話,必須要實現(xiàn)Automation.其它的接收默認(rèn)選項。點擊Finish按鈕,新工程就建立好了。
接下來的工作是添加一個COM對象類。雖然我們用AppWizard創(chuàng)建了應(yīng)用框架,但是還沒有真正的創(chuàng)建COM對象,按照下面的步驟為工程添加一個自動化對象選擇菜單View->ClassWizard打開類向?qū)А?BR> 點擊Add Class按鈕,選擇New命令。
在彈出的New Class對話框的Name中輸入類名CIEcontext,在Base class選擇框中我們選擇CCmdTarget,在對話框的下部我們選中Creatable by type ID,如圖7所示。最后單擊”O(jiān)K“按鈕,這樣CIEcontext創(chuàng)建完成了,并且在類CIEcontext中實現(xiàn)了IIEcontext接口。
下面我們要做的就是添加一個方法真正來實現(xiàn)這個接口,讓它來完成打開Test.exe的功能,步驟如下打開ClassWizard.
選中Automation選項頁。
在Class name字段中選中CIEcontext.
單擊Add Methord按鈕,彈出Add Methord對話框。
在External Name中輸入AddContext,選擇Return type類型為void,因為我們不需要返回什么特別的值,也不需要參數(shù),所以在參數(shù)列表中也不需要添加參數(shù)。
單擊”O(jiān)K“按鈕,關(guān)閉Add Methord對話框。
關(guān)鍵的一步就是要實現(xiàn)AddContext方法。因為我們要在腳本中訪問該方法,而且只訪問該方法就可以了,所以要添加的代碼極其簡單--只有一句代碼,就是打開我們的程序Test.Exe,代碼如下,現(xiàn)在對這個方法進(jìn)行一些說明。該方法調(diào)用了WinExec()函數(shù),目的是運(yùn)行我們自己的程序??梢钥闯觯揂PI有兩個參數(shù):一個是程序的完整路徑和文件名,另一個參數(shù)是打開程序的方式。不過要說明一點,以這種絕對路徑打開程序的方式不是很科學(xué),實際應(yīng)用中,事先應(yīng)該把程序的路徑寫入注冊表,然后在程序中讀取注冊表中的信息。
我們的一個支持自動化的COM組件已經(jīng)建成了,就這么簡單。編譯通過后,你會發(fā)現(xiàn)在工程的Debug目錄下會產(chǎn)生兩個特別的文件:AddIeFun.dll和AddIeFun.tlb,它們就是編譯后產(chǎn)生的庫文件。不過,要讓用戶能在程序中使用它們,首先必須對該組件進(jìn)行注冊。直接運(yùn)行RegSvr32.Exe雖然簡單,但是在VC++的集成環(huán)境中點擊Tools菜單的Register Control更方便。注冊成功的話,會彈出一個消息框,如圖8所示現(xiàn)在,我們大部分任務(wù)已經(jīng)完成了,剩下就是修改MySelf.htm文件,代碼如下錯誤好了,現(xiàn)在你可以放心大膽的使用你的程序了
這么好的功能,我們的程序當(dāng)然也應(yīng)該有!需要說明的是,IE4.0以下的版本并不支持該功能,直到IE5.0發(fā)布,才使該項技術(shù)大眾化。那么怎么實現(xiàn)這個功能呢?下面讓我們分析一下技術(shù)原理。IE啟動的時候,它會去讀取Windows注冊表中相應(yīng)的數(shù)據(jù),如果該鍵值下面有數(shù)據(jù)并且是正確的,那么它將正確的顯示出來。如果沒有數(shù)據(jù)或者有數(shù)據(jù)但數(shù)據(jù)是非法的,那么他將不以理會。所以,實現(xiàn)該功能并不需要復(fù)雜的技術(shù),僅僅是處理注冊表而已!
下面我們先看看這些有用的數(shù)據(jù)到底寫在什么地方。運(yùn)行RegEdit程序,打開HKEY_LOCAL_MACHINE SOFTWAREMicrosoftInternet ExplorerExtensions主鍵,并找到{D6E814A0-E0C5-11d4-8D29-0050BA6940E3}子鍵。該子鍵的具體含義我先不作解釋,后文中將詳細(xì)介紹。圖2就是FlashGet在IE工具欄上顯示按鈕的奧秘所在其中,是顯示在按鈕上的文字,”FlashGet“就是顯示在IE工具欄按鈕上的文本。
是一個GUID,標(biāo)明FlashGet的類。
按鈕默認(rèn)是否可見,我們當(dāng)然希望按鈕可見了,所以取值為”Yes“.
可執(zhí)行文件的路徑及其文件名,即當(dāng)點擊按鈕時,要執(zhí)行的文件。
顧名思義,就是當(dāng)鼠標(biāo)移動在該按鈕上的時候所顯示的圖標(biāo),我們應(yīng)該有這個經(jīng)驗,就是當(dāng)鼠標(biāo)移動到圖標(biāo)上的時候,圖標(biāo)的顏色會發(fā)生變化,就是這個意思。
就是按鈕所顯示的圖標(biāo)。當(dāng)鼠標(biāo)沒有移動上去的時候?qū)@示圖標(biāo)。
是菜單在狀態(tài)條的提示。
與按鈕相應(yīng)的”工具“菜單里的菜單項名稱。
在動手用VC++來完成這些工作之前,我們先來介紹一些預(yù)備知識一、上文中我們曾經(jīng)提到過GUID.GUID(Globally Unique IDentifier),全球標(biāo)識符,是一個128位的隨機(jī)數(shù),是通過計算機(jī)的網(wǎng)卡和計算機(jī)的時間來共同產(chǎn)生的,所以幾乎不會產(chǎn)生重復(fù)數(shù)。從理論上講,如果一臺機(jī)器上每秒產(chǎn)生10,000,000個GUID,那么也可以保證3240年以上不重復(fù)。既然是隨機(jī)數(shù),當(dāng)然就不能保證絕對無重復(fù),但我們已經(jīng)可以看出,如果要重復(fù)的話,那概率是多么的??!
手工構(gòu)造這么一個128的隨機(jī)數(shù)是相當(dāng)麻煩的,所以VC++提供了兩個工具來產(chǎn)生GUID.一個是UUIDGen.exe,這是一個命令行程序,所以我并不喜歡。另一個是GUIDGen.exe(如圖3所示,你可以在Visual Studio安裝目錄的CommonTools中找到),該程序是一個基于對話框的程序,用它來產(chǎn)生GUID十分方便,所以我非常愛用它而不用UUIDGen.Exe.
VC中的注冊表操作函數(shù)主要要用到的注冊表操作函數(shù)有RegCreateKeyEx()、RegSetValueEx()和RegOpenKeyEx()等。RegCreateKeyEx()的作用是創(chuàng)建一個鍵值,如果該鍵值存在的話,那么則打開它。RegSetValueEx()的作用是對某個特定的鍵值進(jìn)行賦值。RegOpenKeyEx()的作用是打開一個鍵值。具體的函數(shù)參數(shù)請參考MSDN,這里就不再贅述了。
下面我們以一個SDI為例演示函數(shù)的使用,為了與下文統(tǒng)一起來,請把它建立在”C:Test“.假設(shè)我們已經(jīng)建立一個SDI應(yīng)用程序Test并給CTestView添加了一個成員函數(shù)WriteReg().我們將在該函數(shù)中實現(xiàn)在IE瀏覽器的工具菜單上和IE的上下文菜單中添加我們的菜單,并實現(xiàn)響應(yīng)菜單消息。在實現(xiàn)該函數(shù)之前,我們先用GUIDGen產(chǎn)生兩個GUID:{32204547-1C47-11d5-A413-00A00CC191CF}和{1FBA04EE-3024-11d2-8F1F-0000F87ABD16}.
該函數(shù)的主要內(nèi)容如下建立上下文菜單, lpSubKey, 0, ”“, REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL, &phkResult,, ”我們自己的上下文菜單(&W)“, REG_SZ, keyValue,建立工具菜單, lpSubKey, 0, ”“, REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS,NULL,&phkResult,, lpSubKey, 0, KEY_ALL_ACCESS,, ”CLSID“, 0, REG_SZ, (const unsigned char *)((LPCSTR)type),, ”MenuText“, 0, REG_SZ, (const unsigned char *)((LPCSTR)type),我們自己的測試程序, ”MenuStatusBar“, 0, REG_SZ, (const unsigned char *)((LPCSTR)type),, ”Exec“, 0, REG_SZ, (const unsigned char *)((LPCSTR)type),工具欄按鈕, ”ButtonText“, 0, REG_SZ, (const unsigned char *)((LPCSTR)type),,, ”Icon“, 0, REG_SZ, (const unsigned char *)((LPCSTR)type),,, ”HotIcon“, 0, REG_SZ, (const unsigned char *)((LPCSTR)type),, ”Default Visible“, 0, REG_SZ, (const unsigned char *)((LPCSTR)type),代碼中我們還用到了一個GetAppPath()函數(shù),該函數(shù)將返回應(yīng)用程序的路徑,pathtemp,函數(shù)已經(jīng)寫好了,我們只要在程序適當(dāng)?shù)牡胤秸{(diào)用函數(shù)WriteReg()就可以了,例如在CTestView::PreCreateWindow()中?,F(xiàn)在啟動IE,你會發(fā)現(xiàn)IE中有三個地方已經(jīng)有所不同了,如圖4、圖5、圖6所示試試點擊”MyTest“按鈕或者”工具“菜單上的”MyTest“項看看,我們剛才編寫的MyTest.exe是不是自動執(zhí)行了?
那么上下文菜單怎樣執(zhí)行呢?從我們的程序中可以看出,我們是把它與一個。htm文件”MySelf.htm“相關(guān)聯(lián)了,即點擊上下文菜單中的”我們自己的上下文菜單“項,IE將會打開MYSelf.htm文件并執(zhí)行其內(nèi)容。
現(xiàn)在讓我們回想使用網(wǎng)絡(luò)螞蟻的情形:右擊一個文件的URL,選擇”Down by NetAnt“上下文菜單項,IE就會打開網(wǎng)絡(luò)螞蟻并開始下載。那么這個功能是怎么實現(xiàn)的呢?
如果用過3721網(wǎng)址軟件的話,它也會在IE的上下文菜單中添加自己的菜單”訪問3721網(wǎng)站“,只要點擊該菜單,就會打開瀏覽器,進(jìn)入3721網(wǎng)站,這又是怎么實現(xiàn)的呢?
其實,兩種功能都是通過那個htm文件來實現(xiàn)的,只是那個htm文件的內(nèi)容不一樣罷了。下面我們就來揭開這層神秘的面紗。我們先看看3721中文網(wǎng)址,它相對比較簡單。實現(xiàn)點擊上下文菜單并打開一個固定的主頁地址是很簡單的,如果你對HTML語言和Script稍有了解的話,閱讀下面MySelf.Htm的代碼就會非常輕松當(dāng)我們點擊”我們自己的上下文菜單“的時候,IE就會自動打開清華大學(xué)的主頁,非常簡單的幾句語句就解決大問題。事實上確實如此,有些問題沒有認(rèn)清本質(zhì)的時候我們會覺得它很神奇,我們一旦弄清楚了,就覺得很簡單了,是不是?
下面要講的是怎樣實現(xiàn)網(wǎng)絡(luò)螞蟻的功能。不要誤會,我們并不是要實現(xiàn)網(wǎng)絡(luò)螞蟻下載的功能,我們只是實現(xiàn)網(wǎng)絡(luò)螞蟻的啟動功能,即通過點擊”我們自己的上下文菜單“啟動我們的Test程序而已。如果你對COM一點都不知道的話,先去看看這方面的書籍,下面的內(nèi)容會簡單一些。如果暫時不懂COM的話也沒有關(guān)系,我會一步步講的,只要按照我講的步驟操作同樣可以成功。
首先我們建立一個很簡單的COM組件。打開VC++開發(fā)環(huán)境并新建一個工程AddIEFun,Location選擇”C:AddIEFun“,工程的類型是MFC AppWizard(dll),完畢以后點擊OK按鈕。在”Step 1 of 1“對話框中選中Automation(自動化)選項,因為要讓組件支持腳本訪問的話,必須要實現(xiàn)Automation.其它的接收默認(rèn)選項。點擊Finish按鈕,新工程就建立好了。
接下來的工作是添加一個COM對象類。雖然我們用AppWizard創(chuàng)建了應(yīng)用框架,但是還沒有真正的創(chuàng)建COM對象,按照下面的步驟為工程添加一個自動化對象選擇菜單View->ClassWizard打開類向?qū)А?BR> 點擊Add Class按鈕,選擇New命令。
在彈出的New Class對話框的Name中輸入類名CIEcontext,在Base class選擇框中我們選擇CCmdTarget,在對話框的下部我們選中Creatable by type ID,如圖7所示。最后單擊”O(jiān)K“按鈕,這樣CIEcontext創(chuàng)建完成了,并且在類CIEcontext中實現(xiàn)了IIEcontext接口。
下面我們要做的就是添加一個方法真正來實現(xiàn)這個接口,讓它來完成打開Test.exe的功能,步驟如下打開ClassWizard.
選中Automation選項頁。
在Class name字段中選中CIEcontext.
單擊Add Methord按鈕,彈出Add Methord對話框。
在External Name中輸入AddContext,選擇Return type類型為void,因為我們不需要返回什么特別的值,也不需要參數(shù),所以在參數(shù)列表中也不需要添加參數(shù)。
單擊”O(jiān)K“按鈕,關(guān)閉Add Methord對話框。
關(guān)鍵的一步就是要實現(xiàn)AddContext方法。因為我們要在腳本中訪問該方法,而且只訪問該方法就可以了,所以要添加的代碼極其簡單--只有一句代碼,就是打開我們的程序Test.Exe,代碼如下,現(xiàn)在對這個方法進(jìn)行一些說明。該方法調(diào)用了WinExec()函數(shù),目的是運(yùn)行我們自己的程序??梢钥闯觯揂PI有兩個參數(shù):一個是程序的完整路徑和文件名,另一個參數(shù)是打開程序的方式。不過要說明一點,以這種絕對路徑打開程序的方式不是很科學(xué),實際應(yīng)用中,事先應(yīng)該把程序的路徑寫入注冊表,然后在程序中讀取注冊表中的信息。
我們的一個支持自動化的COM組件已經(jīng)建成了,就這么簡單。編譯通過后,你會發(fā)現(xiàn)在工程的Debug目錄下會產(chǎn)生兩個特別的文件:AddIeFun.dll和AddIeFun.tlb,它們就是編譯后產(chǎn)生的庫文件。不過,要讓用戶能在程序中使用它們,首先必須對該組件進(jìn)行注冊。直接運(yùn)行RegSvr32.Exe雖然簡單,但是在VC++的集成環(huán)境中點擊Tools菜單的Register Control更方便。注冊成功的話,會彈出一個消息框,如圖8所示現(xiàn)在,我們大部分任務(wù)已經(jīng)完成了,剩下就是修改MySelf.htm文件,代碼如下錯誤好了,現(xiàn)在你可以放心大膽的使用你的程序了

