• 追加された行はこの色です。
  • 削除された行はこの色です。
#title(37)
#title(.NETプログラミング研究 第37号)

#navi(.NETプログラミング研究)

#contents

*37 [#f804b661]
*.NETプログラミング研究 第37号 [#sfa919ae]

**.NET質問箱 [#y06cac1c]

「.NET質問箱」では、「どぼん!のプログラミング掲示板」に書き込まれた.NETプログラミングに関する投稿を基に、さらに考察を加え、Q&A形式にまとめて紹介します。

**コメント [#k04eb412]
-[[どぼん!のプログラミング掲示板>https://dobon.net/vb/bbs.html]]

*** 拡張子に関連付けられた実行ファイルのパスを取得するには? [#vb60c9c0]

#column(注意){{
この記事の最新版は「[[拡張子に関連付けられた実行ファイルのパスを取得する>https://dobon.net/vb/dotnet/system/findassociatedexe.html]]」で公開しています。
}}

''【質問】''

あるファイルの拡張子に関連付けられている実行ファイルのフルパスを取得するには、どのようにすればよいでしょうか?

''【回答】''

まず、Win32 APIのFindExecutable関数を使う方法が考えられます。

-[[プラットフォーム SDK FindExecutable>http://www.microsoft.com/japan/msdn/library/ja/jpshell/html/_win32_findexecutable.asp]]

この場合、次のようなコードで実行ファイルのパスを取得できます。

#code(vbnet){{
Class MainClass
    <System.Runtime.InteropServices.DllImport("shell32.dll")> _
    Public Shared Function FindExecutable(ByVal lpFile As String, _
        ByVal lpDirectory As String, _
        ByVal lpResult As System.Text.StringBuilder) As Integer
    End Function

    '/ <summary>
    '/ エントリポイントです。
    '/ </summary>
    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
}}

#code(csharp){{
class MainClass
{
	[System.Runtime.InteropServices.DllImport("shell32.dll")]
	public static extern int FindExecutable(
		string lpFile, string lpDirectory, 
		System.Text.StringBuilder lpResult);

	/// <summary>
	/// エントリポイントです。
	/// </summary>
	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("失敗しました。");
		}
	}
}
}}

しかし残念ながらFindExecutableには、関連付けられた実行ファイルのパスにスペース文字が含まれる時、はじめのスペースがnull文字で置き換えられてしまうというバグがあります。このために、例えば実行ファイルのパスが、

 C:\Program Files\Microsoft Office\WINWORD.EXE

であった場合、FindExecutableは、

 C:\Program

という文字列を返したかのようになってしまいます。

-[[マイクロソフト サポート技術情報 - 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"というキーに実行ファイルのパス(コマンドライン引数を含む)が格納されています。

レジストリを調べて拡張子に関連付けられた実行ファイルのパスを取得するコードの例を示します。ここでは実行ファイルのパスだけでなく、コマンドライン引数が付いたまま返しています(つまり、「アクションを実行するアプリケーション」で指定されている文字列をそのまま返します)。

#code(vbnet){{
'/ <summary>
'/ ファイルに関連付けられた実行ファイルのパスを取得する
'/ </summary>
'/ <param name="fileName">関連付けを調べるファイル</param>
'/ <param name="extra">アクション(open,print,editなど)</param>
'/ <returns>実行ファイルのパス + コマンドライン引数</returns>
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 

'/ <summary>
'/ ファイルに関連付けられた実行ファイルのパスを取得する
'/ </summary>
'/ <param name="fileName">関連付けを調べるファイル</param>
'/ <returns>実行ファイルのパス + コマンドライン引数</returns>
Public Shared Function FindAssociatedExecutableFile( _
    ByVal fileName As String) As String
    Return FindAssociatedExecutableFile(fileName, "open")
End Function
}}

#code(csharp){{
/// <summary>
/// ファイルに関連付けられた実行ファイルのパスを取得する
/// </summary>
/// <param name="fileName">関連付けを調べるファイル</param>
/// <param name="extra">アクション(open,print,editなど)</param>
/// <returns>実行ファイルのパス + コマンドライン引数</returns>
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;
}

/// <summary>
/// ファイルに関連付けられた実行ファイルのパスを取得する
/// </summary>
/// <param name="fileName">関連付けを調べるファイル</param>
/// <returns>実行ファイルのパス + コマンドライン引数</returns>
public static string FindAssociatedExecutableFile(
	string fileName)
{
	return FindAssociatedExecutableFile(fileName, "open");
}
}}

