MSDN から Visual Studio 11 preview 版(VS2012候補ですね)を入れて、Visual C++ を試してみました。
画像は後から貼り付けますが、インテリセンスが効くようになったよッ!!! ってことで。
これで、まともに C++/CLI でコーディングができそうです。
# VS 2010 にもサービスパック経由で出して欲しいなぁと。
MSDN から Visual Studio 11 preview 版(VS2012候補ですね)を入れて、Visual C++ を試してみました。
画像は後から貼り付けますが、インテリセンスが効くようになったよッ!!! ってことで。
これで、まともに C++/CLI でコーディングができそうです。
# VS 2010 にもサービスパック経由で出して欲しいなぁと。
Windows Azure SDK and Tools | Windows Azure Platform
http://www.microsoft.com/windowsazure/sdk/
予想はしていたことでしたが…って予想していなかったよッ!!!
先月の頭に v1.4 が出てから今の時期に v1.5 って、うーむ。執筆中の書籍は v1.5 で画面キャプチャをし直しですかね。日本語版がいつ出るかにかかっていますが。
私としては、
– Goblal.aspx.cs へのコード挿入をテンプレート時点でして欲しい。
– web.config の sessionState を削除して欲しい。
ってところです。
後で、v1.5 英語版で試してみるということで。
DataGrid への表示は、VB6 の頃から遅くて、表示更新をしないと早くなるという噂(けど真実)があったりします。
で、.NET になって DataGridView への DataSource プロパティへのバインドをすると早くなる、ってのが定番なんですが(セルへちまちま貼り付けるよりも早くなります…が、測定はしてないので、そのうちに)、なぜか、DataSource プロパティへのバインドをしているのに、とてつもなく遅くなる現象が発覚したので、晒します。
1.10 カラムある DataGridView を作ります。
2.データを作成
/// <summary>
/// データ作成
/// </summary>
/// <returns></returns>
private List<Data> MakeData()
{
List<Data> lst = new List<Data>();
for (int i = 0; i < 3000; i++)
{
Data d = new Data();
d.Col1 = i.ToString();
d.Col2 = DateTime.Now.ToString();
d.Col3 = DateTime.Now.ToString();
d.Col4 = DateTime.Now.ToString();
d.Col5 = DateTime.Now.ToString();
d.Col6 = DateTime.Now.ToString();
d.Col7 = DateTime.Now.ToString();
d.Col8 = DateTime.Now.ToString();
d.Col9 = DateTime.Now.ToString();
d.Col10= DateTime.Now.ToString();
lst.Add(d);
}
return lst;
3.データバインド
private void button1_Click(object sender, EventArgs e)
{
var lst = MakeData();
// 自動でカラムを作らない
dataGridView1.AutoGenerateColumns = false;
// 列幅はそのまま
dataGridView1.RowHeadersWidthSizeMode = DataGridViewRowHeadersWidthSizeMode.EnableResizing;
Stopwatch sw = new Stopwatch();
sw.Start();
dataGridView1.DataSource = lst;
sw.Stop();
MessageBox.Show(string.Format("経過時間:{0} msec", sw.ElapsedMilliseconds));
// 10 msec 程度
}
普通に作るととても早いのですが…
dataGridView1.RowHeadersWidthSizeMode = DataGridViewRowHeadersWidthSizeMode.AutoSizeToAllHeaders;
このように、AutoSizeToAllHeaders を指定して列幅を自動で作成しようとすると。
private void button1_Click(object sender, EventArgs e)
{
var lst = MakeData();
// 自動でカラムを作らない
dataGridView1.AutoGenerateColumns = false;
// 列幅を自動調節する
dataGridView1.RowHeadersWidthSizeMode = DataGridViewRowHeadersWidthSizeMode.AutoSizeToAllHeaders;
Stopwatch sw = new Stopwatch();
sw.Start();
dataGridView1.DataSource = lst;
sw.Stop();
MessageBox.Show(string.Format("経過時間:{0} msec", sw.ElapsedMilliseconds));
// 4 分経ってもまだ終わりません。
}
ってな具合に、1000 倍ぐらい遅くなります。
想像するに、DataSource プロパティでバインドしたデータが、1 件加わるごとに AutoSizeToAllHeaders で列幅を調節している感じなんですよね。なので、一度、EnableResizing で計算しないようにしてから、後で AutoSizeToAllHeaders を指定します。
private void button1_Click(object sender, EventArgs e)
{
var lst = MakeData();
// 自動でカラムを作らない
dataGridView1.AutoGenerateColumns = false;
// 列幅はそのままに変える
dataGridView1.RowHeadersWidthSizeMode = DataGridViewRowHeadersWidthSizeMode.EnableResizing;
Stopwatch sw = new Stopwatch();
sw.Start();
dataGridView1.DataSource = lst;
// 全て入力した後に列幅を自動調節する
dataGridView1.RowHeadersWidthSizeMode = DataGridViewRowHeadersWidthSizeMode.AutoSizeToAllHeaders;
sw.Stop();
MessageBox.Show(string.Format("経過時間:{0} msec", sw.ElapsedMilliseconds));
// 108 msec 高速に動作する
}
前回、Ctrl+PrintScreen でアクティブなウィンドウをキャプチャする | Moonmile Solutions Blog を書いている時に、あらかじめ指定したウィンドウの画面キャプチャをする、というのも書いたので晒しておきます。
どうも CopyFromScreen を使ったり、hDC を使って画面キャプチャをすると、Visual Studio 2010 のメニューがキャプチャできないんですよね…仕方がないので、SendKeys クラスを使ってキーエミュレートをします。
キャプチャ画面はこんな感じ。メインウィンドウに乗っている場合、そのままキャプチャします。
■メインウィンドウを持つプロセスの一覧を取得
まずは、ウィンドウを持つプロセス一覧を取って、hWnd を保存しておきます。
///
/// プロセス一覧を取得
///
/// <param name="sender" />
/// <param name="e" />
private void button3_Click(object sender, EventArgs e)
{
listBox1.Items.Clear();
foreach (Process p in Process.GetProcesses())
{
if (p.MainWindowHandle != IntPtr.Zero)
{
Debug.Print(p.MainWindowTitle);
ProcessWin pw = new ProcessWin();
pw.Title = p.MainWindowTitle;
pw.hWnd = p.MainWindowHandle;
listBox1.Items.Add(pw);
}
}
}
■リストで選択してキャプチャ
///
/// Window Proc のオーバーライド
///
/// <param name="message" />
protected override void WndProc(ref Message message)
{
if (message.Msg == WM_HOTKEY && (int)message.WParam == HOTKEY_ID)
{
if (checkBox1.Checked == false)
{
// PrtSc キーを送信
SendKeys.SendWait("^{PRTSC}");
return;
}
else
{
if (listBox1.SelectedIndex == -1) return;
ProcessWin pw = (ProcessWin)listBox1.SelectedItem;
Bitmap bmp = WindowCapture(pw.hWnd);
Clipboard.SetImage(bmp);
return;
}
}
base.WndProc(ref message);
}
///
/// 指定したウィンドウをキャプチャ
///
///
private Bitmap WindowCapture( IntPtr hWnd )
{
IntPtr hDC = GetWindowDC(hWnd);
//ウィンドウの大きさを取得
RECT rect = new RECT();
GetWindowRect(hWnd, ref rect);
Bitmap bmp = new Bitmap(rect.right - rect.left, rect.bottom - rect.top);
// キーエミュレート
SendKeys.SendWait("^{PRTSC}");
Application.DoEvents();
Image img = Clipboard.GetImage();
if (img != null)
{
// クリップボードから指定画面を切り取る
Graphics g = Graphics.FromImage(bmp);
g.DrawImage(img, -rect.left, -rect.top);
}
return bmp;
}
これをホットキーの【Ctrl】+【PrtSc】に設定しておけば ok です。
手順書などを作るために画面のキャプチャをする時に、Alt+PrintScreen でアクティブな画面をキャプチャします。
が、メニューをキャプチャしたいときに【Alt】キーを押すと、そのメニューが消えてしまうんですよね。
なので、各種ツールを探すんですが…Ctrl+PrintScreen に割り当てればいいんじゃないの?ということで自作します。
Ctrl キーの場合は、メニューが閉じられませんからね。
こんな感じで、手軽にメニューもキャプチャできます。
■アクティブウィンドウのキャプチャ
using System.Runtime.InteropServices;
[StructLayout(LayoutKind.Sequential)]
private struct RECT
{
public int left;
public int top;
public int right;
public int bottom;
}
[DllImport("user32.dll")]
private static extern IntPtr GetWindowDC(IntPtr hwnd);
[DllImport("user32.dll")]
private static extern IntPtr GetForegroundWindow();
[DllImport("user32.dll")]
private static extern int GetWindowRect(IntPtr hwnd, ref RECT lpRect);
private const int SRCCOPY = 13369376;
[DllImport("user32.dll")]
private static extern IntPtr GetDC(IntPtr hwnd);
[DllImport("gdi32.dll")]
private static extern int BitBlt(IntPtr hDestDC,
int x,
int y,
int nWidth,
int nHeight,
IntPtr hSrcDC,
int xSrc,
int ySrc,
int dwRop);
[DllImport("user32.dll")]
private static extern IntPtr ReleaseDC(IntPtr hwnd, IntPtr hdc);
///
/// アクティブウィンドウをキャプチャ
///
///
private Bitmap ActiveWindowCapture()
{
IntPtr hWnd = GetForegroundWindow();
IntPtr hDC = GetWindowDC(hWnd);
//ウィンドウの大きさを取得
RECT rect = new RECT();
GetWindowRect(hWnd, ref rect);
Bitmap bmp = new Bitmap(rect.right - rect.left, rect.bottom - rect.top);
Graphics g = Graphics.FromImage(bmp);
IntPtr gDC = g.GetHdc();
BitBlt(gDC, 0, 0, bmp.Width, bmp.Height, hDC, 0, 0, SRCCOPY);
g.ReleaseHdc(gDC);
g.Dispose();
ReleaseDC(hWnd, hDC);
return bmp;
}
win api を多用しないといけないので、DllImport が多いですが、こんな感じ。
# BitBlt とか使いたくないけど、他にいい方法がありませんかね?
■ホットキーの登録/解除
ホットキーは、RegisterHotKey と UnregisterHotKey を使います。
HOTKEY_ID のほうは、他のアプリケーションとダブらないように適当に変えてください。
//
[DllImport("user32.dll")]
extern static int RegisterHotKey(IntPtr hWnd, int id, int modKey, int key);
[DllImport("user32.dll")]
extern static int UnregisterHotKey(IntPtr hWnd, int id);
const int MOD_ALT = 0x0001;
const int MOD_CONTROL = 0x0002;
const int MOD_SHIFT = 0x0004;
const int HOTKEY_ID = 0x1234;
//
// HotKeyのイベントを示すメッセージID
//
const int WM_HOTKEY = 0x0312;
///
/// ホットキーを登録
///
/// <param name="sender" />
/// <param name="e" />
private void button5_Click(object sender, EventArgs e)
{
if (RegisterHotKey(this.Handle, HOTKEY_ID, MOD_CONTROL, (int)Keys.PrintScreen) == 0)
{
MessageBox.Show("既に他のアプリで使用されています。");
}
}
///
/// ホットキーを解除
///
/// <param name="sender" />
/// <param name="e" />
private void button6_Click(object sender, EventArgs e)
{
UnregisterHotKey(this.Handle, HOTKEY_ID);
}
///
/// Window Proc のオーバーライド
///
/// <param name="message" />
protected override void WndProc(ref Message message)
{
if (message.Msg == WM_HOTKEY && (int)message.WParam == HOTKEY_ID)
{
Bitmap bmp = ActiveWindowCapture();
// bmp.Save(@"c:\work\bmp\" + DateTime.Now.ToString("yyyyMMddHHmmss") + ".bmp");
// クリップボードへコピー
Clipboard.SetImage(bmp);
return;
}
base.WndProc(ref message);
}
■参考先
画面をキャプチャする: .NET Tips: C#, VB.NET, Visual Studio
http://dobon.net/vb/dotnet/graphics/screencapture.html
ホットキー(HotKey)の設定 (DllImport, InteropServices, RegisterHotKey, UnRegisterHotKey) – いろいろ備忘録日記
http://d.hatena.ne.jp/gsf_zero1/20070416/p1
ダウンロード詳細 Windows Azure Tools for Microsoft Visual Studio 2010 1.4 (2011 年 8 月)
http://www.microsoft.com/downloads/ja-jp/details.aspx?FamilyID=f6d1609f-08aa-40d6-abd1-119503ecb1f9
をダウンロードして、日本語版の v1.4 を使うわけですが、そのままASP.NET Webアプリを作ってAzureにデプロイをするとエラーが発生します。
Windows Azure ASP.NET MVC 3 Web Role で使っているプロバイダ ≪ ブチザッキ
http://buchizo.wordpress.com/2011/08/04/windows-azure-asp-net-mvc-3-web-role-%e3%81%ab%e3%81%8a%e3%81%91%e3%82%8b%e3%83%87%e3%83%97%e3%83%ad%e3%82%a4%e6%99%82%e3%81%ae%e5%95%8f%e9%a1%8c/
Deploying the Windows Azure ASP.NET MVC 3 Web Role | Wade Wegner
http://www.wadewegner.com/2011/08/deploying-the-windows-azure-asp-net-mvc-3-web-role/?utm_source=feedburner&utm_medium=feed&utm_campaign=Feed%3A+WadeWegner+%28Wade+Wegner+-+Technical%29&utm_content=Google+Reader
これ、セッション情報を設定する sessionState のところが、Custom になっていて、このデータベース先が .\sqlexpress なのが原因なのですね。
<sessionState mode="Custom" customProvider="DefaultSessionProvider">
<providers>
<add name="DefaultSessionProvider"
type="System.Web.Providers.DefaultSessionStateProvider, System.Web.Providers, Version=1.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"
connectionStringName="DefaultConnection"
applicationName="/" />
</providers>
</sessionState>
確かに、複数のワーカープロセスでセッション情報を共有するので、SQL Serverを使う必要があるのは分かるんだけど、v1.3 には無かった記述が、いきなり v1.4 になって入っていて、しかも「何もせずにそのままデプロイしても落ちてる」っていうのは、駄目かなぁと。
なので、v1.4 で Azure アプリを作った時は、web.config を開いて、sessionState を削除します。
sessionState が無い時は、セッション情報はインプロセスになるので、Azure にデプロイしても正常に動作します。
で、
実運用的には、このセッション情報をどうするのか?が問題でして、案しては
1.SQL Azure に接続させる。
2.セッションサーバーを別途用意する。
3.Table Strage にセッション情報を用意する。
ってのが考えられます。
1の方法は、
Deploying the Windows Azure ASP.NET MVC 3 Web Role | Wade Wegner
http://www.wadewegner.com/2011/08/deploying-the-windows-azure-asp-net-mvc-3-web-role/?utm_source=feedburner&utm_medium=feed&utm_campaign=Feed%3A+WadeWegner+%28Wade+Wegner+-+Technical%29&utm_content=Google+Reader
に書いてある通り。SQL Azure に dbo.Sessions テーブルを作成します。
ただし、SQL Azure を使うので課金が発生するんですよね。。。普通に Windows Azure アプリを作るだけなのに、SQL Azure への課金はちょっと痛い。
2.のほうは、ちと見当たらず。
問題は、セッションサーバー自身を Azure に置くわけですが、じゃあそのセッション情報は、SQL Azure を使うことになるのか?ということ。
で、3.の Table Strage にセッション情報を保存するのが現実的なのかなぁと。
Exercise 3: Using the Azure ASP.NET Providers with Web Form Applications
http://msdn.microsoft.com/en-us/wazplatformtrainingcourse_buildingaspnetappswithwindowsazure_topic4#_Toc300153323
に「Microsoft.Samples.ServiceHosting.AspProviders.TableStorageRoleProvider」の記述があるので、できるのかなと。
何故か、IE9 上で windows azure platform を動かすと、「新規ホステッドサービス」を作成できません。
「ホステッドサービス」のリストも出ないし、「ストレージアカウント」のリストもでない。
windows azure platfrom が正常に動きません。
ハンドルされていないアプリケーションエラーが発生しました…と言われましても。
で、Firefox 6 で動かしてみると動く。
う~む。IE9 って microsoft の製品だよなぁ。azure って microsoft の製品だよなぁ。
書籍の画面キャプチャを、Firefox でやってもいいでしょうか?>某社
と思ったら、解決したッ!!!
一度、言語設定を「English」にして「ホステッドサービス」を表示させた後(なぜか、英語版だと表示できる)、その後「日本語」に戻すと表示される。。。うーん。管理ポータルが勝手にアップデートされたっぽい挙動が。
—
で、Windows Azure Tools for Microsoft Visual Studio v1.4 の日本語版がこんなところに↓
テスターですが何か?
http://david9142.wordpress.com/
ダウンロード詳細 Windows Azure Tools for Microsoft Visual Studio 2010 1.4 (2011 年 8 月)
http://www.microsoft.com/downloads/ja-jp/details.aspx?FamilyID=f6d1609f-08aa-40d6-abd1-119503ecb1f9
公開日が 2011/08/23 だそうなので、仕方がない原稿を書き直しますか。
実験メモ。
とあるプロジェクトで、Excel の書式コピーのパフォーマンスが良くない。ので調査。
とあるソースコードでは、
ってことをやっていました。で「遅いのは何処か?」ってな感じなのですが、普通は3を疑うところなのですが、いえいえ実際は2でした、というオチです。
Excel で帳票を作って「いまいち遅いんだよなぁ」って方は、試してみてください。.NET から操作する場合は、データベースアクセスよりも、Excel への操作のほうがネックになることが多いのです。
■いちいち、copy and paste しているのが駄目
最初のコードは、こんな感じです。実は Range のところ、もっと駄目なのですが(column毎にループしていたり)サンプル作るのが面倒なので、ちょっと高速化。
Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
Dim xapp As New Microsoft.Office.Interop.Excel.Application
Dim path As String = System.IO.Directory.GetCurrentDirectory() + "\" + "SampleTemplate.xlsx"
xapp.Workbooks.Open(path)
Dim sh As Worksheet = xapp.Workbooks(1).Sheets(1)
' 先頭行はタイトル、2行目からコピーする
Dim start As Date = Date.Now
For r = 3 To 1000
Dim src As Range = sh.Range(sh.Cells(2, 1), sh.Cells(2, 6))
src.Copy()
Dim dest As Range = sh.Range(sh.Cells(r, 1), sh.Cells(r, 6))
dest.PasteSpecial()
Next
TextBox1.Text = (Date.Now - start).ToString()
path = System.IO.Directory.GetCurrentDirectory() + "\" + "range1.xlsx"
System.IO.File.Delete(path)
xapp.Workbooks(1).SaveAs(path)
xapp.Quit()
MessageBox.Show("クリップボード経由版 保存しました")
End Sub
これを実行すると、2分強かかります。ええッ!!! 単にコピーしているだけなのに…と思うでしょう。
■copy を 1回だけにする
書式として使っている2行目は不変なわけですから、何度も copy する必要はありません。
なので、copy するところを1回にして、後は何度も paste すれば ok。
Private Sub Button2_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button2.Click
Dim xapp As New Microsoft.Office.Interop.Excel.Application
Dim path As String = System.IO.Directory.GetCurrentDirectory() + "\" + "SampleTemplate.xlsx"
xapp.Workbooks.Open(path)
Dim sh As Worksheet = xapp.Workbooks(1).Sheets(1)
' 先頭行はタイトル、2行目からコピーする
Dim start As Date = Date.Now
Dim src As Range = sh.Range(sh.Cells(2, 1), sh.Cells(2, 6))
src.Copy()
For r = 3 To 1000
Dim dest As Range = sh.Range(sh.Cells(r, 1), sh.Cells(r, 6))
dest.PasteSpecial()
Next
TextBox2.Text = (Date.Now - start).ToString()
path = System.IO.Directory.GetCurrentDirectory() + "\" + "range2.xlsx"
System.IO.File.Delete(path)
xapp.Workbooks(1).SaveAs(path)
xapp.Quit()
MessageBox.Show("Range経由版 保存しました")
End Sub
これを実行すると、13秒になります。ええ、10倍早くなりましたね。
■pasteする時に range で範囲を指定する
実は、コピー先は3行から1000行の範囲なので、Range で指定して一気にペーストができます。
これはよく Excel でやると思うのですが、何故かプログラムコードに直すと、なかなか思い付かないようです。
Private Sub Button3_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button3.Click
Dim xapp As New Microsoft.Office.Interop.Excel.Application
Dim path As String = System.IO.Directory.GetCurrentDirectory() + "\" + "SampleTemplate.xlsx"
xapp.Workbooks.Open(path)
Dim sh As Worksheet = xapp.Workbooks(1).Sheets(1)
' 先頭行はタイトル、2行目からコピーする
Dim start As Date = Date.Now
Dim src As Range = sh.Range(sh.Cells(2, 1), sh.Cells(2, 6))
src.Copy()
Dim dest As Range = sh.Range(sh.Cells(3, 1), sh.Cells(1000, 6))
dest.PasteSpecial()
TextBox3.Text = (Date.Now - start).ToString()
path = System.IO.Directory.GetCurrentDirectory() + "\" + "range3.xlsx"
System.IO.File.Delete(path)
xapp.Workbooks(1).SaveAs(path)
xapp.Quit()
MessageBox.Show("Range経由版 保存しました")
End Sub
これを実行すると、0.04秒になります。ええ、1000倍ぐらい早くなります…つーか、一瞬で終わります。
■クリップボードを経由させない。
これまでは copy, paste で、クリップボードを使っていたわけですが、実は copy の引数にはコピー先の range を入れることができます。
Office TANAKA – Excel VBA講座:セルの操作[セルのコピー]
http://officetanaka.net/excel/vba/cell/cell09.htm
こうすると、クリップボードを経由しないので早くなるんですね(多分)。
Private Sub Button4_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button4.Click
Dim xapp As New Microsoft.Office.Interop.Excel.Application
Dim path As String = System.IO.Directory.GetCurrentDirectory() + "\" + "SampleTemplate.xlsx"
xapp.Workbooks.Open(path)
Dim sh As Worksheet = xapp.Workbooks(1).Sheets(1)
' 先頭行はタイトル、2行目からコピーする
Dim start As Date = Date.Now
Dim src As Range = sh.Range(sh.Cells(2, 1), sh.Cells(2, 6))
Dim dest As Range = sh.Range(sh.Cells(3, 1), sh.Cells(1000, 6))
' クリップボードを媒介しない
src.Copy(dest)
TextBox4.Text = (Date.Now - start).ToString()
path = System.IO.Directory.GetCurrentDirectory() + "\" + "range4.xlsx"
System.IO.File.Delete(path)
xapp.Workbooks(1).SaveAs(path)
xapp.Quit()
MessageBox.Show("Range直接版 保存しました")
End Sub
これを実行すると、0.03秒になる。非常に高速化、と言いますか既に誤差の範囲ですね。
まぁ、1000行ぐらいだと差はつかないのかもしれません。
実行結果の画像などはこちら。

C/C++ で言うところの、__FILE__ や __LINE__ を拾ってログ出力したい、という場合
次のような関数を作っておきます。
Public Class DebugTrace
Public Shared Sub Trace()
Dim sf = New StackFrame(1, True)
Dim methodName As String = sf.GetMethod().ToString()
Dim fileName As String = sf.GetFileName()
Dim lineNumber As Integer = sf.GetFileLineNumber()
MessageBox.Show(String.Format( _
"場所 {0} 場所 {1}:行 {2}", methodName, fileName, lineNumber))
End Sub
End Class
で、使いたいときは、
Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
DebugTrace.Trace()
End Sub
のように書けばOK.
StackFrameクラスでは、Exceptionのように呼び出し元を再帰的に呼べるはずですが、ひとまずこれで用は足りるからよいかな、と。
実は、ActiveDirectry を扱うために DirectoryEntry, DirectorySearch なんかを駆使しないと駄目なのかなぁ、と思ったのですが、単純に現在ログインしているユーザーに関してならば、ローカルの Windows ユーザーをチェックすれば OK でした、というオチです。
# ActiveDirecotry 特有のプロパティを調べる場合は、DirectoryEntry などが必要になるのですが、 カレントユーザーのグループ名の列記だけならば、結構簡単に、という話です。
ユーザ名やドメイン名は、Environment のスタティックプロパティを利用します。
グループ名の一覧を取得する時は、NTAccount クラスにキャストして使います。
という訳で簡単にソースをば。
private void Form1_Load(object sender, EventArgs e)
{
string username = Environment.UserName;
string domainname = Environment.UserDomainName;
labelUser.Text = username;
labelDomain.Text = domainname;
// using System.Security.Principal;
WindowsIdentity user =
WindowsIdentity.GetCurrent();
// 属しているグループ名一覧を取得
listBox1.Items.Clear();
foreach (var group in user.Groups)
{
// NTアカウントに変換
NTAccount ac =
(NTAccount)group.Translate(typeof(NTAccount));
listBox1.Items.Add(ac.Value);
}
listBox1.Sorted = true;
}