mirror of
https://github.com/babalae/better-genshin-impact.git
synced 2026-05-17 09:26:50 +08:00
create a setup builder impl from MicaSetup
This commit is contained in:
@@ -0,0 +1,90 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
namespace MicaSetup.Shell.Dialogs;
|
||||
|
||||
internal class ChangeNotifyEventManager
|
||||
{
|
||||
private static readonly ShellObjectChangeTypes[] _changeOrder = {
|
||||
ShellObjectChangeTypes.ItemCreate,
|
||||
ShellObjectChangeTypes.ItemRename,
|
||||
ShellObjectChangeTypes.ItemDelete,
|
||||
|
||||
ShellObjectChangeTypes.AttributesChange,
|
||||
|
||||
ShellObjectChangeTypes.DirectoryCreate,
|
||||
ShellObjectChangeTypes.DirectoryDelete,
|
||||
ShellObjectChangeTypes.DirectoryContentsUpdate,
|
||||
ShellObjectChangeTypes.DirectoryRename,
|
||||
|
||||
ShellObjectChangeTypes.Update,
|
||||
|
||||
ShellObjectChangeTypes.MediaInsert,
|
||||
ShellObjectChangeTypes.MediaRemove,
|
||||
ShellObjectChangeTypes.DriveAdd,
|
||||
ShellObjectChangeTypes.DriveRemove,
|
||||
ShellObjectChangeTypes.NetShare,
|
||||
ShellObjectChangeTypes.NetUnshare,
|
||||
|
||||
ShellObjectChangeTypes.ServerDisconnect,
|
||||
ShellObjectChangeTypes.SystemImageUpdate,
|
||||
|
||||
ShellObjectChangeTypes.AssociationChange,
|
||||
ShellObjectChangeTypes.FreeSpace,
|
||||
|
||||
ShellObjectChangeTypes.DiskEventsMask,
|
||||
ShellObjectChangeTypes.GlobalEventsMask,
|
||||
ShellObjectChangeTypes.AllEventsMask
|
||||
};
|
||||
|
||||
private readonly Dictionary<ShellObjectChangeTypes, Delegate> _events = new();
|
||||
|
||||
public void Register(ShellObjectChangeTypes changeType, Delegate handler)
|
||||
{
|
||||
if (!_events.TryGetValue(changeType, out var del))
|
||||
{
|
||||
_events.Add(changeType, handler);
|
||||
}
|
||||
else
|
||||
{
|
||||
del = MulticastDelegate.Combine(del, handler);
|
||||
_events[changeType] = del;
|
||||
}
|
||||
}
|
||||
|
||||
public void Unregister(ShellObjectChangeTypes changeType, Delegate handler)
|
||||
{
|
||||
if (_events.TryGetValue(changeType, out var del))
|
||||
{
|
||||
del = MulticastDelegate.Remove(del, handler);
|
||||
if (del == null)
|
||||
{
|
||||
_events.Remove(changeType);
|
||||
}
|
||||
else
|
||||
{
|
||||
_events[changeType] = del;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void UnregisterAll() => _events.Clear();
|
||||
|
||||
public void Invoke(object sender, ShellObjectChangeTypes changeType, EventArgs args)
|
||||
{
|
||||
changeType &= ~ShellObjectChangeTypes.FromInterrupt;
|
||||
|
||||
foreach (var change in _changeOrder.Where(x => (x & changeType) != 0))
|
||||
{
|
||||
if (_events.TryGetValue(change, out var del))
|
||||
{
|
||||
del.DynamicInvoke(sender, args);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public ShellObjectChangeTypes RegisteredTypes => _events.Keys.Aggregate<ShellObjectChangeTypes, ShellObjectChangeTypes>(
|
||||
ShellObjectChangeTypes.None,
|
||||
(accumulator, changeType) => (changeType | accumulator));
|
||||
}
|
||||
@@ -0,0 +1,71 @@
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
|
||||
namespace MicaSetup.Shell.Dialogs;
|
||||
|
||||
#pragma warning disable CS8618
|
||||
|
||||
internal class ChangeNotifyLock
|
||||
{
|
||||
private readonly uint _event = 0;
|
||||
|
||||
internal ChangeNotifyLock(Message message)
|
||||
{
|
||||
var lockId = Shell32.SHChangeNotification_Lock(
|
||||
message.WParam, (int)message.LParam, out var pidl, out _event);
|
||||
try
|
||||
{
|
||||
Trace.TraceInformation("Message: {0}", (ShellObjectChangeTypes)_event);
|
||||
|
||||
var notifyStruct = pidl.MarshalAs<ShellNotifyStruct>();
|
||||
|
||||
var guid = new Guid(ShellIIDGuid.IShellItem2);
|
||||
if (notifyStruct.item1 != 0 &&
|
||||
(((ShellObjectChangeTypes)_event) & ShellObjectChangeTypes.SystemImageUpdate) == ShellObjectChangeTypes.None)
|
||||
{
|
||||
if (CoreErrorHelper.Succeeded(Shell32.SHCreateItemFromIDList(
|
||||
notifyStruct.item1, ref guid, out var nativeShellItem)))
|
||||
{
|
||||
nativeShellItem.GetDisplayName(ShellItemDesignNameOptions.FileSystemPath,
|
||||
out var name);
|
||||
ItemName = name;
|
||||
|
||||
Trace.TraceInformation("Item1: {0}", ItemName);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
ImageIndex = (int)notifyStruct.item1;
|
||||
}
|
||||
|
||||
if (notifyStruct.item2 != 0)
|
||||
{
|
||||
if (CoreErrorHelper.Succeeded(Shell32.SHCreateItemFromIDList(
|
||||
notifyStruct.item2, ref guid, out var nativeShellItem)))
|
||||
{
|
||||
nativeShellItem.GetDisplayName(ShellItemDesignNameOptions.FileSystemPath,
|
||||
out var name);
|
||||
ItemName2 = name;
|
||||
|
||||
Trace.TraceInformation("Item2: {0}", ItemName2);
|
||||
}
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (lockId != 0)
|
||||
{
|
||||
Shell32.SHChangeNotification_Unlock(lockId);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public bool FromSystemInterrupt => ((ShellObjectChangeTypes)_event & ShellObjectChangeTypes.FromInterrupt)
|
||||
!= ShellObjectChangeTypes.None;
|
||||
|
||||
public int ImageIndex { get; private set; }
|
||||
public string ItemName { get; private set; }
|
||||
public string ItemName2 { get; private set; }
|
||||
|
||||
public ShellObjectChangeTypes ChangeType => (ShellObjectChangeTypes)_event;
|
||||
}
|
||||
@@ -0,0 +1,204 @@
|
||||
using MicaSetup.Natives;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Threading;
|
||||
using static MicaSetup.Natives.User32;
|
||||
|
||||
namespace MicaSetup.Shell.Dialogs;
|
||||
|
||||
#pragma warning disable CS8618
|
||||
|
||||
internal class MessageListener : IDisposable
|
||||
{
|
||||
public const uint CreateWindowMessage = (uint)WindowMessage.WM_USER + 1;
|
||||
public const uint DestroyWindowMessage = (uint)WindowMessage.WM_USER + 2;
|
||||
public const uint BaseUserMessage = (uint)WindowMessage.WM_USER + 5;
|
||||
|
||||
private const string MessageWindowClassName = "MessageListenerClass";
|
||||
|
||||
private static readonly object _threadlock = new();
|
||||
private static uint _atom;
|
||||
private static Thread _windowThread = null!;
|
||||
private static volatile bool _running = false;
|
||||
|
||||
private static readonly ShellObjectWatcherNativeMethods.WndProcDelegate wndProc = WndProc;
|
||||
private static readonly Dictionary<IntPtr, MessageListener> _listeners = new();
|
||||
private static nint _firstWindowHandle = 0;
|
||||
|
||||
private static readonly object _crossThreadWindowLock = new();
|
||||
private static nint _tempHandle = 0;
|
||||
|
||||
public event EventHandler<WindowMessageEventArgs> MessageReceived;
|
||||
|
||||
public MessageListener()
|
||||
{
|
||||
lock (_threadlock)
|
||||
{
|
||||
if (_windowThread == null)
|
||||
{
|
||||
_windowThread = new Thread(ThreadMethod);
|
||||
_windowThread.SetApartmentState(ApartmentState.STA);
|
||||
_windowThread.Name = "ShellObjectWatcherMessageListenerHelperThread";
|
||||
|
||||
lock (_crossThreadWindowLock)
|
||||
{
|
||||
_windowThread.Start();
|
||||
Monitor.Wait(_crossThreadWindowLock);
|
||||
}
|
||||
|
||||
_firstWindowHandle = WindowHandle;
|
||||
}
|
||||
else
|
||||
{
|
||||
CrossThreadCreateWindow();
|
||||
}
|
||||
|
||||
if (WindowHandle == 0)
|
||||
{
|
||||
throw new ShellException(LocalizedMessages.MessageListenerCannotCreateWindow,
|
||||
Marshal.GetExceptionForHR(Marshal.GetHRForLastWin32Error()));
|
||||
}
|
||||
|
||||
_listeners.Add(WindowHandle, this);
|
||||
}
|
||||
}
|
||||
|
||||
private void CrossThreadCreateWindow()
|
||||
{
|
||||
if (_firstWindowHandle == 0)
|
||||
{
|
||||
throw new InvalidOperationException(LocalizedMessages.MessageListenerNoWindowHandle);
|
||||
}
|
||||
|
||||
lock (_crossThreadWindowLock)
|
||||
{
|
||||
User32.PostMessage(_firstWindowHandle, (int)CreateWindowMessage, 0, 0);
|
||||
Monitor.Wait(_crossThreadWindowLock);
|
||||
}
|
||||
|
||||
WindowHandle = _tempHandle;
|
||||
}
|
||||
|
||||
private static void RegisterWindowClass()
|
||||
{
|
||||
WindowClassEx classEx = new()
|
||||
{
|
||||
ClassName = MessageWindowClassName,
|
||||
WndProc = wndProc,
|
||||
Size = (uint)Marshal.SizeOf(typeof(WindowClassEx)),
|
||||
};
|
||||
|
||||
var atom = ShellObjectWatcherNativeMethods.RegisterClassEx(ref classEx);
|
||||
if (atom == 0)
|
||||
{
|
||||
throw new ShellException(LocalizedMessages.MessageListenerClassNotRegistered,
|
||||
Marshal.GetExceptionForHR(Marshal.GetHRForLastWin32Error()));
|
||||
}
|
||||
_atom = atom;
|
||||
}
|
||||
|
||||
private static nint CreateWindow()
|
||||
{
|
||||
nint handle = ShellObjectWatcherNativeMethods.CreateWindowEx(
|
||||
0,
|
||||
MessageWindowClassName,
|
||||
"MessageListenerWindow",
|
||||
0,
|
||||
0, 0, 0, 0,
|
||||
new IntPtr(-3),
|
||||
0, 0, 0);
|
||||
|
||||
return handle;
|
||||
}
|
||||
|
||||
private void ThreadMethod()
|
||||
{
|
||||
lock (_crossThreadWindowLock)
|
||||
{
|
||||
_running = true;
|
||||
if (_atom == 0)
|
||||
{
|
||||
RegisterWindowClass();
|
||||
}
|
||||
WindowHandle = CreateWindow();
|
||||
|
||||
Monitor.Pulse(_crossThreadWindowLock);
|
||||
}
|
||||
|
||||
while (_running)
|
||||
{
|
||||
if (ShellObjectWatcherNativeMethods.GetMessage(out Message msg, 0, 0, 0))
|
||||
{
|
||||
ShellObjectWatcherNativeMethods.DispatchMessage(ref msg);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static int WndProc(nint hwnd, uint msg, nint wparam, nint lparam)
|
||||
{
|
||||
switch (msg)
|
||||
{
|
||||
case CreateWindowMessage:
|
||||
lock (_crossThreadWindowLock)
|
||||
{
|
||||
_tempHandle = CreateWindow();
|
||||
Monitor.Pulse(_crossThreadWindowLock);
|
||||
}
|
||||
break;
|
||||
|
||||
case (uint)WindowMessage.WM_DESTROY:
|
||||
_running = false;
|
||||
break;
|
||||
|
||||
default:
|
||||
MessageListener listener;
|
||||
if (_listeners.TryGetValue(hwnd, out listener))
|
||||
{
|
||||
Message message = new(hwnd, msg, wparam, lparam, 0, new POINT());
|
||||
listener.MessageReceived.SafeRaise(listener, new WindowMessageEventArgs(message));
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
return ShellObjectWatcherNativeMethods.DefWindowProc(hwnd, msg, wparam, lparam);
|
||||
}
|
||||
|
||||
public nint WindowHandle { get; private set; }
|
||||
|
||||
public static bool Running
|
||||
{ get { return _running; } }
|
||||
|
||||
~MessageListener()
|
||||
{
|
||||
Dispose(false);
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
Dispose(true);
|
||||
GC.SuppressFinalize(this);
|
||||
}
|
||||
|
||||
protected virtual void Dispose(bool disposing)
|
||||
{
|
||||
if (disposing)
|
||||
{
|
||||
lock (_threadlock)
|
||||
{
|
||||
_listeners.Remove(WindowHandle);
|
||||
if (_listeners.Count == 0)
|
||||
{
|
||||
User32.PostMessage(WindowHandle, (int)WindowMessage.WM_DESTROY, 0, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public class WindowMessageEventArgs : EventArgs
|
||||
{
|
||||
public Message Message { get; private set; }
|
||||
|
||||
internal WindowMessageEventArgs(Message msg) => Message = msg;
|
||||
}
|
||||
@@ -0,0 +1,110 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
namespace MicaSetup.Shell.Dialogs;
|
||||
|
||||
internal static class MessageListenerFilter
|
||||
{
|
||||
private static readonly object _registerLock = new();
|
||||
private static readonly List<RegisteredListener> _packages = new();
|
||||
|
||||
public static MessageListenerFilterRegistrationResult Register(Action<WindowMessageEventArgs> callback)
|
||||
{
|
||||
lock (_registerLock)
|
||||
{
|
||||
uint message = 0;
|
||||
var package = _packages.FirstOrDefault(x => x.TryRegister(callback, out message));
|
||||
if (package == null)
|
||||
{
|
||||
package = new RegisteredListener();
|
||||
if (!package.TryRegister(callback, out message))
|
||||
{
|
||||
throw new ShellException(LocalizedMessages.MessageListenerFilterUnableToRegister);
|
||||
}
|
||||
_packages.Add(package);
|
||||
}
|
||||
|
||||
return new MessageListenerFilterRegistrationResult(
|
||||
package.Listener.WindowHandle,
|
||||
message);
|
||||
}
|
||||
}
|
||||
|
||||
public static void Unregister(nint listenerHandle, uint message)
|
||||
{
|
||||
lock (_registerLock)
|
||||
{
|
||||
var package = _packages.FirstOrDefault(x => x.Listener.WindowHandle == listenerHandle);
|
||||
if (package == null || !package.Callbacks.Remove(message))
|
||||
{
|
||||
throw new ArgumentException(LocalizedMessages.MessageListenerFilterUnknownListenerHandle);
|
||||
}
|
||||
|
||||
if (package.Callbacks.Count == 0)
|
||||
{
|
||||
package.Listener.Dispose();
|
||||
_packages.Remove(package);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private class RegisteredListener
|
||||
{
|
||||
public Dictionary<uint, Action<WindowMessageEventArgs>> Callbacks { get; private set; }
|
||||
|
||||
public MessageListener Listener { get; private set; }
|
||||
|
||||
public RegisteredListener()
|
||||
{
|
||||
Callbacks = new Dictionary<uint, Action<WindowMessageEventArgs>>();
|
||||
Listener = new MessageListener();
|
||||
Listener.MessageReceived += MessageReceived;
|
||||
}
|
||||
|
||||
private void MessageReceived(object sender, WindowMessageEventArgs e)
|
||||
{
|
||||
if (Callbacks.TryGetValue(e.Message.Msg, out var action))
|
||||
{
|
||||
action(e);
|
||||
}
|
||||
}
|
||||
|
||||
private uint _lastMessage = MessageListener.BaseUserMessage;
|
||||
|
||||
public bool TryRegister(Action<WindowMessageEventArgs> callback, out uint message)
|
||||
{
|
||||
message = 0;
|
||||
if (Callbacks.Count < ushort.MaxValue - MessageListener.BaseUserMessage)
|
||||
{
|
||||
var i = _lastMessage + 1;
|
||||
while (i != _lastMessage)
|
||||
{
|
||||
if (i > ushort.MaxValue) { i = MessageListener.BaseUserMessage; }
|
||||
|
||||
if (!Callbacks.ContainsKey(i))
|
||||
{
|
||||
_lastMessage = message = i;
|
||||
Callbacks.Add(i, callback);
|
||||
return true;
|
||||
}
|
||||
i++;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
internal class MessageListenerFilterRegistrationResult
|
||||
{
|
||||
internal MessageListenerFilterRegistrationResult(nint handle, uint msg)
|
||||
{
|
||||
WindowHandle = handle;
|
||||
Message = msg;
|
||||
}
|
||||
|
||||
public nint WindowHandle { get; private set; }
|
||||
|
||||
public uint Message { get; private set; }
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
using System;
|
||||
|
||||
namespace MicaSetup.Shell.Dialogs;
|
||||
|
||||
public class ShellObjectNotificationEventArgs : EventArgs
|
||||
{
|
||||
public ShellObjectChangeTypes ChangeType { get; private set; }
|
||||
|
||||
public bool FromSystemInterrupt { get; private set; }
|
||||
|
||||
internal ShellObjectNotificationEventArgs(ChangeNotifyLock notifyLock)
|
||||
{
|
||||
ChangeType = notifyLock.ChangeType;
|
||||
FromSystemInterrupt = notifyLock.FromSystemInterrupt;
|
||||
}
|
||||
}
|
||||
|
||||
public class ShellObjectChangedEventArgs : ShellObjectNotificationEventArgs
|
||||
{
|
||||
public string Path { get; private set; }
|
||||
|
||||
internal ShellObjectChangedEventArgs(ChangeNotifyLock notifyLock)
|
||||
: base(notifyLock) => Path = notifyLock.ItemName;
|
||||
}
|
||||
|
||||
public class ShellObjectRenamedEventArgs : ShellObjectChangedEventArgs
|
||||
{
|
||||
public string NewPath { get; private set; }
|
||||
|
||||
internal ShellObjectRenamedEventArgs(ChangeNotifyLock notifyLock)
|
||||
: base(notifyLock) => NewPath = notifyLock.ItemName2;
|
||||
}
|
||||
|
||||
public class SystemImageUpdatedEventArgs : ShellObjectNotificationEventArgs
|
||||
{
|
||||
public int ImageIndex { get; private set; }
|
||||
|
||||
internal SystemImageUpdatedEventArgs(ChangeNotifyLock notifyLock)
|
||||
: base(notifyLock) => ImageIndex = notifyLock.ImageIndex;
|
||||
}
|
||||
@@ -0,0 +1,427 @@
|
||||
using System;
|
||||
using System.ComponentModel;
|
||||
using System.Threading;
|
||||
|
||||
namespace MicaSetup.Shell.Dialogs;
|
||||
|
||||
public class ShellObjectWatcher : IDisposable
|
||||
{
|
||||
private readonly ShellObject _shellObject;
|
||||
private readonly bool _recursive;
|
||||
|
||||
private readonly ChangeNotifyEventManager _manager = new();
|
||||
private readonly nint _listenerHandle;
|
||||
private readonly uint _message;
|
||||
|
||||
private uint _registrationId;
|
||||
private volatile bool _running;
|
||||
|
||||
private readonly SynchronizationContext _context = SynchronizationContext.Current;
|
||||
|
||||
public ShellObjectWatcher(ShellObject shellObject, bool recursive)
|
||||
{
|
||||
if (_context == null)
|
||||
{
|
||||
_context = new SynchronizationContext();
|
||||
SynchronizationContext.SetSynchronizationContext(_context);
|
||||
}
|
||||
|
||||
_shellObject = shellObject ?? throw new ArgumentNullException("shellObject");
|
||||
_recursive = recursive;
|
||||
|
||||
var result = MessageListenerFilter.Register(OnWindowMessageReceived);
|
||||
_listenerHandle = result.WindowHandle;
|
||||
_message = result.Message;
|
||||
}
|
||||
|
||||
public bool Running
|
||||
{
|
||||
get => _running;
|
||||
private set => _running = value;
|
||||
}
|
||||
|
||||
public void Start()
|
||||
{
|
||||
if (Running) { return; }
|
||||
|
||||
var entry = new SHChangeNotifyEntry
|
||||
{
|
||||
recursively = _recursive,
|
||||
|
||||
pIdl = _shellObject.PIDL
|
||||
};
|
||||
|
||||
_registrationId = Shell32.SHChangeNotifyRegister(
|
||||
_listenerHandle,
|
||||
ShellChangeNotifyEventSource.ShellLevel | ShellChangeNotifyEventSource.InterruptLevel | ShellChangeNotifyEventSource.NewDelivery,
|
||||
_manager.RegisteredTypes,
|
||||
_message,
|
||||
1,
|
||||
ref entry);
|
||||
|
||||
if (_registrationId == 0)
|
||||
{
|
||||
throw new Win32Exception(LocalizedMessages.ShellObjectWatcherRegisterFailed);
|
||||
}
|
||||
|
||||
Running = true;
|
||||
}
|
||||
|
||||
public void Stop()
|
||||
{
|
||||
if (!Running) { return; }
|
||||
if (_registrationId > 0)
|
||||
{
|
||||
Shell32.SHChangeNotifyDeregister(_registrationId);
|
||||
_registrationId = 0;
|
||||
}
|
||||
Running = false;
|
||||
}
|
||||
|
||||
private void OnWindowMessageReceived(WindowMessageEventArgs e)
|
||||
{
|
||||
if (e.Message.Msg == _message)
|
||||
{
|
||||
_context.Send(x => ProcessChangeNotificationEvent(e), null);
|
||||
}
|
||||
}
|
||||
|
||||
private void ThrowIfRunning()
|
||||
{
|
||||
if (Running)
|
||||
{
|
||||
throw new InvalidOperationException(LocalizedMessages.ShellObjectWatcherUnableToChangeEvents);
|
||||
}
|
||||
}
|
||||
|
||||
protected virtual void ProcessChangeNotificationEvent(WindowMessageEventArgs e)
|
||||
{
|
||||
if (!Running) { return; }
|
||||
if (e == null) { throw new ArgumentNullException("e"); }
|
||||
|
||||
var notifyLock = new ChangeNotifyLock(e.Message);
|
||||
ShellObjectNotificationEventArgs args = notifyLock.ChangeType switch
|
||||
{
|
||||
ShellObjectChangeTypes.DirectoryRename or ShellObjectChangeTypes.ItemRename => new ShellObjectRenamedEventArgs(notifyLock),
|
||||
ShellObjectChangeTypes.SystemImageUpdate => new SystemImageUpdatedEventArgs(notifyLock),
|
||||
_ => new ShellObjectChangedEventArgs(notifyLock),
|
||||
};
|
||||
_manager.Invoke(this, notifyLock.ChangeType, args);
|
||||
}
|
||||
|
||||
public event EventHandler<ShellObjectNotificationEventArgs> AllEvents
|
||||
{
|
||||
add
|
||||
{
|
||||
ThrowIfRunning();
|
||||
_manager.Register(ShellObjectChangeTypes.AllEventsMask, value);
|
||||
}
|
||||
remove
|
||||
{
|
||||
ThrowIfRunning();
|
||||
_manager.Unregister(ShellObjectChangeTypes.AllEventsMask, value);
|
||||
}
|
||||
}
|
||||
|
||||
public event EventHandler<ShellObjectNotificationEventArgs> GlobalEvents
|
||||
{
|
||||
add
|
||||
{
|
||||
ThrowIfRunning();
|
||||
_manager.Register(ShellObjectChangeTypes.GlobalEventsMask, value);
|
||||
}
|
||||
remove
|
||||
{
|
||||
ThrowIfRunning();
|
||||
_manager.Unregister(ShellObjectChangeTypes.GlobalEventsMask, value);
|
||||
}
|
||||
}
|
||||
|
||||
public event EventHandler<ShellObjectNotificationEventArgs> DiskEvents
|
||||
{
|
||||
add
|
||||
{
|
||||
ThrowIfRunning();
|
||||
_manager.Register(ShellObjectChangeTypes.DiskEventsMask, value);
|
||||
}
|
||||
remove
|
||||
{
|
||||
ThrowIfRunning();
|
||||
_manager.Unregister(ShellObjectChangeTypes.DiskEventsMask, value);
|
||||
}
|
||||
}
|
||||
|
||||
public event EventHandler<ShellObjectRenamedEventArgs> ItemRenamed
|
||||
{
|
||||
add
|
||||
{
|
||||
ThrowIfRunning();
|
||||
_manager.Register(ShellObjectChangeTypes.ItemRename, value);
|
||||
}
|
||||
remove
|
||||
{
|
||||
ThrowIfRunning();
|
||||
_manager.Unregister(ShellObjectChangeTypes.ItemRename, value);
|
||||
}
|
||||
}
|
||||
|
||||
public event EventHandler<ShellObjectChangedEventArgs> ItemCreated
|
||||
{
|
||||
add
|
||||
{
|
||||
ThrowIfRunning();
|
||||
_manager.Register(ShellObjectChangeTypes.ItemCreate, value);
|
||||
}
|
||||
remove
|
||||
{
|
||||
ThrowIfRunning();
|
||||
_manager.Unregister(ShellObjectChangeTypes.ItemCreate, value);
|
||||
}
|
||||
}
|
||||
|
||||
public event EventHandler<ShellObjectChangedEventArgs> ItemDeleted
|
||||
{
|
||||
add
|
||||
{
|
||||
ThrowIfRunning();
|
||||
_manager.Register(ShellObjectChangeTypes.ItemDelete, value);
|
||||
}
|
||||
remove
|
||||
{
|
||||
ThrowIfRunning();
|
||||
_manager.Unregister(ShellObjectChangeTypes.ItemDelete, value);
|
||||
}
|
||||
}
|
||||
|
||||
public event EventHandler<ShellObjectChangedEventArgs> Updated
|
||||
{
|
||||
add
|
||||
{
|
||||
ThrowIfRunning();
|
||||
_manager.Register(ShellObjectChangeTypes.Update, value);
|
||||
}
|
||||
remove
|
||||
{
|
||||
ThrowIfRunning();
|
||||
_manager.Unregister(ShellObjectChangeTypes.Update, value);
|
||||
}
|
||||
}
|
||||
|
||||
public event EventHandler<ShellObjectChangedEventArgs> DirectoryUpdated
|
||||
{
|
||||
add
|
||||
{
|
||||
ThrowIfRunning();
|
||||
_manager.Register(ShellObjectChangeTypes.DirectoryContentsUpdate, value);
|
||||
}
|
||||
remove
|
||||
{
|
||||
ThrowIfRunning();
|
||||
_manager.Unregister(ShellObjectChangeTypes.DirectoryContentsUpdate, value);
|
||||
}
|
||||
}
|
||||
|
||||
public event EventHandler<ShellObjectRenamedEventArgs> DirectoryRenamed
|
||||
{
|
||||
add
|
||||
{
|
||||
ThrowIfRunning();
|
||||
_manager.Register(ShellObjectChangeTypes.DirectoryRename, value);
|
||||
}
|
||||
remove
|
||||
{
|
||||
ThrowIfRunning();
|
||||
_manager.Unregister(ShellObjectChangeTypes.DirectoryRename, value);
|
||||
}
|
||||
}
|
||||
|
||||
public event EventHandler<ShellObjectChangedEventArgs> DirectoryCreated
|
||||
{
|
||||
add
|
||||
{
|
||||
ThrowIfRunning();
|
||||
_manager.Register(ShellObjectChangeTypes.DirectoryCreate, value);
|
||||
}
|
||||
remove
|
||||
{
|
||||
ThrowIfRunning();
|
||||
_manager.Unregister(ShellObjectChangeTypes.DirectoryCreate, value);
|
||||
}
|
||||
}
|
||||
|
||||
public event EventHandler<ShellObjectChangedEventArgs> DirectoryDeleted
|
||||
{
|
||||
add
|
||||
{
|
||||
ThrowIfRunning();
|
||||
_manager.Register(ShellObjectChangeTypes.DirectoryDelete, value);
|
||||
}
|
||||
remove
|
||||
{
|
||||
ThrowIfRunning();
|
||||
_manager.Unregister(ShellObjectChangeTypes.DirectoryDelete, value);
|
||||
}
|
||||
}
|
||||
|
||||
public event EventHandler<ShellObjectChangedEventArgs> MediaInserted
|
||||
{
|
||||
add
|
||||
{
|
||||
ThrowIfRunning();
|
||||
_manager.Register(ShellObjectChangeTypes.MediaInsert, value);
|
||||
}
|
||||
remove
|
||||
{
|
||||
ThrowIfRunning();
|
||||
_manager.Unregister(ShellObjectChangeTypes.MediaInsert, value);
|
||||
}
|
||||
}
|
||||
|
||||
public event EventHandler<ShellObjectChangedEventArgs> MediaRemoved
|
||||
{
|
||||
add
|
||||
{
|
||||
ThrowIfRunning();
|
||||
_manager.Register(ShellObjectChangeTypes.MediaRemove, value);
|
||||
}
|
||||
remove
|
||||
{
|
||||
ThrowIfRunning();
|
||||
_manager.Unregister(ShellObjectChangeTypes.MediaRemove, value);
|
||||
}
|
||||
}
|
||||
|
||||
public event EventHandler<ShellObjectChangedEventArgs> DriveAdded
|
||||
{
|
||||
add
|
||||
{
|
||||
ThrowIfRunning();
|
||||
_manager.Register(ShellObjectChangeTypes.DriveAdd, value);
|
||||
}
|
||||
remove
|
||||
{
|
||||
ThrowIfRunning();
|
||||
_manager.Unregister(ShellObjectChangeTypes.DriveAdd, value);
|
||||
}
|
||||
}
|
||||
|
||||
public event EventHandler<ShellObjectChangedEventArgs> DriveRemoved
|
||||
{
|
||||
add
|
||||
{
|
||||
ThrowIfRunning();
|
||||
_manager.Register(ShellObjectChangeTypes.DriveRemove, value);
|
||||
}
|
||||
remove
|
||||
{
|
||||
ThrowIfRunning();
|
||||
_manager.Unregister(ShellObjectChangeTypes.DriveRemove, value);
|
||||
}
|
||||
}
|
||||
|
||||
public event EventHandler<ShellObjectChangedEventArgs> FolderNetworkShared
|
||||
{
|
||||
add
|
||||
{
|
||||
ThrowIfRunning();
|
||||
_manager.Register(ShellObjectChangeTypes.NetShare, value);
|
||||
}
|
||||
remove
|
||||
{
|
||||
ThrowIfRunning();
|
||||
_manager.Unregister(ShellObjectChangeTypes.NetShare, value);
|
||||
}
|
||||
}
|
||||
|
||||
public event EventHandler<ShellObjectChangedEventArgs> FolderNetworkUnshared
|
||||
{
|
||||
add
|
||||
{
|
||||
ThrowIfRunning();
|
||||
_manager.Register(ShellObjectChangeTypes.NetUnshare, value);
|
||||
}
|
||||
remove
|
||||
{
|
||||
ThrowIfRunning();
|
||||
_manager.Unregister(ShellObjectChangeTypes.NetUnshare, value);
|
||||
}
|
||||
}
|
||||
|
||||
public event EventHandler<ShellObjectChangedEventArgs> ServerDisconnected
|
||||
{
|
||||
add
|
||||
{
|
||||
ThrowIfRunning();
|
||||
_manager.Register(ShellObjectChangeTypes.ServerDisconnect, value);
|
||||
}
|
||||
remove
|
||||
{
|
||||
ThrowIfRunning();
|
||||
_manager.Unregister(ShellObjectChangeTypes.ServerDisconnect, value);
|
||||
}
|
||||
}
|
||||
|
||||
public event EventHandler<ShellObjectChangedEventArgs> SystemImageChanged
|
||||
{
|
||||
add
|
||||
{
|
||||
ThrowIfRunning();
|
||||
_manager.Register(ShellObjectChangeTypes.SystemImageUpdate, value);
|
||||
}
|
||||
remove
|
||||
{
|
||||
ThrowIfRunning();
|
||||
_manager.Unregister(ShellObjectChangeTypes.SystemImageUpdate, value);
|
||||
}
|
||||
}
|
||||
|
||||
public event EventHandler<ShellObjectChangedEventArgs> FreeSpaceChanged
|
||||
{
|
||||
add
|
||||
{
|
||||
ThrowIfRunning();
|
||||
_manager.Register(ShellObjectChangeTypes.FreeSpace, value);
|
||||
}
|
||||
remove
|
||||
{
|
||||
ThrowIfRunning();
|
||||
_manager.Unregister(ShellObjectChangeTypes.FreeSpace, value);
|
||||
}
|
||||
}
|
||||
|
||||
public event EventHandler<ShellObjectChangedEventArgs> FileTypeAssociationChanged
|
||||
{
|
||||
add
|
||||
{
|
||||
ThrowIfRunning();
|
||||
_manager.Register(ShellObjectChangeTypes.AssociationChange, value);
|
||||
}
|
||||
remove
|
||||
{
|
||||
ThrowIfRunning();
|
||||
_manager.Unregister(ShellObjectChangeTypes.AssociationChange, value);
|
||||
}
|
||||
}
|
||||
|
||||
protected virtual void Dispose(bool disposing)
|
||||
{
|
||||
Stop();
|
||||
_manager.UnregisterAll();
|
||||
|
||||
if (_listenerHandle != 0)
|
||||
{
|
||||
MessageListenerFilter.Unregister(_listenerHandle, _message);
|
||||
}
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
Dispose(true);
|
||||
GC.SuppressFinalize(this);
|
||||
}
|
||||
|
||||
~ShellObjectWatcher()
|
||||
{
|
||||
Dispose(false);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user