S(しょーもない)E(エンジニア)さんねんせいの日記 このページをアンテナに追加

2008.12.29 [Mon] Windowsのテーマ変更を検出する

仕事納めの日が、午後出張で直帰(そのまま忘年会へ…)だったので、細々とした事が残ってたままに。

別に年明けからでも大丈夫なんだけど、なんとなく気分が悪いので、年の瀬休日出社して片付けることに。

[] Windowsのテーマ変更を知る 18:23  Windowsのテーマ変更を知るを含むブックマーク

現在のテーマの調べ方

現在のテーマが何に設定されているかどうかは以下のレジストリを確認すればOK。

レジストリパスはWindows XPの場合も Vistaの場合も同じ。

[HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\ThemeManager] 

  • ColorNameが存在しない(ThemaActive? = 0でも同じ)
  • ColorNameが存在する
    • 値が「NormalColor?」ならXPの場合XP Blue、Vistaの場合Vistaベーシック
    • 値が「HomeStead?」ならXP Green
    • 値が「Metallic」ならXP Silver
    • 上記以外の値ならば知らないテーマってことなんでしょう…

ここらへんは参考コードがCode Projectに載ってたりする。

http://www.codeproject.com/KB/cs/xptheme.aspx


テーマ変更検出

ウィンドウメッセージ「WM_WININICHANGE」を拾うことで検出可能。

WININICHANGEは、ウィンドウズの設定変更時に色々飛んでくるので注意。

WININICHANGEを拾って、現在のテーマを調べ、変更があるかどうかを判定すればよさそう。

というわけで、以下がサンプルコード。

protected override void WndProc(ref Message m) {
    const int WM_WININICHANGE = 0x001A;
    base.WndProc(ref m);
    if (m.Msg == WM_WININICHANGE) {
        Console.WriteLine(m.LParam.ToString() + "\tTheme : " + getCurrentTheme());
    }
}

public Theme getCurrentTheme() {
    Theme currentTheme = Theme.Classic;
    String regPath = @"Software\Microsoft\Windows\CurrentVersion\ThemeManager";
    Microsoft.Win32.RegistryKey regkey = Microsoft.Win32.Registry.CurrentUser.OpenSubKey(regPath);
    if (regkey != null) {
        if ((string)regkey.GetValue("ThemeActive") == "1") {
            String colorName = (string)regkey.GetValue("ColorName");
            if (colorName.Equals("NormalColor")) {
                return Theme.Default;
            } else if (colorName.Equals("HomeStead")) {
                return Theme.XP_Green;
            } else if (colorName.Equals("Metallic")) {
                return Theme.XP_Silver;
            } else {
                return Theme.Unknown;
            }
        }
    }
    return currentTheme;
}

public enum Theme {
    Classic,
    Default,
    XP_Green,
    XP_Silver,
    Unknown
}

実行例は以下のとおり(Windows Vista上で、デフォルトからクラシックに変更した場合)

0 Theme : Default

0 Theme : Classic

3076484 Theme : Classic

3076484 Theme : Classic

3076484 Theme : Classic

3076488 Theme : Classic

3076484 Theme : Classic

3076476 Theme : Classic

3076488 Theme : Classic

3076476 Theme : Classic

3076464 Theme : Classic

2008.11.27 [Thu] XmlSerialize関連2題

[] 配列シリアライズで、配列そのものにタグを与えたくない 11:11  配列のシリアライズで、配列そのものにタグを与えたくないを含むブックマーク

System.Xml.Serialization.XmlSerializer を使用してプロパティ配列を持つオブジェクトを普通にXMLシリアライズする

と、配列にタグがついて、さらに配列の要素一つ一つにもタグがつく.

たとえば,

class Person {
  int id;
  String name;

  // ... setter, getterは省略 ...
}

class Company {
  Person[] persons;
  String companyName;

  public String CompanyName {
    get { return this.companyName; }
    set { this.companyName = value; }
  }
  
  public Person[] Persons {
    get { return this.persons; }
    set { this.persons = value; }
  }
}

