W-SIM状態チェック

こたさんからの情報
通信中を強制切断するには?
 
【 W-SIM状態チェック】
        [DllImport("shphonelib.dll", EntryPoint = "?GetWsimStateInfo@CshphoneClientlib@@SAHXZ")]
        public static extern int GetWsimStateInfo();

//0:通常
//-2:W-SIMなし
//-3:通信中
//-7:停止

【 W-SIM ON/OFF】
        [DllImport("shphonelib.dll", EntryPoint = "?SuspendRadio@CshphoneClientlib@@SAHH@Z")]
        public static extern int SuspendRadio( int val);
    val…0  W-SIM アンテナOff
    val…1  W-SIM アンテナOn
 
 

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

XML Web Serviceで名前空間を変更するとエラー

たとえば、XML Web Service のファイルで、namespace WebServiceAmedasを、namespace Uchukamen.WZero3 のように変更して、その他関連する場所も変更したつもりでも、なぜかエラーになる。何が関係しているのか不明・・・。リファクタリングでも面倒みてくれない。今は時間がないので、とりあえずメモ。

発生するエラーは、次の通り。

‘/’ アプリケーションでサーバー エラーが発生しました。


ランタイム エラー

説明: サーバーでアプリケーション エラーが発生しました。このアプリケーションの現在のカスタム エラー設定では、セキュリティ上の理由により、アプリケーション エラーの詳細をリモート表示できません。ただし、ローカル サーバー コンピュータで実行されているブラウザで表示することはできます。

詳細: このエラー メッセージの詳細をリモート コンピュータで表示できるようにするには、現在の Web アプリケーションのルート ディレクトリにある "web.config" 構成ファイル内に、<customErrors> タグを作成してください。その後で、この <customErrors> タグで "mode" 属性を "off" に設定してください。

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

環境: 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対応アプリケーションの開発
にあるように、ポートレート、ランドスケープ、どちらでも正しくレイアウトするようにする。
 
ただ、コントロールの数が多いと大変。
今回は、面倒だけど、この方法で対処。

