カテゴリ:.Net開発( 216 )
カスタムコントロールでのデフォルトのフォントの変更
カスタムコントロール(Butonを継承し+αしたもの)を作っていて、デフォルトでのFontプロパティのフォント種を変えてほしいという話がありました。

実は.NetにControl.DefaultFontというプロパティがあるのですが、これは読み取り専用でしかもMSDNによると、ユーザーのオペレーティング システム、およびシステムのローカル カルチャの設定によって異なるとのこと。
使えなえい。。

Control.Font プロパティをオーバーライドして、
(C#の場合)

[DefaultValue(typeof(Font),"MS ゴシック, 9")] 
public override Font Font{
...
}


(VBの場合)
<DefaultValue(GetType(Font), "MS ゴシック, 9")> _
Public Overrides Property Font() Font
...
End Property

という方法もあるんでしょうが、これだけのことにオーバーライドするのもめんどいのでとりあえず、下記のコードで対応してました。
カスタムコントロール側のコンストラクタで、Fontプロパティ設定。。。
動きは問題ないようなので、これでええんかな?


Public Sub New()
' この呼び出しは、Windows フォーム デザイナで必要です。
InitializeComponent()
' InitializeComponent() 呼び出しの後で初期化を追加します。
 
MyBase.Font = New Font("HG創英角ポップ体", 18, FontStyle.Regular, GraphicsUnit.Point, 1)

End Sub

[PR]
by jehoshaphat | 2008-04-14 11:51 | .Net開発 | Trackback | Comments(0)
(vb.net)構成マネージャでのdebug,releaseの設定
VS2005の環境設定(VS初回起動時に設定)をを全般的な設定にしておくと標準ツールバーにてビルドのモードを選ぶことができます。
(これが環境設定をVisual Basicにしているとメニューとかツールバーに簡単には出てこないようで。。
自分はVBが嫌いなので、全般的な設定にしています。設定を変更するにはメニュー・バーの[ツール]-[設定のインポートとエクスポート]を実行して、[設定のインポートとエクスポート ウィザード]を呼び出し、[すべての設定をリセット]してから任意の環境設定ができます。
詳しくはここ。)

で、標準だと構成はdebugとreleaseがあるのですが、これらの詳細はプロジェクトのプロパティ→コンパイルタブにて設定できるみたいです。

標準ではdebugとreleaseの違いとしては[詳細コンパイルオプション]の[最適化を有効にする],[デバッグ情報を作成],[DEBUG定数の定義]と、[ビルド出力パス]くらいでしょうか。
コンパイルタブの下のほうのコンパイルオプション的なものは変わりありませんでした。

debug
e0091163_14411751.jpg

release
e0091163_14412989.jpg

この違いがどう変わるのかはまだわかっていませんが。。
[PR]
by jehoshaphat | 2008-04-10 14:42 | .Net開発 | Trackback | Comments(0)
(vb.net)カスタムコントロール作成時に初期化処理を何でもかんでもコンストラクタに書いてはいけない
今回System.Windows.Forms.Buttonクラスを継承したカスタムコントロールを作ってます。
このとき自作コントロール側で、配置してる親フォームの名前を取得したいと思って下記のようなコードを書きました。
Public Class TButton
Inherits System.Windows.Forms.Button
 
'配置しているフォームの名前

Private m_strFormName As String
 
....
 
Public Sub New()

' この呼び出しは、Windows フォーム デザイナで必要です。
InitializeComponent()
' InitializeComponent() 呼び出しの後で初期化を追加します。
 
'親コントロール
Dim ParentObj As Windows.Forms.Control = Me.Parent

'フォームの名前取得
m_strFormName =ParentObj.GetType.FullName
End Sub
End Class


要はコンストラクタで、親オブジェクト(フォームであること前提)の名前を取得しているだけす。
しかし、これをするとデザイナを開いたときに「オブジェクト参照がオブジェクト インスタンスに設定されていません。 」というエラーが出てきます。
e0091163_10143380.jpg

しかもエラー一覧には警告で「呼び出しのターゲットが例外をスローしました。」とでるだけ。
つくづく思うのですが、MSはもうちょっとわかりやすいエラーを出すようにしてほしいですね。
この「オブジェクト参照がオブジェクト インスタンスに設定されていません。 」というのは、あるオブジェクトのプロパティやらメソッドやらを触ろうとしたけど、オブジェクトがNull(VB的に言うとNothing?)だからできないという意味だそうです。

で、なぜ上記のコードの場合このエラーがでるかというと、自作コントロールが張り付けてあるフォームのDesignerファイルInitializeComponentメソッドを見るとわかります。


Private Sub InitializeComponent()
Me.TksButton1 = New TksButton
Me.SuspendLayout()

 
 
'TksButton1
'
'ここで自作コントロールのプロパティを設定。
 
'
'Sample_and_Test

'
....
Me.Controls.Add(Me.TksButton1)
....
End Sub


VSが自動で生成するとこんな感じになっていると思うのですが、まず最初に自作コントロールのインスタンスが生成されます。
しかし、実際にこのコントロールがフォーム上に配置されるのは
Me.Controls.Add(Me.TksButton1)
の部分です。
つまり、コントロールのインスタンス生成時には、まだコントロールはフォームに追加されていないため、コンストラクタで親フォームを探そうとしても探せない(Null)にという状態になるようです。
また、ふりっつさんのブログによると、コントラクタ内で値の初期化は2回実行、2重登録されてしまうためよろしくないようです。

これの解決策として、コントロール配置時に発生するイベントがあるみたいです。(配置時ということは親側のMe.Controls.Add(コントロールオブジェクト)が起きたタイミングか?)
それは、InitLayout()メソッド。
これはSystem.Windows.Forms.Controlに定義されており、オーバーライド可能なので、今回の場合は使えそうです。

とういことでこう書きなおしました。

Public Class TButton
Inherits System.Windows.Forms.Button
 
'配置しているフォームの名前

Private m_strFormName As String
 
....
 
Protected Overrides Sub InitLayout()

'基本クラスのInitLayoutを呼ばないとおかしくなるらしい
MyBase.InitLayout()
 
'親コントロール
Dim ParentObj As Windows.Forms.Control = Me.Parent

'フォームの名前取得
m_strFormName = ParentObj.GetType.FullName
End Sub
 
Public Sub New()

' この呼び出しは、Windows フォーム デザイナで必要です。
InitializeComponent()
' InitializeComponent() 呼び出しの後で初期化を追加します。
End Sub
End Class

こうするとデザイナでもきちんと表示されますし、実行しても正しく動くようになりました。

カスタムコントロールを作成するとデザイナがおかしくなることがよくありますが、やはり呼び出しのタイミングやバグが原因なんでしょうね。


たとえば、この自作コントロール(チェックボックス)が別の自作クラスで描画している場合、CheckedChangeイベントで自作クラスを用い描画するということがあるかもしれません。
この場合、デザイナ側でCheckedプロパティをTrueにしておくと、当然DesignerファイルInitializeComponentメソッド内で、○○.Cheked=Trueになります。
ということはこのコードが実行されるより前に自作クラスのインスタンスがないとやはりエラーになってしまいます。(これはコントロールのコンストラクタを使うくらいしか方法はないのでしょうが。。。)
[PR]
by jehoshaphat | 2008-04-09 10:14 | .Net開発 | Trackback | Comments(1)
[vb.net]あるオブジェクトのクラス名を取得する方法

アプリ内であるオブジェクトがどのクラスが出力したい時があります。
まあ前から使ってたんですが、すぐ忘れるので一応メモ。

Dim str As String = ""
MsbBox(str.GetType.ToString)

とすると

System.String

というような感じで出てきます。
ちゃんと名前空間もはいった形ででてきます。

これを例外発生時に例外クラスにかけてやると、


Try
'エラー起こす処理
      ....
Catch ex As Exception
MsbBox(ex.GetType.ToString)

 
'こう出力される
'System.IO.FileNotFoundException
End Try

というように例外クラスがわかります。
[PR]
by jehoshaphat | 2008-04-08 09:41 | .Net開発 | Trackback | Comments(0)
DirectShow(VB.NET)で描画時にユーザイベントを取得する方法
Panelコントロール内部で動画再生を行うコードをActiveMovie control type livraryを使って書いてますが、ユーザのマウスイベントとかが取得できなかった(Panelのイベントとして)でその方法を調べてみました。
-------------------------------------

'グラフマネージャの作成
Dim m_Grp As FilgraphManager = New FilgraphManager
m_Grp.RenderFile(m_strFilePath)

'IVideoWindowインターフェース取得
Dim VideoWindow As IVideoWindow = Nothing
VideoWindow = TryCast(m_Grp, IVideoWindow)

'描画領域のイベントをコントロールに渡す
VideoWindow.MessageDrain = CInt(Me.Handle)

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

上のコードをPanelを継承したカスタムコントロール内に書けばOKみたいです。
特に
VideoWindow.MessageDrain = CInt(Me.Handle)
が肝です。
これで、VideoWindowがとらえたイベントを指定したハンドルを持つコントロールに渡すことができるようです。

このカスタムコントロールをフォームにデザイナで配置して、下記のようにすれば正しくイベントを拾えました。
-------------------------------------

Private Sub mlt_MouseDown(ByVal sender As Object, ByVal e As System.Windows.Forms.MouseEventArgs)
Handles mlt.MouseDown
MsgBox("クリックされました。")
End Sub

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

なお、IVideoWindowで拾い、渡せるWin32メッセージは(IVideoWindow::put_MessageDrainと同じであれば)下記の分だけ出そうです。
参照:IVideoWindow::put_MessageDrain
http://msdn.microsoft.com/library/ja/default.asp?url=/library/ja/DirectX9_c/directx/htm/ivideowindowput_messagedrain.asp

-------------------------------------
WM_CHAR
WM_DEADCHAR
WM_KEYDOWN
WM_KEYUP
WM_LBUTTONDBLCLK
WM_LBUTTONDOWN
WM_LBUTTONUP
WM_MBUTTONDBLCLK
WM_MBUTTONDOWN
WM_MBUTTONUP
WM_MOUSEACTIVATE
WM_MOUSEMOVE
WM_NCLBUTTONDBLCLK
WM_NCLBUTTONDOWN
WM_NCLBUTTONUP
WM_NCMBUTTONDBLCLK
WM_NCMBUTTONDOWN
WM_NCMBUTTONUP
WM_NCMOUSEMOVE
WM_NCRBUTTONDBLCLK
WM_NCRBUTTONDOWN
WM_NCRBUTTONUP
WM_RBUTTONDBLCLK
WM_RBUTTONDOWN
WM_RBUTTONUP
WM_SYSCHAR
WM_SYSDEADCHAR
WM_SYSKEYDOWN
WM_SYSKEYUP

-------------------------------------
[PR]
by jehoshaphat | 2008-04-04 13:44 | .Net開発 | Trackback | Comments(0)
exeと別フォルダのDLLを参照する方法
今やってる案件が初の.Net開発ということで四苦八苦しながら.Net勉強してます。

そのなかで別のフォルダのDLLをみれないのか?という疑問がわきいろいろ調べてみました。

結論としては「しかるべき手順をとればできる」ということです。
ネット上の掲示板等では「exeと同じ階層にDLLを置くのが常識だ」という意見がちらほらありましたが、下記の連載をみるとそうではないそうです。

インサイド .NET Framework [改訂版]第3回 アセンブリのロード
http://www.atmarkit.co.jp/fdotnet/technology/idnfw11_03/idnfw11_03_01.html

(かなり詳しいレベルで書かれてますが、連載すべてはかなりの量です。まだ少ししか読んでません)

これによると.Netで作られた実行ファイル(正確にはCLR)は下記の順序でアセンブリ(DLL等)を探しに行くみたいです。
1. DEVPATH環境変数に列挙されているディレクトリ
2. グローバル・アセンブリ・キャッシュ
3. アセンブリのコードベース
4. 3.が存在しなかった場合はプローブを行う

この4.のプローブというのが1.~3.まで探して見つからなかったときに最終手段として実行ファイルと同じ階層かアセンブリ名のついたサブフォルダを探すことのようです。

ということは、1.~3.の方法で行うのが正しいということですな。
1.はよく調べてないんであれですが、2.はどのアプリからでも使うDLLを登録して置く方法みたいです。この方法だと、昔のCOMみたいに結局レジストリに参照の設定を書かないといけないし、そもそも自身のアプリしか使わないのにグローバルのするのは勧められてません。
ということで推奨されているのは3.の方法です。これは参照するアセンブリをアプリケーション構成ファイル(app.config) に明記してやる方法です。

ということで、3.をするための具体的な方法を書いていきます。(ほとんど上記リンクの簡易解説となりますが。。)
大まかには下記の流れになります。
【1】アセンブリに署名し厳密名を割り当てる。
【2】sn.exeで厳密名を確認。
【3】アプリケーション構成ファイルにて使用するアセンブリの定義を書く。



【1】アセンブリに署名し厳密名を割り当てる。
まず、参照されるアセンブリは厳密名(いわゆる「アセンブリ署名」)というものがないといけません。
アセンブリの名前は下記の種類があるようです。
* 名前(簡易名)
* バージョン
* カルチャ(どの言語ロケールかというものを指定するみたい。"ja-JP"など)
* 公開キー
この公開キーが付いたもの(署名されたもの)が厳密名のついたアセンブリだそうです。

この公開鍵そして秘密鍵を署名に使っているところがなかなか面白いです。(ちょっと余談ですが、、)
アセンブリのハッシュを秘密鍵で暗号化。それを公開鍵とともにアセンブリに追加(署名)。
これにより、実行時に公開鍵で暗号化されたハッシュを複合して、アセンブリ自体のハッシュと比較してアセンブリが改ざんされていないかどうかチェックできる仕組みみたいです。
電子メールの署名とかの技術をそのままアセンブリにも使ったという感じですが、ウイルス等への対策となることを考えると有効な方法ですね。

まあ、それはさておきとにかく署名をしないといけません。
Visual Studio2005ではIDE上で簡単に署名ができます。
1.プロジェクトのプロパティを開きます。
2.署名タブにて、「アセンブリの署名」にチェック。
3.「新規作成」にて新しいキーが簡単に作れます(しかも1回作っておけば使い回しがききます)

これで署名完了です。

【2】sn.exeで厳密名を確認。
次はアプリケーション構成ファイル(app.config)に読み込むアセンブリを定義します。
が、このとき厳密名を書かないといけません。
この厳密名がVS上でわかればいいのですが、私は見つけられませんでした。。
(署名はできるのに、厳密名がわからんとはどういうこっちゃ。。。)
とういことで、.Net Frameworkに付属している "sn.exe"というツールで確認できます。
(このsnですが、環境によっては入ってない場合もあるようです。VSのインストール時のオプションも関係あるのかな? 自分はProgram Files\Microsoft Visual Studio 8\SDK\v2.0\Binに入ってました)
下記のように使います。

>>sn -Tp test.dll(アセンブリ名)

Microsoft(R) .NET Framework Strong Name Utility バージョン 2.0.50727.42
Copyright (c) Microsoft Corporation. All rights reserved.

公開キー
0024000004800...........

公開キー トークン d57fc5c09b533907

この「公開キー トークン」が厳密名になります。


【3】アプリケーション構成ファイルにて使用するアセンブリの定義を書く。
1.アプリケーション構成ファイルを追加(VSならソリューションエクスプローラでプロジェクト右クリック→追加→新しい項目→アプリケーション構成ファイル)
すでに存在しているならその中に書いていきます。
2.アプリケーション構成ファイルに次のように使用するアセンブリへの参照を定義します。
----------------------------------------------


<assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
<dependentAssembly>
<assemblyIdentity name="test(アセンブリ(簡易)名)"
publicKeyToken="d57fc5c09b533907(上述の公開キートークン)"
culture="neutral" />
<codeBase version="1.0.0.0"
href="..\Common\Bin\test.dll(アセンブリへのパス)"/>
</dependentAssembly>
</assemblyBinding>
</runtime>


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


結構めんどくさいのがあれですね。
まあでもこれで
* 複数のアプリケーションで共有できる
* バージョン管理の対象となる
* セキュリティ・チェックができる
という.Net Frameworkの利点が利用できるのはいいことです。

ちなみに、VS2005の署名タブのところで、「遅延署名のみ」というのがあるのですがこれがいまいちよくわかりません。
遅延署名自体の考え方は分かっているのですが、プロジェクトの実行やデバッグができないというのは困りますね。。
[PR]
by jehoshaphat | 2008-04-03 13:29 | .Net開発 | Trackback | Comments(1)