シリアライズすると


<Company>
  <Persons>
    <Person>
      <Id>1001</Id>
      <Name>Taro</Name>
    </Person>
    <Person>
      <Id>1002</Id>
      <Name>Jiro</Name>
    </Person>
    ・・・
  </Persons>
</Company>

となり,Personsタグが余計な感じとなる.

この場合,CompanyクラスのPersonsプロパティに [XmlElement(Type = typeof(クラス名))]という定義を付けると,Personsタグを省略し,Personタグの繰り返しだけにすることができる.

例:

[XmlElement(Type = typeof(Person))]
public Person[] Person {
  get { return this.persons }
  set { this.persons = value }
}

この場合のシリアライズ後のXMLは以下の通り.


<Company>
  <Person>
    <Id>1001</Id>
    <Name>Taro</Name>
  </Person>
  <Person>
    <Id>1002</Id>
    <Name>Jiro</Name>
  </Person>
    ・・・
</Company>

[] XMLシリアライズ時のInvalidOperationException 11:24  XMLシリアライズ時のInvalidOperationExceptionを含むブックマーク

オブジェクトシリアライズする際には,引数なしのコンストラクタが必要.(コンストラクタを一つも定義していなければデフォルトコンストラクタ引数なし)がoverrideされるから問題ない).

もし,引数ありのコンストラクタのみを定義し,引数なしのコンストラクタを定義していない場合,シリアライズ時にInvalidOperationExceptionが発生する。

このInvalidOperationException,コンストラクタに問題があるオブジェクトが親か子かでメッセージの文面が異なってくるからいやらしい.

例えば前記事の例だと,Companyオブジェクト引数なしコンストラクタが存在しない場合は

System.InvalidOperationException はハンドルされませんでした。

Message="Sample.Company にはパラメータを持たないコンストラクタが含まれていないため、これをシリアル化することはできません。"

ところが,Companyオブジェクトには問題なくて,Personオブジェクト引数なしコンストラクタが存在しない場合は

System.InvalidOperationException はハンドルされませんでした。

Message="型 'Sample.Company' を反映中にエラーが発生しました。"

となり手がかりが少なくなる.

silk-silksilk-silk 2009/03/12 20:01 2題目の情報 (InvalidOperationException) で、とても助かりました。ありがとうございます。

2008.08.15 [Fri]

[] ptとemSize 11:50  ptとemSizeを含むブックマーク

StringFormatを使って、装飾付きのテキストを描こうとしたときの話。

フォントの大きさの指定が、

  • StringFormatではemSize単位
  • Labelとかでは普通 ポイント(pt)単位

というわけで両者の変換が必要になった。

調べたところ、変換式は以下の通りらしい。

pt数×DPI数÷72 = emSize

DPI数はWindowsデフォルト*1では96なので

pt数×96÷72 = emSize

となる模様。

72ってのは 1pt = 1/72インチ の 72らしい。

*1:確認方法は、画面のプロパティ→設定タブ→詳細設定ボタン→全般タブのDPI設定

2008.08.05 [Tue]

[] VisualStudio + VMWareの落とし穴 19:08  VisualStudio + VMWareの落とし穴を含むブックマーク

VisualStudioが入った状態で,VMWareインストールすると VMWare Virtual DebuggerなるアドインがVisual Studioに追加されるらしい.

こいつの嫌らしいところが、勝手に「F6」キーの割り当てを変えてしまうところ.

それまで「ソリューションのビルド」に[F6]が割り当てられてたのが,勝手に「VMWare Virtual Debuggerの開始」に割り当てなおされてしまう.

ビルドしようといつものクセで「F6」をタイプすると,

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

エラー

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

現在の構成では仮想マシンが指定されていません。

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

OK

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

などというダイアログが表示されてビルドに失敗する.

対処法としては

  • ツール→オプション→キーボードから[F6]キーの割り当てをやり直す
  • ツール→アドインマネージャーから「VMDebugger」のチェックを外す

のいずれか.

