Visual Studio 11 では VC++ のインテリセンスが効くよ

MSDN から Visual Studio 11 preview 版(VS2012候補ですね)を入れて、Visual C++ を試してみました。
画像は後から貼り付けますが、インテリセンスが効くようになったよッ!!! ってことで。

これで、まともに C++/CLI でコーディングができそうです。

# VS 2010 にもサービスパック経由で出して欲しいなぁと。

カテゴリー: 開発, C++ | Visual Studio 11 では VC++ のインテリセンスが効くよ はコメントを受け付けていません

Windows Azure Tools for Microsoft Visual Studio v1.5 リリース

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 英語版で試してみるということで。

カテゴリー: 開発, Azure | 1件のコメント

DataGridView へのバインドが遅い場合は、RowHeadersWidthSizeMode プロパティの値を疑ってみよう

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 高速に動作する
}

カテゴリー: 開発, C# | 2件のコメント

ホットキーで指定したウィンドウをキャプチャする

前回、Ctrl+PrintScreen でアクティブなウィンドウをキャプチャする | Moonmile Solutions Blog を書いている時に、あらかじめ指定したウィンドウの画面キャプチャをする、というのも書いたので晒しておきます。

どうも CopyFromScreen を使ったり、hDC を使って画面キャプチャをすると、Visual Studio 2010 のメニューがキャプチャできないんですよね…仕方がないので、SendKeys クラスを使ってキーエミュレートをします。

キャプチャ画面はこんな感じ。メインウィンドウに乗っている場合、そのままキャプチャします。

■メインウィンドウを持つプロセスの一覧を取得

まずは、ウィンドウを持つプロセス一覧を取って、hWnd を保存しておきます。

///
/// プロセス一覧を取得
///
/// <param name=&quot;sender&quot; />
/// <param name=&quot;e&quot; />
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=&quot;message&quot; />
protected override void WndProc(ref Message message)
{
    if (message.Msg == WM_HOTKEY && (int)message.WParam == HOTKEY_ID)
    {
        if (checkBox1.Checked == false)
        {
        	// PrtSc キーを送信
            SendKeys.SendWait(&quot;^{PRTSC}&quot;);
            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 です。

カテゴリー: 開発, C# | ホットキーで指定したウィンドウをキャプチャする はコメントを受け付けていません

Ctrl+PrintScreen でアクティブなウィンドウをキャプチャする

手順書などを作るために画面のキャプチャをする時に、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(&quot;user32.dll&quot;)]
extern static int RegisterHotKey(IntPtr hWnd, int id, int modKey, int key);
[DllImport(&quot;user32.dll&quot;)]
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=&quot;sender&quot; />
/// <param name=&quot;e&quot; />
private void button5_Click(object sender, EventArgs e)
{
    if (RegisterHotKey(this.Handle, HOTKEY_ID,  MOD_CONTROL, (int)Keys.PrintScreen) == 0)
    {
        MessageBox.Show(&quot;既に他のアプリで使用されています。&quot;);
    }
}
///
/// ホットキーを解除
///
/// <param name=&quot;sender&quot; />
/// <param name=&quot;e&quot; />
private void button6_Click(object sender, EventArgs e)
{
    UnregisterHotKey(this.Handle, HOTKEY_ID);
}
///
/// Window Proc のオーバーライド
///
/// <param name=&quot;message&quot; />
protected override void WndProc(ref Message message)
{
    if (message.Msg == WM_HOTKEY && (int)message.WParam == HOTKEY_ID)
    {
        Bitmap bmp = ActiveWindowCapture();
        // bmp.Save(@&quot;c:\work\bmp\&quot; + DateTime.Now.ToString(&quot;yyyyMMddHHmmss&quot;) + &quot;.bmp&quot;);
        // クリップボードへコピー
        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

カテゴリー: 開発, C# | 6件のコメント

Windows Azure for Visual Studio v1.4 でAzureアプリを作成して、そのままアップするとエラーになる

ダウンロード詳細 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=&quot;Custom&quot; customProvider=&quot;DefaultSessionProvider&quot;>
  <providers>
    <add name=&quot;DefaultSessionProvider&quot;
         type=&quot;System.Web.Providers.DefaultSessionStateProvider, System.Web.Providers, Version=1.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35&quot;
         connectionStringName=&quot;DefaultConnection&quot;
         applicationName=&quot;/&quot; />
  </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」の記述があるので、できるのかなと。

カテゴリー: 開発, Azure | Windows Azure for Visual Studio v1.4 でAzureアプリを作成して、そのままアップするとエラーになる はコメントを受け付けていません

IE9上で、Windows Azure Platform が正常に動かない

何故か、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 だそうなので、仕方がない原稿を書き直しますか。

カテゴリー: 開発, Azure | IE9上で、Windows Azure Platform が正常に動かない はコメントを受け付けていません

Excel で 書式をクリップボード経由にすると遅くなる

実験メモ。

とあるプロジェクトで、Excel の書式コピーのパフォーマンスが良くない。ので調査。
とあるソースコードでは、

  1. Excel のテンプレートファイルを開いている。
  2. 書式を揃えるために、2行目から1000行までをコピーしている。
  3. データベースを検索して、セルにちまちま書き込む。

ってことをやっていました。で「遅いのは何処か?」ってな感じなのですが、普通は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行ぐらいだと差はつかないのかもしれません。

実行結果の画像などはこちら。

カテゴリー: 開発, VB | 2件のコメント

VB/C#でトレースログを出力する方法

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のように呼び出し元を再帰的に呼べるはずですが、ひとまずこれで用は足りるからよいかな、と。

カテゴリー: 開発, C#, VB | VB/C#でトレースログを出力する方法 はコメントを受け付けていません

ActiveDirecotryでログインユーザーがどのグループに属しているか調べる

実は、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;
}
カテゴリー: 開発, C# | ActiveDirecotryでログインユーザーがどのグループに属しているか調べる はコメントを受け付けていません