关于桌面删除不掉的图标的实现
2010-08-03 13:41
519 查看
最近朋友的电脑桌面上有了类似淘宝购物的桌面图标,普通的方法都不能删除,最后我使用了金山卫士将这个
可恶的图标清理掉了,同时对它的实现原理也产生了兴趣,几经摸索,终于实现了类似的功能,贴出来分享一下,第
一篇博文,加上水平有限,请多谅解。
其实这个图标的技术实现是非常老的,甚至谈不上技术,但却让普通的用户很头痛,它利用了Shell命名空间扩展使得
该图标具备了类似于我的电脑,回收站等系统图标的特性,所以普通的方法无法删除。Shell命名空间扩展需要一个进程内
服务器来实现,这就要用到COM(组件对象模型),但原始C++实现COM非常麻烦,而ATL非常合适用来实现一个中小的
COM组件,趁这个机会,也接触了一下ATL。好了,废话少说,源码能说明任何问题,让我们来实际体验一下。
1:启动VS2005项目向导,选择ATL项目,在名字栏输入PersistIcon,接下来选择向导默认选项,这样
向导就为我们生成了一个进程内服务器的ATL的框架。
2:在类视图里右击PersistIcon工程,选择添加菜单,类(C)...,在添加类属性选择ATL简单对象,点击添加,最后在
简单对象向导里简称栏输入MyFolder,其它的内容会自动由向导填写.在第二步选择接口类型时选择自定义接口。
3: 打开MyFolder.h文档,向导已经为我们生成了一个组件类,并继承了必要的基类和IMyFolder接口。为实现命名空间
扩展,我们需要实现几个接口,在头文件开始处添加(红色字体为手工添加的):
#pragma once
#include "resource.h" // 主符号
#include "PersistIcon.h"
#include "shlobj.h"
#include "comdef.h"
在COM接口映射部分,添加我们需要实现的接口:
BEGIN_COM_MAP(CMyFolder)
COM_INTERFACE_ENTRY(IMyFolder)
COM_INTERFACE_ENTRY(IShellFolder)
COM_INTERFACE_ENTRY(IPersistFolder)
COM_INTERFACE_ENTRY(IShellExtInit)
COM_INTERFACE_ENTRY(IContextMenu)
END_COM_MAP()
在类中声明以下接口函数:
//IPersist
//{624CD55D-B175-44D8-B772-16ADC850CAA1}
STDMETHODIMP GetClassID(CLSID * pClassID);
//IPersistFolder
STDMETHODIMP Initialize(LPCITEMIDLIST pidl);
//IShellFolder
STDMETHOD (BindToObject) (LPCITEMIDLIST pidl,LPBC pbc,REFIID riid,VOID ** ppvOut);
STDMETHOD (BindToStorage) (LPCITEMIDLIST pidl, LPBC pbc , REFIID riid, VOID ** ppvOut);
STDMETHOD (CompareIDs) (LPARAM lParam,LPCITEMIDLIST pidl1,LPCITEMIDLIST pidl2);
STDMETHOD (CreateViewObject) (HWND hwndOwner,REFIID riid,VOID ** ppvOut);
STDMETHOD (EnumObjects) (HWND hwndOwner,SHCONTF grfFlags,IEnumIDList ** ppenumIdList);
STDMETHOD (GetAttributesOf) (UINT cidl,LPCITEMIDLIST * apidl,SFGAOF * rgfInOut);
STDMETHOD (GetDisplayNameOf) (LPCITEMIDLIST pidl,DWORD uFlags,LPSTRRET lpName);
STDMETHOD (GetUIObjectOf) (HWND hwndOwner,UINT cidl,LPCITEMIDLIST * apidl,
REFIID riid,UINT * rgfReserved,VOID ** ppVoid);
STDMETHOD (ParseDisplayName) (HWND hwnd,LPBC pbc,LPOLESTR pwszDisplayName,
ULONG * pchEaten,LPITEMIDLIST * ppidl,ULONG * pdwAttributes);
STDMETHOD (SetNameOf) (HWND hwndOwner,LPCITEMIDLIST pidl,
LPCOLESTR lpszName,DWORD uFlags,LPITEMIDLIST * ppidlOut);
///////////////////////////////////////////////////////////////////////////
//IShellExtInit
STDMETHOD (Initialize) (LPCITEMIDLIST lpidlFolder,IDataObject * pdtObject,HKEY hKeyProgID);
///////////////////////////////////////////////////////////////////////////
//IContextMenu
STDMETHOD (GetCommandString) (UINT_PTR idCmd,UINT uFlags,UINT * pwReserved,LPSTR lpszName,UINT cchMax);
STDMETHOD (InvokeCommand) (LPCMINVOKECOMMANDINFO pici);
STDMETHOD (QueryContextMenu) (HMENU hMenu,UINT indexMenu,UINT idCmdFirst,UINT idCmdLast,UINT uFlags);
在实现文件MyFolder.cpp中实现接口函数:
//IPersist
STDMETHODIMP CMyFolder::GetClassID(CLSID * pClassID)
{
*pClassID = CLSID_MyFolder;
return S_OK;
}
//IPersistFolder
STDMETHODIMP CMyFolder::Initialize(LPCITEMIDLIST pidl)
{
return S_OK;
}
//IShellExtInit
STDMETHODIMP CMyFolder::Initialize(LPCITEMIDLIST lpidlFolder,IDataObject * pdtObject,HKEY hKeyProgID)
{
return S_OK;
}
//IShellExtInit
STDMETHODIMP CMyFolder::Initialize(LPCITEMIDLIST lpidlFolder,IDataObject * pdtObject,HKEY hKeyProgID)
{
return S_OK;
}
///////////////////////////////////////////////////////////////////////////
//IContextMenu
STDMETHODIMP CMyFolder::GetCommandString(UINT_PTR idCmd,UINT uFlags,UINT * pwReserved,LPSTR lpszName,UINT cchMax)
{
return E_FAIL;
}
STDMETHODIMP CMyFolder::InvokeCommand(LPCMINVOKECOMMANDINFO pici)
{
if(HIWORD(pici->lpVerb) != 0)
return E_INVALIDARG;
switch(LOWORD(pici->lpVerb))
{
case 0:
ShellExecute(NULL,TEXT("open"),TEXT("http://blog.csdn.net/TheHappyWolf"),NULL,NULL,SW_SHOWNORMAL);
break;
case 1:
MessageBox(pici->hwnd,TEXT("我不喜欢被删除!"),TEXT("提示"),MB_OK|MB_ICONEXCLAMATION);
default:
return E_INVALIDARG;
}
return S_OK;
}
STDMETHODIMP CMyFolder::QueryContextMenu(HMENU hMenu,UINT indexMenu,UINT idCmdFirst,UINT idCmdLast,UINT uFlags)
{
//插入打开菜单项
InsertMenu(hMenu,indexMenu,MF_BYPOSITION,idCmdFirst+1,TEXT("删除(&D)"));
InsertMenu(hMenu,indexMenu,MF_BYPOSITION,idCmdFirst,TEXT("打开(&O)"));
return MAKE_HRESULT(SEVERITY_SUCCESS,FACILITY_NULL,2);
}
其它的接口函数实现均返回E_NOTIMPL.
4:到这里我们的工作就算已经完成了,不过ATL在每次组件注册的时候,由于使用了rgs注册脚本,所以不够灵活。为了
让我们的DLL能更灵活一些,我们需要修改其DLL中DllRegisterServer和DllUnregisterServer的实现。在PersistIcon.cpp
包含文件之后添加如下数据结构定义:
#include "stdafx.h"
#include "resource.h"
#include "PersistIcon.h"
#include "shlobj.h"
//定义写入到注册表中的键
typedef struct _Key_Struct{
LPCTSTR lpszSubKeyName; //子键
LPCTSTR lpszKeyName; //键名
DWORD dwType; //键值类型
union KEYVALUE{ //键值
LPCTSTR strValue; //字符串值
DWORD dValue; //整型值
}KeyValue;
//LPCTSTR strValue;
}KEYSTRUCT,*PKEYSTRUCT;
//显示的图标名称
LPCTSTR lpszFolderName = TEXT("Persist Icon");
class CPersistIconModule : public CAtlDllModuleT< CPersistIconModule >
{
//内容略
}
修改DllRegisterServer和DllUnregisterServer的实现:
// DllRegisterServer - 将项添加到系统注册表
STDAPI DllRegisterServer(void)
{
// 注册对象、类型库和类型库中的所有接口
//HRESULT hr = _AtlModule.DllRegisterServer();
HRESULT hr = S_OK;
HKEY hKeyClass,hKeyClassSub,hKeyLocation;
GetModuleFileName(hModule,szModuleName,MAX_PATH);
TCHAR szIconLocation[MAX_PATH + 20] = {TEXT('/0')};
_tcscat(szIconLocation,szModuleName);
_tcscat(szIconLocation,TEXT(",0"));
//注册命名空间的位置
LPCTSTR lpszLocation = TEXT("SOFTWARE//Microsoft//Windows//CurrentVersion//Explorer//Desktop//NameSpace")
TEXT("//{624CD55D-B175-44D8-B772-16ADC850CAA1}"); //这里的组件CLSID需要根据你生成的实际更改,以后不再重述
hr = RegCreateKeyEx(HKEY_LOCAL_MACHINE,lpszLocation,0,NULL,REG_OPTION_NON_VOLATILE,
KEY_ALL_ACCESS,NULL,&hKeyLocation,NULL);
if(hr != ERROR_SUCCESS)
return hr;
LPCTSTR lpszClassID = TEXT("CLSID//{624CD55D-B175-44D8-B772-16ADC850CAA1}");
//自定义添加注册表项
KEYSTRUCT myFolderKey[] = {
{TEXT("InprocServer32"),NULL,REG_SZ,szModuleName},
{TEXT("InprocServer32"),TEXT("ThreadingModel"),REG_SZ,TEXT("Apartment")},
{TEXT("DefaultIcon"),NULL,REG_SZ,szIconLocation},
{TEXT("Shellex//ContextMenuHandlers//0"),NULL,REG_SZ,TEXT("{624CD55D-B175-44D8-B772-16ADC850CAA1}")},
{TEXT("Shellex//MayChangeDefaultMenu"),NULL,REG_SZ,TEXT("")},
{TEXT("ShellFolder"),TEXT("Attributes"),REG_DWORD,0x00000000},
{TEXT("ShellFolder"),TEXT("HideFolderVerbs"),REG_SZ,TEXT("")}
};
//删除CLSID键中的组件的类ID
hr = SHDeleteKey(HKEY_CLASSES_ROOT,lpszClassID);
//在CLSID中建立组件的类ID
hr = RegCreateKeyEx(HKEY_CLASSES_ROOT,lpszClassID,0,NULL,REG_OPTION_NON_VOLATILE,
KEY_ALL_ACCESS,NULL,&hKeyClass,NULL);
if(hr != ERROR_SUCCESS)
return hr;
//设置类ID的默认值,该值将会显示为文件夹的名称
hr = RegSetValueEx(hKeyClass,NULL,0,REG_SZ,
(const BYTE *)(lpszFolderName),(_tcslen(lpszFolderName) + 1) * sizeof(TCHAR));
if(hr != ERROR_SUCCESS)
{//失败则删除所有的键
SHDeleteKey(hKeyClass,NULL);
RegCloseKey(hKeyClass);
return hr;
}
//建立组件的CLSD下的每个键和键值
for(int i = 0;i<(sizeof(myFolderKey))/(sizeof(KEYSTRUCT));i++)
{
HRESULT hr = RegCreateKeyEx(hKeyClass,myFolderKey[i].lpszSubKeyName,0,NULL,
REG_OPTION_NON_VOLATILE,KEY_ALL_ACCESS,NULL,&hKeyClassSub,NULL);
const BYTE * pData = (myFolderKey[i].dwType == REG_SZ?
(const BYTE *)(myFolderKey[i].KeyValue.strValue):
(const BYTE *)(&(myFolderKey[i].KeyValue.dValue)));
HRESULT hr1 = RegSetValueEx(hKeyClassSub,myFolderKey[i].lpszKeyName,0,myFolderKey[i].dwType,pData,
(myFolderKey[i].dwType == REG_SZ)?(_tcslen(myFolderKey[i].KeyValue.strValue ) + 1) * sizeof(TCHAR):sizeof(DWORD));
if(hr1!=ERROR_SUCCESS)
{
SHDeleteKey(hKeyClass,NULL);
break;
}
if(hr == ERROR_SUCCESS)
RegCloseKey(hKeyClassSub);
}
RegCloseKey(hKeyClass);
//更新桌面
LPITEMIDLIST lpidlDesktop;
SHGetSpecialFolderLocation(NULL,CSIDL_DESKTOP,&lpidlDesktop);
SHChangeNotify(SHCNE_UPDATEDIR,SHCNF_IDLIST,lpidlDesktop,0);
//释放内存
IMalloc * pMalloc;
if(SHGetMalloc(&pMalloc) == S_OK)
{
pMalloc->Free(lpidlDesktop);
pMalloc->Release();
}
return S_OK;
}
// DllUnregisterServer - 将项从系统注册表中移除
STDAPI DllUnregisterServer(void)
{
//HRESULT hr = _AtlModule.DllUnregisterServer();
HRESULT hr1,hr2;
//删除组件类键
hr1 = RegDeleteKey(HKEY_CLASSES_ROOT,TEXT("CLSID//{624CD55D-B175-44D8-B772-16ADC850CAA1}"));
//删除命名空间位置键
hr2 = RegDeleteKey(HKEY_LOCAL_MACHINE,
TEXT("SOFTWARE//Microsoft//Windows//CurrentVersion//Explorer//Desktop//NameSpace")
TEXT("//{624CD55D-B175-44D8-B772-16ADC850CAA1}"));
if(hr1!=ERROR_SUCCESS || hr2!=ERROR_SUCCESS)
return S_FALSE;
//更新桌面
LPITEMIDLIST lpidlDesktop;
SHGetSpecialFolderLocation(NULL,CSIDL_DESKTOP,&lpidlDesktop);
SHChangeNotify(SHCNE_UPDATEDIR,SHCNF_IDLIST,lpidlDesktop,0);
//释放内存
IMalloc * pMalloc;
if(SHGetMalloc(&pMalloc) == S_OK)
{
pMalloc->Free(lpidlDesktop);
pMalloc->Release();
}
return S_OK;
}
5:生成工程就会发现桌面多了一个图标,可以进行测试是否正常工作。
6:如果需要将组件注册到别的机器上去,可以写一exe,将该DLL作为资源存放,exe运行过程中从资源生成
DLL文件,并加载该DLL,调用DLL中调出的DllRegisterServer和DllUnRegisterServer进行注册和反注册
操作。
终于完成了,好累啊。对于SHELL命名空间扩展和COM的一些不明白的地方,可以参考ATL开发指南和Visual C++ Windows Shell Programming,网上有电子书可以下载。
可恶的图标清理掉了,同时对它的实现原理也产生了兴趣,几经摸索,终于实现了类似的功能,贴出来分享一下,第
一篇博文,加上水平有限,请多谅解。
其实这个图标的技术实现是非常老的,甚至谈不上技术,但却让普通的用户很头痛,它利用了Shell命名空间扩展使得
该图标具备了类似于我的电脑,回收站等系统图标的特性,所以普通的方法无法删除。Shell命名空间扩展需要一个进程内
服务器来实现,这就要用到COM(组件对象模型),但原始C++实现COM非常麻烦,而ATL非常合适用来实现一个中小的
COM组件,趁这个机会,也接触了一下ATL。好了,废话少说,源码能说明任何问题,让我们来实际体验一下。
1:启动VS2005项目向导,选择ATL项目,在名字栏输入PersistIcon,接下来选择向导默认选项,这样
向导就为我们生成了一个进程内服务器的ATL的框架。
2:在类视图里右击PersistIcon工程,选择添加菜单,类(C)...,在添加类属性选择ATL简单对象,点击添加,最后在
简单对象向导里简称栏输入MyFolder,其它的内容会自动由向导填写.在第二步选择接口类型时选择自定义接口。
3: 打开MyFolder.h文档,向导已经为我们生成了一个组件类,并继承了必要的基类和IMyFolder接口。为实现命名空间
扩展,我们需要实现几个接口,在头文件开始处添加(红色字体为手工添加的):
#pragma once
#include "resource.h" // 主符号
#include "PersistIcon.h"
#include "shlobj.h"
#include "comdef.h"
在COM接口映射部分,添加我们需要实现的接口:
BEGIN_COM_MAP(CMyFolder)
COM_INTERFACE_ENTRY(IMyFolder)
COM_INTERFACE_ENTRY(IShellFolder)
COM_INTERFACE_ENTRY(IPersistFolder)
COM_INTERFACE_ENTRY(IShellExtInit)
COM_INTERFACE_ENTRY(IContextMenu)
END_COM_MAP()
在类中声明以下接口函数:
//IPersist
//{624CD55D-B175-44D8-B772-16ADC850CAA1}
STDMETHODIMP GetClassID(CLSID * pClassID);
//IPersistFolder
STDMETHODIMP Initialize(LPCITEMIDLIST pidl);
//IShellFolder
STDMETHOD (BindToObject) (LPCITEMIDLIST pidl,LPBC pbc,REFIID riid,VOID ** ppvOut);
STDMETHOD (BindToStorage) (LPCITEMIDLIST pidl, LPBC pbc , REFIID riid, VOID ** ppvOut);
STDMETHOD (CompareIDs) (LPARAM lParam,LPCITEMIDLIST pidl1,LPCITEMIDLIST pidl2);
STDMETHOD (CreateViewObject) (HWND hwndOwner,REFIID riid,VOID ** ppvOut);
STDMETHOD (EnumObjects) (HWND hwndOwner,SHCONTF grfFlags,IEnumIDList ** ppenumIdList);
STDMETHOD (GetAttributesOf) (UINT cidl,LPCITEMIDLIST * apidl,SFGAOF * rgfInOut);
STDMETHOD (GetDisplayNameOf) (LPCITEMIDLIST pidl,DWORD uFlags,LPSTRRET lpName);
STDMETHOD (GetUIObjectOf) (HWND hwndOwner,UINT cidl,LPCITEMIDLIST * apidl,
REFIID riid,UINT * rgfReserved,VOID ** ppVoid);
STDMETHOD (ParseDisplayName) (HWND hwnd,LPBC pbc,LPOLESTR pwszDisplayName,
ULONG * pchEaten,LPITEMIDLIST * ppidl,ULONG * pdwAttributes);
STDMETHOD (SetNameOf) (HWND hwndOwner,LPCITEMIDLIST pidl,
LPCOLESTR lpszName,DWORD uFlags,LPITEMIDLIST * ppidlOut);
///////////////////////////////////////////////////////////////////////////
//IShellExtInit
STDMETHOD (Initialize) (LPCITEMIDLIST lpidlFolder,IDataObject * pdtObject,HKEY hKeyProgID);
///////////////////////////////////////////////////////////////////////////
//IContextMenu
STDMETHOD (GetCommandString) (UINT_PTR idCmd,UINT uFlags,UINT * pwReserved,LPSTR lpszName,UINT cchMax);
STDMETHOD (InvokeCommand) (LPCMINVOKECOMMANDINFO pici);
STDMETHOD (QueryContextMenu) (HMENU hMenu,UINT indexMenu,UINT idCmdFirst,UINT idCmdLast,UINT uFlags);
在实现文件MyFolder.cpp中实现接口函数:
//IPersist
STDMETHODIMP CMyFolder::GetClassID(CLSID * pClassID)
{
*pClassID = CLSID_MyFolder;
return S_OK;
}
//IPersistFolder
STDMETHODIMP CMyFolder::Initialize(LPCITEMIDLIST pidl)
{
return S_OK;
}
//IShellExtInit
STDMETHODIMP CMyFolder::Initialize(LPCITEMIDLIST lpidlFolder,IDataObject * pdtObject,HKEY hKeyProgID)
{
return S_OK;
}
//IShellExtInit
STDMETHODIMP CMyFolder::Initialize(LPCITEMIDLIST lpidlFolder,IDataObject * pdtObject,HKEY hKeyProgID)
{
return S_OK;
}
///////////////////////////////////////////////////////////////////////////
//IContextMenu
STDMETHODIMP CMyFolder::GetCommandString(UINT_PTR idCmd,UINT uFlags,UINT * pwReserved,LPSTR lpszName,UINT cchMax)
{
return E_FAIL;
}
STDMETHODIMP CMyFolder::InvokeCommand(LPCMINVOKECOMMANDINFO pici)
{
if(HIWORD(pici->lpVerb) != 0)
return E_INVALIDARG;
switch(LOWORD(pici->lpVerb))
{
case 0:
ShellExecute(NULL,TEXT("open"),TEXT("http://blog.csdn.net/TheHappyWolf"),NULL,NULL,SW_SHOWNORMAL);
break;
case 1:
MessageBox(pici->hwnd,TEXT("我不喜欢被删除!"),TEXT("提示"),MB_OK|MB_ICONEXCLAMATION);
default:
return E_INVALIDARG;
}
return S_OK;
}
STDMETHODIMP CMyFolder::QueryContextMenu(HMENU hMenu,UINT indexMenu,UINT idCmdFirst,UINT idCmdLast,UINT uFlags)
{
//插入打开菜单项
InsertMenu(hMenu,indexMenu,MF_BYPOSITION,idCmdFirst+1,TEXT("删除(&D)"));
InsertMenu(hMenu,indexMenu,MF_BYPOSITION,idCmdFirst,TEXT("打开(&O)"));
return MAKE_HRESULT(SEVERITY_SUCCESS,FACILITY_NULL,2);
}
其它的接口函数实现均返回E_NOTIMPL.
4:到这里我们的工作就算已经完成了,不过ATL在每次组件注册的时候,由于使用了rgs注册脚本,所以不够灵活。为了
让我们的DLL能更灵活一些,我们需要修改其DLL中DllRegisterServer和DllUnregisterServer的实现。在PersistIcon.cpp
包含文件之后添加如下数据结构定义:
#include "stdafx.h"
#include "resource.h"
#include "PersistIcon.h"
#include "shlobj.h"
//定义写入到注册表中的键
typedef struct _Key_Struct{
LPCTSTR lpszSubKeyName; //子键
LPCTSTR lpszKeyName; //键名
DWORD dwType; //键值类型
union KEYVALUE{ //键值
LPCTSTR strValue; //字符串值
DWORD dValue; //整型值
}KeyValue;
//LPCTSTR strValue;
}KEYSTRUCT,*PKEYSTRUCT;
//显示的图标名称
LPCTSTR lpszFolderName = TEXT("Persist Icon");
class CPersistIconModule : public CAtlDllModuleT< CPersistIconModule >
{
//内容略
}
修改DllRegisterServer和DllUnregisterServer的实现:
// DllRegisterServer - 将项添加到系统注册表
STDAPI DllRegisterServer(void)
{
// 注册对象、类型库和类型库中的所有接口
//HRESULT hr = _AtlModule.DllRegisterServer();
HRESULT hr = S_OK;
HKEY hKeyClass,hKeyClassSub,hKeyLocation;
GetModuleFileName(hModule,szModuleName,MAX_PATH);
TCHAR szIconLocation[MAX_PATH + 20] = {TEXT('/0')};
_tcscat(szIconLocation,szModuleName);
_tcscat(szIconLocation,TEXT(",0"));
//注册命名空间的位置
LPCTSTR lpszLocation = TEXT("SOFTWARE//Microsoft//Windows//CurrentVersion//Explorer//Desktop//NameSpace")
TEXT("//{624CD55D-B175-44D8-B772-16ADC850CAA1}"); //这里的组件CLSID需要根据你生成的实际更改,以后不再重述
hr = RegCreateKeyEx(HKEY_LOCAL_MACHINE,lpszLocation,0,NULL,REG_OPTION_NON_VOLATILE,
KEY_ALL_ACCESS,NULL,&hKeyLocation,NULL);
if(hr != ERROR_SUCCESS)
return hr;
LPCTSTR lpszClassID = TEXT("CLSID//{624CD55D-B175-44D8-B772-16ADC850CAA1}");
//自定义添加注册表项
KEYSTRUCT myFolderKey[] = {
{TEXT("InprocServer32"),NULL,REG_SZ,szModuleName},
{TEXT("InprocServer32"),TEXT("ThreadingModel"),REG_SZ,TEXT("Apartment")},
{TEXT("DefaultIcon"),NULL,REG_SZ,szIconLocation},
{TEXT("Shellex//ContextMenuHandlers//0"),NULL,REG_SZ,TEXT("{624CD55D-B175-44D8-B772-16ADC850CAA1}")},
{TEXT("Shellex//MayChangeDefaultMenu"),NULL,REG_SZ,TEXT("")},
{TEXT("ShellFolder"),TEXT("Attributes"),REG_DWORD,0x00000000},
{TEXT("ShellFolder"),TEXT("HideFolderVerbs"),REG_SZ,TEXT("")}
};
//删除CLSID键中的组件的类ID
hr = SHDeleteKey(HKEY_CLASSES_ROOT,lpszClassID);
//在CLSID中建立组件的类ID
hr = RegCreateKeyEx(HKEY_CLASSES_ROOT,lpszClassID,0,NULL,REG_OPTION_NON_VOLATILE,
KEY_ALL_ACCESS,NULL,&hKeyClass,NULL);
if(hr != ERROR_SUCCESS)
return hr;
//设置类ID的默认值,该值将会显示为文件夹的名称
hr = RegSetValueEx(hKeyClass,NULL,0,REG_SZ,
(const BYTE *)(lpszFolderName),(_tcslen(lpszFolderName) + 1) * sizeof(TCHAR));
if(hr != ERROR_SUCCESS)
{//失败则删除所有的键
SHDeleteKey(hKeyClass,NULL);
RegCloseKey(hKeyClass);
return hr;
}
//建立组件的CLSD下的每个键和键值
for(int i = 0;i<(sizeof(myFolderKey))/(sizeof(KEYSTRUCT));i++)
{
HRESULT hr = RegCreateKeyEx(hKeyClass,myFolderKey[i].lpszSubKeyName,0,NULL,
REG_OPTION_NON_VOLATILE,KEY_ALL_ACCESS,NULL,&hKeyClassSub,NULL);
const BYTE * pData = (myFolderKey[i].dwType == REG_SZ?
(const BYTE *)(myFolderKey[i].KeyValue.strValue):
(const BYTE *)(&(myFolderKey[i].KeyValue.dValue)));
HRESULT hr1 = RegSetValueEx(hKeyClassSub,myFolderKey[i].lpszKeyName,0,myFolderKey[i].dwType,pData,
(myFolderKey[i].dwType == REG_SZ)?(_tcslen(myFolderKey[i].KeyValue.strValue ) + 1) * sizeof(TCHAR):sizeof(DWORD));
if(hr1!=ERROR_SUCCESS)
{
SHDeleteKey(hKeyClass,NULL);
break;
}
if(hr == ERROR_SUCCESS)
RegCloseKey(hKeyClassSub);
}
RegCloseKey(hKeyClass);
//更新桌面
LPITEMIDLIST lpidlDesktop;
SHGetSpecialFolderLocation(NULL,CSIDL_DESKTOP,&lpidlDesktop);
SHChangeNotify(SHCNE_UPDATEDIR,SHCNF_IDLIST,lpidlDesktop,0);
//释放内存
IMalloc * pMalloc;
if(SHGetMalloc(&pMalloc) == S_OK)
{
pMalloc->Free(lpidlDesktop);
pMalloc->Release();
}
return S_OK;
}
// DllUnregisterServer - 将项从系统注册表中移除
STDAPI DllUnregisterServer(void)
{
//HRESULT hr = _AtlModule.DllUnregisterServer();
HRESULT hr1,hr2;
//删除组件类键
hr1 = RegDeleteKey(HKEY_CLASSES_ROOT,TEXT("CLSID//{624CD55D-B175-44D8-B772-16ADC850CAA1}"));
//删除命名空间位置键
hr2 = RegDeleteKey(HKEY_LOCAL_MACHINE,
TEXT("SOFTWARE//Microsoft//Windows//CurrentVersion//Explorer//Desktop//NameSpace")
TEXT("//{624CD55D-B175-44D8-B772-16ADC850CAA1}"));
if(hr1!=ERROR_SUCCESS || hr2!=ERROR_SUCCESS)
return S_FALSE;
//更新桌面
LPITEMIDLIST lpidlDesktop;
SHGetSpecialFolderLocation(NULL,CSIDL_DESKTOP,&lpidlDesktop);
SHChangeNotify(SHCNE_UPDATEDIR,SHCNF_IDLIST,lpidlDesktop,0);
//释放内存
IMalloc * pMalloc;
if(SHGetMalloc(&pMalloc) == S_OK)
{
pMalloc->Free(lpidlDesktop);
pMalloc->Release();
}
return S_OK;
}
5:生成工程就会发现桌面多了一个图标,可以进行测试是否正常工作。
6:如果需要将组件注册到别的机器上去,可以写一exe,将该DLL作为资源存放,exe运行过程中从资源生成
DLL文件,并加载该DLL,调用DLL中调出的DllRegisterServer和DllUnRegisterServer进行注册和反注册
操作。
终于完成了,好累啊。对于SHELL命名空间扩展和COM的一些不明白的地方,可以参考ATL开发指南和Visual C++ Windows Shell Programming,网上有电子书可以下载。
相关文章推荐
- 关于桌面Internet Explorer图标无法删除的处理办法
- win7桌面的IE图标删除
- 关于实现局域网桌面音视频广播方案
- 删除桌面hummingbird neighborhood图标
- 关于CollectionView的九宫格排布,多选,全选实现及删除
- 删除桌面 “好玩小游戏” 图标
- 轻松删除win7家庭版桌面回收站图标
- 关于桌面图标后缀全部变成.lnk(WIN7系统电脑除了计算机,网络,回收站以外(包括开始菜单)的图标全都变成后缀为.lnk的文件)的处理方法
- QtQuick桌面应用开发指导 1)关于教程 2)原型和设计 3)实现UI和功能_A
- WIN7桌面出现最近访问的位置图标无法删除,如何处理
- M8如何删除桌面图标
- div+css实现window xp桌面图标布局(至上而下从左往右)
- 长按实现图标抖动和删除的代码例子
- 添加删除桌面图标
- 在活动目录服务器上从桌面中删除“Internet Explorer”图标
- Linux - 麒麟17.04 删除桌面图标(计算机,主文件夹,回收站)与 Cairo-Dock 安装配置
- 关于checkbox的ListView实现多选、全选、反选、删除更简单的方法
- 关于vector的erase删除操作的两种不同方法,在linux与visual studio的实现讨论
- Android桌面快捷方式图标生成与删除,使用Intent与launcher交互
- win7桌面图标删不掉怎么办 桌面快捷方式或桌面文件删除教程