初始化 Shell 擴充處理程式
Shell 擴充處理程序物件的大部分實作是由其類型所決定。 不過,有一些常見的元素。 本主題討論所有Shell擴充處理程式共用的實作層面。
所有 Shell 延伸模組處理程式都是進程元件物件模型 (COM) 物件。 它們必須指派 GUID 並註冊,如 註冊 Shell 擴展處理程序中所述。 它們會實作為 DLL,而且必須匯出下列標準函式:
- DllMain。 DLL 的標準進入點。
- DllGetClassObject。 公開對象的類別處理站。
- DllCanUnloadNow。 COM 會呼叫此函式來判斷物件是否為任何用戶端提供服務。 如果沒有,系統可以卸除 DLL 並釋放相關聯的記憶體。
如同所有 COM 物件,Shell 擴充處理程式必須實作 IUnknown 介面和 類別處理站。 大部分也必須在 Windows XP 或更早版本中實作 IPersistFile 或 IShellExtInit 介面。 這些已由 Windows Vista 中的 IInitializeWithStream、IInitializeWithItem 和 IInitializeWithFile 取代。 Shell 會使用這些介面來初始化處理程式。
IPersistFile 介面必須由下列項目實作:
- 圖示處理程式
- 數據處理者
- 拖放處理程式
IShellExtInit 介面必須由下列項目實作:
- 快捷選單處理程式
- 拖放處理程式
- 屬性表處理程式
本主題的其餘部分會討論下列主題:
實作 IPersistFile
IPersistFile 介面的設計目的是允許從磁碟檔案載入或儲存物件。 除了 IUnknown方法外,它有六個方法,包括其自身的五個方法以及從 IPersist繼承的 GetClassID 方法。 使用 Shell 擴充時,IPersist 只會用來初始化 Shell 擴充處理器物件。 因為通常不需要從磁碟讀取或寫入,只有 GetClassID 和 Load 方法需要非符號實作。
Shell 會先呼叫 GetClassID,而函式會傳回擴充處理程式對象的類別標識碼 (CLSID)。 然後 Shell 會呼叫 Load,並傳入兩個值。 第一個 pszFile是 Unicode 字串,代表 Shell 即將操作的檔案或資料夾的名稱。 第二個是 dwMode,表示檔案存取模式。 因為通常不需要存取檔案,dwMode 通常是零。 方法會視需要儲存這些值,以供稍後參考。
下列代碼段說明一般 Shell 延伸模組處理程式如何實作 GetClassID 和 Load 方法。 其設計目的是要處理 ANSI 或 Unicode。 CLSID_SampleExtHandler是擴充處理程序物件的 GUID,而 CSampleShellExtension 是用來實作介面的類別名稱。 m_szFileName 和 m_dwMode 變數是用來儲存檔名和存取旗標的私人變數。
class CSampleShellExtension : public IPersistFile
{
// Method declarations not included
private:
WCHAR m_szFileName[MAX_PATH]; // The file name
DWORD m_dwMode; // The file access mode
}
IFACEMETHODIMP CSampleShellExtension::GetClassID(__out CLSID *pCLSID)
{
*pCLSID = CLSID_SampleExtHandler;
}
IFACEMETHODIMP CSampleShellExtension::Load(PCWSTR pszFile, DWORD dwMode)
{
m_dwMode = dwMode;
return StringCchCopy(m_szFileName, ARRAYSIZE(m_szFileName), pszFile);
}
// The implementation sample is continued in the next section.
實作 IShellExtInit
除了 IUnknown之外,IShellExtInit 介面只有一個方法,IShellExtInit::Initialize。 方法有三個參數,Shell 可用來傳入各種類型的資訊。 傳入的值取決於處理程式的類型,有些值可以設定為 NULL。
- pidlFolder 保存指向項目識別號清單(PIDL)的資料夾指標。 這是絕對 PIDL。 對於屬性表延伸模組,此值 NULL。 對於快顯功能表延伸模組,這是包含顯示其快顯功能表專案的資料夾的 PIDL。 對於非預設拖放處理程式,它是目標資料夾的 PIDL。
- pDataObject 持有數據物件的 IDataObject 介面指標。 數據物件會以 CF_HDROP 格式保存一或多個檔名。
- hRegKey 保留檔案物件或資料夾類型的登錄機碼。
IShellExtInit::Initialize 方法會儲存檔名、IDataObject 指標,以及稍後使用時所需的登錄機碼。 下列代碼段說明 IShellExtInit::Initialize 的實作。 為了簡單起見,此範例假設數據物件只包含單一檔案。 一般而言,數據物件可能包含多個檔案,每個檔案都需要擷取。
// This code continues the CSampleShellExtension sample shown in the
// "Implementing IPersistFile" section above.
class CSampleShellExtension : public IShellExtInit
{
// Method declarations not included
private:
// IDList of the folder for extensions invoked on the folder, such as
// background context menu handlers or nondefault drag-and-drop handlers.
PIDLIST_ABSOLUTE m_pidlFolder;
// The data object contains an expression of the items that the handler is
// being initialized for. Use SHCreateShellItemArrayFromDataObject to
// convert this object to an array of items. Use SHGetItemFromObject if you
// are only interested in a single Shell item. If you need a file system
// path, use IShellItem::GetDisplayName(SIGDN_FILESYSPATH, ...).
IDataObject *m_pdtobj;
// For context menu handlers, the registry key provides access to verb
// instance data that might be stored there. This is a rare feature to use
// so most extensions do not need this variable.
HKEY m_hRegKey;
}
// This method must be very efficient. Do not do any unnecessary work here.
// Use Initialize to acquire resources that will be used later.
IFACEMETHODIMP CSampleShellExtension::Initialize(__in_opt PCIDLIST_ABSOLUTE pidlFolder,
__in_opt IDataObject *pDataObject,
__in_opt HKEY hRegKey)
{
// In some cases, handlers are initialized multiple times. Therefore,
// clear any previous state here.
CoTaskMemFree(m_pidlFolder);
m_pidlFolder = NULL;
if (m_pdtobj)
{
m_pdtobj->Release();
}
if (m_hRegKey)
{
RegCloseKey(m_hRegKey);
m_hRegKey = NULL;
}
// Capture the inputs for use later.
HRESULT hr = S_OK;
if (pidlFolder)
{
m_pidlFolder = ILClone(pidlFolder); // Make a copy to use later.
hr = m_pidlFolder ? S_OK : E_OUTOFMEMORY;
}
if (SUCCEEDED(hr))
{
// If a data object pointer was passed into the method, save it and
// extract the file name.
if (pDataObject)
{
m_pdtobj = pDataObject;
m_pdtobj->AddRef();
}
// It is uncommon to use the registry handle, but if you need it,
// duplicate it now.
if (hRegKey)
{
LSTATUS const result = RegOpenKeyEx(hRegKey, NULL, 0, KEY_READ, &m_hRegKey);
hr = HRESULT_FROM_WIN32(result);
}
}
return hr;
}
Infotip 自定義
有兩種方式可以自定義資訊提示。 其中一種方法是實作支援 IQueryInfo 的物件,然後在登錄中適當的子機碼下註冊物件(請參閱下方)。 或者,您可以指定要顯示的固定字串或特定檔案屬性的清單。
若要顯示命名空間延伸模組的固定字串,請在命名空間延伸模組的 CLSID 索引鍵下方建立名為 InfoTip 的子機碼。 將該子機碼的值設定為您想要顯示的字串。
HKEY_CLASSES_ROOT
CLSID
{CLSID}
InfoTip = InfoTip string for your namespace extension
若要顯示檔類型的固定字串,請在您想要提供資訊提示的檔類型之 ProgID 索引鍵下,建立一個名為 InfoTip 的子鍵。 將該子機碼的數據設定為您想要顯示的字串。
HKEY_CLASSES_ROOT
ProgID
InfoTip = InfoTip string for all files of this type
如果您想要 Shell 在特定檔案類型的資訊提示中顯示特定檔案屬性,請在該檔類型的 ProgID 索引鍵下方,建立名為 InfoTip 的子機碼。 將該子機碼的數據設定為以分號分隔的標準屬性名稱或 {fmtid}, pid 組的列表,其中 propname 是標準屬性名稱,且 {fmtid}, pid 是 FMTID/PID 組合。
HKEY_CLASSES_ROOT
ProgID
InfoTip = propname;propname;{fmtid},pid;{fmtid},pid
您可以使用下列屬性名稱。
屬性名稱 | 描述 | 擷取自 |
---|---|---|
作者 | 檔的作者 | PIDSI_AUTHOR |
標題 | 檔的標題 | PIDSI_TITLE |
主題 | 主旨摘要 | PIDSI_SUBJECT |
評論 | 文件註解 | PIDSI_COMMENT 或資料夾/磁碟驅動器屬性 |
頁數計算 | 頁數 | PIDSI_PAGECOUNT |
名字 | 易記名稱 | 標準資料夾檢視 |
OriginalLocation | 源檔的位置 | 公事包資料夾和回收站資料夾 |
刪除日期 | 檔案刪除日期 | 回收站資料夾 |
類型 | 檔案類型 | 標準資料夾詳細數據檢視 |
大小 | 檔案大小 | 標準資料夾詳細數據檢視 |
SyncCopyIn | 與 OriginalLocation 相同 | 與 OriginalLocation 相同 |
改 性 | 上次修改日期 | 標準資料夾詳細數據檢視 |
創建 | 建立日期 | 標準資料夾詳細數據檢視 |
存取 | 上次存取的日期 | 標準資料夾詳細數據檢視 |
InFolder | 包含檔案的目錄 | 文件搜尋結果 |
排名 | 搜尋比對的品質 | 文件搜尋結果 |
自由空間 | 可用的儲存空間 | 磁碟驅動器 |
訪問次數 | 瀏覽次數 | Favorites 資料夾 |
屬性 | 檔案屬性 | 標準資料夾詳細數據檢視 |
公司 | 公司名稱 | PIDDSI_COMPANY |
類別 | 檔案類別 | PIDDSI_CATEGORY |
版權 | 媒體版權 | PIDMSI_COPYRIGHT |
HTML資訊提示檔案 | HTML 資訊提示檔案 | 資料夾的 Desktop.ini 檔案 |
相關主題