SSブログ

VB.NET でExcelを利用する際の注意点とExcelの挙動確認 [プログラミング]

VB.NETでExcelを利用する際に注意すべき点とそれを裏付ける挙動確認のためのコード例を紹介しよう。

VB.NETで作成したアプリケーションからExcelのインスタンスを作成して利用する場合、注意しなければいけないのはアプリケーションを実行中にユーザが既存のExcelブックを開いて何らかの作業を行う可能性だ。
なぜそれを気にしなければならないかというと、エクスプローラからExcelブックをダブルクリックして開いたりスタートメニューの最近使った項目からExcelブックを選択した際に、既存のExcelインスタンスが存在するとWindowsはそのインスタンスに対してExcelブックを開くからだ。
つまり、アプリケーションがExcelのインスタンスを作成して作業をしている最中にユーザがExcelブックを開くと、アプリケーションの作成したExcelインスタンスにそのブックが開くことになり、コードの記述内容によってはアプリケーションのExcelに対する操作をユーザに阻害されかねないと言うことだ。

そこで考えたのが、アプリケーションでExcelブックの参照や編集を行う際には、ユーザがExcelブックを操作するためのインスタンスとアプリケーションがExcelブックを操作するためのインスタンスを用意するというものだ。
ユーザがExcelブックを開いたときに利用されるExcelインスタンスが先頭のインスタンスであるなら、アプリケーションはそのインスタンスは利用せず別のExcelインスタンスを起動してそちらを利用すればアプリケーションのExcel操作をユーザに阻害される心配はなくなる。

以下の例はその考え方が正しいことを立証すると共にアプリケーション実行中にExcelブックを開いたときの挙動を確認するものだ。

簡単にコードを説明しよう。

・コンソールウインドウのサイズと表示順の設定
この例ではユーザに確認作業の指示を促すため、コンソールウインドウが常に前面に表示されるようにしている。また、確認作業の邪魔にならない程度にウインドウサイズを小さくしている。
1."GetConsoleWindow"APIを利用してコンソールウインドウのハンドルを取得する。
2.コンソールウインドウのバッファおよびウインドウサイズを設定する。
3."GetWindowRect"APIを利用してコンソールウインドウのウインドウサイズを取得する。
4."SetWindowPos"APIを利用してコンソールウインドウが常に前面に表示されるよう設定する。

・Excelインスタンスの起動
アプリケーションが実行されると二つのExcelインスタンスを起動する。一つ目のインスタンスは非表示の状態で起動し二つ目のインスタンスは表示した状態で起動する。これはExcelのインスタンスが非表示であってもユーザの開いたブックが先頭のインスタンスに開かれることを実証するためだ。
一つ目二つ目共に以下の要領でインスタンスの起動と新規ブックの作成を行っている。
1.Excelのインスタンスを起動する。
2.起動したインスタンスに新規ブックを作成する。
3.作成したブックの"Sheet1"の名称を変更し、その他のシートは削除する。
4.名称を変更した"Sheet1"の"A1"セルに「何番目のインスタンスにアプリケーションが作成したブック」なのかがわかる文言を編集する。
5.作成したブックのSavedプロパティにTrueを設定し、Excelを閉じる際にブックの保存を促されないようにする。

・Excelの挙動確認(その1)
アプリケーションが起動したExcelインスタンスのブックに対して何も操作をしていないときにユーザがExcelブックを開いたときの挙動を確認する。ユーザが開いたExcelブックがアプリケーションの起動した先頭のExcelインスタンスに開かれていることを確認し、ユーザがそのExcelを閉じた後に再度Excelブックを開いてもやはり先頭のExcelインスタンスにブックが開かれることを確認する。
1.コンソールウインドウにメッセージを表示しユーザにブックを開くことを促した後、5秒間待機する。
2.一つ目と二つ目のExcelインスタンスの"Workbooks"オブジェクトにアプリケーションが作成したブック以外のブックが開かれているかを確認し、存在した場合はそのブック名をコンソールウインドウに表示する。
3.ユーザが開いたブックが存在する場合、そのブックが開かれているExcelインスタンスが先頭のインスタンスであることの確認、確認後にそのExcelを閉じることをユーザに促す。
4.再度、上記1、2の処理を行う。
5.ユーザが開いたブックが存在する場合、そのブックが開かれているExcelインスタンスにアプリケーションの作成したブックが存在しないことの確認、確認後にユーザの開いたブックのみを閉じることをユーザに促す。

