最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

C#使用RegNotifyChangeKeyValue監(jiān)聽注冊表更改的方法小結(jié)

 更新時(shí)間:2024年06月03日 09:32:49   作者:HRESULT  
RegNotifyChangeKeyValue的最后一個(gè)參數(shù)傳遞false,表示以同步的方式監(jiān)聽,這篇文章主要介紹了C#使用RegNotifyChangeKeyValue監(jiān)聽注冊表更改的方法小結(jié),需要的朋友可以參考下

養(yǎng)成一個(gè)好習(xí)慣,調(diào)用 Windows API 之前一定要先看文檔

RegNotifyChangeKeyValue 函數(shù) (winreg.h) - Win32 apps | Microsoft Learn

同步阻塞模式

RegNotifyChangeKeyValue的最后一個(gè)參數(shù)傳遞false,表示以同步的方式監(jiān)聽。
同步模式會阻塞調(diào)用線程,直到監(jiān)聽的目標(biāo)發(fā)生更改才會返回,如果在UI線程上調(diào)用,則會導(dǎo)致界面卡死,因此我們一般不會直接在主線程上同步監(jiān)聽,往往是創(chuàng)建一個(gè)新的線程來監(jiān)聽。

示例代碼因?yàn)槭强刂婆_程序,因此沒有創(chuàng)建新的線程。

RegistryKey hKey = Registry.CurrentUser.CreateSubKey("SOFTWARE\\1-RegMonitor");
string changeBefore = hKey.GetValue("TestValue").ToString();
Console.WriteLine($"TestValue的當(dāng)前值是:{changeBefore}, 時(shí)間:{DateTime.Now:HH:mm:ss}");
//此處創(chuàng)建一個(gè)任務(wù),5s之后修改TestValue的值為一個(gè)新的guid
Task.Delay(5000).ContinueWith(t =>
{
    string newValue = Guid.NewGuid().ToString();
    Console.WriteLine($"TestValue的值即將被改為:{newValue}, 時(shí)間:{DateTime.Now:HH:mm:ss}");
    hKey.SetValue("TestValue", newValue);
});
int ret = RegNotifyChangeKeyValue(hKey.Handle, false, RegNotifyFilter.ChangeLastSet, new SafeWaitHandle(IntPtr.Zero, true), false);
if(ret != 0)
{
    Console.WriteLine($"出錯了:{ret}");
    return;
}
string currentValue = hKey.GetValue("TestValue").ToString();
Console.WriteLine($"TestValue的最新值是:{currentValue}, 時(shí)間:{DateTime.Now:HH:mm:ss}");
hKey.Close();
Console.ReadLine();

運(yùn)行結(jié)果:

異步模式

RegNotifyChangeKeyValue的最后一個(gè)參數(shù)傳遞true,表示以異步的方式監(jiān)聽。
異步模式的關(guān)鍵點(diǎn)是需要創(chuàng)建一個(gè)事件,然后RegNotifyChangeKeyValue會立即返回,不會阻塞調(diào)用線程,然后需要在其他的線程中等待事件的觸發(fā)。
當(dāng)然也可以在RegNotifyChangeKeyValue返回之后立即等待事件,這樣跟同步阻塞沒有什么區(qū)別,如果不是出于演示目的,則沒什么意義。

出于演示目的毫無意義的異步模式示例:

