Назначение
Регистрация COM-сервера в реестре Windows
Создание объекта VFP.memlib32 и VFP.memlib
Объект Stream
Write(str)
LenStream()
Asc()
Read(count)
ReadLine()
ReadToEnd()
CloseStream()
Объект Array
NewArray(n)
LenArray()
PutArray(i, val)
GetArray(i)
CloseArray()
Объект Dictionary
LenDic()
PutDic(strKey, val)
GetDic(strKey)
DelDic(strKey)
СloseDic()
Объект Queue/FIFO
LenFIFO()
PutFIFO(val)
PeekFIFO()
GetFIFO()
СloseFIFO()
Объект Task
DoAsync(com, method[, v1[, v2[, v3[, v4[, v5[, v6[, v7[, v8[, v9[, v10]]]]]]]]]])
DoAsyncN(com, method, @vals)
WaitTask()
ITask_OnEnded(ret)
ITask_OnError(method)
CloseTask()
Примеры использования асинхронной задачи на языке Visual FoxPro
Объект Util
RunAsync(cmd[, arguments])
WriteUtil(string)
ReadUtil([N])
CloseUtil()
СloseAll()
Библиотеки memlib32.net.dll и memlib.net.dll реализуют COM-сервер для VFP9 или VFPA, который в принципе может использоваться и на любых других языках, поддерживающих COM технологию обмена данными.
Microsoft VFP имеет ряд ограничений, связанных с использованием ОП. Теоретически в VFP cуществуют способы использовать ОП до 2 Гб, но при этом возникают очень большие утечки памяти, приводящие к блокировке работы VFP.
При создании COM-объекта VFP.memlib32 или VFP.memlib, выделяемая ОП не занимает место в области VFP. Эта память выделяется в объекте VFP.memlib32/VFP.memlib.
В memlib32.net.dll/memlib.net.dll реализованы:
- объект Stream, который по используемым методам напоминает работу с файлом, находящимся в ОП;
- объект Array, представляющий одномерный массив с числовым индексом;
- объект Dictionary, представляющий одномерный массив с текстовым индексом (словарь);
- объект Queue/FIFO, очередь, в которую помещаются любые переменные и объекты;
- объект Task — асинхронная задача, создаваемая из метода любого COM-объекта;
- объект Util — работа с любой консольной утилитой, как с объектом.
Используйте утилиту регистрации regasm.exe для 32-х разрядных программ, находящуюся в папке C:\Windows\Microsoft.NET\Framework\v4.0.30319, с ключами /codebase и /tlb. Пример регистрации:
C:\Windows\Microsoft.NET\Framework\v4.0.30319\regasm.exe D:\VFP\VFP9\memlib32.net.dll /codebase /tlbПредварительно поместите файл memlib32.net.dll в удобную для вас папку, например, в папку, где находятся другие библиотеки Microsoft VFP.
Для удаления регистрации из Windows используйте ключ /unregister:
C:\Windows\Microsoft.NET\Framework\v4.0.30319\regasm.exe D:\VFP\VFP9\memlib32.net.dll /unregisterДля выполнения вышеуказанных команд требуются права администратора.
Чтобы объект VFP.memlib был доступен в разрабатываемых программах 64-х битных версий, его нужно зарегистрировать в ОС с помощью утилиты regasm.exe для 64-х разрядных программ, находящуюся в другой папке (это важно) C:\Windows\Microsoft.NET\Framework64\v4.0.30319, с ключами /codebase и /tlb. Пример регистрации:
C:\Windows\Microsoft.NET\Framework64\v4.0.30319\regasm.exe D:\VFP\VFPA\memlib.net.dll /codebase /tlbПредварительно поместите файл memlib.net.dll в удобную для вас папку, например, в папку, где находятся другие библиотеки Microsoft VFP.
Для удаления регистрации из Windows используйте ключ /unregister:
C:\Windows\Microsoft.NET\Framework64\v4.0.30319\regasm.exe D:\VFP\VFPA\memlib.net.dll /unregisterДля выполнения вышеуказанных команд требуются права администратора.
Текст кода на VFP:
oMem = CreateObject('VFP.memlib32')и
oMem = CreateObject('VFP.memlib')или универсальный вариант:
oMem = CreateObject('VFP.memlib'+iif(sys(17)='Pentium','32',''))Объект Stream имеет ниже следующие методы.
Метод записывает указанную параметром строку в объект Stream.
oMem.Write("Привет, Мир!"+chr(10))Указатель записи всегда находится в конце записанного потока. При первом же запросе любой операции на чтение, запись в этот же поток становится невозможной. В этом случае следующая операция записи откроет новый поток.
Метод возвращает 32-х разрядное положительное число, содержащее длину потока или ноль, если запись в объект еще не производилась.
len = oMem.LenStream()Метод читает код первого за указателем чтения символа, но не перемещает указаль.
kod = oMem.Asc()Если поток пустой или достигнут конец потока, то метод возвращает значение -1.
Метод читает заданное параметром количество символов из Stream и возвращает прочитанную строку. Указатель чтения переносится за последний прочитанный символ.
str = oMem.Read(10)Если начальная позиция указателя находилась в коце потока, то вместо строки возвращается значение NULL.
Метод читает из Stream строку до символа перевода строки. Символы CR и LF не включаются в возвращаемое методом значение. Указатель чтения переносится за последний прочитанный символ включая CR и LF.
str = oMem.ReadLine()Если начальная позиция указателя находилась в коце потока, то вместо строки возвращается значение NULL.
Метод читает из Stream строку до конца потока. Указатель чтения переносится в конец.
str = oMem.ReadToEnd()Если начальная позиция указателя находилась в коце потока, то вместо строки возвращается значение NULL.
Метод удаляет объект Stream из памяти. Память освобождается. Используйте этот метод, если вам больше не нужен объект Stream. Объект Stream создается при первом использовании метода Write(str).
oMem.CloseStream()Объект Array имеет ниже следующие методы.
Метод создает массив размером, передаваемым числовым параметром. В случае успешного создания массива метод возвращает число созданных элементов массива n. В противном случае возвращается ноль.
Метод возвращает длинну массива.
Метод присваивает элементу массива под номером первого числового параметра значение произвольного типа, переданное вторым параметром.
Метод возвращает значение элемента массива с номером переданным числовым параметром.
Метод уничтожает массив.
Объект Dictionary имеет ниже следующие методы.
Метод возвращает число пар ключ-значение.
Метод присваивает элементу словаря со строковым ключем, заданным первым параметром, значение произвольного типа, переданное вторым параметром.
Метод возвращает значение элемента словаря со строковым ключем, заданным параметром.
Метод удаляет элемент словаря ключ-значение, заданное строковым параметром, содержащим значение ключа.
Метод уничтожает словарь и освобождает память.
Объект FIFO представляет собой очередь значений помещаемых и извлекаемых по принципу первый помещен, первый извлечен. Объект имеет ниже следующие методы.
Метод возвращает число значений в очереди.
Метод помещает значение произвольного типа в очередь.
Метод возвращает первое значение в очереди, но не извлекает его.
Метод возвращает первое значение в очереди и извлекает его.
Метод уничтожает очередь и освобождает память.
Объект Task представляеет собой асинхронную задачу. Задача создается на основе метода открытого COM-объекта, такого как Excel.application, com.sun.star.frame.Desktop, VisualFoxPro.Application, ADODB.Connection и т.д. Метод представлятся строкой. Верхний или нижний регистр символов строки с методом имеют значение. Необходимо указывать точное название метода. Объект Task имеет ниже следующие методы и интефейс для обратного вызова после завершения задачи.
Метод запускает асинхронную задачу без параметров или, если неоходимо — с дополнительными параметрами в количестве до 10-ти значений. Метод возвращает 0 или -1 в случае если задача не создана. Первым параметром передается открытый COM-объект, вторым параметром — текстовое наименование метода.
Метод запускает асинхронную задачу со специально подготовленным массивом требуемых параметров, возвращает 0 или -1 в случае если задача не создана. Первым параметром передается открытый COM-объект, вторым параметром — текстовое наименование метода. Нумерация элементов массива с параметрами начинается от нуля. Массив передается по ссылке. Смотрите ниже приведенный пример на языке Visual FoxPro.
Если требуется, метод ожидает завершения задачи. Метод возвращает сформированный результат. Если задача не формирует результат, то возвращается пустая строка.
Метод обеспечивает обратный вызов через интефейс ITask и событие OnEnded. Параметром является сформированный результат закончившейся задачи или пустая строка. Если обнаруживается этот метод на вызывающей стороне, то он получает управление после завершения задачи. Смотрите ниже пример 2 на языке Visual FoxPro.
Примечание. VFPA версий до 2024 года не поддерживает работу интерфесов с обратными вызовами.
Метод обеспечивает обратный вызов через интефейс ITask и событие OnError. Параметром является название метода, в котором произошла ошибка во время выполнения, возникшая в асинхронной задаче. Смотрите ниже пример 2 на языке Visual FoxPro.
Примечание. VFPA версий до 2024 года не поддерживает работу интерфесов с обратными вызовами.
Благодарность. Интерфейс ITask и его события добавлены благодоря усилиям Дмитрия Чунихина.
Пример 1. Без использования обратного вызова:
oMem=CreateO('VFP.memlib'+iif(sys(17)='Pentium','32',''))
oVFP=CreateO('VisualFoxPro.Application')
* Эмитируем работу, выполняемую в течении 12.3 секунд в паралельном процессе.
* Метод DoCmd имеет один параметр - выполняемую команду:
oMem.DoAsync(oVFP,"DoCmd","wait wind '' time 12.3")
* Тем временем вычисляем и возвращаем сумму чисел в текущем процессе.
? 2+2*2 && 6
* Формируем массив параметров размером в 1 элемент:
dime vals(1)
vals(1)="m.A+m.A*m.A" && выражение
* Указываем тип массива с нулевого элемента для COM-объекта oMem:
ComArray(oMem,10)
* Завершаем запущенную асинхронно задачу:
oMem.WaitTask() && Перешли в синхронное ожидание асинхронной задачи
* Заносим значение в переменную m.A синхронно с помощью метода SetVar.
* Метод SetVar требует два параметра:
oVFP.SetVar("A",2)
* Выполняем вычисление асинхронно с использованием массива параметров:
oMem.DoAsyncN(oVFP,"Eval", @vals)
* Получаем результат вычисления асинхронной задачи:
? oMem.WaitTask() && 6
* Закрываем процесс VFP синхронно. Метод Quit не имеет параметров:
oVFP.Quit()
oMem.CloseTask()
rele oVFPПример 2. C использованием обратного вызова и контролем возникновения ошибок:
cBit=iif(sys(17)='Pentium','32','')
oMem = CreateO('VFP.memlib'+m.cBit)
EventHandler(oMem, NewO("Callback"+m.cBit))
oVFP = CreateO('VisualFoxPro.Application')
* Ошибка в асинхронно выполняемой команде:
oMem.DoAsync(oVFP,"DoCMD","wait wind '' :-) time 12.3")
* Здесь могут быть параллельно выполняемые команды
? "Первая задача выполняется..."
* Дождаться выполнения первой асинхронной задачи,
* чтобы в этом же процессе запустить другую команду:
oMem.WaitTask() && можно использовать read even
* Другая асинхронно выполняемая команда:
oMem.DoAsync(oVFP,"Eval","'Теперь '+'ошибки '+ 'нет!'")
* Здесь могут быть параллельно выполняемые команды
? "Вторая задача выполняется..."
* Дождаться выполнения, чтобы завершить второй процесс VFP:
read even && можно использовать oMem.WaitTask()
oMem.CloseTask()
oVFP.Quit()
PROC ITask_OnEnded(ret)
if type('m.ret')='C'
? m.ret
endi
clea even
ENDPROC
PROC ITask_OnError(сMethod)
? 'ОШИБКА в методе COM "'+m.сMethod+'"'
clea even
ENDPROC
DEFINE CLASS Callback32 as Session
IMPLEMENTS ITask IN 'VFP.memlib32'
* Метод, получающий обратный вызов:
PROC ITask_OnEnded(ret)
ITask_OnEnded(ret)
ENDPROC
* Метод обработки ошибки в асинхронной задаче:
PROC ITask_OnError(сMethod)
ITask_OnError(сMethod)
ENDPROC
ENDDEFINE
DEFINE CLASS Callback as Session
IMPLEMENTS ITask IN 'VFP.memlib'
* Метод, получающий обратный вызов:
PROC ITask_OnEnded(ret)
ITask_OnEnded(ret)
ENDPROC
* Метод, обработки ошибки в асинхронной задаче:
PROC ITask_OnError(сMethod)
ITask_OnError(сMethod)
ENDPROC
ENDDEFINEОбъект Util позволяет запустить произвольную утутилиту или любую программу и взаимодействовать с ней через стандартный ввод/вывод. Объект Util имеет ниже следующие методы.
Метод запускает утилиту без параметров или, если неоходимо, со строкой аргументов. Метод возвращает логическое значение правда, если указанная параметром утилита обнаружена. Пример:
if oMem.RunAsync("ipconfig")
? Утилита запушена
else
? Утилита не обнаружена
endiМетод помещает строку в стандартный ввод утилиты.
Метод читает N байт из стандартного вывода утилиты или, если не указан параметр N, весь поток стандартного вывода. Например:
? oMem.ReadUtil()Метод закрывает стандартый ввод и вывод запущенной утилиты. Можно использовать этот метод, если не уверены, что утилита закончила работу.
Метод закрывает все объекты COM-сервера и максимально освобождает всю память.
Задать вопрос или обсудить тему, касающуюся VFP/VFPA, вы можете в разделе проекта Issues > New issue.
0.0.0.0. 08.03.2025. Опубликована первая рабочая версия с объектами Stream, Array и Dictionary.
0.0.1.0. 09.03.2025. Добавлен метод CloseAll().
0.0.2.0. 09.03.2025. Добавлена автоматическая очистка потока записи после формирования потока чтения.
0.0.2.1. 26.03.2025. Добавлен объект FIFO и объект асинхронной задачи.
0.0.2.2. 28.03.2025. Объект Task переведен из памяти вызывающей задачи в память VFP.memlib.
0.0.3.0. 03.04.2025. Добавлен интерфейс ITask, обеспечивающий обратный вызов.
0.1.0.0. 05.04.2025. Устанвлена видимость интерфейса ITask по умолчанию.
0.1.1.0. 06.04.2025. Методы DoAsyncX теперь возвращают 0 в случае успеха. Предусмотрена обработка замеченных исключений.
0.1.2.0. 09.04.2025. Добавлен обратный вызов при возникновении ошибки в асинхронной задаче.
0.1.3.0. 19.04.2025. Вместо нескольких методов создания асинхронной задачи с разным количеством параметров сделан один универсальный метод с числом параметров от 0 до 10.
0.2.0.0. 25.11.2025. Изменены параметры метода возникновения ошибки ITask_OnError на более информационный — название метода возникновения ошибки.
0.2.1.0. 26.11.2025. Добавлено закрытие предыдущей асинхронной задачи в случае, когда запускается новая асинхронная задача, а предыдущая уже выполнена.
0.3.0.0. 20.12.2025. Добавлен объект Util.
0.4.0.0. 08.01.2026. Для объекта Util реализовоно перенаправление потока из канала ошибок в стандартный поток. Если есть оба потока, и стандартный и ошибки, то ошибки дописываются в конец стандартного потока вывода.