Форум программистов, компьютерный форум, киберфорум
C/C++: WinAPI
Войти
Регистрация
Восстановить пароль
Блоги Сообщество Поиск Заказать работу  
 
Рейтинг 4.91/47: Рейтинг темы: голосов - 47, средняя оценка - 4.91
0 / 0 / 0
Регистрация: 24.05.2018
Сообщений: 14

Отслеживание изменений буфера обмена (Си)

25.05.2018, 15:18. Показов 9606. Ответов 12
Метки нет (Все метки)

Студворк — интернет-сервис помощи студентам
Приветствую. Есть код на 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
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
#include <stdio.h>
#include <stdlib.h>
#include "Windows.h"
#include <locale.h>
 
/*BOOL CALLBACK DlgProc(HWND hDlg, UINT msg, WPARAM wParam, LPARAM lParam)
{
        static HWND hNextViewer;
        hNextViewer = SetClipboardViewer(hDlg);
        switch(msg)
        {
             case WM_DRAWCLIPBOARD:
             {
                if(IsWindow(hNextViewer))
                {
                        PostMessage(hNextViewer, msg, wParam, lParam);
                }
             }
             case WM_CHANGECBCHAIN:
             {
                if(hNextViewer == (HWND)wParam) hNextViewer = (HWND)lParam;
                else if(IsWindow(hNextViewer)) PostMessage(hNextViewer, msg, wParam, lParam);
             }
        }
        ChangeClipboardChain(hDlg, hNextViewer);
}*/
 
char* GetClipBoard(void)
{
    HWND hwnd = GetDesktopWindow();
    char* fromClipboard;//в эту переменную сохраним текст из буфера обмена
    if (OpenClipboard(hwnd))//открываем буфер обмена
    {
        if(IsClipboardFormatAvailable(CF_TEXT))
                {
            HANDLE hData = GetClipboardData(CF_TEXT);//извлекаем текст из буфера обмена
                        fromClipboard = (char*)GlobalLock(hData);//блокируем память и получаем содержимое
            GlobalUnlock(hData);//разблокируем память
            CloseClipboard();//закрываем буфер обмена
                        //вывод на консоль
            //AddClipboardFormatListener(hwnd);
        }
        else
        {
            HANDLE hData = GetClipboardData(CF_HDROP);
                    if(hData>0)
            {
                                int i, nBufSize=2;
                                for(i=0;nBufSize>1;i++)
                {
                                    nBufSize = DragQueryFile(hData, i, NULL, 0)+1;
                                    if(nBufSize>1)
                    {
                                                char *fName = (char*)malloc(nBufSize*sizeof(char));
                                                DragQueryFile(hData, i, fName, nBufSize );
                                                if(fName!=NULL)
                        {
                                                    fromClipboard = (char*)malloc(strlen(fName)+1);
                                                    CharToOem(fName, fromClipboard);
                                                    //вывод на консоль - printf("%s\n",buf);
                                                    free(fromClipboard);
                                                }
                                    }
                                }
                    }
                    CloseClipboard();//закрываем буфер обмена
        }
        //SetClipboardViewer(hwnd);
    }
        return fromClipboard;
}
 
int main(int argc, char *argv[])
{
    setlocale(LC_ALL, "Rus");
    
    GetClipBoard();
    
    getch();
    return 0;
}
Прикреплял его к проекту Borland C++. Выводил содержимое буфер обмена на элемент Memo, всё нормально работает.

Вопрос в следующем, как сделать отслеживание изменений буфера обмена? Знаю, что нужно использовать функции ChangeClipboardChain, SetClipboardViewer и т.д. Но ума не приложу, где и как их использовать? Может кто-то подробно объяснить? В интернете искал, но ничего так путного и не нашел на языке C. Буду очень благодарен.

Добавлено через 14 часов 16 минут
Я так понял, что никто не объяснит, ну ладно. Может кто-нибудь знает ссылки на хорошую литературу, желательно с примерами? Буду очень признателен
0
Programming
Эксперт
39485 / 9562 / 3019
Регистрация: 12.04.2006
Сообщений: 41,671
Блог
25.05.2018, 15:18
Ответы с готовыми решениями:

Отслеживание вставки из буфера обмена
Необходимо отследить, а точнее перехватить вставку из буфера обмена. Я сделал хук вида WH_CALLWNDPROC для перехвата сообщения WM_PASTE....

