tagCANDY CGI VBレスキュー(花ちゃん) の Visual Basic 2010 用 掲示板(VB.NET 掲示板) [ツリー表示へ]   [Home]
一括表示(VB.NET VB2005)
タイトルMS-ACCESSの解放が出来ません
記事No11619
投稿日: 2016/02/02(Tue) 13:33
投稿者SUZUKI
いつもお世話になっております
VB6.0からVB2005への変換挑戦中の鈴木です
またわからなくなり相談させて下さい
MS-ACCESS(2003)の停止が出来なく困ってしまいました
記事NO.6555を見て.FIELDSを扱うのは解放が難しいと
指摘されている所です
下記コードは列の追加のコードですが
解放が出来ません
階層の取り扱いで停止しないと思われるのですが
変数化がよくわかっていません
色々調べたのですが、よくわからずよろしくお願いします
  SUB  
  Dim DB As dao.Database
  Dim TDFNEW As dao.TableDef
  Dim CC As Short
  Dim fieldflag As Boolean
  DB = DAODBEngine_definst.OpenDatabase(DbName)
  TDFNEW = DB.TableDefs.Item("DBDATA")
      fieldflag = False
   For CC = 0 To TDFNEW.Fields.Count - 1
       If TDFNEW.Fields(CC).Name = "A区分" Then
             fieldflag = True
       End If
   Next
     ' 新しく 1 つのフィールドを追加します。
    If fieldflag = False Then
            AppendDeleteField(TDFNEW, "APPEND", "A区分", dao.DataTypeEnum.dbText, 1)
            DB.Close()
            MRComObject(DB)
            MsgBox("A区分欄追加しました")
    Else
            DB.Close()
            MRComObject(DB)
    End If
  
  End Sub
  
  Sub AppendDeleteField(ByRef tdfTemp As dao.TableDef, ByRef strCommand As String, ByRef strName As String, Optional ByRef varType_Renamed As Object = Nothing, Optional ByRef varSize As Object = Nothing)
        With tdfTemp
            ' 更新可能かどうかを調べます。
            ' 更新可能でない場合は
            ' 呼び出しているプロシージャに制御を返します。
            If .Updatable = False Then
                Exit Sub
            End If
            ' フィールドの追加や削除を行います。
            If strCommand = "APPEND" Then
                .Fields.Append(.CreateField(strName, varType_Renamed, varSize))
            Else
                If strCommand = "DELETE" Then .Fields.Delete(strName)
            End If

        End With
  Exit Sub

[ツリー表示へ]
タイトルRe: MS-ACCESSの解放が出来ません
記事No11620
投稿日: 2016/02/02(Tue) 19:03
投稿者魔界の仮面弁士
> VB6.0からVB2005への変換挑戦中の鈴木です

ご存知とは思いますが、VS2005 は、
  2011/04/12  メインストリームサポート終了
  2016/04/12  延長サポート終了
ということで、あと数ヶ月でサポート終了となる製品です。

2005 への変換と併せて、現行バージョンへの移行計画も
準備しておくことをお奨めします。


> MS-ACCESS(2003)の停止が出来なく困ってしまいました

DAO の参照設定が、PIA 版であることを確認しておいてください。
http://www.gizcollabo.jp/vbtomo/boards/vbqanda.php?do=spread&num=15630


なお、上記にも書いていますが、移行作業とはいえ、DAO の継続利用は
個人的にはお奨めしていません。とはいえ今回は DML ではなく DDL の操作なので、
DAO (または ACEDAO) を使うのも已む無しですかね。


> 記事NO.6555を見て.FIELDSを扱うのは解放が難しいと
(全角半角、大文字小文字の使い分けは適切に)


> DAODBEngine_definst
これは UpgradeSupport で提供される、DAO.DBEngine 型の変数ですね。


>  TDFNEW = DB.TableDefs.Item("DBDATA")
>  For CC = 0 To TDFNEW.Fields.Count - 1
>  If TDFNEW.Fields(CC).Name = "A区分" Then

ActiveX (COM) のオブジェクトを用いる場合、基本的には
「.」が二回続く記述は NG だと思ってください。解放されにくくなります。

かわりに、コレクションオブジェクトを変数に受けて

tblDefs = DB.TableDefs
tblNew = tblDefs("DBDATA")

flds = tblNew.Fields
fld = flds(CC)

のように扱うようにします。

そして、そのインスタンスがもう使われなくなった場合には、
ReleaseComObject メソッド(今回は MRComObject ですね)を呼び出してください。
ReleaseComObject に渡さなかったオブジェクトは解放が遅れることになります。


また、COM オブジェクトに対して With ステートメントを
利用することもお勧めしません。