拡張子に関連付けられている実行可能ファイルパスを取得するためのAPIには、AssocQueryString関数もあります。これを使用するには、Internet Explorer 5以上が必要となります。詳しくは次のリンク先をご覧ください。

-[[AssocQueryString Function>http://msdn.microsoft.com/library/en-us/shellcc/platform/shell/reference/shlwapi/registry/assocquerystring.asp]]

○この記事の基になった掲示板のスレッド

-[[関連付けられている実行可能ファイルパスの取得: 投稿者(敬称略) riki, 管理人, ピラルク>https://dobon.net/vb/bbs/log3-2/721.html]]

***ピクチャボックスに表示されている画像をドラッグ&ドロップする [#l2fa7453]

#column(注意){{
この記事の最新版は「[[ピクチャボックスに表示されている画像をドラッグ&ドロップする>https://dobon.net/vb/dotnet/graphics/pictureboxdragdrop.html]]」で公開しています。
}}

''【質問】''

ピクチャボックスに表示されている画像をワードパッドやWordなどのアプリケーションにドラッグ&ドロップしてデータを渡したいのですが、どのようにすればよいでしょうか?

''【回答】''

ドラッグ&ドロップの操作を開始するには、コントロールのDoDragDropメソッドを使いますが、ワードパッドやWordにドラッグ&ドロップでデータを渡す場合は、DoDragDropメソッドのドラッグするデータに画像のImageオブジェクトやBitmapオブジェクトをそのまま指定するだけで大丈夫のようです。なお、ドラッグ&ドロップの基本的な方法については、「ドラッグ&ドロップを行う」をご覧ください。

-[[ドラッグ&ドロップを行う>https://dobon.net/vb/dotnet/control/draganddrop.html]]

例えば、ピクチャボックス"PictureBox1"のImageプロパティに設定されている画像をドラッグするためのコードは、次のようになります。(ここではPictureBox1のMouseDownイベントハンドラPictureBox1_MouseDownでドラッグを開始しています。)

#code(vbnet){{
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
}}

#code(csharp){{
private void PictureBox1_MouseDown(
	object sender, System.Windows.Forms.MouseEventArgs e)
{
	//ドラッグを開始する
	PictureBox1.DoDragDrop(PictureBox1.Image, DragDropEffects.All);
}
}}

さらに、画像をアプリケーションにドロップしたときに、画像のイメージに加えさらに画像ファイルのデータを渡すための方法がニュースグループの次のスレッドに投稿されています。

-[[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メソッドにより保存するようにしてください。

#code(vbnet){{
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
}}

#code(csharp){{
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);
}
}}

この方法でドラッグ&ドロップした場合、ドロップ先がエクスプローラである場合はもちろん、ワードパッドなど多くのアプリケーションへのドロップでも単にファイルのドロップとして扱われてしまうようです。

○この記事の基になった掲示板のスレッド

