У меня есть приложение VB6, в котором есть множество сторонних компонентов. Приложение работает хорошо, но при выходе (и только при запуске в качестве автономного EXE-файла, например, не в IDE) оно выдает сообщение об ошибке:
Я видел подобные ошибки раньше, но обычно в нем говорится, в каком компоненте отсутствуют зависимости или он не зарегистрирован должным образом.
Я запустил его через Process Monitor и получил следующие файлы, которые он не может найти:
А потом он уходит. Я гуглил имена файлов, которые он не может найти и не может найти ничего. Похоже, что он ищет вариации MSComENU, MSComEN и MSCOENU dll.
Я проверил и перепроверил, чтобы убедиться, что все сторонние компоненты есть, и они есть - приложение работает нормально, если бы их там не было, этого бы не было.
Стоит отметить, что ошибка возникает после запуска последней строки кода VB6 (в событии Form_Unload
). Я знаю это, потому что последняя строка - это окно сообщения, которое появляется.
Многое, намного позже. РЕДАКТИРОВАТЬ : Я наконец-то вернулся к решению проблемы и выяснил ее с помощью процесса устранения (и это был долгий процесс). В конце концов это не имело ничего общего с записями MSCOMM * .dll. На самом деле, я не знаю, почему они все еще отображаются в Process Monitor. Проблема была намного проще.
У меня было несколько сторонних элементов управления в главной форме. Чтобы не загрязнять основную форму множеством кода обработки событий, я делегировал эти элементы управления новому классу, например:
' declaration code in main form'
Private WithEvents moDelegateObject as clsDelegateObject
' still in the main form, after initialization'
Set moDelegateObject = new clsDelegateObject
With moDelegateObject
Set .ThirdPartyCtlHandler1 = me.ThirdPartyCtl1
Set .ThirdPartyCtlHandler2 = me.ThirdPartyCtl2
Set .ThirdPartyCtlHandler3 = me.ThirdPartyCtl3
end with
' declarations and properties inside of clsDelegateObject'
Private WithEvents moThirdPartyCtlHandler1 as ThirdPartyCtl
Private WithEvents moThirdPartyCtlHandler2 as ThirdPartyCtl
Private WithEvents moThirdPartyCtlHandler3 as ThirdPartyCtl
Public Event FooEvent() ' other various events as well '
Public Property Set ThirdPartyCtlHandler1(o as ThirdPartyCtl)
moThirdPartyCtlHandler1 = o
End Property
Public Property Get ThirdPartyCtlHandler1() as ThirdPartyCtl
ThirdPartyCtlHandler1 = moThirdPartyCtlHandler1
End Property
' ... Repeat for each handler ...'
Чего не хватало, так это кода для явного освобождения этих объектов перед закрытием. Это то, что обычно делает Visual Basic. Поэтому я добавил следующее в Form_QueryClose в основной форме:
With moDelegateObject
Set .ThirdPartyCtlHandler1 = Nothing
Set .ThirdPartyCtlHandler2 = Nothing
Set .ThirdPartyCtlHandler3 = Nothing
End with
Set moDelegateObject = Nothing
Последняя строка оказалась излишней, но я добавил ее для полноты картины. Я думаю, что это была комбинация делегирования элементов управления классу делегата и получения от него событий в главной форме и использования большого количества действительно неясных сторонних элементов управления, которые способствовали этой проблеме. Вероятно, что сторонний элемент управления не освобождает себя. Во всяком случае, урок усвоен.