none
vb.NETでExcelの行を削除する方法について RRS feed

  • 質問

  • はじめまして。VB.NETの初心者です。

    VB.NETでExcelにアクセスし、行を削除する処理を作ろうとしていますが、思うように削除ができません。

    Excel側で行削除の処理をマクロに記録させたところ、以下のコードが取得できました。

         Rows("8:8").Select
         Selection.Delete Shift:=xlUp

    これをVBにコーディングしようとすると、『名前 Rowsは宣言されていません』と言ったエラーが表示される為、

       xlsheet.Rows("8:8").Select

    とコーディングしようと思いましたが、「Select」という候補が出てきません。

    そこで、

       xlrange1 = xlsheet.Rows("8:8")

          xlrange1.Delete()

    とコーディングしましたが、削除されません。

    なお、本当にやりたいことは次のとおりです。

       ある列(たとえばA列)を縦方向(1行目から順次n行目まで)に走査し、

       セルの中身が空の場合は、その行を削除する。

    どのようにやったら良いでしょうか?ご教示願います。

    使用環境はwindowsXP、Office2010、VisualBasic2005Expressです。

    2012年3月29日 3:54

回答

  • とりあえずいくつか。

    2005 から VB は 「.NET」が付かなくなりました。

    Rows は Application オブジェクトにあります。Excel のマクロでも Rows の前に「 Application. 」と書いても動作すると思います。

    Rows(...)の戻り値は Object 型なのでキャストする必要があります。

    • 回答としてマーク 山本春海 2012年4月17日 8:06
    2012年3月29日 6:20
  • COMオブジェクトの扱いは面倒です。参照カウントを正しくデクリメントしないとExcelのプロセスが残ってしまうのでご注意ください。

    C# - COM オブジェクトの参照カウントを解放する

    一案ですが、Excelファイルを扱う処理はすべてExcelマクロで記述し、.NETアプリケーションからそのマクロを呼び出す実装をおすすめします。この方法だと参照するCOMオブジェクトが最小限で済みます。

    以下マクロを呼び出すサンプルです。C#のソースをVBに書き直したのでテストはしていません。参考程度にとどめてください。

    Imports System
    Imports System.Collections.Generic
    Imports System.Runtime.InteropServices
    Imports Microsoft.Office.Interop.Excel
    
    Public Class MacroExecutor
    	Public Sub Execute(ByVal filePath As String, ByVal macroName As String)
    		Dim application As Application = Nothing
    		Dim workbooks As Workbooks = Nothing
    		Dim workbook As Workbook = Nothing
    
    		Try
    			application = New ApplicationClass
    			workbooks = application.Workbooks
    			workbook = workbooks.Open(filePath)
    			application.Run(macroName)
    		Finally
    			If workbook IsNot Nothing Then
    				Try
    					workbook.Close(True)
    				Catch
    				End Try
    			End If
    
    			If application IsNot Nothing Then
    				Try
    					application.Quit()
    				Catch
    				End Try
    			End If
    
    			ReleaseComObjects(workbook, workbooks, application)
    		End Try
    
    	End Sub
    
    	Private Sub ReleaseComObjects(ByVal ParamArray objects As Object())
    		Try
    			For i As Integer = 0 To objects.Length
    				If objects(i) Is Nothing Then
    					Continue For
    				End If
    
    				If Marshal.IsComObject(objects(i)) = False Then
    					Continue For
    				End If
    
    				Marshal.ReleaseComObject(objects(i))
    			Next
    		Catch
    		End Try
    	End Sub
    End Class
    


    Blog:プログラマーな日々 http://d.hatena.ne.jp/JHashimoto/

    • 回答としてマーク 山本春海 2012年4月17日 8:06
    2012年3月29日 8:30
  • やっぱり無暗にMarshal.ReleaseComObject()を呼ぶ(ことを他人に無暗に教える)のはどうかと思います。ランタイム呼び出し可能ラッパーには

    各 RCW は、RCW でラップした COM オブジェクトのインターフェイス ポインターのキャッシュを保持し、RCW が不要になった時点で COM オブジェクトの参照を解放します。

    とありますし、他にも.NET アプリケーションのパフォーマンスとスケーラビリティの向上には

    ReleaseComObject を呼び出せるのは、それが不可避な場合だけです。
    You should only call ReleaseComObject when you absolutely have to.

    なんて記述もあります。

    • 回答としてマーク 山本春海 2012年4月17日 8:06
    2012年3月30日 0:33

