VC++用IcopyHook实现监控文件夹(添加,删除,移动...等 *** 作)

VC++用IcopyHook实现监控文件夹(添加,删除,移动...等 *** 作),第1张

这个很简单吧,创建一个COM工程(个人喜欢基于ATL创建),然后实现了

ICopyHook接口就行了啊,DLL编译出来后,需要在注册表里添加指定的项以便EXPLORER加载它,具体位置参见一下MSDN,大概是这个

HKEY_CLASSES_ROOT

Directory

Shellex

CopyHookHandlers

your_copyhook

(Default)

= {copyhook CLSID value}

如果不能实时生效,重启一下EXPLORER就好,一般建议在虚拟机里调试,省得各种崩溃麻烦

ICopyHook是一个用于创建拷贝钩子处理程序COM接口,它决定一个文件夹或者打印机对象是否可以被移动,拷贝,重命名或删除。Shell在执行这些 *** 作之前,会调用ICopyHook接口的CopyCallback方法对它们进行验证。CopyCallback返回一个int值指示Shell是否应该继续执行这个 *** 作。返回值IDYES表示继续,而返回值IDNO和IDCANCEL则表示终止。【文章来自:开店乐KaiDianLe.Com】最好的网上开店系统:凡人网络购物系统V8.0 网上开店助手 不懂技术怎么建网上商城 网上开店两步搞定

一个文件夹对象可以安装多个拷贝钩子处理程序。如果出现这种情况,Shell会依次调用每个处理程序。只有当每个处理程序都返回IDYES时,Shell才真正执行用户请求的 *** 作。

拷贝钩子处理程序的作用是在上述四种 *** 作执行前对它们进行验证,但是Shell并不会把 *** 作的结果通知给拷贝钩子处理程序。而windows提供的API函数FindFirstChangeNotification和FindNextChangeNotification却可以实现这个功能。因此,只有把这种两种方法结合起来,才能对一个文件夹的状态进行完全的监控。

拷贝钩子处理程序实现并不困难,首先创建一个作为进程内组件的COM对象,它只需要暴露一个ICopyHook接口(当然还有IUnknown)。然后用regsrv32.exe注册这个COM组件。最后一步是向Shell注册你的这个拷贝钩子处理程序,方法是在注册表HKEY_CLASSES_ROOT\Directory\Shellex\CopyHookHandlers下创建一个名称任意的sub key,在此sub key中创建一个类型为REG_SZ的项并将你的COM对象的CLSID作为它的默认值就可以了。

下面就是一个拷贝钩子的实现程序

// CCopyHook.h

//CCopyHook类实现了ICopyHook接口,CClassFactory实现了IClassFactory接口

#include <shlobj.h>

class CCopyHook: public ICopyHook

{

public:

CCopyHook():m_refcnt(0) { }

STDMETHODIMP QueryInterface(REFIID iid,void** ppvObject)

STDMETHODIMP_(ULONG) AddRef()

STDMETHODIMP_(ULONG) Release()

STDMETHODIMP_(UINT) CopyCallback(HWND hwnd,UINT wFunc,UINT wFlags,

LPCTSTR pszSrcFile,DWORD dwSrcAttribs,

LPCTSTR pszDestFile,DWORD dwDestAttribs)

private:

int m_refcnt

}

class CClassFactory:public IClassFactory

{

public:

CClassFactory():m_refcnt(0) { }

STDMETHODIMP QueryInterface(REFIID iid,void** ppvObject)

STDMETHODIMP_(ULONG) AddRef()

STDMETHODIMP_(ULONG) Release()

STDMETHODIMP CreateInstance(IUnknown * pUnkOuter,REFIID riid,void ** ppvObject)

STDMETHODIMP LockServer(BOOL fLock)

private:

int m_refcnt

}

// CCopyHook.cpp

//CCopyHook对象和CClassFactory对象的实现文件

#include <stdio.h>