それと、今回は使用されていないので問題ないのですが、
For Each も避けるようにしてください。For Each を使うと、
裏で IEnumerator のインスタンスが生成されることになるので、
使用するライブラリによっては、解放が難しくなるためです。


>  AppendDeleteField(TDFNEW, "APPEND", "A区分", dao.DataTypeEnum.dbText, 1)
ちなみに「dao.DataTypeEnum.dbText」でも「.」が複数記載されていますが、
こちらはプロパティやメソッドのための「.」ではなく、
 名前空間名.列挙型名.列挙値名
であるため、「.」が複数あっても大丈夫です。
(そもそも、列挙型の値は ReleaseComObject の対象とはならないため)

[ツリー表示へ]
タイトルRe^2: MS-ACCESSの解放が出来ません(解決)
記事No11622
投稿日: 2016/02/03(Wed) 14:32
投稿者SUZUKI
魔界の仮面弁士さん、アドバイスありがとうございます
MSACCESSが消えてくれて感激しております

>   2016/04/12  延長サポート終了
> ということで、あと数ヶ月でサポート終了となる製品です。
>
> 2005 への変換と併せて、現行バージョンへの移行計画も
> 準備しておくことをお奨めします。

実はVB2005への変換で、他にもいっぱいつまずいておりまして
解決したら急ぎバージョンアップ検討します
自分だけ質問してもという事で調べてわからない時
またよろしくお願いします

>
> なお、上記にも書いていますが、移行作業とはいえ、DAO の継続利用は
> 個人的にはお奨めしていません。とはいえ今回は DML ではなく DDL の操作なので、
> DAO (または ACEDAO) を使うのも已む無しですかね。
>
DAOから離れないといけないのですが
知識不足です。がんばるしかないのですが

>
> > 記事NO.6555を見て.FIELDSを扱うのは解放が難しいと
> (全角半角、大文字小文字の使い分けは適切に)
>
了解です
統一するよう心がけます

>
> > DAODBEngine_definst
> これは UpgradeSupport で提供される、DAO.DBEngine 型の変数ですね。
> tblDefs = DB.TableDefs
> tblNew = tblDefs("DBDATA")
>
> flds = tblNew.Fields
> fld = flds(CC)
>
> のように扱うようにします。
>

        Dim dbe As New dao.DBEngine
        Dim DB As dao.Database
        Dim tblDefs As Object
        Dim tblNew As Object
        Dim flds As Object
  
        DB = dbe.OpenDatabase(DbName)
        tblDefs = DB.TableDefs
        tblNew = tblDefs("DBDATA")
        flds = tblNew.fields

にしたらうまく解放してくれました
一番のポイントは"DAODBEngine_definst"を使わない事でした
自動変換を信じると痛い目に会うという事ですね


> それと、今回は使用されていないので問題ないのですが、
> For Each も避けるようにしてください。For Each を使うと、
> 裏で IEnumerator のインスタンスが生成されることになるので、
> 使用するライブラリによっては、解放が難しくなるためです。
>

For Each も実はトライしていました
おかげで助かりました
ほんとに、ありがとうございました

[ツリー表示へ]
タイトルRe^3: MS-ACCESSの解放が出来ません(解決)
記事No11623
投稿日: 2016/02/03(Wed) 15:45
投稿者魔界の仮面弁士
> 実はVB2005への変換で、他にもいっぱいつまずいておりまして
2005 化にあたり、「Option Strict On」でコンパイルできることを目指すと良いですよ。


> 一番のポイントは"DAODBEngine_definst"を使わない事でした
DAODBEngine_definst も解放されていましたか?


> 自動変換を信じると痛い目に会うという事ですね
DAO の場合、Default Workspace のインスタンス管理が気にかかるので、
私自身も、DBEngine のインスタンスは自前で管理する派ですね。



>         Dim tblDefs As Object
>         Dim tblNew As Object
>         Dim flds As Object
これらの型は、
 Dim tblDefs As DAO.TableDefs
 Dim tblNew As DAO.TableDef
 Dim flds As DAO.Fields
が適切かと。



> > For Each も避けるようにしてください。For Each を使うと、
> > 裏で IEnumerator のインスタンスが生成されることになるので、
> For Each も実はトライしていました
For Each の場合の問題点が、下記で紹介されています。
VB 向けの資料ではなく C# の話ですが、とりあえず斜め読みだけでも。
http://www.divakk.co.jp/aoyagi/csharp_tips_vssenum.html

[ツリー表示へ]
タイトルRe^4: MS-ACCESSの解放が出来ません
記事No11624
投稿日: 2016/02/03(Wed) 16:41
投稿者SUZUKI
> > 実はVB2005への変換で、他にもいっぱいつまずいておりまして
> 2005 化にあたり、「Option Strict On」でコンパイルできることを目指すと良いですよ。
最終的には「Option Strict On」にしたいと思います
現時点では、技量が無く収集がつかなくなり中止しています



