Windows Shell 编程 第六章 【来源:http://blog.csdn.net/wangqiulin123456/article/details/7987951】...
第六章?快捷方式的最短路徑
?????????Windows Shell允許存儲(chǔ)任何對(duì)象的引用到系統(tǒng)范圍內(nèi)的任何地點(diǎn)。例如,當(dāng)你從一個(gè)文件夾拖拽可執(zhí)行程序到另一個(gè)文件夾時(shí),鼠標(biāo)自動(dòng)改變形狀給出除拷貝和移動(dòng)文件之外的第三種選擇。
??????????????????????????????????????????
?
?
?????????除非你確定,否則可執(zhí)行文件是不能拷貝或移動(dòng)的,相反,每次你做這樣的操作時(shí),實(shí)際拷貝或移動(dòng)的是對(duì)它的物理位置的一個(gè)引用,實(shí)際所建立的不是文件的拷貝,而是它的初始位置的連接。
?????????所有這些都是快捷方式的示例,這種東西在老版本的Windows中就已經(jīng)存在—例如,程序管理器的圖標(biāo)就是早期的快捷方式。然而,不要弄混了,它們不是相同的,主要差別在于快捷方式具有可以指向文件對(duì)象這個(gè)更普遍的機(jī)理:不僅是可執(zhí)行文件,也不僅僅是文件。在Windows9x和WindowsNT的Shell中,快捷方式是無處不在的。可以在任何文件夾中找到它們,而最多的是在系統(tǒng)的特殊文件夾中。如果你希望應(yīng)用程序具有印象深刻的功能,比如,添加項(xiàng)到‘Favorites’或‘發(fā)送到’文件夾中,甚至是到‘開始’菜單中,則建立快捷方式是一個(gè)可行的方法。快捷方式是Shell的重要組成部分,也是我們?cè)谶@一章里要徹底討論的內(nèi)容。在這一章中我們打算討論:
?
- ??快捷方式確切地是什么
- ??系統(tǒng)怎樣存儲(chǔ)和裝入快捷方式
- ??怎樣建立和刪除快捷方式
- ??可以編碼處理快捷方式的函數(shù)舉例
?
我們將要給出的例子假設(shè)你對(duì)Shell編程外圍知識(shí)有一定了解,但是例子將進(jìn)一步清晰地說明快捷方式的靈活性。例如,在這一章中,我們將使用熱鍵控件和拖拽功能作為示例應(yīng)用的內(nèi)建功能。
什么是快捷方式
?????????快捷方式表示一個(gè)特定文件對(duì)象的連接,并是一個(gè)具有.lnk擴(kuò)展名的微小二進(jìn)制文件。這里的‘微小’意思是快捷方式文件的尺寸很少達(dá)到1KB。并不是所有的快捷方式都確切地有相同的尺寸,但是它們卻擁有固定的屬性集:目標(biāo)文件對(duì)象,描述,熱鍵,圖標(biāo)等。我們將簡(jiǎn)短地檢測(cè)這些內(nèi)容。
?????????快捷方式遍及整個(gè)Windows Shell,可以作為Shell提供的服務(wù)。從軟件的觀點(diǎn)分析,快捷方式是通過暴露IShellLink接口的COM服務(wù)器實(shí)現(xiàn)的,其接口標(biāo)識(shí)是CLSID_ShellLink。通過這個(gè)接口,你可以設(shè)置快捷方式的各種屬性,和調(diào)用接口方法在磁盤上保存或裝入它們。
?
快捷方式文件類型
?????????正如前面所說的,快捷方式是一個(gè)文件,但是,它是一種Shell以特殊方法處理的文件。Shell當(dāng)然知道一個(gè)類行為‘快捷方式’的文件是一個(gè)對(duì)某件東西的引用,所以當(dāng)你雙擊它的時(shí)候(或單擊它—依賴于活動(dòng)桌面的設(shè)置)返回一個(gè)被指向的對(duì)象,而不是你點(diǎn)擊的文件。
?
建立快捷方式
?????????盡管快捷方式通常都與可執(zhí)行文件相關(guān)聯(lián),但這并不是規(guī)定—你可以建立目錄或非可執(zhí)行文件的快捷方式。就編程而言絕對(duì)沒有不同。同樣也能建立非文件系統(tǒng)對(duì)象的快捷方式(如打印機(jī))。而此時(shí),就有一個(gè)小的差別了,你應(yīng)該使用不同的方法做這個(gè)工作。
?????????建立一個(gè)新的.lnk文件有兩個(gè)選擇,頭一個(gè)依賴于Shell DDE接口,它是直接從舊的程序管理器繼承過來的。我們不考慮這種情況,詳情請(qǐng)參看Shell DDE相關(guān)資料(Internet?客戶端SDK)和MSDN庫(kù)。如果你使用DDE編程而不是下面將要看到的技術(shù),這些資料可以使你知道Windows3.x以來都發(fā)生了哪些改變,以及DDE接口中相對(duì)較新的特征。
?
使用IShellLink接口
?????????第二個(gè)建立快捷方式的方法(也是推薦的方法)是使用IShellLink COM接口,這是一個(gè)十分容易的過程,相關(guān)的步驟是:
?
?
? ? ? 建立服務(wù)器就是調(diào)用CoCreateInstance(),一定要保證在處理之前已經(jīng)適當(dāng)?shù)爻跏蓟薈OM庫(kù)(使用CoInitialize()):
?
[cpp]?view plaincopyprint??
? ? ? CLSID在shlobj.h頭文件中定義,上面的調(diào)用返回指向IShellLink接口的指針,這是處理快捷方式的關(guān)鍵。下面表中列出接口的所有方法,和主要的描述,我們將在隨后的代碼例程中指出某些可能存在的缺陷。
?
| 方法 | 描述 |
| GetArguments() SetArguments() | 返回/設(shè)置命令行變量 |
| GetDescription() SetDescription() | 返回/設(shè)置描述串 |
| GetHotkey() SetHotkey() | 返回/設(shè)置快捷方式的熱鍵 |
| GetIconLocation() SetIconLocation() | 返回/設(shè)置路徑和圖標(biāo)索引 |
| GetIDList() SetIDList() | 返回/設(shè)置鏈接對(duì)象的PIDL。如果操作非文件系統(tǒng)對(duì)象,應(yīng)該使用這兩個(gè)方法代替GetPath()和SetPath() |
| GetPath() SetPath() | 返回/設(shè)置鏈接對(duì)象的路徑和文件名 |
| GetShowCmd() SetShowCmd() | 返回/設(shè)置鏈接對(duì)象的SW_XXX標(biāo)志 |
| GetWorkingDirectory() SetWorkingDirectory() | 返回/設(shè)置工作目錄 |
| SetRelativePath() | 設(shè)置連接對(duì)象的相對(duì)路徑 |
| Resolve() | 恢復(fù)有快捷方式指向的文件對(duì)象 |
?
? ? ? ? 一旦獲得了IShellLink接口的指針,你就可以開始通過設(shè)置目標(biāo)對(duì)象(文件,目錄,或非文件對(duì)象的PIDL),和選項(xiàng)屬性列表,構(gòu)造快捷方式了。你也可以設(shè)置描述文字,快速訪問熱鍵,特殊的圖標(biāo),工作目錄,命令行參數(shù)以及表示窗口(如果有)建立行為的值。下面是典型的代碼段:
?
[cpp]?view plaincopyprint??
? ? ? 此時(shí),對(duì)象僅僅存在于內(nèi)存之中,為了使它永久存在,需要把它存進(jìn)文件。就是為了這個(gè)原因,我們使用的COM服務(wù)器(標(biāo)志為CLSID_ShellLink)才實(shí)現(xiàn)了IPersistFile接口。這是一個(gè)包含讀寫磁盤方法的接口,因此可以為調(diào)用者提供通常編程接口意義上的文件裝入與保存服務(wù)。
?
[cpp]?view plaincopyprint??
? ? IPersistFile接口的兩個(gè)最重要的方法Load()和Save(),二者都要求Unicode串,因而需要轉(zhuǎn)換包含文件名的緩沖為寬字符串格式。
?
快捷方式的全程函數(shù)
? ? ? 我們已經(jīng)給出了形成新Shell輔助函數(shù)的信息,用于建立快捷方式—顯然,Windows Shell API并不提供簡(jiǎn)單而直接的函數(shù)來建立(或處理)快捷方式。另一個(gè)想法是,我們打算給函數(shù)取名為SHCreateShortcutEx()。
? ? 事實(shí)上,盡管Win32API沒有,但是WindowsCE SDK中卻包含了這樣一個(gè)函數(shù)SHCreateShortcut(),具有下面的原型:
? ??
[cpp]?view plaincopyprint??
? ? 我們的函數(shù)接受.lnk文件作為目標(biāo)名,和一個(gè)包含這個(gè)快捷方式所有屬性的結(jié)構(gòu):
?
[cpp]?view plaincopyprint??
? ? 下面是這個(gè)函數(shù)的源代碼,這個(gè)函數(shù)我們將在后面的示例程序中使用:
?
[cpp]?view plaincopyprint??
Shell腳本對(duì)象
?????????Shell腳本對(duì)象提出了一種操作快捷方式更好的方法。這在IE4.0中引進(jìn),并且已經(jīng)成為Windows98?的標(biāo)準(zhǔn)部件。在堅(jiān)固的外殼下,他作為自動(dòng)服務(wù)器,給出了建立和解決快捷方式的編程接口(它們還做許多其它有趣的事情…)
?????????最有趣的是這些部件都可以用于桌面應(yīng)用,HTML頁(yè)面,和整個(gè)Windows腳本環(huán)境。?在第十二章中我們將詳細(xì)討論它們。
?
快捷方式正確的命名
?????????在Shell的4.71版本以后,一個(gè)稱之為SHGetNewLinkInfo()的新函數(shù)對(duì)程序員是可用的。然而與你所希望的不同,這個(gè)函數(shù)不能建立快捷方式。相反,它的用途在于為快捷方式安排一個(gè)正確的名字:
?
[cpp]?view plaincopyprint??
? ? ?這個(gè)函數(shù)接受路徑名的指針或者目標(biāo)對(duì)象的PIDL,這個(gè)參數(shù)存儲(chǔ)在pszLinkTo之中。uFlags值指明它是PIDL還是路徑名。目標(biāo)文件夾是pszDir。
? ? ?這個(gè)例程將給出正在建立的快捷方式文件的名字。這個(gè)名字由pszName參量返回,并假設(shè)其緩沖長(zhǎng)度為MAX_PATH字符數(shù)。當(dāng)你對(duì)已經(jīng)存在的快捷方式建立快捷方式時(shí),Shell并不建立新的連接,而是,簡(jiǎn)單地拷貝和修改這個(gè)目標(biāo)。pfMustCopy就用于這個(gè)目的,它返回一個(gè)布爾值來表示Shell是建立了一個(gè)快捷方式文件還是處理了一個(gè)拷貝,TRUE表示pszLinkTo是一個(gè)已存在的快捷方式,此時(shí)Shell只拷貝和適當(dāng)?shù)匦薷乃?#xff0c;FALSE則是建立一個(gè)全新的快捷方式。最后的可用標(biāo)志是:
?
| 標(biāo)志 | 描述 |
| SHGNLI_PIDL | 如果設(shè)置,pszLinkTo變量將作為PIDL而不是串來考慮 |
| SHGNLI_NOUNIQUE | 如果設(shè)置,Shell將首先確定快捷方式的名字,而后檢查可能的沖突,如果名字與同文件夾中的另一個(gè)發(fā)生沖突,就重復(fù)操作,直到找出唯一的名字為止。 |
| SHGNLI_PREFIXNAME | 如果設(shè)置,名字將總是有一個(gè)‘快捷方式到’的前綴 |
?
? ? ? 事實(shí)上,SHGetNewLinkInfo()函數(shù)努力為快捷方式提供與給定目標(biāo)一致的名字。例如,對(duì)于指向DOS可執(zhí)行文件,將給出.pif擴(kuò)展名,否則將給出.lnk擴(kuò)展名。這個(gè)函數(shù)所執(zhí)行的另一個(gè)檢查是關(guān)于目標(biāo)驅(qū)動(dòng)器是否支持長(zhǎng)文件名。如果不支持,則函數(shù)返回8.3格式的名字。
?
刪除快捷方式
?????????刪除快捷方式與刪除文件一樣容易。更重要的是不必考慮它所指向文件的命運(yùn),因?yàn)槟銉H僅刪除了它的引用。被指向的目標(biāo)完全不受影響。
?
解析快捷方式
?????????建立快捷方式僅僅完成了工作的一半,很快你就會(huì)被讀出快捷方式文件的內(nèi)容弄糊涂。解析快捷方式并不是不同于讀文件,但是這個(gè)操作一般稱之為‘解析’而不是‘讀’。有理由說明它們?cè)诟拍钌系牟町?#xff0c;快捷方式指向一個(gè)文件對(duì)象,但是這只是一個(gè)連接—不是嵌入的。在建立快捷方式的時(shí)候,假定對(duì)象是存在的,但是在讀它的時(shí)候并沒有這個(gè)假設(shè)。當(dāng)需要訪問被引用對(duì)象時(shí),沒有東西來保證它不被刪除,移動(dòng),或重命名。
?????????讀一個(gè)快捷方式簡(jiǎn)單地說明你試圖訪問這個(gè).lnk文件指定的對(duì)象。解析快捷方式則說明系統(tǒng)將試圖了解被引用對(duì)象已經(jīng)移動(dòng)到了什么地方,或它是怎樣被重命名的。
探測(cè)器怎樣解析快捷方式
?????????我們說,解析快捷方式是從讀開始的。然而,如果探測(cè)器在.lnk文件指定的位置找不到有效的文件對(duì)象,則它將在所有驅(qū)動(dòng)器和磁盤目錄上執(zhí)行遞歸搜索,直到找到具有相同尺寸,建立日期以及與快捷方式指向的文件一樣屬性的文件為止。如果搜索失敗,探測(cè)器將顯示如下對(duì)話框:
????????????????????????
?
?
? ? ? ?這個(gè)對(duì)話框可以通過適當(dāng)設(shè)置IShellLink::Resolve()的標(biāo)志加以抑制。當(dāng)然,如果你已經(jīng)刪除了引用對(duì)象,探測(cè)器也就不可能找到它們,即使它們?nèi)匀辉凇厥照尽?#xff0c;也不能。
?
解析快捷方式的函數(shù)
?????????Shell API?也缺少解析快捷方式的函數(shù),所以還是需要我們自己寫。相關(guān)的步驟是:
?
?
? ? ? 整個(gè)操作的核心是Resolve()。語(yǔ)法如下:
?
[cpp]?view plaincopyprint??
? ? ? ?頭一個(gè)參數(shù)是一個(gè)父窗口的Handle,函數(shù)利用它來顯示任何需要顯示的對(duì)話框。另一個(gè)是dwFlags變量,它可以是下列值得組合:
?
| 標(biāo)志 | 描述 |
| SLR_NO_UI | 函數(shù)不顯示任何對(duì)話框,即使查找指向文件失敗。此時(shí)函數(shù)在默認(rèn)的3秒鐘之后返回。超時(shí)時(shí)間可以通過這個(gè)變量的高位字客戶化地指定所期望的毫秒數(shù)。 |
| SLR_ANY_MATCH | 試著解析這個(gè)連接,在失敗時(shí)顯示對(duì)話框 |
| SLR_UPDATE | 如果設(shè)置這個(gè)標(biāo)志,并且引用的對(duì)象已經(jīng)被移動(dòng)或重命名,則快捷方式被更新到指向新的位置,這個(gè)行為不是默認(rèn)的。 |
?
注意,更新快捷方式,使其指向新位置上的文件對(duì)象(如果有)的行為不是自動(dòng)的,必須通過傳遞SLR_UPDATE標(biāo)志到IShellLink::Resolve()函數(shù)顯式地請(qǐng)求。下面是SHResolveShortcut()函數(shù)的源代碼,與它的姊妹例程SHCreateShortcutEx()一樣,它在我們說明快捷方式編程的示例程序中被廣泛地使用。
?
[cpp]?view plaincopyprint??
在裝入文件時(shí),我們使用了IPersistFile接口的Load()方法,它有兩個(gè)變量,Unicode格式的.Lnk文件名,和表示要打開文件的訪問模式的參數(shù)。
?
快捷方式與特殊文件夾
?????????在絕大多數(shù)情況下,如果需要編程建立快捷方式,你都需要在一個(gè)特殊文件夾中建立它。然而,這并不復(fù)雜—僅僅是要指定這個(gè)文件夾的正確路徑而已。在下一節(jié)將要討論的程序中,就允許你在很多這種通常的特殊文件夾:‘我的文檔’,‘桌面’,‘開始菜單’,‘程序’,‘發(fā)送到’和‘Favorites’中建立快捷方式。考慮第五章中的SHGetSpecialFolderPath()函數(shù),它正好能發(fā)現(xiàn)非虛擬文件夾的路徑。
?
示例程序:快捷方式管理
?????????下圖所看到的應(yīng)用是一個(gè)建立和解析快捷方式的控制板管理器。它的對(duì)話框窗口分成兩個(gè)部分:上面部分是解析快捷方式,下面的則是建立新的快捷方式。
???????????
?
?
? ? ? ?這個(gè)用戶界面使你能夠選擇打開.Lnk文件,并且可以拉動(dòng)目標(biāo)—即,支持拖拽快捷方式,和解析快捷方式。在這個(gè)程序中解析的每一個(gè)快捷方式都將在觀察中列出報(bào)告。這里開發(fā)的例子將僅僅顯示目標(biāo),描述和熱鍵信息,要進(jìn)一步增強(qiáng)它的功能,對(duì)于你不應(yīng)該是太大的問題。
?
選擇一個(gè)快捷方式
?????????頭一個(gè)必須考慮的問題是安排一個(gè)‘打開’對(duì)話框來選擇要解析的快捷方式。麻煩是,在默認(rèn)情況下,‘打開’對(duì)話框不能處理快捷方式,因此沒有任何.lnk文件的名字被返回。為了在這種環(huán)境下工作,你必須在GetOpenFileName()函數(shù)中指定OFN_NODEREFERENCELINKS標(biāo)志。就象下面顯示的處理器函數(shù)那樣,它在應(yīng)用對(duì)話框上安排兩個(gè)瀏覽按鈕:
?
[cpp]?view plaincopyprint??
? ? ?使用這個(gè)技術(shù),如果你雙擊一個(gè).lnk文件,探測(cè)器將停在那兒,并返回一個(gè)指向文件的名,而不是進(jìn)入引用的文件。
?
Shell拖拽
?????????我承認(rèn),即使我們是對(duì)Shell進(jìn)行編程,拖拽也不是一個(gè)有重要關(guān)系的科目,但是在我們看到它操作的過程之后,這就顯得有價(jià)值了。VC++資源編輯器就有拉動(dòng)目標(biāo)的特征(通過打開WS_EX_ACCEPTFILES位)。當(dāng)然,它也能使你來規(guī)劃怎樣或什么時(shí)候可以處理拉動(dòng)事件。我們想要限制列表觀察的拖拽操作,但是如果你指派了這個(gè)特征,則我們所要面對(duì)的是必須子類化這個(gè)窗口,以便感知相關(guān)的拉動(dòng)事件。反過來,我們希望使用較簡(jiǎn)單的方法:整個(gè)對(duì)話框都將可以拉動(dòng),但是當(dāng)它捕捉到消息WM_DROPFILES后,應(yīng)該校驗(yàn)列表觀察中所發(fā)生的事件,否則,忽略這個(gè)事件。Shell處理拖拽的函數(shù)都定義在shellapi.h中,有DragQueryPoint(),DragQueryFile()和DragFinish(),后面我們還將繼續(xù)討論這個(gè)課題。
?
顯示結(jié)果
?????????這個(gè)程序在用戶界面上有一個(gè)報(bào)告風(fēng)格的列表觀察,為了較容易的使用它,我們建立了兩個(gè)輔助函數(shù)來幫助在觀察中增加列和串。記住以后我們還會(huì)使用它們。
?????????第一個(gè)函數(shù)是MakeReportView(),它轉(zhuǎn)換列表觀察窗口到具有指定列的報(bào)告風(fēng)格的列表觀察。函數(shù)原型要求傳遞一個(gè)列表觀察的Handle,一個(gè)帶有字符串名和列寬度值的數(shù)組,以及一個(gè)列數(shù)值。為了使函數(shù)盡量簡(jiǎn)潔,我們假定,數(shù)組中偶位置為名字串,奇位置為數(shù)字。
????數(shù)組實(shí)際是一個(gè)串指針數(shù)組—即,一個(gè)32位值的數(shù)組,理解了這個(gè)假設(shè)之后,你就可以如下使用數(shù)組了:
?
[cpp]?view plaincopyprint??
MakeReportView()總是以名字/寬度對(duì)方式處理數(shù)組元素,所以,列數(shù)總是等于數(shù)組尺寸的一半。
?
[cpp]?view plaincopyprint??
MakeReportView()的伴隨例程是AddStringToReportView(),它添加新行到指定的列表觀察。由于底層編程接口的原因,充填報(bào)告風(fēng)格列表觀察所有列要求分幾個(gè)步驟。你應(yīng)該為這個(gè)新項(xiàng)的第一列(主列)添加指定的文字,然后依次在其他列上設(shè)置文字。所有這些步驟都由AddStringToReportView()執(zhí)行,你只需要傳遞一個(gè)包含所有子串的NULL分隔串和在iNumOfCols指出有多少列就可以了。
?
[cpp]?view plaincopyprint??
在本例中列表觀察有三列:‘目標(biāo)’,‘描述’和‘熱鍵’。前兩列是直接的,而第三列使用了以前沒用過的通用控件的一個(gè)用法。這是需要進(jìn)一步說明的。
?
熱鍵通用控制
?????????Windows95引進(jìn)了一個(gè)新的控件,可以使你能夠圖像方式選擇一個(gè)鍵的組合(如圖):
???????????????????????
?
?
? ? ? ? ?使用這個(gè)控件的方法是,敲擊按鍵組合,它解釋鍵盤碼,并轉(zhuǎn)換成相應(yīng)文字,顯然,在建立快捷方式環(huán)境下,這個(gè)控件有更友善的用戶界面。
?????????反過來,在解析快捷方式時(shí),你所有的全部?jī)H是一個(gè)由IShellLink::GetHotkey()返回的數(shù)(精確地:DWORD),這需要把它轉(zhuǎn)換成一個(gè)友善格式的串。
?????????這個(gè)字分解成兩個(gè)字節(jié),表示一個(gè)熱鍵,高字節(jié)是修改符(Alt,Ctrl,Shift,或三者的組合),低字節(jié)是你所敲擊的鍵碼。注意,如果你按了A,這個(gè)碼是65 (大寫字符),不是97(小寫字符)。要使用HotkeyToString()例程,你需要相對(duì)于某些已知常量檢查高字節(jié)的位。下面這個(gè)函數(shù)對(duì)此進(jìn)行了處理:
?
[cpp]?view plaincopyprint??
? ? ? ? HotkeyToString()函數(shù)接受熱鍵值和一個(gè)要充填返回結(jié)構(gòu)的串緩沖。它檢查修改器和建立串的第一部分—如,Ctrl+Alt,然后通過關(guān)聯(lián)的按鍵字符完成這個(gè)操作—如,Ctrl+Alt+X。下圖中顯示了在解析快捷方式時(shí)應(yīng)用的結(jié)果:
?
??????????????????????????????????????
?
收集建立變量
?????????如果不是有點(diǎn)微妙的話,建立快捷方式對(duì)話框的這一部分沒有什么可值得注意的。打開一個(gè)已存在的快捷方式(使用在桌面上的一個(gè)是比較好的),試圖給它分配一個(gè)新的熱鍵,此時(shí),你將發(fā)現(xiàn)熱鍵控件校正你的按鍵。A將變成Ctrl+Alt+A。
?????????正是這個(gè)特征,而且是個(gè)重要特征,因?yàn)?#xff0c;如果你試圖編程地分配一個(gè)非Ctrl+Alt+…形式的熱鍵,這個(gè)熱鍵將永遠(yuǎn)不被識(shí)別。稍微考慮一下,你就會(huì)明白,這種行為不是串—Ctrl+Alt+ …?與可能的加速器沖突。這也使我明白了,在前幾個(gè)例子中為什么Alt+A是錯(cuò)誤的了。
?
給出熱鍵規(guī)則
?????????指令熱鍵控件自動(dòng)置換某些錯(cuò)誤或無效的按鍵組合,你需要使用按鍵規(guī)則。不管它的名字如何,這其實(shí)就是簡(jiǎn)單地發(fā)送消息到熱鍵窗口。為了強(qiáng)制使它接受僅僅Ctrl+Alt前綴的按鍵,你必須:
?
[cpp]?view plaincopyprint??
這個(gè)‘規(guī)則’可以重新解釋為:
?????????無效的按鍵組合總是那些有一個(gè)修改符在wParam中列出的按鍵。
?????????用在lParam中指定的組合鍵置換每一個(gè)無效的按鍵。
如果不是從空(HKCOMB_NONE),Shift(HKCOMB_S),?Alt?(HKCOMB_A)?或?Ctrl(HKCOMB_C)開始,則忽略它們,并用Ctrl+Alt代替之。下面圖像顯示了建立快捷方式時(shí)的這個(gè)過程:
?????????????????
?
?
源代碼
?????????現(xiàn)在看一下這個(gè)示例程序的剩余源代碼。要正確地編譯它必須確保包含shlobj.h,?resource.h?和commdlg.h,以及鏈接comdlg32.lib和ole32.lib。另外,由于我們使用了COM,所以還需要用CoInitialize(NULL)和CoUninitialize()把WinMain()中的DialogBox()調(diào)用括起來。
?
DoCreateShortcut()函數(shù)
?????????這個(gè)函數(shù)在點(diǎn)擊‘建立’按鈕時(shí)被調(diào)用。它從控件中收集參數(shù)和安排調(diào)用SHCreateShortcutEx()函數(shù),在combo框中有一些特殊文件夾的名字。
?
[cpp]?view plaincopyprint??
DoResolveShortcut()函數(shù)
?????????這個(gè)函數(shù)在響應(yīng)‘解析’按鈕的點(diǎn)擊時(shí)調(diào)用。盡管它也接受一個(gè)附加的參數(shù)pszFile,用于表示要解析的文件。如果這個(gè)參數(shù)為NULL,則函數(shù)使用‘快捷方式’編輯框中的內(nèi)容。這個(gè)變量存在的原因是使這個(gè)函數(shù)更容易解析拖拽到程序窗口上的任何文件。DoResolveShortcut()首先調(diào)用我們的函數(shù)SHResolveShortcut()解析這個(gè)快捷方式,然后更新用戶界面,附加一個(gè)新行到報(bào)告列表觀察中。
?
[cpp]?view plaincopyprint??
HandleFileDrop()函數(shù)
?????????在響應(yīng)WM_DROPFILES消息時(shí)調(diào)用此函數(shù),這個(gè)函數(shù)定義了當(dāng)用戶拖拽文件到窗口的客戶區(qū)域時(shí)所要求的操作。接受的數(shù)據(jù)是CF_HDROP類型的,這是一種從探測(cè)器窗口或從桌面拖拽文件操作時(shí)用于Shell移動(dòng)文件環(huán)境下的交互格式。任何具有WS_EX_ACCEPTFILES風(fēng)格設(shè)置的窗口都只對(duì)拖拽操作敏感,并以這種格式封裝數(shù)據(jù)。換句話說,當(dāng)源是Windows Shell,或其它以CF_HDROP格式傳遞參數(shù)的程序時(shí),我們的程序也接受拖拽操作。
?????????CF_HDROP是一種剪裁板格式,用于交換基本為文件名的數(shù)據(jù)項(xiàng)的格式—更多關(guān)于剪裁板格式信息和CF_HDROP數(shù)據(jù)的內(nèi)部結(jié)構(gòu)可以參看VC++的幫助文件。對(duì)于我們而言,重要的是,雖然它的內(nèi)存Handle稱為CF_HDROP,還是有一定數(shù)量的函數(shù)能夠讀出這種格式的數(shù)據(jù)。
?????????當(dāng)你從Shell拉動(dòng)文件的時(shí)候,目標(biāo)窗口接收到消息WM_DROPFILES,其中一個(gè)變量是HDROP型的Handle。我們的HandleFileDrop()函數(shù)首先檢查拉動(dòng)發(fā)生的窗口,如果這個(gè)窗口是列表觀察,則進(jìn)一步抽取和解析各種文件名。你可以拉動(dòng)任何文件到這個(gè)列表觀察上,但是僅僅快捷方式被正確地處理。
?
[cpp]?view plaincopyprint??
DragQueryPoint()告知拉動(dòng)發(fā)生時(shí)點(diǎn)的客戶區(qū)域坐標(biāo),而DragQueryFile()則依次抽取所有包裝在HDROP Handle中的文件。你也可以使用這個(gè)函數(shù)獲得拉動(dòng)的文件數(shù)。最后,必須調(diào)用DragFinish()函數(shù)來結(jié)束拉動(dòng)操作。
APP_DlgProc()函數(shù)
?????????這是應(yīng)用主窗口過程,由于涉及到我們前面給出的幾個(gè)例子,所以看一下這個(gè)處理器是有價(jià)值的:
?
[cpp]?view plaincopyprint??
OnInitDialog()函數(shù)
?????????在這個(gè)工程(project)中有幾個(gè)東西要初始化。在處理combo框時(shí),應(yīng)該有一個(gè)熟知的過程,我們還需要設(shè)置列表觀察控件,以及編程熱鍵控件,使其使用Ctrl+Alt…的格式形式。
?
[cpp]?view plaincopyprint??
在系統(tǒng)文件夾中建立快捷方式
?????????現(xiàn)在可以編譯和運(yùn)行的這個(gè)示例程序可以使你很容易在系統(tǒng)文件夾中建立快捷方式—所需要做的全部操作就是從combo框中選擇一個(gè)文件夾名。如果你希望在你自己的程序中靜默地做這項(xiàng)工作,只要知道所涉及的文件夾名,剩下的就是用這個(gè)全路徑名格式化一個(gè)串。
下面是做這項(xiàng)工作的一個(gè)簡(jiǎn)單的函數(shù)。作為變量,它接受要建立的.lnk文件名,特殊文件夾的ID(有CSIDL_XXX格式的常量),以及指向的文件名。代碼是SHCreateShortcutEx()的一個(gè)封裝:
?
[cpp]?view plaincopyprint??
使用上面的函數(shù),在‘桌面’上,在‘開始’菜單中,在‘程序文件’中,或在‘Favorites’中建立快捷方式就非常容易了。要證明這一點(diǎn),要求在‘開始’菜單中添加一個(gè)新項(xiàng)指向‘記事本’,則只需要:
?
[cpp]?view plaincopyprint??
就可以了,顯然,c:/windows/路徑應(yīng)該置換成你機(jī)器上的實(shí)際Windows的目錄。還要注意,在Windows NT下,‘notepad.exe’存儲(chǔ)在‘System’目錄下。
????你也可以建立指向目錄和非可執(zhí)行文件的快捷方式。事實(shí)上,引用任何系統(tǒng)文件對(duì)象,僅僅需要傳遞路徑到IShellLink::SetPath(),或傳遞PIDL調(diào)用IShellLink::SetIDList()。
?
‘發(fā)送到’文件夾
‘發(fā)送到’文件夾是包含兩個(gè)非快捷方式對(duì)象的文件夾,對(duì)于快捷方式是不值得注意的。如果在Windows上安裝了IE4.0以上版,或在Windows98以上版系統(tǒng)上,‘發(fā)送到’文件夾可能包含對(duì)Email容器或桌面的引用。使用這個(gè)機(jī)理,你也可以從Shell把給定的文件作為新消息的附件直接發(fā)送到你自己的發(fā)件箱,或作為快捷方式發(fā)送到桌面。
?????????????????
????????????????
這個(gè)截圖顯示有兩個(gè)沒有典型的快捷標(biāo)記的項(xiàng),它們是‘桌面快捷方式’,是一個(gè)空的.DeskLink文件,其長(zhǎng)度為0字節(jié)。如果你搜索這個(gè)擴(kuò)展名的注冊(cè)表信息,就會(huì)發(fā)現(xiàn),在其后有一個(gè)COM對(duì)象。
???????
?
?
?????????了解到它由一個(gè)COM對(duì)象支持文件是一大進(jìn)步,但是,是哪一種COM對(duì)象在支持它,COM對(duì)象實(shí)現(xiàn)了什么接口,都還需要進(jìn)一步探討。事實(shí)上,這是一個(gè)Shell擴(kuò)展,更確切地講是一個(gè)拖動(dòng)處理器。我們將在第十五章中討論Shell擴(kuò)展。現(xiàn)在,僅說明‘發(fā)送到’文件夾不僅包含快捷方式還有別的就可以了。使用.DeskLink串純粹是一種表示,你也可以使用其它串來表示。
?
‘最近文檔’文件夾
?????????‘最近文檔’文件夾收集最近打開的文檔。這個(gè)目錄下的內(nèi)容可以通過單擊‘開始’菜單的‘文檔’項(xiàng)來查看,其物理位置在Windows目錄下。然而,奇怪的是在它包含的快捷方式和通過菜單顯示的項(xiàng)之間并不是1:1對(duì)應(yīng)的。
?????????Shell API給出了一個(gè)稱之為SHAddToRecentDocs()的函數(shù),使程序員能夠把文檔的鏈接存儲(chǔ)到這個(gè)文件夾下。
?
[cpp]?view plaincopyprint??
第一個(gè)變量指出了第二個(gè)變量的類型:PIDL或路徑名,可以取SHARD_PATH或SHARD_PIDL值。使用這個(gè)函數(shù),能夠成功地把你的文檔引用加進(jìn)菜單中。但是如果簡(jiǎn)單地在這個(gè)文件夾上建立一個(gè)快捷方式,就不對(duì)了—也就是說,建立快捷方式是必要的但不充分。SHAddToRecentDocs()顯然做了更多的事情。
?????????最終,SHAddToRecentDocs()添加項(xiàng)目到由‘開始菜單’使用的MRU(最近使用的)列表中,并且簡(jiǎn)單地加這個(gè)文件到‘最近文檔’文件夾中。這個(gè)函數(shù)還復(fù)制這個(gè)文件夾中的快捷方式,以及處理菜單的順序。因此,你應(yīng)該堅(jiān)定地使用函數(shù),而不是其他方法,以兼容未來在某些方面實(shí)現(xiàn)方式的變化。
?
小結(jié)
這一章中探討了快捷方式,這個(gè)在Windows的任何書和文章中都討論過的課題。快捷方式是相對(duì)簡(jiǎn)單的,但是沒有建立和解析它的單一函數(shù),這一章中討論并寫出了這樣的函數(shù),還查看了:
?????????快捷方式的作用
?????????怎樣建立和解析它們
?????????某些與快捷方式一道工作的有用的函數(shù)
?????????拖拽和熱鍵控件
?????????快捷方式和系統(tǒng)文件夾之間的關(guān)系
轉(zhuǎn)載于:https://www.cnblogs.com/songtzu/p/3239827.html
總結(jié)
以上是生活随笔為你收集整理的Windows Shell 编程 第六章 【来源:http://blog.csdn.net/wangqiulin123456/article/details/7987951】...的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 使用python+django集成钉钉三
- 下一篇: 数据结构教程读书笔记_递归