Форум программистов, компьютерный форум, киберфорум
C# .NET
Войти
Регистрация
Восстановить пароль
Карта форума Темы раздела Блоги Сообщество Поиск Заказать работу  
 
Рейтинг 4.78/27: Рейтинг темы: голосов - 27, средняя оценка - 4.78
Заблокирован
1

перехват сообщений в системе

05.10.2010, 12:30. Показов 5446. Ответов 10

Author24 — интернет-сервис помощи студентам
Здравствуйте форумчане! Столкнулся с проблеммой получения данных с буфера обмена. Но обо всём по порядку.
- Необходимо при нажатии CTRL+C, перехватывать событие в программе. Затем обращаться к буферу обмена и вытягивать инфу в формате текст.

- вот что мне удалось сделать:

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
public Form1() 
{ 
InitializeComponent(); 
MethodInvoker mi = new MethodInvoker(WaitKey); 
mi.BeginInvoke(null, null); 
} 
 
private void WaitKey() 
{ 
while (this.IsHandleCreated) 
{ 
short res1 = GetAsyncKeyState(VK_CTRL); 
short res2 = GetAsyncKeyState(VK_C); 
if (res1!= 0 && res2!= 0) 
{ 
IDataObject iData = Clipboard.GetDataObject(); ----////// тут происходит ошибка "В экземпляре объекта не задана ссылка на объект." 
 
if (iData.GetDataPresent(DataFormats.Text)) ; 
{ 
textBox1.Text = (String)iData.GetData(DataFormats.Text); //показываем текущий текст в буфере обмена 
} 
} 
} 
} 
 
public const int VK_CTRL = 0x11; 
public const int VK_C = 0x43; 
 
[DllImport("user32.dll", CharSet = CharSet.Auto, ExactSpelling = true)] 
internal static extern short GetAsyncKeyState(int vkey);


------------------

На данной строке IDataObject iData = Clipboard.GetDataObject(); выходит сообщение об ошибки
"В экземпляре объекта не задана ссылка на объект."


Точно уверен, что в буфере обмена содержится данные в формате текст. Странно выходит, если я делаю Clipboard.GetDataObject() на кнопке, то всё отображается верно(приведено ниже)! Но мне нужно, чтобы это действие выполнялось на сочетании клавиш CTRL+C.


C#
1
2
3
4
5
6
7
8
private void button1_Click(object sender, EventArgs e) 
{ 
IDataObject iData = Clipboard.GetDataObject(); 
if (iData.GetDataPresent(DataFormats.Text)) 
{ 
textBox1.Text = (String)iData.GetData(DataFormats.Text); 
} 
}
0
Programming
Эксперт
94731 / 64177 / 26122
Регистрация: 12.04.2006
Сообщений: 116,782
05.10.2010, 12:30
Ответы с готовыми решениями:

Перехват сообщений
Добрый вечер! Бывает возникает ситуация когда нужно перехватить у процесса функцию, а ещё точнее...

Перехват системных сообщений
Здравствуйте. Необходимо распознавать сообщения системы, например, при безопасном извлечении...

Перехват сетевого трафика в системе
Здравствуйте! Идея в том, чтоб сделать подобие сетевого устройства, которое бы работало как VPN....

Глобальный перехват нажатий клавиш в системе
Всем доброго вечера. Хотелось реализовать программу которая будет при нажатии скажем Pause/Break?...

10
1319 / 992 / 127
Регистрация: 08.12.2009
Сообщений: 1,299
05.10.2010, 13:04 2
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
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Diagnostics;
using System.Runtime.InteropServices;
 
namespace WindowsFormsApplication1 {
    public partial class Form1 : Form {
 
        public Form1() {
            InitializeComponent();
        }
 
        protected override void OnLoad(EventArgs e) {
            WindowsShell.RegisterHotKey(this, Keys.Control | Keys.C);
            base.OnLoad(e);
        }
 
        protected override void WndProc(ref Message m) {
            base.WndProc(ref m);
            if (m.Msg == WindowsShell.WM_HOTKEY)
                // тут если много горячих клавиш - понадобится проверка
                ProcessBufferCopy();
        }
 
        private void ProcessBufferCopy() {
            IDataObject iData = Clipboard.GetDataObject();
            if (iData != null) {
                string str = iData.GetData(typeof(string)) as string;
                if (!string.IsNullOrEmpty(str))
                    this.Text = str;
            }
        }
 