・Excelの挙動確認(その2)
アプリケーションが起動したExcelインスタンスのブックに対して編集操作をしているときにユーザがExcelブックを開いたときの挙動を確認する。ユーザが開いたExcelブックがアプリケーションの起動した先頭のExcelインスタンスに開かれていることおよびアプリケーションが作成したブックを編集中であることを確認し、ユーザがそのExcelを閉じた後に再度Excelブックを開いてもやはり先頭のExcelインスタンスにブックが開かれることおよびアプリケーションの編集操作が前の続きになっていないことを確認する。
1.Excelを編集するためのスレッドを起動する。
2.コンソールウインドウにメッセージを表示しユーザにブックを開くことを促した後、5秒間待機する。
3.一つ目と二つ目のExcelインスタンスの"Workbooks"オブジェクトにアプリケーションが作成したブック以外のブックが開かれているかを確認し、存在した場合はそのブック名をコンソールウインドウに表示する。
4.ユーザが開いたブックが存在する場合、そのブックが開かれているExcelインスタンスが先頭のインスタンスであることおよびアプリケーションの作成したブックが編集中であることの確認、確認後にそのExcelを閉じることをユーザに促す。
5.再度、上記2、3の処理を行う。
6.ユーザが開いたブックが存在する場合、そのブックが開かれているExcelインスタンスにアプリケーションの作成したブックが存在するが編集処理が先ほどの継続となっていないことの確認をユーザに促す。

・Excel編集スレッド
「Excelの挙動確認(その2)」の際にアプリケーションの作成したブックに別スレッドから編集を行う。編集処理中にブックが閉じられた場合は再度ブックを作成して編集を行う。処理は「Excelの挙動確認(その2)」が終了するまで繰り返す。
1.先頭のExcelインスタンスに作成したブックのシートのインスタンスを生成する。
2."A2"セルに「シート編集[n]回目」の文言を編集し0.5秒間待機する。(基本的にこの処理を繰り返す。)
3.COMエラーが発生した場合、先頭のExcelインスタンスにブックを再度新規作成(「Excelインスタンスの起動」の2~4の処理を実施)し自処理を回帰呼び出しして上記1、2の処理を行う。


コードの説明を読んで大まかに処理の流れは理解できただろうか。もう少し説明をしよう。

1.コードを実行するとコンソールウインドウが表示されるので、そこに表示される指示に従って操作をしていただきたい。

2.アプリケーションが二つのExcelインスタンスを起動し終えると「Excelブックを開く」指示が出るのでPC内にある既存のExcelブックを開いて欲しい。
※この後何度も「Excelブックを開く」指示があるので、その都度違うブックを開いても構わないし同じブックを何度も開いても構わない。アプリケーションを実行する前にエクスプローラを予め起動しておき利用するExcelブックが保存されたフォルダを表示しておくと良いだろう。

3.「Excelの挙動確認(その1)」では開いたExcelブックが先頭のExcelインスタンスに開かれることを実証する。(この時点ではアプリケーションは作成したブックに対して何も操作は行っていない。)
最初の指示で開いたブックが「Excel(1)」に開かれたことがコンソールウインドウに表示されるので確認していただきたい。その後、指示に従ってブックの開かれているExcelで「ウインドウの切り替え(Ctrl+Tab)」を行うとアプリケーションの作成したブックが表示されるので、"A1"セルに編集された内容でもそれが「Excel(1)」であることが確認できるだろう。もし念入りに確認したいのであれば"Alt+Tab"キーを押して、もう一つ起動されているExcelには「Excel(2)」に作成された旨が編集されたブックがあることを確認していただきたい。

※お気づきだと思うが、「Excel(1)」はアプリケーションが起動した際には「非表示」であったがユーザが既存のExcelブックを開いた際に「表示」されている。つまりこの時点でExcelインスタンスの表示/非表示にかかわらず先頭のExcelインスタンスが利用されるということが証明された。

