2011-01-17 2 views
4

Ich habe eine Konsolenanwendung mit einem Befehlsinterpreter erstellt. Um die Dinge einfacher zu machen, musste ich Unterstützung für das Lesen der Zwischenablage hinzufügen, wenn ctrl + v gedrückt wird. Wenn ich Strg + V drücke, sehe ich das Symbol ^V in der Konsole, also ersetze ich dieses Zeichen durch den Text der Zwischenablage. Nach etwas googeln habe ich herausgefunden, dass die Zwischenablage von System.Windows.Forms.Clipboard.GetText() zugegriffen werden kann.Gibt es eine einfachere Möglichkeit, die Windows-Funktion ctrl + v (Einfügen) in einer C# -Konsolenanwendung zu verwenden?

Meine Frage ist: Gibt es eine bessere Lösung zum Hinzufügen von Zwischenablage-Unterstützung zu einer Konsolenanwendung? Möglicherweise ohne System.Windows.Forms.Clipboard? Vielleicht kann ein Interop-Anruf den Trick machen?

Einer der Nachteile dieser Lösung ist, dass die Zwischenablage nur funktioniert, wenn der Thread als [STAThread] definiert ist. Es wäre auch viel schöner, wenn ich das^V-Symbol loswerden könnte.

Dies ist der Code der aktuellen Lösung:

using System; 
using System.Threading; 
using System.Windows.Forms; 

namespace ConsoleApplication1 
{ 
    class Program 
    { 
     public static readonly string ClipboardChar = Convert.ToChar(22).ToString(); 

     [STAThread] 
     static void Main(string[] args) 
     { 
      Console.Write("Do some pastin': "); 

      //read 
      Console.ForegroundColor = ConsoleColor.White; 
      string result = Console.ReadLine(); 
      Console.ResetColor(); 

      //read keyboard 
      if (result.Contains(ClipboardChar)) 
      { 
       result = result.Replace(ClipboardChar, Clipboard.GetText()); 
      } 

      //write result 
      Console.WriteLine("\nResult: "); 
      Console.ForegroundColor = ConsoleColor.White; 
      Console.WriteLine(result); 
      Console.ResetColor(); 

      Console.WriteLine("\nPress any key to continue..."); 
      Console.ReadKey(); 
     } 
    } 
} 
+0

Warum ... möchten Sie keinen Verweis auf System.Windows.Forms? Es ist eine Standard-.NET-Bibliothek, sodass Ihre Anwendung bei der Bereitstellung nicht größer wird. Und wenn Sie eine andere Methode verwenden, wird der Start Ihrer Anwendung sowieso langsamer – Martheen

+1

Wie wäre es langsamer? Ich habe der Frage einige Nachteile der aktuellen Lösung hinzugefügt: Einer der Nachteile dieser Lösung ist, dass die Zwischenablage nur funktioniert, wenn der Thread als [STAThread] definiert ist. Es wäre auch viel schöner, wenn ich das^V-Symbol loswerden könnte. –

+1

zu anderen Hinweis, finden Sie diese Artikel auf Erweiterung Konsole API von .NET nützlich: http://www.devsource.com/c/a/Using-VS/Console-Input-in-NET/, http: // www.devsource.com/c/a/Using-VS/Working-with-Console-Screen-Buffers-in-NET/1/ – VinayC

Antwort

8

Sie können sicherlich P/Invoke verwenden, um dies zu tun. Bitte behandeln Sie den Beispielcode als Proof-of-Concept, da er schnell zusammengeschustert wurde & getestet. Ich habe ein paar Freiheiten genommen - zum Beispiel gibt mein Prototyp für GlobalLockstring zurück, obwohl die Win API wirklich LPVOID zurückgibt.

using System; 
using System.Runtime.InteropServices; 

namespace clipboard 
{ 
    class Program 
    { 
     public static void Main(string[] args) 
     { 
      ConsoleKeyInfo ki = Console.ReadKey(true); 
      if((ki.Key == ConsoleKey.V) && (ki.Modifiers == ConsoleModifiers.Control)) 
      { 
       Console.WriteLine("Ctrl+V pressed"); 
       string s = ClipBoard.PasteTextFromClipboard(); 
       Console.WriteLine(s); 
      } 

      Console.Write("Press any key to continue . . . "); 
      Console.ReadKey(true); 
     } 
    } 

    class ClipBoard 
    { 
     [DllImport("user32.dll", SetLastError = true)] 
     private static extern Int32 IsClipboardFormatAvailable(uint format); 

     [DllImport("user32.dll", SetLastError = true)] 
     private static extern Int32 OpenClipboard(IntPtr hWndNewOwner); 

     [DllImport("user32.dll", SetLastError = true)] 
     private static extern IntPtr GetClipboardData(uint uFormat); 

     [DllImport("user32.dll", SetLastError = true)] 
     private static extern Int32 CloseClipboard(); 

     [DllImport("kernel32.dll", SetLastError = true)] 
     private static extern Int32 GlobalLock(IntPtr hMem); 

     [DllImport("kernel32.dll", SetLastError = true)] 
     private static extern Int32 GlobalUnlock(IntPtr hMem); 

     [DllImport("kernel32.dll")] 
     public static extern UIntPtr GlobalSize(IntPtr hMem); 

     const uint CF_TEXT = 1; 

     public static string PasteTextFromClipboard() 
     { 
      string result = ""; 
      if(IsClipboardFormatAvailable(CF_TEXT) == 0) 
      { 
       return result; 
      } 
      if(OpenClipboard((IntPtr)0) == 0) 
      { 
       return result; 
      } 

      IntPtr hglb = GetClipboardData(CF_TEXT); 
      if(hglb != (IntPtr)0) 
      { 
       UIntPtr size = GlobalSize(hglb); 
       IntPtr s = GlobalLock(hglb); 
       byte[] buffer = new byte[(int)size]; 
       Marshal.Copy(s, buffer, 0, (int)size); 
       if (s != null) 
       { 
        result = ASCIIEncoding.ASCII.GetString(buffer); 
        GlobalUnlock(hglb); 
       } 
      } 

      CloseClipboard(); 
      return result; 
     } 
    } 
} 
+0

Sieht gut aus ... aber jetzt muss ich in die Frage schauen, wie ReadLine() mit ReadKey() simuliert wird: D –

+0

Dieses P/Invoke entfernt auch das [STAThread], das für System.Windows benötigt wurde. Formulare.Clipboard! : D –

+0

Ich liebe dich Mann. Sehr schlau und effektiv. Ich habe Formulare für die Effizienz losgeworden, und ich hasste es wirklich, sie wieder zu injizieren. Danke –

3

Wenn Sie das Symbol in der linken oberen Ecke des Fensters Konsolenanwendung klicken Sie auf ‚Bearbeiten‘ erhalten | 'Einfügen' Option.

+2

Hahaha ... ja, aber meine Benutzer wollen die Unterstützung über ctlr + v. –

+1

Zu einfach und genau das, was ich brauchte. Danke :) – Brian

+0

Ich denke 'Alt + Space, E, P' sollte schneller sein, als auf das Ecksymbol zu klicken. –

Verwandte Themen