tagCANDY CGI VBレスキュー(花ちゃん)の Visual Basic 6.0用 掲示板 [ツリー表示へ]   [Home]
一括表示(VB6.0)
タイトルAccessVBAでエクセルが解放がされない件
記事No15841
投稿日: 2014/02/27(Thu) 17:58
投稿者まほろば
初めまして、まほろばといいます。
まちがえてVB.NETの掲示板に書き込んでしまいました。
再度こちらで質問させていただきたいと思います。
私はVBA歴5年程度の日曜プログラマーです。VB6.0での開発も少しだけ経験がありますが、VB6.0、VBAとも完全にわかっているわけではございませんので質問させていただきたいです。

今、エクセルのシートの時系列の売上データをAccessのテーブルに追加するVBAを作っています。
Access側のコマンドボタンのクリックで下記のVBAを動かそうと思っていました。
テーブルにはエクセルのシートのデータは正しく追加されますが、最後にエクセルが解放されずにプロセスに残ったままになってしまいます。
当サイトを参考にいろいろ調べてやってみたのですが、どうしても解放されず行き詰っています。
本来はVBの掲示板だと理解していますが、VBAでの質問で申し訳ございません。
どうすればうまくいくのか、ご指導よろしくお願いいたします。

環境は、
Windows7ultimate 32bit版 Excel2013,Access2013
です。



(参照設定)
Visual Basic For application
OLE Automation
Microsoft Access 14.0 Object Library
Microsoft ActiveX Data Objects 2.8 Library
Microsoft Excel 14.0 Object Library
Microsoft Windpws Common Controls-2 6.0

(コード)
Private Sub 追加更新日次売上データ()


Dim conAcc As ADODB.Connection
Dim rsAcc As ADODB.Recordset

Dim myDate As Date, myExDate As Date, myAccDate As Date
Dim sql As String
Dim rowCount  As Long


Dim filePath  As String

Dim xlApp As Excel.Application
Dim xlBooks As Excel.Workbooks
Dim xlBook As Excel.Workbook
Dim xlSheet As Excel.Worksheet
Dim myRange As Object

Dim rsTbl As ADODB.Recordset
Dim conTbl As ADODB.Connection

Dim zzz as Long
Dim myStart as Long

    
'Sale_Tの最新の日付を取得
    Set rsAcc = New ADODB.Recordset
    Set conAcc = Application.CurrentProject.Connection
      
    
    ' SQL文作成
    sql = "SELECT * FROM Sale_T ORDER BY [Sale_T].日付; "
    rsAcc.Open sql, conAcc, adOpenDynamic, adLockOptimistic, adCmdText


rsAcc.MoveLast

myAcDate = rsAcc("日付").Value      'Sale_Tの最新日付

rsAcc.Close
conAcc.Close

Set rsAcc = Nothing
Set conAcc = Nothing

'//////////////////////////////////////////////////////////////////////////////
'エクセルのパス

    filePath = "D:\売上\日次売上\SalesDay.xlsx"

'Excelブックオブジェクト
    Set xlApp = CreateObject("New Excel.Application")
    Set xlBooks = xlApp.Workbooks
    Set xlBook = xlBooks.Open(filePath)     'ファイルパスのExcelブックを開く

'ワークシートオブジェクト
    Set xlSheet = xlBook.Worksheets(1)      '1枚目のワークシート
   xlApp.Visible = True

'ワークシート内レコードの最新日付を取得する
    
    rowCount = xlSheet.Range("A1").End(xlDown).Row
    
    xlSheet.Select
    Set myRange = xlSheet.Range(xlSheet.Cells(1, 1), xlSheet.Cells(rowCount, 1))
    myExDate = xlApp.WorksheetFunction.Max(myRange)  'Sale_T.xlsxの最新日付

    myAccDate = Format(myAcDate, "Short Date")
    myExDate = Format(myExDate, "Short Date")

    If myAccDate >= myExDate Then  'Accessテーブルの最新日付よりエクセルの最新日付が遅ければExitする
      
       'Excelを閉じる
      
       Set myRange = Nothing
      
       Set xlSheet = Nothing
      
       xlBook.Saved = True
       xlBook.Close
       Set xlBook = Nothing
       Set xlBooks = Nothing
      
       xlApp.Quit
       Set xlApp = Nothing


   MsgBox ("追加データはありません。")
      
    Exit Sub

   
    Else

       
       For zzz = 2 To rowCount
          
           If xlSheet.Cells(zzz, 1).Value >= #1/1/2013# Then   '2013年から追加更新する
              myStart = zzz
              Exit For
           End If
      
       Next zzz
  
    
    End If
    
    