RegistryKey hKey = Registry.CurrentUser.CreateSubKey("SOFTWARE\\1-RegMonitor");
string changeBefore = hKey.GetValue("TestValue").ToString();
Console.WriteLine($"TestValue的當(dāng)前值是:{changeBefore}, 時(shí)間:{DateTime.Now:HH:mm:ss}");
//此處創(chuàng)建一個(gè)任務(wù),5s之后修改TestValue的值為一個(gè)新的guid
Task.Delay(5000).ContinueWith(t =>
{
    string newValue = Guid.NewGuid().ToString();
    Console.WriteLine($"TestValue的值即將被改為:{newValue}, 時(shí)間:{DateTime.Now:HH:mm:ss}");
    hKey.SetValue("TestValue", newValue);
});
ManualResetEvent manualResetEvent = new ManualResetEvent(false);
int ret = RegNotifyChangeKeyValue(hKey.Handle, false, RegNotifyFilter.ChangeLastSet, manualResetEvent.SafeWaitHandle, true);
if(ret != 0)
{
    Console.WriteLine($"出錯了:{ret}");
    return;
}
Console.WriteLine($"RegNotifyChangeKeyValue立即返回,時(shí)間:{DateTime.Now:HH:mm:ss}");
manualResetEvent.WaitOne();
string currentValue = hKey.GetValue("TestValue").ToString();
Console.WriteLine($"TestValue的最新值是:{currentValue}, 時(shí)間:{DateTime.Now:HH:mm:ss}");
hKey.Close();
manualResetEvent.Close();
Console.WriteLine("收工");
Console.ReadLine();

運(yùn)行結(jié)果:

正經(jīng)的代碼大概應(yīng)該這么寫:

演示代碼請忽略參數(shù)未判空,異常未處理等場景

class RegistryMonitor
{
    private Thread m_thread = null;
    private string m_keyName;
    private RegNotifyFilter m_notifyFilter = RegNotifyFilter.ChangeLastSet;
    public event EventHandler RegistryChanged;
    public RegistryMonitor(string keyName, RegNotifyFilter notifyFilter)
    {
        this.m_keyName = keyName;
        this.m_notifyFilter = notifyFilter;
        this.m_thread = new Thread(ThreadAction);
        this.m_thread.IsBackground = true;
    }
    public void Start()
    {
        this.m_thread.Start();
    }
    private void ThreadAction()
    {
        using(RegistryKey hKey = Registry.CurrentUser.CreateSubKey(this.m_keyName))
        {
            using(ManualResetEvent waitHandle = new ManualResetEvent(false))
            {
                int ret = RegNotifyChangeKeyValue(hKey.Handle, false, this.m_notifyFilter, waitHandle.SafeWaitHandle, true);
                waitHandle.WaitOne();
                this.RegistryChanged?.Invoke(this, EventArgs.Empty);
            }
        }
    }
}
static void Main(string[] args)
{
    string keyName = "SOFTWARE\\1-RegMonitor";
    RegistryKey hKey = Registry.CurrentUser.CreateSubKey(keyName);
    string changeBefore = hKey.GetValue("TestValue").ToString();
    Console.WriteLine($"TestValue的當(dāng)前值是:{changeBefore}, 時(shí)間:{DateTime.Now:HH:mm:ss}");
    //此處創(chuàng)建一個(gè)任務(wù),5s之后修改TestValue的值為一個(gè)新的guid
    Task.Delay(5000).ContinueWith(t =>
    {
        string newValue = Guid.NewGuid().ToString();
        Console.WriteLine($"TestValue的值即將被改為:{newValue}, 時(shí)間:{DateTime.Now:HH:mm:ss}");
        hKey.SetValue("TestValue", newValue);
    });
    RegistryMonitor monitor = new RegistryMonitor(keyName, RegNotifyFilter.ChangeLastSet);
    monitor.RegistryChanged += (sender, e) =>
    {
        Console.WriteLine($"{keyName}的值發(fā)生了改變");
        string currentValue = hKey.GetValue("TestValue").ToString();
        Console.WriteLine($"TestValue的最新值是:{currentValue}, 時(shí)間:{DateTime.Now:HH:mm:ss}");
        hKey.Close();
    };
    monitor.Start();
    Console.WriteLine("收工");
    Console.ReadLine();
}

運(yùn)行結(jié)果:

那么問題來了:

  • 上面監(jiān)聽一個(gè)路徑就需要創(chuàng)建一個(gè)線程,如果要監(jiān)聽多個(gè)路徑,就需要創(chuàng)建多個(gè)線程,且他們什么事都不干,就在那等,這不太科學(xué)。
  • 經(jīng)常寫C#的都知道,一般不建議代碼中直接創(chuàng)建Thread。
  • 改成線程池或者Task行不行?如果在線程池或者Task里面調(diào)用WaitOne進(jìn)行阻塞,那也是不行的。

