Продвинутая работа с буфером обмена на Ассемблере
Продвинутая работа с буфером обмена на Ассемблере
Еще одна статья, посвященная работе с буфером обмена. Обычно для этого используются функции GetClipboardData и SetClipboardData, но сегодня мы будем осваивать новый уровень - чтение и запись различных данных в буфер обмена при помощи OLE-функций. Хорошая практика для закрепления навыков работы с объектами.
Поскольку работать будем с COM-объектами, нам понадобится несколько структур, констант и интерфейсов. С некоторыми вы уже знакомы по предыдущим статьям, а что-то будет в новинку.
Code (Assembler) : Убрать нумерацию
- struct STGMEDIUM
- tymed dd ?
- hGlobal dd ?
- pUnkForRelease dd ?
- ends
- struct FORMATETC
- cfFormat dd ?
- lptd dd ?
- dwAspect dd ?
- lindex dd ?
- tymed dd ?
- ends
- struct DROPFILES
- pFiles dd ?
- pt POINT
- fNC dd ?
- fWide dd ?
- ends
- ; GUID {0000010E-0000-0000-C000-000000000046}
- IID_IDataObject dd 00000010Eh
- dw 00000h
- dw 00000h
- db 0C0h, 000h, 000h, 000h, 000h, 000h, 000h, 046h
- ; IID_IDataObject Interface
- struct IDataObject
- ; IUnknown
- QueryInterface dd ? ; 000h
- AddRef dd ? ; 004h
- Release dd ? ; 008h
- ; IDataObject
- GetData dd ? ; 00Ch
- GetDataHere dd ? ; 010h
- QueryGetData dd ? ; 014h
- GetCanonicalFormatEtc dd ? ; 018h
- SetData dd ? ; 01Ch
- EnumFormatEtc dd ? ; 020h
- DAdvise dd ? ; 024h
- DUnadvise dd ? ; 028h
- EnumDAdvise dd ? ; 02Ch
- ends
- DVASPECT_CONTENT = 1
- TYMED_HGLOBAL = 1
Начнем с получения текстового значения из буфера обмена и запись в буфер произвольной строки. Для получения объекта данных, связанного с буфером обмена, используется функция OleGetClipboard. После этого при помощи метода GetData получаем сами данные, предварительно настроив в структуре FORMATETC их формат. Если формат данных известен заранее и ваша программа ожидает именно его, то указываем это значение, иначе придется проверить доступность нужного формата при помощи функций IsClipboardFormatAvailable или EnumClipboardFormats. В случае успешного вызова, поле hGlobal структуры STGMEDIUM будет содержать хэндл блока памяти с данными буфера обмена.
Code (Assembler) : Убрать нумерацию
- ; Инициализация
- invoke OleInitialize,NULL
- ; Прочитать содержимое буфера обмена
- invoke OleGetClipboard,pDataObject
- ; Настроить формат данных
- mov [fmte.cfFormat],CF_UNICODETEXT
- mov [fmte.lptd],NULL
- mov [fmte.dwAspect],DVASPECT_CONTENT
- mov [fmte.lindex],-1
- mov [fmte.tymed],TYMED_HGLOBAL
- ; Прочитать данные из объекта
- mov eax,[pDataObject]
- mov eax,[eax]
- stdcall dword [eax+IDataObject.GetData],[pDataObject],fmte,medium
- ; Получить адрес содержимого
- invoke GlobalLock,[medium.hGlobal]
- ...
- ; EAX -> данные
- ...
- ; Освободить память
- invoke GlobalUnlock,[medium.hGlobal]
- invoke ReleaseStgMedium,medium
- ; Вызвать метод интерфейса IDataObject->Release()
- mov eax,[pDataObject]
- mov eax,[eax]
- stdcall dword [eax+IDataObject.Release],[pDataObject]
- ; Освободить ресурсы
- invoke OleUninitialize
Code (Assembler) : Убрать нумерацию
- ; Инициализация
- invoke OleInitialize,NULL
- ; Создать объект данных
- invoke SHCreateDataObject,NULL,0,NULL,NULL,IID_IDataObject,pDataObject
- ...
- ; szTxt - строка для записи в буфер
- ; EBX - длина строки в байтах
- ...
- ; Выделить память и записать в нее строку
- invoke GlobalAlloc,GMEM_FIXED+GMEM_ZEROINIT,ebx
- mov [hGlobal],eax
- invoke GlobalLock,[hGlobal]
- mov edi,eax
- mov esi,szTxt
- mov ecx,ebx
- rep movsb
- ; Настроить формат данных
- mov [fmte.cfFormat],CF_UNICODETEXT
- mov [fmte.lptd],NULL
- mov [fmte.dwAspect],DVASPECT_CONTENT
- mov [fmte.lindex],-1
- mov [fmte.tymed],TYMED_HGLOBAL
- mov [medium.tymed],TYMED_HGLOBAL
- mov eax,[hGlobal]
- mov [medium.hGlobal],eax
- ; Связать данные с объектом
- mov eax,[pDataObject]
- mov eax,[eax]
- stdcall dword [eax+IDataObject.SetData],[pDataObject],fmte,medium,TRUE
- ; Установить новое содержимое буфера обмена
- invoke OleSetClipboard,[pDataObject]
- invoke OleFlushClipboard
- ; Освободить память
- invoke GlobalUnlock,[hGlobal]
- ; Вызвать метод интерфейса IDataObject->Release()
- mov eax,[pDataObject]
- mov eax,[eax]
- stdcall dword [eax+IDataObject.Release],[pDataObject]
- ; Освободить ресурсы
- invoke OleUninitialize
Code (Assembler) : Убрать нумерацию
- ; Инициализация
- invoke OleInitialize,NULL
- ; Прочитать содержимое буфера обмена
- invoke OleGetClipboard,pDataObject
- ; Настроить формат данных
- mov [fmte.cfFormat],CF_HDROP
- mov [fmte.lptd],NULL
- mov [fmte.dwAspect],DVASPECT_CONTENT
- mov [fmte.lindex],-1
- mov [fmte.tymed],TYMED_HGLOBAL
- ; Прочитать данные из объекта
- mov eax,[pDataObject]
- mov eax,[eax]
- stdcall dword [eax+IDataObject.GetData],[pDataObject],fmte,medium
- ; Получить адрес содержимого
- invoke GlobalLock,[medium.hGlobal]
- ; Получить количество файлов
- mov esi,eax
- invoke DragQueryFile,esi,0FFFFFFFFh,NULL,NULL
- xor ecx,ecx
- @@:
- push ecx eax
- ; Получить скопированные файлы
- invoke DragQueryFile,esi,ecx,fname,MAX_PATH
- ...
- ; fname - имя скопированного файла
- ...
- pop eax ecx
- inc ecx
- cmp ecx,eax
- jne @b
- ; Освободить память
- invoke GlobalUnlock,[medium.hGlobal]
- invoke ReleaseStgMedium,medium
- ; Вызвать метод интерфейса IDataObject->Release()
- mov eax,[pDataObject]
- mov eax,[eax]
- stdcall dword [eax+IDataObject.Release],[pDataObject]
- ; Освободить ресурсы
- invoke OleUninitialize
Code (Assembler) : Убрать нумерацию
- file1 du 'D:\Data\test.txt',0
- file2 du 'C:\video.avi',0
- ...
- ; Инициализация
- invoke OleInitialize,NULL
- ; Создать объект данных
- invoke SHCreateDataObject,NULL,0,NULL,NULL,IID_IDataObject,pDataObject
- ; Размер структуры DROPFILES
- mov ebx,sizeof.DROPFILES
- inc ebx
- inc ebx
- ; Длина имени первого файла
- invoke lstrlen,file1
- inc eax
- shl eax,1
- add ebx,eax
- ; Длина имени второго файла
- invoke lstrlen,file2
- inc eax
- shl eax,1
- add ebx,eax
- ; Выделить память и записать в нее строку
- invoke GlobalAlloc,GMEM_FIXED+GMEM_ZEROINIT,ebx
- mov [hGlobal],eax
- invoke GlobalLock,[hGlobal]
- mov edi,eax
- ; Заполнить структуру DROPFILES
- mov [edi+DROPFILES.pFiles],sizeof.DROPFILES
- mov [edi+DROPFILES.pt.x],0
- mov [edi+DROPFILES.pt.y],0
- mov [edi+DROPFILES.fNC],FALSE
- mov [edi+DROPFILES.fWide],TRUE
- add edi,sizeof.DROPFILES
- ; Дописать к ней передаваемые файлы
- mov esi,file1
- @@:
- lodsw
- stosw
- or ax,ax
- jnz @b
- mov esi,file2
- @@:
- lodsw
- stosw
- or ax,ax
- jnz @b
- ; Завершающий нулевой WORD
- xor eax,eax
- stosw
- ; Настроить формат данных
- mov [fmte.cfFormat],CF_HDROP
- mov [fmte.lptd],NULL
- mov [fmte.dwAspect],DVASPECT_CONTENT
- mov [fmte.lindex],-1
- mov [fmte.tymed],TYMED_HGLOBAL
- mov [medium.tymed],TYMED_HGLOBAL
- mov eax,[hGlobal]
- mov [medium.hGlobal],eax
- ; Связать данные с объектом
- mov eax,[pDataObject]
- mov eax,[eax]
- stdcall dword [eax+IDataObject.SetData],[pDataObject],fmte,medium,TRUE
- ; Установить новое содержимое буфера обмена
- invoke OleSetClipboard,[pDataObject]
- invoke OleFlushClipboard
- ; Освободить память
- invoke GlobalUnlock,[hGlobal]
- ; Вызвать метод интерфейса IDataObject->Release()
- mov eax,[pDataObject]
- mov eax,[eax]
- stdcall dword [eax+IDataObject.Release],[pDataObject]
- ; Освободить ресурсы
- invoke OleUninitialize
Code (Assembler) : Убрать нумерацию
- ; Инициализация
- invoke OleInitialize,NULL
- ; Создать объект данных
- invoke SHCreateDataObject,NULL,0,NULL,NULL,IID_IDataObject,pDataObject
- ; Сделать скриншот экрана
- invoke GetDesktopWindow
- mov [hwnd],eax
- invoke GetWindowDC,eax
- mov [hDC],eax
- invoke CreateCompatibleDC,[hDC]
- mov [memDC],eax
- invoke GetWindowRect,[hwnd],rc
- mov eax,[rc.right]
- sub eax,[rc.left]
- mov ebx,[rc.bottom]
- sub ebx,[rc.top]
- invoke CreateCompatibleBitmap,[hDC],eax,ebx
- mov [hBitmap],eax
- invoke SelectObject,[memDC],[hBitmap]
- mov [oldbm],eax
- mov eax,[rc.right]
- sub eax,[rc.left]
- mov ebx,[rc.bottom]
- sub ebx,[rc.top]
- invoke BitBlt,[memDC],0,0,eax,ebx,[hDC],0,0,SRCCOPY
- ; Настроить формат данных
- mov [fmte.cfFormat],CF_BITMAP
- mov [fmte.lptd],NULL
- mov [fmte.dwAspect],DVASPECT_CONTENT
- mov [fmte.lindex],-1
- mov [fmte.tymed],TYMED_GDI
- mov [medium.tymed],TYMED_GDI
- mov eax,[hBitmap]
- mov [medium.hBitmap],eax
- mov [medium.pUnkForRelease],NULL
- ; Связать данные с объектом
- mov eax,[pDataObject]
- mov eax,[eax]
- stdcall dword [eax+IDataObject.SetData],[pDataObject],fmte,medium,TRUE
- ; Установить новое содержимое буфера обмена
- invoke OleSetClipboard,[pDataObject]
- invoke OleFlushClipboard
- ; Вызвать метод интерфейса IDataObject->Release()
- mov eax,[pDataObject]
- mov eax,[eax]
- stdcall dword [eax+IDataObject.Release],[pDataObject]
- ; Освободить ресурсы
- invoke SelectObject,[memDC],[oldbm]
- invoke ReleaseDC,[hwnd],[hDC]
- ; Освободить ресурсы
- invoke OleUninitialize
Для очистки содержимого буфера обмена вместо функции EmptyClipboard можно использовать следующую конструкцию. Просто так ее применять, конечно, не надо, но если вся работа с буфером обмена в вашей программе уже выполнена на OLE, то нормально.
Code (Assembler) : Убрать нумерацию
- ; Инициализация
- invoke OleInitialize,NULL
- ; Очистить буфера обмена
- invoke OleSetClipboard,NULL
- ; Освободить ресурсы
- invoke OleUninitialize
Просмотров: 1683 | Комментариев: 0
Внимание! Статья опубликована больше года назад, информация могла устареть!
Комментарии
Отзывы посетителей сайта о статье
Комментариeв нет
Добавить комментарий
Заполните форму для добавления комментария