c#

C# で作る AIR Native Extension

C# で作る AIR Native Extension



ApplicationList.png


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

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

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


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


まぁ、アレです、各プラットフォーム固有の機能が使えたりするというヤツです。
Windowsならね、わざわざAIRでやらなくてもね、C#で全部出来るからね…、あんまり意味無いかもしれませんけどね。 orz
フロントエンドをAIRでまとめて、各プラットフォームごとにANEで固有機能を実装して…という具合にアプリを作るなら、ANE はアリです。

が、結構かなりシビアにキツイです。キツイっス…。orz

レジストリにアクセスしたり、WMI(Windows Management Instrumentation)を使ってハードウェア・ソフト ウェアの情報を取得したり、C#のAPIに丸投げしたり出来ま す。はい。

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


で、作り方。


作るのは4つ。

C#クラスライブラリ(C#のDLL)
VC++のCLRのクラスライブラリ(VC++ CLR/DLL)
Flexライブラリプロジェクト(SWC)
Flexプロジェクト(デスクトップ AIRアプリ)

です。



1.C#でDLL作るよ!

template.png

最初にキモを抑えて起きましょう。
C#で作ったDLLをVC++から参照して、VC++で作るDLLの中でFlashRuntimeExtensionsを組み込むことにより、AIRアプ リに通知することが出来るようになります。

えー???ですよね。C#からVC++のDLLをImportする…のではなく、その逆です。VC++からC#のDLLを参照しま す。
イヤーな予感がします。はい。


キモはコレ!
VC++から参照出来るように、「アセンブリをCOM参照可能にする」のチェックと、「COM相互運用機能の登録」のチェックをONにしておきます。
これでVC++からCOM経由でC#のクラスやそのメンバを参照出来るようになります。

CS_Setting01.png
CS_Setting02.png

ここで1つ注意。