4.開いたExcelブックが先頭のExcelインスタンスに開かれたことが確認できたらそのExcelを閉じるよう指示されるので「Excel(1)」の「×」ボタンをクリックしてExcelを閉じていただきたい。すると再度「Excelブックを開く」指示が出るので既存のExcelブックを開いて欲しい。
ここでもコンソールウインドウに開いたブックが「Excel(1)」に開かれたことが表示される。そして先ほどと同じように指示に従ってブックの開かれているExcelで「ウインドウの切り替え(Ctrl+Tab)」を行っても今度はアプリケーションの作成したブックは存在しない。何故なら先ほどExcelを閉じた際にブックを閉じてしまったからだ。(先ほどExcelを閉じた際にアプリケーションの作成したブックを保存するか否かの確認ダイアログが表示されなかったのは、アプリケーションの作成したブックはSavedプロパティをTrueに設定しているため既に保存が完了しているとExcelが認識したからだ。)
それを確認できたら指示に従って「開いたブック」だけを閉じていただきたい。何もブックの開かれていないExcelが画面に残るはずだ。

※気付いただろうか。先ほど指示に従って「Excel(1)」の「×」ボタンをクリックしてExcelを閉じたはずなのに既存のブックがまた「Excel(1)」のインスタンスに開かれていることを。ユーザ操作によりExcelブックを開いて起動したExcelインスタンスはExcelを閉じた時点で破棄されるのだが、アプリケーションが起動したExcelインスタンスはユーザがExcelを閉じても破棄されないのだ。何故ならExcelのインスタンスを起動したアプリケーションがそのインスタンスを破棄していないためだ。だからユーザが再度Excelブックを開くと先頭インスタンスである「Excel(1)」にブックが開かれることになる。但し、Excelのインスタンスは残っているがExcelを閉じる操作をしているためそこに開かれていたアプリケーションの作成したブックは閉じられてしまう。

5.続いて「Excelの挙動確認(その2)」に進む。ここでは「その1」とは異なりアプリケーションが起動した「Excel(1)」のインスタンスに開いたブックを編集中にユーザが既存のExcelブックを開いたり、Excelを閉じたらどうなるのかを確認する。
指示に従って既存のExcelブックを開いて欲しい。この時点でアプリケーションは「Excel編集スレッド」を起動してアプリケーションの作成したブックの編集を既に始めている。

6.先ほどと同様にコンソールウインドウには開いたブックが「Excel(1)」に開かれたことが表示されているはずだ。再度「ウインドウの切り替え(Ctrl+Tab)」でアプリケーションの作成したブックが存在するかを確認していただきたい。すると今度はアプリケーションの作成したブックの"A2"セルに「シート編集[n]回目」の文言が編集され"[n]"の部分が頻繁に書き換わっているのが確認できる。そう、現在このブックはアプリケーションが編集している最中なのだ。それが確認できたら指示に従って再度Excelを閉じてからもう一度Excelブックを開いていただくのだが、その前にアプリケーションが編集している文言の「[n]回目」の数字を覚えておいて欲しい。

7.またまた開いたブックは「Excel(1)」に開かれたことがコンソールウインドウに表示されるがそれは想定内だろう。そして指示に従って「ウインドウの切り替え(Ctrl+Tab)」を行うと今度はアプリケーションの作成したブックが存在し先ほどと同様に編集中のはずだ。しかし先ほどと違うのは編集中の文言が覚えておいた数字より小さくなっていることだ。(万一数字が大きい場合は6でExcelを閉じてからアプリケーションの編集内容を確認するまでをゆっくり操作していたからだろう…。)
これは何故か…答えは簡単だ。「Excel編集スレッド」には「COMエラー発生時」の処理が記述されており、エラーが発生した際には「Excel(1)」のインスタンスにブックを新規作成してから自処理を呼び出すこととしているため、ユーザ操作でExcelが閉じられたことにより消失した編集対象のブックを再作成して編集を再開しているのだ。よく考えてみるとこのエラー処理は既に前述の4→6の間でも発生しており、4の時点では存在していなかったブックが6の時点ではブックが存在し編集を行っている。
と言うことで閉じられたはずのブックが再作成された理由は理解できたと思うし、編集中の文言の数字が先ほどより小さい理由も編集処理が再呼び出しされたことによりカウンターがリセットされたからだと判ったと思う。


