Доступ: сохранить ссылку на COM при сбросе программы? - PullRequest
0 голосов
/ 01 октября 2010

Есть ли в Access VBA (2003) способы приведения ссылки COM к целому числу и вызова AddRef / Release?(которые выдают ошибку «Функция или интерфейс помечены как ограниченные, или функция использует тип автоматизации, не поддерживаемый в Visual Basic»)

Я использую сторонний COM-объект, который не обрабатывает создаваемый экземплярдважды в одном процессе (это известная ошибка).Поэтому я подумал о сохранении ссылки как заголовка элемента управления в скрытой форме, чтобы защитить ее от сброса программы, очищающего все переменные VB.

Edit : я думаю, что приведение к int можетсделано с недокументированным ObjPtr, и снова с API CopyMemory, и AddRef / Release может быть вызван неявно.Но есть ли лучший способ?Защищены ли надстройки от сброса программы?

1 Ответ

0 голосов
/ 01 октября 2010

Проблема в сохранении сброса кода или в том, что после сброса кода его нельзя повторно инициализировать?

Для первой проблемы оберните ваш объект верхнего уровня в функцию и используйте переменную 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

... и вам не нужно беспокоиться об его инициализации при открытии приложения или после сброса кода - это самовосстановление, поскольку оно проверяет внутреннюю переменную Static и при необходимости повторно инициализирует.

Единственное предостережение в том, что вам нужно сделать вызов с аргументом bolInitialize, установленным в False, когда вы закрываете свое приложение, так как это очищает ссылку, поэтому нет риска зависания вашего приложения, когда оно выходит из области видимости, так как приложение закрывается.

Что касается другой проблемы, я действительно сомневаюсь, что в VBA есть какое-либо решение, если только вы не можете сделать вызов API и уничтожить внешний процесс. Но я думаю, что это что-то очень длинное.

...