vb6でexcelを操作したい。

環境 win xp vb6 pro edition excel 2007 

vb6のフォームにボタンを配置して、クリックすると
excelが開きシートを追加し値を代入する。
もし既にexcelが開いていれば、そのブックにシートを追加し値を代入する。
フォームのボタンが押される毎に上記を実行する。
と言うプログラムを組みました。


以下質問が500文字を超えるのでコメント欄に書きます。

回答の条件
  • 1人5回まで
  • 13歳以上
  • 登録:2011/09/03 11:58:53
  • 終了:2011/09/03 21:38:42

ベストアンサー

id:cx20 No.2

cx20回答回数603ベストアンサー獲得回数1072011/09/03 20:16:44

ポイント60pt

実行時の動作が、型によって異なるとのことですが、型による違いではなく、実行時の、Excel の状態の違いによるものと思われます。

Set app = GetObject(, "Excel.Application")  ' 一番最初に起動した Excel.exe に接続
app.Sheets.Add                              ' ブックが存在しない状態で Sheets にアクセスしようとするとエラー

実行時の Excel(一番最初に起動した Excel.exe)は、ブックが開かれている状態でしょうか?それとも閉じた状態でしょうか?

  • ブックが開かれている状態であれば「ラベル:」の処理を行いますが、
  • ブックが閉じられている状態であれば「app.Sheets」が利用できない為、失敗し、「エラー:」の処理に移動します。

エラーの原因は、Err オブジェクトの内容に記載されていますので、Err オブジェクトをクリアする前に、確認しててください。以下は、エラー内容を確認する為のコード例です。

エラー:
    Debug.Print "Error : [" & Err.Description & "](" & Err.Number & ")"
    Err.Clear
  • 表示例(内容は [表示] - [イミディエイト ウィンドウ]にて確認できます。)
Err : [アプリケーションの定義またはオブジェクト定義のエラーです。](1004)

何故as objectやas Excel.Applicationじゃ駄目なのかが分りません。

オブジェクト型やバリアント型であっても、Excel.Application 型の代入が出来れていれば、オートメーション(Excelの自動化)の動作には影響ないはずです。ですので、ダメではありません。


以下は、バリアント型、オブジェクト型、クラス型の説明です。

Dim app                      ' バリアント型(暗黙的)
Dim app As Object            ' オブジェクト型
Dim app As Variant           ' バリアント型
Dim app As Excel.Application ' Excel.Application クラス型

バリアント型とオブジェクト型は、少し特殊で、異なる型への代入が可能となっています。

  • オブジェクト型 … オブジェクト(クラス)型に限り代入可能
  • バリアント型 … どのような型でも代入可能。数値型、文字列型だけでなく、オブジェクト型も代入可能。
  • クラス型 … 同じクラス型のみ代入可能。

あと、

Dim app

が、グローバル変数(関数の外)として宣言しているようですが、これは意図した記述でしょうか?

意図していないのであれば、ローカル変数(関数内)で宣言した方が、良いかと思います。


グローバル変数の場合、複数回、関数を実行した場合、前の状態(Excel.Application の代入)を保持した状態となっていますので、

2回目以降の処理として、代入する前に、参照の解放(Set app = Nothing)もしくは、

GetObject()/CreateObject() による代入を行わないようにする、と言った対応が必要がなります。

あとWorksheets(1)の(1)の意味はなんでしょう?

VB にてデバッグ実行を行い、[表示] - [変数] にて、オブジェクトの中身を確認してみてください。

Worksheets は、Worksheet のコレクションで、(1) は、コレクションの1つ目の要素を示します。


追加順というわけではなく、表示されているシートの順に対応しているようです。

式                    値             型
--------------------- -------------- ------------------------
[app]
 +-[Workbooks]                       
    +-[Item 1]
       +-[Worksheets]                Sheets/Sheets
          +-[Count]   4              Long
          +-[Item 1]                 Variant/Object/Worksheet
             +-[Name] "Sheet4"
          +-[Item 2]                 Variant/Object/Worksheet
             +-[Name] "Sheet1"
          +-[Item 3]                 Variant/Object/Worksheet
             +-[Name] "Sheet2"
          +-[Item 4]                 Variant/Object/Worksheet
             +-[Name] "Sheet3"
id:Scandium

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


>ブックが開かれている状態でしょうか?

ブックが開かれている状態です。

no1さんの返信でも書きましたが意図しない動きの再現性が変化しているようです。


>Excel.Application 型の代入が出来れていれば、オートメーションの動作には影響ないはずです。

私の考えが根本的に間違っていないと言う事が分りました。ありがとうございます。


>Dim appがグローバル変数(関数の外)として宣言しているようですが、これは意図した記述でしょうか?

いいえ違います。ミスしてました。

Dim appをローカルにするか Set app = Nothingを追加したら、意図した動きをする様になりました。


なんで質問文のような動作をしたのか私の中で説明が付きませんが、オブジェクトの扱い(2週目以降の処理の問題)やexcelの状態等が影響して来ていたのかな?。しかし大まかな動きは理解できて来ました。

