Imported Upstream version 9.20
[platform/upstream/7zip.git] / CPP / 7zip / UI / FileManager / PanelItemOpen.cpp
1 // PanelItemOpen.cpp\r
2 \r
3 #include "StdAfx.h"\r
4 \r
5 #include "Common/AutoPtr.h"\r
6 #include "Common/StringConvert.h"\r
7 \r
8 #include "Windows/Error.h"\r
9 #include "Windows/FileDir.h"\r
10 #include "Windows/FileFind.h"\r
11 #include "Windows/Process.h"\r
12 #include "Windows/PropVariant.h"\r
13 #include "Windows/Thread.h"\r
14 \r
15 #include "../Common/ExtractingFilePath.h"\r
16 \r
17 #include "App.h"\r
18 \r
19 #include "FileFolderPluginOpen.h"\r
20 #include "FormatUtils.h"\r
21 #include "LangUtils.h"\r
22 #include "RegistryUtils.h"\r
23 #include "UpdateCallback100.h"\r
24 \r
25 #include "resource.h"\r
26 \r
27 using namespace NWindows;\r
28 using namespace NSynchronization;\r
29 using namespace NFile;\r
30 using namespace NDirectory;\r
31 \r
32 #ifndef _UNICODE\r
33 extern bool g_IsNT;\r
34 #endif\r
35 \r
36 static wchar_t *kTempDirPrefix = L"7zO";\r
37 \r
38 \r
39 static bool IsNameVirus(const UString &name)\r
40 {\r
41   return (name.Find(L"     ") >= 0);\r
42 }\r
43 \r
44 struct CTmpProcessInfo: public CTempFileInfo\r
45 {\r
46   HANDLE ProcessHandle;\r
47   HWND Window;\r
48   UString FullPathFolderPrefix;\r
49   bool UsePassword;\r
50   UString Password;\r
51   CTmpProcessInfo(): UsePassword(false) {}\r
52 };\r
53 \r
54 class CTmpProcessInfoRelease\r
55 {\r
56   CTmpProcessInfo *_tmpProcessInfo;\r
57 public:\r
58   bool _needDelete;\r
59   CTmpProcessInfoRelease(CTmpProcessInfo &tmpProcessInfo):\r
60       _tmpProcessInfo(&tmpProcessInfo), _needDelete(true) {}\r
61   ~CTmpProcessInfoRelease()\r
62   {\r
63     if (_needDelete)\r
64       _tmpProcessInfo->DeleteDirAndFile();\r
65   }\r
66 };\r
67 \r
68 HRESULT CPanel::OpenItemAsArchive(IInStream *inStream,\r
69     const CTempFileInfo &tempFileInfo,\r
70     const UString &virtualFilePath,\r
71     const UString &arcFormat,\r
72     bool &encrypted)\r
73 {\r
74   encrypted = false;\r
75   CFolderLink folderLink;\r
76   (CTempFileInfo &)folderLink = tempFileInfo;\r
77   if (inStream)\r
78     folderLink.IsVirtual = true;\r
79   else\r
80   {\r
81     if (!folderLink.FileInfo.Find(folderLink.FilePath))\r
82       return ::GetLastError();\r
83     if (folderLink.FileInfo.IsDir())\r
84       return S_FALSE;\r
85     folderLink.IsVirtual = false;\r
86   }\r
87 \r
88   folderLink.VirtualPath = virtualFilePath;\r
89 \r
90   CMyComPtr<IFolderFolder> newFolder;\r
91 \r
92   // _passwordIsDefined = false;\r
93   // _password.Empty();\r
94 \r
95   NDLL::CLibrary library;\r
96 \r
97   UString password;\r
98   RINOK(OpenFileFolderPlugin(inStream,\r
99       folderLink.FilePath.IsEmpty() ? virtualFilePath : folderLink.FilePath,\r
100       arcFormat,\r
101       &library, &newFolder, GetParent(), encrypted, password));\r
102  \r
103   folderLink.Password = password;\r
104   folderLink.UsePassword = encrypted;\r
105 \r
106   folderLink.ParentFolder = _folder;\r
107   _parentFolders.Add(folderLink);\r
108   _parentFolders.Back().Library.Attach(_library.Detach());\r
109 \r
110   _folder.Release();\r
111   _library.Free();\r
112   _folder = newFolder;\r
113   _library.Attach(library.Detach());\r
114 \r
115   _flatMode = _flatModeForArc;\r
116 \r
117   CMyComPtr<IGetFolderArcProps> getFolderArcProps;\r
118   _folder.QueryInterface(IID_IGetFolderArcProps, &getFolderArcProps);\r
119   if (getFolderArcProps)\r
120   {\r
121     CMyComPtr<IFolderArcProps> arcProps;\r
122     getFolderArcProps->GetFolderArcProps(&arcProps);\r
123     if (arcProps)\r
124     {\r
125       UString s;\r
126       UInt32 numLevels;\r
127       if (arcProps->GetArcNumLevels(&numLevels) != S_OK)\r
128         numLevels = 0;\r
129       for (UInt32 level2 = 0; level2 < numLevels; level2++)\r
130       {\r
131         UInt32 level = numLevels - 1 - level2;\r
132         PROPID propIDs[] = { kpidError, kpidPath, kpidType } ;\r
133         UString values[3];\r
134         for (Int32 i = 0; i < 3; i++)\r
135         {\r
136           CMyComBSTR name;\r
137           NCOM::CPropVariant prop;\r
138           if (arcProps->GetArcProp(level, propIDs[i], &prop) != S_OK)\r
139             continue;\r
140           if (prop.vt != VT_EMPTY)\r
141             values[i] = (prop.vt == VT_BSTR) ? prop.bstrVal : L"?";\r
142         }\r
143         if (!values[0].IsEmpty())\r
144         {\r
145           if (!s.IsEmpty())\r
146             s += L"--------------------\n";\r
147           s += values[0]; s += L"\n\n[";\r
148           s += values[2]; s += L"] ";\r
149           s += values[1]; s += L"\n";\r
150         }\r
151       }\r
152       if (!s.IsEmpty())\r
153         MessageBox(s);\r
154     }\r
155   }\r
156 \r
157   return S_OK;\r
158 }\r
159 \r
160 HRESULT CPanel::OpenItemAsArchive(const UString &name, const UString &arcFormat, bool &encrypted)\r
161 {\r
162   CTempFileInfo tfi;\r
163   tfi.ItemName = name;\r
164   tfi.FolderPath = _currentFolderPrefix;\r
165   tfi.FilePath = _currentFolderPrefix + name;\r
166   return OpenItemAsArchive(NULL, tfi, _currentFolderPrefix + name, arcFormat, encrypted);\r
167 }\r
168 \r
169 HRESULT CPanel::OpenItemAsArchive(int index)\r
170 {\r
171   CDisableTimerProcessing disableTimerProcessing1(*this);\r
172   bool encrypted;\r
173   RINOK(OpenItemAsArchive(GetItemRelPath(index), UString(), encrypted));\r
174   RefreshListCtrl();\r
175   return S_OK;\r
176 }\r
177 \r
178 HRESULT CPanel::OpenParentArchiveFolder()\r
179 {\r
180   CDisableTimerProcessing disableTimerProcessing1(*this);\r
181   if (_parentFolders.Size() < 2)\r
182     return S_OK;\r
183   const CFolderLink &folderLink = _parentFolders.Back();\r
184   NFind::CFileInfoW newFileInfo;\r
185   if (newFileInfo.Find(folderLink.FilePath))\r
186   {\r
187     if (folderLink.WasChanged(newFileInfo))\r
188     {\r
189       UString message = MyFormatNew(IDS_WANT_UPDATE_MODIFIED_FILE,\r
190           0x03020280, folderLink.ItemName);\r
191       if (::MessageBoxW(HWND(*this), message, L"7-Zip", MB_OKCANCEL | MB_ICONQUESTION) == IDOK)\r
192       {\r
193         if (OnOpenItemChanged(folderLink.FolderPath, folderLink.ItemName,\r
194             folderLink.UsePassword, folderLink.Password) != S_OK)\r
195         {\r
196           ::MessageBoxW(HWND(*this), MyFormatNew(IDS_CANNOT_UPDATE_FILE,\r
197               0x03020281, folderLink.FilePath), L"7-Zip", MB_OK | MB_ICONSTOP);\r
198           return S_OK;\r
199         }\r
200       }\r
201     }\r
202   }\r
203   folderLink.DeleteDirAndFile();\r
204   return S_OK;\r
205 }\r
206 \r
207 static const char *kStartExtensions =\r
208   #ifdef UNDER_CE\r
209   " cab"\r
210   #endif\r
211   " exe bat com"\r
212   " chm"\r
213   " msi doc xls ppt pps wps wpt wks xlr wdb vsd pub"\r
214 \r
215   " docx docm dotx dotm xlsx xlsm xltx xltm xlsb xps"\r
216   " xlam pptx pptm potx potm ppam ppsx ppsm xsn"\r
217   " mpp"\r
218   " msg"\r
219   " dwf"\r
220 \r
221   " flv swf"\r
222   \r
223   " odt ods"\r
224   " wb3"\r
225   " pdf"\r
226   " ";\r
227 \r
228 static bool FindExt(const char *p, const UString &name)\r
229 {\r
230   int extPos = name.ReverseFind('.');\r
231   if (extPos < 0)\r
232     return false;\r
233   UString ext = name.Mid(extPos + 1);\r
234   ext.MakeLower();\r
235   AString ext2 = UnicodeStringToMultiByte(ext);\r
236   for (int i = 0; p[i] != 0;)\r
237   {\r
238     int j;\r
239     for (j = i; p[j] != ' '; j++);\r
240     if (ext2.Length() == j - i && memcmp(p + i, (const char *)ext2, ext2.Length()) == 0)\r
241       return true;\r
242     i = j + 1;\r
243   }\r
244   return false;\r
245 }\r
246 \r
247 static bool DoItemAlwaysStart(const UString &name)\r
248 {\r
249   return FindExt(kStartExtensions, name);\r
250 }\r
251 \r
252 static UString GetQuotedString(const UString &s)\r
253 {\r
254   return UString(L'\"') + s + UString(L'\"');\r
255 }\r
256 \r
257 static HRESULT StartEditApplication(const UString &path, HWND window, CProcess &process)\r
258 {\r
259   UString command;\r
260   ReadRegEditor(command);\r
261   if (command.IsEmpty())\r
262   {\r
263     #ifdef UNDER_CE\r
264     command = L"\\Windows\\";\r
265     #else\r
266     if (!MyGetWindowsDirectory(command))\r
267       return 0;\r
268     NFile::NName::NormalizeDirPathPrefix(command);\r
269     #endif\r
270     command += L"notepad.exe";\r
271   }\r
272 \r
273   HRESULT res = process.Create(command, GetQuotedString(path), NULL);\r
274   if (res != SZ_OK)\r
275     ::MessageBoxW(window, LangString(IDS_CANNOT_START_EDITOR, 0x03020282), L"7-Zip", MB_OK  | MB_ICONSTOP);\r
276   return res;\r
277 }\r
278 \r
279 void CApp::DiffFiles()\r
280 {\r
281   const CPanel &panel = GetFocusedPanel();\r
282   \r
283   CRecordVector<UInt32> indices;\r
284   panel.GetSelectedItemsIndices(indices);\r
285 \r
286   UString path1, path2;\r
287   if (indices.Size() == 2)\r
288   {\r
289     path1 = panel.GetItemFullPath(indices[0]);\r
290     path2 = panel.GetItemFullPath(indices[1]);\r
291   }\r
292   else if (indices.Size() == 1 && NumPanels >= 2)\r
293   {\r
294     const CPanel &destPanel = Panels[1 - LastFocusedPanel];\r
295     path1 = panel.GetItemFullPath(indices[0]);\r
296     const UString relPath = panel.GetItemRelPath(indices[0]);\r
297     CRecordVector<UInt32> indices2;\r
298     destPanel.GetSelectedItemsIndices(indices2);\r
299     if (indices2.Size() == 1)\r
300       path2 = destPanel.GetItemFullPath(indices2[0]);\r
301     else\r
302       path2 = destPanel._currentFolderPrefix + relPath;\r
303   }\r
304   else\r
305     return;\r
306 \r
307   UString command;\r
308   ReadRegDiff(command);\r
309   if (command.IsEmpty())\r
310     return;\r
311 \r
312   UString param = GetQuotedString(path1) + L' ' + GetQuotedString(path2);\r
313 \r
314   HRESULT res = MyCreateProcess(command, param);\r
315   if (res == SZ_OK)\r
316     return;\r
317   ::MessageBoxW(_window, LangString(IDS_CANNOT_START_EDITOR, 0x03020282), L"7-Zip", MB_OK  | MB_ICONSTOP);\r
318 }\r
319 \r
320 #ifndef _UNICODE\r
321 typedef BOOL (WINAPI * ShellExecuteExWP)(LPSHELLEXECUTEINFOW lpExecInfo);\r
322 #endif\r
323 \r
324 static HRESULT StartApplication(const UString &dir, const UString &path, HWND window, CProcess &process)\r
325 {\r
326   UINT32 result;\r
327   #ifndef _UNICODE\r
328   if (g_IsNT)\r
329   {\r
330     SHELLEXECUTEINFOW execInfo;\r
331     execInfo.cbSize = sizeof(execInfo);\r
332     execInfo.fMask = SEE_MASK_NOCLOSEPROCESS | SEE_MASK_FLAG_DDEWAIT;\r
333     execInfo.hwnd = NULL;\r
334     execInfo.lpVerb = NULL;\r
335     execInfo.lpFile = path;\r
336     execInfo.lpParameters = NULL;\r
337     execInfo.lpDirectory = dir.IsEmpty() ? NULL : (LPCWSTR)dir;\r
338     execInfo.nShow = SW_SHOWNORMAL;\r
339     execInfo.hProcess = 0;\r
340     ShellExecuteExWP shellExecuteExW = (ShellExecuteExWP)\r
341     ::GetProcAddress(::GetModuleHandleW(L"shell32.dll"), "ShellExecuteExW");\r
342     if (shellExecuteExW == 0)\r
343       return 0;\r
344     shellExecuteExW(&execInfo);\r
345     result = (UINT32)(UINT_PTR)execInfo.hInstApp;\r
346     process.Attach(execInfo.hProcess);\r
347   }\r
348   else\r
349   #endif\r
350   {\r
351     SHELLEXECUTEINFO execInfo;\r
352     execInfo.cbSize = sizeof(execInfo);\r
353     execInfo.fMask = SEE_MASK_NOCLOSEPROCESS\r
354       #ifndef UNDER_CE\r
355       | SEE_MASK_FLAG_DDEWAIT\r
356       #endif\r
357       ;\r
358     execInfo.hwnd = NULL;\r
359     execInfo.lpVerb = NULL;\r
360     const CSysString sysPath = GetSystemString(path);\r
361     const CSysString sysDir = GetSystemString(dir);\r
362     execInfo.lpFile = sysPath;\r
363     execInfo.lpParameters = NULL;\r
364     execInfo.lpDirectory =\r
365     #ifdef UNDER_CE\r
366     NULL\r
367     #else\r
368     sysDir.IsEmpty() ? NULL : (LPCTSTR)sysDir\r
369     #endif\r
370     ;\r
371     execInfo.nShow = SW_SHOWNORMAL;\r
372     execInfo.hProcess = 0;\r
373     ::ShellExecuteEx(&execInfo);\r
374     result = (UINT32)(UINT_PTR)execInfo.hInstApp;\r
375     process.Attach(execInfo.hProcess);\r
376   }\r
377   if (result <= 32)\r
378   {\r
379     switch(result)\r
380     {\r
381       case SE_ERR_NOASSOC:\r
382         ::MessageBoxW(window,\r
383           NError::MyFormatMessageW(::GetLastError()),\r
384           // L"There is no application associated with the given file name extension",\r
385           L"7-Zip", MB_OK | MB_ICONSTOP);\r
386     }\r
387   }\r
388   return S_OK;\r
389 }\r
390 \r
391 static void StartApplicationDontWait(const UString &dir, const UString &path, HWND window)\r
392 {\r
393   CProcess process;\r
394   StartApplication(dir, path, window, process);\r
395 }\r
396 \r
397 void CPanel::EditItem(int index)\r
398 {\r
399   if (!_parentFolders.IsEmpty())\r
400   {\r
401     OpenItemInArchive(index, false, true, true);\r
402     return;\r
403   }\r
404   CProcess process;\r
405   StartEditApplication(GetItemFullPath(index), (HWND)*this, process);\r
406 }\r
407 \r
408 void CPanel::OpenFolderExternal(int index)\r
409 {\r
410   UString fsPrefix = GetFsPath();\r
411   UString name;\r
412   if (index == kParentIndex)\r
413   {\r
414     int pos = fsPrefix.ReverseFind(WCHAR_PATH_SEPARATOR);\r
415     if (pos >= 0 && pos == fsPrefix.Length() - 1)\r
416     {\r
417       UString s = fsPrefix.Left(pos);\r
418       pos = s.ReverseFind(WCHAR_PATH_SEPARATOR);\r
419       if (pos >= 0)\r
420         fsPrefix = s.Left(pos + 1);\r
421     }\r
422     name = fsPrefix;\r
423   }\r
424   else\r
425     name = fsPrefix + GetItemRelPath(index) + WCHAR_PATH_SEPARATOR;\r
426   StartApplicationDontWait(fsPrefix, name, (HWND)*this);\r
427 }\r
428 \r
429 void CPanel::OpenItem(int index, bool tryInternal, bool tryExternal)\r
430 {\r
431   CDisableTimerProcessing disableTimerProcessing1(*this);\r
432   if (!_parentFolders.IsEmpty())\r
433   {\r
434     OpenItemInArchive(index, tryInternal, tryExternal, false);\r
435     return;\r
436   }\r
437   UString name = GetItemRelPath(index);\r
438   if (IsNameVirus(name))\r
439   {\r
440     MessageBoxErrorLang(IDS_VIRUS, 0x03020284);\r
441     return;\r
442   }\r
443   UString prefix = GetFsPath();\r
444   UString fullPath = prefix + name;\r
445   if (tryInternal)\r
446     if (!tryExternal || !DoItemAlwaysStart(name))\r
447     {\r
448       HRESULT res = OpenItemAsArchive(index);\r
449       if (res == S_OK || res == E_ABORT)\r
450         return;\r
451       if (res != S_FALSE)\r
452       {\r
453         MessageBoxError(res);\r
454         return;\r
455       }\r
456     }\r
457   if (tryExternal)\r
458   {\r
459     // SetCurrentDirectory opens HANDLE to folder!!!\r
460     // NDirectory::MySetCurrentDirectory(prefix);\r
461     StartApplicationDontWait(prefix, fullPath, (HWND)*this);\r
462   }\r
463 }\r
464 \r
465 class CThreadCopyFrom: public CProgressThreadVirt\r
466 {\r
467   HRESULT ProcessVirt();\r
468 public:\r
469   UString PathPrefix;\r
470   UString Name;\r
471 \r
472   CMyComPtr<IFolderOperations> FolderOperations;\r
473   CMyComPtr<IProgress> UpdateCallback;\r
474   CUpdateCallback100Imp *UpdateCallbackSpec;\r
475 };\r
476   \r
477 HRESULT CThreadCopyFrom::ProcessVirt()\r
478 {\r
479   UStringVector fileNames;\r
480   CRecordVector<const wchar_t *> fileNamePointers;\r
481   fileNames.Add(Name);\r
482   fileNamePointers.Add(fileNames[0]);\r
483   return FolderOperations->CopyFrom(PathPrefix, &fileNamePointers.Front(), fileNamePointers.Size(), UpdateCallback);\r
484 }\r
485       \r
486 HRESULT CPanel::OnOpenItemChanged(const UString &folderPath, const UString &itemName,\r
487     bool usePassword, const UString &password)\r
488 {\r
489   CMyComPtr<IFolderOperations> folderOperations;\r
490   if (_folder.QueryInterface(IID_IFolderOperations, &folderOperations) != S_OK)\r
491   {\r
492     MessageBoxErrorLang(IDS_OPERATION_IS_NOT_SUPPORTED, 0x03020208);\r
493     return E_FAIL;\r
494   }\r
495 \r
496   CThreadCopyFrom t;\r
497   t.UpdateCallbackSpec = new CUpdateCallback100Imp;\r
498   t.UpdateCallback = t.UpdateCallbackSpec;\r
499   t.UpdateCallbackSpec->ProgressDialog = &t.ProgressDialog;\r
500   t.Name = itemName;\r
501   t.PathPrefix = folderPath;\r
502   NName::NormalizeDirPathPrefix(t.PathPrefix);\r
503   t.FolderOperations = folderOperations;\r
504   t.UpdateCallbackSpec->Init(usePassword, password);\r
505   RINOK(t.Create(itemName, (HWND)*this));\r
506   return t.Result;\r
507 }\r
508 \r
509 LRESULT CPanel::OnOpenItemChanged(LPARAM lParam)\r
510 {\r
511   CTmpProcessInfo &tmpProcessInfo = *(CTmpProcessInfo *)lParam;\r
512   // LoadCurrentPath()\r
513   if (tmpProcessInfo.FullPathFolderPrefix != _currentFolderPrefix)\r
514     return 0;\r
515 \r
516   CSelectedState state;\r
517   SaveSelectedState(state);\r
518 \r
519   HRESULT result = OnOpenItemChanged(tmpProcessInfo.FolderPath, tmpProcessInfo.ItemName,\r
520       tmpProcessInfo.UsePassword, tmpProcessInfo.Password);\r
521   if (result != S_OK)\r
522     return 0;\r
523   RefreshListCtrl(state);\r
524   return 1;\r
525 }\r
526 \r
527 /*\r
528 class CTmpProcessInfoList\r
529 {\r
530 public:\r
531   CObjectVector<CTmpProcessInfo> _items;\r
532 } g_TmpProcessInfoList;\r
533 */\r
534 \r
535 class CExitEventLauncher\r
536 {\r
537 public:\r
538   NWindows::NSynchronization::CManualResetEvent _exitEvent;\r
539   CExitEventLauncher()\r
540   {\r
541     if (_exitEvent.Create(false) != S_OK)\r
542       throw 9387173;\r
543   };\r
544   ~CExitEventLauncher() {  _exitEvent.Set(); }\r
545 } g_ExitEventLauncher;\r
546 \r
547 static THREAD_FUNC_DECL MyThreadFunction(void *param)\r
548 {\r
549   CMyAutoPtr<CTmpProcessInfo> tmpProcessInfoPtr((CTmpProcessInfo *)param);\r
550   const CTmpProcessInfo *tmpProcessInfo = tmpProcessInfoPtr.get();\r
551 \r
552   HANDLE hProcess = tmpProcessInfo->ProcessHandle;\r
553   HANDLE events[2] = { g_ExitEventLauncher._exitEvent, hProcess};\r
554   DWORD waitResult = ::WaitForMultipleObjects(2, events, FALSE, INFINITE);\r
555   ::CloseHandle(hProcess);\r
556   if (waitResult == WAIT_OBJECT_0 + 0)\r
557     return 0;\r
558   if (waitResult != WAIT_OBJECT_0 + 1)\r
559     return 1;\r
560   Sleep(200);\r
561   NFind::CFileInfoW newFileInfo;\r
562   if (newFileInfo.Find(tmpProcessInfo->FilePath))\r
563   {\r
564     if (tmpProcessInfo->WasChanged(newFileInfo))\r
565     {\r
566       UString message = MyFormatNew(IDS_WANT_UPDATE_MODIFIED_FILE,\r
567           0x03020280, tmpProcessInfo->ItemName);\r
568       if (::MessageBoxW(g_HWND, message, L"7-Zip", MB_OKCANCEL | MB_ICONQUESTION) == IDOK)\r
569       {\r
570         if (SendMessage(tmpProcessInfo->Window, kOpenItemChanged, 0, (LONG_PTR)tmpProcessInfo) != 1)\r
571         {\r
572           ::MessageBoxW(g_HWND, MyFormatNew(IDS_CANNOT_UPDATE_FILE,\r
573               0x03020281, tmpProcessInfo->FilePath), L"7-Zip", MB_OK | MB_ICONSTOP);\r
574           return 0;\r
575         }\r
576       }\r
577     }\r
578   }\r
579   tmpProcessInfo->DeleteDirAndFile();\r
580   return 0;\r
581 }\r
582 \r
583 void CPanel::OpenItemInArchive(int index, bool tryInternal, bool tryExternal, bool editMode)\r
584 {\r
585   const UString name = GetItemName(index);\r
586   if (IsNameVirus(name))\r
587   {\r
588     MessageBoxErrorLang(IDS_VIRUS, 0x03020284);\r
589     return;\r
590   }\r
591 \r
592   CMyComPtr<IFolderOperations> folderOperations;\r
593   if (_folder.QueryInterface(IID_IFolderOperations, &folderOperations) != S_OK)\r
594   {\r
595     MessageBoxErrorLang(IDS_OPERATION_IS_NOT_SUPPORTED, 0x03020208);\r
596     return;\r
597   }\r
598 \r
599   bool tryAsArchive = tryInternal && (!tryExternal || !DoItemAlwaysStart(name));\r
600 \r
601   UString fullVirtPath = _currentFolderPrefix + name;\r
602 \r
603   NFile::NDirectory::CTempDirectoryW tempDirectory;\r
604   tempDirectory.Create(kTempDirPrefix);\r
605   UString tempDir = tempDirectory.GetPath();\r
606   UString tempDirNorm = tempDir;\r
607   NFile::NName::NormalizeDirPathPrefix(tempDirNorm);\r
608 \r
609   UString tempFilePath = tempDirNorm + GetCorrectFsPath(name);\r
610 \r
611   CTempFileInfo tempFileInfo;\r
612   tempFileInfo.ItemName = name;\r
613   tempFileInfo.FolderPath = tempDir;\r
614   tempFileInfo.FilePath = tempFilePath;\r
615   tempFileInfo.NeedDelete = true;\r
616 \r
617   if (tryAsArchive)\r
618   {\r
619     CMyComPtr<IInArchiveGetStream> getStream;\r
620     _folder.QueryInterface(IID_IInArchiveGetStream, &getStream);\r
621     if (getStream)\r
622     {\r
623       CMyComPtr<ISequentialInStream> subSeqStream;\r
624       getStream->GetStream(index, &subSeqStream);\r
625       if (subSeqStream)\r
626       {\r
627         CMyComPtr<IInStream> subStream;\r
628         subSeqStream.QueryInterface(IID_IInStream, &subStream);\r
629         if (subStream)\r
630         {\r
631           bool encrypted;\r
632           if (OpenItemAsArchive(subStream, tempFileInfo, fullVirtPath, UString(), encrypted) == S_OK)\r
633           {\r
634             tempDirectory.DisableDeleting();\r
635             RefreshListCtrl();\r
636             return;\r
637           }\r
638         }\r
639       }\r
640     }\r
641   }\r
642 \r
643 \r
644   CRecordVector<UInt32> indices;\r
645   indices.Add(index);\r
646 \r
647   UStringVector messages;\r
648 \r
649   bool usePassword = false;\r
650   UString password;\r
651   if (_parentFolders.Size() > 0)\r
652   {\r
653     const CFolderLink &fl = _parentFolders.Back();\r
654     usePassword = fl.UsePassword;\r
655     password = fl.Password;\r
656   }\r
657 \r
658   HRESULT result = CopyTo(indices, tempDirNorm, false, true, &messages, usePassword, password);\r
659 \r
660   if (_parentFolders.Size() > 0)\r
661   {\r
662     CFolderLink &fl = _parentFolders.Back();\r
663     fl.UsePassword = usePassword;\r
664     fl.Password = password;\r
665   }\r
666 \r
667   if (!messages.IsEmpty())\r
668     return;\r
669   if (result != S_OK)\r
670   {\r
671     if (result != E_ABORT)\r
672       MessageBoxError(result);\r
673     return;\r
674   }\r
675 \r
676 \r
677   if (tryAsArchive)\r
678   {\r
679     bool encrypted;\r
680     if (OpenItemAsArchive(NULL, tempFileInfo, fullVirtPath, UString(), encrypted) == S_OK)\r
681     {\r
682       tempDirectory.DisableDeleting();\r
683       RefreshListCtrl();\r
684       return;\r
685     }\r
686   }\r
687 \r
688   CMyAutoPtr<CTmpProcessInfo> tmpProcessInfoPtr(new CTmpProcessInfo());\r
689   CTmpProcessInfo *tmpProcessInfo = tmpProcessInfoPtr.get();\r
690   tmpProcessInfo->FolderPath = tempDir;\r
691   tmpProcessInfo->FilePath = tempFilePath;\r
692   tmpProcessInfo->NeedDelete = true;\r
693   tmpProcessInfo->UsePassword = usePassword;\r
694   tmpProcessInfo->Password = password;\r
695 \r
696   if (!tmpProcessInfo->FileInfo.Find(tempFilePath))\r
697     return;\r
698 \r
699   CTmpProcessInfoRelease tmpProcessInfoRelease(*tmpProcessInfo);\r
700 \r
701   if (!tryExternal)\r
702     return;\r
703 \r
704   CProcess process;\r
705   HRESULT res;\r
706   if (editMode)\r
707     res = StartEditApplication(tempFilePath, (HWND)*this, process);\r
708   else\r
709     res = StartApplication(tempDirNorm, tempFilePath, (HWND)*this, process);\r
710 \r
711   if ((HANDLE)process == 0)\r
712     return;\r
713 \r
714   tmpProcessInfo->Window = (HWND)(*this);\r
715   tmpProcessInfo->FullPathFolderPrefix = _currentFolderPrefix;\r
716   tmpProcessInfo->ItemName = name;\r
717   tmpProcessInfo->ProcessHandle = process.Detach();\r
718 \r
719   NWindows::CThread thread;\r
720   if (thread.Create(MyThreadFunction, tmpProcessInfo) != S_OK)\r
721     throw 271824;\r
722   tempDirectory.DisableDeleting();\r
723   tmpProcessInfoPtr.release();\r
724   tmpProcessInfoRelease._needDelete = false;\r
725 }\r
726 \r
727 /*\r
728 static const UINT64 kTimeLimit = UINT64(10000000) * 3600 * 24;\r
729 \r
730 static bool CheckDeleteItem(UINT64 currentFileTime, UINT64 folderFileTime)\r
731 {\r
732   return (currentFileTime - folderFileTime > kTimeLimit &&\r
733       folderFileTime - currentFileTime > kTimeLimit);\r
734 }\r
735 \r
736 void DeleteOldTempFiles()\r
737 {\r
738   UString tempPath;\r
739   if(!NFile::NDirectory::MyGetTempPath(tempPath))\r
740     throw 1;\r
741 \r
742   UINT64 currentFileTime;\r
743   NTime::GetCurUtcFileTime(currentFileTime);\r
744   UString searchWildCard = tempPath + kTempDirPrefix + L"*.tmp";\r
745   searchWildCard += WCHAR(NName::kAnyStringWildcard);\r
746   NFind::CEnumeratorW enumerator(searchWildCard);\r
747   NFind::CFileInfoW fileInfo;\r
748   while(enumerator.Next(fileInfo))\r
749   {\r
750     if (!fileInfo.IsDir())\r
751       continue;\r
752     const UINT64 &cTime = *(const UINT64 *)(&fileInfo.CTime);\r
753     if(CheckDeleteItem(cTime, currentFileTime))\r
754       RemoveDirectoryWithSubItems(tempPath + fileInfo.Name);\r
755   }\r
756 }\r
757 */\r