Давно хотел написать программу, которая бы хранила заготовки и шаблоны текста, для быстрой вставки в другие приложения. Стандартными средствами .NET это сделать не удалось. В интернете тоже нет конкретной информации, которая бы четко и ясно ответила бы на этот вопрос. По крупицам собрав и разобрав различную информацию, опробовав кучу способов, я смог написать кое-что. Сегодня разберем приложение, которое будет вставлять определенный текст в «чужую» программу.
Реализация
Как я писал выше, одними возможностями .NET такой фокус сделать нельзя. Берем наши старые функции WINAPI. Нам понадобится 7 таких функций. Ниже они перечислены. Каждую описывать не буду. Ищите в MSDN.
1 |
using System.Runtime.InteropServices; |
3 |
[DllImport("user32.dll", CharSet = CharSet.Auto, ExactSpelling = true)] |
4 |
public static extern IntPtr GetFocus(); |
6 |
[DllImport("user32.dll")] |
7 |
public static extern IntPtr GetForegroundWindow(); |
9 |
[DllImport("user32.dll")] |
10 |
public static extern IntPtr SetForegroundWindow(IntPtr hWnd); |
12 |
[DllImport("user32.dll", CharSet = CharSet.Auto)] |
13 |
static extern bool PostMessage(IntPtr hWnd, int Msg, char wParam, int lParam); |
16 |
public static extern bool AttachThreadInput(uint idAttach, uint idAttachTo, bool fAttach); |
19 |
public static extern uint GetWindowThreadProcessId(IntPtr hWnd, out uint lpdwProcessId); |
21 |
[DllImport("kernel32.dll", SetLastError = true)] |
22 |
static extern uint GetCurrentThreadId(); |
Первое дело сделано – описали нужные функции.
Остально написать две функции. Обе важные, хоть и короткие. Первая получает дескриптор(хэндл) окна, в котором содержится фокус ввода.
1 |
void GetFocusedControl() |
7 |
hFore = GetForegroundWindow(); |
9 |
AttachThreadInput(GetWindowThreadProcessId(hFore, out id), GetCurrentThreadId(), true); |
13 |
AttachThreadInput(GetWindowThreadProcessId(hFore, out id), GetCurrentThreadId(), false); |
В переменной hControl содержится наш дескриптор окна, в которое мы будем вставлять текст.
Вторая функции принимает какой-то текст, разбирает его и посимвольно передает его в какое-то окно.
1 |
void pasteText(string text) |
6 |
SetForegroundWindow(hControl); |
9 |
foreach (char ch in text) |
11 |
PostMessage(hControl, WM_CHAR, ch, 1); |
14 |
catch (Exception error) |
16 |
MessageBox.Show(error.Message); |
Перед передачей функцией SetForegroundWindow мы активизируем окно, в которое передаем текст.
Описаный выше способ передачи использует функцию PostMessage. У этого способа есть определенные минусы:
- нельзя передать форматированный-rtf текст;
- теоретически нельзя будет передать некоторым приложениям (каким, пока не знаю, но теоретически такое возможно);
- неизвестно, как будет работать в новых операционных системах Microsoft.
Из плюсов хочу отметить важную особенность – не используется буфер обмена (clipboard). То, что находится в буфере обмена не затрагивается.
Заключение
Как всегда, я представляю тестовый проект, чтобы вы могли посмотреть как это все работает.
Важно! Как запускать:
- создайте ярлык на рабочем столе на exe-файл проекта;
- в свойствах ярлыка назначьте горячие клавиши для запуска;
- поставьте курсор в какое-то поле ввода и нажмите заранее заданную комбинацию клавиш ярлыка;
- введите текст и нажмите вставить.
Все это необходимо, чтобы приложение до запуска получило дескриптор окна с фокусом. Иначе приложение получит само себя.