        protected override void OnClosing(CancelEventArgs e) {
            WindowsShell.UnregisterHotKey(this);
            base.OnClosing(e);
        }
 
    }
 
    public class WindowsShell {
 
        #region fields
        public static int MOD_ALT = 0x1;
        public static int MOD_CONTROL = 0x2;
        public static int MOD_SHIFT = 0x4;
        public static int MOD_WIN = 0x8;
        public static int WM_HOTKEY = 0x312;
        #endregion
 
        [DllImport("user32.dll")]
        private static extern bool RegisterHotKey(IntPtr hWnd, int id, int fsModifiers, int vlc);
 
        [DllImport("user32.dll")]
        private static extern bool UnregisterHotKey(IntPtr hWnd, int id);
 
        private static int keyId;
        public static void RegisterHotKey(Form f, Keys key) {
            int modifiers = 0;
 
            if ((key & Keys.Alt) == Keys.Alt)
                modifiers = modifiers | WindowsShell.MOD_ALT;
 
            if ((key & Keys.Control) == Keys.Control)
                modifiers = modifiers | WindowsShell.MOD_CONTROL;
 
            if ((key & Keys.Shift) == Keys.Shift)
                modifiers = modifiers | WindowsShell.MOD_SHIFT;
 
            Keys k = key & ~Keys.Control & ~Keys.Shift & ~Keys.Alt;
 
            Func ff = delegate() {
                keyId = f.GetHashCode(); // this should be a key unique ID, modify this if you want more than one hotkey
                RegisterHotKey((IntPtr)f.Handle, keyId, modifiers, (int)k);
            };
 
            f.Invoke(ff); // this should be checked if we really need it (InvokeRequired), but it's faster this way
        }
 
        private delegate void Func();
 
        public static void UnregisterHotKey(Form f) {
            try {
                Func ff = delegate() {
                    UnregisterHotKey(f.Handle, keyId); // modify this if you want more than one hotkey
                };
 
                f.Invoke(ff); // this should be checked if we really need it (InvokeRequired), but it's faster this way
            } catch (Exception ex) {
                Debug.WriteLine(ex.ToString());
            }
        }
    }
}
учти, тут происходит перекрытие : в системе Ctrl+c перестанет работать

но можно и так - через хук:

см метод HookCallback
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
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Diagnostics;
using System.Runtime.InteropServices;
 
namespace WindowsFormsApplication1 {
    public partial class Form1 : Form {
 
        public Form1() {
            InitializeComponent();
        }
 
        protected override void OnLoad(EventArgs e) {
            _hookID = SetHook(_proc);
            base.OnLoad(e);
        }
 
        protected override void OnClosed(EventArgs e) {
            UnhookWindowsHookEx(_hookID);
            base.OnClosed(e);
        }
 
        private void ProcessBufferCopy() {
            IDataObject iData = Clipboard.GetDataObject();
            if (iData != null) {
                string str = iData.GetData(typeof(string)) as string;
                if (!string.IsNullOrEmpty(str))
                    this.Text = str;
            }
        }
 
        private const int WH_KEYBOARD_LL = 13;
        private const int WM_KEYDOWN = 0x0100;
        private static LowLevelKeyboardProc _proc = HookCallback;
        private static IntPtr _hookID = IntPtr.Zero;
 
        private static IntPtr SetHook(LowLevelKeyboardProc proc) {
            using (Process curProcess = Process.GetCurrentProcess())
            using (ProcessModule curModule = curProcess.MainModule) {
                return SetWindowsHookEx(WH_KEYBOARD_LL, proc,
                    GetModuleHandle(curModule.ModuleName), 0);
            }
        }
 
        private delegate IntPtr LowLevelKeyboardProc(
            int nCode, IntPtr wParam, IntPtr lParam);
 
        private static IntPtr HookCallback(
            int nCode, IntPtr wParam, IntPtr lParam) {
            if (nCode >= 0 && wParam == (IntPtr)WM_KEYDOWN) {
                int vkCode = Marshal.ReadInt32(lParam);
                Console.WriteLine((Keys)vkCode);
            }
            return CallNextHookEx(_hookID, nCode, wParam, lParam);
        }
 
