Как сохранить/восстановить весь буффер обмена Windows

Тема в разделе "WASM.WIN32", создана пользователем rd, 2 дек 2006.

  1. rd

    rd New Member

    Публикаций:
    0
    Регистрация:
    2 дек 2006
    Сообщения:
    2
    Как можно сохранить (для последующего восстановления) весь буфер обмена. Т.е. данные, которые находятся в нем во всех форматах, стандартных и зарегистрированных другими приложениями. Но нужно это сделать, не вызывая GetClipBoardData для каждого формата, присутствующего в буфере, а именно, не разбираясь вообще, какие форматы доступны в данный момент. Потому что например для стандартных форматов конечно можно вызвать поочерёдно GetClipBoardData, но для нестандартных это сложно, так как ничего не известно о способе организации данных для такого формата.

    В общем, может быть кто знает, как устроен буфер обмена и где он хранит свои данные и как получить к ним доступ.

    Т.е. мне необходим способ создавать снапшоты всего буфера. И потом восстанавливать его данные из такого снапшота.

    Буду очень благодарен за помощь.
     
  2. q_q

    q_q New Member

    Публикаций:
    0
    Регистрация:
    5 окт 2003
    Сообщения:
    1.706
    rd
    Afaik данные не всегда находятся в буфере обмена.
    Правильные приложения, например, ms excel, умеют объявлять несколько форматов, ждать момента запроса, определять конкретный формат, подготовить в нем данные и после этого отдать.
     
  3. leo

    leo Active Member

    Публикаций:
    0
    Регистрация:
    4 авг 2004
    Сообщения:
    2.542
    Адрес:
    Russia
    ИМХО и сама винда наверняка не сразу дублирует все совместимые форматы (например, текстовые или графические), а делает это по запросу, иначе было бы просто глупо-расточительно ;)
     
  4. Y_Mur

    Y_Mur Active Member

    Публикаций:
    0
    Регистрация:
    6 сен 2006
    Сообщения:
    2.494
    Потроши Clipdrd.exe - в 98 он в windows, в XP в system32, есть даже стандартный формат файла на этот случай :)
     
  5. SnugForce

    SnugForce New Member

    Публикаций:
    0
    Регистрация:
    2 май 2005
    Сообщения:
    373
    Адрес:
    Из домУ
    rd
    Самая главная проблема... Я не нашел способа как узнать типа буфера изначально. Осталось перехватывать функцию записи в буфер, либо изучать стандартные форматы распрастраненных программ. Как показал опыт - самый большой размер данных опр-го типа еще не является признаком его первозначимости (((
     
  6. uni

    uni New Member

    Публикаций:
    0
    Регистрация:
    23 май 2005
    Сообщения:
    67
    Могу дать пример восстановления. Записывал сам при помощи clpbrd, хотя, думаю и программно это сделать не очень большая проблема. Ух и намучился я с этим буфером.
    * ищу исходники *
     
  7. uni

    uni New Member

    Публикаций:
    0
    Регистрация:
    23 май 2005
    Сообщения:
    67
    Я давно этим делом занимался, так что надеюсь на Вашу самостоятельность.

    В заголовочном файле определенить:
    Код (Text):
    1. typedef struct
    2. {
    3.     WORD        wId;
    4.     WORD        wCount;
    5. }   CLPBRDFILEHEADER, *PCLPBRDFILEHEADER;
    6.  
    7. typedef struct
    8. {
    9.     WORD        wFormatId;
    10.     DWORD       dwLength;
    11.     DWORD       dwOffset;
    12.     char        szName[79];
    13. }   CLPBRDDATAHEADER, *PCLPBRDDATAHEADER;
    Вот кусок, который считывал и закидывал в память буфера обмена файлы его собственного формата:
    Код (Text):
    1. void CMainFrame::OnInsertTemplates(UINT nID)
    2. {
    3. // План такой:
    4. // 1. Проверяем наличие файлов шаблонов
    5.     CString cs = GetProgramDir();
    6.     switch ( nID ) {
    7.         case ID_INSERT_TEMPLATE_1: {
    8.             cs += "t1.clp";
    9.             break;
    10.         }
    11.         case ID_INSERT_TEMPLATE_2: {
    12.             cs += "t2.clp";
    13.             break;
    14.         }
    15.         case ID_INSERT_TEMPLATE_3: {
    16.             cs += "t3.clp";
    17.             break;
    18.         }
    19.         case ID_INSERT_TEMPLATE_4: {
    20.             cs += "t4.clp";
    21.             break;
    22.         }
    23.         case ID_INSERT_TEMPLATE_5: {
    24.             cs += "t5.clp";
    25.             break;
    26.         }
    27.         case ID_INSERT_TEMPLATE_6: {
    28.             cs += "t6.clp";
    29.             break;
    30.         }
    31.     }
    32.     if ( !FileExists( cs ) ) return;
    33.  
    34. // 2. Проверяем имеет ли файл соответствующий формат
    35.     HANDLE hFile;
    36.     DWORD dwSize, nBytesRead;
    37.     PCLPBRDFILEHEADER pClpHdr = NULL;
    38.     PBYTE   pData = NULL;
    39.  
    40.     hFile = CreateFile(cs, GENERIC_READ, FILE_SHARE_READ,
    41.                       NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
    42.     if ( !(hFile == INVALID_HANDLE_VALUE) ) {
    43.         dwSize = GetFileSize(hFile, NULL);
    44.         if ( dwSize > 0 ) {
    45.             pClpHdr = new CLPBRDFILEHEADER;
    46.             SetFilePointer(hFile, 0, NULL, FILE_BEGIN);
    47.             ReadFile( hFile, pClpHdr, sizeof(CLPBRDFILEHEADER)/sizeof(char), &nBytesRead, NULL);
    48.             // Проверяем тип файла
    49.             if ( pClpHdr->wId == 0xC350 ) {
    50.                 int nCnt = pClpHdr->wCount; // узнаём число записей в файле
    51.                 delete pClpHdr;
    52.                 PCHAR pImg = new char[dwSize];  // создаём образ файла в памяти
    53.                 SetFilePointer(hFile, 0, NULL, FILE_BEGIN);
    54.                 ReadFile( hFile, pImg, dwSize, &nBytesRead, NULL);
    55.                 CloseHandle( hFile );
    56.                 pData = (PBYTE)(pImg + sizeof(CLPBRDFILEHEADER)/sizeof(char));
    57.                 ::OpenClipboard( m_wndMCAD );
    58.                 ::EmptyClipboard();
    59.                 CString str;
    60.                 WORD wFormatId; LPCTSTR szName;
    61.                 DWORD dwOffset;
    62.                 HGLOBAL hData;
    63.                 void * pByte;
    64.                 for ( int i = 0; i < nCnt; i++ ){
    65.                     wFormatId = *(PWORD)(pData + i*0x59);
    66.                     dwSize = *(PDWORD)(pData + i*0x59 + 0x02);
    67.                     dwOffset = *(PDWORD)(pData + i*0x59 + 0x06);
    68.                     szName = (LPCTSTR)(pData + i*0x59 + 0x0A);
    69.                     if ( wFormatId & 0xc000 ) {
    70.                         hData = ::GlobalAlloc( GMEM_SHARE, dwSize );
    71.                         pByte = ::GlobalLock( hData );
    72.                         memcpy( pByte, pImg + dwOffset, dwSize);
    73.                         ::GlobalUnlock( hData );
    74.                         UINT uFormat = ::RegisterClipboardFormat( (LPCTSTR) (pData + i*0x59 + 0x0A) );
    75.                         ::SetClipboardData( uFormat, hData );
    76.                     }
    77.                 }
    78.                 ::CloseClipboard();
    79.                 delete [] pImg;
    80.             } else {
    81.                 delete pClpHdr;
    82.                 CloseHandle( hFile );
    83.                 return;
    84.             }
    85.         } else { // файл имеет нулевой размер
    86.             CloseHandle( hFile );
    87.             return;
    88.         }
    89.     }
    90.  
    91. // 3. Посылаем активному документу комбинацию клавиш [Ctrl] + [V].
    92.     ::SetActiveWindow( m_wndMCAD );
    93.     keybd_event(VK_CONTROL, MapVirtualKey(VK_CONTROL, 0), 0, 0);
    94.     keybd_event((BYTE)('V'), 0, 0,0);
    95.     keybd_event((BYTE)('V'), 0, KEYEVENTF_KEYUP, 0);
    96.     keybd_event(VK_CONTROL, MapVirtualKey(VK_CONTROL, 0), KEYEVENTF_KEYUP, 0);
    97. }
     
  8. uni

    uni New Member

    Публикаций:
    0
    Регистрация:
    23 май 2005
    Сообщения:
    67
    Я много экспериментировал и скажу, что опасная это вещь - сохранять и восстанавливать, а потом вставлять содержимое буфера обмена. Вообще, кроме MSDN, это дело неплохо с исходниками описано в книжке: Р. Саймон, "Microsoft Windows API. Справочник системного программиста." DiaSoft, 2004. К этой книге диск прилагается, там етсь программа, которая показывает все текущие стандартные форматы и форматы данных, которые установило приложение при вставке. Не помню, что там ещё было, но решение с использованием clpbrd для сохранения содержимого буфера мне на тот момент показалось оптимальным.

    К сожалению, диск где-то посеял. Искать надо. В моём коде Вы увидите какие-то непонятные манипуляции с указателями. Дело в том, что я так и не понял как можно передвинуть указатель на число 79 байт - это размер одной записи (заголовка). Передвинуть автоматически, т.е. зная определение и формат заголовка, с использованием унарного инкремента.

    Может у кого ещё эта книжка есть.