ありがとうございました。

2011/09/03 21:37:27

その他の回答(1件)

id:Jupiter2100 No.1

じゅぴたー回答回数444ベストアンサー獲得回数742011/09/03 14:45:30

ポイント40pt

正式には

Dim app as object 

が正解で、Command1_Click サブプログラムの最後に

app.Application.Quit
Set app = Nothing

の2行が抜けています。

Dim app または Dim app as variant にした場合、たまたまシステム内でガベージコレクト(不足していた2行の処理)を行ってくれているのだと思います。


>あとWorksheets(1)の(1)の意味はなんでしょう?

Excelワークシートタブで一番左にあるものが1番目です。

id:Scandium

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

Set app = Nothingにしたら意図した通り動く様になりました。


もう一度Set app = Nothingを付けないで、試してみたら

意図していない動きの再現度が、不定期になって来ました。

どうやら意図していない動きは毎回は起こらないようです。

(今朝も、2日前の朝も同じ意図していない動きをしていたので、毎回起きると勘違いしていた様です。)

No2さんの言うexcelの状態の違いが何か影響を及ぼしているのか、何か別の影響があったのかよく分らなくなって来ましたが、大まかな動きは理解できて来ました。


>ガベージコレクトを行ってくれている

なるほど勉強になります。

2011/09/03 21:37:46
id:cx20 No.2

cx20回答回数603ベストアンサー獲得回数1072011/09/03 20:16:44ここでベストアンサー

ポイント60pt

実行時の動作が、型によって異なるとのことですが、型による違いではなく、実行時の、Excel の状態の違いによるものと思われます。

Set app = GetObject(, "Excel.Application")  ' 一番最初に起動した Excel.exe に接続
app.Sheets.Add                              ' ブックが存在しない状態で Sheets にアクセスしようとするとエラー

実行時の Excel(一番最初に起動した Excel.exe)は、ブックが開かれている状態でしょうか?それとも閉じた状態でしょうか?

  • ブックが開かれている状態であれば「ラベル:」の処理を行いますが、
  • ブックが閉じられている状態であれば「app.Sheets」が利用できない為、失敗し、「エラー:」の処理に移動します。

エラーの原因は、Err オブジェクトの内容に記載されていますので、Err オブジェクトをクリアする前に、確認しててください。以下は、エラー内容を確認する為のコード例です。

エラー:
    Debug.Print "Error : [" & Err.Description & "](" & Err.Number & ")"
    Err.Clear
  • 表示例(内容は [表示] - [イミディエイト ウィンドウ]にて確認できます。)
Err : [アプリケーションの定義またはオブジェクト定義のエラーです。](1004)

何故as objectやas Excel.Applicationじゃ駄目なのかが分りません。

オブジェクト型やバリアント型であっても、Excel.Application 型の代入が出来れていれば、オートメーション(Excelの自動化)の動作には影響ないはずです。ですので、ダメではありません。


以下は、バリアント型、オブジェクト型、クラス型の説明です。

Dim app                      ' バリアント型(暗黙的)
Dim app As Object            ' オブジェクト型
Dim app As Variant           ' バリアント型
Dim app As Excel.Application ' Excel.Application クラス型

バリアント型とオブジェクト型は、少し特殊で、異なる型への代入が可能となっています。

  • オブジェクト型 … オブジェクト(クラス)型に限り代入可能
  • バリアント型 … どのような型でも代入可能。数値型、文字列型だけでなく、オブジェクト型も代入可能。
  • クラス型 … 同じクラス型のみ代入可能。

あと、

Dim app

が、グローバル変数(関数の外)として宣言しているようですが、これは意図した記述でしょうか?

意図していないのであれば、ローカル変数(関数内)で宣言した方が、良いかと思います。


グローバル変数の場合、複数回、関数を実行した場合、前の状態(Excel.Application の代入)を保持した状態となっていますので、

2回目以降の処理として、代入する前に、参照の解放(Set app = Nothing)もしくは、

GetObject()/CreateObject() による代入を行わないようにする、と言った対応が必要がなります。

あとWorksheets(1)の(1)の意味はなんでしょう?

VB にてデバッグ実行を行い、[表示] - [変数] にて、オブジェクトの中身を確認してみてください。

Worksheets は、Worksheet のコレクションで、(1) は、コレクションの1つ目の要素を示します。


追加順というわけではなく、表示されているシートの順に対応しているようです。

式                    値             型
--------------------- -------------- ------------------------
[app]
 +-[Workbooks]                       
    +-[Item 1]
       +-[Worksheets]                Sheets/Sheets
          +-[Count]   4              Long
          +-[Item 1]                 Variant/Object/Worksheet
             +-[Name] "Sheet4"
          +-[Item 2]                 Variant/Object/Worksheet
             +-[Name] "Sheet1"
          +-[Item 3]                 Variant/Object/Worksheet
             +-[Name] "Sheet2"
          +-[Item 4]                 Variant/Object/Worksheet
             +-[Name] "Sheet3"
