Привет всем. Думаю все знают что такое буфер обмена (clipboard). При работе с буфером обмена у нас есть возможность использовать как стандартные форматы хранения данных (CF_TEXT, CF_BITMAP и т.д., полный список смотрите в WinUser.h), так и создавать свои. Нижележащий исходник демонстрирует работу с дефолтовым форматом хранения текста CF_UNICODETEXT, а именно считывает данные из буфера через определенный промежуток времени и пишет в файл вместе с дополнительной информацией о их владельце. Хотелось бы обратить ваше внимание на следующие важные моменты: 1) В один момент времени только одно приложение может работать с буфером. За открытие буфера и предотвращения доступа к нему других приложений отвечает функция OpenClipboard, закрываем буфер функцией CloseClipboard. 2) Максимальный размер данных, считываемых за раз в данной программе задается константой MAX_DATA_SIZE. Вообщем смотрите код с комментами. Скачать src+bin Code: // by SlyBit (c) 07.2008 #include <windows.h> #include <Tlhelp32.h> #pragma comment(linker, "/ENTRY:Entry") #define LOG_FILE_NAME "clipboard.log" #define MAX_DATA_SIZE 1024*10 // Максимальный размер данных, получаемых из буфера за 1 раз BOOL WINAPI GetProccessNameById(DWORD dwPId, PCHAR pName, DWORD dwNameSize) { HANDLE hProcSnap; PROCESSENTRY32 Pe32; if(INVALID_HANDLE_VALUE == (hProcSnap = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0))) { return 0; } Pe32.dwSize = sizeof(PROCESSENTRY32); if(!Process32First(hProcSnap, &Pe32)) { return 0; } while(Process32Next(hProcSnap, &Pe32)) { if(Pe32.th32ProcessID == dwPId) { CloseHandle(hProcSnap); if(lstrlen(Pe32.szExeFile) > dwNameSize) { return 0; } lstrcpy(pName, Pe32.szExeFile); return 1; } } CloseHandle(hProcSnap); return 0; } VOID WINAPI LogClipboardData(PVOID pData, DWORD dwSize) { DWORD dwWrited; static HANDLE hLogClipboardData = NULL; if(!hLogClipboardData || (hLogClipboardData == INVALID_HANDLE_VALUE)) { hLogClipboardData = CreateFile(LOG_FILE_NAME, GENERIC_WRITE, FILE_SHARE_READ, NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, 0); } if(hLogClipboardData != INVALID_HANDLE_VALUE) { SetFilePointer(hLogClipboardData, 0, 0, FILE_END); WriteFile(hLogClipboardData, pData, dwSize, &dwWrited, 0); } } DWORD WINAPI GetTextDataFromClipboard(LPVOID lpParameter) { UINT nClipboardFormat = CF_UNICODETEXT; PWCHAR pClipboardData; HWND hParentWindow; CHAR szLogData[MAX_DATA_SIZE+400], szTempWindowText[50], szWindowText[300], szProcessName[50], szLogDataHeader[400]; SYSTEMTIME SystemTime; DWORD dwOwnerId, dwClipboardDataSize, dwLastClipboardDataSize = 0; WCHAR szPrevBuffer[MAX_DATA_SIZE]; do { // Считываем данные из буфера раз в 0.5 секунд Sleep(500); ZeroMemory(szLogData, MAX_DATA_SIZE+400); szProcessName[0] = '\0'; szWindowText[0] = '\0'; // Блокируем буффер обмена от изменения другими приложениями if(!OpenClipboard(0)) { continue; } if(!(pClipboardData = (PWCHAR)GetClipboardData(nClipboardFormat))) { CloseClipboard(); continue; } if(MAX_DATA_SIZE < (dwClipboardDataSize = lstrlenW(pClipboardData))) { CloseClipboard(); continue; } // Сравниваем с последними данными, чтобы не записывать одну и ту же инфу по несколько раз if(dwLastClipboardDataSize) { if(dwLastClipboardDataSize == dwClipboardDataSize) { if(!lstrcmpW(szPrevBuffer, pClipboardData)) { CloseClipboard(); continue; } } } // Получаем хэндл окна процесса-владельца буфера if(hParentWindow = GetClipboardOwner()) { // Получаем PID процесса-владельца буфера и его имя GetWindowThreadProcessId(hParentWindow, &dwOwnerId); GetProccessNameById(dwOwnerId, szProcessName, 50); // Получаем заголовки всех окон процесса в цепочке Z до самого старшего GetWindowText(hParentWindow, szWindowText, 50); while(hParentWindow) { hParentWindow = GetParent(hParentWindow); if(GetWindowText(hParentWindow, szTempWindowText, 50)) { if((strlen(szWindowText) + strlen(szTempWindowText)) > 290) { break; } lstrcat(szWindowText, " >> "); lstrcat(szWindowText, szTempWindowText); } } } GetLocalTime(&SystemTime); // Формируем заголовок wsprintf(szLogDataHeader, "###### %i.%i.%i %i:%i:%i %s (%s)\r\n", SystemTime.wDay, SystemTime.wMonth, SystemTime.wYear, SystemTime.wHour, SystemTime.wMinute, SystemTime.wSecond, szProcessName, szWindowText); // Декодируем буфферные данные в ANSI, объединяем с заголовком и пишем в файл memcpy(szLogData, szLogDataHeader, lstrlen(szLogDataHeader)); WideCharToMultiByte(CP_ACP, 0, pClipboardData, dwClipboardDataSize, szLogData+lstrlen(szLogDataHeader), dwClipboardDataSize, 0, 0); lstrcat(szLogData, "\r\n\r\n"); LogClipboardData(szLogData, lstrlen(szLogData)); // Запоминаем данные lstrcpyW(szPrevBuffer, pClipboardData); dwLastClipboardDataSize = dwClipboardDataSize; // Снимаем блок с буффера обмена CloseClipboard(); } while(1); return 1; } VOID WINAPI Entry() { HANDLE hThread = NULL; if(hThread = CreateThread(0, 0, GetTextDataFromClipboard, 0, 0, 0)) WaitForSingleObject(hThread, INFINITE); ExitProcess(0); }