3 / 3 / 2
Регистрация: 27.06.2013
Сообщений: 94
1

Ошибка при повторном вызове метода Clipboard.SetDataObject

22.02.2015, 23:11. Показов 4183. Ответов 3
Метки нет (Все метки)

Author24 — интернет-сервис помощи студентам
Необходимо программно отправить текст в текстовое поле стороннего приложения.
Задавал вопрос в разделе C++ WinAPI Программно эмулировать нажатие клавиш, различая регистр и раскладку клавиатуры
Проблема в том, что функция keybd_event не различает регистр и раскладку клавиатуры. Посоветовали функцию WinAPI SendInput. Но в ней у меня та же проблема. Решил попробовать сделать проще. Сохраняю старый буфер обмена, отправляю туда текст, затем с помощью WinAPI нажимаю Shift+Insert и возвращаю в буфер обмена старое содержимое.

C#
1
2
3
4
5
6
7
8
9
10
11
12
static void Main()
        {
            IDataObject old_clipboard = Clipboard.GetDataObject();
            Clipboard.SetText("Текст", TextDataFormat.UnicodeText);
            
//Код, отправляющий сочетание клавиш Shift+Insert с помощью функции WinAPI keybd_event 
...
            Clipboard.SetDataObject(old_clipboard,true);
            Application.EnableVisualStyles();
            Application.SetCompatibleTextRenderingDefault(false);
            Application.Run(new Form1());
        }
Первый раз это работает нормально, когда данные в буфер обмена были помещены через приложение Windows. Но, если в буфере обмена находится содержимое, которое было туда отправлено с помощью SetDataObject при прошлом вызове программы, при следующем вызове программы появляется ошибка на строчке

C#
1
 Clipboard.SetDataObject(old_clipboard,true);

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

Ошибка выглядит следующим образом (оформил в сообщении как код HTML для удобства просмотра).

HTML5
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
Сигнатура проблемы:
  Имя события проблемы:   CLR20r3
  Сигнатура проблемы 01:   bufobmena.exe
  Сигнатура проблемы 02:   1.0.0.0
  Сигнатура проблемы 03:   54ea34f6
  Сигнатура проблемы 04:   System.Windows.Forms
  Сигнатура проблемы 05:   4.0.30319.18408
  Сигнатура проблемы 06:   52311103
  Сигнатура проблемы 07:   13e9
  Сигнатура проблемы 08:   14
  Сигнатура проблемы 09:   AMAG3AACMAWG2XAF344U21ACVE5PSTKL
  Версия ОС:    6.1.7601.2.1.0.256.1
  Код языка:    1049
  Дополнительные сведения 1:  0a9e
  Дополнительные сведения 2:  0a9e372d3b4ad19135b953a78882e789
  Дополнительные сведения 3:  0a9e
  Дополнительные сведения 4:  0a9e372d3b4ad19135b953a78882e789
 
Ознакомьтесь с заявлением о конфиденциальности в Интернете:
  http://go.microsoft.com/fwlink/?linkid=104288&clcid=0x0419
 
Если заявление о конфиденциальности в Интернете недоступно, ознакомьтесь с его локальным вариантом:
  C:\Windows\system32\ru-RU\erofflps.txt
Может ли это быть связано с тем, что не очищается память, занимаемая объектом, и как в этом случае ее очистить?
Присваивание null не помогает.
C#
1
old_clipboard = null;
Есть ли другие способы работы с буфером обмена или программной отправки теста, чтобы различался регистр и раскладка клавиатуры?
0
Programming
Эксперт
94731 / 64177 / 26122
Регистрация: 12.04.2006
Сообщений: 116,782
22.02.2015, 23:11
Ответы с готовыми решениями:

Clipboard.SetDataObject
Вот мой метод. Проблема в том что этот метод вызывается не из основного потока связи с чем и не...

Ошибка при вызове метода (позднее связывание)
Помогите пожалуйста разобраться с ошибкой вызова:

При вызове метода из другого файла ошибка "The type initializer for 'Openxls' threw an exception"
Хелп плиз! Прога работала и вдруг перестала при вызове метода из другого файла пишет The type...

Большое потребление памяти при вызове метода
Наблюдаю очень странное поведение Visual Studio 2008. В моём проекте на C# есть один метод, который...

