2008.12.29 [Mon] Windowsのテーマ変更を検出する
仕事納めの日が、午後出張で直帰(そのまま忘年会へ…)だったので、細々とした事が残ってたままに。
別に年明けからでも大丈夫なんだけど、なんとなく気分が悪いので、年の瀬休日出社して片付けることに。
■[C#] Windowsのテーマ変更を知る

現在のテーマの調べ方
現在のテーマが何に設定されているかどうかは以下のレジストリを確認すればOK。
レジストリパスはWindows XPの場合も Vistaの場合も同じ。
[HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\ThemeManager]
- ColorNameが存在しない(ThemaActive? = 0でも同じ)
- ColorNameが存在する
ここらへんは参考コードが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題
■[C#] 配列のシリアライズで、配列そのものにタグを与えたくない

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 } }
<Company> <Person> <Id>1001</Id> <Name>Taro</Name> </Person> <Person> <Id>1002</Id> <Name>Jiro</Name> </Person> ・・・ </Company>
■[C#] XMLシリアライズ時のInvalidOperationException

オブジェクトをシリアライズする際には,引数なしのコンストラクタが必要.(コンストラクタを一つも定義していなければデフォルトコンストラクタ(引数なし)がoverrideされるから問題ない).
もし,引数ありのコンストラクタのみを定義し,引数なしのコンストラクタを定義していない場合,シリアライズ時にInvalidOperationExceptionが発生する。
このInvalidOperationException,コンストラクタに問題があるオブジェクトが親か子かでメッセージの文面が異なってくるからいやらしい.
例えば前記事の例だと,Companyオブジェクトに引数なしコンストラクタが存在しない場合は
System.InvalidOperationException はハンドルされませんでした。
Message="Sample.Company にはパラメータを持たないコンストラクタが含まれていないため、これをシリアル化することはできません。"
ところが,Companyオブジェクトには問題なくて,Personオブジェクトに引数なしコンストラクタが存在しない場合は
System.InvalidOperationException はハンドルされませんでした。
Message="型 'Sample.Company' を反映中にエラーが発生しました。"
となり手がかりが少なくなる.
silk-silk
2009/03/12 20:01
2題目の情報 (InvalidOperationException) で、とても助かりました。ありがとうございます。
2008.08.15 [Fri]
2008.08.05 [Tue]
■[.NET] VisualStudio + VMWareの落とし穴

VisualStudioが入った状態で,VMWareをインストールすると VMWare Virtual DebuggerなるアドインがVisual Studioに追加されるらしい.
こいつの嫌らしいところが、勝手に「F6」キーの割り当てを変えてしまうところ.
それまで「ソリューションのビルド」に[F6]が割り当てられてたのが,勝手に「VMWare Virtual Debuggerの開始」に割り当てなおされてしまう.
ビルドしようといつものクセで「F6」をタイプすると,
---------------------------
エラー
---------------------------
現在の構成では仮想マシンが指定されていません。
---------------------------
OK
---------------------------
対処法としては
- ツール→オプション→キーボードから[F6]キーの割り当てをやり直す
- ツール→アドインマネージャーから「VMDebugger」のチェックを外す
のいずれか.
どっちにしろ,VisualStudioを起動しなおすと,元に戻ってしまうから鬱陶しいことこの上ない.
なんとかならんものか.
2008.07.10 [Thu] いつの間にか4年目
気がついたら4年目。
そしてこの7月に昇格までしちまった….こんな「しょーもないエンジニア」をもち上げていいのかウチの会社….
近頃は暇気味なので、.NETでの検証ちっくなプログラム書いたり,久しぶりにJavaな方面でお勉強などを.
Javaのほうは,JDK1.6 & Tomcat 6.0という最新の組み合わせに,Struts2を試してるけど,かなり変わってて面白い.
■ [C#] 列挙子の扱い
![はてなブックマーク - [C#] 列挙子の扱い](http://megalodon.jp/get_contents/58533658)
よく忘れるので書いておく。
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の仕事もそろそろ本腰入れないといけないんだけど….
■[.NET] タスクバーのサイズ変更とFormのResizeイベント

Windwosのタスクバーのサイズを変更し、デスクトップのWorkingAreaを小さくすると、デスクトップ上にあったウィンドウはそれにあわせて小さくなる。
この際、当然ながら各ウィンドウにはResizeイベント(とSizeChangedイベント)が飛んでくる。
しかし逆に、タスクバーを縮めて、デスクトップのWorkingAreaを広くしても、小さくなったウィンドウはそのままなので、この場合はResizeイベントは飛んでこない。
なお、Windows.Forms.Formには別途 Resize_Begin, Resize_Endイベントがあるが、これは通常のフォームのリサイズの時は飛んでくるけど、タスクバーのサイズ変更に伴うリサイズ時は飛んでこない模様。(実際にやってみたけどだめだった)
まとめると以下の通り。(数字はイベントが起こる順番。)
通常のリサイズ(フォーム端をマウスでドラッグ)
- ResizeBegin
- Resize
- (Resizeを繰り返し…)
- Resize
- SizeChanged
- ResizeEnd
タスクバーを広げて、フォームを縮めた場合
- Resize(1回だけ)
- SizeChanged
厄介なのは、各イベントが飛んできた際に、Screen.PrimaryScreen.WorkingAreaの値を取得しても、値はリサイズ(タスクバーのサイズ変更)前のままの値しかもらえない。移動完了後に再度取得しなおすと、値が更新されている。
2007.11.06 [Tue] Be Multilingual??
どえりゃー久しぶりの更新.
忙しくはないんだけど,今月は開発が3本平行らしい.
そしてその3本が全て言語が違う(Java, C#, VB)ってことに今日ふと気づいた….
VBなんてひっさしぶりなのでめちゃくちゃ忘れまくってる….
■[VB] And と AndAlso

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#,Java | VB |
---|---|
& | And |
&& | AndAlso |
| | Or |
|| | OrElse |
2007.03.14 [Wed] Vista!! Vista!! ヴィスタ! ヴィスタ! もういやだぁ〜
■[Java] VistaでTomcatの サービスマネージャー(GUI)がうまく起動しない

Windows VistaにTomcat 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フォルダでのアクセス権限の問題っぽいけど,本来の対処としてははどのようにしたらいいんでしょ?
■[Java] メイリオ(meiryo)フォントの問題

サーブレットで,フォント一覧を取得して,それらに対して日本語対応かどうかを調べる処理(参考:20060828の記事)をやってると,Vistaのシステムフォントであるメイリオ系(メイリオ,メイリオイタリック…)に対して,
font.canDisplay('日')
ってやるとここで処理が止まる.
しかも,どうも例外が発生しているようでもなく(try 〜 catchではひっかからず),Tomcatがしずか〜に落ちる)という謎な現象が起こる.
ちなみに,サーブレットではなく,ただのJava アプリケーションで同じことをやると問題はないので,実行ユーザとのからみもあるかもしれない.
詳細は調査中.
とりあえず速報だけということで.詳細は後日.
2007.03.12 [Mon] 久々に更新
■[Windows] Windows Vistaでデュアルブート

とあるオトナの事情により,Windows Vistaを入れて検証することに.
巷の量販店に行けば,もう当たり前のようにVista対応PCばかりな時代になってる.正直聞いていないよーというのが本音だけど,仕方がない.
というわけでインストール.
とりあえずXPとのデュアルブートにするため,空きパーティション(以前Win2000を入れようとして一騒ぎした奴)に入れる.
入れたのはVista Home Basic Editionだったけど,インストール自体はあっさり済んでしまう.きちんと計ったわけではないが,おそらくXP入れるよりも早い.
で,いざブートしてみると,見慣れたブートローダーではなく新しいブートメニューがあがる.
Windows ブートマネージャーってのが表示されて,
てな選択画面になる.
で,「既存のWindows」を選択すると,続いてお馴染みのブートマネージャーが表示される.
#正直XPとして起動させようとするとかったるいったらありゃしない.
どうやら,Vistaでは,既存のboot.iniによる管理ではなく,あらたにBCD(ブート構成データ)というもので管理するようになっているらしい.
詳細は下記に.
2006.12.12 [Tue]
■[.NET] セットアッププロジェクトで(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の下に置きたいものが置かれるようになる.
ちなみに,システム フォルダ プロパティ名の一覧は下記の通り.