bLaunch のアイコンの背景色

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

WZero3 用 Windows Live for Mobile

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

.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を実行時に読み取り可能にする
 
 

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

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

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

 

 

 

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);
            }
        }
    }
}

.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;
                }
            }
        }
    }
}
 

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になる。
————-
参考になるリンク

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’ });
        }
 
エスケープシーケンスで区切られた文字列でアクティブなアプリケーションの名前が帰ってくる。

緯度、経度より、最も至近の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;
        }
    }
}