Imported Upstream version 9.20
[platform/upstream/7zip.git] / CPP / 7zip / UI / Explorer / ContextMenu.cpp
1 // ContextMenu.cpp\r
2 \r
3 #include "StdAfx.h"\r
4 \r
5 #include "ContextMenu.h"\r
6 \r
7 #include "Common/StringConvert.h"\r
8 \r
9 #include "Windows/COM.h"\r
10 #include "Windows/FileDir.h"\r
11 #include "Windows/FileFind.h"\r
12 #include "Windows/Memory.h"\r
13 #include "Windows/Menu.h"\r
14 #include "Windows/Process.h"\r
15 #include "Windows/Shell.h"\r
16 \r
17 #include "../Common/ArchiveName.h"\r
18 #include "../Common/CompressCall.h"\r
19 #include "../Common/ExtractingFilePath.h"\r
20 #include "../Common/ZipRegistry.h"\r
21 \r
22 #include "../FileManager/FormatUtils.h"\r
23 #include "../FileManager/ProgramLocation.h"\r
24 \r
25 #ifdef LANG\r
26 #include "../FileManager/LangUtils.h"\r
27 #endif\r
28 \r
29 #include "ContextMenuFlags.h"\r
30 #include "MyMessages.h"\r
31 \r
32 #include "resource.h"\r
33 \r
34 using namespace NWindows;\r
35 \r
36 \r
37 #ifndef UNDER_CE\r
38 #define EMAIL_SUPPORT 1\r
39 #endif\r
40 \r
41 extern LONG g_DllRefCount;\r
42     \r
43 CZipContextMenu::CZipContextMenu()  { InterlockedIncrement(&g_DllRefCount); }\r
44 CZipContextMenu::~CZipContextMenu() { InterlockedDecrement(&g_DllRefCount); }\r
45 \r
46 HRESULT CZipContextMenu::GetFileNames(LPDATAOBJECT dataObject, UStringVector &fileNames)\r
47 {\r
48   #ifndef UNDER_CE\r
49   fileNames.Clear();\r
50   if (dataObject == NULL)\r
51     return E_FAIL;\r
52   FORMATETC fmte = {CF_HDROP, NULL, DVASPECT_CONTENT, -1, TYMED_HGLOBAL};\r
53   NCOM::CStgMedium stgMedium;\r
54   HRESULT result = dataObject->GetData(&fmte, &stgMedium);\r
55   if (result != S_OK)\r
56     return result;\r
57   stgMedium._mustBeReleased = true;\r
58 \r
59   NShell::CDrop drop(false);\r
60   NMemory::CGlobalLock globalLock(stgMedium->hGlobal);\r
61   drop.Attach((HDROP)globalLock.GetPointer());\r
62   drop.QueryFileNames(fileNames);\r
63   #endif\r
64   return S_OK;\r
65 }\r
66 \r
67 // IShellExtInit\r
68 \r
69 STDMETHODIMP CZipContextMenu::Initialize(LPCITEMIDLIST pidlFolder, LPDATAOBJECT dataObject, HKEY /* hkeyProgID */)\r
70 {\r
71   // OutputDebugString(TEXT("::Initialize\r\n"));\r
72   _dropMode = false;\r
73   _dropPath.Empty();\r
74   if (pidlFolder != 0)\r
75   {\r
76     #ifndef UNDER_CE\r
77     if (NShell::GetPathFromIDList(pidlFolder, _dropPath))\r
78     {\r
79       // OutputDebugString(path);\r
80       // OutputDebugString(TEXT("\r\n"));\r
81       NFile::NName::NormalizeDirPathPrefix(_dropPath);\r
82       _dropMode = !_dropPath.IsEmpty();\r
83     }\r
84     else\r
85     #endif\r
86       _dropPath.Empty();\r
87   }\r
88 \r
89   /*\r
90   m_IsFolder = false;\r
91   if (pidlFolder == 0)\r
92   */\r
93   // pidlFolder is NULL :(\r
94   return GetFileNames(dataObject, _fileNames);\r
95 }\r
96 \r
97 HRESULT CZipContextMenu::InitContextMenu(const wchar_t * /* folder */, const wchar_t **names, UInt32 numFiles)\r
98 {\r
99   _fileNames.Clear();\r
100   for (UInt32 i = 0; i < numFiles; i++)\r
101     _fileNames.Add(names[i]);\r
102   _dropMode = false;\r
103   return S_OK;\r
104 }\r
105 \r
106 \r
107 /////////////////////////////\r
108 // IContextMenu\r
109 \r
110 static LPCWSTR kMainVerb = L"SevenZip";\r
111 \r
112 /*\r
113 static LPCTSTR kOpenVerb = TEXT("SevenOpen");\r
114 static LPCTSTR kExtractVerb = TEXT("SevenExtract");\r
115 static LPCTSTR kExtractHereVerb = TEXT("SevenExtractHere");\r
116 static LPCTSTR kExtractToVerb = TEXT("SevenExtractTo");\r
117 static LPCTSTR kTestVerb = TEXT("SevenTest");\r
118 static LPCTSTR kCompressVerb = TEXT("SevenCompress");\r
119 static LPCTSTR kCompressToVerb = TEXT("SevenCompressTo");\r
120 static LPCTSTR kCompressEmailVerb = TEXT("SevenCompressEmail");\r
121 static LPCTSTR kCompressToEmailVerb = TEXT("SevenCompressToEmail");\r
122 */\r
123 \r
124 struct CContextMenuCommand\r
125 {\r
126   UInt32 flag;\r
127   CZipContextMenu::ECommandInternalID CommandInternalID;\r
128   LPCWSTR Verb;\r
129   UINT ResourceID;\r
130   UINT ResourceHelpID;\r
131   UInt32 LangID;\r
132 };\r
133 \r
134 static CContextMenuCommand g_Commands[] =\r
135 {\r
136   {\r
137     NContextMenuFlags::kOpen,\r
138     CZipContextMenu::kOpen,\r
139     L"Open",\r
140     IDS_CONTEXT_OPEN,\r
141     IDS_CONTEXT_OPEN_HELP,\r
142     0x02000103\r
143   },\r
144   {\r
145     NContextMenuFlags::kExtract,\r
146     CZipContextMenu::kExtract,\r
147     L"Extract",\r
148     IDS_CONTEXT_EXTRACT,\r
149     IDS_CONTEXT_EXTRACT_HELP,\r
150     0x02000105\r
151   },\r
152   {\r
153     NContextMenuFlags::kExtractHere,\r
154     CZipContextMenu::kExtractHere,\r
155     L"ExtractHere",\r
156     IDS_CONTEXT_EXTRACT_HERE,\r
157     IDS_CONTEXT_EXTRACT_HERE_HELP,\r
158     0x0200010B\r
159   },\r
160   {\r
161     NContextMenuFlags::kExtractTo,\r
162     CZipContextMenu::kExtractTo,\r
163     L"ExtractTo",\r
164     IDS_CONTEXT_EXTRACT_TO,\r
165     IDS_CONTEXT_EXTRACT_TO_HELP,\r
166     0x0200010D\r
167   },\r
168   {\r
169     NContextMenuFlags::kTest,\r
170     CZipContextMenu::kTest,\r
171     L"Test",\r
172     IDS_CONTEXT_TEST,\r
173     IDS_CONTEXT_TEST_HELP,\r
174     0x02000109\r
175   },\r
176   {\r
177     NContextMenuFlags::kCompress,\r
178     CZipContextMenu::kCompress,\r
179     L"Compress",\r
180     IDS_CONTEXT_COMPRESS,\r
181     IDS_CONTEXT_COMPRESS_HELP,\r
182     0x02000107,\r
183   },\r
184   {\r
185     NContextMenuFlags::kCompressEmail,\r
186     CZipContextMenu::kCompressEmail,\r
187     L"CompressEmail",\r
188     IDS_CONTEXT_COMPRESS_EMAIL,\r
189     IDS_CONTEXT_COMPRESS_EMAIL_HELP,\r
190     0x02000111\r
191   },\r
192   {\r
193     NContextMenuFlags::kCompressTo7z,\r
194     CZipContextMenu::kCompressTo7z,\r
195     L"CompressTo7z",\r
196     IDS_CONTEXT_COMPRESS_TO,\r
197     IDS_CONTEXT_COMPRESS_TO_HELP,\r
198     0x0200010F\r
199   },\r
200   {\r
201     NContextMenuFlags::kCompressTo7zEmail,\r
202     CZipContextMenu::kCompressTo7zEmail,\r
203     L"CompressTo7zEmail",\r
204     IDS_CONTEXT_COMPRESS_TO_EMAIL,\r
205     IDS_CONTEXT_COMPRESS_TO_EMAIL_HELP,\r
206     0x02000113\r
207   },\r
208   {\r
209     NContextMenuFlags::kCompressToZip,\r
210     CZipContextMenu::kCompressToZip,\r
211     L"CompressToZip",\r
212     IDS_CONTEXT_COMPRESS_TO,\r
213     IDS_CONTEXT_COMPRESS_TO_HELP,\r
214     0x0200010F\r
215   },\r
216   {\r
217     NContextMenuFlags::kCompressToZipEmail,\r
218     CZipContextMenu::kCompressToZipEmail,\r
219     L"CompressToZipEmail",\r
220     IDS_CONTEXT_COMPRESS_TO_EMAIL,\r
221     IDS_CONTEXT_COMPRESS_TO_EMAIL_HELP,\r
222     0x02000113\r
223   }\r
224 };\r
225 \r
226 static int FindCommand(CZipContextMenu::ECommandInternalID &id)\r
227 {\r
228   for (int i = 0; i < sizeof(g_Commands) / sizeof(g_Commands[0]); i++)\r
229     if (g_Commands[i].CommandInternalID == id)\r
230       return i;\r
231   return -1;\r
232 }\r
233 \r
234 void CZipContextMenu::FillCommand(ECommandInternalID id, UString &mainString, CCommandMapItem &commandMapItem)\r
235 {\r
236   int i = FindCommand(id);\r
237   if (i < 0)\r
238     return;\r
239   const CContextMenuCommand &command = g_Commands[i];\r
240   commandMapItem.CommandInternalID = command.CommandInternalID;\r
241   commandMapItem.Verb = (UString)kMainVerb + (UString)command.Verb;\r
242   commandMapItem.HelpString = LangString(command.ResourceHelpID, command.LangID + 1);\r
243   mainString = LangString(command.ResourceID, command.LangID);\r
244 }\r
245 \r
246 static bool MyInsertMenu(CMenu &menu, int pos, UINT id, const UString &s)\r
247 {\r
248   CMenuItem menuItem;\r
249   menuItem.fType = MFT_STRING;\r
250   menuItem.fMask = MIIM_TYPE | MIIM_ID;\r
251   menuItem.wID = id;\r
252   menuItem.StringValue = s;\r
253   return menu.InsertItem(pos, true, menuItem);\r
254 }\r
255 \r
256 static const wchar_t *kArcExts[] =\r
257 {\r
258   L"7z",\r
259   L"bz2",\r
260   L"gz",\r
261   L"rar",\r
262   L"zip"\r
263 };\r
264 \r
265 static bool IsItArcExt(const UString &ext2)\r
266 {\r
267   UString ext = ext2;\r
268   ext.MakeLower();\r
269   for (int i = 0; i < sizeof(kArcExts) / sizeof(kArcExts[0]); i++)\r
270     if (ext.Compare(kArcExts[i]) == 0)\r
271       return true;\r
272   return false;\r
273 }\r
274 \r
275 static UString GetSubFolderNameForExtract(const UString &archiveName)\r
276 {\r
277   int dotPos = archiveName.ReverseFind(L'.');\r
278   if (dotPos < 0)\r
279     return archiveName + UString(L"~");\r
280   const UString ext = archiveName.Mid(dotPos + 1);\r
281   UString res = archiveName.Left(dotPos);\r
282   res.TrimRight();\r
283   dotPos = res.ReverseFind(L'.');\r
284   if (dotPos > 0)\r
285   {\r
286     const UString ext2 = res.Mid(dotPos + 1);\r
287     if (ext.CompareNoCase(L"rar") == 0 &&\r
288         (ext2.CompareNoCase(L"part001") == 0 ||\r
289          ext2.CompareNoCase(L"part01") == 0 ||\r
290          ext2.CompareNoCase(L"part1") == 0) ||\r
291         IsItArcExt(ext2) && ext.CompareNoCase(L"001") == 0)\r
292       res = res.Left(dotPos);\r
293     res.TrimRight();\r
294   }\r
295   return GetCorrectFullFsPath(res);\r
296 }\r
297 \r
298 static UString GetReducedString(const UString &s)\r
299 {\r
300   const int kMaxSize = 64;\r
301   if (s.Length() < kMaxSize)\r
302     return s;\r
303   const int kFirstPartSize = kMaxSize / 2;\r
304   return s.Left(kFirstPartSize) + UString(L" ... ") + s.Right(kMaxSize - kFirstPartSize);\r
305 }\r
306 \r
307 static UString GetQuotedReducedString(const UString &s)\r
308 {\r
309   UString s2 = GetReducedString(s);\r
310   s2.Replace(L"&", L"&&");\r
311   return GetQuotedString(s2);\r
312 }\r
313 \r
314 static const char *kExtractExludeExtensions =\r
315   " 3gp"\r
316   " aac ans ape asc asm asp aspx avi awk"\r
317   " bas bat bmp"\r
318   " c cs cls clw cmd cpp csproj css ctl cxx"\r
319   " def dep dlg dsp dsw"\r
320   " eps"\r
321   " f f77 f90 f95 fla flac frm"\r
322   " gif"\r
323   " h hpp hta htm html hxx"\r
324   " ico idl inc ini inl"\r
325   " java jpeg jpg js"\r
326   " la"\r
327   " mak manifest wmv mov mp3 mp4 mpe mpeg mpg m4a"\r
328   " ofr ogg"\r
329   " pac pas pdf php php3 php4 php5 phptml pl pm png ps py pyo"\r
330   " ra rb rc reg rka rm rtf"\r
331   " sed sh shn shtml sln sql srt swa"\r
332   " tcl tex tiff tta txt"\r
333   " vb vcproj vbs"\r
334   " wav wma wv"\r
335   " xml xsd xsl xslt"\r
336   " ";\r
337 \r
338 static const char *kNoOpenAsExtensions =\r
339   " 7z arj bz2 cab chm cpio dmg flv gz lha lzh lzma rar swm tar tbz2 tgz wim xar xz z zip ";\r
340 \r
341 static bool FindExt(const char *p, const UString &name)\r
342 {\r
343   int extPos = name.ReverseFind('.');\r
344   if (extPos < 0)\r
345     return false;\r
346   UString ext = name.Mid(extPos + 1);\r
347   ext.MakeLower();\r
348   AString ext2 = UnicodeStringToMultiByte(ext);\r
349   for (int i = 0; p[i] != 0;)\r
350   {\r
351     int j;\r
352     for (j = i; p[j] != ' '; j++);\r
353     if (ext2.Length() == j - i && memcmp(p + i, (const char *)ext2, ext2.Length()) == 0)\r
354       return true;\r
355     i = j + 1;\r
356   }\r
357   return false;\r
358 }\r
359 \r
360 static bool DoNeedExtract(const UString &name)\r
361 {\r
362   return !FindExt(kExtractExludeExtensions, name);\r
363 }\r
364 \r
365 STDMETHODIMP CZipContextMenu::QueryContextMenu(HMENU hMenu, UINT indexMenu,\r
366       UINT commandIDFirst, UINT commandIDLast, UINT flags)\r
367 {\r
368   LoadLangOneTime();\r
369   if (_fileNames.Size() == 0)\r
370     return E_FAIL;\r
371   UINT currentCommandID = commandIDFirst;\r
372   if ((flags & 0x000F) != CMF_NORMAL  &&\r
373       (flags & CMF_VERBSONLY) == 0 &&\r
374       (flags & CMF_EXPLORE) == 0)\r
375     return MAKE_HRESULT(SEVERITY_SUCCESS, 0, currentCommandID);\r
376 \r
377   _commandMap.Clear();\r
378 \r
379   CMenu popupMenu;\r
380   CMenuDestroyer menuDestroyer;\r
381 \r
382   CContextMenuInfo ci;\r
383   ci.Load();\r
384   MENUITEMINFO menuItem;\r
385   UINT subIndex = indexMenu;\r
386   if (ci.Cascaded)\r
387   {\r
388     CCommandMapItem commandMapItem;\r
389     if (!popupMenu.CreatePopup())\r
390       return E_FAIL;\r
391     menuDestroyer.Attach(popupMenu);\r
392     commandMapItem.CommandInternalID = kCommandNULL;\r
393     commandMapItem.Verb = kMainVerb;\r
394     commandMapItem.HelpString = LangString(IDS_CONTEXT_CAPTION_HELP, 0x02000102);\r
395     _commandMap.Add(commandMapItem);\r
396     \r
397     menuItem.wID = currentCommandID++;\r
398     subIndex = 0;\r
399   }\r
400   else\r
401   {\r
402     popupMenu.Attach(hMenu);\r
403   }\r
404 \r
405   UInt32 contextMenuFlags = ci.Flags;\r
406 \r
407   UString mainString;\r
408   if (_fileNames.Size() == 1 && currentCommandID + 6 <= commandIDLast)\r
409   {\r
410     const UString &fileName = _fileNames.Front();\r
411     UString folderPrefix;\r
412     NFile::NDirectory::GetOnlyDirPrefix(fileName, folderPrefix);\r
413    \r
414     NFile::NFind::CFileInfoW fileInfo;\r
415     if (!fileInfo.Find(fileName))\r
416       return E_FAIL;\r
417     if (!fileInfo.IsDir() && DoNeedExtract(fileInfo.Name))\r
418     {\r
419       // Open\r
420       bool thereIsMainOpenItem = ((contextMenuFlags & NContextMenuFlags::kOpen) != 0);\r
421       if (thereIsMainOpenItem)\r
422       {\r
423         CCommandMapItem commandMapItem;\r
424         FillCommand(kOpen, mainString, commandMapItem);\r
425         MyInsertMenu(popupMenu, subIndex++, currentCommandID++, mainString);\r
426         _commandMap.Add(commandMapItem);\r
427       }\r
428       if ((contextMenuFlags & NContextMenuFlags::kOpenAs) != 0 &&\r
429           (!thereIsMainOpenItem || !FindExt(kNoOpenAsExtensions, fileInfo.Name)))\r
430       {\r
431         CMenu subMenu;\r
432         if (subMenu.CreatePopup())\r
433         {\r
434           CCommandMapItem commandMapItem;\r
435           \r
436           CMenuItem menuItem;\r
437           menuItem.fType = MFT_STRING;\r
438           menuItem.fMask = MIIM_SUBMENU | MIIM_TYPE | MIIM_ID;\r
439           menuItem.wID = currentCommandID++;\r
440           menuItem.hSubMenu = subMenu;\r
441           menuItem.StringValue = LangString(IDS_CONTEXT_OPEN, 0x02000103);\r
442           popupMenu.InsertItem(subIndex++, true, menuItem);\r
443           \r
444           commandMapItem.CommandInternalID = kCommandNULL;\r
445           commandMapItem.Verb = kMainVerb;\r
446           commandMapItem.HelpString = LangString(IDS_CONTEXT_OPEN_HELP, 0x02000104);\r
447           _commandMap.Add(commandMapItem);\r
448           \r
449           UINT subIndex2 = 0;\r
450           const wchar_t *exts[] = { L"", L"*", L"7z", L"zip", L"cab", L"rar" };\r
451           for (int i = (thereIsMainOpenItem ? 1 : 0); i < sizeof(exts) / sizeof(exts[0]); i++)\r
452           {\r
453             CCommandMapItem commandMapItem;\r
454             if (i == 0)\r
455               FillCommand(kOpen, mainString, commandMapItem);\r
456             else\r
457             {\r
458               mainString = exts[i];\r
459               commandMapItem.CommandInternalID = kOpen;\r
460               commandMapItem.Verb = (UString)kMainVerb + L".Open." + mainString;\r
461               commandMapItem.HelpString = mainString;\r
462               commandMapItem.ArcType = mainString;\r
463             }\r
464             MyInsertMenu(subMenu, subIndex2++, currentCommandID++, mainString);\r
465             _commandMap.Add(commandMapItem);\r
466           }\r
467           subMenu.Detach();\r
468         }\r
469       }\r
470     }\r
471   }\r
472 \r
473   if (_fileNames.Size() > 0 && currentCommandID + 10 <= commandIDLast)\r
474   {\r
475     bool needExtract = false;\r
476     for(int i = 0; i < _fileNames.Size(); i++)\r
477     {\r
478       NFile::NFind::CFileInfoW fileInfo;\r
479       if (!fileInfo.Find(_fileNames[i]))\r
480         return E_FAIL;\r
481       if (!fileInfo.IsDir() && DoNeedExtract(fileInfo.Name))\r
482         needExtract = true;\r
483     }\r
484     const UString &fileName = _fileNames.Front();\r
485     if (needExtract)\r
486     {\r
487       UString folderPrefix;\r
488       NFile::NDirectory::GetOnlyDirPrefix(fileName, folderPrefix);\r
489       NFile::NFind::CFileInfoW fileInfo;\r
490       if (!fileInfo.Find(fileName))\r
491         return E_FAIL;\r
492       // Extract\r
493       if ((contextMenuFlags & NContextMenuFlags::kExtract) != 0)\r
494       {\r
495         CCommandMapItem commandMapItem;\r
496         FillCommand(kExtract, mainString, commandMapItem);\r
497         if (_dropMode)\r
498           commandMapItem.Folder = _dropPath;\r
499         else\r
500           commandMapItem.Folder = folderPrefix;\r
501         commandMapItem.Folder += GetSubFolderNameForExtract(fileInfo.Name) + UString(WCHAR_PATH_SEPARATOR);\r
502         MyInsertMenu(popupMenu, subIndex++, currentCommandID++, mainString);\r
503         _commandMap.Add(commandMapItem);\r
504       }\r
505 \r
506       // Extract Here\r
507       if ((contextMenuFlags & NContextMenuFlags::kExtractHere) != 0)\r
508       {\r
509         CCommandMapItem commandMapItem;\r
510         FillCommand(kExtractHere, mainString, commandMapItem);\r
511         MyInsertMenu(popupMenu, subIndex++, currentCommandID++, mainString);\r
512         if (_dropMode)\r
513           commandMapItem.Folder = _dropPath;\r
514         else\r
515           commandMapItem.Folder = folderPrefix;\r
516         _commandMap.Add(commandMapItem);\r
517       }\r
518 \r
519       // Extract To\r
520       if ((contextMenuFlags & NContextMenuFlags::kExtractTo) != 0)\r
521       {\r
522         CCommandMapItem commandMapItem;\r
523         UString s;\r
524         FillCommand(kExtractTo, s, commandMapItem);\r
525         UString folder;\r
526         if (_fileNames.Size() == 1)\r
527           folder = GetSubFolderNameForExtract(fileInfo.Name);\r
528         else\r
529           folder = L'*';\r
530         if (_dropMode)\r
531           commandMapItem.Folder = _dropPath;\r
532         else\r
533           commandMapItem.Folder = folderPrefix;\r
534         commandMapItem.Folder += folder;\r
535         s = MyFormatNew(s, GetQuotedReducedString(folder + UString(WCHAR_PATH_SEPARATOR)));\r
536         MyInsertMenu(popupMenu, subIndex++, currentCommandID++, s);\r
537         _commandMap.Add(commandMapItem);\r
538       }\r
539       // Test\r
540       if ((contextMenuFlags & NContextMenuFlags::kTest) != 0)\r
541       {\r
542         CCommandMapItem commandMapItem;\r
543         FillCommand(kTest, mainString, commandMapItem);\r
544         MyInsertMenu(popupMenu, subIndex++, currentCommandID++, mainString);\r
545         _commandMap.Add(commandMapItem);\r
546       }\r
547     }\r
548     UString archiveName = CreateArchiveName(fileName, _fileNames.Size() > 1, false);\r
549     UString archiveName7z = archiveName + L".7z";\r
550     UString archiveNameZip = archiveName + L".zip";\r
551     UString archivePathPrefix;\r
552     NFile::NDirectory::GetOnlyDirPrefix(fileName, archivePathPrefix);\r
553 \r
554     // Compress\r
555     if ((contextMenuFlags & NContextMenuFlags::kCompress) != 0)\r
556     {\r
557       CCommandMapItem commandMapItem;\r
558       if (_dropMode)\r
559         commandMapItem.Folder = _dropPath;\r
560       else\r
561         commandMapItem.Folder = archivePathPrefix;\r
562       commandMapItem.ArcName = archiveName;\r
563       FillCommand(kCompress, mainString, commandMapItem);\r
564       MyInsertMenu(popupMenu, subIndex++, currentCommandID++, mainString);\r
565       _commandMap.Add(commandMapItem);\r
566     }\r
567 \r
568     #ifdef EMAIL_SUPPORT\r
569     // CompressEmail\r
570     if ((contextMenuFlags & NContextMenuFlags::kCompressEmail) != 0 && !_dropMode)\r
571     {\r
572       CCommandMapItem commandMapItem;\r
573       commandMapItem.ArcName = archiveName;\r
574       FillCommand(kCompressEmail, mainString, commandMapItem);\r
575       MyInsertMenu(popupMenu, subIndex++, currentCommandID++, mainString);\r
576       _commandMap.Add(commandMapItem);\r
577     }\r
578     #endif\r
579 \r
580     // CompressTo7z\r
581     if (contextMenuFlags & NContextMenuFlags::kCompressTo7z)\r
582     {\r
583       CCommandMapItem commandMapItem;\r
584       UString s;\r
585       FillCommand(kCompressTo7z, s, commandMapItem);\r
586       if (_dropMode)\r
587         commandMapItem.Folder = _dropPath;\r
588       else\r
589         commandMapItem.Folder = archivePathPrefix;\r
590       commandMapItem.ArcName = archiveName7z;\r
591       commandMapItem.ArcType = L"7z";\r
592       s = MyFormatNew(s, GetQuotedReducedString(archiveName7z));\r
593       MyInsertMenu(popupMenu, subIndex++, currentCommandID++, s);\r
594       _commandMap.Add(commandMapItem);\r
595     }\r
596 \r
597     #ifdef EMAIL_SUPPORT\r
598     // CompressTo7zEmail\r
599     if ((contextMenuFlags & NContextMenuFlags::kCompressTo7zEmail) != 0  && !_dropMode)\r
600     {\r
601       CCommandMapItem commandMapItem;\r
602       UString s;\r
603       FillCommand(kCompressTo7zEmail, s, commandMapItem);\r
604       commandMapItem.ArcName = archiveName7z;\r
605       commandMapItem.ArcType = L"7z";\r
606       s = MyFormatNew(s, GetQuotedReducedString(archiveName7z));\r
607       MyInsertMenu(popupMenu, subIndex++, currentCommandID++, s);\r
608       _commandMap.Add(commandMapItem);\r
609     }\r
610     #endif\r
611 \r
612     // CompressToZip\r
613     if (contextMenuFlags & NContextMenuFlags::kCompressToZip)\r
614     {\r
615       CCommandMapItem commandMapItem;\r
616       UString s;\r
617       FillCommand(kCompressToZip, s, commandMapItem);\r
618       if (_dropMode)\r
619         commandMapItem.Folder = _dropPath;\r
620       else\r
621         commandMapItem.Folder = archivePathPrefix;\r
622       commandMapItem.ArcName = archiveNameZip;\r
623       commandMapItem.ArcType = L"zip";\r
624       s = MyFormatNew(s, GetQuotedReducedString(archiveNameZip));\r
625       MyInsertMenu(popupMenu, subIndex++, currentCommandID++, s);\r
626       _commandMap.Add(commandMapItem);\r
627     }\r
628 \r
629     #ifdef EMAIL_SUPPORT\r
630     // CompressToZipEmail\r
631     if ((contextMenuFlags & NContextMenuFlags::kCompressToZipEmail) != 0  && !_dropMode)\r
632     {\r
633       CCommandMapItem commandMapItem;\r
634       UString s;\r
635       FillCommand(kCompressToZipEmail, s, commandMapItem);\r
636       commandMapItem.ArcName = archiveNameZip;\r
637       commandMapItem.ArcType = L"zip";\r
638       s = MyFormatNew(s, GetQuotedReducedString(archiveNameZip));\r
639       MyInsertMenu(popupMenu, subIndex++, currentCommandID++, s);\r
640       _commandMap.Add(commandMapItem);\r
641     }\r
642     #endif\r
643   }\r
644 \r
645 \r
646   // don't use InsertMenu:  See MSDN:\r
647   // PRB: Duplicate Menu Items In the File Menu For a Shell Context Menu Extension\r
648   // ID: Q214477\r
649 \r
650   if (ci.Cascaded)\r
651   {\r
652     CMenuItem menuItem;\r
653     menuItem.fType = MFT_STRING;\r
654     menuItem.fMask = MIIM_SUBMENU | MIIM_TYPE | MIIM_ID;\r
655     menuItem.wID = currentCommandID++;\r
656     menuItem.hSubMenu = popupMenu.Detach();\r
657     menuDestroyer.Disable();\r
658     menuItem.StringValue = LangString(IDS_CONTEXT_POPUP_CAPTION, 0x02000101);\r
659     CMenu menu;\r
660     menu.Attach(hMenu);\r
661     menu.InsertItem(indexMenu++, true, menuItem);\r
662   }\r
663 \r
664   return MAKE_HRESULT(SEVERITY_SUCCESS, 0, currentCommandID - commandIDFirst);\r
665 }\r
666 \r
667 \r
668 int CZipContextMenu::FindVerb(const UString &verb)\r
669 {\r
670   for(int i = 0; i < _commandMap.Size(); i++)\r
671     if (_commandMap[i].Verb.Compare(verb) == 0)\r
672       return i;\r
673   return -1;\r
674 }\r
675 \r
676 static UString Get7zFmPath()\r
677 {\r
678   UString path;\r
679   GetProgramFolderPath(path);\r
680   return path + L"7zFM.exe";\r
681 }\r
682 \r
683 STDMETHODIMP CZipContextMenu::InvokeCommand(LPCMINVOKECOMMANDINFO commandInfo)\r
684 {\r
685   // ::OutputDebugStringA("1");\r
686   int commandOffset;\r
687 \r
688   // It's fix for bug: crashing in XP. See example in MSDN: "Creating Context Menu Handlers".\r
689 \r
690   #ifndef UNDER_CE\r
691   if (commandInfo->cbSize == sizeof(CMINVOKECOMMANDINFOEX) &&\r
692       (commandInfo->fMask & CMIC_MASK_UNICODE) != 0)\r
693   {\r
694     LPCMINVOKECOMMANDINFOEX commandInfoEx = (LPCMINVOKECOMMANDINFOEX)commandInfo;\r
695     if (HIWORD(commandInfoEx->lpVerbW) == 0)\r
696       commandOffset = LOWORD(commandInfo->lpVerb);\r
697     else\r
698       commandOffset = FindVerb(commandInfoEx->lpVerbW);\r
699   }\r
700   else\r
701   #endif\r
702     if (HIWORD(commandInfo->lpVerb) == 0)\r
703       commandOffset = LOWORD(commandInfo->lpVerb);\r
704     else\r
705       commandOffset = FindVerb(GetUnicodeString(commandInfo->lpVerb));\r
706 \r
707   if (commandOffset < 0 || commandOffset >= _commandMap.Size())\r
708     return E_FAIL;\r
709 \r
710   const CCommandMapItem commandMapItem = _commandMap[commandOffset];\r
711   ECommandInternalID cmdID = commandMapItem.CommandInternalID;\r
712 \r
713   try\r
714   {\r
715     switch(cmdID)\r
716     {\r
717       case kOpen:\r
718       {\r
719         UString params;\r
720         params = GetQuotedString(_fileNames[0]);\r
721         if (commandMapItem.ArcType)\r
722         {\r
723           params += L" -t";\r
724           params += commandMapItem.ArcType;\r
725         }\r
726         MyCreateProcess(Get7zFmPath(), params);\r
727         break;\r
728       }\r
729       case kExtract:\r
730       case kExtractHere:\r
731       case kExtractTo:\r
732       {\r
733         ExtractArchives(_fileNames, commandMapItem.Folder, (cmdID == kExtract));\r
734         break;\r
735       }\r
736       case kTest:\r
737       {\r
738         TestArchives(_fileNames);\r
739         break;\r
740       }\r
741       case kCompress:\r
742       case kCompressEmail:\r
743       case kCompressTo7z:\r
744       case kCompressTo7zEmail:\r
745       case kCompressToZip:\r
746       case kCompressToZipEmail:\r
747       {\r
748         bool email =\r
749             (cmdID == kCompressEmail) ||\r
750             (cmdID == kCompressTo7zEmail) ||\r
751             (cmdID == kCompressToZipEmail);\r
752         bool showDialog =\r
753             (cmdID == kCompress) ||\r
754             (cmdID == kCompressEmail);\r
755         CompressFiles(commandMapItem.Folder,\r
756             commandMapItem.ArcName, commandMapItem.ArcType,\r
757             _fileNames, email, showDialog, false);\r
758         break;\r
759       }\r
760     }\r
761   }\r
762   catch(...)\r
763   {\r
764     ::MessageBoxW(0, L"Error", L"7-Zip", MB_ICONERROR);\r
765   }\r
766   return S_OK;\r
767 }\r
768 \r
769 static void MyCopyString(void *dest, const wchar_t *src, bool writeInUnicode)\r
770 {\r
771   if (writeInUnicode)\r
772   {\r
773     MyStringCopy((wchar_t *)dest, src);\r
774   }\r
775   else\r
776     MyStringCopy((char *)dest, (const char *)GetAnsiString(src));\r
777 }\r
778 \r
779 STDMETHODIMP CZipContextMenu::GetCommandString(UINT_PTR commandOffset, UINT uType,\r
780     UINT * /* pwReserved */ , LPSTR pszName, UINT /* cchMax */)\r
781 {\r
782   int cmdOffset = (int)commandOffset;\r
783   switch(uType)\r
784   {\r
785     #ifdef UNDER_CE\r
786     case GCS_VALIDATE:\r
787     #else\r
788     case GCS_VALIDATEA:\r
789     case GCS_VALIDATEW:\r
790     #endif\r
791       if (cmdOffset < 0 || cmdOffset >= _commandMap.Size())\r
792         return S_FALSE;\r
793       else\r
794         return S_OK;\r
795   }\r
796   if (cmdOffset < 0 || cmdOffset >= _commandMap.Size())\r
797     return E_FAIL;\r
798   #ifdef UNDER_CE\r
799   if (uType == GCS_HELPTEXT)\r
800   #else\r
801   if (uType == GCS_HELPTEXTA || uType == GCS_HELPTEXTW)\r
802   #endif\r
803   {\r
804     MyCopyString(pszName, _commandMap[cmdOffset].HelpString,\r
805       #ifdef UNDER_CE\r
806       true\r
807       #else\r
808       uType == GCS_HELPTEXTW\r
809       #endif\r
810       );\r
811     return NO_ERROR;\r
812   }\r
813   #ifdef UNDER_CE\r
814   if (uType == GCS_VERB)\r
815   #else\r
816   if (uType == GCS_VERBA || uType == GCS_VERBW)\r
817   #endif\r
818   {\r
819     MyCopyString(pszName, _commandMap[cmdOffset].Verb,\r
820       #ifdef UNDER_CE\r
821       true\r
822       #else\r
823       uType == GCS_VERBW\r
824       #endif\r
825       );\r
826     return NO_ERROR;\r
827   }\r
828   return E_FAIL;\r
829 }\r