        [DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
        private static extern IntPtr SetWindowsHookEx(int idHook,
            LowLevelKeyboardProc lpfn, IntPtr hMod, uint dwThreadId);
 
        [DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
        [return: MarshalAs(UnmanagedType.Bool)]
        private static extern bool UnhookWindowsHookEx(IntPtr hhk);
 
        [DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
        private static extern IntPtr CallNextHookEx(IntPtr hhk, int nCode,
            IntPtr wParam, IntPtr lParam);
 
        [DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
        private static extern IntPtr GetModuleHandle(string lpModuleName);
    }
}
0
Заблокирован
05.10.2010, 13:13  [ТС] 3
Mikant - большое спасибо за приведённый код, но хотелось бы узнать, что в моём коде не так? почему в строке Clipboard.GetDataObject() выходит ошибка, ведь буфер не пуст!!!
0
1319 / 992 / 127
Регистрация: 08.12.2009
Сообщений: 1,299
05.10.2010, 15:10 4
C#
1
2
3
4
5
6
7
8
9
10
11
12
13
public static IDataObject GetDataObject()
{
    IntSecurity.ClipboardRead.Demand();
    if (Application.OleRequired() == ApartmentState.STA)
    {
        return GetDataObject(10, 100);
    }
    if (Application.MessageLoop)
    {
        throw new ThreadStateException(SR.GetString("ThreadMustBeSTA"));
    }
    return null;
}
за ответ сойдет?

Добавлено через 1 минуту
короче, вводи делай Invoke у контрола - проблемы должны исчезнуть
1
Заблокирован
05.10.2010, 15:31  [ТС] 5
Извините меня, ну что-то последний код мне вообще не понятен( Я ещё значит ламер в этом!
0
Почетный модератор
Эксперт .NET
8721 / 3673 / 404
Регистрация: 14.06.2010
Сообщений: 4,513
Записей в блоге: 9
05.10.2010, 16:05 6
Вот ещё вариант перехвата CTRL+C:
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
using System;
using System.Windows.Forms;
using System.Runtime.InteropServices;
using System.Diagnostics;
 
namespace ClipShow
{
    public partial class frmMain : Form
    { 
        [DllImport("user32.dll")]
        static extern IntPtr SetClipboardViewer(IntPtr hWndNewViewer);
 
        [DllImport("user32.dll")]
        static extern IntPtr GetClipboardViewer();
 
        [DllImport("user32.dll")]
        [return: MarshalAs(UnmanagedType.Bool)]
        static extern bool ChangeClipboardChain(IntPtr hWndRemove, IntPtr hWndNewNext);
 
        [DllImport("user32.dll", SetLastError = true)]
        static extern int SendMessage(IntPtr hWnd, int Msg, IntPtr wParam, IntPtr lParam);
 
        IntPtr hWndNextWindow;
 
        public frmMain()
        {
            InitializeComponent();
        }
 
        protected override void WndProc(ref Message m)
        {
            switch(m.Msg)
            {
                case (0x0001): // WM_CREATE
                    hWndNextWindow = SetClipboardViewer(this.Handle);
                    break;
                case (0x0002): // WM_DESTROY
                    ChangeClipboardChain(this.Handle, hWndNextWindow);
                    break;
                case (0x030D): // WM_CHANGECBCHAIN
                    if (m.WParam == hWndNextWindow)
                        hWndNextWindow = m.LParam;
                    else if (hWndNextWindow != IntPtr.Zero)
                        SendMessage(hWndNextWindow, m.Msg, m.WParam, m.LParam);
                    break;
                case (0x0308): // WM_DRAWCLIPBOARD
                    {
                        Debug.WriteLine("БУФЕР ОБМЕНА ИЗМЕНЁН");
                    }
                    SendMessage(hWndNextWindow, m.Msg, m.WParam, m.LParam);
                    break;
            }
 
            base.WndProc(ref m);
        }
    }
}
0
Заблокирован
06.10.2010, 07:34  [ТС] 7
SSTREGG - предоставленный вами код не работает.


Ошибка 1 Тип "ClipShow.frmMain" уже определяет член "SetClipboardViewer" с такими же типами параметров D:\Free program\2\WindowsFormsApplication1\WindowsFormsApplication1\Form1.Designer.cs 11 30 WindowsFormsApplication1
0
Почетный модератор
Эксперт .NET
8721 / 3673 / 404
Регистрация: 14.06.2010
Сообщений: 4,513
Записей в блоге: 9
06.10.2010, 20:13 8
Ну так ненужно тупо копировать, Вам нужно разместить в классе формы этот код:
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
        using System.Runtime.InteropServices; // Там где using
        ...
        // Это в классе
        [DllImport("user32.dll")]
        static extern IntPtr SetClipboardViewer(IntPtr hWndNewViewer);
 
        [DllImport("user32.dll")]
        static extern IntPtr GetClipboardViewer();
 
        [DllImport("user32.dll")]
        [return: MarshalAs(UnmanagedType.Bool)]
        static extern bool ChangeClipboardChain(IntPtr hWndRemove, IntPtr hWndNewNext);
 
        [DllImport("user32.dll", SetLastError = true)]
        static extern int SendMessage(IntPtr hWnd, int Msg, IntPtr wParam, IntPtr lParam);
 
        IntPtr hWndNextWindow;
 
        protected override void WndProc(ref Message m)
        {
            switch(m.Msg)
            {
                case (0x0001): // WM_CREATE
                    hWndNextWindow = SetClipboardViewer(this.Handle);
                    break;
                case (0x0002): // WM_DESTROY
                    ChangeClipboardChain(this.Handle, hWndNextWindow);
                    break;
                case (0x030D): // WM_CHANGECBCHAIN
                    if (m.WParam == hWndNextWindow)
                        hWndNextWindow = m.LParam;
                    else if (hWndNextWindow != IntPtr.Zero)
                        SendMessage(hWndNextWindow, m.Msg, m.WParam, m.LParam);
                    break;
                case (0x0308): // WM_DRAWCLIPBOARD
                    {
                        Debug.WriteLine("БУФЕР ОБМЕНА ИЗМЕНЁН");
                    }
                    SendMessage(hWndNextWindow, m.Msg, m.WParam, m.LParam);
                    break;
            }
 
            base.WndProc(ref m);
        }
Когда буфер обмена изменён, в окно Output студии будет выводится текст: БУФЕР ОБМЕНА ИЗМЕНЁН. Вам нужно вставить свой код обработки изменения буфера там где строка
C#
1
Debug.WriteLine("БУФЕР ОБМЕНА ИЗМЕНЁН");
1
31 / 31 / 5
Регистрация: 05.01.2011
Сообщений: 65
05.01.2011, 19:05 9
Доброго времени суток! Простите за дубство, но сам не смог сделать то, что мне нужно и вот прошу помощи! В общем мне необходимо как-то вызвать нестатический метод из статического, но как бы я не пробовал, у меня ничего не выходит, ругается "...требуется ссылка на объект", и ссаыку эту я сформировать не смог! =(

Использую пример "HookCallback".

C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
        ...
        private static IntPtr HookCallback(int nCode, IntPtr wParam, IntPtr lParam)
        {
            if (nCode >= 0 && wParam == (IntPtr)WM_KEYDOWN)
            {
                int vkCode = Marshal.ReadInt32(lParam);
                switch((Keys)vkCode)
                {
                    case Keys.Q:
                    MyMethod(); // -- Ошибка*
                    break;
                }               
            }
            return CallNextHookEx(_hookID, nCode, wParam, lParam);            
        }
        ...
* Ошибка 1: Для нестатического поля, метода или свойства "WindowsFormsApplication2.Form1.MyMethod()" требуется ссылка на объект.

И пихаю в "public partial class Form1 : Form":
C#
1
2
3
4
        private void MyMethod()
        {
            label1.Text = "blabla";
        }
Ну или какой-нибудь переход с статического на нестатический метод!
Думаю ответ на этот вопрос поможет не только мне, т.к. в инете нашел много похожих тем, но чет все не то!

И еще, по поводу этого метода, как-то он странно работате (или я что-то упустил), но если в ХукКолбэк "Console.Beep(1000, 500);" или отображение мессага, то после 5-11 срабатываний он перестает действовать!
0
Почетный модератор
Эксперт .NET
8721 / 3673 / 404
Регистрация: 14.06.2010
Сообщений: 4,513
Записей в блоге: 9
05.01.2011, 19:36 10
Поиск по форуму рулит.
Цитата Сообщение от Single Feniks Посмотреть сообщение
Ну или какой-нибудь переход с статического на нестатический метод!
Интересно как ты вызовешь из статического метода не статический, если не статический метод находится в классе, экземпляр которого может еще не существовать?
0
31 / 31 / 5
Регистрация: 05.01.2011
Сообщений: 65
06.01.2011, 17:56 11
Я же сказал дубчик я в этом деле! =) Впринципе я был на 90% уверен что так оно и есть, но всетаки думал есть какая-нибудь лазейка! Спасибо за ответ!
Смотрел я уже этот пример, просто этот симпатичнее выглядит! =)

Добавлено через 17 часов 23 минуты
Сделал на основе примера отсюда.

В Hook.cs:
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
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Diagnostics;
using System.Runtime.InteropServices;
using System.Windows.Forms;
 
namespace MyHook
{
    static class Hook
    {
        [DllImport("user32.dll")]
        private static extern IntPtr SetWindowsHookEx(int idHook, LowLevel_KeyboardProc Ipfn, IntPtr hMod, uint dwThreadId);
        [DllImport("user32.dll")]
        private static extern IntPtr CallNextHookEx(IntPtr hhk, int nCode, IntPtr wParam, IntPtr lParam);
        [DllImport("user32.dll")]
        [return: MarshalAs(UnmanagedType.Bool)]
        private static extern bool UnhookWindowsHookEx(IntPtr hhk);
        private static IntPtr _hookId = IntPtr.Zero;
        private delegate IntPtr LowLevel_KeyboardProc(int nCode, IntPtr wParam, IntPtr lParam);
        private static LowLevel_KeyboardProc _proc = HookCallback;
        [DllImport("Kernel32.dll")]
        private static extern IntPtr GetModuleHandle(string lpModuleName);
        private const int WH_KEYBOARD_LL = 13;
        private const int WH_KEYDOWN = 0x0100;
 
        private static IntPtr SetHook(LowLevel_KeyboardProc proc)
        {
            Process pr = Process.GetCurrentProcess();
            ProcessModule prM = pr.MainModule;
            return SetWindowsHookEx(WH_KEYBOARD_LL, proc, GetModuleHandle(prM.ModuleName), 0);
        }
 
        public static Label lb;
        private static IntPtr HookCallback(int nCode, IntPtr wParam, IntPtr lParam)
        {
            if (nCode >= 0 && wParam == (IntPtr)WH_KEYDOWN)
            {
                int vkCode = Marshal.ReadInt32(lParam);
                switch ((Keys)vkCode)
                {
                    case Keys.Q:
                        lb.Text = "1";
                        break;
                    case Keys.W:
                        lb.Text = "2";
                        break;
                }
            }
            return CallNextHookEx(_hookId, nCode, wParam, lParam);
        }
        public static void StartHook()
        {
            _hookId = SetHook(_proc);
        }
    }
}
В Form1.cs:
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
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
 
namespace MyHook
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
            Hook.StartHook();
            Hook.lb = label1;
            Hook.lb.TextChanged += new System.EventHandler(this.lb_TextChanged);
        }
        private void lb_TextChanged(object sender, EventArgs e)
        {
            switch (Hook.lb.Text)
            {
                case "1":
                    label2.Text = "Opa";
                    Hook.lb.ResetText();
                    Console.Beep(500, 100);
                    break;
                case "2":
                    label2.Text = "Огого";
                    Hook.lb.ResetText();
                    Console.Beep(1000, 100);
                    break;
            }
        }
    }
}
Для меня сойдет, но вопросик такой, почему когда убираю строчку "Hook.lb = label1;" начинает ругаться на "Hook.lb.TextChanged"?! Типа в этот момент и происходит перехват события?
0
06.01.2011, 17:56
IT_Exp
Эксперт
87844 / 49110 / 22898
Регистрация: 17.06.2006
Сообщений: 92,604
06.01.2011, 17:56
Помогаю со студенческими работами здесь

Глобальный перехват сочетания клавиш в системе
Задача такая: нужно сделать программу, которая по-умолчанию будет невидимой, а по нажатию клавиш...

Перехват сообщений от Алисы
Здравствуйте. Кто ни будь пробовал перехватывать сообщения голосового помощника Алисы? Fiddler...

Перехват сообщений с консоли
скажите можно ли сообщения что выводит командная строка вывести в код если да то как

Перехват сообщений из консоли
Подскажите как вывести значение маски подсети не в консоль, а в отдельный текстбокс по нажатию...


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

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