#include "CCopyHook.h"

extern LONG nLocks //对象计数,用于DllCanUnloadNow

ULONG __stdcall CCopyHook::AddRef(){

if(m_refcnt==0)

nLocks++

m_refcnt++

return m_refcnt

}

ULONG __stdcall CCopyHook::Release(){

int nNewCnt=--m_refcnt

if(nNewCnt<=0){

nLocks--

delete this

}

return nNewCnt

}

HRESULT __stdcall CCopyHook::QueryInterface(REFIID iid,void** ppvObject){

if(iid==IID_IUnknown)

*ppvObject=static_cast<IUnknown*>(this)

else

if(iid==IID_IShellCopyHook)

*ppvObject=static_cast<ICopyHook*>(this)

else

return E_NOINTERFACE

reinterpret_cast<IUnknown*>(*ppvObject)->AddRef()

return S_OK

}

//这就是CopyCallback方法,拷贝钩子的所有功能由它实现。参数的具体值参看MSDN

UINT __stdcall CCopyHook::CopyCallback(HWND hwnd,UINT wFunc,UINT wFlags,

LPCTSTR pszSrcFile,DWORD dwSrcAttribs,

LPCTSTR pszDestFile,DWORD dwDestAttribs){

char szMessage[MAX_PATH+14]

sprintf(szMessage,"对%s进行的 *** 作,是否继续?",pszSrcFile)

return MessageBox(NULL,szMessage,"确认",MB_YESNO|MB_ICONEXCLAMATION)

}

ULONG __stdcall CClassFactory::AddRef(){

if(m_refcnt==0)

nLocks++

m_refcnt++

return m_refcnt

}

ULONG __stdcall CClassFactory::Release(){

int nNewCnt=--m_refcnt

if(nNewCnt<=0){

nLocks--

delete this

}

return nNewCnt

}

HRESULT __stdcall CClassFactory::QueryInterface(REFIID iid,void** ppvObject){

if(iid==IID_IUnknown)

*ppvObject=static_cast<IUnknown*>(this)

else

if(iid==IID_IClassFactory)

*ppvObject=static_cast<IClassFactory*>(this)

else

return E_NOINTERFACE

reinterpret_cast<IUnknown*>(*ppvObject)->AddRef()

return S_OK

}

HRESULT __stdcall CClassFactory::CreateInstance(IUnknown* pUnkownOuter,REFIID riid,void** ppvObj){

if(pUnkownOuter!=NULL)

return CLASS_E_NOAGGREGATION

CCopyHook* pObj=new CCopyHook

pObj->AddRef()

HRESULT hr=pObj->QueryInterface(riid,ppvObj)

pObj->Release()

return hr

}

HRESULT __stdcall CClassFactory::LockServer(BOOL fLock){

if(fLock)

nLocks++

else

nLocks--

return S_OK

}

// main.cpp

//主要实现了几个COM对象标准的导出函数。

#include <objbase.h>

#include <olectl.h>

#include "CCopyHook.h"

//这是要添加到注册表中的项,注意如果你要使用这段代码,应该用UUIDGEN.exe生成一

//个新的CLSID。

const char* szRegTable[][3]={

{"CLSID\\{7e10a039-fe03-4f9c-b7e1-c5eeeaf53735}",0,"CopyHook"},

{"CLSID\\{7e10a039-fe03-4f9c-b7e1-c5eeeaf53735}\\InProcServer32",0,(const char*)-1},

{"CLSID\\{7e10a039-fe03-4f9c-b7e1-c5eeeaf53735}\\InProcServer32","ThreadingModel","Apartment"},

{"CLSID\\{7e10a039-fe03-4f9c-b7e1-c5eeeaf53735}\\ProgID",0,"webber84.CopyHook.1"},

{"webber84.CopyHook.1",0,"CopyHook"},

{"webber84.CopyHook.1\\CLSID",0,"{7e10a039-fe03-4f9c-b7e1-c5eeeaf53735}"}}

