Move DevDrive project to repo root

This commit is contained in:
2026-01-05 07:19:06 +11:00
parent 9bf318e41e
commit 9fcad874b9
9 changed files with 8 additions and 0 deletions

174
DriveHider.cs Normal file
View File

@@ -0,0 +1,174 @@
using System.Runtime.Versioning;
using Microsoft.Win32;
namespace DevDrive;
/// <summary>
/// Handles hiding and showing drives from Windows Explorer using registry.
/// </summary>
[SupportedOSPlatform("windows")]
public static class DriveHider
{
private const string LogPrefix = "[DriveHider]";
private const string ExplorerPoliciesKey = @"Software\Microsoft\Windows\CurrentVersion\Policies\Explorer";
private const string NoDrivesValue = "NoDrives";
private static int _hiddenDriveMask;
private static string? _hiddenDriveLetter;
private static int _originalNoDrives;
public static bool HideDrive(string driveLetter)
{
if (_hiddenDriveLetter != null)
{
Console.WriteLine($"{LogPrefix} Drive already hidden");
return true;
}
try
{
var letter = driveLetter.TrimEnd('\\', ':').ToUpperInvariant();
if (letter.Length != 1 || letter[0] < 'A' || letter[0] > 'Z')
{
Console.WriteLine($"{LogPrefix} Invalid drive letter: {driveLetter}");
return false;
}
var driveIndex = letter[0] - 'A';
_hiddenDriveMask = 1 << driveIndex;
_hiddenDriveLetter = letter + ":\\";
using var key = Registry.CurrentUser.CreateSubKey(ExplorerPoliciesKey);
if (key == null)
{
Console.WriteLine($"{LogPrefix} Failed to open registry key");
return false;
}
_originalNoDrives = GetNoDrivesValue(key);
var newValue = _originalNoDrives | _hiddenDriveMask;
key.SetValue(NoDrivesValue, newValue, RegistryValueKind.DWord);
RefreshExplorer();
Console.WriteLine($"{LogPrefix} Hidden drive {letter}: from Explorer");
return true;
}
catch (Exception ex)
{
Console.WriteLine($"{LogPrefix} Error hiding drive: {ex.Message}");
_hiddenDriveMask = 0;
_hiddenDriveLetter = null;
return false;
}
}
public static bool ShowDrive()
{
if (_hiddenDriveLetter == null)
{
return true;
}
try
{
using var key = Registry.CurrentUser.OpenSubKey(ExplorerPoliciesKey, writable: true);
if (key == null)
{
Console.WriteLine($"{LogPrefix} Failed to open registry key for restore");
return false;
}
var currentValue = GetNoDrivesValue(key);
var newValue = currentValue & ~_hiddenDriveMask;
if (newValue == 0)
{
key.DeleteValue(NoDrivesValue, throwOnMissingValue: false);
}
else
{
key.SetValue(NoDrivesValue, newValue, RegistryValueKind.DWord);
}
RefreshExplorer();
Console.WriteLine($"{LogPrefix} Restored drive {_hiddenDriveLetter.TrimEnd('\\')} in Explorer");
_hiddenDriveMask = 0;
_hiddenDriveLetter = null;
return true;
}
catch (Exception ex)
{
Console.WriteLine($"{LogPrefix} Error restoring drive: {ex.Message}");
return false;
}
}
public static bool IsHidden => _hiddenDriveLetter != null;
public static string? HiddenDriveLetter => _hiddenDriveLetter;
private static int GetNoDrivesValue(RegistryKey key)
{
var value = key.GetValue(NoDrivesValue);
return value switch
{
null => 0,
int intValue => intValue,
uint uintValue => (int)uintValue,
byte[] bytes when bytes.Length >= 4 => BitConverter.ToInt32(bytes, 0),
byte[] bytes when bytes.Length > 0 => bytes[0],
_ => 0
};
}
private static void RefreshExplorer()
{
try
{
NativeMethods.SendMessageTimeout(
NativeMethods.HWND_BROADCAST,
NativeMethods.WM_SETTINGCHANGE,
IntPtr.Zero,
"Policy",
NativeMethods.SMTO_ABORTIFHUNG,
1000,
out _);
NativeMethods.SHChangeNotify(
NativeMethods.SHCNE_DRIVEADD | NativeMethods.SHCNE_DRIVEREMOVED,
NativeMethods.SHCNF_FLUSHNOWAIT,
IntPtr.Zero,
IntPtr.Zero);
}
catch
{
}
}
private static class NativeMethods
{
public const int SHCNE_DRIVEADD = 0x00000100;
public const int SHCNE_DRIVEREMOVED = 0x00000080;
public const int SHCNF_FLUSHNOWAIT = 0x3000;
public static readonly IntPtr HWND_BROADCAST = new(0xFFFF);
public const int WM_SETTINGCHANGE = 0x001A;
public const int SMTO_ABORTIFHUNG = 0x0002;
[System.Runtime.InteropServices.DllImport("shell32.dll")]
public static extern void SHChangeNotify(int wEventId, int uFlags, IntPtr dwItem1, IntPtr dwItem2);
[System.Runtime.InteropServices.DllImport("user32.dll", SetLastError = true, CharSet = System.Runtime.InteropServices.CharSet.Auto)]
public static extern IntPtr SendMessageTimeout(
IntPtr hWnd,
int Msg,
IntPtr wParam,
string lParam,
int fuFlags,
int uTimeout,
out IntPtr lpdwResult);
}
}