0

Access VBA (2003) で COM 参照を整数にキャストし、AddRef/Release を呼び出す方法はありますか? (「関数またはインターフェイスが制限付きとしてマークされているか、関数が Visual Basic でサポートされていないオートメーション タイプを使用しています」というエラーが表示されます)

1 つのプロセスで 2 回インスタンス化されることを処理しないサードパーティの COM オブジェクトを使用しています (これは既知のバグです)。したがって、すべての VB 変数をクリアするプログラム リセットから保護するために、非表示フォームのコントロールのキャプションとして参照を保存することを考えました。

編集: int へのキャストは、文書化されていない ObjPtr を使用して行うことができ、CopyMemory API を使用して再度行うことができ、AddRef/Release を暗黙的に呼び出すことができると思います。しかし、より良い方法はありますか?アドインはプログラム リセットから保護されていますか?

4

1 に答える 1

0

コードのリセットを生き残ることに問題がありますか、それともコードがリセットされると再初期化できないことですか?

最初の問題については、最上位オブジェクトを関数でラップし、内部で STATIC 変数を使用して参照をキャッシュします。STATIC 変数が Nothing の場合は、再初期化します。ローカル データベースへの参照をキャッシュするために使用する関数は次のとおりです。

  Public Function dbLocal(Optional bolInitialize As Boolean = True) +
     As DAO.Database
  ' 2003/02/08 DWF added comments to explain it to myself!
  ' 2005/03/18 DWF changed to use Static variable instead
  ' uses GoTos instead of If/Then because:
  '  error of dbCurrent not being Nothing but dbCurrent being closed (3420)
  '  would then be jumping back into the middle of an If/Then statement
  On Error GoTo errHandler
    Static dbCurrent As DAO.Database
    Dim strTest As String

  If Not bolInitialize Then GoTo closeDB

  retryDB:
    If dbCurrent Is Nothing Then
       Set dbCurrent = CurrentDb()
    End If
    ' now that we know the db variable is not Nothing, test if it's Open
    strTest = dbCurrent.Name

  exitRoutine:
    Set dbLocal = dbCurrent
    Exit Function

  closeDB:
    If Not (dbCurrent Is Nothing) Then
       Set dbCurrent = Nothing
    End If
    GoTo exitRoutine

  errHandler:
    Select Case err.Number
      Case 3420 ' Object invalid or no longer set.
        Set dbCurrent = Nothing
        If bolInitialize Then
           Resume retryDB
        Else
           Resume closeDB
        End If
      Case Else
        MsgBox err.Number & ": " & err.Description, vbExclamation, "Error in dbLocal()"
        Resume exitRoutine
    End Select
  End Function

コード内で次のいずれかを実行した場合:

  Dim db As DAO.Database
  Set db = CurrentDB()
  Set db = DBEngine(0)(0)
  db.Execute "[SQL DML]", dbFailOnError

...全体を次のように置き換えることができます:

  dbLocal.Execute "[SQL DML]", dbFailOnError

...そして、アプリを開いたときやコードのリセット後に初期化することを心配する必要はありません。静的内部変数をチェックし、必要に応じて再初期化するため、自己回復します。

唯一の注意点は、アプリをシャットダウンするときに bolInitialize 引数を False に設定して呼び出しを行う必要があることです。これにより、参照がクリーンアップされるため、アプリを閉じるときに範囲外になったときにアプリがハングするリスクがなくなります。

もう1つの問題については、API呼び出しを行って外部プロセスを強制終了できない限り、VBA内に解決策があるとは思えません。しかし、それは大穴だと思います。

于 2010-10-01T03:20:59.060 に答える