DataGridView をエクセルに出力


ちゃまき  2012-06-01 15:31:14  No: 147613  IP: 192.*.*.*

VB2010で DataGridView のデータの必要な列のデータのみ、エクセルの所定のセルへ出力したいと考えているのです。またExcelのバージョンが  社内に2000、2003、2007と3種類存在しています。
現在以下のような構文でexcelに出力はできたのですが、Excelを閉じたあと、普通にエクスプローラなどから開こうとしたら開けません。
何が原因なのでしょうか?

また今回Excel2000で試しているのでが、2003や2007の場合もこの方法でできますか?

'エクセル表示
   Dim xlApp As Excel.Application = Nothing      
   Dim xlBook As Excel.Workbook = Nothing             
   Dim xlSheet As Excel.Worksheet = Nothing    
   Dim xlChart As Excel.Chart = Nothing           
Try                
        xlApp = CType(CreateObject  ("Excel.Application"),Excel.Application)
        xlApp.Workbooks.Add()
        xlBook = xlApp.Workbooks(1)
        xlSheet = xlBook.Worksheets(1)

        xlSheet.Range("A1").Value = "出力データ1"
        xlSheet.Range("B1").Value = "出力データ2"
                        
        xlSheet.SaveAs("D:\Test.xls")  '名前をつけて保存
        'Excelの表示           
        xlApp.Visible = True

       ' オブジェクトを解放します。
        xlSheet = Nothing
        xlBook = Nothing
        xlApp = Nothing

        Catch ex As Exception
            If Not IsNothing(xlBook) Then xlBook.Close()
            If Not IsNothing(xlApp) Then xlApp.Quit()
        End Try

編集 削除
魔界の仮面弁士  2012-06-02 02:26:45  No: 147614  IP: 192.*.*.*

> 普通にエクスプローラなどから開こうとしたら開けません。
> 何が原因なのでしょうか?
提示されたコードには COM オブジェクトの解放処理が漏れているため、
Excel が正しく終了されず、非表示のままゾンビプロセスとして
残っている可能性が考えられます。
(実行後、タスクマネージャーに Excel.exe が残っていませんか?)

もしくは、再描画禁止またはユーザー操作禁止モードのまま
Excel が閉じれられてしまい、次回起動時に真っ白になってしまうなどの
問題を起こしているパターンもあります。(今回はそうでは無さそうですが)


> 2000、2003、2007と3種類存在しています。
複数の Excel バージョンが混在しているというのは、
実行環境でしょうか、それとも開発環境でしょうか。

・VB6 や VBA では、変数に Nothing を代入することでオブジェクト参照を
  解放できるのですが、VB.NET から扱う場合はそれでは不十分です。
  .NET のメモリ管理と ActiveX のメモリ管理は異なるため、この場合は
  Marashal.RelaseComObject メソッドを利用しないと早期解放されません。

・.NET からの Excel 2000 の制御は、あまりお勧めしません。Office XP や
  2003、2007、2010 にはプライマリ相互運用機能アセンブリ(PIA)が
  提供されていますが、2000 や 97 用のものは用意されていないためです。
  (保証されていないというだけで、PIA でなくても一応呼べますが…)

・開発環境の Excel バージョンと実行環境の Excel バージョンは
  できるだけ一致させてください。統一できない場合は、
  「実行環境のExcelバージョン ≧ 開発環境のExcelバージョン」
  にしておくと、呼び出し時の問題を軽減できます。

・開発側のバージョンの方が高くても呼び出せないわけではありませんが、
  一部のメソッドで、引数の数が異なっているとか、Sub が Function に
  拡張されるといった違いがあるため、そのままだと実行時エラーに
  なってしまう物があります。この場合、下位互換の隠しメソッドに
  置き換えるなどで対処は可能ですが、Excel の各バージョンの差異を
  理解している必要があるため、実装難易はやや上がります。

・バージョンを限定できない場合には、参照設定して使うことを諦め、
  すべてレイトバインドで実行するという手もあります。この場合は
  バージョンの差異をかなり吸収できますが、この場合、参照カウントが
  意図せず増加してしまうことがあるため、オブジェクトの後始末処理に、
  多少手を入れねばならないかも知れません。


> xlApp.Workbooks.Add()
> xlBook = xlApp.Workbooks(1)
Workbooks(1) で受けるのではなく、
Add メソッドの戻り値から Workbook を得るようにすべきです。

ただしその前に、Workbooks プロパティも変数に受けるようにしましょう。
そうしないと、オブジェクトを正しく ReleaseComObject できないため、
Excel が正しく終了しなかったり、2回目以降の操作に支障をきたすなどの
弊害をもたらします。
http://hanatyan.sakura.ne.jp/dotnet/Excelflm.htm

そのほか、Worksheets や Range の使い方にも問題があるので、
一度、上記の URL に目を通しておかれることをお奨めします。

