(35) VB6:ErrorLevel
Declare Sub ExitProcess Lib "kernel32" (ByVal uExitCode As Long)で一発。知らなかったよ…orz
Declare Sub ExitProcess Lib "kernel32" (ByVal uExitCode As Long)で一発。知らなかったよ…orz
先日のこと。
VBを使ったプログラミングの説明をしてまして、「0で除算するとオーバーフロー例外が発生して」と説明したら、「0除算例外ではないんですかい?」とツッコみが入りました。
言われてみればその通りだ。
でも実際問題として、VBで0除算すると発生するのは「System.OverflowException」であって「System.DivideByZeroException」ではないんだよなぁ。なんでだ?
VB2005のExpress EditionでやってもTeam SuiteでやってもVB.NET2003でやってもオーバーフロー例外。
むー?とか悩んでいたら、msdnLibraryの/ 演算子 (Visual Basic)のページに、
除算を実行する前に、整数の数式は必ず Double 型に拡大変換されます。
ってええっ。
で、DivideByZeroException クラスの説明では、
浮動小数点値を 0 で除算すると、IEEE 754 の算術規則に従って、結果の値は、正の無限大、負の無限大、または非数 (NaN) のいずれかになります。浮動小数点演算では、例外はスローされません。
ってあらー。
ついでに、Double.PositiveInfinity フィールドの説明では、
正の無限大を表します。このフィールドは定数です。
この定数の値は、正数を 0 で除算した結果です。
つことは、
ってことですかい。
ならば、左辺の受け側変数をDouble型ににしちまえばオーバーフロー例外も発生しなくなるってことですかい?
Private Sub Button1_Click(...) Handles Button1.Click
Dim a As Integer = 10
Dim b As Integer = 0
Dim c As Double = 0
c = a / b
End Sub
うわぁほんとに発生しねぇ。スルーで通っちまいましたよお客さん。
ちなみに、Decimal型の場合は事前のDouble型変換が行われないので、0除算例外が発生します。
上でお見せしたVBのリリースEXE(MSIL)がどうなってるかってぇと、
わー確かにIL_0008とIL_000aでDouble型に変換(conv.r8)してからdivかけてはるー。
VB6までは0除算エラーは型にかかわらず発生していたんですよ。
浮動小数点型の0除算がIEEE754に則って±∞または非数(NaN)を返すようになったのはVB.NETからってゅうか.NET Framework1.0からですね。
例外が発生しないのは浮動小数点型での0除算のみで、整数型・固定小数点型での0除算は旧来通り0除算例外が発生します。
このへん、VB5:Single型・Double型の変数で計算すると微妙に数値が狂うで型ごとのデータの内部格納形式を調べた時にブツカって、「あーVBってIEEEに準拠しない独自仕様なのねー」とちょっとしょんぼりした覚えがあるのでなんか懐かしいす。
かといって小数の演算結果になり得る演算を整数型のままでやるわけにもいかないので、
Dim a As Integer = 10って記述した時は、意味的には
Dim b As Integer = 0
Dim c As Double = 0
c = a / b
Dim a As Integer = 10とせざるを得ないわけです。
Dim b As Integer = 0
Dim c As Double = 0
c = CInt(CDbl(a) / CDbl(b))
C#だと「c = a / b;」でも0除算例外が発生するんですけど、これ、整数型のまま除算しているんですよ。これと同じ演算結果を得ようと思ったら、VBでは「/」ではなく「\」を使うことになります。いわゆる整数除算。
この場合であればVBでもちゃんと0除算例外が発生しますね。
以上より今回の結論。
うーん、意図は納得できるけどめんどくさいなぁ。
でいいんです。いいんですけど。
試しにログ文章用にTextBox1つ、イベントタイプ指定用にOption3つ用意して、実行用のCommandに
Private Sub cmdExec_Click()ってやってみたらさくっとイベントビューアに反映されたんですけども。
Dim logBuffer As String
Dim eventType As Long
logBuffer = Trim$(txtBuffer.Text)
Select Case True
Case optError.Value
eventType = vbLogEventTypeError
Case optWarning.Value
eventType = vbLogEventTypeWarning
Case optInfo.Value
eventType = vbLogEventTypeInformation
End Select
Call App.LogEvent(logBuffer, eventType)
End Sub
ハマったのは、
イベント ログは、アプリケーションがコンパイル済み .EXE として実行されているときにのみ更新されます。IDE から実行した場合は、イベントはイベント ログに書き込まれません。これは、デバッグ中にイベント ログに書き込まれるデータが過剰になるのを防ぐためです。
がわからなかったんですよ!
そんなことMSDN Libraryのどこにも書いてないんですよ!
Visual Basic から Windows NT イベント ログへの書き込み方法までたどり着いてようやく事の次第を理解した次第で。思いきりむかりとした次第で。
VB5の頃からの仕様なんだからMSDN Libraryに書いといてくれよ!
とかやつ当たってみたりもする次第で。とほほ。
検証環境 Dell PRECISION340(Pen4-2.0GHz/512MB)
Win5.1(Build 2600.xpsp_sp2_gdr.050301-1519)/VS.NET2005(8.0.50727.42(RTM.050727-4200)) & .NET Framework2.0(2.0.50727)
ソーシャルネットワーキングサイト(SNS)のmixiってところがありまして。
そこの日記で「ListViewに非表示列を持たせたいよー」とか愚痴ったら、意外にいろんな方からご意見をいただいておもしろいディスカッション(つか一方的に教えてもらいまくったというか)になりましたので、ちょっとまとめてみることにしました。
簡単に表形式でデータを表示したい時に、これを .View = Details にしてよく使うんですが。
今回、主な項目だけを表示しておき、行を選択するとその明細を横に表示するような機能を作ってみたくなったんですね。
しかし表示する項目は重複要素が多く、ユニークなキーにはならないんです。
ってことは、せっかくHashTableで明細情報を保持しても、選択行からHashTableの特定のItemへひもづける方法がない、ということになります。
そこでキー引きできるようなユニークなキーをListViewの非表示列に保持しておきたいなーと思ったんですよ。
ところがどう調べても列を非表示にするプロパティもメソッドも見つからないよどーしよーと。
したっけ知恵者な方々からのナイスアイデアやらアドバイスやらが続々と。
てことで、以下サンプルを交えてのまとめです。
「非表示にできないなら列幅を0にして見えなくしちゃえ」という発想ですね。
正直これが一番簡単だと思います。
実際に作ってみるとこんな感じで。