接下來 ,我們嘗試改造一下

基于線程池的異步模式

調(diào)用線程池的RegisterWaitForSingleObject,給一個(gè)事件注冊一個(gè)回調(diào),當(dāng)事件觸發(fā)時(shí),則執(zhí)行指定的回調(diào)函數(shù),參考ThreadPool.RegisterWaitForSingleObject 方法 (System.Threading) | Microsoft Learn

代碼實(shí)例如下:

class RegistryMonitor
{
    private string m_keyName;
    private RegNotifyFilter m_notifyFilter = RegNotifyFilter.ChangeLastSet;
    private RegisteredWaitHandle m_registered = null;
    private RegistryKey m_key = null;
    private ManualResetEvent m_waitHandle = null;
    public event EventHandler RegistryChanged;
    public RegistryMonitor(string keyName, RegNotifyFilter notifyFilter)
    {
        this.m_keyName = keyName;
        this.m_notifyFilter = notifyFilter;
    }
    public void Start()
    {
        this.m_key = Registry.CurrentUser.CreateSubKey(this.m_keyName);
        this.m_waitHandle = new ManualResetEvent(false);
        int ret = RegNotifyChangeKeyValue(this.m_key.Handle, false, this.m_notifyFilter | RegNotifyFilter.ThreadAgnostic, this.m_waitHandle.SafeWaitHandle, true);
        this.m_registered = ThreadPool.RegisterWaitForSingleObject(this.m_waitHandle, Callback, null, Timeout.Infinite, true);
    }
    private void Callback(object state, bool timedOut)
    {
        this.m_registered.Unregister(this.m_waitHandle);
        this.m_waitHandle.Close();
        this.m_key.Close();
        this.RegistryChanged?.Invoke(this, EventArgs.Empty);
    }
}
static void Main(string[] args)
{
    for(int i = 1; i <= 50; i++)
    {
        string keyName = $"SOFTWARE\\1-RegMonitor\\{i}";
        RegistryKey hKey = Registry.CurrentUser.CreateSubKey(keyName);
        hKey.SetValue("TestValue", Guid.NewGuid().ToString());
        string changeBefore = hKey.GetValue("TestValue").ToString();
        Console.WriteLine($"{keyName} TestValue的當(dāng)前值是:{changeBefore}, 時(shí)間:{DateTime.Now:HH:mm:ss}");
        RegistryMonitor monitor = new RegistryMonitor(keyName, RegNotifyFilter.ChangeLastSet);
        monitor.RegistryChanged += (sender, e) =>
        {
            Console.WriteLine($"{keyName}的值發(fā)生了改變");
            string currentValue = hKey.GetValue("TestValue").ToString();
            Console.WriteLine($"{keyName} TestValue的最新值是:{currentValue}, 時(shí)間:{DateTime.Now:HH:mm:ss}");
            hKey.Close();
        };
        monitor.Start();
        Console.WriteLine($"{keyName}監(jiān)聽中...");
    }
    Console.WriteLine("收工");
    Console.ReadLine();
}

運(yùn)行結(jié)果:

可以看到,創(chuàng)建50個(gè)監(jiān)聽,而進(jìn)程的總線程數(shù)只有7個(gè)。因此使用線程池是最佳方案。

注意事項(xiàng)

  • 官方文檔有說明,調(diào)用RegNotifyChangeKeyValue需要再持久化的線程中,如果不能保證調(diào)用線程持久化(如在線程池中調(diào)用),則可以加上REG_NOTIFY_THREAD_AGNOSTIC標(biāo)識
  • 示例中的監(jiān)聽都是一次性的,重復(fù)監(jiān)聽只需要在事件觸發(fā)后再次執(zhí)行RegNotifyChangeKeyValue的流程即可

基礎(chǔ)代碼

