Распечатать страницу

Динамический обмен данными в Visual FoxPro

« Назад

Динамический обмена данными (Dynamic Data Exchange – DDE) осуществляется между клиентом и сервером. В качестве клиента выступает VFP, а в качестве сервера – иное Windows-приложение. Клиент может передавать серверу данные и команды и получать от сервера запрашиваемую информацию.

Сеанс связи начинается с установления канала. После выполнения DDE-обмена канал следует закрыть.

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

Функции, осуществляющие настройку канала связи и обеспечивающие обмен данными, приведены в табл. 17.1.

Таблица 17.1

Список DDE-функций

Функция

Описание

DDEAbortTrans( )

Завершает асинхронную DDE-транзакцию

DDEAdvise( )

Устанавливает вид связи DDE-канала: с уведомлением, без него или автоматическая связь

DDEEnabled( )

Изменяет или возвращает статус (активный или не активный) DDE-процесса

DDEExecute( )

Посылает серверу команду клиента по DDE-каналу

DDEInitiate( )

Устанавливает DDE-канал связи для динамического обмена данными между клиентом и сервером

DDELastError( )

Возвращает номер ошибки последней выполненной DDE-функции

DDEPoke( )

Посылает данные клиента серверу по DDE-каналу

DDERequest( )

Запрашивает данные сервера

DDESetOption( )

Изменяет или возвращает настройки DDE

DDESetService( )

Создает, освобождает или изменяет службы и установки DDE, когда в качестве сервера выступает VFP

DDESetTopic( )

Создает, освобождает или изменяет тему заданной DDE-службы

DDETerminate( )

Закрывает DDE-канал, установленный DDEInitiate( )

Функция

DDEInitiate(cServiceName, cTopicName)

устанавливает канал связи (DDE-канал) для динамического обмена данными  между VFP и другим Windows-приложением (DDE-сервером).

Возвращает номер канала. Функция вернет –1, если канал не может быть установлен. Природу ошибки определяет функция DDELastError( )

Параметры:

cServiceName – служебное имя сервера (служба), которое в большинстве случаев является именем исполняемого файла без расширения. Список некоторых служб приведен в табл. 17.2.

Таблица 17.2

Служебные имена DDE-серверов

Служба

Приложение

"Excel"

Microsoft Excel

"FoxPro"

Visual FoxPro

"MSAccess"

Microsoft Access

"Project"

Microsoft Project

"WinWord"

Microsoft Word

cTopicName – имя темы (предмета связи). Имя темы должно быть известно приложению. Большинство DDE-серверов предоставляют тему с именем "System".

Служба и предоставляемые ей темы приводятся в документации, прилагаемой к приложению.

После установления канала обмена данными с DDE-сервером VFP, выступая как клиент, может запрашивать данные сервера посредством соответствующих функций.

Приложение, с которым устанавливается DDE-канал, должно быть открыто. Программно это можно выполнить, потребив команду RUN или !, например:

Run /n C:\Program Files\Microsoft Office\Office10\Excel

Если оно закрыто, то VFP осведомится, нужно ли открыть приложение, и при положительном ответе попытается это сделать.

Пример. Устанавливается DDE-канал между VFP и Microsoft Excel. Используется тема System.

Run /n C:\Program Files\Microsoft Office\Office10\Excel

nChannelNumber = DDEInitiate('Excel', 'System')

if nChannelNumber != –1 then

&& Выполняются операции клиента

&& …

&& После их завершения канал закрывается

DDETerminate(nChannelNumber)

endif

Функция

DDETerminate(nChannelNumber | cServiceName)

закрывает DDE-канал, установленный DDEInitiate( ).

Возвращает .T., если канал удалось закрыть, или .F. – в противном случае.

Параметры:

nChannelNumber – номер закрываемого канала.

cServiceName – служба DDE-сервера.

Каналы после завершения обмена данными следует закрывать, экономя системные ресурсы. Все открытые каналы автоматически закрываются при завершении работы с VFP.

Функция

DDEAdvise(nChannelNumber, cItemName, cUDFName, nLinkType)

устанавливает вид связи DDE-канала nChannelNumber: с уведомлением, без него или автоматическая связь.

Возвращает .T., если вид связи установлен, или .F. – в противном случае.

Параметры:

cItemName – имя элемента. Например, имя "R1C1" при работе с Microsoft Excel означает ячейку в первом столбце и первой строке рабочего листа.

cUDFName – строка, содержащая имя пользовательской процедуры, которая выполняется, если установлена связь с уведомлением или автоматическая, при изменении элемента cItemName.