列タイトルが「1列目」「2列目」「4列目」になっているのがミソで、3列目の列幅を0にしているんですね。

表の初期値は、めんどくさいのでForm_Loadイベントの中でアルファベット大文字をキャラクタコードとループで突っ込んであります。3列目だけは区別をつけるために小文字にしてあります。
Private Sub Form1_Load( _で、好きな行をクリックすると、隠れている3列目の内容が下のLabelに表示されると。
ByVal sender As System.Object _
, ByVal e As System.EventArgs _
) Handles MyBase.Load
'*** 初期化
ListView1.Items.Clear()
For i As Integer = &H41 To &H47
ListView1.Items.Add( _
New ListViewItem(New String() {New String(Chr(i), 3) _
, New String(Chr(i), 11) _
, New String(Chr(i + &H20), 11) _
, New String(Chr(i), 5)}))
Next
End Sub
Private Sub ListView1_SelectedIndexChanged( _
ByVal sender As System.Object _
, ByVal e As System.EventArgs _
) Handles ListView1.SelectedIndexChanged
If ListView1.SelectedItems.Count > 0 Then
Label1.Text = ListView1.SelectedItems(0).SubItems(2).Text
End If
End Sub

おお、いい感じだ。
いい感じなんですけど、これ、列見出しの2列目と4列目の間をドラッグすると、隠れた3列目が見えてきちゃうんですよ。

ああっ、なんともかっこ悪い。
見せたくないからこそ非表示にしたのであって、なんかの拍子にぞろりと隠しデータが表示されたらびっくりします。
この操作は2列目の列幅を広げたい時によくやりますので、実際に充分ありえる操作ですよね。
てことで、 .Width = 0 で非表示化した次は見出しドラッグによる列幅の変更を禁止したいということになります。
これは、ColumnWidthChangingイベントで列幅の変更を検出し、むりやりもう一度列幅を0にしてやればいい、ということがわかりました。
Private Sub ListView2_ColumnWidthChanging( _実際に操作していただくとわかりますが、イベント発生ごとに抑え込んでいるなんてまったくわからないくらいにびくともしなくなります。
ByVal sender As Object _
, ByVal e As System.Windows.Forms.ColumnWidthChangingEventArgs _
) Handles ListView2.ColumnWidthChanging
If e.ColumnIndex = 2 Then
e.NewWidth = 0
e.Cancel = True
End If
End Sub

実用上はこれで十分ですね。
…わざわざ「実用上は」と言ったのは、実はマウスカーソルの挙動がちょっと変だからです。
2列目と4列目の見出しの間、ドラッグで2列目の幅を増減できる位置までマウスカーソルを持っていくと、カーソルが左右の矢印(左右へのスライドが可能、との意味を持つ)になります。

この場合は、2列目の幅を増減できるわけです。
で、ここから少しだけ右へマウスカーソルを移動させると、列幅0で非表示になっている列の幅の増減ができるマークに変わってしまうんですよ。

びみょーな違いですが、2列目増減の場合は左右矢印を貫く縦線が1本、3列目増減の場合は2本になります。
しかし2本線左右矢印のマウスカーソルに変わっても、列幅の変更はコードで抑え込んでいますので、実際にドラッグしても何も起こりません。
つまり、画面に表示される補助情報と実際の動作が食い違うという状態になってしまうわけです。
これはユーザにとまどいを感じさせますし、なによりここに隠し列があるのがバレバレで、これはこれでかっこ悪いす。
以上のような推敲の末、ゆっきさん(荒野の喫茶店)に教えていただいたベストリザルト。
ListViewの行はListViewItemってクラスですので、これに表示と関係ない変数を追加した派生クラスを作ってそっちを使っちゃえばいいんだと。
Public Class ListViewItemEXこんな感じで。
Inherits System.Windows.Forms.ListViewItem
Dim KeyData As String
Public Property Key() As String
Get
Return KeyData
End Get
Set(ByVal value As String)
KeyData = value
End Set
End Property
Public Sub New(ByVal subItems As String(), ByVal Key As String)
MyBase.New(subItems)
KeyData = Key
End Sub
End Class
InheritsでListViewItemからの派生を指定して、Newの中にMyBase.NewでListViewItemオリジナルの構造を引き継いで、ついでにString変数Keyも追加して。
Keyは内部的には変数KeyDataで保持しておいて、プロパティでGet/Setできるような出入り口を用意して。
ListViewItemの派生クラスですので、これはこのままふつーにListViewに突っ込めます。
Private Sub Form1_Load( _参照する時はListView.SelectedItems(0)でいいんですけど、これはListViewItemクラスですのでいったんListViewItemEXに型変換してやってからKeyプロパティを見てやればいいということになります。
ByVal sender As System.Object _
, ByVal e As System.EventArgs _
) Handles MyBase.Load
'*** 初期化
ListView1.Items.Clear()
For i As Integer = &H41 To &H47
ListView1.Items.Add( _
New ListViewItem(New String() {New String(Chr(i), 3) _
, New String(Chr(i), 11) _
, New String(Chr(i + &H20), 11) _
, New String(Chr(i), 5)}))
Next
ListView2.Items.Clear()
For i As Integer = &H41 To &H47
ListView2.Items.Add( _
New ListViewItem(New String() {New String(Chr(i), 3) _
, New String(Chr(i), 11) _
, New String(Chr(i + &H20), 11) _
, New String(Chr(i), 5)}))
Next
ListView3.Items.Clear()
For i As Integer = &H41 To &H47
Dim ItemEx As New ListViewItemEX( _
New String() {New String(Chr(i), 3) _
, New String(Chr(i), 11) _
, New String(Chr(i), 5)} _
, New String(Chr(i + &H20), 11))
ListView3.Items.Add(ItemEx)
Next
End Sub
Private Sub ListView3_SelectedIndexChanged( _非表示列がそもそもなく、でも行選択すると表の中にはないデータがLabelに表示される機能が、実にすっきり実装できます。
ByVal sender As System.Object _
, ByVal e As System.EventArgs _
) Handles ListView3.SelectedIndexChanged
If ListView3.SelectedItems.Count > 0 Then
Label3.Text = CType(ListView3.SelectedItems(0), ListViewItemEX).Key
End If
End Sub