3
141 / 138 / 22
Регистрация: 16.02.2012
Сообщений: 453
23.02.2015, 13:24 2
Как эта ошибка выглядит в отладчике?
0
3 / 3 / 0
Регистрация: 12.02.2015
Сообщений: 7
23.02.2015, 15:09 3
Класс Clipboard откровенно не очень хорошо работает, сам сталкивался с этой проблемой. Есть два решения.
Первое - нормально работающий код с буфером обмена:
C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
private const uint CF_UNICODETEXT = 13;
        private const uint GMEM_DDESHARE = 8192;
 
        public static void SetText(string strText)
        {
            if (NativeMethods.OpenClipboard(IntPtr.Zero) != 0)
            {
                IntPtr hgBuffer;
                char* chBuffer;
                NativeMethods.EmptyClipboard();
                hgBuffer = NativeMethods.GlobalAlloc(GMEM_DDESHARE, 2 * Convert.ToUInt64(strText.Length + 1)); // 2 = sizeof(wchar_t) -- C++; sizeof(char) -- C#
                chBuffer = (char*)NativeMethods.GlobalLock(hgBuffer);
                NativeMethods.wcscpy(chBuffer, new StringBuilder(strText));
                NativeMethods.GlobalUnlock(hgBuffer);
                NativeMethods.SetClipboardData(CF_UNICODETEXT, hgBuffer);
                NativeMethods.CloseClipboard();
            }
        }
 
        public static string GetText()
        {
            NativeMethods.CloseClipboard();
            if (NativeMethods.OpenClipboard(IntPtr.Zero) != 0)
            {
                IntPtr hData = NativeMethods.GetClipboardData(CF_UNICODETEXT);
                char* chBuffer = (char*)NativeMethods.GlobalLock(hData);
                string strResult = new string(chBuffer);
                NativeMethods.GlobalUnlock(hData);
                NativeMethods.CloseClipboard();
                return strResult;
            }
            return "";
        }
Второе - библиотека Windows Input Simulator, которая напишет текст с учетом шифта.
1
3 / 3 / 2
Регистрация: 27.06.2013
Сообщений: 94
24.02.2015, 18:33  [ТС] 4
Разобрался с SendInput, как отправлять символы Unicode, включая русские и заглавные буквы.
За основу можно взять этот код.
http://www.ownedcore.com/forum... ple-c.html
И использовать метод SendCharUnicode, (если нужен UTF-32, то второй из них) отсюда:
http://stackoverflow.com/quest... yond-uffff
Получилось следующее. В этом примере делаю задержку по таймеру и активирую нужное окно вручную. Реальное приложение активирует нужное окно через WinAPI
C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.Text;
using System.Runtime.InteropServices;
using System.Threading;
using System.Windows.Input;
using System.Diagnostics;
 
namespace SendTextForms3
{
    static class Program
    {
        /// <summary>
        /// The main entry point for the application.
        /// </summary>
        [STAThread]
        static void Main()
        {
            TextSend.SendText();
            Application.EnableVisualStyles();
            Application.SetCompatibleTextRenderingDefault(false);
            Application.Run(new Form1());
        }
    }
 
    class TextSend
    {
        [DllImport("User32.dll")]
        public static extern uint SendInput(uint numberOfInputs, [MarshalAs(UnmanagedType.LPArray, SizeConst = 1)] INPUT[] input, int structSize);
 
        [DllImport("user32.dll")]
        public static extern IntPtr GetMessageExtraInfo();
        
        public static void SendText()
        {
            Thread.Sleep(3000);
 
            string teststring = @"`1234567890-=\qwertyuiop[]asdfghjkl;'zxcvbnm,./QWERTYUIOP[]ASDFGHJKL;'ZXCVBNM,./?ё1234567890-=\йцукенгшщзхъфывапролджэячсмитьбю.,Ё1234567890-=\ФЫВАПРОЛДЖЭЯЧСМИТЬБЮ.,";
 
            for (int i = 0; i < teststring.Length; i++)            
                SendCharUnicode(teststring[i]);            
        }
 
