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

Blog


    July 16

    プロセスモニタ

    どこかで見たことのあるようなものをWPFで作ってみた。

    image

    簡単に作れるだろうと思っていたのだけど、いくつか、ハマり中。

    1.プロセスの情報を取るいいI/Fが見つからない。System.Diagnostics.Process.GetProcesses() だと、プロセッサタイムが取得できないので、しかたなしにWMIでプロセスの情報を取っているのだけれど、結構重くって、CPUパワーが食われまくり。パフォーマンスカウンターを全プロセス分持つのも芸がないし、Win32 SDKを叩くか?? .NETで、いい方法ない?

    2.画面のリサイズもフォントサイズとPolygon の関係をちゃんと考えないといけないので、意外と難しい。

    3.おまけに6角形にレイアウトするのも面倒。誰か、HexaFlowコントロール作ってくれないかな w

    でも、こんな感じで http://uchukamen.com/pmon/publish.htm 意外と見ていて面白い。

    PS. LINQ は偉大だ。もう LINQ 無しでは生きていけない体になってしまった。

    July 15

    Generic Dictionary の foreach

    あまり使わないので忘れないようにメモ

    Dictionary<uint, Process> processDict = new Dictionary<uint, Process>(100);

    foreach (KeyValuePair<uint, Process> val in processDiff)
    {
       Process p = val.Value;
             …
    }

    July 13

    WPF ユーザーコントロール

    <UserControl x:Class="WpfApplication6.Cell"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
            >
        <Grid >
        <Polygon Name="Polygon" Margin="5 5 5 5"
        Points="25,0 75, 0 100,43 75,86 25, 86 0 43"
        Stroke="Purple"
        StrokeThickness="2">
                <Polygon.Fill>
                    <SolidColorBrush Color="Red" Opacity="0.8"/>
                </Polygon.Fill>
            </Polygon>

            <Label Name="label1" HorizontalContentAlignment="Center" Margin="6,15,6,0">Label</Label>
            <Label Name="label2" HorizontalContentAlignment="Center" Margin="4,47,8,21" >Label</Label>
        </Grid>

    </UserControl>

    用途は・・・

    Process 情報の取得に関するメモ2

    WMI を使用して Process 情報を取得する際に LINQ を使用しようとすると

    ManagementObjectSearcher query1 = new ManagementObjectSearcher("SELECT * FROM Win32_Process");
    ManagementObjectCollection queryCollection1 = query1.Get();

    var query = from proc in queryCollection1 select proc;
    foreach (var process in query)
    {
       …
    }

    エラー    1    ソース型 'System.Management.ManagementObjectCollection' のクエリ パターンの実装が見つかりませんでした。'Select' が見つかりません。範囲変数 'proc' の型を明示的に指定してください。    C:\Users\uchukamen\Documents\Visual Studio 2008\Projects\WpfApplication6\WpfApplication6\Window1.xaml.cs    140    38    WpfApplication6

    というエラーになる。

    回避方法は、範囲変数 proc の型を明示的に指定するために、queryCollection1.Cast<ManagementObject>()  としてあげるとうまくいった。うむむむむ・・・

    ManagementObjectSearcher query1 = new ManagementObjectSearcher("SELECT * FROM Win32_Process");
    ManagementObjectCollection queryCollection1 = query1.Get();

    var query = from proc in queryCollection1.Cast<ManagementObject>() select proc;
    foreach (var process in query)
    {
        Console.WriteLine(process["ProcessId"] + ":");
        Console.WriteLine(process["Name"] + ":");
        Console.WriteLine(process["KernelModeTime"] + ":");
        Console.WriteLine(process["UserModeTime"] + ":");
    }

    ------

    もうちょっと見やすく?すると、IEnumerable<ManagementObject> にキャストしてくれるということ。

    ManagementObjectSearcher query1 = new ManagementObjectSearcher("SELECT * FROM Win32_Process");
    ManagementObjectCollection queryCollection1 = query1.Get();
    IEnumerable<ManagementObject> procQuery = queryCollection1.Cast<ManagementObject>();

    var procs = from proc in procQuery select proc;

    foreach (var process in procs)
    {
        Console.WriteLine(process["ProcessId"] + ":");
        Console.WriteLine(process["Name"] + ":");
        Console.WriteLine(process["KernelModeTime"] + ":");
        Console.WriteLine(process["UserModeTime"] + ":");
    }

    Process 情報の取得に関するメモ

    Visual Studio 2008 , Vista で、GetProcesses() でプロセス情報を取得する際に、TotalProcessorTime などプロセッサタイムを取得しようとすると、Win32Exception により取得できない。なぜ??

    var query = from proc in System.Diagnostics.Process.GetProcesses()
                orderby proc.Id
                select new
                {
                    Id = proc.Id,
                    processName = proc.ProcessName,
                    TotalProcessorTime = proc.TotalProcessorTime
                };

    foreach (var process in query)
    {
        Console.WriteLine(process.Id + ":");
        Console.WriteLine(process.processName + ":");
        Console.WriteLine(process.TotalProcessorTime + ":");
    }

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

    WMI を使用すれば、取得可能。

    ManagementObjectSearcher query1 = new ManagementObjectSearcher("SELECT * FROM Win32_Process");
    ManagementObjectCollection queryCollection1 = query1.Get();

    foreach (ManagementObject mo in queryCollection1)
    {
        Console.WriteLine(mo["ProcessId"] + "\t" + mo["Name"] + "\t" +
            ":\tKernelModeTime=" + mo["KernelModeTime"] +  // in 100 nanosecond units
            ":\tUserModeTime=" + mo["UserModeTime"]);   // in 100 nanosecond units
    }

    July 06

    Visual Studio 2010

    image

    でフローティングを使用すると、

    image

    独立ウィンドウで開けるのがいい感じ。

    Visual Studio 2010 Parallel - Process

    シーケンシャルだと

    var query = from proc in System.Diagnostics.Process.GetProcesses() select proc;
    foreach (var process in query)
    {
        Console.WriteLine(process.Id + " : " + process.ProcessName);
    }

    これがパラレルだと、

    var query = from proc in System.Diagnostics.Process.GetProcesses() select proc;
    Parallel.ForEach(query, process =>
        {
            Console.WriteLine(process.Id + " : " + process.ProcessName);
        }
    );

    処理的には、パラレルでもシーケンシャルでも関係ないので、パラレルで実行しているほうが処理する人の感覚(意図)に近いのかもしれない。

    Visual Studio 2010 Parallel

    Visual Studio 2010 beta を入れてみた。

    image

     

    using System.Threading;
    using System.Diagnostics;

    Stopwatch sw = new Stopwatch();
    sw.Start();
    Parallel.For(0, 10, x =>
        {
            Console.WriteLine(x.ToString() + " : " + Thread.CurrentThread.ManagedThreadId.ToString());
            Thread.Sleep(5000);
        }
    );
    sw.Stop();

    実行結果

    x : ManagedThreadId

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

    0 : 8
    5 : 10
    1 : 11
    6 : 12
    2 : 13
    7 : 14
    3 : 15
    4 : 8
    8 : 10
    9 : 10

    こんなことができてしまうなんて・・・

    May 25

    Codeseek 勉強会のWinRing0の資料をアップしました。

    第40回codeseek勉強会
    「宇宙仮面のWinRing0」
    (共催:tk-engineeringこみゅぷらすeパウダ~.Net/C# Group)

    開催日:2009年5月19日(火) 19:00~21:00 18:55に6F受付集合
    場所:マイクロソフト社新宿オフィス6F会議室
    募集締め切り:2009年5月16(土)23時59分59秒
    20名まで
    参加費無料

    Codeseek 勉強会のWinRing0の資料を
    http://uchukamen.com/wpf/WinRing0/
    にアップしました。
    May 05

    CPUの温度取得に関するメモ4

    Intel® 64 and IA-32 Architectures Software Developer’s Manual によると、今使用中の ASUS P5LD2-V + Pentium 4 D では、MSR から CPU の温度が取れないことが判明した。

    で、http://kariunten.homeip.net/programming/winring0.html

    にマザーボードのI/Oコントローラからデータを取得する方法が載っていたので、OpenLibSys で試してみた。

    ASUS P5LD2-Vのマニュアルを調べてみると、コントローラは W83627EHF だったので、そのマニュアル

    http://www.winbond-usa.com/products/winbond_products/pdfs/PCIC/W83627EHF_W83627EHG.pdf

    を調べてみた。それによると、このチップには温度センサーが3つ搭載されている。ただし、マザーボード上で使用されているのは、CPUTIN Temperature、SYSTIN Temperature の2つのみで、AUXTIN Temperatureは使用されていない模様。

    このコントローラーからデータを取得するには、IO ポートからデータを取得すればよい。

    取得する方法は、0x295 ポートにレジスタを指定、0x296 ポートからデータを取得するという手順。

    ただし、バンクが 0, 1, 2, 3, 4 とあり、0x50 以上のレジスターにアクセスするには、バンクを切り替える必要がある。バンクの切り替え方法は、0x4E ポートの下位3ビットで指定する。

    CPUTIN (CPUの温度)は、

    バンク1、0x50 レジスタにハイビット(温度 ℃)

    バンク1、0x51 レジスタにロービット(温度 7ビット目が立っていれば +0.5℃)

    となっているので、次のようなコードになる。

    //=======================================
    // CPUTIN Temperature
    //=======================================
    // バンク1
    ols.WriteIoPortByte(0x295, 0x4E);
    ols.WriteIoPortByte(0x296, 0x81);
    // データ読出し(50h Bank1)
    ols.WriteIoPortByte(0x295, 0x50);
    hi = ols.ReadIoPortByte(0x296);

    // バンク1
    ols.WriteIoPortByte(0x295, 0x4E);
    ols.WriteIoPortByte(0x296, 0x81);
    // データ読出し(10h Bank1)
    ols.WriteIoPortByte(0x295, 0x51);
    lo = ols.ReadIoPortByte(0x296);

    Console.WriteLine("CPUTIN Temperature Low : ...." + lo.ToString("X") + "\r\n");
    Console.WriteLine("CPUTIN Temperature High: ...." + hi.ToString("X") + "\r\n");

    float CPUTIN = hi + ((lo & 0x80) != 0 ? 0.5f : 0);

    Console.WriteLine("CPUTIN Temperature: ...." + CPUTIN.ToString() + "\r\n");

    同様に、SYSTIN (マザーボードの温度)は、バンク0、0x27 レジスタなので、

    //=======================================
    // SYSTIN Temperature
    //=======================================

    // バンク0 を指定
    ols.WriteIoPortByte(0x295, 0x4E);
    ols.WriteIoPortByte(0x296, 0x81);
    // データ読出し(27h Bank0)
    ols.WriteIoPortByte(0x295, 0x27);
    hi = ols.ReadIoPortByte(0x296);

    Console.WriteLine ("SYSTIN Temperature: ...." + hi.ToString() + "\r\n");

    なお、SYSTINでは、0.5℃単位の測定はできない仕様になっている。

    結果は次の通り。

    [CPUTIN Temperature]
    CPUTIN Temperature Low : ....80
    CPUTIN Temperature High: ....21
    CPUTIN Temperature: ....33.5

    [SYSTIN Temperature]
    SYSTIN Temperature: ....24

    下は、ASUS のおまけアプリの Probe II のデータ

    image

    image

    おおおおっ、ちゃんと取れるじゃないですか。OpenLibSys 偉大だ。

    というか、Core2にアップしてしまえば、MSRで取れるので、こんなことしないですむんだけどなぁ・・・

    というか、こんなハード固有の実装させないように頑張ってよ >> MS

    というか、温度を気にしないといけないような CPU 勘弁してよ >> Intel, AMD

    CPUの温度取得に関するメモ3

    MSR(Model Specific Register) 0x19C Bits [22:16] で温度が取得できることは確認できたが、このセンサーの値は、Tjmax への相対値であることがマニュアルに書かれている。しかし、そのTjmaxの値をMSRから取得する方法がマニュアルに書かれていない。

    いろいろ探していたらば、

    http://software.intel.com/en-us/forums/deleted-posts/topic/51574/page/1/

    で、MSR 0xEE で取得が可能なようだが、undocumented だそうだ。ちょっと古い資料なので、85度か100度と書かれている。

    http://www.xtremesystems.org/forums/showthread.php?t=179044&page=23

    によると、0xEE の bit:30 で、0=100 1=85 といううわさもある。

    一方、Q6600 では、95度らしいという書き込みもある。

    http://www.xtremesystems.org/forums/showthread.php?t=179044&page=27

    Atom の場合、20度室温で 0x19C Bits [22:16] から88前後が返されているので、100度にしても合わない。

    http://download.intel.com/design/processor/datashts/320032.pdf

    によると、a catastrophic processor temperature of 125°C (maximum), or if the THERMTRIP#
    signal is asserted, ということで、125度とすると、ちょうど37度となり、それらしい値になる。

    MSR 0xEE で取得してみると、

    000000EE: 00000000 02F90002

    となり、仕様が分からない。

    http://www.bugtrack.almico.com/view.php?id=1150

    によると、

    if bit 30 of MSR(0x00EE) is 1 then
      Tjmax=85
    else
      Tjmax=100
    endif
    if CPUID=0x06F2 then Tjmax=100
    if CPUID=0x06FB then Tjmax=100
    if CPUID=0x10676 then Tjmax=Tjmax+5

    こんな情報もある。

    それにしても、xtremesystems.org のスレッドがものすごいことになっているのには、驚いた。

    いずれにしても、インテルが仕様をはっきり書いていない(NDAを結ばないともらえないらしい)のが悪いということがよくわかった。

    May 04

    CPUの温度取得に関するメモ2

    石坂さん、渋木さんに教えていただいたサイドバーガジェットを Windows 7 Beta on Atom N280で動かしてみました。こんな感じ。

    image 

    原理はデバイスドライバーで、Ring0のカーネルモードに移行して、そこでアセンブラでRDMSRにより、Model Specific Register を叩いて、直接モードスペシフィックレジスターからデータを読み取っていますね。そのためのライブラリがOpenLibSysから提供されている。なるほど、それなら早いはずだ。それにしても、OpenLibSysを作った人は偉いなぁ・・・とひとしきり感動しました。

    なお、Vista on Pentium4 Dでは、温度が取得できない。orz。MSR的には、0x19C の 22:16 で同じ仕様に見えるんだけど、どこか細かいところで違うのかな・・・

    image

    なお、MSRは、文字通りモデル固有のレジスタであるため、プロセッサのモデルごとに仕様が異なっている。Intel のIntel® 64 and IA-32 Architectures Software Developer’s Manual Volume 3Bによると、Core2、Atom、P4 and Xeon、Core Solor and Core Duo、Pentium M、P6、Pentiumとファミリーごとに説明が分かれています。

    April 29

    CPU 温度の取得に関するメモ

    だんだんと暑い季節になってきて、Core2ではない Pentium 4 Dにとっては、辛い季節になってきました。室温が上がると、調子が悪くなるので、まじめに深刻な問題です。そこで、先日ケースにファンを増設したら、だいぶ効果があるようで、35度ぐらいでおちついていますが、CPUの温度のモニタリングしたいと思って、ちょっと調べてみました。

    WMI の “Win32_TemperatureProbe” が一番まともな方法のようだが、現在のPC “ASUS P5LD2-V”, eee PC 1000 HE では、このインターフェースがサポートされていない模様。

    いろいろ調べてみると、MSAcpi_ThermalZoneTemperature を使った記事がいくつかある

    http://groups.google.co.jp/group/microsoft.public.win32.programmer.wmi/browse_thread/thread/d462fd6d271cc98d

    が、そもそもそんな I/F の情報は MSDNに載っていない。もう使われていないということか?

    さらに調べてみると、

    http://kariunten.homeip.net/programming/winring0.html

    にマザーボードのコントローラを直接操作する方法が載っていた。そうきますか~~~w。

    と思って、そのコードを見てみると、

    http://openlibsys.org/

    で、Windowsからハードウェア(I/O port, MSR, PCI bus, and etc...)へのアクセスを可能とする WinRing0 が提供されているコードを利用している。

    さらに、そこから

    http://www.techpowerup.com/realtemp/

    で、all Intel single Core, Dual Core, Quad Core and Core i7、さらにはNvidia のGPUの温度まで取得できるプロジェクトを発見。

    試してみたが、Pentium 4 Dは、サポートされていない;;

    image

    eee PC 1000 HE の Atom N280だと? 1℃  !  すばらしい CPUだ w

    image

    ASUS からProbe II というモニターツールがあるから問題ないんだけどね。

    image

    温度、ファン回転数ぐらい WMI でちゃんと取れるようにしてよね。>> MS

    それより、せめてCore2にしろよという突っ込みは却下。

    March 14

    Visual Studio 2008 の修復インストール、アンインストールができない

    Visual Studio 2008の調子が悪く、ASP.NETの開発ができなくなってしまった。特に何もしていないのに突然の症状。原因不明。しかたないので、修復セットアップしようとしたら、セットアップもできなくなっている。

    image

    アンインストールもできない。困ったと思っていたら、

    もりさんのページで、

    Visual Studio 2008 自動アンインストールツールが公開されています。

    が紹介されていた。

    Visual Studio 2008 をアンインストールする

    http://msdn.microsoft.com/ja-jp/vstudio/bb968856.aspx

    無事安易ストール完了。

    さて、インストールしますか。

    ・・・1時間後、インストール無事終了。起動してみると、ブルースクリーンでVista 落ちた。

    再起動後、WebApplication を作ってみただけで、

    image

    ということで、なんかすごくおかしくなっている。

    WinForm は問題なくプロジェクトの作成、実行ができる。

    IISがらみか?

    February 03

    RDF を LINQ で読む

    string gooRankingUrl = "http://ranking.goo.ne.jp/rss/keyword/keyrank_all1/index.rdf";
    XDocument feedXML = XDocument.Load(gooRankingUrl);

    XNamespace d = "http://purl.org/rss/1.0/";
    XNamespace dc = "http://purl.org/dc/elements/1.1/";

    var res = from item in feedXML.Descendants(d + "item")
              select new
              {
                  Title = item.Element(d + "title").Value,
                  Link = item.Element(d + "link").Value,
                  PubDate = (item.Element(dc + "date").Value ?? ""),
                  Publisher = (item.Element(dc + "publisher").Value ?? ""),
                  Rank = (item.Element(dc + "rank").Value ?? ""),
                  Point = (item.Element(dc + "point").Value ?? ""),
                  Arrow = (item.Element(dc + "arrow").Value ?? ""),
                  Description = (item.Element(d + "description").Value ?? ""),
                  Guid = item.Element(d + "link").Value
              };

    GridView1.DataSource = res;
    GridView1.DataBind();

    結果は、こんな感じ。image

    January 06

    ASP.NET ルーティング

    MSDN を読んでいたら、ASP.NET ルーティングということで、URLの書き換え方法が載っていた。

    http://msdn.microsoft.com/ja-jp/library/cc668201.aspx

    昔調べた方法から、IIS7 対応もあり、だいぶ変わっているようなので調べてみた。そうしたら、ええ~~、こんな簡単にできようになっちゃたんだー!と感動して、ためしに動かしてみようとしました。すると、CategoryRouteHandler がありませんと怒られる。そりゃそうだ、どこにもそんなコードがない。あれ??ということで調べてみると、どっとねっとふぁんBlog の小野さんが

    ASP.NET ルーティングを実装する

    で丁寧に解説してあった。さすが師匠wと感動する一方、やっぱりハンドラ書かないといけないのね。orz

    LinqDataSource によるメモリ内コレクションのデータへの接続

    http://msdn.microsoft.com/ja-jp/library/bb547113.aspx

    Default.aspx.cs にMoviewLibraryクラスを追加。

    using System;
    using System.Collections;
    using System.Configuration;
    using System.Data;
    using System.Linq;
    using System.Web;
    using System.Web.Security;
    using System.Web.UI;
    using System.Web.UI.HtmlControls;
    using System.Web.UI.WebControls;
    using System.Web.UI.WebControls.WebParts;
    using System.Xml.Linq;

    namespace LinqDataSource
    {
        public partial class _Default : System.Web.UI.Page
        {
            protected void Page_Load(object sender, EventArgs e)
            {

            }
        }

        public class MovieLibrary
        {
            string[] _availableGenres = { "Comedy", "Drama", "Romance" };

            public MovieLibrary()
            {
            }

            public string[] AvailableGenres
            {
                get
                {
                    return _availableGenres;
                }
            }
        }
    }

    GridViewを追加。新しいデータソースを選択。

    image

    LINQを選択。

    image

    データソースの構成ダイアログで、MoviewLibraryを選択。

    image

    データの選択の構成ダイアログで、テーブル、Select, GroupBy, Where, OrderBy を指定可能。

    image

    実行すればこのとおり。

    image

    生成されたWPFコードは、

    <asp:GridView ID="GridView1" runat="server" DataSourceID="LinqDataSource1">
    </asp:GridView>
    <asp:LinqDataSource ID="LinqDataSource1" runat="server"
        ContextTypeName="LinqDataSource.MovieLibrary" TableName="AvailableGenres">
    </asp:LinqDataSource>

    列名までしっかり処理されている。もう少し複雑なテーブルで試してみると、これがずいぶん便利だということに気が付く。

    January 05

    サービス参照の追加(VS2008) と Web参照の追加(VS2005)

    VS2005 では、サービス参照の追加から、次のようなサービスを追加することができる。このダイアログの一番下に、参照設定ボタンがある。

    image 

    この参照設定ボタンをクリックすると、次のようなサービス参照設定の詳細を指定することができる。このダイアログの一番下に、互換性ということで、Web 参照の追加ボタンがある。.NET Framework 2.0 web サービステクノロジーに基づいたコードを生成することができる。

    image

    Web 参照の追加ボタンを押すと、昔懐かしいWeb 参照ダイアログが表示される。

    image

    .NET 2.0とそれ以降では、生成されるコードが若干違ってくるので、注意が必要。

    January 03

    ZAM3Dが生成するXAMLをC#で実装すると

    インラインモデルは、こんな感じ。
    image 
            private void Sample2()
            {
                this.viewPort3D1.Name = "ZAM3DViewport3D";
                viewPort3D1.ClipToBounds = true;
                viewPort3D1.Width = 400;
                viewPort3D1.Height = 300;
    
                PerspectiveCamera camera = new PerspectiveCamera();
                camera.FarPlaneDistance = 10f;
                camera.LookDirection = new Vector3D(2.05609, -1.21509, -2.52021);
                camera.UpDirection = new Vector3D(0f, 1f, 0f);
                camera.NearPlaneDistance = 2f;
                camera.Position = new Point3D(-2.05609,1.21509,2.52021);
                camera.FieldOfView = 39f;
                viewPort3D1.Camera = camera;
    
                ModelVisual3D modelVisual3D = new ModelVisual3D();
                Model3DGroup model3DGroup = new Model3DGroup();
                modelVisual3D.Content = model3DGroup;
                Transform3DGroup transform3DGroup = new Transform3DGroup();
    
    
                TranslateTransform3D translateTransform3D = new TranslateTransform3D(0f, 0f, 0f);
                ScaleTransform3D scaleTransform3D = new ScaleTransform3D(1f, 1f, 1f);
                AxisAngleRotation3D axisAngleRotation3D = new AxisAngleRotation3D(new Vector3D(0f, 1f, 0f), 0f);
                RotateTransform3D rotateTransform3D = new RotateTransform3D();
                rotateTransform3D.Rotation = axisAngleRotation3D;
    
                transform3DGroup.Children.Add(translateTransform3D);
                transform3DGroup.Children.Add(scaleTransform3D);
                transform3DGroup.Children.Add(rotateTransform3D);
    
                model3DGroup.Transform = transform3DGroup;
                //////
                AmbientLight ambientLight = new AmbientLight(Color.FromRgb(0x33, 0x33, 0x33));
                model3DGroup.Children.Add(ambientLight);
                DirectionalLight directionalLight1 = new DirectionalLight(Colors.White, new Vector3D(-0.6f, -0.5f, -0.6f));
                model3DGroup.Children.Add(directionalLight1);
                DirectionalLight directionalLight2 = new DirectionalLight(Colors.White, new Vector3D(0.6f, -0.5f, -0.6f));
                model3DGroup.Children.Add(directionalLight2);
    
    
                //////
                Model3DGroup model3DGroupBox = new Model3DGroup();
                Transform3DGroup transform3DGroupBox = new Transform3DGroup();
    
                TranslateTransform3D translateTransform3DBox = new TranslateTransform3D(0f, 0f, 0f);
                ScaleTransform3D scaleTransform3DBox = new ScaleTransform3D(1f, 1f, 1f);
                AxisAngleRotation3D axisAngleRotation3DBox = new AxisAngleRotation3D(new Vector3D(0f, 1f, 0f), 0f);
                RotateTransform3D rotateTransform3DBox = new RotateTransform3D();
                rotateTransform3DBox.Rotation = axisAngleRotation3DBox;
    
                TranslateTransform3D translateTransform3DBox2 = new TranslateTransform3D(0,0,0);
    
                transform3DGroupBox.Children.Add(translateTransform3DBox);
                transform3DGroupBox.Children.Add(scaleTransform3DBox);
                transform3DGroupBox.Children.Add(rotateTransform3DBox);
                transform3DGroupBox.Children.Add(translateTransform3DBox2);
    
                model3DGroupBox.Transform = transform3DGroupBox;
    
                /////
    
                GeometryModel3D geometryModel3D = new GeometryModel3D();
                MaterialGroup materialGroup = new MaterialGroup();
    
                DiffuseMaterial diffuseMaterial = new DiffuseMaterial();
                diffuseMaterial.Brush = new SolidColorBrush(Color.FromRgb(0xd3, 0xc8, 0xad));
                materialGroup.Children.Add(diffuseMaterial);
    
                SpecularMaterial specularMaterial = new SpecularMaterial();
                specularMaterial.SpecularPower = 93f;
                specularMaterial.Brush = new SolidColorBrush(Color.FromRgb(0x33, 0x33, 0x33));
                materialGroup.Children.Add(specularMaterial);
    
                geometryModel3D.Material = materialGroup;
    
                ////
    
                GeometryModel3D geometryModel3DBack = new GeometryModel3D();
                MaterialGroup materialGroupBack = new MaterialGroup();
    
                DiffuseMaterial diffuseMaterialBack = new DiffuseMaterial();
                diffuseMaterialBack.Brush = new SolidColorBrush(Color.FromRgb(0xd3, 0xc8, 0xad));
                geometryModel3DBack.Material = materialGroupBack;
                materialGroupBack.Children.Add(diffuseMaterialBack);
    
                SpecularMaterial specularMaterialBack = new SpecularMaterial(); 
                specularMaterialBack.Brush = new SolidColorBrush(Color.FromRgb(0x33, 0x33, 0x33));
                specularMaterialBack.SpecularPower = 93f;
                materialGroupBack.Children.Add(specularMaterialBack);
    
                geometryModel3D.BackMaterial = materialGroupBack;
    
                ////
    
                MeshGeometry3D meshGeometry3D = new MeshGeometry3D();
    
                TypeConverter i32ColConv = TypeDescriptor.GetConverter(typeof(Int32Collection));
                meshGeometry3D.TriangleIndices = (Int32Collection)i32ColConv.ConvertFromString("0,1,2 2,3,0 4,5,6 6,7,4 8,9,10 10,11,8 12,13,14 14,15,12 16,17,18 18,19,16 20,21,22 22,23,20");
    
                TypeConverter vector3DColConv = TypeDescriptor.GetConverter(typeof(Vector3DCollection));
                meshGeometry3D.Normals = (Vector3DCollection)vector3DColConv.ConvertFromString("0,0,-1 0,0,-1 0,0,-1 0,0,-1 0,0,1 0,0,1 0,0,1 0,0,1 0,-1,0 0,-1,0 0,-1,0 0,-1,0 1,0,0 1,0,0 1,0,0 1,0,0 0,1,0 0,1,0 0,1,0 0,1,0 -1,0,0 -1,0,0 -1,0,0 -1,0,0 ");
    
                TypeConverter point3DColConv = TypeDescriptor.GetConverter(typeof(Point3DCollection));
                meshGeometry3D.Positions = (Point3DCollection)point3DColConv.ConvertFromString("-0.5,-0.5,-0.5 -0.5,0.5,-0.5 0.5,0.5,-0.5 0.5,-0.5,-0.5 -0.5,-0.5,0.5 0.5,-0.5,0.5 0.5,0.5,0.5 -0.5,0.5,0.5 -0.5,-0.5,-0.5 0.5,-0.5,-0.5 0.5,-0.5,0.5 -0.5,-0.5,0.5 0.5,-0.5,-0.5 0.5,0.5,-0.5 0.5,0.5,0.5 0.5,-0.5,0.5 0.5,0.5,-0.5 -0.5,0.5,-0.5 -0.5,0.5,0.5 0.5,0.5,0.5 -0.5,0.5,-0.5 -0.5,-0.5,-0.5 -0.5,-0.5,0.5 -0.5,0.5,0.5 ");
    
                geometryModel3D.Geometry = meshGeometry3D;
    
                model3DGroupBox.Children.Add(geometryModel3D);
    
                ////
    
                model3DGroup.Children.Add(model3DGroupBox);
                modelVisual3D.Content = model3DGroup;
    
                this.viewPort3D1.Children.Add(modelVisual3D);
            }
    January 01

    C++/CLI によるScreen Saver スケルトンコード

    Windows Mobile の Today のプラグインを実装しようと思うと、WnProc を実装する必要があり、C#だけでは実装できない。

    http://msdn.microsoft.com/en-us/library/ms839442.aspx

    に、Creating a Pocket PC Today Screen Plug-in with the .NET Compact Framework という方法も載っているが、これだと共有メモリを使ってHTMLをレンダリングさせる方法なので、かえって見通しが悪そう。これなら、直接C++/CLIで実装して、一部を C#で書いたほうが楽そう。ただ、TodayのプラグインがC++/CLIで実装可能かどうか・・・C++/CLIでも実装可能なら、一部を C# で書くことも可能なので、ちょっと込み入った実装もだいぶ楽になるはず。

    少し調べていたら、

    http://www.atmarkit.co.jp/fdotnet/special/cppcli/cppcli_01.html

    に「いままたC++が熱い!「C++/CLI」として大進化したVisual C++ 2005」の記事があり、C++/CLI によるScreen Saver のサンプルがあったので、試してみた。

    結果はWinProc をC++/CLIで動かすことができる。ということは、おそらく Windows Mobile の Today のプラグインも同様に動くと思われると、思ったが、スマートデバイスのプロジェクトテンプレートでは、C++/CLI がサポートされないみたい orz

    ピーデー 川俣 晶さんがアップしているコードを VS2008用にちょっと修正したので、とりあえずメモ。

    • コンパイル時の設定に、構成プロパティ→全般に 共通言語ランタイムサポート をセット。
    • 構成プロパティ→リンカ→追加の依存ファイルに scrnsavw.lib comctl32.lib をセット。
    • コンパイルしたイメージを /Sで起動。

    #include <stdafx.h>
    #include <windows.h>
    #include <scrnsave.h>

    #using <mscorlib.dll>
    #using <System.dll>
    #using <System.Drawing.dll>
    #using <System.Windows.Forms.dll>

    using namespace System;
    using namespace System::Drawing;
    using namespace System::Windows::Forms; 

    UINT_PTR wTimer;
    WORD wElapse = 1000;
    int xText=0, yText=0;

    #define ID_TIMER 1

    LONG CALLBACK ScreenSaverProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
    {
      switch (msg)
      {
        case WM_CREATE:
          {
            wTimer = SetTimer(hWnd, ID_TIMER, wElapse, NULL);
          }
          break;

        case WM_TIMER:
          {
            HDC hdc = GetDC(hWnd);
            xText = rand() % GetDeviceCaps(hdc,HORZRES);
            yText = rand() % GetDeviceCaps(hdc,VERTRES);
            ReleaseDC(hWnd,hdc);
            InvalidateRect(hWnd,NULL,TRUE);
          }
          break;

        case WM_DESTROY:
          if( wTimer ) KillTimer(hWnd, ID_TIMER);
          break;

        case WM_PAINT:
          {
            PAINTSTRUCT ps;
            HDC hDC = BeginPaint(hWnd, &ps);
    {
    System::Drawing::
    Graphics ^ g = Graphics::FromHdc((IntPtr)hDC);
    Font font("MS ゴシック", 160);
    SolidBrush brush( Color::Blue);
    PointF position( (float)xText, (float)yText );
    g->DrawString( "テスト!",  %font,  %brush, position );
    }
    EndPaint(hWnd, &ps);
          }
          break;

        case WM_ERASEBKGND:
          {
            RECT rc;
            GetClientRect(hWnd,&rc);
            FillRect((HDC)wParam, &rc,
                (HBRUSH)GetStockObject(BLACK_BRUSH));
          }
          return 0L;

        default:
          break;
      }

      return DefScreenSaverProc(hWnd, msg, wParam, lParam);
    }

    BOOL WINAPI RegisterDialogClasses (HANDLE hInst)
    {
      return TRUE;
    }

    BOOL CALLBACK ScreenSaverConfigureDialog(HWND hDlg, UINT msg, WPARAM wParam, LPARAM lParam)
    {
      return FALSE;
    }