このアプリケーションを実行して確認できたことは、
1.ユーザ操作で開かれたExcelブックは先頭のExcelインスタンスに必ず開く。
2.アプリケーションが作成したExcelインスタンスはユーザ操作でExcelが閉じられても破棄されない。
3.アプリケーションがブックを編集中のExcelインスタンスでもユーザが既存ブックを開くと同一インスタンスにブックが開かれる。
4.アプリケーションが編集中のブックがあってもユーザ操作でExcelを閉じることができるためアプリケーションのExcel操作が阻害される。
5.アプリケーションが二つのExcelインスタンスを起動した場合、二つ目のインスタンスにはユーザ操作の影響は及ばない。
と言うことだ。
※今回は確認がしやすいようにアプリケーションがブックに対して編集操作を行った後、SavedプロパティにTrueを設定してブックを閉じる際に保存を促すダイアログが表示されないようにしているが、この設定を行わない場合はダイアログが表示されるためアプリケーションの編集操作が阻害されることに変わりはない。
※また今回は確認のため二つ目のExcelインスタンスを表示した状態で起動したが、表示されたExcelに対して既存のExcelブックをドラッグ&ドロップで開くことは可能なので、本来は非表示にしておくべきである。


以上の確認結果から、アプリケーションでExcel操作を行う場合は二つのExcelインスタンスを非表示で起動し、一つ目は予期せぬユーザ操作用に、二つ目はアプリケーションからの操作用にと使い分けるのが安全だと言うことだ。


以下の例を実行するには、新規の「コンソールアプリケーション」を作成し、"Microsoft Excel xx.x Object Library"(xx.xはお使いのExcelのバージョンによって異なる)の参照を追加した後、コードを"Module1"に貼り付けて実行すれば良い。
尚、コンソールウインドウの指示以外の操作により発生するエラーについては考慮していないのであしからず…。


------------------------------------------------------------

Imports Microsoft.Office.Interop
Imports System.Runtime.InteropServices

