Форум АНТИЧАТ

Форум АНТИЧАТ (https://forum.antichat.xyz/index.php)
-   С/С++, C#, Delphi, .NET, Asm (https://forum.antichat.xyz/forumdisplay.php?f=24)
-   -   Работа с буфером обмена (WinAPI) (https://forum.antichat.xyz/showthread.php?t=76185)

SlyBit 06.07.2008 04:58

Работа с буфером обмена (WinAPI)
 
Привет всем. Думаю все знают что такое буфер обмена (clipboard). ;)

При работе с буфером обмена у нас есть возможность использовать как стандартные форматы хранения данных (CF_TEXT, CF_BITMAP и т.д., полный список смотрите в WinUser.h), так и создавать свои. Нижележащий исходник демонстрирует работу с дефолтовым форматом хранения текста CF_UNICODETEXT, а именно считывает данные из буфера через определенный промежуток времени и пишет в файл вместе с дополнительной информацией о их владельце.

Хотелось бы обратить ваше внимание на следующие важные моменты:
1) В один момент времени только одно приложение может работать с буфером. За открытие буфера и предотвращения доступа к нему других приложений отвечает функция OpenClipboard, закрываем буфер функцией CloseClipboard.
2) Максимальный размер данных, считываемых за раз в данной программе задается константой MAX_DATA_SIZE.

Вообщем смотрите код с комментами.

Скачать src+bin

Код:

// 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);
}



Время: 10:00