すべての返信

  • とりあえずいくつか。

    2005 から VB は 「.NET」が付かなくなりました。

    Rows は Application オブジェクトにあります。Excel のマクロでも Rows の前に「 Application. 」と書いても動作すると思います。

    Rows(...)の戻り値は Object 型なのでキャストする必要があります。

    • 回答としてマーク 山本春海 2012年4月17日 8:06
    2012年3月29日 6:20
  • COMオブジェクトの扱いは面倒です。参照カウントを正しくデクリメントしないとExcelのプロセスが残ってしまうのでご注意ください。

    C# - COM オブジェクトの参照カウントを解放する

    一案ですが、Excelファイルを扱う処理はすべてExcelマクロで記述し、.NETアプリケーションからそのマクロを呼び出す実装をおすすめします。この方法だと参照するCOMオブジェクトが最小限で済みます。

    以下マクロを呼び出すサンプルです。C#のソースをVBに書き直したのでテストはしていません。参考程度にとどめてください。

    Imports System
    Imports System.Collections.Generic
    Imports System.Runtime.InteropServices
    Imports Microsoft.Office.Interop.Excel
    
    Public Class MacroExecutor
    	Public Sub Execute(ByVal filePath As String, ByVal macroName As String)
    		Dim application As Application = Nothing
    		Dim workbooks As Workbooks = Nothing
    		Dim workbook As Workbook = Nothing
    
    		Try
    			application = New ApplicationClass
    			workbooks = application.Workbooks
    			workbook = workbooks.Open(filePath)
    			application.Run(macroName)
    		Finally
    			If workbook IsNot Nothing Then
    				Try
    					workbook.Close(True)
    				Catch
    				End Try
    			End If
    
    			If application IsNot Nothing Then
    				Try
    					application.Quit()
    				Catch
    				End Try
    			End If
    
    			ReleaseComObjects(workbook, workbooks, application)
    		End Try
    
    	End Sub
    
    	Private Sub ReleaseComObjects(ByVal ParamArray objects As Object())
    		Try
    			For i As Integer = 0 To objects.Length
    				If objects(i) Is Nothing Then
    					Continue For
    				End If
    
    				If Marshal.IsComObject(objects(i)) = False Then
    					Continue For
    				End If
    
    				Marshal.ReleaseComObject(objects(i))
    			Next
    		Catch
    		End Try
    	End Sub
    End Class
    


    Blog:プログラマーな日々 http://d.hatena.ne.jp/JHashimoto/

    • 回答としてマーク 山本春海 2012年4月17日 8:06
    2012年3月29日 8:30
  • やっぱり無暗にMarshal.ReleaseComObject()を呼ぶ(ことを他人に無暗に教える)のはどうかと思います。ランタイム呼び出し可能ラッパーには

    各 RCW は、RCW でラップした COM オブジェクトのインターフェイス ポインターのキャッシュを保持し、RCW が不要になった時点で COM オブジェクトの参照を解放します。

    とありますし、他にも.NET アプリケーションのパフォーマンスとスケーラビリティの向上には

    ReleaseComObject を呼び出せるのは、それが不可避な場合だけです。
    You should only call ReleaseComObject when you absolutely have to.

    なんて記述もあります。

    • 回答としてマーク 山本春海 2012年4月17日 8:06
    2012年3月30日 0:33
  • 佐祐理さん、ご指摘ありがとうございます。資料読ませてもらいます。

    Blog:プログラマーな日々 http://d.hatena.ne.jp/JHashimoto/

    2012年3月30日 5:18
  • こんにちは、tarahina さん。
     
    MSDN フォーラムのご利用ありがとうございます。オペレーターの山本です。
    しばらく経ちましたが、みなさんからのアドバイスは確認されたでしょうか。

    みなさんから参考になるアドバイスをいただいているようでしたので、勝手ながら私のほうで一旦回答としてマークさせていただきました。
    回答くださったみなさん、アドバイスありがとうございます。
     
    いただいた情報の中で、解決に役立った投稿や、参考になる情報など有効な情報には回答としてマークすることをお願いしています。
    今後、同じ問題でこのスレッドを参照される方にも、有効な情報を活用いただけるかと思いますので、ご協力よろしくお願いいたします。
    _____________________
    日本マイクロソフト株式会社 フォーラム オペレーター 山本 春海

    2012年4月17日 8:06