我正在使用WndProc
和WM_DRAWCLIPBOARD
来监控Windows剪贴板并保存复制的文本和图像。除了一种情况外,它运作良好。我正在使用NotifyIcon
并且默认情况下应用程序停靠在通知区域(ShowInTaskbar
= False,WindowState
=最小化)。除了打开表单后,复制逻辑运行良好。当我右键单击应用程序的图标并单击“打开”时,虽然WM_DRAWCLIPBOARD
被不断调用,但在复制一段文本或图像时,WndProc
不再被调用。
NotifyIcon
是否使用与主UI不同的线程,如果是这样,NotifyIcon
线程可能不会监听UI线程。请注意,我实际上并不是Form.Show()
,而是我
我只是最大化表单并显示任务栏图标。当表格“关闭”时,相反的情况就完成了。这是我正在使用的代码。它只是一个类/形式,所以这就是全部。
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace Copy_Storer
{
[DefaultEvent("ClipboardChanged")]
public partial class frmMain : Form
{
IntPtr _NextClipboardViewer;
bool _AppStarting = true;
public frmMain()
{
InitializeComponent();
_NextClipboardViewer = (IntPtr)SetClipboardViewer((int)this.Handle);
}
private void frmMain_Load(object sender, EventArgs e)
{
nfyApp.ShowBalloonTip(10000);
cmsCSRightClick.ItemClicked += new ToolStripItemClickedEventHandler(cmsCSRightClick_ItemClicked);
_AppStarting = false;
}
[DllImport("User32.dll")]
public static extern int
SetClipboardViewer(int hWndNewViewer);
[DllImport("User32.dll", CharSet = CharSet.Auto)]
public static extern bool
ChangeClipboardChain(IntPtr hWndRemove,
IntPtr hWndNewNext);
[DllImport("user32.dll", CharSet = CharSet.Auto)]
public static extern int SendMessage(IntPtr hwnd, int wMsg,
IntPtr wParam,
IntPtr lParam);
void DisplayClipboardData()
{
object dataConverted = null;
string destinationFileName = string.Empty;
string destinationFilePath = string.Empty;
string dataType = string.Empty;
// Problem: After opening the form, the clipboard monitoring function stops working.
try
{
IDataObject iData = new DataObject();
iData = Clipboard.GetDataObject();
if (iData.GetDataPresent(DataFormats.Text) || iData.GetDataPresent(DataFormats.UnicodeText) ||
iData.GetDataPresent(DataFormats.Rtf))
{
// First check if the file already exists.
dataConverted = iData.GetData(DataFormats.Text); //http://social.msdn.microsoft.com/Forums/vstudio/en-US/9a09cb14-5eb3-4b74-9cf1-ac9e0ae641fc/convert-string-to-unicode?forum=csharpgeneral
destinationFileName = string.Format("{0} {1}.txt", "CopiedText", DateTime.Today.ToString("MM-dd-yy"));
destinationFilePath = string.Format("{0}\\{1}", Path.GetTempPath(), destinationFileName);
dataType = DataFormats.Text.ToString();
if (File.Exists(destinationFilePath))
{
// Append to the file
File.AppendAllText(destinationFilePath, string.Format("\r\n{0}", dataConverted));
}
else
{
// Create the file
File.WriteAllText(destinationFilePath, dataConverted.ToString());
}
}
else if (iData.GetDataPresent(DataFormats.Bitmap))
{
// Works for most (or all?) image types.
dataConverted = iData.GetData(DataFormats.Bitmap);
destinationFileName = string.Format("{0} {1} {2}.bmp", "CopiedImage", new Random().Next(1, 10000).ToString(), DateTime.Today.ToString("MM-dd-yy"));
destinationFilePath = string.Format("{0}\\{1}", Path.GetTempPath(), destinationFileName);
dataType = DataFormats.Bitmap.ToString();
while (File.Exists(destinationFilePath))
{
// Write a new path.
destinationFileName = string.Format("{0} {1} {2}.bmp", "CopiedImage", new Random().Next(1, 100000).ToString(), DateTime.Today.ToString("MM-dd-yy"));
destinationFilePath = string.Format("{0}\\{1}", Path.GetTempPath(), destinationFileName);
}
Bitmap copiedImage = (Bitmap)dataConverted;
copiedImage.Save(destinationFilePath);
}
// Add file to grid.
FileInfo f = new FileInfo(destinationFilePath);
string[] newRow = new string[] {destinationFileName, destinationFilePath, dataType, f.Length.ToString()};
dgvFilesCopied.Rows.Add(newRow);
}
catch (Exception e)
{
MessageBox.Show(e.ToString());
}
}
protected override void Dispose(bool disposing)
{
ChangeClipboardChain(this.Handle, _NextClipboardViewer);
if (disposing)
{
if (components != null)
{
components.Dispose();
}
}
base.Dispose(disposing);
}
protected override void WndProc(ref System.Windows.Forms.Message m)
{
// When user opens main form, WndProc is still reacting
// defined in winuser.h
const int WM_DRAWCLIPBOARD = 0x308;
const int WM_CHANGECBCHAIN = 0x030D;
bool randomValue = true;
if (m.Msg == /*WM_SIZE*/ 0x0005)
{
if (this.WindowState == FormWindowState.Minimized) randomValue = false;
}
switch (m.Msg)
{
case WM_DRAWCLIPBOARD:
if (!_AppStarting)
{
DisplayClipboardData();
SendMessage(_NextClipboardViewer, m.Msg, m.WParam, m.LParam);
}
break;
case WM_CHANGECBCHAIN:
if (m.WParam == _NextClipboardViewer)
_NextClipboardViewer = m.LParam;
else
SendMessage(_NextClipboardViewer, m.Msg, m.WParam, m.LParam);
break;
default:
base.WndProc(ref m);
break;
}
}
private void cmsCSRightClick_ItemClicked(object sender, ToolStripItemClickedEventArgs e)
{
switch (e.ClickedItem.Text)
{
case "Open":
// We want to show the form.
ShowHideMainForm(true);
break;
}
}
private void nfyApp_MouseDoubleClick(object sender, MouseEventArgs e)
{
// Show files saved
ShowHideMainForm(true);
if (dgvFilesCopied.Rows.Count < 1)
{
lblHeader.Text = "No files have been copied recently.";
}
}
private void frmMain_FormClosing(object sender, FormClosingEventArgs e)
{
// We only want to hide the form when using the X button of the form.
ShowHideMainForm(false);
e.Cancel = true;
// The form/app can be closed when the icon is right clicked -> Close.
}
private void ShowHideMainForm(bool show)
{
if (show)
{
this.ShowInTaskbar = true;
this.WindowState = FormWindowState.Normal;
}
else
{
this.ShowInTaskbar = false;
this.WindowState = FormWindowState.Minimized;
}
}
private void exitToolStripMenuItem_Click(object sender, EventArgs e)
{
this.Close();
}
}
}
会欣赏另一双眼睛。感谢。
答案 0 :(得分:2)
_NextClipboardViewer = (IntPtr)SetClipboardViewer((int)this.Handle);
您将此代码放在错误的位置。 Handle
属性不保证是稳定属性,当您修改表单的某些属性时,它可以更改。与ShowInTaskbar属性一样,它是一个传递给CreateWindowEx()的样式标志。更改它需要重新创建窗口。这改变了Handle,现在观众链断了。
你需要这样做:
protected override void OnHandleCreated(EventArgs e) {
base.OnHandleCreated(e);
_NextClipboardViewer = SetClipboardViewer(this.Handle);
}
protected override void OnHandleDestroyed(EventArgs e) {
ChangeClipboardChain(this.Handle, _NextClipboardViewer);
base.OnHandleDestroyed(e);
}
现在,您还可以在OnHandleCreated()上设置断点,并查看代码中的哪个语句导致此情况发生。第二次突破是最初的麻烦制造者。不再。请注意,您对SetClipboardViewer()的声明是错误的。