Как можно сохранить (для последующего восстановления) весь буфер обмена. Т.е. данные, которые находятся в нем во всех форматах, стандартных и зарегистрированных другими приложениями. Но нужно это сделать, не вызывая GetClipBoardData для каждого формата, присутствующего в буфере, а именно, не разбираясь вообще, какие форматы доступны в данный момент. Потому что например для стандартных форматов конечно можно вызвать поочерёдно GetClipBoardData, но для нестандартных это сложно, так как ничего не известно о способе организации данных для такого формата. В общем, может быть кто знает, как устроен буфер обмена и где он хранит свои данные и как получить к ним доступ. Т.е. мне необходим способ создавать снапшоты всего буфера. И потом восстанавливать его данные из такого снапшота. Буду очень благодарен за помощь.
rd Afaik данные не всегда находятся в буфере обмена. Правильные приложения, например, ms excel, умеют объявлять несколько форматов, ждать момента запроса, определять конкретный формат, подготовить в нем данные и после этого отдать.
ИМХО и сама винда наверняка не сразу дублирует все совместимые форматы (например, текстовые или графические), а делает это по запросу, иначе было бы просто глупо-расточительно
Потроши Clipdrd.exe - в 98 он в windows, в XP в system32, есть даже стандартный формат файла на этот случай
rd Самая главная проблема... Я не нашел способа как узнать типа буфера изначально. Осталось перехватывать функцию записи в буфер, либо изучать стандартные форматы распрастраненных программ. Как показал опыт - самый большой размер данных опр-го типа еще не является признаком его первозначимости (((
Могу дать пример восстановления. Записывал сам при помощи clpbrd, хотя, думаю и программно это сделать не очень большая проблема. Ух и намучился я с этим буфером. * ищу исходники *
Я давно этим делом занимался, так что надеюсь на Вашу самостоятельность. В заголовочном файле определенить: Код (Text): typedef struct { WORD wId; WORD wCount; } CLPBRDFILEHEADER, *PCLPBRDFILEHEADER; typedef struct { WORD wFormatId; DWORD dwLength; DWORD dwOffset; char szName[79]; } CLPBRDDATAHEADER, *PCLPBRDDATAHEADER; Вот кусок, который считывал и закидывал в память буфера обмена файлы его собственного формата: Код (Text): void CMainFrame::OnInsertTemplates(UINT nID) { // План такой: // 1. Проверяем наличие файлов шаблонов CString cs = GetProgramDir(); switch ( nID ) { case ID_INSERT_TEMPLATE_1: { cs += "t1.clp"; break; } case ID_INSERT_TEMPLATE_2: { cs += "t2.clp"; break; } case ID_INSERT_TEMPLATE_3: { cs += "t3.clp"; break; } case ID_INSERT_TEMPLATE_4: { cs += "t4.clp"; break; } case ID_INSERT_TEMPLATE_5: { cs += "t5.clp"; break; } case ID_INSERT_TEMPLATE_6: { cs += "t6.clp"; break; } } if ( !FileExists( cs ) ) return; // 2. Проверяем имеет ли файл соответствующий формат HANDLE hFile; DWORD dwSize, nBytesRead; PCLPBRDFILEHEADER pClpHdr = NULL; PBYTE pData = NULL; hFile = CreateFile(cs, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); if ( !(hFile == INVALID_HANDLE_VALUE) ) { dwSize = GetFileSize(hFile, NULL); if ( dwSize > 0 ) { pClpHdr = new CLPBRDFILEHEADER; SetFilePointer(hFile, 0, NULL, FILE_BEGIN); ReadFile( hFile, pClpHdr, sizeof(CLPBRDFILEHEADER)/sizeof(char), &nBytesRead, NULL); // Проверяем тип файла if ( pClpHdr->wId == 0xC350 ) { int nCnt = pClpHdr->wCount; // узнаём число записей в файле delete pClpHdr; PCHAR pImg = new char[dwSize]; // создаём образ файла в памяти SetFilePointer(hFile, 0, NULL, FILE_BEGIN); ReadFile( hFile, pImg, dwSize, &nBytesRead, NULL); CloseHandle( hFile ); pData = (PBYTE)(pImg + sizeof(CLPBRDFILEHEADER)/sizeof(char)); ::OpenClipboard( m_wndMCAD ); ::EmptyClipboard(); CString str; WORD wFormatId; LPCTSTR szName; DWORD dwOffset; HGLOBAL hData; void * pByte; for ( int i = 0; i < nCnt; i++ ){ wFormatId = *(PWORD)(pData + i*0x59); dwSize = *(PDWORD)(pData + i*0x59 + 0x02); dwOffset = *(PDWORD)(pData + i*0x59 + 0x06); szName = (LPCTSTR)(pData + i*0x59 + 0x0A); if ( wFormatId & 0xc000 ) { hData = ::GlobalAlloc( GMEM_SHARE, dwSize ); pByte = ::GlobalLock( hData ); memcpy( pByte, pImg + dwOffset, dwSize); ::GlobalUnlock( hData ); UINT uFormat = ::RegisterClipboardFormat( (LPCTSTR) (pData + i*0x59 + 0x0A) ); ::SetClipboardData( uFormat, hData ); } } ::CloseClipboard(); delete [] pImg; } else { delete pClpHdr; CloseHandle( hFile ); return; } } else { // файл имеет нулевой размер CloseHandle( hFile ); return; } } // 3. Посылаем активному документу комбинацию клавиш [Ctrl] + [V]. ::SetActiveWindow( m_wndMCAD ); keybd_event(VK_CONTROL, MapVirtualKey(VK_CONTROL, 0), 0, 0); keybd_event((BYTE)('V'), 0, 0,0); keybd_event((BYTE)('V'), 0, KEYEVENTF_KEYUP, 0); keybd_event(VK_CONTROL, MapVirtualKey(VK_CONTROL, 0), KEYEVENTF_KEYUP, 0); }
Я много экспериментировал и скажу, что опасная это вещь - сохранять и восстанавливать, а потом вставлять содержимое буфера обмена. Вообще, кроме MSDN, это дело неплохо с исходниками описано в книжке: Р. Саймон, "Microsoft Windows API. Справочник системного программиста." DiaSoft, 2004. К этой книге диск прилагается, там етсь программа, которая показывает все текущие стандартные форматы и форматы данных, которые установило приложение при вставке. Не помню, что там ещё было, но решение с использованием clpbrd для сохранения содержимого буфера мне на тот момент показалось оптимальным. К сожалению, диск где-то посеял. Искать надо. В моём коде Вы увидите какие-то непонятные манипуляции с указателями. Дело в том, что я так и не понял как можно передвинуть указатель на число 79 байт - это размер одной записи (заголовка). Передвинуть автоматически, т.е. зная определение и формат заголовка, с использованием унарного инкремента. Может у кого ещё эта книжка есть.