gpt4 book ai didi

c# - ClipboardInterop 内容更改触发两次

转载 作者:太空宇宙 更新时间:2023-11-03 13:45:57 26 4
gpt4 key购买 nike

我正在编写一个监视剪贴板更改的 WPF 应用程序。

我写了下面的类:

public class ClipboardInterop : IDisposable
{
public event EventHandler ClipboardContentChanged;

private void OnClipboardContentChanged()
{
var handlers = ClipboardContentChanged;
if (handlers != null)
{
handlers(this, new EventArgs());
}
}

public static ClipboardInterop GetClipboardInterop(Window window)
{
var hwndSource = PresentationSource.FromVisual(window) as HwndSource;
if (hwndSource == null) return null;

return new ClipboardInterop(hwndSource);
}

private IntPtr _thisHandle;
private IntPtr _nextHandle;
private HwndSource _hwndSource;

public bool IsListening { get; private set; }

private ClipboardInterop(HwndSource hwndSource)
{
_hwndSource = hwndSource;
_thisHandle = hwndSource.Handle;
IsListening = false;
}

public bool StartViewingClipboard()
{
Win32.SetLastError(0);
_nextHandle = Win32.SetClipboardViewer(_thisHandle);
if (_nextHandle == IntPtr.Zero)
{
UInt32 eCode = Win32.GetLastError();
if (eCode != 0)
{
return false;
}
}

_hwndSource.AddHook(HwndSourceHook);
IsListening = true;
return true;
}


public bool StopViewingClipboard()
{
Win32.SetLastError(0);
Win32.ChangeClipboardChain(_thisHandle, _nextHandle);
UInt32 eCode = Win32.GetLastError();
IsListening = false;
return eCode == 0;
}

private IntPtr HwndSourceHook(IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam, ref bool handled)
{
switch (msg)
{
case Win32.WM_CHANGECBCHAIN:
_nextHandle = lParam;
if (_nextHandle != IntPtr.Zero)
{
Win32.SendMessage(_nextHandle, (UInt32)msg, wParam, lParam);
}

break;

case Win32.WM_DRAWCLIPBOARD:

OnClipboardContentChanged();

if (_nextHandle != IntPtr.Zero)
{
Win32.SendMessage(_nextHandle, (UInt32)msg, wParam, lParam);
}

break;
}
return IntPtr.Zero;
}

public void Dispose()
{
if (IsListening)
StopViewingClipboard();
_hwndSource = null;
_nextHandle = IntPtr.Zero;
_thisHandle = IntPtr.Zero;
}
}

Win32.cs 看起来像:

internal static class Win32
{
/// <summary>
/// The WM_DRAWCLIPBOARD message notifies a clipboard viewer window that
/// the content of the clipboard has changed.
/// </summary>
internal const int WM_DRAWCLIPBOARD = 0x0308;

/// <summary>
/// A clipboard viewer window receives the WM_CHANGECBCHAIN message when
/// another window is removing itself from the clipboard viewer chain.
/// </summary>
internal const int WM_CHANGECBCHAIN = 0x030D;

[DllImport("user32.dll", SetLastError = true)]
public static extern IntPtr SetClipboardViewer(
IntPtr hWndNewViewer);

[DllImport("user32.dll")]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool ChangeClipboardChain(
IntPtr hWndRemove,
IntPtr hWndNewNext);

[DllImport("user32.dll", SetLastError = true)]
public static extern IntPtr SendMessage(
IntPtr hWnd,
UInt32 msg,
IntPtr wParam,
IntPtr lParam);

[DllImport("kernel32.dll")]
public static extern void SetLastError(
UInt32 errorCode);

[DllImport("kernel32.dll")]
public static extern UInt32 GetLastError();
}

主窗口.xaml

<Window x:Class="WpfApplication1.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="350" Width="525"
Loaded="MainWindow_OnLoaded">
<Button Content="Toggle" Click="ButtonBase_OnClick"></Button>
</Window>

主窗口.xaml.cs

public partial class MainWindow : Window
{
private ClipboardInterop _clipboardInterop;

public MainWindow()
{
InitializeComponent();
}

private void ButtonBase_OnClick(object sender, RoutedEventArgs e)
{
_clipboardInterop.StopViewingClipboard();
_clipboardInterop.StartViewingClipboard();
}

private void MainWindow_OnLoaded(object sender, RoutedEventArgs e)
{
_clipboardInterop = ClipboardInterop.GetClipboardInterop(this);
_clipboardInterop.StartViewingClipboard();
_clipboardInterop.ClipboardContentChanged +=
(o, args) => Debug.WriteLine(DateTime.Now.ToLongTimeString() + " Content changed");
}
}

所以现在当我启动应用程序时一切正常,当我将文本复制到剪贴板时事件被触发一次。当我单击按钮并再次将文本复制到剪贴板时,该事件被触发了两次。另一个按钮单击,事件被触发三次。我不知道为什么会这样。谁能帮帮我?

最佳答案

好吧,我在 this 的帮助下修改了我的代码,显然我忘记删除 StopViewingClipboard 中的钩子(Hook)。

固定代码如下:

public class ClipboardInterop : IDisposable
{
public event EventHandler ClipboardContentChanged;

private void OnClipboardContentChanged()
{
var handlers = ClipboardContentChanged;
if (handlers != null)
{
handlers(this, new EventArgs());
}
}

public static ClipboardInterop GetClipboardInterop(Window window)
{
var wih = new WindowInteropHelper(window);
var hwndSource = HwndSource.FromHwnd(wih.Handle);
if (hwndSource == null)
{
return null;
}

return new ClipboardInterop(hwndSource);
}

private IntPtr _hWndNextViewer;
private HwndSource _hWndSource;

public bool IsViewing { get; private set; }

private ClipboardInterop(HwndSource hwndSource)
{
_hWndSource = hwndSource;
IsViewing = false;
}

public bool StartViewingClipboard()
{
Win32.SetLastError(0);
_hWndNextViewer = Win32.SetClipboardViewer(_hWndSource.Handle);
if (_hWndNextViewer == IntPtr.Zero)
{
UInt32 eCode = Win32.GetLastError();
if (eCode != 0)
{
return false;
}
}
_hWndSource.AddHook(WinProc);
IsViewing = true;
return true;
}


public bool StopViewingClipboard()
{
Win32.SetLastError(0);
Win32.ChangeClipboardChain(_hWndSource.Handle, _hWndNextViewer);
_hWndNextViewer = IntPtr.Zero;
_hWndSource.RemoveHook(WinProc);
UInt32 eCode = Win32.GetLastError();
IsViewing = false;
return eCode == 0;
}

private IntPtr WinProc(IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam, ref bool handled)
{
switch (msg)
{
case Win32.WM_CHANGECBCHAIN:
if (wParam == _hWndNextViewer)
{
_hWndNextViewer = lParam;
}
else if (_hWndNextViewer != IntPtr.Zero)
{
Win32.SendMessage(_hWndNextViewer, msg, wParam, lParam);
}
break;

case Win32.WM_DRAWCLIPBOARD:
OnClipboardContentChanged();
Win32.SendMessage(_hWndNextViewer, msg, wParam, lParam);
break;

}
return IntPtr.Zero;
}

public void Dispose()
{
if (IsViewing)
StopViewingClipboard();
_hWndSource = null;
_hWndNextViewer = IntPtr.Zero;
}
}

关于c# - ClipboardInterop 内容更改触发两次,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/15333746/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com