Отслеживание изменений в буфере обмена
С помощью каких функций WinAPI можно отслеживать изменения буфера обмена. Для вывода интересует тип содержимого и окно откуда было...

Отслеживание изменений файлов на компьютере
Здравствуйте. Прошу помощи, задача написать программу отката, т.е. как функция восстановления windows только написать на с++, подскажите...

12
Супер-модератор
Эксперт Pascal/DelphiАвтор FAQ
 Аватар для volvo
33374 / 21499 / 8235
Регистрация: 22.10.2011
Сообщений: 36,894
Записей в блоге: 12
26.05.2018, 12:20
Цитата Сообщение от Erlos Посмотреть сообщение
В интернете искал
Я не знаю, что и где ты там искал, но я ЗДЕСЬ, на этом форуме выкладывал решение: Отловить нажатие Ctrl+C и выполнить действие паралельно с системой (причем, именно для Билдера, если что...)
0
0 / 0 / 0
Регистрация: 24.05.2018
Сообщений: 14
26.05.2018, 17:32  [ТС]
Цитата Сообщение от volvo Посмотреть сообщение
Я не знаю, что и где ты там искал, но я ЗДЕСЬ, на этом форуме выкладывал решение: Отловить нажатие Ctrl+C и выполнить действие паралельно с системой (причем, именно для Билдера, если что...)
Правильно я сделал? Для того, чтобы работало это:

C++
1
2
3
4
5
6
7
8
9
10
11
__fastcall TForm1::btnSetViewerClick(TObject *Sender)
{
    if(FNextCbViewer) // Второй раз добавлять себя не будем
    {
        ShowMessage(L"Уже зарегистрировано");
    }
    else
    {
        FNextCbViewer = SetClipboardViewer(this->Handle); // А если еще не делали - добавим
    }
}
Я добавил button на событие OnClick и вызвал функцию:

C++
1
2
3
4
void __fastcall TForm1::Button1Click(TObject *Sender)
{
        TForm1::btnSetViewerClick(Sender);        
}
Вроде как работает, но может я неправильно понял, как нужно сделать.

И получается это же реализовано на C++, а на C можно реализовать такое же? Или я чего-то не понимаю?

Просто мне надо основной алгоритм реализовать на языке C, а интерфейс на любом языке программирования. Решил интерфейс делать в Borland C++ Builder.
0
0 / 0 / 0
Регистрация: 24.05.2018
Сообщений: 14
07.06.2018, 18:45  [ТС]
Кхм, поможет ли кто?
0
Супер-модератор
Эксперт Pascal/DelphiАвтор FAQ
 Аватар для volvo
