c#

C# で作る AIR Native Extension - 2 -

C# で作る AIR Native Extension


Adobe AIR3 から ANE という ネイティブ拡張機能が実装されたのでWindowsで試してみました。

全部で4ページにまとめます。

今回はその2ページ目です。


開発環境
 Windows XP SP3
 Visual Studio 2010 Express Edition( C# / VC++ )
 FlashBuilder4.6( FlexSDK4.6 )


ane-lab(AIR Native Extension is Lab codes) - Google Project Hosting にC#で作ったサンプルをコミットさせて頂きましたので、参考にして下さい。
間違ってるかもしれないので、決して鵜呑みにしないように。



2.VC ++でDLL作るよ!


Visual Studio 2010 Express Edition VC++ を使用して、AIRライブラリ(SWC)からコールするためのDLLを作成していきます。
VC++でCLRライブラリプロジェクトを選択してください。



vc-project.png




先回作成したC#のDLLとtlbファイル、及びAIR SDKに同梱されているヘッダーファイルとlibファイルをプロジェクトに追加します。



cs-dll.png




air-lib.png




project-files.png




で、ヘッダーファイル2つとメインのCPPファイルを書きます。


[ Stdafx.h ]
------------------------------
// stdafx.h : 標準のシステム インクルード ファイルのインクルード ファイル、または
// 参照回数が多く、かつあまり変更されない、プロジェクト専用のインクルード ファイル
// を記述します。

#pragma once
#include "FlashRuntimeExtensions.h";

[ EOF ]
------------------------------


[ libApplicationList.h ]
------------------------------
// libApplicationList.h
#pragma once
#include <stdlib.h>
#include <wchar.h>
#include <windows.h>

#using <mscorlib.dll>
#using "ApplicationList_CS.dll"

using namespace System;
using namespace System::Runtime::InteropServices;
using namespace System::Collections;
using namespace ApplicationList_CS;

namespace libApplicationList {

    public ref class Class1
    {
        // TODO: このクラスの、ユーザーのメソッドをここに追加してください。
    };
}
[ EOF ]
------------------------------

[ libApplicationList.cpp ]
------------------------------
// これは メイン DLL ファイルです。

#include "stdafx.h"
#include "libApplicationList.h"


extern "C" __declspec(dllexport) void initializer(void** extData, FREContextInitializer* ctxInitializer, FREContextFinalizer* ctxFinalizer);
extern "C" __declspec(dllexport) void finalizer(void** extData);

void ConvertToUni(String^ _str, char* szBuf, const int bufLen)
{
    IntPtr ptr = Marshal::StringToHGlobalUni(_str);
    const char* str = static_cast<const char*>(ptr.ToPointer());
    WideCharToMultiByte(CP_UTF8, 0, (wchar_t*)str, -1, szBuf, bufLen, NULL, NULL);
    Marshal::FreeHGlobal(ptr);
}

FREObject GetApplicationList(FREContext ctx, void* funcData, uint32_t argc, FREObject argv[]){
    FREObject resultObj;
    FREObject elementObj;

    ApplicationList_CS::AppList_CS^ cs = gcnew ApplicationList_CS::AppList_CS();
    ArrayList^ list = gcnew ArrayList();
    list = cs->getApplicationNames();

    // Application Name buffer
    const int bufLen = 1024;
    char szBuf[bufLen];

    const int count = list->Count;

    FRENewObject((const uint8_t*)"Array", 0, NULL, &resultObj, NULL);
    FRESetArrayLength(resultObj, count);

    for(int i=0; i<count; i++){
        String^ str = (String^)list[i];
        ConvertToUni(str, szBuf, bufLen);
        FRENewObjectFromUTF8(strlen(szBuf)+1, (const uint8_t *)szBuf, &elementObj);
        FRESetArrayElementAt(resultObj, i, elementObj);
    }

    return resultObj;
}
void contextFinalizer(FREContext ctx)
{
    return;
}

void contextInitializer(void* extData, const uint8_t* ctxType, FREContext ctx, uint32_t* numFunctions, const FRENamedFunction** functions)
{
    *numFunctions = 1;
    FRENamedFunction*  func= (FRENamedFunction*)malloc(sizeof(FRENamedFunction) * (*numFunctions));

    func[0].name = (const uint8_t*) "GetApplicationList";
    func[0].functionData = NULL;
    func[0].function = &GetApplicationList;

    *functions = func;
}

void initializer(void** extData, FREContextInitializer* ctxInitializer, FREContextFinalizer* ctxFinalizer)
{
    *ctxInitializer = &contextInitializer;
    *ctxFinalizer = &contextFinalizer;
}

void finalizer(void** extData)
{
   
}
[ EOF ]
------------------------------

ポイントは

contextInitializerのFRENamedFunctionでActionScriptからCallされる名前を定義しているのと、ネイ ティブの処理として

Marshal::StringToHGlobalUni(_str);
WideCharToMultiByte(CP_UTF8, 0, (wchar_t*)str, -1, szBuf, bufLen, NULL, NULL);

を使用している点でしょう。

WindowsではOS内部の値はUnicodeで格納されているため、UnicodeからUTF8に変換しないと、AIRに持っていったときに文字化け して表示されます。
ですので、WMIやレジストリなどから”マルチバイト文字”を引っ張ってくるときは要注意です。

あとは、ArrayList^ listに格納された文字列を1つ1つ分解して、FREObjectの構造体に突っ込む作業です。
全部突っ込んだらreturnで戻して終わりです。

AIR側に渡すために各パラメータを細かく分解してから、それぞれ格納し直す作業がメンドイですね…。


では、次回はFlashBuilderでFlexライブラリプロジェクト(SWC)とFlexプロジェクト(デスクトップ AIRアプリ)を作ります。

このページの先頭へ