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


все гораздо проще ты все слишком усложнил. пишу с телефона, так что кодом не могу скажу теоретически
1. нужны только такие функции api: getforegroundwindow(intptr, без аргументов) и getwindowtext (string, параметр типа intptr)
2. с помощью вызовов api узнаем, нужно ли отправлять текст в текущее окно
3. с помощью .net метода (рекомендуется не Юзать на xp) system.sendkeys.send(string) пишем в текущее окно нужный текст.
я бы изменил мир и сделал чуточку лучше, но бог не дает сорсы
1. Вариантов передачи текста в форму несколько. Я описал не все. То что описал, работают адекватно и на 100%. Ваш вариант тоже хороший.
2. Зачем узнавать отправляется ли текст в окно? Мы отправили, а дальше уже не наши проблемы.
3. Sendkeys работает крайне плохо. Не во всех приложения. Еще одна проблема в том, что Sendkeys для .NET 2.0 отличается от того, что написано в .NET 3.0. Microsoft старается закрыть возможность использования низкоуровневых API, поэтому Sendkeys — жалкое подобие того, что можно написать самому используя тот же keybd_event, PostMessage и SendMessage.
За комментарий спасибо.
А разве SetWindowText отменили?
А SetWindowText не во всех приложения работает адекватно. Например, если приложение не принимает уникод, а вы передаете его, то будет вставлена абракадабра. Преимущество моего варианта заключается еще и в том, что вы сами можете настроить в каком месте должна быть установлена каретка.
Если вы знаете больше, напишите пожалуйста в комментарии преимущества работы через SetWindowText.