33374 / 21499 / 8235
Регистрация: 22.10.2011
Сообщений: 36,894
Записей в блоге: 12
08.06.2018, 12:52
Цитата Сообщение от Erlos Посмотреть сообщение
поможет ли кто?
Я не понимаю, что значит
Цитата Сообщение от Erlos Посмотреть сообщение
основной алгоритм реализовать на языке C, а интерфейс на любом языке программирования
Если нужен чистый Си + WinAPI - то покажу, как написать функцию окна. Если нужен Билдер - решение уже есть. Где именно тебе в приложении на Билдере нужен чистый Си?
0
0 / 0 / 0
Регистрация: 24.05.2018
Сообщений: 14
08.06.2018, 14:58  [ТС]
Цитата Сообщение от volvo Посмотреть сообщение
Где именно тебе в приложении на Билдере нужен чистый Си?
Может я не совсем правильно делаю, но получается, что получение данных из буфера обмена должны быть на Си (как бы основной алгоритм), а сам интерфейс на C++ (по моему выбору). Но я же уже подключил файл .c как заголовочный, объявил прототип и использую функцию GetClipBoard() (Функция отсюда:
Кликните здесь для просмотра всего текста
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
#include <stdio.h>
#include <stdlib.h>
#include "Windows.h"
#include <locale.h>
 
/*BOOL CALLBACK DlgProc(HWND hDlg, UINT msg, WPARAM wParam, LPARAM lParam)
{
        static HWND hNextViewer;
        hNextViewer = SetClipboardViewer(hDlg);
        switch(msg)
        {
             case WM_DRAWCLIPBOARD:
             {
                if(IsWindow(hNextViewer))
                {
                        PostMessage(hNextViewer, msg, wParam, lParam);
                }
             }
             case WM_CHANGECBCHAIN:
             {
                if(hNextViewer == (HWND)wParam) hNextViewer = (HWND)lParam;
                else if(IsWindow(hNextViewer)) PostMessage(hNextViewer, msg, wParam, lParam);
             }
        }
        ChangeClipboardChain(hDlg, hNextViewer);
}*/
 
char* GetClipBoard(void)
{
    HWND hwnd = GetDesktopWindow();
    char* fromClipboard;//в эту переменную сохраним текст из буфера обмена
    if (OpenClipboard(hwnd))//открываем буфер обмена
    {
        if(IsClipboardFormatAvailable(CF_TEXT))
                {
            HANDLE hData = GetClipboardData(CF_TEXT);//извлекаем текст из буфера обмена
                        fromClipboard = (char*)GlobalLock(hData);//блокируем память и получаем содержимое
            GlobalUnlock(hData);//разблокируем память
            CloseClipboard();//закрываем буфер обмена
                        //вывод на консоль
            //AddClipboardFormatListener(hwnd);
        }
        else
        {
            HANDLE hData = GetClipboardData(CF_HDROP);
                    if(hData>0)
            {
                                int i, nBufSize=2;
                                for(i=0;nBufSize>1;i++)
                {
                                    nBufSize = DragQueryFile(hData, i, NULL, 0)+1;
                                    if(nBufSize>1)
                    {
                                                char *fName = (char*)malloc(nBufSize*sizeof(char));
                                                DragQueryFile(hData, i, fName, nBufSize );
                                                if(fName!=NULL)
                        {
                                                    fromClipboard = (char*)malloc(strlen(fName)+1);
                                                    CharToOem(fName, fromClipboard);
                                                    //вывод на консоль - printf("%s\n",buf);
                                                    free(fromClipboard);
                                                }
                                    }
                                }
                    }
                    CloseClipboard();//закрываем буфер обмена
        }
        //SetClipboardViewer(hwnd);
    }
        return fromClipboard;
}
 
int main(int argc, char *argv[])
{
    setlocale(LC_ALL, "Rus");
    
    GetClipBoard();
    
    getch();
    return 0;
}
)

для получения данных из буфер обмена и занесения их в listBox. Мне не понятно, как работают окна (SetClipboardViewer...) и в общем я думаю, что:
Цитата Сообщение от volvo Посмотреть сообщение
Если нужен чистый Си + WinAPI - то покажу, как написать функцию окна.
это то, что нужно. Но как я понимаю, без WinAPI отслеживание изменения буфера обмена написать не возможно? Т.е. на чистом языке Си?
0
Супер-модератор
Эксперт Pascal/DelphiАвтор FAQ
 Аватар для volvo
33374 / 21499 / 8235
Регистрация: 22.10.2011
Сообщений: 36,894
Записей в блоге: 12
08.06.2018, 22:48
Чистый Си понятия не имеет ни о буфере обмена, ни вообще о Windows.
0
0 / 0 / 0
Регистрация: 24.05.2018
Сообщений: 14
09.06.2018, 11:31  [ТС]
Цитата Сообщение от volvo Посмотреть сообщение
Если нужен чистый Си + WinAPI - то покажу, как написать функцию окна.
Если Вас не затруднит, покажите пожалуйста
0
2734 / 888 / 331
Регистрация: 10.02.2018
Сообщений: 2,099
09.06.2018, 11:54
На MSDN есть "немного" информации про использование буфера обмена. По-моему, этого материала вполне достаточно для ответа на ваш вопрос.
0
0 / 0 / 0
Регистрация: 24.05.2018
Сообщений: 14
09.06.2018, 12:15  [ТС]
Цитата Сообщение от Ygg Посмотреть сообщение
На MSDN есть "немного" информации про использование буфера обмена. По-моему, этого материала вполне достаточно для ответа на ваш вопрос.
Вот эти case WM_CHANGECBCHAIN, WM_DESTROY, WM_CREATE находятся в LRESULT CALLBACK MainWindowProc(hwnd, msg, wParam, lParam) ?