        public static void SendCharUnicode(char ch)
        {   
            INPUT[] input = new INPUT[2];
            input[0] = new INPUT();
            input[0].type = INPUT_KEYBOARD;
            input[0].ki.wVk = 0;
            input[0].ki.wScan = (ushort)ch;
            input[0].ki.time = 0;
            input[0].ki.dwFlags = KEYEVENTF_UNICODE;
            input[0].ki.dwExtraInfo = GetMessageExtraInfo();
            
            input[1] = new INPUT();
            input[1].type = INPUT_KEYBOARD;
            input[1].ki.wVk = 0;
            input[1].ki.wScan = (ushort)ch;
            input[1].ki.time = 0;
            input[1].ki.dwFlags = KEYEVENTF_UNICODE | KEYEVENTF_KEYUP;
            input[1].ki.dwExtraInfo = GetMessageExtraInfo();
            SendInput(2, input, Marshal.SizeOf(typeof(INPUT)));
        }
 
        public const int INPUT_MOUSE = 0;
        public const int INPUT_KEYBOARD = 1;
        public const int INPUT_HARDWARE = 2;
        public const uint KEYEVENTF_EXTENDEDKEY = 0x0001;
        public const uint KEYEVENTF_KEYUP = 0x0002;
        public const uint KEYEVENTF_UNICODE = 0x0004;
        public const uint KEYEVENTF_SCANCODE = 0x0008;
        public const uint XBUTTON1 = 0x0001;
        public const uint XBUTTON2 = 0x0002;
        public const uint MOUSEEVENTF_MOVE = 0x0001;
        public const uint MOUSEEVENTF_LEFTDOWN = 0x0002;
        public const uint MOUSEEVENTF_LEFTUP = 0x0004;
        public const uint MOUSEEVENTF_RIGHTDOWN = 0x0008;
        public const uint MOUSEEVENTF_RIGHTUP = 0x0010;
        public const uint MOUSEEVENTF_MIDDLEDOWN = 0x0020;
        public const uint MOUSEEVENTF_MIDDLEUP = 0x0040;
        public const uint MOUSEEVENTF_XDOWN = 0x0080;
        public const uint MOUSEEVENTF_XUP = 0x0100;
        public const uint MOUSEEVENTF_WHEEL = 0x0800;
        public const uint MOUSEEVENTF_VIRTUALDESK = 0x4000;
        public const uint MOUSEEVENTF_ABSOLUTE = 0x8000;
    }
 
    [StructLayout(LayoutKind.Sequential)]
    public struct MOUSEINPUT
    {
        int dx;
        int dy;
        uint mouseData;
        uint dwFlags;
        uint time;
        IntPtr dwExtraInfo;
    }
 
    [StructLayout(LayoutKind.Sequential)]
    public struct KEYBDINPUT
    {
        public ushort wVk;
        public ushort wScan;
        public uint dwFlags;
        public uint time;
        public IntPtr dwExtraInfo;
    }
 
    [StructLayout(LayoutKind.Sequential)]
    public struct HARDWAREINPUT
    {
        uint uMsg;
        ushort wParamL;
        ushort wParamH;
    }
 
    [StructLayout(LayoutKind.Explicit)]
    public struct INPUT
    {
        [FieldOffset(0)]
        public int type;
        [FieldOffset(4)] //*
        public MOUSEINPUT mi;
        [FieldOffset(4)] //*
        public KEYBDINPUT ki;
        [FieldOffset(4)] //*
        public HARDWAREINPUT hi;
    }
}
0
24.02.2015, 18:33
IT_Exp
Эксперт
87844 / 49110 / 22898
Регистрация: 17.06.2006
Сообщений: 92,604
24.02.2015, 18:33
Помогаю со студенческими работами здесь

Запрос админ прав после нажатия button (либо при вызове метода)
Для выполнения функции, которая вызывается после клика на кнопку, требуются админ права(для всей...

Ошибка при вызове функции из другой библиотеки
Добрый день! У меня есть библиотека с функциями написанными на С. При попытке использования одной...

Ошибка "Сервер RPC недоступен" при повторном обращении к Word
Добрый день! Вывожу на печать с формы в документ Word. Все получается. Но при закрытии и при...

Ошибка при вызове метода dataAdapter.Fill(ds)
Код программы взят из учебного пособия слово в слово, изменён только адрес к фалу базы данных...


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
4
Ответ Создать тему
Опции темы

КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2024, CyberForum.ru