所謂Shell(殼),一般是指由作業系統提供的,用于計算機使用者向作業系統輸入相關指令并得到結果的程式。Shell可以字元形式的,也可以是圖形界面形式的。
Windows Shell最重要的組成部件是explorer.exe。在使用Windows作業系統時,開始菜單、工作列、資料總管等都是explorer.exe提供的。是以Shell程式設計也是圖形使用者界面設計的重要組成部分。掌握Shell程式設計,需首先了解下面4個方面的内容。
(1) Windows Shell程式設計接口。
Windows Shell提供一系列程式設計接口,例如可以擷取特殊檔案夾,使用檔案浏覽對話框等。
Shell程式設計接口的函數名通常是以“SH”開始。
(2) Windows Shell擴充。
Windows平台的Shell是可擴充的。可以為Windows Shell開發擴充程式(Extention),例如:
◇定制不同類型的檔案的右鍵菜單、拖拽菜單(比如WinRAR、Adobe Acrobat等應用程式具有這樣的功能);
◇開發系統通知區域圖示、并為圖示定制菜單和氣泡彈出功能(QQ、MSN、Visual Studio等應用程式具有這樣的功能);
◇定制工作列、定制工具欄等;
◇增加自動播放對話框中的選項;
◇添加控制台項;
◇為不同檔案類型檔案屬性頁、檔案夾的屬性頁(右鍵屬性)增加選項頁。
上面是幾種典型的Shell擴充應用。
(3)系統資料庫在Shell應用中具有重要作用。
Shell應用在很大程度上依賴于系統資料庫,舉例如下。
◇檔案類型輔助:特定擴充名的檔案的圖示、預設打開程式等是通過系統資料庫來配置的。
◇Shell擴充的安裝:比如特定類型檔案的右鍵菜單、拖拽菜單(Context Meun)的菜單項及輸入處理函數所在的動态連結庫。
(4)相關頭檔案和庫檔案。
進行Shell程式的設計,需要使用一些頭檔案和庫檔案。
一般Shell API都在shlobj.h頭檔案中聲明,由She1132.dll導出,連結時需要使用到She1132.lib庫。
一、目錄管理
1、基本介紹
計算機使用者使用Shell最常進行的操作就是檔案操作。Shell最重要的功能之一是進行檔案浏覽、查找、管理以及将檔案和應用程式關聯。
Windows Shell中有很多特殊目錄和檔案,比如所有Windows使用者都經常接觸到的“我的檔案”、“桌面”、“資源回收筒”、“程式檔案”(Program files)等。這些目錄都是Shell特殊目錄。可以通過Shell程式設計接口開發程式,擷取和操作這些特殊目錄。
Shell有一種特殊的檔案和目錄管理方式,每個目錄都有一個PIDL (Pointer of Item identifier list,項辨別符表指針)值,這個值惟一辨別一個檔案夾。
由系統定義的特殊檔案夾的CSIDL (constant special item ID list)是常數,比如:
CSIDL_ DESKTOP代表“桌面”檔案夾,是根目錄;
CSIDL_FAVORITES代表“收藏夾”;
CSIDL_FONTS代表字型檔案夾;
CSIDL_MYDOCUMENTS,代表“我的檔案”;
CSIDL_MYMUSIC代表“我的音樂”;
CSIDL PROFILE代表“使用者”檔案夾,一般情況下是C:\Documents and Settings\username;
CSIDL_PROGRAMS代表“程式”檔案夾,一般情況下是C:\Program Files; .
CSIDL_RECENT,代表“最近的文檔”;
CSIDL_STARTMENU,代表“開始菜單”目錄;
CSIDL_SYSTEM、CSIDL_WINDOWS分别代表“系統”和“Windows”目錄。
SHGetNameFromIDList、SHGetPathFromIDList等Shell API函數通過CSIDL獲得有關于目錄的詳細資訊。
2、操作“我的檔案”等特殊目錄
操作“我的檔案”等特殊目錄相關操作涉及的API:
SHGetSpecialFolderPath通過檔案夾的CSIDL,獲得檔案夾的路徑;
SHGetFolderLocation擷取檔案夾的路徑,并儲存在ITEMIDLIST結構中;
SHGetPathFromIDList從PIDL轉換為路徑。
兩種方法來擷取特殊檔案夾的路徑,一種是直接使用SHGetSpecialFolderPath,
另外一種更為通用,使用SHGetFolderLocation從PIDL或CSIDL獲得檔案夾位置後,再使用SHGetPathFromIDList擷取檔案路徑字元串。

