Принуждение другого приложения к копированию данных в буфер обмена

Я пытаюсь программно заставить внешнее приложение WinForms копировать свои данные в буфер обмена, и это сводит меня с ума.

Поскольку нажатие Ctrl-C в приложении делает правильные вещи, я пытался отправить ctrl-c с помощью моего приложения C # в другое приложение.

Вот моя последовательность команд. Я сравнил сообщения с помощью Spy ++, и они совпадают, за исключением того, что мои сообщения SendMessages отображаются как отправка и получение, а та же операция, выполняемая в WinForm, отображается как опубликованная.

Мой код:

          NativeMethods.SendMessage(hwnd, WM_KEYDOWN, 0x00000011, 0x001D0001);
          NativeMethods.SendMessage(hwnd, WM_KEYDOWN, 0x00000043, 0x002E0001);
          NativeMethods.SendMessage(hwnd, WM_CHAR, 0x00000003, 0x002E0001);
          NativeMethods.SendMessage(hwnd, WM_KEYUP, 0x00000043, 0xC02E0001);
          NativeMethods.SendMessage(hwnd, WM_KEYUP, 0x00000011, 0xC01D0001);

Автозапуск Spy ++ ->

 0059043C P WM_LBUTTONDOWN fwKeys:MK_LBUTTON xPos:322 yPos:54 [wParam:00000001 lParam:00360142]
 0059043C P WM_LBUTTONUP fwKeys:0000 xPos:322 yPos:54 [wParam:00000000 lParam:00360142]
 0059043C P WM_KEYDOWN nVirtKey:VK_CONTROL cRepeat:1 ScanCode:1D fExtended:0 fAltDown:0 fRepeat:0 fUp:0 [wParam:00000011 lParam:001D0001]
 0059043C P WM_KEYDOWN nVirtKey:'C' cRepeat:1 ScanCode:2E fExtended:0 fAltDown:0 fRepeat:0 fUp:0 [wParam:00000043 lParam:002E0001]
 0059043C P WM_CHAR chCharCode:'3' (3) cRepeat:1 ScanCode:2E fExtended:0 fAltDown:0 fRepeat:0 fUp:0 [wParam:00000003 lParam:002E0001]
 0059043C P WM_KEYUP nVirtKey:'C' cRepeat:1 ScanCode:2E fExtended:0 fAltDown:0 fRepeat:1 fUp:1 [wParam:00000043 lParam:C02E0001]
 0059043C P WM_KEYUP nVirtKey:VK_CONTROL cRepeat:1 ScanCode:1D fExtended:0 fAltDown:0 fRepeat:1 fUp:1 [wParam:00000011 lParam:C01D0001]

Мой шпион ++ последовательность:

 0059043C S WM_LBUTTONDOWN fwKeys:MK_LBUTTON xPos:299 yPos:52 [wParam:00000001 lParam:0034012B]
 0059043C R WM_LBUTTONDOWN
 0059043C S WM_LBUTTONUP fwKeys:MK_LBUTTON xPos:299 yPos:52 [wParam:00000001 lParam:0034012B]
 0059043C R WM_LBUTTONUP
 0059043C S WM_KEYDOWN nVirtKey:VK_CONTROL cRepeat:1 ScanCode:1D fExtended:0 fAltDown:0 fRepeat:0 fUp:0 [wParam:00000011 lParam:001D0001]
 0059043C R WM_KEYDOWN
 0059043C S WM_KEYDOWN nVirtKey:'C' cRepeat:1 ScanCode:2E fExtended:0 fAltDown:0 fRepeat:0 fUp:0 [wParam:00000043 lParam:002E0001]
 0059043C R WM_KEYDOWN
 0059043C S WM_CHAR chCharCode:'3' (3) cRepeat:1 ScanCode:2E fExtended:0 fAltDown:0 fRepeat:0 fUp:0 [wParam:00000003 lParam:002E0001]
 0059043C R WM_CHAR
 0059043C S WM_KEYUP nVirtKey:'C' cRepeat:1 ScanCode:2E fExtended:0 fAltDown:0 fRepeat:1 fUp:1 [wParam:00000043 lParam:C02E0001]
 0059043C R WM_KEYUP
 0059043C S WM_KEYUP nVirtKey:VK_CONTROL cRepeat:1 ScanCode:1D fExtended:0 fAltDown:0 fRepeat:1 fUp:1 [wParam:00000011 lParam:C01D0001]
 0059043C R WM_KEYUP

