Inter Process Communication Inter Process Communication или IPC используется для обмена данными между двумя приложениями или процессами. Процессы могут быть запущенными либо на одном и том же компьютере, либо на разных компьютерах объединенных в сеть. Операционная система Windows поддерживает различные методы IPC: Буфер обмена: когда пользователь использует команду копирования или вырезания в любом приложении/окне, скопированные данные сохраняются в буфере обмена окнами (временное хранилище). Другое приложение может получить доступ к данным из буфера обмена. COM: модель компонентных объектов предлагает платформу для взаимодействия между процессами в шаблонах сервера и клиента. COM-сервер может быть локальным сервером или внутрипроцессным сервером. Также может быть несколько COM-клиентов, которые взаимодействуют с COM-сервером и обмениваются данными. WM_COPYDATA: Windows предоставляет сообщение, то есть WM_COPYDATA, которое позволяет процессу обмениваться данными с другим процессом. Можно использовать с SendMessage или SendMessageTimeout, у которого в качестве одного из параметров используется адрес структуры COPYDATASTRUCT. Сообщение WM_COPYDATA используется для обмена данными внутри локального компьютера. DDE: динамический обмен данными — это протокол, который содержит набор рекомендаций и правил для отправки данных между процессами. Процесс использует функцию SendMessage с сообщением WM_DDE_INITIATE или WM_DDE_ACK, отправленным в ответ на сообщение WM_DDE_INITIATE. Для обмена данными используется общая память. Memory Mapped File и Paging File: быстрые механизмы связи между процессами, обеспечивают эффективный способ использования содержимого файла в виртуальной памяти или путем доступа к общей области в памяти. В этих IPC данные файла рассматриваются как часть адресного пространства процесса, так что процесс может легко получить доступ к адресу содержимого. Любой другой процесс, имеющий доступ к общей памяти, должен реализовать синхронизацию, чтобы снизить риск повреждения данных. Сопоставление файлов выполняется в той же системе/машине и недоступно для сетевых процессов. Pipe-каналы: можно использовать как в качестве однонаправленного, так и двунаправленного механизма обмена данными. Windows поддерживает два типа каналов: именованный и анонимный канал. Анонимные каналы могут использоваться в одной сети или только между связанными процессами, Именованные каналы могут использоваться в сети внутри разных процессов. Pipe -канал рассматривают как очередь FIFO, где один конец канала действует как сервер, а другой конец канала — как клиент. Mailslot-канал: обеспечивает только одностороннюю связь. Один процесс может создать mailslot-канал в качестве сервера, а другой процесс — клиентский mailslot-канал. Клиент mailslot отправляет сообщение на сервер mailslot, записывая сообщение, и сообщения добавляются к серверу mailslot до тех пор, пока сервер не прочитает их. Процесс может иметь mailslot как на сервере, так и на клиенте, и это помогает в многонаправленной связи. Mailslot предоставляет возможность транслировать сообщение по сети. Sockets: эффективный способ отправки и получения данных по сети и на локальном компьютере. Использует несколько протоколов, таких как TCP/IP и UDP. Используется с комбинацией IP-адреса машины и адреса порта, по которому могут передаваться данные. RPC: Remote Procedure Call (удаленный вызов процедур) обеспечивает способ связи по сети, так что процесс может вызывать функцию в другом процессе. RPC поддерживает тесную связь между клиентом и сервером с высокой производительностью. LPC: Local Procedure Call (локальный вызов процедур). LPC используется операционной системой для передачи сообщений между подсистемами через порты. Основные достоинства LPC: Высокая производительность; Простота и функциональность; Доступность для программ режима пользователя и для драйверов режима ядра. LPC использует клиент-серверную архитектуру и предоставляет API схожий с интерфейсом сокетов. Во взаимодействии участвуют поток-сервер и один или несколько потоков-клиентов: каждый клиент предварительно соединяется с сервером, посылает одно или несколько сообщений, на некоторые из этих сообщений получает ответ и разрывает соединение. Во вложении приложения для иллюстрации IPC (Mailslot, WM_COPYDATA, DDE, Clipboard, Paging File, Memory Mapped File, Named Pipe). От одного приложения к другому передаются: текстовое сообщение картинки звук из wav-файла Картинки и wav-файл находятся во вложении в папке Images.
01. WM_COPYDATAПеред отправкой сообщения WM_COPYDATA структура COPYDATASTRUCT инициализируется информацией о типе пересылаемых данных, объеме данных и указателем на блок данных. Затем с помощью функции SendMessage сообщение WM_COPYDATA пересылается в принимающую программу; параметр wParam содержит дескриптор окна программы, а lParam ― адрес структуры COPYDATASTRUCT. Для передачи данных должна использоваться только функция синхронной отправки сообщения SendMessage, а не PostMessage, которая передает сообщение асинхронным образом. Память под передаваемые данные резервируется и удерживается до тех пор, пока приложение-приемник не обработает сообщение и не оповестит об этом систему. До этого момента приложение-отправитель переходит в режим ожидания. Если нужно ограничивать время ожидания, пока целевое приложение по какой-то причине может не ответить на сообщение, тогда используют функцию SendMessageTimeout. Когда сообщение поступает обработчику WM_COPYDATA принимающей программы, указатель на данные копируется из структуры COPYDATASTRUCT и используется, как любой другой указатель. В принимающем процессе размер блока данных, адрес которого содержит lpData, извлекается из элемента cbData. Значение, считываемое из элемента lpData принимающей программой, будет отличаться от значения, помещенного туда отправляющей программой. Перед передачей сообщения WM_COPYDATA операционная система выделяет в адресном пространстве принимающего процесса блок памяти, копирует данные из отправляющего процесса и обновляет значение lpData. В адресных пространствах этих процессов адреса размещении блока не совпадут. В структуре COPYDATASTRUCT имеется поле, dwData, в котором можно передать 32-разрядное значение, определяемое в программе. Можно поместить туда любое значение, но я помещаю туда константы определенные для работы с буфером обмена (CF_TEXT, CF_DIB, CF_WAVE) (добавлены некоторые форматы из сообщения SadKo) КонстантаhexОписание формата данныхCF_TEXT1Текстовые данные в виде массив символов. Каждая строка завершается комбинацией символов 0Dh и 0Ah, весь массив закрыт нулемCF_BITMAP2Битовое изображение в формате, который зависит от устройства отображения (Device Dependent Bitmap)CF_METAFILEPICT3МетафайлCF_SYLK4Формат Microsoft Symbolic Link. Этот формат предназначен для передачи текстовых данных, причем каждая строка заканчивается комбинацией символов 0Dh и 0Ah. Используется в некоторых программных продуктах MicrosoftCF_DIF5Формат Data Interchange Format. Аналогично формату CF_SYLK, формат CF_DIF предназначен для передачи текстовых данныхCF_TIFF6Графическое изображение в формате Tag Image File Format, который был разработан Microsoft, Aldus Corporation и Hewlett-PackardCF_OEMTEXT7Аналогично предыдущему, однако буфер содержит символы в кодировке OEMCF_DIB8Битовое изображение в формате, который не зависит от устройства отображения (Device Independent Bitmap)CF_PALETTE9Палитра цветов. Используется при записи в Clipboard битовых изображений DIBCF_PENDATAAФормат данных используется в расширении операционной системы Windows, предназначенном для работы с перьевым вводомCF_RIFFBФормат Resource Interchange File FormatCF_WAVECЗвуковые данные. Подмножество формата Resource Interchange File FormatCF_UNICODETEXTDТекст в формате UTF-16, аналогично CF_TEXT и CF_OEMTEXTCF_ENHMETAFILEEДескриптор (HANDLE) к EMF (Enhanced Metafile) ― HENHMETAFILECF_HDROPFДескриптор к структуре HDROP, которая содержит список путей к файлам, используемая при Drag&Drop. Приложение может запросить информацию о файлах, вызвав функцию DragQueryFileCF_LOCALE10Объект HGLOBAL, содержащий информацию о локали текста в буфере обменаCF_DIBV511Объект в памяти, содержащий структуру BITMAPV5HEADER, за которой следует информация о цветовом пространстве и данные картинкиCF_OWNERDISPLAY80Формат данных определяется приложением, записавшим такие данные в Clipboard. Это же приложение отвечает за отображение данныхCF_DSPTEXT81Текстовое представление данных, формат которых определен приложениемCF_DSPBITMAP82Представление данных, формат которых определен приложением, в виде битового изображенияCF_DSPMETAFILEPICT83Представление данных, формат которых определен приложением, в виде метафайлаCF_DSPENHMETAFILE8EФормат EMF (Enhanced Metafile)При использовании метода WM_COPYDATA помните, что сообщения должны пересылаться, а не просто регистрироваться. Чтобы освободить память, выделенную в адресном пространстве принимающего процесса, операционную систему нужно проинформировать о моменте завершении пересылки. Получатель сообщения WM_COPYDATA обращается с блоком данных как будто он предназначен только для чтения. Для внесения изменении в полученные данные, в принимающей программе необходимо подготовить их локальную копию. Объект памяти, который должен быть помещен в буфер обмена, должен быть размещен, при помощи использования функции GlobalAlloc с флажками GMEM_DDESHARE и GMEM_MOVEABLE. Как только объект памяти помещен в буфер обмена, монопольное использование этого дескриптора памяти переходит к системе. Когда буфер обмена очищается, а объект памяти имеет один из следующих форматов буфера обмена, система освобождает объект памяти, обращаясь к обозначенной функции: Наименование функции, которая освобождает объектФормат буфера обменаDeleteMetaFileCF_DSPENHMETAFILECF_DSPMETAFILEPICTCF_ENHMETAFILECF_METAFILEPICTDeleteObjectCF_BITMAPCF_DSPBITMAPCF_PALETTEGlobalFreeCF_DIBCF_DSPTEXTCF_OEMTEXTCF_TEXTCF_UNICODETEXTВ том случае, если буфер обмена освобожден от объекта памяти, чей формат не показывается в предшествующем списке, прикладная программа сама должна освободить объект памяти. Текст приложения-сервера Код (ASM): ; GUI # include win64a.inc ID_TXT equ 100 ID_SEND_TXT equ 101 ID_SEND_ICO equ 102 ID_SEND_WAV equ 103 IDC_DIALOG equ 200 IDC_ICON1 equ 500 IDC_IMG1 equ 104 COPYDATASTRUCT struct dwData dq ? cbData dd ?,? lpData dq ? COPYDATASTRUCT ends .code WinMain proc enter 30h,0 mov r9d,256 mov [rbp-10h],r9 mov qword ptr [rbp-8],LR_DEFAULTCOLOR invoke LoadImage,IMAGE_BASE,IDC_ICON1,IMAGE_ICON mov r9d,offset DialogProc mov qword ptr[rbp-10h],rax invoke DialogBoxParam,IMAGE_BASE,IDC_DIALOG,HWND_DESKTOP invoke RtlExitUserProcess,NULL WinMain endp DialogProc proc hWnddlg:QWORD,uMsg:QWORD,wParam:QWORD,lParam:QWORD local buffer:qword local cdata:COPYDATASTRUCT local FSize:dword local hFile:dword local p:qword local szReadWrite:qword ;number of bytes actually read or write local hResource:qword local pResource:qword mov hWnddlg,rcx mov lParam,r9 cmp edx,WM_CLOSE je wmCLOSE cmp edx,WM_COMMAND je wmCOMMAND cmp edx,WM_INITDIALOG je wmINITDIALOG xor eax,eax jmp exit0 wmINITDIALOG: invoke GetDlgItem,,IDC_IMG1 invoke SendMessage,eax,STM_SETIMAGE,IMAGE_ICON,lParam jmp wmBYE wmSEND_TXT:invoke GlobalAlloc,GPTR,256 mov buffer,rax mov cdata.lpData,rax invoke GetDlgItemText,hWnddlg,ID_TXT,eax,256 or eax,eax jz wmBYE ; Заполнить структуру COPYDATASTRUCT mov cdata.dwData,CF_TEXT ; Учитываем закрывающий строку 0 inc eax mov cdata.cbData,eax jmp @f wmSEND_ICO:; Отправить изображение второму приложению mov cdata.dwData,CF_BITMAP mov edx,p1 invoke FindResource,0,,RT_ICON; find the resource mov hResource,rax invoke SizeofResource,0,eax ; get its size mov cdata.cbData,eax mov FSize,eax invoke LoadResource,0,hResource ; load the resource invoke LockResource,eax;pResource mov cdata.lpData,rax mov p,rax ;------------------------------------------------- mov ecx,256 and qword ptr[rsp+30h],LR_DEFAULTCOLOR;LR_DEFAULTCOLOR=0 mov [rsp+20h],rcx mov [rsp+28h],rcx mov edx,FSize invoke CreateIconFromResourceEx,p,,TRUE,30000h;270376,TRUE,30000h mov [rsp+20h],rax invoke SendDlgItemMessage,hWnddlg,IDC_IMG1,STM_SETIMAGE,IMAGE_ICON xor p1,11b ;-------------------------------------------------- jmp @f wmSEND_WAV:mov ecx,offset wav_file invoke CreateFile,,GENERIC_READ,FILE_SHARE_READ,0,OPEN_EXISTING,\ FILE_ATTRIBUTE_ARCHIVE,0 mov hFile,eax invoke GetFileSize,eax,0 mov FSize,eax mov cdata.dwData,CF_WAVE mov cdata.cbData,eax invoke GlobalAlloc,GPTR,eax mov cdata.lpData,rax lea r9d,szReadWrite and qword ptr[rsp+20h],0 invoke ReadFile,hFile,eax,FSize invoke CloseHandle,hFile @@:; Найти окно получателя mov edx,offset szWin invoke FindWindow,NULL or eax,eax jz wmBYE ; Отправить данные получателю lea r9d,cdata mov qword ptr[rsp+20h],SMTO_ABORTIFHUNG mov qword ptr[rsp+28h],500 and qword ptr[rsp+30h],0 invoke SendMessageTimeout,eax,WM_COPYDATA,hWnddlg jmp wmBYE wmCOMMAND:cmp r8d,BN_CLICKED shl 16 + ID_SEND_TXT je wmSEND_TXT cmp r8d,BN_CLICKED shl 16 + ID_SEND_ICO je wmSEND_ICO cmp r8d,BN_CLICKED shl 16 + ID_SEND_WAV je wmSEND_WAV cmp r8d,BN_CLICKED shl 16 + IDCANCEL jne wmBYE wmCLOSE:invoke EndDialog,,0 wmBYE: mov eax,TRUE exit0: leave retn DialogProc endp ;--------------------------------------- .data szWin db 'WM_COPYDATA Reciever',0 wav_file db '..\Images\03.wav',0 p1 dd 1 end ресурсы Код (C): #include "resource.h" #define ID_TXT 100 #define ID_SEND_TXT 101 #define ID_SEND_ICO 102 #define ID_SEND_WAV 103 #define IDC_DIALOG 200 #define IDC_ICON1 500 #define IDC_IMG1 104 IDC_ICON1 ICON "..\\Images\\icon1.ico" IDC_ICON2 ICON "..\\Images\\icon2.ico" IDC_DIALOG DIALOG 0, 0, 212, 140 STYLE 0x0004 | DS_CENTER | WS_CAPTION | WS_MINIMIZEBOX | WS_SYSMENU | WS_VISIBLE | WS_OVERLAPPED | DS_MODALFRAME | DS_3DLOOK CAPTION "WM_COPYDATA Sender" BEGIN CONTROL "",-1,"BUTTON",BS_GROUPBOX, 2, -1, 207, 24 CONTROL "",IDC_IMG1,"Static",WS_CHILDWINDOW|WS_VISIBLE|SS_ICON,5,23,128,128 CONTROL "Напишите что-нибудь и нажмите 'Отправить текст'",ID_TXT,"EDIT",WS_BORDER | WS_TABSTOP | ES_AUTOHSCROLL,5,7,199,13 DEFPUSHBUTTON "Отправить текст",ID_SEND_TXT,149,27,60,15 PUSHBUTTON "Отправить ICO",ID_SEND_ICO, 149,45,60,15 PUSHBUTTON "Отправить WAV",ID_SEND_WAV, 149,65,60,15 PUSHBUTTON "Выход", IDCANCEL, 149,85,60,15 END Текст приложения-клиента Код (ASM): ; GUI # include win64a.inc IDC_DIALOG equ 200 IMAGE_BASE equ 400000h ID_TXT equ 100 ID_ICON equ 102 IDC_ICON1 equ 500 COPYDATASTRUCT struct dwData dq ? ;дескриптор типа передаваемых данных cbData dd ?,? ;размер данных lpData dq ? ;указатель на данные COPYDATASTRUCT ends .code WinMain proc dummy:qword mov r9d,offset DialogProc and qword ptr[rsp+20h],0 invoke DialogBoxParam,IMAGE_BASE,IDC_DIALOG,HWND_DESKTOP invoke RtlExitUserProcess,NULL WinMain endp DialogProc proc hWnddlg:qword,msg:qword,wParam:qword,lParam:qword local p:qword local FSize:dword local lpwiocb:WAVEHDR local hWaveOut:qword mov hWnddlg,rcx mov lParam,r9 cmp edx,WM_CLOSE je wmCLOSE cmp edx,WM_COPYDATA ; Пришло сообщение WM_COPYDATA? je wmCOPYDATA cmp edx,WM_COMMAND je wmCOMMAND xor eax,eax jmp exit0 wmCOPYDATA:; Получить строку от первого приложения ; В lParam приходит указатель на структуру COPYDATASTRUCT cmp [r9+COPYDATASTRUCT.cbData],0; Размер данных нулевой? je wmBYE; Да, пропускаем cmp [r9+COPYDATASTRUCT.dwData],CF_TEXT; Это нужный тип данных? je COPYDATA_TEXT; Нет, пропускаем cmp [r9+COPYDATASTRUCT.dwData],CF_BITMAP; Это нужный тип данных? je COPYDATA_ICON; Нет, пропускаем cmp [r9+COPYDATASTRUCT.dwData],CF_WAVE; Это нужный тип данных? jne wmBYE COPYDATA_MUSIC:mov eax,[r9+COPYDATASTRUCT.cbData] mov FSize,eax mov r8,[r9+COPYDATASTRUCT.lpData] mov p,r8 add r8d,14h lea ecx,hWaveOut xor r9,r9 mov [rsp+20h],r9 mov qword ptr[rsp+28h],WAVE_ALLOWSYNC or edx,WAVE_MAPPER invoke waveOutOpen ; Подготавливаем заголовок для вывода xor eax,eax mov ecx,(sizeof WAVEHDR)/8 lea edx,lpwiocb mov edi,edx rep stosq mov rax,p add rax,2Ch mov [rdx].WAVEHDR.lpData,rax ;адрес блока данных mov eax,FSize sub eax,2Ch mov [rdx].WAVEHDR.dwBufferLength,eax ;размер блока данных invoke waveOutPrepareHeader,hWaveOut,,sizeof WAVEHDR ; Запускаем проигрывание блока lea edx,lpwiocb invoke waveOutWrite,hWaveOut,,sizeof WAVEHDR @@: test lpwiocb.dwFlags,WHDR_DONE jz @b lea edx,lpwiocb invoke waveOutUnprepareHeader,hWaveOut,,sizeof WAVEHDR invoke waveOutClose,hWaveOut jmp wmBYE COPYDATA_TEXT: invoke SetDlgItemText,,ID_TXT,[r9+COPYDATASTRUCT.lpData] jmp wmBYE COPYDATA_ICON:; Создать HICON напрямую из памяти and qword ptr[rsp+30h],LR_DEFAULTCOLOR;LR_DEFAULTCOLOR=0 mov qword ptr[rsp+20h],256 mov qword ptr[rsp+28h],256 invoke CreateIconFromResourceEx,[r9+COPYDATASTRUCT.lpData],\ [r9+COPYDATASTRUCT.cbData],TRUE,30000h mov [rsp+20h],rax invoke SendDlgItemMessage,hWnddlg,ID_ICON,STM_SETIMAGE,IMAGE_ICON;,eax jmp wmBYE wmCOMMAND:cmp r8d,BN_CLICKED shl 16 + IDCANCEL jne wmBYE wmCLOSE:invoke EndDialog,,0 wmBYE: mov eax,TRUE exit0: leave ret DialogProc endp end ресурсы Код (C): #include "resource.h" #define IDC_DIALOG 200 #define ID_TXT 100 #define ID_ICON 102 IDC_DIALOG DIALOG 0,0,212,140 STYLE 0x0004 | DS_CENTER | WS_CAPTION | WS_MINIMIZEBOX | WS_SYSMENU | WS_VISIBLE | WS_OVERLAPPED | DS_MODALFRAME | DS_3DLOOK CAPTION "WM_COPYDATA Reciever" BEGIN CONTROL "",-1,"BUTTON",BS_GROUPBOX, 2, -1, 207, 24 CONTROL "",ID_TXT,"STATIC",WS_BORDER | WS_TABSTOP | ES_AUTOHSCROLL,5,7,199,13 DEFPUSHBUTTON "Выход",IDCANCEL,149,27,60,15 CONTROL 1,ID_ICON,"STATIC",WS_CHILDWINDOW | SS_ICON,5,23,128,128 END
02. ClipboardФункции для работы с ClipboardВ Windows предусмотрено несколько функций для работы с Clipboard. Перед тем как выполнить запись или чтение данных, приложение должно получить доступ к Clipboard, открыв ее при помощи функции OpenClipboard: Код (C): BOOL WINAPI OpenClipboard(HWND hwnd); В качестве параметра этой функции передается дескриптор окна, которое будет "владеть" Clipboard. При необходимости функция этого окна будет получать сообщения, извещающие о необходимости выполнения определенных операций с Clipboard. Если доступ к Clipboard получен, OpenClipboard = TRUE. Если же Clipboard уже открыт другим приложением, OpenClipboard вернет FALSE. После использования приложение должно закрыть Clipboard, вызвав функцию CloseClipboard: Код (C): BOOL WINAPI CloseClipboard(void); Функция в случае успеха возвращает TRUE, в случае ошибки ― FALSE. Содержимое открытого Clipboard можно сбросить функцией EmptyClipboard: Код (C): BOOL WINAPI EmptyClipboard(void); EmptyClipboard возвращает TRUE при нормальном завершении или FALSE при ошибке. Для выполнения записи данных в Clipboard используют функцию SetClipboardData: Код (C): HANDLE WINAPI SetClipboardData(UINT uFormat, HANDLE hData); У SetClipboardData два параметра. Первый параметр определяет формат запоминаемых в Clipboard данных, второй параметр передается дескриптор незафиксированного глобального блока памяти, содержащего запоминаемые данные. Для параметра uFormat используют константу, соответствующую одному из предопределенных форматов, или константу полученную от функции RegisterClipboardFormat. Функция RegisterClipboardFormat позволяет регистрировать собственные форматы данных для Clipboard. Список предопределенных форматов данных для Clipboard в разделе об WM_COPYDATA. Для чтения данных из Clipboard используют функцию GetClipboardData: Код (C): HANDLE WINAPI GetClipboardData(UINT uFormat); Единственный параметр задает требуемый формат данных. Если Clipboard содержит данные в указанном формате, функция GetClipboardData возвращает дескриптор незафиксированного глобального блока памяти, содержащего требуемые данные. Запись данных в Clipboard Для записи данных в Clipboard, выполняют следующую последовательность действий: Открыть Clipboard функцией OpenClipboard Сбросить содержимое Clipboard функцией EmptyClipboard Заказать с помощью GlobalAlloc глобальный блок памяти с размером, достаточным для размещения записываемых в Clipboard данных Зафиксировать полученный блок памяти функцией GlobalLock Записать в зафиксированный блок памяти данные Расфиксировать блок памяти функцией GlobalUnlock Вызвать функцию SetClipboardData, передав ей через первый параметр формат данных, а через второй ― дескриптор расфиксированного блока памяти, содержащего данные Закрыть Clipboard функцией CloseClipboard Блок памяти, полученный для данных, не уничтожается функцией GlobalFree, после того как его дескриптор был использован в вызове функции SetClipboardData. При записи в Clipboard перемещения данных не происходит. Функция SetClipboardData изменяет атрибуты передаваемого ей блока памяти, блок памяти меняет своего "хозяина", переходит в собственность операционной системы Windows и приобретает атрибут GMEM_DDESHARE. Если приложение заказало глобальный блок памяти без атрибута GMEM_DDESHARE, этот блок памяти принадлежит приложению. Оно отвечает за уничтожение такого блока памяти. Если же приложение "забыло" уничтожить заказанный ей глобальный блок памяти, блок памяти уничтожает Windows при завершении приложения. Блок памяти, предназначенный для хранения данных Clipboard, не уничтожается при завершении работы приложения, создавшего его. Если приложение снабдит блок памяти атрибутом GMEM_DDESHARE, Windows не будет автоматически уничтожать его при завершении работы приложения. Приложение обязано уничтожить его самостоятельно, как только этот блок памяти перестанет быть нужным. Блоки памяти с атрибутом GMEM_DDESHARE используются в Windows для организации общего поля памяти, доступного всем приложениям. В Windows для адресации памяти все приложения обращаются к одной локальной таблице дескрипторов LDT, все приложения могут адресоваться к одному блоку памяти, если будут знать его селектор. Память Clipboard в Windows устроена в виде набора блоков памяти "общего пользования" (по одному на каждый формат данных). Функция SetClipboardData получает у приложения "личный" глобальный блок памяти с данными, и отдает его в "коллективное пользование", добавляя атрибут GMEM_DDESHARE. Если данные записаны в Clipboard с передачей дескриптора глобального блока памяти функции SetClipboardData, больше нельзя использовать этот дескриптор для адресации данных. В любой момент времени пользователь может уничтожить такой блок памяти записью в Clipboard новых данных. В процессе записи новых данных приложение вызовет функцию EmptyClipboard, которая уничтожит все блоки памяти, распределенные Clipboard раньше. Если операция записи данных в Clipboard выполняется при обработке одного сообщения, никакое другое приложение не будет работать с Clipboard во время записи данных. Если этот обработчик попутно создает диалоговые панели, пользователь может записать в Clipboard содержимое, например, однострочного текстового редактора, реализованного в виде органа управления диалоговой панели. Для исключения конфликтных ситуаций, связанных с попыткой одновременного доступа к Clipboard со стороны нескольких приложений, используют следующее правило: Все операции с Clipboard от его открытия и до закрытия должны выполняться в одном обработчике сообщения. Нельзя открывать Clipboard в обработчике одного сообщения, а закрывать в обработчике другого сообщения. Между открытием и закрытием Clipboard нельзя создавать диалоговые панели или выполнять другие действия, которые могут повлечь за собой создание диалоговых панелей (например, вызов функций SendMessage или PeekMessage) Операционная система Windows создает для каждого приложения отдельную локальную таблицу дескрипторов LDT и отдельное адресное пространство. Никакое приложение ни при каких обстоятельствах не может иметь доступа к адресному пространству другого приложения. Если для передачи данных между приложениями использовать функции Clipboard, гарантирована совместимость на уровне исходных текстов с операционной системой Windows. Чтение данных из Clipboard Процедура чтения данных из Clipboard. Приложение должно сделать следующее. Открыть Clipboard функцией OpenClipboard Вызвать GetClipboardData, передав ей через единственный параметр требуемый формат данных. Если Clipboard содержит данные в указанном формате, функция GetClipboardData возвратит дескриптор незафиксированного блока памяти, содержащего нужные данные. Если в Clipboard нет данных в указанном формате, будет возвращено значение NULL Зафиксировать блок памяти, дескриптор которого получен от функции GetClipboardData, функцией GlobalLock Переписать данные из зафиксированного буфера данных Clipboard в буфер, заказанный специально для этого приложением Расфиксировать блок памяти, дескриптор которого получен от функции GetClipboardData, функцией GlobalUnlock Закрыть Clipboard функцией CloseClipboard Чтение содержимого Clipboard, как и запись в Clipboard, нужно выполнять в обработчике одного сообщения. Приложение должно переписать данные из блока памяти Clipboard в свой, созданный специально, а не пользоваться блоком памяти, дескриптор которого был получен от функции GetClipboardData. В любой момент времени пользователь может уничтожить этот блок памяти, перезаписав содержимое Clipboard новыми данными. Текст приложения-сервера Код (ASM): ; GUI # include win64a.inc IDC_DIALOG equ 200 ID_TXT equ 100 ID_ICON equ 102 IDC_ICON1 equ 500 WM_CLIPBOARDUPDATE equ 31Dh .code WinMain proc dummy:qword mov r9d,offset DialogProc and qword ptr[rsp+20h],0 invoke DialogBoxParam,IMAGE_BASE,IDC_DIALOG,HWND_DESKTOP invoke RtlExitUserProcess,NULL WinMain endp DialogProc proc hWnddlg:qword,msg:qword,wParam:qword,lParam:qword local buffer[96]:BYTE local hGin:qword local p:qword local FSize:dword local lpwiocb:WAVEHDR local hWaveOut:qword mov hWnddlg,rcx mov lParam,r9 cmp edx,WM_CLOSE je wmCLOSE cmp edx,WM_CLIPBOARDUPDATE je wmCLIPBOARDUPDATE cmp edx,WM_COMMAND je wmCOMMAND xor eax,eax jmp exit0 wmCLIPBOARDUPDATE:; Получить строку от первого приложения ; В lParam приходит указатель на тип данных? invoke OpenClipboard,hWnddlg ;открываем буфер обмена invoke __imp_GetClipboardData,lParam;извлекаем текст из буфера обмена mov hGin,rax invoke GlobalLock,eax ;блокируем память cmp lParam,CF_WAVE; Это нужный тип данных? jz WAVE cmp lParam,CF_DIB; Это нужный тип данных? jz DIB cmp lParam,CF_TEXT jnz wmBYE ;--------------------------------------------------- TXT: mov ecx,96 mov esi,eax lea edi,buffer mov r8d,edi rep movsb invoke SetDlgItemText,hWnddlg,ID_TXT jmp @0 DIB: and qword ptr[rsp+30h],LR_DEFAULTCOLOR;LR_DEFAULTCOLOR=0 mov qword ptr[rsp+20h],256 mov qword ptr[rsp+28h],256 invoke CreateIconFromResourceEx,eax,lParam,TRUE,30000h mov [rsp+20h],rax invoke SendDlgItemMessage,hWnddlg,ID_ICON,STM_SETIMAGE,IMAGE_ICON;,eax jmp @0 WAVE: mov p,rax mov r8,rax;p mov eax,[r8+4] mov FSize,eax add r8d,14h lea ecx,hWaveOut xor r9,r9 mov [rsp+20h],r9 mov qword ptr[rsp+28h],WAVE_ALLOWSYNC or edx,WAVE_MAPPER invoke waveOutOpen ; Подготавливаем заголовок для вывода lea edx,lpwiocb mov edi,edx xor eax,eax mov ecx,(sizeof WAVEHDR)/8 rep stosq mov rax,p add rax,2Ch mov [rdx].WAVEHDR.lpData,rax ;адрес блока данных mov eax,FSize sub eax,2Ch mov [rdx].WAVEHDR.dwBufferLength,eax ;размер блока данных invoke waveOutPrepareHeader,hWaveOut,,sizeof WAVEHDR ; Запускаем проигрывание блока lea edx,lpwiocb invoke waveOutWrite,hWaveOut,,sizeof WAVEHDR @@: test lpwiocb.dwFlags,WHDR_DONE jz @b lea edx,lpwiocb invoke waveOutUnprepareHeader,hWaveOut,,sizeof WAVEHDR invoke waveOutClose,hWaveOut @0: invoke GlobalLock,hGin invoke CloseClipboard jmp wmBYE wmCOMMAND:cmp r8d,BN_CLICKED shl 16 + IDCANCEL jne wmBYE wmCLOSE:invoke EndDialog,,0 wmBYE: mov eax,TRUE exit0: leave ret DialogProc endp end ресурсы Код (C): #include "resource.h" #define IDC_DIALOG 200 #define ID_TXT 100 #define ID_ICON 102 IDC_DIALOG DIALOG 0,0,212,140 STYLE 0x0004 | DS_CENTER | WS_CAPTION | WS_MINIMIZEBOX | WS_SYSMENU | WS_VISIBLE | WS_OVERLAPPED | DS_MODALFRAME | DS_3DLOOK CAPTION "Clipboard Reciever" BEGIN CONTROL "",-1,"BUTTON",BS_GROUPBOX, 2, -1, 207, 24 CONTROL "",ID_TXT,"STATIC",WS_BORDER | WS_TABSTOP | ES_AUTOHSCROLL,5,7,199,13 DEFPUSHBUTTON "Выход",IDCANCEL,149,27,60,15 CONTROL "",ID_ICON,"STATIC",WS_CHILDWINDOW | SS_ICON,5,23,128,128 END Текст приложения-клиента Код (ASM): ; GUI # include win64a.inc ID_TXT equ 100 ID_SEND_TXT equ 101 ID_SEND_ICO equ 102 ID_SEND_WAV equ 103 IDC_DIALOG equ 200 IDC_ICON1 equ 500 IDC_IMG1 equ 104 WM_CLIPBOARDUPDATE equ 31Dh extern __imp_SetClipboardData:qword .code WinMain proc enter 30h,0 mov r9d,256;cx mov [rbp-10h],r9 mov qword ptr [rbp-8],LR_DEFAULTCOLOR invoke LoadImage,IMAGE_BASE,IDC_ICON1,IMAGE_ICON;,256,256,LR_DEFAULTCOLOR mov r9d,offset DialogProc mov qword ptr[rbp-10h],rax;30h-10h=+20h invoke DialogBoxParam,IMAGE_BASE,IDC_DIALOG,HWND_DESKTOP invoke RtlExitUserProcess,NULL WinMain endp DialogProc proc hWnddlg:QWORD,uMsg:QWORD,wParam:QWORD,lParam:QWORD size_of_buffer equ 96 local buffer[size_of_buffer]:BYTE local hGout:qword local p:qword local FSize:dword local hFile:dword local szReadWrite:qword ;number of bytes actually read or write local hResource:qword local pResource:qword local type0:qword mov hWnddlg,rcx mov lParam,r9 cmp edx,WM_CLOSE je wmCLOSE cmp edx,WM_COMMAND je wmCOMMAND cmp edx,WM_INITDIALOG je wmINITDIALOG xor eax,eax jmp exit0 wmINITDIALOG:; invoke GetDlgItem,,IDC_IMG1 invoke SendMessage,eax,STM_SETIMAGE,IMAGE_ICON,lParam jmp wmBYE wmSEND_TXT:lea r8d,buffer invoke GetDlgItemText,,ID_TXT,,size_of_buffer;255 or eax,eax jz wmBYE mov FSize,eax invoke GlobalAlloc,GPTR,size_of_buffer;GHND or GMEM_DDESHARE mov hGout,rax invoke GlobalLock,eax mov p,rax mov edi,eax lea esi,buffer mov ecx,FSize rep movsb and byte ptr[rdi],0 mov type0,CF_TEXT ;---------------------------------------------------- jmp @f wmSEND_ICO:; Отправить изображение второму приложению mov edx,p1 invoke FindResource,0,,RT_ICON; find the resource mov hResource,rax invoke SizeofResource,0,eax ; get its size mov FSize,eax invoke GlobalAlloc,GPTR,eax; or GMEM_DDESHARE,eax mov hGout,rax invoke GlobalLock,eax mov p,rax mov edi,eax invoke LoadResource,0,hResource ; load the resource invoke LockResource,eax;pResource mov esi,eax mov ecx,FSize rep movsb ;------------------------------------------------ mov ecx,256 and qword ptr[rsp+30h],LR_DEFAULTCOLOR;LR_DEFAULTCOLOR=0 mov [rsp+20h],rcx mov [rsp+28h],rcx mov edx,FSize invoke CreateIconFromResourceEx,p,,TRUE,30000h mov [rsp+20h],rax invoke SendDlgItemMessage,hWnddlg,IDC_IMG1,STM_SETIMAGE,IMAGE_ICON mov type0,CF_DIB xor p1,11b ;-------------------------------------------------- jmp @f wmSEND_WAV:mov ecx,offset wav_file invoke CreateFile,,GENERIC_READ,0,0,OPEN_EXISTING,\ FILE_ATTRIBUTE_ARCHIVE,0 mov hFile,eax invoke GetFileSize,eax,0 mov FSize,eax invoke GlobalAlloc,GPTR,eax mov hGout,rax invoke GlobalLock,eax mov p,rax lea r9d,szReadWrite invoke ReadFile,hFile,eax,FSize,,0 invoke CloseHandle,hFile mov type0,CF_WAVE ;-------------------------------------------------------- @@: invoke GlobalUnlock,hGout invoke OpenClipboard,hWnddlg or eax,eax jz wmBYE invoke EmptyClipboard invoke __imp_SetClipboardData,type0,hGout invoke CloseClipboard ; Найти окно получателя mov edx,offset szWin invoke FindWindow,NULL or eax,eax jz wmBYE ; Отправить данные получателю invoke PostMessage,eax,WM_CLIPBOARDUPDATE,hWnddlg,type0 jmp wmBYE wmCOMMAND:cmp r8d,BN_CLICKED shl 16 + ID_SEND_TXT je wmSEND_TXT cmp r8d,BN_CLICKED shl 16 + ID_SEND_ICO je wmSEND_ICO cmp r8d,BN_CLICKED shl 16 + ID_SEND_WAV je wmSEND_WAV cmp r8d,BN_CLICKED shl 16 + IDCANCEL jne wmBYE wmCLOSE:invoke EndDialog,,0 wmBYE: mov eax,TRUE exit0: leave retn DialogProc endp ;--------------------------------------- .data szWin db 'Clipboard Reciever',0 wav_file db '..\Images\03.wav',0 p1 dd 1 end ресурсы Код (C): #include "resource.h" #define ID_TXT 100 #define ID_SEND_TXT 101 #define ID_SEND_ICO 102 #define ID_SEND_WAV 103 #define IDC_DIALOG 200 #define IDC_ICON1 500 #define IDC_IMG1 104 IDC_ICON1 ICON "..\\Images\\icon1.ico" IDC_ICON2 ICON "..\\Images\\icon2.ico" IDC_DIALOG DIALOG 0, 0, 212, 140 STYLE 0x0004 | DS_CENTER | WS_CAPTION | WS_MINIMIZEBOX | WS_SYSMENU | WS_VISIBLE | WS_OVERLAPPED | DS_MODALFRAME | DS_3DLOOK CAPTION "Clipboard Sender" BEGIN CONTROL "",-1,"BUTTON",BS_GROUPBOX, 2, -1, 207, 24 CONTROL "",IDC_IMG1,"Static",WS_CHILDWINDOW|WS_VISIBLE|SS_ICON,5,23,128,128 CONTROL "Напишите что-нибудь и нажмите 'Отправить текст'",ID_TXT,"EDIT",WS_BORDER | WS_TABSTOP | ES_AUTOHSCROLL,5,7,199,13 DEFPUSHBUTTON "Отправить текст",ID_SEND_TXT,149,27,60,15 PUSHBUTTON "Отправить ICO",ID_SEND_ICO, 149,45,60,15 PUSHBUTTON "Отправить WAV",ID_SEND_WAV, 149,65,60,15 PUSHBUTTON "Выход", IDCANCEL, 149,85,60,15 END
04. Paging File (страничный файл)Страничный файл входит в общую физическую память вычислительной системы увеличивая ее объем. В физической памяти создается проекция страничного файла, которая отображается на виртуальное адресное пространство нескольких процессов. Первый процесс создает в памяти проекцию страничного файла и отображает ее на свое адресное пространство, записывает в эту память некоторые данные. Второй процесс отображает ту же проекцию страничного файла на свое адресное пространство, читает эти данные. При создании проекции файла в разделе Memory Mapped File в качестве первого параметра функции CreateFileMapping указывают дескриптор открытого файла на диске. Чтобы создать проекцию страничного файла, первый параметр функции CreateFileMapping должен быть равным -1 (INVALID_HANDLE_VALUE). Предпоследний параметр функции задает размер проекции, а последний ― произвольное имя объекта, которое должно быть известно во втором процессе. С помощью функции MapViewOfFile в виртуальной памяти процесса выделяется область в памяти того же размера и проекция страничного файла отображается на эту же область памяти. Текст приложения-сервера Код (ASM): ; GUI # include win64a.inc ID_TXT equ 100 ID_SEND_TXT equ 101 ID_SEND_ICO equ 102 ID_SEND_WAV equ 103 IDC_DIALOG equ 200 IDC_ICON1 equ 500 IDC_IMG1 equ 104 .code WinMain proc dummy:qword mov r9d,256 mov [rsp+20h],r9 mov qword ptr [rsp+28],LR_DEFAULTCOLOR invoke LoadImage,IMAGE_BASE,IDC_ICON1,IMAGE_ICON mov r9d,offset DialogProc mov qword ptr[rsp+20h],rax invoke DialogBoxParam,IMAGE_BASE,IDC_DIALOG,HWND_DESKTOP invoke RtlExitUserProcess,NULL WinMain endp DialogProc proc hWnddlg:QWORD,uMsg:QWORD,wParam:QWORD,lParam:QWORD size_of_buffer equ 96 local buffer[size_of_buffer]:BYTE local hFile:dword local FSize:dword local hMapping:qword local pMapping:qword local hResource:qword local pResource:qword local szReadWrite:qword local type0:qword mov hWnddlg,rcx mov lParam,r9 cmp edx,WM_CLOSE je wmCLOSE cmp edx,WM_COMMAND je wmCOMMAND cmp edx,WM_INITDIALOG je wmINITDIALOG xor eax,eax jmp exit0 wmINITDIALOG:; invoke GetDlgItem,,IDC_IMG1 invoke SendMessage,eax,STM_SETIMAGE,IMAGE_ICON,lParam jmp wmBYE wmSEND_TXT: lea r8d,buffer invoke GetDlgItemText,,ID_TXT,,size_of_buffer or eax,eax jz wmBYE inc eax mov FSize,eax ;создание в памяти объекта "проекция файла" sub esp,30h movr qword ptr[rsp+28h],szMapName mov eax,FSize mov [rsp+20h],rax or rcx,INVALID_HANDLE_VALUE invoke CreateFileMapping,,0,PAGE_READWRITE,0 mov hMapping,rax ;отображение проекции файла на адресное пространство процесса mov ecx,eax mov eax,FSize mov [rsp+20h],rax invoke MapViewOfFile,,FILE_MAP_ALL_ACCESS,0,0 mov pMapping,rax mov ecx,FSize mov edi,eax lea esi,buffer rep movsb mov type0,WM_USER+1 ;-------------------------------------------------- jmp @f wmSEND_ICO:sub esp,30h mov edx,p1 invoke FindResource,0,,RT_ICON; find the resource mov hResource,rax invoke SizeofResource,0,eax ; get its size mov FSize,eax invoke LoadResource,0,hResource ; load the resource invoke LockResource,eax mov esi,eax ;созддание в памяти объекта "проекция файла" movr qword ptr[rsp+28h],szMapName mov eax,FSize mov [rsp+20h],rax or rcx,INVALID_HANDLE_VALUE invoke CreateFileMapping,,0,PAGE_READWRITE,0 mov hMapping,rax ;отображение проекции файла на адресное пространство процесса mov ecx,eax mov eax,FSize mov [rsp+20h],rax invoke MapViewOfFile,,FILE_MAP_ALL_ACCESS,0,0 mov pMapping,rax mov ecx,FSize mov edi,eax;rdi,pMapping rep movsb ;-------------------------------------------------- mov ecx,256 and qword ptr[rsp+30h],LR_DEFAULTCOLOR;LR_DEFAULTCOLOR=0 mov [rsp+20h],rcx mov [rsp+28h],rcx mov edx,FSize invoke CreateIconFromResourceEx,pMapping,,TRUE,30000h;270376,TRUE,30000h mov [rsp+20h],rax invoke SendDlgItemMessage,hWnddlg,IDC_IMG1,STM_SETIMAGE,IMAGE_ICON xor p1,11b mov type0,WM_USER+2 ;------------------------------------------------------- jmp @f wmSEND_WAV:sub esp,40h mov ecx,offset wav_file xor r9d,r9d mov qword ptr[rsp+30h],r9 mov qword ptr[rsp+28h],FILE_ATTRIBUTE_ARCHIVE mov qword ptr[rsp+20h],OPEN_EXISTING invoke CreateFile,,GENERIC_READ or GENERIC_WRITE,\ FILE_SHARE_READ or FILE_SHARE_WRITE mov hFile,eax invoke GetFileSize,eax,0 mov FSize,eax ;созддание в памяти объекта "проекция файла" movr qword ptr[rsp+28h],szMapName mov eax,FSize mov [rsp+20h],rax or rcx,INVALID_HANDLE_VALUE invoke CreateFileMapping,,0,PAGE_READWRITE,0 mov hMapping,rax ;отображение проекции файла на адресное пространство процесса xor r8d,r8d mov [rsp+20h],r8 invoke MapViewOfFile,eax,FILE_MAP_ALL_ACCESS,,0,FSize mov pMapping,rax ;------------------------------------------------- and qword ptr[rsp+20h],0 lea r9,szReadWrite invoke ReadFile,hFile,pMapping,FSize mov type0,WM_USER+3 @@:; Найти окно получателя mov edx,offset szWin invoke FindWindow,NULL or eax,eax jz wmBYE ; Отправить данные получателю mov qword ptr[rsp+20h],SMTO_ABORTIFHUNG mov qword ptr[rsp+28h],5000 and qword ptr[rsp+30h],0 invoke SendMessageTimeout,eax,type0,hWnddlg,FSize invoke UnmapViewOfFile,pMapping invoke CloseHandle,hMapping jmp wmBYE wmCOMMAND:cmp r8d,BN_CLICKED shl 16 + ID_SEND_TXT je wmSEND_TXT cmp r8d,BN_CLICKED shl 16 + ID_SEND_ICO je wmSEND_ICO cmp r8d,BN_CLICKED shl 16 + ID_SEND_WAV je wmSEND_WAV cmp r8d,BN_CLICKED shl 16 + IDCANCEL jne wmBYE wmCLOSE:invoke EndDialog,,0 wmBYE: mov eax,TRUE exit0: leave retn DialogProc endp ;--------------------------------------- .data szWin db 'Paging File Reciever',0 wav_file db '..\Images\03.wav',0 szMapName db "13-15=Mapping",0 p1 dd 1 end ресурсы Код (C): #include "resource.h" #define ID_TXT 100 #define ID_SEND_TXT 101 #define ID_SEND_ICO 102 #define ID_SEND_WAV 103 #define IDC_DIALOG 200 #define IDC_ICON1 500 #define IDC_IMG1 104 IDC_ICON1 ICON "..\\Images\\icon1.ico" IDC_ICON2 ICON "..\\Images\\icon2.ico" IDC_DIALOG DIALOG 0, 0, 212, 140 STYLE 0x0004 | DS_CENTER | WS_CAPTION | WS_MINIMIZEBOX | WS_SYSMENU | WS_VISIBLE | WS_OVERLAPPED | DS_MODALFRAME | DS_3DLOOK CAPTION "Paging File Sender" BEGIN CONTROL "",-1,"BUTTON",BS_GROUPBOX, 2, -1, 207, 24 CONTROL "",IDC_IMG1,"Static",WS_CHILDWINDOW|WS_VISIBLE|SS_ICON,5,23,128,128 CONTROL "Напишите что-нибудь и нажмите 'Отправить текст'",ID_TXT,"EDIT",WS_BORDER | WS_TABSTOP | ES_AUTOHSCROLL,5,7,199,13 DEFPUSHBUTTON "Отправить текст",ID_SEND_TXT,149,27,60,15 PUSHBUTTON "Отправить ICO",ID_SEND_ICO, 149,45,60,15 PUSHBUTTON "Отправить WAV",ID_SEND_WAV, 149,65,60,15 PUSHBUTTON "Выход", IDCANCEL, 149,85,60,15 END Текст приложения-клиента Код (ASM): ; GUI # include win64a.inc IDC_DIALOG equ 200 IMAGE_BASE equ 400000h ID_TXT equ 100 ID_ICON equ 102 IDC_ICON1 equ 500 .code WinMain proc dummy:qword mov r9d,offset DialogProc and qword ptr[rsp+20h],0 invoke DialogBoxParam,IMAGE_BASE,IDC_DIALOG,HWND_DESKTOP invoke RtlExitUserProcess,NULL WinMain endp DialogProc proc hWnddlg:qword,msg:qword,wParam:qword,lParam:qword local pMapping:qword local hMapping:qword local FSize:dword local lpwiocb:WAVEHDR local hWaveOut:qword local type0:dword mov hWnddlg,rcx mov lParam,r9 cmp edx,WM_CLOSE je wmCLOSE cmp edx,WM_USER+3 je wmUSER_3 cmp edx,WM_USER+1 je wmUSER_1 cmp edx,WM_USER+2 je wmUSER_2 cmp edx,WM_COMMAND je wmCOMMAND xor eax,eax jmp exit0 wmUSER_3:; Получить музыку от первого приложения mov type0,CF_WAVE jmp @f wmUSER_1:; Получить строку от первого приложения mov type0,CF_TEXT jmp @f wmUSER_2:; Получить картинку от первого приложения mov type0,CF_DIB @@: mov r8d,offset lpszName invoke OpenFileMapping,FILE_MAP_ALL_ACCESS,FALSE mov hMapping,rax mov ecx,eax mov rax,lParam mov [rsp+20h],rax invoke MapViewOfFile,,FILE_MAP_ALL_ACCESS,0,0 mov pMapping,rax cmp type0,CF_TEXT je TXT cmp type0,CF_DIB je DIB WAVE: mov r8,pMapping add r8d,14h lea ecx,hWaveOut xor r9,r9 mov [rsp+20h],r9 mov qword ptr[rsp+28h],WAVE_ALLOWSYNC or edx,WAVE_MAPPER invoke waveOutOpen ; Подготавливаем заголовок для вывода lea edx,lpwiocb mov edi,edx xor eax,eax mov ecx,(sizeof WAVEHDR)/8 rep stosq mov rax,pMapping mov ecx,eax add rax,2Ch mov [rdx].WAVEHDR.lpData,rax ;адрес блока данных mov eax,[rcx+4] sub eax,2Ch mov [rdx].WAVEHDR.dwBufferLength,eax ;размер блока данных invoke waveOutPrepareHeader,hWaveOut,,sizeof WAVEHDR ; Запускаем проигрывание блока lea edx,lpwiocb mov rcx,hWaveOut mov r8d,sizeof WAVEHDR invoke waveOutWrite @@: cmp lpwiocb.dwFlags,WHDR_DONE or WHDR_PREPARED jnz @b lea edx,lpwiocb invoke waveOutUnprepareHeader,hWaveOut,,sizeof WAVEHDR invoke waveOutClose,hWaveOut jmp @f TXT: invoke SetDlgItemText,hWnddlg,ID_TXT,pMapping jmp @f DIB: and qword ptr[rsp+30h],LR_DEFAULTCOLOR;LR_DEFAULTCOLOR=0 mov qword ptr[rsp+20h],256 mov qword ptr[rsp+28h],256 invoke CreateIconFromResourceEx,pMapping,lParam,TRUE,30000h mov [rsp+20h],rax invoke SendDlgItemMessage,hWnddlg,ID_ICON,STM_SETIMAGE,IMAGE_ICON @@: invoke UnmapViewOfFile,pMapping invoke CloseHandle,hMapping jmp wmBYE wmCOMMAND:cmp r8d,BN_CLICKED shl 16 + IDCANCEL jne wmBYE wmCLOSE:invoke EndDialog,,0 wmBYE: mov eax,TRUE exit0: leave ret DialogProc endp lpszName db "13-15=Mapping",0 end ресурсы Код (C): #include "resource.h" #define IDC_DIALOG 200 #define ID_TXT 100 #define ID_ICON 102 IDC_DIALOG DIALOG 0,0,212,140 STYLE 0x0004 | DS_CENTER | WS_CAPTION | WS_MINIMIZEBOX | WS_SYSMENU | WS_VISIBLE | WS_OVERLAPPED | DS_MODALFRAME | DS_3DLOOK CAPTION "Paging File Reciever" BEGIN CONTROL "",-1,"BUTTON",BS_GROUPBOX, 2, -1, 207, 24 CONTROL "",ID_TXT,"STATIC",WS_BORDER | WS_TABSTOP | ES_AUTOHSCROLL,5,7,199,13 DEFPUSHBUTTON "Выход",IDCANCEL,149,27,60,15 CONTROL "",ID_ICON,"STATIC",WS_CHILDWINDOW | SS_ICON,5,23,128,128 END
06a. Named PipeСредство передачи данных между параллельно работающими процессами. Позволяет организовать передачу данных между локальными процессами, а также между процессами, запущенными на различных рабочих станциях в сети. Pipe-каналы похожи на файлы. Pipe просты в использовании. Через Pipe-канал можно передавать данные только между двумя процессами. Один из процессов создает канал, другой открывает его. После этого оба процесса могут передавать данные через канал в одну или обе стороны, используя для этого функции, предназначенные для работы с файлами ReadFile и WriteFile. Приложения могут выполнять над Pipe-каналами синхронные или асинхронные операции. При использовании асинхронных операций необходимо обеспечить синхронизацию. Именованные и анонимные каналыСуществуют две разновидности pipe-каналов ― именованные (Named Pipes) и анонимные (Anonymous Pipes). Именованным каналам при создании присваивается имя, которое доступно для других процессов. Зная имя какой-либо рабочей станции в сети, процесс может получить доступ к каналу, созданному на этой рабочей станции. Анонимные каналы используются для организации передачи данных между родительскими и дочерними процессами, запущенными на одном компьютере.Имена каналовИмена каналов имеют следующий вид: Код (C): \\Имя_Сервера\pipe\Имя_Канала Если процесс открывает канал, созданный на другой рабочей станции нужно указать имя сервера. Если процесс создает канал или открывает канал на своей рабочей станции, вместо имени указывается символ точки: Код (C): \\.\pipe\Имя_Канала Процесс может создать канал только на той рабочей станции, где он запущен, поэтому при создании канала имя сервера никогда не указывается.Реализации каналовОдин серверный процесс создает один канал (одну реализацию канала) для работы с одним клиентским процессом. Если требуется организовать взаимодействие одного серверного процесса с несколькими клиентскими. Например, сервер базы данных должен принимать от клиентов запросы и рассылать ответы на них. Тогда серверный процесс создает несколько реализаций канала, по одной реализации для каждого клиентского процесса.Функции для работы с каналамиНаиболее важные функции предназначенные для работы с Pipe-каналами. Более подробная информация в документации MSDN.Создание каналаДля создания именованных и анонимных pipe-каналов используются функции CreatePipe и CreateNamedPipe.Функция CreatePipeАнонимный канал создается функцией CreatePipe Код (C): BOOL CreatePipe( PHANDLE hReadPipe,// адрес переменной, в которую будет записан дескриптор канала для чтения данных PHANDLE hWritePipe,// адрес переменной, в которую будет записан дескриптор канала для записи данных LPSECURITY_ATTRIBUTES lpPipeAttributes, // адрес переменной для атрибутов защиты DWORD nSize);// количество байт памяти, зарезервированной для канала Канал может использоваться как для записи в него данных, так и для чтения. Поэтому при создании канала функция CreatePipe возвращает два дескриптора, записывая их по адресу, заданному в параметрах hReadPipe и hWritePipe. дескриптор, записанный по адресу hReadPipe, передается как параметр функции ReadFile или ReadFileEx для выполнения операции чтения. дескриптор, записанный по адресу hWritePipe, передается функции WriteFile или WriteFileEx для выполнения операции записи. Через параметр lpPipeAttributes передается адрес переменной, содержащей атрибуты защиты для создаваемого канала. Чаще этот параметр указывают как NULL. В результате канал будет иметь атрибуты защиты, принятые по умолчанию. Параметр nSize определяет размер буфера для создаваемого канала. Если этот размер указан как нуль, создается буфер с размером, принятым по умолчанию. При необходимости система может изменить указанный размер буфера. В случае успеха функция CreatePipe возвращает значение TRUE, при ошибке ― FALSE. Для уточнения причины возникновения ошибки используют функцию GetLastError.Функция CreateNamedPipeДля создания именованного канала Pipe используют функцию CreateNamedPipe. Прототип этой функции: Код (C): HANDLE CreateNamedPipe( LPCTSTR lpName, // адрес строки имени канала DWORD dwOpenMode, // режим открытия канала DWORD dwPipeMode, // режим работы канала DWORD nMaxInstances, // максимальное количество реализаций канала DWORD nOutBufferSize, // размер выходного буфера в байтах DWORD nInBufferSize, // размер входного буфера в байтах DWORD nDefaultTimeOut, // время ожидания в миллисекундах LPSECURITY_ATTRIBUTES lpSecurityAttributes); // адрес переменной для атрибутов защиты Через параметр lpName передается адрес строки имени канала в форме \\.\pipe\Имя_Канала (при создании канала имя сервера не указывается, так как канал можно создать только на той рабочей станции, где запущен процесс, создающий канал). Параметр dwOpenMode задает режим, в котором открывается канал. Pipe-канал может быть ориентирован либо на передачу потока байт, либо на передачу сообщений. В первом случае данные через канал передаются по байтам, во втором ― отдельными блоками заданной длины. Режим работы канала (ориентированный на передачу байт или сообщений) задается константами PIPE_TYPE_BYTE или PIPE_TYPE_MESSAGE, которые указываются в параметре dwOpenMode. По умолчанию используют режим PIPE_TYPE_BYTE. Помимо способа передачи данных через канал, с помощью параметра dwOpenMode можно указать, будет ли данный канал использован только для чтения данных, только для записи или одновременно для чтения и записи. Способ использования канала задается указанием одной из следующих констант: КонстантаhexbinИспользование каналаPIPE_ACCESS_INBOUND100000001Только для чтенияPIPE_ACCESS_OUTBOUND200000010Только для записиPIPE_ACCESS_DUPLEX300000011Для чтения и записиПеречисленные параметры должны быть одинаковы для всех реализаций канала. Параметры, которые могут отличаться для разных реализаций канала: Константаhex Использование каналаPIPE_READMODE_BYTE0Канал открывается на чтение в режиме последовательной передачи отдельных байтPIPE_READMODE_MESSAGE2Канал открывается на чтение в режиме передачи отдельных сообщений указанной длиныPIPE_WAIT0Канал будет работать в блокирующем режиме, когда процесс переводится в состояние ожидания до завершения операций в каналеPIPE_NOWAIT1Неблокирующий режим работы канала. Если операция не может быть выполнена немедленно, в неблокирующем режиме функция завершается с ошибкойFILE_FLAG_OVERLAPPED40000000 Использование асинхронных операций (ввод и вывод с перекрытием). Данный режим позволяет процессу выполнять полезную работу параллельно с проведением операций в каналеFILE_FLAG_WRITE_THROUGH80000000В этом режиме функции, работающие с каналом, не возвращают управление до тех пор, пока не будет полностью завершена операция на удаленном компьютере. Используется только с каналом, ориентированном на передачу отдельных байт и только в том случае, когда канал создан между процессами, запущенными на различных станциях сетиДополнительно через параметр dwOpenMode можно передавать флаги защиты: ФлагhexОписаниеWRITE_DAC40000 Вызывающий процесс должен иметь права доступа на запись к произвольному управляющему списку доступа именованного канала access control list (ACL)WRITE_OWNER80000 Вызывающий процесс должен иметь права доступа на запись к процессу, владеющему именованным каналом PipeACCESS_SYSTEM_SECURITY1000000 Вызывающий процесс должен иметь права доступа на запись к управляющему списку доступа именованного канала access control list (ACL)Параметр dwPipeMode определяет режим работы канала. В этом параметре можно указать константы PIPE_TYPE_BYTE, PIPE_TYPE_MESSAGE, PIPE_READMODE_BYTE, PIPE_READMODE_MESSAGE, PIPE_WAIT и PIPE_NOWAIT. Для всех реализаций канала необходимо указывать один и тот же набор констант. Параметр nMaxInstances определяет максимальное количество реализаций, которые могут быть созданы для канала. Можно указывать значения от 1 до PIPE_UNLIMITED_INSTANCES. В случае максимальное количество реализаций ограничивается только наличием свободных системных ресурсов. Если один серверный процесс использует несколько реализаций канала для связи с несколькими клиентскими процессами, общее количество реализаций может быть меньше, чем потенциальное максимальное количество клиентов. Это связано с тем, что клиенты могут использовать реализации по очереди, если только они не пожелают связаться с серверным процессом все одновременно. Параметры nOutBufferSize и nInBufferSize определяют размер буферов, используемых для записи в канал и чтения из канала. При необходимости система может использовать буферы других, по сравнению с указанными, размеров. Параметр nDefaultTimeOut определяет время ожидания для реализации канала. Для всех реализаций необходимо указывать одинаковое значение этого параметра. Через параметр lpPipeAttributes передается адрес переменной, содержащей атрибуты защиты для создаваемого канала. Обычно этот параметр равен NULL. В результате канал будет иметь атрибуты защиты, принятые по умолчанию. В случае успеха функция CreateNamedPipe возвращает дескриптор созданной реализации канала, который можно использовать в операциях чтения и записи, выполняемых с помощью функций ReadFile и WriteFile. При ошибке CreateNamedPipe возвращает значение INVALID_HANDLE_VALUE. Код ошибки можете уточнить, вызвав функцию GetLastError.Использование функции CreateFileФункция CreateFile, предназначена для работы с файлами, может использоваться для создания новых каналов и открытия существующих. Вместо имени файла указывают имя pipe-канала. Текст приложения-сервера Код (ASM): ; GUI # include win64a.inc WM_CLIPBOARDUPDATE equ 31Dh ID_TXT equ 100 ID_SEND_TXT equ 101 ID_SEND_ICO equ 102 ID_SEND_WAV equ 103 IDC_DIALOG equ 200 IDC_ICON1 equ 500 IDC_IMG1 equ 104 .code WinMain proc dummy:qword mov r9d,256 mov [rsp+20h],r9 mov qword ptr [rsp+28],LR_DEFAULTCOLOR invoke LoadImage,IMAGE_BASE,IDC_ICON1,IMAGE_ICON;,256,256,LR_DEFAULTCOLOR mov r9d,offset DialogProc mov qword ptr[rsp+20h],rax invoke DialogBoxParam,IMAGE_BASE,IDC_DIALOG,HWND_DESKTOP invoke RtlExitUserProcess,NULL WinMain endp DialogProc proc hWnddlg:QWORD,uMsg:QWORD,wParam:QWORD,lParam:QWORD size_of_buffer equ 256 local cbWritten:dword;Количество байт, переданных через канал local FSize:dword; local hNamePipe:qword; дескриптор канала Mailslot local hFile:dword local p:qword local hResource:qword local type0:qword mov hWnddlg,rcx mov lParam,r9 cmp edx,WM_CLOSE je wmCLOSE cmp edx,WM_COMMAND je wmCOMMAND cmp edx,WM_INITDIALOG je wmINITDIALOG xor eax,eax jmp exit0 wmINITDIALOG:; invoke GetDlgItem,,IDC_IMG1 invoke SendMessage,eax,STM_SETIMAGE,IMAGE_ICON,lParam jmp wmBYE wmSEND_TXT:invoke GlobalAlloc,GPTR,size_of_buffer mov p,rax;Буфер для передачи данных через канал invoke GetDlgItemText,hWnddlg,ID_TXT,eax,size_of_buffer;255 or eax,eax jz wmBYE inc eax mov FSize,eax mov type0,WM_USER+1 jmp @f wmSEND_ICO:mov edx,p1 invoke FindResource,0,,RT_ICON; find the resource mov hResource,rax invoke SizeofResource,0,eax ; get its size mov FSize,eax invoke LoadResource,0,hResource ; load the resource invoke LockResource,eax;pResource mov p,rax ;------------------------------------------------- mov ecx,256 and qword ptr[rsp+30h],LR_DEFAULTCOLOR mov [rsp+20h],rcx mov [rsp+28h],rcx mov edx,FSize invoke CreateIconFromResourceEx,p,,TRUE,30000h mov [rsp+20h],rax invoke SendDlgItemMessage,hWnddlg,IDC_IMG1,STM_SETIMAGE,IMAGE_ICON xor p1,11b mov type0,WM_USER+2 jmp @f wmSEND_WAV:mov ecx,offset wav_file xor r9d,r9d mov qword ptr[rsp+30h],r9 mov qword ptr[rsp+28h],FILE_ATTRIBUTE_ARCHIVE mov qword ptr[rsp+20h],OPEN_EXISTING invoke CreateFile,,GENERIC_READ or GENERIC_WRITE,\ FILE_SHARE_READ or FILE_SHARE_WRITE mov hFile,eax invoke GetFileSize,eax,0 mov FSize,eax invoke GlobalAlloc,GPTR,eax mov p,rax lea r9d,cbWritten and qword ptr[rsp+20h],0 invoke ReadFile,hFile,eax,FSize invoke CloseHandle,hFile mov type0,WM_USER+3 @@:; Найти окно получателя mov edx,offset szWin invoke FindWindow,NULL or eax,eax jz wmBYE ; Отправить данные получателю mov qword ptr[rsp+20h],SMTO_ABORTIFHUNG mov qword ptr[rsp+28h],250 and qword ptr[rsp+30h],0 invoke SendMessageTimeout,eax,type0,hWnddlg,FSize ; Создаем пайп mov ecx,offset szPipeName xor r9d,r9d mov qword ptr[rsp+20h],OPEN_EXISTING mov [rsp+28h],r9 mov [rsp+30h],r9 invoke CreateFile,,GENERIC_WRITE,FILE_SHARE_READ mov hNamePipe,rax mov rdx,p lea r9d,cbWritten and qword ptr[rsp+20h],0 invoke WriteFile,eax,,FSize ;Закрываем дескриптор канала invoke CloseHandle,hNamePipe jmp wmBYE wmCOMMAND:cmp r8d,BN_CLICKED shl 16 + ID_SEND_TXT je wmSEND_TXT cmp r8d,BN_CLICKED shl 16 + ID_SEND_ICO je wmSEND_ICO cmp r8d,BN_CLICKED shl 16 + ID_SEND_WAV je wmSEND_WAV cmp r8d,BN_CLICKED shl 16 + IDCANCEL jne wmBYE wmCLOSE:invoke EndDialog,,0 wmBYE: mov eax,TRUE exit0: leave retn DialogProc endp ;--------------------------------------- szWin db 'Pipe Reciever',0 szPipeName db "\\.\pipe\MyPipe",0; Имя создаваемого пайпа p1 dd 1 wav_file db '..\Images\03.wav',0 end ресурсы Код (C): #include "resource.h" #define ID_TXT 100 #define ID_SEND_TXT 101 #define ID_SEND_ICO 102 #define ID_SEND_WAV 103 #define IDC_DIALOG 200 #define IDC_ICON1 500 #define IDC_IMG1 104 IDC_ICON1 ICON "..\\Images\\icon1.ico" IDC_ICON2 ICON "..\\Images\\icon2.ico" IDC_DIALOG DIALOG 0, 0, 212, 140 STYLE 0x0004 | DS_CENTER | WS_CAPTION | WS_MINIMIZEBOX | WS_SYSMENU | WS_VISIBLE | WS_OVERLAPPED | DS_MODALFRAME | DS_3DLOOK CAPTION "Pipe Sender" BEGIN CONTROL "",-1,"BUTTON",BS_GROUPBOX, 2, -1, 207, 24 CONTROL "",IDC_IMG1,"Static",WS_CHILDWINDOW|WS_VISIBLE|SS_ICON,5,23,128,128 CONTROL "Напишите что-нибудь и нажмите 'Отправить текст'",ID_TXT,"EDIT",WS_BORDER | WS_TABSTOP | ES_AUTOHSCROLL,5,7,199,13 DEFPUSHBUTTON "Отправить текст",ID_SEND_TXT,149,27,60,15 PUSHBUTTON "Отправить ICO",ID_SEND_ICO, 149,45,60,15 PUSHBUTTON "Отправить WAV",ID_SEND_WAV, 149,65,60,15 PUSHBUTTON "Выход", IDCANCEL, 149,85,60,15 END Текст приложения-клиента Код (ASM): ; GUI # include win64a.inc WM_CLIPBOARDUPDATE equ 31Dh IDC_DIALOG equ 200 ID_TXT equ 100 ID_ICON equ 102 IDC_ICON1 equ 500 .code WinMain proc dummy:qword mov r9d,offset DialogProc and qword ptr[rsp+20h],0 invoke DialogBoxParam,IMAGE_BASE,IDC_DIALOG,HWND_DESKTOP invoke RtlExitUserProcess,NULL WinMain endp DialogProc proc hWnddlg:qword,msg:qword,wParam:qword,lParam:qword local cbRead:DWORD;Количество байт данных, принятых через канал local buffer:qword;Буфер для передачи данных через канал local lpwiocb:WAVEHDR local hWaveOut:qword mov hWnddlg,rcx mov lParam,r9 cmp edx,WM_CLOSE je wmCLOSE cmp edx,WM_USER+1 je wmUSER_1 cmp edx,WM_USER+2 je wmUSER_2 cmp edx,WM_USER+3 je wmUSER_3 cmp edx,WM_COMMAND je wmCOMMAND xor eax,eax jmp exit0 wmUSER_1:; Получить строку от первого приложения mov type0,CF_TEXT jmp @f wmUSER_2:mov type0,CF_DIB jmp @f wmUSER_3:mov type0,CF_WAVE @@: invoke GlobalAlloc,GMEM_FIXED,lParam mov buffer,rax mov ecx,offset lpszPipeName invoke CreateNamedPipe,,PIPE_ACCESS_INBOUND,PIPE_TYPE_BYTE,1,0,lParam,0,0 mov hNamedPipe,rax invoke ConnectNamedPipe,eax,NULL lea r9d,cbRead and qword ptr[rsp+20h],0 invoke ReadFile,hNamedPipe,buffer,lParam ;---------------------------------------------------- cmp type0,CF_TEXT je TEXT cmp type0,CF_DIB je DIB WAVE: mov r8,buffer add r8d,14h lea ecx,hWaveOut xor r9,r9 mov [rsp+20h],r9 mov qword ptr[rsp+28h],WAVE_ALLOWSYNC or edx,WAVE_MAPPER invoke waveOutOpen ; Подготавливаем заголовок для вывода lea edx,lpwiocb mov edi,edx xor eax,eax mov ecx,(sizeof WAVEHDR)/8 rep stosq mov rax,buffer mov ecx,eax add rax,2Ch mov [rdx].WAVEHDR.lpData,rax ;адрес блока данных mov eax,[rcx+4] sub eax,2Ch mov [rdx].WAVEHDR.dwBufferLength,eax ;размер блока данных invoke waveOutPrepareHeader,hWaveOut,,sizeof WAVEHDR ; Запускаем проигрывание блока lea edx,lpwiocb mov rcx,hWaveOut mov r8d,sizeof WAVEHDR invoke waveOutWrite @@: test lpwiocb.dwFlags,WHDR_DONE jz @b lea edx,lpwiocb invoke waveOutUnprepareHeader,hWaveOut,,sizeof WAVEHDR invoke waveOutClose,hWaveOut jmp @0 ;------------------------------------------------------------ TEXT: invoke SetDlgItemText,hWnddlg,ID_TXT,buffer jmp @0 ;---------------------------------------------------- DIB: and qword ptr[rsp+30h],LR_DEFAULTCOLOR;LR_DEFAULTCOLOR=0 mov qword ptr[rsp+20h],256 mov qword ptr[rsp+28h],256 invoke CreateIconFromResourceEx,buffer,lParam,TRUE,30000h mov [rsp+20h],rax invoke SendDlgItemMessage,hWnddlg,ID_ICON,STM_SETIMAGE,IMAGE_ICON ;----------------------------------------------------------- @0: invoke GlobalFree,buffer invoke DisconnectNamedPipe,hNamedPipe invoke CloseHandle,hNamedPipe jmp wmBYE wmCOMMAND:cmp r8d,BN_CLICKED shl 16 + IDCANCEL jne wmBYE wmCLOSE:;Перед завершением приложения закрываем дескриптор канала Mailslot invoke EndDialog,hWnddlg,0 wmBYE: mov eax,TRUE exit0: leave ret DialogProc endp type0 db ? lpszPipeName db "\\.\pipe\MyPipe",0;Имя создаваемого пайпа hNamedPipe dq ?;дескриптор пайпа end ресурсы Код (C): #include "resource.h" #define IDC_DIALOG 200 #define ID_TXT 100 #define ID_ICON 102 IDC_DIALOG DIALOG 0,0,212,140 STYLE 0x0004 | DS_CENTER | WS_CAPTION | WS_MINIMIZEBOX | WS_SYSMENU | WS_VISIBLE | WS_OVERLAPPED | DS_MODALFRAME | DS_3DLOOK CAPTION "Pipe Reciever" BEGIN CONTROL "",-1,"BUTTON",BS_GROUPBOX, 2, -1, 207, 24 CONTROL "",ID_TXT,"STATIC",WS_BORDER | WS_TABSTOP | ES_AUTOHSCROLL,5,7,199,13 DEFPUSHBUTTON "Выход",IDCANCEL,149,27,60,15 CONTROL "",ID_ICON,"STATIC",WS_CHILDWINDOW | SS_ICON,5,23,128,128 END
03. Memory Mapped FileОбмен данными между процессами через файлы, отображенных на память. Обладает высоким быстродействием, так как данные передаются между процессами непосредственно через виртуальную память. Отображение создается функцией CreateFileMapping. Фрагмент кода в котором создается отображение файла, а затем выполняется отображение этого файла в память: Код (C): hFileMapping = CreateFileMapping(hSrcFile, NULL,PAGE_READWRITE,0,dwFileSize,NULL); if(hFileMapping == NULL) return; lpFileMap = MapViewOfFile(hFileMapping, FILE_MAP_WRITE, 0, 0, 0); if(lpFileMap == 0) return; В качестве первого параметра для функции CreateFileMapping передают дескриптор файла, открытого функцией CreateFile. Последний параметр указан как NULL, поэтому отображение не имеет имени. Если отображение используется для передачи данных между процессами, указывают имя. Пользуясь этим именем, другие процессы смогут открыть отображение функцией OpenFileMapping. дескриптора файла, передаваемого функции CreateFileMapping через первый параметр. Если создается отображение только для того чтобы обеспечить передачу данных между процессами, не нужно создавать файл на диске компьютера. В качестве дескриптора файла указывается значение 0FFFFFFFFh (-1), создается отображение непосредственно в виртуальной памяти без использования дополнительного файла. Код (C): CHAR lpFileShareName[] = "$MyVerySpecialFileShareName$"; hFileMapping=CreateFileMapping((HANDLE)0xFFFFFFFF,NULL,PAGE_READWRITE,0, 100,lpFileShareName); После того как создан объект-отображение, выполняется отображение файла в память при помощи функции MapViewOfFile. В случае успеха эта функция вернет указатель на отображенную область памяти. Первый процесс создал отображение. Второй процесс, который выполняет обмен данными с первым процессом, открывает это отображение по имени при помощи функции OpenFileMapping: Код (C): hFileMapping = OpenFileMapping (FILE_MAP_READ | FILE_MAP_WRITE, FALSE, lpFileShareName); Далее второе приложение выполняет отображение, вызывая функцию MapViewOfFile: Код (C): lpFileMap = MapViewOfFile(hFileMapping,FILE_MAP_READ| FILE_MAP_WRITE,0,0,0); Используя значением, полученное от функции MapViewOfFile, второе приложение получает указатель на отображенную область памяти. Эта область находится в тех же страницах виртуальной памяти, что и область, созданная первым процессом. Два процесса получили указатели на общие страницы памяти. Перед завершением работы процессы должны отменить отображение файла и освободить дескриптор созданного объекта-отображения: Код (C): UnmapViewOfFile(lpFileMap); CloseHandle(hFileMapping); Текст приложения-сервера Код (ASM): ; GUI # include win64a.inc ID_TXT equ 100 ID_SEND_TXT equ 101 ID_SEND_ICO equ 102 ID_SEND_WAV equ 103 IDC_DIALOG equ 200 IDC_ICON1 equ 500 IDC_IMG1 equ 104 .code WinMain proc dummy:qword mov r9d,256 mov [rsp+20h],r9 mov qword ptr [rsp+28],LR_DEFAULTCOLOR invoke LoadImage,IMAGE_BASE,IDC_ICON1,IMAGE_ICON;,256,256,LR_DEFAULTCOLOR mov r9d,offset DialogProc mov qword ptr[rsp+20h],rax invoke DialogBoxParam,IMAGE_BASE,IDC_DIALOG,HWND_DESKTOP invoke RtlExitUserProcess,NULL WinMain endp DialogProc proc hWnddlg:QWORD,uMsg:QWORD,wParam:QWORD,lParam:QWORD size_of_buffer equ 96 local buffer[size_of_buffer]:BYTE local FSize:dword local hResource:qword local pResource:qword local szReadWrite:qword local type0:qword mov hWnddlg,rcx mov lParam,r9 cmp edx,WM_CLOSE je wmCLOSE cmp edx,WM_COMMAND je wmCOMMAND cmp edx,WM_INITDIALOG je wmINITDIALOG xor eax,eax jmp exit0 wmINITDIALOG:; invoke GetDlgItem,,IDC_IMG1 invoke SendMessage,eax,STM_SETIMAGE,IMAGE_ICON,lParam jmp wmBYE wmSEND_TXT:mov type0,WM_USER+1 lea r8d,buffer invoke GetDlgItemText,,ID_TXT,,size_of_buffer;255 or eax,eax jz wmBYE inc eax mov FSize,eax ;созддание файла sub esp,40h xor r8,r8 mov qword ptr[rsp+20h],OPEN_ALWAYS mov [rsp+28h],r8 mov [rsp+30h],r8 mov ecx,offset szMapName0 invoke CreateFile,,GENERIC_READ or GENERIC_WRITE,,0 mov hFile,rax lea edx,buffer lea r9d,szReadWrite and qword ptr[rsp+20h],0 invoke WriteFile,eax,,FSize invoke Func,hFile,0 jmp @0 wmSEND_ICO:sub esp,30h mov type0,WM_USER+2 mov edx,p1 invoke FindResource,0,,RT_ICON; find the resource mov hResource,rax invoke SizeofResource,0,eax ; get its size mov FSize,eax invoke LoadResource,0,hResource ; load the resource invoke LockResource,eax mov esi,eax ;созддание в памяти объекта "проекция файла" и ;отображение проекции файла на адресное пространство процесса invoke Func,INVALID_HANDLE_VALUE,FSize ;----------------------------------------------------------------- mov ecx,FSize mov edi,eax;rdi,pMapping rep movsb ;-------------------------------------------------- and qword ptr[rsp+30h],LR_DEFAULTCOLOR;LR_DEFAULTCOLOR=0 mov qword ptr[rsp+20h],256 mov qword ptr[rsp+28h],256 mov edx,FSize invoke CreateIconFromResourceEx,pMapping,,TRUE,30000h;270376,TRUE,30000h mov [rsp+20h],rax invoke SendDlgItemMessage,hWnddlg,IDC_IMG1,STM_SETIMAGE,IMAGE_ICON xor p1,11b jmp @0 ;------------------------------------------------------- wmSEND_WAV:sub esp,40h mov type0,WM_USER+3 mov ecx,offset wav_file xor r9d,r9d mov qword ptr[rsp+30h],r9 mov qword ptr[rsp+28h],FILE_ATTRIBUTE_ARCHIVE mov qword ptr[rsp+20h],OPEN_EXISTING invoke CreateFile,,GENERIC_READ or GENERIC_WRITE,\ FILE_SHARE_READ or FILE_SHARE_WRITE mov hFile,rax invoke Func,rax,0 @0:; Найти окно получателя mov edx,offset szWin invoke FindWindow,NULL or eax,eax jz wmBYE ; Отправить данные получателю mov qword ptr[rsp+20h],SMTO_ABORTIFHUNG mov qword ptr[rsp+28h],5000 and qword ptr[rsp+30h],0 invoke SendMessageTimeout,eax,type0,hWnddlg,0 invoke UnmapViewOfFile,pMapping invoke CloseHandle,hMapping invoke CloseHandle,hFile cmp type0,WM_USER+1 jnz wmBYE mov ecx,offset szMapName0 invoke DeleteFile jmp wmBYE wmCOMMAND:cmp r8d,BN_CLICKED shl 16 + ID_SEND_TXT je wmSEND_TXT cmp r8d,BN_CLICKED shl 16 + ID_SEND_ICO je wmSEND_ICO cmp r8d,BN_CLICKED shl 16 + ID_SEND_WAV je wmSEND_WAV cmp r8d,BN_CLICKED shl 16 + IDCANCEL jne wmBYE wmCLOSE:invoke EndDialog,,0 wmBYE: mov eax,TRUE exit0: leave retn DialogProc endp ;---------------------------------------- Func proc hFile:qword,FSize:qword mov FSize,rdx ;созддание в памяти объекта "проекция файла" movr qword ptr[rsp+28h],szMapName mov [rsp+20h],rdx invoke CreateFileMapping,,0,PAGE_READWRITE,0 mov hMapping,rax ;отображение проекции файла на адресное пространство процесса mov rax,FSize mov [rsp+20h],rax invoke MapViewOfFile,hMapping,FILE_MAP_ALL_ACCESS,0,0 mov pMapping,rax leave ret Func endp ;--------------------------------------- szWin db 'Memory-Mapped File Reciever',0 wav_file db '..\Images\03.wav',0 szMapName db "13-15=Mapping",0 szMapName0 db "15.txt",0 p1 dd 1 hMapping dq ? pMapping dq ? hFile dq ? end ресурсы Код (C): #include "resource.h" #define ID_TXT 100 #define ID_SEND_TXT 101 #define ID_SEND_ICO 102 #define ID_SEND_WAV 103 #define IDC_DIALOG 200 #define IDC_ICON1 500 #define IDC_IMG1 104 IDC_ICON1 ICON "..\\Images\\icon1.ico" IDC_ICON2 ICON "..\\Images\\icon2.ico" IDC_DIALOG DIALOG 0, 0, 212, 140 STYLE 0x0004 | DS_CENTER | WS_CAPTION | WS_MINIMIZEBOX | WS_SYSMENU | WS_VISIBLE | WS_OVERLAPPED | DS_MODALFRAME | DS_3DLOOK CAPTION "Memory-Mapped File Sender" BEGIN CONTROL "",-1,"BUTTON",BS_GROUPBOX, 2, -1, 207, 24 CONTROL "",IDC_IMG1,"Static",WS_CHILDWINDOW|WS_VISIBLE|SS_ICON,5,23,128,128 CONTROL "Напишите что-нибудь и нажмите 'Отправить текст'",ID_TXT,"EDIT",WS_BORDER | WS_TABSTOP | ES_AUTOHSCROLL,5,7,199,13 DEFPUSHBUTTON "Отправить текст",ID_SEND_TXT,149,27,60,15 PUSHBUTTON "Отправить ICO",ID_SEND_ICO, 149,45,60,15 PUSHBUTTON "Отправить WAV",ID_SEND_WAV, 149,65,60,15 PUSHBUTTON "Выход", IDCANCEL, 149,85,60,15 END Текст приложения-клиента Код (ASM): ; GUI # include win64a.inc WM_CLIPBOARDUPDATE equ 31Dh IDC_DIALOG equ 200 IMAGE_BASE equ 400000h ID_TXT equ 100 ID_ICON equ 102 IDC_ICON1 equ 500 .code WinMain proc dummy:qword mov r9d,offset DialogProc and qword ptr[rsp+20h],0 invoke DialogBoxParam,IMAGE_BASE,IDC_DIALOG,HWND_DESKTOP invoke RtlExitUserProcess,NULL WinMain endp DialogProc proc hWnddlg:qword,msg:qword,wParam:qword,lParam:qword local pMapping:qword local hMapping:qword local FSize:dword local lpwiocb:WAVEHDR local hWaveOut:qword mov hWnddlg,rcx mov lParam,r9 cmp edx,WM_CLOSE je wmCLOSE cmp edx,WM_USER+3 je wmUSER_3 cmp edx,WM_USER+1 je wmUSER_1 cmp edx,WM_USER+2 je wmUSER_2 cmp edx,WM_COMMAND je wmCOMMAND xor eax,eax jmp exit0 wmUSER_2:; Получить иконку от первого приложения mov type0,CF_DIB jmp @f wmUSER_1:; Получить строку от первого приложения mov type0,CF_TEXT jmp @f wmUSER_3:; Получить музыку от первого приложения mov type0,CF_WAVE jmp @f @@: mov r8d,offset lpszName invoke OpenFileMapping,FILE_MAP_READ,FALSE mov hMapping,rax xor r8,r8 mov [rsp+20h],r8 invoke MapViewOfFile,eax,FILE_MAP_READ,,0 mov pMapping,rax ;------------------------------------------- cmp type0,CF_DIB je DIB cmp type0,CF_TEXT je TEXT WAVE: mov r8,pMapping add r8d,14h lea ecx,hWaveOut xor r9,r9 mov [rsp+20h],r9 mov qword ptr[rsp+28h],WAVE_ALLOWSYNC or edx,WAVE_MAPPER invoke waveOutOpen ; Подготавливаем заголовок для вывода lea edx,lpwiocb mov edi,edx xor eax,eax mov ecx,(sizeof WAVEHDR)/8 rep stosq mov rax,pMapping mov ecx,eax add rax,2Ch mov [rdx].WAVEHDR.lpData,rax ;адрес блока данных mov eax,[rcx+4] sub eax,2Ch mov [rdx].WAVEHDR.dwBufferLength,eax ;размер блока данных invoke waveOutPrepareHeader,hWaveOut,,sizeof WAVEHDR ; Запускаем проигрывание блока lea edx,lpwiocb mov rcx,hWaveOut mov r8d,sizeof WAVEHDR invoke waveOutWrite @@: cmp lpwiocb.dwFlags,WHDR_DONE or WHDR_PREPARED jnz @b lea edx,lpwiocb invoke waveOutUnprepareHeader,hWaveOut,,sizeof WAVEHDR invoke waveOutClose,hWaveOut jmp @f;wmBYE ;-------------------------------------------------- TEXT: invoke SetDlgItemText,hWnddlg,ID_TXT,pMapping jmp @f;wmBYE ;------------------------------------------------------ DIB: and qword ptr[rsp+30h],LR_DEFAULTCOLOR;LR_DEFAULTCOLOR=0 mov qword ptr[rsp+20h],256 mov qword ptr[rsp+28h],256 invoke CreateIconFromResourceEx,pMapping,lParam,TRUE,30000h mov [rsp+20h],rax invoke SendDlgItemMessage,hWnddlg,ID_ICON,STM_SETIMAGE,IMAGE_ICON @@: invoke UnmapViewOfFile,pMapping invoke CloseHandle,hMapping jmp wmBYE wmCOMMAND:cmp r8d,BN_CLICKED shl 16 + IDCANCEL jne wmBYE wmCLOSE:invoke EndDialog,,0 wmBYE: mov eax,TRUE exit0: leave ret DialogProc endp align 10h lpszName db "13-15=Mapping",0 type0 db ? end ресурсы Код (C): #include "resource.h" #define IDC_DIALOG 200 #define ID_TXT 100 #define ID_ICON 102 IDC_DIALOG DIALOG 0,0,212,140 STYLE 0x0004 | DS_CENTER | WS_CAPTION | WS_MINIMIZEBOX | WS_SYSMENU | WS_VISIBLE | WS_OVERLAPPED | DS_MODALFRAME | DS_3DLOOK CAPTION "Memory-Mapped File Reciever" BEGIN CONTROL "",-1,"BUTTON",BS_GROUPBOX, 2, -1, 207, 24 CONTROL "",ID_TXT,"STATIC",WS_BORDER | WS_TABSTOP | ES_AUTOHSCROLL,5,7,199,13 DEFPUSHBUTTON "Выход",IDCANCEL,149,27,60,15 CONTROL "",ID_ICON,"STATIC",WS_CHILDWINDOW | SS_ICON,5,23,128,128 END
07. Dynamic Data ExchangeМеханизм динамического обмена данными DDE (Dynamic Data Exchange), позволяет создать постоянно действующие каналы между несколькими одновременно работающими приложениями Windows. Каналы могут создаваться автоматически при запуске приложения или при необходимости и по явному запросу пользователя. После создания каналов, они будут работать без вмешательства пользователя. В Windows механизм DDE реализован через передачу сообщений с помощью функции SendMessage с использованием глобальных блоков памяти, доступных всем приложениям. При создании DDE-приложений программист вынужден вникать во все детали процесса создания канала связи, придерживаясь определенного в SDK протокола. Начиная с Windows 3.1 появилось расширение ― управляющая библиотека динамического обмена данными DDEML, выполненная как DLL. Библиотека DDEML упрощает DDE-приложения и избавляет программиста от учета деталей протокола обмена сообщениями. В Windows динамический обмен данных организуется с помощью библиотеки DDEML. Сетевые возможности Windows базируются на сетевом динамическом обмене данными Network DDE. Текст приложения-сервера Код (ASM): ; GUI # include win64a.inc ID_TXT equ 100 ID_SEND_TXT equ 101 ID_SEND_ICO equ 102 ID_SEND_WAV equ 103 IDC_DIALOG equ 200 IDC_ICON1 equ 500 IDC_IMG1 equ 104 WM_USER_INITIATE equ WM_USER + 1 extern __imp_DdeGetData:qword .code WinMain proc dummy:qword mov r9d,256 mov [rsp+20h],r9 mov qword ptr [rsp+28],LR_DEFAULTCOLOR invoke LoadImage,IMAGE_BASE,IDC_ICON1,IMAGE_ICON;,256,256,LR_DEFAULTCOLOR mov r9d,offset DialogProc mov qword ptr[rsp+20h],rax invoke DialogBoxParam,IMAGE_BASE,IDC_DIALOG,HWND_DESKTOP invoke RtlExitUserProcess,NULL WinMain endp DialogProc proc hWnddlg:QWORD,uMsg:QWORD,wParam:QWORD,lParam:QWORD local hFile:dword local cbWritten:dword local hResource:qword local pResource:qword mov hWnddlg,rcx mov lParam,r9 cmp edx,WM_CLOSE je wmCLOSE cmp edx,WM_COMMAND je wmCOMMAND cmp edx,WM_INITDIALOG je wmINITDIALOG cmp edx,WM_USER_INITIATE je wmUSER_INITIATE xor eax,eax jmp exit0 wmUSER_INITIATE: mov edx,offset szService invoke DdeCreateStringHandle,idInst,,CP_WINANSI mov hszService,rax mov edx,offset szTopic invoke DdeCreateStringHandle,idInst,,CP_WINANSI mov hszTopic,rax mov edx,offset szItem invoke DdeCreateStringHandle,idInst,,CP_WINANSI mov hszItem,rax ; Регистрируем сервис invoke DdeNameService,idInst,hszService,NULL,DNS_REGISTER jmp wmBYE wmINITDIALOG: ; mov hwnd,rcx invoke GetDlgItem,,IDC_IMG1 invoke SendMessage,eax,STM_SETIMAGE,IMAGE_ICON,lParam ; Выполняем инициализацию mov ecx,offset idInst mov edx,offset DDEServerCallback invoke DdeInitialize,,,APPCLASS_STANDARD,0 or eax,eax jz @f mov edx,offset Error0 mov edx,offset szAppName invoke MessageBox,hWnddlg,,,MB_ICONEXCLAMATION or MB_OK jmp wmCLOSE ; После успешной инициализации получаем дескрипторы строк для сервиса, раздела и элемента данных @@: invoke SendMessage,hWnddlg,WM_USER_INITIATE,0,0 mov eax,TRUE jmp wmBYE wmSEND_ICO:mov edx,p1 mov type0,(WM_USER+3) invoke FindResource,0,,RT_ICON; find the resource mov hResource,rax invoke SizeofResource,0,eax ; get its size mov FSize,rax invoke LoadResource,0,hResource ; load the resource invoke LockResource,eax;pResource mov p,rax mov ecx,eax and qword ptr[rsp+30h],LR_DEFAULTCOLOR;LR_DEFAULTCOLOR=0 mov qword ptr[rsp+20h],256 mov qword ptr[rsp+28h],256 invoke CreateIconFromResourceEx,,FSize,TRUE,30000h;270376,TRUE,30000h mov [rsp+20h],rax invoke SendDlgItemMessage,hWnddlg,IDC_IMG1,STM_SETIMAGE,IMAGE_ICON xor p1,11b jmp @f wmSEND_WAV:mov ecx,offset wav_file xor r9d,r9d mov type0,(WM_USER+4) mov qword ptr[rsp+30h],r9 mov qword ptr[rsp+28h],FILE_ATTRIBUTE_ARCHIVE mov qword ptr[rsp+20h],OPEN_EXISTING invoke CreateFile,,GENERIC_READ or GENERIC_WRITE,\ FILE_SHARE_READ or FILE_SHARE_WRITE mov hFile,eax invoke GetFileSize,eax,0 mov FSize,rax invoke GlobalAlloc,GPTR,eax mov p,rax lea r9d,cbWritten and qword ptr[rsp+20h],0 invoke ReadFile,hFile,eax,FSize invoke CloseHandle,hFile jmp @f wmSEND_TXT:invoke GlobalAlloc,GPTR,256 mov p,rax mov type0,(WM_USER+2) invoke GetDlgItemText,hWnddlg,ID_TXT,eax,256 inc eax mov FSize,rax ; Найти окно получателя @@: mov edx,offset szWin invoke FindWindow,NULL or eax,eax jz wmBYE ; Отправить данные получателю invoke PostMessage,eax,type0,hWnddlg,FSize jmp wmBYE wmCOMMAND:cmp r8d,BN_CLICKED shl 16 + ID_SEND_WAV je wmSEND_WAV cmp r8d,BN_CLICKED shl 16 + ID_SEND_TXT je wmSEND_TXT cmp r8d,BN_CLICKED shl 16 + ID_SEND_ICO je wmSEND_ICO cmp r8d,BN_CLICKED shl 16 + IDCANCEL jne wmBYE wmCLOSE:;Завершение работы канала связи cmp hConvApp,NULL jnz @f invoke DdeDisconnect,hConvApp @@:; Сервис больше не доступен invoke DdeNameService,idInst,hszService,NULL,DNS_UNREGISTER ; Освобождение дескрипторов строк invoke DdeFreeStringHandle,idInst, hszService invoke DdeFreeStringHandle,idInst, hszTopic invoke DdeFreeStringHandle,idInst, hszItem invoke EndDialog,hWnddlg,0 wmBYE: mov eax,TRUE exit0: leave retn DialogProc endp DDEServerCallback proc wType:qword,wFmt:qword,hConv:qword,hsz1:qword,hsz2:qword,hData:qword,dwData1:qword,dwData2:qword mov hConv,r8 mov hsz1,r9 cmp ecx,XTYP_CONNECT je xtypCONNECT cmp ecx,XTYP_REQUEST je xtypREQUEST cmp ecx,XTYP_EXECUTE je xtypEXECUTE cmp ecx,XTYP_ERROR je xtypERROR cmp ecx,XTYP_DISCONNECT je xtypDISCONNECT cmp ecx,XTYP_CONNECT_CONFIRM je xtypCONNECT_CONFIRM xor eax,eax jmp wmBYE xtypCONNECT:;Создание канала передачи данных ; Если сервис поддерживается, возвращаем признак успешного создания канала mov rax,hsz2 cmp rax,hszService jne xtypEXECUTE mov eax,TRUE jmp wmBYE xtypDISCONNECT:; Завершение работы канала and hConvApp,NULL xtypERROR:; Ошибка ; Запрос на выполнение команды, отрабатывается вхолостую xtypEXECUTE: xor eax,eax jmp wmBYE xtypREQUEST:; Создаем дескриптор данных cmp edx,CF_TEXT jz @f cmp edx,CF_BITMAP jz @f cmp edx,CF_WAVE jnz wmBYE @@: xor r9d,r9d mov rax,hszItem mov [rsp+20h],rax mov [rsp+28h],rdx mov [rsp+30h],r9 invoke DdeCreateDataHandle,idInst,p,FSize ; В случае успеха возвращаем созданный дескриптор или ноль mov hData,rax jmp wmBYE ; Подтверждение создания канала xtypCONNECT_CONFIRM: mov hConvApp,r8 @@: xor eax,eax wmBYE: leave retn DDEServerCallback endp ;--------------------------------------- szWin db 'DDE Reciever',0 wav_file db '..\Images\03.wav',0 Error0 db "Could not initialize server!",0 ; дескриптор приложения, полученный после регистрации в библиотеке DDEML idInst dq 0 hszService dq 0 hszTopic dq 0 hszItem dq 0 ; дескриптор канала hConvApp dq 0 ; Буфер для приема данных p dq ? szService db "07s",0 szTopic db "Brer Rabbit",0 szItem db "DDEData",0 szAppName db "DDEML Server",0 ;hwnd dq ? FSize dq ? type0 dq ? p1 dd 1 end ресурсы Код (C): #include "resource.h" #define ID_TXT 100 #define ID_SEND_TXT 101 #define ID_SEND_ICO 102 #define ID_SEND_WAV 103 #define IDC_IMG1 104 #define IDC_DIALOG 200 #define IDC_ICON1 500 IDC_ICON1 ICON "..\\Images\\icon1.ico" IDC_ICON2 ICON "..\\Images\\icon2.ico" IDC_DIALOG DIALOG 0, 0, 212, 140 STYLE 0x0004 | DS_CENTER | WS_CAPTION | WS_MINIMIZEBOX | WS_SYSMENU | WS_VISIBLE | WS_OVERLAPPED | DS_MODALFRAME | DS_3DLOOK CAPTION "DDE Sender" BEGIN CONTROL "",-1,"BUTTON",BS_GROUPBOX, 2, -1, 207, 24 CONTROL "",IDC_IMG1,"Static",WS_CHILDWINDOW|WS_VISIBLE|SS_ICON,5,23,128,128 CONTROL "Напишите что-нибудь и нажмите 'Отправить текст'",ID_TXT,"EDIT",WS_BORDER | WS_TABSTOP | ES_AUTOHSCROLL,5,7,199,13 DEFPUSHBUTTON "Отправить текст",ID_SEND_TXT,149,27,60,15 PUSHBUTTON "Отправить ICO",ID_SEND_ICO, 149,45,60,15 PUSHBUTTON "Отправить WAV",ID_SEND_WAV, 149,65,60,15 PUSHBUTTON "Выход", IDCANCEL, 149,85,60,15 END Текст приложения-клиента Код (ASM): ; GUI # include win64a.inc IDC_DIALOG equ 200 ID_TXT equ 100 ID_ICON equ 102 IDC_ICON1 equ 500 TXT equ 10 ICO equ 11 WAV equ 12 WM_USER_INITIATE equ WM_USER + 1 extern __imp_DdeGetData:qword .code WinMain proc dummy:qword mov r9d,offset DialogProc and qword ptr[rsp+20h],0 invoke DialogBoxParam,IMAGE_BASE,IDC_DIALOG,HWND_DESKTOP invoke RtlExitUserProcess,NULL WinMain endp DialogProc proc hWnddlg:qword,msg:qword,wParam:qword,lParam:qword local buffer:qword local lpwiocb:WAVEHDR local hWaveOut:qword local dwResult:dword mov hWnddlg,rcx mov lParam,r9 cmp edx,WM_CLOSE je wmCLOSE cmp edx,WM_USER+4 je MUSIC_FROM_SERVER cmp edx,WM_USER+2 je MSG_FROM_SERVER cmp edx,WM_USER+3 je ICON_FROM_SERVER cmp edx,WM_COMMAND je wmCOMMAND cmp edx,WM_USER_INITIATE je wmUSER_INITIATE cmp edx,WM_INITDIALOG je wmINITDIALOG xor eax,eax jmp exit0 wmINITDIALOG:; Выполняем инициализацию xor esi,esi mov ecx,offset idInst mov edx,offset DDEServerCallback invoke DdeInitialize,,,APPCMD_CLIENTONLY or APPCLASS_STANDARD,0 or eax,eax jnz Error ; После успешной инициализации получаем дескрипторы строк для сервиса, раздела и элемента данных @@: invoke SendMessage,hWnddlg,WM_USER_INITIATE,0,0 mov eax,TRUE jmp wmBYE ICON_FROM_SERVER:mov wFmt,CF_BITMAP jmp @f MSG_FROM_SERVER:mov wFmt,CF_TEXT jmp @f MUSIC_FROM_SERVER:mov wFmt,CF_WAVE @@: invoke GlobalAlloc,GMEM_FIXED,lParam mov buffer,rax ; Запускаем транзакцию чтения данных mov rax,hConv mov esi,4 or eax,eax jz Error mov r8,rax mov rax,wFmt mov [rsp+20h],rax mov qword ptr[rsp+28h],XTYP_REQUEST mov qword ptr[rsp+30h],TIMEOUT_ASYNC;5000 lea eax,dwResult mov [rsp+38h],rax invoke DdeClientTransaction,0,0,,hszItem ; Получаем строку от сервера mov esi,5 or eax,eax;if(hData != NULL) jz Error invoke __imp_DdeGetData,eax,buffer,lParam,0 mov esi,6 or eax,eax jz Error cmp wFmt,CF_BITMAP jnz @f and qword ptr[rsp+30h],LR_DEFAULTCOLOR;LR_DEFAULTCOLOR=0 mov qword ptr[rsp+20h],256 mov qword ptr[rsp+28h],256 invoke CreateIconFromResourceEx,buffer,eax,TRUE,30000h mov [rsp+20h],rax invoke SendDlgItemMessage,hWnddlg,ID_ICON,STM_SETIMAGE,IMAGE_ICON jmp @0 @@: cmp wFmt,CF_TEXT jnz @f invoke SetDlgItemText,hWnddlg,ID_TXT,buffer jmp @0 ;----------------------------------------------------------- @@: mov r8,buffer add r8d,14h lea ecx,hWaveOut xor r9,r9 mov [rsp+20h],r9 mov qword ptr[rsp+28h],WAVE_ALLOWSYNC or edx,WAVE_MAPPER invoke waveOutOpen ; Подготавливаем заголовок для вывода lea edx,lpwiocb mov edi,edx xor eax,eax mov ecx,(sizeof WAVEHDR)/8 rep stosq mov rax,buffer mov ecx,eax add rax,2Ch mov [rdx].WAVEHDR.lpData,rax ;адрес блока данных mov eax,[rcx+4] sub eax,2Ch mov [rdx].WAVEHDR.dwBufferLength,eax ;размер блока данных invoke waveOutPrepareHeader,hWaveOut,,sizeof WAVEHDR ; Запускаем проигрывание блока lea edx,lpwiocb mov rcx,hWaveOut mov r8d,sizeof WAVEHDR invoke waveOutWrite @@: test lpwiocb.dwFlags,WHDR_DONE jz @b lea edx,lpwiocb invoke waveOutUnprepareHeader,hWaveOut,,sizeof WAVEHDR invoke waveOutClose,hWaveOut ;------------------------------------------------------------ @0: invoke GlobalFree,buffer jmp wmBYE wmUSER_INITIATE:; Инициализация DDEML и создание канала связи invoke DDEClientOpen or eax,eax jnz wmBYE mov edx,offset Error1 mov r8d,offset szAppName invoke MessageBox,hWnddlg,,,MB_ICONEXCLAMATION or MB_YESNO cmp eax,IDNO jz wmBYE mov ecx,offset szService invoke WinExec,,SW_SHOW cmp eax,32 mov esi,2 jb Error ; После удачного запуска повторяем попытку инициализации DDEML и создания канала связи invoke DDEClientOpen jmp wmBYE Error: mov r8d,offset szAppName invoke MessageBox,hWnddlg,ErrorMsg[rsi*8],,MB_ICONEXCLAMATION jmp aExit wmCOMMAND:cmp r8d,BN_CLICKED shl 16 + IDCANCEL jne wmBYE wmCLOSE:; Завершаем работу с DDEML. Закрываем канал связи cmp hConv,0 jz @f invoke DdeDisconnect,hConv @@:; Освобождаем дескрипторы строк invoke DdeFreeStringHandle,idInst,hszService invoke DdeFreeStringHandle,idInst,hszTopic invoke DdeFreeStringHandle,idInst,hszItem aExit: invoke EndDialog,hWnddlg,0 wmBYE: mov eax,TRUE exit0: leave ret DialogProc endp DDEServerCallback proc wType:qword,wFmt:qword,hConv:qword,hsz1:qword,hsz2:qword,hData:qword,dwData1:qword,dwData2:qword xor eax,eax wmBYE: leave retn DDEServerCallback endp DDEClientOpen proc local dummy:qword ; При успешной инициализации создаем дескрипторы строк для сервиса, ; раздела и элемента данных mov edx,offset szService invoke DdeCreateStringHandle,idInst,,CP_WINANSI mov hszService,rax mov edx,offset szTopic invoke DdeCreateStringHandle,idInst,,CP_WINANSI mov hszTopic,rax mov edx,offset szItem invoke DdeCreateStringHandle,idInst,,CP_WINANSI mov hszItem,rax ; Устанавливаем канал связи invoke DdeConnect,idInst, hszService, hszTopic,0 mov hConv,rax ; Возвращаем дескриптор созданного канала связи leave ret DDEClientOpen endp ;----------------------------------- szAppName db "DDEML Client",0 szService db "07s",0 szTopic db "Brer Rabbit",0 szItem db "DDEData",0 ErrorMsg dq Error0,Error1,Error2,Error3,Error4,Error5,Error6 Error0 db "Could not initialize client!",0 Error1 db "Сервер не запущен",10,"Запустить?",0 Error2 db "Невозможно запустить сервер",0 Error3 db "Сервер не отвечает",0 Error4 db "hConv = 0",0 Error5 db "hData = 0",0 Error6 db "lParam = 0",0 ; дескриптор приложения для DDEML hConv dq 0 idInst dq 0 hszService dq ? hszTopic dq ? hszItem dq ? wFmt dq ? end ресурсы Код (C): #include "resource.h" #define IDC_DIALOG 200 #define ID_TXT 100 #define ID_ICON 102 IDC_DIALOG DIALOG 0,0,212,140 STYLE 0x0004 | DS_CENTER | WS_CAPTION | WS_MINIMIZEBOX | WS_SYSMENU | WS_VISIBLE | WS_OVERLAPPED | DS_MODALFRAME | DS_3DLOOK CAPTION "DDE Reciever" BEGIN CONTROL "",-1,"BUTTON",BS_GROUPBOX, 2, -1, 207, 24 CONTROL "",ID_TXT,"STATIC",WS_BORDER | WS_TABSTOP | ES_AUTOHSCROLL,5,7,199,13 DEFPUSHBUTTON "Выход",IDCANCEL,149,27,60,15 CONTROL "",ID_ICON,"STATIC",WS_CHILDWINDOW | SS_ICON,5,23,128,128 END
05. MailslotMailslot-каналы позволяют выполнять одностороннюю передачу данных от одного или нескольких клиентов к одному или нескольким серверам. Особенность mailslot-каналов в том, что они позволяют передавать данные в широковещательном режиме. На компьютере или в сети могут работать несколько серверных процессов, способных получать сообщения через mailslot-каналы. При этом один клиентский процесс может посылать сообщения сразу всем этим серверным процессам. Создание mailslot-канала Mailslot-канал создается серверным процессом с помощью функции CreateMailslot. После создания серверный процесс получает дескриптор mailslot-канала. Используя этот дескриптор, сервер может читать сообщения, посылаемые в канал клиентскими процессами. Сервер не может выполнять над mailslot-каналом операцию записи, так как этот канал предназначен только для односторонней передачи данных ― от клиента к серверу. Прототип функции CreateMailslot: Код (C): HANDLE CreateMailslot( LPCTSTR lpName, // адрес имени канала Mailslot DWORD nMaxMsgSize, // максимальный размер сообщения DWORD lReadTimeout, // время ожидания для чтения LPSECURITY_ATTRIBUTES lpSecurityAttributes); // адрес структуры защиты Через параметр lpName передают функции CreateMailslot адрес строки символов с именем mailslot-канала. Имя имеет следующий вид: Код (C): \\.\mailslot\[Путь]Имя_Канала В этом имени путь необязательная компонента. Но можно указать его аналогично тому, как это делается для файлов. Имя mailslot-канала задается аналогично имени pipe-канала. Параметр nMaxMsgSize ― максимальный размер сообщений, передаваемых через mailslot-канал. Можно указать нулевое значение, при этом размер сообщений не будет ограничен. Есть одно исключение ― размер широковещательных сообщений, передаваемых всем рабочим станциям и серверам домена не должен превышать 400 байт. С помощью параметра lReadTimeout серверное приложение задает время ожидания для операции чтения в миллисекундах, по истечении которого функция чтения вернет код ошибки. Если в этом параметре указать значение MAILSLOT_WAIT_FOREVER, ожидание будет бесконечным. Параметр lpSecurityAttributes задает адрес структуры защиты, который можно указать как NULL. При ошибке функцией CreateMailslot возвращается значение INVALID_HANDLE_VALUE. Код ошибки можно определить при помощи функции GetLastError. Пример использования функции CreateMailslot в серверном приложении: Код (C): LPSTR lpszMailslotName = "\\\\.\\mailslot\\$MailslotName$"; hMailslot = CreateMailslot(lpszMailslotName, 0, MAILSLOT_WAIT_FOREVER, NULL); В примере задан максимальный размер сообщения, поэтому на эту величину нет ограничений (кроме ограничения в 400 байт для сообщений, передаваемых всем компьютерам домена в широковещательном режиме). Время ожидания указано как MAILSLOT_WAIT_FOREVER, поэтому функции, работающие с данным mailslot-каналом , будут работать в блокирующем режиме. Открытие mailslot-канала Сперва клиентский процесс должен открыть mailslot-канал. Для этого используют функцию CreateFile Код (C): LPSTR lpszMailslotName = "\\\\.\\mailslot\\$MailslotName$"; hMailslot = CreateFile( lpszMailslotName, GENERIC_WRITE, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL); Здесь в качестве первого параметра функции CreateFile передается имя mailslot-канала. Вы можете открыть mailslot-канал, созданный на другой рабочей станции в сети. Для этого строка имени канала, передаваемая функции CreateFile, должна иметь следующий вид: Код (C): \\Имя_Рабочей_Станции\mailslot\[Путь]Имя_Канала Можно открыть канал для передачи сообщений всем рабочим станциям заданного домена. Для этого необходимо задать имя по следующему образцу: Код (C): \\Имя_Домена\mailslot\[Путь]Имя_Канала Для передачи сообщений одновременно всем рабочим станциям сети первичного домена имя задается следующим образом Код (C): \\*\mailslot\[Путь]Имя_Канала В качестве второго параметра функции CreateFile используют константу GENERIC_WRITE. Эта константа определяет, что над открываемым каналом будет выполняться операция записи. Клиентский процесс может только посылать сообщения в mailslot-канал, но не читать их оттуда. Чтение сообщений из mailslot-канала ― задача для серверного процесса. Третий параметр FILE_SHARE_READ, так как сервер может читать сообщения, посылаемые одновременно несколькими клиентскими процессами. Константа OPEN_EXISTING используется потому, что функция CreateFile открывает существующий канал, а не создает новый. Запись сообщений в канал Mailslot Запись сообщений в mailslot-канал выполняет клиентский процесс, вызывая для этого функцию WriteFile. Код (C): HANDLE hMailslot; char szBuf[512]; DWORD cbWritten; WriteFile(hMailslot, szBuf, strlen(szBuf) + 1, &cbWritten, NULL); В качестве первого параметра этой функции необходимо передать дескриптор mailslot-канала, полученный от функции CreateFile. Второй параметр определяет адрес буфера с сообщением, третий ― размер сообщения. Если сообщение передается в виде текстовой строки, тогда закрыть строку нужно нулем, для определения длины сообщения можно воспользоваться функцией strlen. Чтение сообщений из канала Mailslot Серверный процесс может читать сообщения из созданного им mailslot-канала при помощи функции ReadFile Код (C): HANDLE hMailslot; char szBuf[512]; DWORD cbRead; ReadFile(hMailslot, szBuf, 512, &cbRead, NULL); Через первый параметр функции ReadFile передается дескриптор созданного mailslot-канала, полученный от функции CreateMailslot. Второй и третий параметры задают, адрес буфера сообщения и его размер. Перед выполнением операции чтения следует проверить состояние mailslot-канала. Если в mailslot-канале нет сообщений, то функцию ReadFile вызывать не следует. Для проверки состояния канала воспользуйтесь функцией GetMailslotInfo. Определение состояния канала Mailslot Серверный процесс может определить текущее состояние mailslot-канала по его дескриптору с помощью функции GetMailslotInfo Код (C): BOOL GetMailslotInfo( HANDLE hMailslot, // дескриптор канала Mailslot LPDWORD lpMaxMessageSize, // адрес максимального размера сообщения LPDWORD lpNextSize, // адрес размера следующего сообщения LPDWORD lpMessageCount, // адрес количества сообщений LPDWORD lpReadTimeout); // адрес времени ожидания Через параметр hMailslot передается дескриптор mailslot-канала , состояние которого необходимо определить. Остальные параметры ― указатели на переменные типа DWORD, в которые будут записаны параметры состояния mailslot-канала. В переменную, адрес которой передается через параметр lpMaxMessageSize, после возвращения из функции GetMailslotInfo будет записан максимальный размер сообщения. Это значение можно использовать для динамического получения буфера памяти, в который это сообщение будет прочитано функцией ReadFile. В переменную, адрес которой указан через параметр lpNextSize, записывается размер следующего сообщения, если оно есть в канале. Если в канале больше нет сообщений, в эту переменную будет записана константа MAILSLOT_NO_MESSAGE. С помощью параметра lpMessageCount можно определить количество сообщений, записанных в канал клиентскими процессами. Если это количество равно нулю ― не следует вызывать функцию ReadFile для чтения несуществующего сообщения. В переменную, адрес которой задается в параметре lpReadTimeout, записывается текущее время ожидания, установленное для канала (в миллисекундах). Если вся информация, которую можно получить с помощью функции GetMailslotInfo не нужна, некоторые из ее параметров (первого) можно указать как NULL. В случае успешного завершения функция GetMailslotInfo возвращает значение TRUE, а при ошибке ― FALSE. Код ошибки можно получить, вызвав функцию GetLastError. Пример использования функции GetMailslotInfo: Код (C): BOOL fReturnCode; DWORD cbMessages; DWORD cbMsgNumber; fReturnCode = GetMailslotInfo(hMailslot, NULL, &cbMessages, &cbMsgNumber, NULL); Изменение состояния канала Mailslot С помощью функции SetMailslotInfo серверный процесс может изменить время ожидания для mailslot-канала уже после его создания. Прототип функции SetMailslotInfo Код (C): BOOL SetMailslotInfo( HANDLE hMailslot, // дескриптор канала Mailslot DWORD dwReadTimeout); // время ожидания Через параметр hMailslot функции SetMailslotInfo передается дескриптор mailslot-канала, для которого нужно изменить время ожидания. Новое значение времени ожидания в миллисекундах задается через параметр dwReadTimeout. Можно указать здесь значение 0 или MAILSLOT_WAIT_FOREVER. Если dwReadTimeout=0 функции, работающие с каналом, вернут управление немедленно, dwReadTimeout=MAILSLOT_WAIT_FOREVER ― будут находиться в состоянии ожидания до тех пор, пока не завершится выполняемая операция. Текст приложения-сервера Код (ASM): ; GUI # include win64a.inc WM_CLIPBOARDUPDATE equ 31Dh ID_TXT equ 100 ID_SEND_TXT equ 101 ID_SEND_ICO equ 102 ID_SEND_WAV equ 103 IDC_DIALOG equ 200 IDC_ICON1 equ 500 IDC_IMG1 equ 104 .code WinMain proc dummy:qword mov r9d,256 mov [rsp+20h],r9 mov qword ptr [rsp+28],LR_DEFAULTCOLOR invoke LoadImage,IMAGE_BASE,IDC_ICON1,IMAGE_ICON;,256,256,LR_DEFAULTCOLOR mov r9d,offset DialogProc mov qword ptr[rsp+20h],rax invoke DialogBoxParam,IMAGE_BASE,IDC_DIALOG,HWND_DESKTOP invoke RtlExitUserProcess,NULL WinMain endp DialogProc proc hWnddlg:QWORD,uMsg:QWORD,wParam:QWORD,lParam:QWORD local cbWritten:dword;Количество байт, переданных через канал local FSize:dword; local p:qword local hMailslot:qword; дескриптор канала Mailslot local hResource:qword local hFile:dword local szReadWrite:qword ;number of bytes actually read or write local lpwiocb:WAVEHDR local hWaveOut:qword local type0:qword mov hWnddlg,rcx mov lParam,r9 cmp edx,WM_CLOSE je wmCLOSE cmp edx,WM_COMMAND je wmCOMMAND cmp edx,WM_INITDIALOG je wmINITDIALOG xor eax,eax jmp exit0 wmINITDIALOG:; invoke GetDlgItem,,IDC_IMG1 invoke SendMessage,eax,STM_SETIMAGE,IMAGE_ICON,lParam jmp wmBYE wmSEND_TXT:invoke GlobalAlloc,GPTR,256 mov p,rax;Буфер для передачи данных через канал invoke GetDlgItemText,hWnddlg,ID_TXT,eax,256 or eax,eax jz wmBYE inc eax mov FSize,eax mov type0,WM_USER+1 jmp @f wmSEND_ICO:mov edx,p1 invoke FindResource,0,,RT_ICON; find the resource mov hResource,rax invoke SizeofResource,0,eax ; get its size mov FSize,eax invoke LoadResource,0,hResource ; load the resource invoke LockResource,eax;pResource mov p,rax ;------------------------------------------------- and qword ptr[rsp+30h],LR_DEFAULTCOLOR;LR_DEFAULTCOLOR=0 mov qword ptr[rsp+20h],256 mov qword ptr[rsp+28h],256 mov edx,FSize invoke CreateIconFromResourceEx,p,,TRUE,30000h;270376,TRUE,30000h mov [rsp+20h],rax invoke SendDlgItemMessage,hWnddlg,IDC_IMG1,STM_SETIMAGE,IMAGE_ICON xor p1,11b mov type0,WM_USER+2 jmp @f wmSEND_WAV:sub esp,40h mov ecx,offset wav_file xor r9d,r9d mov qword ptr[rsp+30h],r9 mov qword ptr[rsp+28h],FILE_ATTRIBUTE_ARCHIVE mov qword ptr[rsp+20h],OPEN_EXISTING invoke CreateFile,,GENERIC_READ or GENERIC_WRITE,\ FILE_SHARE_READ or FILE_SHARE_WRITE mov hFile,eax invoke GetFileSize,eax,0 mov FSize,eax invoke GlobalAlloc,GPTR,eax mov p,rax mov type0,WM_USER+3 lea r9d,cbWritten and qword ptr[rsp+20h],0 invoke ReadFile,hFile,eax,FSize invoke CloseHandle,hFile @@:; Создаем канал с процессом MSLOTS mov ecx,offset szMailslotName xor r9d,r9d mov qword ptr[rsp+20h],OPEN_EXISTING mov [rsp+28h],r9 mov [rsp+30h],r9 invoke CreateFile,,GENERIC_WRITE,FILE_SHARE_READ mov hMailslot,rax lea r9d,cbWritten and qword ptr[rsp+20h],0 invoke WriteFile,hMailslot,p,FSize ; Найти окно получателя mov edx,offset szWin invoke FindWindow,NULL or eax,eax jz wmBYE ; Отправить данные получателю invoke PostMessage,eax,type0,hWnddlg,FSize ;Закрываем дескриптор канала invoke CloseHandle,hMailslot jmp wmBYE wmCOMMAND:cmp r8d,BN_CLICKED shl 16 + ID_SEND_TXT je wmSEND_TXT cmp r8d,BN_CLICKED shl 16 + ID_SEND_ICO je wmSEND_ICO cmp r8d,BN_CLICKED shl 16 + ID_SEND_WAV je wmSEND_WAV cmp r8d,BN_CLICKED shl 16 + IDCANCEL jne wmBYE wmCLOSE:invoke EndDialog,,0 wmBYE: mov eax,TRUE exit0: leave retn DialogProc endp ;--------------------------------------- szWin db 'Mailslot Reciever',0 szMailslotName db "\\.\mailslot\brer_Rabbit",0; Имя создаваемого канала wav_file db '..\Images\03.wav',0 p1 dd 1 end ресурсы Код (C): #include "resource.h" #define ID_TXT 100 #define ID_SEND_TXT 101 #define ID_SEND_ICO 102 #define ID_SEND_WAV 103 #define IDC_DIALOG 200 #define IDC_ICON1 500 #define IDC_IMG1 104 IDC_ICON1 ICON "..\\Images\\icon1.ico" IDC_ICON2 ICON "..\\Images\\icon2.ico" IDC_DIALOG DIALOG 0, 0, 212, 140 STYLE 0x0004 | DS_CENTER | WS_CAPTION | WS_MINIMIZEBOX | WS_SYSMENU | WS_VISIBLE | WS_OVERLAPPED | DS_MODALFRAME | DS_3DLOOK CAPTION "Mailslot Sender" BEGIN CONTROL "",-1,"BUTTON",BS_GROUPBOX, 2, -1, 207, 24 CONTROL "",IDC_IMG1,"Static",WS_CHILDWINDOW|WS_VISIBLE|SS_ICON,5,23,128,128 CONTROL "Напишите что-нибудь и нажмите 'Отправить текст'",ID_TXT,"EDIT",WS_BORDER | WS_TABSTOP | ES_AUTOHSCROLL,5,7,199,13 DEFPUSHBUTTON "Отправить текст",ID_SEND_TXT,149,27,60,15 PUSHBUTTON "Отправить ICO",ID_SEND_ICO, 149,45,60,15 PUSHBUTTON "Отправить WAV",ID_SEND_WAV, 149,65,60,15 PUSHBUTTON "Выход", IDCANCEL, 149,85,60,15 END Текст приложения-клиента Код (ASM): ; GUI # include win64a.inc WM_CLIPBOARDUPDATE equ 31Dh IDC_DIALOG equ 200 ID_TXT equ 100 ID_ICON equ 102 IDC_ICON1 equ 500 TXT equ 10 ICO equ 11 WAV equ 12 .code WinMain proc dummy:qword mov r9d,offset DialogProc and qword ptr[rsp+20h],0 invoke DialogBoxParam,IMAGE_BASE,IDC_DIALOG,HWND_DESKTOP invoke RtlExitUserProcess,NULL WinMain endp DialogProc proc hWnddlg:qword,msg:qword,wParam:qword,lParam:qword local cbRead:DWORD;Количество байт данных, принятых через канал local cbMessages:DWORD;Размер сообщения в байтах local cbMsgNumber:DWORD;Количество сообщений в канале Mailslot local buffer:QWORD local lpwiocb:WAVEHDR local hWaveOut:qword mov hWnddlg,rcx mov lParam,r9 cmp edx,WM_CLOSE je wmCLOSE cmp edx,WM_INITDIALOG je wmINITDIALOG cmp edx,WM_USER+1 je wmUSER_1 cmp edx,WM_USER+2 je wmUSER_2 cmp edx,WM_USER+3 je wmUSER_3 cmp edx,WM_COMMAND je wmCOMMAND xor eax,eax jmp exit0 wmUSER_1:mov type0,CF_TEXT jmp @f wmUSER_2:mov type0,CF_DIB jmp @f wmUSER_3:mov type0,CF_WAVE ; Определяем состояние канала Mailslot @@: lea r8d,cbMessages lea r9d,cbMsgNumber xor edx,edx mov [rsp+20h],rdx invoke GetMailslotInfo,hMailslot ; Выполняем задержку на 500 миллисекунд invoke Sleep,500 ; Если в канале есть Mailslot сообщения, читаем первое из них и выводим на экран cmp cbMsgNumber,0 jz wmBYE invoke GlobalAlloc,GMEM_FIXED,lParam mov buffer,rax mov edx,eax lea r9d,cbRead and qword ptr[rsp+20h],0 invoke ReadFile,hMailslot,,lParam cmp type0,CF_TEXT je TEXT cmp type0,CF_DIB je DIB WAVE: mov r8,buffer add r8d,14h lea ecx,hWaveOut xor r9,r9 mov [rsp+20h],r9 mov qword ptr[rsp+28h],WAVE_ALLOWSYNC or edx,WAVE_MAPPER invoke waveOutOpen ; Подготавливаем заголовок для вывода lea edx,lpwiocb mov edi,edx xor eax,eax mov ecx,(sizeof WAVEHDR)/8 rep stosq mov rax,buffer mov ecx,eax add rax,2Ch mov [rdx].WAVEHDR.lpData,rax ;адрес блока данных mov eax,[rcx+4] sub eax,2Ch mov [rdx].WAVEHDR.dwBufferLength,eax ;размер блока данных invoke waveOutPrepareHeader,hWaveOut,,sizeof WAVEHDR ; Запускаем проигрывание блока lea edx,lpwiocb mov rcx,hWaveOut mov r8d,sizeof WAVEHDR invoke waveOutWrite @@: test lpwiocb.dwFlags,WHDR_DONE jz @b lea edx,lpwiocb invoke waveOutUnprepareHeader,hWaveOut,,sizeof WAVEHDR invoke waveOutClose,hWaveOut invoke GlobalFree,buffer jmp wmBYE TEXT: invoke SetDlgItemText,hWnddlg,ID_TXT,buffer invoke GlobalFree,buffer jmp wmBYE DIB: and qword ptr[rsp+30h],LR_DEFAULTCOLOR;LR_DEFAULTCOLOR=0 mov qword ptr[rsp+20h],256 mov qword ptr[rsp+28h],256 invoke CreateIconFromResourceEx,buffer,lParam,TRUE,30000h mov [rsp+20h],rax invoke SendDlgItemMessage,hWnddlg,ID_ICON,STM_SETIMAGE,IMAGE_ICON invoke GlobalFree,buffer jmp wmBYE wmINITDIALOG:; Создаем канал Mailslot, имеющий имя lpszMailslotName mov ecx,offset lpszMailslotName invoke CreateMailslot,,0,MAILSLOT_WAIT_FOREVER, NULL mov hMailslot,rax jmp wmBYE wmCOMMAND:cmp r8d,BN_CLICKED shl 16 + IDCANCEL jne wmBYE wmCLOSE:;Перед завершением приложения закрываем дескриптор канала Mailslot invoke CloseHandle,hMailslot invoke EndDialog,hWnddlg,0 wmBYE: mov eax,TRUE exit0: leave ret DialogProc endp lpszMailslotName db "\\.\mailslot\brer_Rabbit",0;Имя создаваемого канала Mailslot hMailslot dq ?;дескриптор канала Mailslot type0 db ? end ресурсы Код (C): #include "resource.h" #define IDC_DIALOG 200 #define ID_TXT 100 #define ID_ICON 102 IDC_DIALOG DIALOG 0,0,212,140 STYLE 0x0004 | DS_CENTER | WS_CAPTION | WS_MINIMIZEBOX | WS_SYSMENU | WS_VISIBLE | WS_OVERLAPPED | DS_MODALFRAME | DS_3DLOOK CAPTION "Mailslot Reciever" BEGIN CONTROL "",-1,"BUTTON",BS_GROUPBOX, 2, -1, 207, 24 CONTROL "",ID_TXT,"STATIC",WS_BORDER | WS_TABSTOP | ES_AUTOHSCROLL,5,7,199,13 DEFPUSHBUTTON "Выход",IDCANCEL,149,27,60,15 CONTROL "",ID_ICON,"STATIC",WS_CHILDWINDOW | SS_ICON,5,23,128,128 END
OLE/ActiveXУниверсальная технология, одно из ее применений ― межпроцессный обмен данными. OLE создавалась на смену DDE. Для обмена данными существует интерфейс IDataObject. Для обмена данными по сети используется DCOM, ее можно рассматривать как объединение ActiveX и RPC.Windows SocketsОтвечает за обмен данными в глобальной сети. Сокеты используются в локальных сетях. Взаимодействие происходит через так называемые разъемы-"сокеты", которые представляют собой абстракцию конечных точек коммуникационной линии, соединяющей два приложения. С этими объектами программа работает, ждет соединения, посылает данные и так далее. Microsoft Message Queue (MSMQ)Этот протокол обеспечивает посылку сообщений между приложениями с помощью очереди сообщений. Отличие от стандартной очереди сообщений Windows ― он может работать с удаленными процессами и с процессами, которые на данный момент недоступны (например, не запущены). Доставка сообщения по адресу гарантируется. Оно ставится в специальную очередь сообщений и находится там до тех пор, пока не появляется возможность его доставить.Удаленный вызов процедур (Remote Procedure Call, RPC)С помощью этой технологии общение через сеть прозрачно как для сервера, так и для клиента. И серверу, и клиенту кажется, что "собеседник" расположен локально по отношению к ним.Distributed Component Object Model (DCOM)Программная архитектура, разработанная компанией Microsoft для распределения приложений между несколькими компьютерами в сети. Программный компонент на одной из машин может использовать DCOM для передачи сообщения (его называют удаленным вызовом процедуры) к компоненту на другой машине. DCOM автоматически устанавливает соединение, передает сообщение и возвращает ответ удаленного компонента. Remote Method Invocation (RMI)Механизм, который позволяет вызывать метод удаленного объекта. Все операции по подготовке и передаче данных инкапсулируются в вызываемом методе клиентского объекта-заглушки (stub). Вызов метода не отличается от вызова метода обычного локального объекта, за небольшим исключением: локальные объекты передаются по значению (копии) при передаче удаленного (Remote) объекта, если он экспортирован, передается stub этого объекта передаваемые объекты должны быть Serializable при вызове удаленного метода может возбуждаться исключение RemoteException (ошибки маршализации/демаршализации, передачи данных и другие возможные ошибки протокола) При вызове метода работают с удаленным интерфейсом, а не с удаленным классом. Common Object Request Broker Architecture (CORBA)Общая архитектура брокера объектных запросов; типовая архитектура опосредованных запросов к объектам) — технологический стандарт написания распределенных приложений, продвигаемый консорциумом (рабочей группой) OMG и соответствующая ему информационная технология. CORBA обеспечивает взаимодействие между системами, работающих под разными операционными системами, написанными на разных языках программирования и запущенных на разном вычислительном оборудовании. CORBA использует объектно-ориентированную модель, системы, использующие CORBA, не обязательно должны быть объектно-ориентированными. CORBA — пример парадигмы распределенной объектной системы. DLLВажной особенностью использования динамических библиотек является возможность одновременного использования одной библиотеки несколькими модулями. Динамическая библиотека становится продолжением запустившего ее приложения, загружаясь в адресное пространство процесса. Данные процесса доступны из динамической библиотеки и данные динамической библиотеки доступны для процесса. При компоновке динамической библиотеки сегмент данных объявлен как секция с общим доступом. При запуске приложения, которое будет загружать динамическую библиотеку, эта область памяти будет общей для всех приложений.
Код (C): static void SendString (LPCSTR string) { HANDLE handles[257]; char name[32]; int i, length; for (i=0; i<257; i++) { sprintf (name, "Mutex#u", i); handles[i] = CreateMutex (NULL, TRUE, name); } length = lstrlen (string); for (i=0; i<length; i++) { ReleaseMutex (handles[string[i]]); WaitForSingleObject (handles[string[i]], INFINITE); } ReleaseMutex (handles[256]); for (i=0; i<257; i++) CloseHandle (handles[i]); } static LPSTR ReceiveString () { LPSTR string; HANDLE handles[257]; char name[32]; int i, length, result; string = malloc (1024); length = 0; for (i=0; i<257; i++) { sprintf (name, "Mutex#u", i); handles[i] = CreateMutex (NULL, FALSE, name); } while (TRUE) { result = WaitForMultipleObjects (257, handles, FALSE, INFINITE); if (result < 0 || result > 255) break; string[length++] = (char)result; ReleaseMutex (handles[result]); } string[length] = 0; for (i=0; i<257; i++) CloseHandle (handles[i]); return string; }
Не может. Это надо на потоках разруливать. Основной поток записывает в массив хендлов MAX-1 дескрипторов, а последним ― хендл вспомогательного потока, который ждет на следующих MAX-1 дескрипторах и опционально дополнительном вспомогательном потоке.
Объекты синхронизации08. Evet PipesWindows позволяет создавать объекты синхронизации, которые называются событиями (event object). Объекты-события могут находиться в signaled состоянии или nonsignaled состоянии. Сигнальное состояние объекта (signaled) соответствует моменту времени, когда объект не принадлежит ни одному потоку и его можно "захватить". Состояние "сброшен" (nonsignaled) соответствует моменту, когда какой-либо поток уже владеет этим объектом. Доступ к объекту разрешается, когда поток, владеющий объектом, освободит его. Установка состояния выполняется вызовом соответствующей функции. Одна из задач создает объект-событие, вызывая для этого функцию CreateEvent. У события есть имя, которое доступно всем задачам активных процессов. В процессе создания или позже эта задача устанавливает событие в исходное состояние (signaled или nonsignaled). Вызывая функции WaitForSingleObject или WaitForMultipleObjects, задача ожидает момент, когда событие перейдет в signaled состояние. Другая задача, принадлежащая тому же самому или другому процессу, получает дескриптор события по его имени с помощью функции OpenEvent. Дальше используя функции SetEvent, ResetEvent или PulseEvent, приложение изменяет состояние события. После создания nonsignaled/неотмеченного события первая задача переходит в состояние ожидания, пока вторая задача не подготовит для нее данные. Как только это произойдет, вторая задача отмечает и затем сбрасывает событие, что приводит к завершению ожидания первой задачей. Отобразив подготовленные данные, первая задача опять входит в состояние ожидания, пока вторая задача не подготовит данные и не отметит событие. С помощью объекта-события две задачи синхронизируют свою работу.Создание событияДля создания события приложение вызывает функцию CreateEvent Код (C): HANDLE CreateEvent( LPSECURITY_ATTRIBUTES lpEventAttributes, // атрибуты защиты BOOL bManualReset, // флаг ручного сброса события BOOL bInitialState, // флаг начального состояния события LPCTSTR lpName // адрес имени объекта-события ); Параметр lpEventAttributes задает атрибуты защиты и в большинстве случаев может быть указан как NULL. Параметр bManualReset выбирает один из двух режимов работы объекта-события: ручной или автоматический. Если bManualReset=TRUE, событие нужно сбрасывать вручную при помощи функции ResetEvent. Если bManualReset=FALSE, событие будет сброшено (переведено в nonsignaled состояние) автоматически сразу после того как задача завершит ожидание этого события. Параметр bInitialState определяет начальное состояние события. Если bInitialState =TRUE, объект-событие создается в signaled/отмеченном состоянии, если bInitialState=FALSE ― в nonsignaled. Чтобы событием могли использовать задачи, созданные разными процессами, необходимо с помощью параметра lpName задать имя объекта-события. В качестве имени можно выбрать любое имя размером не более MAX_PATH=260 символов, не содержащее символ “\”. Если событие используется задачами, работающими в рамках одного процесса, имя события можно не задавать (lpName=NULL). Будет создано безымянное событие. В случае успешного завершения функция CreateEvent возвращает дескриптор события, который используется при выполнении операций над объектом-событием. При ошибке возвращается NULL (код ошибки получают при помощи GetLastError). Если при создании события указано имя уже существующего в системе события, созданного другой задачей ― тогда функция GetLastError возвратит значение ERROR_ALREADY_EXISTS=0B7h.Открытие событияЕсли событие используется задачами, созданными в рамках одного процесса, его не нужно открывать. В качестве параметра функциям, изменяющим состояние объекта-события, можно передавать дескриптор события, полученный при создании от функции CreateEvent. Если событие используется для синхронизации задач, принадлежащих разным процессам, нужно при создании события задать его имя. Задача, изменяющая состояние события и принадлежащая другому процессу, должна открыть объект-событие с помощью функции OpenEvent, передав ей имя этого объекта. Прототип функции OpenEvent: Код (C): HANDLE OpenEvent( DWORD fdwAccess, // флаги доступа BOOL fInherit, // флаг наследования LPCTSTR lpszEventName // адрес имени объекта-события ); Флаги доступа, передаваемые через параметр fdwAccess, определяют требуемый уровень доступа к объекту-событию. Этот параметр может быть комбинацией следующих значений: Значениеhexbin Описание EVENT_QUERY_STATE SEMAPHORE_QUERY_STATE10.0000.0000.0000.0000.0001Право на запрос состояния объекта события EVENT_MODIFY_STATE SEMAPHORE_MODIFY_STATE20.0000.0000.0000.0000.0010 Полученный дескриптор можно использовать функциями SetEvent и ResetEvent40.0000.0000.0000.0000.010080.0000.0000.0000.0000.1000DELETE100000.0001.0000.0000.0000.0000Право на удаление объектаREAD_CONTROL200000.0010.0000.0000.0000.0000Право на чтение информации в дескрипторе безопасности для объекта, не включая информацию в SACL. Для чтения или записи SACL необходимо запросить право доступа ACCESS_SYSTEM_SECURITYWRITE_DAC400000.0100.0000.0000.0000.0000Право на изменение DACL в дескрипторе безопасности для объекта. Право доступа на запись к произвольному управляющему списку доступа объекта access control list (ACL)WRITE_OWNER800000.1000.0000.0000.0000.0000Право на изменение владельца в дескрипторе безопасности объекта. SYNCHRONIZE1000001.0000.0000.0000.0000.0000 Полученный дескриптор можно использовать в любых функциях ожидания событияMUTEX_ALL_ACCESS1F00011.1111.0000.0000.0000.0001Указаны все возможные для Mutex флаги доступаEVENT_ALL_ACCESS SEMAPHORE_ALL_ACCESS1F00031.1111.0000.0000.0000.0011Указаны все возможные для Event и Semaphore флаги доступаПараметр fInherit определяет возможность наследования полученного дескриптора. Если fInherit=TRUE, дескриптор может наследоваться дочерними процессами. Если fInherit=FALSE, наследование не допускается. Через параметр lpszEventName передают имени объекта-события. С помощью OpenEvent несколько задач могут открыть один и тот же объект-событие и выполнять одновременное ожидание этого объекта.Установка событияДля установки объекта-события в отмеченное состояние используется функция SetEvent: Код (C): BOOL SetEvent(HANDLE hEvent); В качестве параметра функции необходимо передать дескриптор объекта-события, полученного от CreateEvent или OpenEvent. При успешном завершении возвращается TRUE, при ошибке ― FALSE. Код ошибки получают через GetLastError.Cброс событияСброс события (установка в неотмеченное состояние) выполняется функцией ResetEvent: Код (C): BOOL ResetEvent(HANDLE hEvent); Если задача создала событие, работающее в автоматическом режиме, оно будет сбрасываться без помощи ResetEvent, если какая-либо задача выполняла ожидание этого события и событие произошло.Функция PulseEventФункция PulseEvent выполняет установку объекта-события в signaled состояние с последующим сбросом события в nonsignaled состояние: Код (C): BOOL PulseEvent(HANDLE hEvent); Если эта функция вызвана для события, работающего в ручном режиме, то все задачи, ожидающие это событие, завершат ожидание и продолжат свою работу. Событие при этом будет установлено в nonsignaled состояние. Для автоматических объектов-событий выполняются аналогичные действия, но функция возвращает управление сразу как только одна из ожидающих задач перейдет в активное состояние. Текст приложения-сервера (08s.asm) Код (ASM): ; GUI # include win64a.inc ID_TXT equ 100 ID_SEND_TXT equ 101 ID_SEND_ICO equ 102 ID_SEND_WAV equ 103 IDC_DIALOG equ 200 IDC_ICON1 equ 500 IDC_IMG1 equ 104 EVENT_DATA_COUNT = 16 size_of_buffer = 96 time_interval = 10 EventPipeObjectStruct struct hEventDataHigh dq EVENT_DATA_COUNT dup(?) hEventDataLow dq EVENT_DATA_COUNT dup(?) hEventAck dq ? EventPipeObjectStruct ends .code WinMain proc enter 30h,0 mov r9d,256;cx mov [rbp-10h],r9 mov qword ptr [rbp-8],LR_DEFAULTCOLOR invoke LoadImage,IMAGE_BASE,IDC_ICON1,IMAGE_ICON;,256,256,LR_DEFAULTCOLOR mov r9d,offset DialogProc mov qword ptr[rbp-10h],rax;30h-10h=+20h invoke DialogBoxParam,IMAGE_BASE,IDC_DIALOG,HWND_DESKTOP invoke RtlExitUserProcess,NULL WinMain endp DialogProc proc hWnddlg:QWORD,uMsg:QWORD,wParam:QWORD,lParam:QWORD local hFile:qword local szEventName[32]:byte local szReadWrite:qword ;number of bytes actually read or write local hResource:qword local pResource:qword mov hWnddlg,rcx mov lParam,r9 cmp edx,WM_INITDIALOG je wmINITDIALOG cmp edx,WM_CLOSE je wmCLOSE cmp edx,WM_COMMAND je wmCOMMAND xor eax,eax jmp exit0 wmINITDIALOG:invoke GetDlgItem,,IDC_IMG1 invoke SendMessage,eax,STM_SETIMAGE,IMAGE_ICON,lParam xor edi,edi;for(DWORD i = 0; i < 16; i++) @@:; set current event name invoke sprintf,&szEventName,&Format1,edi ; create new object invoke CreateEvent,0,0,0,&szEventName mov EventPipeObject.hEventDataHigh[rdi*8],rax ; check for errors or eax,eax;if(EventPipeObject.hEventDataHigh[i] == NULL) jz wmBYE;exit0; ; create "low" data event handles ; set current event name invoke sprintf,&szEventName,&Format2,edi ; create new object invoke CreateEvent,0,0,0,&szEventName mov EventPipeObject.hEventDataLow[rdi*8],rax ; check for errors or eax,eax;if(EventPipeObject.hEventDataLow[i] == NULL) jz wmBYE;exit0 inc edi cmp edi,EVENT_DATA_COUNT jb @b ; create acknowledgement event ; create new object invoke CreateEvent,0,0,0,&Format3 mov EventPipeObject.hEventAck,rax jmp wmBYE wmSEND_TXT:invoke GlobalAlloc,GPTR,size_of_buffer mov p,rax invoke GetDlgItemText,hWnddlg,ID_TXT,eax,size_of_buffer or eax,eax jz wmBYE mov dwLength,eax mov edx,offset szWin invoke FindWindow,NULL or eax,eax jz wmBYE mov edx,WM_USER+