/// <summary>
/// 指示應(yīng)報(bào)告的更改
/// </summary>
[Flags]
enum RegNotifyFilter
{
    /// <summary>
    /// 通知調(diào)用方是添加還是刪除了子項(xiàng)
    /// </summary>
    ChangeName = 0x00000001,
    /// <summary>
    /// 向調(diào)用方通知項(xiàng)屬性(例如安全描述符信息)的更改
    /// </summary>
    ChangeAttributes = 0x00000002,
    /// <summary>
    /// 向調(diào)用方通知項(xiàng)值的更改。 這包括添加或刪除值,或更改現(xiàn)有值
    /// </summary>
    ChangeLastSet = 0x00000004,
    /// <summary>
    /// 向調(diào)用方通知項(xiàng)的安全描述符的更改
    /// </summary>
    ChangeSecurity = 0x00000008,
    /// <summary>
    /// 指示注冊的生存期不得綁定到發(fā)出 RegNotifyChangeKeyValue 調(diào)用的線程的生存期。<b>注意</b> 此標(biāo)志值僅在 Windows 8 及更高版本中受支持。
    /// </summary>
    ThreadAgnostic = 0x10000000
}
/// <summary>
/// 通知調(diào)用方對指定注冊表項(xiàng)的屬性或內(nèi)容的更改。
/// </summary>
/// <param name="hKey">打開的注冊表項(xiàng)的句柄。密鑰必須已使用KEY_NOTIFY訪問權(quán)限打開。</param>
/// <param name="bWatchSubtree">如果此參數(shù)為 TRUE,則函數(shù)將報(bào)告指定鍵及其子項(xiàng)中的更改。 如果參數(shù)為 FALSE,則函數(shù)僅報(bào)告指定鍵中的更改。</param>
/// <param name="dwNotifyFilter">
/// 一個(gè)值,該值指示應(yīng)報(bào)告的更改。 此參數(shù)可使用以下一個(gè)或多個(gè)值。<br/>
/// REG_NOTIFY_CHANGE_NAME 0x00000001L 通知調(diào)用方是添加還是刪除了子項(xiàng)。<br/>
/// REG_NOTIFY_CHANGE_ATTRIBUTES 0x00000002L 向調(diào)用方通知項(xiàng)屬性(例如安全描述符信息)的更改。<br/>
/// REG_NOTIFY_CHANGE_LAST_SET 0x00000004L 向調(diào)用方通知項(xiàng)值的更改。 這包括添加或刪除值,或更改現(xiàn)有值。<br/>
/// REG_NOTIFY_CHANGE_SECURITY 0x00000008L 向調(diào)用方通知項(xiàng)的安全描述符的更改。<br/>
/// REG_NOTIFY_THREAD_AGNOSTIC 0x10000000L 指示注冊的生存期不得綁定到發(fā)出 RegNotifyChangeKeyValue 調(diào)用的線程的生存期。<b>注意</b> 此標(biāo)志值僅在 Windows 8 及更高版本中受支持。
/// </param>
/// <param name="hEvent">事件的句柄。 如果 fAsynchronous 參數(shù)為 TRUE,則函數(shù)將立即返回 ,并通過發(fā)出此事件信號來報(bào)告更改。 如果 fAsynchronous 為 FALSE,則忽略 hEvent 。</param>
/// <param name="fAsynchronous">
/// 如果此參數(shù)為 TRUE,則函數(shù)將立即返回并通過向指定事件發(fā)出信號來報(bào)告更改。 如果此參數(shù)為 FALSE,則函數(shù)在發(fā)生更改之前不會返回 。<br/>
/// 如果 hEvent 未指定有效的事件, 則 fAsynchronous 參數(shù)不能為 TRUE。
/// </param>
/// <returns></returns>
[DllImport("Advapi32.dll", CharSet = CharSet.Unicode, SetLastError = true)]
private static extern int RegNotifyChangeKeyValue(SafeHandle hKey, bool bWatchSubtree, RegNotifyFilter dwNotifyFilter, SafeHandle hEvent, bool fAsynchronous);

