1 #include "StdAfx.h"
2
3 #include "../../../Common/IntToString.h"
4 #include "../../../Common/StringConvert.h"
5
6 #include "../../../Windows/COM.h"
7 #include "../../../Windows/Clipboard.h"
8 #include "../../../Windows/Menu.h"
9 #include "../../../Windows/PropVariant.h"
10 #include "../../../Windows/PropVariantConv.h"
11
12 #include "../../PropID.h"
13 #include "../Common/PropIDUtils.h"
14 #include "../Explorer/ContextMenu.h"
15
16 #include "App.h"
17 #include "FormatUtils.h"
18 #include "LangUtils.h"
19 #include "MyLoadMenu.h"
20 #include "PropertyName.h"
21
22 #include "resource.h"
23 #include "PropertyNameRes.h"
24
25 using namespace NWindows;
26
27 LONG g_DllRefCount = 0;
28
29 static const UINT kSevenZipStartMenuID = kMenuCmdID_Plugin_Start;
30 static const UINT kSystemStartMenuID = kMenuCmdID_Plugin_Start + 100;
31
InvokeSystemCommand(const char * command)32 void CPanel::InvokeSystemCommand(const char *command)
33 {
34 NCOM::CComInitializer comInitializer;
35 if (!IsFsOrPureDrivesFolder())
36 return;
37 CRecordVector<UInt32> operatedIndices;
38 GetOperatedItemIndices(operatedIndices);
39 if (operatedIndices.IsEmpty())
40 return;
41 CMyComPtr<IContextMenu> contextMenu;
42 if (CreateShellContextMenu(operatedIndices, contextMenu) != S_OK)
43 return;
44
45 CMINVOKECOMMANDINFO ci;
46 ZeroMemory(&ci, sizeof(ci));
47 ci.cbSize = sizeof(CMINVOKECOMMANDINFO);
48 ci.hwnd = GetParent();
49 ci.lpVerb = command;
50 contextMenu->InvokeCommand(&ci);
51 }
52
53 static const char * const kSeparator = "----------------------------\n";
54 static const char * const kSeparatorSmall = "----\n";
55 static const char * const kPropValueSeparator = ": ";
56
57 extern UString ConvertSizeToString(UInt64 value) throw();
58 bool IsSizeProp(UINT propID) throw();
59
60 UString GetOpenArcErrorMessage(UInt32 errorFlags);
61
AddPropertyString(PROPID propID,const wchar_t * nameBSTR,const NCOM::CPropVariant & prop,UString & s)62 static void AddPropertyString(PROPID propID, const wchar_t *nameBSTR,
63 const NCOM::CPropVariant &prop, UString &s)
64 {
65 if (prop.vt != VT_EMPTY)
66 {
67 UString val;
68
69 if (propID == kpidErrorFlags ||
70 propID == kpidWarningFlags)
71 {
72 UInt32 flags = GetOpenArcErrorFlags(prop);
73 if (flags == 0)
74 return;
75 if (flags != 0)
76 val = GetOpenArcErrorMessage(flags);
77 }
78 if (val.IsEmpty())
79 if ((prop.vt == VT_UI8 || prop.vt == VT_UI4 || prop.vt == VT_UI2) && IsSizeProp(propID))
80 {
81 UInt64 v = 0;
82 ConvertPropVariantToUInt64(prop, v);
83 val = ConvertSizeToString(v);
84 }
85 else
86 ConvertPropertyToString2(val, prop, propID);
87
88 if (!val.IsEmpty())
89 {
90 s += GetNameOfProperty(propID, nameBSTR);
91 s += kPropValueSeparator;
92 /*
93 if (propID == kpidComment)
94 s.Add_LF();
95 */
96 s += val;
97 s.Add_LF();
98 }
99 }
100 }
101
102
AddPropertyString(PROPID propID,UInt64 val,UString & s)103 static void AddPropertyString(PROPID propID, UInt64 val, UString &s)
104 {
105 NCOM::CPropVariant prop = val;
106 AddPropertyString(propID, NULL, prop, s);
107 }
108
109
GetHex(Byte value)110 static inline char GetHex(Byte value)
111 {
112 return (char)((value < 10) ? ('0' + value) : ('A' + (value - 10)));
113 }
114
115 static const Byte kSpecProps[] =
116 {
117 kpidPath,
118 kpidType,
119 kpidErrorType,
120 kpidError,
121 kpidErrorFlags,
122 kpidWarning,
123 kpidWarningFlags,
124 kpidOffset,
125 kpidPhySize,
126 kpidTailSize
127 };
128
Properties()129 void CPanel::Properties()
130 {
131 CMyComPtr<IGetFolderArcProps> getFolderArcProps;
132 _folder.QueryInterface(IID_IGetFolderArcProps, &getFolderArcProps);
133 if (!getFolderArcProps)
134 {
135 InvokeSystemCommand("properties");
136 return;
137 }
138
139 {
140 UString message;
141
142 CRecordVector<UInt32> operatedIndices;
143 GetOperatedItemIndices(operatedIndices);
144
145 if (operatedIndices.Size() == 1)
146 {
147 UInt32 index = operatedIndices[0];
148 // message += "Item:\n");
149 UInt32 numProps;
150 if (_folder->GetNumberOfProperties(&numProps) == S_OK)
151 {
152 for (UInt32 i = 0; i < numProps; i++)
153 {
154 CMyComBSTR name;
155 PROPID propID;
156 VARTYPE varType;
157
158 if (_folder->GetPropertyInfo(i, &name, &propID, &varType) != S_OK)
159 continue;
160
161 NCOM::CPropVariant prop;
162 if (_folder->GetProperty(index, propID, &prop) != S_OK)
163 continue;
164 AddPropertyString(propID, name, prop, message);
165 }
166 }
167
168
169 if (_folderRawProps)
170 {
171 _folderRawProps->GetNumRawProps(&numProps);
172 for (UInt32 i = 0; i < numProps; i++)
173 {
174 CMyComBSTR name;
175 PROPID propID;
176 if (_folderRawProps->GetRawPropInfo(i, &name, &propID) != S_OK)
177 continue;
178
179 const void *data;
180 UInt32 dataSize;
181 UInt32 propType;
182 if (_folderRawProps->GetRawProp(index, propID, &data, &dataSize, &propType) != S_OK)
183 continue;
184
185 if (dataSize != 0)
186 {
187 AString s;
188 if (propID == kpidNtSecure)
189 ConvertNtSecureToString((const Byte *)data, dataSize, s);
190 else
191 {
192 const UInt32 kMaxDataSize = 64;
193 if (dataSize > kMaxDataSize)
194 {
195 s += "data:";
196 s.Add_UInt32(dataSize);
197 }
198 else
199 {
200 for (UInt32 k = 0; k < dataSize; k++)
201 {
202 Byte b = ((const Byte *)data)[k];
203 s += GetHex((Byte)((b >> 4) & 0xF));
204 s += GetHex((Byte)(b & 0xF));
205 }
206 }
207 }
208 message += GetNameOfProperty(propID, name);
209 message += kPropValueSeparator;
210 message += s.Ptr();
211 message.Add_LF();
212 }
213 }
214 }
215
216 message += kSeparator;
217 }
218 else if (operatedIndices.Size() >= 1)
219 {
220 UInt64 packSize = 0;
221 UInt64 unpackSize = 0;
222 UInt64 numFiles = 0;
223 UInt64 numDirs = 0;
224
225 FOR_VECTOR (i, operatedIndices)
226 {
227 const UInt32 index = operatedIndices[i];
228 unpackSize += GetItemSize(index);
229 packSize += GetItem_UInt64Prop(index, kpidPackSize);
230 if (IsItem_Folder(index))
231 {
232 numDirs++;
233 numDirs += GetItem_UInt64Prop(index, kpidNumSubDirs);
234 numFiles += GetItem_UInt64Prop(index, kpidNumSubFiles);;
235 }
236 else
237 numFiles++;
238 }
239 {
240 wchar_t temp[32];
241 ConvertUInt32ToString(operatedIndices.Size(), temp);
242 message += MyFormatNew(g_App.LangString_N_SELECTED_ITEMS, temp);
243 message.Add_LF();
244 }
245
246 if (numDirs != 0)
247 AddPropertyString(kpidNumSubDirs, numDirs, message);
248 if (numFiles != 0)
249 AddPropertyString(kpidNumSubFiles, numFiles, message);
250 AddPropertyString(kpidSize, unpackSize, message);
251 AddPropertyString(kpidPackSize, packSize, message);
252
253 message += kSeparator;
254 }
255
256
257 /*
258 AddLangString(message, IDS_PROP_FILE_TYPE);
259 message += kPropValueSeparator;
260 message += GetFolderTypeID();
261 message.Add_LF();
262 */
263
264 {
265 NCOM::CPropVariant prop;
266 if (_folder->GetFolderProperty(kpidPath, &prop) == S_OK)
267 {
268 AddPropertyString(kpidName, L"Path", prop, message);
269 }
270 }
271
272 CMyComPtr<IFolderProperties> folderProperties;
273 _folder.QueryInterface(IID_IFolderProperties, &folderProperties);
274 if (folderProperties)
275 {
276 UInt32 numProps;
277 if (folderProperties->GetNumberOfFolderProperties(&numProps) == S_OK)
278 {
279 for (UInt32 i = 0; i < numProps; i++)
280 {
281 CMyComBSTR name;
282 PROPID propID;
283 VARTYPE vt;
284 if (folderProperties->GetFolderPropertyInfo(i, &name, &propID, &vt) != S_OK)
285 continue;
286 NCOM::CPropVariant prop;
287 if (_folder->GetFolderProperty(propID, &prop) != S_OK)
288 continue;
289 AddPropertyString(propID, name, prop, message);
290 }
291 }
292 }
293
294 if (getFolderArcProps)
295 {
296 CMyComPtr<IFolderArcProps> getProps;
297 getFolderArcProps->GetFolderArcProps(&getProps);
298 if (getProps)
299 {
300 UInt32 numLevels;
301 if (getProps->GetArcNumLevels(&numLevels) != S_OK)
302 numLevels = 0;
303 for (UInt32 level2 = 0; level2 < numLevels; level2++)
304 {
305 {
306 UInt32 level = numLevels - 1 - level2;
307 UInt32 numProps;
308 if (getProps->GetArcNumProps(level, &numProps) == S_OK)
309 {
310 const int kNumSpecProps = ARRAY_SIZE(kSpecProps);
311
312 message += kSeparator;
313
314 for (Int32 i = -(int)kNumSpecProps; i < (Int32)numProps; i++)
315 {
316 CMyComBSTR name;
317 PROPID propID;
318 VARTYPE vt;
319 if (i < 0)
320 propID = kSpecProps[i + kNumSpecProps];
321 else if (getProps->GetArcPropInfo(level, i, &name, &propID, &vt) != S_OK)
322 continue;
323 NCOM::CPropVariant prop;
324 if (getProps->GetArcProp(level, propID, &prop) != S_OK)
325 continue;
326 AddPropertyString(propID, name, prop, message);
327 }
328 }
329 }
330
331 if (level2 != numLevels - 1)
332 {
333 UInt32 level = numLevels - 1 - level2;
334 UInt32 numProps;
335 if (getProps->GetArcNumProps2(level, &numProps) == S_OK)
336 {
337 message += kSeparatorSmall;
338 for (Int32 i = 0; i < (Int32)numProps; i++)
339 {
340 CMyComBSTR name;
341 PROPID propID;
342 VARTYPE vt;
343 if (getProps->GetArcPropInfo2(level, i, &name, &propID, &vt) != S_OK)
344 continue;
345 NCOM::CPropVariant prop;
346 if (getProps->GetArcProp2(level, propID, &prop) != S_OK)
347 continue;
348 AddPropertyString(propID, name, prop, message);
349 }
350 }
351 }
352 }
353 }
354 }
355 ::MessageBoxW(*(this), message, LangString(IDS_PROPERTIES), MB_OK);
356 }
357 }
358
EditCut()359 void CPanel::EditCut()
360 {
361 // InvokeSystemCommand("cut");
362 }
363
EditCopy()364 void CPanel::EditCopy()
365 {
366 /*
367 CMyComPtr<IGetFolderArcProps> getFolderArcProps;
368 _folder.QueryInterface(IID_IGetFolderArcProps, &getFolderArcProps);
369 if (!getFolderArcProps)
370 {
371 InvokeSystemCommand("copy");
372 return;
373 }
374 */
375 UString s;
376 CRecordVector<UInt32> indices;
377 GetSelectedItemsIndices(indices);
378 FOR_VECTOR (i, indices)
379 {
380 if (i != 0)
381 s += "\xD\n";
382 s += GetItemName(indices[i]);
383 }
384 ClipboardSetText(_mainWindow, s);
385 }
386
EditPaste()387 void CPanel::EditPaste()
388 {
389 /*
390 UStringVector names;
391 ClipboardGetFileNames(names);
392 CopyFromNoAsk(names);
393 UString s;
394 for (int i = 0; i < names.Size(); i++)
395 {
396 s += L' ';
397 s += names[i];
398 }
399
400 MessageBoxW(0, s, L"", 0);
401 */
402
403 // InvokeSystemCommand("paste");
404 }
405
406
407
408 struct CFolderPidls
409 {
410 LPITEMIDLIST parent;
411 CRecordVector<LPITEMIDLIST> items;
412
CFolderPidlsCFolderPidls413 CFolderPidls(): parent(NULL) {}
~CFolderPidlsCFolderPidls414 ~CFolderPidls()
415 {
416 FOR_VECTOR (i, items)
417 CoTaskMemFree(items[i]);
418 CoTaskMemFree(parent);
419 }
420 };
421
422
CreateShellContextMenu(const CRecordVector<UInt32> & operatedIndices,CMyComPtr<IContextMenu> & systemContextMenu)423 HRESULT CPanel::CreateShellContextMenu(
424 const CRecordVector<UInt32> &operatedIndices,
425 CMyComPtr<IContextMenu> &systemContextMenu)
426 {
427 systemContextMenu.Release();
428 const UString folderPath = GetFsPath();
429
430 CMyComPtr<IShellFolder> desktopFolder;
431 RINOK(::SHGetDesktopFolder(&desktopFolder));
432 if (!desktopFolder)
433 {
434 // ShowMessage("Failed to get Desktop folder");
435 return E_FAIL;
436 }
437
438 CFolderPidls pidls;
439 DWORD eaten;
440
441 // if (folderPath.IsEmpty()), then ParseDisplayName returns pidls of "My Computer"
442 RINOK(desktopFolder->ParseDisplayName(
443 GetParent(), NULL, (wchar_t *)(const wchar_t *)folderPath,
444 &eaten, &pidls.parent, NULL));
445
446 /*
447 STRRET pName;
448 res = desktopFolder->GetDisplayNameOf(pidls.parent, SHGDN_NORMAL, &pName);
449 WCHAR dir[MAX_PATH];
450 if (!SHGetPathFromIDListW(pidls.parent, dir))
451 dir[0] = 0;
452 */
453
454 if (!pidls.parent)
455 return E_FAIL;
456
457 if (operatedIndices.IsEmpty())
458 {
459 // how to get IContextMenu, if there are no selected files?
460 return E_FAIL;
461
462 /*
463 xp64 :
464 1) we can't use GetUIObjectOf() with (numItems == 0), it throws exception
465 2) we can't use desktopFolder->GetUIObjectOf() with absolute pidls of folder
466 context menu items are different in that case:
467 "Open / Explorer" for folder
468 "Delete" for "My Computer" icon
469 "Preperties" for "System"
470 */
471 /*
472 parentFolder = desktopFolder;
473 pidls.items.AddInReserved(pidls.parent);
474 pidls.parent = NULL;
475 */
476
477 // CreateViewObject() doesn't show all context menu items
478 /*
479 HRESULT res = parentFolder->CreateViewObject(
480 GetParent(), IID_IContextMenu, (void**)&systemContextMenu);
481 */
482 }
483
484 CMyComPtr<IShellFolder> parentFolder;
485 RINOK(desktopFolder->BindToObject(pidls.parent,
486 NULL, IID_IShellFolder, (void**)&parentFolder));
487 if (!parentFolder)
488 {
489 // ShowMessage("Invalid file name");
490 return E_FAIL;
491 }
492
493 pidls.items.ClearAndReserve(operatedIndices.Size());
494 FOR_VECTOR (i, operatedIndices)
495 {
496 LPITEMIDLIST pidl;
497 const UString fileName = GetItemRelPath2(operatedIndices[i]);
498 RINOK(parentFolder->ParseDisplayName(GetParent(), 0,
499 (wchar_t *)(const wchar_t *)fileName, &eaten, &pidl, 0));
500 pidls.items.AddInReserved(pidl);
501 }
502
503 // Get IContextMenu for items
504
505 RINOK(parentFolder->GetUIObjectOf(GetParent(), pidls.items.Size(),
506 (LPCITEMIDLIST *)&pidls.items.Front(), IID_IContextMenu, 0, (void**)&systemContextMenu));
507
508 if (!systemContextMenu)
509 {
510 // ShowMessage("Unable to get context menu interface");
511 return E_FAIL;
512 }
513 return S_OK;
514 }
515
516
CreateSystemMenu(HMENU menuSpec,const CRecordVector<UInt32> & operatedIndices,CMyComPtr<IContextMenu> & systemContextMenu)517 void CPanel::CreateSystemMenu(HMENU menuSpec,
518 const CRecordVector<UInt32> &operatedIndices,
519 CMyComPtr<IContextMenu> &systemContextMenu)
520 {
521 systemContextMenu.Release();
522
523 CreateShellContextMenu(operatedIndices, systemContextMenu);
524
525 if (systemContextMenu == 0)
526 return;
527
528 // Set up a CMINVOKECOMMANDINFO structure.
529 CMINVOKECOMMANDINFO ci;
530 ZeroMemory(&ci, sizeof(ci));
531 ci.cbSize = sizeof(CMINVOKECOMMANDINFO);
532 ci.hwnd = GetParent();
533
534 /*
535 if (Sender == GoBtn)
536 {
537 // Verbs that can be used are cut, paste,
538 // properties, delete, and so on.
539 String action;
540 if (CutRb->Checked)
541 action = "cut";
542 else if (CopyRb->Checked)
543 action = "copy";
544 else if (DeleteRb->Checked)
545 action = "delete";
546 else if (PropertiesRb->Checked)
547 action = "properties";
548
549 ci.lpVerb = action.c_str();
550 result = cm->InvokeCommand(&ci);
551 if (result)
552 ShowMessage(
553 "Error copying file to clipboard.");
554
555 }
556 else
557 */
558 {
559 // HMENU hMenu = CreatePopupMenu();
560 CMenu popupMenu;
561 // CMenuDestroyer menuDestroyer(popupMenu);
562 if (!popupMenu.CreatePopup())
563 throw 210503;
564
565 HMENU hMenu = popupMenu;
566
567 DWORD Flags = CMF_EXPLORE;
568 // Optionally the shell will show the extended
569 // context menu on some operating systems when
570 // the shift key is held down at the time the
571 // context menu is invoked. The following is
572 // commented out but you can uncommnent this
573 // line to show the extended context menu.
574 // Flags |= 0x00000080;
575 systemContextMenu->QueryContextMenu(hMenu, 0, kSystemStartMenuID, 0x7FFF, Flags);
576
577
578 {
579 CMenu menu;
580 menu.Attach(menuSpec);
581 CMenuItem menuItem;
582 menuItem.fMask = MIIM_SUBMENU | MIIM_TYPE | MIIM_ID;
583 menuItem.fType = MFT_STRING;
584 menuItem.hSubMenu = popupMenu.Detach();
585 // menuDestroyer.Disable();
586 LangString(IDS_SYSTEM, menuItem.StringValue);
587 menu.InsertItem(0, true, menuItem);
588 }
589 /*
590 if (Cmd < 100 && Cmd != 0)
591 {
592 ci.lpVerb = MAKEINTRESOURCE(Cmd - 1);
593 ci.lpParameters = "";
594 ci.lpDirectory = "";
595 ci.nShow = SW_SHOWNORMAL;
596 cm->InvokeCommand(&ci);
597 }
598 // If Cmd is > 100 then it's one of our
599 // inserted menu items.
600 else
601 // Find the menu item.
602 for (int i = 0; i < popupMenu1->Items->Count; i++)
603 {
604 TMenuItem* menu = popupMenu1->Items->Items[i];
605 // Call its OnClick handler.
606 if (menu->Command == Cmd - 100)
607 menu->OnClick(this);
608 }
609 // Release the memory allocated for the menu.
610 DestroyMenu(hMenu);
611 */
612 }
613 }
614
CreateFileMenu(HMENU menuSpec)615 void CPanel::CreateFileMenu(HMENU menuSpec)
616 {
617 CreateFileMenu(menuSpec, _sevenZipContextMenu, _systemContextMenu, true);
618 }
619
CreateSevenZipMenu(HMENU menuSpec,const CRecordVector<UInt32> & operatedIndices,CMyComPtr<IContextMenu> & sevenZipContextMenu)620 void CPanel::CreateSevenZipMenu(HMENU menuSpec,
621 const CRecordVector<UInt32> &operatedIndices,
622 CMyComPtr<IContextMenu> &sevenZipContextMenu)
623 {
624 sevenZipContextMenu.Release();
625
626 CMenu menu;
627 menu.Attach(menuSpec);
628 // CMenuDestroyer menuDestroyer(menu);
629 // menu.CreatePopup();
630
631 bool sevenZipMenuCreated = false;
632
633 CZipContextMenu *contextMenuSpec = new CZipContextMenu;
634 CMyComPtr<IContextMenu> contextMenu = contextMenuSpec;
635 // if (contextMenu.CoCreateInstance(CLSID_CZipContextMenu, IID_IContextMenu) == S_OK)
636 {
637 /*
638 CMyComPtr<IInitContextMenu> initContextMenu;
639 if (contextMenu.QueryInterface(IID_IInitContextMenu, &initContextMenu) != S_OK)
640 return;
641 */
642 UString currentFolderUnicode = GetFsPath();
643 UStringVector names;
644 unsigned i;
645 for (i = 0; i < operatedIndices.Size(); i++)
646 names.Add(currentFolderUnicode + GetItemRelPath2(operatedIndices[i]));
647 CRecordVector<const wchar_t *> namePointers;
648 for (i = 0; i < operatedIndices.Size(); i++)
649 namePointers.Add(names[i]);
650
651 // NFile::NDirectory::MySetCurrentDirectory(currentFolderUnicode);
652 if (contextMenuSpec->InitContextMenu(currentFolderUnicode, &namePointers.Front(),
653 operatedIndices.Size()) == S_OK)
654 {
655 HRESULT res = contextMenu->QueryContextMenu(menu, 0, kSevenZipStartMenuID,
656 kSystemStartMenuID - 1, 0);
657 sevenZipMenuCreated = (HRESULT_SEVERITY(res) == SEVERITY_SUCCESS);
658 if (sevenZipMenuCreated)
659 sevenZipContextMenu = contextMenu;
660 // int code = HRESULT_CODE(res);
661 // int nextItemID = code;
662 }
663 }
664 }
665
IsReadOnlyFolder(IFolderFolder * folder)666 static bool IsReadOnlyFolder(IFolderFolder *folder)
667 {
668 if (!folder)
669 return false;
670
671 bool res = false;
672 {
673 NCOM::CPropVariant prop;
674 if (folder->GetFolderProperty(kpidReadOnly, &prop) == S_OK)
675 if (prop.vt == VT_BOOL)
676 res = VARIANT_BOOLToBool(prop.boolVal);
677 }
678 return res;
679 }
680
IsThereReadOnlyFolder() const681 bool CPanel::IsThereReadOnlyFolder() const
682 {
683 if (!_folderOperations)
684 return true;
685 if (IsReadOnlyFolder(_folder))
686 return true;
687 FOR_VECTOR (i, _parentFolders)
688 {
689 if (IsReadOnlyFolder(_parentFolders[i].ParentFolder))
690 return true;
691 }
692 return false;
693 }
694
CheckBeforeUpdate(UINT resourceID)695 bool CPanel::CheckBeforeUpdate(UINT resourceID)
696 {
697 if (!_folderOperations)
698 {
699 MessageBox_Error_UnsupportOperation();
700 // resourceID = resourceID;
701 // MessageBoxErrorForUpdate(E_NOINTERFACE, resourceID);
702 return false;
703 }
704
705 for (int i = (int)_parentFolders.Size(); i >= 0; i--)
706 {
707 IFolderFolder *folder;
708 if (i == (int)_parentFolders.Size())
709 folder = _folder;
710 else
711 folder = _parentFolders[i].ParentFolder;
712
713 if (!IsReadOnlyFolder(folder))
714 continue;
715
716 UString s;
717 AddLangString(s, resourceID);
718 s.Add_LF();
719 AddLangString(s, IDS_OPERATION_IS_NOT_SUPPORTED);
720 s.Add_LF();
721 if (i == 0)
722 s += GetFolderPath(folder);
723 else
724 s += _parentFolders[i - 1].VirtualPath;
725 s.Add_LF();
726 AddLangString(s, IDS_PROP_READ_ONLY);
727 MessageBox_Error(s);
728 return false;
729 }
730
731 return true;
732 }
733
CreateFileMenu(HMENU menuSpec,CMyComPtr<IContextMenu> & sevenZipContextMenu,CMyComPtr<IContextMenu> & systemContextMenu,bool programMenu)734 void CPanel::CreateFileMenu(HMENU menuSpec,
735 CMyComPtr<IContextMenu> &sevenZipContextMenu,
736 CMyComPtr<IContextMenu> &systemContextMenu,
737 bool programMenu)
738 {
739 sevenZipContextMenu.Release();
740 systemContextMenu.Release();
741
742 CRecordVector<UInt32> operatedIndices;
743 GetOperatedItemIndices(operatedIndices);
744
745 CMenu menu;
746 menu.Attach(menuSpec);
747
748 if (!IsArcFolder())
749 {
750 CreateSevenZipMenu(menu, operatedIndices, sevenZipContextMenu);
751 // CreateSystemMenu is very slow if you call it inside ZIP archive with big number of files
752 // Windows probably can parse items inside ZIP archive.
753 if (g_App.ShowSystemMenu)
754 CreateSystemMenu(menu, operatedIndices, systemContextMenu);
755 }
756
757 /*
758 if (menu.GetItemCount() > 0)
759 menu.AppendItem(MF_SEPARATOR, 0, (LPCTSTR)0);
760 */
761
762 unsigned i;
763 for (i = 0; i < operatedIndices.Size(); i++)
764 if (IsItem_Folder(operatedIndices[i]))
765 break;
766 bool allAreFiles = (i == operatedIndices.Size());
767
768 CFileMenu fm;
769
770 fm.readOnly = IsThereReadOnlyFolder();
771 fm.isFsFolder = Is_IO_FS_Folder();
772 fm.programMenu = programMenu;
773 fm.allAreFiles = allAreFiles;
774 fm.numItems = operatedIndices.Size();
775
776 fm.isAltStreamsSupported = false;
777
778 if (_folderAltStreams)
779 {
780 if (operatedIndices.Size() <= 1)
781 {
782 Int32 realIndex = -1;
783 if (operatedIndices.Size() == 1)
784 realIndex = operatedIndices[0];
785 Int32 val = 0;
786 if (_folderAltStreams->AreAltStreamsSupported(realIndex, &val) == S_OK)
787 fm.isAltStreamsSupported = IntToBool(val);
788 }
789 }
790 else
791 {
792 if (fm.numItems == 0)
793 fm.isAltStreamsSupported = IsFSFolder();
794 else
795 fm.isAltStreamsSupported = IsFolder_with_FsItems();
796 }
797
798 fm.Load(menu, menu.GetItemCount());
799 }
800
InvokePluginCommand(int id)801 bool CPanel::InvokePluginCommand(int id)
802 {
803 return InvokePluginCommand(id, _sevenZipContextMenu, _systemContextMenu);
804 }
805
806 #if defined(_MSC_VER) && !defined(UNDER_CE)
807 #define use_CMINVOKECOMMANDINFOEX
808 #endif
809
InvokePluginCommand(int id,IContextMenu * sevenZipContextMenu,IContextMenu * systemContextMenu)810 bool CPanel::InvokePluginCommand(int id,
811 IContextMenu *sevenZipContextMenu, IContextMenu *systemContextMenu)
812 {
813 UInt32 offset;
814 bool isSystemMenu = (id >= kSystemStartMenuID);
815 if (isSystemMenu)
816 offset = id - kSystemStartMenuID;
817 else
818 offset = id - kSevenZipStartMenuID;
819
820 #ifdef use_CMINVOKECOMMANDINFOEX
821 CMINVOKECOMMANDINFOEX
822 #else
823 CMINVOKECOMMANDINFO
824 #endif
825 commandInfo;
826
827 memset(&commandInfo, 0, sizeof(commandInfo));
828 commandInfo.cbSize = sizeof(commandInfo);
829
830 commandInfo.fMask = 0
831 #ifdef use_CMINVOKECOMMANDINFOEX
832 | CMIC_MASK_UNICODE
833 #endif
834 ;
835
836 commandInfo.hwnd = GetParent();
837 commandInfo.lpVerb = (LPCSTR)(MAKEINTRESOURCE(offset));
838 commandInfo.lpParameters = NULL;
839 const CSysString currentFolderSys (GetSystemString(_currentFolderPrefix));
840 commandInfo.lpDirectory = (LPCSTR)(LPCTSTR)(currentFolderSys);
841 commandInfo.nShow = SW_SHOW;
842
843 #ifdef use_CMINVOKECOMMANDINFOEX
844
845 commandInfo.lpParametersW = NULL;
846 commandInfo.lpTitle = "";
847 commandInfo.lpVerbW = (LPCWSTR)(MAKEINTRESOURCEW(offset));
848 UString currentFolderUnicode = _currentFolderPrefix;
849 commandInfo.lpDirectoryW = currentFolderUnicode;
850 commandInfo.lpTitleW = L"";
851 // commandInfo.ptInvoke.x = xPos;
852 // commandInfo.ptInvoke.y = yPos;
853 commandInfo.ptInvoke.x = 0;
854 commandInfo.ptInvoke.y = 0;
855
856 #endif
857
858 HRESULT result;
859 if (isSystemMenu)
860 result = systemContextMenu->InvokeCommand(LPCMINVOKECOMMANDINFO(&commandInfo));
861 else
862 result = sevenZipContextMenu->InvokeCommand(LPCMINVOKECOMMANDINFO(&commandInfo));
863 if (result == NOERROR)
864 {
865 KillSelection();
866 return true;
867 }
868 return false;
869 }
870
OnContextMenu(HANDLE windowHandle,int xPos,int yPos)871 bool CPanel::OnContextMenu(HANDLE windowHandle, int xPos, int yPos)
872 {
873 if (::GetParent((HWND)windowHandle) == _listView)
874 {
875 ShowColumnsContextMenu(xPos, yPos);
876 return true;
877 }
878
879 if (windowHandle != _listView)
880 return false;
881 /*
882 POINT point;
883 point.x = xPos;
884 point.y = yPos;
885 if (!_listView.ScreenToClient(&point))
886 return false;
887
888 LVHITTESTINFO info;
889 info.pt = point;
890 int index = _listView.HitTest(&info);
891 */
892
893 CRecordVector<UInt32> operatedIndices;
894 GetOperatedItemIndices(operatedIndices);
895
896 // negative x,y are possible for multi-screen modes.
897 // x=-1 && y=-1 for keyboard call (SHIFT+F10 and others).
898 if (xPos == -1 && yPos == -1)
899 {
900 if (operatedIndices.Size() == 0)
901 {
902 xPos = 0;
903 yPos = 0;
904 }
905 else
906 {
907 int itemIndex = _listView.GetNextItem(-1, LVNI_FOCUSED);
908 if (itemIndex == -1)
909 return false;
910 RECT rect;
911 if (!_listView.GetItemRect(itemIndex, &rect, LVIR_ICON))
912 return false;
913 xPos = (rect.left + rect.right) / 2;
914 yPos = (rect.top + rect.bottom) / 2;
915 }
916 POINT point = {xPos, yPos};
917 _listView.ClientToScreen(&point);
918 xPos = point.x;
919 yPos = point.y;
920 }
921
922 CMenu menu;
923 CMenuDestroyer menuDestroyer(menu);
924 menu.CreatePopup();
925
926 CMyComPtr<IContextMenu> sevenZipContextMenu;
927 CMyComPtr<IContextMenu> systemContextMenu;
928 CreateFileMenu(menu, sevenZipContextMenu, systemContextMenu, false);
929
930 int result = menu.Track(TPM_LEFTALIGN
931 #ifndef UNDER_CE
932 | TPM_RIGHTBUTTON
933 #endif
934 | TPM_RETURNCMD | TPM_NONOTIFY,
935 xPos, yPos, _listView);
936
937 if (result == 0)
938 return true;
939
940 if (result >= kMenuCmdID_Plugin_Start)
941 {
942 InvokePluginCommand(result, sevenZipContextMenu, systemContextMenu);
943 return true;
944 }
945 if (ExecuteFileCommand(result))
946 return true;
947 return true;
948 }
949