<   2008年 04月 ( 12 )   > この月の画像一覧
(VB.Net)DoubleからIntegerへのキャスト時の小数点以下のおかしな挙動。
doubleからintegerにキャストするときに、小数点以下の扱いですが、どうやらCやJavaのように切り捨てではないようです。
VB.Netの場合は結果は丸められるようです。(VB6もそうだったのか?)
しかも丸めの法則が理解不能です。
具体的には下記のコードを見比べてください。

C#
double dblA = 0.4;
double dblB = 0.5;
double dblC = 0.51;
double dblD = 0.6;

int numA, numB, numC, numD;
numA = (int)dblA;
numB = (int)dblB;
numC = (int)dblC;
numD = (int)dblD;
 
Console.WriteLine("numA="+numA);
Console.WriteLine("numB="+numB);
Console.WriteLine("numC="+numC);
Console.WriteLine("numD="+numD);

結果
numA=0
numB=0
numC=0
numD=0

C#だとキャスト時に小数点以下は無条件に切り捨てになります。
これは私が今まで慣れ親しんできたC,Javaと同じ形で納得できます。


VB.Net
Dim dblA As Double = 0.1
Dim dblB As Double = 0.5

Dim dblC As Double = 0.51
Dim dblD As Double = 0.6

Dim numA, numB, numC, numD As Integer
numA = CType(dblA, Integer)
numB = CType(dblB, Integer)

numC = CType(dblC, Integer)
numD = CType(dblD, Integer)
 
Console.WriteLine("numA=" & numA)

Console.WriteLine("numB=" & numB)
Console.WriteLine("numC=" & numC)
Console.WriteLine("numD=" & numD)

結果
numA=0
numB=0
numC=1
numD=1

これをどう思いますか?
最初は勝手に四捨五入してくれるのか~と思ってましたがそうでないようです。
.00 <= 値 <= .5 までは切り捨てになるようです。
不思議なことに .5 <= 値 < .0 までは切り上げになるようです。
気持ち悪いのは .5 は切り捨てなのに .51 が切り上げになるという点ですね。
四捨五入でもないし五捨六入でもない。。
どうやらVB6からの負の遺産みたいですが、どうせ.Netにしたんだからそこらへんの分かりにくい仕様も変更してほしかったです。

いちおうMSDNにもキャスト時に丸められることは書いてましたが、VBの場合の具体的な挙動については書いてませんでした。
[PR]
by jehoshaphat | 2008-04-28 10:11 | .Net開発 | Trackback | Comments(1)
(.Net)オリジナクラスのドキュメント(リファレンス)作成方法。(Sandcastle編)
.Netでオリジナルクラスを生成した時、そのドキュメント(リファレンス)をソースのドキュメントコメントから生成する方法です。

環境はVisual Studio2005。
いくつか方法があるみたいですが、一番メジャーだと思われるSandcastleを使ってみました。


Sandcastleはコマンドラインベースのツールで使いにくかったので(というより自分の環境ではなぜか失敗してしまいました)、Sandcastle Help File BuilderというGUIツールからSandcastleを使ってみます。

まずここからSandcastleの最新版をダウンロードします。
(2008/04/24時点で最新は2008/1/16 Update版です。)
なお、マイクロソフトのWebからもダウンロード可能ですが、こちらのは2007年のCTP版なので、最新のSandcastle Help File Builderからは使えませんでしたので注意です。

Sandcastle Help File Builderはここからダウンロードします。
1.6.0.4 Producion と 1.6.0.6 BETA がありました、今回はベータ版を使いました。

なお、Visual Studioのプロジェクトの設定で「XMLドキュメントファイル」の出力にチェックを入れる必要があります。

これでプロジェクトをビルドし、Sandcastle Help File Builderを起動して、VSのソリューションかプロジェクトファイルを開きます。
自動でビルド時に出てきたxmlファイルが上部のリストに出てきてますが、一応 Edit ボタンからただしくリンクしてるか確認します(ビルド先を変えていると結構間違っていることがあるようです)
デフォルトではPublicメンバしか作ってくれないっぽいので、Visibility配下のプロパティで、どのレベルまでのリファレンスを作るかを指定できます。英語さっぱしのため詳しくはわからないのでいろいろ試してみるしかなさそうです。

参照している別DLLなどがあれば、それもDependenciesプロパティで指定してあげないとビルド中にエラーが出るみたいです。

また、自分の環境ではHelpFileFormatがHelp1xだとうまくいかなかったので、Websiteでビルドしなおしました。
(まあどのみちWebサーバでみれるようにしたかったのでこれでかまわなかったのですが。)

とここまでいろいろ書いてきましたが、詳しいことは。非常にわかりやすかったので助かりました。

また、
こちらでも詳しく説明されているので参考になります。
ただ、「4.「スタートメニュー」-「すべてのプログラム」-「Sandcastle Help File Builder」-「Build Reflection Data (first use)」を実行。」の部分は実行しなくても動きました。
(Sandcastleの最新版をいれておくと「すでにフォルダがある」みたいなエラーメッセージが出てきます。)


自動でリファレンスがでてくるというのは非常にありがたいですね。
ただ、作ったリファレンスがプロジェクトメンバに見てもらえず、みな口頭でききにくるというのはちょっと悲しいですが。。
[PR]
by jehoshaphat | 2008-04-25 18:23 | .Net開発 | Trackback(1) | Comments(0)
(.Net)インスタンスをコピーしたい
今回はあるインスタンスをコピーしたいという時に使える方法です。(もちろん参照のコピーではなく、あるインスタンスをメモリ空間ごとガバッとコピーすることです。)