А сам колбэк где находится или его надо создавать? Если создавать то где?
0
2734 / 888 / 331
Регистрация: 10.02.2018
Сообщений: 2,099
09.06.2018, 13:48
Erlos, как работает оконное приложение?
Обычно оно крутится в бесконечном цикле и ждёт "событий"/"сообщений".
Как только происходит "событие"/"сообщение" запускается "обработчик событий"/"оконная функция".
"Обработчик событий"/"оконная функция" проверяет тип "события"/"сообщений".
Если для данного типа есть функция обработки, то выполняется эта функция.
Дальше всё возвращается в бесконечный цикл ожидания "событий"/"сообщений".

Написание оконной программы, по большей части, заключается в написании небольших функций обработки различных событий. Оконная функция (например, MainWindowProc) вызывается каждый раз при получении нового события. Тип и прочие параметры события находятся в аргументах функции. Внутри оконной функции вы ставите проверку сообщений и, если нужно, вызываете собственную функцию обработки. Если нет такой нужды, то вызываете стандартный обработчик.

По умолчанию, оконная программа не получает никаких сообщений в случае изменений буфера обмена. Но можно зарегистрировать в ОС своё окно с помощью специальной функции, например, AddClipboardFormatListener. После это, каждый раз при изменении буфера обмена в окно будет приходить сообщение WM_CLIPBOARDUPDATE. Данное сообщение нужно отлавливать точно так же, как и все другие сообщения, то есть с помощью оконной функции.

Когда вы пишете свою программу на чистом WinApi вы явно и полностью пишете оконную функцию, как это сделано в примере MSDN. Когда вы используете более высокоуровневые IDE, то каждое окно заворачивается в класс, а оконная функция "прячется" от пользователя. Связывание обрабатывающих функций и сообщений осуществляется визуально в различных визардах. При автоматическом связывании функций и сообщений в код классов добавляются специальные макросы, которые позже превращаются в оконную функцию. Возможно, всё это обусловлено тем, что иначе было бы не возможно автоматизировать и визуализировать процесс связывания.
Так, например, для MFC в h-файл класса прописывается макрос:
C++
1
2
3
4
5
6
class CMyDlg
{
    //...
    DECLARE_MESSAGE_MAP()
    //...
}
А в cpp-файл класса прописывается группа макросов, по макросу на каждое событие:
C++
1
2
3
4
5
6
7
BEGIN_MESSAGE_MAP(CMyDlg, CDialogEx)
    ON_WM_PAINT()
    ON_WM_QUERYDRAGICON()
    ON_WM_CREATE()
    ON_NOTIFY(TVN_SELCHANGED, IDC_MYTREE, &CMyDlg::OnTvnSelchangedTree1)
    //...
END_MESSAGE_MAP()
При компиляции макросы разворачиваются в полноценную оконную функцию.
Судя по коду volvo из второго сообщения, в борланде свои заморочки и особенности по сокрытию и конструированию оконной функции из макросов. В коде показано, как правильно задать макросы для связывания сообщений и функций относящихся к буферу обмена.
0
0 / 0 / 0
Регистрация: 24.05.2018
Сообщений: 14
09.06.2018, 14:24  [ТС]
Ygg, что-то Вы меня вообще запутали, теперь я не уверен, что вообще правильно что-то делаю Было бы хорошо, если бы Вы привели пример (не большой) создания окна, связанного с буфером обмена (что угодно), без участия MFC, а только C++ WinAPI, ведь на практике легче понять. Буду очень признателен.
0
2734 / 888 / 331
Регистрация: 10.02.2018
Сообщений: 2,099
09.06.2018, 15:19
Пример из MSDN подправленный до возможности запуска, по крайней мере у меня работает на VS15.
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
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
#include "stdafx.h"
#include <stdio.h>
 
#define IDM_EXIT  0x10
#define IDM_AUTO  0x11
 
HINSTANCE hinst;
UINT uFormat = (UINT)(-1);
BOOL fAuto = TRUE;
 
LRESULT CALLBACK MainWndProc(HWND, UINT, WPARAM, LPARAM);
void WINAPI SetAutoView(HWND hwnd);
void WINAPI InitMenu(HWND hwnd, HMENU hmenu);
BOOL WINAPI IsDisplayableFormat(UINT uFormat);
 
