2013-08-19 3 views
0

Я пишу dll с глобальными крючками. Одной из задач является просмотр буфера обмена и удаление всех данных из него, когда кто-то выполняет операцию копирования. Вот моя функция обратного вызова для окна:Мониторинг буфера обмена

string test("my data"); 

LRESULT CALLBACK WndHandler(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) { 
    switch(msg) { 
     case WM_CREATE: 
      nextClipboardViewer = SetClipboardViewer(windowHandler); 
      MessageBeep(MB_ICONINFORMATION); 
      break; 
     case WM_CHANGECBCHAIN: 
      if((HWND) wParam == nextClipboardViewer) 
       nextClipboardViewer == (HWND) lParam; 
      else if(nextClipboardViewer != NULL) 
       SendMessage(nextClipboardViewer, msg, wParam, lParam); 
      break; 
     case WM_DRAWCLIPBOARD: 
      if(OpenClipboard(windowHandler)) { 
       EmptyClipboard(); 
       HGLOBAL hClipboardData; 
       hClipboardData = GlobalAlloc(GMEM_MOVEABLE, test.size() + 1); 
       char * pchData; 
       pchData = (char*)GlobalLock(hClipboardData); 
       memcpy(pchData, test.c_str(), test.size() + 1); 
       GlobalUnlock(hClipboardData); 
       SetClipboardData(CF_TEXT, hClipboardData); 
       CloseClipboard(); 
      } 
      SendMessage(nextClipboardViewer, msg, wParam, lParam); 
      break; 
     case WM_DESTROY: 
      ChangeClipboardChain(windowHandler, nextClipboardViewer); 
      PostQuitMessage(0); 
      break; 
     default: 
      return DefWindowProc(hwnd, msg, wParam, lParam); 
      break; 
    } 
    return 0; 
} 

Я просто пытаюсь заменить информацию в буфере обмена, но этот код не работает.

Обновлено: Теперь я использую невидимое окно и SetClipboardViewer для мониторинга изменений. Но данные в буфере обмена не меняются.

+1

Даже если это может быть сделано, чтобы работать, все, что вы ловушка где сообщение 'WM_COPY' используется для размещения данных в буфере обмена - нет гарантии, что это будет. Создание окна и использование 'SetClipboardViewer' или' AddClipboardFormatListener' - гораздо лучшее решение. –

+3

Нет смысла опустошать буфер обмена * до * приложение копирует данные на него. Неправильный крючок, используйте WH_CALLWNDPROCRET. И вы действительно * * хотите использовать SetClipboardViewer. Если у вас нет HWND, просто создайте его, он не должен быть видимым. Удостоверьтесь, что ваш деинсталлятор безупречен, он получит хорошую тренировку. –

ответ

1

Я сомневаюсь, что это действительно безопасно для изменения содержимого буфера обмена при обработке WM_DRAWCLIPBOARD сообщения - по крайней мере, я удивлен, что вы не вызываете бесконечный цикл (так как звонки на EmptyClipboard() и SetClipboardData() могут быть запуском другого WM_DRAWCLIPBOARD сообщение). Возможно, у системы есть защита от этого - я никогда не пытался узнать, но он по-прежнему чувствует себя не так :)

Пробуйте эту версию, которая: а) перемещает обновление буфера обмена в отдельное сообщение о том, что окно заносится в себя (перемещая его за пределы кода уведомления об изменении буфера обмена), и б) использует глобальный флаг, чтобы игнорировать изменения, которые он сам делает.

(примечание:. Я думаю, что фактическая ошибка с кодом, что, когда вы обрабатываете WM_CREATE, windowHandler еще не назначен Вы, вероятно, что установка на значение CreateWindowEx возвращается, но когда WM_CREATE обрабатывается CreateWindowEx hasn» т на самом деле еще вернулся. Это означает, что зритель буфер обмена фактически никогда не установлено правильно. Я изменил ссылки использовать hwnd, чтобы исправить это.)

string test("my data"); 

#define MSG_UPDATECLIPBOARD  (WM_APP + 1) 
static bool g_fIgnoreClipboardChange = false; 

LRESULT CALLBACK WndHandler(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) { 
    switch(msg) { 
     case WM_CREATE: 
      nextClipboardViewer = SetClipboardViewer(hwnd); 
      MessageBeep(MB_ICONINFORMATION); 
      break; 
     case WM_CHANGECBCHAIN: 
      if((HWND) wParam == nextClipboardViewer) 
       nextClipboardViewer == (HWND) lParam; 
      else if(nextClipboardViewer != NULL) 
       SendMessage(nextClipboardViewer, msg, wParam, lParam); 
      break; 
     case WM_DRAWCLIPBOARD: 
      if (!g_fIgnoreClipboardChange) 
       PostMessage(hwnd, MSG_UPDATECLIPBOARD, 0, 0); 
      if(nextClipboardViewer != NULL) 
       SendMessage(nextClipboardViewer, msg, wParam, lParam); 
      break; 
     case MSG_UPDATECLIPBOARD: 
      g_fIgnoreClipboardChange = true; 
      if(OpenClipboard(hwnd)) { 
       HGLOBAL hClipboardData; 
       hClipboardData = GlobalAlloc(GMEM_MOVEABLE, test.size() + 1); 
       char * pchData; 
       pchData = (char*)GlobalLock(hClipboardData); 
       memcpy(pchData, test.c_str(), test.size() + 1); 
       GlobalUnlock(hClipboardData); 
       SetClipboardData(CF_TEXT, hClipboardData); 
       CloseClipboard(); 
      } 
      g_fIgnoreClipboardChange = false; 
      break;  
     case WM_DESTROY: 
      ChangeClipboardChain(hwnd, nextClipboardViewer); 
      PostQuitMessage(0); 
      break; 
     default: 
      return DefWindowProc(hwnd, msg, wParam, lParam); 
      break; 
    } 
    return 0; 
} 
+0

Да, вы правы. Моя головная боль была неправильной обработкой окна в функции SetClipboardViewer(). Теперь он работает отлично. –

+0

Я просто изучаю C++ и задаю вам очень простой вопрос: я пытаюсь использовать этот код для создания нового потока в моем консольном приложении win32. Я получаю сообщение об ошибке «nextClipboardViewer» не определено. В какую библиотеку я могу включить эту проблему? Я искал его, но ничего не нашел в этой конкретной функции и библиотечном импорте; Я предполагаю, что это моя проблема. – user1017063

+1

Этот код пришел из OP и был всего лишь фрагментом, это была не полная программа. Если вы добавите 'HWND nextClipboardViewer = 0;' ** вне ** функцию (чтобы сделать ее глобальной), она должна пройти мимо этой ошибки, но я не уверен, какие другие ошибки вы встретите, используя только фрагмент чужой код. –