Работа с буфером обмена (WinAPI)

Discussion in 'С/С++, C#, Rust, Swift, Go, Java, Perl, Ruby' started by SlyBit, 6 Jul 2008.

  1. SlyBit

    SlyBit Elder - Старейшина

    Joined:
    4 Jul 2008
    Messages:
    49
    Likes Received:
    8
    Reputations:
    0
    Привет всем. Думаю все знают что такое буфер обмена (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);
    }
     
Loading...