到此這篇關(guān)于C#使用RegNotifyChangeKeyValue監(jiān)聽注冊表更改的幾種方式的文章就介紹到這了,更多相關(guān)C# RegNotifyChangeKeyValue監(jiān)聽注冊表內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • C#基于Spire.Doc for .NET從URL下載Word文檔的實(shí)現(xiàn)方案

    C#基于Spire.Doc for .NET從URL下載Word文檔的實(shí)現(xiàn)方案

    在日常的軟件開發(fā)中,我們經(jīng)常會遇到這樣的場景:需要從一個(gè)指定的 URL 地址下載文件,當(dāng)涉及到 Word 文檔這類復(fù)雜的二進(jìn)制格式時(shí),情況就變得不那么簡單了,本文將深入探討在 C# 應(yīng)用程序中,如何高效、可靠地從 URL 下載 Word 文檔,需要的朋友可以參考下
    2025-12-12
  • c#獲取本機(jī)在局域網(wǎng)ip地址的二種方法

    c#獲取本機(jī)在局域網(wǎng)ip地址的二種方法

    在項(xiàng)目中經(jīng)常要獲取用戶的上網(wǎng)的IP地址,如何獲取用戶的IP地址,方法很多,現(xiàn)在介紹以下2種
    2014-01-01
  • C#三種方法獲取文件的Content-Type(MIME Type)

    C#三種方法獲取文件的Content-Type(MIME Type)

    這篇文章介紹了C#獲取文件Content-Type(MIME Type)的三種方法,文中通過示例代碼介紹的非常詳細(xì)。對大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2022-01-01
  • C#特性之匿名方法和Lambda表達(dá)式

    C#特性之匿名方法和Lambda表達(dá)式

    這篇文章主要介紹了C#特性之匿名方法和Lambda表達(dá)式,需要的朋友可以參考下
    2014-12-12
  • C#中使用YOLO的常用方式的詳細(xì)指南

    C#中使用YOLO的常用方式的詳細(xì)指南

    在C#中使用YOLO(You Only Look Once)目標(biāo)檢測算法,通常有幾種不同的實(shí)現(xiàn)方式,例如OpenCV,ONNX Runtime等,下面我們來看看具體的操作方法吧
    2025-05-05
  • c#調(diào)用jar包的方法步驟(非常詳細(xì))

    c#調(diào)用jar包的方法步驟(非常詳細(xì))

    這篇文章主要給大家介紹了關(guān)于c#調(diào)用jar包的方法步驟,文中通過圖文介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2021-01-01
  • c#獲取兩個(gè)特定字符之間的內(nèi)容并輸出的方法

    c#獲取兩個(gè)特定字符之間的內(nèi)容并輸出的方法

    今天小編就為大家分享一篇c#獲取兩個(gè)特定字符之間的內(nèi)容并輸出的方法,具有很好的參考價(jià)值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2018-12-12
  • c# mutex互斥量的深入解析

    c# mutex互斥量的深入解析

    本篇文章主要是對c#中的mutex互斥量進(jìn)行了詳細(xì)的分析介紹,需要的朋友可以過來參考下,希望對大家有所幫助
    2014-01-01
  • 詳細(xì)介紹C# 泛型

    詳細(xì)介紹C# 泛型

    這篇文章主要介紹了C# 泛型的相關(guān)資料,幫助大家更好的理解和學(xué)習(xí)C#,感興趣的朋友可以了解下
    2020-08-08
  • Unity利用UGUI制作提示框效果

    Unity利用UGUI制作提示框效果

    這篇文章主要為大家詳細(xì)介紹了Unity利用UGUI制作提示框效果,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2020-06-06

最新評論

麻城市| 涟源市| 五家渠市| 阳江市| 蒙城县| 天气| 新平| 南和县| 新野县| 北宁市| 阿图什市| 开化县| 合水县| 崇左市| 明溪县| 迭部县| 海伦市| 罗江县| 昌都县| 楚雄市| 喀什市| 广德县| 泰宁县| 拉萨市| 普兰店市| 海伦市| 饶河县| 蒙自县| 资阳市| 饶平县| 彩票| 吉木乃县| 卓尼县| 赤水市| 祁东县| 金溪县| 万盛区| 聊城市| 棋牌| 三台县| 石渠县|