// точка входа
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpszCmdLine, int nCmdShow)
{
    hinst = hInstance;
 
    WNDCLASS wc;
    wc.lpszClassName = TEXT("MyWindowClass");
    wc.hInstance = hInstance;
    wc.lpfnWndProc = MainWndProc; // !!! оконная функция
    wc.hCursor = LoadCursor(NULL, IDC_ARROW);
    wc.hIcon = 0;
    wc.lpszMenuName = 0;
    wc.hbrBackground = GetSysColorBrush(COLOR_WINDOW);
    wc.style = CS_HREDRAW | CS_VREDRAW;
    wc.cbClsExtra = 0;
    wc.cbWndExtra = 0;
    if (!RegisterClass(&wc))
        return 0;
 
    HMENU hSubMenu = CreatePopupMenu();
    AppendMenu(hSubMenu, 0, IDM_AUTO, "Auto");
    HMENU hMenu = CreateMenu();
    AppendMenu(hMenu, 0, IDM_EXIT, "Exit");
    AppendMenu(hMenu, MF_POPUP, (UINT_PTR)hSubMenu, "Format");
 
    HWND hWnd = CreateWindow(wc.lpszClassName, TEXT("My Window Caption"), WS_OVERLAPPEDWINDOW, 100, 100, 500, 400, 0, hMenu, hInstance, 0);
 
    ShowWindow(hWnd, nCmdShow);
    UpdateWindow(hWnd);
 
    // цикл обработки сообщений
    MSG msg;
    while (GetMessage(&msg, 0, 0, 0))
    {
        TranslateMessage(&msg);
        DispatchMessage(&msg);
    }
 
    return msg.wParam;
}
 
LRESULT APIENTRY MainWndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
    static HWND hwndNextViewer;
 
    HDC hdc;
    HDC hdcMem;
    PAINTSTRUCT ps;
    LPPAINTSTRUCT lpps;
    RECT rc;
    LPRECT lprc;
    HGLOBAL hglb;
    LPSTR lpstr;
    HBITMAP hbm;
    HENHMETAFILE hemf;
    HWND hwndOwner;
 
    switch (uMsg)
    {
    case WM_PAINT:
        hdc = BeginPaint(hwnd, &ps);
 
        // Branch depending on the clipboard format. 
 
        switch (uFormat)
        {
        case CF_OWNERDISPLAY:
            hwndOwner = GetClipboardOwner();
            hglb = GlobalAlloc(GMEM_MOVEABLE, sizeof(PAINTSTRUCT));
            lpps = (LPPAINTSTRUCT)GlobalLock(hglb);
            memcpy(lpps, &ps, sizeof(PAINTSTRUCT));
            GlobalUnlock(hglb);
 
            SendMessage(hwndOwner, WM_PAINTCLIPBOARD, (WPARAM)hwnd, (LPARAM)hglb);
 
            GlobalFree(hglb);
            break;
 
        case CF_BITMAP:
            hdcMem = CreateCompatibleDC(hdc);
            if (hdcMem != NULL)
            {
                if (OpenClipboard(hwnd))
                {
                    hbm = (HBITMAP)GetClipboardData(uFormat);
                    SelectObject(hdcMem, hbm);
                    GetClientRect(hwnd, &rc);
 
                    BitBlt(hdc, 0, 0, rc.right, rc.bottom, hdcMem, 0, 0, SRCCOPY);
                    CloseClipboard();
                }
                DeleteDC(hdcMem);
            }
            break;
 
        case CF_TEXT:
            if (OpenClipboard(hwnd))
            {
                hglb = GetClipboardData(uFormat);
                lpstr = (LPSTR)GlobalLock(hglb);
 
                GetClientRect(hwnd, &rc);
                DrawText(hdc, lpstr, -1, &rc, DT_LEFT);
 
                GlobalUnlock(hglb);
                CloseClipboard();
            }
            break;
 
        case CF_ENHMETAFILE:
            if (OpenClipboard(hwnd))
            {
                hemf = (HENHMETAFILE)GetClipboardData(uFormat);
                GetClientRect(hwnd, &rc);
                PlayEnhMetaFile(hdc, hemf, &rc);
                CloseClipboard();
            }
            break;
 
        case 0:
            GetClientRect(hwnd, &rc);
            DrawText(hdc, "The clipboard is empty.", -1,
                &rc, DT_CENTER | DT_SINGLELINE |
                DT_VCENTER);
            break;
 
        default:
            GetClientRect(hwnd, &rc);
            DrawText(hdc, "Unable to display format.", -1,
                &rc, DT_CENTER | DT_SINGLELINE |
                DT_VCENTER);
        }
        EndPaint(hwnd, &ps);
        break;
 
    case WM_SIZE:
        if (uFormat == CF_OWNERDISPLAY)
        {
            hwndOwner = GetClipboardOwner();
            hglb = GlobalAlloc(GMEM_MOVEABLE, sizeof(RECT));
            lprc = (LPRECT)GlobalLock(hglb);
            GetClientRect(hwnd, lprc);
            GlobalUnlock(hglb);
 
            SendMessage(hwndOwner, WM_SIZECLIPBOARD,
                (WPARAM)hwnd, (LPARAM)hglb);
 
            GlobalFree(hglb);
        }
        break;
 
    case WM_CREATE:
 
        // Add the window to the clipboard viewer chain. 
 
        hwndNextViewer = SetClipboardViewer(hwnd);
        break;
 
    case WM_CHANGECBCHAIN:
 
        // If the next window is closing, repair the chain. 
 
        if ((HWND)wParam == hwndNextViewer)
            hwndNextViewer = (HWND)lParam;
 
        // Otherwise, pass the message to the next link. 
 
        else if (hwndNextViewer != NULL)
            SendMessage(hwndNextViewer, uMsg, wParam, lParam);
 
        break;
 
    case WM_DESTROY:
        ChangeClipboardChain(hwnd, hwndNextViewer);
        PostQuitMessage(0);
        break;
 
    case WM_DRAWCLIPBOARD:  // clipboard contents changed. 
 
                            // Update the window by using Auto clipboard format. 
 
        SetAutoView(hwnd);
 
        // Pass the message to the next window in clipboard 
        // viewer chain. 
 
        SendMessage(hwndNextViewer, uMsg, wParam, lParam);
        break;
 
    case WM_INITMENUPOPUP:
        if (!HIWORD(lParam))
            InitMenu(hwnd, (HMENU)wParam);
        break;
 
    case WM_COMMAND:
        switch (LOWORD(wParam))
        {
        case IDM_EXIT:
            DestroyWindow(hwnd);
            break;
 
        case IDM_AUTO:
            SetAutoView(hwnd);
            break;
 
        default:
            fAuto = FALSE;
            uFormat = LOWORD(wParam);
            InvalidateRect(hwnd, NULL, TRUE);
        }
        break;
 
    default:
        return DefWindowProc(hwnd, uMsg, wParam, lParam);
    }
    return (LRESULT)NULL;
}
 