-[[ドラッグ&ドロップについて。: 投稿者(敬称略) どんちゃん, ピラルク>https://dobon.net/vb/bbs/log3-2/740.html]]

***DataGridにLinkLabelを表示するには? [#v3fe5aee]

#column(注意){{
この記事の最新版は「[[DataGridにLinkLabelを表示する>https://dobon.net/vb/dotnet/datagrid/datagridlinklabel.html]]」で公開しています。
}}

''【質問】''

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にそのまま代えたという感じです。

-[[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]]
-[[DataGridでComboBoxを使う>https://dobon.net/vb/dotnet/datagrid/datagridcombobox.html]]

この方法はEditメソッドでLinkLabelを表示しているため、セルがアクティブになってからLinkLabelが表示され、はじめからLinkLabelが表示されるわけではありません。

この方法を使った簡単なサンプルを下に示します(かなりの手抜きです)。ここでは、LinkLabelをクリックすると、セルに表示されている文字列をProcess.Startメソッドに渡して呼び出しています。なお、DataGridColumnStyleクラスの使用法に関しては、「DataGridの列の幅を変更する」をご覧ください。

-[[DataGridの列の幅を変更する>https://dobon.net/vb/dotnet/datagrid/columnwidth.html]]

#code(vbnet){{
Imports System
Imports System.Data
Imports System.Drawing
Imports System.Windows.Forms

Namespace Dobon.Samples.Forms
    '/ <summary>
    '/ DataGridにLinkLabelを表示するDataGridColumnStyle
    '/ </summary>
    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
}}

#code(csharp){{
using System;
using System.Data;
using System.Drawing;
using System.Windows.Forms;

namespace Dobon.Samples.Forms
{
	/// <summary>
	/// DataGridにLinkLabelを表示するDataGridColumnStyle
	/// </summary>
	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);
		}
	}
}
}}

アクティブなセルだけでなく、すべての行にLinkLabelを表示するには、Paintメソッドで何らかの処理を行う必要があります。具体的には、必要な数だけLinkLabelコントロールを作成するか、あたかもLinkLabelコントロールのように文字列を描画するかということになるでしょう。

必要な数だけLinkLabelコントロールを作成する例が、ニュースグループ「microsoft.public.dotnet.framework.windowsforms.controls」に投稿されています。

-[[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イベントでクリックされたことにしています。

#code(vbnet){{
Namespace Dobon.Samples.Forms
    '/ <summary>
    '/ DataGridにLinkLabelを表示するDataGridColumnStyle
    '/ </summary>
    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
}}

#code(csharp){{
namespace Dobon.Samples.Forms
{
	/// <summary>
	/// DataGridにLinkLabelを表示するDataGridColumnStyle
	/// </summary>
	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);
			}
		}
	}
}
}}

これらの方法に不満があるならば、市販品を使うのがよいでしょう。LinkLabelを表示できるフリーのライブラリはほとんど見かけませんが、「Extended DataGrid」というものがあります。

-[[Extended DataGrid>http://dotnet.leadit.be/extendeddatagrid/]]

○この記事の基になった掲示板のスレッド

-[[DataGridのプロパティ変更)お願いします: 投稿者(敬称略) 晋作, fuku, 管理人, ピラルク>https://dobon.net/vb/bbs/log3-2/934.html]]

**コンピュータ雑学 [#d1ac873e]

ここでは、話すと人に嫌われるなまぬるいコンピュータに関する雑学
を紹介します。

***Windows NTの「NT」の意味は? [#t99112c5]

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」と名づけたと明かしています。

-[[Windows & .NET Magazine Network: WinInfo Daily UPDATE, January 24, 2003>http://www.winnetmag.com/Article/ArticleID/37778/37778.html]]
-[[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]]

一体どれが真実でどれがただの噂話(あるいは冗談)なのか、本当のところは誰にも分からないのかもしれませんね。

**コメント [#nf1a4bfa]
#comment

//これより下は編集しないでください
#pageinfo([[:Category/.NET]] [[:Category/ASP.NET]],2010-03-21 (日) 02:31:26,DOBON!,2010-03-21 (日) 02:31:26,DOBON!)
#pageinfo([[:Category/.NET]],2004-07-14 (水) 06:00:00,DOBON!,2010-03-21 (日) 02:33:20,DOBON!)

[ トップ ]   [ 新規 | 子ページ作成 | 一覧 | 単語検索 | 最終更新 | ヘルプ ]