Когда процедура выполняется, она получает 6 описанных в табл. 17.3 параметров; та же таблица отображает и порядок их следования.

Таблица 17.3

Параметры, передаваемые процедуры, заданной cUDFName

Параметр

Описание

nChannelNumber

Номер DDE-канала

Action

Действие: ADVISE или TERMINATE.

Item

Имя элемента, например "R1C1" для ячейки листа Microsoft Excel

Data

Новые данные, если автоматическая связь, или пустая строка, если связь с уведомлением

Format

Формат данных, например CF_TEXT

AdviseStatus

Тип связи (0, 1 или 2)

Пользовательская процедура должна иметь 6 параметров.

В случае связи с уведомлением новые данные должны быть получены DDERequest( ); при автоматической связи они содержатся в параметре Data.

Параметр Action равен 'ADVISE', когда связь обновляется сервером, и содержит 'TERMINATE', когда связь прерывается клиентом или сервером.

nLinkType – тип связи; принимает следующие значения:

0 – связь без уведомления;

1 – связь с уведомлением;

2 – автоматическая связь.

Если для nLinkType указан 0, то при изменении элемента пользовательская процедура, заданная параметром cUDFName, не выполняется.

Разница между видами связи 1 и 2 в том, что в первом случае для Data возвращается пустая строка, а во втором – строка с новыми данными. В обоих случаях при изменении элемента cItemName пользовательская процедура выполняется.

Пример (приводится в справке VFP). Устанавливается связь с двумя ячейками листа Microsoft Excel. Вид связи с ячейкой 'R1C1' – 1, в ячейкой 'R1C2' – 2. При обновлении данных в ячейках выполняется пользовательская процедура GetAdvise( ). Полученные от Microsoft Excel данные отображаются в окне VFP.

Run /n C:\Program Files\Microsoft Office\Office10\Excel

nChannelNumber = DDEInitiate('Excel', 'Лист1')

if nChannelNumber != –1 then

DDEAdvise(nChannelNumber, 'R1C1', "GetAdvise", 1)

DDEAdvise(nChannelNumber, 'R1C2', "GetAdvise", 2)

wait window 'Введите данные в первые две ячейки строки 1 Microsoft Excel'

endif 

procedure GetAdvise

parameters nChannelNumber, action, item, data, format, advise

if action = 'ADVISE' then

do case

case item = 'R1C1'

&& Связь с уведомлением; для получения данных выполняем DDERequest( )

newValue = DDERequest(nChannelNumber, item)

? 'R1C1 – связь с уведомлением: ' + newValue

case item = 'R1C2'

&& Автоматическая связь

newValue = data

? 'R1C2 - автоматическая связь: ' + newValue

endCase

else

DDETerminate(nChannelNumber)

endif

endProc

Замечание. В нерусифицированном Microsoft Excel в DDEInitiate( ) вместо  'Лист1' следует употребить 'Sheet1'.

Функция

DDEEnabled([lExpression1 | nChannelNumber [, lExpression2]])

изменяет или возвращает статус (активный или не активный) DDE-процесса.

Возвращает при выполнении без параметров .T., если DDE-процесс глобально активен, или .F. – в противном случае.

Параметры:

lExpression1 – задает глобально (для всех DDE-каналов) статус DDE-процесса; .T. – активный; .F. – не активный. Возвращает .T. при удачном завершении или .F. – в противном случае.

nChannelNumber – номер DDE-канала. Возвращает .T., если DDE-процесс для указанного канала активен, или .F. – в противном случае.

lExpression2 – задает статус DDE-процесса для канала nChannelNumber.

Когда DDE-процесс неактивен, то запросы клиента становятся в очередь до тех пор, пока процесс не будет активизирован.

Функция

DDESetService(cServiceName, cOption [, cDataFormat | lExpression])

создает, освобождает или изменяет службы и установки DDE, когда в качестве сервера выступает VFP.

Результат имеет логический тип. Функция, если действие выполнено, возвращает .T., или F. – в противном случае.

Параметры:

cServiceName – служба, которая создается, освобождается или изменяется или информация о которой возвращается. Имя службы VFP по умолчанию – "FoxPro".

cOption – строка, задающая выполняемое функцией DDESetService( ) действие. Принимает приведенные в табл. 17.4 значения.

Таблица 17.4

Значения параметра cOption

cOption

Значение по умолчанию

Описание

"DEFINE"

Создает новую службу, например:

glNewService = DDESetService('myService', 'DEFINE')

"RELEASE"