void WINAPI SetAutoView(HWND hwnd)
{
    static UINT auPriorityList[] = {
        CF_OWNERDISPLAY,
        CF_TEXT,
        CF_ENHMETAFILE,
        CF_BITMAP
    };
 
    uFormat = GetPriorityClipboardFormat(auPriorityList, 4);
    fAuto = TRUE;
 
    InvalidateRect(hwnd, NULL, TRUE);
    UpdateWindow(hwnd);
}
 
void WINAPI InitMenu(HWND hwnd, HMENU hmenu)
{
    UINT uFormat;
    char szFormatName[80];
    UINT fuFlags;
    UINT idMenuItem;
 
    // If a menu is not the display menu, no initialization is necessary. 
 
    if (GetMenuItemID(hmenu, 0) != IDM_AUTO)
        return;
 
    // Delete all menu items except the first. 
 
    while (GetMenuItemCount(hmenu) > 1)
        DeleteMenu(hmenu, 1, MF_BYPOSITION);
 
    // Check or uncheck the Auto menu item. 
 
    fuFlags = fAuto ? (MF_BYCOMMAND | MF_CHECKED) : (MF_BYCOMMAND | MF_UNCHECKED);
    CheckMenuItem(hmenu, IDM_AUTO, fuFlags);
 
    // If there are no clipboard formats, return. 
 
    if (CountClipboardFormats() == 0)
        return;
 
    // Open the clipboard. 
 
    if (!OpenClipboard(hwnd))
        return;
 
    // Add a separator and then a menu item for each format. 
 
    AppendMenu(hmenu, MF_SEPARATOR, 0, NULL);
    uFormat = EnumClipboardFormats(0);
 
    while (uFormat)
    {
        if (!GetClipboardFormatName(uFormat, szFormatName, sizeof(szFormatName)))
            sprintf_s(szFormatName, "unknown: 0x%0X", uFormat);
 
        // Add a menu item for the format. For displayable 
        // formats, use the format ID for the menu ID. 
        if (IsDisplayableFormat(uFormat))
        {
            fuFlags = MF_STRING;
            idMenuItem = uFormat;
        }
        else
        {
            fuFlags = MF_STRING | MF_GRAYED;
            idMenuItem = 0;
        }
 
        AppendMenu(hmenu, fuFlags, idMenuItem, szFormatName);
 
        uFormat = EnumClipboardFormats(uFormat);
    }
    CloseClipboard();
 
}
 
