2017-05-21 23 views
1

如果系统剪贴板上有大量文本(例如150MB文本文件),我希望能够以Unicode文本的形式从流中读取系统剪贴板,例如避免OutOfMemoryException。这是否可以通过调整下面的pinvoke例子来完成?将系统剪贴板作为流而不是字符串读取

对于这些非常大的剪贴板,Clipboard.GetText(TextDataFormat.UnicodeText)将返回一个空字符串而不会引发异常。

或者,如果我使用的PInvoke像从这里的例子中,我会得到一个OutOfMemoryException http://komalmangal.blogspot.ca/2016/04/how-to-get-clipboard-data-and-its-size.html

[DllImport("user32.dll")] 
    static extern IntPtr GetClipboardData(uint uFormat); 
    [DllImport("user32.dll")] 
    static extern bool IsClipboardFormatAvailable(uint format); 
    [DllImport("user32.dll", SetLastError = true)] 
    static extern bool OpenClipboard(IntPtr hWndNewOwner); 
    [DllImport("user32.dll", SetLastError = true)] 
    static extern bool CloseClipboard(); 
    [DllImport("kernel32.dll")] 
    static extern IntPtr GlobalLock(IntPtr hMem); 
    [DllImport("kernel32.dll")] 
    static extern bool GlobalUnlock(IntPtr hMem); 

    const uint CF_UNICODETEXT = 13; 
    public static string GetText() 
    { 
     if (!IsClipboardFormatAvailable(CF_UNICODETEXT)) 
      return null; 
     if (!OpenClipboard(IntPtr.Zero)) 
      return null; 

     string data = null; 
     var hGlobal = GetClipboardData(CF_UNICODETEXT); 
     if (hGlobal != IntPtr.Zero) 
     { 
      var lpwcstr = GlobalLock(hGlobal); 
      if (lpwcstr != IntPtr.Zero) 
      { 
       data = Marshal.PtrToStringUni(lpwcstr); 
       GlobalUnlock(lpwcstr); 
      } 
     } 
     CloseClipboard(); 

     return data; 
    } 
+0

您选择了文件并复制或打开,然后选择所有文本,然后复制? –

+0

作为测试我在Notepad ++中打开一个大文件并选择全部然后复制,但实际上,剪贴板可能来自其他地方,例如SQL Server Management Studio。 – tjsmith

+1

150Mb(在ANSI或UTF8中)为unicode〜=> 300Mb的内存。所以你最终会得到300M(剪贴板)+ 300M(你的.NET字符串)=> 600M的进程内存,流或不流。内存不足可能会发生在剪贴板中的大量信息中。除非你想用剪贴板内容做别的事情,比如直接将它保存为一个文件,而不是将它实现为一个字符串。这样做会导致潜在的记忆问题。 –

回答

5

这将写出系统剪贴板到一个文本文件,而无需先将其转换为字符串,使要写出非常大的剪贴板而不会遇到OutOfMemoryException。它要求使用/不安全的标志来构建Visual Studio项目。

[DllImport("user32.dll")] 
private static extern IntPtr GetClipboardData(uint uFormat); 
[DllImport("user32.dll")] 
private static extern bool IsClipboardFormatAvailable(uint format); 
[DllImport("user32.dll", SetLastError = true)] 
private static extern bool OpenClipboard(IntPtr hWndNewOwner); 
[DllImport("user32.dll", SetLastError = true)] 
private static extern bool CloseClipboard(); 
[DllImport("kernel32.dll")] 
private static extern IntPtr GlobalLock(IntPtr hMem); 
[DllImport("kernel32.dll")] 
private static extern bool GlobalUnlock(IntPtr hMem); 
[DllImport("kernel32.dll")] 
private static extern UIntPtr GlobalSize(IntPtr hMem); 
private const uint CF_UNICODETEXT = 13; 

//Write the clipboard to a text file without having to first convert it to a string. 
//This avoids OutOfMemoryException for large clipboards and is faster than other methods 
public static bool WriteClipboardTextToFile(string filename) 
{ 
    try 
    { 
     if (!IsClipboardFormatAvailable(CF_UNICODETEXT) || !OpenClipboard(IntPtr.Zero)) 
      return false; 
    } 
    catch 
    { 
     return false; 
    } 

    try 
    { 
     var hGlobal = GetClipboardData(CF_UNICODETEXT); 
     if (hGlobal == IntPtr.Zero) 
      return false; 

     var lpwcstr = GlobalLock(hGlobal); 
     if (lpwcstr == IntPtr.Zero) 
      return false; 

     try 
     { 
      long length = (long)GlobalSize(lpwcstr); 
      Stream stream; 
      unsafe 
      { 
       stream = new UnmanagedMemoryStream((byte*)lpwcstr, length); 
      } 

      const int bufSize = 4096; 
      var buffer = new char[bufSize]; 
      using (var sw = new StreamWriter(new FileStream(filename, FileMode.Create, FileAccess.Write), Encoding.UTF8)) 
      { 
       //Clipboard text is in Encoding.Unicode == UTF-16LE 
       using (var sr = new StreamReader(stream, Encoding.Unicode)) 
       { 
        int charCount; 
        while (!sr.EndOfStream && (charCount = sr.ReadBlock(buffer, 0, bufSize)) > 0) 
        { 
         if (sr.EndOfStream && buffer[charCount - 1] == '\0') 
          sw.Write(buffer, 0, charCount - 1); //don't write out null terminator 
         else 
          sw.Write(buffer, 0, charCount); 
        } 
       } 
      } 
     } 
     finally 
     { 
      GlobalUnlock(lpwcstr); 
     } 
    } 
    catch 
    { 
     return false; 
    } 
    finally 
    { 
     try 
     { 
      CloseClipboard(); 
     } 
     catch 
     { 
      //ignore 
     } 
    } 
    return true; 
} 
相关问题