編集 削除
ちゃまき  2012-06-02 09:52:08  No: 147615  IP: 192.*.*.*

現在、開発環境がExcel2000で、実行環境が2000.2003.2007が存在する
状態です。
まず、参考ページのImports Microsoft.Office Interrop
ですが、エラーになります。
参照追加でExcel object library9は追加しています。
そこでいきなり、つまづいてしまいました。
開発環境が2000なので、発生しているようです。

編集 削除
魔界の仮面弁士  2012-06-02 12:43:15  No: 147616  IP: 192.*.*.*

> 開発環境がExcel2000で、実行環境が2000.2003.2007が存在する
> 状態です。
Workbooks.Open や Range.Insert メソッドだけでも、バージョンによって
これだけメソッド定義に差異があります。
http://dobon.net/vb/bbs/log3-46/27545.html
http://madia.world.coocan.jp/cgi-bin/VBBBS/wwwlng.cgi?print+200603/06030081.txt

この非互換性のため、実行時に呼び出しが失敗してエラーとなる可能性が
ありますので、それぞれの環境での動作検証は十分に行ってください、


> まず、参考ページのImports Microsoft.Office Interrop
> ですが、エラーになります。
スペルミスには目を瞑るとして:

名前空間を含めた長い名前が、
  Microsoft.Office.Interop.Excel.Application
などの形式になるのは、PIA (プライマリ相互運用機能アセンブリ)を
参照している場合です。

2000 の場合は、電子署名された公式の「PIA」は提供されていないため、
参照設定時に Visual Studio によって自動生成される
「IA(相互運用機能アセンブリ)」の DLL を使う事になります。

手元に環境が無いので確認できませんが、この自動生成される DLL は、
確か Interop.Excel.DLL といったファイル名になっているはずです。
また、名前空間は Microsoft.Office.Interop.Excel ではなく、
Excel.Application になったかと記憶しています。

※タイプライブラリインポータ(Tlbimp.exe)等を使えば、
  別の名前空間にすることもできますけれども。

なので Excel 2000 の場合は、Imports 宣言は特に行わずに
  Dim xlApp As Excel.Application
などと記述できるかと思います。


後はとにかく、「各オブジェクトを、使用後に ReleaseComObject する」
ことを徹底し、終了後に Excel.exe がタスクに残っていないかを
確認するようにしてみてください。

編集 削除
ちゃまき  2012-06-04 13:38:42  No: 147617  IP: 192.*.*.*

http://hanatyan.sakura.ne.jp/dotnet/Excelflm.htm
を参考に引き続きエクセルへの出力プログラムを作成中です。

開発PC エクセル2000
実行PC エクセル2000  2003  2007  の状態ですが、

'拡張子に合せて保存形式を変更
  Select Case kts
   Case ".csv"    'CSV (カンマ区切り) 形式
       fm = Excel.XlFileFormat.xlCSV
   Case ".xls"    'Excel 97〜2003 ブック形式
       fm = Excel.XlFileFormat.xlExcel8 '★
   Case ".xlsx"   'Excel 2007〜ブック形式
       fm = Excel.XlFileFormat.xlOpenXMLWorkbook  '★
   Case ".xlsm"   'Excel 2007〜マクロ有効ブック形式
       fm = Excel.XlFileFormat.xlOpenXMLWorkbookMacroEnabled  ’★
   Case Else      '必要なものは、追加して下さい。
       fm = Excel.XlFileFormat.xlWorkbookDefault'★
       MessageBox.Show("ファイルの保存形式を確認して下さい。")
  End Select

のところで、Excle.XlFileFormat のメンバではありませんとエラーが出てしまいます。

編集 削除
魔界の仮面弁士  2012-06-04 14:58:20  No: 147618  IP: 192.*.*.*

開発環境と実行環境の Excel バージョンは合わせておくのが基本です。
(可能であれば、各バージョンごとに別の EXE にしておくのがなお安全)

複数バージョン対応として作りこみたいのであれば、引数の違いや
追加された列挙型の定数など、それぞれの違いを把握しておくべきかと。


> Case ".xlsx"   'Excel 2007〜ブック形式
>    fm = Excel.XlFileFormat.xlOpenXMLWorkbook  '★

そりゃまぁ、Excel 2000 で「Excel 2007/2010 ブック形式」のための
ファイルフォーマット定数が使える道理はありませんよね。(^_^;)


Excel 2000 の環境で開発するのなら、出来上がったソフトウェアも
Excel 2000 までの機能しか扱えないのが普通です。


それでも現在の開発環境から Excel 2007 向けの機能を呼び出したいなら、
(1) Excel 2007 入りの開発環境を用意する。
(2) 参照設定せずにレイトバインドで記述し、必要な定数等も自分で記述する。
の 2 択だと思ってください。

1 の場合は、2007 未満の実行環境で動作させることは難しくなります。
2 の場合は、各バージョンの違いを把握しているということが大前提です。

編集 削除