Обмен данными в Windows - Программирование, компьютеры и кибернетика лекция

Обмен данными в Windows - Программирование, компьютеры и кибернетика лекция



































Просмотр, запись и чтение данных буфера обмена. Динамический обмен данными (DDE), способы его организации. Атомы в Windows, их понятие и функции. Особенности задания параметра lParam сообщений DDE. Обмен и передача данных между клиентом и сервером.


посмотреть текст работы


скачать работу можно здесь


полная информация о работе


весь список подобных работ


Нужна помощь с учёбой? Наши эксперты готовы помочь!
Нажимая на кнопку, вы соглашаетесь с
политикой обработки персональных данных

Студенты, аспиранты, молодые ученые, использующие базу знаний в своей учебе и работе, будут вам очень благодарны.
как можно самим класть или читать данные из буфера обмена
как можно использовать буфер обмена со стандартным окном-редактором
как написать собственную программу просмотра содержимого буфера обмена.
Предварительно мы разберемся с некоторыми основными понятиями, связанными с применением буфера обмена.
Как мы уже сказали, Windows предполагает использование определенных форматов данных для передачи через буфер обмена. Конечно, у Вас есть возможность передавать данные в собственном формате, только для использования собственным приложением, однако рекомендуется придерживаться общепринятых стандартов, так как возможность передачи данных между самыми разнообразными приложениями является очень удобной.
Каждому применяемому формату данных буфера обмена в Windows поставлен в соответствие определенный номер. Windows определяет несколько стандартных форматов и предоставляет для них определенные символические имена:
CF_TEXT соответствует ASCIIZ тексту
CF_DIB битмап, независящий от устройства
CF_PALETTE палитра (обычно применяется вместе с CF_DIB )
При отображении данных этих форматов в программе просмотра буфера обмена не возникает никаких проблем, так как Windows содержит все необходимые средства для отображения этих данных. Однако Вы можете класть в буфер обмена данные в собственном формате. Если Вы хотите, что бы их отображала стандартная программа просмотра, то Вы должны их объявить как
CF_OWNERDISPLAY данные, отображаемые пользователем
В этом случае программа просмотра будет посылать специальные сообщения Вашему окну для отображения этих данных в окне.
Несколько дополнительных форматов, являясь обычными форматами данных, имеют отличные от них номера. В символических именах таких данных присутствует аббревиатура ` DSP'
CF_DSPTEXT соответствует ASCIIZ тексту
данные этих форматов отображаются в программе просмотра как данные соответствующих форматов, но обычно не используются другими приложениями, кроме Вашего.
Помимо рассмотренных, Windows дополнительно определяет большое количество других стандартных форматов данных, однако они используются сравнительно редко. В большинстве случаев это специфические форматы данных разных популярных программ, которые было решено включить в стандарт Windows.
При необходимости использования собственного формата данных для буфера обмена надо получить номер этого формата. Для того, что бы избежать возможных накладок, Вы должны зарегистрировать Ваш формат данных с помощью функции
UINT RegisterClipboardFormat( lpszFormatName );
для уже зарегистрированного формата Вы можете узнать его имя:
int GetClipboardFormatName( nFormat, lpsBuffer, nMaxCount );
Буфер обмена содержит не более одного блока данных каждого формата, причем все данные, находящиеся в буфере должны быть положены одним окном. Так как данные, передаваемые в буфер обмена, должны быть доступны всем приложениям, то для их передачи используются только блоки глобальной памяти.
если Вы положите какие-либо данные в буфер, то окно, указанное Вами, будет считаться владельцем всех данных буфера обмена.
3) Затем Вы можете осуществить необходимые операции обмена данными. Если Вы собираетесь положить данные в буфер обмена, то Вы должны предварительно удалить все уже находящиеся в нем данные:
и только затем положить нужные данные, воспользовавшись функцией:
HGLOBAL SetClipboardData( nFormat, hGlobal );
параметр nFormat задает имя формата данных, а hGlobal является хендлом глобального блока данных. Функция возвращает Вам новый хендл этого блока данных, с помощью которого Вы можете обращаться к этим данным до закрытия буфера обмена.
Вы можете положить в буфер обмена несколько блоков данных разного формата одновременно. Так как положенные в буфер данные сохраняются там либо до его очистки, либо до завершения работы Windows, то передавать большие блоки может быть слишком накладно.
Для этого случая в Windows предусмотрен механизм передачи данных с задержкой. Вызывая функцию SetClipboardData Вы указываете вместо хендла блока данных NULL . Это означает, что данные для буфер обмена у Вас есть, но передавать Вы их будете только по требованию. Для такой передачи Вам надо будет обрабатывать три сообщения:
сообщение требует данные для буфера обмена. При этом буфер уже открыт другим приложением, поэтому Вам открывать или закрывать его не надо. Вам надо просто вызвать функцию
SetClipboardData( nFormat, hGlobal );
передав ей хендл реального блока данных.
сообщение посылается Вашему окну когда оно уничтожается, а буфер обмена содержит задержанные данные Вашего окна. Вы должны обычным образом (то есть открыть-очистить-положить-закрыть) передать все данные в буфер обмена.
сообщение информирует Вас о том, что вызвана функция EmptyClipboard , когда буфер обмена содержит задержанные данные Вашего окна. Ваши данные больше не понадобятся, поэтому Вы можете освободить используемые структуры данных.
Если Вы собираетесь только читать данные из буфера обмена, то очищать его не надо, а получить данные нужного формата можно с помощью функции
HGLOBAL GetClipboardData( nFormat );
Функция возвращает хендл глобального блока памяти, который Вы должны скопировать к себе.
4) После завершения обмена с буфером обмена Вы должны закрыть его с помощью функции
На этом заканчиваются операции обмена данными с буфером обмена.
Кроме рассмотренных, Вы можете применять еще несколько функций, облегчающих работу с буфером обмена:
BOOL IsClipboardFormatAvailable( nFormat );
Эта функция сообщает, присутствуют-ли данные нужного формата в буфере обмена. Проверку на наличие тех или иных форматов данных можно выполнить и иным способом, с помощью функции
UINT EnumClipboardFormats( nFormat );
Эта функция перебирает присутствующие форматы данных в буфере обмена и возвращает номер следующего в списке или 0 . Пример применения:
while ( ( nFormat= EnumClipboardFormats( nFormat ) ) != 0 ) { // перебор форматов }
Можно узнать количество присутствующих в буфере обмена форматов данных с помощью функции
UINT CountClipboardFormats( void );
5) Сейчас мы рассмотрим правила применения форматов данных CF_DSP... Эти данные предназначены для использования только Вашим приложениями.
Основная идея заключается в том, что приложения, читающие, скажем, формат CF_TEXT , его и будут запрашивать у буфера обмена. При этом, даже если буфер обмена содержит данные в формате CF_DSPTEXT , он их не передаст - номера форматов разные, поэтому считается, что Вы можете передавать данные в формате CF_DSP... только для своего приложения, “спрятав” его от остальных.
Однако может случиться так, что одновременно два разных приложения попробуют использовать приватные данные в таком формате. Поэтому возникает необходимость научиться различать данные, положенные Вашим приложением, от данных, положенных чужим приложением. Для этого Вы можете воспользоваться функцией
которая вернет хендл окна, положившего данные. Если вы затрудняетесь по хендлу определить принадлежность окна к нужному приложению, то Вы почти наверняка знаете, к какому классу оно должно принадлежать (так как и данные, и приложение, и класс окон разработаны Вами). Поэтому Вы можете узнать еще и имя класса окна:
int GetClassName( hWnd, lpsBuffer, nMaxCount );
вставить текст из Clipboard в текущую позицию каретки
скопировать выделенный текст из редактора в Clipboard
скопировать выделенный текст и удалить его из редактора
Мы должны просто послать нужное сообщение редактору и он выполнит все остальное. Обратите внимание на то, что эти сообщения не являются специфичными для редактора - они имеют префикс WM_ - то есть это сообщения для обычного окна.
Если Ваше окно будет поддерживать работу с буфером обмена, то настоятельно рекомендуется поддерживать эти сообщения.
Для того, что бы разрешать или запрещать нужные пункты меню можно воспользоваться функцией IsClipboardFormatAvailable для разрешения/запрещения операции Paste и передачей сообщения EM_GETSEL для выяснения возможности операций Cut и Copy.
Однако одновременно может работать несколько программ (окон) просмотра. При этом возникает необходимость где-то удерживать список всех таких программ (окон) и посылать им всем соответствующие сообщения. Для этого организуется цепочка программ просмотра, которую они сами поддерживают в корректном состоянии.
В какой-то степени это похоже на обработку прерываний DOS - система удерживает хендл только первого окна просмотра, тот - хендл следующего и так далее.
Когда Вы запускаете свою программу просмотра, она регистрируется в качестве программы просмотра буфера обмена с помощью функции
при этом он становится на первое место в цепочке, а функция SetClipboardViewer возвращает хендл следующего за ним (или 0 , если других программ (окон) просмотра нет). Этот хендл должен быть сохранен.
Далее, при обновлении данных в буфере обмена, Ваше окно получает сообщение WM_DRAWCLIPBOARD . Обычная обработка этого сообщения:
case WM_DRAWCLIPBOARD: if ( hWndNextViewer ) PostMessage( hWndNextViewer, wMsg, wParam, lParam ); InvalidateRect( hWnd, NULL, TRUE ); return 0;
В результате обработки этого сообщения окно программы просмотра перерисовывается, и такое же сообщение получает другая программа.
Во время нормальной работы какая-либо из программ просмотра заканчивает функционирование прежде остальных. При этом цепочка программ просмотра изменяется. Для того, чтобы корректно изменить цепочку, применяется функция
BOOL ChangeClipboardChain( hWndViewer, hWndNextViewer );
Что значит: вместо окна hWndViewer будет использоваться окно hWndNextViewer . Эта функция обычно вызывается при обработке сообщения WM_DESTROY . В результате выполнения этой функции первая программа просмотра в цепочке получит сообщение ( WM_CHANGECBCHAIN, hWndRemoved, hWndNext ). Это сообщение обрабатывается так:
case WM_CHANGECBCHAIN: if ( wParam == hWndNextViewer ) { hWndNextViewer= LOWORD( lParam ); } else if ( hWndNextViewer ) { PostMessage( hWndNextViewer, wMsg, wParam, lParam ); } return 0;
В результате такой обработки, если наше окно стоит в цепочке до удаляемого, но не прямо перед ним, оно передаст сообщение дальше; если оно стоит прямо перед удаляемым, то оно исправит свой хендл следующего окна просмотра и не пустит сообщение дальше, так как цепочка уже исправлена.
Отображение данных программой просмотра происходит также, как и их обычное чтение (открыл-прочитал-закрыл).
клиент передает всем доступным приложениям сообщение о том, что ему надо.
если в системе находится подходящий сервер, он отвечает клиенту о возможности обслуживания.
клиент посылает запрос(ы) серверу для выполнения требований.
в некоторых случаях сервер может информировать клиента об изменении или наличии тех или иных данных. Для этого клиент должен подписаться (advise) на необходимые данные.
обмен между клиентом и сервером может продолжаться до тех пор, пока один из них не потребует прекращения.
В процессе DDE-разговора происходит обмен сообщениями между двумя приложениями. Понятно, что адресатами таких сообщений являются не сами приложения, а их окна. В большинстве случаев для нормального ведения DDE-разговора создаются специальные скрытые (невидимые) окна, которые и осуществляют обмен сообщениями между собой. Конечно, в DDE могут участвовать окна одного приложения, не только разных, но надо учесть, что DDE для обмена данными в пределах одного приложения является неэффективным. Так как процессы подготовки и приема данных могут занимать значительное время, то требуется, чтобы для обмена сообщениями использовалась функция PostMessage , а не SendMessage (кроме установления DDE-разговора). Это, правда, создает дополнительную сложность -- необходимость синхронизации действий разных окон между собой.
В Windows содержится все необходимое для организации DDE, причем в двух экземплярах. Помимо старого способа, существующего с первых версий Windows, в Windows версии 3.1 была добавлена специальная библиотека DDEML (DDE Management Library), являющаяся “надстройкой” над старым способом и предназначенная для формализации протоколов обмена. Существенная разница между этими способами связана с тем, что для организации DDE старым способом вы должны предусмотреть обработку специальных сообщений необходимыми Вам окнами, а библиотека DDEML сама создает необходимые скрытые окна и организует обмен сообщениями; при этом для взаимодействия с Вашим приложением DDEML будет вызывать специально разработанную Вами CALLBACK процедуру (не являющую оконной процедурой).
Считается, что при использовании DDEML несколько упрощается написание приложений, так как она берет на себя вопросы синхронизации обмена. Однако на практике не было замечено реального упрощения работы в связи с применением библиотеки. Более того, исходный текст может оказаться даже больше, чем при использовании старого метода.
Поэтому мы будем рассматривать только старый способ организации DDE. Предварительно мы введем несколько терминов, используемых в DDE. Когда клиент начинает DDE или требует данные, он посылает серверу спецификацию того, что он требует.
Эта спецификация состоит из 3 пунктов:
имя приложения -- application (в DDEML называется сервис (service)); так как в большинстве случаев в документации применяется термин service, то его мы и будем использовать дальше. Хотя, надо отметить, этот параметр обычно задает условное имя приложения-сервера.
Имя сервиса и тема DDE-разговора используютсяпри установлении связи. В результате этого в системе должно быть установлен обмен данными между одной или несколькими парами окон, которые поддерживают данные сервис и тему. Одно из окон в каждой паре будет являться клиентом, а другое -- сервером. В процессе дальнейшего DDE-разговора может происходить обмен данными, имя которых задается отдельно и является возможным именем данных для данного сервиса и темы.
Эти три имени представлены в виде атомов (ATOM), поэтому нам надо разобраться с атомами и правилами их применения перед продолжением разговора о DDE.
ATOM GlobalAddAtom( lpszName ); UINT GlobalGetAtomName( aAtom, lpsBuffer, nMaxCount ); ATOM GlobalFindAtom( lpszName ); ATOM GlobalDeleteAtom( aAtom );
С помощью этих функций можно добавить атомы, узнать имя конкретного атома, найти нужный атом в таблице и удалить атом. Причем, сколько раз добавлялся атом с одним именем, столько раз он должен быть удален, что бы он действительно был удален из таблицы.
Для работы с локальными атомами используются аналогичные функции, но не имеющие в начале слова “ Global ”. Помимо этого для работы с локальной таблицей атомов добавлена еще одна функция:
ATOM AddAtom( lpszName ); UINT GetAtomName( aAtom, lpsBuffer, nMaxCount ); ATOM FindAtom( lpszName ); ATOM DeleteAtom( aAtom );
BOOL InitAtomTable( UINT cTableEntries );
Которая позволяет указать максимальное число строк, помещаемых в локальную таблицу атомов. По умолчанию это число равно 37 (размер глобальной таблицы атомов изменить нельзя). При работе с локальной таблицей атомов удалять атомы в конце работы приложения необязательно -- при завершении работы всего приложения таблица будет автоматически удалена.
При обмене данными посредством DDE происходит последовательная посылка сообщений от одного приложения к другому и наоборот. Одна DDE транзакция обычно состоит из двух -- трех последовательных сообщений. В этих сообщениях часто передаются необходимые имена, представленные в виде глобальных атомов. При этом возникает необходимость так организовать обмен сообщениями, что бы обеспечить удаление всех вновь добавляемых атомов. Для этого принято такое решение: приложение, посылающее атомы вместе с сообщение должно эти атомы создать, а затем проверить код завершения функции PostMessage -- если посылка прошла успешно, то атом должен быть освобожден принимающим приложением, а если при посылке возникла ошибка, то атом должно удалить посылющее приложение. В некоторых случаях атом, полученный приложением с сообщением, может быть послан вместе с ответным сообщением назад (кроме сообщения WM_DDE_INITIATE , о чем см. ниже). В этом случае не обязательно атом удалять а потом создавать снова, можно использовать полученный; однако необходимо убедиться, что он был послан с ответным сообщением и, если посылка не состоялась, его надо удалить.
LONG PackDDElParam( UINT uMsg, UINT uLow, UINT uHigh ); LONG UnpackDDElParam( UINT uMsg, LONG lParam, PUINT puLow, PUINT puHigh ); LONG FreeDDElParam( UINT uMsg, LONG lParam ); LONG ReuseDDElParam( LONG lParam, UINT uMsgIn, UINT uMsgOut, UINT uLow, UINT uHigh );
Функция PackDDElParam упаковывает указанные данные в промежуточную структуру, хендл которой возвращается в виде LONG ; возвращаемое значение может быть использовано только для передачи данных с помощью функции PostMessage и только для некоторых сообщений DDE. Функция UnpackDDElParam выполняет обратную операцию, но промежуточная структура данных при этом сохраняется. Для того, что бы ее удалить необходимо использовать FreeDDElParam . Последняя функция ReuseDDElParam может применяться для использования одной структуры при повторной передаче данных или ответе на принятое сообщение. В качестве параметра lParam функции PostMessage необходимо указывать возвращаемое, а не первоначальное значение.
В описании параметров сообщений мы сохраняем прежний синтаксис, причем lParam может по-прежнему задаваться в виде двух компонент старший & младший. Единственное отличие, что под старшим и младшим компонентом не надо подразумевать слова, а для получения этих компонентом может потребоваться функция UnpackDDElParam , о чем в описании сообщения будет сделана специальная оговорка. В редких случаях могут даваться два описания параметров, для Windows 3.x и для Win32. Для различия этих вариантов в описании параметров сообщения могут быть добавлены специальные пояснения
(Packed Win32) -- если параметр упаковывается в случае платформы Win32
(Windows 3.x) -- если описание применяется только в случае Windows 3.x
(Win32) -- если описание применяется только в случае Win32
WM_DDE_INITIATE hWnd aTopic & aService
это сообщение используется для начала DDE-разговора. Параметр wParam содержит хендл пославшего окна, а lParam в младшем слове -- атом aService , а в старшем -- атом aTopic , задающие, соответственно, сервис и тему DDE-разговора. Нулевые значения атомов указывают соответственно на любую поддерживаемую тему и любой сервис. Передача: Когда клиент вызывает функцию SendMessage для установления DDE-разговора, он создает необходимые атомы, а после возврата из функции SendMessage он обязан эти атомы удалить. Получение: сервер, получивший это сообщение, и поддерживающий указанные сервис и тему отвечает сообщением WM_DDE_ACK . При этом он обязан создать заново требуемые атомы -- использовать атомы, полученные с сообщением запрещено. Значения атомов aTopic и aService равные 0 указывают, соответственно, на любую поддерживаемую сервером тему и сервис. В этом случае сервер должен ответить столько раз, сколько подходящих тем и сервисов он поддерживает.
Это сообщение передается всем приложениям (в качестве хендла окна-получателя сообщения используется HWND_BROADCAST или -1). Тот сервер, который поддерживает данную тему и сервис должен ответить на этот запрос передачей сообщения
сообщение, подтверждающее принятое прежде сообщение. Параметр wParam содержит хендл пославшего окна, а lParam используется разными способами, в зависимости от того, какое сообщение вызвало это подтверждение. В зависимости от значений параметров сообщения рассматривают положительные и отрицательные подтверждения. При ответе на WM_DDE_INITIATE младшее слово lParam содержит атом сервиса, а старшее -- атом темы, при этом WM_DDE_ACK не посылается, а передается с помощью функции SendMessage , причем оно рассматривается только как положительное, так как в качестве отрицательного ответа используется отсутствие этого сообщения. Если WM_DDE_ACK получено в ответ на WM_DDE_INITIATE , то для обоих платформ -- Windows 3.x и Win32 оно используется одинаково; а если оно получено в ответ на какое-либо иное сообщение, то параметр lParam будет использован для передачи “упакованного” значения. Получение: приложение-клиент, получившее сообщение WM_DDE_ACK обязано удалить все сопровождающие его атомы. Передача: при ответе на WM_DDE_INITIATE запрещено использовать полученные атомы, сервер обязан создать необходимые для ответа атомы и послать их (так как на одно WM_DDE_INITIATE может ответить несколько серверов, а при обработке WM_DDE_ACK клиент обязан удалять все атомы).
Если WM_DDE_ACK передается в ответ на сообщение WM_DDE_INITIATE , то в lParam содержатся такие-же данные, что и у сообщения WM_DDE_INITIATE . Это считается положительным подтверждением. Если ответ отрицательный, то подтверждение при инициализации просто не выдается.
В большинстве случаев сервер, отвечающий на WM_DDE_INITIATE , создает специальное окно для каждого DDE-разговора. Это связано с тем, что при дальнейшем обмене данными сервис и тема указываться не будут, а сам DDE-разговор определяется фактически окном-клиентом и окном-сервером. Одна такая пара окон обменивается данными только в рамках указанных при установлении DDE-разговора темы и сервиса. Только самые простые DDE-серверы могут обходиться одним окном, но при этом они в данный момент времени могут работать только с одним клиентом.
Внимание! При установлении связи с каким-либо сервером Вы можете получить несколько сообщений WM_DDE_ACK от разных серверов, поддерживающих указанные сервис и тему. Если в сообщении WM_DDE_INITIATE вы указали любую поддерживаемую тему и/или любой возможный сервис, то практически всегда отвечают сразу несколько серверов. В этом случае Вы должны создавать список всех тем и сервисов, с которыми устанавливается связь данной операцией (не забудьте в конце закрыть все начатые DDE-разговоры), а если вы собираетесь работать только с одним из ответивших серверов, то со всеми остальными вы должны завершить DDE-разговор посылкой WM_DDE_TERMINATE .
Замечание. Согласно документации сервер, получивший WM_DDE_INITIATE с указанием любой поддерживаемой темы или сервиса, обязан отправить в ответ столько сообщений WM_DDE_ACK , сколько тем и сервисов он поддерживает. На самом деле многие DDE серверы этого не делают, как, например, Microsoft Internet Explorer. Такие серверы отвечают только на точно указанные сервис и тему. Это может быть оправдано, если сервер поддерживает значительное число тем или сервисов. При ответе на WM_DDE_INITIATE уже устанавливаетя DDE-разговор, для которого сервер создает отдельное окно и, соответственно, расходует ресурсы. Если сервер отвечает на целый список тем и/или сервисов, то создается много окон, что, скорее всего, излишне. Строго говоря, указывать любую тему или сервис надо только в случае реальной необходимости, так как одним таким запросом могут быть установлены несколько десятков DDE-разговоров сразу (так, например, один только Netscape Navigator отвечает примерно 3 десятками поддерживаемых им тем).
Начало DDE-разговора - это единственный случай, когда сообщения DDE передаются с помощью SendMessage , а не PostMessage . Это необходимо для нормального начала обмена.
Сейчас мы рассмотрим небольшой пример взаимодействия двух приложений, клиента и сервера при начале DDE-разговора.
В данном примере рассмотрен самый простой случай, когда связь устанавливается только с одним сервером и для одной темы. При этом можно обойтись без создания списка сервисов и тем, с которыми устанавливаются соединения.
Считается, что при инициализации DDE-разговора, клиент должен получить ответ (или убедится в его отсутствии) немедленно. Этого можно достичь только используя передачу, а не посылку сообщений. В этом случае подтверждение приходит в то время, пока клиент ожидает завершения работы процедуры SendMessage . Для нормального продолжения DDE клиент должен запомнить хендл сервера (а сервер - хендл клиента).
Так как возможен случай, что на запрос клиента ответят два и более серверов, то надо предусмотреть либо отказ от установления более чем одного соединения (как в приведенном примере), либо организовать DDE сразу с несколькими серверами.
Если клиент получил положительный ответ от сервера, то он может начать обмен данными. Этот обмен будет продолжаться до тех пор, пока оба приложения не обменяются сообщениями
сообщение оканчивает DDE-разговор. Параметр hWnd является хендлом пославшего окна. При этом уничтожаются вспомогательные структуры и обнуляются переменные.
Послать WM_DDE_TERMINATE может как клиент, так и сервер. Оба они должны быть готовы к приему такого сообщения от напарника.
обмен данными происходит только по запросу клиента. Сервер посылает в ответ данные или отрицательное подтверждение.
клиент “подписывается” на периодическое получение данных от сервера, после чего сервер начинает передавать данные клиенту, как только в этом возникает необходимость. Для завершения горячей связи клиент должен сообщить об этом серверу.
клиент, как и при горячей связи, подписывается на получение обновленных данных. Однако сервер передает не данные, а только сообщения о том, что у него есть данные для клиента. Клиент может затребовать данные у сервера в любой удобный для него момент.
Последние два вида связи (теплая и горячая) называются иногда постоянной (permanent) связью.
Передача данных от клиента к серверу осуществляется только одним способом, по инициативе клиента, который передает серверу соответствующее сообщение, содержащее посылаемые данные.
Когда два приложения обмениваются данными друг с другом, они передают друг другу хендлы блоков данных и атомы. Для того, что бы эти данные были доступны обоим приложениям, они должны быть глобальными. Однако надо учесть, что обычно глобальные блоки данных связаны с тем приложением, которое их создало, то есть при завершении приложения эти данные автоматически уничтожаются. Так как процесс DDE-разговора является асинхронным, то необходимо обеспечивать сохранность данных независимо от существования создавшего их приложения. Для этого глобальные блоки данных должны быть разделяемыми -- при их выделении надо указывать флаг GMEM_DDESHARE (или GMEM_SHARE , который является синонимом).
В случае платформы Win32 используются прежние функции для выделения глобальных блоков данных, несмотря на то, что блоки выделяются только в локальном для каждого процесса виртуальном адресном пространстве. Система автоматически осуществляет передачу данных из адресного пространства одного процесса в адресное пространство другого процесса при передаще соответствующих сообщений.
Особое внимание надо уделить вопросу освобождения ресурсов, так как атомы и передаваемые блоки данных сами не уничтожаются, даже если все участвующие в DDE приложения завершили работу. Все созданные объекты должны быть обязательно уничтожены, независимо от исхода операции. Сложности связаны с тем, что один и тот-же объект может быть уничтожен либо клиентом, либо сервером, в зависимости от протекания процесса обмена, а, кроме того, в процессе обмена могут присходить различные ошибки (например, функция PostMessage не может послать сообщение).
WM_DDE_REQUEST hWnd aItem & cfFormat
это сообщение является требованием передачи данных. Параметр wParam является хендлом пославшего сообщение окна, а lParam содержит в младшем слове номер формата данных (номера те-же, что используются буфером обмена), а в старшем - атом имени данных. Платформы Win32 и Windows 3.x используют это сообщение одинаково.
В ответ на это сообщение сервер может ответить либо сообщением WM_DDE_DATA , если он имеет необходимые данные и может их послать, либо “отрицательным” сообщением WM_DDE_ACK , указывающим, что сервер не может послать требуемые данные.
WM_DDE_DATA hWnd aItem & hData (Packed Win32)
Это сообщение передает данные клиенту. Младший компонент lParam содержит хендл глобального разделяемого блока данных hData . Этот параметр может быть равен 0 , что реально встречается только в случае “теплой” связи (см. ниже). Передаваемый блок данных должен начинаться со структуры DDEDATA , флаг fAckReq которой указывает на необходимость отправки подтверждения о получении данных. Передача: сервер не может сбрасывать одновременно оба бита fRelease и fAckReq в 0 . То есть корректными являются только три возможных комбинации fRelease и fAckReq , при которых можно определить, кто должен освобождать блок данных -- клиент или сервер. Освобождение ресурсов: атом aItem должен удаляться, если только он не посылается с ответным сообщением WM_DDE_ACK (если бит fAckReq заголовка данных равен 1 , то есть требуется ответ). Освобождение блока данных зависит от установки битов fRelease и fAckReq заголовка данных:
блок данных всегда освобождается сервером при получении ответа от клиента (считается, что к моменту получения сервером подтверждения клиент уже прочитал требуемые данные и они ему больше не нужны).
блок данных всегда освобождается клиентом, сервер ответа не получает (так клиент может некоторое время сохранять полученные данные независимо от течения DDE-разговора).
при успешном чтении блок данных освобождается клиентом, а в случае ошибки (то есть при получении сервером отрицательного подтверждения) блок освобождается сервером. Этот вариант близок к предыдущему, за исключением того, что за ошибочно полученный блок клиент ответственности не несет.
Структура DDEDATA содержит следующие данные:
typedef struct tagDDEDATA { WORD unused:12, fResponse:1, // 1 в ответ на WM_DDE_REQUEST, 0 -- WM_DDE_ADVISE fRelease:1, // данные должны быть удалены после получения reserved:1, fAckReq:1; // 1 -- необходимо послать подтверждение о приеме short cfFormat; // формат данных BYTE Value[1]; // сами данные } DDEDATA;
Внимание! в документации по Windows 3.x SDK и Win32 SDK содержалась ошибка -- там были перепутаны пояснения к полям fResponse и fAckReq , так что описание структуры DDEDATA противоречило описанию сообщения WM_DDE_DATA . В документации, сопровождающей компилятор Microsoft Visual C++ v4.0 эта ошибка была исправлена.
Заметьте, что сервер может потребовать подтверждения о приеме посланных данных. Для этого он устанавливает бит fAckReq в заголовке переданных данных равным
Обмен данными в Windows лекция. Программирование, компьютеры и кибернетика.
Реферат: Компоненты, границы и морфологическая структура ландшафтов
Реферат: по устойчиво развитие „генно модифицирани организми”
Сочинение Карамзин Бедная Лиза Образ Лизы
Выпускное Сочинение Чем Опасно Бессмысленное Существование
Дипломная работа по теме Проектирование технологического потока для изготовления блузки женской из поплина
Курсовая работа по теме Квалиметрическая оценка качества пищевых продуктов (печенье овсяное)
Курсовая работа по теме Учет прибыли предприятия
Входная Контрольная Работа 9 Класс
Реферат: Анализ финансово-экономической деятельности предприятия на примере ООО Соло
Реферат: Психічний розвиток особистості
Реферат: Мембрана клетки
Сочинение Про Школу На Английском 8 Класс
Дипломная Работа Управление Персоналом В Условиях Инноваций
Пришвин Собрание Сочинений Купить
Язык Как Базовый Код Коммуникации Реферат
Сочинение по теме Второй Чадаев, мой Евгений… Евгений Онегин
Дипломная работа по теме Пейзаж в технике живопись
Структура Социологического Знания Реферат 7 Листов
Реферат по теме Время в культуре
Реферат: Who Was To Blame For Macbeths Downfall
Русские народные промыслы - Культура и искусство реферат
Діяльність органів виконавчої влади, функція прийняття рішень - Государство и право магистерская работа
Творчество учителя как активный элемент художественного образования (на занятиях керамикой в системе дополнительного образования) - Педагогика дипломная работа


Report Page