HMODULE hInstance=NULL

LONG nLocks=0

BOOL APIENTRY DllMain( HANDLE hModule,

DWORD ul_reason_for_call,

LPVOID lpReserved

){

if(ul_reason_for_call==DLL_PROCESS_ATTACH)

hInstance=(HMODULE)hModule

return TRUE

}

STDAPI DllUnregisterServer(){

HRESULT hr=S_OKLONG ret=0

int items=sizeof(szRegTable)/sizeof(szRegTable[0])

for(int i=items-1i>=0i--){

const char* szKeyName=szRegTable[i][0]

if( (i==items-1) || stricmp(szRegTable[i+1][0],szKeyName)!=0)

ret=RegDeleteKey(HKEY_CLASSES_ROOT,szKeyName)

if(ret!=ERROR_SUCCESS)

hr=SELFREG_E_CLASS

}

return hr

}

//可重用的DllRegisterServer函数,只要照上面的格式把注册表项放到一个数组中,就可以//用这段代码完成对任意组件的注册。

STDAPI DllRegisterServer(void){

HRESULT hr=S_OK

int items=sizeof(szRegTable)/sizeof(szRegTable[0])

char szDllPath[MAX_PATH]

GetModuleFileName(hInstance,szDllPath,MAX_PATH)

for(int i=0i<items &&SUCCEEDED(hr)i++){

const char* szKeyName=szRegTable[i][0]

const char* szValueName=szRegTable[i][1]

const char* szValue=szRegTable[i][2]

if(szValue==(const char*)-1)

szValue=szDllPath

HKEY hKey

LONG ret=RegCreateKey(HKEY_CLASSES_ROOT,szKeyName,&hKey)

if(ret==ERROR_SUCCESS){

RegSetValueEx(hKey,szValueName,0,REG_SZ,(const BYTE*)szValue,

strlen(szValue)+1)

RegCloseKey(hKey)

}

if(ret!=ERROR_SUCCESS){

hr=SELFREG_E_CLASS

DllUnregisterServer()

}

}

return hr

}

STDAPI DllGetClassObject (REFCLSID rclsid, REFIID riid, void** ppvObj) {

HRESULT hr = E_OUTOFMEMORY

*ppvObj = NULL

CClassFactory *pClassFactory = new CClassFactory

if (pClassFactory != NULL)

hr = pClassFactory->QueryInterface(riid, ppvObj)

return hr

}

STDAPI DllCanUnloadNow(){

return nLocks==0 ? S_OK : S_FALSE

}

COM接口,它决定一个文件夹或者打印机对象是否可以被移动,拷贝,重命名或删除。Shell在执行这些 *** 作之前,会调用ICopyHook接口的CopyCallback方法对它们进行验证。CopyCallback返回一个int值指示Shell是否应该继续执行这个 *** 作。返回值IDYES表示继续,而返回值IDNO和IDCANCEL则表示终止。最好的网上开店系统:凡人网络购物系统V8.0 网上开店助手 不懂技术怎么建网上商城 网上开店两步搞定

一个文件夹对象可以安装多个拷贝钩子处理程序。如果出现这种情况,Shell会依次调用每个处理程序。只有当每个处理程序都返回IDYES时,Shell才真正执行用户请求的 *** 作。

拷贝钩子处理程序的作用是在上述四种 *** 作执行前对它们进行验证,但是Shell并不会把 *** 作的结果通知给拷贝钩子处理程序。而windows提供的API函数FindFirstChangeNotification和FindNextChangeNotification却可以实现这个功能。因此,只有把这种两种方法结合起来,才能对一个文件夹的状态进行完全的监控。

