┏第37号━━━━━━━━━━━━━━━━━━━━━━━━━━┓ ┃         .NETプログラミング研究         ┃ ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ ──<メニュー>─────────────────────── ■.NET質問箱 ・拡張子に関連付けられた実行ファイルのパスを取得するには? ・ピクチャボックスに表示されている画像をドラッグ&ドロップする ・DataGridにLinkLabelを表示するには? ■コンピュータ雑学 ・Windows NTの「NT」の意味は? ─────────────────────────────── ─────────────────────────────── ■.NET質問箱 ─────────────────────────────── 「.NET質問箱」では、「どぼん!のプログラミング掲示板」に書き込 まれた.NETプログラミングに関する投稿を基に、さらに考察を加え、 Q&A形式にまとめて紹介します。 [URL]どぼん!のプログラミング掲示板 http://dobon.net/vb/bbs.html ●拡張子に関連付けられた実行ファイルのパスを取得するには? 【質問】 あるファイルの拡張子に関連付けられている実行ファイルのフルパス を取得するには、どのようにすればよいでしょうか? 【回答】 まず、Win32 APIのFindExecutable関数を使う方法が考えられます。 [URL]プラットフォーム SDK FindExecutable http://www.microsoft.com/japan/msdn/library/ja/jpshell/html/_win32_findexecutable.asp この場合、次のようなコードで実行ファイルのパスを取得できます。 ‥‥▽VB.NET ここから▽‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥ Class MainClass _ Public Shared Function FindExecutable(ByVal lpFile As String, _ ByVal lpDirectory As String, _ ByVal lpResult As System.Text.StringBuilder) As Integer End Function '/ '/ エントリポイントです。 '/ Public Shared Sub Main() '関連付けられた実行ファイルを取得するファイル名 Dim fileName As String = "C:\test.txt" '結果を受け取るためのStringBuilderオブジェクト Dim exePath As New System.Text.StringBuilder(255) 'fileNameに関連付けられた実行ファイルのパスを取得する If FindExecutable(fileName, Nothing, exePath) > 32 Then '成功した時は、exePathの内容を表示する Console.WriteLine(exePath.ToString()) Else Console.WriteLine("失敗しました。") End If End Sub End Class ‥‥△VB.NET ここまで△‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥ ‥‥▽C# ここから▽‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥ class MainClass { [System.Runtime.InteropServices.DllImport("shell32.dll")] public static extern int FindExecutable( string lpFile, string lpDirectory, System.Text.StringBuilder lpResult); /// /// エントリポイントです。 /// public static void Main() { //関連付けられた実行ファイルを取得するファイル名 string fileName = "C:\\test.txt"; //結果を受け取るためのStringBuilderオブジェクト System.Text.StringBuilder exePath = new System.Text.StringBuilder(255); //fileNameに関連付けられた実行ファイルのパスを取得する if (FindExecutable(fileName, null, exePath) > 32) { //成功した時は、exePathの内容を表示する Console.WriteLine(exePath.ToString()); } else { Console.WriteLine("失敗しました。"); } } } ‥‥△C# ここまで△‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥ しかし残念ながらFindExecutableには、関連付けられた実行ファイル のパスにスペース文字が含まれる時、はじめのスペースがnull文字で 置き換えられてしまうというバグがあります。このために、例えば実 行ファイルのパスが、 C:\Program Files\Microsoft Office\WINWORD.EXE であった場合、FindExecutableは、 C:\Program という文字列を返したかのようになってしまいます。 [URL]マイクロソフト サポート技術情報 - 140724 PRB: FindExecutable() Truncates Result at First Space in LFN http://support.microsoft.com/?kbid=140724 FindExecutableのようなWin32 APIを使用しなくても、拡張子の関連付 けに関する情報はレジストリに保存されていますので、レジストリを 調べれば拡張子に関連付けられた実行ファイルのパスは分かります。 拡張子の関連付けに関する情報は、レジストリのHKEY_CLASS_ROOTにあ ります。具体的には、"HKEY_CLASS_ROOT\(拡張子)"というキーにそ の拡張子に関連付けられているファイルタイプ名が格納されており、 "HKEY_CLASS_ROOT\(ファイルタイプ名)\shell\(openなどのアクシ ョン名)\command"というキーに実行ファイルのパス(コマンドライン 引数を含む)が格納されています。 レジストリを調べて拡張子に関連付けられた実行ファイルのパスを取 得するコードの例を示します。ここでは実行ファイルのパスだけでな く、コマンドライン引数が付いたまま返しています(つまり、「アク ションを実行するアプリケーション」で指定されている文字列をその まま返します)。 ‥‥▽VB.NET ここから▽‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥ '/ '/ ファイルに関連付けられた実行ファイルのパスを取得する '/ '/ 関連付けを調べるファイル '/ アクション(open,print,editなど) '/ 実行ファイルのパス + コマンドライン引数 Public Shared Function FindAssociatedExecutableFile( _ ByVal fileName As String, ByVal extra As String) As String '拡張子を取得 Dim extName As String = System.IO.Path.GetExtension(fileName) 'ファイルタイプを取得 Dim regKey As Microsoft.Win32.RegistryKey = _ Microsoft.Win32.Registry.ClassesRoot.OpenSubKey(extName) If regKey Is Nothing Then Throw New Exception("見つかりませんでした。") End If Dim fileType As String = CStr(regKey.GetValue("")) regKey.Close() '「アクションを実行するアプリケーション」を取得 Dim regKey2 As Microsoft.Win32.RegistryKey = _ Microsoft.Win32.Registry.ClassesRoot.OpenSubKey( _ String.Format("{0}\shell\{1}\command", fileType, extra)) If regKey2 Is Nothing Then Throw New Exception("見つかりませんでした。") End If Dim command As String = CStr(regKey2.GetValue("")) regKey2.Close() Return command End Function '/ '/ ファイルに関連付けられた実行ファイルのパスを取得する '/ '/ 関連付けを調べるファイル '/ 実行ファイルのパス + コマンドライン引数 Public Shared Function FindAssociatedExecutableFile( _ ByVal fileName As String) As String Return FindAssociatedExecutableFile(fileName, "open") End Function ‥‥△VB.NET ここまで△‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥ ‥‥▽C# ここから▽‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥ /// /// ファイルに関連付けられた実行ファイルのパスを取得する /// /// 関連付けを調べるファイル /// アクション(open,print,editなど) /// 実行ファイルのパス + コマンドライン引数 public static string FindAssociatedExecutableFile( string fileName, string extra) { //拡張子を取得 string extName = System.IO.Path.GetExtension(fileName); //ファイルタイプを取得 Microsoft.Win32.RegistryKey regKey = Microsoft.Win32.Registry.ClassesRoot.OpenSubKey(extName); if (regKey == null) throw new Exception("見つかりませんでした。"); string fileType = (string) regKey.GetValue(""); regKey.Close(); //「アクションを実行するアプリケーション」を取得 Microsoft.Win32.RegistryKey regKey2 = Microsoft.Win32.Registry.ClassesRoot.OpenSubKey( string.Format(@"{0}\shell\{1}\command", fileType, extra)); if (regKey2 == null) throw new Exception("見つかりませんでした。"); string command = (string) regKey2.GetValue(""); regKey2.Close(); return command; } /// /// ファイルに関連付けられた実行ファイルのパスを取得する /// /// 関連付けを調べるファイル /// 実行ファイルのパス + コマンドライン引数 public static string FindAssociatedExecutableFile( string fileName) { return FindAssociatedExecutableFile(fileName, "open"); } ‥‥△C# ここまで△‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥ 拡張子に関連付けられている実行可能ファイルパスを取得するための APIには、AssocQueryString関数もあります。これを使用するには、 Internet Explorer 5以上が必要となります。詳しくは次のリンク先を ご覧ください。 [URL]AssocQueryString Function http://msdn.microsoft.com/library/en-us/shellcc/platform/shell/reference/shlwapi/registry/assocquerystring.asp ○この記事の基になった掲示板のスレッド [題名] 関連付けられている実行可能ファイルパスの取得 [投稿者(敬称略)] riki, 管理人, ピラルク [URL] http://dobon.net/vb/bbs/log3-2/721.html ─────────────────────────────── ●ピクチャボックスに表示されている画像をドラッグ&ドロップする 【質問】 ピクチャボックスに表示されている画像をワードパッドやWordなどの アプリケーションにドラッグ&ドロップしてデータを渡したいのですが、 どのようにすればよいでしょうか? 【回答】 ドラッグ&ドロップの操作を開始するには、コントロールの DoDragDropメソッドを使いますが、ワードパッドやWordにドラッグ&ド ロップでデータを渡す場合は、DoDragDropメソッドのドラッグするデー タに画像のImageオブジェクトやBitmapオブジェクトをそのまま指定す るだけで大丈夫のようです。なお、ドラッグ&ドロップの基本的な方法 については、「ドラッグ&ドロップを行う」をご覧ください。 [URL]ドラッグ&ドロップを行う http://dobon.net/vb/dotnet/control/draganddrop.html 例えば、ピクチャボックス"PictureBox1"のImageプロパティに設定さ れている画像をドラッグするためのコードは、次のようになります。 (ここではPictureBox1のMouseDownイベントハンドラ PictureBox1_MouseDownでドラッグを開始しています。) ‥‥▽VB.NET ここから▽‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥ Private Sub PictureBox1_MouseDown(ByVal sender As Object, _ ByVal e As System.Windows.Forms.MouseEventArgs) _ Handles PictureBox1.MouseDown 'ドラッグを開始する PictureBox1.DoDragDrop(PictureBox1.Image, DragDropEffects.All) End Sub ‥‥△VB.NET ここまで△‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥ ‥‥▽C# ここから▽‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥ private void PictureBox1_MouseDown( object sender, System.Windows.Forms.MouseEventArgs e) { //ドラッグを開始する PictureBox1.DoDragDrop(PictureBox1.Image, DragDropEffects.All); } ‥‥△C# ここまで△‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥ さらに、画像をアプリケーションにドロップしたときに、画像のイメー ジに加えさらに画像ファイルのデータを渡すための方法がニュースグ ループの次のスレッドに投稿されています。 [URL]Newsgroups:microsoft.public.dotnet.framework.windowsforms How do I drag images from my app and drop them as files in explorer? http://groups.google.co.jp/groups?hl=ja&lr=&ie=UTF-8&inlang=ja&threadm=en1LqODACHA.1340%40tkmsftngp02 この方法によると、まずピクチャボックスに表示されている画像がフ ァイルに保存されていない時はこれをファイルに保存してから、 DataObjectオブジェクトのSetDataにより画像ファイルのパスとイメー ジを格納し、DoDragDropメソッドによりドラッグを行うというもので す。 次にこの方法を使った例を示します。前と同様にピクチャボックス "PictureBox1"のImageプロパティに設定されている画像をドラッグす るものとし、この画像はすでに"C:\temp.bmp"というファイルに保存さ れているものとします。画像が保存されていない場合は、あらかじめ Saveメソッドにより保存するようにしてください。 ‥‥▽VB.NET ここから▽‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥ Private Sub PictureBox1_MouseDown(ByVal sender As Object, _ ByVal e As System.Windows.Forms.MouseEventArgs) _ Handles PictureBox1.MouseDown '画像ファイル名の入ったstring型配列を作る Dim fileNames As String() = {"c:\temp.bmp"} 'ファイルドロップ形式でDataObjectオブジェクトを作成する Dim dataObj As New DataObject(DataFormats.FileDrop, fileNames) 'さらにビットマップ形式でも格納する dataObj.SetData(DataFormats.Bitmap, Image.FromFile(fileNames(0))) 'ドラッグを開始する PictureBox1.DoDragDrop(dataObj, DragDropEffects.All) End Sub ‥‥△VB.NET ここまで△‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥ ‥‥▽C# ここから▽‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥ private void PictureBox1_MouseDown( object sender, System.Windows.Forms.MouseEventArgs e) { //画像ファイル名の入ったstring型配列を作る string[] fileNames = {"c:\\temp.bmp"}; //ファイルドロップ形式でDataObjectオブジェクトを作成する DataObject dataObj = new DataObject(DataFormats.FileDrop, fileNames); //さらにビットマップ形式でも格納する dataObj.SetData( DataFormats.Bitmap, Image.FromFile(fileNames[0])); //ドラッグを開始する PictureBox1.DoDragDrop(dataObj,DragDropEffects.All); } ‥‥△C# ここまで△‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥ この方法でドラッグ&ドロップした場合、ドロップ先がエクスプローラ である場合はもちろん、ワードパッドなど多くのアプリケーションへ のドロップでも単にファイルのドロップとして扱われてしまうようで す。 ○この記事の基になった掲示板のスレッド [題名] ドラッグ&ドロップについて。 [投稿者(敬称略)] どんちゃん, ピラルク [URL] http://dobon.net/vb/bbs/log3-2/740.html ─────────────────────────────── ●DataGridにLinkLabelを表示するには? 【質問】 System.Windows.Forms.DataGridコントロールにLinkLabelを表示して、 ハイパーリンクがはられているようにしたいのですが、どのようにす ればよいでしょうか? 【回答】 DataGridColumnStyleクラスから派生した新しいクラスを作成すること により実現させる方法が適当だと思いますが、問題はどのように LinkLabelを表示するかという点でしょう。 一番簡単で分かりやすいのは、DataGridColumnStyleクラスのEditメソ ッドでLinkLabelコントロールを表示するという方法です。ピラルクさ んが掲示板に投稿していただいた方法や、ニュースグループ「 microsoft.public.dotnet.framework.windowsforms」に投稿された Travis Merkelさんの方法がこれです。DOBON.NET .NET Tipsで紹介し ている「DataGridでComboBoxを使う」のComboBoxをLinkLabelにそのま ま代えたという感じです。 [URL]microsoft.public.dotnet.framework.windowsforms RE: How do you add a hyperlink to a datagrid? http://groups.google.co.jp/groups?hl=ja&lr=&ie=UTF-8&inlang=ja&selm=B9FD3364-D395-404E-9744-E9DE08114FC7%40microsoft.com [URL]DataGridでComboBoxを使う http://dobon.net/vb/dotnet/datagrid/datagridcombobox.html この方法はEditメソッドでLinkLabelを表示しているため、セルがアク ティブになってからLinkLabelが表示され、はじめからLinkLabelが表 示されるわけではありません。 この方法を使った簡単なサンプルを下に示します(かなりの手抜きで す)。ここでは、LinkLabelをクリックすると、セルに表示されている 文字列をProcess.Startメソッドに渡して呼び出しています。なお、 DataGridColumnStyleクラスの使用法に関しては、「DataGridの列の幅 を変更する」をご覧ください。 [URL]DataGridの列の幅を変更する http://dobon.net/vb/dotnet/datagrid/columnwidth.html ‥‥▽VB.NET ここから▽‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥ Imports System Imports System.Data Imports System.Drawing Imports System.Windows.Forms Namespace Dobon.Samples.Forms '/ '/ DataGridにLinkLabelを表示するDataGridColumnStyle '/ Public Class DataGridLinkLabelColumn Inherits DataGridTextBoxColumn 'TextBoxの代わりに表示するLinkLabel Private _linkLabel As LinkLabel Public ReadOnly Property LinkLabel() As LinkLabel Get Return _linkLabel End Get End Property Public Sub New() _linkLabel = New LinkLabel AddHandler _linkLabel.Click, AddressOf _linkLabel_Click End Sub Protected Overloads Overrides Sub Edit( _ ByVal source As System.Windows.Forms.CurrencyManager, _ ByVal rowNum As Integer, _ ByVal bounds As System.Drawing.Rectangle, _ ByVal [readOnly] As Boolean, _ ByVal instantText As String, _ ByVal cellIsVisible As Boolean) MyBase.Edit(source, rowNum, bounds, [readOnly], _ instantText, cellIsVisible) 'TextBoxの代わりにLinkLabelを表示する TextBox.Visible = False _linkLabel.Parent = TextBox.Parent _linkLabel.Bounds = bounds _linkLabel.Text = TextBox.Text _linkLabel.Visible = True _linkLabel.BringToFront() _linkLabel.Focus() End Sub Private Sub _linkLabel_Click( _ ByVal sender As Object, ByVal e As EventArgs) 'LinkLabelがクリックされた時は表示されているTextを実行する Dim link As LinkLabel = CType(sender, LinkLabel) System.Diagnostics.Process.Start(link.Text) End Sub End Class End Namespace ‥‥△VB.NET ここまで△‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥ ‥‥▽C# ここから▽‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥ using System; using System.Data; using System.Drawing; using System.Windows.Forms; namespace Dobon.Samples.Forms { /// /// DataGridにLinkLabelを表示するDataGridColumnStyle /// public class DataGridLinkLabelColumn : DataGridTextBoxColumn { //TextBoxの代わりに表示するLinkLabel private LinkLabel _linkLabel; public LinkLabel LinkLabel { get {return _linkLabel;} } public DataGridLinkLabelColumn() { _linkLabel = new LinkLabel(); _linkLabel.Click += new EventHandler(_linkLabel_Click); } protected override void Edit( CurrencyManager source, int rowNum, Rectangle bounds, bool readOnly, string instantText, bool cellIsVisible) { base.Edit(source, rowNum, bounds, readOnly, instantText, cellIsVisible); //TextBoxの代わりにLinkLabelを表示する TextBox.Visible = false; _linkLabel.Parent = TextBox.Parent; _linkLabel.Bounds = bounds; _linkLabel.Text = TextBox.Text; _linkLabel.Visible = true; _linkLabel.BringToFront(); _linkLabel.Focus(); } private void _linkLabel_Click(object sender, EventArgs e) { //LinkLabelがクリックされた時は表示されているTextを実行する LinkLabel link = (LinkLabel) sender; System.Diagnostics.Process.Start(link.Text); } } } ‥‥△C# ここまで△‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥ アクティブなセルだけでなく、すべての行にLinkLabelを表示するには、 Paintメソッドで何らかの処理を行う必要があります。具体的には、必 要な数だけLinkLabelコントロールを作成するか、あたかもLinkLabel コントロールのように文字列を描画するかということになるでしょう。 必要な数だけLinkLabelコントロールを作成する例が、ニュースグルー プ「microsoft.public.dotnet.framework.windowsforms.controls」に 投稿されています。 [URL]microsoft.public.dotnet.framework.windowsforms.controls Re: DataGrid: How to get hyperlinks? From:developers http://groups.google.co.jp/groups?hl=ja&lr=&ie=UTF-8&inlang=ja&selm=u29LLDsVDHA.2252%40TK2MSFTNGP10.phx.gbl この方法は、LinkLabelコントロールを行ごとにHashtableに保存して おき、Paintメソッドで必要に応じて配置するというものです。行ごと にLinkLabelコントロールを作成しているため、行が多くなると、かな りメモリを消費するでしょう。 それが嫌であれば、PaintメソッドでLinkLabelのような文字列を描画 すればよいということになります。ここで問題なのは、どうやってク リックされたことを知るかということです。そのためには、例えば DataGridのMouseUpイベントでHitTestInfoメソッドを使ってセル上で マウスボタンが押されたか判断するという方法があります。 LinkLabelの動作とはかなり違いますが、仕方のないところでしょう。 以下にPaintメソッドで文字列を描画するDataGridColumnStyleの簡単 な例を示します。ここでは、DataGridのMouseMoveイベントでマウスが セル上にあるか調べ、そうであればマウスカーソルをハンドカーソル に変更しています。また、DataGridのMouseUpイベントでクリックされ たことにしています。 ‥‥▽VB.NET ここから▽‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥ Namespace Dobon.Samples.Forms '/ '/ DataGridにLinkLabelを表示するDataGridColumnStyle '/ Public Class DataGridLinkLabelColumn2 Inherits DataGridTextBoxColumn Private _margin As New Point(1, 2) Private _visitedLinks As System.Collections.ArrayList Private _dataGrid As DataGrid Public Sub New() _visitedLinks = New System.Collections.ArrayList End Sub Protected Overloads Overrides Sub Edit( _ ByVal [source] As CurrencyManager, _ ByVal rowNum As Integer, _ ByVal bounds As Rectangle, _ ByVal [readOnly] As Boolean, _ ByVal instantText As String, _ ByVal cellIsVisible As Boolean) End Sub 'Paintメソッドをオーバーライドする Protected Overloads Overrides Sub Paint( _ ByVal g As Graphics, _ ByVal bounds As Rectangle, _ ByVal [source] As CurrencyManager, _ ByVal rowNum As Integer, _ ByVal backBrush As Brush, _ ByVal foreBrush As Brush, _ ByVal alignToRight As Boolean) '表示する文字列を取得 Dim [text] As String = _ GetColumnValueAtRow([source], rowNum).ToString() Dim sf As New StringFormat '配置を指定する Select Case Me.Alignment Case HorizontalAlignment.Left sf.Alignment = StringAlignment.Near Case HorizontalAlignment.Center sf.Alignment = StringAlignment.Center Case HorizontalAlignment.Right sf.Alignment = StringAlignment.Far End Select 'テキストの方向を指定する If alignToRight Then sf.FormatFlags = _ sf.FormatFlags Or _ StringFormatFlags.DirectionRightToLeft End If '背景を塗りつぶす g.FillRectangle(backBrush, bounds) '前景色を決める Dim textBrush As Brush If _visitedLinks.Contains([text]) Then textBrush = Brushes.Purple Else textBrush = Brushes.Blue End If 'フォントにアンダーラインをつける Dim textFont As New Font( _ DataGridTableStyle.DataGrid.Font.FontFamily, _ DataGridTableStyle.DataGrid.Font.Size, _ DataGridTableStyle.DataGrid.Font.Style _ Or FontStyle.Underline) Dim rectf As New RectangleF( _ bounds.X, bounds.Y, bounds.Width, bounds.Height) rectf.Inflate(-_margin.X, -_margin.Y) '文字列を描画する g.DrawString([text], textFont, textBrush, rectf, sf) sf.Dispose() textFont.Dispose() End Sub Protected Overrides Sub SetDataGridInColumn( _ ByVal value As DataGrid) MyBase.SetDataGridInColumn(value) AddHandler value.MouseMove, AddressOf DataGrid_MouseMove AddHandler value.MouseUp, AddressOf DataGrid_MouseUp _dataGrid = value End Sub Protected Overloads Overrides Sub Dispose( _ ByVal disposing As Boolean) MyBase.Dispose(disposing) RemoveHandler _dataGrid.MouseMove, _ AddressOf DataGrid_MouseMove RemoveHandler _dataGrid.MouseUp, _ AddressOf DataGrid_MouseUp End Sub Private Sub DataGrid_MouseMove( _ ByVal sender As Object, ByVal e As MouseEventArgs) 'マウスがセル上にあるときは、カーソルを変更する Dim hti As DataGrid.HitTestInfo = _ DataGridTableStyle.DataGrid.HitTest(e.X, e.Y) If hti.Type = DataGrid.HitTestType.Cell And _ hti.Column = _ DataGridTableStyle.GridColumnStyles.IndexOf(Me) Then DataGridTableStyle.DataGrid.Parent.Cursor = _ Cursors.Hand Else DataGridTableStyle.DataGrid.Parent.Cursor = _ Cursors.Default End If End Sub Private Sub DataGrid_MouseUp( _ ByVal sender As Object, ByVal e As MouseEventArgs) Dim grid As DataGrid = DataGridTableStyle.DataGrid Dim info As DataGrid.HitTestInfo = grid.HitTest(e.X, e.Y) 'マウスがセル上にあるか調べる If info.Type = DataGrid.HitTestType.Cell And info.Column = _ DataGridTableStyle.GridColumnStyles.IndexOf(Me) Then 'Process.Startを呼び出す Dim cm As CurrencyManager = _ CType(grid.BindingContext( _ grid.DataSource, grid.DataMember), CurrencyManager) Dim str As String = _ GetColumnValueAtRow(cm, info.Row).ToString() System.Diagnostics.Process.Start(str) '訪れたことを記憶する _visitedLinks.Add(str) End If End Sub End Class End Namespace ‥‥△VB.NET ここまで△‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥ ‥‥▽C# ここから▽‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥ namespace Dobon.Samples.Forms { /// /// DataGridにLinkLabelを表示するDataGridColumnStyle /// public class DataGridLinkLabelColumn2 : DataGridTextBoxColumn { Point _margin = new Point(1, 2); private System.Collections.ArrayList _visitedLinks; DataGrid _dataGrid; public DataGridLinkLabelColumn2() { _visitedLinks = new System.Collections.ArrayList(); } protected override void Edit( CurrencyManager source, int rowNum, Rectangle bounds, bool readOnly, string instantText, bool cellIsVisible) { } //Paintメソッドをオーバーライドする protected override void Paint(Graphics g, Rectangle bounds, CurrencyManager source, int rowNum, Brush backBrush, Brush foreBrush, bool alignToRight) { //表示する文字列を取得 string text = GetColumnValueAtRow(source, rowNum).ToString(); StringFormat sf = new StringFormat(); //配置を指定する switch (this.Alignment) { case HorizontalAlignment.Left: sf.Alignment = StringAlignment.Near; break; case HorizontalAlignment.Center: sf.Alignment = StringAlignment.Center; break; case HorizontalAlignment.Right: sf.Alignment = StringAlignment.Far; break; } //テキストの方向を指定する if (alignToRight) sf.FormatFlags |= StringFormatFlags.DirectionRightToLeft; //背景を塗りつぶす g.FillRectangle(backBrush, bounds); //前景色を決める Brush textBrush; if (_visitedLinks.Contains(text)) textBrush = Brushes.Purple; else textBrush = Brushes.Blue; //フォントにアンダーラインをつける Font textFont = new Font(DataGridTableStyle.DataGrid.Font.FontFamily, DataGridTableStyle.DataGrid.Font.Size, DataGridTableStyle.DataGrid.Font.Style | FontStyle.Underline); RectangleF rectf = new RectangleF( bounds.X, bounds.Y, bounds.Width, bounds.Height); rectf.Inflate(-_margin.X, -_margin.Y); //文字列を描画する g.DrawString(text, textFont, textBrush, rectf, sf); sf.Dispose(); textFont.Dispose(); } protected override void SetDataGridInColumn(DataGrid value) { base.SetDataGridInColumn(value); value.MouseMove += new MouseEventHandler(DataGrid_MouseMove); value.MouseUp += new MouseEventHandler(DataGrid_MouseUp); _dataGrid = value; } protected override void Dispose(bool disposing) { base.Dispose(disposing); _dataGrid.MouseMove -= new MouseEventHandler(DataGrid_MouseMove); _dataGrid.MouseUp -= new MouseEventHandler(DataGrid_MouseUp); } private void DataGrid_MouseMove( object sender, MouseEventArgs e) { //マウスがセル上にあるときは、カーソルを変更する DataGrid.HitTestInfo hti = DataGridTableStyle.DataGrid.HitTest(e.X, e.Y); if (hti.Type == DataGrid.HitTestType.Cell && hti.Column == DataGridTableStyle.GridColumnStyles.IndexOf(this)) DataGridTableStyle.DataGrid.Parent.Cursor = Cursors.Hand; else DataGridTableStyle.DataGrid.Parent.Cursor = Cursors.Default; } private void DataGrid_MouseUp(object sender, MouseEventArgs e) { DataGrid grid = DataGridTableStyle.DataGrid; DataGrid.HitTestInfo info = grid.HitTest(e.X, e.Y); //マウスがセル上にあるか調べる if (info.Type == DataGrid.HitTestType.Cell && info.Column == DataGridTableStyle.GridColumnStyles.IndexOf(this)) { //Process.Startを呼び出す CurrencyManager cm = (CurrencyManager) grid.BindingContext[ grid.DataSource, grid.DataMember]; string str = GetColumnValueAtRow(cm, info.Row).ToString(); System.Diagnostics.Process.Start(str); //訪れたことを記憶する _visitedLinks.Add(str); } } } } ‥‥△C# ここまで△‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥‥ これらの方法に不満があるならば、市販品を使うのがよいでしょう。 LinkLabelを表示できるフリーのライブラリはほとんど見かけませんが、 「Extended DataGrid」というものがあります。 [URL]Extended DataGrid http://dotnet.leadit.be/extendeddatagrid/ ○この記事の基になった掲示板のスレッド [題名] DataGridのプロパティ変更)お願いします [投稿者(敬称略)] 晋作, fuku, 管理人, ピラルク [URL] http://dobon.net/vb/bbs/log3-2/934.html ─────────────────────────────── ■コンピュータ雑学 ─────────────────────────────── ここでは、話すと人に嫌われるなまぬるいコンピュータに関する雑学 を紹介します。 ●Windows NTの「NT」の意味は? Microsoft Windows NTの「NT」の意味に関して、Microsoftは公式には なんら言及をしていないようですが、Microsoftのいくつかの発行物で は、「New Technology」の略で「NT」と説明されているようです。 しかし広く信じられている説には、別のものがあります。それは、「 Windows NTの父」と呼ばれるDave CutlerがMicrosoftに来る前にDEC社 で開発したOS、VMSのそれぞれのアルファベットを次の文字に進めた「 WNT」から由来しているというものです。しかし、Windows NTははじめ 「NT OS/2」と呼ばれていたことを考慮すると、この説はただの冗談で あるように思われます。 さらには、Windows & .NET Magazine Networkの「WinInfo Daily UPDATE, January 24, 2003」によると、Windows NTの開発者の一人で あるMark Lucovskyが「NT」の意味について、開発にi860のエミュレー タである「N10」を使っていたため、「N-Ten」で動くことから「NT」 と名づけたと明かしています。 [URL]Windows & .NET Magazine Network WinInfo Daily UPDATE, January 24, 2003 http://www.winnetmag.com/Article/ArticleID/37778/37778.html [URL]Paul Thurrott's SuperSite for Windows: Windows Server 2003: The Road To Gold, Part One: The Early Years http://www.winsupersite.com/reviews/winserver2k3_gold1.asp 一体どれが真実でどれがただの噂話(あるいは冗談)なのか、本当の ところは誰にも分からないのかもしれませんね。 =============================== ■このマガジンの購読、購読中止、バックナンバー、説明に関しては  次のページをご覧ください。  http://www.mag2.com/m/0000104516.htm ■発行人・編集人:どぼん!  (Microsoft MVP for Visual Basic, Oct 2003-Oct 2004)  http://dobon.net  dobon_info@yahoo.co.jp ■ご質問等はメールではなく、掲示板へお願いいたします。  http://dobon.net/vb/bbs.html ■上記メールアドレスへのメールは確実に読まれる保障はありません  (スパム、ウィルス対策です)。メールは下記URLのフォームメール  から送信してください。  http://dobon.net/mail.html Copyright (c) 2003 - 2004 DOBON! All rights reserved. ===============================