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

環境: 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";

 

W-ZERO3用 メモリ容量取得クラス

W-ZERO3 プログラミングコンテスト用の部品を作り始める。
1月末まであと10日。実質、3日間。間に合うか?
複雑なことはできないので、とりあえず簡単にできるものを。
 
using System;
using System.Collections.Generic;
using System.Text;
using System.Runtime.InteropServices;
 
namespace Uchukamen.WZero3
{
    public class MemoryStatus
    {
        private class MEMORYSTATUS
        {
            public uint dwLength = 0;
            public uint dwMemoryLoad = 0;
            public uint dwTotalPhys = 0;
            public uint dwAvailPhys = 0;
            public uint dwTotalPageFile = 0;
            public uint dwAvailPageFile = 0;
            public uint dwTotalVirtual = 0;
            public uint dwAvailVirtual = 0;
        }
        [DllImport("CoreDll.dll")]
        private static extern void GlobalMemoryStatus
        (
        MEMORYSTATUS lpBuffer
        );
        [DllImport("CoreDll.dll")]
        public static extern int GetSystemMemoryDivision
        (
        ref uint lpdwStorePages,
        ref uint lpdwRamPages,
        ref uint lpdwPageSize
        );
        private float totalPhys = 0;
        public float TotalPhysicalMB
        {
            get { return totalPhys; }
        }
        private float availPhys = 0;
        public float AvailPhysicalMB
        {
            get { return availPhys; }
        }
        private float totalVirtual = 0;
        public float TotalVirtualMB
        {
            get { return totalVirtual; }
        }
        private float availVirtual = 0;
        public float AvailVirtualMB
        {
            get { return availVirtual; }
        }
        public void Get()
        {
            uint storePages = 0;
            uint ramPages = 0;
            uint pageSize = 0;
            int res = GetSystemMemoryDivision(ref storePages, ref ramPages, ref pageSize);
            MEMORYSTATUS memStatus = new MEMORYSTATUS();
            GlobalMemoryStatus(memStatus);
            totalPhys = memStatus.dwTotalPhys / 1024F / 1024F;
            availPhys = memStatus.dwAvailPhys / 1024F / 1024F;
            totalVirtual = memStatus.dwTotalVirtual / 1024F / 1024F;
            availVirtual = memStatus.dwAvailVirtual / 1024F / 1024F;
        }
    }
}
 
呼び出し
            MemoryStatus mstat = new MemoryStatus();
            mstat.Get();            textBox1.Text =
             "合計 物理   " + mstat.TotalPhysicalMB.ToString("n2") + " MB\r\n" +
             "空き 物理   " + mstat.AvailPhysicalMB.ToString("n2") + " MB\r\n" +
             "合計 仮想   " + mstat.TotalVirtualMB.ToString("n2") + " MB\r\n" +
             "空き 仮想   " + mstat.AvailVirtualMB.ToString("n2") + " MB\r\n";
 

Windows Mobile 開発メモ

開発環境構築メモ
 
1.VS2005 をインストール
2.Windows Mobile 5.0 SDK for Pocket PC (英語)をインストール 約174MB
   READMEによると、
  SDKを入れる前に、Please disable any virus checking software prior to installation. すること。
  ActiveSync over Ethernetは動かない。
  言語ごとにあるので、Windows Mobile 5.0 Emulator Images for Pocket PC – JPN.msi を選択。約106MB
  インストール時に、SDKとActiveSync 4.0 が必要と表示されるが、必要なし。