SHChangeNotifyRegisterを使うとWindows上でファイルやフォルダが作成されたことなどを瞬時に知ることができる。
以下のフラグなどを組み合わせることでフォルダの作成だけを知るなどもできる#define SHCNE_RENAMEITEM 0x00000001L #define SHCNE_CREATE 0x00000002L #define SHCNE_DELETE 0x00000004L #define SHCNE_MKDIR 0x00000008L #define SHCNE_RMDIR 0x00000010L #define SHCNE_MEDIAINSERTED 0x00000020L #define SHCNE_MEDIAREMOVED 0x00000040L #define SHCNE_DRIVEREMOVED 0x00000080L #define SHCNE_DRIVEADD 0x00000100L #define SHCNE_NETSHARE 0x00000200L #define SHCNE_NETUNSHARE 0x00000400L #define SHCNE_ATTRIBUTES 0x00000800L #define SHCNE_UPDATEDIR 0x00001000L #define SHCNE_UPDATEITEM 0x00002000L #define SHCNE_SERVERDISCONNECT 0x00004000L #define SHCNE_UPDATEIMAGE 0x00008000L #define SHCNE_DRIVEADDGUI 0x00010000L #define SHCNE_RENAMEFOLDER 0x00020000L #define SHCNE_FREESPACE 0x00040000L
ここではWTLアプリケーションウイザードでダイアログベースのプロジェクトを作成し、生成されたMainDlg.hを以下のように変更した。
// MainDlg.h : CMainDlg クラスのインターフェイス
//
/////////////////////////////////////////////////////////////////////////////
#pragma once
#include "atlstr.h"
#define WM_CHANGENOTIFY WM_APP + 1
class CMainDlg : public CDialogImpl<CMainDlg>, public CUpdateUI<CMainDlg>,
public CMessageFilter, public CIdleHandler
{
public:
enum { IDD = IDD_MAINDLG };
virtual BOOL PreTranslateMessage(MSG* pMsg)
{
return CWindow::IsDialogMessage(pMsg);
}
virtual BOOL OnIdle()
{
return FALSE;
}
BEGIN_UPDATE_UI_MAP(CMainDlg)
END_UPDATE_UI_MAP()
BEGIN_MSG_MAP(CMainDlg)
//シェル通知用メッセージハンドラの追加
MESSAGE_HANDLER(WM_CHANGENOTIFY, OnChangeNotify)
MESSAGE_HANDLER(WM_INITDIALOG, OnInitDialog)
COMMAND_ID_HANDLER(ID_APP_ABOUT, OnAppAbout)
COMMAND_ID_HANDLER(IDOK, OnOK)
COMMAND_ID_HANDLER(IDCANCEL, OnCancel)
END_MSG_MAP()
// ハンドラーのプロトタイプ (引数が必要な場合はコメントを外してください):
// LRESULT MessageHandler(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/)
// LRESULT CommandHandler(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/)
// LRESULT NotifyHandler(int /*idCtrl*/, LPNMHDR /*pnmh*/, BOOL& /*bHandled*/)
//
// パスからPIDLを取得する
//
//取得したPIDLは必ずILFreeで解放すること!
//
bool GetItemIdListFromPath(LPCTSTR pszPath,LPITEMIDLIST* ppItemIdList)
{
if(ppItemIdList == NULL)
return false;
//ILCreateFromPathで取得
*ppItemIdList = ::ILCreateFromPath(pszPath);
if(*ppItemIdList)
return true;
//SHSimpleIDListFromPathで取得
*ppItemIdList = ::SHSimpleIDListFromPath((CAtlStringW)pszPath);
if(*ppItemIdList)
return true;
//IShellFolderで取得
{
IShellFolder* pIShellFolder;
HRESULT hr;
ULONG nAttribute;
hr = ::SHGetDesktopFolder(&pIShellFolder);
if(pIShellFolder)
{
nAttribute = ::PathIsDirectory(pszPath) ? SFGAO_FOLDER : 0;
#ifdef UNICODE
hr = pIShellFolder->ParseDisplayName(NULL,NULL,pszPath,NULL,&pItemIdList,NULL);
#else
{
CAtlStringW ustrPath;
//簡単にUnicode変換
ustrPath = pszPath;
hr = pIShellFolder->ParseDisplayName(NULL,NULL,ustrPath.GetBuffer(0),NULL,ppItemIdList,&nAttribute);
}
#endif
pIShellFolder->Release();
if(SUCCEEDED(hr))
return true;
}
}
return false;
}
//
// シェル通知の登録/登録解除関数
//
//pszPathは登録時のみ必須
//
bool RegisterNotify(bool bRegister,ULONG* pnID,LPCTSTR pszPath=NULL)
{
if(pnID == NULL)
return false;
//登録
if(bRegister)
{
bool ret;
LPITEMIDLIST pidl;
SHChangeNotifyEntry sEntry;
if(pszPath == NULL)
return false;
ret = GetItemIdListFromPath(pszPath,&pidl);
if(ret == false)
return false;
sEntry.fRecursive = TRUE;
sEntry.pidl = pidl;
//ファイルやフォルダの作成と名前変更のみを処理
*pnID = ::SHChangeNotifyRegister(m_hWnd,SHCNRF_ShellLevel | SHCNRF_InterruptLevel,SHCNE_RENAMEITEM | SHCNE_CREATE | SHCNE_DELETE | SHCNE_MKDIR | SHCNE_RMDIR | SHCNE_RENAMEFOLDER,WM_CHANGENOTIFY,1,&sEntry);
::ILFree(pidl);
return *pnID ? true : false;
}
if(*pnID == 0)
return false;
//登録解除
BOOL ret;
ret = ::SHChangeNotifyDeregister(*pnID);
return ret ? true : false;
}
//
// シェル通知ハンドラー
//
//イベントIDはlParamに入る
//関連するフォルダやパスを示すPIDLはwParamに入る
//
LRESULT OnChangeNotify(UINT /*uMsg*/, WPARAM wParam, LPARAM lParam, BOOL& /*bHandled*/)
{
LONG nEvent;
LPITEMIDLIST pidl;
LPITEMIDLIST pidlExtra;
nEvent = lParam;
pidl = ((LPITEMIDLIST*)wParam)[0];
pidlExtra = ((LPITEMIDLIST*)wParam)[1];
BOOL ret;
TCHAR pszPath[MAX_PATH*2];
CAtlString strMessage;
ret = ::SHGetPathFromIDList(pidl,pszPath);
if(ret)
{
strMessage += pszPath;
strMessage += _T("\n");
}
switch(nEvent)
{
case SHCNE_CREATE:
strMessage += _T("ファイルを作成しました");
break;
case SHCNE_DELETE:
strMessage += _T("ファイルを削除しました");
break;
case SHCNE_RENAMEITEM:
ret = ::SHGetPathFromIDList(pidlExtra,pszPath);
if(ret)
{
strMessage += pszPath;
strMessage += _T("\n");
}
strMessage += _T("ファイル名を変更しました");
break;
case SHCNE_MKDIR:
strMessage += _T("フォルダを作成しました");
break;
case SHCNE_RMDIR:
strMessage += _T("フォルダを削除しました");
break;
case SHCNE_RENAMEFOLDER:
ret = ::SHGetPathFromIDList(pidlExtra,pszPath);
if(ret)
{
strMessage += pszPath;
strMessage += _T("\n");
}
strMessage += _T("フォルダ名を変更しました");
break;
default:
strMessage += _T("その他の操作");
break;
}
MessageBox(strMessage);
return 0;
}
LRESULT OnInitDialog(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/)
{
// 画面の中心へダイアログを移動
CenterWindow();
// アイコンの設定
HICON hIcon = (HICON)::LoadImage(_Module.GetResourceInstance(), MAKEINTRESOURCE(IDR_MAINFRAME),
IMAGE_ICON, ::GetSystemMetrics(SM_CXICON), ::GetSystemMetrics(SM_CYICON), LR_DEFAULTCOLOR);
SetIcon(hIcon, TRUE);
HICON hIconSmall = (HICON)::LoadImage(_Module.GetResourceInstance(), MAKEINTRESOURCE(IDR_MAINFRAME),
IMAGE_ICON, ::GetSystemMetrics(SM_CXSMICON), ::GetSystemMetrics(SM_CYSMICON), LR_DEFAULTCOLOR);
SetIcon(hIconSmall, FALSE);
// メッセージ フィルターおよび画面更新用のオブジェクト登録
CMessageLoop* pLoop = _Module.GetMessageLoop();
ATLASSERT(pLoop != NULL);
pLoop->AddMessageFilter(this);
pLoop->AddIdleHandler(this);
UIAddChildWindowContainer(m_hWnd);
//シェル通知の登録
RegisterNotify(true,&_nID,_T("c:\\"));
return TRUE;
}
ULONG _nID;
LRESULT OnAppAbout(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/)
{
CAboutDlg dlg;
dlg.DoModal();
return 0;
}
LRESULT OnOK(WORD /*wNotifyCode*/, WORD wID, HWND /*hWndCtl*/, BOOL& /*bHandled*/)
{
// TODO: チェックコードの追加
CloseDialog(wID);
return 0;
}
LRESULT OnCancel(WORD /*wNotifyCode*/, WORD wID, HWND /*hWndCtl*/, BOOL& /*bHandled*/)
{
CloseDialog(wID);
return 0;
}
void CloseDialog(int nVal)
{
//シェル通知の登録解除
RegisterNotify(false,&_nID);
DestroyWindow();
::PostQuitMessage(nVal);
}
};