コードピッチテクニック (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.

 

 

Compact Framework のメモリ管理

W-Zero3 用のメモリ状況を表示するアプリケーションを作ってみたところ、メモリの挙動がおかしい。
 
たとえば、
起動初期状態で25MBほどあるフリーメモリーが、アプリを起動した後は22MBぐらいになる。
その後、メールを見たり、IEを開いたり、いろいろ使っているうちに10MBぐらいになる。
その後、すべてのアプリケーションを閉じてメモリを解放しても、初期の25MBには戻らず、15MB程度になる。
 
最初、プログラムのメモリ管理が悪く、Disposeまわりでメモリーリークが発生しているのかと思っていろいろやってみたが、先にポスとしたプログラムなので、そんなメモリリークが発生するような複雑なコードではない。
 
MSDN を調べてみたところ、やはりシステム側で動的にキャッシュを管理しているということですね。
 
MSDN の記事は次の通り。
 

RAM ストレージ

ランダム アクセス メモリ (RAM) を使用して、動的なデータ構造と JIT でコンパイルされたコードを保存します。.NET Compact Framework は、デバイスで指定された制限内で、使用可能な RAM を使用して生成されたコードやデータ構造をキャッシュし、後から適宜メモリを解放します。

メモリ不足になると、共通言語ランタイムではコードピッチ技法を使用して、JIT でコンパイルされたコード ブロックを実行時に解放します。これにより、RAM に制約のあるシステムで大きいプログラムを実行するときに、パフォーマンスの低下を最小限に抑えることができます。
 』

W-Zero3 用開発環境設定

レイアウトに関するメモ
 
メニュー→ターゲットプラットフォームの変更で、
『Windows Mobile 5.0 Pocket PC SDK』 を選択。
 
Form のプロパティで、FormFactor を
『Windows Mobile 5.0 Pocket PC VGA』を選択。
 
これをで正しくレイアウトができた。
 
—————–
ターゲットプラットフォームの変更で、Windows CE 5.0 だと、VS2005では 640×480 でレイアウトできるが、
実行すると、320×240 のサイズになってしまう。
 
 

緯度、経度より標高を返すクラス

緯度、経度より標高を返す web service を発見。
 
とりあえず、Windows Formsで作ってみた。
Compact Framework 5.0 で、ネームスペースサポートされているのかな・・・
 
using System;
using System.Collections.Generic;
using System.Text;
using System.Net;
using System.IO;
using System.Web;
using System.Diagnostics;
using System.Xml;
namespace Uchukamen.WZero3
{
    class Altitude
    {
        private const string webServiceUrl = "http://lab.uribou.net/ll2h/";
        public static float GetAltitude(string latitude, string longitude)
        {
            string encodedUrl = GetEncodedUrl(latitude, longitude);
            HttpWebRequest req = (HttpWebRequest)WebRequest.Create(encodedUrl);
            req.Method = "GET";
            float height = 0F;
            int err = 0;
            string msg = "";
            // レスポンスの取得と読み込み
            WebResponse res = req.GetResponse();
            using (Stream resStream = res.GetResponseStream())
            using (XmlTextReader reader = new XmlTextReader(resStream))
            {
                while (!reader.EOF)
                {
                    if (reader.IsStartElement("height"))
                        height = reader.ReadElementContentAsFloat();
                    else if (reader.IsStartElement("error"))
                        err = reader.ReadElementContentAsInt();
                    else if (reader.IsStartElement("message"))
                        msg = reader.ReadElementString("message");
                    else
                        reader.Read();
                }
                if (err != 0)
                    throw (new Exception(msg));
            }
            return height;
        }
        private static string GetEncodedUrl(string latitude, string longitude)
        {
            string url = webServiceUrl + "?ll="
                + latitude + "," + longitude;
            string encodedUrl = HttpUtility.HtmlEncode(url);
            return encodedUrl;
        }
    }
}
呼び出し
            textBoxAltitude.Text= Altitude.GetAltitude(textBoxLatitude.Text, textBoxLongitude.Text).ToString();

W-ZERO3用 CPU使用率取得クラス

using System;
using System.Collections.Generic;
using System.Text;
using System.Runtime.InteropServices;
using System.Diagnostics;
namespace Uchukamen.WZero3
{
    class CPUStatus
    {
        [DllImport("COREDLL.DLL")]
        private extern static uint GetTickCount();
        [DllImport("COREDLL.DLL")]
        private extern static uint GetIdleTime();
        private static uint dwStartTick = 0;
        private static uint dwIdleSt = 0;
        /// <summary>
        /// CPU使用率
        /// </summary>
        /// <returns>uint 0:最小-100:最大</returns>
        public uint GetCPU()
        {
            uint dwStopTick = GetTickCount();
            uint dwIdleEd = GetIdleTime();
            uint idle = ((100 * (dwIdleEd – dwIdleSt)) / (dwStopTick – dwStartTick));
            dwStartTick = dwStopTick;
            dwIdleSt = dwIdleEd;
            uint cpu = 100 – idle;
            Debug.WriteLine(cpu.ToString());
            return cpu;
        }
    }
}
 
呼び出し
            CPUStatus cpuStat = new CPUStatus();
            uint cpu = cpuStat.GetCPU();

W-ZERO3用 ディスク容量取得クラス

using System;
using System.Collections.Generic;
using System.Text;
using System.Runtime.InteropServices;
namespace Uchukamen.WZero3
{
    public class DiskStatus
    {
        [DllImport("coredll.dll")]
        public static extern bool GetDiskFreeSpaceEx
           (
           string directory,
           ref UInt64 lpFreeBytesAvailableToCaller,
           ref UInt64 lpTotalNumberOfBytes,
           ref UInt64 lpTotalNumberOfFreeBytes
           );
        #region プロパティ
        /// <summary>
        /// The total number of free bytes on the disk
        /// that are available to the user associated with the calling thread.
        /// </summary>
        private UInt64 freeBytesAvailableToCaller = 0;
        public UInt64 FreeBytesAvailableToCaller
        {
            get { return freeBytesAvailableToCaller; }
        }
        public float FreeMB
        {
            get { return (float)freeBytesAvailableToCaller / 1024F / 1024F; }
        }
       
        /// <summary>
        /// The total number of bytes on the disk
        /// that are available to the user associated with the calling thread.
        /// </summary>
        private UInt64 totalNumberOfBytes = 0;
        public UInt64 TotalNumberOfBytes
        {
            get { return totalNumberOfBytes; }
        }
        public float TotalMB
        {
            get { return (float)totalNumberOfBytes/1024F/1024F; }
        }
       
       
        /// <summary>
        /// The total number of free bytes on the disk.
        /// </summary>
        private UInt64 totalNumberOfFreeBytes = 0;
        public UInt64 TotalNumberOfFreeBytes
        {
            get { return totalNumberOfFreeBytes; }
        }
        #endregion
        /// <summary>
        /// ディスク容量を取得する。
        /// </summary>
        /// <param name="path">ディスクのパス</param>
        public void Get(string path)
        {
            bool res = GetDiskFreeSpaceEx(
                path,
                ref freeBytesAvailableToCaller,
                ref totalNumberOfBytes,
                ref totalNumberOfFreeBytes);
        }
    }
}
呼び出し
            DiskStatus dstat = new DiskStatus();
            dstat.Get("\\");

            textBox1.Text +=
             "空き容量     " + dstat.FreeMB.ToString("n2") + " MB\r\n" +
             "合計容量     " + dstat.TotalMB.ToString("n2") + " MB\r\n";