日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 运维知识 > windows >内容正文

windows

Windows Shell 编程 第六章 【来源:http://blog.csdn.net/wangqiulin123456/article/details/7987951】...

發布時間:2023/12/13 windows 24 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Windows Shell 编程 第六章 【来源:http://blog.csdn.net/wangqiulin123456/article/details/7987951】... 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

第六章?快捷方式的最短路徑

?????????Windows Shell允許存儲任何對象的引用到系統范圍內的任何地點。例如,當你從一個文件夾拖拽可執行程序到另一個文件夾時,鼠標自動改變形狀給出除拷貝和移動文件之外的第三種選擇。

??????????????????????????????????????????

?

?

?????????除非你確定,否則可執行文件是不能拷貝或移動的,相反,每次你做這樣的操作時,實際拷貝或移動的是對它的物理位置的一個引用,實際所建立的不是文件的拷貝,而是它的初始位置的連接。

?????????所有這些都是快捷方式的示例,這種東西在老版本的Windows中就已經存在—例如,程序管理器的圖標就是早期的快捷方式。然而,不要弄混了,它們不是相同的,主要差別在于快捷方式具有可以指向文件對象這個更普遍的機理:不僅是可執行文件,也不僅僅是文件。在Windows9x和WindowsNT的Shell中,快捷方式是無處不在的??梢栽谌魏挝募A中找到它們,而最多的是在系統的特殊文件夾中。如果你希望應用程序具有印象深刻的功能,比如,添加項到‘Favorites’或‘發送到’文件夾中,甚至是到‘開始’菜單中,則建立快捷方式是一個可行的方法。快捷方式是Shell的重要組成部分,也是我們在這一章里要徹底討論的內容。在這一章中我們打算討論:

?

  • ??快捷方式確切地是什么
  • ??系統怎樣存儲和裝入快捷方式
  • ??怎樣建立和刪除快捷方式
  • ??可以編碼處理快捷方式的函數舉例

?

我們將要給出的例子假設你對Shell編程外圍知識有一定了解,但是例子將進一步清晰地說明快捷方式的靈活性。例如,在這一章中,我們將使用熱鍵控件和拖拽功能作為示例應用的內建功能。

什么是快捷方式

?????????快捷方式表示一個特定文件對象的連接,并是一個具有.lnk擴展名的微小二進制文件。這里的‘微小’意思是快捷方式文件的尺寸很少達到1KB。并不是所有的快捷方式都確切地有相同的尺寸,但是它們卻擁有固定的屬性集:目標文件對象,描述,熱鍵,圖標等。我們將簡短地檢測這些內容。

?????????快捷方式遍及整個Windows Shell,可以作為Shell提供的服務。從軟件的觀點分析,快捷方式是通過暴露IShellLink接口的COM服務器實現的,其接口標識是CLSID_ShellLink。通過這個接口,你可以設置快捷方式的各種屬性,和調用接口方法在磁盤上保存或裝入它們。

?

快捷方式文件類型

?????????正如前面所說的,快捷方式是一個文件,但是,它是一種Shell以特殊方法處理的文件。Shell當然知道一個類行為‘快捷方式’的文件是一個對某件東西的引用,所以當你雙擊它的時候(或單擊它—依賴于活動桌面的設置)返回一個被指向的對象,而不是你點擊的文件。

?

建立快捷方式

?????????盡管快捷方式通常都與可執行文件相關聯,但這并不是規定—你可以建立目錄或非可執行文件的快捷方式。就編程而言絕對沒有不同。同樣也能建立非文件系統對象的快捷方式(如打印機)。而此時,就有一個小的差別了,你應該使用不同的方法做這個工作。

?????????建立一個新的.lnk文件有兩個選擇,頭一個依賴于Shell DDE接口,它是直接從舊的程序管理器繼承過來的。我們不考慮這種情況,詳情請參看Shell DDE相關資料(Internet?客戶端SDK)和MSDN庫。如果你使用DDE編程而不是下面將要看到的技術,這些資料可以使你知道Windows3.x以來都發生了哪些改變,以及DDE接口中相對較新的特征。

?

使用IShellLink接口

?????????第二個建立快捷方式的方法(也是推薦的方法)是使用IShellLink COM接口,這是一個十分容易的過程,相關的步驟是:

?

  • ? ? 建立適當的COM服務器
  • ? ? 獲得IShellLink接口指針
  • ? ? 通過IShellLink的方法設置屬性
  • ? ? 獲得IPersistFile接口指針
  • ? ? 使用IPersistFile的方法保存一個文件的快捷方式
  • ?

    ? ? ? 建立服務器就是調用CoCreateInstance(),一定要保證在處理之前已經適當地初始化了COM庫(使用CoInitialize()):

    ?

    [cpp]?view plaincopyprint?
  • IShellLink*?pShellLink?=?NULL;??
  • HRESULT?hr?=?CoCreateInstance(CLSID_ShellLink,?NULL,?CLSCTX_INPROC_SERVER,??
  • IID_IShellLink,?reinterpret_cast<LPVOID*>(&pShellLink));??
  • if(FAILED(hr))??
  • return?hr;??
  • ?

    ? ? ? CLSID在shlobj.h頭文件中定義,上面的調用返回指向IShellLink接口的指針,這是處理快捷方式的關鍵。下面表中列出接口的所有方法,和主要的描述,我們將在隨后的代碼例程中指出某些可能存在的缺陷。

    ?

    方法

    描述

    GetArguments()

    SetArguments()

    返回/設置命令行變量

    GetDescription()

    SetDescription()

    返回/設置描述串

    GetHotkey()

    SetHotkey()

    返回/設置快捷方式的熱鍵

    GetIconLocation()

    SetIconLocation()

    返回/設置路徑和圖標索引

    GetIDList()

    SetIDList()

    返回/設置鏈接對象的PIDL。如果操作非文件系統對象,應該使用這兩個方法代替GetPath()和SetPath()

    GetPath()

    SetPath()

    返回/設置鏈接對象的路徑和文件名

    GetShowCmd()

    SetShowCmd()

    返回/設置鏈接對象的SW_XXX標志

    GetWorkingDirectory()

    SetWorkingDirectory()

    返回/設置工作目錄

    SetRelativePath()

    設置連接對象的相對路徑

    Resolve()

    恢復有快捷方式指向的文件對象

    ?

    ? ? ? ? 一旦獲得了IShellLink接口的指針,你就可以開始通過設置目標對象(文件,目錄,或非文件對象的PIDL),和選項屬性列表,構造快捷方式了。你也可以設置描述文字,快速訪問熱鍵,特殊的圖標,工作目錄,命令行參數以及表示窗口(如果有)建立行為的值。下面是典型的代碼段:

    ?

    [cpp]?view plaincopyprint?
  • pShellLink->SetPath(pszTarget);??
  • pShellLink->SetDescription(pszDesc);??
  • pShellLink->SetHotkey(wHotKey);??
  • pShellLink->SetIconLocation(pszIconPath,?wIconIndex);??
  • ?

    ? ? ? 此時,對象僅僅存在于內存之中,為了使它永久存在,需要把它存進文件。就是為了這個原因,我們使用的COM服務器(標志為CLSID_ShellLink)才實現了IPersistFile接口。這是一個包含讀寫磁盤方法的接口,因此可以為調用者提供通常編程接口意義上的文件裝入與保存服務。

    ?

    [cpp]?view plaincopyprint?
  • IPersistFile*?pPF;??
  • pShellLink->QueryInterface(IID_IPersistFile,?reinterpret_cast<LPVOID*>(&pPF));??
  • MultiByteToWideChar(CP_ACP,?0,?szLnkFile,?-1,?wszLnkFile,?MAX_PATH);??
  • pPF->Save(wszLnkFile,?TRUE);??
  • ?

    ? ? IPersistFile接口的兩個最重要的方法Load()和Save(),二者都要求Unicode串,因而需要轉換包含文件名的緩沖為寬字符串格式。

    ?

    快捷方式的全程函數

    ? ? ? 我們已經給出了形成新Shell輔助函數的信息,用于建立快捷方式—顯然,Windows Shell API并不提供簡單而直接的函數來建立(或處理)快捷方式。另一個想法是,我們打算給函數取名為SHCreateShortcutEx()。

    ? ? 事實上,盡管Win32API沒有,但是WindowsCE SDK中卻包含了這樣一個函數SHCreateShortcut(),具有下面的原型:

    ? ??

    [cpp]?view plaincopyprint?
  • BOOL?SHCreateShortcut(LPTSTR?szShortcut,?LPTSTR?szTarget);??
  • ?

    ? ? 我們的函數接受.lnk文件作為目標名,和一個包含這個快捷方式所有屬性的結構:

    ?

    [cpp]?view plaincopyprint?
  • struct?SHORTCUTSTRUCT??
  • {??
  • ?????LPTSTR?pszTarget;??
  • ?????LPTSTR?pszDesc;??
  • ?????WORD?wHotKey;??
  • ?????LPTSTR?pszIconPath;??
  • ?????WORD?wIconIndex;??
  • };??
  • typedef?SHORTCUTSTRUCT*?LPSHORTCUTSTRUCT;??
  • ?

    ? ? 下面是這個函數的源代碼,這個函數我們將在后面的示例程序中使用:

    ?

    [cpp]?view plaincopyprint?
  • HRESULT?SHCreateShortcutEx(LPCTSTR?szLnkFile,?LPSHORTCUTSTRUCT?lpss)??
  • {??
  • WCHAR?wszLnkFile[MAX_PATH]?=?{0};??
  • IShellLink*?pShellLink?=?NULL;??
  • IPersistFile*?pPF?=?NULL;??
  • //?驗證SHORTCUTSTRUCT指針??
  • if(lpss?==?NULL)??
  • return?E_FAIL;??
  • //?建立COM服務器,假設CoInitialize()已經被調用??
  • HRESULT?hr?=?CoCreateInstance(CLSID_ShellLink,?NULL,??
  • CLSCTX_INPROC_SERVER,?IID_IShellLink,??
  • reinterpret_cast<LPVOID*>(&pShellLink));??
  • if(FAILED(hr))??
  • return?hr;??
  • //設置屬性??
  • pShellLink->SetPath(lpss->pszTarget);??
  • pShellLink->SetDescription(lpss->pszDesc);??
  • pShellLink->SetHotkey(lpss->wHotKey);??
  • pShellLink->SetIconLocation(lpss->pszIconPath,?lpss->wIconIndex);??
  • //取得IPersistFile接口??
  • hr?=?pShellLink->QueryInterface(??
  • IID_IPersistFile,?reinterpret_cast<LPVOID*>(&pPF));??
  • if(FAILED(hr))??
  • {??
  • pShellLink->Release();??
  • return?hr;??
  • }??
  • //?保存LNK(Unicode名)??
  • MultiByteToWideChar(CP_ACP,?MB_PRECOMPOSED,??
  • szLnkFile,?-1,?wszLnkFile,?MAX_PATH);??
  • hr?=?pPF->Save(wszLnkFile,?TRUE);??
  • //?清理??
  • pPF->Release();??
  • pShellLink->Release();??
  • return?hr;??
  • }??
  • ?

    Shell腳本對象

    ?????????Shell腳本對象提出了一種操作快捷方式更好的方法。這在IE4.0中引進,并且已經成為Windows98?的標準部件。在堅固的外殼下,他作為自動服務器,給出了建立和解決快捷方式的編程接口(它們還做許多其它有趣的事情…)

    ?????????最有趣的是這些部件都可以用于桌面應用,HTML頁面,和整個Windows腳本環境。?在第十二章中我們將詳細討論它們。

    ?

    快捷方式正確的命名

    ?????????在Shell的4.71版本以后,一個稱之為SHGetNewLinkInfo()的新函數對程序員是可用的。然而與你所希望的不同,這個函數不能建立快捷方式。相反,它的用途在于為快捷方式安排一個正確的名字:

    ?

    [cpp]?view plaincopyprint?
  • BOOL?SHGetNewLinkInfo(LPCTSTR?pszLinkTo,??
  • LPCTSTR?pszDir,??
  • LPTSTR?pszName,??
  • BOOL*?pfMustCopy,??
  • UINT?uFlags);??
  • ?

    ? ? ?這個函數接受路徑名的指針或者目標對象的PIDL,這個參數存儲在pszLinkTo之中。uFlags值指明它是PIDL還是路徑名。目標文件夾是pszDir。

    ? ? ?這個例程將給出正在建立的快捷方式文件的名字。這個名字由pszName參量返回,并假設其緩沖長度為MAX_PATH字符數。當你對已經存在的快捷方式建立快捷方式時,Shell并不建立新的連接,而是,簡單地拷貝和修改這個目標。pfMustCopy就用于這個目的,它返回一個布爾值來表示Shell是建立了一個快捷方式文件還是處理了一個拷貝,TRUE表示pszLinkTo是一個已存在的快捷方式,此時Shell只拷貝和適當地修改它,FALSE則是建立一個全新的快捷方式。最后的可用標志是:

    ?

    標志

    描述

    SHGNLI_PIDL

    如果設置,pszLinkTo變量將作為PIDL而不是串來考慮

    SHGNLI_NOUNIQUE

    如果設置,Shell將首先確定快捷方式的名字,而后檢查可能的沖突,如果名字與同文件夾中的另一個發生沖突,就重復操作,直到找出唯一的名字為止。

    SHGNLI_PREFIXNAME

    如果設置,名字將總是有一個‘快捷方式到’的前綴

    ?

    ? ? ? 事實上,SHGetNewLinkInfo()函數努力為快捷方式提供與給定目標一致的名字。例如,對于指向DOS可執行文件,將給出.pif擴展名,否則將給出.lnk擴展名。這個函數所執行的另一個檢查是關于目標驅動器是否支持長文件名。如果不支持,則函數返回8.3格式的名字。

    ?

    刪除快捷方式

    ?????????刪除快捷方式與刪除文件一樣容易。更重要的是不必考慮它所指向文件的命運,因為你僅僅刪除了它的引用。被指向的目標完全不受影響。

    ?

    解析快捷方式

    ?????????建立快捷方式僅僅完成了工作的一半,很快你就會被讀出快捷方式文件的內容弄糊涂。解析快捷方式并不是不同于讀文件,但是這個操作一般稱之為‘解析’而不是‘讀’。有理由說明它們在概念上的差異,快捷方式指向一個文件對象,但是這只是一個連接—不是嵌入的。在建立快捷方式的時候,假定對象是存在的,但是在讀它的時候并沒有這個假設。當需要訪問被引用對象時,沒有東西來保證它不被刪除,移動,或重命名。

    ?????????讀一個快捷方式簡單地說明你試圖訪問這個.lnk文件指定的對象。解析快捷方式則說明系統將試圖了解被引用對象已經移動到了什么地方,或它是怎樣被重命名的。

    探測器怎樣解析快捷方式

    ?????????我們說,解析快捷方式是從讀開始的。然而,如果探測器在.lnk文件指定的位置找不到有效的文件對象,則它將在所有驅動器和磁盤目錄上執行遞歸搜索,直到找到具有相同尺寸,建立日期以及與快捷方式指向的文件一樣屬性的文件為止。如果搜索失敗,探測器將顯示如下對話框:

    ????????????????????????

    ?

    ?

    ? ? ? ?這個對話框可以通過適當設置IShellLink::Resolve()的標志加以抑制。當然,如果你已經刪除了引用對象,探測器也就不可能找到它們,即使它們仍然在‘回收站’中,也不能。

    ?

    解析快捷方式的函數

    ?????????Shell API?也缺少解析快捷方式的函數,所以還是需要我們自己寫。相關的步驟是:

    ?

  • ??建立必要的COM服務器
  • ??取得IPersistFile接口指針
  • ? 使用IPersistFile的方法從.lnk文件裝入快捷方式
  • ? 取得IShellLink接口指針
  • ? 解析這個快捷方式
  • ?

    ? ? ? 整個操作的核心是Resolve()。語法如下:

    ?

    [cpp]?view plaincopyprint?
  • HRESULT?IShellLink::Resolve(HWND?hwnd,?DWORD?fFlags);??
  • ?

    ? ? ? ?頭一個參數是一個父窗口的Handle,函數利用它來顯示任何需要顯示的對話框。另一個是dwFlags變量,它可以是下列值得組合:

    ?

    標志

    描述

    SLR_NO_UI

    函數不顯示任何對話框,即使查找指向文件失敗。此時函數在默認的3秒鐘之后返回。超時時間可以通過這個變量的高位字客戶化地指定所期望的毫秒數。

    SLR_ANY_MATCH

    試著解析這個連接,在失敗時顯示對話框

    SLR_UPDATE

    如果設置這個標志,并且引用的對象已經被移動或重命名,則快捷方式被更新到指向新的位置,這個行為不是默認的。

    ?

    注意,更新快捷方式,使其指向新位置上的文件對象(如果有)的行為不是自動的,必須通過傳遞SLR_UPDATE標志到IShellLink::Resolve()函數顯式地請求。下面是SHResolveShortcut()函數的源代碼,與它的姊妹例程SHCreateShortcutEx()一樣,它在我們說明快捷方式編程的示例程序中被廣泛地使用。

    ?

    [cpp]?view plaincopyprint?
  • HRESULT?SHResolveShortcut(LPCTSTR?szLnkFile,?LPSHORTCUTSTRUCT?lpss)??
  • {??
  • WCHAR?wszLnkFile[MAX_PATH]?=?{0};??
  • IShellLink*?pShellLink?=?NULL;??
  • IPersistFile*?pPF?=?NULL;??
  • //?建立合適的COM服務器??
  • HRESULT?hr?=?CoCreateInstance(CLSID_ShellLink,?NULL,CLSCTX_INPROC_SERVER,??
  • ?IID_IShellLink,reinterpret_cast<LPVOID*>(&pShellLink));??
  • if(FAILED(hr))??
  • return?hr;??
  • //?取得裝入.LNK?文件的IPersistFile接口??
  • hr?=?pShellLink->QueryInterface(IID_IPersistFile,??
  • ?reinterpret_cast<LPVOID*>(&pPF));??
  • if(FAILED(hr))??
  • {??
  • pShellLink->Release();??
  • return?hr;??
  • }??
  • //?裝入快捷方式(Unicode?名)??
  • MultiByteToWideChar(CP_ACP,?0,?szLnkFile,?-1,?wszLnkFile,?MAX_PATH);??
  • hr?=?pPF->Load(wszLnkFile,?STGM_READ);??
  • if(FAILED(hr))??
  • {??
  • pPF->Release();??
  • pShellLink->Release();??
  • return?hr;??
  • }??
  • //?解析連接??
  • hr?=?pShellLink->Resolve(NULL,?SLR_ANY_MATCH);??
  • if(FAILED(hr))??
  • {??
  • pPF->Release();??
  • pShellLink->Release();??
  • return?hr;??
  • }??
  • //?抽取信息,充填到lpss??
  • if(lpss?!=?NULL)??
  • {??
  • TCHAR?szPath[MAX_PATH]?=?{0};??
  • TCHAR?szDesc[MAX_PATH]?=?{0};??
  • TCHAR?szIcon[MAX_PATH]?=?{0};??
  • WORD?w?=?0;??
  • WORD?wIcon?=?0;??
  • WIN32_FIND_DATA?wfd;??
  • pShellLink->GetPath(szPath,?MAX_PATH,?&wfd,?SLGP_SHORTPATH);??
  • pShellLink->GetDescription(szDesc,?MAX_PATH);??
  • pShellLink->GetHotkey(&w);??
  • pShellLink->GetIconLocation(szIcon,?MAX_PATH,??
  • ?reinterpret_cast<int*>(&wIcon));??
  • lpss->pszTarget?=?szPath;??
  • lpss->pszDesc?=?szDesc;??
  • lpss->pszIconPath?=?szIcon;??
  • lpss->wHotKey?=?w;??
  • lpss->wIconIndex?=?wIcon;??
  • }??
  • pPF->Release();??
  • pShellLink->Release();??
  • return?hr;??
  • }??
  • ?

    在裝入文件時,我們使用了IPersistFile接口的Load()方法,它有兩個變量,Unicode格式的.Lnk文件名,和表示要打開文件的訪問模式的參數。

    ?

    快捷方式與特殊文件夾

    ?????????在絕大多數情況下,如果需要編程建立快捷方式,你都需要在一個特殊文件夾中建立它。然而,這并不復雜—僅僅是要指定這個文件夾的正確路徑而已。在下一節將要討論的程序中,就允許你在很多這種通常的特殊文件夾:‘我的文檔’,‘桌面’,‘開始菜單’,‘程序’,‘發送到’和‘Favorites’中建立快捷方式??紤]第五章中的SHGetSpecialFolderPath()函數,它正好能發現非虛擬文件夾的路徑。

    ?

    示例程序:快捷方式管理

    ?????????下圖所看到的應用是一個建立和解析快捷方式的控制板管理器。它的對話框窗口分成兩個部分:上面部分是解析快捷方式,下面的則是建立新的快捷方式。

    ???????????

    ?

    ?

    ? ? ? ?這個用戶界面使你能夠選擇打開.Lnk文件,并且可以拉動目標—即,支持拖拽快捷方式,和解析快捷方式。在這個程序中解析的每一個快捷方式都將在觀察中列出報告。這里開發的例子將僅僅顯示目標,描述和熱鍵信息,要進一步增強它的功能,對于你不應該是太大的問題。

    ?

    選擇一個快捷方式

    ?????????頭一個必須考慮的問題是安排一個‘打開’對話框來選擇要解析的快捷方式。麻煩是,在默認情況下,‘打開’對話框不能處理快捷方式,因此沒有任何.lnk文件的名字被返回。為了在這種環境下工作,你必須在GetOpenFileName()函數中指定OFN_NODEREFERENCELINKS標志。就象下面顯示的處理器函數那樣,它在應用對話框上安排兩個瀏覽按鈕:

    ?

    [cpp]?view plaincopyprint?
  • void?OnBrowse(HWND?hDlg,?WPARAM?wID)??
  • {??
  • TCHAR?szFile[MAX_PATH]?=?{0};??
  • OPENFILENAME?ofn;??
  • ZeroMemory(&ofn,?sizeof(OPENFILENAME));??
  • ofn.lStructSize?=?sizeof(OPENFILENAME);??
  • if(wID?==?IDC_SHORTCUT)??
  • {??
  • ofn.lpstrFilter?=?__TEXT("Shortcuts/0*.lnk/0");??
  • ofn.Flags?=?OFN_NODEREFERENCELINKS;??
  • }??
  • else??
  • ofn.lpstrFilter?=?__TEXT("All?files/0*.*/0");??
  • ofn.nMaxFile?=?MAX_PATH;??
  • ofn.lpstrInitialDir?=?__TEXT("c://");??
  • ofn.lpstrFile?=?szFile;??
  • if(!GetOpenFileName(&ofn))??
  • return;??
  • else??
  • SetDlgItemText(hDlg,?wID,?ofn.lpstrFile);??
  • return;??
  • }??
  • ?

    ? ? ?使用這個技術,如果你雙擊一個.lnk文件,探測器將停在那兒,并返回一個指向文件的名,而不是進入引用的文件。

    ?

    Shell拖拽

    ?????????我承認,即使我們是對Shell進行編程,拖拽也不是一個有重要關系的科目,但是在我們看到它操作的過程之后,這就顯得有價值了。VC++資源編輯器就有拉動目標的特征(通過打開WS_EX_ACCEPTFILES位)。當然,它也能使你來規劃怎樣或什么時候可以處理拉動事件。我們想要限制列表觀察的拖拽操作,但是如果你指派了這個特征,則我們所要面對的是必須子類化這個窗口,以便感知相關的拉動事件。反過來,我們希望使用較簡單的方法:整個對話框都將可以拉動,但是當它捕捉到消息WM_DROPFILES后,應該校驗列表觀察中所發生的事件,否則,忽略這個事件。Shell處理拖拽的函數都定義在shellapi.h中,有DragQueryPoint(),DragQueryFile()和DragFinish(),后面我們還將繼續討論這個課題。

    ?

    顯示結果

    ?????????這個程序在用戶界面上有一個報告風格的列表觀察,為了較容易的使用它,我們建立了兩個輔助函數來幫助在觀察中增加列和串。記住以后我們還會使用它們。

    ?????????第一個函數是MakeReportView(),它轉換列表觀察窗口到具有指定列的報告風格的列表觀察。函數原型要求傳遞一個列表觀察的Handle,一個帶有字符串名和列寬度值的數組,以及一個列數值。為了使函數盡量簡潔,我們假定,數組中偶位置為名字串,奇位置為數字。

    ????數組實際是一個串指針數組—即,一個32位值的數組,理解了這個假設之后,你就可以如下使用數組了:

    ?

    [cpp]?view plaincopyprint?
  • LPTSTR?psz[]?=?{"Target",?reinterpret_cast<TCHAR*>(170),??
  • "Description",?reinterpret_cast<TCHAR*>(170),??
  • "Hotkey",?reinterpret_cast<TCHAR*>(100)};??
  • MakeReportView(hwndList,?psz,?3);??
  • ?

    MakeReportView()總是以名字/寬度對方式處理數組元素,所以,列數總是等于數組尺寸的一半。

    ?

    [cpp]?view plaincopyprint?
  • void?MakeReportView(HWND?hwndList,?LPTSTR*?psz,?int?iNumOfCols)??
  • {??
  • RECT?rc;??
  • DWORD?dwStyle?=?GetWindowStyle(hwndList);??
  • SetWindowLong(hwndList,?GWL_STYLE,?dwStyle?|?LVS_REPORT);??
  • GetClientRect(hwndList,?&rc);??
  • //?處理元素對,數組尺寸假設為?2?*?iNumOfCols??
  • for(int?i?=?0?;?i?<?2?*?iNumOfCols?;?i?=?i?+?2)??
  • {??
  • LV_COLUMN?lvc;??
  • ZeroMemory(&lvc,?sizeof(LV_COLUMN));??
  • lvc.mask?=?LVCF_TEXT?|?LVCF_WIDTH;??
  • lvc.pszText?=?psz[i];??
  • if(reinterpret_cast<int>(psz[i?+?1])?==?0)??
  • lvc.cx?=?rc.right?/?iNumOfCols;??
  • else??
  • lvc.cx?=?reinterpret_cast<int>(psz[i?+?1]);??
  • ListView_InsertColumn(hwndList,?i,?&lvc);??
  • }??
  • return;??
  • }??
  • ?

    MakeReportView()的伴隨例程是AddStringToReportView(),它添加新行到指定的列表觀察。由于底層編程接口的原因,充填報告風格列表觀察所有列要求分幾個步驟。你應該為這個新項的第一列(主列)添加指定的文字,然后依次在其他列上設置文字。所有這些步驟都由AddStringToReportView()執行,你只需要傳遞一個包含所有子串的NULL分隔串和在iNumOfCols指出有多少列就可以了。

    ?

    [cpp]?view plaincopyprint?
  • void?AddStringToReportView(HWND?hwndList,?LPTSTR?psz,?int?iNumOfCols)??
  • {??
  • LV_ITEM?lvi;??
  • ZeroMemory(&lvi,?sizeof(LV_ITEM));??
  • lvi.mask?=?LVIF_TEXT;??
  • lvi.pszText?=?psz;??
  • lvi.cchTextMax?=?lstrlen(psz);??
  • lvi.iItem?=?0;??
  • ListView_InsertItem(hwndList,?&lvi);??
  • //?其它列??
  • for(int?i?=?1?;?i?<?iNumOfCols?;?i++)??
  • {??
  • psz?+=?lstrlen(psz)?+?1;??
  • ListView_SetItemText(hwndList,?0,?i,?psz);??
  • }??
  • return;??
  • }??
  • ?

    在本例中列表觀察有三列:‘目標’,‘描述’和‘熱鍵’。前兩列是直接的,而第三列使用了以前沒用過的通用控件的一個用法。這是需要進一步說明的。

    ?

    熱鍵通用控制

    ?????????Windows95引進了一個新的控件,可以使你能夠圖像方式選擇一個鍵的組合(如圖):

    ???????????????????????

    ?

    ?

    ? ? ? ? ?使用這個控件的方法是,敲擊按鍵組合,它解釋鍵盤碼,并轉換成相應文字,顯然,在建立快捷方式環境下,這個控件有更友善的用戶界面。

    ?????????反過來,在解析快捷方式時,你所有的全部僅是一個由IShellLink::GetHotkey()返回的數(精確地:DWORD),這需要把它轉換成一個友善格式的串。

    ?????????這個字分解成兩個字節,表示一個熱鍵,高字節是修改符(Alt,Ctrl,Shift,或三者的組合),低字節是你所敲擊的鍵碼。注意,如果你按了A,這個碼是65 (大寫字符),不是97(小寫字符)。要使用HotkeyToString()例程,你需要相對于某些已知常量檢查高字節的位。下面這個函數對此進行了處理:

    ?

    [cpp]?view plaincopyprint?
  • void?HotkeyToString(WORD?wHotKey,?LPTSTR?pszBuf)??
  • {??
  • BYTE?bKey?=?LOBYTE(wHotKey);??
  • BYTE?bMod?=?HIBYTE(wHotKey);??
  • if(bMod?&?HOTKEYF_CONTROL)??
  • lstrcpy(pszBuf,?__TEXT("Ctrl"));??
  • if(bMod?&?HOTKEYF_SHIFT)??
  • if(lstrlen(pszBuf))??
  • lstrcat(pszBuf,?__TEXT("?+?Shift"));??
  • else??
  • lstrcpy(pszBuf,?__TEXT("Shift"));??
  • if(bMod?&?HOTKEYF_ALT)??
  • if(lstrlen(pszBuf))??
  • lstrcat(pszBuf,?__TEXT("?+?Alt"));??
  • else??
  • lstrcpy(pszBuf,?__TEXT("Alt"));??
  • TCHAR?s[2]?=?{0};??
  • wsprintf(s,?__TEXT("%c"),?bKey);??
  • if(lstrlen(pszBuf))??
  • {??
  • lstrcat(pszBuf,?__TEXT("?+?"));??
  • lstrcat(pszBuf,?s);??
  • }??
  • else??
  • lstrcpy(pszBuf,?s);??
  • }??
  • ?

    ? ? ? ? HotkeyToString()函數接受熱鍵值和一個要充填返回結構的串緩沖。它檢查修改器和建立串的第一部分—如,Ctrl+Alt,然后通過關聯的按鍵字符完成這個操作—如,Ctrl+Alt+X。下圖中顯示了在解析快捷方式時應用的結果:

    ?

    ??????????????????????????????????????

    ?

    收集建立變量

    ?????????如果不是有點微妙的話,建立快捷方式對話框的這一部分沒有什么可值得注意的。打開一個已存在的快捷方式(使用在桌面上的一個是比較好的),試圖給它分配一個新的熱鍵,此時,你將發現熱鍵控件校正你的按鍵。A將變成Ctrl+Alt+A。

    ?????????正是這個特征,而且是個重要特征,因為,如果你試圖編程地分配一個非Ctrl+Alt+…形式的熱鍵,這個熱鍵將永遠不被識別。稍微考慮一下,你就會明白,這種行為不是串—Ctrl+Alt+ …?與可能的加速器沖突。這也使我明白了,在前幾個例子中為什么Alt+A是錯誤的了。

    ?

    給出熱鍵規則

    ?????????指令熱鍵控件自動置換某些錯誤或無效的按鍵組合,你需要使用按鍵規則。不管它的名字如何,這其實就是簡單地發送消息到熱鍵窗口。為了強制使它接受僅僅Ctrl+Alt前綴的按鍵,你必須:

    ?

    [cpp]?view plaincopyprint?
  • SendMessage(hwndHotkey,?HKM_SETRULES,??
  • HKCOMB_NONE?|?HKCOMB_S?|?HKCOMB_A?|?HKCOMB_C,??
  • HOTKEYF_CONTROL?|?HOTKEYF_ALT);??
  • ?

    這個‘規則’可以重新解釋為:

    ?????????無效的按鍵組合總是那些有一個修改符在wParam中列出的按鍵。

    ?????????用在lParam中指定的組合鍵置換每一個無效的按鍵。

    如果不是從空(HKCOMB_NONE),Shift(HKCOMB_S),?Alt?(HKCOMB_A)?或?Ctrl(HKCOMB_C)開始,則忽略它們,并用Ctrl+Alt代替之。下面圖像顯示了建立快捷方式時的這個過程:

    ?????????????????

    ?

    ?

    源代碼

    ?????????現在看一下這個示例程序的剩余源代碼。要正確地編譯它必須確保包含shlobj.h,?resource.h?和commdlg.h,以及鏈接comdlg32.lib和ole32.lib。另外,由于我們使用了COM,所以還需要用CoInitialize(NULL)和CoUninitialize()把WinMain()中的DialogBox()調用括起來。

    ?

    DoCreateShortcut()函數

    ?????????這個函數在點擊‘建立’按鈕時被調用。它從控件中收集參數和安排調用SHCreateShortcutEx()函數,在combo框中有一些特殊文件夾的名字。

    ?

    [cpp]?view plaincopyprint?
  • void?DoCreateShortcut(HWND?hDlg)??
  • {??
  • SHORTCUTSTRUCT?ss;??
  • ZeroMemory(&ss,?sizeof(SHORTCUTSTRUCT));??
  • TCHAR?szTarget[MAX_PATH]?=?{0};??
  • TCHAR?szDesc[MAX_PATH]?=?{0};??
  • //?取得熱鍵??
  • ss.wHotKey?=?static_cast<WORD>(SendDlgItemMessage(??
  • hDlg,?IDC_HOTKEY,?HKM_GETHOTKEY,?0,?0));??
  • //?取得目標和描述??
  • GetDlgItemText(hDlg,?IDC_TARGET,?szTarget,?MAX_PATH);??
  • GetDlgItemText(hDlg,?IDC_DESCRIPTION,?szDesc,?MAX_PATH);??
  • ss.pszTarget?=?szTarget;??
  • ss.pszDesc?=?szDesc;??
  • //?確定快捷方式文件名??
  • //?取得目標文件夾和最后的反斜杠??
  • HWND?hwndCbo?=?GetDlgItem(hDlg,?IDC_SPECIAL);??
  • int?i?=?ComboBox_GetCurSel(hwndCbo);??
  • DWORD?nFolder?=?ComboBox_GetItemData(hwndCbo,?i);??
  • TCHAR?szPath[MAX_PATH]?=?{0};??
  • SHGetSpecialFolderPath(hDlg,?szPath,?nFolder,?FALSE);??
  • if(szPath[lstrlen(szPath)?-?1]?!=?'//')??
  • lstrcat(szPath,?__TEXT("//"));??
  • TCHAR?szLnkFile[MAX_PATH]?=?{0};??
  • GetDlgItemText(hDlg,?IDC_LNKFILE,?szLnkFile,?MAX_PATH);??
  • lstrcat(szPath,?szLnkFile);??
  • lstrcat(szPath,?__TEXT(".lnk"));??
  • //?建立??
  • SHCreateShortcutEx(szPath,?&ss);??
  • //?更新UI??
  • SetDlgItemText(hDlg,?IDC_SHORTCUT,?szPath);??
  • return;??
  • }??
  • ?

    DoResolveShortcut()函數

    ?????????這個函數在響應‘解析’按鈕的點擊時調用。盡管它也接受一個附加的參數pszFile,用于表示要解析的文件。如果這個參數為NULL,則函數使用‘快捷方式’編輯框中的內容。這個變量存在的原因是使這個函數更容易解析拖拽到程序窗口上的任何文件。DoResolveShortcut()首先調用我們的函數SHResolveShortcut()解析這個快捷方式,然后更新用戶界面,附加一個新行到報告列表觀察中。

    ?

    [cpp]?view plaincopyprint?
  • void?DoResolveShortcut(HWND?hDlg,?LPTSTR?pszFile)??
  • {??
  • TCHAR?szLnkFile[MAX_PATH]?=?{0};??
  • if(pszFile?==?NULL)??
  • GetDlgItemText(hDlg,?IDC_SHORTCUT,?szLnkFile,?MAX_PATH);??
  • else??
  • lstrcpy(szLnkFile,?pszFile);??
  • //?解析快捷方式??
  • SHORTCUTSTRUCT?ss;??
  • HRESULT?hr?=?SHResolveShortcut(szLnkFile,?&ss);??
  • if(FAILED(hr))??
  • return;??
  • //??
  • //?更新UI??
  • //?建立列表觀察串??
  • TCHAR?pszBuf[1024]?=?{0};??
  • LPTSTR?psz?=?pszBuf;??
  • lstrcpy(psz,?ss.pszTarget);??
  • lstrcat(psz,?__TEXT("/0"));??
  • psz?+=?lstrlen(psz)?+?1;??
  • lstrcpy(psz,?ss.pszDesc);??
  • lstrcat(psz,?__TEXT("/0"));??
  • psz?+=?lstrlen(psz)?+?1;??
  • //?Try?to?get?the?text?version?of?the?hotkey??
  • TCHAR?szKey[30]?=?{0};??
  • HotkeyToString(ss.wHotKey,?szKey);??
  • lstrcpy(psz,?szKey);??
  • lstrcat(psz,?__TEXT("/0"));??
  • //?加一個新項到報告列表觀察(3?列)??
  • HWND?hwndList?=?GetDlgItem(hDlg,?IDC_VIEW);??
  • AddStringToReportView(hwndList,?pszBuf,?3);??
  • return;??
  • }??
  • ?

    HandleFileDrop()函數

    ?????????在響應WM_DROPFILES消息時調用此函數,這個函數定義了當用戶拖拽文件到窗口的客戶區域時所要求的操作。接受的數據是CF_HDROP類型的,這是一種從探測器窗口或從桌面拖拽文件操作時用于Shell移動文件環境下的交互格式。任何具有WS_EX_ACCEPTFILES風格設置的窗口都只對拖拽操作敏感,并以這種格式封裝數據。換句話說,當源是Windows Shell,或其它以CF_HDROP格式傳遞參數的程序時,我們的程序也接受拖拽操作。

    ?????????CF_HDROP是一種剪裁板格式,用于交換基本為文件名的數據項的格式—更多關于剪裁板格式信息和CF_HDROP數據的內部結構可以參看VC++的幫助文件。對于我們而言,重要的是,雖然它的內存Handle稱為CF_HDROP,還是有一定數量的函數能夠讀出這種格式的數據。

    ?????????當你從Shell拉動文件的時候,目標窗口接收到消息WM_DROPFILES,其中一個變量是HDROP型的Handle。我們的HandleFileDrop()函數首先檢查拉動發生的窗口,如果這個窗口是列表觀察,則進一步抽取和解析各種文件名。你可以拉動任何文件到這個列表觀察上,但是僅僅快捷方式被正確地處理。

    ?

    [cpp]?view plaincopyprint?
  • void?HandleFileDrop(HWND?hDlg,?HDROP?hDrop)??
  • {??
  • //?檢查拉動到的窗口??
  • POINT?pt;??
  • DragQueryPoint(hDrop,?&pt);??
  • ClientToScreen(hDlg,?&pt);??
  • HWND?hwndDrop?=?WindowFromPoint(pt);??
  • if(hwndDrop?!=?GetDlgItem(hDlg,?IDC_VIEW))??
  • {??
  • Msg(__TEXT("抱歉,你必須拉動到列表觀察控件上!"));??
  • return;??
  • }??
  • //?檢查文件??
  • int?iNumOfFiles?=?DragQueryFile(hDrop,?-1,?NULL,?0);??
  • for(int?i?=?0?;?i?<?iNumOfFiles;?i++)??
  • {??
  • TCHAR?szFileName[MAX_PATH]?=?{0};??
  • DragQueryFile(hDrop,?i,?szFileName,?MAX_PATH);??
  • DoResolveShortcut(hDlg,?szFileName);??
  • }??
  • DragFinish(hDrop);??
  • }??
  • ?

    DragQueryPoint()告知拉動發生時點的客戶區域坐標,而DragQueryFile()則依次抽取所有包裝在HDROP Handle中的文件。你也可以使用這個函數獲得拉動的文件數。最后,必須調用DragFinish()函數來結束拉動操作。

    APP_DlgProc()函數

    ?????????這是應用主窗口過程,由于涉及到我們前面給出的幾個例子,所以看一下這個處理器是有價值的:

    ?

    [cpp]?view plaincopyprint?
  • BOOL?CALLBACK?APP_DlgProc(HWND?hDlg,?UINT?uiMsg,?WPARAM?wParam,?LPARAM?lParam)??
  • {??
  • switch(uiMsg)??
  • {??
  • case?WM_INITDIALOG:??
  • OnInitDialog(hDlg);??
  • break;??
  • case?WM_DROPFILES:??
  • HandleFileDrop(hDlg,?reinterpret_cast<HDROP>(wParam));??
  • break;??
  • case?WM_COMMAND:??
  • switch(wParam)??
  • {??
  • case?IDC_RESOLVE:??
  • DoResolveShortcut(hDlg,?NULL);??
  • return?FALSE;??
  • case?IDC_CREATE:??
  • DoCreateShortcut(hDlg);??
  • return?FALSE;??
  • case?IDC_BROWSE:??
  • OnBrowse(hDlg,?IDC_SHORTCUT);??
  • return?FALSE;??
  • case?IDC_BROWSETARGET:??
  • OnBrowse(hDlg,?IDC_TARGET);??
  • return?FALSE;??
  • case?IDCANCEL:??
  • EndDialog(hDlg,?FALSE);??
  • return?FALSE;??
  • }??
  • break;??
  • }??
  • return?FALSE;??
  • }??
  • ?

    OnInitDialog()函數

    ?????????在這個工程(project)中有幾個東西要初始化。在處理combo框時,應該有一個熟知的過程,我們還需要設置列表觀察控件,以及編程熱鍵控件,使其使用Ctrl+Alt…的格式形式。

    ?

    [cpp]?view plaincopyprint?
  • void?OnInitDialog(HWND?hDlg)??
  • {??
  • //?設置圖標(T/F?大/小圖標)??
  • SendMessage(hDlg,?WM_SETICON,?FALSE,?reinterpret_cast<LPARAM>(g_hIconSmall));??
  • SendMessage(hDlg,?WM_SETICON,?TRUE,?reinterpret_cast<LPARAM>(g_hIconLarge));??
  • //?初始化報告觀察??
  • HWND?hwndList?=?GetDlgItem(hDlg,?IDC_VIEW);??
  • LPTSTR?psz[]?=?{"Target",?reinterpret_cast<TCHAR*>(170),??
  • "Description",?reinterpret_cast<TCHAR*>(170),??
  • "Hotkey",?reinterpret_cast<TCHAR*>(100)};??
  • MakeReportView(hwndList,?psz,?3);??
  • //?可用的特殊文件夾??
  • HWND?hwndCbo?=?GetDlgItem(hDlg,?IDC_SPECIAL);??
  • int?i?=?ComboBox_AddString(hwndCbo,?"Desktop");??
  • ComboBox_SetItemData(hwndCbo,?i,?CSIDL_DESKTOP);??
  • i?=?ComboBox_AddString(hwndCbo,?"Favorites");??
  • ComboBox_SetItemData(hwndCbo,?i,?CSIDL_FAVORITES);??
  • i?=?ComboBox_AddString(hwndCbo,?"Programs");??
  • ComboBox_SetItemData(hwndCbo,?i,?CSIDL_PROGRAMS);??
  • i?=?ComboBox_AddString(hwndCbo,?"My?Documents");??
  • ComboBox_SetItemData(hwndCbo,?i,?CSIDL_PERSONAL);??
  • i?=?ComboBox_AddString(hwndCbo,?"SendTo");??
  • ComboBox_SetItemData(hwndCbo,?i,?CSIDL_SENDTO);??
  • i?=?ComboBox_AddString(hwndCbo,?"Start?Menu");??
  • ComboBox_SetItemData(hwndCbo,?i,?CSIDL_STARTMENU);??
  • ComboBox_SetCurSel(hwndCbo,?0);??
  • //?初始化熱鍵控件,每一件東西都有Ctrl+Alt前綴??
  • SendDlgItemMessage(hDlg,?IDC_HOTKEY,?HKM_SETRULES,??
  • HKCOMB_NONE?|?HKCOMB_S?|?HKCOMB_A?|?HKCOMB_C,??
  • HOTKEYF_CONTROL?|?HOTKEYF_ALT);??
  • SetDlgItemText(hDlg,?IDC_TARGET,?__TEXT("C://"));??
  • }??
  • ?

    在系統文件夾中建立快捷方式

    ?????????現在可以編譯和運行的這個示例程序可以使你很容易在系統文件夾中建立快捷方式—所需要做的全部操作就是從combo框中選擇一個文件夾名。如果你希望在你自己的程序中靜默地做這項工作,只要知道所涉及的文件夾名,剩下的就是用這個全路徑名格式化一個串。

    下面是做這項工作的一個簡單的函數。作為變量,它接受要建立的.lnk文件名,特殊文件夾的ID(有CSIDL_XXX格式的常量),以及指向的文件名。代碼是SHCreateShortcutEx()的一個封裝:

    ?

    [cpp]?view plaincopyprint?
  • HRESULT?SHCreateSystemShortcut(LPCTSTR?szLnkFile,?int?nFolder,?LPCTSTR?szFile)??
  • {??
  • WCHAR?wszLnkFile[MAX_PATH]?=?{0};??
  • TCHAR?szPath[MAX_PATH]?=?{0};??
  • IShellLink*?pShellLink?=?NULL;??
  • IPersistFile*?pPF?=?NULL;??
  • //?建立適當的COM服務器??
  • HRESULT?hr?=?CoCreateInstance(CLSID_ShellLink,?NULL,??
  • CLSCTX_INPROC_SERVER,?IID_IShellLink,??
  • reinterpret_cast<LPVOID*>(&pShellLink));??
  • if(FAILED(hr))??
  • return?hr;??
  • //?設置屬性??
  • pShellLink->SetPath(szFile);??
  • //?取得IPersistFile接口,用于保存??
  • hr?=?pShellLink->QueryInterface(??
  • IID_IPersistFile,?reinterpret_cast<LPVOID*>(&pPF));??
  • if(FAILED(hr))??
  • {??
  • pShellLink->Release();??
  • return?hr;??
  • }??
  • //?準備快捷方式名??
  • SHGetSpecialFolderPath(NULL,?szPath,?nFolder,?FALSE);??
  • if(szPath[lstrlen(szPath)?-?1]?!=?'//')??
  • lstrcat(szPath,?__TEXT("//"));??
  • lstrcat(szPath,?szLnkFile);??
  • //?存儲LNK(Unicode?名)??
  • MultiByteToWideChar(CP_ACP,?MB_PRECOMPOSED,?szPath,?-1,?wszLnkFile,?MAX_PATH);??
  • hr?=?pPF->Save(wszLnkFile,?TRUE);??
  • //?清理??
  • pPF->Release();??
  • pShellLink->Release();??
  • return?hr;??
  • }??
  • ?

    使用上面的函數,在‘桌面’上,在‘開始’菜單中,在‘程序文件’中,或在‘Favorites’中建立快捷方式就非常容易了。要證明這一點,要求在‘開始’菜單中添加一個新項指向‘記事本’,則只需要:

    ?

    [cpp]?view plaincopyprint?
  • SHCreateSystemShortcut(__TEXT("Notepad.lnk"),?CSIDL_STARTMENU,??
  • ????????????????????????????????????????__TEXT("c://windows//notepad.exe"));??
  • ?

    就可以了,顯然,c:/windows/路徑應該置換成你機器上的實際Windows的目錄。還要注意,在Windows NT下,‘notepad.exe’存儲在‘System’目錄下。

    ????你也可以建立指向目錄和非可執行文件的快捷方式。事實上,引用任何系統文件對象,僅僅需要傳遞路徑到IShellLink::SetPath(),或傳遞PIDL調用IShellLink::SetIDList()。

    ?

    ‘發送到’文件夾

    ‘發送到’文件夾是包含兩個非快捷方式對象的文件夾,對于快捷方式是不值得注意的。如果在Windows上安裝了IE4.0以上版,或在Windows98以上版系統上,‘發送到’文件夾可能包含對Email容器或桌面的引用。使用這個機理,你也可以從Shell把給定的文件作為新消息的附件直接發送到你自己的發件箱,或作為快捷方式發送到桌面。

    ?????????????????

    ????????????????

    這個截圖顯示有兩個沒有典型的快捷標記的項,它們是‘桌面快捷方式’,是一個空的.DeskLink文件,其長度為0字節。如果你搜索這個擴展名的注冊表信息,就會發現,在其后有一個COM對象。

    ???????

    ?

    ?

    ?????????了解到它由一個COM對象支持文件是一大進步,但是,是哪一種COM對象在支持它,COM對象實現了什么接口,都還需要進一步探討。事實上,這是一個Shell擴展,更確切地講是一個拖動處理器。我們將在第十五章中討論Shell擴展?,F在,僅說明‘發送到’文件夾不僅包含快捷方式還有別的就可以了。使用.DeskLink串純粹是一種表示,你也可以使用其它串來表示。

    ?

    ‘最近文檔’文件夾

    ?????????‘最近文檔’文件夾收集最近打開的文檔。這個目錄下的內容可以通過單擊‘開始’菜單的‘文檔’項來查看,其物理位置在Windows目錄下。然而,奇怪的是在它包含的快捷方式和通過菜單顯示的項之間并不是1:1對應的。

    ?????????Shell API給出了一個稱之為SHAddToRecentDocs()的函數,使程序員能夠把文檔的鏈接存儲到這個文件夾下。

    ?

    [cpp]?view plaincopyprint?
  • void?SHAddToRecentDocs(UINT?uFlags,?LPCVOID?pv);??
  • ?

    第一個變量指出了第二個變量的類型:PIDL或路徑名,可以取SHARD_PATH或SHARD_PIDL值。使用這個函數,能夠成功地把你的文檔引用加進菜單中。但是如果簡單地在這個文件夾上建立一個快捷方式,就不對了—也就是說,建立快捷方式是必要的但不充分。SHAddToRecentDocs()顯然做了更多的事情。

    ?????????最終,SHAddToRecentDocs()添加項目到由‘開始菜單’使用的MRU(最近使用的)列表中,并且簡單地加這個文件到‘最近文檔’文件夾中。這個函數還復制這個文件夾中的快捷方式,以及處理菜單的順序。因此,你應該堅定地使用函數,而不是其他方法,以兼容未來在某些方面實現方式的變化。

    ?

    小結

    這一章中探討了快捷方式,這個在Windows的任何書和文章中都討論過的課題??旖莘绞绞窍鄬唵蔚?#xff0c;但是沒有建立和解析它的單一函數,這一章中討論并寫出了這樣的函數,還查看了:

    ?????????快捷方式的作用

    ?????????怎樣建立和解析它們

    ?????????某些與快捷方式一道工作的有用的函數

    ?????????拖拽和熱鍵控件

    ?????????快捷方式和系統文件夾之間的關系

    轉載于:https://www.cnblogs.com/songtzu/p/3239827.html

    總結

    以上是生活随笔為你收集整理的Windows Shell 编程 第六章 【来源:http://blog.csdn.net/wangqiulin123456/article/details/7987951】...的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。