> >         Dim tblDefs As Object
> >         Dim tblNew As Object
> >         Dim flds As Object
> これらの型は、
>  Dim tblDefs As DAO.TableDefs
>  Dim tblNew As DAO.TableDef
>  Dim flds As DAO.Fields
> が適切かと。
>
なるほど、勉強になります
最終形は下記のようになると思うのですが
fld1 の定義ですがObjectでよろしいのでしょうか
Object型も実はよくわかっておらずはずかしいです

        Dim DB As dao.Database
        Dim tblDefs As dao.TableDefs
        Dim tblNew As dao.TableDef
        Dim flds As dao.Fields
        Dim fld As dao.Field
        Dim fld1 As Object
        Dim CC As Short
        Dim CC1 As Short
        Dim fieldflag As Boolean
        DB = dbe.OpenDatabase(DbName)
        tblDefs = DB.TableDefs
        tblNew = tblDefs("DATABASE")
        flds = tblNew.fields
        cc1 = flds.COUNT - 1
        For CC = 0 To cc1
            fld = flds(CC)
            fld1 = fld.name
            If fld1.ToString = "A区分" Then
                fieldflag = True
            End If
            MRComObject(fld1)
            MRComObject(fld)
        Next

[ツリー表示へ]
タイトルRe^5: MS-ACCESSの解放が出来ません
記事No11625
投稿日: 2016/02/03(Wed) 18:34
投稿者魔界の仮面弁士
> cc1 = flds.COUNT - 1
> For CC = 0 To cc1

VB6/VB.NET の For ループでは、To 句の評価は、
初回しか行われません。

そのため、万一ループ中で flds.COUNT の値が変化するようなことがあっても、
 For CC = 0 To flds.COUNT - 1
という処理は、「For CC = 0 To cc1」の場合と同じ回数だけループします。

C# の for ループの場合は、毎ループごとに判定されるのですけれどね。


> fld1 = fld.name
> If fld1.ToString = "A区分" Then
Name プロパティの戻り値は String 型なので、
それを ToString することは冗長です。

> MRComObject(fld1)
String 型は COM オブジェクトではないため、
ReleaseComObject の対象にはなりません。


> 最終形は下記のようになると思うのですが

コードの意図を汲み取れているか分かりませんが、
私なら下記のように記述します。


Dim db As dao.Database = dbe.OpenDatabase(DbName)
Dim tbls As dao.TableDefs = db.TableDefs
Dim tbl As dao.TableDef = tbls("DATABASE")
Dim flds As dao.Fields = tbl.Fields

Dim found As Boolean = False   '列が見つかれば True

For colIdx As Integer = 0 To flds.Count - 1
    Dim fld As dao.Field = flds(colIdx)
    found = (fld.Name = "A区分")
    MRComObject(fld)
    If found Then
       Exit For
    End If
Next

MRComObject(flds)
MRComObject(tbl)
MRComObject(tbls)
db.Close()
MRComObject(db)

[ツリー表示へ]
タイトルRe^6: MS-ACCESSの解放が出来ません
記事No11626
投稿日: 2016/02/04(Thu) 10:05
投稿者SUZUKI
魔界の仮面弁士さん 最後まで面倒見て頂きありがとうございました
FOR   TO
NEXT
のループ評価は気が付いていませんでした

found = (fld.Name = "A区分")

上記のコード近辺が自分にとってはハードルが高いのですが
じっくり鑑賞させて頂きます

[ツリー表示へ]
タイトルRe^7: MS-ACCESSの解放が出来ません
記事No11627
投稿日: 2016/02/04(Thu) 12:01
投稿者魔界の仮面弁士
>  found = (fld.Name = "A区分")

VB6 のそれと同じ意味ですよ。
最初の = は代入演算子、右にある = は比較演算子。


この場合の括弧は必ずしも必要ではないので、
  found = fld.Name = "A区分"
としても OK です。

あるいは比較式であることを明確化するために
  found = CBool(fld.Name = "A区分")
といった、あえて冗長な型変換をするケースもあるようで。



そうした表記に慣れないのであれば、ばらして
 If fld.Name = "A区分" Then
  found = True
 Else
  found = False
 End If
のように書いておいてください。

[ツリー表示へ]
タイトルRe^8: MS-ACCESSの解放が出来ません
記事No11628
投稿日: 2016/02/04(Thu) 15:50
投稿者SUZUKI
アクセス関係の定義の仕方
A=B=Cのコードの意味
FOR ループ内での DIM 定義
ループ評価
短いけど自分にとってすごく新鮮さを感じる
コードでほんとにありがとうございました

[ツリー表示へ]