1270 lines
31 KiB
C++
1270 lines
31 KiB
C++
// PanelItemOpen.cpp
|
|
|
|
#include "StdAfx.h"
|
|
|
|
// For compilers that support precompilation, includes "wx/wx.h".
|
|
#include "wx/wxprec.h"
|
|
|
|
#ifdef __BORLANDC__
|
|
#pragma hdrstop
|
|
#endif
|
|
|
|
#ifndef WX_PRECOMP
|
|
#include "wx/wx.h"
|
|
#endif
|
|
#include "wx/mimetype.h"
|
|
|
|
#undef _WIN32
|
|
|
|
// #include <tlhelp32.h>
|
|
|
|
#include "../../../Common/AutoPtr.h"
|
|
#include "../../../Common/StringConvert.h"
|
|
|
|
// #include "../../../Windows/ProcessUtils.h"
|
|
#include "../../../Windows/FileName.h"
|
|
#include "../../../Windows/PropVariant.h"
|
|
#include "../../../Windows/PropVariantConv.h"
|
|
|
|
#include "../../Common/FileStreams.h"
|
|
#include "../../Common/StreamObjects.h"
|
|
|
|
#include "../Common/ExtractingFilePath.h"
|
|
|
|
#include "App.h"
|
|
|
|
#include "FileFolderPluginOpen.h"
|
|
#include "FormatUtils.h"
|
|
#include "LangUtils.h"
|
|
#include "RegistryUtils.h"
|
|
#include "UpdateCallback100.h"
|
|
|
|
#include "resource.h"
|
|
|
|
using namespace NWindows;
|
|
using namespace NSynchronization;
|
|
using namespace NFile;
|
|
using namespace NDir;
|
|
|
|
extern UInt64 g_RAM_Size;
|
|
|
|
#ifndef _UNICODE
|
|
extern bool g_IsNT;
|
|
#endif
|
|
|
|
static CFSTR kTempDirPrefix = FTEXT("7zO");
|
|
|
|
#if 0 // ifndef UNDER_CE
|
|
|
|
class CProcessSnapshot
|
|
{
|
|
HANDLE _handle;
|
|
public:
|
|
CProcessSnapshot(): _handle(INVALID_HANDLE_VALUE) {};
|
|
~CProcessSnapshot() { Close(); }
|
|
|
|
bool Close()
|
|
{
|
|
if (_handle == INVALID_HANDLE_VALUE)
|
|
return true;
|
|
if (!::CloseHandle(_handle))
|
|
return false;
|
|
_handle = INVALID_HANDLE_VALUE;
|
|
return true;
|
|
}
|
|
|
|
bool Create()
|
|
{
|
|
_handle = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
|
|
return (_handle != INVALID_HANDLE_VALUE);
|
|
}
|
|
|
|
bool GetFirstProcess(PROCESSENTRY32 *pe) { return BOOLToBool(Process32First(_handle, pe)); }
|
|
bool GetNextProcess(PROCESSENTRY32 *pe) { return BOOLToBool(Process32Next(_handle, pe)); }
|
|
};
|
|
|
|
typedef DWORD (WINAPI *GetProcessIdFunc)(HANDLE process);
|
|
|
|
class CChildProcesses
|
|
{
|
|
#ifndef UNDER_CE
|
|
CRecordVector<DWORD> _ids;
|
|
#endif
|
|
public:
|
|
CRecordVector<HANDLE> Handles;
|
|
CRecordVector<bool> NeedWait;
|
|
|
|
~CChildProcesses() { CloseAll(); }
|
|
void DisableWait(int index) { NeedWait[index] = false; }
|
|
|
|
void CloseAll()
|
|
{
|
|
FOR_VECTOR (i, Handles)
|
|
{
|
|
HANDLE h = Handles[i];
|
|
if (h != NULL)
|
|
CloseHandle(h);
|
|
}
|
|
Handles.Clear();
|
|
NeedWait.Clear();
|
|
}
|
|
|
|
void AddProcess(HANDLE h)
|
|
{
|
|
#ifndef UNDER_CE
|
|
GetProcessIdFunc func = (GetProcessIdFunc)::GetProcAddress(::GetModuleHandleA("kernel32.dll"), "GetProcessId");
|
|
if (func)
|
|
_ids.AddToUniqueSorted(func(h));
|
|
#endif
|
|
Handles.Add(h);
|
|
NeedWait.Add(true);
|
|
}
|
|
|
|
void Update()
|
|
{
|
|
#ifndef UNDER_CE
|
|
CRecordVector<DWORD> ids, parents;
|
|
{
|
|
CProcessSnapshot snapshot;
|
|
if (snapshot.Create())
|
|
{
|
|
PROCESSENTRY32 pe;
|
|
memset(&pe, 0, sizeof(pe));
|
|
pe.dwSize = sizeof(pe);
|
|
BOOL res = snapshot.GetFirstProcess(&pe);
|
|
while (res)
|
|
{
|
|
ids.Add(pe.th32ProcessID);
|
|
parents.Add(pe.th32ParentProcessID);
|
|
res = snapshot.GetNextProcess(&pe);
|
|
}
|
|
}
|
|
}
|
|
|
|
for (;;)
|
|
{
|
|
unsigned i;
|
|
for (i = 0; i < ids.Size(); i++)
|
|
{
|
|
DWORD id = ids[i];
|
|
if (_ids.FindInSorted(parents[i]) >= 0 &&
|
|
_ids.FindInSorted(id) < 0)
|
|
{
|
|
HANDLE hProcess = OpenProcess(SYNCHRONIZE, FALSE, id);
|
|
if (hProcess)
|
|
{
|
|
_ids.AddToUniqueSorted(id);
|
|
Handles.Add(hProcess);
|
|
NeedWait.Add(true);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
if (i == ids.Size())
|
|
break;
|
|
}
|
|
#endif
|
|
}
|
|
};
|
|
#endif
|
|
|
|
struct CTmpProcessInfo: public CTempFileInfo
|
|
{
|
|
HANDLE ProcessHandle; // CChildProcesses Processes;
|
|
HWND Window;
|
|
UString FullPathFolderPrefix;
|
|
bool UsePassword;
|
|
UString Password;
|
|
|
|
CTmpProcessInfo(): UsePassword(false) {}
|
|
};
|
|
|
|
class CTmpProcessInfoRelease
|
|
{
|
|
CTmpProcessInfo *_tmpProcessInfo;
|
|
public:
|
|
bool _needDelete;
|
|
CTmpProcessInfoRelease(CTmpProcessInfo &tpi):
|
|
_tmpProcessInfo(&tpi), _needDelete(true) {}
|
|
~CTmpProcessInfoRelease()
|
|
{
|
|
if (_needDelete)
|
|
_tmpProcessInfo->DeleteDirAndFile();
|
|
}
|
|
};
|
|
|
|
HRESULT CPanel::OpenItemAsArchive(IInStream *inStream,
|
|
const CTempFileInfo &tempFileInfo,
|
|
const UString &virtualFilePath,
|
|
const UString &arcFormat,
|
|
bool &encrypted)
|
|
{
|
|
encrypted = false;
|
|
CFolderLink folderLink;
|
|
(CTempFileInfo &)folderLink = tempFileInfo;
|
|
if (inStream)
|
|
folderLink.IsVirtual = true;
|
|
else
|
|
{
|
|
if (!folderLink.FileInfo.Find(folderLink.FilePath))
|
|
return ::GetLastError();
|
|
if (folderLink.FileInfo.IsDir())
|
|
return S_FALSE;
|
|
folderLink.IsVirtual = false;
|
|
}
|
|
|
|
folderLink.VirtualPath = virtualFilePath;
|
|
|
|
CMyComPtr<IFolderFolder> newFolder;
|
|
|
|
// _passwordIsDefined = false;
|
|
// _password.Empty();
|
|
|
|
NDLL::CLibrary library;
|
|
|
|
UString password;
|
|
RINOK(OpenFileFolderPlugin(inStream,
|
|
folderLink.FilePath.IsEmpty() ? us2fs(virtualFilePath) : folderLink.FilePath,
|
|
arcFormat,
|
|
&library, &newFolder, GetParent(), encrypted, password));
|
|
|
|
folderLink.Password = password;
|
|
folderLink.UsePassword = encrypted;
|
|
|
|
if (_folder)
|
|
folderLink.ParentFolderPath = GetFolderPath(_folder);
|
|
else
|
|
folderLink.ParentFolderPath = _currentFolderPrefix;
|
|
if (!_parentFolders.IsEmpty())
|
|
folderLink.ParentFolder = _folder;
|
|
|
|
_parentFolders.Add(folderLink);
|
|
_parentFolders.Back().Library.Attach(_library.Detach());
|
|
|
|
ReleaseFolder();
|
|
_library.Free();
|
|
SetNewFolder(newFolder);
|
|
_library.Attach(library.Detach());
|
|
|
|
_flatMode = _flatModeForArc;
|
|
|
|
CMyComPtr<IGetFolderArcProps> getFolderArcProps;
|
|
_folder.QueryInterface(IID_IGetFolderArcProps, &getFolderArcProps);
|
|
_thereAreDeletedItems = false;
|
|
if (getFolderArcProps)
|
|
{
|
|
CMyComPtr<IFolderArcProps> arcProps;
|
|
getFolderArcProps->GetFolderArcProps(&arcProps);
|
|
if (arcProps)
|
|
{
|
|
/*
|
|
UString s;
|
|
UInt32 numLevels;
|
|
if (arcProps->GetArcNumLevels(&numLevels) != S_OK)
|
|
numLevels = 0;
|
|
for (UInt32 level2 = 0; level2 <= numLevels; level2++)
|
|
{
|
|
UInt32 level = numLevels - level2;
|
|
PROPID propIDs[] = { kpidError, kpidPath, kpidType, kpidErrorType } ;
|
|
UString values[4];
|
|
for (Int32 i = 0; i < 4; i++)
|
|
{
|
|
CMyComBSTR name;
|
|
NCOM::CPropVariant prop;
|
|
if (arcProps->GetArcProp(level, propIDs[i], &prop) != S_OK)
|
|
continue;
|
|
if (prop.vt != VT_EMPTY)
|
|
values[i] = (prop.vt == VT_BSTR) ? prop.bstrVal : L"?";
|
|
}
|
|
UString s2;
|
|
if (!values[3].IsEmpty())
|
|
{
|
|
s2 = L"Can not open the file as [" + values[3] + L"] archive";
|
|
if (level2 != 0)
|
|
s2 += L"\nThe file is open as [" + values[2] + L"] archive";
|
|
}
|
|
if (!values[0].IsEmpty())
|
|
{
|
|
if (!s2.IsEmpty())
|
|
s2.Add_LF();
|
|
s2 += L"[";
|
|
s2 += values[2];
|
|
s2 += L"] Error: ";
|
|
s2 += values[0];
|
|
}
|
|
if (!s2.IsEmpty())
|
|
{
|
|
if (!s.IsEmpty())
|
|
s += L"--------------------\n";
|
|
s += values[1];
|
|
s.Add_LF();
|
|
s += s2;
|
|
}
|
|
}
|
|
*/
|
|
/*
|
|
if (!s.IsEmpty())
|
|
MessageBoxWarning(s);
|
|
else
|
|
*/
|
|
// after MessageBoxWarning it throws exception in nested archives in Debug Mode. why ?.
|
|
// MessageBoxWarning(L"test error");
|
|
}
|
|
}
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
HRESULT CPanel::OpenItemAsArchive(const UString &relPath, const UString &arcFormat, bool &encrypted)
|
|
{
|
|
CTempFileInfo tfi;
|
|
tfi.RelPath = relPath;
|
|
tfi.FolderPath = us2fs(GetFsPath());
|
|
const UString fullPath = GetFsPath() + relPath;
|
|
tfi.FilePath = us2fs(fullPath);
|
|
return OpenItemAsArchive(NULL, tfi, fullPath, arcFormat, encrypted);
|
|
}
|
|
|
|
HRESULT CPanel::OpenItemAsArchive(int index, const wchar_t *type)
|
|
{
|
|
CDisableTimerProcessing disableTimerProcessing1(*this);
|
|
CDisableNotify disableNotify(*this);
|
|
bool encrypted;
|
|
HRESULT res = OpenItemAsArchive(GetItemRelPath2(index), type ? type : L"", encrypted);
|
|
if (res != S_OK)
|
|
{
|
|
RefreshTitle(true); // in case of error we must refresh changed title of 7zFM
|
|
return res;
|
|
}
|
|
RefreshListCtrl();
|
|
return S_OK;
|
|
}
|
|
|
|
HRESULT CPanel::OpenParentArchiveFolder()
|
|
{
|
|
CDisableTimerProcessing disableTimerProcessing(*this);
|
|
CDisableNotify disableNotify(*this);
|
|
if (_parentFolders.Size() < 2)
|
|
return S_OK;
|
|
const CFolderLink &folderLinkPrev = _parentFolders[_parentFolders.Size() - 2];
|
|
const CFolderLink &folderLink = _parentFolders.Back();
|
|
NFind::CFileInfo newFileInfo;
|
|
if (newFileInfo.Find(folderLink.FilePath))
|
|
{
|
|
if (folderLink.WasChanged(newFileInfo))
|
|
{
|
|
UString message = MyFormatNew(IDS_WANT_UPDATE_MODIFIED_FILE, folderLink.RelPath);
|
|
if (::MessageBoxW((HWND)*this, message, L"7-Zip", MB_OKCANCEL | MB_ICONQUESTION) == IDOK)
|
|
{
|
|
if (OnOpenItemChanged(folderLink.FileIndex, fs2us(folderLink.FilePath),
|
|
folderLinkPrev.UsePassword, folderLinkPrev.Password) != S_OK)
|
|
{
|
|
::MessageBoxW((HWND)*this, MyFormatNew(IDS_CANNOT_UPDATE_FILE,
|
|
fs2us(folderLink.FilePath)), L"7-Zip", MB_OK | MB_ICONSTOP);
|
|
return S_OK;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
folderLink.DeleteDirAndFile();
|
|
return S_OK;
|
|
}
|
|
|
|
static const char *kStartExtensions =
|
|
#ifdef UNDER_CE
|
|
" cab"
|
|
#endif
|
|
" exe bat com"
|
|
" chm"
|
|
" msi doc xls ppt pps wps wpt wks xlr wdb vsd pub"
|
|
|
|
" docx docm dotx dotm xlsx xlsm xltx xltm xlsb xps"
|
|
" xlam pptx pptm potx potm ppam ppsx ppsm xsn"
|
|
" mpp"
|
|
" msg"
|
|
" dwf"
|
|
|
|
" flv swf"
|
|
|
|
" odt ods"
|
|
" wb3"
|
|
" pdf"
|
|
" ";
|
|
|
|
static bool FindExt(const char *p, const UString &name)
|
|
{
|
|
int dotPos = name.ReverseFind_Dot();
|
|
if (dotPos < 0 || dotPos == (int)name.Len() - 1)
|
|
return false;
|
|
|
|
AString s;
|
|
for (unsigned pos = dotPos + 1;; pos++)
|
|
{
|
|
wchar_t c = name[pos];
|
|
if (c == 0)
|
|
break;
|
|
if (c >= 0x80)
|
|
return false;
|
|
s += (char)MyCharLower_Ascii((char)c);
|
|
}
|
|
for (unsigned i = 0; p[i] != 0;)
|
|
{
|
|
unsigned j;
|
|
for (j = i; p[j] != ' '; j++);
|
|
if (s.Len() == j - i && memcmp(p + i, (const char *)s, s.Len()) == 0)
|
|
return true;
|
|
i = j + 1;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
static bool DoItemAlwaysStart(const UString &name)
|
|
{
|
|
return FindExt(kStartExtensions, name);
|
|
}
|
|
|
|
UString GetQuotedString(const UString &s);
|
|
|
|
static void StartEditApplication(const UString &path, bool useEditor, HWND window /* , CProcess &process */ )
|
|
{
|
|
UString command;
|
|
ReadRegEditor(useEditor, command);
|
|
if (command.IsEmpty())
|
|
{
|
|
#ifdef _WIN32
|
|
#ifdef UNDER_CE
|
|
command = L"\\Windows\\";
|
|
#else
|
|
FString winDir;
|
|
if (!GetWindowsDir(winDir))
|
|
return 0;
|
|
NName::NormalizeDirPathPrefix(winDir);
|
|
command = fs2us(winDir);
|
|
#endif
|
|
command += L"notepad.exe";
|
|
#else
|
|
command += L"vi";
|
|
#endif
|
|
}
|
|
|
|
#ifdef _WIN32
|
|
HRESULT res = process.Create(command, GetQuotedString(path), NULL);
|
|
if (res != SZ_OK)
|
|
::MessageBoxW(window, LangString(IDS_CANNOT_START_EDITOR), L"7-Zip", MB_OK | MB_ICONSTOP);
|
|
return res;
|
|
#else
|
|
wxString cmd = (const wchar_t *)command;
|
|
long pid = wxExecute(cmd, wxEXEC_ASYNC);
|
|
if (pid) return ;
|
|
::MessageBoxW(window, LangString(IDS_CANNOT_START_EDITOR), L"7-Zip", MB_OK | MB_ICONSTOP);
|
|
#endif
|
|
}
|
|
|
|
void CApp::DiffFiles()
|
|
{
|
|
const CPanel &panel = GetFocusedPanel();
|
|
|
|
CRecordVector<UInt32> indices;
|
|
panel.GetSelectedItemsIndices(indices);
|
|
|
|
UString path1, path2;
|
|
if (indices.Size() == 2)
|
|
{
|
|
path1 = panel.GetItemFullPath(indices[0]);
|
|
path2 = panel.GetItemFullPath(indices[1]);
|
|
}
|
|
else if (indices.Size() == 1 && NumPanels >= 2)
|
|
{
|
|
const CPanel &destPanel = Panels[1 - LastFocusedPanel];
|
|
path1 = panel.GetItemFullPath(indices[0]);
|
|
CRecordVector<UInt32> indices2;
|
|
destPanel.GetSelectedItemsIndices(indices2);
|
|
if (indices2.Size() == 1)
|
|
path2 = destPanel.GetItemFullPath(indices2[0]);
|
|
else
|
|
{
|
|
UString relPath = panel.GetItemRelPath2(indices[0]);
|
|
if (panel._flatMode && !destPanel._flatMode)
|
|
relPath = panel.GetItemName(indices[0]);
|
|
path2 = destPanel._currentFolderPrefix + relPath;
|
|
}
|
|
}
|
|
else
|
|
return;
|
|
|
|
UString command;
|
|
ReadRegDiff(command);
|
|
if (command.IsEmpty())
|
|
return;
|
|
|
|
UString param = GetQuotedString(path1);
|
|
param.Add_Space();
|
|
param += GetQuotedString(path2);
|
|
|
|
#ifdef _WIN32
|
|
HRESULT res = MyCreateProcess(command, param);
|
|
if (res == SZ_OK)
|
|
return;
|
|
#else
|
|
wxString cmd = (const wchar_t *)command;
|
|
cmd += L" ";
|
|
cmd += (const wchar_t *)param;
|
|
|
|
long pid = wxExecute(cmd, wxEXEC_ASYNC);
|
|
if (pid) return ;
|
|
#endif
|
|
::MessageBoxW(_window, LangString(IDS_CANNOT_START_EDITOR), L"7-Zip", MB_OK | MB_ICONSTOP);
|
|
}
|
|
|
|
#ifndef _UNICODE
|
|
typedef BOOL (WINAPI * ShellExecuteExWP)(LPSHELLEXECUTEINFOW lpExecInfo);
|
|
#endif
|
|
|
|
static void StartApplication(const UString &dir, const UString &path, HWND window /* , CProcess &process */ )
|
|
{
|
|
// FIXME
|
|
extern const TCHAR * nameWindowToUnix(const TCHAR * lpFileName);
|
|
UString tmpPath = path;
|
|
|
|
wxString filename(nameWindowToUnix(tmpPath));
|
|
|
|
|
|
wxString ext = filename.AfterLast(_T('.'));
|
|
|
|
printf("StartApplication(%ls) ext='%ls'\n",(const wchar_t *)filename,(const wchar_t *)ext);
|
|
|
|
if ( ! ext.empty() )
|
|
{
|
|
wxFileType *ft = wxTheMimeTypesManager->GetFileTypeFromExtension(ext);
|
|
// printf("StartApplication(%ls) ft=%p\n",(const wchar_t *)filename,ft);
|
|
if (ft)
|
|
{
|
|
wxString cmd;
|
|
// wxString type; ft->GetMimeType(&type);
|
|
wxFileType::MessageParameters params(filename); // , type);
|
|
bool ok = ft->GetOpenCommand(&cmd, params);
|
|
// printf("StartApplication(%ls) ok=%d\n",(const wchar_t *)filename,(int)ok);
|
|
delete ft;
|
|
if ( ok )
|
|
{
|
|
printf("StartApplication(%ls) cmd='%ls'\n",(const wchar_t *)filename,(const wchar_t *)cmd);
|
|
long pid = wxExecute(cmd, wxEXEC_ASYNC);
|
|
if (pid) return ;
|
|
}
|
|
}
|
|
}
|
|
::MessageBoxW(window,
|
|
// NError::MyFormatMessageW(::GetLastError()),
|
|
L"There is no application associated with the given file name extension",
|
|
L"7-Zip", MB_OK | MB_ICONSTOP);
|
|
|
|
}
|
|
|
|
static void StartApplicationDontWait(const UString &dir, const UString &path, HWND window)
|
|
{
|
|
// CProcess process;
|
|
StartApplication(dir, path, window /* , process */ );
|
|
}
|
|
|
|
void CPanel::EditItem(int index, bool useEditor)
|
|
{
|
|
if (!_parentFolders.IsEmpty())
|
|
{
|
|
OpenItemInArchive(index, false, true, true, useEditor);
|
|
return;
|
|
}
|
|
// CProcess process;
|
|
StartEditApplication(GetItemFullPath(index), useEditor, (HWND)*this /* , process */ );
|
|
}
|
|
|
|
void CPanel::OpenFolderExternal(int index)
|
|
{
|
|
UString fsPrefix = GetFsPath();
|
|
UString name;
|
|
if (index == kParentIndex)
|
|
{
|
|
int pos = fsPrefix.ReverseFind_PathSepar();
|
|
if (pos >= 0 && pos == (int)fsPrefix.Len() - 1)
|
|
{
|
|
UString s = fsPrefix.Left(pos);
|
|
pos = s.ReverseFind_PathSepar();
|
|
if (pos >= 0)
|
|
fsPrefix.SetFrom(s, pos + 1);
|
|
}
|
|
name = fsPrefix;
|
|
}
|
|
else
|
|
name = fsPrefix + GetItemRelPath(index) + WCHAR_PATH_SEPARATOR;
|
|
StartApplicationDontWait(fsPrefix, name, (HWND)*this);
|
|
}
|
|
|
|
bool CPanel::IsVirus_Message(const UString &name)
|
|
{
|
|
UString name2;
|
|
|
|
const wchar_t cRLO = (wchar_t)0x202E;
|
|
bool isVirus = false;
|
|
bool isSpaceError = false;
|
|
name2 = name;
|
|
|
|
if (name2.Find(cRLO) >= 0)
|
|
{
|
|
UString badString = cRLO;
|
|
name2.Replace(badString, L"[RLO]");
|
|
isVirus = true;
|
|
}
|
|
{
|
|
const wchar_t *kVirusSpaces = L" ";
|
|
// const unsigned kNumSpaces = strlen(kVirusSpaces);
|
|
for (;;)
|
|
{
|
|
int pos = name2.Find(kVirusSpaces);
|
|
if (pos < 0)
|
|
break;
|
|
isVirus = true;
|
|
isSpaceError = true;
|
|
name2.Replace(kVirusSpaces, L" ");
|
|
}
|
|
}
|
|
|
|
if (!isVirus)
|
|
return false;
|
|
|
|
UString s = LangString(IDS_VIRUS);
|
|
|
|
if (!isSpaceError)
|
|
{
|
|
int pos1 = s.Find(L'(');
|
|
if (pos1 >= 0)
|
|
{
|
|
int pos2 = s.Find(L')', pos1 + 1);
|
|
if (pos2 >= 0)
|
|
{
|
|
s.Delete(pos1, pos2 + 1 - pos1);
|
|
if (pos1 > 0 && s[pos1 - 1] == ' ' && s[pos1] == '.')
|
|
s.Delete(pos1 - 1);
|
|
}
|
|
}
|
|
}
|
|
|
|
UString name3 = name;
|
|
name3.Replace(L'\n', L'_');
|
|
name2.Replace(L'\n', L'_');
|
|
|
|
s.Add_LF(); s += name2;
|
|
s.Add_LF(); s += name3;
|
|
|
|
MessageBoxMyError(s);
|
|
return true;
|
|
}
|
|
|
|
void CPanel::OpenItem(int index, bool tryInternal, bool tryExternal, const wchar_t *type)
|
|
{
|
|
CDisableTimerProcessing disableTimerProcessing(*this);
|
|
UString name = GetItemRelPath2(index);
|
|
|
|
if (IsVirus_Message(name))
|
|
return;
|
|
|
|
if (!_parentFolders.IsEmpty())
|
|
{
|
|
OpenItemInArchive(index, tryInternal, tryExternal, false, false, type);
|
|
return;
|
|
}
|
|
|
|
CDisableNotify disableNotify(*this);
|
|
UString prefix = GetFsPath();
|
|
UString fullPath = prefix + name;
|
|
|
|
if (tryInternal)
|
|
if (!tryExternal || !DoItemAlwaysStart(name))
|
|
{
|
|
HRESULT res = OpenItemAsArchive(index, type);
|
|
disableNotify.Restore(); // we must restore to allow text notification update
|
|
InvalidateList();
|
|
if (res == S_OK || res == E_ABORT)
|
|
return;
|
|
if (res != S_FALSE)
|
|
{
|
|
MessageBoxError(res);
|
|
return;
|
|
}
|
|
}
|
|
|
|
if (tryExternal)
|
|
{
|
|
// SetCurrentDirectory opens HANDLE to folder!!!
|
|
// NDirectory::MySetCurrentDirectory(prefix);
|
|
StartApplicationDontWait(prefix, fullPath, (HWND)*this);
|
|
}
|
|
}
|
|
|
|
class CThreadCopyFrom: public CProgressThreadVirt
|
|
{
|
|
HRESULT ProcessVirt();
|
|
public:
|
|
UString FullPath;
|
|
UInt32 ItemIndex;
|
|
|
|
CMyComPtr<IFolderOperations> FolderOperations;
|
|
CMyComPtr<IProgress> UpdateCallback;
|
|
CUpdateCallback100Imp *UpdateCallbackSpec;
|
|
};
|
|
|
|
HRESULT CThreadCopyFrom::ProcessVirt()
|
|
{
|
|
return FolderOperations->CopyFromFile(ItemIndex, FullPath, UpdateCallback);
|
|
}
|
|
|
|
HRESULT CPanel::OnOpenItemChanged(UInt32 index, const wchar_t *fullFilePath,
|
|
bool usePassword, const UString &password)
|
|
{
|
|
if (!_folderOperations)
|
|
{
|
|
MessageBoxErrorLang(IDS_OPERATION_IS_NOT_SUPPORTED);
|
|
return E_FAIL;
|
|
}
|
|
|
|
CThreadCopyFrom t;
|
|
t.UpdateCallbackSpec = new CUpdateCallback100Imp;
|
|
t.UpdateCallback = t.UpdateCallbackSpec;
|
|
t.UpdateCallbackSpec->ProgressDialog = &t.ProgressDialog;
|
|
t.ItemIndex = index;
|
|
t.FullPath = fullFilePath;
|
|
t.FolderOperations = _folderOperations;
|
|
|
|
t.UpdateCallbackSpec->Init();
|
|
t.UpdateCallbackSpec->PasswordIsDefined = usePassword;
|
|
t.UpdateCallbackSpec->Password = password;
|
|
|
|
|
|
RINOK(t.Create(GetItemName(index), (HWND)*this));
|
|
return t.Result;
|
|
}
|
|
|
|
LRESULT CPanel::OnOpenItemChanged(LPARAM lParam)
|
|
{
|
|
CTmpProcessInfo &tpi = *(CTmpProcessInfo *)lParam;
|
|
if (tpi.FullPathFolderPrefix != _currentFolderPrefix)
|
|
return 0;
|
|
UInt32 fileIndex = tpi.FileIndex;
|
|
UInt32 numItems;
|
|
_folder->GetNumberOfItems(&numItems);
|
|
|
|
// This code is not 100% OK for cases when there are several files with
|
|
// tpi.RelPath name and there are changes in archive before update.
|
|
// So tpi.FileIndex can point to another file.
|
|
|
|
if (fileIndex >= numItems || GetItemRelPath(fileIndex) != tpi.RelPath)
|
|
{
|
|
UInt32 i;
|
|
for (i = 0; i < numItems; i++)
|
|
if (GetItemRelPath(i) == tpi.RelPath)
|
|
break;
|
|
if (i == numItems)
|
|
return 0;
|
|
fileIndex = i;
|
|
}
|
|
|
|
CSelectedState state;
|
|
SaveSelectedState(state);
|
|
|
|
CDisableNotify disableNotify(*this); // do we need it??
|
|
|
|
HRESULT result = OnOpenItemChanged(fileIndex, fs2us(tpi.FilePath), tpi.UsePassword, tpi.Password);
|
|
RefreshListCtrl(state);
|
|
if (result != S_OK)
|
|
return 0;
|
|
return 1;
|
|
}
|
|
|
|
class CExitEventLauncher
|
|
{
|
|
public:
|
|
NWindows::NSynchronization::CManualResetEvent _exitEvent;
|
|
CExitEventLauncher()
|
|
{
|
|
if (_exitEvent.Create(false) != S_OK)
|
|
throw 9387173;
|
|
};
|
|
~CExitEventLauncher() { _exitEvent.Set(); }
|
|
} g_ExitEventLauncher;
|
|
|
|
#ifdef _WIN32
|
|
static THREAD_FUNC_DECL MyThreadFunction(void *param)
|
|
{
|
|
CMyAutoPtr<CTmpProcessInfo> tmpProcessInfoPtr((CTmpProcessInfo *)param);
|
|
CTmpProcessInfo *tpi = tmpProcessInfoPtr.get();
|
|
CChildProcesses &processes = tpi->Processes;
|
|
|
|
for (;;)
|
|
{
|
|
CRecordVector<HANDLE> handles;
|
|
CRecordVector<int> indices;
|
|
|
|
FOR_VECTOR (i, processes.Handles)
|
|
{
|
|
if (processes.NeedWait[i])
|
|
{
|
|
handles.Add(processes.Handles[i]);
|
|
indices.Add(i);
|
|
}
|
|
}
|
|
|
|
if (handles.IsEmpty())
|
|
break;
|
|
|
|
handles.Add(g_ExitEventLauncher._exitEvent);
|
|
|
|
DWORD waitResult = ::WaitForMultipleObjects(handles.Size(), &handles.Front(), FALSE, INFINITE);
|
|
|
|
if (waitResult >= (DWORD)handles.Size() - 1)
|
|
{
|
|
processes.CloseAll();
|
|
return waitResult >= (DWORD)handles.Size() ? 1 : 0;
|
|
}
|
|
processes.Update();
|
|
processes.DisableWait(indices[waitResult]);
|
|
}
|
|
|
|
NFind::CFileInfo newFileInfo;
|
|
if (newFileInfo.Find(tpi->FilePath))
|
|
{
|
|
if (tpi->WasChanged(newFileInfo))
|
|
{
|
|
UString message = MyFormatNew(IDS_WANT_UPDATE_MODIFIED_FILE, tpi->RelPath);
|
|
if (::MessageBoxW(g_HWND, message, L"7-Zip", MB_OKCANCEL | MB_ICONQUESTION) == IDOK)
|
|
{
|
|
if (SendMessage(tpi->Window, kOpenItemChanged, 0, (LONG_PTR)tpi) != 1)
|
|
{
|
|
::MessageBoxW(g_HWND, MyFormatNew(IDS_CANNOT_UPDATE_FILE,
|
|
fs2us(tpi->FilePath)), L"7-Zip", MB_OK | MB_ICONSTOP);
|
|
return 0;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
tpi->DeleteDirAndFile();
|
|
return 0;
|
|
}
|
|
#endif
|
|
|
|
#if defined(_WIN32) && !defined(UNDER_CE)
|
|
static const FChar *k_ZoneId_StreamName = FTEXT(":Zone.Identifier");
|
|
#endif
|
|
|
|
|
|
#ifndef UNDER_CE
|
|
|
|
static void ReadZoneFile(CFSTR fileName, CByteBuffer &buf)
|
|
{
|
|
buf.Free();
|
|
NIO::CInFile file;
|
|
if (!file.Open(fileName))
|
|
return;
|
|
UInt64 fileSize;
|
|
if (!file.GetLength(fileSize))
|
|
return;
|
|
if (fileSize == 0 || fileSize >= ((UInt32)1 << 20))
|
|
return;
|
|
buf.Alloc((size_t)fileSize);
|
|
UInt32 processed;
|
|
if (file.Read(buf, (UInt32)fileSize, processed) && processed == fileSize)
|
|
return;
|
|
buf.Free();
|
|
}
|
|
|
|
static bool WriteZoneFile(CFSTR fileName, const CByteBuffer &buf)
|
|
{
|
|
NIO::COutFile file;
|
|
if (!file.Create(fileName, true))
|
|
return false;
|
|
UInt32 processed;
|
|
if (!file.Write(buf, (UInt32)buf.Size(), processed))
|
|
return false;
|
|
return processed == buf.Size();
|
|
}
|
|
|
|
#endif
|
|
|
|
/*
|
|
class CBufSeqOutStream_WithFile:
|
|
public ISequentialOutStream,
|
|
public CMyUnknownImp
|
|
{
|
|
Byte *_buffer;
|
|
size_t _size;
|
|
size_t _pos;
|
|
|
|
|
|
size_t _fileWritePos;
|
|
bool fileMode;
|
|
public:
|
|
|
|
bool IsStreamInMem() const { return !fileMode; }
|
|
size_t GetMemStreamWrittenSize() const { return _pos; }
|
|
|
|
// ISequentialOutStream *FileStream;
|
|
FString FilePath;
|
|
COutFileStream *outFileStreamSpec;
|
|
CMyComPtr<ISequentialOutStream> outFileStream;
|
|
|
|
CBufSeqOutStream_WithFile(): outFileStreamSpec(NULL) {}
|
|
|
|
void Init(Byte *buffer, size_t size)
|
|
{
|
|
fileMode = false;
|
|
_buffer = buffer;
|
|
_pos = 0;
|
|
_size = size;
|
|
_fileWritePos = 0;
|
|
}
|
|
|
|
HRESULT FlushToFile();
|
|
size_t GetPos() const { return _pos; }
|
|
|
|
MY_UNKNOWN_IMP
|
|
STDMETHOD(Write)(const void *data, UInt32 size, UInt32 *processedSize);
|
|
};
|
|
|
|
static const UInt32 kBlockSize = ((UInt32)1 << 31);
|
|
|
|
STDMETHODIMP CBufSeqOutStream_WithFile::Write(const void *data, UInt32 size, UInt32 *processedSize)
|
|
{
|
|
if (processedSize)
|
|
*processedSize = 0;
|
|
if (!fileMode)
|
|
{
|
|
if (_size - _pos >= size)
|
|
{
|
|
if (size != 0)
|
|
{
|
|
memcpy(_buffer + _pos, data, size);
|
|
_pos += size;
|
|
}
|
|
if (processedSize)
|
|
*processedSize = (UInt32)size;
|
|
return S_OK;
|
|
}
|
|
|
|
fileMode = true;
|
|
}
|
|
RINOK(FlushToFile());
|
|
return outFileStream->Write(data, size, processedSize);
|
|
}
|
|
|
|
HRESULT CBufSeqOutStream_WithFile::FlushToFile()
|
|
{
|
|
if (!outFileStream)
|
|
{
|
|
outFileStreamSpec = new COutFileStream;
|
|
outFileStream = outFileStreamSpec;
|
|
if (!outFileStreamSpec->Create(FilePath, false))
|
|
{
|
|
outFileStream.Release();
|
|
return E_FAIL;
|
|
// MessageBoxMyError(UString(L"Can't create file ") + fs2us(tempFilePath));
|
|
}
|
|
}
|
|
while (_fileWritePos != _pos)
|
|
{
|
|
size_t cur = _pos - _fileWritePos;
|
|
UInt32 curSize = (cur < kBlockSize) ? (UInt32)cur : kBlockSize;
|
|
UInt32 processedSizeLoc = 0;
|
|
HRESULT res = outFileStream->Write(_buffer + _fileWritePos, curSize, &processedSizeLoc);
|
|
_fileWritePos += processedSizeLoc;
|
|
RINOK(res);
|
|
if (processedSizeLoc == 0)
|
|
return E_FAIL;
|
|
}
|
|
return S_OK;
|
|
}
|
|
*/
|
|
|
|
/*
|
|
static HRESULT GetTime(IFolderFolder *folder, UInt32 index, PROPID propID, FILETIME &filetime, bool &filetimeIsDefined)
|
|
{
|
|
filetimeIsDefined = false;
|
|
NCOM::CPropVariant prop;
|
|
RINOK(folder->GetProperty(index, propID, &prop));
|
|
if (prop.vt == VT_FILETIME)
|
|
{
|
|
filetime = prop.filetime;
|
|
filetimeIsDefined = (filetime.dwHighDateTime != 0 || filetime.dwLowDateTime != 0);
|
|
}
|
|
else if (prop.vt != VT_EMPTY)
|
|
return E_FAIL;
|
|
return S_OK;
|
|
}
|
|
*/
|
|
|
|
void CPanel::OpenItemInArchive(int index, bool tryInternal, bool tryExternal, bool editMode, bool useEditor, const wchar_t *type)
|
|
{
|
|
const UString name = GetItemName(index);
|
|
const UString relPath = GetItemRelPath(index);
|
|
|
|
if (IsVirus_Message(name))
|
|
return;
|
|
|
|
if (!_folderOperations)
|
|
{
|
|
MessageBoxErrorLang(IDS_OPERATION_IS_NOT_SUPPORTED);
|
|
return;
|
|
}
|
|
|
|
bool tryAsArchive = tryInternal && (!tryExternal || !DoItemAlwaysStart(name));
|
|
|
|
UString fullVirtPath = _currentFolderPrefix + relPath;
|
|
|
|
CTempDir tempDirectory;
|
|
if (!tempDirectory.Create(kTempDirPrefix))
|
|
{
|
|
MessageBoxLastError();
|
|
return;
|
|
}
|
|
FString tempDir = tempDirectory.GetPath();
|
|
FString tempDirNorm = tempDir;
|
|
NName::NormalizeDirPathPrefix(tempDirNorm);
|
|
const FString tempFilePath = tempDirNorm + us2fs(Get_Correct_FsFile_Name(name));
|
|
|
|
CTempFileInfo tempFileInfo;
|
|
tempFileInfo.FileIndex = index;
|
|
tempFileInfo.RelPath = relPath;
|
|
tempFileInfo.FolderPath = tempDir;
|
|
tempFileInfo.FilePath = tempFilePath;
|
|
tempFileInfo.NeedDelete = true;
|
|
|
|
if (tryAsArchive)
|
|
{
|
|
CMyComPtr<IInArchiveGetStream> getStream;
|
|
_folder.QueryInterface(IID_IInArchiveGetStream, &getStream);
|
|
if (getStream)
|
|
{
|
|
CMyComPtr<ISequentialInStream> subSeqStream;
|
|
getStream->GetStream(index, &subSeqStream);
|
|
if (subSeqStream)
|
|
{
|
|
CMyComPtr<IInStream> subStream;
|
|
subSeqStream.QueryInterface(IID_IInStream, &subStream);
|
|
if (subStream)
|
|
{
|
|
bool encrypted;
|
|
HRESULT res = OpenItemAsArchive(subStream, tempFileInfo, fullVirtPath, type ? type : L"", encrypted);
|
|
if (res == S_OK)
|
|
{
|
|
tempDirectory.DisableDeleting();
|
|
RefreshListCtrl();
|
|
return;
|
|
}
|
|
if (res == E_ABORT)
|
|
return;
|
|
if (res != S_FALSE)
|
|
{
|
|
// probably we must show some message here
|
|
// return;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
CRecordVector<UInt32> indices;
|
|
indices.Add(index);
|
|
|
|
UStringVector messages;
|
|
|
|
bool usePassword = false;
|
|
UString password;
|
|
if (_parentFolders.Size() > 0)
|
|
{
|
|
const CFolderLink &fl = _parentFolders.Back();
|
|
usePassword = fl.UsePassword;
|
|
password = fl.Password;
|
|
}
|
|
|
|
#if defined(_WIN32) && !defined(UNDER_CE)
|
|
CByteBuffer zoneBuf;
|
|
#ifndef _UNICODE
|
|
if (g_IsNT)
|
|
#endif
|
|
if (_parentFolders.Size() > 0)
|
|
{
|
|
const CFolderLink &fl = _parentFolders.Front();
|
|
if (!fl.IsVirtual && !fl.FilePath.IsEmpty())
|
|
ReadZoneFile(fl.FilePath + k_ZoneId_StreamName, zoneBuf);
|
|
}
|
|
#endif
|
|
|
|
|
|
CVirtFileSystem *virtFileSystemSpec = NULL;
|
|
CMyComPtr<ISequentialOutStream> virtFileSystem;
|
|
|
|
bool isAltStream = IsItem_AltStream(index);
|
|
|
|
CCopyToOptions options;
|
|
options.includeAltStreams = true;
|
|
options.replaceAltStreamChars = isAltStream;
|
|
|
|
if (tryAsArchive)
|
|
{
|
|
NCOM::CPropVariant prop;
|
|
_folder->GetProperty(index, kpidSize, &prop);
|
|
UInt64 fileLimit = g_RAM_Size / 4;
|
|
UInt64 fileSize = 0;
|
|
if (!ConvertPropVariantToUInt64(prop, fileSize))
|
|
fileSize = fileLimit;
|
|
if (fileSize <= fileLimit && fileSize > 0)
|
|
{
|
|
options.streamMode = true;
|
|
virtFileSystemSpec = new CVirtFileSystem;
|
|
virtFileSystem = virtFileSystemSpec;
|
|
// we allow additional total size for small alt streams;
|
|
virtFileSystemSpec->MaxTotalAllocSize = fileSize + (1 << 10);
|
|
|
|
virtFileSystemSpec->DirPrefix = tempDirNorm;
|
|
virtFileSystemSpec->Init();
|
|
options.VirtFileSystem = virtFileSystem;
|
|
options.VirtFileSystemSpec = virtFileSystemSpec;
|
|
}
|
|
}
|
|
|
|
options.folder = fs2us(tempDirNorm);
|
|
options.showErrorMessages = true;
|
|
HRESULT result = CopyTo(options, indices, &messages, usePassword, password);
|
|
|
|
if (_parentFolders.Size() > 0)
|
|
{
|
|
CFolderLink &fl = _parentFolders.Back();
|
|
fl.UsePassword = usePassword;
|
|
fl.Password = password;
|
|
}
|
|
|
|
if (!messages.IsEmpty())
|
|
return;
|
|
if (result != S_OK)
|
|
{
|
|
if (result != E_ABORT)
|
|
MessageBoxError(result);
|
|
return;
|
|
}
|
|
|
|
if (options.VirtFileSystem)
|
|
{
|
|
if (virtFileSystemSpec->IsStreamInMem())
|
|
{
|
|
const CVirtFile &file = virtFileSystemSpec->Files[0];
|
|
|
|
size_t streamSize = (size_t)file.Size;
|
|
CBufInStream *bufInStreamSpec = new CBufInStream;
|
|
CMyComPtr<IInStream> bufInStream = bufInStreamSpec;
|
|
bufInStreamSpec->Init(file.Data, streamSize, virtFileSystem);
|
|
bool encrypted;
|
|
if (OpenItemAsArchive(bufInStream, tempFileInfo, fullVirtPath, type ? type : L"", encrypted) == S_OK)
|
|
{
|
|
tempDirectory.DisableDeleting();
|
|
RefreshListCtrl();
|
|
return;
|
|
}
|
|
if (virtFileSystemSpec->FlushToDisk(true) != S_OK)
|
|
return;
|
|
}
|
|
}
|
|
|
|
|
|
#if defined(_WIN32) && !defined(UNDER_CE)
|
|
if (zoneBuf.Size() != 0)
|
|
{
|
|
if (NFind::DoesFileExist(tempFilePath))
|
|
{
|
|
WriteZoneFile(tempFilePath + k_ZoneId_StreamName, zoneBuf);
|
|
}
|
|
}
|
|
#endif
|
|
|
|
|
|
if (tryAsArchive)
|
|
{
|
|
bool encrypted;
|
|
if (OpenItemAsArchive(NULL, tempFileInfo, fullVirtPath, type ? type : L"", encrypted) == S_OK)
|
|
{
|
|
tempDirectory.DisableDeleting();
|
|
RefreshListCtrl();
|
|
return;
|
|
}
|
|
}
|
|
|
|
CMyAutoPtr<CTmpProcessInfo> tmpProcessInfoPtr(new CTmpProcessInfo());
|
|
CTmpProcessInfo *tpi = tmpProcessInfoPtr.get();
|
|
tpi->FolderPath = tempDir;
|
|
tpi->FilePath = tempFilePath;
|
|
tpi->NeedDelete = true;
|
|
tpi->UsePassword = usePassword;
|
|
tpi->Password = password;
|
|
|
|
if (!tpi->FileInfo.Find(tempFilePath))
|
|
return;
|
|
|
|
CTmpProcessInfoRelease tmpProcessInfoRelease(*tpi);
|
|
|
|
if (!tryExternal)
|
|
return;
|
|
|
|
// CProcess process;
|
|
// HRESULT res;
|
|
if (editMode)
|
|
/* res = */ StartEditApplication(fs2us(tempFilePath), useEditor, (HWND)*this /* , process */ );
|
|
else
|
|
/* res = */ StartApplication(fs2us(tempDirNorm), fs2us(tempFilePath), (HWND)*this /* , process */ );
|
|
|
|
#ifdef _WIN32
|
|
if ((HANDLE)process == 0)
|
|
return;
|
|
|
|
tpi->Window = (HWND)(*this);
|
|
tpi->FullPathFolderPrefix = _currentFolderPrefix;
|
|
tpi->FileIndex = index;
|
|
tpi->RelPath = relPath;
|
|
tpi->Processes.AddProcess(process.Detach());
|
|
|
|
NWindows::CThread thread;
|
|
if (thread.Create(MyThreadFunction, tpi) != S_OK)
|
|
throw 271824;
|
|
#endif
|
|
tempDirectory.DisableDeleting();
|
|
tmpProcessInfoPtr.release();
|
|
tmpProcessInfoRelease._needDelete = false;
|
|
}
|
|
|
|
/*
|
|
static const UINT64 kTimeLimit = UINT64(10000000) * 3600 * 24;
|
|
|
|
static bool CheckDeleteItem(UINT64 currentFileTime, UINT64 folderFileTime)
|
|
{
|
|
return (currentFileTime - folderFileTime > kTimeLimit &&
|
|
folderFileTime - currentFileTime > kTimeLimit);
|
|
}
|
|
|
|
void DeleteOldTempFiles()
|
|
{
|
|
UString tempPath;
|
|
if(!MyGetTempPath(tempPath))
|
|
throw 1;
|
|
|
|
UINT64 currentFileTime;
|
|
NTime::GetCurUtcFileTime(currentFileTime);
|
|
UString searchWildCard = tempPath + kTempDirPrefix + L"*.tmp";
|
|
searchWildCard += WCHAR(NName::kAnyStringWildcard);
|
|
NFind::CEnumeratorW enumerator(searchWildCard);
|
|
NFind::CFileInfo fileInfo;
|
|
while(enumerator.Next(fileInfo))
|
|
{
|
|
if (!fileInfo.IsDir())
|
|
continue;
|
|
const UINT64 &cTime = *(const UINT64 *)(&fileInfo.CTime);
|
|
if(CheckDeleteItem(cTime, currentFileTime))
|
|
RemoveDirectoryWithSubItems(tempPath + fileInfo.Name);
|
|
}
|
|
}
|
|
*/
|