どっちにしろ,VisualStudioを起動しなおすと,元に戻ってしまうから鬱陶しいことこの上ない.

なんとかならんものか.

AtrasWorldAtrasWorld 2008/08/23 19:02 VMdebuggerのアドインDLLをリネームすれば対応可能でした。
きれいな方法ではないですが・・・F6を押すとIDEが強制終了するのは防げます^^;

http://mt4.atras.net/2008/08/vmdebugger.html

初心者初心者 2009/04/23 16:05 ・ツール→アドインマネージャーから「VMDebugger」のチェックを外す
・さらに「VMDebugger」の「スタートアップ」のチェックも外すとOKでした。

2008.07.10 [Thu] いつの間にか4年目

気がついたら4年目。

そしてこの7月に昇格までしちまった….こんな「しょーもないエンジニア」をもち上げていいのかウチの会社….

近頃は暇気味なので、.NETでの検証ちっくなプログラム書いたり,久しぶりにJavaな方面でお勉強などを.

Javaのほうは,JDK1.6 & Tomcat 6.0という最新の組み合わせに,Struts2を試してるけど,かなり変わってて面白い.

[C#] 列挙子の扱い 17:38  [C#] 列挙子の扱いを含むブックマーク

よく忘れるので書いておく。

MessageBoxIcon列挙子(MessageBoxIcon.WarnningとかMessageBoxIcon.Infoとか)の一覧を扱いたいときにどう書くかという話。

列挙子の名前一覧を取りたい

列挙子の名前一覧をコンボボックス(プルダウン)に登録するサンプル

foreach (String name in Enum.GetNames(typeof(MessageBoxIcon))){
    comboBox.add(name);
}

列挙子のオブジェクト一覧を取りたい

列挙子のオブジェクト一覧をコンボボックス(プルダウン)に登録するサンプル。

プルダウンを選択すると、MessageBoxIconオブジェクトが返って来る。

foreach (MessageBoxIcon icon in Enum.GetValues(typeof(MessageBoxIcon))){
    conboBox.add(icon);
}

2008.01.25 [Fri] 年あけて….

気がついたら年も明けて2008年.

今年もまったりきまぐれ更新で行きます.

相変わらずVB時々C#,時折Javaも忘れずに…ってな日々.頭がこんがらがる….

Javaの仕事もそろそろ本腰入れないといけないんだけど….

[] タスクバーのサイズ変更とFormのResizeイベント 16:03  タスクバーのサイズ変更とFormのResizeイベントを含むブックマーク

Windwosのタスクバーのサイズを変更し、デスクトップのWorkingAreaを小さくすると、デスクトップ上にあったウィンドウはそれにあわせて小さくなる。

この際、当然ながら各ウィンドウにはResizeイベント(とSizeChangedイベント)が飛んでくる。

しかし逆に、タスクバーを縮めて、デスクトップのWorkingAreaを広くしても、小さくなったウィンドウはそのままなので、この場合はResizeイベントは飛んでこない。

なお、Windows.Forms.Formには別途 Resize_Begin, Resize_Endイベントがあるが、これは通常のフォームのリサイズの時は飛んでくるけど、タスクバーのサイズ変更に伴うリサイズ時は飛んでこない模様。(実際にやってみたけどだめだった)

まとめると以下の通り。(数字はイベントが起こる順番。)

通常のリサイズ(フォーム端をマウスドラッグ

  1. ResizeBegin
  2. Resize
  3. (Resizeを繰り返し…)
  4. Resize
  5. SizeChanged
  6. ResizeEnd

タスクバーを広げて、フォームを縮めた場合

  1. Resize(1回だけ)
  2. SizeChanged

厄介なのは、各イベントが飛んできた際に、Screen.PrimaryScreen.WorkingAreaの値を取得しても、値はリサイズ(タスクバーのサイズ変更)前のままの値しかもらえない。移動完了後に再度取得しなおすと、値が更新されている。

2007.11.06 [Tue] Be Multilingual??

どえりゃー久しぶりの更新.

忙しくはないんだけど,今月は開発が3本平行らしい.

そしてその3本が全て言語が違う(Java, C#, VB)ってことに今日ふと気づいた….

VBなんてひっさしぶりなのでめちゃくちゃ忘れまくってる….

[] And と AndAlso 18:46  And と AndAlsoを含むブックマーク

C#とかJavaの条件文で

String[] array = new String[]{"item0", "item1", "item2"};
if(array.Length > 3 && array[3].Contains("item")){
  Console.WriteLine("TRUE!!");
}

て書くように,なーんも考えずにVBで下のように書くと例外(ArrayIndexOutOfBoundsException)が発生する.

Dim array As String() = {"item0", "item1", "item2"}
If array.Length > 3 And array(3).Contains("item") Then
  Console.WriteLine("TRUE!!")
End If

C#Javaで言うところの「&&」はVBでは「AndAlso」なのでした.

C#,JavaVB
&And
&&AndAlso
Or
||OrElse

2007.03.14 [Wed] Vista!! Vista!! ヴィスタ! ヴィスタ! もういやだぁ〜

サービスマネージャー起動失敗

相変わらずVistaと戯れ,もとい格闘中….

Tomcat(で作ってたもの)がVistaでも動くかってコトをやってるんですが,これがなかなか.

[] VistaTomcatの サービスマネージャー(GUI)がうまく起動しない 18:19  VistaでTomcatの サービスマネージャー(GUI)がうまく起動しないを含むブックマーク

Windows VistaTomcat 5.0.28(JDKは1.4.2_12)を入れてlocalhost起動させようとする.

とりあえずインストール時の設定でStartup typeを「Automatic」にしておくとOS起動と共にTomcatもあがってくれるのだが,

「スタート」→「すべてのプログラム」→「Apache Tomcat 5.0」→「Configure Tomcat」で,Tomcatのサービスマネージャーを起動させようとすると右上のようなエラーダイアログが出て起動しない.

「Application System Error」

(×)アクセスが拒否されました

Unable to open the Service Manager

仮の対処法としては,Vistaの機能である「ユーザアカウント制御」を無効化する*1と,普通に起動するようになった.

おそらく%Program Files%以下にインストールされたTomcatフォルダでのアクセス権限の問題っぽいけど,本来の対処としてははどのようにしたらいいんでしょ?

[] メイリオmeiryoフォントの問題 18:19  メイリオ(meiryo)フォントの問題を含むブックマーク

サーブレットで,フォント一覧を取得して,それらに対して日本語対応かどうかを調べる処理(参考:20060828の記事)をやってると,Vistaのシステムフォントであるメイリオ系(メイリオメイリオイタリック…)に対して,

font.canDisplay('日')

ってやるとここで処理が止まる.

しかも,どうも例外が発生しているようでもなく(try 〜 catchではひっかからず),Tomcatがしずか〜に落ちる)という謎な現象が起こる.

ちなみに,サーブレットではなく,ただのJava アプリケーションで同じことをやると問題はないので,実行ユーザとのからみもあるかもしれない.

詳細は調査中.

とりあえず速報だけということで.詳細は後日.

*1:「コントロールパネル」→「ユーザアカウント」→「ユーザアカウント制御の有効化・無効化」より実施

2007.03.12 [Mon] 久々に更新

しばらく更新がなかったのは,

デスマ真っ最中!

だったから….

久々の更新で感覚がつかめないのでとりあえず小ネタだけ….

[] Windows Vistaでデュアルブート 17:04  Windows Vistaでデュアルブートを含むブックマーク

とあるオトナの事情により,Windows Vistaを入れて検証することに.

巷の量販店に行けば,もう当たり前のようにVista対応PCばかりな時代になってる.正直聞いていないよーというのが本音だけど,仕方がない.

というわけでインストール

とりあえずXPとのデュアルブートにするため,空きパーティション(以前Win2000を入れようとして一騒ぎした奴)に入れる.

入れたのはVista Home Basic Editionだったけど,インストール自体はあっさり済んでしまう.きちんと計ったわけではないが,おそらくXP入れるよりも早い.

で,いざブートしてみると,見慣れたブートローダーではなく新しいブートメニューがあがる.

Windows ブートマネージャーってのが表示されて,

てな選択画面になる.

で,「既存のWindows」を選択すると,続いてお馴染みのブートマネージャーが表示される.

#正直XPとして起動させようとするとかったるいったらありゃしない.


どうやら,Vistaでは,既存のboot.iniによる管理ではなく,あらたにBCD(ブート構成データ)というもので管理するようになっているらしい.

詳細は下記に.

http://www.microsoft.com/japan/technet/windowsvista/library/85cd5efe-c349-427c-b035-c2719d4af778.mspx

2006.12.12 [Tue]

[] セットアッププロジェクトで(Local Settings\Application Data\)LocalAppDataFolderにファイルを配置する 14:12  セットアッププロジェクトで(Local Settings\Application Data\)LocalAppDataFolderにファイルを配置するを含むブックマーク

インストーラ作成でのオハナシ.

VisualStudio2005でセットアッププロジェクトを作成し,アプリケーションで使用する(ユーザ毎の)設定ファイルをインストール時に配備することを考える.

この場合,ユーザ別設定ファイルはユーザ毎に配置したいので,置き場所としては下記の2つが候補になる.


  • アプリケーションデータフォルダ(ローミングあり)
    • System.Environment.SpecialFolder.ApplicationDataに相当
    • パス例 C:\Documents and Settings\[ユーザ名]\Application Data配下
  • アプリケーションデータフォルダ(ローミングなし)
    • System.Environment.SpecialFolder.LocalApplicationDataに相当
    • パス例 C:\Documents and Settings\[ユーザ名]\Local Settings\Application Data配下

※両者の違いはhttp://www.atmarkit.co.jp/fdotnet/dotnettips/263apppath/apppath.htmlを参照.


で問題なのは,このフォルダを指定しその下に特定のファイルを置く方法.


セットアップ時にファイルの配置を指定するには,セットアッププロジェクトのファイルシステムタブ(プロジェクト名右クリック→表示→「ファイルシステム」)を使う.

デフォルトでは,上記いずれも左側のフォルダ一覧にはないので追加してやるのだが,右クリック→「特別なフォルダの追加」ってやると,「アプリケーションデータフォルダ」ってのは一つしかない.

でもってこれは,ローミングありのやつ(C:\Documents and Settings\[ユーザ名]\Application Data のほう)になっている.

じゃあ,ローミングなし版(C:\Documents and Settings\[ユーザ名]\Local Settings\Application Data)はどうするか?


しょうがないので右クリック→「特別なフォルダの追加」→「カスタムフォルダ」ってのを選択する。

すると新しいフォルダが作成される.じゃあこいつのパスをどう設定するかだが,プロパティ欄を見てみると,さっきのシステムフォルダとはちょっと違ってて,DefaultLocation なんて項目ができてる.

VisualStudioのヘルプによるとココにWindows インストーラがサポートしているシステム フォルダ プロパティ名を入れるものらしい.

でもって,今回使いたいアプリケーションデータフォルダ(ローミングなし)のプロパティ名は「LocalAppDataFolder」らしいのだけど,プルダウンに入っていないので(ナンデダヨ…),「[LocalAppDataFolder]」と直接入力してやる.(カギ括弧もつける)

んで,ちゃんと今作ったフォルダの下にサブフォルダ作って,配置したいファイルを指定し,プロジェクトビルドしてインストーラーを動かしてみると,ちゃんとC:\Documents and Settings\[ユーザ名]\Local Settings\Application Dataの下に置きたいものが置かれるようになる.


ちなみに,システム フォルダ プロパティ名の一覧は下記の通り.

http://msdn.microsoft.com/library/default.asp?url=/library/en-us/msi/setup/system_folder_properties.asp

C#初心者C#初心者 2007/06/13 11:13 アプリケーションデータ配布時の問題可決ができました。 WindowsAP開発には、この情報が大変にありがたかったです。