На волне растущей популярности здесь PureBasic , предлагаю вам ознакомиться еще с одной областью применения этого языка.
Начиная с третьей версии Air, появилось возможность компенсировать ограничения SDK за счет расширений (Flash Runtime Extensions).
Расширения можно писать на C/C++/Java(Android) и на любом другом языке, позволяющем создавать нативные библиотеки для соответствующих платформ.
Скорость вычислений, многопоточность, взаимодействие с операционной системой — все это доступно расширениям.
Некоторое время назад я написал расширение C для Mac и Windows — обертку для кроссплатформенной библиотеки.
ХИДАПИ .
Несмотря на некоторые трудности, удобство заключалось в том, что библиотека была кроссплатформенной, что позволяло один раз написать код расширения и с минимальными усилиями собрать его для каждой платформы.
PureBasic, в свою очередь, предоставляет возможность создания приложений (dll, т. водители ) для нескольких систем.
Есть возможность оптимизации, поддержка Unicode, готовые объекты (Список, Карта), набор кроссплатформенных функций (алгоритмы сжатия, обработка изображений, шифрование), большая часть WINAPI, макросы и даже ООП импортированы для Windows. Все это значительно ускоряет разработку (для тех, у кого нет опыта работы с C/C++) по сравнению с голым C.
Пример – системный модальный диалог
Исходники и демо-приложение для Windows доступны по адресу code.google.com .Первым шагом было Импортировать функции из библиотеки FlashRuntimeExtensions.lib (Windows, {AIR SDK}\lib\win\), это делается относительно просто с помощью FlashRuntimeExtensions.h ({AIR SDK}\include\):
В настройках компилятора необходимо указать формат Shared Dll, при необходимости включить поддержку Unicode (+ в меню Файл/Формат выбрать кодировку UTF8 исходных файлов), потокобезопасность или поддержку ассемблера.ImportC ".
/lib/FlashRuntimeExtensions.lib" ;returns FRE_OK ; FRE_WRONG_THREAD ; FRE_INVALID_ARGUMENT If nativeData is null. ;FREResult FREGetContextNativeData( FREContext ctx, void** nativeData ); ;-FREGetContextNativeData FREGetContextNativeData.l (ctx.l, nativeData.l) .
EndImport
Единственное неудобство — отсутствие в PureBasic беззнакового типа long; для этого пришлось написать дополнительные функции.
В дескрипторе расширения указываем платформу, библиотеку расширений и единственные 2 экспортируемые функции (инициализатор и финализатор): <Эxml version="1.0" encoding="UTF-8"?>
<extension xmlns=" http://ns.adobe.com/air/extension/3.1 ">
<id>com.pure.Extension</id>
<name>pureair</name>
<copyright>compile4fun 2012</copyright>
<description>Extenion for Adobe AIR</description>
<versionNumber>1.0.0</versionNumber>
<platforms>
<platform name="Windows-x86">
<applicationDeployment>
<nativeLibrary>pureair.dll</nativeLibrary>
<initializer>initializer</initializer>
<finalizer>finalizer</finalizer>
</applicationDeployment>
</platform>
</platforms>
</extension>
Идентификатор должен совпадать с указанным в манифесте приложения и пакете расширения (ActionScript), профиль приложения — ExtendedDesktop.
Обязательная часть расширения — это функции AttachProcess(Instance), DetachProcess(Instance), AttachThread(Instance) и DetachThread(Instance), а также: .
;CDecl
ProcedureC contextInitializer(extData.l, ctxType.s, ctx.l, *numFunctions.Long, *functions.Long)
*log\info("create context: " + Str(ctx) + "=" + Utf8ToUnicode(ctxType))
Define result.l
;exported extension functions count:
Define size.l = 1
;Array of FRENamedFunction:
Dim f.FRENamedFunction(size - 1)
;there is no unsigned long type in PB
setULong(*numFunctions, size)
;If you want to return a string out of a DLL, the string has to be declared as Global before using it.
;method name
f(0)\name = asGlobal("showDialog")
;function data example
f(0)\functionData = asGlobal("showDialog")
;function pointer
f(0)\function = @showDialog()
*functions\l = @f()
;some additional data can be stored
extData = #Null
;native data example
result = FRESetContextNativeData(ctx, asGlobal("FRESetContextNativeData"))
*log\Debug(ResultDescription(result, "FRESetContextNativeData"))
*log\info("create context complete");
EndProcedure
;CDecl
ProcedureC contextFinalizer(ctx.l)
*log\info("dispose context: " + Str(ctx))
EndProcedure
;CDecl
ProcedureCDLL initializer(extData.l, *ctxInitializer.Long, *ctxFinalizer.Long)
*ctxInitializer\l = @contextInitializer()
*ctxFinalizer\l = @contextFinalizer()
EndProcedure
;CDecl
;this method is never called on Windows.
ProcedureCDLL finalizer(extData.l)
;do nothing
EndProcedure
Массив FRENamedFunction содержит методы нашего расширения (в данном случае только один — showDialog), также есть возможность привязки любых данных к экземпляру функции или расширения.
Следует обратить внимание на тип вызова CDecl и функцию asGlobal, которая специально выделяет память для строк, передаваемых из расширения в основную программу, об этом упоминается в справке PureBasic по работе с dll.
Наше расширение покажет модальный диалог с настраиваемым набором кнопок и текста и передаст событие закрытия диалога: Structure MessageParameters
text.s
title.s
dwFlags.l
ctx.l
EndStructure
Procedure ModalMessage(*params.MessageParameters)
Define result.l, code.l
code = MessageRequester(*params\title, *params\text, *params\dwFlags)
result = FREDispatchStatusEventAsync(*params\ctx, asGlobal("showDialog"), asGlobal(Str(code)))
*log\Debug (ResultDescription(result, "FREDispatchStatusEventAsync"))
EndProcedure
;CDecl
ProcedureC.l showDialog(ctx.l, funcData.l, argc.l, *argv.FREObjectArray)
*log\info("Invoked showDialog")
Define result.l
;ActionScriptData example
Define actionScriptObject.l, actionScriptInt.l, type.l
result = FREGetContextActionScriptData(ctx, @actionScriptObject)
*log\Debug(ResultDescription(result, "FREGetContextActionScriptData"))
result = FREGetObjectType(actionScriptObject, @type)
*log\Debug("result=" + ResultDescription(result, "FREGetObjectType"))
*log\info("ContextActionScriptData: type=" + TypeDescription(type))
result = FREGetObjectAsInt32(actionScriptObject, @actionScriptInt)
*log\Debug("result=" + ResultDescription(result, "FREGetObjectAsInt32"))
*log\info("ContextActionScriptData: actionScriptInt=" + Str(actionScriptInt))
;function data example
Define funcDataS.s
funcDataS = PeekS(funcData, -1, #PB_Ascii)
*log\info("FunctionData: " + funcDataS)
*log\info("Method args size: " + Str(fromULong(argc)))
Define resultObject.l, length.l, booleanArg.l, dwFlags.l, message.s, *string.Ascii
result = FREGetObjectAsBool(*argv\object[0], @booleanArg)
*log\Debug("result=" + ResultDescription(result, "FREGetObjectAsBool"))
result = FREGetObjectAsInt32(*argv\object[1], @dwFlags)
*log\Debug("result=" + ResultDescription(result, "FREGetObjectAsInt32"))
result = FREGetObjectAsUTF8(*argv\object[2], @length, @*string)
*log\Debug("result=" + ResultDescription(result, "FREGetObjectAsUTF8"))
message = PeekS(*string, fromULong(length) + 1)
*log\info("Argument: booleanArg=" + Str(fromULong(booleanArg)))
*log\info("Argument: dwFlags=" + Str(dwFlags))
*log\info("Argument: message=" + Utf8ToUnicode(message))
;native data example
Define native.l, nativeData.s
result = FREGetContextNativeData(ctx, @native)
*log\Debug(ResultDescription(result, "FREGetContextNativeData"))
nativeData = PeekS(native, -1, #PB_Ascii)
*log\info("FREGetContextNativeData: " + nativeData)
Define *params.MessageParameters = AllocateMemory(SizeOf(MessageParameters))
*params\ctx = ctx
*params\title = "PureBasic"
*params\text = Utf8ToUnicode(message)
*params\dwFlags = dwFlags
CreateThread(@ModalMessage(), *params)
;return Boolean.TRUE
result = FRENewObjectFromBool(toULong(1), @resultObject)
*log\Debug(ResultDescription(result, "FRENewObjectFromBool"))
ProcedureReturn resultObject
EndProcedure
Со стороны Воздуха это выглядит так: package com.pure
{
import flash.events.StatusEvent;
import flash.external.ExtensionContext;
import mx.logging.ILogger;
import mx.logging.Log;
/**
* Wrapper for PureBasic extension
*/
public class Extension
{
/**
* Extension id, must be specified in air-manifest.xml and extension.xml
*/
public static const CONTEXT:String = "com.pure.Extension";
private static const log:ILogger = Log.getLogger(CONTEXT);
/**
* @private
*/
private var _context:ExtensionContext;
/**
* @private
*/
private var contextType:String;
/**
* Creates context
* @param contextType default value is "PureAir"
* @param actionScriptData any number
*/
public function Extension(contextType:String = "PureAir", actionScriptData:int = 4)
{
//random type
this.contextType = contextType + Math.round(Math.random() * 100000);
try
{
log.debug("Creating context: {0}, contextType: {1}", CONTEXT, this.contextType);
_context = ExtensionContext.createExtensionContext(CONTEXT, this.contextType);
if (_context == null)
{
//creation failed
log.error("Failed to create context: {0}, contextType: {1}", CONTEXT, this.contextType);
}
else
{
log.debug("Context was created successfully");
//listen for extension events
_context.addEventListener(StatusEvent.STATUS, onStatusEvent);
//set actionScript data
_context.actionScriptData = actionScriptData;
}
}
catch(e:Error)
{
log.error("Failed to create context: {0}, contextType: {1}, stacktrace: {2}", CONTEXT, this.contextType, e.getStackTrace());
}
}
private function get contextCreated():Boolean
{
return _context != null;
}
/**
* Test method, shows YesNoCancel modal dialog
* @param booleanArg boolean parameter
* @param flags integer parameter, #PB_MessageRequester_YesNoCancel=3, #MB_APPLMODAL = 0
* @param message string parameter
* @return
*/
public function showDialog(booleanArg:Boolean, flags:int, message:String):Boolean
{
if (!contextCreated)
return false;
var result:Boolean = false;
try
{
result = _context.call('showDialog', booleanArg, flags, message) as Boolean;
if (!result)
{
log.error("Invocation error: test({0}, {1}, {2})", booleanArg, flags, message);
}
}
catch (e:Error)
{
log.error("Invocation error: test({0}, {1}, {2}), stacktrace: {3}", booleanArg, flags, message, e.getStackTrace());
}
return result;
}
private function onStatusEvent(event:StatusEvent):void
{
log.info("Status event received: contextType={0} level={2}, code={1}", this.contextType, event.code, event.level);
}
/**
* Performs clean-up
*/
public function dispose():void
{
if (_context)
{
_context.dispose();
//clean all references
_context.removeEventListener(StatusEvent.STATUS, onStatusEvent);
_context = null;
log.info("Disposed {0}", this.contextType);
}
else
{
log.warn("Can not dispose {0}: Context is null", this.contextType);
}
}
}
}
StatusEvent — единственный тип событий, который может отправлять расширение.
Результат работы можно увидеть на скриншоте:
Спасибо за внимание.
Теги: #purebasic #PureBasic #Adobe AIR #собственное расширение #flex #Flex #программирование #Adobe Flash
-
Типографика В Сети
19 Oct, 24 -
Вышел Untethered Jailbreak Для Ios 4.2.1
19 Oct, 24 -
Distype: Простое Приложение Для Чата
19 Oct, 24 -
Unreal Engine 3 Портирован На Прошивку
19 Oct, 24 -
Блоги + Gps = Геоблоги!
19 Oct, 24 -
Google Снова Переходит На Процессоры Intel
19 Oct, 24