Module Module1

    '非同期処理のデリゲート宣言
    Delegate Function EditExcelDelegate() As Boolean

    '定数宣言
    Private Const HWND_TOPMOST _
        As Integer = -1 '最前面にする

    '構造体宣言
    Private Structure RECT
        Dim Left As Integer
        Dim Top As Integer
        Dim Right As Integer
        Dim Bottom As Integer
    End Structure

    '変数宣言
    Private gobjExcel1, gobjExcel2 _
        As Excel.Application
    Private gblnCEBQuit As Boolean
    Private gstrBookName(1) As String
    '非同期処理デリゲートインスタンス
    Private gobjEEDelegate As EditExcelDelegate
    '非同期処理戻り値
    Private gobjEEReturn As IAsyncResult
    '非同期処理実行中判定変数
    Private gblnEEExec As Boolean
    'Excel編集実行判定変数
    Private gblnEEStart As Boolean

    'WindowsAPI宣言
    Private Declare Function GetConsoleWindow Lib _
        "kernel32" () As Integer
    Private Declare Function GetWindowRect Lib _
        "user32.dll" (ByVal hwnd As Integer, _
                      ByRef lpRect As RECT) As Integer
    Private Declare Function SetWindowPos Lib "user32" _
        (ByVal hwnd As Integer, _
         ByVal hWndInsertAfter As Integer, _
         ByVal x As Integer, ByVal y As Integer, _
         ByVal cx As Integer, ByVal cy As Integer, _
         ByVal wFlags As Integer) As Integer

    Sub Main()

        Try

            Dim intHwnd As Integer = GetConsoleWindow
            Console.SetBufferSize(80, 50)
            Console.SetWindowSize(50, 10)
            Dim typRect As RECT = New RECT
            Call GetWindowRect(intHwnd, typRect)
            Call SetWindowPos( _
                intHwnd, HWND_TOPMOST, _
                typRect.Left, typRect.Top, _
                typRect.Right - typRect.Left, 250, 0)

            'Excelのインスタンスを生成して新規ブックを作成①
            Console.WriteLine( _
                "一つ目のExcelを非表示で起動します...")
            gobjExcel1 = New Excel.Application
            gobjExcel1.Visible = False
            If fncCreateExcelBook(gobjExcel1, 1) = False _
                Then
                MsgBox( _
                    "一つ目のExcelの起動に失敗しました。" & _
                       ControlChars.CrLf & _
                       "アプリケーションを終了します。", _
                       MsgBoxStyle.Exclamation)
                Exit Try
            End If
            Console.WriteLine( _
                "Excelの起動に成功しました...")

            'Excelのインスタンスを生成して新規ブックを作成②
            Console.WriteLine( _
                "二つ目のExcelを表示して起動します...")
            gobjExcel2 = New Excel.Application
            gobjExcel2.Visible = True
            If fncCreateExcelBook(gobjExcel2, 2) = False _
                Then
                MsgBox( _
                    "二つ目のExcelの起動に失敗しました。" & _
                       ControlChars.CrLf & _
                       "アプリケーションを終了します。", _
                       MsgBoxStyle.Exclamation)
                Exit Try
            End If
            Console.WriteLine( _
                "Excelの起動に成功しました...")

            'Excelの挙動確認①
            'アプリケーション待機中
            Console.WriteLine("")
            Console.WriteLine( _
                "Excelに対して何もしていないときの挙動" & _
                "を確認します...")
            If fncConfirmExcelBehavior(False) = False Then
                MsgBox( _
                    "Excelの挙動確認に失敗しました。" & _
                    ControlChars.CrLf & _
                    "アプリケーションを終了します。", _
                    MsgBoxStyle.Exclamation)
                Exit Try
            End If

            'Excelの挙動確認②
            'アプリケーション作業中
            Console.WriteLine("")
            Console.WriteLine( _
                "Excelに対してシート編集中のときの挙動" & _
                "を確認します...")
            If fncEditExcelStart() = False Then
                MsgBox( _
                    "Excel編集処理の起動に失敗しました。" & _
                    ControlChars.CrLf & _
                    "アプリケーションを終了します。", _
                    MsgBoxStyle.Exclamation)
                Exit Try
            End If
            If fncConfirmExcelBehavior(True) = False Then
                MsgBox( _
                    "Excelの挙動確認に失敗しました。" & _
                    ControlChars.CrLf & _
                    "アプリケーションを終了します。", _
                    MsgBoxStyle.Exclamation)
                Exit Try
            End If
            Console.WriteLine( _
                "Excelの挙動確認を終了しました...")
            Console.WriteLine( _
                "何かキーを押してください...")
            Console.ReadKey(True)

        Catch comex As COMException
            MsgBox(comex.Message, MsgBoxStyle.Exclamation)

        Catch ex As Exception
            MsgBox(ex.Message, MsgBoxStyle.Exclamation)

        Finally
            If Not IsNothing(gobjExcel1) Then
                For Each objBk As Excel.Workbook _
                                    In gobjExcel1.Workbooks
                    Call subBookClose(objBk, False)
                Next
                gobjExcel1.Quit()
                Call subMRComObject(CType(gobjExcel1, _
                                    Object))
                gobjExcel1 = Nothing
            End If
            If Not IsNothing(gobjExcel2) Then
                For Each objBk As Excel.Workbook _
                                    In gobjExcel2.Workbooks
                    Call subBookClose(objBk, False)
                Next
                gobjExcel2.Quit()
                Call subMRComObject(CType(gobjExcel2, _
                                    Object))
                gobjExcel2 = Nothing
            End If

        End Try

    End Sub

    Private Function fncConfirmExcelBehavior( _
                ByVal pEdit As Boolean) As Boolean
        '*************************
        'Excelの挙動を確認する
        '
        '   pEdit   :  Excel編集有無判定
        '
        '*************************

        Dim blnReturn As Boolean

        Try
            'Excelの挙動確認完了判定を初期化
            gblnCEBQuit = False
            Dim intCheck As Integer = 0
            'Excelの挙動確認が完了するまで繰り返し
            Do While gblnCEBQuit = False
                If pEdit = True AndAlso _
                    gblnEEStart = False Then
                    'Excel編集実行判定変数を設定
                    gblnEEStart = True
                    Do While gobjExcel1.Workbooks.Count = 0
                        Threading.Thread.Sleep(500)
                    Loop
                End If
                Dim intCnt1 As Integer = _
                    gobjExcel1.Workbooks.Count
                Dim intCnt2 As Integer = _
                    gobjExcel2.Workbooks.Count
                Console.WriteLine( _
                    "何かExcelブックを開いてください...")
                Threading.Thread.Sleep(5000)
                Dim intNo As Integer = 1
                For Each objBk As Excel.Workbook _
                                In gobjExcel1.Workbooks
                    If objBk.Name <> gstrBookName(0) Then
                        Console.WriteLine("「" & _
                            objBk.Name & "」が" & _
                            "アプリケーションの起動した" & _
                            "Excel(" & intNo.ToString & _
                            ")に開かれました。")
                    End If
                    Call subMRComObject(CType(objBk, _
                                        Object))
                Next
                intNo += 1
                For Each objBk As Excel.Workbook _
                                In gobjExcel2.Workbooks
                    If objBk.Name <> gstrBookName(1) Then
                        Console.WriteLine("「" & _
                            objBk.Name & "」が" & _
                            "アプリケーションの起動した" & _
                            "Excel(" & intNo.ToString & _
                            ")に開かれました。")
                    End If
                    Call subMRComObject(CType(objBk, _
                                        Object))
                Next
                If intCnt1 <> gobjExcel1.Workbooks.Count _
                    OrElse _
                    intCnt2 <> gobjExcel2.Workbooks.Count _
                    Then
                    Console.WriteLine("")
                    If intCheck = 0 Then
                        '一回目の挙動確認
                        Console.WriteLine( _
                            "ブックが開かれているExcelで" & _
                            "Ctrl+Tabを使って")
                        If pEdit = False Then
                            Console.WriteLine( _
                            "アプリケーションの作成した" & _
                            "ブックがあること")
                            Console.WriteLine( _
                            "を確認してください...")
                        Else
                            Console.WriteLine( _
                            "アプリケーションの作成した" & _
                            "ブックが編集中で")
                            Console.WriteLine( _
                            "あることを" & _
                            "確認してください...")
                        End If
                        Console.WriteLine( _
                            "何かキーを押してください...")
                        Console.ReadKey(True)
                        Console.WriteLine( _
                            "ブックが開かれているExcel" & _
                            "を閉じてください...")
                        Console.WriteLine( _
                            "何かキーを押してください...")
                        Console.ReadKey(True)
                        intCheck += 1
                    ElseIf pEdit = False Then
                        '二回目の挙動確認(編集なし)
                        Console.WriteLine( _
                            "ブックが開かれているExcelで" & _
                            "Ctrl+Tabを使って")
                        Console.WriteLine( _
                            "アプリケーションの作成した" & _
                            "ブックがないこと")
                        Console.WriteLine( _
                            "を確認してください...")
                        Console.WriteLine( _
                            "何かキーを押してください...")
                        Console.ReadKey(True)
                        Console.WriteLine( _
                            "開いたブックだけ" & _
                            "を閉じてください...")
                        Console.WriteLine( _
                            "何かキーを押してください...")
                        Console.ReadKey(True)
                        'Excelの挙動確認完了判定を設定
                        gblnCEBQuit = True
                    Else
                        '二回目の挙動確認(編集あり)
                        Console.WriteLine( _
                            "ブックが開かれているExcelで" & _
                            "Ctrl+Tabを使って")
                        Console.WriteLine( _
                            "アプリケーションの作成した" & _
                            "ブックの編集が")
                        Console.WriteLine( _
                            "先ほどの続きではないことを" & _
                            "確認してください...")
                        Console.WriteLine( _
                            "何かキーを押してください...")
                        Console.ReadKey(True)
                        'Excel編集実行判定変数を初期化
                        gblnEEStart = False
                        'Excelの挙動確認完了判定を設定
                        gblnCEBQuit = True
                    End If
                End If
            Loop
            blnReturn = True

        Catch ex As Exception
            MsgBox(ex.Message, MsgBoxStyle.Exclamation)
            blnReturn = False

        End Try

        Return blnReturn

    End Function

    Private Function fncCreateExcelBook( _
                ByVal pExcel As Excel.Application, _
                ByVal pNo As Integer) As Boolean
        '*************************
        'Excelのインスタンスを生成してブックを新規作成
        '
        '   pExcel  :  ブックを作成する対象のExcelのインスタンス
        '   pNo     :  何番目のExcelかを示す値
        '
        '*************************

        Dim blnReturn As Boolean
        Dim objBooks As Excel.Workbooks = Nothing
        Dim objBook As Excel.Workbook = Nothing

        Try
            'Excelブックを新規作成
            objBooks = pExcel.Workbooks
            objBook = objBooks.Add
            gstrBookName(CInt(pNo - 1)) = objBook.Name

            'シートの名称変更と削除
            Dim strName As String = ""
            For Each objSh As Excel.Worksheet _
                                In objBook.Worksheets
                Select Case objSh.Name
                    Case "Sheet1"
                        strName = "Excel" & pNo.ToString & _
                            "_" & objSh.Name
                        objSh.Name = strName
                    Case Else : objSh.Delete()
                End Select
                Call subMRComObject(CType(objSh, Object))
            Next

            'シートの編集
            Dim objSheet As Excel.Worksheet = _
                DirectCast(objBook.Worksheets(strName),  _
                    Excel.Worksheet)
            Dim objCells As Excel.Range = _
                DirectCast(objSheet.Cells, Excel.Range)
            Dim objCell As Excel.Range = _
                DirectCast(objCells.Item(1, 1), Excel.Range)
            objCell.Value = _
                "このブックはVBアプリケーションが" & _
                "起動したExcel(" & pNo.ToString & _
                ")に作成されたものです。"
            objBook.Saved = True

            'Cell、Cells、Sheetオブジェクトの破棄
            Call subMRComObject(CType(objCell, Object))
            objCell = Nothing
            Call subMRComObject(CType(objCells, Object))
            objCells = Nothing
            Call subMRComObject(CType(objSheet, Object))
            objSheet = Nothing

            blnReturn = True

        Catch comex As COMException
            MsgBox(comex.Message, MsgBoxStyle.Exclamation)
            blnReturn = False

        Catch ex As Exception
            MsgBox(ex.Message, MsgBoxStyle.Exclamation)
            blnReturn = False

        Finally
            If blnReturn = False Then
                'エラーが発生した場合
                If Not IsNothing(objBook) Then
                    'ブックのインスタンスが生成されている場合はブック保存せずにを閉じる
                    Call subBookClose(objBook, False)
                End If
            End If
            'Bookオブジェクトを破棄
            Call subMRComObject(CType(objBook, Object))
            objBook = Nothing
            'Booksオブジェクトを破棄
            Call subMRComObject(CType(objBooks, Object))
            objBooks = Nothing

        End Try

        Return blnReturn

    End Function

    Private Function fncEditExcelStart() As Boolean
        '*************************
        'Excel編集処理を起動
        '*************************

        Dim blnReturn As Boolean

        Try
            'Excel編集処理実行中判定変数を設定
            gblnEEExec = True
            'Excel編集処理のデリゲートインスタンスを生成
            gobjEEDelegate = New EditExcelDelegate( _
                AddressOf fncEditExcelMain)
            'Excel編集処理の非同期実行を開始
            gobjEEReturn = gobjEEDelegate.BeginInvoke( _
                New AsyncCallback( _
                    AddressOf subEditExcelCallback), _
                Nothing)
            blnReturn = True

        Catch ex As Exception
            MsgBox(ex.Message, MsgBoxStyle.Exclamation)
            'Excel編集処理実行中判定変数を設定
            gblnEEExec = False
            blnReturn = False

        End Try

        Return blnReturn

    End Function

    Private Function fncEditExcelMain() As Boolean
        '*************************
        'Excel編集メイン処理
        '*************************

        Dim blnReturn As Boolean

        Try
            Do
                If gblnEEStart = True Then
                    'Excel編集実行判定がTrueの場合
                    Do While gblnEEStart = True
                        'Excel編集実行判定がTrueの間、
                        'Excelへの編集を実行
                        If fncEditExcelSub() = False Then
                            'Excel編集を終了
                            gblnEEStart = False
                            blnReturn = False
                            Exit Try
                        End If
                    Loop
                Else
                    'Excel編集実行判定がFalseの場合
                    Threading.Thread.Sleep(1000)
                End If
            Loop
            blnReturn = True

        Catch ex As Exception
            'エラーが発生した場合
            MsgBox(ex.Message, MsgBoxStyle.Exclamation)
            blnReturn = False

        End Try

        Return blnReturn

    End Function

    Private Function fncEditExcelSub() As Boolean
        '*************************
        'Excel編集サブ処理
        '*************************

        Dim blnReturn As Boolean
        Dim objBk As Excel.Workbook = Nothing
        Dim objSh As Excel.Worksheet = Nothing
        Dim objUsedRange As Excel.Range = Nothing
        Dim objRows As Excel.Range = Nothing
        Dim objCells As Excel.Range = Nothing
        Dim objCell As Excel.Range = Nothing

        Try
            'Excel1のインスタンスに作成したブックのインスタンスを生成
            objBk = DirectCast(gobjExcel1.Workbooks( _
                    gstrBookName(0)), Excel.Workbook)
            'シートのインスタンスを生成
            objSh = DirectCast(objBk.Worksheets(1),  _
                Excel.Worksheet)
            objCells = DirectCast(objSh.Cells, Excel.Range)
            objUsedRange = DirectCast(objSh.UsedRange,  _
                Excel.Range)
            objRows = DirectCast(objUsedRange.Rows,  _
                Excel.Range)
            Dim intNo As Integer = 0

            Do While gblnEEStart = True
                '編集済の次のセルのインスタンスを生成
                objCell = DirectCast(objCells.Item( _
                        objRows.Count + 1, 1), Excel.Range)
                intNo += 1
                objCell.Value = _
                    "シート編集" & intNo.ToString & "回目"
                objBk.Saved = True
                '使用したCOMオブジェクトの破棄
                Call subMRComObject(CType(objCell, Object))
                objCell = Nothing
                Threading.Thread.Sleep(500)
            Loop
            blnReturn = True

        Catch comex As COMException
            'COMエラーが発生した場合
            'Excel1のインスタンスにブックを再作成
            Call fncCreateExcelBook(gobjExcel1, 1)
            'Excel編集サブ処理を回帰呼び出し
            blnReturn = fncEditExcelSub()

        Catch ex As Exception
            'エラーが発生した場合
            MsgBox(ex.Message, MsgBoxStyle.Exclamation)
            blnReturn = False

        Finally
            '使用したCOMオブジェクトの破棄
            If Not IsNothing(objCell) Then
                Call subMRComObject(CType(objCell, _
                                    Object))
                objCell = Nothing
            End If
            If Not IsNothing(objRows) Then
                Call subMRComObject(CType(objRows, _
                                    Object))
                objRows = Nothing
            End If
            If Not IsNothing(objUsedRange) Then
                Call subMRComObject(CType(objUsedRange, _
                                    Object))
                objUsedRange = Nothing
            End If
            If Not IsNothing(objCells) Then
                Call subMRComObject(CType(objCells, _
                                    Object))
                objCells = Nothing
            End If
            If Not IsNothing(objSh) Then
                Call subMRComObject(CType(objSh, _
                                    Object))
                objSh = Nothing
            End If
            If Not IsNothing(objBk) Then
                Call subMRComObject(CType(objBk, _
                                    Object))
                objBk = Nothing
            End If

        End Try

        Return blnReturn

    End Function

    Private Sub subBookClose( _
                ByVal pBook As Excel.Workbook, _
                ByVal pSave As Boolean)
        '*************************
        'ブックを閉じる
        '
        '   pBook   :  閉じる対象のブックのインスタンス
        '   pSave   :  ブックを保存するか否かを示す値
        '
        '*************************

        Try
            pBook.Close(pSave)

        Catch ex As Exception

        End Try

    End Sub

    Private Sub subEditExcelCallback( _
                                ByVal ar As IAsyncResult)
        '*************************
        'Excel編集処理のコールバック関数
        '
        '   ar      :   非同期処理情報インターフェース
        '
        '*************************

        Try
            Do
                If gobjEEReturn.IsCompleted = True Then
                    'Excel編集処理が完了した場合
                    Dim blnReturn As Boolean = _
                        gobjEEDelegate.EndInvoke( _
                            gobjEEReturn)
                    If blnReturn = False Then
                        '異常終了メッセージを表示
                        MsgBox( _
                            "Excel編集処理で異常を" & _
                            "検出しました。", _
                            MsgBoxStyle.Exclamation)
                    End If
                    'Excel編集処理のデリゲートインスタンスを破棄
                    gobjEEDelegate = Nothing
                    'Excel編集処理の戻り値インスタンスを破棄
                    gobjEEReturn = Nothing
                    'Excel編集処理実行中判定変数を設定
                    gblnEEExec = False
                    Exit Do
                Else
                    'Excel編集処理が実行中の場合
                    Threading.Thread.Sleep(250)
                End If
            Loop

        Catch ex As Exception
            MsgBox(ex.Message, MsgBoxStyle.Exclamation)

        End Try

    End Sub

    Private Sub subMRComObject(ByRef pObject As Object)
        '*************************
        'COMオブジェクトの参照カウントを解放
        '
        '   pObject :  参照を破棄するオブジェクトのインスタンス
        '
        '*************************

        If Not IsNothing(pObject) Then
            Marshal.ReleaseComObject(pObject)
        End If

    End Sub

End Module

------------------------------------------------------------

 


タグ:Excel VB.NET
nice!(0)  コメント(0)  トラックバック(0) 

nice! 0

コメント 0

コメントを書く

お名前:
URL:
コメント:
画像認証:
下の画像に表示されている文字を入力してください。

トラックバック 0

この広告は前回の更新から一定期間経過したブログに表示されています。更新すると自動で解除されます。