id:Scandium

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


>ブックが開かれている状態でしょうか?

ブックが開かれている状態です。

no1さんの返信でも書きましたが意図しない動きの再現性が変化しているようです。


>Excel.Application 型の代入が出来れていれば、オートメーションの動作には影響ないはずです。

私の考えが根本的に間違っていないと言う事が分りました。ありがとうございます。


>Dim appがグローバル変数(関数の外)として宣言しているようですが、これは意図した記述でしょうか?

いいえ違います。ミスしてました。

Dim appをローカルにするか Set app = Nothingを追加したら、意図した動きをする様になりました。


なんで質問文のような動作をしたのか私の中で説明が付きませんが、オブジェクトの扱い(2週目以降の処理の問題)やexcelの状態等が影響して来ていたのかな?。しかし大まかな動きは理解できて来ました。

ありがとうございました。

2011/09/03 21:37:27
  • id:Scandium
    (vb6参照設定でexcelを指定してます。)
    Dim app
    Private Sub Command1_Click()
    On Error GoTo エラー
    Set app = GetObject(, "Excel.Application")
    app.Sheets.Add
    GoTo ラベル:
    エラー:
    Err.Clear
    Set app = CreateObject("Excel.Application")
    app.Workbooks.Add 'ワークブックを新規作成
    app.Sheets.Add          'シートを追加
    app.Visible = True 'アプリケーションの表示設定
    ラベル:
    app.Workbooks(1).Worksheets(1).Cells(1, 1) = 20
    End Sub

    Dim appの部分をDim app as object
    にすると、既にexcelが開いている状態でプログラムを実行すると、新しいbookを作ってそこにシートを追加していくようになる。

    Dim app as Excel.Applicationにすると
    プログラムは意図した通りに動くが、一度作られたブックを閉じると、フォームのボタンクリック毎に新しいbookを作る様になる。
    既にexcelが開いている状態でプログラムを実行すると、フォームのボタンをクリック毎に新しいbookを作っていく。

    Dim app 又は Dim app as variant にすると
    意図した通りに動く。

    初めプログラムを作った時はas Excel.Applicationにしてました。
    何故as objectやas Excel.Applicationじゃ駄目なのかが分りません。
    知ってたら教えて下さい

    あとWorksheets(1)の(1)の意味はなんでしょう?
    webで調べたら1番目のシートと書いてありましたが、一番最後に追加したシートが1番目になるのでしょうか?既にデフォルトでsheet1があるのですが、こちらが1番目じゃないのですか?
  • id:cx20
    > ブックが開かれている状態です。
    > no1さんの返信でも書きましたが意図しない動きの再現性が変化しているようです。

    1. Set app = GetObject(, "Excel.Application")
    2. app.Sheets.Add

    「エラー:」に飛ぶケースとしては「1.」もしくは「2.」のどちらかで失敗していることになります。
    Excel が起動していれば「1.」が失敗するケースは、ほとんどないかと思いますが、
    以下のようなエラーケースがあるようです。

    ■ [OFF2003] [PRB] GetObject や GetActiveObject を使用して実行中の Office アプリケーションを検出できない
    http://support.microsoft.com/kb/238610/ja

    Excel は、起動時に、実行中オブジェクト テーブル(ROT:Running Object Table)というテーブルに、自分自身のクラス情報を登録します。
    GetObject() は、実際には、ここに登録があるかどうか?をチェックしています。

    しかし、この登録処理は、実際には、起動時ではなく、フォーカスがアクティブになったときに初めて登録されるようです。
    ですので、場合によっては、GetObject() 自体が失敗するケースがあるようです。

    「2.」のケースについては、接続先の、Excel.exe のブックが閉じられているケースです。
    ブックが閉じられていれば、Sheets オブジェクトにもアクセスできない為、エラーになります。
    (接続可能な Excel.exe は、1つだけですので、タスクマネージャに複数の Excel.exe が存在しないことを確認願います。オートメーションで Visible = True し忘れた場合等で、非表示の Excel.exe が残っている可能性があります。)

    「1.」と「2.」のどちらの原因かは、Err.Description を参照すれば、判断ができるかと思います。
  • id:Scandium
    cx20さんが言われている事が理解出来ました。


    >「1.」もしくは「2.」のどちらかで失敗している
    >この登録処理は、実際には、起動時ではなく、フォーカスがアクティブになったときに初めて登録される


    教えてもらったDebug.Print "Error を使った所、確かに2種類のエラーメッセージが出ます。(ActiveX コンポーネント作成エラー と シート作成エラー)
    意図しない動作の原因は、これだと理解出来ました。
    ありがとうございました。

この質問への反応(ブックマークコメント)

「あの人に答えてほしい」「この質問はあの人が答えられそう」というときに、回答リクエストを送ってみてましょう。

これ以上回答リクエストを送信することはできません。制限について

絞り込み :
はてなココの「ともだち」を表示します。
回答リクエストを送信したユーザーはいません