わーい。
やはり.NETになって、RADツールは死んだのかもしれません。くそぉ。
Huizhong Long's WebLogのDisplaying custom bitmap for VS add-in command button from satellite DLL。
ちょっとややこしいかも…翻訳しておきたいところだなぁ。
ちなみにサテライトDLLってなぁMSDNのチュートリアル : マネージ サテライト DLL の作成で詳しく。
英語版ですが、Visual Studio 2005 Automation Samplesって奴が米国MSから提供されておりまして。
この中のUnSupportedToolで、ExtBrowser.dllってのがあるんですね。
どぅもDTE.Properties回りのAdd-Inらしいんですが。
どんなもんかイジってみたくて、さっそくダウンロードしてみました。
入手したmsiを実行すると、「(マイドキュメントフォルダ)\Microsoft Visual Studio 2005 Automation Samples」ってフォルダに25種類のサンプルが展開されます。で、目指すExtBrowser.dllは「(マイドキュメントフォルダ)\Microsoft Visual Studio 2005 Automation Samples\unsupptools\x86」にありましたありました。
unsupptoolsフォルダのreadme.txtには
To use it, run regsvr32 on the dll, ~とありますので、レジストリ登録もしました。って、
えーだめじゃんさすがアンサポートツール(T-T)。
でも一度も実行できずにあきらめるのはくやしいので、目玉飛び出させそうになりながらあちこち検索かけてみると、米国MSDN ForumsのDTE.GetObjectスレッドに解決策がありました。
実行結果はこちら。
なんか初回はフリーズ?ってくらいに時間がかかるのでお気をつけ。
MSDN Libraryの「ツールのオプション設定の制御(ローカル、オンライン)」以下。
ついで。IDE回りでツールウィンドウなどを作成するには、「環境ウィンドウの作成と制御(ローカル、オンライン)」。「オプション」ダイアログに独自のページを追加することなんかもできたりします。
プロパティ項目は「HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\VisualStudio\8.0\AutomationProperties」に格納されており、一覧することが可能です。Itemはこのキーに含まれるGUIDで指定されるパッケージ(dll)の中で実装されているので、レジストリから参照することはできません。
元ネタであるMZ-ToolsのHOWTO: Getting properties from the DTE.Properties collection of Visual Studio .NET. によると、自分なりに拡張することも可能らしいです。
あと、参照。
Craig Skibo's WebLogのProperties: How they work, why they exist。
VS2005がMicrosoft Visual Studio 2005 ドキュメント(MSDN Library for Visual Studio 2005)込みで提供開始されたのが2005.12.15。VS2005だけに限っていえば2005.12.14には提供開始されていたわけですが。
なんですけれども、その後2006.01.12に単体で提供されたMSDN LibraryはJanuary 2006、
このEditionはVS.NET2003に自動的に組み込まれる最後のEdition、VS.NET2003・.NET Framework1.1に関する記述が含まれる最後のEditionですなんて注釈がついておりまして、VS2005のための資料ではなかったんです。
VS2005用の更新版MSDN LibraryJune 2006は、2006.05.01によぅやっと出ました。
English版はMay 2006として2006.03.17(なぜ3月?^^;)に既に出ていましたので、お待たせしました日本の皆さんというかお待たせされましたよえぇもぅほんとにというかなんかそんな感じで。
わくわくしながらMSDNサブスクライバからダウンロードしましたよ、2,236,194,816バイトなどといぅADSL野郎にはかなり過負荷なサイズでしたけれども。
血沸き肉躍らせながらインストールしましたよ、またとんでもないインストール時間というかヘルプ結合時間がかかることを覚悟しながらも。
したっけ、「ファイルのコピー」フェイズが始まったとたんに
次のディスクを挿入してください Visual Studio 2005 DVDダイアログが表示されて、にっちもさっちも行かなくなってしまいました。いぇー。
もーVS2005TS、Exp、MSDN LibraryのどのDVDを入れても認識してくれない→∴(だから)そこから先に進まない(T-T)。
TSとExpを混在させていたので、あるいはMSDN Express Libraryが悪さしているのかとも思いそっちをアンインストもしてみましたけれども状況は一向に改善されず。
とりあえず困っちゃってたのは自宅マシンなんですが、仕事場のマシンでならどーよ?ってことで同じことをやってみたんですけど同じ現象が(T-T)。
どーにもお手上げで、ついにマイクロソフトサポート(有償)に「なんでですかね?」と連絡とってみました。
返ってきた答えは、「"MSDN Subscriptions Library June 2006 Edition" のインストールが正常に完了する手順に関してご案内いたします。」との前置き付きで、「この手順なら正常にインストールできるのではないか?」との提案がいくつか。
その中に、「既存のMSDN LibraryをアンインストしてJune 2006を新規インスト」ってのがありまして。
え。
June 2006って更新モジュールじゃなかったの?だって起動した時に
MSDN Library for Visual Studio 2005 - 日本語版の更新のセットアップウィザードへようこそって出るじゃないすか。
でもまぁ他に手もないことだし、ってVS2005回りのすべてのMSDN LibraryをアンインストしてからJune 2006を起動すると。
MSDN Library for Visual Studio 2005 - 日本語版のセットアップウィザードへようこそって新規インストール可能だったのかよ!
おかげさまで職場マシンには無事インストール完了ってなんか納得いきませんけれども。
自宅マシンで同じ作業をやってみて、同様に正常にインストールできることを確認しました。
以上、マイクロソフトサポートに「おかげさまでうまくいきました」と完了報告上げて一件落着としたいと思います。
さすがにこれ検証1つに数時間かかるので、June 2006が正常にインストールできている環境でわざわざ試す気には今さらなれませんけれども、やるとしたらそんな感じということで。
が、職場のマシンで[スタート]メニューから[すべてのプログラム]-[Microsoft Visual Studio 2005]-[Microsoft Visual Studio 2005 ドキュメント]で起動すると、さくっと起動ページとして表示されるじゃありませんか。
もちろん検索かけると、トップでヒットするわけで。あれぇ?
June 2006がどうのという前に、自宅のマシンでも試してみました。
ショートカットのプロパティを見比べてみると、「Microsoft Visual Studio 2005 ドキュメント」の方は
"C:\Program Files\Common Files\Microsoft Shared\Help 8\dexplore.exe" /helpcol ms-help://ms.vscc.v80 /LaunchNamedUrlTopic DefaultPage /usehelpsettings VisualStudio.8.0「Visual Studio 2005 MSDN ライブラリ」の方は
"C:\Program Files\Common Files\Microsoft Shared\Help 8\dexplore.exe" /helpcol ms-help://MS.MSDNQTR.v80.ja /LaunchNamedUrlTopic DefaultPageでした。
まぁ引数がそもそもms.vscc.v80とMS.MSDNQTR.v80.jaで大違いなので、動作が違ったって不思議はないんですが。なんでこんな2通りの動作を用意したのかなーと、そっちの方が不思議だったりします。
今回提供されたJune 2006、
とりあえず無理無理調べるなら、「C:\Program Files\MSDN\MSDN8.0\1041\eula.txt」の作成日時が「2006.02.24 3:52:53」だとか「C:\Program Files\MSDN\MSDN8.0\1041\readme.htm」の作成日時が「2006.03.18 12:11:33」だとかならJune 2006版だ、みたいな感じで確認するしかないっぽいです。
VS2005添付のMSDN Library for VS2005だと、「C:\Program Files\MSDN\MSDN8.0\1041\eula.txt」の作成日時が「2005.11.24 0:16:37」、「C:\Program Files\MSDN\MSDN8.0\1041\readme.htm」の作成日時が「2005.11.30 0:00:43」ですので、まぁとりあえず明確に違いますと。なんとかこれで確認できますと。
どのページを更新したのかの情報もないので、「このページの記述がこうなっているからJune 2006版だ」とかの確認もできませんしね。
アップデートしたのかどうなのか確認しにくい、ってのはかなり不便なんですけどねぇ…なんとかならんもんでしょうかこのへん。
検証環境 Dell PRECISION340(Pen4-2.0GHz/512MB)
Win5.1(Build 2600.xpsp_sp2_gdr.050301-1519)/VS.NET2005(8.0.50727.42(RTM.050727-4200)) & .NET Framework2.0(2.0.50727)
えー、ちょっと気になったので、VS2005 IDEのショートカット情報の仕組みについて調査結果メモ。
「(既定)」以外の選択肢は、「(VSフォルダ*1)\Common7\IDE」直下に格納されている.vskファイルの「拡張子抜きファイル名」がそのまま表示される。
.vskファイルは、それぞれのキーボードマップスキーム情報の実体。
「(既定)」はデータファイルとしては用意されておらず、システム内に埋め込まれているようだ。
どのスキームが選択されているかは、「HKEY_CURRENT_USER\Software\Microsoft\VisualStudio\8.0\Keyboard」キーの「SchemeName」値にフルパスで格納される(例:「C:\Program Files\Microsoft Visual Studio 8\Common7\IDE\Brief.vsk」)。
ただし「(既定)」の場合は「SchemeName」値はそのままで、値のデータが空文字列となる。
この選択スキームをDTE側から確認する場合は、
Dim props As EnvDTE.Properties = DTE.Properties("Environment", "Keyboard")
Dim prop As EnvDTE.Property = props.Item("SchemeName")とした時の prop.Value で取得できる。
逆にスキームを設定したい場合は、
prop.Value = "Brief"の2種類の書き方がある。
prop.Let_Value("Brief")
この手法はMSDN Library for VS2005の「方法 : コマンドの既存のショートカット キーを保持する(ローカル、オンライン)」および「Command.Bindings プロパティ(ローカル、オンライン)」で確認できる。
ただし「Command.Bindings プロパティ」の方のサンプルプログラムではスキーム名を引っ張り出すアイテム名を「Scheme」としているが、そんなアイテム名はない。「方法 : コマンドの既存のショートカット キーを保持する」で説明されているアイテム名「SchemeName」が正解。
とはいうものの、「方法 : コマンドの既存のショートカット キーを保持する」の記述がすべて正しいわけでもない。prop.Valueを「<FileName.vsk>」と、いかにも拡張子まで込みでファイル名を保持しているように書かれているが、実際に保持されるのは拡張子抜き。
「Brief.vsk」であれば「Brief」と保持されている。
では、実データファイルの存在しない「(既定)」の場合はどう保持されるのか?と調べてみると、「(既定)」と保持されていた。まんまじゃん。
というよりはむしろ、日本語版の表記そのもので内部保持しているところに問題がある。この点でVSマクロはローカル言語版でしか動作しなくなってしまうからだ。
確認は取っていないがオリジナルの英語版で「(既定)」になっていることはあり得ないだろう。「(Default)」かなんかになっているはずで、VSマクロをどのローカル言語版なのかに依存せずに動作させたいなら、そのVSのローカル言語を取得してその値によって振り分けてやらなければならないことになる。って、ローカル言語の取得ってどうやるんだろう。
VS2005はWin2000以降での動作を前提としているので、ログインするユーザごとに異なる環境を保持する。キー割り当ても例外ではなく、ログインするユーザごとにカスタマイズの状態を保持することとなる。
これは、「C:\Documents and Settings\(UserName)\Application Data\Microsoft\VisualStudio\8.0」直下の「Current.vsk」に保持される。
もう少し具体的に言うと。
ちなみに、「User.vsk」を削除してもVS IDEの動作に影響はない。
また、「Default.dsk」というファイルも「Current.vsk」「User.vsk」と同時に生成されるが、何に使用しているのかよくわからない。
これら3つのファイルはインストール時ではなく、ログインしているユーザー単位にVS IDEの初回起動時に生成される。ので、VS2005インストール後に作成したユーザーからでも、そのマシンにインストールされているVS2005を使用可能。もちろんショートカット回りだけではなくさまざまな初期値が用意されるのだろうが、現時点ではそちらの方までは未検証。
というわけで「Current.vsk」は原稿のショートカットキー割り当て情報のフルセットということになるのだが、では、これはインストール時に格納されるスキームファイルとどう違うのか。
実は何も変わらない。
実際、「Current.vsk」を「(VSフォルダ)\Common7\IDE」にコピーして「Salvage.vsk」に変更してみると、きちんと[次の追加キーボードマップスキームを適用:]リストボックスに「Salvage」の選択肢が追加される。「Salvage」を選択してみると、「Current.vsk」作成時に埋め込んでおいた独自のキー割り当てまでが再現できる。
VS2005には独自のキーボードマップスキームを新規スキームセットとして保存する機能はないが、「Current.vsk」に独自のファイル名(選択肢名)をつけて「(VSフォルダ)\Common7\IDE」にコピーする機能を作れば、独自スキームの選択肢作成機能になる。
[次の追加キーボードマップスキームを適用:]が「(既定)」に設定されていると、VSマクロやアドインから独自のキー割り当てをしようとしてもなぜかエラーになってしまう。.vskファイルとして用意されているいずれかの選択肢を設定してから独自のキー割り当て機能に移行する必要がある。
しかし現実には、「(既定)」を下敷きにしてキー割り当てを拡張する人が圧倒的多数だろうと推測できるので、やはり「(既定)」と同じキー割り当て情報を持つスキームファイルが必要だろう。
となると、一度「(既定)」の状態で作成された「Current.vsk」を別名でコピーして下敷きにするしかない。
となると、
実装すべき事柄が決まれば、あとは演出の問題だけ。
とはいうものの、キー割り当て回りはセットしたとたんにファイルにまで書き出しているようなので、どのタイミングで掃き出されたという前提で次の動作をしていいのか、ファイルがクローズされていると当て込んでリネームやコピーを行っていいかはちょっとびみょー。
このへんのからくり自体明確に説明されている資料が存在していないので、当然タイムチャートも存在しないし保証もされない。
タイミングの可否状態をあぶり出す検証作業を細かいレベルでやっておかないと、マシンによって動作する/しないなんて事態にもなり得る。
ここまででも私の頭にとっては相当ややこしい(;-;)。
VSマクロを実行させると、システムトレイにカセットテープアイコンが表示され、実行中ずっとぐるぐる回るんですね。
VS IDE側(マクロエクスプローラなど)から実行させると、VS IDEのステータスバー右隅でも同じアイコンがぐるぐる回るわけです。
それだけならなかなか愛らしいような気もするんですが、ときどきシステムトレイのカセットテープから、「このマクロを止めたい場合にはここをクリックしてください」ってバルーンヘルプが出ることがあるんです。
私のところでは、2台ある作業用マシンのうち1台では出、1台では出なかったりするんですが。で、出ると出ないの違いが、Windowsのタスクバーを固定にするか自動的に隠すかの設定の違いのような気もするんですが、別に検証したわけではないので断言は避けておきます。
つかそこが本題ではなく。
このマクロバルーン、どーいうわけだかマクロ愛好家の皆さんの間ではあまり評判がよろしくないようで。
まぁマクロそのもののデバッグならともかく、それを拡張機能として組み込んだ状態のVS IDEを使ってなんらかの開発作業をしている時に、いちいちIDE内部の動作についての報告なんか受けたくないという気持ちはわかります。集中がそがれちゃいますし、間違ってクリックしちゃうととんでもないところでマクロが止まったりしますので、不便っちゃ不便ですよね。
てことで、そのへんお怒りの方々がバルーン表示をさせない方法を探し出してます。
HKEY_CURRENT_USER\Software\Microsoft\VisualStudioってことでひとつ。
\8.0\DontShowMacrosBalloon ← 「6」
私自身は試していないので、メモレベルの情報です。ご注意ください。
元ネタはCraig Skibo's WebLogのStopping the “Click here balloon”から。
Visual Studio 2005に搭載されているVisual Studioマクロ。
こいつでしばらく遊んでみようと、マクロエクスプローラから"Samples"ノードを開いてみようとしたわけです。
したっけ、
以下の理由により、マクロ プロジェクト '' を読み込めません :ってえええええ(T-T)。
'(マイドキュメントのPath)\Visual Studio 2005\Projects\VSMacros80\Samples\Samples.vsmacros' は無効か、またはアクセス不可能なマクロ プロジェクト ファイルです。
えーと、どぅも私の環境では、VSマクロのサンプルがうまくコピーされないようです。
VSのバグなのかなぁという気もしますが、VB/C#のExpress Editionも一緒にインストールしている環境ですので、あるいはそちらと混在させたが故の現象なのかもしれません。
ですからことさら「不具合だバグだ」と騒ぎ立てるつもりはありませんが、だからといってSamples抜きの環境のままで調査や学習をしていくのもムダに大変です。
ここは一発、手作業でSamplesを参照できる環境を作ってみましょう。
上記のエラーメッセージでは「(マイドキュメントのPath)\Visual Studio 2005\Projects\」フォルダの下層にある「VSMacros80\Samples\」から読み取ろうとしていますが、VSのインストール直後にエクスプローラで見てみると、そんなフォルダは存在していません。
マクロエクスプローラを初めて表示した際に作成されるようなんですね。
つことは、本来このタイミングでSamplesフォルダにサンプルファイルがコピーされるはず。
またマイドキュメントフォルダ以降に生成されるということは、ログオンするユーザーごとに別々のタイミングで生成されるはず。
つことは、コピーされる元ネタは別の位置に保存されているはず。
という推測が成り立ちますというか推測してみました。
もひとつ。
コピーされるファイルは、具体的になんなのか。
私の環境にはVS2003も併せてインストールしてあり、こちらのマクロエクスプローラからはサンプルのノードが正常に表示されていますので、これを手がかりにしてみましょう。
VS2003の個人データは「(マイドキュメントのPath)\Visual Studio Projects」以下にできます。で、目指すSamplesフォルダは「(マイドキュメントのPath)\Visual Studio Projects\VSMacros71\Samples」と、ほぼVS2005と同じ階層構造になっています。このへんの管理のしかたはあまり変わっていないようですので、中のファイル群も参考にできる可能性大です。
…実際に「(マイドキュメントのPath)\Visual Studio Projects\VSMacros71\Samples」に格納されているファイルはSamples.vsmacrosひとつだけでした。
「コメントを追加→保存」などして試してみると、Samples.vsmacrosそのものの内容が変化しますので、どうもこれ自体が実体のようですね。
VSのソリューション/プロジェクトとは異なり、VSマクロはまとめてひとつの.vsmacrosファイルにバイナリで保存されるようです。
ふむ。では、VS2003のSamples.vsmacrosをVS2005用のフォルダにコピーしてしまえば。
っていやいや、上記の推測では「どこかにVS2005用Samples.vsmacrosのコピー元ネタが存在しているのではないか?」ですので、そいつを探してみるのが先でしょう。
第一VS2003と2005でVSマクロがバイナリレベルで完全互換があるとは限らないので、安易なバージョン間移行は危なくってしょうがありません。
もっともふつーにVS2005をインストールすると、そのファイル群はデフォルト指定で
探してみました。
えーと、2つ見つかったんですけど。デフォルト指定で
でVS2005起動→マクロエクスプローラ表示→Samplesノード展開。
おおっ、なんかいろいろサンプルが表示されているぜソースもエディタで表示されるぜ!
自動でSamplesフォルダにコピーされないのがいまいち気にくわないところではありますが、まぁこれで十分実用になりますので今回はよしとしましょうか。
VS2005セットアップのメンテナンスモードで「修復/再インストール」を実行すると、Disc1の挿入を促す「ディスクの挿入」ダイアログが表示される。
msdnDVDなどからインストールする場合の指定パスは「(ドライブレター):\vs\」だが、ここでうっかり「(ドライブレター):\」などとすると、「無効なディスクが挿入されました。Microsoft Visual Studio 2005 Team Suite - JPN Disc 1 を挿入してください。」メッセージボックスの無限ループになってしまう。
この無限ループから脱出するには、誤って指定してしまったドライブからDVDを抜いて[OK]。
HDDドライブを指定した時などはメッセージボックスは表示されず、無反応。
CD/DVDドライブの時にのみ発生。試してはいないが、それ以外のリムーバブルメディアの場合も同様か?
気づけばなんということはないが、気づかないともータスクマネージャから強制終了するしかないというカメイワTipsといぅことでひとつ。
※カメイワ:
「ゼルダの伝説/神々のトライフォース」プレイ時に、3本の杭を順番に叩くだけの簡単な亀岩のイベントで私が3日もハマったことに由来。
以来個人的に「気づけば簡単なのに、気づかないために猛烈にドツボにハマる状態」を「カメイワ」と呼ぶことに決定。
個人的な表現には、他に「ナガサキ」、「トレロカモミロ」などがある。
Procedure/FunctionのVBからの生成は、素直にCREATE/UPDATE - PROCEDURE/FUNCTIONをDbExecuteSQL(VB6 & OO4O)でブン投げればOK。
ただしPL/SQLコードはVBCrLfではなくVBLfで改行しないとコンパイルエラー発生。OracleではCRを処理できないらしい。
たぶん標準のDataGridでは効かせにくい融通なんかもあるので、中規模以上の基幹系受注生産タイプ旧来型開発では、やはりActiveReportsやFlexGridを組み込むケースが多いと思うんです。
ちなみに私の知る限りもっとも融通の利くGridコントロールはSpreadなんですが、たぶんこれを使わないと満たせないような仕様は、エンドユーザにひきずられて機能設計の時点ですでに泥沼になっている可能性が高いので、「使ってる」とわかった時点でそのプロジェクトからは逃げ腰になったりします。
UIのレスポンスまで考えるとSpreadは必ずしもベストの選択肢ではないので、あえてSpreadにしている場合はなんらかのマイナスファクターがある場合が経験上多かったもので…。
それはさておき、むちゃくちゃ守備範囲が狭いんだけれども、自分としてはちょいちょい思い出す必要に迫られるので、ここにメモ。
いゃ実際にはフォーカス当たってんですけども、見えなきゃわかんないべといぅポリシーの元に。
いつも「フォーカスを当てない方法ってどぅすんだっけー」と慌てるんですが、この考えだと次に「じゃあフォーカスをどこに置くんだ」といぅことを考えねばならず、さらに「フォーカスをよそに持ってった状態でカーソルキーで選択行を移動させたい場合はどぅ制御すんだ」といぅことを考えねばならず、やってできないことはないんでしょぅけれどもやたら力技でフォーカスやらキー押下やらを制御しまくるといぅ本筋と全然関係ない部分にマニアックな対応を行わなければならず。
だったらフォーカスを見せなきゃいいじゃんといぅことで。
検証環境 自作ATX(PenIII1.2GHz/GA-6VTXE/512MB)
WinXPPro(2002)SP2/VS.NET2003(7.1.3091) & .NET Framework1.1(1.1.4322SP1)/MSDN-Lib Oct,2004
上記はIDE環境からデバッグ実行しようとした時のエラーメッセージの前半。
EXEを直接実行した場合はそのEXEファイルのフルパスが表示された上で、
で、どぅすりゃいいかってぇと、
最初、原因がわからなくてかなりあせりました。
自宅のメインマシンで発生したんですが、どうしてApp.configがShift-JISで生成されたのかがいまいちわかっていません。
会社のマシンで検証したら、デフォルトUTF-8の文字コードでApp.configが生成されたので、わざわざ手動でShift-JISにエンコード切り替えないとこの現象は発生しませんでしたし。
まぁ、「こんなエラーが出たら原因としてそのへんも疑ってみよう」ってことでひとつ。
単純に、App.configの中に文法エラーがあってもこのエラーは出ます。
どぅも、構成ファイルを正常に読み込めなかった時全般で発生するエラーみたいですね。
心当たりを片っ端から当たってみるしかない、対象範囲の広いちょっととほほなエラーといぅことでひとつ。
コードエディタ上ブレークポイント(F9)はコマンド単位で背景色が変わるのに対し、ブックマーク(Ctrl+K,Ctrl+K)は行の左側に水色の四角が付きます。
もちろん使用者の好みの問題なんですが、私としてはブックマークも行単位の背景色変更で表示されたいわけです。
が、[オプション]-[環境]-[フォントおよび色]では特に行/マージンの表示振り分け設定は見当たりません。
ブックマークもブレークポイントと同じように、背景色-文字色の組み合わせでサンプル表示されます。
そーいぇば、旧VBの時には行/マージンの表示振り分け設定みたいな項目があったが、行単位で表示と設定しても、マージンを非表示にしないと有効にならなかったなー、などと思い出し。
.NET IDEでも同様かと推測、[オプション]-[テキストエディタ]-[全般]-[表示]で「マージン」のチェックをはずしてましみた。
…アウトラインの[+][-]が非表示になったよorz。
正解は、同じダイアログの「インジケータマージン」のチェックをOffでした。
現在の私の仕事の一部に「中国の協力会社へソースレベルで指示を出したり」ってのがあるので、コードエディタに行番号も表示しています。
どぅしても、「****.vbのxxx行目からのSQL文を見直してくださーい」とか言わなきゃならない場合があるので。
これは、[オプション]-[テキストエディタ]-[すべての言語]-[全般]-[表示]から「行番号」にチェック。
さらにちなみに。
2ストロークデフォルトになったのがちょっと痛いけど、やはりショートカットキーは楽ちんなので多用しているんですが。
ウチの若い者の中には、カット&ペーストまでマウスでこなすつわものがいますが、ユーザならともかく開発者としてはいかがなものか。
が、実際それでも私がキーボードから操作するのと同等以上のスピードだったり。
Oracleのインストール時など、ダイアログが表示される前に、ボタンが表示されるはずの場所を先にクリックして待つ(表示された途端にクリックされた動作が始まる)ほどのマウス捌きを見ていると、すでに私は旧世代なのか!?とたまげてみたりもするんですよね。
それはともかく、マイフェイバレットショートカットキー。
| Ctrl+ASZXCVP | 基本過ぎなので省略 |
| F1 | ダイナミックヘルプ |
| F5 | プログラムの開始 |
| F9 | ブレークポイントのOn/Off |
| Shift+Ctrl+F9 | ブレークポイント全Off |
| F10 | コマンド1つ実行(実行中のプロシージャかその親) |
| F11 | コマンド1つ実行(子プロシージャ突入) |
| Shift+F11 | 親プロシージャまで一気に実行 |
| Ctrl+「-」 | 直前のカーソル位置へ戻る |
| Shift+Ctrl+「-」 | 戻ったカーソル位置へもう一度進む |
| Ctrl+L | 行削除 |
| Ctrl+K,Ctrl+K | ブックマークのOn/Off |
| Ctrl+K,Ctrl+L | ブックマークの全Off |
| Ctrl+K,Ctrl+C | 選択行のコメント化 |
| Ctrl+K,Ctrl+U | 選択行のコメント解除 |
| Ctrl+M,Ctrl+M | アウトラインのOn/Off |
| Ctrl+M,Ctrl+H | 選択行のアウトライン化 |
| Ctrl+M,Ctrl+U | 選択行のアウトライン解除 |
| Shift+Ctrl+Enter | 全画面表示のOn/Off |
| Shift+Ctrl+B | ソリューションのビルド |
| Ctrl+↑↓ | カーソル位置を変えずにスクロール |
| Ctrl+RollUp/Down | 表示画面をスクロールせずにカーソルを最上行/最下行へ |
| Alt+↑↓ | プロシージャの先頭/最後へ(MZ) |
| Shift+Ctrl+H | プロシージャのヘッダコメント挿入(MZ) |
こんなところかなー。
「(MZ)」とあるのは、IDE標準ではなくMZ-TOOLSで提供されていて、自力でショートカットキーに割り当てて使っている機能。
特に「Alt+↑↓」は旧VBにあって重宝していた操作だったので私にとっては必須だったり。
「Ctrl+M,Ctrl+M」は、カーソルがどこにあるかきちんと把握していないととんでもない深さでたたまれるので、実はちょっとつらい。
プロシージャとプロシージャの間にカーソルがある時にうっかりたたむと、Class/Module/Regionのレベルでたたまれてしまい、あわててもう一度開いてもカーソルはその先頭行へ。
数千行あるソースでこれをやっちゃうと、元の場所へたどり着くまでが一苦労なんですよね。
コンテキスト(右クリック)メニューの[定義へ移動]で子プロシージャへよく飛ぶんですが、これの「元の場所へ戻る」がありません。旧VBにはあったし、.NET IDEでもツールバーにはあるんですが(ちょっと飛び位置が違いますが)。
って、コンテキストメニューのカスタマイズの方法がわかりません(T-T)。できないのかなぁ…
とか嘆いていたら、The Code ProjectでGo Back Add-in for VS.NET 2003ってのを発見。
コンテキストメニュー(→クリックメニュー)に[Previos Location]ってのが追加されて、[定義へ移動]とセットの操作で自由に参照元と参照先を行ったり来たり。
[Choose Location]って項目もあって、こちらは飛び元のスタックを一覧表示・好きな位置を選択できるナイスっぷり。
Formのコード上で操作した場合にFormエディタウィンドウへ切り替わってしまぅのがちょっとあれですが、まぁそこらへんは今後の改善を祈って。
そいえば、私はヘルプを「外部ヘルプ」にしています。
F1でカーソル/フォーカス位置状況に合わせてなかなかいいヒット率で知りたい情報へ飛ぶので重宝しているんですが、IDE側に出てくるダイナミックヘルプツールウィンドウは邪魔なので要らないんですよ。
自宅の環境では出てこないようにできているので何らかの設定方法があったはずなんですが、どこだったかどーしても思い出せません。
仕事場の環境では、このウィンドウが何かと出てきて、もーいやだーって感じです。
Office Assistant以来のいらいらさせられっぷりなんだよなー。
検証環境 自作ATX(PenIII1.2GHz/GA-6VTXE/512MB)
WinXPPro(2002)SP2/VS.NET2003(7.1.3091) & .NET Framework1.1(1.1.4322SP1)/MSDN-Lib Oct,2004
旧VBの時。
デスマーチになってやっつけ仕事になると、とりあえずButtonのClickイベントに実コード書いて、後から同じ機能を別のトリガで(たとえばキー操作から)使いたい場合に、Clickイベントを直接Callしちゃうなんてのはよくある話だったんですが。
VB.NETになったらClickイベントの引数が妙にめんどくさくなった(てゅうか.NET標準に合わせたてゅうか)ので、この手法は使えないなぁとあきらめていたんです。
PerformClickメソッドなんてのがあったのね。
知りませんでした…orz
検証環境 自作ATX(PenIII1.2GHz/GA-6VTXE/512MB)
WinXPPro(2002)SP2/VS.NET2003(7.1.3091) & .NET Framework1.1(1.1.4322SP1)/MSDN-Lib Oct,2004
泥Tips(6)の手法でおっけー、とか思っていたら、IMessageFilter.PreFilterMessageでWM_KEYDOWNメッセージを拾ってる人を発見しました。
Message.WParamでキーコードを取得して、Tabキー(&H09)だったらモジュールレベルのスコープを持つフラグ変数を立てておいて、TextBoxのLeaveイベントの中でそのフラグを参照してTab押下によるフォーカス移動かどぅかを判断してんですわ。
その手があったかー、と思うより先に、Formに来るメッセージを味噌もくそも一緒くたに処理しよぅとするPreFilterMessageの存在にものすごく疑問が。
確かにmsdnLibraryでは「このメソッドを使用すると、メッセージがディスパッチされる前に行う必要のあるコード作業も実行できます。」とか記述されてて、ButtonのClickコマンドを横取りするような例を挙げちゃっているわけで。
これを鵜呑みにすると、確かにTextBoxのキー押下も横取りできる、って発想はアリだよなぁ。
でも、コード間の脈絡がまったくなくなってしまぅので、フラグ変数名でコード内を検索するかデバッグトレースでもしない限り、操作から発生するイベント及びそこからCallされるプロシージャの流れと無関係なところで動作が制御されていることがわからなくなるんですよね。
これはデバッグ/メンテナンス時にかなりなツラさだと思ぅわけですよ。
C++で考えれば、ふつーコントロールへ流れてくるメッセージはコントロールの中でつかまえて処理するよなぁ。
Formで一律してメッセージをつかまえるってのはよっぽどのこと、てゅうか客先のわがまま要求に負けて泣く泣くへんてこな動作を作りこんだ時くらいしか覚えがありません。
まぁmsdnLibraryの例はわかりやすく説明したいがためにあんまり適切ではない例をつい出しちゃった、くらいに解釈しておいたとしても。
そもそPreFilterMessageって、何を想定して用意されたメソッドなんでしょぅ。
むちゃくちゃ泥臭い使い方しか思いつきませんよ?
検証環境 自作ATX(PenIII1.2GHz/GA-6VTXE/512MB)
WinXPPro(2002)SP2/VS.NET2003(7.1.3091) & .NET Framework1.1(1.1.4322SP1)/MSDN-Lib Oct,2004
前提として。
ふつーに考えれば、TextBoxから、Tabキー押下時のイベントをこっち側に持ってくるような派生クラス作ってしまえばいいんですけれども。
クラスってWindows Formデザイナの管理の対象外なもんで、せっかく作っても[ツールボックス]-[マイユーザーコントロール]に表示されないんですよね。
コードでインスタンス作ってFormに割り当てて表示位置とか属性とか決めて、ってやらなきゃならないんですよ。つまり、Windows Formエディタの管理外となりますので、大変作りにくい状況になってしまぅわけです。
かといってユーザーコントロールとして作るとツールボックスには表示されるものの、Control型のオブジェクトになってしまぅので、TextBox特有のプロパティなんかを明示的に公開するよぅに作り込まなければならないのも手間ですし、デザイン時にそこだけすでに実行されているのも個人的には大変気に食いません。
もちろん高度に特殊なコントロールを作るのなら上記の手間やら動作やらもわかった上で積極的に使っていくつもりはありますが、たかがTextBoxにTabをスルーさせるためだけにユーザーコントロール、ってのもちょっとおもしろくないよぅな気がします。
てことで、[ツールボックス]に表示される派生クラスの作り方。
Protected Overrides Function IsInputKey( _こんな感じで。
ByVal keyData As System.Windows.Forms.Keys) As Boolean
If (keyData = Keys.Tab + Keys.Shift) _
Or (keyData = Keys.Tab) Then
Return True
Else
Return MyBase.IsInputKey(keyData)
End If
End Function
ちなみに、こーやって作った派生クラスファイルを他のプロジェクトで使用しようとして「既存項目の追加」で読み込んでも、[ツールボックス]には表示されません。
この場合は、読み込んだU_Test.vbをコードエディタで開き、上記(3)で書き換えた 「Inherits System.Windows.Forms.TextBox」の「TextBox」を「UserControl」に書き戻して、デザイナでも開きます。
これで[ツールボックス]に表示されますので、再度「UserControl」を「TextBox」に書き戻します。
なんだか単にデザイナをだましているだけのよぅな気もしますし、2005とかで通用する手段かどぅかはわからないわけなんですが。
今んとこは割と重宝しています。
検証環境 自作ATX(PenIII1.2GHz/GA-6VTXE/512MB)
WinXPPro(2002)SP2/VS.NET2003(7.1.3091) & .NET Framework1.1(1.1.4322SP1)/MSDN-Lib Oct,2004
私は今VS.NET2003にOracle9.1とCrystalReports10を組み込んでプログラムを作ったりする仕事をしているわけなんですが。
OracleとCRのHelpが.NETのHelpと連動しなくてもーどーにもなりません。
どちらも.HxS(MS HTML HELP 2.0のデータファイル)とかは提供されているわけですから、連動できてしかるべきとかやはり考えるわけで。
いーかげんいらいらしてきたのでちょっと調べてみました。やみくもに。
VS.NETのヘルププログラムの実体は「Microsoft Document Explorer」って奴で、C:\Program Files\Common Files\Microsoft Shared\Helpとかに格納されているdexplore.exeがそれです。
で、これを単体で立ち上げると、デフォルトで表示されるトピックは「Visual Studio .NET 連結ヘルプ コレクション」。
このページから「Visual Studio .NET 連結ヘルプ コレクション マネージャ」のリンクをクリック→移動、「VSCC に含めることのできるコレクション」の項目に、うわぁあるよ。「Oracle Data Provider for .NET Help」(ODP.NET)も「Crystal Reports 10」もチェックできる選択肢として。
「Crystal Reports 10」にはチェック付いてるんですが、なんでだか現状私のマシンでは表示も