仮面's profile宇宙仮面の C# 研究室.Live SpacePhotosBlogListsMore Tools Help

Blog


    November 10

    Willcom 03 でグーグルマップを表示するソフトを1.0.0.2へバージョンアップ

    機能追加・変更

    1. ちょっと外出時に使ってみたが、毎回 Google Map が表示されるのがうっとうしいので、ボタンを押したときだけ表示するように変更。
    2. メールで Google Map の URL を送信できる機能を追加。
    3. 設定ファイルは1つのダイアログに移動。
    4. Updateに対応。

    使い方、ソフトはこちらから。

    http://uchukamen.com/w03degooglemapweb/

    November 01

    Mobile Google Map で特定の場所を表示する方法

    http://www.syware.com/support/customer_support/tip_of_the_month/tip_0709.php

    ここで、

    -URL "?action=locn&a=Cambridge MA"
    -URL "?action=locn&a=@latlon:-22.54,-43.14"
    -URL "?action=locn&view=mapv&a=1600 Pennsylvania Ave Washington D.C."
    -URL "?action=locn&view=satv&a=Statue of Liberty"

    というパラメーターで起動する方法が載っていた。

    latitude, longitude お精度としては、float では甘いので、double でないとだめ。

    string loc = string.Format("-URL \"?action=locn&a=@latlon:{0:F9},{1:F9}\"", latitude, longitude);
    System.Diagnostics.Process.Start(@"\Program Files\GoogleMaps\GoogleMaps.exe", loc);

    これで表示できる。

    モバイル Glogle マップのバージョンは、2.2.0.19。確認したのは、緯度、経度の場合のみ。

    モバイル Glogle マップ は、ここからダウンロード可能  www.google.co.jp/gmm

    ただし、Google マップは 世界測地系、一方でWillcom の基地局データは日本測地系なので、少しずれる。
    http://www.k-erc.pref.kanagawa.jp/learning/gakusyuDB/chizu/I_HK/I_HK.htm 参照

    簡易変換式は次に載っている。

    http://homepage3.nifty.com/Nowral/02_DATUM/02_DATUM.html

    これを適用すると

    double BWGS84 = latitude - 0.00010695D * latitude + 0.000017464D * longitude + 0.0046017D;
    double LWGS84 = longitude - 0.000046038D * latitude - 0.000083043D * longitude + 0.010040D;

    string loc = string.Format("-URL \"?action=locn&a=@latlon:{0:F9}, {1:F9}\"", BWGS84, LWGS84);
    System.Diagnostics.Process.Start(@"\Program Files\GoogleMaps\GoogleMaps.exe", loc);

    October 22

    Willcom 03 でスクリーンショットを撮るには

    方法1: Fn + Ctrl + 画面回転キー

    ファイルは、トップフォルダーに作成されます。

    方法2: Visual Studio があれば、

    スタート→すべてのプログラム→Visual Studio 2008 → Visual Studio Remote Tools → リモートズームイン

    image

    Willcom 03 での自局番号、緯度、経度情報の取得

    Willcom 03 からATコマンドで自局番号を取得するには

    ATI6
    07012345678
    OK

    基地局の位置情報(緯度、経度、郵便番号)を取得するには

    AT@LBC1
    AT@LBC?
    AT@LBC2

    白耳の場合(Willcom WZero3/WS004SH)

    AT@LBC?
    1234567                <<<< 郵便番号
    N35:22:33       <<<<緯度
    E139:44:55             <<<<<経度
    OK

    青耳の場合(Willcom 03)

    AT@LBC?
    1234567                <<<< 郵便番号
    N35:22:33       <<<<緯度
    E139:44:55             <<<<<経度
    OK

    ということで、フォーマットは同じでした。ラッキー!

    August 12

    WZero3 で、GPS?!

    PRO' LOGUE さんのところで、[03es] 擬似GPSでGoogleMap…MimicGPS という記事が紹介されています。
    明日からキャンプなんですが、カーナビついてないもので、これは!と思い、試してみました。
     
    以下、手順です。
     
    1. レジストリエディタで
       HKEY_LOCAL_MACHINE\ControlPanel\GPS Settings の
       Hide 1 を Hide 0
       に変更し、再起動すると、GPSコントロールパネルが表示された。
    2. レジストリエディタで
       HKEY_LOCAL_MACHINE\Drivers\BuiltIn\GPSIDレジストリ内に
       文字列キー(値:Dll/値のデータ:GPSID.dll)を追加する。
    3. [スタート]→[設定]→[システム]→[GPS]
       より、
       【プログラム】タブ内のGPSプログラムポートをCOM0に設定する。
       【ハードウェア】タブ内は設定をする必要は特に無し。
       【アクセス】タブ内の□GPSを自動的に管理するにチェックをつける。
    4. MimicGPSインストール
       公開先からダウンロードして実行する。
       測位開始をタップする。
       MimicGPS はそのまま実行しておく。
    5. WZero3 から、www.google.co.jp/gmm にアクセスして、
       Google Map をインストールする。
       [メニュー]→[現在地を検出] により、現在位置を表示する。
     
    これで、無事  WZero3 WS004SH でも動きました。
     
    こんなことを考える人がいるなんて・・・・すごい!
    August 03

    WZero3DeAmedas に関するバグレポート・要望など

    WZero3DeAmedas を公開します。
    WZero3DeAmedas に関するバグレポート・要望など、ありましたらこちらにコメントお願いします。
     
    元記事はこちら。
     
    現在の最新バージョンは、WZero3DeAmedas V2.0.4.0 (ベータ4)です。
     
    ツールのダウンロードは、
     
    2007/9/9 2.0.4.0 Beta4 Beta4バージョン。
      • レーダー・降水ナウキャストを過去2時間、予想1時間、10分刻みに修正。
      • スレッド動作中にアプリを終了できないバグを修正。
      • 拡大・縮小率の計算が間違っていたので、修正。これに伴い、拡大縮小率を次のように変更。
        全体表示(内接)→全体表示(外接)→150%→200%→400%
     

    無線LAN接続切替ツール バージョンアップ

    WZero3 で、無線LAN接続切替ツール の1,5,6 を使用していましたが、1.5.6(1.5.5も)には重大なバグがありました。ということなので、最新版の1.5.7 をインストール。Visual Studio で開発中のソフトを USB 接続でダウンロードしながら使っていると、USBの抜き差し後にW-SIMが無効になって、電話がかけられなくなるという問題があった。ひょっとしたら、この影響かもしれない。とりあえず、アップデートして様子を見てみることにします。
     
    August 02

    bLaunch のアイコンの背景色

    W-Zero3 でプログラムを作っていて、ほぼ完成したのでアイコンをまともにしようとして、はまりました。
    bLaunch というローンチャーを使用していますが、実はこれには背景色でマゼンタが使われているみたいです。
    このため、画像では本来 AmeDas と表示されるべき所が、Am Das となって、eが抜けています。
    本来は、icon の設定の画像にあるように、"e"だけマゼンタになっています。
    最初、すべてマゼンタにしていたので、なぜかbLaunch にアイコンが表示されず、数時間試行錯誤してしまいました。orz
    馬鹿みたい・・・
     
    なお、bLaunch に対して、Visual Studio から exe を配置しても、アイコンは変更されません。
    W-Zero3を再起動して、bLaunch がアイコンを再読み込みする必要があります。
     
     
    April 23

    WZero3 用 Windows Live for Mobile

    W-ZERO3 用 Windows Live for Windows Mobile がリリースされていて、今週は結構オンラインになっていました。帰宅途中で家にチャットするのも結構面白い。
     
     
    ただ、オンラインだと、かなりバッテリーが早くなくなるような気がします。
    April 22

    .NET Compact Framework 3.5

    Visual Studio Orcas March CTP を入れながら、.NET Compact Framework 3.5 になっている。
     
    によると、4つのエリアにフォーカスして開発中とのこと。
      1. 分散モバイルアプリケーションを作成するため、WCF(Windows Communication Foundation)との連携を可能とする
      2. デバイス固有のフィーチャーをLINQで実装
      3. 要求の高い機能の実現
      4. ダイアグと信頼性解決とサポートの問題のための機能をリファイン

    New Features Included in the Orcas January CTPでの新しい機能は次の通り

    • • HTTP compressionを含むSystem.IO.Compression のサポート
    • • LINQ の標準クエリオペレータのサブセットをサポート
    • • WaveOut による同時サウンドプレイを可能にする SoundPlayerのサポート.
    • • Smartphone and Pocket PCの識別を容易にするMicrosoft.WindowsCE.Forms の新しいAPI
    • • ネストしたFuncEvalを可能にする。??
    • • InterOpのログの強化
    • • Stack Trace の強化.
    • • GACの改良.
    • • StrongName keysを1024以上に対応.
    • • ファイナライザーの動作をログする機能を強化.(サポートのため)
    • . log fileを実行時に読み取り可能にする
     
     
    April 16

    W-Zero3 の.NETアプリを作ってみての感想

    メリット
    • Visual Studio でほとんど違和感なく C# でアプリが組める。すごく楽。
    デメリット
    • 結構メモリ食い。.NETアプリ4つも動かしたらアウトかも。
    • 起動が遅い。数秒待たされる。起動しておけばいいのだけど、メモリ食いなので、いまいち。
    • W-Zero3の機能(カメラ、通信など)を使おうと思うと、InterOpが必須になってしまい、結構面倒。

    ちょこっとしたアプリを作って遊ぶ分にはいいかもしれないけれども、売り物を作ろうと思うと、ネイティブで作らないと厳しいと思う。InterOpするぐらいなら、最初から C++で書いたほうが早そう。というっことで、NGEN for Windows Mobile が欲しい!

     

     

     

    AltEscape r1.04 をGet

    とりあえず、インストール完了。
     
    April 15

    WZero3の通信を切断する方法

    RASの切断方法
                に書いてあるとおり。
     
    呼び出し
                RasConn.CloseAllConnections();
    -----------------
    using System;
    using System.Runtime.InteropServices;
     
    namespace Uchukamen.WZero3
    {
        /// <summary>
        /// This class is based on code from "mikinder".
        /// http://www.developersdex.com/vb/message.asp?p=2916&r=5643969
        /// </summary>
        class RasConn
        {
            const int MAX_PATH = 260;
            const int RAS_MaxDeviceType = 16;
            const int RAS_MaxPhoneNumber = 128;
            const int RAS_MaxEntryName = 20;
            const int RAS_MaxDeviceName = 128;
            const int SUCCESS = 0;
            const int ERROR_NOT_ENOUGH_MEMORY = 8;
            const int RASBASE = 600;
            const int ERROR_BUFFER_TOO_SMALL = RASBASE + 3;
            const int ERROR_INVALID_SIZE = RASBASE + 32;
            #region DllImport
            //// --- RASCONN data structure definition (refer to ras.h) --
            //private const int RAS_MaxEntryName = 20;
            [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
            public struct RASCONN
            {
                public int dwSize;
                public IntPtr hrasconn;
                [MarshalAs(UnmanagedType.ByValTStr, SizeConst = RAS_MaxEntryName + 1)]
                public string szEntryName;
            }
            // --------------------------------------------
            [DllImport("coredll.dll", SetLastError = true, CharSet = CharSet.Auto)]
            private static extern uint RasEnumConnections(
                [In, Out] RASCONN[] rasconn,
                [In, Out] ref int cb,
                [Out] out int connections);
            [DllImport("coredll.dll")]
            private static extern uint RasHangUp(IntPtr pRasConn);
            #endregion
            /// <summary>
            /// Returns all active RAS connections as an array of data structure RASCONN
            /// </summary>
            /// <returns></returns>
            public static RASCONN[] GetAllConnections()
            {
                RASCONN[] tempConn = new RASCONN[1];
                RASCONN[] allConnections = tempConn;
                tempConn[0].dwSize = Marshal.SizeOf(typeof(RASCONN));
                int lpcb = tempConn[0].dwSize;
                int lpcConnections = 0;
                uint ret = RasEnumConnections(tempConn, ref lpcb, out lpcConnections);
                if (ret == ERROR_INVALID_SIZE)
                {
                    throw new Exception("RAS: RASCONN data structure has invalid format");
                }
                else if (ret == ERROR_BUFFER_TOO_SMALL && lpcb != 0)
                {
                    // first call returned that there are more than one connections
                    // and more memory is required
                    allConnections = new RASCONN[lpcb / Marshal.SizeOf(typeof(RASCONN))];
                    allConnections[0] = tempConn[0];
                    ret = RasEnumConnections(allConnections, ref lpcb, out lpcConnections);
                }
                // Check errors
                if (ret != SUCCESS)
                {
                    throw new Exception("RAS returns error: " + ret);
                }
                if (lpcConnections > allConnections.Length)
                {
                    throw new Exception("RAS: error retrieving correct connection count");
                }
                else if (lpcConnections == 0)
                {
                    // if there are no connections resize the data structure
                    allConnections = new RASCONN[0];
                }
                return allConnections;
            }
            /// <summary>
            /// Closes all active RAS connections
            /// </summary>
            /// <returns></returns>
            public static void CloseAllConnections()
            {
                RASCONN[] connections = GetAllConnections();
                for (int i = 0; i < connections.Length; ++i)
                {
                    RasHangUp(connections[i].hrasconn);
                }
            }
        }
    }
    April 14

    .NET Compact FrameworkのP/Invoke

    WZero3 でアプリを書いていて、接続の制御をしようとして適当に書いていたら、動かない。ちょっと調べてみたら、.NET Compact Framework は .NET Framework のサブセットなので完全な .NET Framework の方法とはやや異なる。ということで、注意が必要。

    Microsoft .NET Compact Framework の P/Invoke とマーシャリング入門

    Microsoft .NET Compact Framework での高度な P/Invoke

     
    ぐちゃぐちゃ書いてあって、わかりにくいので、簡単にポイントだけ整理する。

    .NET Compact Framework の相違点の概要
      • SetLastError を true にすることを忘れないように。[DllImport("abc.dll", SetLastError=true)]
      • すべてが Unicode
      • Winapi(既定のCdecl) のみをサポート
      • .NET Compact FrameworkのP/Invokeは、 コールバックをサポートしない
      • EntryPointNotFoundException, ExecutionEngineExceptionのかわりに、 MissingMethodExceptionとNotSupportedExceptionが上がる
      • Formでは、ウィンドウハンドル (hwnd)、DefWndProc メソッドがサポートされない。MessageWindow、Messageクラスを使用して、他のウィンドウにメッセージを送信できる。サンプル コード... smartdevices.microsoftdev.com 。
      • 複合オブジェクト (参照型) をマーシャリングできないことがある。特に、構造体の中にstring配列があるような場合は注意。対応法方法は複数あり。

    構造体内の文字列のマーシャリング

    構造体内またはクラス内の文字列ポインタを正しくマーシャリングできない。対応方法は次の3つがある。
        • サンク層での呼び出し
        • unsafe ブロックの使用
        • 文字列ポインタを処理するカスタム クラスの作成

    構造体内の固定長文字列のマーシャリング

    System.Char の配列が実行時に配列への 4 バイト ポインタとしてマーシャリングされるので、構造体内の固定長文字列のマーシャリングは単純には動作しない。対応方法は2つ。
      • 正確な合計サイズのバイト配列を作成した後、構造体の各フィールドをバイト配列にコピーしたり、バイト配列からコピーする。 →複雑。
      • カスタム マーシャリングを組み合わせる方法。

    ------------------

    class Memory のC#版
    using System;
    using System.Runtime.InteropServices;
    using System.ComponentModel;
    namespace Uchukamen.WZero3
    {
        class Memory
        {
            [DllImport("coredll.dll", SetLastError = true)]
            private static extern IntPtr LocalAlloc(int uFlags, int uByte);
            [DllImport("coredll.dll", SetLastError = true)]
            private static extern IntPtr LocalFree(IntPtr hMem);
            [DllImport("coredll.dll", SetLastError = true)]
            private static extern IntPtr LocalReAlloc(IntPtr hMem, int uBytes, int fuFlags);
            private const int LMEM_FIXED = 0;
            private const int LMEM_MOVEABLE = 2;
            private const int LMEM_ZEROINIT = 0x40;
            private const int LPTR = LMEM_FIXED | LMEM_ZEROINIT;
            // LocalAlloc を使用して、メモリ ブロックを割り当てます。
            public static IntPtr AllocHLocal(int cb)
            {
                return LocalAlloc(LPTR, cb);
            }
            // AllocHLocal で割り当てられたメモリを解放します。
            public static void FreeHLocal(IntPtr hlocal)
            {
                if (!hlocal.Equals(IntPtr.Zero))
                {
                    if (!IntPtr.Zero.Equals(LocalFree(hlocal)))
                    {
                        throw new Win32Exception(Marshal.GetLastWin32Error());
                    }
                    hlocal = IntPtr.Zero;
                }
            }
            // 以前に AllocHLocal で割り当てられたメモリ ブロックのサイズを変更します。
            public static IntPtr ReAllocHLocal(IntPtr pv, int cb)
            {
                IntPtr newMem = LocalReAlloc(pv, cb, LMEM_MOVEABLE);
                if (newMem.Equals(IntPtr.Zero))
                {
                    throw new OutOfMemoryException();
                }
                return newMem;
            }
            // マネージ文字列の内容をアンマネージ メモリにコピーします。
            public static IntPtr StringToHLocalUni(string s)
            {
                if (s == null)
                    return IntPtr.Zero;
                else
                {
                    int nc = s.Length;
                    int len = 2 * (1 + nc);
                    IntPtr hLocal = AllocHLocal(len);
                    if (hLocal.Equals(IntPtr.Zero))
                        throw new OutOfMemoryException();
                    else
                    {
                        Marshal.Copy(s.ToCharArray(), 0, hLocal, s.Length);
                        return hLocal;
                    }
                }
            }
        }
    }
     

    April 11

    RASCONN

    結構面倒
      C:\Program Files\Microsoft Visual Studio 8\SmartDevices\SDK\Smartphone2003\Include\ras.h

    #define RAS_MaxEntryName      20
    RASCONNW
    {
        DWORD    dwSize;
        HRASCONN hrasconn;
        WCHAR    szEntryName[ RAS_MaxEntryName + 1 ];
    };

    #define RASCONN RASCONNW
     
    注意: sizeof RASCONN は、4 + 4 + 2 * ( RAS_MaxEntryName + 1 ) = 50 byteだけども、4byte バウンダリーになるため、52 byteになる。
    -------------
    参考になるリンク
    April 01

    WZero3 ActiveApplicationの取得

            SystemState activeApplication = new SystemState(SystemProperty.ActiveApplication);

            activeApplication.Changed += new ChangeEventHandler(activeApplication_Changed);
     
            void activeApplication_Changed(object sender, ChangeEventArgs args)
            {
                string res = (string)args.NewValue;
                string[] apps = res.Split(new char[] { '\x1b' });
            }
     
    エスケープシーケンスで区切られた文字列でアクティブなアプリケーションの名前が帰ってくる。
    January 30

    緯度、経度より、最も至近のAmedasの観測所コードを取得する XML Web Service

    全国のAmedas コードをデータベースに入れて、経度、緯度から、至近の観測ポイントのIDを取り出すストアドを作って、XML Web Service化した。
     
    呼び出しは、
    int code = amedas.GetNearestCode(35.1239f, 139.455f);
    ああっ、なんて楽チンな。
     
    緯度、経度をとる方法は分かったが、こたさんの情報によると、InterOpしなきゃ・・だめか・・・
    あと2日。
    -------------
    using System;
    using System.Data;
    using System.Web;
    using System.Collections;
    using System.Web.Services;
    using System.Web.Services.Protocols;
    using System.ComponentModel;
    using System.Configuration;
    using System.Data.SqlClient;
    namespace WebServiceAmedas
    {
        /// <summary>
        /// WebServiceAmedas の概要の説明です
        /// </summary>
        [WebService(Namespace = "http://uchukamen.com/")]
        [WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]
        [ToolboxItem(false)]
        public class Amedas : System.Web.Services.WebService
        {
            /// <summary>
            /// 緯度、経度より、最も至近のAmedasのエリアコードを取得する。
            /// </summary>
            /// <param name="latitude">緯度</param>
            /// <param name="longitude">経度</param>
            /// <returns></returns>
            [WebMethod]
            public int GetNearestCode(float latitude, float longitude)
            {
                string connectionString = ConfigurationManager.ConnectionStrings["uchukamen_comConnectionString1"].ConnectionString;
                using (SqlConnection sqlConn = new SqlConnection(connectionString))
                using (SqlCommand sqlCmdStored = new SqlCommand("GetNearestAmedasCode"))
                {
                    sqlCmdStored.CommandType = CommandType.StoredProcedure;
                    SqlParameter sqlLatitude = new SqlParameter("@緯度", SqlDbType.Float);
                    sqlLatitude.Value = latitude;
                    sqlCmdStored.Parameters.Add(sqlLatitude);
                    SqlParameter sqlLongitude = new SqlParameter("@経度", SqlDbType.Float);
                    sqlLongitude.Value = longitude;
                    sqlCmdStored.Parameters.Add(sqlLongitude);
                    sqlConn.Open();
                    sqlCmdStored.Connection = sqlConn;
                    using (SqlDataReader dr = sqlCmdStored.ExecuteReader())
                    {
                        if (dr.Read())
                        {
                            return (int)dr["ID"];
                        }
                    }
                }
                return 0;
            }
        }
    }
    January 24

    リサイズイベントで、スクリーンオリエンテーションを変更すると例外

    環境: Windows Mobile 5.0、.NET Compact Framework 2.0
     
     
    レイアウトがめんどくさいので、スクリーンのオリエンテーションが変更されるときに発生するリサイズイベントの中で、スクリーンのオリエンテーションを変更しようとすると、例外("RegistryException")になる。
     
            private void Form1_Resize(object sender, EventArgs e)
            {
                if (SystemState.DisplayRotation == 0)
                    SystemSettings.ScreenOrientation = ScreenOrientation.Angle90;
            }
     
    この対応は、 
    ..NET Compact Framework 向けの表示方向切り替え対応および高dpi対応アプリケーションの開発
    にあるように、ポートレート、ランドスケープ、どちらでも正しくレイアウトするようにする。
     
    ただ、コントロールの数が多いと大変。
    今回は、面倒だけど、この方法で対処。
    January 23

    コードピッチテクニック (code pitching technique ) とは

    コードピッチテクニック (code pitching technique ) とは
     
    しばらく使われていないメソッドで使われているメモリを解放し、メソッドのネィティブコードコードブロックを解放する機能。
    コードブロックをスタブで置き換え、再度呼ばれた時にスタブがJITerを呼び出し、ネィティブコードを再生成する。
     
    ふ~~ん、苦労しているねぇ・・・
    早く Windows Mobile 6.0 出ないかな・・・そうすればメモリの制約がかなり軽減されるはず。
     
    参照先
     
    In addition, the economy JITter supports code pitching. Code pitching is the ability for the common language runtime to discard a method's native code block, freeing up memory used by methods that haven't been executed in a while. Of course, when the common language runtime pitches a block of code, it replaces the method with a stub so that the JITter can regenerate the native code the next time the method is called.