person Gooose    schedule 29.08.2010    source источник
comment
У вас есть причина не использовать SendKeys? msdn.microsoft.com/en-us/library/   -  person Albin Sunnanbo    schedule 29.08.2010


Ответы (1)


Вы можете использовать PostMessage

Или попробуйте SendInput, хотя тогда вы должны сначала установить фокус целевого окна .

person Ben Voigt    schedule 29.08.2010
comment
Пробовал PostMessage, и теперь я могу видеть в Spy ++ тот же код состояния «P» вместо «S» или «R» для сообщений, но все еще не работает. - person Gooose; 29.08.2010
comment
Пожалуйста, помогите. Это сводит меня с ума - person Gooose; 29.08.2010
comment
Нужно ли мне использовать функции буфера обмена? - person Gooose; 29.08.2010
comment
SendInput будет работать правильно, если вы можете гарантировать, что пользователь не взаимодействует с компьютером одновременно: он использует ряд глобальных настроек, включая фокус и состояние клавиши-модификатора. Если вам нужно работать полностью в фоновом режиме и не мешать пользователю, ваш единственный вариант - SendMessage в сочетании с SetKeyboardState, и это нужно делать из целевого потока. И подключение других приложений с помощью .NET имеет действительно плохие последствия (хотя .NET 4 смягчает некоторые из них, позволяя параллельную среду CLR в одном процессе). - person Ben Voigt; 29.08.2010
comment
Однако, если ваша причина для отправки Ctrl-C - скопировать что-то в буфер обмена, то определенно есть лучшие способы. Вы можете либо поместить данные в буфер обмена самостоятельно, используя SendMessage с WM_GETTEXT или EM_GETSELTEXT или аналогичные функции, а затем использовать функции буфера обмена (но если вы получите текст таким образом, вам по-прежнему нужен буфер обмена?), Либо попросите другое приложение скопировать в -clipboard либо с WM_COPY, либо с помощью Spy ++, чтобы узнать, какие WM_COMMAND аргументы генерируются его пунктом меню Правка- ›Копировать. - person Ben Voigt; 29.08.2010
comment
В другом приложении Ctrl-C, скорее всего, обрабатывается TranslateMessage и таблицей-ускорителем и становится сообщением WM_COMMAND, поэтому приложение может совместно использовать обработку между горячей клавишей Ctrl-C, кнопкой панели инструментов копирования и пунктом меню Правка- ›Копировать . - person Ben Voigt; 29.08.2010
comment
Расстраивает то, что в Spy ++ я вижу, что я отправляю точно такой же набор клавиатурных команд (ctrl + a, ctrl + c) в своей программе этому внешнему приложению, а не выполняю команды в самом приложении. Последний копирует данные, а первый - нет. - person Gooose; 29.08.2010
comment
Тот факт, что вы пытаетесь заставить другое приложение копировать данные в буфер обмена, должен быть указан в вопросе, поскольку это приводит к некоторым более простым решениям, чем общий случай отправки измененных нажатий клавиш. Посмотрите, сможете ли вы записать (с помощью Spy ++) сообщение WM_COMMAND, сгенерированное при выборе Правка- ›Копировать в приложении, и сможете ли вы использовать PostMessage для дублирования, которое не копирует данные так, как вы хотите. - person Ben Voigt; 29.08.2010
comment
Я только что отредактировал ваш вопрос как пример того, что вы должны были сказать. Хороший вопрос состоит из трех частей: (1) ваша цель, (2) что вы пытаетесь сделать, чтобы ее достичь, и (3) что происходит / идет не так. (У вас уже были достаточно хорошо освещены части 2 и 3, что на самом деле значительно опережает вас по большинству вопросов.) - person Ben Voigt; 29.08.2010
comment
Во внешнем приложении нет и меню «Правка». Я не вижу Edit- ›Copy в приложении. - person Gooose; 29.08.2010
comment
Во внешнем приложении WinForm есть элемент управления datagridview. У меня есть дескриптор элемента управления datagridview, и я выбрал первую строку с помощью SendMessage- ›WM_LMBUTTONDOWN и WM_LBUTTONUP. Теперь мне нужно скопировать данные этой выбранной строки. Здесь я застрял. - person Gooose; 29.08.2010
comment
Хорошо ... есть ли на панели инструментов кнопка для копирования или, может быть, элемент Копировать в контекстном меню? - person Ben Voigt; 29.08.2010
comment
Я пробовал следующее .. не повезло. StringBuilder sg = новый StringBuilder (1000); NativeMethods.SendMessage (hwnd, EM_GETSELTEXT, новый IntPtr (500), sg); строка str = sg.ToString (); - person Gooose; 29.08.2010
comment
Самое странное, что когда я отправляю EM_GETSELTEXT, WM_COPY или WM_PASTE, я не вижу соответствующих сигналов в Spy ++. - person Gooose; 29.08.2010
comment
Бен ... искренне ценю, что ты помог мне здесь. - person Gooose; 29.08.2010
comment
О, с элементом управления datagridview это потенциально очень уродливо, поскольку приложение может обрабатывать нажатия клавиш напрямую, а не с помощью обычных механизмов горячих клавиш. Поскольку другое приложение также является .NET, возможно, стоит декомпилировать его с помощью Red Gate Reflector и посмотреть, есть ли собственный код для записи в буфер обмена. Reflector довольно хорош тем, что вы можете перейти к System.Windows.Clipboard.SetText, а затем найти все места, где эта функция используется приложением. - person Ben Voigt; 29.08.2010
comment
Других вариантов нет? Что меня действительно сбивает с толку, так это то, что я вижу те же самые сообщения ctrl-c, когда я нажимаю ctrl-c во внешнем приложении, и последнее работает, но я не отправляю ctrl-c из моего приложения. - person Gooose; 29.08.2010
comment
В Spy ++ вы смотрите форму или DataGridView? Параметры KeyPreview в форме могут повлиять на обработку горячих клавиш, но не повлияют на другие сообщения. Я полагаю, когда вы получаете дескриптор элемента управления, который использует ChildWindowFromPoint или GetDlgItem, или у вас, возможно, есть дескриптор главного окна? - person Ben Voigt; 29.08.2010
comment
У меня есть дескриптор элемента управления datagridview. Мне пришлось резво найти этот элемент управления. - person Gooose; 29.08.2010
comment
Если вы все равно изменяете выделение в приложении, то использование SetFocus, за которым следует SendInput, более старый более простой keybd_event или .NET Wrapper SendKeys (как предлагается в комментарии Альбина) для фактической отправки Ctrl-C, может быть самым быстрым путем к раствору. Однако будьте осторожны, потому что вы можете установить фокус только в том случае, если вы в настоящее время владеете им, и как только вы его отдадите, вы не сможете вернуть его автоматически. Таким образом, решение, которое не использует эмуляцию нажатия клавиш, определенно было бы лучше, если оно существует. - person Ben Voigt; 29.08.2010
comment
Я могу выбрать первую строку в этом элементе управления, используя следующее ... SendMessage (hwnd, WM_LBUTTONDOWN, 0x00000001, 0x0034012B); SendMessage (hwnd, WM_LBUTTONUP, 0x00000001, 0x0034012B); hwnd = дескриптор datagridview - person Gooose; 29.08.2010
comment
Мне нужно будет изучить эмуляцию дальше, поскольку SendKeys может быть нежелательным решением. Бен, ценю всю информацию здесь. Я выложу окончательное решение, если найду. Еще раз спасибо. - person Gooose; 29.08.2010