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