拷贝钩子处理程序实现并不困难,首先创建一个作为进程内组件的COM对象,它只需要暴露一个ICopyHook接口(当然还有IUnknown)。然后用regsrv32.exe注册这个COM组件。最后一步是向Shell注册你的这个拷贝钩子处理程序,方法是在注册表HKEY_CLASSES_ROOT\Directory\Shellex\CopyHookHandlers下创建一个名称任意的sub key,在此sub key中创建一个类型为REG_SZ的项并将你的COM对象的CLSID作为它的默认值就可以了。

下面就是一个拷贝钩子的实现程序

// CCopyHook.h

//CCopyHook类实现了ICopyHook接口,CClassFactory实现了IClassFactory接口

#include <shlobj.h>

class CCopyHook: public ICopyHook

{

public:

CCopyHook():m_refcnt(0)

STDMETHODIMP QueryInterface(REFIID iid,void** ppvObject)

STDMETHODIMP_(ULONG) AddRef()

STDMETHODIMP_(ULONG) Release()

STDMETHODIMP_(UINT) CopyCallback(HWND hwnd,UINT wFunc,UINT wFlags,

LPCTSTR pszSrcFile,DWORD dwSrcAttribs,

LPCTSTR pszDestFile,DWORD dwDestAttribs)

private:

int m_refcnt

}

class CClassFactory:public IClassFactory

{

public:

CClassFactory():m_refcnt(0)

STDMETHODIMP QueryInterface(REFIID iid,void** ppvObject)

STDMETHODIMP_(ULONG) AddRef()

STDMETHODIMP_(ULONG) Release()

STDMETHODIMP CreateInstance(IUnknown * pUnkOuter,REFIID riid,void ** ppvObject)

STDMETHODIMP LockServer(BOOL fLock)

private:

int m_refcnt

}

// CCopyHook.cpp

//CCopyHook对象和CClassFactory对象的实现文件

#include <stdio.h>

#include "CCopyHook.h"

extern LONG nLocks //对象计数,用于DllCanUnloadNow

ULONG __stdcall CCopyHook::AddRef(){

if(m_refcnt==0)

nLocks++

m_refcnt++

return m_refcnt

}

ULONG __stdcall CCopyHook::Release(){

int nNewCnt=--m_refcnt

if(nNewCnt<=0){

nLocks--

delete this

}

return nNewCnt

}

HRESULT __stdcall CCopyHook::QueryInterface(REFIID iid,void** ppvObject){

if(iid==IID_IUnknown)

*ppvObject=static_cast<IUnknown*>(this)

else

if(iid==IID_IShellCopyHook)

*ppvObject=static_cast<ICopyHook*>(this)

else

return E_NOINTERFACE

reinterpret_cast<IUnknown*>(*ppvObject)->AddRef()

return S_OK

}

//这就是CopyCallback方法,拷贝钩子的所有功能由它实现。参数的具体值参看MSDN

UINT __stdcall CCopyHook::CopyCallback(HWND hwnd,UINT wFunc,UINT wFlags,

LPCTSTR pszSrcFile,DWORD dwSrcAttribs,

LPCTSTR pszDestFile,DWORD dwDestAttribs){

char szMessage[MAX_PATH+14]

sprintf(szMessage,"对%s进行的 *** 作,是否继续?",pszSrcFile)

return MessageBox(NULL,szMessage,"确认",MB_YESNO|MB_ICONEXCLAMATION)

}

ULONG __stdcall CClassFactory::AddRef(){

if(m_refcnt==0)

nLocks++

m_refcnt++

return m_refcnt

}

ULONG __stdcall CClassFactory::Release(){

int nNewCnt=--m_refcnt

if(nNewCnt<=0){

nLocks--

delete this

}

return nNewCnt

}

HRESULT __stdcall CClassFactory::QueryInterface(REFIID iid,void** ppvObject){

if(iid==IID_IUnknown)

*ppvObject=static_cast<IUnknown*>(this)

else

if(iid==IID_IClassFactory)

*ppvObject=static_cast<IClassFactory*>(this)

else

return E_NOINTERFACE

reinterpret_cast<IUnknown*>(*ppvObject)->AddRef()

return S_OK

}

