├── .gitattributes
├── .gitignore
├── LICENSE.txt
├── README.md
├── README_cn.md
├── img
├── Confirmation01_cn.png
├── Confirmation01_en.png
├── FixPath01_cn.png
├── FixPath01_en.png
├── Main01_cn.png
├── Main01_en.png
├── Open01_cn.png
├── Open01_en.png
├── Open02_cn.png
├── Open02_en.png
├── RightClick01_cn.png
├── RightClick01_en.png
├── RightClick02_cn.png
└── RightClick02_en.png
└── src
├── DelApp.sln
└── DelApp
├── App.config
├── DelApp.csproj
├── FormMain.Designer.cs
├── FormMain.cs
├── FormMain.resx
├── Internals
├── AppLanguageService.cs
├── DefaultIcons.cs
├── DisposableSingleton.cs
├── FileNDir.cs
├── FileUnlocker.cs
├── HandleInfo.cs
├── IAppLanguageProvider.cs
├── InternelDriveInfo.cs
├── NativeWin32
│ ├── ChangeFilterStruct.cs
│ ├── FindFileHandle.cs
│ ├── LUID.cs
│ ├── NativeMethods.cs
│ ├── RmStructs.cs
│ ├── SHSTOCKICONINFO.cs
│ ├── SingleTokenPrivilegeOn.cs
│ ├── SysInfo.cs
│ ├── WaitObjectResult.cs
│ └── Win32FindData.cs
├── ObjPool.cs
├── PeReader.cs
├── PipeService.cs
├── ProcessModuleLite.cs
├── RemoteFunction.cs
├── RestartManagerHelper.cs
├── RightClickMenuHelper.cs
├── SoundPlayHelper.cs
├── UnmanagedBuffer.cs
└── Utils.cs
├── Locals
├── AppLanguageProvider.cs
├── AppLanguageProviderChs.cs
└── AppLanguageProviderEn.cs
├── OpenFileDialogLite.Designer.cs
├── OpenFileDialogLite.cs
├── OpenFileDialogLite.resx
├── Program.cs
├── Properties
├── AssemblyInfo.cs
├── Resources.Designer.cs
├── Resources.resx
├── Settings.Designer.cs
└── Settings.settings
├── app.manifest
└── icon.ico
/.gitattributes:
--------------------------------------------------------------------------------
1 | ###############################################################################
2 | # Set default behavior to automatically normalize line endings.
3 | ###############################################################################
4 | * text=auto
5 |
6 | ###############################################################################
7 | # Set default behavior for command prompt diff.
8 | #
9 | # This is need for earlier builds of msysgit that does not have it on by
10 | # default for csharp files.
11 | # Note: This is only used by command line
12 | ###############################################################################
13 | #*.cs diff=csharp
14 |
15 | ###############################################################################
16 | # Set the merge driver for project and solution files
17 | #
18 | # Merging from the command prompt will add diff markers to the files if there
19 | # are conflicts (Merging from VS is not affected by the settings below, in VS
20 | # the diff markers are never inserted). Diff markers may cause the following
21 | # file extensions to fail to load in VS. An alternative would be to treat
22 | # these files as binary and thus will always conflict and require user
23 | # intervention with every merge. To do so, just uncomment the entries below
24 | ###############################################################################
25 | #*.sln merge=binary
26 | #*.csproj merge=binary
27 | #*.vbproj merge=binary
28 | #*.vcxproj merge=binary
29 | #*.vcproj merge=binary
30 | #*.dbproj merge=binary
31 | #*.fsproj merge=binary
32 | #*.lsproj merge=binary
33 | #*.wixproj merge=binary
34 | #*.modelproj merge=binary
35 | #*.sqlproj merge=binary
36 | #*.wwaproj merge=binary
37 |
38 | ###############################################################################
39 | # behavior for image files
40 | #
41 | # image files are treated as binary by default.
42 | ###############################################################################
43 | #*.jpg binary
44 | #*.png binary
45 | #*.gif binary
46 |
47 | ###############################################################################
48 | # diff behavior for common document formats
49 | #
50 | # Convert binary document formats to text before diffing them. This feature
51 | # is only available from the command line. Turn it on by uncommenting the
52 | # entries below.
53 | ###############################################################################
54 | #*.doc diff=astextplain
55 | #*.DOC diff=astextplain
56 | #*.docx diff=astextplain
57 | #*.DOCX diff=astextplain
58 | #*.dot diff=astextplain
59 | #*.DOT diff=astextplain
60 | #*.pdf diff=astextplain
61 | #*.PDF diff=astextplain
62 | #*.rtf diff=astextplain
63 | #*.RTF diff=astextplain
64 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | ## Ignore Visual Studio temporary files, build results, and
2 | ## files generated by popular Visual Studio add-ons.
3 | ##
4 | ## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore
5 |
6 | # User-specific files
7 | *.rsuser
8 | *.suo
9 | *.user
10 | *.userosscache
11 | *.sln.docstates
12 |
13 | # User-specific files (MonoDevelop/Xamarin Studio)
14 | *.userprefs
15 |
16 | # Mono auto generated files
17 | mono_crash.*
18 |
19 | # Build results
20 | [Dd]ebug/
21 | [Dd]ebugPublic/
22 | [Rr]elease/
23 | [Rr]eleases/
24 | x64/
25 | x86/
26 | [Ww][Ii][Nn]32/
27 | [Aa][Rr][Mm]/
28 | [Aa][Rr][Mm]64/
29 | bld/
30 | [Bb]in/
31 | [Oo]bj/
32 | [Oo]ut/
33 | [Ll]og/
34 | [Ll]ogs/
35 |
36 | # Visual Studio 2015/2017 cache/options directory
37 | .vs/
38 | # Uncomment if you have tasks that create the project's static files in wwwroot
39 | #wwwroot/
40 |
41 | # Visual Studio 2017 auto generated files
42 | Generated\ Files/
43 |
44 | # MSTest test Results
45 | [Tt]est[Rr]esult*/
46 | [Bb]uild[Ll]og.*
47 |
48 | # NUnit
49 | *.VisualState.xml
50 | TestResult.xml
51 | nunit-*.xml
52 |
53 | # Build Results of an ATL Project
54 | [Dd]ebugPS/
55 | [Rr]eleasePS/
56 | dlldata.c
57 |
58 | # Benchmark Results
59 | BenchmarkDotNet.Artifacts/
60 |
61 | # .NET Core
62 | project.lock.json
63 | project.fragment.lock.json
64 | artifacts/
65 |
66 | # ASP.NET Scaffolding
67 | ScaffoldingReadMe.txt
68 |
69 | # StyleCop
70 | StyleCopReport.xml
71 |
72 | # Files built by Visual Studio
73 | *_i.c
74 | *_p.c
75 | *_h.h
76 | *.ilk
77 | *.meta
78 | *.obj
79 | *.iobj
80 | *.pch
81 | *.pdb
82 | *.ipdb
83 | *.pgc
84 | *.pgd
85 | *.rsp
86 | *.sbr
87 | *.tlb
88 | *.tli
89 | *.tlh
90 | *.tmp
91 | *.tmp_proj
92 | *_wpftmp.csproj
93 | *.log
94 | *.vspscc
95 | *.vssscc
96 | .builds
97 | *.pidb
98 | *.svclog
99 | *.scc
100 |
101 | # Chutzpah Test files
102 | _Chutzpah*
103 |
104 | # Visual C++ cache files
105 | ipch/
106 | *.aps
107 | *.ncb
108 | *.opendb
109 | *.opensdf
110 | *.sdf
111 | *.cachefile
112 | *.VC.db
113 | *.VC.VC.opendb
114 |
115 | # Visual Studio profiler
116 | *.psess
117 | *.vsp
118 | *.vspx
119 | *.sap
120 |
121 | # Visual Studio Trace Files
122 | *.e2e
123 |
124 | # TFS 2012 Local Workspace
125 | $tf/
126 |
127 | # Guidance Automation Toolkit
128 | *.gpState
129 |
130 | # ReSharper is a .NET coding add-in
131 | _ReSharper*/
132 | *.[Rr]e[Ss]harper
133 | *.DotSettings.user
134 |
135 | # TeamCity is a build add-in
136 | _TeamCity*
137 |
138 | # DotCover is a Code Coverage Tool
139 | *.dotCover
140 |
141 | # AxoCover is a Code Coverage Tool
142 | .axoCover/*
143 | !.axoCover/settings.json
144 |
145 | # Coverlet is a free, cross platform Code Coverage Tool
146 | coverage*.json
147 | coverage*.xml
148 | coverage*.info
149 |
150 | # Visual Studio code coverage results
151 | *.coverage
152 | *.coveragexml
153 |
154 | # NCrunch
155 | _NCrunch_*
156 | .*crunch*.local.xml
157 | nCrunchTemp_*
158 |
159 | # MightyMoose
160 | *.mm.*
161 | AutoTest.Net/
162 |
163 | # Web workbench (sass)
164 | .sass-cache/
165 |
166 | # Installshield output folder
167 | [Ee]xpress/
168 |
169 | # DocProject is a documentation generator add-in
170 | DocProject/buildhelp/
171 | DocProject/Help/*.HxT
172 | DocProject/Help/*.HxC
173 | DocProject/Help/*.hhc
174 | DocProject/Help/*.hhk
175 | DocProject/Help/*.hhp
176 | DocProject/Help/Html2
177 | DocProject/Help/html
178 |
179 | # Click-Once directory
180 | publish/
181 |
182 | # Publish Web Output
183 | *.[Pp]ublish.xml
184 | *.azurePubxml
185 | # Note: Comment the next line if you want to checkin your web deploy settings,
186 | # but database connection strings (with potential passwords) will be unencrypted
187 | *.pubxml
188 | *.publishproj
189 |
190 | # Microsoft Azure Web App publish settings. Comment the next line if you want to
191 | # checkin your Azure Web App publish settings, but sensitive information contained
192 | # in these scripts will be unencrypted
193 | PublishScripts/
194 |
195 | # NuGet Packages
196 | *.nupkg
197 | # NuGet Symbol Packages
198 | *.snupkg
199 | # The packages folder can be ignored because of Package Restore
200 | **/[Pp]ackages/*
201 | # except build/, which is used as an MSBuild target.
202 | !**/[Pp]ackages/build/
203 | # Uncomment if necessary however generally it will be regenerated when needed
204 | #!**/[Pp]ackages/repositories.config
205 | # NuGet v3's project.json files produces more ignorable files
206 | *.nuget.props
207 | *.nuget.targets
208 |
209 | # Microsoft Azure Build Output
210 | csx/
211 | *.build.csdef
212 |
213 | # Microsoft Azure Emulator
214 | ecf/
215 | rcf/
216 |
217 | # Windows Store app package directories and files
218 | AppPackages/
219 | BundleArtifacts/
220 | Package.StoreAssociation.xml
221 | _pkginfo.txt
222 | *.appx
223 | *.appxbundle
224 | *.appxupload
225 |
226 | # Visual Studio cache files
227 | # files ending in .cache can be ignored
228 | *.[Cc]ache
229 | # but keep track of directories ending in .cache
230 | !?*.[Cc]ache/
231 |
232 | # Others
233 | ClientBin/
234 | ~$*
235 | *~
236 | *.dbmdl
237 | *.dbproj.schemaview
238 | *.jfm
239 | *.pfx
240 | *.publishsettings
241 | orleans.codegen.cs
242 |
243 | # Including strong name files can present a security risk
244 | # (https://github.com/github/gitignore/pull/2483#issue-259490424)
245 | #*.snk
246 |
247 | # Since there are multiple workflows, uncomment next line to ignore bower_components
248 | # (https://github.com/github/gitignore/pull/1529#issuecomment-104372622)
249 | #bower_components/
250 |
251 | # RIA/Silverlight projects
252 | Generated_Code/
253 |
254 | # Backup & report files from converting an old project file
255 | # to a newer Visual Studio version. Backup files are not needed,
256 | # because we have git ;-)
257 | _UpgradeReport_Files/
258 | Backup*/
259 | UpgradeLog*.XML
260 | UpgradeLog*.htm
261 | ServiceFabricBackup/
262 | *.rptproj.bak
263 |
264 | # SQL Server files
265 | *.mdf
266 | *.ldf
267 | *.ndf
268 |
269 | # Business Intelligence projects
270 | *.rdl.data
271 | *.bim.layout
272 | *.bim_*.settings
273 | *.rptproj.rsuser
274 | *- [Bb]ackup.rdl
275 | *- [Bb]ackup ([0-9]).rdl
276 | *- [Bb]ackup ([0-9][0-9]).rdl
277 |
278 | # Microsoft Fakes
279 | FakesAssemblies/
280 |
281 | # GhostDoc plugin setting file
282 | *.GhostDoc.xml
283 |
284 | # Node.js Tools for Visual Studio
285 | .ntvs_analysis.dat
286 | node_modules/
287 |
288 | # Visual Studio 6 build log
289 | *.plg
290 |
291 | # Visual Studio 6 workspace options file
292 | *.opt
293 |
294 | # Visual Studio 6 auto-generated workspace file (contains which files were open etc.)
295 | *.vbw
296 |
297 | # Visual Studio LightSwitch build output
298 | **/*.HTMLClient/GeneratedArtifacts
299 | **/*.DesktopClient/GeneratedArtifacts
300 | **/*.DesktopClient/ModelManifest.xml
301 | **/*.Server/GeneratedArtifacts
302 | **/*.Server/ModelManifest.xml
303 | _Pvt_Extensions
304 |
305 | # Paket dependency manager
306 | .paket/paket.exe
307 | paket-files/
308 |
309 | # FAKE - F# Make
310 | .fake/
311 |
312 | # CodeRush personal settings
313 | .cr/personal
314 |
315 | # Python Tools for Visual Studio (PTVS)
316 | __pycache__/
317 | *.pyc
318 |
319 | # Cake - Uncomment if you are using it
320 | # tools/**
321 | # !tools/packages.config
322 |
323 | # Tabs Studio
324 | *.tss
325 |
326 | # Telerik's JustMock configuration file
327 | *.jmconfig
328 |
329 | # BizTalk build output
330 | *.btp.cs
331 | *.btm.cs
332 | *.odx.cs
333 | *.xsd.cs
334 |
335 | # OpenCover UI analysis results
336 | OpenCover/
337 |
338 | # Azure Stream Analytics local run output
339 | ASALocalRun/
340 |
341 | # MSBuild Binary and Structured Log
342 | *.binlog
343 |
344 | # NVidia Nsight GPU debugger configuration file
345 | *.nvuser
346 |
347 | # MFractors (Xamarin productivity tool) working folder
348 | .mfractor/
349 |
350 | # Local History for Visual Studio
351 | .localhistory/
352 |
353 | # BeatPulse healthcheck temp database
354 | healthchecksdb
355 |
356 | # Backup folder for Package Reference Convert tool in Visual Studio 2017
357 | MigrationBackup/
358 |
359 | # Ionide (cross platform F# VS Code tools) working folder
360 | .ionide/
361 |
362 | # Fody - auto-generated XML schema
363 | FodyWeavers.xsd
364 |
365 | /ReferenceMaterial
--------------------------------------------------------------------------------
/LICENSE.txt:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2023 differentrain
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Delapp
2 |
3 | [简体中文](./README_cn.md)
4 |
5 | A simple tool to delete files and folders in Windows.
6 |
7 | ## Requirement
8 |
9 | - Windows 7 or later
10 | - [.NET Framework 4.8 Runtime or later](https://dotnet.microsoft.com/zh-cn/download/dotnet-framework/net48)
11 |
12 | ## Getting Started
13 |
14 | Delapp is a single-file app, no installation required, just [download latest release version](https://github.com/differentrain/Delapp/releases/latest/download/Delapp.zip), and extract it into wherever you want.
15 |
16 | 
17 |
18 | Drag and drop files or folders into the delete-list, and click `Fast delete` button or `Delete` button, a dialogue box will pop up on the screen.
19 |
20 | 
21 |
22 | Click `YES` , all the files and folders in delete-list will be deleted. The deleted items will **NOT** be moved to the recycle bin, so if you want to restore them, you must rely on other software.
23 |
24 | As a supplementary explanation, The objects which are Dragged and dropped on the icon of Delapp, will be add to the delete-list too.
25 |
26 | ## Right-click Menu
27 |
28 | 
29 |
30 | Click `File` -- `Add to right-click menu` to add/remove Delapp into right-click context menu of explorer.
31 |
32 | Then you can add the files or folders by right-clicking the target objects and selete the `Delapp - add to delete-list` menu.
33 |
34 | 
35 |
36 | Note that if you move Delapp to a new location, you should add right-click menu again.
37 |
38 | ## Invalid Pathes
39 |
40 | One of my motivations for writing this app is that some folders contains invalid chars can not be deleted easily.
41 |
42 | Open the Command Prompt, and try to create a folder end with `..` :
43 |
44 | ```
45 | md test..\
46 | ```
47 |
48 | Then you get a folder named `test..`, which can not be deleted in general ways.
49 |
50 | Don't worry, this command could remove the tiresome folder:
51 |
52 | ```
53 | rd test..\
54 | ```
55 |
56 | Or you can use Delapp.
57 |
58 | 
59 |
60 | Click `File` -- `Open` menu, or press `Ctrl+O`, selete the files/folders you want to delete on right, then you can add them into delete-list.
61 |
62 | 
63 |
64 | If the 'bad' folder contains files that you still needed, you can choose it in delete-list, and click `Edit` -- `Fix invalid path`, or press `Ctrl+R`, Delapp will fix the invalid path automatically.
65 |
66 | 
67 |
68 | ## The Difference Between `Fast delete` and `Delete`
69 |
70 | Basically, `Fast delete` is faster than `Delete`.
71 |
72 | On most occasions, `Fast delete` is enough, but in some case, `Fast delete` is not satisfying.
73 |
74 | Delapp can remove occupied files - files opened by other programs, or executable files of running programs, and it's 'dll'.
75 |
76 | `Fast delete` powers by [Restart Manager](https://learn.microsoft.com/en-us/windows/win32/RstMgr/restart-manager-portal), which could find the programs or services that occupy the target files.
77 |
78 | Unfortunately, Restart Manager can not process the **folder** opened by other programs, although this is not a common case, but a more comprehensive way is still necessary : `Delete` is slower than `Fast delete`, but is checks all process to find file occupancies.
79 |
80 | Another potential problem of `Fast delete` is that it uses recursion to traversal folders. The maximum length of path is 32767 characters, so the value of maximum directory depth in theory may be very large. So if you got `StackoverflowException`, try `Delete` instead of `Fast delete`.
81 |
82 | ## Translations
83 |
84 | I would be grateful if you could help me to translate Delapp to your own language.
85 |
86 | You can pull a request to submit the translated version:
87 |
88 | - Create a new class derived from `DelApp.Locals.AppLanguageProvider`
89 | - Let `abstract string TwoLetterISOLanguageName` property returns the [ISO 639-1 two-letter or ISO 639-3 three-letter code](https://learn.microsoft.com/en-us/dotnet/api/system.globalization.cultureinfo.twoletterisolanguagename?view=netframework-4.8)
90 | - Let `abstract int LCID` property returns the [culture identifier](https://learn.microsoft.com/en-us/dotnet/api/system.globalization.cultureinfo.lcid?view=netframework-4.8) for the target language
91 | - Implement other members which returns relevant translated string.
92 | - Modify `StartApp()` method in `DelApp.Program` class, add this code : `YourLanguageProvider.Instance.Register();`
93 |
94 | Or you can also open a new issue directly to give me your translation.
95 |
--------------------------------------------------------------------------------
/README_cn.md:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/differentrain/Delapp/c0d1d34a9a6327fb0326938493ca32162d78c9e3/README_cn.md
--------------------------------------------------------------------------------
/img/Confirmation01_cn.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/differentrain/Delapp/c0d1d34a9a6327fb0326938493ca32162d78c9e3/img/Confirmation01_cn.png
--------------------------------------------------------------------------------
/img/Confirmation01_en.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/differentrain/Delapp/c0d1d34a9a6327fb0326938493ca32162d78c9e3/img/Confirmation01_en.png
--------------------------------------------------------------------------------
/img/FixPath01_cn.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/differentrain/Delapp/c0d1d34a9a6327fb0326938493ca32162d78c9e3/img/FixPath01_cn.png
--------------------------------------------------------------------------------
/img/FixPath01_en.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/differentrain/Delapp/c0d1d34a9a6327fb0326938493ca32162d78c9e3/img/FixPath01_en.png
--------------------------------------------------------------------------------
/img/Main01_cn.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/differentrain/Delapp/c0d1d34a9a6327fb0326938493ca32162d78c9e3/img/Main01_cn.png
--------------------------------------------------------------------------------
/img/Main01_en.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/differentrain/Delapp/c0d1d34a9a6327fb0326938493ca32162d78c9e3/img/Main01_en.png
--------------------------------------------------------------------------------
/img/Open01_cn.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/differentrain/Delapp/c0d1d34a9a6327fb0326938493ca32162d78c9e3/img/Open01_cn.png
--------------------------------------------------------------------------------
/img/Open01_en.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/differentrain/Delapp/c0d1d34a9a6327fb0326938493ca32162d78c9e3/img/Open01_en.png
--------------------------------------------------------------------------------
/img/Open02_cn.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/differentrain/Delapp/c0d1d34a9a6327fb0326938493ca32162d78c9e3/img/Open02_cn.png
--------------------------------------------------------------------------------
/img/Open02_en.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/differentrain/Delapp/c0d1d34a9a6327fb0326938493ca32162d78c9e3/img/Open02_en.png
--------------------------------------------------------------------------------
/img/RightClick01_cn.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/differentrain/Delapp/c0d1d34a9a6327fb0326938493ca32162d78c9e3/img/RightClick01_cn.png
--------------------------------------------------------------------------------
/img/RightClick01_en.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/differentrain/Delapp/c0d1d34a9a6327fb0326938493ca32162d78c9e3/img/RightClick01_en.png
--------------------------------------------------------------------------------
/img/RightClick02_cn.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/differentrain/Delapp/c0d1d34a9a6327fb0326938493ca32162d78c9e3/img/RightClick02_cn.png
--------------------------------------------------------------------------------
/img/RightClick02_en.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/differentrain/Delapp/c0d1d34a9a6327fb0326938493ca32162d78c9e3/img/RightClick02_en.png
--------------------------------------------------------------------------------
/src/DelApp.sln:
--------------------------------------------------------------------------------
1 |
2 | Microsoft Visual Studio Solution File, Format Version 12.00
3 | # Visual Studio Version 17
4 | VisualStudioVersion = 17.5.33424.131
5 | MinimumVisualStudioVersion = 10.0.40219.1
6 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DelApp", "DelApp\DelApp.csproj", "{B7DD4552-F9AC-4487-866C-9C8BF686F196}"
7 | EndProject
8 | Global
9 | GlobalSection(SolutionConfigurationPlatforms) = preSolution
10 | Debug|Any CPU = Debug|Any CPU
11 | Release|Any CPU = Release|Any CPU
12 | EndGlobalSection
13 | GlobalSection(ProjectConfigurationPlatforms) = postSolution
14 | {B7DD4552-F9AC-4487-866C-9C8BF686F196}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
15 | {B7DD4552-F9AC-4487-866C-9C8BF686F196}.Debug|Any CPU.Build.0 = Debug|Any CPU
16 | {B7DD4552-F9AC-4487-866C-9C8BF686F196}.Release|Any CPU.ActiveCfg = Release|Any CPU
17 | {B7DD4552-F9AC-4487-866C-9C8BF686F196}.Release|Any CPU.Build.0 = Release|Any CPU
18 | EndGlobalSection
19 | GlobalSection(SolutionProperties) = preSolution
20 | HideSolutionNode = FALSE
21 | EndGlobalSection
22 | GlobalSection(ExtensibilityGlobals) = postSolution
23 | SolutionGuid = {D742A0BD-A83C-40C0-9B30-88055AC93165}
24 | EndGlobalSection
25 | EndGlobal
26 |
--------------------------------------------------------------------------------
/src/DelApp/App.config:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/src/DelApp/DelApp.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Debug
6 | AnyCPU
7 | {B7DD4552-F9AC-4487-866C-9C8BF686F196}
8 | WinExe
9 | Delapp
10 | Delapp
11 | v4.8
12 | 512
13 | true
14 | true
15 |
16 |
17 | AnyCPU
18 | true
19 | full
20 | false
21 | bin\Debug\
22 | DEBUG;TRACE
23 | prompt
24 | 4
25 | false
26 | true
27 |
28 |
29 | AnyCPU
30 | pdbonly
31 | true
32 | bin\Release\
33 | TRACE
34 | prompt
35 | 4
36 | false
37 | true
38 |
39 |
40 | icon.ico
41 |
42 |
43 | app.manifest
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 | Form
62 |
63 |
64 | FormMain.cs
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 | Form
92 |
93 |
94 | OpenFileDialogLite.cs
95 |
96 |
97 |
98 |
99 |
100 |
101 |
102 |
103 |
104 |
105 |
106 | FormMain.cs
107 |
108 |
109 | OpenFileDialogLite.cs
110 |
111 |
112 | ResXFileCodeGenerator
113 | Resources.Designer.cs
114 | Designer
115 |
116 |
117 | True
118 | Resources.resx
119 | True
120 |
121 |
122 |
123 | SettingsSingleFileGenerator
124 | Settings.Designer.cs
125 |
126 |
127 | True
128 | Settings.settings
129 | True
130 |
131 |
132 |
133 |
134 |
135 |
136 |
137 |
138 |
139 |
140 |
--------------------------------------------------------------------------------
/src/DelApp/FormMain.Designer.cs:
--------------------------------------------------------------------------------
1 | namespace DelApp
2 | {
3 | partial class FormMain
4 | {
5 | ///
6 | /// 必需的设计器变量。
7 | ///
8 | private System.ComponentModel.IContainer components = null;
9 |
10 | ///
11 | /// 清理所有正在使用的资源。
12 | ///
13 | /// 如果应释放托管资源,为 true;否则为 false。
14 | protected override void Dispose(bool disposing)
15 | {
16 | if (disposing && (components != null))
17 | {
18 | components.Dispose();
19 | }
20 | base.Dispose(disposing);
21 | }
22 |
23 | #region Windows 窗体设计器生成的代码
24 |
25 | ///
26 | /// 设计器支持所需的方法 - 不要修改
27 | /// 使用代码编辑器修改此方法的内容。
28 | ///
29 | private void InitializeComponent()
30 | {
31 | System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(FormMain));
32 | this.ToolStripMain = new System.Windows.Forms.ToolStrip();
33 | this.ToolStripDropDownButtonFile = new System.Windows.Forms.ToolStripDropDownButton();
34 | this.ToolStripMenuItemOpen = new System.Windows.Forms.ToolStripMenuItem();
35 | this.toolStripSeparator1 = new System.Windows.Forms.ToolStripSeparator();
36 | this.ToolStripMenuItemRightClickContextMenu = new System.Windows.Forms.ToolStripMenuItem();
37 | this.ToolStripMenuItemSource = new System.Windows.Forms.ToolStripMenuItem();
38 | this.toolStripSeparator3 = new System.Windows.Forms.ToolStripSeparator();
39 | this.ToolStripMenuItemExitApp = new System.Windows.Forms.ToolStripMenuItem();
40 | this.ToolStripDropDownButtonEdit = new System.Windows.Forms.ToolStripDropDownButton();
41 | this.ToolStripMenuItemRemove = new System.Windows.Forms.ToolStripMenuItem();
42 | this.ToolStripMenuItemClearList = new System.Windows.Forms.ToolStripMenuItem();
43 | this.toolStripSeparator2 = new System.Windows.Forms.ToolStripSeparator();
44 | this.ToolStripMenuItemFix = new System.Windows.Forms.ToolStripMenuItem();
45 | this.toolStripSeparator4 = new System.Windows.Forms.ToolStripSeparator();
46 | this.ToolStripButtonFastDelete = new System.Windows.Forms.ToolStripButton();
47 | this.ToolStripButtonDelete = new System.Windows.Forms.ToolStripButton();
48 | this.ListViewMain = new System.Windows.Forms.ListView();
49 | this.columnHeader1 = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader()));
50 | this.BackgroundWorkerMain = new System.ComponentModel.BackgroundWorker();
51 | this.ToolStripMain.SuspendLayout();
52 | this.SuspendLayout();
53 | //
54 | // ToolStripMain
55 | //
56 | this.ToolStripMain.GripStyle = System.Windows.Forms.ToolStripGripStyle.Hidden;
57 | this.ToolStripMain.Items.AddRange(new System.Windows.Forms.ToolStripItem[] {
58 | this.ToolStripDropDownButtonFile,
59 | this.ToolStripDropDownButtonEdit,
60 | this.toolStripSeparator4,
61 | this.ToolStripButtonFastDelete,
62 | this.ToolStripButtonDelete});
63 | this.ToolStripMain.Location = new System.Drawing.Point(0, 0);
64 | this.ToolStripMain.Name = "ToolStripMain";
65 | this.ToolStripMain.Size = new System.Drawing.Size(433, 25);
66 | this.ToolStripMain.TabIndex = 0;
67 | //
68 | // ToolStripDropDownButtonFile
69 | //
70 | this.ToolStripDropDownButtonFile.DisplayStyle = System.Windows.Forms.ToolStripItemDisplayStyle.Text;
71 | this.ToolStripDropDownButtonFile.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] {
72 | this.ToolStripMenuItemOpen,
73 | this.toolStripSeparator1,
74 | this.ToolStripMenuItemRightClickContextMenu,
75 | this.ToolStripMenuItemSource,
76 | this.toolStripSeparator3,
77 | this.ToolStripMenuItemExitApp});
78 | this.ToolStripDropDownButtonFile.Image = ((System.Drawing.Image)(resources.GetObject("ToolStripDropDownButtonFile.Image")));
79 | this.ToolStripDropDownButtonFile.ImageTransparentColor = System.Drawing.Color.Magenta;
80 | this.ToolStripDropDownButtonFile.Name = "ToolStripDropDownButtonFile";
81 | this.ToolStripDropDownButtonFile.Size = new System.Drawing.Size(40, 22);
82 | this.ToolStripDropDownButtonFile.Text = "File";
83 | //
84 | // ToolStripMenuItemOpen
85 | //
86 | this.ToolStripMenuItemOpen.Name = "ToolStripMenuItemOpen";
87 | this.ToolStripMenuItemOpen.ShortcutKeys = ((System.Windows.Forms.Keys)((System.Windows.Forms.Keys.Control | System.Windows.Forms.Keys.O)));
88 | this.ToolStripMenuItemOpen.Size = new System.Drawing.Size(217, 22);
89 | this.ToolStripMenuItemOpen.Text = "Open...";
90 | this.ToolStripMenuItemOpen.Click += new System.EventHandler(this.ToolStripMenuItemOpen_Click);
91 | //
92 | // toolStripSeparator1
93 | //
94 | this.toolStripSeparator1.Name = "toolStripSeparator1";
95 | this.toolStripSeparator1.Size = new System.Drawing.Size(214, 6);
96 | //
97 | // ToolStripMenuItemRightClickContextMenu
98 | //
99 | this.ToolStripMenuItemRightClickContextMenu.CheckOnClick = true;
100 | this.ToolStripMenuItemRightClickContextMenu.Name = "ToolStripMenuItemRightClickContextMenu";
101 | this.ToolStripMenuItemRightClickContextMenu.Size = new System.Drawing.Size(217, 22);
102 | this.ToolStripMenuItemRightClickContextMenu.Text = "Right click context menu";
103 | //
104 | // ToolStripMenuItemSource
105 | //
106 | this.ToolStripMenuItemSource.Name = "ToolStripMenuItemSource";
107 | this.ToolStripMenuItemSource.Size = new System.Drawing.Size(217, 22);
108 | this.ToolStripMenuItemSource.Text = "Source code";
109 | this.ToolStripMenuItemSource.Click += new System.EventHandler(this.ToolStripMenuItemSource_Click);
110 | //
111 | // toolStripSeparator3
112 | //
113 | this.toolStripSeparator3.Name = "toolStripSeparator3";
114 | this.toolStripSeparator3.Size = new System.Drawing.Size(214, 6);
115 | //
116 | // ToolStripMenuItemExitApp
117 | //
118 | this.ToolStripMenuItemExitApp.Name = "ToolStripMenuItemExitApp";
119 | this.ToolStripMenuItemExitApp.ShortcutKeys = ((System.Windows.Forms.Keys)((System.Windows.Forms.Keys.Alt | System.Windows.Forms.Keys.F4)));
120 | this.ToolStripMenuItemExitApp.Size = new System.Drawing.Size(217, 22);
121 | this.ToolStripMenuItemExitApp.Text = "Exit";
122 | this.ToolStripMenuItemExitApp.Click += new System.EventHandler(this.ToolStripMenuItemExitApp_Click);
123 | //
124 | // ToolStripDropDownButtonEdit
125 | //
126 | this.ToolStripDropDownButtonEdit.DisplayStyle = System.Windows.Forms.ToolStripItemDisplayStyle.Text;
127 | this.ToolStripDropDownButtonEdit.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] {
128 | this.ToolStripMenuItemRemove,
129 | this.ToolStripMenuItemClearList,
130 | this.toolStripSeparator2,
131 | this.ToolStripMenuItemFix});
132 | this.ToolStripDropDownButtonEdit.Image = ((System.Drawing.Image)(resources.GetObject("ToolStripDropDownButtonEdit.Image")));
133 | this.ToolStripDropDownButtonEdit.ImageTransparentColor = System.Drawing.Color.Magenta;
134 | this.ToolStripDropDownButtonEdit.Name = "ToolStripDropDownButtonEdit";
135 | this.ToolStripDropDownButtonEdit.Size = new System.Drawing.Size(43, 22);
136 | this.ToolStripDropDownButtonEdit.Text = "Edit";
137 | //
138 | // ToolStripMenuItemRemove
139 | //
140 | this.ToolStripMenuItemRemove.Enabled = false;
141 | this.ToolStripMenuItemRemove.Name = "ToolStripMenuItemRemove";
142 | this.ToolStripMenuItemRemove.ShortcutKeys = System.Windows.Forms.Keys.Delete;
143 | this.ToolStripMenuItemRemove.Size = new System.Drawing.Size(220, 22);
144 | this.ToolStripMenuItemRemove.Text = "Remove from list";
145 | this.ToolStripMenuItemRemove.Click += new System.EventHandler(this.ToolStripMenuItemRemove_Click);
146 | //
147 | // ToolStripMenuItemClearList
148 | //
149 | this.ToolStripMenuItemClearList.Enabled = false;
150 | this.ToolStripMenuItemClearList.Name = "ToolStripMenuItemClearList";
151 | this.ToolStripMenuItemClearList.ShortcutKeys = ((System.Windows.Forms.Keys)((System.Windows.Forms.Keys.Control | System.Windows.Forms.Keys.Delete)));
152 | this.ToolStripMenuItemClearList.Size = new System.Drawing.Size(220, 22);
153 | this.ToolStripMenuItemClearList.Text = "Clear list";
154 | this.ToolStripMenuItemClearList.Click += new System.EventHandler(this.ToolStripMenuItemClearList_Click);
155 | //
156 | // toolStripSeparator2
157 | //
158 | this.toolStripSeparator2.Name = "toolStripSeparator2";
159 | this.toolStripSeparator2.Size = new System.Drawing.Size(217, 6);
160 | //
161 | // ToolStripMenuItemFix
162 | //
163 | this.ToolStripMenuItemFix.Enabled = false;
164 | this.ToolStripMenuItemFix.Name = "ToolStripMenuItemFix";
165 | this.ToolStripMenuItemFix.ShortcutKeys = ((System.Windows.Forms.Keys)((System.Windows.Forms.Keys.Control | System.Windows.Forms.Keys.R)));
166 | this.ToolStripMenuItemFix.Size = new System.Drawing.Size(220, 22);
167 | this.ToolStripMenuItemFix.Text = "Fix invalid path";
168 | this.ToolStripMenuItemFix.Click += new System.EventHandler(this.ToolStripMenuItemFix_Click);
169 | //
170 | // toolStripSeparator4
171 | //
172 | this.toolStripSeparator4.Name = "toolStripSeparator4";
173 | this.toolStripSeparator4.Size = new System.Drawing.Size(6, 25);
174 | //
175 | // ToolStripButtonFastDelete
176 | //
177 | this.ToolStripButtonFastDelete.DisplayStyle = System.Windows.Forms.ToolStripItemDisplayStyle.Text;
178 | this.ToolStripButtonFastDelete.Enabled = false;
179 | this.ToolStripButtonFastDelete.Image = ((System.Drawing.Image)(resources.GetObject("ToolStripButtonFastDelete.Image")));
180 | this.ToolStripButtonFastDelete.ImageTransparentColor = System.Drawing.Color.Magenta;
181 | this.ToolStripButtonFastDelete.Name = "ToolStripButtonFastDelete";
182 | this.ToolStripButtonFastDelete.Size = new System.Drawing.Size(76, 22);
183 | this.ToolStripButtonFastDelete.Text = "Fast Delete";
184 | this.ToolStripButtonFastDelete.Click += new System.EventHandler(this.ToolStripButtonDelete_Click);
185 | //
186 | // ToolStripButtonDelete
187 | //
188 | this.ToolStripButtonDelete.DisplayStyle = System.Windows.Forms.ToolStripItemDisplayStyle.Text;
189 | this.ToolStripButtonDelete.Enabled = false;
190 | this.ToolStripButtonDelete.Image = ((System.Drawing.Image)(resources.GetObject("ToolStripButtonDelete.Image")));
191 | this.ToolStripButtonDelete.ImageTransparentColor = System.Drawing.Color.Magenta;
192 | this.ToolStripButtonDelete.Name = "ToolStripButtonDelete";
193 | this.ToolStripButtonDelete.Size = new System.Drawing.Size(49, 22);
194 | this.ToolStripButtonDelete.Text = "Delete";
195 | this.ToolStripButtonDelete.Click += new System.EventHandler(this.ToolStripButtonDelete_Click);
196 | //
197 | // ListViewMain
198 | //
199 | this.ListViewMain.Alignment = System.Windows.Forms.ListViewAlignment.Left;
200 | this.ListViewMain.BorderStyle = System.Windows.Forms.BorderStyle.FixedSingle;
201 | this.ListViewMain.Columns.AddRange(new System.Windows.Forms.ColumnHeader[] {
202 | this.columnHeader1});
203 | this.ListViewMain.Dock = System.Windows.Forms.DockStyle.Fill;
204 | this.ListViewMain.FullRowSelect = true;
205 | this.ListViewMain.GridLines = true;
206 | this.ListViewMain.HeaderStyle = System.Windows.Forms.ColumnHeaderStyle.None;
207 | this.ListViewMain.HideSelection = false;
208 | this.ListViewMain.Location = new System.Drawing.Point(0, 25);
209 | this.ListViewMain.Name = "ListViewMain";
210 | this.ListViewMain.ShowGroups = false;
211 | this.ListViewMain.ShowItemToolTips = true;
212 | this.ListViewMain.Size = new System.Drawing.Size(433, 261);
213 | this.ListViewMain.TabIndex = 1;
214 | this.ListViewMain.UseCompatibleStateImageBehavior = false;
215 | this.ListViewMain.View = System.Windows.Forms.View.Details;
216 | this.ListViewMain.SelectedIndexChanged += new System.EventHandler(this.ListViewMain_SelectedIndexChanged);
217 | //
218 | // columnHeader1
219 | //
220 | this.columnHeader1.Text = "Delete list";
221 | this.columnHeader1.Width = 10000;
222 | //
223 | // BackgroundWorkerMain
224 | //
225 | this.BackgroundWorkerMain.DoWork += new System.ComponentModel.DoWorkEventHandler(this.BackgroundWorkerMain_DoWork);
226 | this.BackgroundWorkerMain.RunWorkerCompleted += new System.ComponentModel.RunWorkerCompletedEventHandler(this.BackgroundWorkerMain_RunWorkerCompleted);
227 | //
228 | // FormMain
229 | //
230 | this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 12F);
231 | this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
232 | this.ClientSize = new System.Drawing.Size(433, 286);
233 | this.Controls.Add(this.ListViewMain);
234 | this.Controls.Add(this.ToolStripMain);
235 | this.Icon = ((System.Drawing.Icon)(resources.GetObject("$this.Icon")));
236 | this.Name = "FormMain";
237 | this.StartPosition = System.Windows.Forms.FormStartPosition.CenterScreen;
238 | this.Text = "Delapp";
239 | this.FormClosing += new System.Windows.Forms.FormClosingEventHandler(this.FormMain_FormClosing);
240 | this.ToolStripMain.ResumeLayout(false);
241 | this.ToolStripMain.PerformLayout();
242 | this.ResumeLayout(false);
243 | this.PerformLayout();
244 |
245 | }
246 |
247 | #endregion
248 |
249 | private System.Windows.Forms.ToolStrip ToolStripMain;
250 | private System.Windows.Forms.ToolStripDropDownButton ToolStripDropDownButtonFile;
251 | private System.Windows.Forms.ToolStripMenuItem ToolStripMenuItemOpen;
252 | private System.Windows.Forms.ToolStripSeparator toolStripSeparator1;
253 | private System.Windows.Forms.ToolStripMenuItem ToolStripMenuItemExitApp;
254 | private System.Windows.Forms.ToolStripButton ToolStripButtonDelete;
255 | private System.Windows.Forms.ListView ListViewMain;
256 | private System.Windows.Forms.ToolStripMenuItem ToolStripMenuItemRightClickContextMenu;
257 | private System.Windows.Forms.ToolStripSeparator toolStripSeparator3;
258 | private System.ComponentModel.BackgroundWorker BackgroundWorkerMain;
259 | private System.Windows.Forms.ColumnHeader columnHeader1;
260 | private System.Windows.Forms.ToolStripSeparator toolStripSeparator4;
261 | private System.Windows.Forms.ToolStripDropDownButton ToolStripDropDownButtonEdit;
262 | private System.Windows.Forms.ToolStripMenuItem ToolStripMenuItemRemove;
263 | private System.Windows.Forms.ToolStripMenuItem ToolStripMenuItemClearList;
264 | private System.Windows.Forms.ToolStripSeparator toolStripSeparator2;
265 | private System.Windows.Forms.ToolStripMenuItem ToolStripMenuItemFix;
266 | private System.Windows.Forms.ToolStripMenuItem ToolStripMenuItemSource;
267 | private System.Windows.Forms.ToolStripButton ToolStripButtonFastDelete;
268 | }
269 | }
270 |
271 |
--------------------------------------------------------------------------------
/src/DelApp/FormMain.cs:
--------------------------------------------------------------------------------
1 | using DelApp.Internals;
2 | using DelApp.Internals.Win32;
3 | using DelApp.Locals;
4 | using System;
5 | using System.Collections.Generic;
6 | using System.ComponentModel;
7 | using System.Data;
8 | using System.Diagnostics;
9 | using System.Linq;
10 | using System.Windows.Forms;
11 |
12 |
13 | namespace DelApp
14 | {
15 | internal partial class FormMain : Form, IMessageFilter
16 | {
17 | private const uint WM_COPYGLOBALDATA = 0x0049;
18 | private const uint WM_COPYDATA = 0x004A;
19 | private const uint WM_DROPFILES = 0x0233;
20 | private const uint MSGFLT_ALLOW = 1;
21 | private const uint MSGFLT_RESET = 0;
22 |
23 | private readonly bool _canDrag;
24 | private readonly OpenFileDialogLite _openPathDialog = new OpenFileDialogLite();
25 |
26 | public FormMain()
27 | {
28 | CheckForIllegalCrossThreadCalls = false;
29 |
30 | InitializeComponent();
31 |
32 | _openPathDialog.Owner = this;
33 |
34 | PipeService.PathRecived += PipeService_PathRecived;
35 |
36 | ListViewMain.Columns[0].Width = Screen.GetWorkingArea(this).Width;
37 | ListViewMain.SmallImageList = _openPathDialog.ImageListMain;
38 |
39 | _canDrag = RegDragDropMsgFilter(ListViewMain);
40 |
41 | try
42 | {
43 | ToolStripMenuItemRightClickContextMenu.Checked = RightClickMenuHelper.HasRightClickMenu;
44 | }
45 | catch (Exception exc)
46 | {
47 | MessageBox.Show(exc.ToString());
48 | }
49 | finally
50 | {
51 | ToolStripMenuItemRightClickContextMenu.CheckedChanged += ToolStripMenuItemRightClickContextMenu_CheckedChanged;
52 | }
53 |
54 | ListViewMain.BeginUpdate();
55 | foreach (var item in Program.FilePathes)
56 | {
57 | OpenFileDialogLite.TryAddToList(ListViewMain, new FileNDir(item));
58 | }
59 | ListViewMain.EndUpdate();
60 | EnsureButtonForHoleList();
61 |
62 | IAppLanguageProvider lp = AppLanguageService.LanguageProvider;
63 |
64 | ToolStripDropDownButtonFile.Text = lp.UI_File;
65 | ToolStripMenuItemOpen.Text = lp.UI_File_Open;
66 | ToolStripMenuItemRightClickContextMenu.Text = lp.UI_File_RightClickContextMenu;
67 | ToolStripMenuItemSource.Text = lp.UI_File_SourceCode;
68 | ToolStripMenuItemExitApp.Text = lp.UI_File_Exit;
69 |
70 | ToolStripDropDownButtonEdit.Text = lp.UI_Edit;
71 | ToolStripMenuItemRemove.Text = lp.UI_Edit_RemoveFromList;
72 | ToolStripMenuItemClearList.Text = lp.UI_Edit_ClearList;
73 | ToolStripMenuItemFix.Text = lp.UI_Edit_FixPath;
74 |
75 | ToolStripButtonFastDelete.Text = lp.UI_FastDelete;
76 | ToolStripButtonDelete.Text = lp.UI_Delete;
77 |
78 | }
79 |
80 | private void PipeService_PathRecived(object sender, EventArgs e)
81 | {
82 | if (ListViewMain.Enabled)
83 | AddPipeSendedFile();
84 | }
85 |
86 | private void AddPipeSendedFile()
87 | {
88 | ListViewMain.BeginUpdate();
89 | while (PipeService.PathQueue.TryDequeue(out FileNDir fd))
90 | OpenFileDialogLite.TryAddToList(ListViewMain, fd);
91 | ListViewMain.EndUpdate();
92 | EnsureButtonForHoleList();
93 | }
94 |
95 | private void ToolStripMenuItemExitApp_Click(object sender, EventArgs e)
96 | {
97 | Close();
98 | }
99 |
100 | public bool PreFilterMessage(ref Message m)
101 | {
102 | if (m.Msg == WM_DROPFILES)
103 | {
104 | ListViewMain.BeginUpdate();
105 | foreach (FileNDir item in Utils.GetDrapDropFiles(m.WParam))
106 | {
107 | OpenFileDialogLite.TryAddToList(ListViewMain, item);
108 | }
109 | ListViewMain.EndUpdate();
110 | EnsureButtonForHoleList();
111 | return true;
112 | }
113 | return false;
114 | }
115 |
116 | private void FormMain_FormClosing(object sender, FormClosingEventArgs e)
117 | {
118 | if (_canDrag)
119 | {
120 | RemoveDragDropMsgFilter(ListViewMain);
121 | }
122 | }
123 |
124 | private bool RegDragDropMsgFilter(Control control)
125 | {
126 | IntPtr handle = control.Handle;
127 | var status = new ChangeFilterStruct() { CbSize = 8 };
128 |
129 | if (NativeMethods.ChangeWindowMessageFilterEx(handle, WM_DROPFILES, MSGFLT_ALLOW, in status) &&
130 | NativeMethods.ChangeWindowMessageFilterEx(handle, WM_COPYGLOBALDATA, MSGFLT_ALLOW, in status) &&
131 | NativeMethods.ChangeWindowMessageFilterEx(handle, WM_COPYDATA, MSGFLT_ALLOW, in status))
132 | {
133 | NativeMethods.DragAcceptFiles(handle, true);
134 | Application.AddMessageFilter(this);
135 | return true;
136 | }
137 | return false;
138 | }
139 |
140 | private void RemoveDragDropMsgFilter(Control control)
141 | {
142 | IntPtr handle = control.Handle;
143 | NativeMethods.DragAcceptFiles(handle, false);
144 | var status = new ChangeFilterStruct() { CbSize = 8 };
145 | NativeMethods.ChangeWindowMessageFilterEx(handle, WM_DROPFILES, MSGFLT_RESET, in status);
146 | NativeMethods.ChangeWindowMessageFilterEx(handle, WM_COPYGLOBALDATA, MSGFLT_RESET, in status);
147 | NativeMethods.ChangeWindowMessageFilterEx(handle, WM_COPYDATA, MSGFLT_RESET, in status);
148 | Application.RemoveMessageFilter(this);
149 | }
150 |
151 |
152 |
153 | private void ToolStripMenuItemRightClickContextMenu_CheckedChanged(object sender, EventArgs e)
154 | {
155 | ToolStripMenuItemRightClickContextMenu.CheckedChanged -= ToolStripMenuItemRightClickContextMenu_CheckedChanged;
156 | try
157 | {
158 | RightClickMenuHelper.HasRightClickMenu = ToolStripMenuItemRightClickContextMenu.Checked;
159 | ToolStripMenuItemRightClickContextMenu.Checked = RightClickMenuHelper.HasRightClickMenu;
160 | }
161 | catch (Exception exc)
162 | {
163 | MessageBox.Show(exc.ToString());
164 | }
165 | finally
166 | {
167 | ToolStripMenuItemRightClickContextMenu.CheckedChanged += ToolStripMenuItemRightClickContextMenu_CheckedChanged;
168 | }
169 | }
170 |
171 | private void ListViewMain_SelectedIndexChanged(object sender, EventArgs e)
172 | {
173 | int selCount = ListViewMain.SelectedItems.Count;
174 | if (selCount == 0)
175 | {
176 | ToolStripMenuItemFix.Enabled = ToolStripMenuItemRemove.Enabled = false;
177 | }
178 | else
179 | {
180 | ToolStripMenuItemRemove.Enabled = true;
181 | ToolStripMenuItemFix.Enabled = selCount == 1 && (ListViewMain.SelectedItems[0].Tag as FileNDir).IsInvalidPath;
182 | }
183 |
184 | }
185 |
186 | private void ToolStripMenuItemRemove_Click(object sender, EventArgs e)
187 | {
188 | while (ListViewMain.SelectedItems.Count > 0)
189 | {
190 | ListViewMain.SelectedItems[0].Remove();
191 | }
192 | EnsureButtonForHoleList();
193 | }
194 |
195 | private void ToolStripMenuItemClearList_Click(object sender, EventArgs e)
196 | {
197 | ListViewMain.SelectedItems.Clear();
198 | ListViewMain.Items.Clear();
199 | EnsureButtonForHoleList();
200 | }
201 |
202 |
203 | private void ToolStripMenuItemOpen_Click(object sender, EventArgs e)
204 | {
205 | if (_openPathDialog.ShowDialog() == DialogResult.OK)
206 | {
207 | int count = _openPathDialog.Pathes.Count;
208 | for (int i = 0; i < count; i++)
209 | {
210 | OpenFileDialogLite.TryAddToList(ListViewMain, _openPathDialog.Pathes[i]);
211 | }
212 | }
213 | EnsureButtonForHoleList();
214 | }
215 |
216 | private void ToolStripMenuItemFix_Click(object sender, EventArgs e)
217 | {
218 | bool ret = (ListViewMain.SelectedItems[0].Tag as FileNDir).FixPath(out FileNDir newFile);
219 |
220 | if (ret)
221 | {
222 | ListViewMain.SelectedItems[0].Remove();
223 | OpenFileDialogLite.TryAddToList(ListViewMain, newFile);
224 | }
225 | else
226 | {
227 | MessageBox.Show(AppLanguageService.LanguageProvider.Message_FailToFixPath, "Delapp");
228 | }
229 | }
230 |
231 | private void ToolStripButtonDelete_Click(object sender, EventArgs e)
232 | {
233 | if (MessageBox.Show(AppLanguageService.LanguageProvider.Message_Confirmation, "Delapp", MessageBoxButtons.YesNo) == DialogResult.Yes)
234 | {
235 | ToolStripDropDownButtonFile.Enabled = false;
236 | ToolStripDropDownButtonEdit.Enabled = false;
237 | ListViewMain.Enabled = false;
238 | ToolStripButtonDelete.Enabled = false;
239 | ToolStripButtonFastDelete.Enabled = false;
240 |
241 | BackgroundWorkerMain.RunWorkerAsync(
242 | (sender as ToolStripButton).Name == "ToolStripButtonFastDelete");
243 | }
244 | }
245 |
246 | private bool EnsureButtonForHoleList()
247 | {
248 | return ToolStripButtonFastDelete.Enabled = ToolStripButtonDelete.Enabled = ToolStripMenuItemClearList.Enabled = ListViewMain.Items.Count > 0;
249 | }
250 |
251 | private void BackgroundWorkerMain_DoWork(object sender, DoWorkEventArgs e)
252 | {
253 | if ((bool)e.Argument)
254 | FastDel(e);
255 | else
256 | NormalDel(e);
257 | }
258 |
259 | private void FastDel(DoWorkEventArgs e)
260 | {
261 | ListView.ListViewItemCollection items = ListViewMain.Items;
262 | List files = ObjPool.RentFDList();
263 | List dirs = ObjPool.RentFDList();
264 | FileNDir fd;
265 | ListViewMain.BeginUpdate();
266 | for (int i = 0; i < items.Count; i++)
267 | {
268 | fd = items[i].Tag as FileNDir;
269 | if (fd.FastDelete(files, dirs))
270 | items.RemoveAt(i--);
271 | }
272 | ListViewMain.EndUpdate();
273 | if (files.Count > 0)
274 | {
275 | InternelDriveInfo.RefreshDriveCache();
276 |
277 | int[] locker = RestartManagerHelper.Shared.GetHolderList(out _, files.Select(f => f.FullPath).ToArray());
278 | FileUnlocker.UnlockModuleAndMemory(files.Select(fd1 => fd1.FullPath).ToDictionary(s => s, s => 0), locker);
279 | DeleteLockedFile(files, items);
280 | if (files.Count > 0)
281 | {
282 | FileUnlocker.UnlockHandle(files.Select(fd1 => fd1.FullPath).ToDictionary(s => s, s => 0), locker);
283 | DeleteLockedFile(files, items);
284 | }
285 | DeleteLockedFile(dirs, items);
286 | }
287 | e.Result = files.Count + dirs.Count;
288 | ObjPool.ReturnFDList(files);
289 | ObjPool.ReturnFDList(dirs);
290 |
291 | void DeleteLockedFile(List fl, ListView.ListViewItemCollection ob)
292 | {
293 | ListViewMain.BeginUpdate();
294 | FileNDir fd1;
295 | FileNDir fd2;
296 | for (int i = 0; i < fl.Count; i++)
297 | {
298 | fd1 = fl[i];
299 | if (fd1.FastDelete(null, null))
300 | {
301 | fl.RemoveAt(i--);
302 | for (int j = 0; j < ob.Count; j++)
303 | {
304 | fd2 = ob[j].Tag as FileNDir;
305 | if (fd2.Equals(fd1))
306 | {
307 | ob.RemoveAt(j);
308 | break;
309 | }
310 | }
311 | }
312 | }
313 | ListViewMain.EndUpdate();
314 | }
315 | }
316 |
317 |
318 |
319 | private void NormalDel(DoWorkEventArgs e)
320 | {
321 | ListView.ListViewItemCollection items = ListViewMain.Items;
322 | List pathes = ObjPool.RentFDList();
323 | FileNDir fd;
324 | ListViewMain.BeginUpdate();
325 | for (int i = 0; i < items.Count; i++)
326 | {
327 | fd = items[i].Tag as FileNDir;
328 | if (fd.Delete(pathes))
329 | items.RemoveAt(i--);
330 | }
331 | ListViewMain.EndUpdate();
332 | if (pathes.Count > 0)
333 | {
334 | InternelDriveInfo.RefreshDriveCache();
335 | FileUnlocker.UnlockModuleAndMemory(pathes.Select(pt => pt.FullPath).ToDictionary(s => s, s => 0));
336 | DeleteLockedFile(pathes, items);
337 | if (pathes.Count > 0)
338 | {
339 | FileUnlocker.UnlockHandle(pathes.Select(pt => pt.FullPath).ToDictionary(s => s, s => 0));
340 | DeleteLockedFile(pathes, items);
341 | }
342 | void DeleteLockedFile(List pl, ListView.ListViewItemCollection ob)
343 | {
344 | ListViewMain.BeginUpdate();
345 | FileNDir fd1;
346 | FileNDir fd2;
347 | for (int i = 0; i < pl.Count; i++)
348 | {
349 | fd1 = pl[i];
350 | if (fd1.Delete(null))
351 | {
352 | pl.RemoveAt(i--);
353 | for (int j = 0; j < ob.Count; j++)
354 | {
355 | fd2 = ob[j].Tag as FileNDir;
356 | if (fd2.Equals(fd1))
357 | {
358 | ob.RemoveAt(j);
359 | break;
360 | }
361 | }
362 | }
363 | }
364 | ListViewMain.EndUpdate();
365 | }
366 | }
367 | e.Result = pathes.Count;
368 | ObjPool.ReturnFDList(pathes);
369 | }
370 |
371 |
372 |
373 | private void BackgroundWorkerMain_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
374 | {
375 | if ((int)e.Result != 0)
376 | {
377 | MessageBox.Show(AppLanguageService.LanguageProvider.Message_NotFullyCompleted, "Delapp");
378 | }
379 | else
380 | SoundPlayHelper.Shared.TryPlayEmptyRecyclebin(true);
381 |
382 | ToolStripDropDownButtonFile.Enabled = true;
383 | ToolStripDropDownButtonEdit.Enabled = true;
384 | ListViewMain.Enabled = true;
385 | AddPipeSendedFile();
386 | }
387 |
388 | private void ToolStripMenuItemSource_Click(object sender, EventArgs e)
389 | {
390 | Process.Start("https://github.com/differentrain/Delapp").Dispose();
391 | }
392 | }
393 | }
394 |
--------------------------------------------------------------------------------
/src/DelApp/Internals/AppLanguageService.cs:
--------------------------------------------------------------------------------
1 | using System.Collections.Generic;
2 | using System.Globalization;
3 |
4 | namespace DelApp.Locals
5 | {
6 | internal static class AppLanguageService
7 | {
8 | private static readonly Dictionary s_dictLanguageName;
9 | private static readonly Dictionary s_dictLCID;
10 | private static readonly IAppLanguageProvider s_defaultLan;
11 |
12 | private static IAppLanguageProvider s_provider;
13 |
14 | static AppLanguageService()
15 | {
16 | s_dictLanguageName = new Dictionary();
17 | s_dictLCID = new Dictionary();
18 | s_defaultLan = AppLanguageProviderEn.Instance;
19 | }
20 |
21 | public static IAppLanguageProvider LanguageProvider
22 | {
23 | get
24 | {
25 | if (s_provider == null)
26 | {
27 | CultureInfo lang = CultureInfo.CurrentCulture;
28 | s_provider = s_dictLCID.TryGetValue(lang.LCID, out IAppLanguageProvider p) ||
29 | s_dictLanguageName.TryGetValue(lang.TwoLetterISOLanguageName, out p) ?
30 | p :
31 | s_defaultLan;
32 | }
33 | return s_provider;
34 | }
35 |
36 | }
37 |
38 | public static void RegisterLanguageProvider(IAppLanguageProvider lp)
39 | {
40 | if (!s_dictLanguageName.ContainsKey(lp.TwoLetterISOLanguageName))
41 | s_dictLanguageName.Add(lp.TwoLetterISOLanguageName, lp);
42 | if (!s_dictLCID.ContainsKey(lp.LCID))
43 | s_dictLCID.Add(lp.LCID, lp);
44 | }
45 |
46 | }
47 | }
48 |
--------------------------------------------------------------------------------
/src/DelApp/Internals/DefaultIcons.cs:
--------------------------------------------------------------------------------
1 | using DelApp.Internals.Win32;
2 | using System.Drawing;
3 | using System.Runtime.InteropServices;
4 |
5 | namespace DelApp.Internals
6 | {
7 | internal static class DefaultIcons
8 | {
9 |
10 | private const uint SIID_FOLDER = 3;
11 | private const uint SIID_DOCNOASSOC = 0;
12 | private const uint SIID_FOLDERBACK = 75;
13 | private const uint SHGSI_ICON = 0x100;
14 |
15 |
16 | private const uint SHGSI_SMALLICON = 0x1;
17 |
18 |
19 | public static Icon BackSmall { get; } = GetStockIcon(SIID_FOLDERBACK, SHGSI_SMALLICON);
20 | public static Icon FileSmall { get; } = GetStockIcon(SIID_DOCNOASSOC, SHGSI_SMALLICON);
21 | public static Icon DirSmall { get; } = GetStockIcon(SIID_FOLDER, SHGSI_SMALLICON);
22 |
23 | public static Icon GetStockIcon(uint type, uint size)
24 | {
25 | var info = new SHSTOCKICONINFO();
26 | info.cbSize = (uint)Marshal.SizeOf(info);
27 |
28 | NativeMethods.SHGetStockIconInfo(type, SHGSI_ICON | size, ref info);
29 | var icon = (Icon)Icon.FromHandle(info.hIcon).Clone(); // Get a copy that doesn't use the original handle
30 | NativeMethods.DestroyIcon(info.hIcon); // Clean up native icon to prevent resource leak
31 |
32 | return icon;
33 | }
34 |
35 |
36 |
37 |
38 |
39 | }
40 | }
41 |
--------------------------------------------------------------------------------
/src/DelApp/Internals/DisposableSingleton.cs:
--------------------------------------------------------------------------------
1 | using System;
2 |
3 | namespace DelApp.Internals
4 | {
5 | internal abstract class DisposableSingleton : IDisposable
6 | where TSelf : DisposableSingleton
7 | {
8 | private static TSelf _sharedInstance;
9 | private bool _disposedValue;
10 |
11 | // the inherited class must and has better has only a private constructor without arguments.
12 | public static TSelf Shared
13 | {
14 | get
15 | {
16 | if (_sharedInstance == null)
17 | _sharedInstance = (TSelf)Activator.CreateInstance(typeof(TSelf), true);
18 | return _sharedInstance;
19 | }
20 | }
21 |
22 | // Invoke when app exiting
23 | public static void ReleaseSharedInstance()
24 | {
25 | ((IDisposable)_sharedInstance)?.Dispose();
26 | }
27 |
28 |
29 | protected abstract void DisposeManaged();
30 | protected abstract void DisposeUnmanaged();
31 |
32 | private void Dispose(bool disposing)
33 | {
34 | if (!_disposedValue)
35 | {
36 | if (disposing)
37 | {
38 | DisposeManaged();
39 | }
40 | DisposeUnmanaged();
41 | _disposedValue = true;
42 | }
43 | }
44 |
45 | ~DisposableSingleton()
46 | {
47 | Dispose(disposing: false);
48 | }
49 |
50 | // This is a singleton class.
51 | // So it is better to "hide" Dispose method,
52 | // to to remind developers that This method should only be invoked when app is closing, or never be invoked.
53 | void IDisposable.Dispose()
54 | {
55 | Dispose(disposing: true);
56 | GC.SuppressFinalize(this);
57 | }
58 | }
59 | }
60 |
--------------------------------------------------------------------------------
/src/DelApp/Internals/FileNDir.cs:
--------------------------------------------------------------------------------
1 | using DelApp.Internals.Win32;
2 | using System;
3 | using System.Collections.Generic;
4 | using System.IO;
5 | using System.Runtime.InteropServices;
6 | using System.Threading.Tasks;
7 |
8 | namespace DelApp.Internals
9 | {
10 | internal sealed class FileNDir : IEquatable
11 | {
12 | private const int ERROR_FILE_NOT_FOUND = 2;
13 | private const int ERROR_ACCESS_DENIED = 5;
14 | private const int ERROR_DIR_NOT_EMPTY = 145;
15 | private const int ERROR_SHARING_VIOLATION = 0x20;
16 |
17 | private const FileAttributes INVALID_FILE_ATTRIBUTES = (FileAttributes)(-1);
18 | private const string LongPathPrefix = @"\\?\";
19 | private const string SearchSuffix = @"\*";
20 |
21 | public FileNDir(string path)
22 | {
23 | FullPath = path;
24 | }
25 |
26 | public string FullPath { get; }
27 |
28 | public bool IsInvalidPath
29 | {
30 | get
31 | {
32 | unsafe
33 | {
34 |
35 | fixed (char* p = FullPath)
36 | {
37 | char ch = p[FullPath.Length - 1];
38 | return ch == '.' || ch == ' ';
39 | }
40 | }
41 | }
42 | }
43 |
44 | public FileAttributes Attributes => GetFileAttributes(LongPathPrefix + FullPath);
45 |
46 | public bool Exists => Attributes != 0;
47 |
48 | public bool IsFile => (Attributes & FileAttributes.Directory) == 0;
49 |
50 | public bool IsDrive => InternelDriveInfo.IsDrive(FullPath);
51 |
52 | public FileNDir PreviewDir
53 | {
54 | get
55 | {
56 | if (InternelDriveInfo.IsDrive(FullPath))
57 | return null;
58 |
59 | int length = FullPath.Length - 1;
60 | unsafe
61 | {
62 | fixed (char* p = FullPath)
63 | {
64 | while (p[length] != '\\')
65 | {
66 | --length;
67 | }
68 | if (p[length - 1] == ':')
69 | {
70 | ++length;
71 | }
72 | string dir = new string(p, 0, length);
73 | return new FileNDir(dir);
74 | }
75 | }
76 | }
77 | }
78 |
79 | public IEnumerable GetChilds()
80 | {
81 | FileAttributes attr = Attributes;
82 | if (attr == 0 || (attr & FileAttributes.Directory) == 0)
83 | yield break;
84 | foreach (var item in GetChildsCore(FullPath))
85 | {
86 | yield return item;
87 | }
88 | }
89 |
90 | public bool Delete(List lockedList)
91 | {
92 | FileAttributes attr = Attributes;
93 |
94 | if (attr == 0)
95 | return true;
96 | else if ((attr & FileAttributes.Directory) != 0)
97 | return DeleteDirCore(lockedList);
98 | else
99 | return DeleteFileNDir(lockedList, NativeMethods.DeleteFileW);
100 | }
101 |
102 | public bool FastDelete(List fileList, List dirList)
103 | {
104 | FileAttributes attr = Attributes;
105 | if (attr == 0)
106 | return true;
107 | else if ((attr & FileAttributes.Directory) != 0)
108 | return DeleteDirCore2(fileList, dirList);
109 | else
110 | return DeleteFileNDir(fileList, NativeMethods.DeleteFileW);
111 | }
112 |
113 | public bool FixPath(out FileNDir newFile)
114 | {
115 | newFile = null;
116 |
117 | if (!Exists || !IsInvalidPath)
118 | return false;
119 |
120 | string npath = GetCorrectPath(FullPath);
121 | string lpath = LongPathPrefix + npath;
122 | int i = 2;
123 |
124 | while (GetFileAttributes(lpath) != 0)
125 | {
126 | lpath += i;
127 | npath += i;
128 | ++i;
129 | }
130 |
131 | bool ret = NativeMethods.MoveFileW(LongPathPrefix + FullPath, lpath);
132 | if (ret)
133 | {
134 | newFile = new FileNDir(npath);
135 | }
136 | return ret;
137 | string GetCorrectPath(string invalidPath)
138 | {
139 | unsafe
140 | {
141 | fixed (char* p = invalidPath)
142 | {
143 | int pos = invalidPath.Length - 1;
144 | while (p[pos] == '.' ||
145 | p[pos] == ' ')
146 | --pos;
147 |
148 | var str = new string(p, 0, pos + 1);
149 | if (p[pos] == '\\')
150 | {
151 | return str + $"new_{(IsFile ? "file" : "directory")}";
152 | }
153 | else
154 | {
155 | return str;
156 | }
157 | }
158 | }
159 | }
160 | }
161 |
162 |
163 | private bool DeleteDirCore(List lockedList)
164 | {
165 | List dirs = TraverseDirectory(lockedList);
166 | bool suc = true;
167 | int index = dirs.Count - 1;
168 | while (index >= 0)
169 | {
170 | if (!dirs[index--].DeleteFileNDir(lockedList, NativeMethods.RemoveDirectoryW))
171 | suc = false;
172 | }
173 | ObjPool.ReturnFDList(dirs);
174 | return suc;
175 |
176 | List TraverseDirectory(List mlockedList)
177 | {
178 | List mdirs = ObjPool.RentFDList();
179 | mdirs.Add(this);
180 | int i = 0;
181 | while (i < mdirs.Count)
182 | {
183 | foreach (var item in GetChildsCore(mdirs[i++].FullPath))
184 | {
185 | if (item.IsFile)
186 | {
187 | item.DeleteFileNDir(mlockedList, NativeMethods.DeleteFileW);
188 | }
189 | else
190 | {
191 | mdirs.Add(item);
192 | }
193 | }
194 | }
195 | return mdirs;
196 | }
197 | }
198 |
199 | private bool DeleteDirCore2(List fileList, List dirList)
200 | {
201 | Parallel.ForEach(GetChilds(), fd =>
202 | {
203 | fd.FastDelete(fileList, dirList);
204 | });
205 | return DeleteFileNDir(dirList, NativeMethods.RemoveDirectoryW);
206 | }
207 |
208 |
209 | private bool DeleteFileNDir(List lockedList, Func func)
210 | {
211 | var path = LongPathPrefix + FullPath;
212 | var attr = GetFileAttributes(path);
213 | if (attr == INVALID_FILE_ATTRIBUTES)
214 | return true;
215 | if ((attr & FileAttributes.ReadOnly) != 0)
216 | NativeMethods.SetFileAttributesW(path, attr - 1);
217 | if (func(path))
218 | return true;
219 | int erro = Marshal.GetLastWin32Error();
220 | if (erro == ERROR_ACCESS_DENIED || erro == ERROR_SHARING_VIOLATION || erro == ERROR_DIR_NOT_EMPTY)
221 | lockedList?.Add(this);
222 | return false;
223 | }
224 |
225 |
226 |
227 | public static FileAttributes GetFileAttributes(string path)
228 | {
229 | FileAttributes ret = NativeMethods.GetFileAttributesW(path);
230 | return ret == INVALID_FILE_ATTRIBUTES ? 0 : ret;
231 | }
232 |
233 | public static string GetFullPath(string path)
234 | {
235 | if (path.StartsWith(LongPathPrefix) || InternelDriveInfo.IsDrive(path))
236 | return null;
237 |
238 | path = LongPathPrefix + path;
239 |
240 | using (var handle = NativeMethods.CreateFileW(
241 | path,
242 | FileAccess.Read,
243 | FileShare.ReadWrite | FileShare.Delete,
244 | IntPtr.Zero,
245 | FileMode.Open,
246 | (FileAttributes)0x02000000, //FILE_FLAG_BACKUP_SEMANTICS
247 | IntPtr.Zero))
248 | {
249 | if (handle.IsInvalid)
250 | return null;
251 | return Utils.GetPathByFileHandle(handle.DangerousGetHandle());
252 | }
253 | }
254 |
255 | private static IEnumerable GetChildsCore(string path)
256 | {
257 | var sc = new SearchContent();
258 | bool isDrive = InternelDriveInfo.IsDrive(path);
259 | if (isDrive)
260 | path = path.Substring(0, path.Length - 1);
261 | using (FindFileHandle handle = sc.BeginFind(LongPathPrefix + path + SearchSuffix))
262 | {
263 | if (handle == null)
264 | yield break;
265 |
266 | if (!isDrive)
267 | sc.NextFind(handle);
268 | else
269 | yield return new FileNDir($@"{path}\{sc.LastFileName}");
270 |
271 | while (sc.NextFind(handle))
272 | {
273 | string lfn = sc.LastFileName;
274 | yield return new FileNDir($@"{path}\{lfn}");
275 | }
276 | }
277 | }
278 |
279 |
280 | public bool Equals(FileNDir other) => FullPath == other.FullPath;
281 |
282 | public override bool Equals(object obj) => obj is FileNDir fd && Equals(fd);
283 |
284 | public override int GetHashCode() => FullPath.GetHashCode();
285 |
286 | public override string ToString() => FullPath.ToString();
287 |
288 |
289 |
290 |
291 | private struct SearchContent
292 | {
293 | private const int FINDFIRSTEX_INFO_BASIC = 1;
294 | private const int FINDFIRSTEX_SEARCH_NAME_MATCH = 0;
295 | private const int FINDFIRSTEX_LARGE_FETCH_ON_DISK_ENTRIES_ONLY = 2 | 4;
296 |
297 | private Win32FindData _findDate;
298 |
299 | public FileAttributes LastFileAttributs => _findDate.FileAttributes;
300 |
301 | public string LastFileName => _findDate.CFileName;
302 |
303 | public FindFileHandle BeginFind(string path)
304 | {
305 | FindFileHandle handle = NativeMethods.FindFirstFileExW(
306 | path,
307 | FINDFIRSTEX_INFO_BASIC,
308 | ref _findDate,
309 | FINDFIRSTEX_SEARCH_NAME_MATCH,
310 | IntPtr.Zero,
311 | FINDFIRSTEX_LARGE_FETCH_ON_DISK_ENTRIES_ONLY);
312 |
313 | if (handle.IsInvalid)
314 | {
315 | handle.Dispose();
316 | return null;
317 | }
318 | return handle;
319 | }
320 |
321 | public bool NextFind(FindFileHandle findHandle)
322 | {
323 | return (NativeMethods.FindNextFileW(findHandle.DangerousGetHandle(), ref _findDate));
324 | }
325 | }
326 |
327 | }
328 | }
329 |
--------------------------------------------------------------------------------
/src/DelApp/Internals/FileUnlocker.cs:
--------------------------------------------------------------------------------
1 | using DelApp.Internals.Win32;
2 | using System;
3 | using System.Collections.Generic;
4 | using System.Data;
5 | using System.Linq;
6 | using System.Threading.Tasks;
7 |
8 | namespace DelApp.Internals
9 | {
10 | internal static class FileUnlocker
11 | {
12 | private const int FILE_TYPE_DISK = 1;
13 | private const int DuplicateCloseSource = 0x00000001;
14 |
15 | private const int SystemHandleInformation = 0x0010;
16 | private const uint STATUS_INFO_LENGTH_MISMATCH = 0xC0000004;
17 | private const uint Success = 0x00000000;
18 |
19 | private const int ALL_ACCESS = 0x001F0FFF;
20 |
21 | private const int LIST_MODULES_ALL = 0x03;
22 |
23 | private const int MemoryBasicInformation = 0;
24 | private const int MemorySectionName = 2;
25 | private const int MemInfoBufferSizeInt = 32767 * 2;
26 | private const int MEM_Commit = 0x1000;
27 | private const int MEM_Mapped = 0x40000;
28 |
29 | private const int DuplicateSameAccess = 0x00000002;
30 |
31 | private static readonly IntPtr s_stemMinAppAddress;
32 | private static readonly IntPtr s_systemMaxAppAddress;
33 | private static readonly IntPtr s_systemMaxApp32Address;
34 |
35 | private static readonly IntPtr s_memInfoBufferSizeIntPtr = new IntPtr(MemInfoBufferSizeInt);
36 |
37 | private static readonly int s_handleEntrySize = 8 + IntPtr.Size * 2;
38 | private static readonly int s_handleInfoSize = s_handleEntrySize + IntPtr.Size;
39 |
40 | static FileUnlocker()
41 | {
42 | var systemInfo = new SysInfo();
43 | NativeMethods.GetSystemInfo(systemInfo);
44 | long maxAddr = systemInfo.MaximumApplicationAddress.ToInt64();
45 | s_systemMaxApp32Address = new IntPtr(maxAddr & 0x7FFFFFFF);
46 | s_systemMaxAppAddress = (ulong)maxAddr <= uint.MaxValue ? s_systemMaxApp32Address : systemInfo.MaximumApplicationAddress;
47 | s_stemMinAppAddress = systemInfo.MinimumApplicationAddress;
48 | }
49 |
50 |
51 | public static void UnlockModuleAndMemory(Dictionary pathes)
52 | {
53 | using (var buffer = new UnmanagedBuffer(1024 * 1024))
54 | {
55 | bool success;
56 | int realSize;
57 | while ((success = NativeMethods.K32EnumProcesses(buffer.Handle, buffer.Size, out realSize)) && buffer.Size <= realSize)
58 | {
59 | buffer.Resize(realSize << 1);
60 | }
61 | if (!success)
62 | return;
63 | unsafe
64 | {
65 | ReleaseModuleAndMemory(pathes, (int*)buffer.Handle.ToPointer(), realSize >> 2);
66 | }
67 | }
68 | }
69 |
70 | public static void UnlockHandle(Dictionary pathes)
71 | {
72 |
73 | ReleaseHandle(null, pathes);
74 | }
75 |
76 | public static void UnlockModuleAndMemory(Dictionary pathes, int[] locker)
77 | {
78 | unsafe
79 | {
80 | fixed (int* p = locker)
81 | ReleaseModuleAndMemory(pathes, p, locker.Length);
82 | }
83 | }
84 |
85 | public static void UnlockHandle(Dictionary pathes, int[] locker)
86 | {
87 | Dictionary handleLocker = locker.Where(p => p >= 0).ToDictionary(p => p, p => p);
88 | ReleaseHandle(handleLocker, pathes);
89 | }
90 |
91 |
92 |
93 | private unsafe static void ReleaseModuleAndMemory(Dictionary pathes, int* locker, int length)
94 | {
95 | Parallel.For(0, length, i =>
96 | {
97 | IntPtr handle = NativeMethods.OpenProcess(ALL_ACCESS, false, locker[i]);
98 | if (handle == IntPtr.Zero || ReleaseModules(handle, pathes) || ReleaseMappedFile(handle, pathes))
99 | locker[i] = -1;
100 | NativeMethods.CloseHandle(handle);
101 |
102 | });
103 | }
104 |
105 | private static bool ReleaseModules(IntPtr handle, Dictionary pathes)
106 | {
107 | using (var buffer = new UnmanagedBuffer(4))
108 | {
109 | bool success;
110 | while ((success = NativeMethods.K32EnumProcessModulesEx(handle, buffer.Handle, buffer.Size, out int newCb, LIST_MODULES_ALL)) &&
111 | buffer.Size != newCb)
112 | {
113 | buffer.Resize(newCb);
114 | }
115 |
116 | if (!success)
117 | return true;
118 |
119 | IntPtr baseAddr = buffer.Read(0);
120 |
121 | // main module
122 | int found = IsFound(baseAddr, handle, pathes);
123 |
124 | if (found < 0) // can not get module
125 | return true;
126 |
127 | if (found != 0) // kill proc
128 | {
129 | NativeMethods.TerminateProcess(handle, -1);
130 | return true;
131 | }
132 |
133 | int moudleCount = buffer.Size / IntPtr.Size;
134 |
135 | for (int i = 1; i < moudleCount; i++)
136 | {
137 | baseAddr = buffer.Read(i * IntPtr.Size);
138 | found = IsFound(baseAddr, handle, pathes);
139 | if (found < 0) // can not get module
140 | return true;
141 | if (found != 0) // unmap dll
142 | NativeMethods.NtUnmapViewOfSection(handle, baseAddr);
143 | }
144 | return false;
145 | }
146 |
147 | int IsFound(IntPtr baseAddr, IntPtr phandle, Dictionary targets)
148 | {
149 | char[] charBuf = ObjPool.RentCharBuffer();
150 | int clen = NativeMethods.K32GetMappedFileNameW(phandle, baseAddr, charBuf, charBuf.Length);
151 | if (clen == 0)
152 | {
153 | ObjPool.ReturnCharBuffer(charBuf);
154 | return -1;
155 | }
156 | string path = InternelDriveInfo.GetNtPathFromDosPath(charBuf, clen);
157 | ObjPool.ReturnCharBuffer(charBuf);
158 | return targets.ContainsKey(path) ? 1 : 0;
159 | }
160 |
161 | }
162 |
163 | private static bool ReleaseMappedFile(IntPtr handle, Dictionary pathes)
164 | {
165 |
166 | IntPtr start = s_stemMinAppAddress;
167 | long end = (!Utils.IsWow64Process(handle) ? s_systemMaxAppAddress : s_systemMaxApp32Address).ToInt64();
168 | long regionSize;
169 | IntPtr baseAddress;
170 | string path;
171 | using (var buffer = new UnmanagedBuffer(MemInfoBufferSizeInt))
172 | {
173 | while (start.ToInt64() < end)
174 | {
175 | //MEMORY_BASIC_INFORMATION
176 | if (NativeMethods.NtQueryVirtualMemory(handle, start, MemoryBasicInformation, buffer.Handle, s_memInfoBufferSizeIntPtr, out _) != Success)
177 | return true;
178 | baseAddress = buffer.Read(0);
179 | regionSize = buffer.ReadSizeT(IntPtr.Size * 3);
180 |
181 | if (buffer.Read(IntPtr.Size * 4) == MEM_Commit &&
182 | buffer.Read(IntPtr.Size * 4 + 8) == MEM_Mapped &&
183 | NativeMethods.NtQueryVirtualMemory(handle, baseAddress, MemorySectionName, buffer.Handle, s_memInfoBufferSizeIntPtr, out IntPtr len) == Success &&
184 | // UNICODE_STRING
185 | !string.IsNullOrEmpty(path = InternelDriveInfo.GetNtPathFromDosPath(buffer.Handle + (IntPtr.Size << 1), (len.ToInt32() >> 1) - IntPtr.Size - 1)) &&
186 | pathes.ContainsKey(path))
187 | {
188 | NativeMethods.NtUnmapViewOfSection(handle, baseAddress);
189 | }
190 | start = new IntPtr(baseAddress.ToInt64() + regionSize);
191 | }
192 | return false;
193 | }
194 | }
195 |
196 | private static void ReleaseHandle(Dictionary handleLocker, Dictionary pathes)
197 | {
198 | using (var buffer = new UnmanagedBuffer(s_handleInfoSize))
199 | {
200 | uint apiRet;
201 | while ((apiRet = NativeMethods.NtQuerySystemInformation(
202 | SystemHandleInformation,
203 | buffer.Handle,
204 | buffer.Size,
205 | out int realLength)) == STATUS_INFO_LENGTH_MISMATCH)
206 | {
207 | buffer.Resize(realLength);
208 | }
209 | if (apiRet != Success)
210 | return;
211 | long handleCount = buffer.ReadSizeT(0);
212 |
213 | Parallel.For(0L, handleCount, l =>
214 | {
215 | int pid = buffer.Read((int)(IntPtr.Size + l * s_handleEntrySize));
216 |
217 | if (handleLocker == null)
218 | {
219 | if (pid == Utils.AppProcessId)
220 | return;
221 | }
222 | else if (!handleLocker.ContainsKey(pid))
223 | return;
224 |
225 | IntPtr handle = NativeMethods.OpenProcess(ALL_ACCESS, false, pid);
226 | if (handle == IntPtr.Zero)
227 | return;
228 | IntPtr objHandle = new IntPtr(
229 | buffer.Read((int)(l * s_handleEntrySize + IntPtr.Size + 6)
230 | ));
231 | // long access = buffer.ReadSizeT((int)(l * s_handleEntrySize + 8 + IntPtr.Size));
232 | IntPtr mh;
233 | if ((mh = CopyHandle(handle, objHandle)) == IntPtr.Zero)
234 | return;
235 | string path;
236 | bool isTargetHandle =
237 | NativeMethods.GetFileType(mh) == FILE_TYPE_DISK && // is file or dir
238 | (path = Utils.GetPathByFileHandle(mh)) != null &&
239 | pathes.ContainsKey(path);
240 |
241 | NativeMethods.CloseHandle(mh);
242 |
243 | if (isTargetHandle &&
244 | (mh = CopyHandle(handle, objHandle, DuplicateCloseSource)) != IntPtr.Zero)
245 | NativeMethods.CloseHandle(mh);
246 |
247 | NativeMethods.CloseHandle(handle);
248 |
249 | IntPtr CopyHandle(IntPtr sph, IntPtr sh, int option = 0)
250 | {
251 | return NativeMethods.DuplicateHandle(
252 | sph,
253 | sh,
254 | Utils.AppProcessHandle,
255 | out IntPtr myHandle,
256 | 0,
257 | false,
258 | DuplicateSameAccess | option) ? myHandle : IntPtr.Zero;
259 | }
260 | });
261 | }
262 | }
263 |
264 |
265 |
266 | }
267 | }
268 |
--------------------------------------------------------------------------------
/src/DelApp/Internals/HandleInfo.cs:
--------------------------------------------------------------------------------
1 | using System;
2 |
3 | namespace DelApp.Internals
4 | {
5 | internal sealed class HandleInfo
6 | {
7 | public readonly IntPtr Handle;
8 | public readonly long Access;
9 |
10 | private HandleInfo(IntPtr handle, long access) { Handle = handle; Access = access; }
11 |
12 |
13 |
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/src/DelApp/Internals/IAppLanguageProvider.cs:
--------------------------------------------------------------------------------
1 | namespace DelApp.Locals
2 | {
3 | internal interface IAppLanguageProvider
4 | {
5 | string TwoLetterISOLanguageName { get; }
6 | int LCID { get; }
7 |
8 | string UI_File { get; }
9 | string UI_File_Open { get; }
10 | string UI_File_RightClickContextMenu { get; }
11 | string UI_File_SourceCode { get; }
12 | string UI_File_Exit { get; }
13 |
14 | string UI_Edit { get; }
15 | string UI_Edit_RemoveFromList { get; }
16 | string UI_Edit_ClearList { get; }
17 | string UI_Edit_FixPath { get; }
18 |
19 | string UI_FastDelete { get; }
20 | string UI_Delete { get; }
21 |
22 | string UI_OpenDialog_Title { get; }
23 | string UI_OpenDialog_OKButton { get; }
24 | string UI_OpenDialog_CancelButton { get; }
25 | string UI_OpenDialog_FastAccess { get; }
26 | string UI_OpenDialog_FastAccess_Desktop { get; }
27 | string UI_OpenDialog_FastAccess_Document { get; }
28 | string UI_OpenDialog_Drives { get; }
29 |
30 | string Shell_RightClickContextText { get; }
31 |
32 | string Message_FailToFixPath { get; }
33 | string Message_Confirmation { get; }
34 | string Message_NotFullyCompleted { get; }
35 | }
36 | }
37 |
--------------------------------------------------------------------------------
/src/DelApp/Internals/InternelDriveInfo.cs:
--------------------------------------------------------------------------------
1 | using DelApp.Internals.Win32;
2 | using System;
3 | using System.Collections.Generic;
4 | using System.IO;
5 |
6 | namespace DelApp.Internals
7 | {
8 | internal static class InternelDriveInfo
9 | {
10 | private static readonly int s_pro_drive_count = Environment.GetLogicalDrives().Length << 1;
11 | private static readonly Dictionary s_driveCache = new Dictionary(s_pro_drive_count);
12 | private static readonly Dictionary s_driveDosNameMap = new Dictionary(s_pro_drive_count);
13 |
14 | public static bool IsDrive(string path) => s_driveCache.ContainsKey(path);
15 |
16 | public static void RefreshDriveCache()
17 | {
18 | s_driveCache.Clear();
19 | s_driveDosNameMap.Clear();
20 | foreach (string item in RefreshDriveCore())
21 | {
22 | AddToCacheCore(item);
23 | }
24 | }
25 |
26 |
27 | public static IEnumerable RefreshDriveCacheAndReturnsDriveName()
28 | {
29 |
30 | s_driveCache.Clear();
31 | s_driveDosNameMap.Clear();
32 |
33 | foreach (string item in RefreshDriveCore())
34 | {
35 | AddToCacheCore(item);
36 | yield return item;
37 | }
38 | }
39 |
40 |
41 | public static string GetNtPathFromDosPath(IntPtr dosPath, int charCount)
42 | {
43 | unsafe
44 | {
45 | var s = (char*)dosPath.ToPointer();
46 | return GetNtPathFromDosPathCore(s, charCount);
47 | }
48 |
49 | }
50 |
51 | public static string GetNtPathFromDosPath(char[] dosPath, int charCount)
52 | {
53 | unsafe
54 | {
55 | fixed (char* s = dosPath)
56 | return GetNtPathFromDosPathCore(s, charCount);
57 | }
58 | }
59 |
60 |
61 | private static unsafe string GetNtPathFromDosPathCore(char* s, int charCount)
62 | {
63 | int length;
64 | int i = 0, j = 0;
65 | foreach (KeyValuePair item in s_driveDosNameMap)
66 | {
67 | length = item.Key.Length;
68 | if (length < charCount)
69 | {
70 | fixed (char* pDos = item.Key)
71 | {
72 | while (i < length)
73 | {
74 | if (pDos[i] != s[i])
75 | {
76 | goto final;
77 | }
78 | ++i;
79 | }
80 | i -= item.Value.Length;
81 | fixed (char* pWin = item.Value)
82 | {
83 | while (i < length)
84 | {
85 | s[i++] = pWin[j++];
86 | }
87 | }
88 | length = item.Key.Length - item.Value.Length;
89 | return new string(s, length, charCount - length);
90 |
91 | }
92 | }
93 |
94 | final:
95 | i = 0;
96 | j = 0;
97 | }
98 | return null;
99 | }
100 |
101 |
102 |
103 | private static void AddToCacheCore(string driveName)
104 | {
105 | s_driveCache.Add(driveName, null);
106 | string deviceName = driveName.Substring(0, driveName.Length - 1);
107 | var result = TryQueryDosDevice(deviceName);
108 | if (result != null)
109 | {
110 | s_driveDosNameMap.Add(result, deviceName);
111 | }
112 |
113 | string TryQueryDosDevice(string ntDeviceName)
114 | {
115 | char[] pathBuf = ObjPool.RentCharBuffer();
116 | unsafe
117 | {
118 | fixed (char* p = pathBuf)
119 | {
120 | int len = NativeMethods.QueryDosDeviceW(ntDeviceName, p, pathBuf.Length);
121 | try
122 | {
123 | return len == 0 ? null : new string(p, 0, len - 2);
124 | }
125 | finally
126 | {
127 | ObjPool.ReturnCharBuffer(pathBuf);
128 | }
129 | }
130 | }
131 |
132 | }
133 | }
134 |
135 | private static IEnumerable RefreshDriveCore()
136 | {
137 | DriveInfo[] drives = DriveInfo.GetDrives();
138 | int length = drives.Length;
139 | DriveInfo di;
140 | DriveType dt;
141 | for (int i = 0; i < length; i++)
142 | {
143 | di = drives[i];
144 | dt = di.DriveType;
145 | if (di.IsReady && (dt == DriveType.Fixed || dt == DriveType.Removable))
146 | {
147 | yield return di.Name;
148 | }
149 | }
150 | }
151 |
152 |
153 | }
154 | }
155 |
--------------------------------------------------------------------------------
/src/DelApp/Internals/NativeWin32/ChangeFilterStruct.cs:
--------------------------------------------------------------------------------
1 | using System.Runtime.InteropServices;
2 |
3 | namespace DelApp.Internals.Win32
4 | {
5 | [StructLayout(LayoutKind.Sequential)]
6 | internal struct ChangeFilterStruct
7 | {
8 | public uint CbSize;
9 | public uint ExtStatus;
10 | }
11 | }
12 |
--------------------------------------------------------------------------------
/src/DelApp/Internals/NativeWin32/FindFileHandle.cs:
--------------------------------------------------------------------------------
1 | using Microsoft.Win32.SafeHandles;
2 |
3 | namespace DelApp.Internals.Win32
4 | {
5 | internal sealed class FindFileHandle : SafeHandleZeroOrMinusOneIsInvalid
6 | {
7 | private FindFileHandle() : base(true)
8 | {
9 | }
10 |
11 | protected override bool ReleaseHandle()
12 | {
13 | return NativeMethods.FindClose(handle);
14 | }
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/src/DelApp/Internals/NativeWin32/LUID.cs:
--------------------------------------------------------------------------------
1 | using System.Runtime.InteropServices;
2 |
3 | namespace DelApp.Internals.Win32
4 | {
5 | [StructLayout(LayoutKind.Sequential)]
6 | internal struct LUID
7 | {
8 | public int LowPart;
9 | public int HighPart;
10 | }
11 | }
12 |
--------------------------------------------------------------------------------
/src/DelApp/Internals/NativeWin32/NativeMethods.cs:
--------------------------------------------------------------------------------
1 | using Microsoft.Win32.SafeHandles;
2 | using System;
3 | using System.IO;
4 | using System.Runtime.InteropServices;
5 | using System.Security;
6 |
7 | namespace DelApp.Internals.Win32
8 | {
9 | [SuppressUnmanagedCodeSecurity]
10 | internal static class NativeMethods
11 | {
12 | //==================================== message ================================================
13 |
14 | [DllImport("user32.dll", ExactSpelling = true, SetLastError = false, CallingConvention = CallingConvention.Winapi)]
15 | [return: MarshalAs(UnmanagedType.Bool)]
16 | public static extern bool ChangeWindowMessageFilterEx(IntPtr hWnd, uint message, uint action, in ChangeFilterStruct pChangeFilterStruct);
17 |
18 | //==================================== drag drop ================================================
19 |
20 | [DllImport("shell32", ExactSpelling = true, CharSet = CharSet.Unicode)]
21 | public unsafe static extern int DragQueryFileW(IntPtr hDrop, uint iFile, char* pszFile, int cch);
22 |
23 | [DllImport("shell32.dll", ExactSpelling = true, SetLastError = false, CallingConvention = CallingConvention.Winapi)]
24 | public static extern void DragAcceptFiles(IntPtr hWnd, bool fAccept);
25 |
26 | [DllImport("shell32.dll", ExactSpelling = true, SetLastError = false, CallingConvention = CallingConvention.Winapi)]
27 | public static extern void DragFinish(IntPtr hDrop);
28 |
29 | //==================================== file ================================================
30 |
31 | [DllImport("kernel32.dll", ExactSpelling = true, CharSet = CharSet.Unicode, SetLastError = false)]
32 | public static extern FindFileHandle FindFirstFileExW(string lpFileName, int fInfoLevelId, ref Win32FindData lpFindFileData, int fSearchOp, IntPtr lpSearchFilter, int dwAdditionalFlags);
33 |
34 | [DllImport("kernel32.dll", ExactSpelling = true, CharSet = CharSet.Unicode, SetLastError = false)]
35 | public static extern bool FindNextFileW(IntPtr hFindFile, ref Win32FindData lpFindFileData);
36 |
37 | [DllImport("kernel32.dll", ExactSpelling = true, SetLastError = false)]
38 | public static extern bool FindClose(IntPtr hFindFile);
39 |
40 | [DllImport("kernel32.dll", ExactSpelling = true, CharSet = CharSet.Unicode, SetLastError = false)]
41 | public static extern SafeFileHandle CreateFileW(
42 | string filename,
43 | FileAccess access,
44 | FileShare share,
45 | IntPtr securityAttributes, // optional SECURITY_ATTRIBUTES struct or IntPtr.Zero
46 | FileMode creationDisposition,
47 | FileAttributes flagsAndAttributes,
48 | IntPtr templateFile);
49 |
50 |
51 | [DllImport("kernel32.dll", ExactSpelling = true, CharSet = CharSet.Unicode)]
52 | public static extern FileAttributes GetFileAttributesW(string lpFileName);
53 |
54 | [DllImport("kernel32.dll", ExactSpelling = true, CharSet = CharSet.Unicode, SetLastError = false)]
55 | public static extern bool MoveFileW(string lpExistingFileName, string lpNewFileName);
56 |
57 | [DllImport("kernel32.dll", SetLastError = false)]
58 | public static extern int GetFileType(IntPtr hFile);
59 |
60 | [DllImport("kernel32.dll", ExactSpelling = true, CharSet = CharSet.Unicode, SetLastError = true)]
61 | public static extern bool DeleteFileW(string lpPathName);
62 |
63 | [DllImport("kernel32.dll", ExactSpelling = true, CharSet = CharSet.Unicode, SetLastError = true)]
64 | public static extern bool RemoveDirectoryW(string lpPathName);
65 |
66 | [DllImport("Kernel32.dll", ExactSpelling = true, SetLastError = true, CharSet = CharSet.Unicode)]
67 | public static extern int GetFinalPathNameByHandleW(IntPtr hFile, char[] lpszFilePath, int cchFilePath, uint dwFlags);
68 |
69 | [DllImport("kernel32.dll", ExactSpelling = true, CharSet = CharSet.Unicode, SetLastError = false)]
70 | public static extern bool SetFileAttributesW(string lpFileName, FileAttributes dwFileAttributes);
71 |
72 | //==================================== drives ================================================
73 |
74 | [DllImport("kernel32.dll", ExactSpelling = true, CharSet = CharSet.Unicode, SetLastError = true)]
75 | public unsafe static extern int QueryDosDeviceW(string lpDeviceName, char* lpTargetPath, int ucchMax);
76 |
77 | //==================================== icon info ================================================
78 |
79 | [DllImport("shell32.dll")]
80 | public static extern int SHGetStockIconInfo(uint siid, uint uFlags, ref SHSTOCKICONINFO psii);
81 |
82 | [DllImport("user32.dll")]
83 | public static extern bool DestroyIcon(IntPtr handle);
84 |
85 | //==================================== query object ================================================
86 |
87 | [DllImport("ntdll.dll", ExactSpelling = true, SetLastError = false, CallingConvention = CallingConvention.Winapi)]
88 | public static extern uint NtQuerySystemInformation(int infoClass, [Out] IntPtr info, int size, out int length);
89 |
90 | //[DllImport("ntdll.dll", ExactSpelling = true, SetLastError = false, CharSet = CharSet.Unicode, CallingConvention = CallingConvention.Winapi)]
91 | //public static extern uint NtQueryObject(IntPtr objectHandle, int informationClass, [Out] IntPtr informationPtr, int informationLength, out int Length);
92 |
93 | //==================================== environment ================================================
94 | [DllImport("kernel32", ExactSpelling = true, SetLastError = false)]
95 | public static extern void GetSystemInfo(SysInfo lpSystemInfo);
96 |
97 | //==================================== process ================================================
98 | [DllImport("kernel32.dll", ExactSpelling = true, SetLastError = false)]
99 | public static extern IntPtr OpenProcess(int processAccess, bool bInheritHandle, int processId);
100 |
101 | [DllImport("kernel32.dll", ExactSpelling = true, SetLastError = false)]
102 | public static extern bool DuplicateHandle(IntPtr hSourceProcessHandle, IntPtr hSourceHandle, IntPtr hTargetProcessHandle, out IntPtr lpTargetHandle, int dwDesiredAccess, bool bInheritHandle, int dwOptions);
103 |
104 | [DllImport("kernel32.dll", ExactSpelling = true)]
105 | public static extern IntPtr GetCurrentProcess();
106 |
107 | [DllImport("ntdll.dll", ExactSpelling = true, SetLastError = false, CharSet = CharSet.Unicode, CallingConvention = CallingConvention.Winapi)]
108 | public static extern uint NtQueryVirtualMemory(IntPtr hProcess, IntPtr lpAddress, int MemoryInformationClass, IntPtr lpBuffer, IntPtr dwLength, out IntPtr size);
109 |
110 | [DllImport("kernel32.dll", ExactSpelling = true, SetLastError = false, CallingConvention = CallingConvention.Winapi)]
111 | public static extern bool IsWow64Process(IntPtr hProcess, [Out] out bool Wow64Process);
112 |
113 | [DllImport("kernel32.dll", ExactSpelling = true, SetLastError = false, CharSet = CharSet.Unicode, CallingConvention = CallingConvention.Winapi)]
114 | public static extern IntPtr GetModuleHandleW(string lpModuleName);
115 |
116 | [DllImport("kernel32.dll", ExactSpelling = true, SetLastError = false, CharSet = CharSet.Ansi, BestFitMapping = false, CallingConvention = CallingConvention.Winapi)]
117 | public static extern IntPtr GetProcAddress(IntPtr module, string proc);
118 |
119 | [DllImport("kernel32.dll", ExactSpelling = true, SetLastError = false)]
120 | public static extern bool CloseHandle(IntPtr hObject);
121 |
122 | [DllImport("kernel32.dll", ExactSpelling = true, SetLastError = false)]
123 | public static extern bool TerminateProcess(IntPtr processHandle, int exitCode);
124 |
125 | [DllImport("kernel32.dll", ExactSpelling = true, CallingConvention = CallingConvention.Winapi, SetLastError = false)]
126 | public static extern bool K32EnumProcesses(IntPtr buffer, int bufferSize, out int realSize);
127 |
128 | [DllImport("kernel32.dll", ExactSpelling = true, CallingConvention = CallingConvention.Winapi, SetLastError = false)]
129 | public static extern bool K32EnumProcessModulesEx(
130 | [In] IntPtr hProcess,
131 | [In, Out] IntPtr lphModule,
132 | [In] int cb,
133 | [Out] out int lpcbNeeded,
134 | [In] int dwFilterFlag);
135 |
136 | [DllImport("kernel32.dll", ExactSpelling = true, CharSet = CharSet.Unicode, CallingConvention = CallingConvention.Winapi, SetLastError = false)]
137 | public static extern int K32GetMappedFileNameW([In] IntPtr hProcess, [In] IntPtr hModule, [In, Out] char[] lpFilename, [In] int nSize);
138 |
139 | [DllImport("kernel32.dll", ExactSpelling = true, CallingConvention = CallingConvention.Winapi, SetLastError = false)]
140 | public static extern int GetProcessId(IntPtr hProcess);
141 |
142 | [DllImport("ntdll.dll", ExactSpelling = true, SetLastError = false, CallingConvention = CallingConvention.Winapi)]
143 | public static extern uint NtUnmapViewOfSection(IntPtr hProcess, IntPtr baseAddress);
144 |
145 |
146 | [DllImport("advapi32.dll", ExactSpelling = true, SetLastError = false)]
147 | public static extern bool OpenProcessToken(IntPtr processHandle, int desiredAccess, out IntPtr tokenHandle);
148 | [DllImport("advapi32.dll", ExactSpelling = true, CharSet = CharSet.Unicode, SetLastError = false)]
149 | public static extern bool LookupPrivilegeValueW(string lpSystemName, string lpName, out LUID lpLuid);
150 | [DllImport("advapi32.dll", ExactSpelling = true, SetLastError = false)]
151 | public static extern bool AdjustTokenPrivileges(IntPtr tokenHandle, bool disableAllPrivileges, SingleTokenPrivilegeOn NewState, int bufferLength, IntPtr previousState, IntPtr returnLength);
152 |
153 |
154 | // ========================================= thread ===================================================
155 |
156 | //[DllImport("kernel32.dll", ExactSpelling = true, SetLastError = false, CallingConvention = CallingConvention.Winapi)]
157 | //public static extern unsafe SafeWaitHandle CreateRemoteThread(IntPtr hProcess, IntPtr lpThreadAttributes, IntPtr dwStackSize, IntPtr lpStartAddress, void* lpParameter, int dwCreationFlags, out int threadID);
158 |
159 | //[DllImport("kernel32.dll", ExactSpelling = true, SetLastError = false, CallingConvention = CallingConvention.Winapi)]
160 | //public static extern WaitObjectResult WaitForSingleObject([In] IntPtr hHandle, [In] int dwMilliseconds);
161 |
162 | //[DllImport("kernel32.dll", ExactSpelling = true, SetLastError = false, CallingConvention = CallingConvention.Winapi)]
163 | //[return: MarshalAs(UnmanagedType.Bool)]
164 | //public static extern bool TerminateThread(IntPtr hThread, int dwExitCode);
165 |
166 |
167 |
168 | // =========================================restart manager ===================================================
169 |
170 | [DllImport("rstrtmgr.dll", ExactSpelling = true, CharSet = CharSet.Unicode)]
171 | public static extern int RmStartSession(out uint pSessionHandle, uint dwSessionFlags, char[] strSessionKey);
172 | [DllImport("rstrtmgr.dll", ExactSpelling = true, CharSet = CharSet.Unicode)]
173 | public static extern int RmRegisterResources(uint dwSessionHandle, int nFiles, string[] rgsFilenames, uint nApplications, RmUniqueProcess[] rgApplications, uint nServices, string[] rgsServiceNames);
174 | [DllImport("rstrtmgr.dll", ExactSpelling = true, CharSet = CharSet.Unicode)]
175 | public static extern int RmGetList(uint dwSessionHandle, out uint pnProcInfoNeeded, ref uint pnProcInfo, [Out] RmProcessInfo[] rgAffectedApps, out RmRebootReason lpdwRebootReasons);
176 | [DllImport("rstrtmgr.dll", ExactSpelling = true)]
177 | public static extern int RmEndSession(uint pSessionHandle);
178 |
179 | }
180 | }
181 |
--------------------------------------------------------------------------------
/src/DelApp/Internals/NativeWin32/RmStructs.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Runtime.InteropServices;
3 |
4 | namespace DelApp.Internals.Win32
5 | {
6 | [StructLayout(LayoutKind.Sequential)]
7 | internal struct RmUniqueProcess
8 | {
9 | public int ProcessId;
10 | public System.Runtime.InteropServices.ComTypes.FILETIME ProcessStartTime;
11 | }
12 |
13 | internal enum RmAppType
14 | {
15 | RmUnknownApp = 0,
16 | RmMainWindow = 1,
17 | RmOtherWindow = 2,
18 | RmService = 3,
19 | RmExplorer = 4,
20 | RmConsole = 5,
21 | RmCritical = 1000
22 | }
23 |
24 | [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
25 | internal unsafe struct RmProcessInfo
26 | {
27 | public RmUniqueProcess Process;
28 | //CCH_RM_MAX_APP_NAME+1
29 | private fixed char ApplicationName[256];
30 | //CCH_RM_MAX_SVC_NAME+1
31 | private fixed char ServiceShortName[64];
32 | public RmAppType ApplicationType;
33 | public RmAppStatus AppStatus;
34 | public int TSSessionId;
35 | public bool bRestartable;
36 | public static int Size => Marshal.SizeOf(typeof(RmProcessInfo));
37 | }
38 | [Flags]
39 | internal enum RmRebootReason
40 | {
41 | None = 0x0,
42 | PermissionDenied = 0x1,
43 | SessionMismatch = 0x2,
44 | CriticalProcess = 0x4,
45 | CriticalService = 0x8,
46 | DetectedSelf = 0x10
47 | }
48 |
49 | [Flags]
50 | internal enum RmAppStatus
51 | {
52 | RmStatusUnknown = 0x0,
53 | RmStatusRunning = 0x1,
54 | RmStatusStopped = 0x2,
55 | RmStatusStoppedOther = 0x4,
56 | RmStatusRestarted = 0x8,
57 | RmStatusErrorOnStop = 0x10,
58 | RmStatusErrorOnRestart = 0x20,
59 | RmStatusShutdownMasked = 0x40,
60 | RmStatusRestartMasked = 0x80
61 | }
62 |
63 |
64 | }
65 |
--------------------------------------------------------------------------------
/src/DelApp/Internals/NativeWin32/SHSTOCKICONINFO.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Runtime.InteropServices;
3 |
4 | namespace DelApp.Internals.Win32
5 | {
6 | [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
7 | public unsafe struct SHSTOCKICONINFO
8 | {
9 | public uint cbSize;
10 | public IntPtr hIcon;
11 | public int iSysIconIndex;
12 | public int iIcon;
13 | public fixed char szPath[260];
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/src/DelApp/Internals/NativeWin32/SingleTokenPrivilegeOn.cs:
--------------------------------------------------------------------------------
1 | using System.Runtime.InteropServices;
2 |
3 | namespace DelApp.Internals.Win32
4 | {
5 | [StructLayout(LayoutKind.Sequential)]
6 | internal class SingleTokenPrivilegeOn
7 | {
8 | public readonly int PrivilegeCount = 1;
9 | public LUID Luid;
10 | public readonly int Attributes = 2;
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/src/DelApp/Internals/NativeWin32/SysInfo.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Runtime.InteropServices;
3 |
4 | namespace DelApp.Internals.Win32
5 | {
6 | [StructLayout(LayoutKind.Sequential, Pack = 2)]
7 | internal sealed class SysInfo
8 | {
9 | private readonly uint _oemId;
10 |
11 | public readonly int PageSize;
12 |
13 | public readonly IntPtr MinimumApplicationAddress;
14 |
15 | public readonly IntPtr MaximumApplicationAddress;
16 |
17 | public readonly IntPtr ActiveProcessorMask;
18 |
19 | public readonly int NumberOfProcessors;
20 |
21 | public readonly int OrgProcessorType;
22 |
23 | public readonly int AllocationGranularity;
24 |
25 | public readonly short ProcessorLevel;
26 |
27 | public readonly short ProcessorRevision;
28 |
29 |
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/src/DelApp/Internals/NativeWin32/WaitObjectResult.cs:
--------------------------------------------------------------------------------
1 | namespace DelApp.Internals.Win32
2 | {
3 |
4 | internal enum WaitObjectResult : uint
5 | {
6 | WAIT_OBJECT_0 = 0x00000000,
7 | WAIT_TIMEOUT = 0x00000102,
8 | WAIT_FAILED = 0xFFFFFFFF,
9 | WAIT_ABANDONED = 0x00000080
10 | }
11 | }
12 |
--------------------------------------------------------------------------------
/src/DelApp/Internals/NativeWin32/Win32FindData.cs:
--------------------------------------------------------------------------------
1 | using System.IO;
2 | using System.Runtime.InteropServices;
3 |
4 | namespace DelApp.Internals.Win32
5 | {
6 | [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
7 | [BestFitMapping(false)]
8 | internal unsafe struct Win32FindData
9 | {
10 | public readonly FileAttributes FileAttributes;
11 | private readonly System.Runtime.InteropServices.ComTypes.FILETIME ftCreationTime;
12 | private readonly System.Runtime.InteropServices.ComTypes.FILETIME ftLastAccessTime;
13 | private readonly System.Runtime.InteropServices.ComTypes.FILETIME ftLastWriteTime;
14 | private readonly uint FileSizeHigh;
15 | private readonly uint FileSizeLow;
16 | private readonly uint dwReserved0;
17 | private readonly uint dwReserved1;
18 | private fixed char cFileName[260];
19 | private fixed char _cAlternateFileName[14];
20 | internal string CFileName { get { fixed (char* c = cFileName) return new string(c); } }
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/src/DelApp/Internals/ObjPool.cs:
--------------------------------------------------------------------------------
1 | using System.Collections.Concurrent;
2 | using System.Collections.Generic;
3 |
4 | namespace DelApp.Internals
5 | {
6 | internal static class ObjPool
7 | {
8 | public const int CharBufferSize = 32767;
9 |
10 | private static readonly ConcurrentBag s_chars_pool = new ConcurrentBag();
11 | private static readonly ConcurrentBag> s_stringList_pool = new ConcurrentBag>();
12 |
13 | public static char[] RentCharBuffer() => s_chars_pool.TryTake(out char[] buffer) ? buffer : new char[CharBufferSize];
14 | public static void ReturnCharBuffer(char[] buffer) => s_chars_pool.Add(buffer);
15 |
16 | public static List RentFDList() => s_stringList_pool.TryTake(out List list) ? list : new List(512);
17 | public static void ReturnFDList(List list)
18 | {
19 | list.Clear();
20 | s_stringList_pool.Add(list);
21 | }
22 |
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/src/DelApp/Internals/PeReader.cs:
--------------------------------------------------------------------------------
1 | //using System;
2 | //using System.Collections.Generic;
3 | //using System.IO;
4 | //using System.Linq;
5 | //using System.Runtime.InteropServices;
6 | //using System.Runtime.InteropServices.ComTypes;
7 | //using System.Text;
8 | //using System.Threading.Tasks;
9 |
10 | //namespace DelApp.Internals
11 | //{
12 | // internal class PeReader : IDisposable
13 | // {
14 | // private const int BUFFER_SIZE = 4096;
15 |
16 | // private readonly byte[] _buf;
17 |
18 | // private Stream _stream;
19 |
20 | // public PeReader(string dllPath)
21 | // {
22 | // _stream = new FileStream(dllPath, FileMode.Open, FileAccess.Read, FileShare.Read);
23 | // _buf = new byte[BUFFER_SIZE];
24 | // _stream.Read(_buf, 0, BUFFER_SIZE);
25 | // }
26 |
27 | // public T Read(long pos)
28 | // where T : unmanaged
29 | // {
30 | // int offset = GetBufferOffset(pos, Marshal.SizeOf());
31 | // unsafe
32 | // {
33 | // fixed (byte* p = _buf)
34 | // return *(T*)(p + offset);
35 | // }
36 | // }
37 |
38 | // public string ReadStringAnsi(long pos)
39 | // {
40 | // the max length of function name is 4096
41 | // int offset = GetBufferOffset(pos, BUFFER_SIZE);
42 | // int i = offset;
43 | // unsafe
44 | // {
45 | // fixed (byte* p = _buf)
46 | // {
47 | // while (i < BUFFER_SIZE)
48 | // {
49 | // if (p[i] == 0)
50 | // {
51 | // return new string((sbyte*)p, offset, i - offset, Encoding.ASCII);
52 | // }
53 | // ++i;
54 | // }
55 | // }
56 | // throw new NotSupportedException();
57 | // }
58 | // }
59 |
60 | // public bool EqualsStringAnsi(long pos, string str)
61 | // {
62 | // int length = str.Length;
63 | // int offset = GetBufferOffset(pos, length + 1);
64 | // unsafe
65 | // {
66 | // fixed (byte* ptrBuf = _buf)
67 | // fixed (char* ptrStr = str)
68 | // {
69 | // int i = 0;
70 | // byte* strInByte = ptrBuf + offset;
71 | // while (i < length)
72 | // {
73 | // if (strInByte[i] != ptrStr[i])
74 | // return false;
75 | // ++i;
76 | // }
77 | // if (strInByte[i] != 0)
78 | // return false;
79 | // }
80 | // return true;
81 | // }
82 | // }
83 |
84 |
85 | // public int[] GetFunctionOffset(params string[] functionNames)
86 | // {
87 | // int addressOfNewExeHeader = Read(0x3C);
88 | // int optionalHeaderOffset = addressOfNewExeHeader + 0x04 + 0x14;
89 | // ushort magic = Read(optionalHeaderOffset);
90 | // int exportTableOffset = GetOptionalHeaderDataOffset(magic) + optionalHeaderOffset;
91 | // int exportTableRav = Read(exportTableOffset);
92 | // int numberOfSections = Read(addressOfNewExeHeader + 0x04 + 0x02);
93 | // int sectionOffset = optionalHeaderOffset + Read(addressOfNewExeHeader + 0x04 + 0x10);
94 | // if (!GetRavRelation(
95 | // numberOfSections,
96 | // sectionOffset,
97 | // rav: exportTableRav,
98 | // out int va,
99 | // out int pra,
100 | // out int foa))
101 | // {
102 | // return Array.Empty();
103 | // }
104 | // int numOfFunName = Read(foa + 0x18);
105 | // int addrOfFun = Read(foa + 0x1C);
106 | // int addrOfFunName = Read(foa + 0x20);
107 | // int orderOfFun = Read(foa + 0x24);
108 | // return SearchFuncs(numOfFunName, addrOfFunName, orderOfFun, addrOfFun, va, pra, functionNames);
109 | // }
110 |
111 | // protected virtual int GetOptionalHeaderDataOffset(ushort magic)
112 | // {
113 | // switch (magic)
114 | // {
115 | // case 0x10b:
116 | // return 0x60;
117 | // default: //0x20b
118 | // return 0x70;
119 | // }
120 | // }
121 |
122 | // private bool GetRavRelation(int numberOfSections, int sectionOffset, int rav, out int va, out int pra, out int foa)
123 | // {
124 | // pra = foa = 0;
125 | // sectionOffset += 0x0C;
126 | // int count = 0;
127 | // va = Read(sectionOffset);
128 | // int sra = Read(sectionOffset + 4);
129 | // while (count < numberOfSections &&
130 | // (va + sra) < rav)
131 | // {
132 | // sectionOffset += 0x28;
133 | // va = Read(sectionOffset);
134 | // sra = Read(sectionOffset + 4);
135 | // ++count;
136 | // }
137 | // if (count == numberOfSections)
138 | // return false;
139 | // pra = Read(sectionOffset + 8);
140 | // foa = rav - va + pra;
141 | // return true;
142 | // }
143 |
144 | // private int[] SearchFuncs(int funcCount, int startFuncName, int startFuncOrder, int startFuncAddr, int va, int pra, params string[] functionNames)
145 | // {
146 | // int funcFoa;
147 | // int found = 0;
148 | // int offset = pra - va;
149 | // int searchLength = functionNames.Length;
150 | // int[] result = null;
151 | // startFuncName += offset;
152 | // startFuncOrder += offset;
153 | // startFuncAddr += offset;
154 | // for (int i = 0; i < funcCount; i++)
155 | // {
156 | // funcFoa = Read(startFuncName + (i << 2)) + offset;
157 | // for (int j = 0; j < searchLength; j++)
158 | // {
159 | // if (EqualsStringAnsi(funcFoa, functionNames[j]))
160 | // {
161 | // if (result == null)
162 | // result = new int[searchLength];
163 |
164 | // var off = Read(startFuncOrder + (i << 1));
165 | // result[j] = Read(startFuncAddr + (off << 2));
166 | // ++found;
167 | // if (found == searchLength)
168 | // return result;
169 | // }
170 | // }
171 | // }
172 | // return Array.Empty();
173 | // }
174 |
175 | // private int GetBufferOffset(long pos, int size)
176 | // {
177 | // long streamPos = _stream.Position;
178 | // if (pos + size > streamPos ||
179 | // pos < streamPos - BUFFER_SIZE)
180 | // {
181 | // _stream.Seek(pos, SeekOrigin.Begin);
182 | // _stream.Read(_buf, 0, BUFFER_SIZE);
183 | // }
184 | // return (int)(pos - _stream.Position + BUFFER_SIZE);
185 | // }
186 |
187 | // protected virtual void Dispose(bool disposing)
188 | // {
189 | // if (_stream != null)
190 | // {
191 | // if (disposing)
192 | // _stream.Dispose();
193 | // _stream = null;
194 | // }
195 | // }
196 |
197 | // public void Dispose()
198 | // {
199 | // Dispose(disposing: true);
200 | // GC.SuppressFinalize(this);
201 | // }
202 | // }
203 | //}
204 |
--------------------------------------------------------------------------------
/src/DelApp/Internals/PipeService.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Concurrent;
3 | using System.Collections.Generic;
4 | using System.IO.Pipes;
5 | using System.Text;
6 | using System.Threading;
7 | using System.Windows.Forms;
8 |
9 | namespace DelApp.Internals
10 | {
11 | internal static class PipeService
12 | {
13 | private const int DEFALUT_BYTES_BUFFER_SIZE = 32767 * 2;
14 |
15 |
16 | public static event EventHandler PathRecived;
17 |
18 | public static ConcurrentQueue PathQueue = new ConcurrentQueue();
19 |
20 |
21 | public static bool CreateService()
22 | {
23 | return ThreadPool.QueueUserWorkItem(ServiceCoreAsync);
24 | }
25 |
26 | public static void SendPath(IEnumerable pathes)
27 | {
28 | using (var pipeClient = new NamedPipeClientStream(".", Utils.MyGuidString, PipeDirection.Out))
29 | {
30 | var lenBuf = new byte[4];
31 | var buffer = new byte[DEFALUT_BYTES_BUFFER_SIZE];
32 | int len;
33 | try
34 | {
35 | pipeClient.Connect();
36 | unsafe
37 | {
38 | fixed (byte* p = lenBuf)
39 | {
40 | foreach (var item in pathes)
41 | {
42 | len = Encoding.Unicode.GetBytes(item, 0, item.Length, buffer, 0);
43 | *(int*)p = len;
44 | pipeClient.Write(lenBuf, 0, 4);
45 | pipeClient.Write(buffer, 0, len);
46 | }
47 | }
48 | }
49 | pipeClient.WaitForPipeDrain();
50 | }
51 | catch
52 | {
53 | }
54 | }
55 | }
56 |
57 | private static async void ServiceCoreAsync(object stateInfo)
58 | {
59 | using (var pipeServer = new NamedPipeServerStream(Utils.MyGuidString, PipeDirection.In))
60 | {
61 | var lenBuf = new byte[4];
62 | var buffer = new byte[DEFALUT_BYTES_BUFFER_SIZE];
63 | int len;
64 | string path;
65 | while (true)
66 | {
67 | try
68 | {
69 | if (!pipeServer.IsConnected)
70 | await pipeServer.WaitForConnectionAsync().ConfigureAwait(false);
71 |
72 | unsafe
73 | {
74 | fixed (byte* p = lenBuf)
75 | {
76 | while (pipeServer.Read(lenBuf, 0, 4) == 4)
77 | {
78 | len = *(int*)p;
79 | if (pipeServer.Read(buffer, 0, len) == len)
80 | PathQueue.Enqueue(new FileNDir(Encoding.Unicode.GetString(buffer, 0, len)));
81 | }
82 | PathRecived?.Invoke(PathQueue, EventArgs.Empty);
83 | }
84 | }
85 | }
86 | catch (Exception ecx)
87 | {
88 | Utils.WriteErrorLog(ecx.Message);
89 | }
90 | finally
91 | {
92 | try
93 | {
94 | pipeServer.Disconnect();
95 | }
96 | catch (Exception ecx2)
97 | {
98 | Utils.WriteErrorLog(ecx2.Message);
99 | }
100 | }
101 | }
102 | }
103 | }
104 |
105 |
106 | }
107 | }
108 |
--------------------------------------------------------------------------------
/src/DelApp/Internals/ProcessModuleLite.cs:
--------------------------------------------------------------------------------
1 | //using DelApp.Internals.Win32;
2 | //using Microsoft.Win32.SafeHandles;
3 | //using System;
4 | //using System.Collections.Generic;
5 | //using System.ComponentModel;
6 | //using System.Linq;
7 | //using System.Reflection;
8 | //using System.Text;
9 | //using System.Threading.Tasks;
10 |
11 | //namespace DelApp.Internals
12 | //{
13 | // internal class ProcessModuleLite
14 | // {
15 | // private const int LIST_MODULES_ALL = 0x03;
16 |
17 | // private ProcessModuleLite(int index, IntPtr baseAddr, string path)
18 | // {
19 | // Index = index;
20 | // BaseAddr = baseAddr;
21 | // Path = path;
22 | // }
23 | // public readonly int Index;
24 | // public readonly IntPtr BaseAddr;
25 | // public readonly string Path;
26 |
27 | // public override string ToString() => Path;
28 |
29 |
30 | // public static IEnumerable GetModules(SafeProcessHandle handle)
31 | // {
32 | // IntPtr proc = handle.DangerousGetHandle();
33 | // if (!NativeMethods.K32EnumProcessModulesEx(proc, null, 0, out int cbNeed, LIST_MODULES_ALL))
34 | // {
35 | // handle.Dispose();
36 | // yield break;
37 | // }
38 | // int moudleCount = cbNeed / IntPtr.Size;
39 | // var handleArray = new IntPtr[moudleCount];
40 | // bool success;
41 | // while ((success = NativeMethods.K32EnumProcessModulesEx(proc, handleArray, cbNeed, out int newCb, LIST_MODULES_ALL)) &&
42 | // cbNeed != newCb)
43 | // {
44 | // moudleCount = newCb / IntPtr.Size;
45 | // handleArray = new IntPtr[moudleCount];
46 | // }
47 | // if (!success)
48 | // {
49 | // handle.Dispose();
50 | // yield break;
51 | // }
52 |
53 | // char[] buffer = ObjPool.RentCharBuffer();
54 | // IntPtr h;
55 | // int clen;
56 | // for (int i = 0; i < moudleCount; i++)
57 | // {
58 | // h = handleArray[i];
59 | // clen = NativeMethods.K32GetMappedFileName(proc, h, buffer, buffer.Length);
60 | // if (clen == 0)
61 | // {
62 | // handle.Dispose();
63 | // ObjPool.ReturnCharBuffer(buffer);
64 | // yield break;
65 | // }
66 | // yield return new ProcessModuleLite(i, h, InternelDriveInfo.GetNtPathFromDosPath(buffer, clen));
67 | // }
68 | // ObjPool.ReturnCharBuffer(buffer);
69 | // }
70 | // }
71 | //}
72 |
--------------------------------------------------------------------------------
/src/DelApp/Internals/RemoteFunction.cs:
--------------------------------------------------------------------------------
1 | //using DelApp.Internals.Win32;
2 | //using Microsoft.Win32.SafeHandles;
3 | //using System;
4 | //using System.CodeDom;
5 | //using System.Collections.Generic;
6 | //using System.Diagnostics;
7 | //using System.Drawing;
8 | //using System.IO;
9 | //using System.Linq;
10 | //using System.Runtime.InteropServices;
11 | //using System.Runtime.InteropServices.ComTypes;
12 | //using System.Security.Cryptography;
13 | //using System.Text;
14 | //using System.Threading.Tasks;
15 |
16 | //namespace DelApp.Internals
17 | //{
18 | // internal static class RemoteFunction
19 | // {
20 | // public const int INFINITE_INT = -1;
21 |
22 | // private static readonly string s_ntdllPath32;
23 |
24 | // private static readonly IntPtr s_ldrUnloadDllAnyCpu;
25 |
26 |
27 |
28 | // static RemoteFunction()
29 | // {
30 | // s_ldrUnloadDllAnyCpu = NativeMethods.GetProcAddress(NativeMethods.GetModuleHandle("ntdll.dll"), "LdrUnloadDll");
31 | // s_ntdllPath32 = FileNDir.GetFullPath(Environment.GetFolderPath(Environment.SpecialFolder.SystemX86) + "\\ntdll.dll");
32 | // if (Environment.Is64BitProcess)
33 | // {
34 | // using (var pe = new PeReader(s_ntdllPath32))
35 | // {
36 | // int[] ints = pe.GetFunctionOffset("LdrUnloadDll");
37 | // s_ldrUnloadDllOffset32 = ints.Length != 0 ? ints[0] : 0;
38 | // }
39 | // s_ntdllBaseAddress32 = IntPtr.Zero;
40 | // }
41 | // else
42 | // {
43 | // Any cpu
44 | // s_ldrUnloadDllOffset32 = -1;
45 | // s_ntdllBaseAddress32 = s_ldrUnloadDllAnyCpu;
46 | // }
47 | // }
48 |
49 |
50 | // public static async Task CallRemoteFunctionAsync(IntPtr proc, IntPtr func, TParam arg, int millisecondTimeout = INFINITE_INT)
51 | // where TParam : unmanaged
52 | // {
53 | // return await Task.FromResult(CallRemoteFunction(proc, func, arg, millisecondTimeout)).ConfigureAwait(false);
54 | // }
55 |
56 | // public static WaitObjectResult CallRemoteFunction(IntPtr proc, IntPtr func, TParam arg, int millisecondTimeout = INFINITE_INT)
57 | // where TParam : unmanaged
58 | // {
59 | // unsafe
60 | // {
61 | // using (SafeWaitHandle hHandle = NativeMethods.CreateRemoteThread(
62 | // proc, //process handle
63 | // IntPtr.Zero,
64 | // IntPtr.Zero,
65 | // func, //address
66 | // &arg, // pointer to param
67 | // 0, out _))
68 | // {
69 | // if (hHandle.IsInvalid)
70 | // return WaitObjectResult.WAIT_FAILED;
71 | // WaitObjectResult waitResult = NativeMethods.WaitForSingleObject(hHandle.DangerousGetHandle(), millisecondTimeout);
72 | // if (waitResult == WaitObjectResult.WAIT_TIMEOUT ||
73 | // waitResult == WaitObjectResult.WAIT_ABANDONED)
74 | // NativeMethods.TerminateThread(hHandle.DangerousGetHandle(), 0);
75 | // return waitResult;
76 |
77 | // }
78 | // }
79 | // }
80 |
81 |
82 | // }
83 | //}
84 |
--------------------------------------------------------------------------------
/src/DelApp/Internals/RestartManagerHelper.cs:
--------------------------------------------------------------------------------
1 | using DelApp.Internals.Win32;
2 | using System;
3 | using System.Linq;
4 |
5 | namespace DelApp.Internals
6 | {
7 | //Unfortunately, RM DO NOT Supports folder.
8 |
9 | // The max count of the RestartManager's session is 64.
10 | internal sealed class RestartManagerHelper : DisposableSingleton
11 | {
12 | private const int ERROR_MORE_DATA = 234;
13 |
14 | private readonly uint _handle;
15 |
16 | private RestartManagerHelper()
17 | {
18 | if (NativeMethods.RmStartSession(out _handle, 0, Utils.MyGuidStringWithNullChar) != 0)
19 | _handle = 0;
20 | }
21 |
22 | public int[] GetHolderList(out RmRebootReason reason, params string[] fileNames)
23 | {
24 | reason = RmRebootReason.None;
25 | if (NativeMethods.RmRegisterResources(
26 | _handle,
27 | fileNames.Length, fileNames,
28 | 0, null,
29 | 0, null) != 0)
30 | return Array.Empty();
31 |
32 | RmProcessInfo[] affectedApps = null;
33 | uint nCount = 0;
34 | int err;
35 | while ((err = NativeMethods.RmGetList(_handle, out var nlength, ref nCount, affectedApps, out reason)) == ERROR_MORE_DATA)
36 | {
37 | affectedApps = new RmProcessInfo[nlength];
38 | nCount = (uint)affectedApps.Length;
39 | }
40 | return err == 0 ? affectedApps.Select(rmi => rmi.Process.ProcessId).ToArray() : Array.Empty();
41 | }
42 |
43 |
44 | protected override void DisposeManaged() { }
45 |
46 | protected override void DisposeUnmanaged()
47 | {
48 | if (_handle != 0)
49 | NativeMethods.RmEndSession(_handle);
50 | }
51 |
52 | }
53 | }
54 |
--------------------------------------------------------------------------------
/src/DelApp/Internals/RightClickMenuHelper.cs:
--------------------------------------------------------------------------------
1 | using DelApp.Locals;
2 | using Microsoft.Win32;
3 | using System.Windows.Forms;
4 |
5 | namespace DelApp.Internals
6 | {
7 | internal static class RightClickMenuHelper
8 | {
9 |
10 | private static readonly string s_dir_subkey = $"Directory\\shell\\{Utils.MyGuidString}\\command";
11 | private static readonly string s_file_subkey = $"*\\shell\\{Utils.MyGuidString}\\command";
12 | private static readonly string s_open_command = $"{Application.ExecutablePath} \"%L\"";
13 |
14 | public static bool HasRightClickMenu
15 | {
16 | get => GetHasRightMenu();
17 | set
18 | {
19 | if (value)
20 | AddRightClickMenu();
21 | else
22 | RemoveRightClickMenu();
23 | }
24 | }
25 |
26 | private static bool GetHasRightMenu()
27 | {
28 | using (RegistryKey regRoot0 = Registry.ClassesRoot.OpenSubKey("Directory\\shell", true),
29 | regRoot1 = Registry.ClassesRoot.OpenSubKey("*\\shell", true))
30 | {
31 | if (!GetHasRightMenuCore(regRoot0))
32 | return false;
33 | else if (!GetHasRightMenuCore(regRoot1))
34 | {
35 | RemoveRightClickMenuCore(regRoot0);
36 | return false;
37 | }
38 | else
39 | return true;
40 | }
41 | }
42 |
43 |
44 | private static bool GetHasRightMenuCore(RegistryKey regRoot)
45 | {
46 | using (RegistryKey regshell = regRoot?.OpenSubKey(Utils.MyGuidString, true))
47 | {
48 | if (regshell == null)
49 | return false;
50 | regshell.SetValue(null, AppLanguageService.LanguageProvider.Shell_RightClickContextText);
51 | regshell.SetValue("icon", Application.ExecutablePath);
52 | using (RegistryKey regCmd = regshell.CreateSubKey("command"))
53 | {
54 | if (regCmd == null)
55 | {
56 | regRoot.DeleteSubKeyTree(Utils.MyGuidString);
57 | return false;
58 | }
59 | regCmd.SetValue(null, s_open_command);
60 | }
61 | }
62 | return true;
63 | }
64 |
65 | // Do not need set value, since we always invokes HasRightClickMenu_get .
66 | private static void AddRightClickMenu()
67 | {
68 | using (RegistryKey regRoot = Registry.ClassesRoot.CreateSubKey(s_dir_subkey, true))
69 | {
70 | }
71 | using (RegistryKey regRoot = Registry.ClassesRoot.CreateSubKey(s_file_subkey, true))
72 | {
73 | }
74 | }
75 |
76 | private static void RemoveRightClickMenu()
77 | {
78 | using (RegistryKey regRoot0 = Registry.ClassesRoot.OpenSubKey("Directory\\shell", true),
79 | regRoot1 = Registry.ClassesRoot.OpenSubKey("*\\shell", true))
80 | {
81 | RemoveRightClickMenuCore(regRoot0);
82 | RemoveRightClickMenuCore(regRoot1);
83 | }
84 | }
85 |
86 | private static void RemoveRightClickMenuCore(RegistryKey regRoot)
87 | {
88 | using (RegistryKey regshell = regRoot?.OpenSubKey(Utils.MyGuidString, true))
89 | {
90 | if (regshell != null)
91 | regRoot.DeleteSubKeyTree(Utils.MyGuidString);
92 | }
93 | }
94 | }
95 | }
96 |
--------------------------------------------------------------------------------
/src/DelApp/Internals/SoundPlayHelper.cs:
--------------------------------------------------------------------------------
1 | using Microsoft.Win32;
2 | using System;
3 | using System.IO;
4 | using System.Media;
5 |
6 |
7 | namespace DelApp.Internals
8 | {
9 | // The large object heap threshold is 85K which is smaller than ths size of media file.
10 | // Singleton pattern can avoid repeatedly allocate memory.
11 | internal sealed class SoundPlayHelper : DisposableSingleton
12 | {
13 | private SoundPlayer _player;
14 |
15 | private SoundPlayHelper()
16 | {
17 | try
18 | {
19 | // returns null if not found.
20 | string soundPath = GetSoundPath();
21 |
22 | if (soundPath != null)
23 | {
24 | _player = new SoundPlayer(soundPath);
25 | _player.Load();
26 | }
27 |
28 |
29 | }
30 | catch (Exception ecx)
31 | {
32 | Utils.WriteErrorLog(ecx.Message);
33 | if (_player != null)
34 | {
35 | _player.Dispose();
36 | _player = null;
37 | }
38 | }
39 | }
40 |
41 |
42 | public void TryPlayEmptyRecyclebin(bool isAsync)
43 | {
44 | if (_player != null)
45 | {
46 | try
47 | {
48 | if (isAsync)
49 | _player.Play();
50 | else
51 | _player.PlaySync();
52 | }
53 | catch (Exception ecx)
54 | {
55 | Utils.WriteErrorLog(ecx.Message);
56 | }
57 | }
58 | }
59 |
60 |
61 | protected override void DisposeManaged() => _player?.Dispose();
62 |
63 | protected override void DisposeUnmanaged() => _player = null;
64 |
65 |
66 | // returns null if not found.
67 | private static string GetSoundPath()
68 | {
69 | // read path from registery
70 | using (RegistryKey reg = Registry.CurrentUser.OpenSubKey(@"AppEvents\Schemes\Apps\Explorer\EmptyRecycleBin\.Current", false))
71 | {
72 | if (reg == null || !(reg.GetValue(null) is string path))
73 | {
74 | // if not found, try "windows\media\Windows Recycle.wav"
75 | path = Environment.GetFolderPath(Environment.SpecialFolder.Windows);
76 | if (path == string.Empty)
77 | return null;
78 | path += "\\media\\Windows Recycle.wav";
79 | return File.Exists(path) ? path : null;
80 | }
81 | return path;
82 | }
83 | }
84 |
85 |
86 |
87 | }
88 | }
89 |
--------------------------------------------------------------------------------
/src/DelApp/Internals/UnmanagedBuffer.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Runtime.InteropServices;
3 |
4 | namespace DelApp.Internals
5 | {
6 | internal struct UnmanagedBuffer : IDisposable
7 | {
8 | private IntPtr _handle;
9 |
10 | public UnmanagedBuffer(int size)
11 | {
12 | _handle = Marshal.AllocHGlobal(size);
13 | Size = size;
14 | }
15 |
16 | public IntPtr Handle => _handle;
17 |
18 | public int Size { get; private set; }
19 |
20 | public void Resize(int size)
21 | {
22 | Marshal.FreeHGlobal(_handle);
23 | _handle = Marshal.AllocHGlobal(size);
24 | Size = size;
25 | }
26 |
27 | public T Read(int offsetInBytes)
28 | where T : unmanaged
29 | {
30 | unsafe
31 | {
32 | var ptr = (byte*)_handle.ToPointer() + offsetInBytes;
33 | return *(T*)ptr;
34 | }
35 | }
36 |
37 | public long ReadSizeT(int offsetInBytes)
38 | {
39 | unsafe
40 | {
41 | var ptr = (byte*)_handle.ToPointer() + offsetInBytes;
42 | return (*(IntPtr*)ptr).ToInt64();
43 | }
44 | }
45 |
46 | public void Dispose()
47 | {
48 | Marshal.FreeHGlobal(_handle);
49 | }
50 | }
51 | }
52 |
--------------------------------------------------------------------------------
/src/DelApp/Internals/Utils.cs:
--------------------------------------------------------------------------------
1 | using DelApp.Internals.Win32;
2 | using System;
3 | using System.Collections.Generic;
4 | using System.IO;
5 | using System.Reflection;
6 | using System.Runtime.InteropServices;
7 |
8 | namespace DelApp.Internals
9 | {
10 | internal static class Utils
11 | {
12 | private const int TOKEN_ADJUST_PRIVILEGES = 0x20;
13 |
14 | public static readonly string MyGuidString = Marshal.GetTypeLibGuidForAssembly(Assembly.GetExecutingAssembly()).ToString();
15 | public static readonly char[] MyGuidStringWithNullChar = ToCharArrayWithNullChar(MyGuidString);
16 |
17 | public static readonly IntPtr AppProcessHandle = NativeMethods.GetCurrentProcess();
18 | public static readonly int AppProcessId = NativeMethods.GetProcessId(AppProcessHandle);
19 |
20 | public static bool IsWow64Process(IntPtr processHandle) => NativeMethods.IsWow64Process(processHandle, out bool isWow64) && isWow64;
21 |
22 | public static void EnablePrivileges()
23 | {
24 | if (NativeMethods.OpenProcessToken(AppProcessHandle, TOKEN_ADJUST_PRIVILEGES, out IntPtr hToken))
25 | {
26 | var mtkp = new SingleTokenPrivilegeOn();
27 | AddPrivileges(hToken, mtkp, "SeDebugPrivilege");
28 | AddPrivileges(hToken, mtkp, "SeBackupPrivilege");
29 | AddPrivileges(hToken, mtkp, "SeRestorePrivilege");
30 | NativeMethods.CloseHandle(hToken);
31 | }
32 | void AddPrivileges(IntPtr token, SingleTokenPrivilegeOn tkp, string pn)
33 | {
34 | if (NativeMethods.LookupPrivilegeValueW(null, pn, out LUID luid))
35 | {
36 | tkp.Luid = luid;
37 | NativeMethods.AdjustTokenPrivileges(token, false, tkp, 0, IntPtr.Zero, IntPtr.Zero);
38 | }
39 | }
40 | }
41 |
42 | public static string GetPathByFileHandle(IntPtr fileHandle)
43 | {
44 | char[] buffer = ObjPool.RentCharBuffer();
45 | try
46 | {
47 | int len = NativeMethods.GetFinalPathNameByHandleW(fileHandle, buffer, buffer.Length - 1, 0);
48 | if (len == 0)
49 | return null;
50 | return new string(buffer, 4, len - 4);
51 | }
52 | finally
53 | {
54 | ObjPool.ReturnCharBuffer(buffer);
55 | }
56 | }
57 |
58 |
59 |
60 |
61 | public static IEnumerable GetDrapDropFiles(IntPtr hDrop)
62 | {
63 |
64 | int fileCount = GetDragFileCount(hDrop);
65 | if (fileCount <= 0)
66 | goto Final_Drag_Final;
67 | InternelDriveInfo.RefreshDriveCache();
68 | for (uint i = 0; i < fileCount; i++)
69 | {
70 | var file = CreateFromDropItem(hDrop, i);
71 | if (!file.IsDrive && file.Exists)
72 | yield return CreateFromDropItem(hDrop, i);
73 | }
74 | Final_Drag_Final:
75 | NativeMethods.DragFinish(hDrop);
76 |
77 | int GetDragFileCount(IntPtr hd)
78 | {
79 | unsafe
80 | {
81 | return NativeMethods.DragQueryFileW(hd, uint.MaxValue, null, 0);
82 | }
83 | }
84 |
85 | FileNDir CreateFromDropItem(IntPtr hd, uint index)
86 | {
87 | char[] pathBuf = ObjPool.RentCharBuffer();
88 | unsafe
89 | {
90 | fixed (char* p = pathBuf)
91 | {
92 | int len = NativeMethods.DragQueryFileW(hd, index, p, pathBuf.Length);
93 | try
94 | {
95 | return new FileNDir(new string(p, 0, len));
96 | }
97 | finally
98 | {
99 | ObjPool.ReturnCharBuffer(pathBuf);
100 | }
101 | }
102 | }
103 | }
104 | }
105 |
106 |
107 | public static void WriteErrorLog(string info)
108 | {
109 | FileStream fs = null;
110 | StreamWriter sw = null;
111 | try
112 | {
113 | fs = File.Open("DelAppError.log", FileMode.Append);
114 | sw = new StreamWriter(fs);
115 | sw.Write(info);
116 | }
117 | catch { }
118 | finally
119 | {
120 | sw?.Dispose();
121 | fs?.Dispose();
122 | }
123 | }
124 |
125 |
126 |
127 |
128 |
129 |
130 |
131 | private static char[] ToCharArrayWithNullChar(string str)
132 | {
133 | int length = str.Length;
134 | var chaArray = new char[length + 1];
135 | str.CopyTo(0, chaArray, 0, length);
136 | return chaArray;
137 | }
138 |
139 | }
140 | }
141 |
--------------------------------------------------------------------------------
/src/DelApp/Locals/AppLanguageProvider.cs:
--------------------------------------------------------------------------------
1 | namespace DelApp.Locals
2 | {
3 | public abstract class AppLanguageProvider : IAppLanguageProvider
4 | where TSelf : AppLanguageProvider, new()
5 | {
6 |
7 | public static readonly TSelf Instance = new TSelf();
8 |
9 | public abstract string TwoLetterISOLanguageName { get; }
10 |
11 | public abstract int LCID { get; }
12 |
13 | public abstract string UI_File { get; }
14 | public abstract string UI_File_Open { get; }
15 | public abstract string UI_File_RightClickContextMenu { get; }
16 | public abstract string UI_File_SourceCode { get; }
17 | public abstract string UI_File_Exit { get; }
18 |
19 | public abstract string UI_Edit { get; }
20 | public abstract string UI_Edit_RemoveFromList { get; }
21 | public abstract string UI_Edit_ClearList { get; }
22 | public abstract string UI_Edit_FixPath { get; }
23 |
24 | public abstract string UI_FastDelete { get; }
25 | public abstract string UI_Delete { get; }
26 |
27 | public abstract string UI_OpenDialog_Title { get; }
28 | public abstract string UI_OpenDialog_OKButton { get; }
29 | public abstract string UI_OpenDialog_CancelButton { get; }
30 | public abstract string UI_OpenDialog_FastAccess { get; }
31 | public abstract string UI_OpenDialog_FastAccess_Desktop { get; }
32 | public abstract string UI_OpenDialog_FastAccess_Document { get; }
33 | public abstract string UI_OpenDialog_Drives { get; }
34 |
35 | public abstract string Shell_RightClickContextText { get; }
36 |
37 | public abstract string Message_FailToFixPath { get; }
38 | public abstract string Message_Confirmation { get; }
39 | public abstract string Message_NotFullyCompleted { get; }
40 |
41 | public void Register() => AppLanguageService.RegisterLanguageProvider(Instance);
42 |
43 | }
44 | }
45 |
--------------------------------------------------------------------------------
/src/DelApp/Locals/AppLanguageProviderChs.cs:
--------------------------------------------------------------------------------
1 | namespace DelApp.Locals
2 | {
3 | internal sealed class AppLanguageProviderChs : AppLanguageProvider
4 | {
5 | public override string TwoLetterISOLanguageName => "zh";
6 |
7 | public override int LCID => 2052;
8 |
9 | public override string UI_File => "文件";
10 | public override string UI_File_Open => "打开...";
11 | public override string UI_File_RightClickContextMenu => "添加到右键菜单";
12 | public override string UI_File_SourceCode => "源代码";
13 | public override string UI_File_Exit => "退出";
14 |
15 | public override string UI_Edit => "编辑";
16 | public override string UI_Edit_RemoveFromList => "移除项目";
17 | public override string UI_Edit_ClearList => "清空列表";
18 | public override string UI_Edit_FixPath => "修复错误路径";
19 |
20 | public override string UI_FastDelete => "快速删除";
21 | public override string UI_Delete => "删除";
22 |
23 | public override string UI_OpenDialog_Title => "打开...";
24 | public override string UI_OpenDialog_OKButton => "确定";
25 | public override string UI_OpenDialog_CancelButton => "取消";
26 | public override string UI_OpenDialog_FastAccess => "快速访问";
27 | public override string UI_OpenDialog_FastAccess_Desktop => "桌面";
28 | public override string UI_OpenDialog_FastAccess_Document => "我的文档";
29 | public override string UI_OpenDialog_Drives => "驱动器";
30 |
31 | public override string Shell_RightClickContextText => "加入 Delapp 删除列表";
32 |
33 | public override string Message_FailToFixPath => "修复路径失败。";
34 | public override string Message_Confirmation => "我知道我在干啥。";
35 | public override string Message_NotFullyCompleted => "只完成了部分的删除任务。";
36 | }
37 | }
38 |
--------------------------------------------------------------------------------
/src/DelApp/Locals/AppLanguageProviderEn.cs:
--------------------------------------------------------------------------------
1 | namespace DelApp.Locals
2 | {
3 | internal sealed class AppLanguageProviderEn : AppLanguageProvider
4 | {
5 | public override string TwoLetterISOLanguageName => "en";
6 |
7 | public override int LCID => 9;
8 |
9 | public override string UI_File => "File";
10 | public override string UI_File_Open => "Open...";
11 | public override string UI_File_RightClickContextMenu => "Add to right-click menu";
12 | public override string UI_File_SourceCode => "Source code";
13 | public override string UI_File_Exit => "Exit";
14 |
15 | public override string UI_Edit => "Edit";
16 | public override string UI_Edit_RemoveFromList => "Remove from list";
17 | public override string UI_Edit_ClearList => "Clear list";
18 | public override string UI_Edit_FixPath => "Fix invalid path";
19 |
20 | public override string UI_FastDelete => "Fast delete";
21 | public override string UI_Delete => "Delete";
22 |
23 | public override string UI_OpenDialog_Title => "Open...";
24 | public override string UI_OpenDialog_OKButton => "OK";
25 | public override string UI_OpenDialog_CancelButton => "Cancel";
26 | public override string UI_OpenDialog_FastAccess => "Fast Access";
27 | public override string UI_OpenDialog_FastAccess_Desktop => "Desktop";
28 | public override string UI_OpenDialog_FastAccess_Document => "My Documents";
29 | public override string UI_OpenDialog_Drives => "Drives";
30 |
31 | public override string Shell_RightClickContextText => "Delapp - Add to delete-list";
32 |
33 | public override string Message_FailToFixPath => "Fail to fix path.";
34 | public override string Message_Confirmation => "I know what I want to do.";
35 | public override string Message_NotFullyCompleted => "Only part of delete tasks were completed.";
36 | }
37 | }
38 |
--------------------------------------------------------------------------------
/src/DelApp/OpenFileDialogLite.Designer.cs:
--------------------------------------------------------------------------------
1 | namespace DelApp
2 | {
3 | partial class OpenFileDialogLite
4 | {
5 | ///
6 | /// Required designer variable.
7 | ///
8 | private System.ComponentModel.IContainer components = null;
9 |
10 | ///
11 | /// Clean up any resources being used.
12 | ///
13 | /// true if managed resources should be disposed; otherwise, false.
14 | protected override void Dispose(bool disposing)
15 | {
16 | if (disposing && (components != null))
17 | {
18 | components.Dispose();
19 | }
20 | base.Dispose(disposing);
21 | }
22 |
23 | #region Windows Form Designer generated code
24 |
25 | ///
26 | /// Required method for Designer support - do not modify
27 | /// the contents of this method with the code editor.
28 | ///
29 | private void InitializeComponent()
30 | {
31 | this.components = new System.ComponentModel.Container();
32 | System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(OpenFileDialogLite));
33 | this.ButtonOK = new System.Windows.Forms.Button();
34 | this.ButtonCancel = new System.Windows.Forms.Button();
35 | this.ListViewMain = new System.Windows.Forms.ListView();
36 | this.ColumnHeaderBack = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader()));
37 | this.ImageListMain = new System.Windows.Forms.ImageList(this.components);
38 | this.TreeViewMain = new System.Windows.Forms.TreeView();
39 | this.SuspendLayout();
40 | //
41 | // ButtonOK
42 | //
43 | this.ButtonOK.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right)));
44 | this.ButtonOK.DialogResult = System.Windows.Forms.DialogResult.OK;
45 | this.ButtonOK.Location = new System.Drawing.Point(329, 275);
46 | this.ButtonOK.Name = "ButtonOK";
47 | this.ButtonOK.Size = new System.Drawing.Size(75, 23);
48 | this.ButtonOK.TabIndex = 0;
49 | this.ButtonOK.TabStop = false;
50 | this.ButtonOK.Text = "OK";
51 | this.ButtonOK.UseVisualStyleBackColor = true;
52 | this.ButtonOK.Click += new System.EventHandler(this.ButtonOK_Click);
53 | //
54 | // ButtonCancel
55 | //
56 | this.ButtonCancel.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left)));
57 | this.ButtonCancel.DialogResult = System.Windows.Forms.DialogResult.Cancel;
58 | this.ButtonCancel.Location = new System.Drawing.Point(12, 275);
59 | this.ButtonCancel.Name = "ButtonCancel";
60 | this.ButtonCancel.Size = new System.Drawing.Size(75, 23);
61 | this.ButtonCancel.TabIndex = 3;
62 | this.ButtonCancel.Text = "Cancel";
63 | this.ButtonCancel.UseVisualStyleBackColor = true;
64 | //
65 | // ListViewMain
66 | //
67 | this.ListViewMain.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom)
68 | | System.Windows.Forms.AnchorStyles.Left)
69 | | System.Windows.Forms.AnchorStyles.Right)));
70 | this.ListViewMain.Columns.AddRange(new System.Windows.Forms.ColumnHeader[] {
71 | this.ColumnHeaderBack});
72 | this.ListViewMain.FullRowSelect = true;
73 | this.ListViewMain.HideSelection = false;
74 | this.ListViewMain.Location = new System.Drawing.Point(143, 12);
75 | this.ListViewMain.Name = "ListViewMain";
76 | this.ListViewMain.Size = new System.Drawing.Size(261, 253);
77 | this.ListViewMain.TabIndex = 4;
78 | this.ListViewMain.UseCompatibleStateImageBehavior = false;
79 | this.ListViewMain.View = System.Windows.Forms.View.Details;
80 | this.ListViewMain.ColumnClick += new System.Windows.Forms.ColumnClickEventHandler(this.ListViewMain_ColumnClick);
81 | this.ListViewMain.SelectedIndexChanged += new System.EventHandler(this.ListViewMain_SelectedIndexChanged);
82 | this.ListViewMain.MouseDoubleClick += new System.Windows.Forms.MouseEventHandler(this.ListViewMain_MouseDoubleClick);
83 | //
84 | // ColumnHeaderBack
85 | //
86 | this.ColumnHeaderBack.Text = "↑";
87 | //
88 | // ImageListMain
89 | //
90 | this.ImageListMain.ColorDepth = System.Windows.Forms.ColorDepth.Depth8Bit;
91 | this.ImageListMain.ImageSize = new System.Drawing.Size(16, 16);
92 | this.ImageListMain.TransparentColor = System.Drawing.Color.Transparent;
93 | //
94 | // TreeViewMain
95 | //
96 | this.TreeViewMain.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom)
97 | | System.Windows.Forms.AnchorStyles.Left)));
98 | this.TreeViewMain.BorderStyle = System.Windows.Forms.BorderStyle.FixedSingle;
99 | this.TreeViewMain.FullRowSelect = true;
100 | this.TreeViewMain.HideSelection = false;
101 | this.TreeViewMain.Location = new System.Drawing.Point(12, 12);
102 | this.TreeViewMain.Name = "TreeViewMain";
103 | this.TreeViewMain.Size = new System.Drawing.Size(125, 253);
104 | this.TreeViewMain.TabIndex = 5;
105 | this.TreeViewMain.NodeMouseClick += new System.Windows.Forms.TreeNodeMouseClickEventHandler(this.TreeViewMain_NodeMouseClick);
106 | //
107 | // OpenFileDialogLite
108 | //
109 | this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 12F);
110 | this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
111 | this.CancelButton = this.ButtonCancel;
112 | this.ClientSize = new System.Drawing.Size(411, 304);
113 | this.Controls.Add(this.TreeViewMain);
114 | this.Controls.Add(this.ListViewMain);
115 | this.Controls.Add(this.ButtonCancel);
116 | this.Controls.Add(this.ButtonOK);
117 | this.Icon = ((System.Drawing.Icon)(resources.GetObject("$this.Icon")));
118 | this.MaximizeBox = false;
119 | this.MinimizeBox = false;
120 | this.MinimumSize = new System.Drawing.Size(323, 213);
121 | this.Name = "OpenFileDialogLite";
122 | this.ShowInTaskbar = false;
123 | this.StartPosition = System.Windows.Forms.FormStartPosition.CenterParent;
124 | this.Text = "Open...";
125 | this.Load += new System.EventHandler(this.OpenFileDialogLite_Load);
126 | this.ResumeLayout(false);
127 |
128 | }
129 |
130 | #endregion
131 | private System.Windows.Forms.Button ButtonOK;
132 | private System.Windows.Forms.Button ButtonCancel;
133 | private System.Windows.Forms.ListView ListViewMain;
134 | public System.Windows.Forms.ImageList ImageListMain;
135 | private System.Windows.Forms.TreeView TreeViewMain;
136 | private System.Windows.Forms.ColumnHeader ColumnHeaderBack;
137 | }
138 | }
--------------------------------------------------------------------------------
/src/DelApp/OpenFileDialogLite.cs:
--------------------------------------------------------------------------------
1 | using DelApp.Internals;
2 | using DelApp.Locals;
3 | using System;
4 | using System.Collections;
5 | using System.Collections.Generic;
6 | using System.Drawing;
7 | using System.Net.NetworkInformation;
8 | using System.Windows.Forms;
9 |
10 |
11 |
12 |
13 | namespace DelApp
14 | {
15 | internal partial class OpenFileDialogLite : Form
16 | {
17 | private const int FILE_ICON_INDEX = 0;
18 | private const int DIR_ICON_INDEX = 1;
19 |
20 | private static readonly string s_mpath = Application.ExecutablePath;
21 |
22 | private readonly FileNDir _defaultDir;
23 | private FileNDir _currentDir;
24 |
25 | public OpenFileDialogLite()
26 | {
27 | InitializeComponent();
28 |
29 |
30 | IAppLanguageProvider lp = AppLanguageService.LanguageProvider;
31 | Text = lp.UI_OpenDialog_Title;
32 | ButtonOK.Text = lp.UI_OpenDialog_OKButton;
33 | ButtonCancel.Text = lp.UI_OpenDialog_CancelButton;
34 |
35 | ListViewMain.ListViewItemSorter = new ListViewComparer();
36 | ImageListMain.Images.Add("file", FromIconToBitmap(DefaultIcons.FileSmall));
37 | ImageListMain.Images.Add("dir", FromIconToBitmap(DefaultIcons.DirSmall));
38 | ListViewMain.SmallImageList = ImageListMain;
39 | ListViewMain.Columns[0].Width = Screen.PrimaryScreen.WorkingArea.Width;
40 | TreeViewMain.BeginUpdate();
41 | var rootFastAccess = new TreeNode(lp.UI_OpenDialog_FastAccess);
42 | _defaultDir = AddEnvFolder(rootFastAccess, Environment.SpecialFolder.DesktopDirectory, lp.UI_OpenDialog_FastAccess_Desktop);
43 | AddEnvFolder(rootFastAccess, Environment.SpecialFolder.MyDocuments, lp.UI_OpenDialog_FastAccess_Document);
44 | TreeViewMain.Nodes.Add(rootFastAccess);
45 | TreeViewMain.Nodes.Add(lp.UI_OpenDialog_Drives);
46 | TreeViewMain.EndUpdate();
47 |
48 | }
49 |
50 | public List Pathes { get; } = new List();
51 |
52 |
53 |
54 |
55 | internal static void TryAddToList(ListView listview, FileNDir fd, bool check = true)
56 | {
57 | int itemIconIdx;
58 | if (fd.IsFile)
59 | {
60 | itemIconIdx = FILE_ICON_INDEX;
61 | if (check && (s_mpath == fd.FullPath || ListViewContainsFile(listview, fd.FullPath)))
62 | return;
63 | }
64 | else
65 | {
66 | itemIconIdx = DIR_ICON_INDEX;
67 | if (check && (s_mpath.StartsWith(fd.FullPath) || ListViewContainsDir(listview, fd.FullPath)))
68 | return;
69 | }
70 |
71 | var listItem = new ListViewItem(fd.FullPath, itemIconIdx)
72 | {
73 | Tag = fd,
74 | ToolTipText = fd.FullPath
75 | };
76 | listItem.SubItems.Add(fd.FullPath);
77 | listview.Items.Add(listItem);
78 |
79 | }
80 |
81 |
82 | private static bool ListViewContainsFile(ListView listview, string path)
83 | {
84 | ListView.ListViewItemCollection listViewItemCollection = listview.Items;
85 | ListViewItem item;
86 | FileNDir file;
87 | for (int i = 0; i < listViewItemCollection.Count; i++)
88 | {
89 | item = listViewItemCollection[i];
90 | file = item.Tag as FileNDir;
91 | if (file.IsFile)
92 | {
93 | if (item.Text == path)
94 | return true;
95 | }
96 | else if (path.StartsWith(item.Text))
97 | return true;
98 | }
99 | return false;
100 | }
101 |
102 | private static bool ListViewContainsDir(ListView listview, string path)
103 | {
104 | ListView.ListViewItemCollection listViewItemCollection = listview.Items;
105 | ListViewItem item;
106 | FileNDir file;
107 |
108 | int length = listViewItemCollection.Count;
109 | for (int i = 0; i < length; i++)
110 | {
111 | item = listViewItemCollection[i];
112 | file = item.Tag as FileNDir;
113 | if (file.IsFile)
114 | {
115 | if (item.Text.StartsWith(path))
116 | {
117 | listview.Items.RemoveAt(i);
118 | --i;
119 | --length;
120 | }
121 |
122 | }
123 | else
124 | {
125 | if (path.Length >= item.Text.Length)
126 | {
127 | if (path.StartsWith(item.Text))
128 | return true;
129 | }
130 | else if (item.Text.StartsWith(path))
131 | {
132 | listview.Items.RemoveAt(i);
133 | --i;
134 | --length;
135 | }
136 | }
137 | }
138 | return false;
139 | }
140 |
141 |
142 | private void ListViewMain_SelectedIndexChanged(object sender, EventArgs e)
143 | {
144 | int count = ListViewMain.SelectedIndices.Count;
145 | ButtonOK.Enabled = count != 0;
146 | }
147 |
148 | private void ListViewMain_MouseDoubleClick(object sender, MouseEventArgs e)
149 | {
150 | ListViewHitTestInfo info = ListViewMain.HitTest(e.X, e.Y);
151 | ListViewItem item = info.Item;
152 |
153 | if (item != null && item.Tag is FileNDir file && !file.IsFile)
154 | {
155 | _currentDir = file;
156 | RefreshListView();
157 | }
158 |
159 | }
160 |
161 | private void ButtonOK_Click(object sender, EventArgs e)
162 | {
163 | this.DialogResult = DialogResult.OK;
164 | Pathes.Clear();
165 |
166 | var items = ListViewMain.SelectedItems;
167 | var length = items.Count;
168 | FileNDir file;
169 | for (int i = 0; i < length; i++)
170 | {
171 | file = (items[i].Tag as FileNDir);
172 | if (file.Exists)
173 | Pathes.Add(file);
174 | }
175 | this.Close();
176 | }
177 |
178 | private void ListViewMain_ColumnClick(object sender, ColumnClickEventArgs e)
179 | {
180 | if (ListViewMain.Columns[0].Tag is FileNDir file)
181 | {
182 | _currentDir = file;
183 | RefreshListView();
184 | }
185 | }
186 |
187 | private void TreeViewMain_NodeMouseClick(object sender, TreeNodeMouseClickEventArgs e)
188 | {
189 | var selNode = e.Node;
190 | if (selNode.Tag is FileNDir file)
191 | {
192 | _currentDir = file;
193 | RefreshListView();
194 | }
195 | }
196 |
197 |
198 | private void OpenFileDialogLite_Load(object sender, EventArgs e)
199 | {
200 | TreeViewMain.BeginUpdate();
201 | TreeNode root = TreeViewMain.Nodes[1];
202 | root.Nodes.Clear();
203 | foreach (string item in InternelDriveInfo.RefreshDriveCacheAndReturnsDriveName())
204 | {
205 | AddNode(root, item, item);
206 | }
207 | TreeViewMain.ExpandAll();
208 | TreeViewMain.EndUpdate();
209 |
210 | RefreshListView();
211 | }
212 |
213 |
214 | private void RefreshListView()
215 | {
216 | if (_currentDir == null)
217 | {
218 | _currentDir = _defaultDir;
219 | }
220 | else
221 | {
222 | if (!_currentDir.Exists)
223 | _currentDir = _defaultDir;
224 | }
225 |
226 | ListViewMain.BeginUpdate();
227 | ListViewMain.SelectedItems.Clear();
228 | ListViewMain.Items.Clear();
229 | ListViewMain.Columns[0].Tag = _currentDir.PreviewDir;
230 | foreach (FileNDir item in _currentDir.GetChilds())
231 | {
232 | TryAddToList(ListViewMain, item, false);
233 | }
234 |
235 | ListViewMain.EndUpdate();
236 | }
237 |
238 | private FileNDir AddNode(TreeNode node, string path, string text)
239 | {
240 | var file = new FileNDir(path);
241 | node.Nodes.Add(new TreeNode(text)
242 | {
243 | Tag = file
244 | });
245 | return file;
246 | }
247 |
248 | private FileNDir AddEnvFolder(TreeNode node, Environment.SpecialFolder folder, string text)
249 | {
250 | try
251 | {
252 | string path = Environment.GetFolderPath(folder);
253 | return path == string.Empty ? null : AddNode(node, path, text);
254 | }
255 | catch (Exception ecx)
256 | {
257 | Utils.WriteErrorLog(ecx.Message);
258 | return null;
259 | }
260 |
261 | }
262 |
263 | private static Bitmap FromIconToBitmap(Icon icon)
264 | {
265 | Bitmap bmp = new Bitmap(icon.Width, icon.Height);
266 | using (Graphics gp = Graphics.FromImage(bmp))
267 | {
268 | gp.Clear(Color.Transparent);
269 | gp.DrawIcon(icon, new Rectangle(0, 0, icon.Width, icon.Height));
270 | }
271 | return bmp;
272 | }
273 |
274 |
275 | private sealed class ListViewComparer : IComparer
276 | {
277 | public int Compare(object x, object y)
278 | {
279 | var a = (x as ListViewItem);
280 | var b = (y as ListViewItem);
281 | int ret = -(a.ImageIndex.CompareTo(b.ImageIndex));
282 | return ret == 0 ?
283 | a.Name.CompareTo(b.Name) :
284 | ret;
285 | }
286 | }
287 |
288 |
289 | }
290 | }
291 |
--------------------------------------------------------------------------------
/src/DelApp/Program.cs:
--------------------------------------------------------------------------------
1 | using DelApp.Internals;
2 | using DelApp.Locals;
3 | using System;
4 | using System.Collections.Generic;
5 | using System.Threading;
6 | using System.Windows.Forms;
7 |
8 | namespace DelApp
9 | {
10 | internal static class Program
11 | {
12 |
13 | public static IEnumerable FilePathes;
14 |
15 | ///
16 | /// 应用程序的主入口点。
17 | ///
18 | [STAThread]
19 | static void Main()
20 | {
21 | AppDomain.CurrentDomain.UnhandledException += CurrentDomain_UnhandledException;
22 |
23 |
24 |
25 |
26 | using (var mutex = new Mutex(true, Utils.MyGuidString, out bool createdNew))
27 | {
28 | if (createdNew)
29 | {
30 | FilePathes = GetPathes();
31 | if (PipeService.CreateService())
32 | StartApp();
33 | }
34 | else
35 | {
36 | PipeService.SendPath(GetPathes());
37 | }
38 | }
39 | }
40 |
41 |
42 | static void StartApp()
43 | {
44 | // Todo : add new language providers here.
45 | AppLanguageProviderChs.Instance.Register();
46 |
47 | Utils.EnablePrivileges();
48 |
49 | Application.EnableVisualStyles();
50 | Application.SetCompatibleTextRenderingDefault(false);
51 | Application.Run(new FormMain());
52 | RestartManagerHelper.ReleaseSharedInstance();
53 | SoundPlayHelper.ReleaseSharedInstance();
54 | }
55 |
56 | static IEnumerable GetPathes()
57 | {
58 | string[] args = Environment.GetCommandLineArgs();
59 | if (args.Length == 1)
60 | yield break;
61 | string path;
62 | InternelDriveInfo.RefreshDriveCache();
63 | for (int i = 1; i < args.Length; i++)
64 | {
65 | path = FileNDir.GetFullPath(args[i]);
66 | if (path != null)
67 | yield return path;
68 | }
69 | }
70 |
71 | static void CurrentDomain_UnhandledException(object sender, UnhandledExceptionEventArgs e) => Utils.WriteErrorLog(e.ExceptionObject.ToString());
72 |
73 |
74 |
75 |
76 | }
77 | }
78 |
--------------------------------------------------------------------------------
/src/DelApp/Properties/AssemblyInfo.cs:
--------------------------------------------------------------------------------
1 | using System.Reflection;
2 | using System.Runtime.InteropServices;
3 |
4 | // 有关程序集的一般信息由以下
5 | // 控制。更改这些特性值可修改
6 | // 与程序集关联的信息。
7 | [assembly: AssemblyTitle("DelApp")]
8 | [assembly: AssemblyDescription("")]
9 | [assembly: AssemblyConfiguration("")]
10 | [assembly: AssemblyCompany("")]
11 | [assembly: AssemblyProduct("DelApp")]
12 | [assembly: AssemblyCopyright("Copyright © 2023")]
13 | [assembly: AssemblyTrademark("")]
14 | [assembly: AssemblyCulture("")]
15 |
16 | // 将 ComVisible 设置为 false 会使此程序集中的类型
17 | //对 COM 组件不可见。如果需要从 COM 访问此程序集中的类型
18 | //请将此类型的 ComVisible 特性设置为 true。
19 | [assembly: ComVisible(false)]
20 |
21 | // 如果此项目向 COM 公开,则下列 GUID 用于类型库的 ID
22 | [assembly: Guid("b7dd4552-f9ac-4487-866c-9c8bf686f196")]
23 |
24 | // 程序集的版本信息由下列四个值组成:
25 | //
26 | // 主版本
27 | // 次版本
28 | // 生成号
29 | // 修订号
30 | //
31 | //可以指定所有这些值,也可以使用“生成号”和“修订号”的默认值
32 | //通过使用 "*",如下所示:
33 | // [assembly: AssemblyVersion("1.0.*")]
34 | [assembly: AssemblyVersion("1.0.2.0")]
35 | [assembly: AssemblyFileVersion("1.0.2.0")]
36 |
--------------------------------------------------------------------------------
/src/DelApp/Properties/Resources.Designer.cs:
--------------------------------------------------------------------------------
1 | //------------------------------------------------------------------------------
2 | //
3 | // 此代码由工具生成。
4 | // 运行时版本:4.0.30319.42000
5 | //
6 | // 对此文件的更改可能会导致不正确的行为,并且如果
7 | // 重新生成代码,这些更改将会丢失。
8 | //
9 | //------------------------------------------------------------------------------
10 |
11 | namespace Delapp.Properties {
12 | using System;
13 |
14 |
15 | ///
16 | /// 一个强类型的资源类,用于查找本地化的字符串等。
17 | ///
18 | // 此类是由 StronglyTypedResourceBuilder
19 | // 类通过类似于 ResGen 或 Visual Studio 的工具自动生成的。
20 | // 若要添加或移除成员,请编辑 .ResX 文件,然后重新运行 ResGen
21 | // (以 /str 作为命令选项),或重新生成 VS 项目。
22 | [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "17.0.0.0")]
23 | [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
24 | [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
25 | internal class Resources {
26 |
27 | private static global::System.Resources.ResourceManager resourceMan;
28 |
29 | private static global::System.Globalization.CultureInfo resourceCulture;
30 |
31 | [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
32 | internal Resources() {
33 | }
34 |
35 | ///
36 | /// 返回此类使用的缓存的 ResourceManager 实例。
37 | ///
38 | [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
39 | internal static global::System.Resources.ResourceManager ResourceManager {
40 | get {
41 | if (object.ReferenceEquals(resourceMan, null)) {
42 | global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("Delapp.Properties.Resources", typeof(Resources).Assembly);
43 | resourceMan = temp;
44 | }
45 | return resourceMan;
46 | }
47 | }
48 |
49 | ///
50 | /// 重写当前线程的 CurrentUICulture 属性,对
51 | /// 使用此强类型资源类的所有资源查找执行重写。
52 | ///
53 | [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
54 | internal static global::System.Globalization.CultureInfo Culture {
55 | get {
56 | return resourceCulture;
57 | }
58 | set {
59 | resourceCulture = value;
60 | }
61 | }
62 | }
63 | }
64 |
--------------------------------------------------------------------------------
/src/DelApp/Properties/Resources.resx:
--------------------------------------------------------------------------------
1 |
2 |
3 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 |
92 |
93 |
94 |
95 |
96 |
97 |
98 |
99 |
100 |
101 |
102 |
103 |
104 |
105 |
106 | text/microsoft-resx
107 |
108 |
109 | 2.0
110 |
111 |
112 | System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
113 |
114 |
115 | System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
116 |
117 |
--------------------------------------------------------------------------------
/src/DelApp/Properties/Settings.Designer.cs:
--------------------------------------------------------------------------------
1 | //------------------------------------------------------------------------------
2 | //
3 | // 此代码由工具生成。
4 | // 运行时版本:4.0.30319.42000
5 | //
6 | // 对此文件的更改可能会导致不正确的行为,并且如果
7 | // 重新生成代码,这些更改将会丢失。
8 | //
9 | //------------------------------------------------------------------------------
10 |
11 | namespace Delapp.Properties {
12 |
13 |
14 | [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
15 | [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "17.5.0.0")]
16 | internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase {
17 |
18 | private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings())));
19 |
20 | public static Settings Default {
21 | get {
22 | return defaultInstance;
23 | }
24 | }
25 |
26 | [global::System.Configuration.UserScopedSettingAttribute()]
27 | [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
28 | [global::System.Configuration.DefaultSettingValueAttribute("False")]
29 | public bool ClearListEnabled {
30 | get {
31 | return ((bool)(this["ClearListEnabled"]));
32 | }
33 | set {
34 | this["ClearListEnabled"] = value;
35 | }
36 | }
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/src/DelApp/Properties/Settings.settings:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | False
7 |
8 |
9 |
--------------------------------------------------------------------------------
/src/DelApp/app.manifest:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 | true
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
68 |
69 |
70 |
71 |
72 |
73 |
--------------------------------------------------------------------------------
/src/DelApp/icon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/differentrain/Delapp/c0d1d34a9a6327fb0326938493ca32162d78c9e3/src/DelApp/icon.ico
--------------------------------------------------------------------------------