C# と VB.NET の質問掲示板

ASP.NET、C++/CLI、Java 何でもどうぞ

C# と VB.NET の入門サイト

Re[5]: C# エクセルのセルにデータを入れる


(過去ログ 118 を表示中)

[トピック内 6 記事 (1 - 6 表示)]  << 0 >>

■69203 / inTopicNo.1)  C# エクセルのセルにデータを入れる
  
□投稿者/ ぽんた (1回)-(2013/12/09(Mon) 20:35:40)

分類:[.NET 全般] 

お世話になります。

分類:[.NET 全般] 

環境:
Windows7
Visualstudio2008
Excel 2010

画像データを配列化して、それをエクセルシートに入力するというプログラムをC#で作成しているのですが、
Range.set_Value()で応答なしになってしまいます。どこに問題があるのでしょうか?
概略は以下のような感じです。

byte[,] data = new byte[xsize, ysize];
copyImageData(data); // 画像データを配列に格納
range = sheet.get_Range(sheet.Cells[1,1], sheet.Cells[xsize, ysize]);
range.set_Value(Type.Missing, data); // ここで応答が返らない。

ちなみに、rangeを使わずに、for文で、sheet.Cells[i, j] = data[i, j]はうまくいきますが、非常に時間がかかります。

引用返信 編集キー/
■69206 / inTopicNo.2)  Re[1]: C# エクセルのセルにデータを入れる
□投稿者/ 魔界の仮面弁士 (457回)-(2013/12/09(Mon) 21:39:41)
No69203 (ぽんた さん) に返信
> Range.set_Value()で応答なしになってしまいます。
配列のサイズはどの程度でしょうか?
1x1 とか 3x3 程度の小さなデータでも駄目でしょうか。


こちらでは現象を確認できていないのですが、もしも
応答なしの間、使用メモリ量が増加し続けているようであれば、
単純に長い時間がかかっているという事なのかもしれません。

如何に配列渡しといえど、項目数が多くなるにつれ、
処理時間が加速度的に延びることになりますので。


VBA から設定するのとは異なり、プロセス間のデータ渡しを伴うため、
おそらくはマーシャリングの時間が莫迦にならないということなのでしょう。

そのため、大きめのデータについては、すべてを一度に渡すのではなく、
ある程度の配列サイズに区切って処理した方が効率が良くなるようです。
どの程度に区切るかは、試行錯誤で決めるしかないですが…。


あと、Visible は true にしておいた方が高速に処理されるようです(falseではなく)。
描画抑制のために ScreenUpdating = false にする必要はあるでしょうけれども。

それ以外で速度差が生じるところでは、Enable(FormatConditions)Calculation とか…。
引用返信 編集キー/
■69207 / inTopicNo.3)  Re[2]: C# エクセルのセルにデータを入れる
□投稿者/ ぽんた (3回)-(2013/12/09(Mon) 21:57:52)
No69206 (魔界の仮面弁士 さん) に返信
> ■No69203 (ぽんた さん) に返信
>>Range.set_Value()で応答なしになってしまいます。
> 配列のサイズはどの程度でしょうか?
> 1x1 とか 3x3 程度の小さなデータでも駄目でしょうか。

回答ありがとうございます。

2x2もだめでしたので、応答なしと判断しました。
下記サイトのほぼ真似なんですけどね。。
http://support.microsoft.com/kb/302096/ja

Range.set_Valueなどの説明がどのサイトでもあまりないのでよくわからないまま使っています。
引用返信 編集キー/
■69210 / inTopicNo.4)  Re[3]: C# エクセルのセルにデータを入れる
□投稿者/ 魔界の仮面弁士 (458回)-(2013/12/09(Mon) 23:53:23)
No69207 (ぽんた さん) に返信
> 2x2もだめでしたので、応答なしと判断しました。
> 下記サイトのほぼ真似なんですけどね。。
> http://support.microsoft.com/kb/302096/ja

ほぼ同様の環境があったので追加検証してみましたが、
当方では応答無しではなく、COM例外(0x800A03EC)が発生しました。


Windows 7(x64)、Excel 2010(x86)、C#2008(AnyCPUビルド)です。


//-----------------------------
using System;
using Excel = Microsoft.Office.Interop.Excel;
using System.Runtime.InteropServices;

class Sample
{
    [MTAThread]
    static void Main()
    {
        Excel.Application app = new Excel.ApplicationClass();
        app.Visible = true;
        Excel.Workbooks books = app.Workbooks;
        Excel.Workbook book = books.Add(Type.Missing);
        Excel.Sheets sheets = book.Worksheets;
        Excel._Worksheet ws = (Excel.Worksheet)sheets[1];

        // この場合は COMException が発生する
        //byte[,] data = new byte[,] { { 12, 34 }, { 56, 78 } };

        // Option Base 1 な配列にしても駄目
        //byte[,] data = (byte[,])Array.CreateInstance(typeof(byte), new int[] { 2, 2 }, new int[] { 1, 1 });
        //data[1, 1] = 12;
        //data[1, 2] = 34;
        //data[2, 1] = 56;
        //data[2, 2] = 78;

        // これなら処理される
        object[,] data = { { (byte)12, (byte)34 }, { (byte)56, (byte)78 } };

        Excel.Range cells = ws.Cells;
        Excel.Range lt = (Excel.Range)cells[1, 1];
        Excel.Range rb = (Excel.Range)cells[2, 2];
        Excel.Range range = ws.get_Range(lt, rb);

        Release(ref lt);
        Release(ref rb);
        Release(ref cells);

        Console.Write("セット開始");
        Console.ReadLine();
        range.set_Value(Type.Missing, data);
        Console.WriteLine("セット完了");

        Release(ref range);
        Release(ref ws);

        Release(ref sheets);
        book.Saved = true;
        Release(ref book);
        Release(ref books);

        Console.Write("終了します");
        Console.ReadLine();
        app.Quit();
        Release(ref app);
    }

    static int Release<T>(ref T o) where T : class
    {
        int cRCW = 0;
        if (o != null && Marshal.IsComObject(o))
        {
            cRCW = Marshal.ReleaseComObject(o);
            o = null;
        }
        return cRCW;
    }

}
//-----------------------------



> Range.set_Valueなどの説明がどのサイトでもあまりないのでよくわからないまま使っています。

要するに、『Range オブジェクトの Value プロパティ』ですよね。
(機能的については Excel VBA のヘルプを参照)

C# の「range.set_Value(Type.Missing, data);」は、
Excel 的には「range.Value = data」を意味します。

厳密には、Excel のバージョンによって
 2000 まで「Property Value() As Object」
 2002 から「Property Value(Optional RangeValueDataType As Object = XlRangeValueDataType.xlRangeValueDefault) As Object」
のような違いがありますけれども。

引用返信 編集キー/
■69241 / inTopicNo.5)  Re[4]: C# エクセルのセルにデータを入れる
□投稿者/ ぽんた (5回)-(2013/12/10(Tue) 19:29:44)
ありがとうございます。

おかげさまで、数分かかっていた処理が、数秒で終わるようになりました。

byte配列が受け付けないようで、object型にすることがポイントのようですね。
object型でなく、int配列に直してもうまくいきました。

引用返信 編集キー/
■69243 / inTopicNo.6)  Re[5]: C# エクセルのセルにデータを入れる
□投稿者/ ぽんた (6回)-(2013/12/10(Tue) 22:47:30)
解決済みにチェックしておきます。
解決済み
引用返信 編集キー/


トピック内ページ移動 / << 0 >>

このトピックに書きこむ

過去ログには書き込み不可

管理者用

- Child Tree -