Как скопировать строку в буфер обмена в моем консольном приложении БЕЗ добавления ссылки на System.Windows.Forms?
У меня есть консольное приложение .NET 4.0, которое генерирует SQL и сохраняет его в строковой переменной. Я хочу, чтобы эта строка была скопирована непосредственно в буфер обмена.
До сих пор все мои исследования показывают, что ТОЛЬКО это возможно сделать, добавив ссылку на System.Windows.Forms. Я не хочу добавлять ссылку на сборку, которая не имеет отношения к консольному приложению.
В пределах юниверса, в котором мы в настоящее время существуем, существует ли известный способ копирования строки текста в буфер обмена в консольном приложении, который не включает добавление ссылки на System.Windows.Forms или любую другую сборку, целью которой является не имеет отношения к консольному приложению bare-bones?
Ответы
Ответ 1
Платформа, вызывающая, API-интерфейс буфера обмена является возможным решением. Пример:
using System.Runtime.InteropServices;
class Program
{
[DllImport("user32.dll")]
internal static extern bool OpenClipboard(IntPtr hWndNewOwner);
[DllImport("user32.dll")]
internal static extern bool CloseClipboard();
[DllImport("user32.dll")]
internal static extern bool SetClipboardData(uint uFormat, IntPtr data);
[STAThread]
static void Main(string[] args)
{
OpenClipboard(IntPtr.Zero);
var yourString = "Hello World!";
var ptr = Marshal.StringToHGlobalUni(yourString);
SetClipboardData(13, ptr);
CloseClipboard();
Marshal.FreeHGlobal(ptr);
}
}
Это просто пример. Добавление небольшой обработки ошибок вокруг кода, например проверка возвращаемых значений функций P/Invoke, будет хорошим дополнением.
SetClipboardData
- интересный бит. Вы также хотите, чтобы вы открыли и закрывали буфер обмена.
13
передается как первый аргумент - это формат данных. 13 означает строку Unicode.
Ответ 2
Функция Marshal.StringToHGlobalUni
фактически распределяет память в непригодном для SetClipboardData (using LocalAlloc with LMEM_FIXED)
способе, который может привести к сбоям (вы не ожидали, что это дано имя метода, но вступает в код, например, используя ReSharper показывает это).
SetClipboardData
требует GlobalAlloc
с GMEM_MOVABLE
в соответствии с документацией: SetClipboardData на MSDN.
Здесь MIT лицензировал System.Windows.Forms альтернативу, протестировал и завершил обработку ошибок: Clippy
(Сам код нажатия на буфер обмена можно найти здесь: Clippy.cs.)