Освобождает существующее службу; все связанные с ней темы также освобождаются, например:

glRelease = DDESetService('myService', 'RELEASE')
glRelFox = DDESetService('FoxPro', 'RELEASE')

"ADVISE"

.F.

Активизирует или отменяет уведомление клиента об изменении элементов сервера. В первом случае действуют установки DDEAdvise( )

"EXECUTE"

.F.

Активизирует  или отменяет  выполнение команд, передаваемых серверу, например:

glExecute = DDESetService('myService', 'EXECUTE', .T.)

"POKE"

.F.

Активизирует или отменяет передачу данных серверу от клиента

"REQUEST"

.T.

Активизирует или отменяет запросы серверу, например:

glRequest = DDESetService('myService', 'REQUEST', .F.)

"FORMATS"

CF_TEXT

Задает формат данных

Замечание. Активизация установки выполняется, если lExpression = .T., а отмена, – если lExpression = . F.; Если параметр lExpression опущен, то выводится текущее значение установки ADVISE, EXECUTE, POKE или REQUEST, например:

? DDESetService('myService', 'EXECUTE')

cDataFormat – формат данных, поддерживаемый сервером. Форматы, если их в строке cDataFormat несколько, разделяются запятыми, например:

DDESetService('myService', 'FORMATS', 'CF_TEXT, CF_SYLK')

Если cDataFormat опущен, то поддерживается только формат CF_TEXT.

lExpression – задает статус установки ADVISE, EXECUTE, POKE или REQUEST.

Служба VFP имеет одну тему – System. Ею поддерживаются следующие элементы:

Topics        - список доступных тем;

Formats – список поддерживаемых форматов;

Status – статус: "Занят" или "Готов".

SysItems – список имен элементов.

Функция

DDESetTopic(cServiceName, cTopicName [, cUDFName])

создает, освобождает или изменяет тему заданной DDE-службы.

Результат имеет логический тип. Функция, если действие выполнено, возвращает .T., или F. – в противном случае.

Параметры:

cServiceName – служба, которая создается, освобождается или изменяется или информация о которой возвращается.

cTopicName – создаваемая или освобождаемая тема. Если параметр cUDFName имеется, то тема создается, и освобождается – в противном случае. Если cTopicName – это пустая строка, то функция, заданная параметром cUDFName, выполняется для каждой темы, не имеющей явно указанной cUDFName-функции.

cUDFName – строка, содержащая имя пользовательской функции, выполняемой, когда приложение клиента запрашивает тему. Если параметр опущен, то тема cTopicName освобождается.

Функция, задаваемая cUDFName, должна содержать описанные в табл. 17.3 параметры.

Значения параметров Item, Data и AdviseStatus зависят от значения параметра Action (табл. 17.5).

Таблица 17.5

Параметр Action и соответствующие значения
параметров Item, Data и AdviseStatus

Action

Item

Data

AdviseStatus

"INITIATE"

Пустая строка

Имя темы

Пустая строка

"TERMINATE"

"

Пустая строка

"

"POKE"

Имя элемента

Новые данные

"

"REQUEST"

"

Пустая строка

"

"EXECUTE"

Пустая строка

Новая команда

"

"ADVISE"

Имя элемента

Пустая строка

Тип соединения

Если пользовательская cUDFName-функция успешно обрабатывает запрос клиента, то она должна возвращать .T., или .F. – в противном случае. Если функция возвращает .F., если Action это:

INITIATE, то тема отвергается;

POKE, REQUEST или EXECUTE, то запрос игнорируется;

ADVISE, то связь с уведомлением или автоматическая связь не выполняется.

После создания темы каждый запрос клиента к теме приводит к выполнению cUDFName-функции. Результат функции (.T. или .F.) передается клиенту посредством DDEPoke( ). Причину неудачи вернет функция DDELastError( ).

Пример (приводится в справке VFP). В качестве сервера употребляется VFP. Создается служба myService и тема DO, через которую клиент связывается со службой. В частности, в примере клиент передает следующую команду:

wait window "Команда выполнена"

При выполнении команды клиента используется макроподстановка.

&& VFP используется и как DDE-сервер и как DDE-клиент

&& Определяем новую службу и ее установки

DDESetService('myService', 'DEFINE')

DDESetService('myService', 'EXECUTE', .T.)

DDESetTopic('myService', 'DO', 'DOTopic')

&& Устанавливаем DDE-канал

gnChannel = DDEInitiate('myService', 'DO')

DDEExecute(gnChannel, 'wait window "Команда выполнена"')

DDETerminate(gnChannel) 

