Showing preview only (443K chars total). Download the full file or copy to clipboard to get everything.
Repository: hxseven/Remove-Empty-Directories
Branch: master
Commit: d31505f04ce2
Files: 44
Total size: 424.7 KB
Directory structure:
gitextract_p_szlfn3/
├── .gitignore
├── Installer/
│ ├── README.md
│ ├── legacy-files/
│ │ ├── legacy-disclaimer.txt
│ │ ├── manifest-info.txt
│ │ ├── red_installer-v1.iss
│ │ ├── require_administrator.manifest
│ │ └── set_require_administrator.bat
│ ├── license.txt
│ └── red_installer.iss
├── LICENSE
├── README.md
├── RED2/
│ ├── DeletionError.Designer.cs
│ ├── DeletionError.cs
│ ├── DeletionError.resx
│ ├── Lib/
│ │ ├── Core.cs
│ │ ├── DeletionWorker.cs
│ │ ├── Enums.cs
│ │ ├── Events.cs
│ │ ├── FindEmptyDirectoryWorker.cs
│ │ ├── RuntimeData.cs
│ │ ├── SystemFunctions.cs
│ │ ├── TreeManager.cs
│ │ └── UIHelpers.cs
│ ├── LogWindow.Designer.cs
│ ├── LogWindow.cs
│ ├── LogWindow.resx
│ ├── MainWindow.Designer.cs
│ ├── MainWindow.cs
│ ├── MainWindow.resx
│ ├── Program.cs
│ ├── Properties/
│ │ ├── AssemblyInfo.cs
│ │ ├── Resources.Designer.cs
│ │ ├── Resources.resx
│ │ ├── Resources_de.resx
│ │ ├── Settings.Designer.cs
│ │ └── Settings.settings
│ ├── RED2.csproj
│ ├── RED2.csproj.user
│ ├── app.config
│ ├── app.manifest
│ └── packages.config
├── Scripts/
│ ├── create-1000-empty-directories.bat
│ └── create-test-directories.bat
└── red2_project.sln
================================================
FILE CONTENTS
================================================
================================================
FILE: .gitignore
================================================
*.suo
RED2/bin/
RED2/obj/
RED2/publish/
Installer/output/
Installer/bin/
.vs
packages/
Scripts/test-*
================================================
FILE: Installer/README.md
================================================
# RED Installer
This directory contains all resources related to the RED installer.
I wrote this document mostly for myself because I forgot how I did it last time.
Maybe it can be helpful to others too.
## How-to generate a new installer
### Step 1: Build binaries
* Install Microsoft Visual Studio (Community), I used version 2019
* Open the project file "red2_project.sln"
* Change to build configuration to "Release-x86" and build the solution
* Then change the build configuration to "Release-x64" and build the solution again
### Step 2: Compile installer
* Install Inno Setup (Version 6.1+)
* Make sure you build the binaries first (see step 1)
* Open red_installer-v2.iss with Inno Setup
* Select "Compile" in the "Build" menu
* Inno Setup should automatically find and use the newly generated binaries, otherwise, paths in the iss file might need to be fixed
* Inno Setup should now compile a new installer and save it into the bin/ folder below this directory
* Check the compiler output of Inno Setup to see if there were any problems
* Done :)
================================================
FILE: Installer/legacy-files/legacy-disclaimer.txt
================================================
# Archived legacy disclaimer
## Remark from 2021
No more cases where reported since about ten years, so I removed this disclaimer from the main license and info files.
Keeping this file is for historic reasons.
## Original message
To be honest with you as user of RED I have to tell you that one user of RED
(v2.1) reported that it deleted folders which were not completely empty and
contained files important to him. I'm really very sorry for that! I checked all
routines of RED several times to ensure nothing goes wrong, but somehow it
happened on the system of that user. Unfortunately, I could not determine what
caused that behaviour. In addition to that the user did not wanted to try to
locate the error, because he was (understandably) very upset and uninstalled RED
instantly. But he told me that the directory names contained chinese characters.
So I tried to reproduce the error by testing RED with foreign directory names.
But I could not find a bug - RED worked as expected.
My conclusion: I currently assume it was a unfortunate exception or some sort
of misconfiguration and I hope that it does not happen again. I also refactored
and optimized the whole sourcecode of RED 2.2 to improve the stability and the
error handling.
To sum up, if you use RED for the first time have a look at the directories
RED found and rethink if they are plausible. And if you want to be really
safe double-click a few folders to see if they are really empty. This
especially applies to systems with directory names containing any special
characters. Contact me if you notice anything strange.
BTW: As I originally developed RED for myself therefore I took particular
care to ensure everything works correctly.
================================================
FILE: Installer/legacy-files/manifest-info.txt
================================================
http://msdn.microsoft.com/en-us/library/bb756929.aspx
================================================
FILE: Installer/legacy-files/red_installer-v1.iss
================================================
; Script generated by the Inno Setup Script Wizard.
; SEE THE DOCUMENTATION FOR DETAILS ON CREATING INNO SETUP SCRIPT FILES!
#include "scripts\products.iss"
#include "scripts\products\dotnetfx35.iss"
[Setup]
; NOTE: The value of AppId uniquely identifies this application.
; Do not use the same AppId value in installers for other applications.
; (To generate a new GUID, click Tools | Generate GUID inside the IDE.)
AppId={{06F25DC8-71E2-44E2-805A-F15E15B51C74}
;AppId=Remove Empty Directories
AppName=Remove Empty Directories
;AppVersion=2.2
AppVersion=2.2 (Admin Editon)
AppPublisher=Jonas John
AppCopyright=Remove Empty Directories Jonas John 2006-2011
AppPublisherURL=http://www.jonasjohn.de/
AppSupportURL=http://www.jonasjohn.de/
AppUpdatesURL=http://www.jonasjohn.de/
DefaultDirName={pf}\Remove Empty Directories
DefaultGroupName=Remove Empty Directories
AllowNoIcons=true
LicenseFile=license.txt
;OutputBaseFilename=red-v2.2-setup
OutputBaseFilename=red-v2.2-setup-admin
SourceDir=.
OutputDir=output\
;SetupIconFile=red.ico
Compression=lzma
SolidCompression=true
UninstallDisplayIcon={app}\RED2.exe
;MinVersion=4.1,5.0
;PrivilegesRequired=admin
;ArchitecturesAllowed=x86 x64 ia64
;ArchitecturesInstallIn64BitMode=x64 ia64
[Languages]
Name: en; MessagesFile: compiler:Default.isl
;Name: "de"; MessagesFile: "compiler:Languages\German.isl"
[Tasks]
Name: desktopicon; Description: {cm:CreateDesktopIcon}; GroupDescription: {cm:AdditionalIcons}; Flags: unchecked
; Name: quicklaunchicon; Description: {cm:CreateQuickLaunchIcon}; GroupDescription: {cm:AdditionalIcons}; Flags: unchecked; OnlyBelowVersion: 0,6.1
;Name: common; Description: "&All users"; GroupDescription: "Install For:"; Flags: exclusive unchecked
;Name: local; Description: "Just &me"; GroupDescription: "Install For:"; Flags: exclusive
[Files]
Source: RED2.exe; DestDir: {app}; Flags: ignoreversion
Source: license.txt; DestDir: {app}; Flags: ignoreversion
Source: credits.txt; DestDir: {app}; Flags: ignoreversion
; NOTE: Don't use "Flags: ignoreversion" on any shared system files
[InstallDelete]
; Delete old files from RED 2.1
Name: {group}\Readme file.lnk; Type: files
Name: {group}\Uninstall.lnk; Type: files
Name: {app}\readme.txt; Type: files
Name: {app}\lgpl.txt; Type: files
Name: {app}\RED2.exe.manifest; Type: files
Name: {app}\uninst.exe; Type: files
[UninstallDelete]
; cleanup - delete config dir
Name: {localappdata}\Remove_Empty_Directories; Type: filesandordirs; Tasks: ; Languages:
; Delete application directory if empty
Name: {app}; Type: dirifempty
[Icons]
Name: {group}\Remove Empty Directories; Filename: {app}\RED2.exe
Name: {group}\{cm:UninstallProgram,Remove Empty Directories}; Filename: {uninstallexe}
Name: {commondesktop}\Remove Empty Directories; Filename: {app}\RED2.exe; Tasks: desktopicon
;Name: {userappdata}\Microsoft\Internet Explorer\Quick Launch\Remove Empty Directories; Filename: {app}\RED2.exe; Tasks: quicklaunchicon
[Registry]
; remove explorer context entry if exists
Root: HKCR; Subkey: Folder\shell\Remove empty dirs; ValueType: string; Flags: uninsdeletekey deletekey dontcreatekey; Tasks: ; Languages:
[Run]
Filename: {app}\RED2.exe; Description: {cm:LaunchProgram,Remove Empty Directories}; Flags: nowait postinstall skipifsilent shellexec; Tasks: ; Languages:
[Code]
function InitializeSetup(): Boolean;
var
UninstallerPath: String;
ErrorCode: Integer;
begin
//install .net 3.5 if possible
dotnetfx35();
// Check whether application is already installed
if RegKeyExists(HKEY_LOCAL_MACHINE, 'SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\Remove Empty Directories') then
begin
if MsgBox('The setup has detected that RED is already installed on your computer. Do you wish to uninstall the previous version and continue with a fresh installation?', mbConfirmation, MB_YESNO) = IDYES then
begin
RegQueryStringValue(HKEY_LOCAL_MACHINE, 'SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\Remove Empty Directories', 'UninstallString', UninstallerPath);
// ShellExec('runas', uninstaller, '/SILENT', '', SW_HIDE, ewWaitUntilTerminated, ErrorCode);
// use above statement if extra level security is required usually it is not req
//ShellExec('open', UninstallerPath, '/S', '', SW_SHOW, ewWaitUntilTerminated, ErrorCode);
ShellExec('runas', UninstallerPath, '/S', '', SW_SHOW, ewWaitUntilTerminated, ErrorCode);
//Exec(UninstallerPath, '/S', '', SW_SHOWNORMAL, ewWaitUntilTerminated, ErrorCode);
end;
end;
Result := true;
end;
================================================
FILE: Installer/legacy-files/require_administrator.manifest
================================================
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
<ms_asmv2:trustInfo xmlns:ms_asmv2="urn:schemas-microsoft-com:asm.v2">
<ms_asmv2:security>
<ms_asmv2:requestedPrivileges>
<ms_asmv2:requestedExecutionLevel level="requireAdministrator" uiAccess="False" />
</ms_asmv2:requestedPrivileges>
</ms_asmv2:security>
</ms_asmv2:trustInfo>
</assembly>
================================================
FILE: Installer/legacy-files/set_require_administrator.bat
================================================
"C:\Program Files\Microsoft SDKs\Windows\v7.0A\bin\mt.exe" -manifest "require_administrator.manifest" -outputresource:"RED2.exe;#1"
pause
================================================
FILE: Installer/license.txt
================================================
DISCLAIMER
RED is a tool that DELETES stuff! So please be careful with it and its settings.
LICENSE
The program is distributed under the terms of the GNU Lesser General Public License which I copied from here: http://www.gnu.org/copyleft/lgpl.html
GNU LESSER GENERAL PUBLIC LICENSE
Version 3, 29 June 2007
Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
This version of the GNU Lesser General Public License incorporates
the terms and conditions of version 3 of the GNU General Public
License, supplemented by the additional permissions listed below.
0. Additional Definitions.
As used herein, "this License" refers to version 3 of the GNU Lesser
General Public License, and the "GNU GPL" refers to version 3 of the GNU
General Public License.
"The Library" refers to a covered work governed by this License,
other than an Application or a Combined Work as defined below.
An "Application" is any work that makes use of an interface provided
by the Library, but which is not otherwise based on the Library.
Defining a subclass of a class defined by the Library is deemed a mode
of using an interface provided by the Library.
A "Combined Work" is a work produced by combining or linking an
Application with the Library. The particular version of the Library
with which the Combined Work was made is also called the "Linked
Version".
The "Minimal Corresponding Source" for a Combined Work means the
Corresponding Source for the Combined Work, excluding any source code
for portions of the Combined Work that, considered in isolation, are
based on the Application, and not on the Linked Version.
The "Corresponding Application Code" for a Combined Work means the
object code and/or source code for the Application, including any data
and utility programs needed for reproducing the Combined Work from the
Application, but excluding the System Libraries of the Combined Work.
1. Exception to Section 3 of the GNU GPL.
You may convey a covered work under sections 3 and 4 of this License
without being bound by section 3 of the GNU GPL.
2. Conveying Modified Versions.
If you modify a copy of the Library, and, in your modifications, a
facility refers to a function or data to be supplied by an Application
that uses the facility (other than as an argument passed when the
facility is invoked), then you may convey a copy of the modified
version:
a) under this License, provided that you make a good faith effort to
ensure that, in the event an Application does not supply the
function or data, the facility still operates, and performs
whatever part of its purpose remains meaningful, or
b) under the GNU GPL, with none of the additional permissions of
this License applicable to that copy.
3. Object Code Incorporating Material from Library Header Files.
The object code form of an Application may incorporate material from
a header file that is part of the Library. You may convey such object
code under terms of your choice, provided that, if the incorporated
material is not limited to numerical parameters, data structure
layouts and accessors, or small macros, inline functions and templates
(ten or fewer lines in length), you do both of the following:
a) Give prominent notice with each copy of the object code that the
Library is used in it and that the Library and its use are
covered by this License.
b) Accompany the object code with a copy of the GNU GPL and this license
document.
4. Combined Works.
You may convey a Combined Work under terms of your choice that,
taken together, effectively do not restrict modification of the
portions of the Library contained in the Combined Work and reverse
engineering for debugging such modifications, if you also do each of
the following:
a) Give prominent notice with each copy of the Combined Work that
the Library is used in it and that the Library and its use are
covered by this License.
b) Accompany the Combined Work with a copy of the GNU GPL and this license
document.
c) For a Combined Work that displays copyright notices during
execution, include the copyright notice for the Library among
these notices, as well as a reference directing the user to the
copies of the GNU GPL and this license document.
d) Do one of the following:
0) Convey the Minimal Corresponding Source under the terms of this
License, and the Corresponding Application Code in a form
suitable for, and under terms that permit, the user to
recombine or relink the Application with a modified version of
the Linked Version to produce a modified Combined Work, in the
manner specified by section 6 of the GNU GPL for conveying
Corresponding Source.
1) Use a suitable shared library mechanism for linking with the
Library. A suitable mechanism is one that (a) uses at run time
a copy of the Library already present on the user's computer
system, and (b) will operate properly with a modified version
of the Library that is interface-compatible with the Linked
Version.
e) Provide Installation Information, but only if you would otherwise
be required to provide such information under section 6 of the
GNU GPL, and only to the extent that such information is
necessary to install and execute a modified version of the
Combined Work produced by recombining or relinking the
Application with a modified version of the Linked Version. (If
you use option 4d0, the Installation Information must accompany
the Minimal Corresponding Source and Corresponding Application
Code. If you use option 4d1, you must provide the Installation
Information in the manner specified by section 6 of the GNU GPL
for conveying Corresponding Source.)
5. Combined Libraries.
You may place library facilities that are a work based on the
Library side by side in a single library together with other library
facilities that are not Applications and are not covered by this
License, and convey such a combined library under terms of your
choice, if you do both of the following:
a) Accompany the combined library with a copy of the same work based
on the Library, uncombined with any other library facilities,
conveyed under the terms of this License.
b) Give prominent notice with the combined library that part of it
is a work based on the Library, and explaining where to find the
accompanying uncombined form of the same work.
6. Revised Versions of the GNU Lesser General Public License.
The Free Software Foundation may publish revised and/or new versions
of the GNU Lesser General Public License from time to time. Such new
versions will be similar in spirit to the present version, but may
differ in detail to address new problems or concerns.
Each version is given a distinguishing version number. If the
Library as you received it specifies that a certain numbered version
of the GNU Lesser General Public License "or any later version"
applies to it, you have the option of following the terms and
conditions either of that published version or of any later version
published by the Free Software Foundation. If the Library as you
received it does not specify a version number of the GNU Lesser
General Public License, you may choose any version of the GNU Lesser
General Public License ever published by the Free Software Foundation.
If the Library as you received it specifies that a proxy can decide
whether future versions of the GNU Lesser General Public License shall
apply, that proxy's public statement of acceptance of any version is
permanent authorization for you to choose that version for the
Library.
The progam may also contain traces of nuts.
================================================
FILE: Installer/red_installer.iss
================================================
// contribute: https://github.com/DomGries/InnoDependencyInstaller
// official article: https://codeproject.com/Articles/20868/Inno-Setup-Dependency-Installer
#define APP_ID "06F25DC8-71E2-44E2-805A-F15E15B51C74"
#define MyAppSetupName "Remove Empty Directories"
#define MyAppVersion "2.3"
#define MyAppPublisher "Jonas John"
#define MyAppCopyright 'Copyright (c) Jonas John'
#define MyAppURL "https://www.jonasjohn.de/"
#define MyAppSourceDir ""
#define MyAppExeName "RED2.exe"
#define SourceBinPathX86 "..\RED2\bin\x86\Release-x86\RED2.exe"
#define SourceBinPathX64 "..\RED2\bin\x64\Release-x64\RED2.exe"
; DLL is the same for X86 & X64
#define SourceDLLPath "..\RED2\bin\x86\Release-x86\AlphaFS.dll"
[Setup]
; NOTE: The value of AppId uniquely identifies this application. Do not use the same AppId value in installers for other applications.
; (To generate a new GUID, click Tools | Generate GUID inside the IDE.)
AppId={{{#APP_ID}}
AppName={#MyAppSetupName}
AppVersion={#MyAppVersion}
AppVerName={#MyAppSetupName} {#MyAppVersion}
AppCopyright={#MyAppCopyright}
VersionInfoVersion={#MyAppVersion}
VersionInfoCompany={#MyAppPublisher}
AppPublisher={#MyAppPublisher}
AppPublisherURL={#MyAppURL}
AppSupportURL={#MyAppURL}
AppUpdatesURL={#MyAppURL}
OutputBaseFilename=red-{#MyAppVersion}-setup
DefaultGroupName={#MyAppSetupName}
DefaultDirName={autopf}\{#MyAppSetupName}
UninstallDisplayIcon={app}\{#MyAppExeName}
; SourceDir={#MyAppSourceDir}
OutputDir={#SourcePath}\bin
AllowNoIcons=yes
LicenseFile=license.txt
; WizardStyle=modern
; Compression=lzma
SolidCompression=yes
MinVersion=6.0
PrivilegesRequired=admin
// remove next line if you only deploy 32-bit binaries and dependencies
ArchitecturesInstallIn64BitMode=x64
// dependency installation requires ready page and ready memo to be enabled (default behaviour)
DisableReadyPage=no
DisableReadyMemo=no
// shared code for installing the dependencies
[Code]
// types and variables
type
TDependency = record
Filename: String;
Parameters: String;
Title: String;
URL: String;
Checksum: String;
ForceSuccess: Boolean;
InstallClean: Boolean;
RebootAfter: Boolean;
end;
InstallResult = (InstallSuccessful, InstallRebootRequired, InstallError);
var
MemoInstallInfo: String;
Dependencies: array of TDependency;
DelayedReboot, ForceX86: Boolean;
DownloadPage: TDownloadWizardPage;
procedure AddDependency(const Filename, Parameters, Title, URL, Checksum: String; const ForceSuccess, InstallClean, RebootAfter: Boolean);
var
Dependency: TDependency;
I: Integer;
begin
MemoInstallInfo := MemoInstallInfo + #13#10 + '%1' + Title;
Dependency.Filename := Filename;
Dependency.Parameters := Parameters;
Dependency.Title := Title;
if FileExists(ExpandConstant('{tmp}{\}') + Filename) then begin
Dependency.URL := '';
end else begin
Dependency.URL := URL;
end;
Dependency.Checksum := Checksum;
Dependency.ForceSuccess := ForceSuccess;
Dependency.InstallClean := InstallClean;
Dependency.RebootAfter := RebootAfter;
I := GetArrayLength(Dependencies);
SetArrayLength(Dependencies, I + 1);
Dependencies[I] := Dependency;
end;
function IsPendingReboot: Boolean;
var
Value: String;
begin
Result := RegQueryMultiStringValue(HKEY_LOCAL_MACHINE, 'SYSTEM\CurrentControlSet\Control\Session Manager', 'PendingFileRenameOperations', Value) or
(RegQueryMultiStringValue(HKEY_LOCAL_MACHINE, 'SYSTEM\CurrentControlSet\Control\Session Manager', 'SetupExecute', Value) and (Value <> ''));
end;
function InstallProducts: InstallResult;
var
ResultCode, I, ProductCount: Integer;
begin
Result := InstallSuccessful;
ProductCount := GetArrayLength(Dependencies);
MemoInstallInfo := SetupMessage(msgReadyMemoTasks);
if ProductCount > 0 then begin
DownloadPage.Show;
for I := 0 to ProductCount - 1 do begin
if Dependencies[I].InstallClean and (DelayedReboot or IsPendingReboot) then begin
Result := InstallRebootRequired;
break;
end;
DownloadPage.SetText(Dependencies[I].Title, '');
DownloadPage.SetProgress(I + 1, ProductCount);
while True do begin
ResultCode := 0;
if ShellExec('', ExpandConstant('{tmp}{\}') + Dependencies[I].Filename, Dependencies[I].Parameters, '', SW_SHOWNORMAL, ewWaitUntilTerminated, ResultCode) then begin
if Dependencies[I].RebootAfter then begin
// delay reboot after install if we installed the last dependency anyways
if I = ProductCount - 1 then begin
DelayedReboot := True;
end else begin
Result := InstallRebootRequired;
MemoInstallInfo := Dependencies[I].Title;
end;
break;
end else if (ResultCode = 0) or Dependencies[I].ForceSuccess then begin
break;
end else if ResultCode = 3010 then begin
// Windows Installer ResultCode 3010: ERROR_SUCCESS_REBOOT_REQUIRED
DelayedReboot := True;
break;
end;
end;
case SuppressibleMsgBox(FmtMessage(SetupMessage(msgErrorFunctionFailed), [Dependencies[I].Title, IntToStr(ResultCode)]), mbError, MB_ABORTRETRYIGNORE, IDIGNORE) of
IDABORT: begin
Result := InstallError;
MemoInstallInfo := MemoInstallInfo + #13#10 + ' ' + Dependencies[I].Title;
break;
end;
IDIGNORE: begin
MemoInstallInfo := MemoInstallInfo + #13#10 + ' ' + Dependencies[I].Title;
break;
end;
end;
end;
if Result <> InstallSuccessful then begin
break;
end;
end;
DownloadPage.Hide;
end;
end;
// Inno Setup event functions
procedure InitializeWizard;
begin
DownloadPage := CreateDownloadPage(SetupMessage(msgWizardPreparing), SetupMessage(msgPreparingDesc), nil);
end;
function PrepareToInstall(var NeedsRestart: Boolean): String;
var
I: Integer;
begin
DelayedReboot := False;
case InstallProducts of
InstallError: begin
Result := MemoInstallInfo;
end;
InstallRebootRequired: begin
Result := MemoInstallInfo;
NeedsRestart := True;
// write into the registry that the installer needs to be executed again after restart
RegWriteStringValue(HKEY_CURRENT_USER, 'SOFTWARE\Microsoft\Windows\CurrentVersion\RunOnce', 'InstallBootstrap', ExpandConstant('{srcexe}'));
end;
end;
end;
function NeedRestart: Boolean;
begin
Result := DelayedReboot;
end;
function UpdateReadyMemo(const Space, NewLine, MemoUserInfoInfo, MemoDirInfo, MemoTypeInfo, MemoComponentsInfo, MemoGroupInfo, MemoTasksInfo: String): String;
begin
Result := '';
if MemoUserInfoInfo <> '' then begin
Result := Result + MemoUserInfoInfo + Newline + NewLine;
end;
if MemoDirInfo <> '' then begin
Result := Result + MemoDirInfo + Newline + NewLine;
end;
if MemoTypeInfo <> '' then begin
Result := Result + MemoTypeInfo + Newline + NewLine;
end;
if MemoComponentsInfo <> '' then begin
Result := Result + MemoComponentsInfo + Newline + NewLine;
end;
if MemoGroupInfo <> '' then begin
Result := Result + MemoGroupInfo + Newline + NewLine;
end;
if MemoTasksInfo <> '' then begin
Result := Result + MemoTasksInfo;
end;
if MemoInstallInfo <> '' then begin
if MemoTasksInfo = '' then begin
Result := Result + SetupMessage(msgReadyMemoTasks);
end;
Result := Result + FmtMessage(MemoInstallInfo, [Space]);
end;
end;
function NextButtonClick(const CurPageID: Integer): Boolean;
var
I, ProductCount: Integer;
Retry: Boolean;
begin
Result := True;
if (CurPageID = wpReady) and (MemoInstallInfo <> '') then begin
DownloadPage.Show;
ProductCount := GetArrayLength(Dependencies);
for I := 0 to ProductCount - 1 do begin
if Dependencies[I].URL <> '' then begin
DownloadPage.Clear;
DownloadPage.Add(Dependencies[I].URL, Dependencies[I].Filename, Dependencies[I].Checksum);
Retry := True;
while Retry do begin
Retry := False;
try
DownloadPage.Download;
except
if GetExceptionMessage = SetupMessage(msgErrorDownloadAborted) then begin
Result := False;
I := ProductCount;
end else begin
case SuppressibleMsgBox(AddPeriod(GetExceptionMessage), mbError, MB_ABORTRETRYIGNORE, IDIGNORE) of
IDABORT: begin
Result := False;
I := ProductCount;
end;
IDRETRY: begin
Retry := True;
end;
end;
end;
end;
end;
end;
end;
DownloadPage.Hide;
end;
end;
// architecture helper functions
function IsX64: Boolean;
begin
Result := not ForceX86 and Is64BitInstallMode;
end;
function GetString(const x86, x64: String): String;
begin
if IsX64 then begin
Result := x64;
end else begin
Result := x86;
end;
end;
function GetArchitectureSuffix: String;
begin
Result := GetString('', '_x64');
end;
function GetArchitectureTitle: String;
begin
Result := GetString(' (x86)', ' (x64)');
end;
function CompareVersion(const Version1, Version2: String): Integer;
var
Position, Number1, Number2: Integer;
begin
Result := 0;
while (Version1 <> '') or (Version2 <> '') do begin
Position := Pos('.', Version1);
if Position > 0 then begin
Number1 := StrToIntDef(Copy(Version1, 1, Position - 1), 0);
Delete(Version1, 1, Position);
end else if Version1 <> '' then begin
Number1 := StrToIntDef(Version1, 0);
Version1 := '';
end else begin
Number1 := 0;
end;
Position := Pos('.', Version2);
if Position > 0 then begin
Number2 := StrToIntDef(Copy(Version2, 1, Position - 1), 0);
Delete(Version2, 1, Position);
end else if Version2 <> '' then begin
Number2 := StrToIntDef(Version2, 0);
Version2 := '';
end else begin
Number2 := 0;
end;
if Number1 < Number2 then begin
Result := -1;
break;
end else if Number1 > Number2 then begin
Result := 1;
break;
end;
end;
end;
// custom setup content
[Languages]
// Name: en; MessagesFile: "compiler:Default.isl"
// Name: nl; MessagesFile: "compiler:Languages\Dutch.isl"
// Name: de; MessagesFile: "compiler:Languages\German.isl"
Name: "english"; MessagesFile: "compiler:Default.isl"
Name: "armenian"; MessagesFile: "compiler:Languages\Armenian.isl"
Name: "brazilianportuguese"; MessagesFile: "compiler:Languages\BrazilianPortuguese.isl"
Name: "catalan"; MessagesFile: "compiler:Languages\Catalan.isl"
Name: "corsican"; MessagesFile: "compiler:Languages\Corsican.isl"
Name: "czech"; MessagesFile: "compiler:Languages\Czech.isl"
Name: "danish"; MessagesFile: "compiler:Languages\Danish.isl"
Name: "dutch"; MessagesFile: "compiler:Languages\Dutch.isl"
Name: "finnish"; MessagesFile: "compiler:Languages\Finnish.isl"
Name: "french"; MessagesFile: "compiler:Languages\French.isl"
Name: "german"; MessagesFile: "compiler:Languages\German.isl"
Name: "hebrew"; MessagesFile: "compiler:Languages\Hebrew.isl"
Name: "icelandic"; MessagesFile: "compiler:Languages\Icelandic.isl"
Name: "italian"; MessagesFile: "compiler:Languages\Italian.isl"
Name: "japanese"; MessagesFile: "compiler:Languages\Japanese.isl"
Name: "norwegian"; MessagesFile: "compiler:Languages\Norwegian.isl"
Name: "polish"; MessagesFile: "compiler:Languages\Polish.isl"
Name: "portuguese"; MessagesFile: "compiler:Languages\Portuguese.isl"
Name: "russian"; MessagesFile: "compiler:Languages\Russian.isl"
Name: "slovak"; MessagesFile: "compiler:Languages\Slovak.isl"
Name: "slovenian"; MessagesFile: "compiler:Languages\Slovenian.isl"
Name: "spanish"; MessagesFile: "compiler:Languages\Spanish.isl"
Name: "turkish"; MessagesFile: "compiler:Languages\Turkish.isl"
Name: "ukrainian"; MessagesFile: "compiler:Languages\Ukrainian.isl"
[Files]
// TODO: .NET could be included in the installer
// Source: "dotnetfx46.exe"; Flags: dontcopy noencryption
Source: "{#SourceBinPathX64}"; DestDir: "{app}"; DestName: "{#MyAppExeName}"; Check: IsX64; Flags: ignoreversion
Source: "{#SourceBinPathX86}"; DestDir: "{app}"; Check: not IsX64; Flags: ignoreversion
Source: "{#SourceDLLPath}"; DestDir: "{app}"; Flags: ignoreversion
; NOTE: Don't use "Flags: ignoreversion" on any shared system files
[Icons]
Name: "{group}\{#MyAppSetupName}"; Filename: "{app}\{#MyAppExeName}"
Name: "{group}\{cm:UninstallProgram,{#MyAppSetupName}}"; Filename: "{uninstallexe}"
Name: "{commondesktop}\{#MyAppSetupName}"; Filename: "{app}\{#MyAppExeName}"; Tasks: desktopicon
[Tasks]
Name: "desktopicon"; Description: "{cm:CreateDesktopIcon}"; GroupDescription: "{cm:AdditionalIcons}"; Flags: unchecked
[Registry]
; remove explorer context entry if it exists
Root: HKCR; Subkey: Folder\shell\Remove empty dirs; ValueType: string; Flags: uninsdeletekey deletekey dontcreatekey; Tasks: ; Languages:
[Run]
Filename: "{app}\{#MyAppExeName}"; Description: "{cm:LaunchProgram,{#MyAppSetupName}}"; Flags: nowait postinstall skipifsilent
[Code]
function InitializeSetup: Boolean;
var
Version: String;
UninstallerPath: String;
// PrevVersion: String;
ErrorCode: Integer;
begin
// Check whether application is already installed (legacy)
if RegKeyExists(HKEY_LOCAL_MACHINE, 'SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\Remove Empty Directories') then begin
if MsgBox('The setup has detected that RED is already installed on your computer. Do you wish to uninstall the previous version and continue with a fresh installation?', mbConfirmation, MB_YESNO) = IDYES then begin
RegQueryStringValue(HKEY_LOCAL_MACHINE, 'SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\Remove Empty Directories', 'UninstallString', UninstallerPath);
// ShellExec('runas', uninstaller, '/SILENT', '', SW_HIDE, ewWaitUntilTerminated, ErrorCode);
// use above statement if extra level security is required usually it is not req
//ShellExec('open', UninstallerPath, '/S', '', SW_SHOW, ewWaitUntilTerminated, ErrorCode);
ShellExec('runas', UninstallerPath, '/SILENT', '', SW_SHOW, ewWaitUntilTerminated, ErrorCode);
//Exec(UninstallerPath, '/S', '', SW_SHOWNORMAL, ewWaitUntilTerminated, ErrorCode);
end;
end;
// Check whether application is already installed (new way with appId)
if RegKeyExists(HKEY_LOCAL_MACHINE, 'SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\{{#APP_ID}}_is1') then begin
if MsgBox('The setup has detected that RED is already installed on your computer. Do you wish to uninstall the previous version and continue with a fresh installation?', mbConfirmation, MB_YESNO) = IDYES then begin
RegQueryStringValue(HKEY_LOCAL_MACHINE, 'SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\{{#APP_ID}}_is1', 'UninstallString', UninstallerPath);
// ShellExec('runas', uninstaller, '/SILENT', '', SW_HIDE, ewWaitUntilTerminated, ErrorCode);
// use above statement if extra level security is required usually it is not req
//ShellExec('open', UninstallerPath, '/S', '', SW_SHOW, ewWaitUntilTerminated, ErrorCode);
ShellExec('runas', UninstallerPath, '/SILENT', '', SW_SHOW, ewWaitUntilTerminated, ErrorCode);
//Exec(UninstallerPath, '/S', '', SW_SHOWNORMAL, ewWaitUntilTerminated, ErrorCode);
end;
end;
// Check whether application is already installed (new way with appId + WOW6432Node tree)
if RegKeyExists(HKEY_LOCAL_MACHINE, 'SOFTWARE\WOW6432Node\Microsoft\Windows\CurrentVersion\Uninstall\{{#APP_ID}}_is1') then begin
if MsgBox('The setup has detected that RED is already installed on your computer. Do you wish to uninstall the previous version and continue with a fresh installation?', mbConfirmation, MB_YESNO) = IDYES then begin
RegQueryStringValue(HKEY_LOCAL_MACHINE, 'SOFTWARE\WOW6432Node\Microsoft\Windows\CurrentVersion\Uninstall\{{#APP_ID}}_is1', 'UninstallString', UninstallerPath);
// RegQueryStringValue(HKEY_LOCAL_MACHINE, 'SOFTWARE\WOW6432Node\Microsoft\Windows\CurrentVersion\Uninstall\{{#APP_ID}}_is1', 'DisplayVersion', PrevVersion);
// ShellExec('runas', uninstaller, '/SILENT', '', SW_HIDE, ewWaitUntilTerminated, ErrorCode);
// use above statement if extra level security is required usually it is not req
//ShellExec('open', UninstallerPath, '/S', '', SW_SHOW, ewWaitUntilTerminated, ErrorCode);
ShellExec('runas', UninstallerPath, '/SILENT', '', SW_SHOW, ewWaitUntilTerminated, ErrorCode);
//Exec(UninstallerPath, '/S', '', SW_SHOWNORMAL, ewWaitUntilTerminated, ErrorCode);
end;
end;
// Check for .NET Framework 4.6.2
// https://www.microsoft.com/en-US/download/details.aspx?id=53345
if not IsDotNetInstalled(net462, 0) then begin
AddDependency('dotnetfx46.exe',
'/lcid ' + IntToStr(GetUILanguage) + ' /passive /norestart',
'.NET Framework 4.6.2',
'https://download.microsoft.com/download/D/5/C/D5C98AB0-35CC-45D9-9BA5-B18256BA2AE6/NDP462-KB3151802-Web.exe',
'', False, False, False);
end;
Result := True;
end;
================================================
FILE: LICENSE
================================================
GNU LESSER GENERAL PUBLIC LICENSE
Version 3, 29 June 2007
Copyright (C) 2007 Free Software Foundation, Inc. <https://fsf.org/>
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
This version of the GNU Lesser General Public License incorporates
the terms and conditions of version 3 of the GNU General Public
License, supplemented by the additional permissions listed below.
0. Additional Definitions.
As used herein, "this License" refers to version 3 of the GNU Lesser
General Public License, and the "GNU GPL" refers to version 3 of the GNU
General Public License.
"The Library" refers to a covered work governed by this License,
other than an Application or a Combined Work as defined below.
An "Application" is any work that makes use of an interface provided
by the Library, but which is not otherwise based on the Library.
Defining a subclass of a class defined by the Library is deemed a mode
of using an interface provided by the Library.
A "Combined Work" is a work produced by combining or linking an
Application with the Library. The particular version of the Library
with which the Combined Work was made is also called the "Linked
Version".
The "Minimal Corresponding Source" for a Combined Work means the
Corresponding Source for the Combined Work, excluding any source code
for portions of the Combined Work that, considered in isolation, are
based on the Application, and not on the Linked Version.
The "Corresponding Application Code" for a Combined Work means the
object code and/or source code for the Application, including any data
and utility programs needed for reproducing the Combined Work from the
Application, but excluding the System Libraries of the Combined Work.
1. Exception to Section 3 of the GNU GPL.
You may convey a covered work under sections 3 and 4 of this License
without being bound by section 3 of the GNU GPL.
2. Conveying Modified Versions.
If you modify a copy of the Library, and, in your modifications, a
facility refers to a function or data to be supplied by an Application
that uses the facility (other than as an argument passed when the
facility is invoked), then you may convey a copy of the modified
version:
a) under this License, provided that you make a good faith effort to
ensure that, in the event an Application does not supply the
function or data, the facility still operates, and performs
whatever part of its purpose remains meaningful, or
b) under the GNU GPL, with none of the additional permissions of
this License applicable to that copy.
3. Object Code Incorporating Material from Library Header Files.
The object code form of an Application may incorporate material from
a header file that is part of the Library. You may convey such object
code under terms of your choice, provided that, if the incorporated
material is not limited to numerical parameters, data structure
layouts and accessors, or small macros, inline functions and templates
(ten or fewer lines in length), you do both of the following:
a) Give prominent notice with each copy of the object code that the
Library is used in it and that the Library and its use are
covered by this License.
b) Accompany the object code with a copy of the GNU GPL and this license
document.
4. Combined Works.
You may convey a Combined Work under terms of your choice that,
taken together, effectively do not restrict modification of the
portions of the Library contained in the Combined Work and reverse
engineering for debugging such modifications, if you also do each of
the following:
a) Give prominent notice with each copy of the Combined Work that
the Library is used in it and that the Library and its use are
covered by this License.
b) Accompany the Combined Work with a copy of the GNU GPL and this license
document.
c) For a Combined Work that displays copyright notices during
execution, include the copyright notice for the Library among
these notices, as well as a reference directing the user to the
copies of the GNU GPL and this license document.
d) Do one of the following:
0) Convey the Minimal Corresponding Source under the terms of this
License, and the Corresponding Application Code in a form
suitable for, and under terms that permit, the user to
recombine or relink the Application with a modified version of
the Linked Version to produce a modified Combined Work, in the
manner specified by section 6 of the GNU GPL for conveying
Corresponding Source.
1) Use a suitable shared library mechanism for linking with the
Library. A suitable mechanism is one that (a) uses at run time
a copy of the Library already present on the user's computer
system, and (b) will operate properly with a modified version
of the Library that is interface-compatible with the Linked
Version.
e) Provide Installation Information, but only if you would otherwise
be required to provide such information under section 6 of the
GNU GPL, and only to the extent that such information is
necessary to install and execute a modified version of the
Combined Work produced by recombining or relinking the
Application with a modified version of the Linked Version. (If
you use option 4d0, the Installation Information must accompany
the Minimal Corresponding Source and Corresponding Application
Code. If you use option 4d1, you must provide the Installation
Information in the manner specified by section 6 of the GNU GPL
for conveying Corresponding Source.)
5. Combined Libraries.
You may place library facilities that are a work based on the
Library side by side in a single library together with other library
facilities that are not Applications and are not covered by this
License, and convey such a combined library under terms of your
choice, if you do both of the following:
a) Accompany the combined library with a copy of the same work based
on the Library, uncombined with any other library facilities,
conveyed under the terms of this License.
b) Give prominent notice with the combined library that part of it
is a work based on the Library, and explaining where to find the
accompanying uncombined form of the same work.
6. Revised Versions of the GNU Lesser General Public License.
The Free Software Foundation may publish revised and/or new versions
of the GNU Lesser General Public License from time to time. Such new
versions will be similar in spirit to the present version, but may
differ in detail to address new problems or concerns.
Each version is given a distinguishing version number. If the
Library as you received it specifies that a certain numbered version
of the GNU Lesser General Public License "or any later version"
applies to it, you have the option of following the terms and
conditions either of that published version or of any later version
published by the Free Software Foundation. If the Library as you
received it does not specify a version number of the GNU Lesser
General Public License, you may choose any version of the GNU Lesser
General Public License ever published by the Free Software Foundation.
If the Library as you received it specifies that a proxy can decide
whether future versions of the GNU Lesser General Public License shall
apply, that proxy's public statement of acceptance of any version is
permanent authorization for you to choose that version for the
Library.
================================================
FILE: README.md
================================================
Remove Empty Directories
========================
RED finds, displays, and deletes empty directories recursively below a given start folder. Furthermore,
it allows you to create custom rules for keeping and deleting folders (e.g. treat directories with empty files as empty).
## Features
- Simple user interface
- Shows empty directories before deleting them
- Supports multiple delete modes (including Delete to recycle bin)
- Allows white and blacklisting of directories by using filter lists
- Can detect directories with empty files as empty
## System requirements
- Windows 7 or 10
- Version 2.2 should also still work with older Windows versions like XP or Vista
- Microsoft .NET Framework 4.6.2 or later
- The installer checks for the right version and installs it if missing
## How to contribute to the project
You are very welcome to contribute code, translations, or anything else :)
Here are some tasks you can help with:
- Look at open issues/bugs and try to fix them
- Fix typos and general wording
- Optimize user interface
- Create a strategy/foundation for translations, are there any existing frameworks/concepts?
- Add unit tests
## History
The first version of RED was created by [Jonas John](http://www.jonasjohn.de/) around 2005.
Since then [a small team of contributors](https://github.com/hxseven/Remove-Empty-Directories/graphs/contributors) helped to fix bugs and add new features.
## Changelog
2.3
- Disabled settings during active search or deletion process
- Refactored the interface to improve the design and usability
- Divided packed settings tab into three separate tabs
- Renamed some options and captions to make more sense
- Added more descriptions and examples to explain settings
- Increased default window size and added more whitespace to make it look less crowded
- Optimized config defaults
- Set pause between deletions to zero because the default delete to recycle bin method is slow enough to not overwhelm the GUI
- Deleted some unnecessary entries and updated some values
- Removed *.tmp as default pattern to make the default settings safer because those files could still contain valuable data in some cases.
- Long paths support and other improvements (contributed by gioccher, see #5)
- Fix crash due to case sensitivity of paths
- Speed up crawl and deletion by disabling UI updates (dubbed fast mode)
- Long path support by switching to AlphaFS
- And more minor improvements (see closed pull request #5 for details)
- Ignore folders newer than N hours #3 (contributed by jsytniak, see #3)
2.2
- Improved error handling
- Added logging of errors and deleted directories
- Added multiple delete modes (e.g. delete to recycle bin)
- Implemented a function to delete a single empty directory
- Implemented optional function to detect paths in clipboard
- Infinite loop detection
- Added a few new configuration settings
- Removed counting method to increase speed
- Replaced old custom settings module with the default settings framework of .NET to be more standard-compliant (This should fix problems some users had when starting RED)
2.1
- Implemented a "Protect" and "Unprotect" function to let the user choose folders to keep
- Implemented an update button for a fast update check
2.0
- Created the installer (using NSIS)
- Updated this readme file
1.9
- Added better-looking icons to the GUI
- Corrected and updates some texts
1.8
- Finished the main parts of the application
- Added XML configuration file
1.7
- Removed some main parts of the new application and started
using the "BackgroundWorker" for threading support.
1.6
- Finished the first prototype of the C# version
1.5
- Started the development of an entirely new version of RED by using Microsoft Visual C# (.NET 2.0)
1.4
- Updated the readme and changed the license from GPL to LGPL
- fixed some small issues
1.2
- Fixed the gauge in the process window
- implemented a second safety check to prevent deleting filled folders
1.1
- renamed the program to RED (Remove empty directories)
- made a new icon
1.0
- changes some structure things, renamed functions, renamed variables
- corrected code, fixed some issues...
- optional logfile implemented
- other minor changes
- updated version history -> complete rewrite ;)
0.9
- Added a readme, the licenses
- Translated the readme into English
0.8
- Cleaned the directories and sorted the files
- Renamed some functions and variables, to make it look better
0.6 + 0.7
- I learned about WinBinder (A native Windows binding for PHP) and converted
the program to PHP with a Windows GUI using WinBinder
0.5
- Used NSIS Install System (http://nsis.sourceforge.net/) to create a
GUI for the perl script
0.2 - 0.4
- Minor changes
- Added filters to exclude some folders like the recycler
0.1
- I made a simple perl script to delete empty folders, I called it "DEF" (Delete Empty Folders)
## Credits
Third-party components
- File system calls are powered by the [AlphaFS library](https://github.com/alphaleonis/AlphaFS)
- The Installer is made by using [Inno Setup](https://jrsoftware.org/isinfo.php) & [Inno Setup Dependency Installer](https://github.com/DomGries/InnoDependencyInstaller)
Icon sources
- Nuvola icons (GNU LGPL 2.1. license)
- NuoveXT icons (GPL license)
- [famfamfam silk icons](http://www.famfamfam.com/lab/icons/ "famfamfam silk icons") (Creative Commons Attribution license)
- [Coffee icon](https://www.freeimages.com/de/photo/coffee-and-desserts-1571223 "Coffee icon") by Ivan Freaner
- Ignore list icon taken from "Primo Icon Set" made by [Webdesigner Depot](http://www.webdesignerdepot.com/)
- License: Free of charge for personal or commercial purposes
## License
RED is free software; you can redistribute it and/or modify it under the terms of the
[GNU Lesser General Public License](http://www.gnu.org/licenses/lgpl.html) as published by the Free Software Foundation; either version 3 of the License, or (at your option) any later version.
================================================
FILE: RED2/DeletionError.Designer.cs
================================================
namespace RED2
{
partial class DeletionError
{
/// <summary>
/// Erforderliche Designervariable.
/// </summary>
private System.ComponentModel.IContainer components = null;
/// <summary>
/// Verwendete Ressourcen bereinigen.
/// </summary>
/// <param name="disposing">True, wenn verwaltete Ressourcen gelöscht werden sollen; andernfalls False.</param>
protected override void Dispose(bool disposing)
{
if (disposing && (components != null))
{
components.Dispose();
}
base.Dispose(disposing);
}
#region Vom Windows Form-Designer generierter Code
/// <summary>
/// Erforderliche Methode für die Designerunterstützung.
/// Der Inhalt der Methode darf nicht mit dem Code-Editor geändert werden.
/// </summary>
private void InitializeComponent()
{
this.label1 = new System.Windows.Forms.Label();
this.btnAbort = new System.Windows.Forms.Button();
this.btnIgnore = new System.Windows.Forms.Button();
this.btnIgnoreAllErrors = new System.Windows.Forms.Button();
this.tbErrorMessage = new System.Windows.Forms.TextBox();
this.tbPath = new System.Windows.Forms.TextBox();
this.panel1 = new System.Windows.Forms.Panel();
this.panel1.SuspendLayout();
this.SuspendLayout();
//
// label1
//
this.label1.AutoSize = true;
this.label1.Location = new System.Drawing.Point(8, 7);
this.label1.Name = "label1";
this.label1.Size = new System.Drawing.Size(301, 13);
this.label1.TabIndex = 0;
this.label1.Text = "An error occurred while RED tried to delete a file or a directory:";
//
// btnAbort
//
this.btnAbort.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right)));
this.btnAbort.DialogResult = System.Windows.Forms.DialogResult.Abort;
this.btnAbort.Location = new System.Drawing.Point(158, 180);
this.btnAbort.Name = "btnAbort";
this.btnAbort.Size = new System.Drawing.Size(88, 25);
this.btnAbort.TabIndex = 1;
this.btnAbort.Text = "A&bort";
this.btnAbort.UseVisualStyleBackColor = true;
//
// btnIgnore
//
this.btnIgnore.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right)));
this.btnIgnore.DialogResult = System.Windows.Forms.DialogResult.Ignore;
this.btnIgnore.Location = new System.Drawing.Point(251, 180);
this.btnIgnore.Name = "btnIgnore";
this.btnIgnore.Size = new System.Drawing.Size(88, 25);
this.btnIgnore.TabIndex = 2;
this.btnIgnore.Text = "&Ignore error";
this.btnIgnore.UseVisualStyleBackColor = true;
//
// btnIgnoreAllErrors
//
this.btnIgnoreAllErrors.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right)));
this.btnIgnoreAllErrors.DialogResult = System.Windows.Forms.DialogResult.Retry;
this.btnIgnoreAllErrors.Location = new System.Drawing.Point(344, 180);
this.btnIgnoreAllErrors.Name = "btnIgnoreAllErrors";
this.btnIgnoreAllErrors.Size = new System.Drawing.Size(122, 25);
this.btnIgnoreAllErrors.TabIndex = 3;
this.btnIgnoreAllErrors.Text = "Ignore &all errors";
this.btnIgnoreAllErrors.UseVisualStyleBackColor = true;
//
// tbErrorMessage
//
this.tbErrorMessage.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom)
| System.Windows.Forms.AnchorStyles.Left)
| System.Windows.Forms.AnchorStyles.Right)));
this.tbErrorMessage.Font = new System.Drawing.Font("Lucida Console", 9F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
this.tbErrorMessage.Location = new System.Drawing.Point(8, 53);
this.tbErrorMessage.Multiline = true;
this.tbErrorMessage.Name = "tbErrorMessage";
this.tbErrorMessage.ReadOnly = true;
this.tbErrorMessage.ScrollBars = System.Windows.Forms.ScrollBars.Vertical;
this.tbErrorMessage.Size = new System.Drawing.Size(458, 108);
this.tbErrorMessage.TabIndex = 5;
//
// tbPath
//
this.tbPath.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left)
| System.Windows.Forms.AnchorStyles.Right)));
this.tbPath.Location = new System.Drawing.Point(8, 28);
this.tbPath.Name = "tbPath";
this.tbPath.ReadOnly = true;
this.tbPath.Size = new System.Drawing.Size(458, 20);
this.tbPath.TabIndex = 6;
//
// panel1
//
this.panel1.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom)
| System.Windows.Forms.AnchorStyles.Left)
| System.Windows.Forms.AnchorStyles.Right)));
this.panel1.BackColor = System.Drawing.SystemColors.Window;
this.panel1.Controls.Add(this.tbPath);
this.panel1.Controls.Add(this.label1);
this.panel1.Controls.Add(this.tbErrorMessage);
this.panel1.Location = new System.Drawing.Point(0, 0);
this.panel1.Name = "panel1";
this.panel1.Size = new System.Drawing.Size(476, 171);
this.panel1.TabIndex = 7;
//
// DeletionError
//
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.ClientSize = new System.Drawing.Size(474, 212);
this.Controls.Add(this.btnIgnoreAllErrors);
this.Controls.Add(this.btnIgnore);
this.Controls.Add(this.btnAbort);
this.Controls.Add(this.panel1);
this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedDialog;
this.MaximizeBox = false;
this.MinimizeBox = false;
this.Name = "DeletionError";
this.ShowIcon = false;
this.ShowInTaskbar = false;
this.StartPosition = System.Windows.Forms.FormStartPosition.CenterParent;
this.Text = "Warning deletion failed";
this.Load += new System.EventHandler(this.DeletionError_Load);
this.panel1.ResumeLayout(false);
this.panel1.PerformLayout();
this.ResumeLayout(false);
}
#endregion
private System.Windows.Forms.Label label1;
private System.Windows.Forms.Button btnAbort;
private System.Windows.Forms.Button btnIgnore;
private System.Windows.Forms.Button btnIgnoreAllErrors;
private System.Windows.Forms.TextBox tbErrorMessage;
private System.Windows.Forms.TextBox tbPath;
private System.Windows.Forms.Panel panel1;
}
}
================================================
FILE: RED2/DeletionError.cs
================================================
using System;
using System.Windows.Forms;
namespace RED2
{
public partial class DeletionError : Form
{
public DeletionError()
{
InitializeComponent();
}
private void DeletionError_Load(object sender, EventArgs e)
{
}
internal void SetPath(string path)
{
this.tbPath.Text = path;
}
internal void SetErrorMessage(string msg)
{
this.tbErrorMessage.Text = msg;
}
}
}
================================================
FILE: RED2/DeletionError.resx
================================================
<?xml version="1.0" encoding="utf-8"?>
<root>
<!--
Microsoft ResX Schema
Version 2.0
The primary goals of this format is to allow a simple XML format
that is mostly human readable. The generation and parsing of the
various data types are done through the TypeConverter classes
associated with the data types.
Example:
... ado.net/XML headers & schema ...
<resheader name="resmimetype">text/microsoft-resx</resheader>
<resheader name="version">2.0</resheader>
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
<value>[base64 mime encoded serialized .NET Framework object]</value>
</data>
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
<comment>This is a comment</comment>
</data>
There are any number of "resheader" rows that contain simple
name/value pairs.
Each data row contains a name, and value. The row also contains a
type or mimetype. Type corresponds to a .NET class that support
text/value conversion through the TypeConverter architecture.
Classes that don't support this are serialized and stored with the
mimetype set.
The mimetype is used for serialized objects, and tells the
ResXResourceReader how to depersist the object. This is currently not
extensible. For a given mimetype the value must be set accordingly:
Note - application/x-microsoft.net.object.binary.base64 is the format
that the ResXResourceWriter will generate, however the reader can
read any of the formats listed below.
mimetype: application/x-microsoft.net.object.binary.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.soap.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.bytearray.base64
value : The object must be serialized into a byte array
: using a System.ComponentModel.TypeConverter
: and then encoded with base64 encoding.
-->
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" />
</xsd:sequence>
<xsd:attribute name="name" use="required" type="xsd:string" />
<xsd:attribute name="type" type="xsd:string" />
<xsd:attribute name="mimetype" type="xsd:string" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="assembly">
<xsd:complexType>
<xsd:attribute name="alias" type="xsd:string" />
<xsd:attribute name="name" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" />
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
</root>
================================================
FILE: RED2/Lib/Core.cs
================================================
using System;
using System.Collections.Generic;
using System.ComponentModel;
namespace RED2
{
/// <summary>
/// RED core class, handles events and communicates with the GUI
/// </summary>
public class REDCore
{
private MainWindow redMainWindow = null;
public WorkflowSteps CurrentProcessStep = WorkflowSteps.Idle;
private RuntimeData Data = null;
// Workers
private FindEmptyDirectoryWorker searchEmptyFoldersWorker = null;
private DeletionWorker deletionWorker = null;
// Events
public event EventHandler<ErrorEventArgs> OnError;
public event EventHandler OnCancelled;
public event EventHandler OnAborted;
public event EventHandler<ProgressChangedEventArgs> OnProgressChanged;
public event EventHandler<FoundEmptyDirInfoEventArgs> OnFoundEmptyDirectory;
public event EventHandler<FinishedScanForEmptyDirsEventArgs> OnFinishedScanForEmptyDirs;
public event EventHandler<DeleteProcessUpdateEventArgs> OnDeleteProcessChanged;
public event EventHandler<DeletionErrorEventArgs> OnDeleteError;
public event EventHandler<DeleteProcessFinishedEventArgs> OnDeleteProcessFinished;
public REDCore(MainWindow mainWindow, RuntimeData data)
{
this.redMainWindow = mainWindow;
this.Data = data;
}
/// <summary>
/// Start searching empty folders
/// </summary>
public void SearchingForEmptyDirectories()
{
this.CurrentProcessStep = WorkflowSteps.StartSearchingForEmptyDirs;
// Rest folder list
this.Data.ProtectedFolderList = new Dictionary<string, bool>();
// Start async empty directory search worker
searchEmptyFoldersWorker = new FindEmptyDirectoryWorker();
searchEmptyFoldersWorker.Data = this.Data;
searchEmptyFoldersWorker.ProgressChanged += new ProgressChangedEventHandler(searchEmptyFoldersWorker_ProgressChanged);
searchEmptyFoldersWorker.RunWorkerCompleted += new RunWorkerCompletedEventHandler(searchEmptyFoldersWorker_RunWorkerCompleted);
searchEmptyFoldersWorker.RunWorkerAsync(this.Data.StartFolder);
}
/// <summary>
/// This function gets called on a status update of the find worker
/// </summary>
void searchEmptyFoldersWorker_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
if (e.UserState is FoundEmptyDirInfoEventArgs)
{
var info = (FoundEmptyDirInfoEventArgs)e.UserState;
if (info.Type == DirectorySearchStatusTypes.Empty)
{
// Found an empty dir, add it to the list
this.Data.EmptyFolderList.Add(info.Directory);
}
else if (info.Type == DirectorySearchStatusTypes.Error && this.Data.HideScanErrors)
{
return;
}
if (this.OnFoundEmptyDirectory != null)
this.OnFoundEmptyDirectory(this, info);
}
else if (e.UserState is string)
{
if (this.OnProgressChanged != null)
this.OnProgressChanged(this, new ProgressChangedEventArgs(0, (string)e.UserState));
}
else
{
// TODO: Handle unknown types
}
}
void searchEmptyFoldersWorker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
this.CurrentProcessStep = WorkflowSteps.Idle;
if (e.Error != null)
{
this.searchEmptyFoldersWorker.Dispose(); this.searchEmptyFoldersWorker = null;
this.showErrorMsg(e.Error.Message);
}
else if (e.Cancelled)
{
if (this.searchEmptyFoldersWorker.ErrorInfo != null)
{
// A error occurred, process was stopped
this.showErrorMsg(this.searchEmptyFoldersWorker.ErrorInfo.ErrorMessage);
this.searchEmptyFoldersWorker.Dispose(); this.searchEmptyFoldersWorker = null;
if (this.OnAborted != null)
this.OnAborted(this, new EventArgs());
}
else
{
this.searchEmptyFoldersWorker.Dispose(); this.searchEmptyFoldersWorker = null;
if (this.OnCancelled != null)
this.OnCancelled(this, new EventArgs());
}
}
else
{
int FolderCount = this.searchEmptyFoldersWorker.FolderCount;
this.searchEmptyFoldersWorker.Dispose(); this.searchEmptyFoldersWorker = null;
if (this.OnFinishedScanForEmptyDirs != null)
this.OnFinishedScanForEmptyDirs(this, new FinishedScanForEmptyDirsEventArgs(this.Data.EmptyFolderList.Count, FolderCount));
}
}
internal void CancelCurrentProcess()
{
if (this.CurrentProcessStep == WorkflowSteps.StartSearchingForEmptyDirs)
{
if (this.searchEmptyFoldersWorker == null) return;
if ((this.searchEmptyFoldersWorker.IsBusy == true) || (searchEmptyFoldersWorker.CancellationPending == false))
searchEmptyFoldersWorker.CancelAsync();
}
else if (this.CurrentProcessStep == WorkflowSteps.DeleteProcessRunning)
{
if (this.deletionWorker == null) return;
if ((this.deletionWorker.IsBusy == true) || (deletionWorker.CancellationPending == false))
deletionWorker.CancelAsync();
}
}
public void StartDeleteProcess()
{
this.CurrentProcessStep = WorkflowSteps.DeleteProcessRunning;
// Kick-off deletion worker to async delete directories
this.deletionWorker = new DeletionWorker();
this.deletionWorker.Data = this.Data;
this.deletionWorker.ProgressChanged += new ProgressChangedEventHandler(deletionWorker_ProgressChanged);
this.deletionWorker.RunWorkerCompleted += new RunWorkerCompletedEventHandler(deletionWorker_RunWorkerCompleted);
this.deletionWorker.RunWorkerAsync();
}
void deletionWorker_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
var state = e.UserState as DeleteProcessUpdateEventArgs;
if (this.OnDeleteProcessChanged != null)
this.OnDeleteProcessChanged(this, state);
}
void deletionWorker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
this.CurrentProcessStep = WorkflowSteps.Idle;
if (e.Error != null)
{
this.showErrorMsg(e.Error.Message);
this.deletionWorker.Dispose(); this.deletionWorker = null;
}
else if (e.Cancelled)
{
if (this.deletionWorker.ErrorInfo != null)
{
// A error occurred, process was stopped
//
// -> Ask user to continue
if (OnDeleteError != null)
OnDeleteError(this, this.deletionWorker.ErrorInfo);
else
throw new Exception("Internal error: event handler is missing.");
}
else
{
// The user cancelled the process
if (this.OnCancelled != null)
this.OnCancelled(this, new EventArgs());
}
}
else
{
// TODO: Use separate class here?
int deletedCount = this.deletionWorker.DeletedCount;
int failedCount = this.deletionWorker.FailedCount;
int protectedCount = this.deletionWorker.ProtectedCount;
this.deletionWorker.Dispose();
this.deletionWorker = null;
if (this.OnDeleteProcessFinished != null)
this.OnDeleteProcessFinished(this, new DeleteProcessFinishedEventArgs(deletedCount, failedCount, protectedCount));
}
}
internal void AddProtectedFolder(string path)
{
if (!this.Data.ProtectedFolderList.ContainsKey(path))
this.Data.ProtectedFolderList.Add(path, true);
}
internal void RemoveProtected(string FolderFullName)
{
if (this.Data.ProtectedFolderList.ContainsKey(FolderFullName))
this.Data.ProtectedFolderList.Remove(FolderFullName);
}
public string GetLogMessages()
{
return this.Data.LogMessages.ToString();
}
private void showErrorMsg(string errorMessage)
{
if (this.OnError != null)
this.OnError(this, new ErrorEventArgs(errorMessage));
}
internal void AbortDeletion()
{
this.CurrentProcessStep = WorkflowSteps.Idle;
this.deletionWorker.Dispose(); this.deletionWorker = null;
if (this.OnAborted != null)
this.OnAborted(this, new EventArgs());
}
internal void ContinueDeleteProcess()
{
this.CurrentProcessStep = WorkflowSteps.DeleteProcessRunning;
this.deletionWorker.RunWorkerAsync();
}
}
}
================================================
FILE: RED2/Lib/DeletionWorker.cs
================================================
using System;
using System.ComponentModel;
using System.Threading;
using Alphaleonis.Win32.Filesystem;
namespace RED2
{
/// <summary>
/// Deletes the empty directories RED found
/// </summary>
public class DeletionWorker : BackgroundWorker
{
public RuntimeData Data { get; set; }
public int DeletedCount { get; set; }
public int FailedCount { get; set; }
public int ProtectedCount { get; set; }
public int ListPos { get; set; }
public DeletionErrorEventArgs ErrorInfo { get; set; }
public DeletionWorker()
{
WorkerReportsProgress = true;
WorkerSupportsCancellation = true;
this.ListPos = 0;
}
protected override void OnDoWork(DoWorkEventArgs e)
{
// This method will run on a thread other than the UI thread.
// Be sure not to manipulate any Windows Forms controls created
// on the UI thread from this method.
if (CancellationPending)
{
e.Cancel = true;
return;
}
bool stopNow = false;
string errorMessage = "";
this.ErrorInfo = null;
int count = this.Data.EmptyFolderList.Count;
while (this.ListPos < this.Data.EmptyFolderList.Count)
{
if (CancellationPending)
{
e.Cancel = true;
return;
}
var folder = this.Data.EmptyFolderList[this.ListPos];
var status = DirectoryDeletionStatusTypes.Ignored;
// Do not delete one time protected folders
if (!this.Data.ProtectedFolderList.ContainsKey(folder))
{
try
{
// Try to delete the directory
this.secureDelete(folder);
this.Data.AddLogMessage(String.Format("Successfully deleted dir \"{0}\"", folder));
status = DirectoryDeletionStatusTypes.Deleted;
this.DeletedCount++;
}
catch (REDPermissionDeniedException ex)
{
errorMessage = ex.Message;
this.Data.AddLogMessage(String.Format("Directory is protected by the system \"{0}\" - Message: \"{1}\"", folder, errorMessage));
status = DirectoryDeletionStatusTypes.Protected;
this.ProtectedCount++;
}
catch (Exception ex)
{
errorMessage = ex.Message;
stopNow = (!this.Data.IgnoreAllErrors);
this.Data.AddLogMessage(String.Format("Failed to delete dir \"{0}\" - Error message: \"{1}\"", folder, errorMessage));
status = DirectoryDeletionStatusTypes.Warning;
this.FailedCount++;
}
if (!stopNow && this.Data.PauseTime > 0)
Thread.Sleep(TimeSpan.FromMilliseconds(this.Data.PauseTime));
}
else
status = DirectoryDeletionStatusTypes.Protected;
this.ReportProgress(1, new DeleteProcessUpdateEventArgs(this.ListPos, folder, status, count));
this.ListPos++;
if (stopNow)
{
// stop here for now
if (errorMessage == "") errorMessage = "Unknown error";
e.Cancel = true;
this.ErrorInfo = new DeletionErrorEventArgs(folder, errorMessage);
return;
}
}
e.Result = count;
}
private void secureDelete(string path)
{
var emptyDirectory = new DirectoryInfo(path);
if (!emptyDirectory.Exists)
throw new Exception("Could not delete the directory \"" + emptyDirectory.FullName + "\" because it does not exist anymore.");
// Cleanup folder
String[] ignoreFileList = this.Data.GetIgnoreFileList();
FileInfo[] Files = emptyDirectory.GetFiles();
if (Files != null && Files.Length != 0)
{
// loop trough files and cancel if containsFiles == true
for (int f = 0; f < Files.Length; f++)
{
var file = Files[f];
string delPattern = "";
bool deleteTrashFile = SystemFunctions.MatchesIgnorePattern(file, (int)file.Length, this.Data.IgnoreEmptyFiles, ignoreFileList, out delPattern);
// If only one file is good, then stop.
if (deleteTrashFile)
{
try
{
SystemFunctions.SecureDeleteFile(file, this.Data.DeleteMode);
this.Data.AddLogMessage(String.Format("-> Successfully deleted file \"{0}\" because it matched the ignore pattern \"{1}\"", file.FullName, delPattern));
}
catch (Exception ex)
{
this.Data.AddLogMessage(String.Format("Failed to delete file \"{0}\" - Error message: \"{1}\"", file.FullName, ex.Message));
var msg = "Could not delete this empty (trash) file:" + Environment.NewLine + file.FullName + Environment.NewLine + Environment.NewLine + "Error message: " + ex.Message;
if (ex is REDPermissionDeniedException)
throw new REDPermissionDeniedException(msg, ex);
else
throw new Exception(msg, ex);
}
}
}
}
// End cleanup
// This function will ensure that the directory is really empty before it gets deleted
SystemFunctions.SecureDeleteDirectory(emptyDirectory.FullName, this.Data.DeleteMode);
}
}
}
================================================
FILE: RED2/Lib/Enums.cs
================================================
namespace RED2
{
/// <summary>
/// RED workflow steps
/// </summary>
public enum WorkflowSteps
{
Idle,
StartSearchingForEmptyDirs,
DeleteProcessRunning,
}
/// <summary>
/// Result status types of the scan
/// </summary>
public enum DirectorySearchStatusTypes
{
Empty,
Error,
NotEmpty,
Ignore
}
/// <summary>
/// Result types of the deletion process
/// </summary>
public enum DirectoryDeletionStatusTypes
{
Deleted,
Warning,
Ignored,
Protected
}
}
================================================
FILE: RED2/Lib/Events.cs
================================================
using System;
using Alphaleonis.Win32.Filesystem;
namespace RED2
{
public class WorkflowStepChangedEventArgs : EventArgs
{
public WorkflowSteps NewStep { get; set; }
public WorkflowStepChangedEventArgs(WorkflowSteps NewStep)
{
this.NewStep = NewStep;
}
}
public class ErrorEventArgs : EventArgs
{
public string Message { get; set; }
public ErrorEventArgs(string msg)
{
this.Message = msg;
}
}
public class FinishedScanForEmptyDirsEventArgs : EventArgs
{
public int EmptyFolderCount { get; set; }
public int FolderCount { get; set; }
public FinishedScanForEmptyDirsEventArgs(int EmptyFolderCount, int FolderCount)
{
this.EmptyFolderCount = EmptyFolderCount;
this.FolderCount = FolderCount;
}
}
public class DeleteProcessUpdateEventArgs : EventArgs
{
public int ProgressStatus { get; set; }
public string Path { get; set; }
public DirectoryDeletionStatusTypes Status { get; set; }
public int FolderCount { get; set; }
public DeleteProcessUpdateEventArgs(int progressStatus, string path, DirectoryDeletionStatusTypes status, int folderCount)
{
this.ProgressStatus = progressStatus;
this.Path = path;
this.Status = status;
this.FolderCount = folderCount;
}
}
public class DeleteProcessFinishedEventArgs : EventArgs
{
public int DeletedFolderCount { get; set; }
public int FailedFolderCount { get; set; }
public int ProtectedCount { get; set; }
public DeleteProcessFinishedEventArgs(int deletedFolderCount, int failedFolderCount, int protectedCount)
{
this.DeletedFolderCount = deletedFolderCount;
this.FailedFolderCount = failedFolderCount;
this.ProtectedCount = protectedCount;
}
}
public class ProtectionStatusChangedEventArgs : EventArgs
{
public string Path { get; set; }
public bool Protected { get; set; }
public ProtectionStatusChangedEventArgs(string Path, bool Protected)
{
this.Path = Path;
this.Protected = Protected;
}
}
public class DeleteRequestFromTreeEventArgs : EventArgs
{
public string Directory { get; set; }
public DeleteRequestFromTreeEventArgs(string Directory)
{
this.Directory = Directory;
}
}
public class DeletionErrorEventArgs : EventArgs
{
public string Path { get; set; }
public string ErrorMessage { get; set; }
public DeletionErrorEventArgs(string Path, string ErrorMessage)
{
this.Path = Path;
this.ErrorMessage = ErrorMessage;
}
}
public class FoundEmptyDirInfoEventArgs : EventArgs
{
public string Directory { get; set; }
public DirectorySearchStatusTypes Type { get; set; }
public string ErrorMessage { get; set; }
public FoundEmptyDirInfoEventArgs(string Directory, DirectorySearchStatusTypes type)
{
this.Directory = Directory;
this.Type = type;
this.ErrorMessage = "";
}
public FoundEmptyDirInfoEventArgs(string Directory, DirectorySearchStatusTypes type, string ErrorMessage)
{
this.Directory = Directory;
this.Type = type;
this.ErrorMessage = ErrorMessage;
}
}
}
================================================
FILE: RED2/Lib/FindEmptyDirectoryWorker.cs
================================================
using System;
using System.Collections.Generic;
using System.ComponentModel;
using Alphaleonis.Win32.Filesystem;
using FileAttributes = System.IO.FileAttributes;
namespace RED2
{
/// <summary>
/// Searches for empty directories
/// </summary>
public class FindEmptyDirectoryWorker : BackgroundWorker
{
private int folderCount = 0;
public int FolderCount
{
get { return folderCount; }
}
public RuntimeData Data { get; set; }
private string[] ignoreFolderList = null;
private string[] ignoreFileList = null;
public DeletionErrorEventArgs ErrorInfo { get; set; }
public int PossibleEndlessLoop { get; set; }
public FindEmptyDirectoryWorker()
{
WorkerReportsProgress = true;
WorkerSupportsCancellation = true;
}
protected override void OnDoWork(DoWorkEventArgs e)
{
DirectoryInfo startFolder = (DirectoryInfo)e.Argument;
this.PossibleEndlessLoop = 0;
// Clean dir list
this.Data.EmptyFolderList = new List<string>();
this.ignoreFileList = this.Data.GetIgnoreFileList();
this.ignoreFolderList = this.Data.GetIgnoreDirectories();
try
{
var rootStatusType = this.checkIfDirectoryEmpty(startFolder, 1);
this.ReportProgress(0, new FoundEmptyDirInfoEventArgs(startFolder.FullName, rootStatusType));
if (this.PossibleEndlessLoop > this.Data.InfiniteLoopDetectionCount)
{
this.Data.AddLogMessage("Detected possible infinite-loop somewhere in the target path \"" + startFolder + "\" (symbolic links can cause this)");
throw new Exception("Possible infinite-loop detected (symbolic links can cause this)");
}
}
catch (Exception ex)
{
e.Cancel = true;
this.Data.AddLogMessage("An error occurred during the scan process: " + ex.Message);
this.ErrorInfo = new DeletionErrorEventArgs(startFolder.FullName, ex.Message);
return;
}
if (CancellationPending)
{
this.Data.AddLogMessage("Scan process was cancelled");
e.Cancel = true;
e.Result = 0;
return;
}
e.Result = 1;
}
private DirectorySearchStatusTypes checkIfDirectoryEmpty(DirectoryInfo startDir, int depth)
{
if (this.PossibleEndlessLoop > this.Data.InfiniteLoopDetectionCount)
{
this.ReportProgress(0, new FoundEmptyDirInfoEventArgs(startDir.FullName, DirectorySearchStatusTypes.Error, "Aborted - possible infinite-loop detected"));
return DirectorySearchStatusTypes.Error;
}
try
{
// Thread.Sleep(500); -> ?
if (this.Data.MaxDepth != -1 && depth > this.Data.MaxDepth)
return DirectorySearchStatusTypes.NotEmpty;
// Cancel process if the user hits stop
if (CancellationPending)
return DirectorySearchStatusTypes.NotEmpty;
this.folderCount++;
// update status progress bar after 100 steps:
if (this.folderCount % 100 == 0)
this.ReportProgress(folderCount, "Checking directory: " + startDir.Name);
bool containsFiles = false;
// Get file list
FileInfo[] fileList = null;
// some directories could trigger an exception:
try
{
fileList = startDir.GetFiles();
}
catch
{
fileList = null;
}
if (fileList == null)
{
// CF = true = folder does not get deleted:
containsFiles = true; // secure way
this.Data.AddLogMessage("Failed to access files in \"" + startDir.FullName + "\"");
this.ReportProgress(0, new FoundEmptyDirInfoEventArgs(startDir.FullName, DirectorySearchStatusTypes.Error, "Failed to access files"));
}
else if (fileList.Length == 0)
{
containsFiles = false;
}
else
{
string delPattern = "";
// loop trough files and cancel if containsFiles == true
for (int f = 0; (f < fileList.Length && !containsFiles); f++)
{
FileInfo file = null;
int filesize = 0;
try
{
file = fileList[f];
filesize = (int)file.Length;
}
catch
{
// keep folder if there is a strange file that
// triggers a exception:
containsFiles = true;
break;
}
// If only one file is good, then stop.
if (!SystemFunctions.MatchesIgnorePattern(file, filesize, this.Data.IgnoreEmptyFiles, this.ignoreFileList, out delPattern))
containsFiles = true;
}
}
// If the folder does not contain any files -> get subfolders:
DirectoryInfo[] subFolderList = null;
try
{
subFolderList = startDir.GetDirectories();
}
catch
{
// If we can not read the folder -> don't delete it:
this.Data.AddLogMessage("Failed to access subdirectories in \"" + startDir.FullName + "\"");
this.ReportProgress(0, new FoundEmptyDirInfoEventArgs(startDir.FullName, DirectorySearchStatusTypes.Error, "Failed to access subdirectories"));
return DirectorySearchStatusTypes.Error;
}
// The folder is empty, break here:
if (!containsFiles && subFolderList.Length == 0)
{
return DirectorySearchStatusTypes.Empty;
}
bool allSubDirectoriesEmpty = true;
foreach (var curDir in subFolderList)
{
var attribs = curDir.Attributes;
bool ignoreSystemDir = (this.Data.KeepSystemFolders && ((attribs & FileAttributes.System) == FileAttributes.System));
bool ignoreHiddenDir = (this.Data.IgnoreHiddenFolders && ((attribs & FileAttributes.Hidden) == FileAttributes.Hidden));
bool ignoreSubDirectory = (ignoreSystemDir || ignoreHiddenDir);
if (!ignoreSubDirectory && checkIfDirectoryIsOnIgnoreList(curDir))
{
this.Data.AddLogMessage("Aborted scan of \"" + curDir.FullName + "\" because it is on the ignore list.");
this.ReportProgress(0, new FoundEmptyDirInfoEventArgs(curDir.FullName, DirectorySearchStatusTypes.Ignore));
ignoreSubDirectory = true;
}
if (!ignoreSubDirectory && (attribs & FileAttributes.ReparsePoint) == FileAttributes.ReparsePoint)
{
this.Data.AddLogMessage("Aborted scan of \"" + curDir.FullName + "\" because it is a symbolic link");
this.ReportProgress(0, new FoundEmptyDirInfoEventArgs(curDir.FullName, DirectorySearchStatusTypes.Error, "Aborted because dir is a symbolic link"));
ignoreSubDirectory = true;
}
// TODO: Implement more checks
//else if ((attribs & FileAttributes.Device) == FileAttributes.Device) msg = "Device - Aborted - found";
//else if ((attribs & FileAttributes.Encrypted) == FileAttributes.Encrypted) msg = "Encrypted - found";
// The file will not be indexed by the operating system's content indexing service.
// else if ((attribs & FileAttributes.NotContentIndexed) == FileAttributes.NotContentIndexed) msg = "NotContentIndexed - Device found";
//else if ((attribs & FileAttributes.Offline) == FileAttributes.Offline) msg = "Offline - found";
//else if ((attribs & FileAttributes.ReadOnly) == FileAttributes.ReadOnly) msg = "ReadOnly - found";
//else if ((attribs & FileAttributes.Temporary) == FileAttributes.Temporary) msg = "Temporary - found";
// Scan sub folder:
var subFolderStatus = DirectorySearchStatusTypes.NotEmpty;
if (!ignoreSubDirectory)
{
// JRS ADDED check for AGE of folder
if(curDir.CreationTime.AddHours(this.Data.MinFolderAgeHours) < DateTime.Now)
{
subFolderStatus = this.checkIfDirectoryEmpty(curDir, depth + 1);
}
else
{
this.Data.AddLogMessage(String.Format(RED2.Properties.Resources.young_folder_skipped, curDir.FullName, this.Data.MinFolderAgeHours.ToString(), curDir.CreationTime.ToString()));
}
// Report status to the GUI
if (subFolderStatus == DirectorySearchStatusTypes.Empty)
this.ReportProgress(0, new FoundEmptyDirInfoEventArgs(curDir.FullName, subFolderStatus));
}
// this folder is not empty:
if (subFolderStatus != DirectorySearchStatusTypes.Empty || ignoreSubDirectory)
allSubDirectoriesEmpty = false;
}
// All subdirectories are empty
return (allSubDirectoriesEmpty && !containsFiles) ? DirectorySearchStatusTypes.Empty : DirectorySearchStatusTypes.NotEmpty;
}
catch (Exception ex)
{
// Error handling
if (ex is System.IO.PathTooLongException)
this.PossibleEndlessLoop++;
this.Data.AddLogMessage("An unknown error occurred while trying to scan this directory: \"" + startDir.FullName + "\" - Error message: " + ex.Message);
this.ReportProgress(0, new FoundEmptyDirInfoEventArgs(startDir.FullName, DirectorySearchStatusTypes.Error, ex.Message));
return DirectorySearchStatusTypes.Error;
}
}
private bool checkIfDirectoryIsOnIgnoreList(DirectoryInfo Folder)
{
bool ignoreFolder = false;
if (this.ignoreFolderList.Length > 0)
{
foreach (string currentPath in this.ignoreFolderList)
{
if (currentPath == "") continue;
// skip directory if a part of it is on the filterlist
// TODO: Use better compare method
if (Folder.FullName.ToLower().Contains(currentPath.ToLower()))
ignoreFolder = true;
}
}
return ignoreFolder;
}
}
}
================================================
FILE: RED2/Lib/RuntimeData.cs
================================================
using System;
using System.Collections.Generic;
using Alphaleonis.Win32.Filesystem;
using System.Text;
namespace RED2
{
/// <summary>
/// Container for runtime related data
/// </summary>
public class RuntimeData
{
// Configuration
public DirectoryInfo StartFolder { get; set; }
public bool IgnoreAllErrors { get; set; }
public bool DisableLogging { get; set; }
public DeleteModes DeleteMode { get; set; }
public string IgnoreFiles { get; set; }
public string IgnoreDirectoriesList { get; set; }
public bool IgnoreEmptyFiles { get; set; }
public bool IgnoreHiddenFolders { get; set; }
public bool KeepSystemFolders { get; set; }
public bool HideScanErrors { get; set; }
public double PauseTime { get; set; }
public uint MinFolderAgeHours { get; set; }
public int MaxDepth { get; set; }
public int InfiniteLoopDetectionCount { get; set; }
public StringBuilder LogMessages = null;
public Dictionary<string, bool> ProtectedFolderList = new Dictionary<string, bool>();
/// <summary>
/// List containing all empty directories that were found
/// </summary>
public List<string> EmptyFolderList { get; set; }
public RuntimeData()
{
this.LogMessages = new StringBuilder();
this.ProtectedFolderList = new Dictionary<string, bool>();
this.EmptyFolderList = new List<string>();
}
private string[] fixNewLines(string input)
{
return input.Replace("\r\n", "\n").Replace("\r", "\n").Split('\n');
}
public string[] GetIgnoreFileList()
{
return this.fixNewLines(this.IgnoreFiles);
}
public string[] GetIgnoreDirectories()
{
return this.fixNewLines(this.IgnoreDirectoriesList);
}
public void AddLogMessage(string msg)
{
this.LogMessages.AppendLine(DateTime.Now.ToString("r") + "\t" + msg);
}
internal void AddLogSpacer()
{
if (this.LogMessages.Length > 0)
this.LogMessages.Append(Environment.NewLine);
}
}
}
================================================
FILE: RED2/Lib/SystemFunctions.cs
================================================
using System;
using System.Diagnostics;
using System.Security.Permissions;
using System.Text.RegularExpressions;
using System.Windows.Forms;
using Microsoft.VisualBasic.FileIO;
using Microsoft.Win32;
using Alphaleonis.Win32.Filesystem;
using FileAccess = System.IO.FileAccess;
using FileMode = System.IO.FileMode;
using FileShare = System.IO.FileShare;
namespace RED2
{
public enum DeleteModes
{
RecycleBin = 0,
RecycleBinShowErrors = 1,
RecycleBinWithQuestion = 2,
Direct = 3,
Simulate = 4
}
[Serializable]
public class REDPermissionDeniedException : Exception
{
public REDPermissionDeniedException() { }
public REDPermissionDeniedException(string message) : base(message) { }
public REDPermissionDeniedException(string message, Exception inner) : base(message, inner) { }
}
/// <summary>
/// A collection of (generic) system functions
///
/// Exception handling should be made by the caller
/// </summary>
public class SystemFunctions
{
// Registry keys
private const string registryMenuName = "Folder\\shell\\Remove empty dirs";
private const string registryCommand = "Folder\\shell\\Remove empty dirs\\command";
public static string ConvertLineBreaks(string str)
{
return str.Replace(@"\r\n", "\r\n").Replace(@"\n", "\n");
}
public static bool MatchesIgnorePattern(FileInfo file, int filesize, bool Ignore0kbFiles, string[] ignoreFileList, out string delPattern)
{
bool matches_pattern = false;
Regex regexPattern = null;
delPattern = "";
for (int pos = 0; (pos < ignoreFileList.Length && !matches_pattern); pos++)
{
string pattern = ignoreFileList[pos];
// TODO: Check patterns for errors
// Skip empty patterns
if (pattern == "") continue;
if (Ignore0kbFiles && filesize == 0)
{
delPattern = "[Empty file]";
matches_pattern = true;
}
else if (pattern.ToLower() == file.Name.ToLower())
{
// Direct match - ignore case
delPattern = pattern;
matches_pattern = true;
}
else if (pattern.Contains("*") || (pattern.StartsWith("/") && pattern.EndsWith("/")))
{
// Pattern is a regex
if (pattern.StartsWith("/") && pattern.EndsWith("/"))
{
regexPattern = new Regex(pattern.Substring(1, pattern.Length - 2));
}
else
{
pattern = Regex.Escape(pattern).Replace("\\*", ".*");
regexPattern = new Regex("^" + pattern + "$");
}
if (regexPattern.IsMatch(file.Name))
{
delPattern = pattern;
matches_pattern = true;
}
}
}
return matches_pattern;
}
public static void ManuallyDeleteDirectory(string path, DeleteModes deleteMode)
{
if (deleteMode == DeleteModes.Simulate) return;
if (path == "") throw new Exception("Could not delete directory because the path was empty.");
//TODO: Add FileIOPermission code?
FileSystem.DeleteDirectory(path, UIOption.AllDialogs, RecycleOption.SendToRecycleBin, UICancelOption.ThrowException);
}
public static bool IsDirLocked(string path)
{
try
{
// UGLY hack to determine whether we have write access
// to a specific directory
var r = new Random();
var tempName = path + "deltest";
int counter = 0;
while (Directory.Exists(tempName))
{
tempName = path + "deltest" + r.Next(0, 9999).ToString();
if (counter > 100) return true; // Something strange is going on... stop here...
counter++;
}
Directory.Move(path, tempName);
Directory.Move(tempName, path);
return false;
}
catch //(Exception ex)
{
// Could not rename -> probably we have no
// write access to the directory
return true;
}
}
public static bool IsFileLocked(FileInfo file)
{
try
{
using (file.Open(FileMode.Open, FileAccess.ReadWrite, FileShare.None))
{
return false;
}
}
catch //(IOException)
{
// Could not open file -> probably we have no
// write access to the file
return true;
}
}
public static void SecureDeleteDirectory(string path, DeleteModes deleteMode)
{
if (deleteMode == DeleteModes.Simulate) return;
if (deleteMode == DeleteModes.Direct)
{
Directory.Delete(path, recursive: false, ignoreReadOnly: true); //throws IOException if not empty anymore
return;
}
// Last security check before deletion
if (Directory.GetFiles(path).Length == 0 && Directory.GetDirectories(path).Length == 0)
{
if (deleteMode == DeleteModes.RecycleBin)
{
// Check CLR permissions -> could raise a exception
new FileIOPermission(FileIOPermissionAccess.Write, path + Path.DirectorySeparatorChar.ToString()).Demand();
//if (!CheckWriteAccess(Directory.GetAccessControl(path)))
if (IsDirLocked(path))
throw new REDPermissionDeniedException("Could not delete directory \"" + path + "\" because the access is protected by the (file) system (permission denied).");
FileSystem.DeleteDirectory(path, UIOption.OnlyErrorDialogs, RecycleOption.SendToRecycleBin, UICancelOption.ThrowException);
}
else if (deleteMode == DeleteModes.RecycleBinShowErrors)
{
FileSystem.DeleteDirectory(path, UIOption.OnlyErrorDialogs, RecycleOption.SendToRecycleBin, UICancelOption.ThrowException);
}
else if (deleteMode == DeleteModes.RecycleBinWithQuestion) FileSystem.DeleteDirectory(path, UIOption.AllDialogs, RecycleOption.SendToRecycleBin, UICancelOption.ThrowException);
else throw new Exception("Internal error: Unknown delete mode: \"" + deleteMode.ToString() + "\"");
}
else
throw new Exception("Aborted deletion of the directory \"" + path + "\" because it is no longer empty. This can happen if RED previously failed to delete a empty (trash) file.");
}
public static void SecureDeleteFile(FileInfo file, DeleteModes deleteMode)
{
if (deleteMode == DeleteModes.Simulate) return;
if (deleteMode == DeleteModes.RecycleBin)
{
// Check CLR permissions -> could raise a exception
new FileIOPermission(FileIOPermissionAccess.Write, file.FullName).Demand();
if (IsFileLocked(file))
throw new REDPermissionDeniedException("Could not delete file \"" + file.FullName + "\" because the access is protected by the (file) system (permission denied).");
FileSystem.DeleteFile(file.FullName, UIOption.OnlyErrorDialogs, RecycleOption.SendToRecycleBin, UICancelOption.ThrowException);
}
else if (deleteMode == DeleteModes.RecycleBinShowErrors)
{
FileSystem.DeleteFile(file.FullName, UIOption.OnlyErrorDialogs, RecycleOption.SendToRecycleBin, UICancelOption.ThrowException);
}
else if (deleteMode == DeleteModes.RecycleBinWithQuestion) FileSystem.DeleteFile(file.FullName, UIOption.AllDialogs, RecycleOption.SendToRecycleBin, UICancelOption.ThrowException);
else if (deleteMode == DeleteModes.Direct)
{
// Was used for testing the error handling:
// if (SystemFunctions.random.NextDouble() > 0.5) throw new Exception("Test error");
file.Delete(ignoreReadOnly: true);
}
else throw new Exception("Internal error: Unknown delete mode: \"" + deleteMode.ToString() + "\"");
}
public static string ChooseDirectoryDialog(string path)
{
FolderBrowserDialog folderDialog = new FolderBrowserDialog();
folderDialog.Description = RED2.Properties.Resources.please_select;
folderDialog.ShowNewFolderButton = false;
if (path != "")
{
DirectoryInfo dir = new DirectoryInfo(path);
if (dir.Exists)
folderDialog.SelectedPath = path;
}
if (folderDialog.ShowDialog() == DialogResult.OK)
path = folderDialog.SelectedPath;
folderDialog.Dispose();
folderDialog = null;
return path;
}
/// <summary>
/// Opens a folder
/// </summary>
public static void OpenDirectoryWithExplorer(string path)
{
if (path == "")
return;
string windows_folder = Environment.GetEnvironmentVariable("SystemRoot");
Process.Start(windows_folder + "\\explorer.exe", "/e,\"" + path + "\"");
}
/// <summary>
/// Check for the registry key
/// </summary>
/// <returns></returns>
public static bool IsRegKeyIntegratedIntoWindowsExplorer()
{
return (Registry.ClassesRoot.OpenSubKey(registryMenuName) != null);
}
internal static void AddOrRemoveRegKey(bool add)
{
RegistryKey regmenu = null;
RegistryKey regcmd = null;
if (add)
{
try
{
regmenu = Registry.ClassesRoot.CreateSubKey(registryMenuName);
if (regmenu != null)
regmenu.SetValue("", "Remove empty dirs");
regcmd = Registry.ClassesRoot.CreateSubKey(registryCommand);
if (regcmd != null)
regcmd.SetValue("", Application.ExecutablePath + " \"%1\"");
}
catch (Exception ex)
{
MessageBox.Show(ex.ToString());
}
finally
{
if (regmenu != null)
regmenu.Close();
if (regcmd != null)
regcmd.Close();
}
}
else
{
try
{
var reg = Registry.ClassesRoot.OpenSubKey(registryCommand);
if (reg != null)
{
reg.Close();
Registry.ClassesRoot.DeleteSubKey(registryCommand);
}
reg = Registry.ClassesRoot.OpenSubKey(registryMenuName);
if (reg != null)
{
reg.Close();
Registry.ClassesRoot.DeleteSubKey(registryMenuName);
}
}
catch (Exception ex)
{
MessageBox.Show(RED2.Properties.Resources.error + "\nCould not change registry settings: " + ex.ToString());
}
}
}
}
}
================================================
FILE: RED2/Lib/TreeManager.cs
================================================
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Windows.Forms;
using Alphaleonis.Win32.Filesystem;
using FileAttributes = System.IO.FileAttributes;
namespace RED2
{
/// <summary>
/// Handles tree related things
///
/// TODO: Handle null references within tree nodes
/// </summary>
public class TreeManager
{
private TreeView treeView = null;
private TreeNode rootNode = null;
private string rootPath = "";
private Label fastModeInfoLabel = null;
private Dictionary<String, TreeNode> directoryToTreeNodeMapping = null;
/// <summary>
/// This dictionary holds the original properties of protected
/// nodes so that they can be restored if the user undoes the action
/// </summary>
private Dictionary<string, object> nodePropsBackup = new Dictionary<string, object>();
public event EventHandler<ProtectionStatusChangedEventArgs> OnProtectionStatusChanged;
public event EventHandler<DeleteRequestFromTreeEventArgs> OnDeleteRequest;
private bool fastMode { get; set; } = true;
public TreeManager(TreeView dirTree, Label fastModeInfoLabel)
{
this.treeView = dirTree;
this.treeView.MouseClick += new System.Windows.Forms.MouseEventHandler(this.tvFolders_MouseClick);
this.fastModeInfoLabel = fastModeInfoLabel;
this.resetTree();
this.rootPath = "";
}
#region Incoming "events"
public void SetFastMode(bool fastModeActive)
{
this.fastMode = fastModeActive;
if (this.fastMode)
{
this.treeView.SuspendLayout();
}
else
{
this.clearFastMode();
this.treeView.ResumeLayout();
}
}
public void OnSearchStart(DirectoryInfo directory)
{
this.resetTree();
// Disable UI updates when fast mode is enabled
if (this.fastMode)
{
suspendTreeViewForFastMode();
}
this.createRootNode(directory, DirectoryIcons.home);
}
public void OnSearchFinished()
{
this.showFastModeResults();
}
public void OnDeletionProcessStart()
{
if (this.fastMode)
{
this.treeView.Nodes.Clear();
suspendTreeViewForFastMode();
}
}
public void OnDeletionProcessFinished()
{
this.showFastModeResults();
}
public void OnProcessCancelled()
{
this.showFastModeResults();
}
#endregion
private void suspendTreeViewForFastMode()
{
this.treeView.SuspendLayout();
this.treeView.BackColor = System.Drawing.SystemColors.Control;
this.fastModeInfoLabel.Visible = true;
}
private void clearFastMode()
{
this.treeView.BackColor = System.Drawing.SystemColors.Window;
this.fastModeInfoLabel.Visible = false;
}
private void showFastModeResults()
{
if (!this.fastMode) return;
this.treeView.ResumeLayout();
this.clearFastMode();
this.addRootNode();
// Scroll to root node and expand all dirs
this.rootNode.EnsureVisible();
this.treeView.ExpandAll();
}
/// <summary>
/// Hack to selected the correct node
/// </summary>
private void tvFolders_MouseClick(object sender, MouseEventArgs e)
{
this.treeView.SelectedNode = this.treeView.GetNodeAt(e.X, e.Y);
}
private void resetTree()
{
this.rootNode = null;
this.directoryToTreeNodeMapping = new Dictionary<string, TreeNode>();
this.nodePropsBackup = new Dictionary<string, object>();
this.treeView.Nodes.Clear();
}
private void createRootNode(DirectoryInfo directory, DirectoryIcons imageKey)
{
this.rootPath = directory.FullName.Trim('\\');
rootNode = new TreeNode(directory.Name);
rootNode.Tag = directory;
rootNode.ImageKey = imageKey.ToString();
rootNode.SelectedImageKey = imageKey.ToString();
directoryToTreeNodeMapping = new Dictionary<String, TreeNode>();
directoryToTreeNodeMapping.Add(directory.FullName, rootNode);
if (!this.fastMode)
{
// During fast mode the root node will be added after the search finished
addRootNode();
}
}
private void addRootNode()
{
if (rootNode == null || (treeView.Nodes.Count == 1 && treeView.Nodes[0] == rootNode))
return;
this.treeView.Nodes.Clear();
this.treeView.Nodes.Add(rootNode);
}
private void scrollToNode(TreeNode node)
{
// Ignore when fast mode is enabled
if (!this.fastMode)
{
node.EnsureVisible();
}
}
/// <summary>
/// Marks a folder with the warning or deleted icon
/// </summary>
/// <param name="path">Dir path</param>
/// <param name="iconKey">Icon</param>
internal void UpdateItemIcon(string path, DirectoryIcons iconKey)
{
var treeNode = this.findOrCreateDirectoryNodeByPath(path);
treeNode.ImageKey = iconKey.ToString();
treeNode.SelectedImageKey = iconKey.ToString();
this.scrollToNode(treeNode);
}
// TODO: Find better code structure for the following two routines
private TreeNode findOrCreateDirectoryNodeByPath(string path)
{
if (path == null) return null;
if (directoryToTreeNodeMapping.ContainsKey(path))
return directoryToTreeNodeMapping[path];
else
return AddOrUpdateDirectoryNode(path, DirectorySearchStatusTypes.NotEmpty, "");
}
/// <summary>
/// Add or update directory tree node
/// </summary>
/// <param name="path">Directory path</param>
/// <param name="statusType">Result status</param>
/// <param name="optionalErrorMsg">Error message (optional)</param>
/// <returns></returns>
public TreeNode AddOrUpdateDirectoryNode(string path, DirectorySearchStatusTypes statusType, string optionalErrorMsg)
{
if (directoryToTreeNodeMapping.ContainsKey(path))
{
// Just update the style if the node already exists
var node = directoryToTreeNodeMapping[path];
applyNodeStyle(node, path, statusType, optionalErrorMsg);
return node;
}
var directory = new DirectoryInfo(path);
// Create new tree node
var newTreeNode = new TreeNode(directory.Name);
applyNodeStyle(newTreeNode, path, statusType, optionalErrorMsg);
newTreeNode.Tag = directory;
if (directory.Parent.FullName.Trim('\\').Equals(this.rootPath, StringComparison.OrdinalIgnoreCase))
{
this.rootNode.Nodes.Add(newTreeNode);
}
else
{
var parentNode = this.findOrCreateDirectoryNodeByPath(directory.Parent.FullName);
parentNode.Nodes.Add(newTreeNode);
}
directoryToTreeNodeMapping.Add(path, newTreeNode);
this.scrollToNode(newTreeNode);
return newTreeNode;
}
private void applyNodeStyle(TreeNode treeNode, string path, DirectorySearchStatusTypes statusType, string optionalErrorMsg)
{
var directory = new DirectoryInfo(path);
// TODO: use enums for icon names
treeNode.ForeColor = (statusType == DirectorySearchStatusTypes.Empty) ? Color.Red : Color.Gray;
var iconKey = "";
if (statusType == DirectorySearchStatusTypes.Empty)
{
var fileCount = directory.GetFiles().Length;
var containsTrash = (fileCount > 0);
iconKey = containsTrash ? "folder_trash_files" : "folder";
// TODO: use data from scan thread
if ((directory.Attributes & FileAttributes.Hidden) == FileAttributes.Hidden)
iconKey = containsTrash ? "folder_hidden_trash_files" : "folder_hidden";
if ((directory.Attributes & FileAttributes.Encrypted) == FileAttributes.Encrypted)
iconKey = containsTrash ? "folder_lock_trash_files" : "folder_lock";
if ((directory.Attributes & FileAttributes.System) == FileAttributes.System)
iconKey = containsTrash ? "folder_lock_trash_files" : "folder_lock";
if (containsTrash && fileCount == 1)
{
treeNode.Text += " (contains " + fileCount.ToString() + " empty file)";
}
else if (containsTrash)
{
treeNode.Text += " (contains " + fileCount.ToString() + " empty files)";
}
}
else if (statusType == DirectorySearchStatusTypes.Error)
{
iconKey = "folder_warning";
if (optionalErrorMsg != "")
{
optionalErrorMsg = optionalErrorMsg.Replace("\r", "").Replace("\n", "");
if (optionalErrorMsg.Length > 55) optionalErrorMsg = optionalErrorMsg.Substring(0, 55) + "...";
treeNode.Text += " (" + optionalErrorMsg + ")";
}
}
else if (statusType == DirectorySearchStatusTypes.Ignore)
{
iconKey = "protected_icon";
treeNode.ForeColor = Color.Blue;
}
if (treeNode != this.rootNode)
{
treeNode.ImageKey = iconKey;
treeNode.SelectedImageKey = iconKey;
}
}
/// <summary>
/// Returns the selected folder path
/// </summary>
public string GetSelectedFolderPath()
{
if (this.treeView.SelectedNode != null && this.treeView.SelectedNode.Tag != null && this.treeView.SelectedNode.Tag is DirectoryInfo)
return ((DirectoryInfo)this.treeView.SelectedNode.Tag).FullName;
return "";
}
internal void DeleteSelectedDirectory()
{
if (this.treeView.SelectedNode != null && this.treeView.SelectedNode.Tag != null && this.treeView.SelectedNode.Tag is DirectoryInfo)
{
var folder = (DirectoryInfo)this.treeView.SelectedNode.Tag;
if (OnDeleteRequest != null)
OnDeleteRequest(this, new DeleteRequestFromTreeEventArgs(folder.FullName));
}
}
internal void RemoveNode(string path)
{
if (this.nodePropsBackup.ContainsKey(path))
this.nodePropsBackup.Remove(path);
if (this.directoryToTreeNodeMapping.ContainsKey(path))
{
this.directoryToTreeNodeMapping[path].Remove();
this.directoryToTreeNodeMapping.Remove(path);
}
}
#region Directory protection
internal void ProtectSelected()
{
if (treeView.SelectedNode != null)
this.ProtectNode(treeView.SelectedNode);
}
internal void UnprotectSelected()
{
unprotectNode(treeView.SelectedNode);
}
private void unprotectNode(TreeNode node)
{
if (node != null)
{
var directory = ((DirectoryInfo)node.Tag);
if (!this.nodePropsBackup.ContainsKey(directory.FullName))
{
// TODO: What to do when this info is missing, show error?
return;
}
// Restore props from backup values
string[] propList = ((string)this.nodePropsBackup[directory.FullName]).Split('|');
this.nodePropsBackup.Remove(directory.FullName);
node.ImageKey = propList[0];
node.SelectedImageKey = propList[0];
node.ForeColor = Color.FromArgb(Int32.Parse(propList[1]));
if (OnProtectionStatusChanged != null)
OnProtectionStatusChanged(this, new ProtectionStatusChangedEventArgs(directory.FullName, false));
// Unprotect all subnodes
foreach (TreeNode subNode in node.Nodes)
this.unprotectNode(subNode);
}
}
private void ProtectNode(TreeNode node)
{
DirectoryInfo directory = (DirectoryInfo)node.Tag;
if (nodePropsBackup.ContainsKey(directory.FullName))
return;
if (OnProtectionStatusChanged != null)
OnProtectionStatusChanged(this, new ProtectionStatusChangedEventArgs(directory.FullName, true));
// Backup node props if the user changes his mind we can restore the node
// TODO: I'm sure there is a better way to do this, maybe this info can be stored
// in the node.Tag or we simply recreate this info like it's a new node.
nodePropsBackup.Add(directory.FullName, node.ImageKey + "|" + node.ForeColor.ToArgb().ToString());
node.ImageKey = "protected_icon";
node.SelectedImageKey = "protected_icon";
node.ForeColor = Color.Blue;
// Recursively protect directories
if (node.Parent != this.rootNode)
ProtectNode(node.Parent);
}
#endregion
}
}
================================================
FILE: RED2/Lib/UIHelpers.cs
================================================
using System;
namespace RED2
{
/// <summary>
/// Icon names (Warning: Entries are case sensitive)
/// </summary>
public enum DirectoryIcons
{
home,
deleted,
protected_icon,
folder_warning
}
/// <summary>
/// List box container class thingy
/// </summary>
public class DeleteModeItem
{
public DeleteModes DeleteMode { get; set; }
public DeleteModeItem(DeleteModes Mode)
{
this.DeleteMode = Mode;
}
public static DeleteModes[] GetList()
{
return new DeleteModes[] {
DeleteModes.RecycleBin,
DeleteModes.RecycleBinShowErrors,
DeleteModes.RecycleBinWithQuestion,
DeleteModes.Direct,
DeleteModes.Simulate
};
}
public override string ToString()
{
switch (this.DeleteMode)
{
case DeleteModes.RecycleBin:
return "Delete to recycle bin and ignore errors (safer but slower, default setting)";
case DeleteModes.Direct:
return "Bypass recycle bin and directly delete dirs (more dangerous but faster)";
case DeleteModes.RecycleBinShowErrors:
return "Delete to recycle bin and show all errors (can be annoying)";
case DeleteModes.RecycleBinWithQuestion:
return "Delete to recycle bin and ask before every deletion";
case DeleteModes.Simulate:
return "Simulate deletion (just pretend doing it, for testing)";
// TODO: Idea -> Move files instead of deleting?
default:
throw new Exception("Unknown delete mode");
}
}
}
}
================================================
FILE: RED2/LogWindow.Designer.cs
================================================
namespace RED2
{
partial class LogWindow
{
/// <summary>
/// Erforderliche Designervariable.
/// </summary>
private System.ComponentModel.IContainer components = null;
/// <summary>
/// Verwendete Ressourcen bereinigen.
/// </summary>
/// <param name="disposing">True, wenn verwaltete Ressourcen gelöscht werden sollen; andernfalls False.</param>
protected override void Dispose(bool disposing)
{
if (disposing && (components != null))
{
components.Dispose();
}
base.Dispose(disposing);
}
#region Vom Windows Form-Designer generierter Code
/// <summary>
/// Erforderliche Methode für die Designerunterstützung.
/// Der Inhalt der Methode darf nicht mit dem Code-Editor geändert werden.
/// </summary>
private void InitializeComponent()
{
this.tbLog = new System.Windows.Forms.TextBox();
this.SuspendLayout();
//
// tbLog
//
this.tbLog.Dock = System.Windows.Forms.DockStyle.Fill;
this.tbLog.Font = new System.Drawing.Font("Lucida Console", 9F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
this.tbLog.Location = new System.Drawing.Point(0, 0);
this.tbLog.Multiline = true;
this.tbLog.Name = "tbLog";
this.tbLog.ScrollBars = System.Windows.Forms.ScrollBars.Both;
this.tbLog.Size = new System.Drawing.Size(684, 462);
this.tbLog.TabIndex = 0;
this.tbLog.WordWrap = false;
this.tbLog.DoubleClick += new System.EventHandler(this.tbLog_DoubleClick);
//
// LogWindow
//
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.ClientSize = new System.Drawing.Size(684, 462);
this.Controls.Add(this.tbLog);
this.MinimizeBox = false;
this.Name = "LogWindow";
this.ShowIcon = false;
this.ShowInTaskbar = false;
this.StartPosition = System.Windows.Forms.FormStartPosition.CenterParent;
this.Text = "Logs";
this.Load += new System.EventHandler(this.LogWindow_Load);
this.ResumeLayout(false);
this.PerformLayout();
}
#endregion
private System.Windows.Forms.TextBox tbLog;
}
}
================================================
FILE: RED2/LogWindow.cs
================================================
using System;
using System.Windows.Forms;
namespace RED2
{
public partial class LogWindow : Form
{
public LogWindow()
{
InitializeComponent();
}
private void LogWindow_Load(object sender, EventArgs e)
{
}
public void SetLog(string log) {
this.tbLog.Text = log;
}
private void tbLog_DoubleClick(object sender, EventArgs e)
{
this.tbLog.SelectAll();
}
}
}
================================================
FILE: RED2/LogWindow.resx
================================================
<?xml version="1.0" encoding="utf-8"?>
<root>
<!--
Microsoft ResX Schema
Version 2.0
The primary goals of this format is to allow a simple XML format
that is mostly human readable. The generation and parsing of the
various data types are done through the TypeConverter classes
associated with the data types.
Example:
... ado.net/XML headers & schema ...
<resheader name="resmimetype">text/microsoft-resx</resheader>
<resheader name="version">2.0</resheader>
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
<value>[base64 mime encoded serialized .NET Framework object]</value>
</data>
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
<comment>This is a comment</comment>
</data>
There are any number of "resheader" rows that contain simple
name/value pairs.
Each data row contains a name, and value. The row also contains a
type or mimetype. Type corresponds to a .NET class that support
text/value conversion through the TypeConverter architecture.
Classes that don't support this are serialized and stored with the
mimetype set.
The mimetype is used for serialized objects, and tells the
ResXResourceReader how to depersist the object. This is currently not
extensible. For a given mimetype the value must be set accordingly:
Note - application/x-microsoft.net.object.binary.base64 is the format
that the ResXResourceWriter will generate, however the reader can
read any of the formats listed below.
mimetype: application/x-microsoft.net.object.binary.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.soap.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.bytearray.base64
value : The object must be serialized into a byte array
: using a System.ComponentModel.TypeConverter
: and then encoded with base64 encoding.
-->
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" />
</xsd:sequence>
<xsd:attribute name="name" use="required" type="xsd:string" />
<xsd:attribute name="type" type="xsd:string" />
<xsd:attribute name="mimetype" type="xsd:string" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="assembly">
<xsd:complexType>
<xsd:attribute name="alias" type="xsd:string" />
<xsd:attribute name="name" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" />
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
</root>
================================================
FILE: RED2/MainWindow.Designer.cs
================================================
namespace RED2
{
partial class MainWindow
{
/// <summary>
/// Erforderliche Designervariable.
/// </summary>
private System.ComponentModel.IContainer components = null;
/// <summary>
/// Verwendete Ressourcen bereinigen.
/// </summary>
/// <param name="disposing">True, wenn verwaltete Ressourcen gelöscht werden sollen; andernfalls False.</param>
protected override void Dispose(bool disposing)
{
if (disposing && (components != null))
{
components.Dispose();
}
base.Dispose(disposing);
}
#region Vom Windows Form-Designer generierter Code
/// <summary>
/// Erforderliche Methode für die Designerunterstützung.
/// Der Inhalt der Methode darf nicht mit dem Code-Editor geändert werden.
/// </summary>
private void InitializeComponent()
{
this.components = new System.ComponentModel.Container();
System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(MainWindow));
this.ilFolderIcons = new System.Windows.Forms.ImageList(this.components);
this.tcMain = new System.Windows.Forms.TabControl();
this.tabSearch = new System.Windows.Forms.TabPage();
this.lbFastModeInfo = new System.Windows.Forms.Label();
this.btnShowLog = new System.Windows.Forms.Button();
this.btnCancel = new System.Windows.Forms.Button();
this.btnScan = new System.Windows.Forms.Button();
this.btnDelete = new System.Windows.Forms.Button();
this.pnlIcons = new System.Windows.Forms.Panel();
this.label1 = new System.Windows.Forms.Label();
this.panel5 = new System.Windows.Forms.Panel();
this.panel3 = new System.Windows.Forms.Panel();
this.label18 = new System.Windows.Forms.Label();
this.panel2 = new System.Windows.Forms.Panel();
this.label17 = new System.Windows.Forms.Label();
this.panel1 = new System.Windows.Forms.Panel();
this.label12 = new System.Windows.Forms.Label();
this.label6 = new System.Windows.Forms.Label();
this.lbStatus = new System.Windows.Forms.Label();
this.pbProgressStatus = new System.Windows.Forms.ProgressBar();
this.tvFolders = new System.Windows.Forms.TreeView();
this.cmStrip = new System.Windows.Forms.ContextMenuStrip(this.components);
this.openFolderToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
this.scanOnlyThisDirectoryToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
this.toolStripSeparator4 = new System.Windows.Forms.ToolStripSeparator();
this.toolStripExpandAll = new System.Windows.Forms.ToolStripMenuItem();
this.toolStripCollapseAll = new System.Windows.Forms.ToolStripMenuItem();
this.toolStripSeparator1 = new System.Windows.Forms.ToolStripSeparator();
this.protectFolderFromBeingDeletedToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
this.unprotectFolderToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
this.toolStripSeparator3 = new System.Windows.Forms.ToolStripSeparator();
this.proToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
this.toolStripSeparator2 = new System.Windows.Forms.ToolStripSeparator();
this.deleteToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
this.btnExit = new System.Windows.Forms.Button();
this.tbFolder = new System.Windows.Forms.TextBox();
this.btnChooseFolder = new System.Windows.Forms.Button();
this.lblPickAFolder = new System.Windows.Forms.Label();
this.tabSettings = new System.Windows.Forms.TabPage();
this.gbDeleteMode = new System.Windows.Forms.GroupBox();
this.label15 = new System.Windows.Forms.Label();
this.cbDeleteMode = new System.Windows.Forms.ComboBox();
this.groupBoxExplorerIntegration = new System.Windows.Forms.GroupBox();
this.lblReqAdmin = new System.Windows.Forms.Label();
this.btnExplorerRemove = new System.Windows.Forms.Button();
this.btnExplorerIntegrate = new System.Windows.Forms.Button();
this.label16 = new System.Windows.Forms.Label();
this.gbOptions = new System.Windows.Forms.GroupBox();
this.label25 = new System.Windows.Forms.Label();
this.label11 = new System.Windows.Forms.Label();
this.label21 = new System.Windows.Forms.Label();
this.cbFastSearchMode = new System.Windows.Forms.CheckBox();
this.cbHideScanErrors = new System.Windows.Forms.CheckBox();
this.cbIgnoreErrors = new System.Windows.Forms.CheckBox();
this.cbClipboardDetection = new System.Windows.Forms.CheckBox();
this.cbIgnoreHiddenFolders = new System.Windows.Forms.CheckBox();
this.cbIgnore0kbFiles = new System.Windows.Forms.CheckBox();
this.tabIgnoreList = new System.Windows.Forms.TabPage();
this.label22 = new System.Windows.Forms.Label();
this.tbIgnoreFolders = new System.Windows.Forms.TextBox();
this.label10 = new System.Windows.Forms.Label();
this.tabAdvanced = new System.Windows.Forms.TabPage();
this.gbAdvancedSettings = new System.Windows.Forms.GroupBox();
this.label20 = new System.Windows.Forms.Label();
this.label26 = new System.Windows.Forms.Label();
this.label27 = new System.Windows.Forms.Label();
this.label19 = new System.Windows.Forms.Label();
this.cbKeepSystemFolders = new System.Windows.Forms.CheckBox();
this.nuFolderAge = new System.Windows.Forms.NumericUpDown();
this.label7 = new System.Windows.Forms.Label();
this.label24 = new System.Windows.Forms.Label();
this.nuPause = new System.Windows.Forms.NumericUpDown();
this.nuMaxDepth = new System.Windows.Forms.NumericUpDown();
this.label4 = new System.Windows.Forms.Label();
this.label3 = new System.Windows.Forms.Label();
this.nuInfiniteLoopDetectionCount = new System.Windows.Forms.NumericUpDown();
this.btnResetConfig = new System.Windows.Forms.Button();
this.btnCopyDebugInfo = new System.Windows.Forms.Button();
this.gbIgnoreFilenames = new System.Windows.Forms.GroupBox();
this.label23 = new System.Windows.Forms.Label();
this.label14 = new System.Windows.Forms.Label();
this.tbIgnoreFiles = new System.Windows.Forms.TextBox();
this.label2 = new System.Windows.Forms.Label();
this.label8 = new System.Windows.Forms.Label();
this.tabAbout = new System.Windows.Forms.TabPage();
this.llGithub = new System.Windows.Forms.LinkLabel();
this.linkLabel2 = new System.Windows.Forms.LinkLabel();
this.linkLabel1 = new System.Windows.Forms.LinkLabel();
this.tbCredits = new System.Windows.Forms.TextBox();
this.lblRedStats = new System.Windows.Forms.Label();
this.label5 = new System.Windows.Forms.Label();
this.llWebsite = new System.Windows.Forms.LinkLabel();
this.lbAppTitle = new System.Windows.Forms.Label();
this.tcMain.SuspendLayout();
this.tabSearch.SuspendLayout();
this.pnlIcons.SuspendLayout();
this.cmStrip.SuspendLayout();
this.tabSettings.SuspendLayout();
this.gbDeleteMode.SuspendLayout();
this.groupBoxExplorerIntegration.SuspendLayout();
this.gbOptions.SuspendLayout();
this.tabIgnoreList.SuspendLayout();
this.tabAdvanced.SuspendLayout();
this.gbAdvancedSettings.SuspendLayout();
((System.ComponentModel.ISupportInitialize)(this.nuFolderAge)).BeginInit();
((System.ComponentModel.ISupportInitialize)(this.nuPause)).BeginInit();
((System.ComponentModel.ISupportInitialize)(this.nuMaxDepth)).BeginInit();
((System.ComponentModel.ISupportInitialize)(this.nuInfiniteLoopDetectionCount)).BeginInit();
this.gbIgnoreFilenames.SuspendLayout();
this.tabAbout.SuspendLayout();
this.SuspendLayout();
//
// ilFolderIcons
//
this.ilFolderIcons.ImageStream = ((System.Windows.Forms.ImageListStreamer)(resources.GetObject("ilFolderIcons.ImageStream")));
this.ilFolderIcons.TransparentColor = System.Drawing.Color.White;
this.ilFolderIcons.Images.SetKeyName(0, "trash");
this.ilFolderIcons.Images.SetKeyName(1, "cancel");
this.ilFolderIcons.Images.SetKeyName(2, "deleted");
this.ilFolderIcons.Images.SetKeyName(3, "folder");
this.ilFolderIcons.Images.SetKeyName(4, "folder_hidden");
this.ilFolderIcons.Images.SetKeyName(5, "folder_lock");
this.ilFolderIcons.Images.SetKeyName(6, "folder_lock_trash_files");
this.ilFolderIcons.Images.SetKeyName(7, "folder_trash_files");
this.ilFolderIcons.Images.SetKeyName(8, "folder_warning");
this.ilFolderIcons.Images.SetKeyName(9, "help");
this.ilFolderIcons.Images.SetKeyName(10, "home");
this.ilFolderIcons.Images.SetKeyName(11, "search");
this.ilFolderIcons.Images.SetKeyName(12, "folder_hidden_trash_files");
this.ilFolderIcons.Images.SetKeyName(13, "preferences");
this.ilFolderIcons.Images.SetKeyName(14, "exit");
this.ilFolderIcons.Images.SetKeyName(15, "protected_icon");
this.ilFolderIcons.Images.SetKeyName(16, "filter");
//
// tcMain
//
this.tcMain.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom)
| System.Windows.Forms.AnchorStyles.Left)
| System.Windows.Forms.AnchorStyles.Right)));
this.tcMain.Controls.Add(this.tabSearch);
this.tcMain.Controls.Add(this.tabSettings);
this.tcMain.Controls.Add(this.tabIgnoreList);
this.tcMain.Controls.Add(this.tabAdvanced);
this.tcMain.Controls.Add(this.tabAbout);
this.tcMain.ImageList = this.ilFolderIcons;
this.tcMain.Location = new System.Drawing.Point(9, 7);
this.tcMain.Multiline = true;
this.tcMain.Name = "tcMain";
this.tcMain.Padding = new System.Drawing.Point(10, 5);
this.tcMain.RightToLeft = System.Windows.Forms.RightToLeft.No;
this.tcMain.SelectedIndex = 0;
this.tcMain.ShowToolTips = true;
this.tcMain.Size = new System.Drawing.Size(706, 575);
this.tcMain.TabIndex = 18;
//
// tabSearch
//
this.tabSearch.AccessibleDescription = "";
this.tabSearch.AccessibleName = "";
this.tabSearch.Controls.Add(this.lbFastModeInfo);
this.tabSearch.Controls.Add(this.btnShowLog);
this.tabSearch.Controls.Add(this.btnCancel);
this.tabSearch.Controls.Add(this.btnScan);
this.tabSearch.Controls.Add(this.btnDelete);
this.tabSearch.Controls.Add(this.pnlIcons);
this.tabSearch.Controls.Add(this.label6);
this.tabSearch.Controls.Add(this.lbStatus);
this.tabSearch.Controls.Add(this.pbProgressStatus);
this.tabSearch.Controls.Add(this.tvFolders);
this.tabSearch.Controls.Add(this.btnExit);
this.tabSearch.Controls.Add(this.tbFolder);
this.tabSearch.Controls.Add(this.btnChooseFolder);
this.tabSearch.Controls.Add(this.lblPickAFolder);
this.tabSearch.ImageKey = "search";
this.tabSearch.Location = new System.Drawing.Point(4, 27);
this.tabSearch.Name = "tabSearch";
this.tabSearch.Padding = new System.Windows.Forms.Padding(3);
this.tabSearch.Size = new System.Drawing.Size(698, 544);
this.tabSearch.TabIndex = 0;
this.tabSearch.Text = "Find";
this.tabSearch.ToolTipText = "Search for empty directories";
this.tabSearch.UseVisualStyleBackColor = true;
//
// lbFastModeInfo
//
this.lbFastModeInfo.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom)
| System.Windows.Forms.AnchorStyles.Left)
| System.Windows.Forms.AnchorStyles.Right)));
this.lbFastModeInfo.BackColor = System.Drawing.SystemColors.Control;
this.lbFastModeInfo.ForeColor = System.Drawing.Color.Gray;
this.lbFastModeInfo.Location = new System.Drawing.Point(107, 257);
this.lbFastModeInfo.Name = "lbFastModeInfo";
this.lbFastModeInfo.Size = new System.Drawing.Size(346, 13);
this.lbFastModeInfo.TabIndex = 18;
this.lbFastModeInfo.Text = "[Fast mode is enabled, results will be shown after the process is finished]";
this.lbFastModeInfo.Visible = false;
//
// btnShowLog
//
this.btnShowLog.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left)));
this.btnShowLog.Enabled = false;
this.btnShowLog.Location = new System.Drawing.Point(380, 498);
this.btnShowLog.Name = "btnShowLog";
this.btnShowLog.Size = new System.Drawing.Size(79, 34);
this.btnShowLog.TabIndex = 17;
this.btnShowLog.Text = "Show &logs";
this.btnShowLog.UseVisualStyleBackColor = true;
this.btnShowLog.Click += new System.EventHandler(this.btnShowLog_Click);
//
// btnCancel
//
this.btnCancel.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left)));
this.btnCancel.Enabled = false;
this.btnCancel.ImageKey = "cancel";
this.btnCancel.ImageList = this.ilFolderIcons;
this.btnCancel.Location = new System.Drawing.Point(276, 498);
this.btnCancel.Name = "btnCancel";
this.btnCancel.Size = new System.Drawing.Size(98, 34);
this.btnCancel.TabIndex = 6;
this.btnCancel.Text = "&Cancel";
this.btnCancel.TextAlign = System.Drawing.ContentAlignment.MiddleLeft;
this.btnCancel.TextImageRelation = System.Windows.Forms.TextImageRelation.ImageBeforeText;
this.btnCancel.UseVisualStyleBackColor = true;
this.btnCancel.Click += new System.EventHandler(this.btnCancel_Click);
//
// btnScan
//
this.btnScan.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left)));
this.btnScan.ImageKey = "search";
this.btnScan.ImageList = this.ilFolderIcons;
this.btnScan.Location = new System.Drawing.Point(13, 497);
this.btnScan.Name = "btnScan";
this.btnScan.Size = new System.Drawing.Size(130, 35);
this.btnScan.TabIndex = 4;
this.btnScan.Text = "&Find directories";
this.btnScan.TextAlign = System.Drawing.ContentAlignment.MiddleLeft;
this.btnScan.TextImageRelation = System.Windows.Forms.TextImageRelation.ImageBeforeText;
this.btnScan.UseVisualStyleBackColor = true;
this.btnScan.Click += new System.EventHandler(this.btnScan_Click);
//
// btnDelete
//
this.btnDelete.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left)));
this.btnDelete.Enabled = false;
this.btnDelete.ImageKey = "trash";
this.btnDelete.ImageList = this.ilFolderIcons;
this.btnDelete.Location = new System.Drawing.Point(150, 497);
this.btnDelete.Name = "btnDelete";
this.btnDelete.Size = new System.Drawing.Size(120, 35);
this.btnDelete.TabIndex = 5;
this.btnDelete.Text = "&Delete matches";
this.btnDelete.TextAlign = System.Drawing.ContentAlignment.MiddleLeft;
this.btnDelete.TextImageRelation = System.Windows.Forms.TextImageRelation.ImageBeforeText;
this.btnDelete.UseVisualStyleBackColor = true;
this.btnDelete.Click += new System.EventHandler(this.btnDelete_Click);
//
// pnlIcons
//
this.pnlIcons.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom)
| System.Windows.Forms.AnchorStyles.Right)));
this.pnlIcons.BackColor = System.Drawing.SystemColors.Info;
this.pnlIcons.BorderStyle = System.Windows.Forms.BorderStyle.FixedSingle;
this.pnlIcons.Controls.Add(this.label1);
this.pnlIcons.Controls.Add(this.panel5);
this.pnlIcons.Controls.Add(this.panel3);
this.pnlIcons.Controls.Add(this.label18);
this.pnlIcons.Controls.Add(this.panel2);
this.pnlIcons.Controls.Add(this.label17);
this.pnlIcons.Controls.Add(this.panel1);
this.pnlIcons.Controls.Add(this.label12);
this.pnlIcons.Location = new System.Drawing.Point(557, 60);
this.pnlIcons.Name = "pnlIcons";
this.pnlIcons.Size = new System.Drawing.Size(126, 406);
this.pnlIcons.TabIndex = 16;
//
// label1
//
this.label1.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left)
| System.Windows.Forms.AnchorStyles.Right)));
this.label1.AutoSize = true;
this.label1.Location = new System.Drawing.Point(25, 382);
this.label1.Name = "label1";
this.label1.Size = new System.Drawing.Size(53, 13);
this.label1.TabIndex = 22;
this.label1.Text = "Protected";
//
// panel5
//
this.panel5.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left)));
this.panel5.BackColor = System.Drawing.Color.Blue;
this.panel5.Location = new System.Drawing.Point(8, 381);
this.panel5.Name = "panel5";
this.panel5.Size = new System.Drawing.Size(15, 15);
this.panel5.TabIndex = 21;
//
// panel3
//
this.panel3.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left)
| System.Windows.Forms.AnchorStyles.Right)));
this.panel3.BackColor = System.Drawing.SystemColors.Control;
this.panel3.Location = new System.Drawing.Point(8, 325);
this.panel3.Name = "panel3";
this.panel3.Size = new System.Drawing.Size(120, 2);
this.panel3.TabIndex = 18;
//
// label18
//
this.label18.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left)
| System.Windows.Forms.AnchorStyles.Right)));
this.label18.AutoSize = true;
this.label18.Location = new System.Drawing.Point(25, 359);
this.label18.Name = "label18";
this.label18.Size = new System.Drawing.Size(77, 13);
this.label18.TabIndex = 20;
this.label18.Text = "Will be deleted";
//
// panel2
//
this.panel2.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left)));
this.panel2.BackColor = System.Drawing.Color.Red;
this.panel2.Location = new System.Drawing.Point(8, 358);
this.panel2.Name = "panel2";
this.panel2.Size = new System.Drawing.Size(15, 15);
this.panel2.TabIndex = 19;
//
// label17
//
this.label17.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left)
| System.Windows.Forms.AnchorStyles.Right)));
this.label17.AutoSize = true;
this.label17.Location = new System.Drawing.Point(24, 336);
this.label17.Name = "label17";
this.label17.Size = new System.Drawing.Size(99, 13);
this.label17.TabIndex = 18;
this.label17.Text = "Will not be touched";
//
// panel1
//
this.panel1.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left)));
this.panel1.BackColor = System.Drawing.Color.Gray;
this.panel1.Location = new System.Drawing.Point(8, 335);
this.panel1.Name = "panel1";
this.panel1.Size = new System.Drawing.Size(15, 15);
this.panel1.TabIndex = 17;
//
// label12
//
this.label12.AutoSize = true;
this.label12.Font = new System.Drawing.Font("Microsoft Sans Serif", 8.25F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
this.label12.Location = new System.Drawing.Point(4, 6);
this.label12.Name = "label12";
this.label12.Size = new System.Drawing.Size(98, 13);
this.label12.TabIndex = 0;
this.label12.Text = "Icon description";
//
// label6
//
this.label6.AutoSize = true;
this.label6.Location = new System.Drawing.Point(11, 16);
this.label6.Name = "label6";
this.label6.Size = new System.Drawing.Size(177, 13);
this.label6.TabIndex = 15;
this.label6.Text = "Please choose a directory to check:";
//
// lbStatus
//
this.lbStatus.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left)
| System.Windows.Forms.AnchorStyles.Right)));
this.lbStatus.Location = new System.Drawing.Point(149, 475);
this.lbStatus.Name = "lbStatus";
this.lbStatus.Size = new System.Drawing.Size(532, 13);
this.lbStatus.TabIndex = 13;
this.lbStatus.Text = "Status text";
//
// pbProgressStatus
//
this.pbProgressStatus.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left)));
this.pbProgressStatus.Location = new System.Drawing.Point(14, 475);
this.pbProgressStatus.Name = "pbProgressStatus";
this.pbProgressStatus.Size = new System.Drawing.Size(129, 13);
this.pbProgressStatus.TabIndex = 12;
//
// tvFolders
//
this.tvFolders.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom)
| System.Windows.Forms.AnchorStyles.Left)
| System.Windows.Forms.AnchorStyles.Right)));
this.tvFolders.ContextMenuStrip = this.cmStrip;
this.tvFolders.ImageKey = "folder";
this.tvFolders.ImageList = this.ilFolderIcons;
this.tvFolders.Location = new System.Drawing.Point(14, 60);
this.tvFolders.Name = "tvFolders";
this.tvFolders.SelectedImageKey = "folder";
this.tvFolders.Size = new System.Drawing.Size(533, 406);
this.tvFolders.TabIndex = 3;
this.tvFolders.DoubleClick += new System.EventHandler(this.tvFolders_DoubleClick);
//
// cmStrip
//
this.cmStrip.ImageScalingSize = new System.Drawing.Size(20, 20);
this.cmStrip.Items.AddRange(new System.Windows.Forms.ToolStripItem[] {
this.openFolderToolStripMenuItem,
this.scanOnlyThisDirectoryToolStripMenuItem,
this.toolStripSeparator4,
this.toolStripExpandAll,
this.toolStripCollapseAll,
this.toolStripSeparator1,
this.protectFolderFromBeingDeletedToolStripMenuItem,
this.unprotectFolderToolStripMenuItem,
this.toolStripSeparator3,
this.proToolStripMenuItem,
this.toolStripSeparator2,
this.deleteToolStripMenuItem});
this.cmStrip.Name = "cmStrip";
this.cmStrip.RenderMode = System.Windows.Forms.ToolStripRenderMode.System;
this.cmStrip.ShowImageMargin = false;
this.cmStrip.Size = new System.Drawing.Size(202, 204);
this.cmStrip.Opening += new System.ComponentModel.CancelEventHandler(this.cmStrip_Opening);
//
// openFolderToolStripMenuItem
//
this.openFolderToolStripMenuItem.Name = "openFolderToolStripMenuItem";
this.openFolderToolStripMenuItem.Size = new System.Drawing.Size(201, 22);
this.openFolderToolStripMenuItem.Text = "&Open";
this.openFolderToolStripMenuItem.Click += new System.EventHandler(this.openFolderToolStripMenuItem_Click);
//
// scanOnlyThisDirectoryToolStripMenuItem
//
this.scanOnlyThisDirectoryToolStripMenuItem.Name = "scanOnlyThisDirectoryToolStripMenuItem";
this.scanOnlyThisDirectoryToolStripMenuItem.Size = new System.Drawing.Size(201, 22);
this.scanOnlyThisDirectoryToolStripMenuItem.Text = "&Search only this directory";
this.scanOnlyThisDirectoryToolStripMenuItem.Click += new System.EventHandler(this.scanOnlyThisDirectoryToolStripMenuItem_Click);
//
// toolStripSeparator4
//
this.toolStripSeparator4.Name = "toolStripSeparator4";
this.toolStripSeparator4.Size = new System.Drawing.Size(198, 6);
//
// toolStripExpandAll
//
this.toolStripExpandAll.Name = "toolStripExpandAll";
this.toolStripExpandAll.Size = new System.Drawing.Size(201, 22);
this.toolStripExpandAll.Text = "&Expand all";
this.toolStripExpandAll.Click += new System.EventHandler(this.toolStripExpandAll_Click);
//
// toolStripCollapseAll
//
this.toolStripCollapseAll.Name = "toolStripCollapseAll";
this.toolStripCollapseAll.Size = new System.Drawing.Size(201, 22);
this.toolStripCollapseAll.Text = "&Collapse all";
this.toolStripCollapseAll.Click += new System.EventHandler(this.toolStripCollapseAll_Click);
//
// toolStripSeparator1
//
this.toolStripSeparator1.Name = "toolStripSeparator1";
this.toolStripSeparator1.Size = new System.Drawing.Size(198, 6);
//
// protectFolderFromBeingDeletedToolStripMenuItem
//
this.protectFolderFromBeingDeletedToolStripMenuItem.Name = "protectFolderFromBeingDeletedToolStripMenuItem";
this.protectFolderFromBeingDeletedToolStripMenuItem.Size = new System.Drawing.Size(201, 22);
this.protectFolderFromBeingDeletedToolStripMenuItem.Text = "&Protect from deletion (once)";
this.protectFolderFromBeingDeletedToolStripMenuItem.Click += new System.EventHandler(this.protectFolderFromBeingDeletedToolStripMenuItem_Click);
//
// unprotectFolderToolStripMenuItem
//
this.unprotectFolderToolStripMenuItem.Name = "unprotectFolderToolStripMenuItem";
this.unprotectFolderToolStripMenuItem.Size = new System.Drawing.Size(201, 22);
this.unprotectFolderToolStripMenuItem.Text = "&Unprotect";
this.unprotectFolderToolStripMenuItem.Click += new System.EventHandler(this.unprotectFolderToolStripMenuItem_Click);
//
// toolStripSeparator3
//
this.toolStripSeparator3.Name = "toolStripSeparator3";
this.toolStripSeparator3.Size = new System.Drawing.Size(198, 6);
//
// proToolStripMenuItem
//
this.proToolStripMenuItem.Name = "proToolStripMenuItem";
this.proToolStripMenuItem.Size = new System.Drawing.Size(201, 22);
this.proToolStripMenuItem.Text = "Add to permanent &ignore list";
this.proToolStripMenuItem.Click += new System.EventHandler(this.proToolStripMenuItem_Click);
//
// toolStripSeparator2
//
this.toolStripSeparator2.Name = "toolStripSeparator2";
this.toolStripSeparator2.Size = new System.Drawing.Size(198, 6);
//
// deleteToolStripMenuItem
//
this.deleteToolStripMenuItem.Name = "deleteToolStripMenuItem";
this.deleteToolStripMenuItem.Size = new System.Drawing.Size(201, 22);
this.deleteToolStripMenuItem.Text = "&Delete";
this.deleteToolStripMenuItem.Click += new System.EventHandler(this.deleteToolStripMenuItem_Click);
//
// btnExit
//
this.btnExit.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right)));
this.btnExit.ImageKey = "exit";
this.btnExit.ImageList = this.ilFolderIcons;
this.btnExit.Location = new System.Drawing.Point(558, 498);
this.btnExit.Name = "btnExit";
this.btnExit.Size = new System.Drawing.Size(126, 34);
this.btnExit.TabIndex = 7;
this.btnExit.Text = "&Exit";
this.btnExit.TextAlign = System.Drawing.ContentAlignment.MiddleLeft;
this.btnExit.TextImageRelation = System.Windows.Forms.TextImageRelation.ImageBeforeText;
this.btnExit.UseVisualStyleBackColor = true;
this.btnExit.Click += new System.EventHandler(this.btnExit_Click);
//
// tbFolder
//
this.tbFolder.AccessibleDescription = "Root directory";
this.tbFolder.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left)
| System.Windows.Forms.AnchorStyles.Right)));
this.tbFolder.Location = new System.Drawing.Point(14, 34);
this.tbFolder.Name = "tbFolder";
this.tbFolder.Size = new System.Drawing.Size(533, 20);
this.tbFolder.TabIndex = 1;
this.tbFolder.Text = "C:\\";
this.tbFolder.MouseDoubleClick += new System.Windows.Forms.MouseEventHandler(this.tbFolder_MouseDoubleClick);
//
// btnChooseFolder
//
this.btnChooseFolder.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right)));
this.btnChooseFolder.Location = new System.Drawing.Point(558, 33);
this.btnChooseFolder.Name = "btnChooseFolder";
this.btnChooseFolder.Size = new System.Drawing.Size(126, 21);
this.btnChooseFolder.TabIndex = 2;
this.btnChooseFolder.Text = "Browse...";
this.btnChooseFolder.UseVisualStyleBackColor = true;
this.btnChooseFolder.Click += new System.EventHandler(this.btnChooseFolder_Click);
//
// lblPickAFolder
//
this.lblPickAFolder.AutoSize = true;
this.lblPickAFolder.Location = new System.Drawing.Point(10, 13);
this.lblPickAFolder.Name = "lblPickAFolder";
this.lblPickAFolder.Size = new System.Drawing.Size(0, 13);
this.lblPickAFolder.TabIndex = 3;
//
// tabSettings
//
this.tabSettings.Controls.Add(this.gbDeleteMode);
this.tabSettings.Controls.Add(this.groupBoxExplorerIntegration);
this.tabSettings.Controls.Add(this.gbOptions);
this.tabSettings.ImageKey = "preferences";
this.tabSettings.Location = new System.Drawing.Point(4, 27);
this.tabSettings.Name = "tabSettings";
this.tabSettings.Padding = new System.Windows.Forms.Padding(3);
this.tabSettings.Size = new System.Drawing.Size(698, 544);
this.tabSettings.TabIndex = 1;
this.tabSettings.Text = "Settings";
this.tabSettings.ToolTipText = "Application settings";
this.tabSettings.UseVisualStyleBackColor = true;
//
// gbDeleteMode
//
this.gbDeleteMode.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left)
| System.Windows.Forms.AnchorStyles.Right)));
this.gbDeleteMode.Controls.Add(this.label15);
this.gbDeleteMode.Controls.Add(this.cbDeleteMode);
this.gbDeleteMode.Location = new System.Drawing.Point(14, 358);
this.gbDeleteMode.Name = "gbDeleteMode";
this.gbDeleteMode.Size = new System.Drawing.Size(669, 84);
this.gbDeleteMode.TabIndex = 20;
this.gbDeleteMode.TabStop = false;
this.gbDeleteMode.Text = "Delete mode";
//
// label15
//
this.label15.AutoSize = true;
this.label15.Location = new System.Drawing.Point(16, 27);
this.label15.Name = "label15";
this.label15.Size = new System.Drawing.Size(204, 13);
this.label15.TabIndex = 14;
this.label15.Text = "How should empty directories be deleted?";
//
// cbDeleteMode
//
this.cbDeleteMode.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left)
| System.Windows.Forms.AnchorStyles.Right)));
this.cbDeleteMode.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList;
this.cbDeleteMode.FormattingEnabled = true;
this.cbDeleteMode.Location = new System.Drawing.Point(19, 45);
this.cbDeleteMode.Name = "cbDeleteMode";
this.cbDeleteMode.Size = new System.Drawing.Size(631, 21);
this.cbDeleteMode.TabIndex = 7;
//
// groupBoxExplorerIntegration
//
this.groupBoxExplorerIntegration.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left)
| System.Windows.Forms.AnchorStyles.Right)));
this.groupBoxExplorerIntegration.Controls.Add(this.lblReqAdmin);
this.groupBoxExplorerIntegration.Controls.Add(this.btnExplorerRemove);
this.groupBoxExplorerIntegration.Controls.Add(this.btnExplorerIntegrate);
this.groupBoxExplorerIntegration.Controls.Add(this.label16);
this.groupBoxExplorerIntegration.Location = new System.Drawing.Point(14, 461);
this.groupBoxExplorerIntegration.Name = "groupBoxExplorerIntegration";
this.groupBoxExplorerIntegration.Size = new System.Drawing.Size(669, 71);
this.groupBoxExplorerIntegration.TabIndex = 14;
this.groupBoxExplorerIntegration.TabStop = false;
this.groupBoxExplorerIntegration.Text = "Windows Explorer integration";
//
// lblReqAdmin
//
this.lblReqAdmin.AutoSize = true;
this.lblReqAdmin.ForeColor = System.Drawing.SystemColors.GrayText;
this.lblReqAdmin.Location = new System.Drawing.Point(16, 43);
this.lblReqAdmin.Name = "lblReqAdmin";
this.lblReqAdmin.Size = new System.Drawing.Size(314, 13);
this.lblReqAdmin.TabIndex = 26;
this.lblReqAdmin.Text = "You need to start the application as an Admin user to change this";
//
// btnExplorerRemove
//
this.btnExplorerRemove.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right)));
this.btnExplorerRemove.Location = new System.Drawing.Point(532, 24);
this.btnExplorerRemove.Name = "btnExplorerRemove";
this.btnExplorerRemove.Size = new System.Drawing.Size(119, 34);
this.btnExplorerRemove.TabIndex = 25;
this.btnExplorerRemove.Text = "Uninstall";
this.btnExplorerRemove.UseVisualStyleBackColor = true;
this.btnExplorerRemove.Click += new System.EventHandler(this.btnExplorerRemove_Click);
//
// btnExplorerIntegrate
//
this.btnExplorerIntegrate.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right)));
this.btnExplorerIntegrate.Location = new System.Drawing.Point(407, 24);
this.btnExplorerIntegrate.Name = "btnExplorerIntegrate";
this.btnExplorerIntegrate.Size = new System.Drawing.Size(119, 34);
this.btnExplorerIntegrate.TabIndex = 24;
this.btnExplorerIntegrate.Text = "Install";
this.btnExplorerIntegrate.UseVisualStyleBackColor = true;
this.btnExplorerIntegrate.Click += new System.EventHandler(this.btnExplorerIntegrate_Click);
//
// label16
//
this.label16.AutoSize = true;
this.label16.Location = new System.Drawing.Point(16, 24);
this.label16.Name = "label16";
this.label16.Size = new System.Drawing.Size(268, 13);
this.label16.TabIndex = 14;
this.label16.Text = "Integrate RED into the Windows Explorer context menu";
//
// gbOptions
//
this.gbOptions.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom)
| System.Windows.Forms.AnchorStyles.Left)
| System.Windows.Forms.AnchorStyles.Right)));
this.gbOptions.Controls.Add(this.label25);
this.gbOptions.Controls.Add(this.label11);
this.gbOptions.Controls.Add(this.label21);
this.gbOptions.Controls.Add(this.cbFastSearchMode);
this.gbOptions.Controls.Add(this.cbHideScanErrors);
this.gbOptions.Controls.Add(this.cbIgnoreErrors);
this.gbOptions.Controls.Add(this.cbClipboardDetection);
this.gbOptions.Controls.Add(this.cbIgnoreHiddenFolders);
this.gbOptions.Controls.Add(this.cbIgnore0kbFiles);
this.gbOptions.Location = new System.Drawing.Point(14, 12);
this.gbOptions.Name = "gbOptions";
this.gbOptions.Size = new System.Drawing.Size(669, 330);
this.gbOptions.TabIndex = 19;
this.gbOptions.TabStop = false;
this.gbOptions.Text = "General options";
//
// label25
//
this.label25.AutoSize = true;
this.label25.ForeColor = System.Drawing.SystemColors.GrayText;
this.label25.Location = new System.Drawing.Point(36, 170);
this.label25.Name = "label25";
this.label25.Size = new System.Drawing.Size(439, 26);
this.label25.TabIndex = 22;
this.label25.Text = "Whenever you start or switch into the application it will check if your clipboard" +
" contains\r\na path to a directory (e.g. C:/test) and if it detects a directory it" +
" will use it as the root directory";
//
// label11
//
this.label11.AutoSize = true;
this.label11.ForeColor = System.Drawing.SystemColors.GrayText;
this.label11.Location = new System.Drawing.Point(36, 53);
this.label11.Name = "label11";
this.label11.Size = new System.Drawing.Size(409, 13);
this.label11.TabIndex = 20;
this.label11.Text = "An empty file means files with zero bytes this option also applies to multiple em" +
"pty files.";
//
// label21
//
this.label21.AutoSize = true;
this.label21.ForeColor = System.Drawing.SystemColors.GrayText;
this.label21.Location = new System.Drawing.Point(36, 105);
this.label21.Name = "label21";
this.label21.Size = new System.Drawing.Size(586, 26);
this.label21.TabIndex = 19;
this.label21.Text = resources.GetString("label21.Text");
//
// cbFastSearchMode
//
this.cbFastSearchMode.AutoSize = true;
this.cbFastSearchMode.Location = new System.Drawing.Point(19, 86);
this.cbFastSearchMode.Name = "cbFastSearchMode";
this.cbFastSearchMode.Size = new System.Drawing.Size(75, 17);
this.cbFastSearchMode.TabIndex = 18;
this.cbFastSearchMode.Text = "Fast mode";
this.cbFastSearchMode.UseVisualStyleBackColor = true;
//
// cbHideScanErrors
//
this.cbHideScanErrors.AutoSize = true;
this.cbHideScanErrors.Location = new System.Drawing.Point(19, 288);
this.cbHideScanErrors.Name = "cbHideScanErrors";
this.cbHideScanErrors.Size = new System.Drawing.Size(238, 17);
this.cbHideScanErrors.TabIndex = 16;
this.cbHideScanErrors.Tag = "hide_scan_errors";
this.cbHideScanErrors.Text = "Hide search errors (like access denied errors)";
this.cbHideScanErrors.UseVisualStyleBackColor = true;
//
// cbIgnoreErrors
//
this.cbIgnoreErrors.AutoSize = true;
this.cbIgnoreErrors.Location = new System.Drawing.Point(19, 252);
this.cbIgnoreErrors.Name = "cbIgnoreErrors";
this.cbIgnoreErrors.Size = new System.Drawing.Size(157, 17);
this.cbIgnoreErrors.TabIndex = 15;
this.cbIgnoreErrors.Tag = "ignore_deletion_errors";
this.cbIgnoreErrors.Text = "Ignore errors during deletion\r\n";
this.cbIgnoreErrors.UseVisualStyleBackColor = true;
//
// cbClipboardDetection
//
this.cbClipboardDetection.AutoSize = true;
this.cbClipboardDetection.Location = new System.Drawing.Point(19, 151);
this.cbClipboardDetection.Name = "cbClipboardDetection";
this.cbClipboardDetection.Size = new System.Drawing.Size(162, 17);
this.cbClipboardDetection.TabIndex = 5;
this.cbClipboardDetection.Tag = "clipboard_detection";
this.cbClipboardDetection.Text = "Detect paths in the clipboard";
this.cbClipboardDetection.UseVisualStyleBackColor = true;
//
// cbIgnoreHiddenFolders
//
this.cbIgnoreHiddenFolders.AutoSize = true;
this.cbIgnoreHiddenFolders.Location = new System.Drawing.Point(19, 216);
this.cbIgnoreHiddenFolders.Name = "cbIgnoreHiddenFolders";
this.cbIgnoreHiddenFolders.Size = new System.Drawing.Size(142, 17);
this.cbIgnoreHiddenFolders.TabIndex = 4;
this.cbIgnoreHiddenFolders.Tag = "ignore_hidden";
this.cbIgnoreHiddenFolders.Text = "Ignore hidden directories";
this.cbIgnoreHiddenFolders.UseVisualStyleBackColor = true;
//
// cbIgnore0kbFiles
//
this.cbIgnore0kbFiles.AutoSize = true;
this.cbIgnore0kbFiles.Checked = true;
this.cbIgnore0kbFiles.CheckState = System.Windows.Forms.CheckState.Checked;
this.cbIgnore0kbFiles.Location = new System.Drawing.Point(19, 34);
this.cbIgnore0kbFiles.Name = "cbIgnore0kbFiles";
this.cbIgnore0kbFiles.Size = new System.Drawing.Size(268, 17);
this.cbIgnore0kbFiles.TabIndex = 3;
this.cbIgnore0kbFiles.Tag = "ignore_0kb_files";
this.cbIgnore0kbFiles.Text = "Directories with empty files will be considered empty";
this.cbIgnore0kbFiles.UseVisualStyleBackColor = true;
//
// tabIgnoreList
//
this.tabIgnoreList.Controls.Add(this.label22);
this.tabIgnoreList.Controls.Add(this.tbIgnoreFolders);
this.tabIgnoreList.Controls.Add(this.label10);
this.tabIgnoreList.ImageKey = "filter";
this.tabIgnoreList.Location = new System.Drawing.Point(4, 27);
this.tabIgnoreList.Name = "tabIgnoreList";
this.tabIgnoreList.Padding = new System.Windows.Forms.Padding(3);
this.tabIgnoreList.Size = new System.Drawing.Size(698, 544);
this.tabIgnoreList.TabIndex = 4;
this.tabIgnoreList.Text = "Ignore list";
this.tabIgnoreList.UseVisualStyleBackColor = true;
//
// label22
//
this.label22.AutoSize = true;
this.label22.ForeColor = System.Drawing.SystemColors.GrayText;
this.label22.Location = new System.Drawing.Point(14, 38);
this.label22.Name = "label22";
this.label22.Size = new System.Drawing.Size(435, 13);
this.label22.TabIndex = 14;
this.label22.Text = "Use one item per line and you can specify a directory name or a full path like \"C" +
":/example\".";
//
// tbIgnoreFolders
//
this.tbIgnoreFolders.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom)
| System.Windows.Forms.AnchorStyles.Left)
| System.Windows.Forms.AnchorStyles.Right)));
this.tbIgnoreFolders.Font = new System.Drawing.Font("Lucida Console", 9F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
this.tbIgnoreFolders.Location = new System.Drawing.Point(14, 64);
this.tbIgnoreFolders.Multiline = true;
this.tbIgnoreFolders.Name = "tbIgnoreFolders";
this.tbIgnoreFolders.ScrollBars = System.Windows.Forms.ScrollBars.Both;
this.tbIgnoreFolders.Size = new System.Drawing.Size(668, 467);
this.tbIgnoreFolders.TabIndex = 6;
this.tbIgnoreFolders.WordWrap = false;
//
// label10
//
this.label10.AutoSize = true;
this.label10.Location = new System.Drawing.Point(14, 16);
this.label10.Name = "label10";
this.label10.Size = new System.Drawing.Size(458, 13);
this.label10.TabIndex = 13;
this.label10.Text = "When a directory name matches an item of this list it will be skipped (including " +
"all subdirectories).";
//
// tabAdvanced
//
this.tabAdvanced.Controls.Add(this.gbAdvancedSettings);
this.tabAdvanced.Controls.Add(this.btnResetConfig);
this.tabAdvanced.Controls.Add(this.btnCopyDebugInfo);
this.tabAdvanced.Controls.Add(this.gbIgnoreFilenames);
this.tabAdvanced.Controls.Add(this.label8);
this.tabAdvanced.ImageKey = "(none)";
this.tabAdvanced.Location = new System.Drawing.Point(4, 27);
this.tabAdvanced.Name = "tabAdvanced";
this.tabAdvanced.Padding = new System.Windows.Forms.Padding(3);
this.tabAdvanced.Size = new System.Drawing.Size(698, 544);
this.tabAdvanced.TabIndex = 3;
this.tabAdvanced.Text = "Advanced settings";
this.tabAdvanced.UseVisualStyleBackColor = true;
//
// gbAdvancedSettings
//
this.gbAdvancedSettings.Controls.Add(this.label20);
this.gbAdvancedSettings.Controls.Add(this.label26);
this.gbAdvancedSettings.Controls.Add(this.label27);
this.gbAdvancedSettings.Controls.Add(this.label19);
this.gbAdvancedSettings.Controls.Add(this.cbKeepSystemFolders);
this.gbAdvancedSettings.Controls.Add(this.nuFolderAge);
this.gbAdvancedSettings.Controls.Add(this.label7);
this.gbAdvancedSettings.Controls.Add(this.label24);
this.gbAdvancedSettings.Controls.Add(this.nuPause);
this.gbAdvancedSettings.Controls.Add(this.nuMaxDepth);
this.gbAdvancedSettings.Controls.Add(this.label4);
this.gbAdvancedSettings.Controls.Add(this.label3);
this.gbAdvancedSettings.Controls.Add(this.nuInfiniteLoopDetectionCount);
this.gbAdvancedSettings.Location = new System.Drawing.Point(15, 17);
this.gbAdvancedSettings.Name = "gbAdvancedSettings";
this.gbAdvancedSettings.Size = new System.Drawing.Size(668, 160);
this.gbAdvancedSettings.TabIndex = 30;
this.gbAdvancedSettings.TabStop = false;
this.gbAdvancedSettings.Text = "Advanced settings";
//
// label20
//
this.label20.AutoSize = true;
this.label20.ForeColor = System.Drawing.SystemColors.GrayText;
this.label20.Location = new System.Drawing.Point(16, 134);
this.label20.Name = "label20";
this.label20.Size = new System.Drawing.Size(314, 13);
this.label20.TabIndex = 19;
this.label20.Text = "This gives you time to stop the process but is not really necessary";
//
// label26
//
this.label26.AutoSize = true;
this.label26.ForeColor = System.Drawing.SystemColors.GrayText;
this.label26.Location = new System.Drawing.Point(357, 79);
this.label26.Name = "label26";
this.label26.Size = new System.Drawing.Size(246, 13);
this.label26.TabIndex = 28;
this.label26.Text = "This allows you to ignore freshly created directories";
//
// label27
//
this.label27.AutoSize = true;
this.label27.ForeColor = System.Drawing.SystemColors.GrayText;
this.label27.Location = new System.Drawing.Point(16, 78);
this.label27.Name = "label27";
this.label27.Size = new System.Drawing.Size(259, 13);
this.label27.TabIndex = 29;
this.label27.Text = "RED will only able to find empty directories that are N ";
//
// label19
//
this.label19.AutoSize = true;
this.label19.Location = new System.Drawing.Point(357, 56);
this.label19.Name = "label19";
this.label19.Size = new System.Drawing.Size(167, 13);
this.label19.TabIndex = 26;
this.label19.Text = "Skip folders less than N hours old:";
//
// cbKeepSystemFolders
//
this.cbKeepSystemFolders.AutoSize = true;
this.cbKeepSystemFolders.Checked = true;
this.cbKeepSystemFolders.CheckState = System.Windows.Forms.CheckState.Checked;
this.cbKeepSystemFolders.Location = new System.Drawing.Point(248, 26);
this.cbKeepSystemFolders.Name = "cbKeepSystemFolders";
this.cbKeepSystemFolders.Size = new System.Drawing.Size(15, 14);
this.cbKeepSystemFolders.TabIndex = 2;
this.cbKeepSystemFolders.Tag = "keep_system_dirs";
this.cbKeepSystemFolders.UseVisualStyleBackColor = true;
//
// nuFolderAge
//
this.nuFolderAge.Location = new System.Drawing.Point(588, 52);
this.nuFolderAge.Margin = new System.Windows.Forms.Padding(2);
this.nuFolderAge.Maximum = new decimal(new int[] {
96,
0,
0,
0});
this.nuFolderAge.Name = "nuFolderAge";
this.nuFolderAge.Size = new System.Drawing.Size(53, 20);
this.nuFolderAge.TabIndex = 25;
//
// label7
//
this.label7.AutoSize = true;
this.label7.Location = new System.Drawing.Point(16, 113);
this.label7.Name = "label7";
this.label7.Size = new System.Drawing.Size(218, 13);
this.label7.TabIndex = 17;
this.label7.Text = "Pause between each deletion in milliseconds";
//
// label24
//
this.label24.AutoSize = true;
this.label24.Location = new System.Drawing.Point(16, 26);
this.label24.Name = "label24";
this.label24.Size = new System.Drawing.Size(190, 13);
this.label24.TabIndex = 27;
this.label24.Text = "Skip system directories (recommended)";
//
// nuPause
//
this.nuPause.Location = new System.Drawing.Point(249, 109);
this.nuPause.Maximum = new decimal(new int[] {
999999,
0,
0,
0});
this.nuPause.Name = "nuPause";
this.nuPause.Size = new System.Drawing.Size(53, 20);
this.nuPause.TabIndex = 8;
//
// nuMaxDepth
//
this.nuMaxDepth.Location = new System.Drawing.Point(249, 52);
this.nuMaxDepth.Maximum = new decimal(new int[] {
10000000,
0,
0,
0});
this.nuMaxDepth.Minimum = new decimal(new int[] {
1,
0,
0,
-2147483648});
this.nuMaxDepth.Name = "nuMaxDepth";
this.nuMaxDepth.Size = new System.Drawing.Size(53, 20);
this.nuMaxDepth.TabIndex = 7;
this.nuMaxDepth.Value = new decimal(new int[] {
1,
0,
0,
-2147483648});
//
// label4
//
this.label4.AutoSize = true;
this.label4.Location = new System.Drawing.Point(357, 119);
this.label4.Name = "label4";
this.label4.Size = new System.Drawing.Size(200, 13);
this.label4.TabIndex = 20;
this.label4.Text = "Infinite-loop detection: Stop after N errors";
//
// label3
//
this.label3.AutoSize = true;
this.label3.Location = new System.Drawing.Point(16, 56);
this.label3.Name = "label3";
this.label3.Size = new System.Drawing.Size(200, 13);
this.label3.TabIndex = 13;
this.label3.Text = "Max directory nesting depth (-1 = infinite):";
//
// nuInfiniteLoopDetectionCount
//
this.nuInfiniteLoopDetectionCount.Location = new System.Drawing.Point(588, 115);
this.nuInfiniteLoopDetectionCount.Maximum = new decimal(new int[] {
999999,
0,
0,
0});
this.nuInfiniteLoopDetectionCount.Name = "nuInfiniteLoopDetectionCount";
this.nuInfiniteLoopDetectionCount.Size = new System.Drawing.Size(53, 20);
this.nuInfiniteLoopDetectionCount.TabIndex = 21;
this.nuInfiniteLoopDetectionCount.Value = new decimal(new int[] {
10,
0,
0,
0});
//
// btnResetConfig
//
this.btnResetConfig.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left)));
this.btnResetConfig.Location = new System.Drawing.Point(318, 505);
this.btnResetConfig.Name = "btnResetConfig";
this.btnResetConfig.Size = new System.Drawing.Size(183, 27);
this.btnResetConfig.TabIndex = 23;
this.btnResetConfig.Text = "Reset settings to default values";
this.btnResetConfig.UseVisualStyleBackColor = true;
this.btnResetConfig.Click += new System.EventHandler(this.btnResetConfig_Click);
//
// btnCopyDebugInfo
//
this.btnCopyDebugInfo.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left)));
this.btnCopyDebugInfo.Location = new System.Drawing.Point(15, 505);
this.btnCopyDebugInfo.Name = "btnCopyDebugInfo";
this.btnCopyDebugInfo.Size = new System.Drawing.Size(297, 27);
this.btnCopyDebugInfo.TabIndex = 24;
this.btnCopyDebugInfo.Text = "Copy debugging information to clipboard (for error reports)";
this.btnCopyDebugInfo.UseVisualStyleBackColor = true;
this.btnCopyDebugInfo.Click += new System.EventHandler(this.btnCopyDebugInfo_Click);
//
// gbIgnoreFilenames
//
this.gbIgnoreFilenames.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom)
| System.Windows.Forms.AnchorStyles.Left)
| System.Windows.Forms.AnchorStyles.Right)));
this.gbIgnoreFilenames.Controls.Add(this.label23);
this.gbIgnoreFilenames.Controls.Add(this.label14);
this.gbIgnoreFilenames.Controls.Add(this.tbIgnoreFiles);
this.gbIgnoreFilenames.Controls.Add(this.label2);
this.gbIgnoreFilenames.Location = new System.Drawing.Point(15, 194);
this.gbIgnoreFilenames.Name = "gbIgnoreFilenames";
this.gbIgnoreFilenames.Size = new System.Drawing.Size(668, 303);
this.gbIgnoreFilenames.TabIndex = 20;
this.gbIgnoreFilenames.TabStop = false;
this.gbIgnoreFilenames.Text = "Filenames to ignore";
//
// label23
//
this.label23.AutoSize = true;
this.label23.Location = new System.Drawing.Point(15, 60);
this.label23.Name = "label23";
this.label23.Size = new System.Drawing.Size(357, 78);
this.label23.TabIndex = 13;
this.label23.Text = resources.GetString("label23.Text");
//
// label14
//
this.label14.AutoSize = true;
this.label14.BackColor = System.Drawing.SystemColors.Info;
this.label14.ForeColor = System.Drawing.Color.DarkRed;
this.label14.Location = new System.Drawing.Point(484, 64);
this.label14.Name = "label14";
this.label14.Padding = new System.Windows.Forms.Padding(5);
this.label14.Size = new System.Drawing.Size(165, 62);
this.label14.TabIndex = 12;
this.label14.Text = "Warning: Use this feature with \r\ncare, a bad pattern could \r\npotentially cause a" +
"ccidental \r\ndeletion of important files.";
this.label14.TextAlign = System.Drawing.ContentAlignment.MiddleLeft;
//
// tbIgnoreFiles
//
this.tbIgnoreFiles.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom)
| System.Windows.Forms.AnchorStyles.Left)
| System.Windows.Forms.AnchorStyles.Right)));
this.tbIgnoreFiles.Font = new System.Drawing.Font("Lucida Console", 9F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
this.tbIgnoreFiles.Location = new System.Drawing.Point(18, 150);
this.tbIgnoreFiles.Multiline = true;
this.tbIgnoreFiles.Name = "tbIgnoreFiles";
this.tbIgnoreFiles.ScrollBars = System.Windows.Forms.ScrollBars.Both;
this.tbIgnoreFiles.Size = new System.Drawing.Size(631, 139);
this.tbIgnoreFiles.TabIndex = 5;
this.tbIgnoreFiles.Wor
gitextract_p_szlfn3/ ├── .gitignore ├── Installer/ │ ├── README.md │ ├── legacy-files/ │ │ ├── legacy-disclaimer.txt │ │ ├── manifest-info.txt │ │ ├── red_installer-v1.iss │ │ ├── require_administrator.manifest │ │ └── set_require_administrator.bat │ ├── license.txt │ └── red_installer.iss ├── LICENSE ├── README.md ├── RED2/ │ ├── DeletionError.Designer.cs │ ├── DeletionError.cs │ ├── DeletionError.resx │ ├── Lib/ │ │ ├── Core.cs │ │ ├── DeletionWorker.cs │ │ ├── Enums.cs │ │ ├── Events.cs │ │ ├── FindEmptyDirectoryWorker.cs │ │ ├── RuntimeData.cs │ │ ├── SystemFunctions.cs │ │ ├── TreeManager.cs │ │ └── UIHelpers.cs │ ├── LogWindow.Designer.cs │ ├── LogWindow.cs │ ├── LogWindow.resx │ ├── MainWindow.Designer.cs │ ├── MainWindow.cs │ ├── MainWindow.resx │ ├── Program.cs │ ├── Properties/ │ │ ├── AssemblyInfo.cs │ │ ├── Resources.Designer.cs │ │ ├── Resources.resx │ │ ├── Resources_de.resx │ │ ├── Settings.Designer.cs │ │ └── Settings.settings │ ├── RED2.csproj │ ├── RED2.csproj.user │ ├── app.config │ ├── app.manifest │ └── packages.config ├── Scripts/ │ ├── create-1000-empty-directories.bat │ └── create-test-directories.bat └── red2_project.sln
SYMBOL INDEX (179 symbols across 18 files)
FILE: RED2/DeletionError.Designer.cs
class DeletionError (line 3) | partial class DeletionError
method Dispose (line 14) | protected override void Dispose(bool disposing)
method InitializeComponent (line 29) | private void InitializeComponent()
FILE: RED2/DeletionError.cs
class DeletionError (line 6) | public partial class DeletionError : Form
method DeletionError (line 8) | public DeletionError()
method DeletionError_Load (line 13) | private void DeletionError_Load(object sender, EventArgs e)
method SetPath (line 18) | internal void SetPath(string path)
method SetErrorMessage (line 23) | internal void SetErrorMessage(string msg)
FILE: RED2/Lib/Core.cs
class REDCore (line 10) | public class REDCore
method REDCore (line 31) | public REDCore(MainWindow mainWindow, RuntimeData data)
method SearchingForEmptyDirectories (line 40) | public void SearchingForEmptyDirectories()
method searchEmptyFoldersWorker_ProgressChanged (line 60) | void searchEmptyFoldersWorker_ProgressChanged(object sender, ProgressC...
method searchEmptyFoldersWorker_RunWorkerCompleted (line 90) | void searchEmptyFoldersWorker_RunWorkerCompleted(object sender, RunWor...
method CancelCurrentProcess (line 131) | internal void CancelCurrentProcess()
method StartDeleteProcess (line 149) | public void StartDeleteProcess()
method deletionWorker_ProgressChanged (line 163) | void deletionWorker_ProgressChanged(object sender, ProgressChangedEven...
method deletionWorker_RunWorkerCompleted (line 171) | void deletionWorker_RunWorkerCompleted(object sender, RunWorkerComplet...
method AddProtectedFolder (line 216) | internal void AddProtectedFolder(string path)
method RemoveProtected (line 222) | internal void RemoveProtected(string FolderFullName)
method GetLogMessages (line 228) | public string GetLogMessages()
method showErrorMsg (line 233) | private void showErrorMsg(string errorMessage)
method AbortDeletion (line 239) | internal void AbortDeletion()
method ContinueDeleteProcess (line 249) | internal void ContinueDeleteProcess()
FILE: RED2/Lib/DeletionWorker.cs
class DeletionWorker (line 11) | public class DeletionWorker : BackgroundWorker
method DeletionWorker (line 23) | public DeletionWorker()
method OnDoWork (line 31) | protected override void OnDoWork(DoWorkEventArgs e)
method secureDelete (line 117) | private void secureDelete(string path)
FILE: RED2/Lib/Enums.cs
type WorkflowSteps (line 6) | public enum WorkflowSteps
type DirectorySearchStatusTypes (line 16) | public enum DirectorySearchStatusTypes
type DirectoryDeletionStatusTypes (line 27) | public enum DirectoryDeletionStatusTypes
FILE: RED2/Lib/Events.cs
class WorkflowStepChangedEventArgs (line 6) | public class WorkflowStepChangedEventArgs : EventArgs
method WorkflowStepChangedEventArgs (line 10) | public WorkflowStepChangedEventArgs(WorkflowSteps NewStep)
class ErrorEventArgs (line 16) | public class ErrorEventArgs : EventArgs
method ErrorEventArgs (line 20) | public ErrorEventArgs(string msg)
class FinishedScanForEmptyDirsEventArgs (line 26) | public class FinishedScanForEmptyDirsEventArgs : EventArgs
method FinishedScanForEmptyDirsEventArgs (line 31) | public FinishedScanForEmptyDirsEventArgs(int EmptyFolderCount, int Fol...
class DeleteProcessUpdateEventArgs (line 38) | public class DeleteProcessUpdateEventArgs : EventArgs
method DeleteProcessUpdateEventArgs (line 45) | public DeleteProcessUpdateEventArgs(int progressStatus, string path, D...
class DeleteProcessFinishedEventArgs (line 54) | public class DeleteProcessFinishedEventArgs : EventArgs
method DeleteProcessFinishedEventArgs (line 60) | public DeleteProcessFinishedEventArgs(int deletedFolderCount, int fail...
class ProtectionStatusChangedEventArgs (line 68) | public class ProtectionStatusChangedEventArgs : EventArgs
method ProtectionStatusChangedEventArgs (line 73) | public ProtectionStatusChangedEventArgs(string Path, bool Protected)
class DeleteRequestFromTreeEventArgs (line 80) | public class DeleteRequestFromTreeEventArgs : EventArgs
method DeleteRequestFromTreeEventArgs (line 84) | public DeleteRequestFromTreeEventArgs(string Directory)
class DeletionErrorEventArgs (line 90) | public class DeletionErrorEventArgs : EventArgs
method DeletionErrorEventArgs (line 95) | public DeletionErrorEventArgs(string Path, string ErrorMessage)
class FoundEmptyDirInfoEventArgs (line 102) | public class FoundEmptyDirInfoEventArgs : EventArgs
method FoundEmptyDirInfoEventArgs (line 108) | public FoundEmptyDirInfoEventArgs(string Directory, DirectorySearchSta...
method FoundEmptyDirInfoEventArgs (line 115) | public FoundEmptyDirInfoEventArgs(string Directory, DirectorySearchSta...
FILE: RED2/Lib/FindEmptyDirectoryWorker.cs
class FindEmptyDirectoryWorker (line 12) | public class FindEmptyDirectoryWorker : BackgroundWorker
method FindEmptyDirectoryWorker (line 29) | public FindEmptyDirectoryWorker()
method OnDoWork (line 35) | protected override void OnDoWork(DoWorkEventArgs e)
method checkIfDirectoryEmpty (line 78) | private DirectorySearchStatusTypes checkIfDirectoryEmpty(DirectoryInfo...
method checkIfDirectoryIsOnIgnoreList (line 256) | private bool checkIfDirectoryIsOnIgnoreList(DirectoryInfo Folder)
FILE: RED2/Lib/RuntimeData.cs
class RuntimeData (line 11) | public class RuntimeData
method RuntimeData (line 43) | public RuntimeData()
method fixNewLines (line 50) | private string[] fixNewLines(string input)
method GetIgnoreFileList (line 55) | public string[] GetIgnoreFileList()
method GetIgnoreDirectories (line 60) | public string[] GetIgnoreDirectories()
method AddLogMessage (line 65) | public void AddLogMessage(string msg)
method AddLogSpacer (line 70) | internal void AddLogSpacer()
FILE: RED2/Lib/SystemFunctions.cs
type DeleteModes (line 15) | public enum DeleteModes
class REDPermissionDeniedException (line 24) | [Serializable]
method REDPermissionDeniedException (line 27) | public REDPermissionDeniedException() { }
method REDPermissionDeniedException (line 28) | public REDPermissionDeniedException(string message) : base(message) { }
method REDPermissionDeniedException (line 29) | public REDPermissionDeniedException(string message, Exception inner) :...
class SystemFunctions (line 37) | public class SystemFunctions
method ConvertLineBreaks (line 43) | public static string ConvertLineBreaks(string str)
method MatchesIgnorePattern (line 48) | public static bool MatchesIgnorePattern(FileInfo file, int filesize, b...
method ManuallyDeleteDirectory (line 98) | public static void ManuallyDeleteDirectory(string path, DeleteModes de...
method IsDirLocked (line 109) | public static bool IsDirLocked(string path)
method IsFileLocked (line 141) | public static bool IsFileLocked(FileInfo file)
method SecureDeleteDirectory (line 158) | public static void SecureDeleteDirectory(string path, DeleteModes dele...
method SecureDeleteFile (line 192) | public static void SecureDeleteFile(FileInfo file, DeleteModes deleteM...
method ChooseDirectoryDialog (line 220) | public static string ChooseDirectoryDialog(string path)
method OpenDirectoryWithExplorer (line 247) | public static void OpenDirectoryWithExplorer(string path)
method IsRegKeyIntegratedIntoWindowsExplorer (line 261) | public static bool IsRegKeyIntegratedIntoWindowsExplorer()
method AddOrRemoveRegKey (line 266) | internal static void AddOrRemoveRegKey(bool add)
FILE: RED2/Lib/TreeManager.cs
class TreeManager (line 15) | public class TreeManager
method TreeManager (line 36) | public TreeManager(TreeView dirTree, Label fastModeInfoLabel)
method SetFastMode (line 49) | public void SetFastMode(bool fastModeActive)
method OnSearchStart (line 64) | public void OnSearchStart(DirectoryInfo directory)
method OnSearchFinished (line 77) | public void OnSearchFinished()
method OnDeletionProcessStart (line 82) | public void OnDeletionProcessStart()
method OnDeletionProcessFinished (line 90) | public void OnDeletionProcessFinished()
method OnProcessCancelled (line 95) | public void OnProcessCancelled()
method suspendTreeViewForFastMode (line 101) | private void suspendTreeViewForFastMode()
method clearFastMode (line 109) | private void clearFastMode()
method showFastModeResults (line 115) | private void showFastModeResults()
method tvFolders_MouseClick (line 132) | private void tvFolders_MouseClick(object sender, MouseEventArgs e)
method resetTree (line 137) | private void resetTree()
method createRootNode (line 146) | private void createRootNode(DirectoryInfo directory, DirectoryIcons im...
method addRootNode (line 165) | private void addRootNode()
method scrollToNode (line 174) | private void scrollToNode(TreeNode node)
method UpdateItemIcon (line 188) | internal void UpdateItemIcon(string path, DirectoryIcons iconKey)
method findOrCreateDirectoryNodeByPath (line 199) | private TreeNode findOrCreateDirectoryNodeByPath(string path)
method AddOrUpdateDirectoryNode (line 216) | public TreeNode AddOrUpdateDirectoryNode(string path, DirectorySearchS...
method applyNodeStyle (line 252) | private void applyNodeStyle(TreeNode treeNode, string path, DirectoryS...
method GetSelectedFolderPath (line 311) | public string GetSelectedFolderPath()
method DeleteSelectedDirectory (line 319) | internal void DeleteSelectedDirectory()
method RemoveNode (line 330) | internal void RemoveNode(string path)
method ProtectSelected (line 344) | internal void ProtectSelected()
method UnprotectSelected (line 350) | internal void UnprotectSelected()
method unprotectNode (line 355) | private void unprotectNode(TreeNode node)
method ProtectNode (line 385) | private void ProtectNode(TreeNode node)
FILE: RED2/Lib/UIHelpers.cs
type DirectoryIcons (line 8) | public enum DirectoryIcons
class DeleteModeItem (line 19) | public class DeleteModeItem
method DeleteModeItem (line 23) | public DeleteModeItem(DeleteModes Mode)
method GetList (line 28) | public static DeleteModes[] GetList()
method ToString (line 39) | public override string ToString()
FILE: RED2/LogWindow.Designer.cs
class LogWindow (line 3) | partial class LogWindow
method Dispose (line 14) | protected override void Dispose(bool disposing)
method InitializeComponent (line 29) | private void InitializeComponent()
FILE: RED2/LogWindow.cs
class LogWindow (line 6) | public partial class LogWindow : Form
method LogWindow (line 8) | public LogWindow()
method LogWindow_Load (line 13) | private void LogWindow_Load(object sender, EventArgs e)
method SetLog (line 18) | public void SetLog(string log) {
method tbLog_DoubleClick (line 22) | private void tbLog_DoubleClick(object sender, EventArgs e)
FILE: RED2/MainWindow.Designer.cs
class MainWindow (line 3) | partial class MainWindow
method Dispose (line 14) | protected override void Dispose(bool disposing)
method InitializeComponent (line 29) | private void InitializeComponent()
FILE: RED2/MainWindow.cs
class MainWindow (line 13) | public partial class MainWindow : Form
method MainWindow (line 26) | public MainWindow()
method fMain_Load (line 34) | private void fMain_Load(object sender, EventArgs e)
method bindConfigToControls (line 87) | private void bindConfigToControls()
method adminCheck (line 117) | private void adminCheck()
method processCommandLineArgs (line 149) | private void processCommandLineArgs()
method Default_SettingChanging (line 165) | void Default_SettingChanging(object sender, System.Configuration.Setti...
method Default_PropertyChanged (line 178) | void Default_PropertyChanged(object sender, PropertyChangedEventArgs e)
method drawDirectoryIcons (line 184) | private void drawDirectoryIcons()
method btnScan_Click (line 233) | private void btnScan_Click(object sender, EventArgs e)
method core_OnProgressChanged (line 273) | void core_OnProgressChanged(object sender, ProgressChangedEventArgs e)
method core_OnFoundEmptyDir (line 278) | void core_OnFoundEmptyDir(object sender, FoundEmptyDirInfoEventArgs e)
method core_OnFoundFinishedScanForEmptyDirs (line 283) | void core_OnFoundFinishedScanForEmptyDirs(object sender, FinishedScanF...
method btnDelete_Click (line 319) | private void btnDelete_Click(object sender, EventArgs e)
method updateRuntimeDataObject (line 340) | private void updateRuntimeDataObject()
method core_OnDeleteProcessChanged (line 356) | private void core_OnDeleteProcessChanged(object sender, DeleteProcessU...
method core_OnDeleteError (line 377) | private void core_OnDeleteError(object sender, DeletionErrorEventArgs e)
method core_OnDeleteProcessFinished (line 402) | private void core_OnDeleteProcessFinished(object sender, DeleteProcess...
method core_OnCancelled (line 431) | private void core_OnCancelled(object sender, EventArgs e)
method core_OnAborted (line 447) | private void core_OnAborted(object sender, EventArgs e)
method core_OnError (line 463) | private void core_OnError(object sender, ErrorEventArgs e)
method tvFolders_DoubleClick (line 477) | private void tvFolders_DoubleClick(object sender, EventArgs e)
method openFolderToolStripMenuItem_Click (line 482) | private void openFolderToolStripMenuItem_Click(object sender, EventArg...
method scanOnlyThisDirectoryToolStripMenuItem_Click (line 487) | private void scanOnlyThisDirectoryToolStripMenuItem_Click(object sende...
method protectFolderFromBeingDeletedToolStripMenuItem_Click (line 493) | private void protectFolderFromBeingDeletedToolStripMenuItem_Click(obje...
method unprotectFolderToolStripMenuItem_Click (line 498) | private void unprotectFolderToolStripMenuItem_Click(object sender, Eve...
method tree_OnProtectionStatusChanged (line 503) | private void tree_OnProtectionStatusChanged(object sender, ProtectionS...
method proToolStripMenuItem_Click (line 511) | private void proToolStripMenuItem_Click(object sender, EventArgs e)
method deleteToolStripMenuItem_Click (line 525) | private void deleteToolStripMenuItem_Click(object sender, EventArgs e)
method tree_OnDeleteRequest (line 530) | private void tree_OnDeleteRequest(object sender, DeleteRequestFromTree...
method toolStripExpandAll_Click (line 561) | private void toolStripExpandAll_Click(object sender, EventArgs e)
method toolStripCollapseAll_Click (line 566) | private void toolStripCollapseAll_Click(object sender, EventArgs e)
method setProcessActiveLock (line 579) | private void setProcessActiveLock(bool isActive)
method btnCancel_Click (line 594) | private void btnCancel_Click(object sender, EventArgs e)
method setStatusAndLogMessage (line 599) | private void setStatusAndLogMessage(string msg)
method fMain_DragDrop (line 609) | private void fMain_DragDrop(object sender, DragEventArgs e)
method fMain_DragEnter (line 623) | private void fMain_DragEnter(object sender, DragEventArgs e)
method fMain_Activated (line 631) | private void fMain_Activated(object sender, EventArgs e)
method tbFolder_MouseDoubleClick (line 649) | private void tbFolder_MouseDoubleClick(object sender, MouseEventArgs e)
method btnExit_Click (line 654) | private void btnExit_Click(object sender, EventArgs e)
method btnChooseFolder_Click (line 662) | private void btnChooseFolder_Click(object sender, EventArgs e)
method btnShowConfig_Click (line 667) | private void btnShowConfig_Click(object sender, EventArgs e)
method btnShowLog_Click (line 672) | private void btnShowLog_Click(object sender, EventArgs e)
method btnResetConfig_Click (line 684) | private void btnResetConfig_Click(object sender, EventArgs e)
method btnExplorerIntegrate_Click (line 694) | private void btnExplorerIntegrate_Click(object sender, EventArgs e)
method btnExplorerRemove_Click (line 701) | private void btnExplorerRemove_Click(object sender, EventArgs e)
method llWebsite_LinkClicked (line 708) | private void llWebsite_LinkClicked(object sender, LinkLabelLinkClicked...
method llGithub_LinkClicked (line 713) | private void llGithub_LinkClicked(object sender, LinkLabelLinkClickedE...
method linkLabel1_LinkClicked (line 718) | private void linkLabel1_LinkClicked(object sender, LinkLabelLinkClicke...
method linkLabel2_LinkClicked_1 (line 723) | private void linkLabel2_LinkClicked_1(object sender, LinkLabelLinkClic...
method btnCopyDebugInfo_Click (line 729) | private void btnCopyDebugInfo_Click(object sender, EventArgs e)
method cmStrip_Opening (line 807) | private void cmStrip_Opening(object sender, CancelEventArgs e)
method UpdateContextMenu (line 817) | private void UpdateContextMenu(ContextMenuStrip contextMenuStrip, bool...
FILE: RED2/Program.cs
class Program (line 7) | static class Program
method Main (line 12) | [STAThread]
FILE: RED2/Properties/Resources.Designer.cs
class Resources (line 22) | [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resource...
method Resources (line 31) | [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Mic...
FILE: RED2/Properties/Settings.Designer.cs
class Settings (line 14) | [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
Condensed preview — 44 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (457K chars).
[
{
"path": ".gitignore",
"chars": 109,
"preview": "*.suo\r\nRED2/bin/\r\nRED2/obj/\r\nRED2/publish/\r\nInstaller/output/\r\nInstaller/bin/\r\n.vs\r\npackages/\nScripts/test-*\n"
},
{
"path": "Installer/README.md",
"chars": 1069,
"preview": "# RED Installer\n\nThis directory contains all resources related to the RED installer.\n\nI wrote this document mostly for m"
},
{
"path": "Installer/legacy-files/legacy-disclaimer.txt",
"chars": 1726,
"preview": "# Archived legacy disclaimer\n\n## Remark from 2021\n\nNo more cases where reported since about ten years, so I removed this"
},
{
"path": "Installer/legacy-files/manifest-info.txt",
"chars": 53,
"preview": "http://msdn.microsoft.com/en-us/library/bb756929.aspx"
},
{
"path": "Installer/legacy-files/red_installer-v1.iss",
"chars": 4604,
"preview": "; Script generated by the Inno Setup Script Wizard.\n; SEE THE DOCUMENTATION FOR DETAILS ON CREATING INNO SETUP SCRIPT FI"
},
{
"path": "Installer/legacy-files/require_administrator.manifest",
"chars": 469,
"preview": "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?>\n<assembly xmlns=\"urn:schemas-microsoft-com:asm.v1\" manifestVersi"
},
{
"path": "Installer/legacy-files/set_require_administrator.bat",
"chars": 137,
"preview": "\"C:\\Program Files\\Microsoft SDKs\\Windows\\v7.0A\\bin\\mt.exe\" -manifest \"require_administrator.manifest\" -outputresource:\"R"
},
{
"path": "Installer/license.txt",
"chars": 7951,
"preview": "DISCLAIMER\n\nRED is a tool that DELETES stuff! So please be careful with it and its settings.\n\n\nLICENSE\n\nThe program is "
},
{
"path": "Installer/red_installer.iss",
"chars": 17158,
"preview": "// contribute: https://github.com/DomGries/InnoDependencyInstaller\n// official article: https://codeproject.com/Articles"
},
{
"path": "LICENSE",
"chars": 7652,
"preview": " GNU LESSER GENERAL PUBLIC LICENSE\n Version 3, 29 June 2007\n\n Copyright (C) 2007"
},
{
"path": "README.md",
"chars": 5995,
"preview": "Remove Empty Directories\n========================\n\nRED finds, displays, and deletes empty directories recursively below "
},
{
"path": "RED2/DeletionError.Designer.cs",
"chars": 7845,
"preview": "namespace RED2\r\n{\r\n partial class DeletionError\r\n {\r\n /// <summary>\r\n /// Erforderliche Designervar"
},
{
"path": "RED2/DeletionError.cs",
"chars": 541,
"preview": "using System;\r\nusing System.Windows.Forms;\r\n\r\nnamespace RED2\r\n{\r\n public partial class DeletionError : Form\r\n {\r\n"
},
{
"path": "RED2/DeletionError.resx",
"chars": 5815,
"preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\r\n<root>\r\n <!-- \r\n Microsoft ResX Schema \r\n \r\n Version 2.0\r\n \r\n T"
},
{
"path": "RED2/Lib/Core.cs",
"chars": 9940,
"preview": "using System;\r\nusing System.Collections.Generic;\r\nusing System.ComponentModel;\r\n\r\nnamespace RED2\r\n{\r\n /// <summary>\r"
},
{
"path": "RED2/Lib/DeletionWorker.cs",
"chars": 6446,
"preview": "using System;\r\nusing System.ComponentModel;\r\nusing System.Threading;\r\nusing Alphaleonis.Win32.Filesystem;\r\n\r\nnamespace "
},
{
"path": "RED2/Lib/Enums.cs",
"chars": 645,
"preview": "namespace RED2\r\n{\r\n /// <summary>\r\n /// RED workflow steps\r\n /// </summary>\r\n public enum WorkflowSteps\r\n "
},
{
"path": "RED2/Lib/Events.cs",
"chars": 3706,
"preview": "using System;\r\nusing Alphaleonis.Win32.Filesystem;\r\n\r\nnamespace RED2\r\n{\r\n public class WorkflowStepChangedEventArgs "
},
{
"path": "RED2/Lib/FindEmptyDirectoryWorker.cs",
"chars": 12031,
"preview": "using System;\r\nusing System.Collections.Generic;\r\nusing System.ComponentModel;\r\nusing Alphaleonis.Win32.Filesystem;\r\nusi"
},
{
"path": "RED2/Lib/RuntimeData.cs",
"chars": 2331,
"preview": "using System;\r\nusing System.Collections.Generic;\r\nusing Alphaleonis.Win32.Filesystem;\r\nusing System.Text;\r\n\r\nnamespace "
},
{
"path": "RED2/Lib/SystemFunctions.cs",
"chars": 12453,
"preview": "using System;\r\nusing System.Diagnostics;\r\nusing System.Security.Permissions;\r\nusing System.Text.RegularExpressions;\r\nus"
},
{
"path": "RED2/Lib/TreeManager.cs",
"chars": 14463,
"preview": "using System;\r\nusing System.Collections.Generic;\r\nusing System.Drawing;\r\nusing System.Windows.Forms;\r\nusing Alphaleonis"
},
{
"path": "RED2/Lib/UIHelpers.cs",
"chars": 1926,
"preview": "using System;\r\n\r\nnamespace RED2\r\n{\r\n /// <summary>\r\n /// Icon names (Warning: Entries are case sensitive)\r\n //"
},
{
"path": "RED2/LogWindow.Designer.cs",
"chars": 2665,
"preview": "namespace RED2\r\n{\r\n partial class LogWindow\r\n {\r\n /// <summary>\r\n /// Erforderliche Designervariabl"
},
{
"path": "RED2/LogWindow.cs",
"chars": 523,
"preview": "using System;\r\nusing System.Windows.Forms;\r\n\r\nnamespace RED2\r\n{\r\n public partial class LogWindow : Form\r\n {\r\n "
},
{
"path": "RED2/LogWindow.resx",
"chars": 5815,
"preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\r\n<root>\r\n <!-- \r\n Microsoft ResX Schema \r\n \r\n Version 2.0\r\n \r\n T"
},
{
"path": "RED2/MainWindow.Designer.cs",
"chars": 77801,
"preview": "namespace RED2\r\n{\r\n\tpartial class MainWindow\r\n\t{\r\n\t\t/// <summary>\r\n\t\t/// Erforderliche Designervariable.\r\n\t\t/// </summa"
},
{
"path": "RED2/MainWindow.cs",
"chars": 31911,
"preview": "using System;\r\nusing System.Collections.Generic;\r\nusing System.ComponentModel;\r\nusing System.Diagnostics;\r\nusing System."
},
{
"path": "RED2/MainWindow.resx",
"chars": 80471,
"preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\r\n<root>\r\n <!-- \r\n Microsoft ResX Schema \r\n \r\n Version 2.0\r\n \r\n Th"
},
{
"path": "RED2/Program.cs",
"chars": 405,
"preview": "using System;\r\nusing System.Collections.Generic;\r\nusing System.Windows.Forms;\r\n\r\nnamespace RED2\r\n{\r\n\tstatic class Progr"
},
{
"path": "RED2/Properties/AssemblyInfo.cs",
"chars": 1623,
"preview": "using System.Reflection;\r\nusing System.Runtime.CompilerServices;\r\nusing System.Runtime.InteropServices;\r\n\r\n// General I"
},
{
"path": "RED2/Properties/Resources.Designer.cs",
"chars": 11780,
"preview": "//------------------------------------------------------------------------------\r\n// <auto-generated>\r\n// This code"
},
{
"path": "RED2/Properties/Resources.resx",
"chars": 9040,
"preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\r\n<root>\r\n <!-- \r\n Microsoft ResX Schema \r\n \r\n Version 2.0\r\n \r\n T"
},
{
"path": "RED2/Properties/Resources_de.resx",
"chars": 50539,
"preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\r\n<root>\r\n <!-- \r\n Microsoft ResX Schema \r\n \r\n Version 2.0\r\n \r\n T"
},
{
"path": "RED2/Properties/Settings.Designer.cs",
"chars": 8613,
"preview": "//------------------------------------------------------------------------------\r\n// <auto-generated>\r\n// This code"
},
{
"path": "RED2/Properties/Settings.settings",
"chars": 2610,
"preview": "<?xml version='1.0' encoding='utf-8'?>\r\n<SettingsFile xmlns=\"http://schemas.microsoft.com/VisualStudio/2004/01/settings"
},
{
"path": "RED2/RED2.csproj",
"chars": 11671,
"preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\r\n<Project DefaultTargets=\"Build\" xmlns=\"http://schemas.microsoft.com/developer/m"
},
{
"path": "RED2/RED2.csproj.user",
"chars": 721,
"preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\r\n<Project xmlns=\"http://schemas.microsoft.com/developer/msbuild/2003\">\r\n <Prope"
},
{
"path": "RED2/app.config",
"chars": 2976,
"preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\r\n<configuration>\r\n <configSections>\r\n <sectionGroup name=\"userSettings\""
},
{
"path": "RED2/app.manifest",
"chars": 3299,
"preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<assembly manifestVersion=\"1.0\" xmlns=\"urn:schemas-microsoft-com:asm.v1\">\n <ass"
},
{
"path": "RED2/packages.config",
"chars": 130,
"preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<packages>\n <package id=\"AlphaFS\" version=\"2.2.6\" targetFramework=\"net462\" />\n<"
},
{
"path": "Scripts/create-1000-empty-directories.bat",
"chars": 135,
"preview": "mkdir test-1000-dirs\n\nFOR /L %%A IN (1,1,1000) DO (\n mkdir test-1000-dirs\\dir-%%A\n)\n\necho \"Done, created 1000 empty dir"
},
{
"path": "Scripts/create-test-directories.bat",
"chars": 3956,
"preview": "rem Change active code page to utf-8 (because of special chars)\nchcp 65001\n\nmkdir test-dirs\\empty-1\nmkdir test-dirs\\empt"
},
{
"path": "red2_project.sln",
"chars": 3130,
"preview": "\r\nMicrosoft Visual Studio Solution File, Format Version 12.00\r\n# Visual Studio Version 16\r\nVisualStudioVersion = 16.0.3"
}
]
About this extraction
This page contains the full source code of the hxseven/Remove-Empty-Directories GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 44 files (424.7 KB), approximately 131.9k tokens, and a symbol index with 179 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.
Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.