回答
所有的Shell擴展處理程序都是進程中的組件對象模型(COM)對象。必須按照註冊外殼擴展處理程序中的描述爲它們分配一個GUID並進行註冊。它們以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);
}
//下一節繼續實施示例。
實施IShellExtInit 的IShellExtInit接口只有一個方法,IShellExtInit ::初始化,除的IUnknown。該方法有三個參數,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_ABSOLUTEpidlFolder,__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; }
無論何時您創建或更改Shell擴展處理程序,都必須通知系統您已做出更改。通過調用SHChangeNotify來指定SHCNE_ASSOCCHANGED事件。如果您不調用SHChangeNotify,則在系統重新啓動之前可能無法識別更改。 還有一些其他因素適用於Windows 2000系統。有關詳細信息,請參閱Windows 2000系統上的註冊Shell擴展處理程序部分。 與所有組件對象模型(COM)對象一樣,您必須使用與Windows軟件開發工具包(SDK)一起提供的工具(如Guidgen.exe)爲該處理程序創建GUID。在HKEY_CLASSES_ROOT \ CLSID下創建一個子項,其名稱是該GUID的字符串形式。由於Shell擴展處理程序是進程內服務器,因此還必須在該GUID子項下創建一個InprocServer32子項,並將(默認)值設置爲處理程序DLL的路徑。使用公寓線程模型。一個例子如下所示:
HKEY_CLASSES_ROOT CLSID
{00021500-0000-0000-C000-000000000046}
InprocServer32
(Default) = %windir%\System32\Example.dll
ThreadingModel = Apartment
任何時候殼牌需要可以涉及一個外殼擴展處理程序的動作時,它檢查適當的註冊表子項。註冊擴展處理程序的子項控制何時調用它。例如,當Shell爲文件類型的成員顯示快捷菜單時,通常會調用快捷菜單處理程序。在這種情況下,處理程序必須在文件類型的ProgID子項下注冊。
這是一個非常好的答案我想在[更基本的問題](http://stackoverflow.com/questions/8438066)中進行概述。我想你會得到賞金。但我可以在哪裏更改類別?在截圖上的紅色框。 – rekire 2012-01-25 08:12:11
很棒的分析....真的很有幫助。 – 2012-03-21 07:31:13
- 1. 如何使用Azure流暢資源管理註冊資源提供者?
- 2. VS代碼 - 文件資源管理器/資源管理器更改案例
- 3. Postgres是否提供符合XA標準的資源管理器?
- 4. 更改火花數據網格的數據提供者數據?
- 5. 資源管理器
- 6. 數據庫資源管理器服務器資源管理器在更換VS 2010
- 7. MySQL的數據提供者是在更改數據源不存在VS2013
- 8. Azure資源提供者概念
- 9. 內容提供者資源$ NotFoundException
- 10. 自定義資源提供者
- 11. EF通用資源庫到任何數據提供者
- 12. Azure資源管理器 - 更新現有資源組的標籤
- 13. Azure資源管理器 - 更新標籤
- 14. 應用WPF中的實時資源管理器中的更改
- 15. 沒有提供者的角色管理?
- 16. 如何更改DDMS /文件資源管理器/ sdcard的權限?
- 17. 更改PyDev包資源管理器中的字體
- 18. 以編程方式更改Windows資源管理器的外觀?
- 19. Eclipse - 如何更改包資源管理器的字體顏色?
- 20. 如何更改Windows資源管理器中使用的圖標?
- 21. 提供參數,以$資源
- 22. 在Bazaar資源管理器中,想要修改提交消息
- 23. 無法從Eclipse的數據源資源管理器
- 24. 測試用例類別中的獨立數據提供者
- 25. Flex 4 - 數據提供者更改時的調用函數
- 26. Coherence資源管理器
- 27. 在Windows資源管理器
- 28. PyDev包資源管理器
- 29. Azure資源管理器
- 30. 在Windows資源管理器
那麼,這與C++有什麼關係? – 2012-01-20 07:57:28