BOOL WINAPI IsDisplayableFormat(UINT uFormat)
{
    switch (uFormat)
    {
    case CF_OWNERDISPLAY:
    case CF_TEXT:
    case CF_ENHMETAFILE:
    case CF_BITMAP:
        return TRUE;
    }
    return FALSE;
}
0
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
inter-admin
Эксперт
29715 / 6470 / 2152
Регистрация: 06.03.2009
Сообщений: 28,500
Блог
09.06.2018, 15:19
Помогаю со студенческими работами здесь

отслеживание изменений
вот у каждого разработчика получается есть своя копия репозитория(которую он получает спомощью git clone) так? И если я у себя создам...

Отслеживание изменений в БД
Есть БД, к которой подключено несколько клиентов. Каждый из них имеет компоненты &quot;DataSource&quot;, &quot;ADOConnection&quot;...

Отслеживание изменений
Добрый день. Уважаемые форумчане, подскажите где подсмотреть. Пытаюсь написать пинговалку. private bool ConnectedStatus(string _ip) ...

Отслеживание изменений
Здравствуйте, подскажите пожалуйста, как в Access можно отследить изменения и пользователя который эти изменения сделал. В Excel есть такая...

Отслеживание изменений БД
Добрый вечер! Подскажите, есть ли простой способ отслеживания изменений в БД? Необходимо, чтобы при открытии БД юзер выбирал своё...


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

Или воспользуйтесь поиском по форуму:
13
Ответ Создать тему
Новые блоги и статьи
http://iceja.net/ математические сервисы
iceja 20.01.2026
Обновила свой сайт http:/ / iceja. net/ , приделала Fast Fourier Transform экстраполяцию сигналов. Однако предсказывает далеко не каждый сигнал (см ограничения http:/ / iceja. net/ fourier/ docs ). Также. . .
http://iceja.net/ сервер решения полиномов
iceja 18.01.2026
Выкатила http:/ / iceja. net/ сервер решения полиномов (находит действительные корни полиномов методом Штурма). На сайте документация по API, но скажу прямо VPS слабенький и 200 000 полиномов. . .
Расчёт переходных процессов в цепи постоянного тока
igorrr37 16.01.2026
/ * Дана цепь постоянного тока с R, L, C, k(ключ), U, E, J. Программа составляет систему уравнений по 1 и 2 законам Кирхгофа, решает её и находит переходные токи и напряжения на элементах схемы. . . .
Восстановить юзерскрипты Greasemonkey из бэкапа браузера
damix 15.01.2026
Если восстановить из бэкапа профиль Firefox после переустановки винды, то список юзерскриптов в Greasemonkey будет пустым. Но восстановить их можно так. Для этого понадобится консольная утилита. . .
Сукцессия микоризы: основная теория в виде двух уравнений.
anaschu 11.01.2026
https:/ / rutube. ru/ video/ 7a537f578d808e67a3c6fd818a44a5c4/
WordPad для Windows 11
Jel 10.01.2026
WordPad для Windows 11 — это приложение, которое восстанавливает классический текстовый редактор WordPad в операционной системе Windows 11. После того как Microsoft исключила WordPad из. . .
Classic Notepad for Windows 11
Jel 10.01.2026
Old Classic Notepad for Windows 11 Приложение для Windows 11, позволяющее пользователям вернуть классическую версию текстового редактора «Блокнот» из Windows 10. Программа предоставляет более. . .
Почему дизайн решает?
Neotwalker 09.01.2026
В современном мире, где конкуренция за внимание потребителя достигла пика, дизайн становится мощным инструментом для успеха бренда. Это не просто красивый внешний вид продукта или сайта — это. . .
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2026, CyberForum.ru