1 /* 2 * PROJECT: ReactOS Zip Shell Extension 3 * LICENSE: GPL-2.0+ (https://spdx.org/licenses/GPL-2.0+) 4 * PURPOSE: Main class 5 * COPYRIGHT: Copyright 2017 Mark Jansen (mark.jansen@reactos.org) 6 */ 7 8 9 EXTERN_C HRESULT WINAPI SHCreateFileExtractIconW(LPCWSTR pszPath, DWORD dwFileAttributes, REFIID riid, void **ppv); 10 11 12 struct FolderViewColumns 13 { 14 int iResource; 15 DWORD dwDefaultState; 16 int cxChar; 17 int fmt; 18 }; 19 20 static FolderViewColumns g_ColumnDefs[] = 21 { 22 { IDS_COL_NAME, SHCOLSTATE_TYPE_STR | SHCOLSTATE_ONBYDEFAULT, 25, LVCFMT_LEFT }, 23 { IDS_COL_TYPE, SHCOLSTATE_TYPE_STR | SHCOLSTATE_ONBYDEFAULT, 20, LVCFMT_LEFT }, 24 { IDS_COL_COMPRSIZE, SHCOLSTATE_TYPE_STR | SHCOLSTATE_ONBYDEFAULT, 10, LVCFMT_RIGHT }, 25 { IDS_COL_PASSWORD, SHCOLSTATE_TYPE_STR | SHCOLSTATE_ONBYDEFAULT, 10, LVCFMT_LEFT }, 26 { IDS_COL_SIZE, SHCOLSTATE_TYPE_STR | SHCOLSTATE_ONBYDEFAULT, 10, LVCFMT_RIGHT }, 27 { IDS_COL_RATIO, SHCOLSTATE_TYPE_STR | SHCOLSTATE_ONBYDEFAULT, 10, LVCFMT_LEFT }, 28 { IDS_COL_DATE_MOD, SHCOLSTATE_TYPE_DATE | SHCOLSTATE_ONBYDEFAULT, 15, LVCFMT_LEFT }, 29 }; 30 31 32 class CZipFolder : 33 public CComCoClass<CZipFolder, &CLSID_ZipFolderStorageHandler>, 34 public CComObjectRootEx<CComMultiThreadModelNoCS>, 35 public IShellFolder2, 36 //public IStorage, 37 public IContextMenu, 38 public IShellExtInit, 39 //public IPersistFile, 40 public IPersistFolder2, 41 public IZip 42 { 43 CStringW m_ZipFile; 44 CStringA m_ZipDir; 45 CComHeapPtr<ITEMIDLIST> m_CurDir; 46 unzFile m_UnzipFile; 47 48 public: 49 CZipFolder() 50 :m_UnzipFile(NULL) 51 { 52 } 53 54 ~CZipFolder() 55 { 56 Close(); 57 } 58 59 void Close() 60 { 61 if (m_UnzipFile) 62 unzClose(m_UnzipFile); 63 m_UnzipFile = NULL; 64 } 65 66 // *** IZip methods *** 67 STDMETHODIMP_(unzFile) getZip() 68 { 69 if (!m_UnzipFile) 70 { 71 m_UnzipFile = unzOpen2_64(m_ZipFile, &g_FFunc); 72 } 73 74 return m_UnzipFile; 75 } 76 77 // *** IShellFolder2 methods *** 78 STDMETHODIMP GetDefaultSearchGUID(GUID *pguid) 79 { 80 UNIMPLEMENTED; 81 return E_NOTIMPL; 82 } 83 STDMETHODIMP EnumSearches(IEnumExtraSearch **ppenum) 84 { 85 UNIMPLEMENTED; 86 return E_NOTIMPL; 87 } 88 STDMETHODIMP GetDefaultColumn(DWORD dwRes, ULONG *pSort, ULONG *pDisplay) 89 { 90 UNIMPLEMENTED; 91 return E_NOTIMPL; 92 } 93 STDMETHODIMP GetDefaultColumnState(UINT iColumn, DWORD *pcsFlags) 94 { 95 if (!pcsFlags || iColumn >= _countof(g_ColumnDefs)) 96 return E_INVALIDARG; 97 *pcsFlags = g_ColumnDefs[iColumn].dwDefaultState; 98 return S_OK; 99 } 100 STDMETHODIMP GetDetailsEx(PCUITEMID_CHILD pidl, const SHCOLUMNID *pscid, VARIANT *pv) 101 { 102 UNIMPLEMENTED; 103 return E_NOTIMPL; 104 } 105 // Adapted from CFileDefExt::GetFileTimeString 106 BOOL _GetFileTimeString(LPFILETIME lpFileTime, LPWSTR pwszResult, UINT cchResult) 107 { 108 SYSTEMTIME st; 109 110 if (!FileTimeToSystemTime(lpFileTime, &st)) 111 return FALSE; 112 113 size_t cchRemaining = cchResult; 114 LPWSTR pwszEnd = pwszResult; 115 int cchWritten = GetDateFormatW(LOCALE_USER_DEFAULT, DATE_SHORTDATE, &st, NULL, pwszEnd, cchRemaining); 116 if (cchWritten) 117 --cchWritten; // GetDateFormatW returns count with terminating zero 118 else 119 return FALSE; 120 cchRemaining -= cchWritten; 121 pwszEnd += cchWritten; 122 123 StringCchCopyExW(pwszEnd, cchRemaining, L" ", &pwszEnd, &cchRemaining, 0); 124 125 cchWritten = GetTimeFormatW(LOCALE_USER_DEFAULT, 0, &st, NULL, pwszEnd, cchRemaining); 126 if (cchWritten) 127 --cchWritten; // GetTimeFormatW returns count with terminating zero 128 else 129 return FALSE; 130 131 return TRUE; 132 } 133 STDMETHODIMP GetDetailsOf(PCUITEMID_CHILD pidl, UINT iColumn, SHELLDETAILS *psd) 134 { 135 if (iColumn >= _countof(g_ColumnDefs)) 136 return E_FAIL; 137 138 psd->cxChar = g_ColumnDefs[iColumn].cxChar; 139 psd->fmt = g_ColumnDefs[iColumn].fmt; 140 141 if (pidl == NULL) 142 { 143 return SHSetStrRet(&psd->str, _AtlBaseModule.GetResourceInstance(), g_ColumnDefs[iColumn].iResource); 144 } 145 146 PCUIDLIST_RELATIVE curpidl = ILGetNext(pidl); 147 if (curpidl->mkid.cb != 0) 148 { 149 DPRINT1("ERROR, unhandled PIDL!\n"); 150 return E_FAIL; 151 } 152 153 const ZipPidlEntry* zipEntry = _ZipFromIL(pidl); 154 if (!zipEntry) 155 return E_INVALIDARG; 156 157 WCHAR Buffer[100]; 158 bool isDir = zipEntry->ZipType == ZIP_PIDL_DIRECTORY; 159 switch (iColumn) 160 { 161 case 0: /* Name, ReactOS specific? */ 162 return GetDisplayNameOf(pidl, 0, &psd->str); 163 case 1: /* Type */ 164 { 165 SHFILEINFOA shfi; 166 DWORD dwAttributes = isDir ? FILE_ATTRIBUTE_DIRECTORY : FILE_ATTRIBUTE_NORMAL; 167 ULONG_PTR firet = SHGetFileInfoA(zipEntry->Name, dwAttributes, &shfi, sizeof(shfi), SHGFI_USEFILEATTRIBUTES | SHGFI_TYPENAME); 168 if (!firet) 169 return E_FAIL; 170 return SHSetStrRet(&psd->str, shfi.szTypeName); 171 } 172 case 2: /* Compressed size */ 173 case 4: /* Size */ 174 { 175 if (isDir) 176 return SHSetStrRet(&psd->str, L""); 177 178 ULONG64 Size = iColumn == 2 ? zipEntry->CompressedSize : zipEntry->UncompressedSize; 179 if (!StrFormatByteSizeW(Size, Buffer, _countof(Buffer))) 180 return E_FAIL; 181 return SHSetStrRet(&psd->str, Buffer); 182 } 183 case 3: /* Password */ 184 if (isDir) 185 return SHSetStrRet(&psd->str, L""); 186 return SHSetStrRet(&psd->str, _AtlBaseModule.GetResourceInstance(), zipEntry->Password ? IDS_YES : IDS_NO); 187 case 5: /* Ratio */ 188 { 189 if (isDir) 190 return SHSetStrRet(&psd->str, L""); 191 192 int ratio = 0; 193 if (zipEntry->UncompressedSize) 194 ratio = 100 - (int)((zipEntry->CompressedSize*100)/zipEntry->UncompressedSize); 195 StringCchPrintfW(Buffer, _countof(Buffer), L"%d%%", ratio); 196 return SHSetStrRet(&psd->str, Buffer); 197 } 198 case 6: /* Date */ 199 { 200 if (isDir) 201 return SHSetStrRet(&psd->str, L""); 202 FILETIME ftLocal; 203 DosDateTimeToFileTime((WORD)(zipEntry->DosDate>>16), (WORD)zipEntry->DosDate, &ftLocal); 204 if (!_GetFileTimeString(&ftLocal, Buffer, _countof(Buffer))) 205 return E_FAIL; 206 return SHSetStrRet(&psd->str, Buffer); 207 } 208 } 209 210 UNIMPLEMENTED; 211 return E_NOTIMPL; 212 } 213 STDMETHODIMP MapColumnToSCID(UINT column, SHCOLUMNID *pscid) 214 { 215 UNIMPLEMENTED; 216 return E_NOTIMPL; 217 } 218 219 // *** IShellFolder methods *** 220 STDMETHODIMP ParseDisplayName(HWND hwndOwner, LPBC pbc, LPOLESTR lpszDisplayName, ULONG *pchEaten, PIDLIST_RELATIVE *ppidl, ULONG *pdwAttributes) 221 { 222 UNIMPLEMENTED; 223 return E_NOTIMPL; 224 } 225 STDMETHODIMP EnumObjects(HWND hwndOwner, DWORD dwFlags, LPENUMIDLIST *ppEnumIDList) 226 { 227 return _CEnumZipContents_CreateInstance(this, dwFlags, m_ZipDir, IID_PPV_ARG(IEnumIDList, ppEnumIDList)); 228 } 229 STDMETHODIMP BindToObject(PCUIDLIST_RELATIVE pidl, LPBC pbcReserved, REFIID riid, LPVOID *ppvOut) 230 { 231 if (riid == IID_IShellFolder) 232 { 233 CStringA newZipDir = m_ZipDir; 234 PCUIDLIST_RELATIVE curpidl = pidl; 235 while (curpidl->mkid.cb) 236 { 237 const ZipPidlEntry* zipEntry = _ZipFromIL(curpidl); 238 if (!zipEntry) 239 { 240 return E_FAIL; 241 } 242 newZipDir += zipEntry->Name; 243 newZipDir += '/'; 244 245 curpidl = ILGetNext(curpidl); 246 } 247 return ShellObjectCreatorInit<CZipFolder>(m_ZipFile, newZipDir, m_CurDir, pidl, riid, ppvOut); 248 } 249 DbgPrint("%s(%S) UNHANDLED\n", __FUNCTION__, guid2string(riid)); 250 return E_NOTIMPL; 251 } 252 STDMETHODIMP BindToStorage(PCUIDLIST_RELATIVE pidl, LPBC pbcReserved, REFIID riid, LPVOID *ppvOut) 253 { 254 UNIMPLEMENTED; 255 return E_NOTIMPL; 256 } 257 STDMETHODIMP CompareIDs(LPARAM lParam, PCUIDLIST_RELATIVE pidl1, PCUIDLIST_RELATIVE pidl2) 258 { 259 const ZipPidlEntry* zipEntry1 = _ZipFromIL(pidl1); 260 const ZipPidlEntry* zipEntry2 = _ZipFromIL(pidl2); 261 262 if (!zipEntry1 || !zipEntry2) 263 return E_INVALIDARG; 264 265 int result = 0; 266 if (zipEntry1->ZipType != zipEntry2->ZipType) 267 result = zipEntry1->ZipType - zipEntry2->ZipType; 268 else 269 result = stricmp(zipEntry1->Name, zipEntry2->Name); 270 271 if (!result && zipEntry1->ZipType == ZIP_PIDL_DIRECTORY) 272 { 273 PCUIDLIST_RELATIVE child1 = ILGetNext(pidl1); 274 PCUIDLIST_RELATIVE child2 = ILGetNext(pidl2); 275 276 if (child1->mkid.cb && child2->mkid.cb) 277 return CompareIDs(lParam, child1, child2); 278 else if (child1->mkid.cb) 279 result = 1; 280 else if (child2->mkid.cb) 281 result = -1; 282 } 283 284 return MAKE_COMPARE_HRESULT(result); 285 } 286 STDMETHODIMP CreateViewObject(HWND hwndOwner, REFIID riid, LPVOID *ppvOut) 287 { 288 static const GUID UnknownIID = // {93F81976-6A0D-42C3-94DD-AA258A155470} 289 {0x93F81976, 0x6A0D, 0x42C3, {0x94, 0xDD, 0xAA, 0x25, 0x8A, 0x15, 0x54, 0x70}}; 290 if (riid == IID_IShellView) 291 { 292 SFV_CREATE sfvparams = {sizeof(SFV_CREATE), this}; 293 CComPtr<IShellFolderViewCB> pcb; 294 295 HRESULT hr = _CFolderViewCB_CreateInstance(IID_PPV_ARG(IShellFolderViewCB, &pcb)); 296 if (FAILED_UNEXPECTEDLY(hr)) 297 return hr; 298 299 sfvparams.psfvcb = pcb; 300 hr = SHCreateShellFolderView(&sfvparams, (IShellView**)ppvOut); 301 302 return hr; 303 } 304 else if (riid == IID_IExplorerCommandProvider) 305 { 306 return _CExplorerCommandProvider_CreateInstance(this, riid, ppvOut); 307 } 308 else if (riid == IID_IContextMenu) 309 { 310 // Folder context menu 311 return QueryInterface(riid, ppvOut); 312 } 313 if (UnknownIID != riid) 314 DbgPrint("%s(%S) UNHANDLED\n", __FUNCTION__, guid2string(riid)); 315 return E_NOTIMPL; 316 } 317 STDMETHODIMP GetAttributesOf(UINT cidl, PCUITEMID_CHILD_ARRAY apidl, DWORD *rgfInOut) 318 { 319 if (!rgfInOut || !cidl || !apidl) 320 return E_INVALIDARG; 321 322 *rgfInOut = 0; 323 324 //static DWORD dwFileAttrs = SFGAO_STREAM | SFGAO_HASPROPSHEET | SFGAO_CANDELETE | SFGAO_CANCOPY | SFGAO_CANMOVE; 325 //static DWORD dwFolderAttrs = SFGAO_FOLDER | SFGAO_DROPTARGET | SFGAO_HASPROPSHEET | SFGAO_CANDELETE | SFGAO_STORAGE | SFGAO_CANCOPY | SFGAO_CANMOVE; 326 static DWORD dwFileAttrs = SFGAO_STREAM; 327 static DWORD dwFolderAttrs = SFGAO_FOLDER | SFGAO_HASSUBFOLDER | SFGAO_BROWSABLE; 328 329 330 while (cidl > 0 && *apidl) 331 { 332 const ZipPidlEntry* zipEntry = _ZipFromIL(*apidl); 333 334 if (zipEntry) 335 { 336 if (zipEntry->ZipType == ZIP_PIDL_FILE) 337 *rgfInOut |= dwFileAttrs; 338 else 339 *rgfInOut |= dwFolderAttrs; 340 } 341 else 342 { 343 *rgfInOut = 0; 344 } 345 346 apidl++; 347 cidl--; 348 } 349 350 *rgfInOut &= ~SFGAO_VALIDATE; 351 return S_OK; 352 } 353 static HRESULT CALLBACK ZipFolderMenuCallback(IShellFolder *psf, HWND hwnd, IDataObject *pdtobj, 354 UINT uMsg, WPARAM wParam, LPARAM lParam) 355 { 356 switch (uMsg) 357 { 358 case DFM_MERGECONTEXTMENU: 359 { 360 CComQIIDPtr<I_ID(IContextMenu)> spContextMenu(psf); 361 if (!spContextMenu) 362 return E_NOINTERFACE; 363 364 QCMINFO *pqcminfo = (QCMINFO *)lParam; 365 HRESULT hr = spContextMenu->QueryContextMenu(pqcminfo->hmenu, 366 pqcminfo->indexMenu, 367 pqcminfo->idCmdFirst, 368 pqcminfo->idCmdLast, 369 CMF_NORMAL); 370 if (FAILED_UNEXPECTEDLY(hr)) 371 return hr; 372 373 pqcminfo->idCmdFirst += HRESULT_CODE(hr); 374 return S_OK; 375 } 376 case DFM_INVOKECOMMAND: 377 { 378 CComQIIDPtr<I_ID(IContextMenu)> spContextMenu(psf); 379 if (!spContextMenu) 380 return E_NOINTERFACE; 381 382 CMINVOKECOMMANDINFO ici = { sizeof(ici) }; 383 ici.lpVerb = MAKEINTRESOURCEA(wParam); 384 return spContextMenu->InvokeCommand(&ici); 385 } 386 case DFM_INVOKECOMMANDEX: 387 case DFM_GETDEFSTATICID: // Required for Windows 7 to pick a default 388 return S_FALSE; 389 } 390 return E_NOTIMPL; 391 } 392 STDMETHODIMP GetUIObjectOf(HWND hwndOwner, UINT cidl, PCUITEMID_CHILD_ARRAY apidl, REFIID riid, UINT * prgfInOut, LPVOID * ppvOut) 393 { 394 if ((riid == IID_IExtractIconA || riid == IID_IExtractIconW) && cidl == 1) 395 { 396 const ZipPidlEntry* zipEntry = _ZipFromIL(*apidl); 397 if (zipEntry) 398 { 399 CComHeapPtr<WCHAR> pathW; 400 401 int len = MultiByteToWideChar(CP_ACP, 0, zipEntry->Name, -1, NULL, 0); 402 pathW.Allocate(len); 403 MultiByteToWideChar(CP_ACP, 0, zipEntry->Name, -1, pathW, len); 404 405 DWORD dwAttributes = (zipEntry->ZipType == ZIP_PIDL_DIRECTORY) ? FILE_ATTRIBUTE_DIRECTORY : FILE_ATTRIBUTE_NORMAL; 406 return SHCreateFileExtractIconW(pathW, dwAttributes, riid, ppvOut); 407 } 408 } 409 else if (riid == IID_IContextMenu && cidl >= 0) 410 { 411 // Context menu of an object inside the zip 412 const ZipPidlEntry* zipEntry = _ZipFromIL(*apidl); 413 if (zipEntry) 414 { 415 HKEY keys[1] = {0}; 416 int nkeys = 0; 417 if (zipEntry->ZipType == ZIP_PIDL_DIRECTORY) 418 { 419 LSTATUS res = RegOpenKeyExW(HKEY_CLASSES_ROOT, L"Folder", 0, KEY_READ | KEY_QUERY_VALUE, keys); 420 if (res != ERROR_SUCCESS) 421 return E_FAIL; 422 nkeys++; 423 } 424 return CDefFolderMenu_Create2(NULL, hwndOwner, cidl, apidl, this, ZipFolderMenuCallback, nkeys, keys, (IContextMenu**)ppvOut); 425 } 426 } 427 else if (riid == IID_IDataObject && cidl >= 1) 428 { 429 return CIDLData_CreateFromIDArray(m_CurDir, cidl, apidl, (IDataObject**)ppvOut); 430 } 431 432 DbgPrint("%s(%S) UNHANDLED\n", __FUNCTION__ , guid2string(riid)); 433 return E_NOINTERFACE; 434 } 435 STDMETHODIMP GetDisplayNameOf(PCUITEMID_CHILD pidl, DWORD dwFlags, LPSTRRET strRet) 436 { 437 if (!pidl) 438 return S_FALSE; 439 440 PCUIDLIST_RELATIVE curpidl = ILGetNext(pidl); 441 if (curpidl->mkid.cb != 0) 442 { 443 DPRINT1("ERROR, unhandled PIDL!\n"); 444 return E_FAIL; 445 } 446 447 const ZipPidlEntry* zipEntry = _ZipFromIL(pidl); 448 if (!zipEntry) 449 return E_FAIL; 450 451 return SHSetStrRet(strRet, (LPCSTR)zipEntry->Name); 452 } 453 STDMETHODIMP SetNameOf(HWND hwndOwner, PCUITEMID_CHILD pidl, LPCOLESTR lpName, DWORD dwFlags, PITEMID_CHILD *pPidlOut) 454 { 455 UNIMPLEMENTED; 456 return E_NOTIMPL; 457 } 458 //// IStorage 459 //STDMETHODIMP CreateStream(LPCOLESTR pwcsName, DWORD grfMode, DWORD reserved1, DWORD reserved2, IStream **ppstm); 460 //STDMETHODIMP OpenStream(LPCOLESTR pwcsName, void *reserved1, DWORD grfMode, DWORD reserved2, IStream **ppstm); 461 //STDMETHODIMP CreateStorage(LPCOLESTR pwcsName, DWORD grfMode, DWORD dwStgFmt, DWORD reserved2, IStorage **ppstg); 462 //STDMETHODIMP OpenStorage(LPCOLESTR pwcsName, IStorage *pstgPriority, DWORD grfMode, SNB snbExclude, DWORD reserved, IStorage **ppstg); 463 //STDMETHODIMP CopyTo(DWORD ciidExclude, const IID *rgiidExclude, SNB snbExclude, IStorage *pstgDest); 464 //STDMETHODIMP MoveElementTo(LPCOLESTR pwcsName, IStorage *pstgDest, LPCOLESTR pwcsNewName, DWORD grfFlags); 465 //STDMETHODIMP Commit(DWORD grfCommitFlags); 466 //STDMETHODIMP Revert(); 467 //STDMETHODIMP EnumElements(DWORD reserved1, void *reserved2, DWORD reserved3, IEnumSTATSTG **ppenum); 468 //STDMETHODIMP DestroyElement(LPCOLESTR pwcsName); 469 //STDMETHODIMP RenameElement(LPCOLESTR pwcsOldName, LPCOLESTR pwcsNewName); 470 //STDMETHODIMP SetElementTimes(LPCOLESTR pwcsName, const FILETIME *pctime, const FILETIME *patime, const FILETIME *pmtime); 471 //STDMETHODIMP SetClass(REFCLSID clsid); 472 //STDMETHODIMP SetStateBits(DWORD grfStateBits, DWORD grfMask); 473 //STDMETHODIMP Stat(STATSTG *pstatstg, DWORD grfStatFlag); 474 475 // *** IContextMenu methods *** 476 STDMETHODIMP GetCommandString(UINT_PTR idCmd, UINT uFlags, UINT *pwReserved, LPSTR pszName, UINT cchMax) 477 { 478 if (idCmd != 0) 479 return E_INVALIDARG; 480 481 switch (uFlags) 482 { 483 case GCS_VERBA: 484 return StringCchCopyA(pszName, cchMax, EXTRACT_VERBA); 485 case GCS_VERBW: 486 return StringCchCopyW((LPWSTR)pszName, cchMax, EXTRACT_VERBW); 487 case GCS_HELPTEXTA: 488 { 489 CStringA helpText(MAKEINTRESOURCEA(IDS_HELPTEXT)); 490 return StringCchCopyA(pszName, cchMax, helpText); 491 } 492 case GCS_HELPTEXTW: 493 { 494 CStringW helpText(MAKEINTRESOURCEA(IDS_HELPTEXT)); 495 return StringCchCopyW((LPWSTR)pszName, cchMax, helpText); 496 } 497 case GCS_VALIDATEA: 498 case GCS_VALIDATEW: 499 return S_OK; 500 } 501 502 return E_INVALIDARG; 503 } 504 STDMETHODIMP InvokeCommand(LPCMINVOKECOMMANDINFO pici) 505 { 506 if (!pici || (pici->cbSize != sizeof(CMINVOKECOMMANDINFO) && pici->cbSize != sizeof(CMINVOKECOMMANDINFOEX))) 507 return E_INVALIDARG; 508 509 if (pici->lpVerb == MAKEINTRESOURCEA(0) || (HIWORD(pici->lpVerb) && !strcmp(pici->lpVerb, EXTRACT_VERBA))) 510 { 511 BSTR ZipFile = m_ZipFile.AllocSysString(); 512 InterlockedIncrement(&g_ModuleRefCnt); 513 514 DWORD tid; 515 HANDLE hThread = CreateThread(NULL, 0, s_ExtractProc, ZipFile, NULL, &tid); 516 if (hThread) 517 { 518 CloseHandle(hThread); 519 return S_OK; 520 } 521 } 522 return E_INVALIDARG; 523 } 524 STDMETHODIMP QueryContextMenu(HMENU hmenu, UINT indexMenu, UINT idCmdFirst, UINT idCmdLast, UINT uFlags) 525 { 526 UINT idCmd = idCmdFirst; 527 528 if (!(uFlags & CMF_DEFAULTONLY)) 529 { 530 CStringW menuText(MAKEINTRESOURCEW(IDS_MENUITEM)); 531 532 if (indexMenu) 533 { 534 InsertMenuW(hmenu, indexMenu++, MF_BYPOSITION | MF_SEPARATOR, 0, NULL); 535 } 536 InsertMenuW(hmenu, indexMenu++, MF_BYPOSITION | MF_STRING, idCmd++, menuText); 537 } 538 539 return MAKE_HRESULT(SEVERITY_SUCCESS, FACILITY_NULL, idCmd - idCmdFirst); 540 } 541 542 // *** IShellExtInit methods *** 543 STDMETHODIMP Initialize(PCIDLIST_ABSOLUTE pidlFolder, LPDATAOBJECT pDataObj, HKEY hkeyProgID) 544 { 545 FORMATETC etc = { CF_HDROP, NULL, DVASPECT_CONTENT, -1, TYMED_HGLOBAL }; 546 STGMEDIUM stg; 547 548 HRESULT hr = pDataObj->GetData(&etc, &stg); 549 if (FAILED_UNEXPECTEDLY(hr)) 550 { 551 return hr; 552 } 553 hr = E_FAIL; 554 HDROP hdrop = (HDROP)GlobalLock(stg.hGlobal); 555 if (hdrop) 556 { 557 UINT uNumFiles = DragQueryFileW(hdrop, 0xFFFFFFFF, NULL, 0); 558 if (uNumFiles == 1) 559 { 560 WCHAR szFile[MAX_PATH * 2]; 561 if (DragQueryFileW(hdrop, 0, szFile, _countof(szFile))) 562 { 563 CComHeapPtr<ITEMIDLIST> pidl; 564 hr = SHParseDisplayName(szFile, NULL, &pidl, 0, NULL); 565 if (!FAILED_UNEXPECTEDLY(hr)) 566 { 567 hr = Initialize(pidl); 568 } 569 } 570 else 571 { 572 DbgPrint("Failed to query the file.\r\n"); 573 } 574 } 575 else 576 { 577 DbgPrint("Invalid number of files: %d\r\n", uNumFiles); 578 } 579 GlobalUnlock(stg.hGlobal); 580 } 581 else 582 { 583 DbgPrint("Could not lock stg.hGlobal\r\n"); 584 } 585 ReleaseStgMedium(&stg); 586 return hr; 587 588 } 589 590 //// IPersistFile 591 ////STDMETHODIMP GetClassID(CLSID *pclsid); 592 //STDMETHODIMP IsDirty(); 593 //STDMETHODIMP Load(LPCOLESTR pszFileName, DWORD dwMode); 594 //STDMETHODIMP Save(LPCOLESTR pszFileName, BOOL fRemember); 595 //STDMETHODIMP SaveCompleted(LPCOLESTR pszFileName); 596 //STDMETHODIMP GetCurFile(LPOLESTR *ppszFileName); 597 598 //// *** IPersistFolder2 methods *** 599 STDMETHODIMP GetCurFolder(PIDLIST_ABSOLUTE * pidl) 600 { 601 *pidl = ILClone(m_CurDir); 602 return S_OK; 603 } 604 605 // *** IPersistFolder methods *** 606 STDMETHODIMP Initialize(PCIDLIST_ABSOLUTE pidl) 607 { 608 WCHAR tmpPath[MAX_PATH]; 609 610 if (SHGetPathFromIDListW(pidl, tmpPath)) 611 { 612 m_ZipFile = tmpPath; 613 m_CurDir.Attach(ILClone(pidl)); 614 return S_OK; 615 } 616 DbgPrint("%s() => Unable to parse pidl\n", __FUNCTION__); 617 return E_INVALIDARG; 618 } 619 620 // *** IPersist methods *** 621 STDMETHODIMP GetClassID(CLSID *lpClassId) 622 { 623 DbgPrint("%s\n", __FUNCTION__); 624 return E_NOTIMPL; 625 } 626 627 628 STDMETHODIMP Initialize(PCWSTR zipFile, PCSTR zipDir, PCUIDLIST_ABSOLUTE curDir, PCUIDLIST_RELATIVE pidl) 629 { 630 m_ZipFile = zipFile; 631 m_ZipDir = zipDir; 632 633 m_CurDir.Attach(ILCombine(curDir, pidl)); 634 return S_OK; 635 } 636 static DWORD WINAPI s_ExtractProc(LPVOID arg) 637 { 638 CComBSTR ZipFile; 639 ZipFile.Attach((BSTR)arg); 640 641 _CZipExtract_runWizard(ZipFile); 642 643 InterlockedDecrement(&g_ModuleRefCnt); 644 return 0; 645 } 646 647 public: 648 DECLARE_NO_REGISTRY() // Handled manually because this object is exposed via multiple clsid's 649 DECLARE_NOT_AGGREGATABLE(CZipFolder) 650 651 DECLARE_PROTECT_FINAL_CONSTRUCT() 652 653 BEGIN_COM_MAP(CZipFolder) 654 COM_INTERFACE_ENTRY_IID(IID_IShellFolder2, IShellFolder2) 655 COM_INTERFACE_ENTRY_IID(IID_IShellFolder, IShellFolder) 656 // COM_INTERFACE_ENTRY_IID(IID_IStorage, IStorage) 657 COM_INTERFACE_ENTRY_IID(IID_IContextMenu, IContextMenu) 658 COM_INTERFACE_ENTRY_IID(IID_IShellExtInit, IShellExtInit) 659 //COM_INTERFACE_ENTRY_IID(IID_IPersistFile, IPersistFile) 660 COM_INTERFACE_ENTRY_IID(IID_IPersistFolder2, IPersistFolder2) 661 COM_INTERFACE_ENTRY_IID(IID_IPersistFolder, IPersistFolder) 662 COM_INTERFACE_ENTRY_IID(IID_IPersist, IPersist) 663 END_COM_MAP() 664 }; 665 666