COM 参照可能にする、とかCOM相互運用機能の登録とありますが、これはWindowsのCOMという機能を利用/経由(.NET/C#がCOMにラップされ る)して、VC++から.NET Objectを操作出来るようにする(マネージドからアンマネージにアクセスする)…というものです。

詳しくは「COM ・ RCW ・ 参照カウント 」などのキーワードで調べてください。

C#(.NET)にはGC(ガベージコレクション)という機能があります。が、COMはMSのドキュメントによると、「COM 自身は、オブジェクトが不要になったと判断しても、メモリから自動的にオブジェクトを削除するわけではありません。不要なオブジェクトの削除は、オブジェ クトのプログラマが行います。プログラマは、参照カウントに基づいて、オブジェクトを削除できるかどうかを判断します。」とあります。(http://msdn.microsoft.com/ja-jp/library/4947zb56%28v=vs.100%29.aspx)


完全にGCと相反していますね…。C#でどうやんのよ、それ…。

えー、通常C#で開発をする場合、変数にスコープがあり、このスコープから抜けるとGCの対象になる(実際にGCが何時行われるかはプログラマからは分か りませんが)…のですが、VC++から参照させるために、C#のライブラリをCOM参照させる必要があるため、C#側のインスタン スを明示的に解放してやる必要があります。

MSのドキュメントにも「すべてのア ウトポ インタパ ラメータを明 示的にNULLに設定する必要があります。」 と記載されています。(http://msdn.microsoft.com/ja-jp/library/ms686638.aspx)& rdquo;すばらしいGoogle翻訳”。

えー、ですので、C#側でも不必要な変数にはNULLを入れてやって下さい。
そうしないと、AIRアプリのプロセスが正常に終了しない場合があります。

あと、string[] とかは使わない方が良いです。使うなら、List<string>とかCollection.Genericを使いましょ う。



では、サンプルです。
OS内にインストールされているアプリケーション一覧を表示します。
これで、えろげとかもバッチリだね!(ぉ

プロジェクト名は ” ApplicationList_CS ” です。


[ App.cs ]
----------------------------------------
using System;
using System.Collections;
using System.Collections.Generic;
using System.Management;
using Microsoft.Win32;

namespace ApplicationList_CS {
    class App {
        //HotFix情報
        private const string root = "root\\CIMV2";
        private const string query = "SELECT * FROM Win32_QuickFixEngineering WHERE ServicePackInEffect <> '' AND InstalledBy <> ''";

        public ArrayList getApplicationNames() {
            List<string> hotfix = new List<string>();
            List<string> app = new List<string>();

            ManagementObjectSearcher searcher = new ManagementObjectSearcher(root, query);

            try {
                foreach (ManagementObject queryObj in searcher.Get()) {
                    hotfix.Add((string)queryObj["HotFixID"]);
                }
            } catch (Exception e) {
                Console.WriteLine(e.StackTrace);
            } finally {
                searcher = null;
            }
            RegistryKey regKey = null;
            RegistryKey _subRegKey = null;
            try {
                //アプリケーション情報
                string reg = @"SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\";
                string regValue = "DisplayName";
                regKey = Registry.LocalMachine.OpenSubKey(reg);
                string[] subkey = regKey.GetSubKeyNames();

                foreach (string keyName in subkey) {

                    _subRegKey = Registry.LocalMachine.OpenSubKey(reg + keyName);
                    string value = (string)_subRegKey.GetValue(regValue);

                    if (value != null) {
                        for (int j = 0; j < hotfix.Count; j++) {
                            if (value.Contains(hotfix[j].ToString())) {
                                ;
                            } else if (value.Contains("KB")) {
                                ;
                            } else {
                                app.Add(value);
                                break;
                            }
                        }
                    }
                    //value = null;
                }
                app.TrimExcess();

                reg = null;
                regValue = null;
                subkey = null;
            } catch (NullReferenceException e) {
                Console.WriteLine(e.StackTrace);
            } finally {
                regKey.Close();
                _subRegKey.Close();
            }

            app.Sort();

            for (int i = 0; i < (app.Count - 1); i++) {
                try {
                    if (app[i].Equals(app[i + 1])) {
                        app.RemoveAt(i);
                    }
                } catch (Exception ex) {
                    Console.WriteLine(ex.Message);
                }
            }
            app.TrimExcess();
            hotfix = null;
            return new ArrayList(app);
        }
    }
}
[ EOF ]
----------------------------------------



[ AppList_CS.cs ]
----------------------------------------
using System;
using System.Collections;

namespace ApplicationList_CS {
    public class AppList_CS {

        private App app = new App();
       
        public ArrayList getApplicationNames() {
            return app.getApplicationNames();
        }
    }
}
[ EOF ]
----------------------------------------


やっちゃダメなダメ・コードも記載しておきます。絶対やっちゃダメだよw
配列多すぎ。orz


[ アプリケーション名・バージョン・HotFix情報を取得する変なC#コード ]
----------------------------------------
private void setApplicationReg() {
            string[] val1 = null;
            string[] val2 = null;
            string[] val3 = null;

            ArrayList application;
            ArrayList applicationVersion;
            ArrayList hotfix;

            application = new ArrayList(); // application
            applicationVersion = new ArrayList(); // applicationVersion
            hotfix = new ArrayList(); // HotFix

            try {
                //HotFix情報
                string root = "root\\CIMV2";
                string query = "SELECT * FROM Win32_QuickFixEngineering WHERE ServicePackInEffect <> '' AND InstalledBy <> ''";
                ManagementObjectSearcher searcher = new ManagementObjectSearcher(root, query);
                int cnt = 0;
                foreach (ManagementObject queryObj in searcher.Get()) { cnt++; }
                val1 = new string[cnt];
                int i=0;
                foreach (ManagementObject queryObj in searcher.Get()) {
                    val1[i] = (string)queryObj["HotFixID"];
                    i++;
                }
            }catch(Exception e){
                string error = e.StackTrace;
                //Console.WriteLine(e.StackTrace);
            }
            try {
                //アプリケーション情報
                string reg = @"SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\";
                string regValue = "DisplayName";
                RegistryKey regKey = Registry.LocalMachine.OpenSubKey(reg);
                string[] subkey = regKey.GetSubKeyNames();
                int max = subkey.Length;
                regKey.Close();

                //アプリケーションの総数
                val2 = new string[max];
                val3 = new string[max];
                RegistryKey _subRegKey = null;
                int i = 0;
                foreach (string keyName in subkey) {
                    _subRegKey = Registry.LocalMachine.OpenSubKey(reg + keyName);
                    if ((string)_subRegKey.GetValue(regValue) != null) {
                        val2[i] = (string)_subRegKey.GetValue("DisplayName");
                        val3[i] = (string)_subRegKey.GetValue("DisplayVersion");
                        i++;
                    }
                    _subRegKey.Close();
                }
            } catch (NullReferenceException e) {
                string error = e.StackTrace;
                //Console.WriteLine(e.StackTrace);
            }
            try {
                for (int i = 0; i < val2.Length; i++) {
                    if(val2[i] != null){
                        for(int j = 0; j < val1.Length; j++){
                            if (val2[i].Contains(val1[j])) {
                                hotfix.Add(val2[i]);
                                val2[i] = null;
                                val3[i] = null;
                                break;
                            }else if(val2[i].Contains("KB")){
                                hotfix.Add(val2[i]);
                                val2[i] = null;
                                val3[i] = null;
                                break;
                            }
                        }
                    }
                }
                foreach(string _val in val2){
                    if( _val == null){
                        ;
                    } else {
                        application.Add(_val);
                    }
                }
                foreach (string _val in val3) {
                    if (_val == null) {
                        ;
                    } else {
                        applicationVersion.Add(_val);
                    }
                }
                application.TrimToSize();
                applicationVersion.TrimToSize();
                hotfix.TrimToSize();

                application.Sort();
                for (int i = 0; i < application.Count; i++ ) {
                    try {
                        if (application[i].Equals(application[i + 1])) {
                            application.RemoveAt(i);
                        }
                    }catch(Exception){
                   
                    }
                }
                application.TrimToSize();

                this.application = new string[application.Count];
                this.applicationVersion = new string[applicationVersion.Count];
                this.hotfix = new string[hotfix.Count];

                for (int i = 0; i < application.Count; i++) { this.application[i] = (string)application[i]; }
                for (int i = 0; i < applicationVersion.Count; i++) { this.applicationVersion[i] = (string)applicationVersion[i]; }
                for (int i = 0; i < hotfix.Count; i++) { this.hotfix[i] = (string)hotfix[i]; }
            } catch (NullReferenceException ne) {
                Console.WriteLine(ne.StackTrace);
            }
        }
----------------------------------------



もうちょっとだけ続くんじゃ。


ダメじゃない方のコードをコンパイルすると、DLLとtlbファイルが出来ますので、その2つをVC++のプロジェクトで使用します。

で、結局このDLLってどうなるのっ?ってことなのですが、「Visual Studioコマンドプロンプト」というのがあります。
このDOS窓で、oleviewと入力すると、COMを使用しているアプリケーションやコンポーネントが見れたりします。

oleview.png


えー、2ページ目に続きますが、今度はVC++を使って、AIRアプリとを繋ぐDLLを作成していきます。

このページの先頭へ