int OperationFailed(const string& Object, LNGID Title, const string& Description, bool AllowSkip) { std::vector<string> Msg; IFileIsInUse *pfiu = nullptr; LNGID Reason = MObjectLockedReasonOpened; bool SwitchBtn = false, CloseBtn = false; DWORD Error = Global->CaughtError(); if(Error == ERROR_ACCESS_DENIED || Error == ERROR_SHARING_VIOLATION || Error == ERROR_LOCK_VIOLATION || Error == ERROR_DRIVE_LOCKED) { string FullName; ConvertNameToFull(Object, FullName); pfiu = CreateIFileIsInUse(FullName); if (pfiu) { FILE_USAGE_TYPE UsageType = FUT_GENERIC; pfiu->GetUsage(&UsageType); switch(UsageType) { case FUT_PLAYING: Reason = MObjectLockedReasonPlayed; break; case FUT_EDITING: Reason = MObjectLockedReasonEdited; break; case FUT_GENERIC: Reason = MObjectLockedReasonOpened; break; } DWORD Capabilities = 0; pfiu->GetCapabilities(&Capabilities); if(Capabilities&OF_CAP_CANSWITCHTO) { SwitchBtn = true; } if(Capabilities&OF_CAP_CANCLOSE) { CloseBtn = true; } LPWSTR AppName = nullptr; if(SUCCEEDED(pfiu->GetAppName(&AppName))) { Msg.emplace_back(AppName); } } else { DWORD dwSession; WCHAR szSessionKey[CCH_RM_SESSION_KEY+1] = {}; if (Imports().RmStartSession(&dwSession, 0, szSessionKey) == ERROR_SUCCESS) { PCWSTR pszFile = FullName.data(); if (Imports().RmRegisterResources(dwSession, 1, &pszFile, 0, nullptr, 0, nullptr) == ERROR_SUCCESS) { DWORD dwReason; DWORD RmGetListResult; UINT nProcInfoNeeded; UINT nProcInfo = 1; std::vector<RM_PROCESS_INFO> rgpi(nProcInfo); while((RmGetListResult=Imports().RmGetList(dwSession, &nProcInfoNeeded, &nProcInfo, rgpi.data(), &dwReason)) == ERROR_MORE_DATA) { nProcInfo = nProcInfoNeeded; rgpi.resize(nProcInfo); } if(RmGetListResult ==ERROR_SUCCESS) { for (size_t i = 0; i < nProcInfo; i++) { string tmp = rgpi[i].strAppName; if (*rgpi[i].strServiceShortName) { tmp.append(L" [").append(rgpi[i].strServiceShortName).append(L"]"); } tmp += L" (PID: " + std::to_wstring(rgpi[i].Process.dwProcessId); HANDLE hProcess = OpenProcess(PROCESS_QUERY_LIMITED_INFORMATION, FALSE, rgpi[i].Process.dwProcessId); if (hProcess) { FILETIME ftCreate, ftExit, ftKernel, ftUser; if (GetProcessTimes(hProcess, &ftCreate, &ftExit, &ftKernel, &ftUser) && rgpi[i].Process.ProcessStartTime == ftCreate) { string Name; if (os::GetModuleFileNameEx(hProcess, nullptr, Name)) { tmp += L", " + Name; } } CloseHandle(hProcess); } tmp += L")"; Msg.emplace_back(tmp); } } } Imports().RmEndSession(dwSession); } } } auto Msgs = make_vector(Description, QuoteLeadingSpace(string(Object))); if(!Msg.empty()) { Msgs.emplace_back(LangString(MObjectLockedReason) << MSG(Reason)); Msgs.insert(Msgs.end(), ALL_CONST_RANGE(Msg)); } std::vector<string> Buttons; Buttons.reserve(4); if(SwitchBtn) { Buttons.emplace_back(MSG(MObjectLockedSwitchTo)); } Buttons.emplace_back(MSG(CloseBtn? MObjectLockedClose : MDeleteRetry)); if(AllowSkip) { Buttons.emplace_back(MSG(MDeleteSkip)); Buttons.emplace_back(MSG(MDeleteFileSkipAll)); } Buttons.emplace_back(MSG(MDeleteCancel)); int Result = -1; for(;;) { Result = Message(MSG_WARNING|MSG_ERRORTYPE, MSG(Title), Msgs, Buttons); if(SwitchBtn) { if(Result == 0) { HWND Wnd = nullptr; if (pfiu && SUCCEEDED(pfiu->GetSwitchToHWND(&Wnd))) { SetForegroundWindow(Wnd); if (IsIconic(Wnd)) ShowWindow(Wnd, SW_RESTORE); } continue; } else if(Result > 0) { --Result; } } if(CloseBtn && Result == 0) { // close & retry if (pfiu) { pfiu->CloseFile(); } } break; } if (pfiu) { pfiu->Release(); } return Result; }
ShellDelete::ShellDelete(Panel *SrcPanel,bool Wipe): ReadOnlyDeleteMode(-1), m_SkipMode(-1), SkipWipeMode(-1), SkipFoldersMode(-1), ProcessedItems(0) { SCOPED_ACTION(ChangePriority)(Global->Opt->DelThreadPriority); SCOPED_ACTION(TPreRedrawFuncGuard)(std::make_unique<DelPreRedrawItem>()); os::FAR_FIND_DATA FindData; string strDeleteFilesMsg; string strSelName; string strSelShortName; string strDizName; DWORD FileAttr; size_t SelCount; int UpdateDiz; int DizPresent; int Ret; BOOL NeedUpdate=TRUE, NeedSetUpADir=FALSE; bool Opt_DeleteToRecycleBin=Global->Opt->DeleteToRecycleBin; /*& 31.05.2001 OT Запретить перерисовку текущего окна*/ auto WindowFromLaunched = Global->WindowManager->GetCurrentWindow(); WindowFromLaunched->Lock(); bool DeleteAllFolders=!Global->Opt->Confirm.DeleteFolder; UpdateDiz=(Global->Opt->Diz.UpdateMode==DIZ_UPDATE_ALWAYS || (SrcPanel->IsDizDisplayed() && Global->Opt->Diz.UpdateMode==DIZ_UPDATE_IF_DISPLAYED)); SCOPE_EXIT { Global->Opt->DeleteToRecycleBin=Opt_DeleteToRecycleBin; // Разрешить перерисовку окна WindowFromLaunched->Unlock(); if (NeedUpdate) { ShellUpdatePanels(SrcPanel,NeedSetUpADir); } }; if (!(SelCount=SrcPanel->GetSelCount())) return; // Удаление в корзину только для FIXED-дисков { string strRoot; SrcPanel->GetSelName(nullptr,FileAttr); SrcPanel->GetSelName(&strSelName,FileAttr); ConvertNameToFull(strSelName, strRoot); GetPathRoot(strRoot,strRoot); if (Global->Opt->DeleteToRecycleBin && FAR_GetDriveType(strRoot) != DRIVE_FIXED) Global->Opt->DeleteToRecycleBin=0; } if (SelCount==1) { SrcPanel->GetSelName(nullptr,FileAttr); SrcPanel->GetSelName(&strSelName,FileAttr); if (TestParentFolderName(strSelName) || strSelName.empty()) { NeedUpdate=FALSE; return; } strDeleteFilesMsg = strSelName; QuoteLeadingSpace(strDeleteFilesMsg); } else { // в зависимости от числа ставим нужное окончание const wchar_t *Ends; FormatString StrItems; StrItems << SelCount; Ends=MSG(MAskDeleteItemsA); size_t LenItems = StrItems.size(); if (LenItems > 0) { if ((LenItems >= 2 && StrItems[LenItems-2] == L'1') || StrItems[LenItems-1] >= L'5' || StrItems[LenItems-1] == L'0') Ends=MSG(MAskDeleteItemsS); else if (StrItems[LenItems-1] == L'1') Ends=MSG(MAskDeleteItems0); } strDeleteFilesMsg = LangString(MAskDeleteItems) << SelCount << Ends; } Ret=1; // Обработка "удаления" линков if ((FileAttr & FILE_ATTRIBUTE_REPARSE_POINT) && SelCount==1) { string strJuncName; ConvertNameToFull(strSelName,strJuncName); if (GetReparsePointInfo(strJuncName, strJuncName)) // ? SelName ? { NormalizeSymlinkName(strJuncName); string strAskDeleteLink=MSG(MAskDeleteLink); os::fs::file_status Status(strJuncName); if (os::fs::exists(Status)) { strAskDeleteLink+=L" "; strAskDeleteLink += MSG(is_directory(Status)? MAskDeleteLinkFolder : MAskDeleteLinkFile); } Ret=Message(0,2,MSG(MDeleteLinkTitle), strDeleteFilesMsg.data(), strAskDeleteLink.data(), strJuncName.data(), MSG(MDeleteLinkDelete), MSG(MCancel)); if (Ret) return; } } if (Ret && Global->Opt->Confirm.Delete) { LNGID mTitle = Wipe ? MDeleteWipeTitle : MDeleteTitle; LNGID mDText; string tText; LNGID mDBttn = Wipe ? MDeleteWipe : Global->Opt->DeleteToRecycleBin ? MDeleteRecycle : MDelete; bool bHilite = Global->Opt->DelOpt.HighlightSelected; int mshow = std::min(std::max((int)Global->Opt->DelOpt.ShowSelected, 1), ScrY/2); std::vector<string> items; items.push_back(strDeleteFilesMsg); if (SelCount == 1) { bool folder = (FileAttr & FILE_ATTRIBUTE_DIRECTORY) != 0; if (Wipe && !(FileAttr & FILE_ATTRIBUTE_REPARSE_POINT)) mDText = folder ? MAskWipeFolder : MAskWipeFile; else { if (Global->Opt->DeleteToRecycleBin) mDText = folder ? MAskDeleteRecycleFolder : MAskDeleteRecycleFile; else mDText = folder ? MAskDeleteFolder : MAskDeleteFile; } if (bHilite) { string name, sname; SrcPanel->GetCurName(name, sname); QuoteLeadingSpace(name); bHilite = strDeleteFilesMsg != name; } } else { if (Wipe) { mDText = MAskWipe; mTitle = MDeleteWipeTitle; } else mDText = Global->Opt->DeleteToRecycleBin ? MAskDeleteRecycle : MAskDelete; if (mshow > 1) { tText = MSG(mDText) + string(L" ") + strDeleteFilesMsg; items.clear(); DWORD attr; string name; SrcPanel->GetSelName(nullptr, attr); for (size_t i = 0; i < SelCount; ++i) { if (i == (size_t)mshow-1 && i+1 < SelCount) { items.push_back(L"..."); break; } SrcPanel->GetSelName(&name, attr); QuoteLeadingSpace(name); items.push_back(name); } } } intptr_t start_hilite = 0, end_hilite = 0; DialogBuilder Builder(mTitle, nullptr, [&](Dialog* Dlg, intptr_t Msg, intptr_t Param1, void* Param2) -> intptr_t { if (bHilite && Msg == DN_CTLCOLORDLGITEM && Param1 >= start_hilite && Param1 <= end_hilite) { auto Colors = static_cast<FarDialogItemColors*>(Param2); Colors->Colors[0] = Colors->Colors[1]; } return Dlg->DefProc(Msg, Param1, Param2); }); if (tText.empty()) tText = MSG(mDText); Builder.AddText(tText.data())->Flags = DIF_CENTERTEXT; if (bHilite || (mshow > 1 && SelCount > 1)) Builder.AddSeparator(); std::for_each(RANGE(items, i) { TruncStrFromCenter(i, ScrX+1-6*2); auto dx = Builder.AddText(i.data()); dx->Flags = (SelCount <= 1 || mshow <= 1 ? DIF_CENTERTEXT : 0) | DIF_SHOWAMPERSAND; size_t index = Builder.GetLastID(); end_hilite = index; if (!start_hilite) start_hilite = index; });