DOBON.NET DOBON.NETプログラミング掲示板過去ログ

EXCELオブジェクトをBLOBへセットしたい

環境/言語:[WinXP/C#/Framework2.0/Oracle10g]
分類:[.NET]

いつもお世話になっております。

現在、EXCELオブジェクトをOracleのBLOB型へセットしているプログラムが
あるのですが、以下のような流れでデータをセットしています。

@.Excelオブジェクトを SaveAs でTempファイルとして保存(C:\temp.xls を作成)
A.@で作成したTempファイルをSystem.IO.FileStreamで読込み、変数(byte[])へセット
B.Aでセットした変数をBLOB型のフィールドへセットする

@、Aの作業で1秒くらいかかっているのでこの処理を除き、Excelオブジェクトを
変数(byte[])へ変換できればと思ったのですが、このようなことは出来ないのでしょうか?

知っておられる方がおりましたら教えて頂けないでしょうか?

よろしくお願いします。
> @、Aの作業で1秒くらいかかっているのでこの処理を除き、Excelオブジェクトを
> 変数(byte[])へ変換できればと思ったのですが、このようなことは出来ないのでしょうか?

  Excelの出力は物理的にファイル保存なので、高速化したいならば
  RAMDISK程度しか無理でしょう。後は、Excelの出力を高速化する
  くらい・・・

  よって、Excelでどうされているのか解りませんが、Excelを使わず
  他有償商品(ExcelCreator/SpreadSheetGear2008)を使って行うく
  らいですか・・・

※ 未確認ですが、MemoryStreamに出力できるようでしたら、物理的に
  ファイルに保存しなくてもバイト配列で取得できますので、BLOBの
  フィールドには一気に代入できます。

  参考まで・・・

以上。
オショウさま ありがとうございました。

別の手法で考えて見ます。
解決済み!
解決済みチェックの後で何ですが・・・

> @、Aの作業で1秒くらいかかっているのでこの処理を除き、Excelオブジェクトを
> 変数(byte[])へ変換できればと思ったのですが、このようなことは出来ないのでしょうか?

OLEのAPIを直接使用すれば直接バイト配列に出力することができます。
OLE的に正当な手順は以下のようになるかと。
1. バイト配列上に保存できるように ILockBytes を実装
2. StgCreateDocfileOnILockBytes で IStorage に変換
3. OleCreate で Excel ワークブックオブジェクトを作成
4. ワークブックをいろいろ編集
5. OleSave で IStorage 上にExcelを保存
6. IPersistStorage.SaveCompleted を呼ぶ
7. IOleObject.Close を呼ぶ
で、バイト配列上に Excel ワークブックを保存できます。
ただし、この手順ではExcelのウィンドウが非表示状態のまま保存されるので、
オートメーションで表示状態にした後、保存する必要があります。

正当ではない手法としては、OleCreate を使用せず、
オートメーションを使って作成したワークブックに対して、
直接 OleSave を呼び出しても普通に動作してくれます。(多分)
この場合、6と7の手順は不要です。

パフォーマンス要件が厳しくないならば、CreateILockBytesOnHGlobal によって、
システムの実装による ILockBytes を使用することも可能です。
解決済み!
2009/02/27(Fri) 22:40:18 編集(投稿者)

> OLEのAPIを直接使用すれば直接バイト配列に出力することができます。

  一応できますネ!
  勉強になりました。

  Atata!!さんのホームページからサンプルダウンロードさせて
  頂きました。応用できますネ〜

  しかしながら、Oleの下でExcel動作するので、やはり速度面
  が気になります。

  パフォ−マンスを得たいのであれば、ことエクセルに関しては
  ExcelCreateやSpreadSheetGearがありますので、セクセルファ
  イルの生成は、Excel本体より高速です。

  有償商品を購入できない事情があるならば、この方法は有用で
  すネ!

以上。
解決済み!
Atata!!様、ありがとうございました。

早速、情報を元にAtata!!さんのホームページからサンプルを
ダウンロードしてみたり自分なりに色々と調べたりしてやっているのですが
なかなか思うようにいきません。

ほとんど答えを書いて頂いていただいていると推測できるのですが、
なかなかその実現が出来ておらず、ここ2,3日嵌っております。

大変恐縮ではございますが、間違い等あればご指導願いませんでしょうか?

よろしくお願いします。


以下、Atata!!様の記述の内容
 1. バイト配列上に保存できるように ILockBytes を実装
 2. StgCreateDocfileOnILockBytes で IStorage に変換
★3. OleCreate で Excel ワークブックオブジェクトを作成
★4. ワークブックをいろいろ編集
 5. OleSave で IStorage 上にExcelを保存
★6. IPersistStorage.SaveCompleted を呼ぶ
★7. IOleObject.Close を呼ぶ

★正当ではない手法としては、OleCreate を使用せず、
オートメーションを使って作成したワークブックに対して、
直接 OleSave を呼び出しても普通に動作してくれます。(多分)
この場合、6と7の手順は不要です。
→別のクラスでExcelObjectの操作が行われている為、3,4,6,7は
ここでは不要にしています。

こちらでの記述内容

●Interface
// ILockBytes
[ComImport(),
Guid("00000127-0000-0000-C000-000000000046"),
InterfaceType(ComInterfaceType.InterfaceIsIUnknown),
ComVisible(false)]
public interface ILockBytes
{
[PreserveSig()]
HRESULT ReadAt(UInt64 ulOffset, byte[] pv, uint cb, out uint pcbRead);

[PreserveSig()]
HRESULT WriteAt(UInt64 ulOffset, byte[] pv, uint cb, out uint pcbWritten);

[PreserveSig()]
HRESULT Flush();

[PreserveSig()]
HRESULT SetSize(UInt64 cb);

[PreserveSig()]
HRESULT LockRegion(UInt64 libOffset, UInt64 cb, uint dwLockType);

[PreserveSig()]
HRESULT UnlockRegion(UInt64 libOffset, UInt64 cb, uint dwLockType);

[PreserveSig()]
HRESULT Stat(STATSTG[] pstatstg, uint grfStatFlag);

}

●OLE32
// StgCreateDocfileOnILockBytes
[DllImport("OLE32.DLL")]
public extern static HRESULT StgCreateDocfileOnILockBytes(
ILockBytes pilbOutput,
STGM grfMode,
uint reserved,
out IStorage pistgOutput);

// OleSave
[DllImport("OLE32.DLL")]
public extern static HRESULT OleSave(
IPersistStorage pPS,
IStorage pStg,
[MarshalAs(UnmanagedType.Bool)]
bool fSameAsLoad);

●ソース
  :
  :
HRESULT hr;
ILockBytes m_lockbytes = null;
IStorage m_stg;
Byte[] bytTempFile = null;

//StgCreateDocfileOnILockBytesでIStorageに変換
hr = Ole32.StgCreateDocfileOnILockBytes(
m_lockbytes,
STGM.STGM_CREATE | STGM.STGM_TRANSACTED | STGM.STGM_READWRITE | STGM.STGM_SHARE_EXCLUSIVE,
0,
out m_stg);

●エラー発生箇所
if (Win32.FAILED(hr)){
pstrErrorMsg = "IStorageの作成に失敗しました。";
return false;
}

//Excelオブジェクトの変換
IPersistStorage m_persistStg = obj.CurrentBook as IPersistStorage;

//IStorage上にExcelオブジェクトを保存
hr = Ole32.OleSave(m_persistStg, m_stg, true);
if (Win32.FAILED(hr))
{
pstrErrorMsg = "IStorage上へのExcelオブジェクト保存に失敗しました。";
return false;
}



上記のロジックを実行すると、●エラー発生箇所 にて「STG_E_INVALIDPOINTER」
のエラーが発生します。
恐らく変数定義で ILockBytes m_lockbytes = null; がまずいのではと思うのですが、new が使用できないのでとりあえずnullをセットしました。
ILockBytesの定義もこれでいいのかと思ってしまい、どれが正解なのか分からなくなってしまいました。
2週間も経てば何らかの解決策を独自に編み出していると思われるので
ILockBytesのサンプルを私のサイトに載せておきました。
Atata!!様

> 2週間も経てば何らかの解決策を独自に編み出していると思われるので
> ILockBytesのサンプルを私のサイトに載せておきました。

早速、Atata!!様のサイトを確認いたしました。
わざわざ、サンプルまで載せて頂き本当にありがとうございました。

おかげさまで、何とか解決できました。
解決済み!

DOBON.NET | プログラミング道 | プログラミング掲示板