擷取并顯示特殊目錄,周遊資源回收筒示例
/* 頭檔案 */
#include <Windows.h>
#include <shlobj.h>
#include <stdio.h>
/* 函數申明 */
DWORD ListFileInRecycleBin();
VOID GetSpecialFolder();
/*************************************
* int main()
* 功能 調用相關函數
*
* 參數 未使用
**************************************/
int main()
{
GetSpecialFolder();
ListFileInRecycleBin();
}
* VOID GetSpecialFolder()
* 功能 擷取并顯示特殊目錄
VOID GetSpecialFolder()
// 擷取我的檔案的路徑
CHAR szMyDocument[MAX_PATH];// My Document的路徑
// 使用SHGetSpecialFolderPath擷取特殊目錄路徑
SHGetSpecialFolderPath(NULL,szMyDocument,CSIDL_PERSONAL,FALSE);
// 擷取桌面的路徑
CHAR szDesktop[MAX_PATH]; //DeskTop的路徑
LPITEMIDLIST pidl = NULL;
LPMALLOC pMalloc = NULL;
// 配置設定
SHGetMalloc(&pMalloc);
// 使用SHGetFolderLocation、SHGetPathFromIDList可以擷取任意目錄的路徑
SHGetFolderLocation(NULL, CSIDL_DESKTOPDIRECTORY, NULL, 0, &pidl);
SHGetPathFromIDList(pidl,szDesktop);
// 釋放
pMalloc->Free(pidl);
pMalloc->Release();
// 顯示結果
printf("My Document:\t %s\n",szMyDocument);
printf("DeskTop:\t %s\n",szDesktop);
* VOID ListFileInRecycleBin()
* 功能 周遊并顯示資源回收筒中的檔案
DWORD ListFileInRecycleBin()
CHAR pszPath[MAX_PATH]; // 儲存路徑
// IShellFolder接口
IShellFolder *pisf = NULL;
IShellFolder *pisfRecBin = NULL;
// 擷取“根”目錄,桌面
SHGetDesktopFolder(&pisfRecBin);
IEnumIDList *peidl = NULL; // 對象周遊接口
LPITEMIDLIST pidlBin = NULL;
LPITEMIDLIST idlCurrent = NULL;
// 資源回收筒位置
SHGetFolderLocation(NULL, CSIDL_BITBUCKET, NULL, 0, &pidlBin);
// 綁定資源回收筒對象
pisfRecBin->BindToObject(pidlBin,NULL,IID_IShellFolder,(void **) &pisf);
// 列舉資源回收筒中的對象,得到IEnumIDList接口,包括SHCONTF_FOLDERS、
// SHCONTF_NONFOLDERS、SHCONTF_INCLUDEHIDDEN類型的對象
pisf->EnumObjects(NULL,
SHCONTF_FOLDERS | SHCONTF_NONFOLDERS |SHCONTF_INCLUDEHIDDEN,
&peidl);
STRRET strret;
ULONG uFetched;
HANDLE hOutPut = GetStdHandle(STD_OUTPUT_HANDLE);
printf("\nFiles In Recycle Bin:\n");
while(1)
// 周遊IEnumIDList對象,idlCurrent為目前對象
if(peidl->Next(1,&idlCurrent,&uFetched) == S_FALSE)
break;
// 擷取資源回收筒目前對象目前的路徑,這裡沒有輸出結果,讀者可自行修改
SHGetPathFromIDList(idlCurrent, pszPath);
// DisplayName,删除前的路徑
pisf->GetDisplayNameOf(idlCurrent,SHGDN_NORMAL,&strret);
// 顯示,printf可能會造成字元編碼不正确。
WriteConsoleW(hOutPut,L"\t",1,NULL,NULL);
WriteConsoleW(hOutPut,strret.pOleStr,lstrlenW(strret.pOleStr),NULL,NULL);
WriteConsoleW(hOutPut,L"\n",1,NULL,NULL);
// 釋放資源
pMalloc->Free(pidlBin);
pMalloc->Free(strret.pOleStr);
peidl->Release();
pisf->Release();
return 0;
3、綁定、周遊、屬性擷取
1)相關API,接口,資料結構
SHGetDesktopFolder是擷取以IShellFolder接口形式傳回的桌面檔案夾
2)IShellFolder接口
IshellFolder是Windows Shell程式對目标進行管理的一個重要接口。每一個目錄對應一個執行個體化的IshellFolder接口。IshellFolder接口的成員包括EnumObj ects、GetAttributesOf、GetDisplayNameOf等。[2]
3)IEnumIDList接口。
IEnumIDList接口提供了一組标準的方法,用于周遊PIDL (Item identifier lists的指針),其成員包括Clone、Next、Reset、Skip等。[3]
示例代碼,見上。
3、浏覽檔案對話框
示例代碼

彈出“浏覽檔案夾”對話框
DWORD Browse(HWND hwnd) ;
* WinMain
* 功能 程式入口點,調用Browse
int WINAPI WinMain(
HINSTANCE hInstance,
HINSTANCE hPrevInstance,
LPSTR lpCmdLine,
int nCmdShow
)
Browse(NULL);
* 功能 彈出“浏覽檔案夾”對話框,
并擷取使用者選擇的檔案夾目錄
* 參數 HWND hwnd 父視窗句柄
DWORD Browse(HWND hwnd)
// 用于儲存路徑
CHAR szRoot[MAX_PATH];
CHAR szChoose[MAX_PATH];
CHAR szDisplayName[MAX_PATH];
// 相關變量
LPITEMIDLIST pidlRoot = NULL;
LPITEMIDLIST pidlSelected = NULL;
BROWSEINFO bi = {0};
// “浏覽檔案夾”的根路徑,開發人員可根據情況選擇,比如隻浏覽“我的檔案”。
SHGetFolderLocation(NULL, CSIDL_DESKTOP, NULL, 0, &pidlRoot);
SHGetPathFromIDList(pidlRoot,szRoot);
// 填充 BROWSEINFO 結構
bi.hwndOwner = hwnd;
bi.pidlRoot = pidlRoot;
bi.pszDisplayName = szDisplayName;
bi.lpszTitle = "Choose a target";
bi.ulFlags = 0;
bi.lpfn = NULL;
bi.lParam = 0;
// 彈出對話框
pidlSelected = SHBrowseForFolder(&bi);
// DisplayName
MessageBox(NULL,szDisplayName,"Display Name:",MB_OK);
// 選擇的檔案夾
SHGetPathFromIDList( pidlSelected, szChoose );
MessageBox(NULL,szChoose,"Choose:",MB_OK);
ILFree(pidlRoot);
參考
[1] 精通Windows API 函數、接口、程式設計執行個體