'///////////////データの取り込み///////////////////////////////////////////////
'1行づつ読み込む
        
    For zzz = myStart To rowCount
        
        '各フィールド
        Dim hiz As Date
        Dim b As Variant
        
        
        'レコードの取得
        hiz = Format(xlSheet.Range("A" & zzz).Value, "Short Date")
      
        b = xlSheet.Range("B" & zzz).Value
        
        Set rsTbl = New ADODB.Recordset
        Set conTbl = Application.CurrentProject.Connection

        sql = "SELECT * FROM Sale_T WHERE 日付=#" & hiz & "#"
            rsTbl.Open sql, conTbl, adOpenKeyset, adLockOptimistic


      If Not rsTbl.EOF Then

        rsTbl.MoveFirst
                
        rsTbl.Fields("日付").Value = hiz
        rsTbl.Fields("売上").Value = b
                          
        rsTbl.Update
            
     Else
        
        rsTbl.AddNew
            
        rsTbl.Fields("日付").Value = hiz
        rsTbl.Fields("売上").Value = b
    
        rsTbl.Update

     End If


        rsTbl.Close
        conTbl.Close

        Set rsTbl = Nothing
        Set conTbl = Nothing
      
        
    Next zzz


'Excelブックを閉じる

    Set myRange = Nothing
      
       Set xlSheet = Nothing
      
       xlBook.Saved = True
       xlBook.Close
       Set xlBook = Nothing
       Set xlBooks = Nothing
      
       xlApp.Quit
       Set xlApp = Nothing


End Sub

以上よろしくお願いいたします。

[ツリー表示へ]
タイトルRe: AccessVBAでエクセルが解放がされない件
記事No15842
投稿日: 2014/02/27(Thu) 19:13
投稿者魔界の仮面弁士
> Microsoft Windpws Common Controls-2 6.0
# google ってみたら、同じ typo が 70 万件…(汗)


> 最後にエクセルが解放されずにプロセスに残ったままになってしまいます。

ざっと見た限り、提示頂いたコードそのものには問題点が見当たりませんでした。

Excelにファイルを開かせず、Workbooks オブジェクトにもアクセスせず、
Excel.Application だけを 起動→表示→終了→Nothing させるコードを試してみてください。

それだけでも解放漏れが出るてしまうようであれば、プログラミングの問題ではなく、
環境依存の問題が生じている可能性も考えられます。

何かアドインや自動起動マクロの類を利用していたりはしないでしょうか?
(Excel 2003 互換メニューやツールバー系のソフトなど)


もしも、起動→表示→終了 だけの単純な実験コードで試した場合には
正常に解放されるのであれば、それ以外の場所に問題があることになります。
元のコードを少しずつ削っていき、どの行を実行したときに
問題が発生しているのか、原因箇所を特定してみてください。


>     Set xlApp = CreateObject("New Excel.Application")
違います。正しくは
 Set xlApp = New Excel.Application
と書きます。


CreateObject を使う構文であれば、ご存知のように、
 Set xlApp = CreateObject("Excel.Application")
と書くことになります。こちらの構文の場合は、変数宣言を
Dim xlApp As Object などと書き換えてやれば、そもそも Excel への
参照設定も不要になります。


>     myAccDate = Format(myAcDate, "Short Date")

右辺の myAcDate というのが Date 型なのか Variant 型なのかは分かりませんが、
左辺の myAccDate については、Date 型なのですよね? Variant 型ではなく。

だとすれば、Format関数の戻り値は String 型(正確には違いますが)なので、
文字列を直接 Date 型に突っ込むことは、あまり望ましくありません。
(左辺が Variant か String であるならば問題ないですけど)


もしも時刻部を切り捨てたいという意味だとしたら、こういう方法もあります。

(案1) x = Fix(myAcDate)
(案2) x = DateValue(myAcDate)
(案3) x = DateSerial(Year(myAcDate), Month(myAcDate), Day(myAcDate))

これらの方法なら、変換後の型も Date 型のままなので、
左辺が Date 型の変数であっても、問題は生じません。


>    MsgBox ("追加データはありません。")
括弧が不要です。VBA でのメソッド呼び出しは、以下のいずれかの形式となります。

1: MsgBox "追加データはありません。"
2: Call MsgBox("追加データはありません。")
3:  ret = MsgBox("追加データはありません。")


戻り値が必要な場合は 3 の文法。括弧が必要です。
戻り値が不要な場合は 1 の文法。括弧は付けません。

戻り値が不要だけど括弧をつけたい場合は、2 の Call 構文を使います。

[ツリー表示へ]
タイトルRe^2: AccessVBAでエクセルが解放がされない件
記事No15843
投稿日: 2014/02/27(Thu) 23:54
投稿者まほろば
1.
>環境依存の問題が生じている可能性も考えられます
すみません、自宅の方はExcel2013と2010が共存していることを忘れていました。
その他アドインや自動マクロの類はありません。