function DOTopic

parameters gnChannel, gcAction, gcItem, gData, gcFormat, gnAdvise

glResult = .F.

&& Необходимо вернуть .T., когда Action – это 'INITIATE';

&& в противном случае DDE-канал не будет установлен

do case

case gcAction = 'INITIATE'

glResult = .T.

case gcAction = 'EXECUTE'

&gData                               && Применяем макроподстановку

glResult = .T.

case gcAction = 'TERMINATE'

wait window 'Сеанс завершен' nowait

glResult = .T.

endcase

return glResult

endFunc

После выполнения этой программы будет установлена DDE-служба VFP, которая доступна другим приложениям.

Функция

DDESetOption(cOption [, nTimeoutValue | lExpression])

изменяет или возвращает настройки DDE.

Возвращает текущее значение TIMEOUT или SAFETY.

Параметры:

cOption – задает вид настройки. Принимает приведенные в табл. 17.6 значения.

Таблица 17.6

Значения параметра cOption

cOption

Параметр

Описание

"TIMEOUT"

nTimeoutValue

Число миллисекунд, в течение которых DDE-функции ожидают ответ сервера; значение по умолчанию – 2000

"SAFETY"

lExpression

Если приложение-сервер не отвечает, то при выполнении DDEInitiate( ) диалог с вопросом, нужно ли установлении DDE-канал, будет появляться, когда настройка SAFETY – это .T. (по умолчанию), и не будет – в противном случае

nTimeoutValue – значение настройки TIMEOUT.

lExpression – значение настройки SAFETY.

Функция

DDEExecute(nChannelNumber, cCommand [, cUDFName])

посылает серверу команду клиента по DDE-каналу nChannelNumber.

Функция, если опущен параметр cUDFName, возвращает .T., если сервер успешно выполнил команду, или .F. – в противном случае. Причиной неудачи может также быть и неверное указание канала. Если параметр cUDFName задан, то возвращается номер транзакции (нуль или положительное число), а в случае ошибки – число –1.

Параметры:

cCommand – строка, содержащая команду, посылаемую другому приложению. Формат команды определяется приложением, ее получающим.

cUDFName – строка, задающая имя пользовательской функции, позволяющей асинхронный обмен данными. Если параметр опущен, то клиент (VFP) ожидает данные сервера в течение периода, заданного по умолчанию или DDESetOption( ). Если параметр задан, то VFP продолжает выполнение программы сразу после выполнения запроса.

Когда сервер завершает выполнение посланной ему команды, cUDFName-функция исполняется. Всего такая функция должна иметь 6 перечисленных в табл. 17.7 параметров; порядок следования параметров в функции совпадает с указанным в табл. порядком.

Таблица 17.7

Параметры cUDFName-функции

Параметр

Описание

ChannelNumber

Номер DDE-канала

Action

Действие: XACTCOMPLETE (успешная транзакция) или XACTFAIL (неудачная транзакция)

Item

Имя элемента, например "R1C1" для ячейки листа Microsoft Excel

Data

Новые данные (REQUEST) или переданные данные (POKE или EXECUTED)

Format

Формат данных, например CF_TEXT

Transaction Number

Номер транзакции, возвращаемый DDERequest( )

При необходимости отмена незавершенной транзакции выполняется DDEAbortTrans( ). Если транзакция сорвалась, то причину неудачи можно узнать, употребив DDELastError( ).

Пример (приведен в справке VFP). DDEExecute( ) используется для максимизации окна Excel.

Run /n C:\Program Files\Microsoft Office\Office10\Excel

gnChanNum = DDEInitiate('Excel', 'Лист1')

if gnChanNum != –1

glExecute = DDEExecute(gnChanNum, '[App.Maximize]')

if glExecute then

wait window 'Окно Excel распахнуто'

endif

DDETerminate(gnChanNum) && Закрываем канал gnChanNum

endif

Функция

DDEPoke(nChannelNumber, cItemName, cDataSent
                  
[, cDataFormat [, cUDFName]])

посылает данные клиента серверу по DDE-каналу nChannelNumber.

Функция, если опущен параметр cUDFName, возвращает .T., если данные успешно отосланы, или .F. – в противном случае. Если параметр cUDFName задан, то возвращается номер транзакции, а в случае ошибки – число –1.

Параметры:

cItemName – строка, содержащая имя элемента, которому посылаются данные, например ячейка "R1C1" листа Microsoft Excel.

cDataSent – строка с посылаемыми данными.