HRESULT __stdcall CClassFactory::CreateInstance(IUnknown* pUnkownOuter,REFIID riid,void** ppvObj){

if(pUnkownOuter!=NULL)

return CLASS_E_NOAGGREGATION

CCopyHook* pObj=new CCopyHook

pObj->AddRef()

HRESULT hr=pObj->QueryInterface(riid,ppvObj)

pObj->Release()

return hr

}

HRESULT __stdcall CClassFactory::LockServer(BOOL fLock){

if(fLock)

nLocks++

else

nLocks--

return S_OK

}

// main.cpp

//主要实现了几个COM对象标准的导出函数。

#include <objbase.h>

#include <olectl.h>

#include "CCopyHook.h"

//这是要添加到注册表中的项,注意如果你要使用这段代码,应该用UUIDGEN.exe生成一

//个新的CLSID。

const char* szRegTable[][3]={

",0,"CopyHook"},

\\InProcServer32",0,(const char*)-1},

\\InProcServer32","ThreadingModel","Apartment"},

\\ProgID",0,"webber84.CopyHook.1"},

,

"}}

HMODULE hInstance=NULL

LONG nLocks=0

BOOL APIENTRY DllMain( HANDLE hModule,

DWORD ul_reason_for_call,

LPVOID lpReserved

){

if(ul_reason_for_call==DLL_PROCESS_ATTACH)

hInstance=(HMODULE)hModule

return TRUE

}

STDAPI DllUnregisterServer(){

HRESULT hr=S_OKLONG ret=0

int items=sizeof(szRegTable)/sizeof(szRegTable[0])

for(int i=items-1i>=0i--){

const char* szKeyName=szRegTable[i][0]

if( (i==items-1) || stricmp(szRegTable[i+1][0],szKeyName)!=0)

ret=RegDeleteKey(HKEY_CLASSES_ROOT,szKeyName)

if(ret!=ERROR_SUCCESS)

hr=SELFREG_E_CLASS

}

return hr

}

//可重用的DllRegisterServer函数,只要照上面的格式把注册表项放到一个数组中,就可以//用这段代码完成对任意组件的注册。

STDAPI DllRegisterServer(void){

HRESULT hr=S_OK

int items=sizeof(szRegTable)/sizeof(szRegTable[0])

char szDllPath[MAX_PATH]

GetModuleFileName(hInstance,szDllPath,MAX_PATH)

for(int i=0i<items &&SUCCEEDED(hr)i++){

const char* szKeyName=szRegTable[i][0]

const char* szValueName=szRegTable[i][1]

const char* szValue=szRegTable[i][2]

if(szValue==(const char*)-1)

szValue=szDllPath

HKEY hKey

LONG ret=RegCreateKey(HKEY_CLASSES_ROOT,szKeyName,&hKey)

if(ret==ERROR_SUCCESS){

RegSetValueEx(hKey,szValueName,0,REG_SZ,(const BYTE*)szValue,

strlen(szValue)+1)

RegCloseKey(hKey)

}

if(ret!=ERROR_SUCCESS){

hr=SELFREG_E_CLASS

DllUnregisterServer()

}

}

return hr

}

STDAPI DllGetClassObject (REFCLSID rclsid, REFIID riid, void** ppvObj) {

HRESULT hr = E_OUTOFMEMORY

*ppvObj = NULL

CClassFactory *pClassFactory = new CClassFactory

if (pClassFactory != NULL)

hr = pClassFactory->QueryInterface(riid, ppvObj)

return hr

}

STDAPI DllCanUnloadNow(){

return nLocks==0 ? S_OK : S_FALSE

}


欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/tougao/12104355.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2023-05-21
下一篇 2023-05-21

发表评论

登录后才能评论

评论列表(0条)

保存