2.
>Excel.Application だけを 起動→表示→終了→Nothing させるコードを試してみてください
これもテストしましたが依然解放されていませんでした。

3.
>myAccDate = Format(myAcDate, "Short Date")
右辺のmyAcDateはmyAccDateの投稿するときのタイプミスです。お手数かけてすみませんでした。

4.
>原因箇所を特定してみてください。
いろいろとテストするうち下記のような結果になりました。
書き換えたのは「Excelの参照設定の有無」と「Set xlApp =〜」の2か所です。
結果は

(1)Excelの参照設定あり
Dim xlApp As Object
Set xlApp = CreateObject("Excel.Application")
解放される


(2)Excelの参照設定なし
Dim xlApp As Object
Set xlApp = CreateObject("Excel.Application") 

rowCount = mysheet.Range("A1").End(xlDown).Row
(反転)xlDown
「コンパイルエラー 変数が定義されていません。」
となったので

rowCount=600

としてテスト
解放される


(3)Excelの参照設定あり
Dim xlApp As Object
Set xlApp = New Excel.Application
解放される


(4)Excelの参照設定なし
Dim xlApp As Object
Set xlApp = New Excel.Application
(反転)New Excel.Application
「コンパイルエラー ユーザー定義型は定義されていません。」


(2)は途中のエラーはあったものの結果的に解放されていましたが、これは最初に投稿したコードだと思うのです。
その時は途中のエラーもなく、最後に解放されない状態であったのですが、、、。
ちょっと不思議な気分です。
違いはというと参照設定を外すことなくテストしていたことです。今回投稿してみて初めて参照設定をはずして再度設定してテストしてみてうまく解放されたということは、何かコード以外の原因があるのかなぁとか思っています。
ともあれまずはうまくいきましたので当面の間これで続けていきます。
魔界の仮面弁士様、花ちゃん様、いろいろたくさんのご指導ありがとうございました。

[ツリー表示へ]
タイトルRe^3: AccessVBAでエクセルが解放がされない件
記事No15844
投稿日: 2014/02/28(Fri) 09:44
投稿者魔界の仮面弁士
> >Excel.Application だけを 起動→表示→終了→Nothing させるコードを試してみてください
> これもテストしましたが依然解放されていませんでした。

つまり、こういうコードということですよね。

Dim x As Excel.Application
Set x = New Excel.Application
MsgBox "起動"
x.Visible = True
MsgBox "表示"
x.Quit
Set x = Nothing
MsgBox "終了…解放されているか?"

これで解放されないなら、環境側に問題があるのでしょう。
インストール順は、2010→2013になっていましたか?
他に、複数バージョンの Office を混在させていない環境はありませんか?


> >myAccDate = Format(myAcDate, "Short Date")
> 右辺のmyAcDateはmyAccDateの投稿するときのタイプミスです。
だとして、左辺が Date 型なのに、右辺が String 型という点は
変わりませんので、コードとしてはあまり望ましくありません。



> (2)Excelの参照設定なし
> rowCount = mysheet.Range("A1").End(xlDown).Row
> (反転)xlDown
> 「コンパイルエラー 変数が定義されていません。」
参照設定していない場合は、定数宣言を補ってください。
 Const xlDown As Long = -4121

[ツリー表示へ]
タイトルRe^4: AccessVBAでエクセルが解放がされない件
記事No15845
投稿日: 2014/02/28(Fri) 10:30
投稿者まほろば

> インストール順は、2010→2013になっていましたか?
> 他に、複数バージョンの Office を混在させていない環境はありませんか?

このOFFICEは購入直後のPCに、OFFICE2010(2013への無償アップグレード付き)をインストールしたのち、2013へアップグレードしたものです。アップグレードすると2010と2013が混在しておりました。
その他のOFFICE製品はインストールしておりません。


> > >myAccDate = Format(myAcDate, "Short Date")
> > 右辺のmyAcDateはmyAccDateの投稿するときのタイプミスです。
> だとして、左辺が Date 型なのに、右辺が String 型という点は
> 変わりませんので、コードとしてはあまり望ましくありません。

そうですね。理解できます。ただこのシートはエクセル側で配列からシートへvbaで転記したもので日付データが文字列になっていましたのでこうなってしまいました。myAccDateを日付型で宣言するならエクセルの方で日付型に変換してからの方がよさそうですね。


> 参照設定していない場合は、定数宣言を補ってください。
>  Const xlDown As Long = -4121

あ、なるほど。この辺のところをもう一度基本から復習していきます。
細かいところまでご指示いただき本当にありがとうございます。

[ツリー表示へ]