1つにはあるインスタンスをループでまわして、フィールドをコピーすると方法がありますが、あまり現実的ではないでしょう。(なぜならフィールド数が多いとそれだけコードが増えるし、Publicなフィールドしかコピーできないからです)


ひとつが、System.Object.MemberwiseClone メソッドを使用する方法があるようです。
MemberwiseCloneメソッドはコピーしたいクラスに、System.ICloneable インターフェイスを実装しないと使えないようです。
(MemberwiseCloneメソッドはプロテクト メソッドなので、これを公開するためにSystem.ICloneable インターフェイスを実装するみたいです)
注意点は
    1.MemberwiseCloneメソッド、実装しないといけないICloneable.Clone メソッドの戻り値はObject型になるので明示的にキャストしないといけないこと。
    2.これはシャローコピー(簡易コピー)と呼ばれるものらしくて、インスタンス内の値型のフィールドはコピーするが、参照型のフィールドは参照(Cでポインタ)しかコピーしないこと。(ということはコピー元のAという参照型フィールドとコピーされたAという参照型フィールドは同じということですな)

じゃあ、参照型フィールドでも参照先のインスタンスをコピーしたい場合は?という疑問がわいてきますが、その方法もあるようです。
この方法をディープコピー(詳細コピー)というらしいです。

で、どんなふうにするのかとうのをじゃんぬさんの記事のコード見ると、コピー対象となるクラス内で、簡易コピーしてから、参照フィールドをColone(Implements System.ICloneableの実装)するという感じでした。
なるほど。でも結局は参照フィールド数しないとコピーしなおさないといけないのか。。

ほかにもっと手間かからない方法ないかなと探していると、こういう記事を見つけました。
(vb.netはこちら)
オブジェクトをシリアライズし、それを別オブジェクトにデシリアライズするという方法みたいです。
条件としてはオブジェクトがシリアライズ化できること。(これが結構めんどかった。。特に外部DLLのインスタンスを持ってるときとか。)
読みやすいコードも載っています。
が、まだ自分が勉強不足なためシリアライズがなんなのかは詳しく分かっていません。
Javaでも使われてるようですが、わからないとはJavaをやってたのに恥ずかしい。
ま、概略はインスタンス化してるデータを外部でも使えるようにバイナリ化したりだとか、ネットワークに流すだとかすることみたいです。
いづれによせ、これでインスタンス丸ごとコピーできるので使い勝手はいいですね。
[PR]
by jehoshaphat | 2008-04-21 19:33 | .Net開発 | Trackback | Comments(0)
(vb.net)VB.Net、VB2005で変わった点1
プログラム人生の最初にCをやってるせいか、VB6のプロジェクトに入ったとき、IF文の評価の時に、たとえば

If 最初の条件式 And 2つ目の条件式 Then
....
End If

というコードの時、"最初の条件式"の結果が False でも"2つ目の条件式"は評価されてしまう という事実になかなか慣れれませんでした。

さらにループ中でCやJavaでは contineu; があるなのに、なぜにVB6はないのだ。このせいで余計にIf文のネストが深くなる。という悲壮な気持ちになったこともありました。
さらには変数宣言と同時になぜ初期化できないのかとか、まあVB6への不満は山ほどありましたが。。

どうやらVB.Netではこの点は大きく改善されているようです。

最初の複数の条件式を判断する部分ではVB.Netには "AndAlso" と "OrElse" という演算子が追加されています。

AndAlso はC言語の && と同じ意味、OrElse はC言語の || と同じ意味です。
具体的なコードはこちらにコード付きで詳しく説明されています。
パフォーマンス的にもAndAlso、OrElseを使ったほうがよ下げみたいですね。


contineuについてはC,Javaは知ってる方ならわかると思います。まさにC,Javaのcotinue文をそのまま移植したという感じです。
また、"IsNot" 演算子ができたため、

If Not myObj Is Nothing Then

というようなコード

If myObj IsNot Nothing Then

というようによりシンプルに書くことが可能になったみたいです。
しかし、この2つはVB2005からの機能みたいです。

VB2005の変更点は下記MSサイトに詳しく出てます。
http://www.microsoft.com/japan/msdn/vs05/vbasic/languageenhancements.aspx#languageenhancements_topic8

(タイトルに"1"とかって書いてますが、いつのことになるやら。。。)
[PR]
by jehoshaphat | 2008-04-14 14:59 | .Net開発 | Trackback | Comments(0)
.NET Frameworkのソースコードを見たい
昨年末くらいにあのMicrosoftが.NET Frameworkのソースコードを公開するとかいう記事があちこちのニュースサイトに上がってました。
で、今年に入って本当に公開されたようなので、ちょっと参考にしようかなと思ったのですが、オープンソース系みたいにアーカイブでどんと置いてあるのではなくて、閲覧手順も結構めんどいみたいです。

ということでナカイさんのサイトを参考にしてVSのデバッグ中に見れるようにしました。
手順が細かく記されている上にVS2005でも見れる方法についてわかりやすく書いてあります。

デバッグ以外で個別ソースを見たい時は.NET Mass Downloaderでダウンロードしたフォルダの中から個別に見ることができます。

いろいろ見てると勉強になりますね。
やっぱりFramework部分はC#で書かれてます。
仕事でも早くVB.NetぬけてC#したいと思う今日この頃。。
[PR]
by jehoshaphat | 2008-04-14 14:19 | .Net開発 | Trackback | Comments(0)
カスタムコントロールでのデフォルトのフォントの変更
カスタムコントロール(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)