65.9K
CodeProject 正在变化。 阅读更多。
Home

C# 中的剪贴板备份

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.38/5 (14投票s)

2006 年 8 月 25 日

2分钟阅读

viewsIcon

96635

downloadIcon

3727

使用 C# 和 Windows API 调用备份剪贴板,以避免 C# 对剪贴板管理的限制。

引言

该代码使用 Windows API 调用来读取和写入剪贴板。

它提供了一个 ClipboardHelper,一个易于使用的 API 桥接器,它还提供了使用 XmlSerializer 将复杂的剪贴板数据序列化到硬盘并在需要时恢复的功能,而不是 .NET Framework,后者只能管理符合 CLR 的数据。

我在 Internet Explorer、Word、OpenOffice(包括图像文件)中测试了它。

背景

.NET framework 和 Windows.Forms.Clipboard 类只允许操作可序列化的数据。那么,如果您的剪贴板包含来自不兼容应用程序的数据会发生什么?很简单!.NET Framework 认为剪贴板是空的。

要读取和操作这些数据,我们需要调用user32.dllkernerl32.dll

使用代码

该代码包括两个项目:库 ClipboardHelper 和控制台应用程序 ClipboardTest。

整个代码都添加了注释,以理解 API 的使用和实现的保存过程。

使用该库非常容易:它是一个静态类,公开了一个static void ClipboardHelper.Serialize函数,用于将剪贴板数据序列化到硬盘,以及static void Deserialize用于反序列化它并将其放回剪贴板,准备好粘贴。

    //Comment next line to end the demo mode
    //and backup your clipboard data.
    ClipboardHelper.Deserialize(demo);
    Console.WriteLine("restore the demo clipboard");

    //Open the clipboard and serialize into a directory
    ClipboardHelper.Serialize(fileName);
    Console.WriteLine("serialize clipboard to " + fileName);

    //Deserialize the clipboard and set data
    //to win clipboard ready to be pasted
    ClipboardHelper.Deserialize(fileName);
    Console.WriteLine("restore the clipboard " + fileName);

测试应用程序展示了 ClipboardHelper 的一个实际例子。 它在从 CodeProject 主页上的 Internet Explorer 复制了一些行后,反序列化剪贴板,备份它,然后再次从备份中反序列化它。运行它之后,您的剪贴板中就有剪贴板备份,可以粘贴。

ClipboardHelper 内部

API 调用返回的数据保存在 [Serializable]DataClip 对象中。 它允许轻松地在远程处理上下文中发送剪贴板,并通过 XmlSerializer 保存它。

public static void SaveToFile(ReadOnlyCollection<DATACLIP> clipData, string clipName)
{
    IEnumerator<DATACLIP> cData = clipData.GetEnumerator();
    while (cData.MoveNext())
    {
        XmlSerializer xml = new XmlSerializer(typeof(DataClip));
        using (StreamWriter sw = new StreamWriter(di.FullName + 
                                 @"\" + i.ToString() + ".cli",false))
        {
            xml.Serialize(sw, cData.Current);
        }
    }
 }

深入剪贴板

剪贴板包含碎片缓冲区中的数据。 它们中的每一个都有一个特定的 DataFormat,供剪贴板查看器和从中复制数据的软件使用,以识别如何正确呈现缓冲区。

user32.dll的函数 EnumClipboardFormats 返回剪贴板中包含的 DataFormat 数组。 对于每个 DataFormat,我们可以调用 GetClipboardData。 它返回剪贴板对象的句柄。 通过调用 kernel32.dllGlobalSizeGlobalLock,我们获得剪贴板对象的属性(它的长度和指向它的指针),因此我们可以通过 Marshal.Copy 方法将剪贴板对象复制到我们的缓冲区(一个byte 数组)。

要获取剪贴板,首先要检查是否打开了剪贴板

Win32ClipboardAPI.OpenClipboard(IntPtr.Zero)

然后,我们获取所有 DataFormat;查询它们,我们得到剪贴板数据缓冲区

    //Init a list of ClipData,
    // which will contain each Clipboard Data
    List<DataClip> clipData = new List<DataClip>();
    //Loop for each clipboard data type
    uint format = 0;
    while ((format = Win32ClipboardAPI.EnumClipboardFormats(format)) != 0)
    {
        //Get the formatName
        StringBuilder formatName = new StringBuilder();
        Win32ClipboardAPI.GetClipboardFormatName(format, 
                                       formatName, 100);
        
        //Get the pointer for the current Clipboard Data 
        IntPtr pos = Win32ClipboardAPI.GetClipboardData(format);
        //Get the clipboard buffer data properties
        UIntPtr lenght = Win32MemoryAPI.GlobalSize(pos);
        IntPtr gLock = Win32MemoryAPI.GlobalLock(pos);
        byte[] buffer;
        //Init a buffer which will contain the clipboard data
        buffer = new byte[(int)lenght];
        int l = Convert.ToInt32(lenght.ToString());
        //Copy data from clipboard to our byte[] buffer
        Marshal.Copy(gLock, buffer, 0, l);
        //Create a ClipData object that 
        //represents the current clipboard data
        DataClip cd = new DataClip(format, 
                      formatName.ToString(), buffer);
        //Add current Clipboard Data to the list
        clipData.Add(cd);
}

历史

  • 2006/08/23 - 初始版本。
  • 2006/08/29 - 整个保存系统都已更改,实现了 XmlSerializer。 它工作得更好,解决了写入文件过程中的错误。
© . All rights reserved.