cDataFormat – формат посылаемых данных. По умолчанию берется формат CF_TEXT. При таком формате поля разделяются символами табуляции, а строки символами новой строки и возврата каретки.

cUDFName – см. описание одноименного параметра функции DDEExecute( ).

Пример. Строится диаграмма Microsoft Excel по данным массива sales.

dimension sales(3, 8)

&& Формируем массив sales

for k = 1 to Alen(sales, 2)

sales(1, k) = 'Hat_' + Transform(k)

sales(2, k) = Transform(20 + 3 * (–1)^k)

sales(3, k) = "20"

next

&&

&& Массив sales

&& Hat_1          17             20

&& Hat_2          23             20

&& …

&& Hat_7          17             20

&& Hat_8          23             20

&&

Run /n C:\Program Files\Microsoft Office\Office10\Excel

gnChanNum = DDEInitiate('Excel', 'Лист1')

if gnChanNum = –1

wait window 'Канал не установлен'

return

endif

&& Передаем данные в Microsoft Excel

for k = 1 to Alen(sales, 2)

rowNo = 'R' + Transform(k)

cell1 = rowNo + 'C1'

cell2 = rowNo + 'C2'

cell3 = rowNo + 'C3'

DDEPoke(gnChanNum, cell1, sales(1, k))

DDEPoke(gnChanNum, cell2, sales(2, k))

DDEPoke(gnChanNum, cell3, sales(3, k))

next

&& Выделяем область и строим диаграмму. Результат приведен на рис. 17.1

DDEExecute(gnChanNum, '[Select("R1C1:'+rowNo+'C3")]')

DDEExecute(gnChanNum, '[New(2, 1)]')

DDETerminate(gnChanNum) && Закрываем канал gnChanNum

248.1.-Диаграмма-Microsoft-Excel-по-данным-массива-sales

Рис. 17.1. Диаграмма Microsoft Excel по данным массива sales

Функция

DDERequest(nChannelNumber, cItemName [, cDataFormat [, cUDFName]])

запрашивает данные сервера по каналу nChannelNumber.

Возвращает, если запрос выполнен, строку, содержащую данные, или пустую строку – в противном случае. Если включена cUDFName-функция, то DDERequest( ) вернет в случае удачи номер транзакции, или –1 при возникновении ошибки.

Смысл параметров cItemName и cDataFormat см. в описании функции DDEPoke( ), а параметра cUDFName – в описании функции DDEExecute( ).

Пример (приведен в справке VFP). DDERequest( ) запрашивает данные элемента 'R1C1' листа 'Лист1' приложения Microsoft Excel.

Run /n C:\Program Files\Microsoft Office\Office10\Excel

gnChanNum = DDEInitiate('Excel', 'Лист1')

if gnChanNum != –1 then

nRequest = DDERequest(gnChanNum, 'R1C1')

if not Empty(nRequest) and DDELastError( ) = 0

&& Запрос удачно выполнен

wait window 'R1C1-данные: ' + nRequest

endif

DDETerminate(gnChanNum) && Закрываем канал gnChanNum

endif

Функция

DDELastError( )

возвращает номер ошибки последней выполненной DDE-функции.

Функция вернет 0, если последняя DDE-функция выполнена без ошибки.

Возможные номера DDE-ошибок приведены в табл. 17.8.

Таблица 17.8

Номера DDE-ошибок

Номер ошибки

Описание

1

Служба занята

2

Тема занята

3

Канал занят

4

Нет такой службы

5

Нет такой темы

6

Нет такого канала

7

Недостаточно памяти

8

Request-превышение времени ожидания

9

Требуется перерыв

10

Не выполнена функция DDEInitiate( )

11

Действие клиента выполнено во время транзакции сервера

12

Execute-превышение времени ожидания

13

Неверный параметр

14

Медленная память

15

Ошибка памяти

16

Ошибка соединения

17

Ошибка запроса

18

Poke-превышение времени ожидания

19

Нельзя вывести сообщение

20

Множественные синхронные транзакции

21

Сервер не работает

22

Внутренняя DDE-ошибка

23

Advise-превышение времени ожидания

24

Неверный идентификатор транзакции

25

Неизвестная ошибка

Функция

DDEAbortTrans(nTransactionNumber)

завершает асинхронную DDE-транзакцию.

Возвращает .T., если транзакция функцией завершена, или .F. – в противном случае. Для определения причины неудачи используется DDELastError( ).

Параметр:

nTransactionNumber – номер транзакции, возвращаемый функцией DDEExecute( ), DDEPoke( ) или DDERequest( ), начавшей эту транзакцию.