Changeset 692
- Timestamp:
- 12/2/2008 10:05:33 AM (5 years ago)
- Location:
- branches/erasershellext/cpp
- Files:
-
- 1 added
- 2 edited
-
CtxMenu.cpp (modified) (1 diff)
-
EShll.txt (added)
-
EraserCtxMenu.vcproj (modified) (2 diffs)
Legend:
- Unmodified
- Added
- Removed
-
branches/erasershellext/cpp/CtxMenu.cpp
r691 r692 33 33 const wchar_t* CCtxMenu::m_szMenuTitle = L"Eraser v6"; 34 34 35 HRESULT CCtxMenu::Initialize(LPCITEMIDLIST /*pidlFolder*/, LPDATAOBJECT pDataObj, 36 HKEY /*hProgID*/) 37 { 38 m_itemID = 0; 39 FORMATETC fmt = { CF_HDROP, NULL, DVASPECT_CONTENT, -1, TYMED_HGLOBAL }; 40 STGMEDIUM stg = { TYMED_HGLOBAL }; 41 HDROP hDrop; 42 43 //Look for CF_HDROP data in the data object. 44 if (FAILED(pDataObj->GetData (&fmt, &stg))) 45 //Nope! Return an "invalid argument" error back to Explorer. 46 return E_INVALIDARG; 47 48 //Get a pointer to the actual data. 49 hDrop = static_cast<HDROP>(GlobalLock(stg.hGlobal)); 50 51 //Make sure it worked. 52 if (hDrop == NULL) 53 return E_INVALIDARG; 54 55 //Sanity check - make sure there is at least one filename. 56 UINT uNumFiles = DragQueryFile(hDrop, 0xFFFFFFFF, NULL, 0); 57 if (!uNumFiles) 58 { 35 HRESULT CCtxMenu::Initialize(LPCITEMIDLIST /*pidlFolder*/, LPDATAOBJECT pDataObj, 36 HKEY /*hProgID*/) 37 { 38 m_itemID = 0; 39 FORMATETC fmt = { CF_HDROP, NULL, DVASPECT_CONTENT, -1, TYMED_HGLOBAL }; 40 STGMEDIUM stg = { TYMED_HGLOBAL }; 41 HDROP hDrop; 42 43 //Look for CF_HDROP data in the data object. 44 if (FAILED(pDataObj->GetData (&fmt, &stg))) 45 //Nope! Return an "invalid argument" error back to Explorer. 46 return E_INVALIDARG; 47 48 //Get a pointer to the actual data. 49 hDrop = static_cast<HDROP>(GlobalLock(stg.hGlobal)); 50 51 //Make sure it worked. 52 if (hDrop == NULL) 53 return E_INVALIDARG; 54 55 //Sanity check - make sure there is at least one filename. 56 UINT uNumFiles = DragQueryFile(hDrop, 0xFFFFFFFF, NULL, 0); 57 if (!uNumFiles) 58 { 59 GlobalUnlock(stg.hGlobal); 60 ReleaseStgMedium(&stg); 61 return E_INVALIDARG; 62 } 63 64 HRESULT hr = S_OK; 65 WCHAR Buffer[MAX_PATH] = {0}; 66 for (UINT i = uNumFiles; i < uNumFiles; i++) 67 { 68 //TODO: Collect the list of files queried. 69 UINT charsWritten = DragQueryFile(hDrop, i, Buffer, sizeof(Buffer) / sizeof(Buffer[0])); 70 if (!charsWritten) 71 hr = E_INVALIDARG; 72 else 73 PathQuoteSpaces(Buffer); 74 } 75 59 76 GlobalUnlock(stg.hGlobal); 60 77 ReleaseStgMedium(&stg); 61 return E_INVALIDARG; 62 } 63 64 HRESULT hr = S_OK; 65 WCHAR Buffer[MAX_PATH] = {0}; 66 for (UINT i = uNumFiles; i < uNumFiles; i++) 67 { 68 //TODO: Collect the list of files queried. 69 UINT charsWritten = DragQueryFile(hDrop, i, Buffer, sizeof(Buffer) / sizeof(Buffer[0])); 70 if (!charsWritten) 71 hr = E_INVALIDARG; 78 return hr; 79 } 80 /* 81 +-------------------+ 82 | | 83 | | 84 | | 85 | | 86 +-------------------+ +-------------------+ 87 |(ICON) Eraser v6 > | | Erase selected | //--> erase the files immediately using defaults 88 +-------------------+ | Schedule Selected | //--> open the scheduler menu, with files/folders filled in 89 | | +-------------------+ 90 | | | Secure move | //--> secure move the files 91 | | +-------------------+ // Eraser.Manager Algorithms popup 92 | | |(*) Customise | // set algorithm for this query only 93 +-------------------+ +-------------------+ 94 */ 95 96 HRESULT CCtxMenu::QueryContextMenu(HMENU hmenu, UINT uMenuIndex, UINT uidFirstCmd, 97 UINT /*uidLastCmd*/, UINT uFlags) 98 { 99 //If the flags include CMF_DEFAULTONLY then we shouldn't do anything. 100 if (uFlags & CMF_DEFAULTONLY) 101 return MAKE_HRESULT(SEVERITY_SUCCESS, FACILITY_NULL, 0); 102 103 //First, create and populate a submenu. 104 UINT uID = uidFirstCmd; 105 HMENU hSubmenu = CreatePopupMenu(); 106 107 //Create the submenu, following the order defined in the CEraserLPVERB enum 108 InsertMenu (hSubmenu, CERASER_ERASE, MF_BYPOSITION, uID++, _T("&Erase")); 109 InsertMenu (hSubmenu, CERASER_SCHEDULE, MF_BYPOSITION, uID++, _T("&Schedule")); 110 InsertMenu (hSubmenu, CERASER_ERASE_ON_RESTART, MF_BYPOSITION, uID++, _T("Erase on &Restart")); 111 //------------------------------------------------------------------------- 112 InsertMenuItem(hSubmenu, CERASER_SEPERATOR_1, TRUE, GetSeparator()); 113 InsertMenu (hSubmenu, CERASER_SECURE_MOVE, MF_BYPOSITION, uID++, _T("Secure &Move")); 114 //------------------------------------------------------------------------- 115 InsertMenuItem(hSubmenu, CERASER_SEPERATOR_2, TRUE, GetSeparator()); 116 InsertMenu (hSubmenu, CERASER_CUSTOMISE, MF_BYPOSITION, uID++, _T("&Console")); 117 118 //Insert the submenu into the Context menu provided by Explorer. 119 { 120 MENUITEMINFO mii = { sizeof(MENUITEMINFO) }; 121 mii.wID = uID++; 122 mii.fMask = MIIM_SUBMENU | MIIM_STRING | MIIM_ID; 123 mii.hSubMenu = hSubmenu; 124 mii.dwTypeData = const_cast<wchar_t*>(m_szMenuTitle); 125 126 //Set the bitmap for the registered item. Vista machines will be set using a DIB, 127 //older machines will be ownerdrawn. 128 OSVERSIONINFO osvi; 129 ZeroMemory(&osvi, sizeof(osvi)); 130 osvi.dwOSVersionInfoSize = sizeof(osvi); 131 132 if (GetVersionEx(&osvi) && osvi.dwPlatformId == VER_PLATFORM_WIN32_NT && 133 osvi.dwMajorVersion >= 6) 134 { 135 mii.fMask |= MIIM_CHECKMARKS; 136 mii.hbmpUnchecked = GetMenuBitmap(); 137 } 138 else 139 { 140 mii.fMask |= MIIM_FTYPE; 141 mii.fType = MFT_OWNERDRAW; 142 } 143 144 m_itemID = uMenuIndex++; 145 InsertMenuItem(hmenu, m_itemID, TRUE, &mii); 146 } 147 148 return MAKE_HRESULT(SEVERITY_SUCCESS, FACILITY_NULL, uID - uidFirstCmd); 149 } 150 151 HRESULT CCtxMenu::HandleMenuMsg(UINT uMsg, WPARAM wParam, LPARAM lParam) 152 { 153 return HandleMenuMsg2(uMsg, wParam, lParam, NULL); 154 } 155 156 HRESULT CCtxMenu::HandleMenuMsg2(UINT uMsg, WPARAM /*wParam*/, LPARAM lParam, 157 LRESULT* result) 158 { 159 //Skip if we aren't handling our own. 160 bool handleResult = false; 161 switch (uMsg) 162 { 163 case WM_MEASUREITEM: 164 { 165 MEASUREITEMSTRUCT* mis = reinterpret_cast<MEASUREITEMSTRUCT*>(lParam); 166 if (mis->CtlID == m_itemID) 167 handleResult = OnMeasureItem(mis->itemWidth, mis->itemHeight); 168 else 169 handleResult = false; 170 break; 171 } 172 173 case WM_DRAWITEM: 174 { 175 DRAWITEMSTRUCT* dis = reinterpret_cast<DRAWITEMSTRUCT*>(lParam); 176 if (dis->CtlID == m_itemID) 177 handleResult = OnDrawItem(dis->hDC, dis->rcItem, dis->itemAction, dis->itemState); 178 else 179 handleResult = false; 180 } 181 } 182 183 if (result) 184 *result = handleResult; 185 return S_OK; 186 } 187 188 bool CCtxMenu::OnMeasureItem(UINT& itemWidth, UINT& itemHeight) 189 { 190 LOGFONT logFont; 191 if (!SystemParametersInfo(SPI_GETICONTITLELOGFONT, sizeof(logFont), &logFont, 0)) 192 return false; 193 194 //Measure the size of the text. 195 Handle<HDC> screenDC = GetDC(NULL); 196 Handle<HFONT> font = CreateFontIndirect(&logFont); 197 SelectObject(screenDC, font); 198 SIZE textSize; 199 if (!GetTextExtentPoint32(screenDC, m_szMenuTitle, wcslen(m_szMenuTitle), &textSize)) 200 return false; 201 202 itemWidth = textSize.cx; 203 itemHeight = textSize.cy; 204 205 //Account for the size of the bitmap. 206 UINT iconWidth = GetSystemMetrics(SM_CXMENUCHECK); 207 itemWidth += iconWidth; 208 itemHeight = std::max(iconWidth, itemHeight); 209 210 //And remember the minimum size for menu items. 211 itemHeight = std::max((int)itemHeight, GetSystemMetrics(SM_CXMENUSIZE)); 212 return true; 213 } 214 215 bool CCtxMenu::OnDrawItem(HDC hdc, RECT rect, UINT /*action*/, UINT state) 216 { 217 //Draw the background. 218 LOGBRUSH logBrush = { BS_SOLID, 219 (state & ODS_SELECTED) ? 220 GetSysColor(COLOR_HIGHLIGHT) : GetSysColor(COLOR_MENU), 221 0 222 }; 223 Handle<HBRUSH> bgBrush = CreateBrushIndirect(&logBrush); 224 FillRect(hdc, &rect, bgBrush); 225 226 //Then the bitmap. 227 { 228 //Draw the icon with alpha and all first. 229 Handle<HICON> icon(GetMenuIcon()); 230 int iconSize = GetSystemMetrics(SM_CXMENUCHECK); 231 int iconMargin = GetSystemMetrics(SM_CXEDGE); 232 DrawIconEx(hdc, rect.left + iconMargin, rect.top + (rect.bottom - rect.top - iconSize) / 2, 233 icon, 0, 0, 0, bgBrush, DI_NORMAL); 234 235 //Move the rectangle's left bound to the text starting position 236 rect.left += iconMargin * 2 + iconSize; 237 } 238 239 //Draw the text. 240 SetBkMode(hdc, TRANSPARENT); 241 LOGFONT logFont; 242 if (!SystemParametersInfo(SPI_GETICONTITLELOGFONT, sizeof(logFont), &logFont, 0)) 243 return false; 244 245 /*Handle<HFONT> font = CreateFontIndirect(&logFont); 246 SelectObject(hdc, font);*/ 247 SIZE textSize; 248 if (!GetTextExtentPoint32(hdc, m_szMenuTitle, wcslen(m_szMenuTitle), &textSize)) 249 return false; 250 251 COLORREF oldColour = SetTextColor(hdc, (state & ODS_SELECTED) ? 252 GetSysColor(COLOR_HIGHLIGHTTEXT) : GetSysColor(COLOR_MENUTEXT)); 253 UINT flags = DST_PREFIXTEXT; 254 if (state & ODS_NOACCEL) 255 flags |= DSS_HIDEPREFIX; 256 ::DrawState(hdc, NULL, NULL, reinterpret_cast<LPARAM>(m_szMenuTitle), wcslen(m_szMenuTitle), 257 rect.left, rect.top + (rect.bottom - rect.top - textSize.cy) / 2, textSize.cx, textSize.cy, flags); 258 SetTextColor(hdc, oldColour); 259 return true; 260 } 261 262 HRESULT CCtxMenu::GetCommandString(UINT idCmd, UINT uFlags, UINT* /*pwReserved*/, 263 LPSTR pszName, UINT cchMax) 264 { 265 USES_CONVERSION; 266 267 //Check idCmd, it must be 0 or 1 since we have two menu items. 268 if ( idCmd > 2 ) 269 return E_INVALIDARG; 270 271 //If Explorer is asking for a help string, copy our string into the supplied buffer. 272 if (!(uFlags & GCS_HELPTEXT)) 273 return E_INVALIDARG; 274 275 static LPCTSTR szErase = _T("Erases the currently selected file\r\n"); 276 static LPCTSTR szEraseUnunsed = _T("Erases the currently selected drive's unused disk space\r\n"); 277 LPCTSTR pszText = (0 == idCmd) ? szErase : szEraseUnunsed; 278 279 if (uFlags & GCS_UNICODE) 280 //We need to cast pszName to a Unicode string, and then use the Unicode string copy API. 281 lstrcpynW((LPWSTR)pszName, T2CW(pszText), cchMax); 72 282 else 73 PathQuoteSpaces(Buffer); 74 } 75 76 GlobalUnlock(stg.hGlobal); 77 ReleaseStgMedium(&stg); 78 return hr; 283 //Use the ANSI string copy API to return the help string. 284 lstrcpynA(pszName, T2CA(pszText), cchMax); 285 286 return S_OK; 287 } 288 289 /* 290 usage: Eraser <action> <arguments> 291 where action is 292 addtask Adds tasks to the current task list. 293 querymethods Lists all registered Erasure methods. 294 295 global parameters: 296 --quiet, -q Do not create a Console window to display progress. 297 298 parameters for addtask: 299 eraser addtask --method=<methodGUID> (--recycled | --unused=<volume> | --dir=<directory> | [file1 [file2 [...]]]) 300 --method, -m The Erasure method to use. 301 --recycled, -r Erases files and folders in the recycle bin 302 --unused, -u Erases unused space in the volume. 303 optional arguments: --unused=<drive>[,clusterTips] 304 clusterTips If specified, the drive's files will have their cluster tips 305 erased. 306 --dir, --directory, -d Erases files and folders in the directory 307 optional arguments: --dir=<directory>[,e=excludeMask][,i=includeMask][,delete] 308 excludeMask A wildcard expression for files and folders to exclude. 309 includeMask A wildcard expression for files and folders to include. 310 The include mask is applied before the exclude mask. 311 delete Deletes the folder at the end of the erasure if specified. 312 file1 ... fileN The list of files to erase. 313 314 parameters for querymethods: 315 eraser querymethods 316 317 no parameters to set. 318 319 All arguments are case sensitive. 320 321 */ 322 323 HRESULT CCtxMenu::InvokeCommand ( LPCMINVOKECOMMANDINFO pCmdInfo ) 324 { 325 // If lpVerb really points to a string, ignore this function call and bail out. 326 if ( HIWORD( pCmdInfo->lpVerb ) != 0) 327 return E_INVALIDARG; 328 329 HRESULT result = E_INVALIDARG; 330 // final eraser command to call 331 string_type command(L"eraser "); 332 string_type files, directories, unuseds; 333 334 // compile the eraser command syntax 335 for (string_list::const_iterator i = m_szSelectedFiles.begin(); 336 i != m_szSelectedFiles.end(); ++i) 337 { 338 files += L"\"" + *i + L"\" "; 339 } 340 for (string_list::const_iterator i = m_szSelectedUnused.begin(); 341 i != m_szSelectedUnused.end(); ++i) 342 { 343 unuseds += L"--unused=\"" + *i + L"\" "; 344 } 345 for (string_list::const_iterator i = m_szSelectedDirectories.begin(); 346 i != m_szSelectedDirectories.end(); ++i) 347 { 348 directories += L"--dir=\"" + *i + L"\" "; 349 } 350 351 // Get the command index. 352 switch(LOWORD(pCmdInfo->lpVerb + 1)) 353 { 354 #if 0 355 case CERASER_ERASE: 356 { 357 command += L"addtask " + files + unuseds + directories; 358 //result = system(command.c_str()); 359 break; 360 } 361 case CERASER_SECURE_MOVE: 362 { 363 result = S_OK; 364 // we need some user interaction, thus we will have a windows form 365 // has to be native, so i guess a bit of work 366 break; 367 } 368 // NOT IMPLEMENTED METHODS 369 case CERASER_ERASE_ON_RESTART: 370 { 371 MessageBox (pCmdInfo->hwnd, szMsg, _T("Eraser v6 - Shell Extention Query"), MB_ICONINFORMATION ); 372 command += S("--restart ") + objects; 373 result = system(command.c_str()); 374 break; 375 } 376 case CERASER_SCHEDULE: 377 { 378 command += S("--schedule ") + objects; 379 result = system(command.c_str()); 380 break; 381 } 382 case CERASER_CONSOLE: 383 { 384 // interactive eraser console 385 break; 386 } 387 #endif 388 default: 389 { 390 TCHAR szMsg [MAX_PATH + 32]; 391 wsprintf ( szMsg, _T("Invalid Query was submitted, unable to process!\n\nCommand ID = %d\n\n"), LOWORD(pCmdInfo->lpVerb) ); 392 MessageBox ( pCmdInfo->hwnd, szMsg, _T("Eraser v6 - Shell Extention Query"), MB_ICONINFORMATION ); 393 } 394 return result; 395 } 396 } 397 398 MENUITEMINFO* CCtxMenu::GetSeparator() 399 { 400 MENUITEMINFO *mii = new MENUITEMINFO(); 401 mii->cbSize = sizeof(MENUITEMINFO); 402 mii->fMask = MIIM_TYPE; 403 mii->fType = MF_SEPARATOR; 404 return mii; 405 } 406 407 HICON CCtxMenu::GetMenuIcon() 408 { 409 int smIconSize = GetSystemMetrics(SM_CXMENUCHECK); 410 return static_cast<HICON>(LoadImage(theApp.m_hInstance, L"Eraser", 411 IMAGE_ICON, smIconSize, smIconSize, LR_LOADTRANSPARENT)); 412 } 413 414 HBITMAP CCtxMenu::GetMenuBitmap() 415 { 416 BITMAP bitmap; 417 ICONINFO iconInfo; 418 ZeroMemory(&bitmap, sizeof(bitmap)); 419 ZeroMemory(&iconInfo, sizeof(iconInfo)); 420 Handle<HICON> icon(GetMenuIcon()); 421 422 //Try to get the icon's size, bitmap and bit depth. We will try to convert 423 //the bitmap into a DIB for display on Vista if it contains an alpha channel. 424 if (!GetIconInfo(icon, &iconInfo)) 425 return NULL; 426 427 Handle<HBITMAP> iconMask(iconInfo.hbmMask); 428 if (!GetObject(iconInfo.hbmColor, sizeof(BITMAP), &bitmap) || 429 bitmap.bmBitsPixel < 32) 430 return iconInfo.hbmColor; 431 432 //Try converting the DDB into a DIB. 433 DIBSECTION dibSection; 434 HBITMAP dib = CreateDIB(bitmap.bmWidth, bitmap.bmHeight, NULL); 435 if (!GetObject(dib, sizeof(dibSection), &dibSection) || 436 !GetDIBits(CreateCompatibleDC(NULL), iconInfo.hbmColor, 0, bitmap.bmHeight, 437 dibSection.dsBm.bmBits, reinterpret_cast<BITMAPINFO*>(&dibSection.dsBmih), 438 DIB_RGB_COLORS)) 439 { 440 return iconInfo.hbmColor; 441 } 442 443 return dib; 444 } 445 446 HBITMAP CCtxMenu::CreateDIB(LONG width, LONG height, char** bitmapBits) 447 { 448 BITMAPINFO info; 449 ZeroMemory(&info, sizeof(info)); 450 info.bmiHeader.biSize = sizeof(BITMAPINFOHEADER); 451 info.bmiHeader.biWidth = width; 452 info.bmiHeader.biHeight = height; 453 info.bmiHeader.biPlanes = 1; 454 info.bmiHeader.biBitCount = 32; 455 info.bmiHeader.biCompression = BI_RGB; 456 char* dibBitmapBits = NULL; 457 return ::CreateDIBSection(0, &info, DIB_RGB_COLORS, 458 reinterpret_cast<void**>(bitmapBits ? bitmapBits : &dibBitmapBits), NULL, 0); 459 } 79 460 } 80 /*81 +-------------------+82 | |83 | |84 | |85 | |86 +-------------------+ +-------------------+87 |(ICON) Eraser v6 > | | Erase selected | //--> erase the files immediately using defaults88 +-------------------+ | Schedule Selected | //--> open the scheduler menu, with files/folders filled in89 | | +-------------------+90 | | | Secure move | //--> secure move the files91 | | +-------------------+ // Eraser.Manager Algorithms popup92 | | |(*) Customise | // set algorithm for this query only93 +-------------------+ +-------------------+94 */95 96 /*97 we have eraser shell scripts (.eshlls) where we use them98 to generate shell extention menus dynamically.99 the syntax is simple.100 This project should be aimed at the 6.1 release.101 102 BEGIN @MENU : POSITION($INDEX)103 [ICON="PATH"]104 [TEXT="DISPLAY_TEXT"]105 106 [FLAGS=MIIM_*]107 //MIIM_BITMAP108 //MIIM_CHECKMARKS109 //MIIM_DATA110 //MIIM_FTYPE111 //MIIM_ID112 //MIIM_STATE113 //MIIM_STRING114 //MIIM_SUBMENU115 //MIIM_TYPE116 117 [TYPE=MF_*]118 //MF_APPEND,119 //MF_BITMAP,120 //MF_BYCOMMAND,121 //MF_BYPOSITION122 //MF_CHECKED123 //MF_DEFAULT124 //MF_DELETE125 //MF_DISABLED126 //MF_ENABLED127 //MF_END128 //MF_GRAYED129 //MF_HELP130 //MF_HILITE131 //MF_INSERT132 //MF_MENUBARBREAK133 //MF_MENUBREAK134 //MF_MOUSESELECT135 //MF_OWNERDRAW136 //MF_POPUP137 //MF_POPUP138 //MF_REMOVE,139 //MF_RIGHTJUSTIFY,140 //MF_SEPARATOR,141 //MF_STRING,142 //MF_SYSMENU,143 //MF_UNCHECKED,144 //MF_UNHILITE145 //MF_USECHECKBITMAPS146 END147 148 // Desirable to have bitmaps cached149 @MENU150 {151 BITMAP = "FILE";152 TEXT="Eraser";153 BITMAP CHECKED="FILE";154 BITMAP UNCHECKED="FILE";155 156 // submenu creation157 @MENU158 {159 @CHECKBOX160 {161 }162 @SEPERATOR163 }164 }165 166 UINT cbSize;167 UINT fMask;168 UINT fType; // used if MIIM_TYPE (4.0) or MIIM_FTYPE (>4.0)169 UINT fState; // used if MIIM_STATE170 UINT wID; // used if MIIM_ID171 HMENU hSubMenu; // used if MIIM_SUBMENU172 HBITMAP hbmpChecked; // used if MIIM_CHECKMARKS173 HBITMAP hbmpUnchecked; // used if MIIM_CHECKMARKS174 ULONG_PTR dwItemData; // used if MIIM_DATA175 __field_ecount_opt(cch) LPSTR dwTypeData; // used if MIIM_TYPE (4.0) or MIIM_STRING (>4.0)176 UINT cch; // used if MIIM_TYPE (4.0) or MIIM_STRING (>4.0)177 HBITMAP hbmpItem; // used if MIIM_BITMAP178 179 */180 181 HRESULT CCtxMenu::QueryContextMenu(HMENU hmenu, UINT uMenuIndex, UINT uidFirstCmd,182 UINT /*uidLastCmd*/, UINT uFlags)183 {184 //If the flags include CMF_DEFAULTONLY then we shouldn't do anything.185 if (uFlags & CMF_DEFAULTONLY)186 return MAKE_HRESULT(SEVERITY_SUCCESS, FACILITY_NULL, 0);187 188 //First, create and populate a submenu.189 UINT uID = uidFirstCmd;190 HMENU hSubmenu = CreatePopupMenu();191 192 //Create the submenu, following the order defined in the CEraserLPVERB enum193 InsertMenu (hSubmenu, CERASER_ERASE, MF_BYPOSITION, uID++, _T("&Erase"));194 InsertMenu (hSubmenu, CERASER_SCHEDULE, MF_BYPOSITION, uID++, _T("&Schedule"));195 InsertMenu (hSubmenu, CERASER_ERASE_ON_RESTART, MF_BYPOSITION, uID++, _T("Erase on &Restart"));196 //-------------------------------------------------------------------------197 InsertMenuItem(hSubmenu, CERASER_SEPERATOR_1, TRUE, GetSeparator());198 InsertMenu (hSubmenu, CERASER_SECURE_MOVE, MF_BYPOSITION, uID++, _T("Secure &Move"));199 //-------------------------------------------------------------------------200 InsertMenuItem(hSubmenu, CERASER_SEPERATOR_2, TRUE, GetSeparator());201 InsertMenu (hSubmenu, CERASER_CUSTOMISE, MF_BYPOSITION, uID++, _T("&Console"));202 203 //Insert the submenu into the Context menu provided by Explorer.204 {205 MENUITEMINFO mii = { sizeof(MENUITEMINFO) };206 mii.wID = uID++;207 mii.fMask = MIIM_SUBMENU | MIIM_STRING | MIIM_ID;208 mii.hSubMenu = hSubmenu;209 mii.dwTypeData = const_cast<wchar_t*>(m_szMenuTitle);210 211 //Set the bitmap for the registered item. Vista machines will be set using a DIB,212 //older machines will be ownerdrawn.213 OSVERSIONINFO osvi;214 ZeroMemory(&osvi, sizeof(osvi));215 osvi.dwOSVersionInfoSize = sizeof(osvi);216 217 if (GetVersionEx(&osvi) && osvi.dwPlatformId == VER_PLATFORM_WIN32_NT &&218 osvi.dwMajorVersion >= 6)219 {220 mii.fMask |= MIIM_CHECKMARKS;221 mii.hbmpUnchecked = GetMenuBitmap();222 }223 else224 {225 mii.fMask |= MIIM_FTYPE;226 mii.fType = MFT_OWNERDRAW;227 }228 229 m_itemID = uMenuIndex++;230 InsertMenuItem(hmenu, m_itemID, TRUE, &mii);231 }232 233 return MAKE_HRESULT(SEVERITY_SUCCESS, FACILITY_NULL, uID - uidFirstCmd);234 }235 236 HRESULT CCtxMenu::HandleMenuMsg(UINT uMsg, WPARAM wParam, LPARAM lParam)237 {238 return HandleMenuMsg2(uMsg, wParam, lParam, NULL);239 }240 241 HRESULT CCtxMenu::HandleMenuMsg2(UINT uMsg, WPARAM /*wParam*/, LPARAM lParam, LRESULT* result)242 {243 //Skip if we aren't handling our own.244 bool handleResult = false;245 switch (uMsg)246 {247 case WM_MEASUREITEM:248 {249 MEASUREITEMSTRUCT* mis = reinterpret_cast<MEASUREITEMSTRUCT*>(lParam);250 if (mis->CtlID == m_itemID)251 handleResult = OnMeasureItem(mis->itemWidth, mis->itemHeight);252 else253 handleResult = false;254 break;255 }256 257 case WM_DRAWITEM:258 {259 DRAWITEMSTRUCT* dis = reinterpret_cast<DRAWITEMSTRUCT*>(lParam);260 if (dis->CtlID == m_itemID)261 handleResult = OnDrawItem(dis->hDC, dis->rcItem, dis->itemAction, dis->itemState);262 else263 handleResult = false;264 }265 }266 267 if (result)268 *result = handleResult;269 return S_OK;270 }271 272 bool CCtxMenu::OnMeasureItem(UINT& itemWidth, UINT& itemHeight)273 {274 LOGFONT logFont;275 if (!SystemParametersInfo(SPI_GETICONTITLELOGFONT, sizeof(logFont), &logFont, 0))276 return false;277 278 //Measure the size of the text.279 Handle<HDC> screenDC = GetDC(NULL);280 Handle<HFONT> font = CreateFontIndirect(&logFont);281 SelectObject(screenDC, font);282 SIZE textSize;283 if (!GetTextExtentPoint32(screenDC, m_szMenuTitle, wcslen(m_szMenuTitle), &textSize))284 return false;285 286 itemWidth = textSize.cx;287 itemHeight = textSize.cy;288 289 //Account for the size of the bitmap.290 UINT iconWidth = GetSystemMetrics(SM_CXMENUCHECK);291 itemWidth += iconWidth;292 itemHeight = std::max(iconWidth, itemHeight);293 294 //And remember the minimum size for menu items.295 itemHeight = std::max((int)itemHeight, GetSystemMetrics(SM_CXMENUSIZE));296 return true;297 }298 299 bool CCtxMenu::OnDrawItem(HDC hdc, RECT rect, UINT /*action*/, UINT state)300 {301 //Draw the background.302 LOGBRUSH logBrush = { BS_SOLID,303 (state & ODS_SELECTED) ?304 GetSysColor(COLOR_HIGHLIGHT) : GetSysColor(COLOR_MENU),305 0306 };307 Handle<HBRUSH> bgBrush = CreateBrushIndirect(&logBrush);308 FillRect(hdc, &rect, bgBrush);309 310 //Then the bitmap.311 {312 //Draw the icon with alpha and all first.313 Handle<HICON> icon(GetMenuIcon());314 int iconSize = GetSystemMetrics(SM_CXMENUCHECK);315 int iconMargin = GetSystemMetrics(SM_CXEDGE);316 DrawIconEx(hdc, rect.left + iconMargin, rect.top + (rect.bottom - rect.top - iconSize) / 2,317 icon, 0, 0, 0, bgBrush, DI_NORMAL);318 319 //Move the rectangle's left bound to the text starting position320 rect.left += iconMargin * 2 + iconSize;321 }322 323 //Draw the text.324 SetBkMode(hdc, TRANSPARENT);325 LOGFONT logFont;326 if (!SystemParametersInfo(SPI_GETICONTITLELOGFONT, sizeof(logFont), &logFont, 0))327 return false;328 329 /*Handle<HFONT> font = CreateFontIndirect(&logFont);330 SelectObject(hdc, font);*/331 SIZE textSize;332 if (!GetTextExtentPoint32(hdc, m_szMenuTitle, wcslen(m_szMenuTitle), &textSize))333 return false;334 335 COLORREF oldColour = SetTextColor(hdc, (state & ODS_SELECTED) ?336 GetSysColor(COLOR_HIGHLIGHTTEXT) : GetSysColor(COLOR_MENUTEXT));337 UINT flags = DST_PREFIXTEXT;338 if (state & ODS_NOACCEL)339 flags |= DSS_HIDEPREFIX;340 ::DrawState(hdc, NULL, NULL, reinterpret_cast<LPARAM>(m_szMenuTitle), wcslen(m_szMenuTitle),341 rect.left, rect.top + (rect.bottom - rect.top - textSize.cy) / 2, textSize.cx, textSize.cy, flags);342 SetTextColor(hdc, oldColour);343 return true;344 }345 346 HRESULT CCtxMenu::GetCommandString(UINT idCmd, UINT uFlags, UINT* /*pwReserved*/,347 LPSTR pszName, UINT cchMax)348 {349 USES_CONVERSION;350 351 //Check idCmd, it must be 0 or 1 since we have two menu items.352 if ( idCmd > 2 )353 return E_INVALIDARG;354 355 //If Explorer is asking for a help string, copy our string into the supplied buffer.356 if (!(uFlags & GCS_HELPTEXT))357 return E_INVALIDARG;358 359 static LPCTSTR szErase = _T("Erases the currently selected file\r\n");360 static LPCTSTR szEraseUnunsed = _T("Erases the currently selected drive's unused disk space\r\n");361 LPCTSTR pszText = (0 == idCmd) ? szErase : szEraseUnunsed;362 363 if (uFlags & GCS_UNICODE)364 //We need to cast pszName to a Unicode string, and then use the Unicode string copy API.365 lstrcpynW((LPWSTR)pszName, T2CW(pszText), cchMax);366 else367 //Use the ANSI string copy API to return the help string.368 lstrcpynA(pszName, T2CA(pszText), cchMax);369 370 return S_OK;371 }372 373 /*374 usage: Eraser <action> <arguments>375 where action is376 addtask Adds tasks to the current task list.377 querymethods Lists all registered Erasure methods.378 379 global parameters:380 --quiet, -q Do not create a Console window to display progress.381 382 parameters for addtask:383 eraser addtask --method=<methodGUID> (--recycled | --unused=<volume> | --dir=<directory> | [file1 [file2 [...]]])384 --method, -m The Erasure method to use.385 --recycled, -r Erases files and folders in the recycle bin386 --unused, -u Erases unused space in the volume.387 optional arguments: --unused=<drive>[,clusterTips]388 clusterTips If specified, the drive's files will have their cluster tips389 erased.390 --dir, --directory, -d Erases files and folders in the directory391 optional arguments: --dir=<directory>[,e=excludeMask][,i=includeMask][,delete]392 excludeMask A wildcard expression for files and folders to exclude.393 includeMask A wildcard expression for files and folders to include.394 The include mask is applied before the exclude mask.395 delete Deletes the folder at the end of the erasure if specified.396 file1 ... fileN The list of files to erase.397 398 parameters for querymethods:399 eraser querymethods400 401 no parameters to set.402 403 All arguments are case sensitive.404 405 */406 407 HRESULT CCtxMenu::InvokeCommand ( LPCMINVOKECOMMANDINFO pCmdInfo )408 {409 // If lpVerb really points to a string, ignore this function call and bail out.410 if ( HIWORD( pCmdInfo->lpVerb ) != 0)411 return E_INVALIDARG;412 413 HRESULT result = E_INVALIDARG;414 // final eraser command to call415 string_type command(L"eraser ");416 string_type files, directories, unuseds;417 418 // compile the eraser command syntax419 for (string_list::const_iterator i = m_szSelectedFiles.begin();420 i != m_szSelectedFiles.end(); ++i)421 {422 files += L"\"" + *i + L"\" ";423 }424 for (string_list::const_iterator i = m_szSelectedUnused.begin();425 i != m_szSelectedUnused.end(); ++i)426 {427 unuseds += L"--unused=\"" + *i + L"\" ";428 }429 for (string_list::const_iterator i = m_szSelectedDirectories.begin();430 i != m_szSelectedDirectories.end(); ++i)431 {432 directories += L"--dir=\"" + *i + L"\" ";433 }434 435 // Get the command index.436 switch(LOWORD(pCmdInfo->lpVerb + 1))437 {438 #if 0439 case CERASER_ERASE:440 {441 command += L"addtask " + files + unuseds + directories;442 //result = system(command.c_str());443 break;444 }445 case CERASER_SECURE_MOVE:446 {447 result = S_OK;448 // we need some user interaction, thus we will have a windows form449 // has to be native, so i guess a bit of work450 break;451 }452 // NOT IMPLEMENTED METHODS453 case CERASER_ERASE_ON_RESTART:454 {455 MessageBox (pCmdInfo->hwnd, szMsg, _T("Eraser v6 - Shell Extention Query"), MB_ICONINFORMATION );456 command += S("--restart ") + objects;457 result = system(command.c_str());458 break;459 }460 case CERASER_SCHEDULE:461 {462 command += S("--schedule ") + objects;463 result = system(command.c_str());464 break;465 }466 case CERASER_CONSOLE:467 {468 // interactive eraser console469 break;470 }471 #endif472 default:473 {474 TCHAR szMsg [MAX_PATH + 32];475 wsprintf ( szMsg, _T("Invalid Query was submitted, unable to process!\n\nCommand ID = %d\n\n"), LOWORD(pCmdInfo->lpVerb) );476 MessageBox ( pCmdInfo->hwnd, szMsg, _T("Eraser v6 - Shell Extention Query"), MB_ICONINFORMATION );477 }478 return result;479 }480 }481 482 MENUITEMINFO* CCtxMenu::GetSeparator()483 {484 MENUITEMINFO *mii = new MENUITEMINFO();485 mii->cbSize = sizeof(MENUITEMINFO);486 mii->fMask = MIIM_TYPE;487 mii->fType = MF_SEPARATOR;488 return mii;489 }490 491 HICON CCtxMenu::GetMenuIcon()492 {493 int smIconSize = GetSystemMetrics(SM_CXMENUCHECK);494 return static_cast<HICON>(LoadImage(theApp.m_hInstance, L"Eraser",495 IMAGE_ICON, smIconSize, smIconSize, LR_LOADTRANSPARENT));496 }497 498 HBITMAP CCtxMenu::GetMenuBitmap()499 {500 BITMAP bitmap;501 ICONINFO iconInfo;502 ZeroMemory(&bitmap, sizeof(bitmap));503 ZeroMemory(&iconInfo, sizeof(iconInfo));504 Handle<HICON> icon(GetMenuIcon());505 506 //Try to get the icon's size, bitmap and bit depth. We will try to convert507 //the bitmap into a DIB for display on Vista if it contains an alpha channel.508 if (!GetIconInfo(icon, &iconInfo))509 return NULL;510 511 Handle<HBITMAP> iconMask(iconInfo.hbmMask);512 if (!GetObject(iconInfo.hbmColor, sizeof(BITMAP), &bitmap) ||513 bitmap.bmBitsPixel < 32)514 return iconInfo.hbmColor;515 516 //Try converting the DDB into a DIB.517 DIBSECTION dibSection;518 HBITMAP dib = CreateDIB(bitmap.bmWidth, bitmap.bmHeight, NULL);519 if (!GetObject(dib, sizeof(dibSection), &dibSection) ||520 !GetDIBits(CreateCompatibleDC(NULL), iconInfo.hbmColor, 0, bitmap.bmHeight,521 dibSection.dsBm.bmBits, reinterpret_cast<BITMAPINFO*>(&dibSection.dsBmih),522 DIB_RGB_COLORS))523 {524 return iconInfo.hbmColor;525 }526 527 return dib;528 }529 530 HBITMAP CCtxMenu::CreateDIB(LONG width, LONG height, char** bitmapBits)531 {532 BITMAPINFO info;533 ZeroMemory(&info, sizeof(info));534 info.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);535 info.bmiHeader.biWidth = width;536 info.bmiHeader.biHeight = height;537 info.bmiHeader.biPlanes = 1;538 info.bmiHeader.biBitCount = 32;539 info.bmiHeader.biCompression = BI_RGB;540 char* dibBitmapBits = NULL;541 return ::CreateDIBSection(0, &info, DIB_RGB_COLORS,542 reinterpret_cast<void**>(bitmapBits ? bitmapBits : &dibBitmapBits), NULL, 0);543 }544 } -
branches/erasershellext/cpp/EraserCtxMenu.vcproj
r686 r692 202 202 </Configuration> 203 203 </Configurations> 204 <References> 205 </References> 204 206 <Files> 205 207 <Filter … … 342 344 </File> 343 345 </Filter> 346 <File 347 RelativePath=".\EShll.txt" 348 > 349 </File> 344 350 </Files> 345 351 <Globals>
Note: See TracChangeset
for help on using the changeset viewer.
