Skip to content

Commit afb563b

Browse files
authored
[Hidden files] - Enable setting file/folder as hidden in Properties page (#2337)
1 parent fc4072f commit afb563b

File tree

10 files changed

+218
-96
lines changed

10 files changed

+218
-96
lines changed

Files/Commands/Delete.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -168,7 +168,7 @@ private async Task<FilesystemResult> DeleteItemAsync(StorageDeleteOption deleteO
168168
else
169169
{
170170
// Try again with DeleteFileFromApp
171-
if (!NativeDirectoryChangesHelper.DeleteFileFromApp(storItem.ItemPath))
171+
if (!NativeFileOperationsHelper.DeleteFileFromApp(storItem.ItemPath))
172172
{
173173
Debug.WriteLine(System.Runtime.InteropServices.Marshal.GetLastWin32Error());
174174
}

Files/Commands/Paste.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -147,7 +147,7 @@ await AppInstance.FilesystemViewModel.GetFolderFromPathAsync(destinationPath)
147147
else if (pasted.ErrorCode == FilesystemErrorCode.ERROR_UNAUTHORIZED)
148148
{
149149
// Try again with CopyFileFromApp
150-
if (NativeDirectoryChangesHelper.CopyFileFromApp(item.Path, Path.Combine(destinationPath, item.Name), true))
150+
if (NativeFileOperationsHelper.CopyFileFromApp(item.Path, Path.Combine(destinationPath, item.Name), true))
151151
{
152152
pastedSourceItems.Add(item);
153153
}
@@ -203,7 +203,7 @@ await AppInstance.FilesystemViewModel.GetFolderFromPathAsync(destinationPath)
203203
if (deleted == FilesystemErrorCode.ERROR_UNAUTHORIZED)
204204
{
205205
// Try again with DeleteFileFromApp
206-
if (!NativeDirectoryChangesHelper.DeleteFileFromApp(item.Path))
206+
if (!NativeFileOperationsHelper.DeleteFileFromApp(item.Path))
207207
{
208208
Debug.WriteLine(System.Runtime.InteropServices.Marshal.GetLastWin32Error());
209209
}

Files/Files.csproj

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -191,6 +191,7 @@
191191
<Compile Include="Helpers\ItemsDataTemplateSelector.cs" />
192192
<Compile Include="Helpers\JumpListManager.cs" />
193193
<Compile Include="Helpers\NativeDirectoryChangesHelper.cs" />
194+
<Compile Include="Helpers\NativeFileOperationsHelper.cs" />
194195
<Compile Include="Helpers\NativeFindStorageItemHelper.cs" />
195196
<Compile Include="Helpers\NativeWinApiHelper.cs" />
196197
<Compile Include="Helpers\NaturalStringComparer.cs" />
Lines changed: 1 addition & 86 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
using System;
22
using System.Runtime.InteropServices;
3+
using System.Runtime.InteropServices.ComTypes;
34

45
namespace Files.Helpers
56
{
@@ -29,61 +30,6 @@ public class NativeDirectoryChangesHelper
2930
[DllImport("api-ms-win-core-synch-l1-2-0.dll", SetLastError = true)]
3031
public static extern UInt32 WaitForSingleObjectEx(IntPtr hHandle, UInt32 dwMilliseconds, bool bAlertable);
3132

32-
public enum File_Attributes : uint
33-
{
34-
Readonly = 0x00000001,
35-
Hidden = 0x00000002,
36-
System = 0x00000004,
37-
Directory = 0x00000010,
38-
Archive = 0x00000020,
39-
Device = 0x00000040,
40-
Normal = 0x00000080,
41-
Temporary = 0x00000100,
42-
SparseFile = 0x00000200,
43-
ReparsePoint = 0x00000400,
44-
Compressed = 0x00000800,
45-
Offline = 0x00001000,
46-
NotContentIndexed = 0x00002000,
47-
Encrypted = 0x00004000,
48-
Write_Through = 0x80000000,
49-
Overlapped = 0x40000000,
50-
NoBuffering = 0x20000000,
51-
RandomAccess = 0x10000000,
52-
SequentialScan = 0x08000000,
53-
DeleteOnClose = 0x04000000,
54-
BackupSemantics = 0x02000000,
55-
PosixSemantics = 0x01000000,
56-
OpenReparsePoint = 0x00200000,
57-
OpenNoRecall = 0x00100000,
58-
FirstPipeInstance = 0x00080000
59-
}
60-
61-
public const uint GENERIC_READ = 0x80000000;
62-
63-
[DllImport("api-ms-win-core-file-fromapp-l1-1-0.dll", CharSet = CharSet.Auto,
64-
CallingConvention = CallingConvention.StdCall,
65-
SetLastError = true)]
66-
public static extern IntPtr CreateFileFromApp(
67-
string lpFileName,
68-
uint dwDesiredAccess,
69-
uint dwShareMode,
70-
IntPtr SecurityAttributes,
71-
uint dwCreationDisposition,
72-
uint dwFlagsAndAttributes,
73-
IntPtr hTemplateFile
74-
);
75-
76-
[DllImport("api-ms-win-core-file-fromapp-l1-1-0.dll", CharSet = CharSet.Auto,
77-
CallingConvention = CallingConvention.StdCall,
78-
SetLastError = true)]
79-
public static extern IntPtr CreateFile2FromApp(
80-
string lpFileName,
81-
uint dwDesiredAccess,
82-
uint dwShareMode,
83-
uint dwCreationDisposition,
84-
IntPtr pCreateExParams
85-
);
86-
8733
public delegate void LpoverlappedCompletionRoutine(uint dwErrorCode,
8834
uint dwNumberOfBytesTransfered,
8935
OVERLAPPED lpOverlapped
@@ -123,36 +69,5 @@ public unsafe static extern bool ReadDirectoryChangesW(IntPtr hDirectory, byte*
12369
int nBufferLength, bool bWatchSubtree, int dwNotifyFilter, int*
12470
lpBytesReturned, ref OVERLAPPED lpOverlapped,
12571
LpoverlappedCompletionRoutine lpCompletionRoutine);
126-
127-
[DllImport("api-ms-win-core-file-fromapp-l1-1-0.dll", CharSet = CharSet.Auto,
128-
CallingConvention = CallingConvention.StdCall,
129-
SetLastError = true)]
130-
public static extern bool MoveFileFromApp(
131-
string lpExistingFileName,
132-
string lpNewFileName
133-
);
134-
135-
[DllImport("api-ms-win-core-file-fromapp-l1-1-0.dll", CharSet = CharSet.Auto,
136-
CallingConvention = CallingConvention.StdCall,
137-
SetLastError = true)]
138-
public static extern bool CopyFileFromApp(
139-
string lpExistingFileName,
140-
string lpNewFileName,
141-
bool bFailIfExists
142-
);
143-
144-
[DllImport("api-ms-win-core-file-fromapp-l1-1-0.dll", CharSet = CharSet.Auto,
145-
CallingConvention = CallingConvention.StdCall,
146-
SetLastError = true)]
147-
public static extern bool DeleteFileFromApp(
148-
string lpFileName
149-
);
150-
151-
[DllImport("api-ms-win-core-file-fromapp-l1-1-0.dll", CharSet = CharSet.Auto,
152-
CallingConvention = CallingConvention.StdCall,
153-
SetLastError = true)]
154-
public static extern bool RemoveDirectoryFromApp(
155-
string lpPathName
156-
);
15772
}
15873
}
Lines changed: 154 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,154 @@
1+
using System;
2+
using System.Runtime.InteropServices;
3+
using System.Runtime.InteropServices.ComTypes;
4+
5+
namespace Files.Helpers
6+
{
7+
public class NativeFileOperationsHelper
8+
{
9+
public enum File_Attributes : uint
10+
{
11+
Readonly = 0x00000001,
12+
Hidden = 0x00000002,
13+
System = 0x00000004,
14+
Directory = 0x00000010,
15+
Archive = 0x00000020,
16+
Device = 0x00000040,
17+
Normal = 0x00000080,
18+
Temporary = 0x00000100,
19+
SparseFile = 0x00000200,
20+
ReparsePoint = 0x00000400,
21+
Compressed = 0x00000800,
22+
Offline = 0x00001000,
23+
NotContentIndexed = 0x00002000,
24+
Encrypted = 0x00004000,
25+
Write_Through = 0x80000000,
26+
Overlapped = 0x40000000,
27+
NoBuffering = 0x20000000,
28+
RandomAccess = 0x10000000,
29+
SequentialScan = 0x08000000,
30+
DeleteOnClose = 0x04000000,
31+
BackupSemantics = 0x02000000,
32+
PosixSemantics = 0x01000000,
33+
OpenReparsePoint = 0x00200000,
34+
OpenNoRecall = 0x00100000,
35+
FirstPipeInstance = 0x00080000
36+
}
37+
38+
public const uint GENERIC_READ = 0x80000000;
39+
40+
[DllImport("api-ms-win-core-file-fromapp-l1-1-0.dll", CharSet = CharSet.Auto,
41+
CallingConvention = CallingConvention.StdCall,
42+
SetLastError = true)]
43+
public static extern IntPtr CreateFileFromApp(
44+
string lpFileName,
45+
uint dwDesiredAccess,
46+
uint dwShareMode,
47+
IntPtr SecurityAttributes,
48+
uint dwCreationDisposition,
49+
uint dwFlagsAndAttributes,
50+
IntPtr hTemplateFile
51+
);
52+
53+
[DllImport("api-ms-win-core-file-fromapp-l1-1-0.dll", CharSet = CharSet.Auto,
54+
CallingConvention = CallingConvention.StdCall,
55+
SetLastError = true)]
56+
public static extern IntPtr CreateFile2FromApp(
57+
string lpFileName,
58+
uint dwDesiredAccess,
59+
uint dwShareMode,
60+
uint dwCreationDisposition,
61+
IntPtr pCreateExParams
62+
);
63+
64+
[DllImport("api-ms-win-core-file-fromapp-l1-1-0.dll", CharSet = CharSet.Auto,
65+
CallingConvention = CallingConvention.StdCall,
66+
SetLastError = true)]
67+
public static extern bool MoveFileFromApp(
68+
string lpExistingFileName,
69+
string lpNewFileName
70+
);
71+
72+
[DllImport("api-ms-win-core-file-fromapp-l1-1-0.dll", CharSet = CharSet.Auto,
73+
CallingConvention = CallingConvention.StdCall,
74+
SetLastError = true)]
75+
public static extern bool CopyFileFromApp(
76+
string lpExistingFileName,
77+
string lpNewFileName,
78+
bool bFailIfExists
79+
);
80+
81+
[DllImport("api-ms-win-core-file-fromapp-l1-1-0.dll", CharSet = CharSet.Auto,
82+
CallingConvention = CallingConvention.StdCall,
83+
SetLastError = true)]
84+
public static extern bool DeleteFileFromApp(
85+
string lpFileName
86+
);
87+
88+
[DllImport("api-ms-win-core-file-fromapp-l1-1-0.dll", CharSet = CharSet.Auto,
89+
CallingConvention = CallingConvention.StdCall,
90+
SetLastError = true)]
91+
public static extern bool RemoveDirectoryFromApp(
92+
string lpPathName
93+
);
94+
95+
[DllImport("api-ms-win-core-file-fromapp-l1-1-0.dll", SetLastError = true, CharSet = CharSet.Auto)]
96+
[return: MarshalAs(UnmanagedType.Bool)]
97+
public static extern bool GetFileAttributesExFromApp(
98+
string lpFileName,
99+
GET_FILEEX_INFO_LEVELS fInfoLevelId,
100+
out WIN32_FILE_ATTRIBUTE_DATA lpFileInformation);
101+
102+
[DllImport("api-ms-win-core-file-fromapp-l1-1-0.dll", SetLastError = true, CharSet = CharSet.Auto)]
103+
[return: MarshalAs(UnmanagedType.Bool)]
104+
public static extern bool SetFileAttributesFromApp(
105+
string lpFileName,
106+
System.IO.FileAttributes dwFileAttributes);
107+
108+
public enum GET_FILEEX_INFO_LEVELS
109+
{
110+
GetFileExInfoStandard,
111+
}
112+
113+
[StructLayout(LayoutKind.Sequential)]
114+
public struct WIN32_FILE_ATTRIBUTE_DATA
115+
{
116+
public System.IO.FileAttributes dwFileAttributes;
117+
public FILETIME ftCreationTime;
118+
public FILETIME ftLastAccessTime;
119+
public FILETIME ftLastWriteTime;
120+
public uint nFileSizeHigh;
121+
public uint nFileSizeLow;
122+
}
123+
124+
public static bool HasFileAttribute(string lpFileName, System.IO.FileAttributes dwAttrs)
125+
{
126+
if (GetFileAttributesExFromApp(
127+
lpFileName, GET_FILEEX_INFO_LEVELS.GetFileExInfoStandard, out var lpFileInfo))
128+
{
129+
return (lpFileInfo.dwFileAttributes & dwAttrs) == dwAttrs;
130+
}
131+
return false;
132+
}
133+
134+
public static bool SetFileAttribute(string lpFileName, System.IO.FileAttributes dwAttrs)
135+
{
136+
if (!GetFileAttributesExFromApp(
137+
lpFileName, GET_FILEEX_INFO_LEVELS.GetFileExInfoStandard, out var lpFileInfo))
138+
{
139+
return false;
140+
}
141+
return SetFileAttributesFromApp(lpFileName, lpFileInfo.dwFileAttributes | dwAttrs);
142+
}
143+
144+
public static bool UnsetFileAttribute(string lpFileName, System.IO.FileAttributes dwAttrs)
145+
{
146+
if (!GetFileAttributesExFromApp(
147+
lpFileName, GET_FILEEX_INFO_LEVELS.GetFileExInfoStandard, out var lpFileInfo))
148+
{
149+
return false;
150+
}
151+
return SetFileAttributesFromApp(lpFileName, lpFileInfo.dwFileAttributes & ~dwAttrs);
152+
}
153+
}
154+
}

Files/Helpers/NativeFindStorageItemHelper.cs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -49,9 +49,9 @@ public enum FINDEX_SEARCH_OPS
4949
public struct WIN32_FIND_DATA
5050
{
5151
public uint dwFileAttributes;
52-
public System.Runtime.InteropServices.ComTypes.FILETIME ftCreationTime;
53-
public System.Runtime.InteropServices.ComTypes.FILETIME ftLastAccessTime;
54-
public System.Runtime.InteropServices.ComTypes.FILETIME ftLastWriteTime;
52+
public FILETIME ftCreationTime;
53+
public FILETIME ftLastAccessTime;
54+
public FILETIME ftLastWriteTime;
5555
public uint nFileSizeHigh;
5656
public uint nFileSizeLow;
5757
public uint dwReserved0;

Files/Interacts/Interaction.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -851,7 +851,7 @@ public async Task<bool> RenameFileItemAsync(ListedItem item, string oldName, str
851851
if (renamed == FilesystemErrorCode.ERROR_UNAUTHORIZED)
852852
{
853853
// Try again with MoveFileFromApp
854-
if (!NativeDirectoryChangesHelper.MoveFileFromApp(item.ItemPath, Path.Combine(Path.GetDirectoryName(item.ItemPath), newName)))
854+
if (!NativeFileOperationsHelper.MoveFileFromApp(item.ItemPath, Path.Combine(Path.GetDirectoryName(item.ItemPath), newName)))
855855
{
856856
Debug.WriteLine(System.Runtime.InteropServices.Marshal.GetLastWin32Error());
857857
return false;

Files/View Models/ItemViewModel.cs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@
3131
using Windows.UI.Xaml.Media.Imaging;
3232
using static Files.Helpers.NativeDirectoryChangesHelper;
3333
using static Files.Helpers.NativeFindStorageItemHelper;
34+
using static Files.Helpers.NativeFileOperationsHelper;
3435
using FileAttributes = System.IO.FileAttributes;
3536

3637
namespace Files.Filesystem
@@ -1062,7 +1063,9 @@ private bool CheckFolderForHiddenAttribute(string path)
10621063
int additionalFlags = FIND_FIRST_EX_LARGE_FETCH;
10631064
IntPtr hFileTsk = FindFirstFileExFromApp(path + "\\*.*", findInfoLevel, out WIN32_FIND_DATA findDataTsk, FINDEX_SEARCH_OPS.FindExSearchNameMatch, IntPtr.Zero,
10641065
additionalFlags);
1065-
return ((FileAttributes)findDataTsk.dwFileAttributes & FileAttributes.Hidden) == FileAttributes.Hidden;
1066+
var isHidden = ((FileAttributes)findDataTsk.dwFileAttributes & FileAttributes.Hidden) == FileAttributes.Hidden;
1067+
FindClose(hFileTsk);
1068+
return isHidden;
10661069
}
10671070

10681071
private async Task<bool> CheckBitlockerStatusAsync(StorageFolder rootFolder)

0 commit comments

Comments
 (0)