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