Вылетает ошибка при закрытии формы

Программирование на Visual Basic, главный форум. Обсуждение тем программирования на VB 1—6.
Даже если вы плохо разбираетесь в VB и программировании вообще — тут вам помогут. В разумных пределах, конечно.
Правила форума
Темы, в которых будет сначала написано «что нужно сделать», а затем просьба «помогите», будут закрыты.
Читайте требования к создаваемым темам.
Avtopic
Постоялец
Постоялец
 
Сообщения: 442
Зарегистрирован: 30.09.2005 (Пт) 17:15
Откуда: Tbilisi

Вылетает ошибка при закрытии формы

Сообщение Avtopic » 02.05.2007 (Ср) 14:09

Эту проблему мне самому не решить.

Вылетает ошибка при закрытии формы крестиком (Exit) на форме.

В самом проекте: присоединяюсь к локальной mdb базе, и жду результат выборки (асинхронно).
Если в этот момент жму на крестик, иногда вылетает ошибка и программа грохается.
Это происходит не всегда, очень трудно поймать этот момент.

Попробовал очень много вариантов, чтобы найти причину, в данный момент сделано следующее:

1. перенес все связанное с ADO в отдельный класс. В Class_Terminate поставил код
Код: Выделить всё
]If Not r Is Nothing Then

        Do While r.State = adStateExecuting
            r.Cancel
        Loop
       
        Do While r.State = adStateOpen
            r.Close
        Loop

    End If

    If Not cn Is Nothing Then
       
        Do While cn.State = adStateConnecting
            cn.Cancel
        Loop
       
        Do While cn.State = adStateOpen
            cn.Close
        Loop

    End If
   
    Set r = Nothing
    Set cn = Nothing

    ClassIsBisy=False

2. в Form_QueryUnload посадил код
Код: Выделить всё
Private Sub Form_QueryUnload(Cancel As Integer, UnloadMode As Integer)
   
    If Not cnn Is Nothing Then '  (cnn объект моего класса)
        Do While cnn.ClassIsBisy 
            DoEvents
        Loop
        Set cnn = Nothing   
 
    End If   
End Sub


3. во всем проекте после каждой строчк и (!!!) вызываю маленькую функцию и пишу информацию в текстовый файл.

по этому файлу видно что, не смотря на то, когда произошло нажатие крестика на форме, код всегда корректно доходит до закрытия Connection, и класса, и выхода из цикла в Form_QueryUnload только после этого. Но после этого программа все ровно валится.

После открытия C++ дебагера (где ничего абсолютна не понимаю) пошаговом режиме смотрю что авария происходит на шаге
Код: Выделить всё
call ntdll.RtlExitUserTread
при повторном и последующих проходах, на шаге
Код: Выделить всё
call ntdll.NtRaiseExeption


Поиском, в гуугле, эта комбинация слов встречается всего один раз, и то в нашем форуме.
Если этот баг не исправлю, дальше двигаться не имеет смысла.

Что можно предпринять, и о чем говорят приведенные моменты из дебагера, полезном для поиска неисправности.
Спасибо заранее!

GSerg
Шаман
Шаман
 
Сообщения: 14286
Зарегистрирован: 14.12.2002 (Сб) 5:25
Откуда: Магадан

Сообщение GSerg » 02.05.2007 (Ср) 14:26

Do While r.State = adStateExecuting
r.Cancel
Loop

:roll:

Код: Выделить всё
a = 5
while a<>5
  a=5
wend

a = 5 'контрольный



ClassIsBisy

ClassIsBusy


Стоит MDAC 2.8 SP2?
Как только вы переберёте все варианты решения и не найдёте нужного, тут же обнаружится решение, простое и очевидное для всех, кроме вас

tyomitch
Пользователь #1352
Пользователь #1352
Аватара пользователя
 
Сообщения: 12822
Зарегистрирован: 20.10.2002 (Вс) 17:02
Откуда: חיפה

Сообщение tyomitch » 02.05.2007 (Ср) 14:47

GSerg писал(а):
Код: Выделить всё
a = 5
while a<>5
  a=5
wend

a = 5 'контрольный


Оригинал был на http://bbs.vbstreets.ru/viewtopic.php?t=9860
Изображение

GSerg
Шаман
Шаман
 
Сообщения: 14286
Зарегистрирован: 14.12.2002 (Сб) 5:25
Откуда: Магадан

Сообщение GSerg » 02.05.2007 (Ср) 14:57

О да.
Я просто не нашёл :)
Как только вы переберёте все варианты решения и не найдёте нужного, тут же обнаружится решение, простое и очевидное для всех, кроме вас

Avtopic
Постоялец
Постоялец
 
Сообщения: 442
Зарегистрирован: 30.09.2005 (Пт) 17:15
Откуда: Tbilisi

Сообщение Avtopic » 02.05.2007 (Ср) 15:33

Код: Выделить всё
Do While r.State = adStateExecuting
r.Cancel
Loop
?? может в шоковом состоянии что-то путаю, но по идее вкладываю следующее, если идет выборка в рекордсет, не выходи из цикла, пока r.Cancel не прервет выборку.
нет?
конешно, такие цикли вообще не использую, здесь вставил для проверки где наступает ошибка.


ClassIsBusy Boolean своиство, ставлю в True при инициализации класса и в False только в конце терминате.


Стоит MDAC 2.8 SP2? Нет.

Спасибо, читаю...

GSerg
Шаман
Шаман
 
Сообщения: 14286
Зарегистрирован: 14.12.2002 (Сб) 5:25
Откуда: Магадан

Сообщение GSerg » 02.05.2007 (Ср) 15:46

Avtopic писал(а):может в шоковом состоянии что-то путаю

Да, сходи по ссылке Тёмыча.

Avtopic писал(а):ClassIsBusy Boolean своиство, ставлю в True при инициализации класса и в False только в конце терминате.

Я не спрашивал, что это. Я написал, что Busy пишется через u, а не через i.

Avtopic писал(а):Стоит MDAC 2.8 SP2? Нет.

Почему нет? Какой стоит?

Avtopic писал(а):Спасибо, читаю...

Боюсь спросить... читаешь что?
Как только вы переберёте все варианты решения и не найдёте нужного, тут же обнаружится решение, простое и очевидное для всех, кроме вас

Avtopic
Постоялец
Постоялец
 
Сообщения: 442
Зарегистрирован: 30.09.2005 (Пт) 17:15
Откуда: Tbilisi

Сообщение Avtopic » 02.05.2007 (Ср) 16:06

Стоит MDAC 2.7

Боюсь спросить... читаешь что?
:)

Читаю чем 2.7 чревато, какие баги в версии (support.microsoft.com), и совпадают или нет их характерные черты с моей ошибкой
и что исправлено в новой 2.8.

Avtopic
Постоялец
Постоялец
 
Сообщения: 442
Зарегистрирован: 30.09.2005 (Пт) 17:15
Откуда: Tbilisi

Сообщение Avtopic » 02.05.2007 (Ср) 20:07

Установил MDAC 2.8 и потом установил SP8 (JET)
Вот уже полтора часа, Click-аю на крестик формы.
Гораздо сложнее, спровоцировать ошибку,
но она иногда, все ровно происходит, за это время четыре раза.
(до установки, за такой же период смог бы вызвать его 30-40 раз)

Что интересно, из той же базы, тот же вариант использую в Excel VBA.
В отношении работы с базой нет ни малейшего отличия.
Там за пол года не помню не одного такого случая, чтобы при закрытии формы...
Хотел перенести тот же вариант в отдельную программу, на первой же форме
споткнулся...

GSerg
Шаман
Шаман
 
Сообщения: 14286
Зарегистрирован: 14.12.2002 (Сб) 5:25
Откуда: Магадан

Сообщение GSerg » 02.05.2007 (Ср) 20:39

Только один вызов cancel должен быть в каждом случае, Avtopic... Ты сделал так?
Как только вы переберёте все варианты решения и не найдёте нужного, тут же обнаружится решение, простое и очевидное для всех, кроме вас

Avtopic
Постоялец
Постоялец
 
Сообщения: 442
Зарегистрирован: 30.09.2005 (Пт) 17:15
Откуда: Tbilisi

Сообщение Avtopic » 03.05.2007 (Чт) 15:09

Думаю, нашел причину.
В help-е имеется ремарка
The Recordset object’s State property can have a combination of values. For example, if a statement is executing, this property will have a combined value of adStateOpen and adStateExecuting.

Если честно, я вообще не смог себе представить себе ситуацию, когда может быть NOT adStateOpen and adStateExecuting.
Короче, в моем коде оказывается, State вообще никогда не принимает значение adStateExecuting, оно при Executing ровняется не adStateOpen=1 и не adStateExecuting=3,
а ровняется 9 :shock: . по какой арифметике ровняется 9 adStateOpenand adStateExecuting я не понимаю.
Если пишу r.Cancel и в это время State<>9 происходит сбой.
Еще нужно проверит, наверно когда State=adStateFetching, так как, как писал выше выборка идет асинхронно.
Перепишу код и буду проверять заново...

[Добавлено позже]

ааа!!!..., adStateOpen Or adStateFetching = 9

jangle
Википедик
Википедик
Аватара пользователя
 
Сообщения: 3013
Зарегистрирован: 03.06.2005 (Пт) 12:02
Откуда: Нидерланды

Сообщение jangle » 03.05.2007 (Чт) 15:39

Вызывай при выгрузке формы, API функцию ExitProcess, и будет тебе счастье ))


Call ExitProcess(0)

keks-n
Доктор VB наук
Доктор VB наук
Аватара пользователя
 
Сообщения: 2509
Зарегистрирован: 19.09.2005 (Пн) 17:17
Откуда: г. Москва

Сообщение keks-n » 03.05.2007 (Чт) 15:53

jangle
Такой подход(равно как и с End), как писал кто-то на форуме(и я с ним полностью согласен), означает, что автору программы абсолютно пофиг, что как и где у него выгружается, и насколько корректно.
Изображение

jangle
Википедик
Википедик
Аватара пользователя
 
Сообщения: 3013
Зарегистрирован: 03.06.2005 (Пт) 12:02
Откуда: Нидерланды

Сообщение jangle » 03.05.2007 (Чт) 16:06

End от VB это вообще какое-то недрозумение. Лучше его никогда не использовать. Скорее всего у автора топика, в программе не освобождаются какие-то ресурсы или объекты, чтобы обычный программе не ломал голову, Mикрософт придумала замечательную функцию ExitProcess, при ее вызове, уничтожением и выгрузкой используемых объектов займется сама система. При вызове этой функции, винда корректно пройдется по цепочке связанных объектов и поочередно удалит их, снимет все сетевый соеденения со стека TCP, выгрузит используемые процессом DLL библиотеки, и вернет очищенную память в систему.
Отсуствие завершения программы вызовом ExitProcess, не просто плохой стиль программирования, а грубая ошибка.

GSerg
Шаман
Шаман
 
Сообщения: 14286
Зарегистрирован: 14.12.2002 (Сб) 5:25
Откуда: Магадан

Сообщение GSerg » 03.05.2007 (Чт) 16:12

keks-n писал(а):кто-то

Я.

И сейчас скажу -- ручки отрывать.


jangle писал(а):Отсуствие завершения программы вызовом ExitProcess, не просто плохой стиль программирования, а грубая ошибка.

Перепутал полюса.
Надо так: наличие завершения программы на VB6 вызовом ExitProcess не просто плохой стиль программирования, а грубая ошибка.
Как только вы переберёте все варианты решения и не найдёте нужного, тут же обнаружится решение, простое и очевидное для всех, кроме вас

tyomitch
Пользователь #1352
Пользователь #1352
Аватара пользователя
 
Сообщения: 12822
Зарегистрирован: 20.10.2002 (Вс) 17:02
Откуда: חיפה

Сообщение tyomitch » 03.05.2007 (Чт) 16:16

jangle писал(а):Отсуствие завершения программы вызовом ExitProcess, не просто плохой стиль программирования, а грубая ошибка.

Чушь.

У рантайма VB полно своих ресурсов, которые при выходе из программы надо освободить. И это его ресурсы, а не ресурсы системы, поэтому сами собой они не освободятся.

Вот поэтому завершение программы на VB6 вызовом ExitProcess не просто плохой стиль программирования, а грубая ошибка. Когда рантайм решит, что он всё своё уже освободил, тогда он сам вызовет ExitProcess.


(когда писал, комментария от GSerg-а ещё не было)
Изображение

jangle
Википедик
Википедик
Аватара пользователя
 
Сообщения: 3013
Зарегистрирован: 03.06.2005 (Пт) 12:02
Откуда: Нидерланды

Сообщение jangle » 03.05.2007 (Чт) 17:04

Перепутал полюса.
Надо так: наличие завершения программы на VB6 вызовом ExitProcess не просто плохой стиль программирования, а грубая ошибка.


У рантайма VB полно своих ресурсов, которые при выходе из программы надо освободить. И это его ресурсы, а не ресурсы системы, поэтому сами собой они не освободятся.


Последний фраза просто жесть! :) Как могут ресурсы осовободится сами собой? Их система освобождает. Для этого и существует функция ExitProcess. Операционной системе абсолютно фиолетово, есть ли рантайм у приложения или его нет, она одинаково завершает программы написанные на VB и C++.


Вот описание этой функции из "WIN32 Programmer Reference"
Красным выделил, на что надо обратить внимание. По докам от Mикрософт функция ExitProcess - единственно правильный метод завершения процесса в Win32.


ExitProcess

ExitProcess is the preferred method of ending a process. This function provides a clean process shutdown. This includes calling the entry-point function of all attached dynamic-link libraries (DLLs) with a value indicating that the process is detaching from the DLL. If a process terminates by calling TerminateProcess, the DLLs that the process is attached to are not notified of the process termination.
After all attached DLLs have executed any process termination value, this function terminates the current process.

Terminating a process causes the following:

1. All of the object handles opened by the process are closed.
2. All of the threads in the process terminate their execution.
3. The state of the process object becomes signaled, satisfying any threads that had been waiting for the process to terminate.
4. The states of all threads of the process become signaled, satisfying any threads that had been waiting for the threads to terminate.
5. The termination status of the process changes from STILL_ACTIVE to the exit value of the process.



Terminating a process does not cause child processes to be terminated.
Terminating a process does not necessarily remove the process object from the operating system. A process object is deleted when the last handle to the process is closed.
The ExitProcess, ExitThread, CreateThread, CreateRemoteThread functions, and a process that is starting (as the result of a call by CreateProcess) are serialized between each other within a process. Only one of these events can happen in an address space at a time. This means the following restrictions hold:

· During process startup and DLL initialization routines, new threads can be created, but they do not begin execution until DLL initialization is done for the process.
· Only one thread in a process can be in a DLL initialization or detach routine at a time.
· ExitProcess does not return until no threads are in their DLL initialization or detach routines.

GSerg
Шаман
Шаман
 
Сообщения: 14286
Зарегистрирован: 14.12.2002 (Сб) 5:25
Откуда: Магадан

Сообщение GSerg » 03.05.2007 (Чт) 17:12

jangle, с моих программах вообще нет ни End, ни ExitProcess. Это -- правильно.
В программах на асме вызов ExitProcess встречается часто. Там это правильно.
Понимаешь ли ты это?
Как только вы переберёте все варианты решения и не найдёте нужного, тут же обнаружится решение, простое и очевидное для всех, кроме вас

tyomitch
Пользователь #1352
Пользователь #1352
Аватара пользователя
 
Сообщения: 12822
Зарегистрирован: 20.10.2002 (Вс) 17:02
Откуда: חיפה

Сообщение tyomitch » 03.05.2007 (Чт) 17:44

Отлично. Тогда будь добр, конкретизируй сказанное ранее:

jangle писал(а):Mикрософт придумала замечательную функцию ExitProcess, при ее вызове, уничтожением и выгрузкой используемых объектов займется сама система. При вызове этой функции, винда корректно пройдется по цепочке связанных объектов и поочередно удалит их

О каких объектах и каких цепочках идёт речь?


Ну и заодно:
Операционной системе абсолютно фиолетово, есть ли рантайм у приложения или его нет, она одинаково завершает программы написанные на VB и C++.

Поясни, зачем нужны такие функции, как CoUninitialize и WSACleanup? Кто и когда их должен вызывать?
Изображение

Avtopic
Постоялец
Постоялец
 
Сообщения: 442
Зарегистрирован: 30.09.2005 (Пт) 17:15
Откуда: Tbilisi

Сообщение Avtopic » 03.05.2007 (Чт) 17:52

jangle писал(а):Вызывай при выгрузке формы, API функцию ExitProcess, и будет тебе счастье ))

Мой взгляд: Описание ExitProcess продолжение мысли из описания TerminateProcess где начинается разговор о том что лучше использовать ExitProcess чем TerminateProcess. и если с этого угла прочитать приведенное описание ExitProcess, то в нем говорится как раз об этом, а не предлагается вызвать ExitProcess функцию всегда.

Во вторых, у меня другие формы еще открыты, так что мне нельзя ничего завершать кроме DB машины.

keks-n
Доктор VB наук
Доктор VB наук
Аватара пользователя
 
Сообщения: 2509
Зарегистрирован: 19.09.2005 (Пн) 17:17
Откуда: г. Москва

Сообщение keks-n » 03.05.2007 (Чт) 19:44

jangle
Может возникнуть ситуация, когда подгружен некий COM-объект. И он управляет неким ресурсом, который не принадлежит только ему(наследуемый хэндл пайпа или ещё что). При корректном уничтожении объекта с вызовом Release он проводит некие действия(причём необязательно связанные только с освобождением ресурса, там может быть ещё какое-нибудь оповещение другого процесса). При вызове ExitProcess действий этих не произойдёт(в то время как VB-шный рантайм всё корректно выгружает, делая нужные COM-вызовы). Следствие: это может нарушить работу других процессов, с которыми шла коммуникация.

Это всё условно, и не сильно имеет отношение к реальности. Просто, то, что такое завершение может вызвать сбой, является фактом.


P. S. ExitProcess, ИМХО, не сильно предназначен для прямого использования в ЯВУ, скорее, это функция для использования рантаймом оных.
Изображение

tyomitch
Пользователь #1352
Пользователь #1352
Аватара пользователя
 
Сообщения: 12822
Зарегистрирован: 20.10.2002 (Вс) 17:02
Откуда: חיפה

Сообщение tyomitch » 03.05.2007 (Чт) 20:09

keks-n, это не обязательно должен быть COM-объект: любая сущность, которая работает с ресурсами за пределами процесса, будет выгружена некорректно. Например, достаточно связи по TCP-протоколу, требующему явного завершения сеанса. (Открытые сокеты, кстати, по ExitProcess тоже закроются некорректно: shutdown на них сам собой не вызовется.) Семафоры тоже не будут освобождены сами собой. Ещё могут остаться временные файлы и записи в реестре, и/или не создаться нужные, которые должны создаваться при выходе. В общем случае, много чего может искривиться от выхода по ExitProcess.
Изображение

keks-n
Доктор VB наук
Доктор VB наук
Аватара пользователя
 
Сообщения: 2509
Зарегистрирован: 19.09.2005 (Пн) 17:17
Откуда: г. Москва

Сообщение keks-n » 03.05.2007 (Чт) 20:15

Я лишь привёл пример. См. последнее предложение второго абзаца. Это - основная мысль. :)
Изображение

jangle
Википедик
Википедик
Аватара пользователя
 
Сообщения: 3013
Зарегистрирован: 03.06.2005 (Пт) 12:02
Откуда: Нидерланды

Сообщение jangle » 03.05.2007 (Чт) 22:01

jangle, с моих программах вообще нет ни End, ни ExitProcess. Это -- правильно. В программах на асме вызов ExitProcess встречается часто. Там это правильно.
Понимаешь ли ты это?


Если у тебя в конце работы приложения, не вызывается ExitProcess каким образом ты можешь гарантировать, что все отображенные на адресное пространство DLL смогут получить через параметр fdwReason сообщение DLL_PROCESS_DETACH ?

В случае, если ты используешь многопоточную DLL, то попытка ее выгрузки без уведомления, скорее всего приведут к крашу. Это обычно происходит, когда закрывают приложение, а потом появляется сообщение об ошибке.

Или например, в твоей DLL запущен фоновый поток, и ты с помощью WaitForSingleObject ждешь его завершения, коректная выгрузка может быть только через ExitProcess, т.к. эта функция не возвращается до тех пор, пока есть потоки в их инициализациях DLL или отдельном исполнении. Если же ты выйдешь из процесса просто так, то опять же после выгрузки программы получишь краш.

Еще примеры приводить надо?

jangle
Википедик
Википедик
Аватара пользователя
 
Сообщения: 3013
Зарегистрирован: 03.06.2005 (Пт) 12:02
Откуда: Нидерланды

Сообщение jangle » 03.05.2007 (Чт) 22:12

Во вторых, у меня другие формы еще открыты, так что мне нельзя ничего завершать кроме DB машины


Ну тогда конечно нельзя, я думал у тебя происходит ошибка после закрытия твоего приложения, из-за некоректной выгрузки библиотек и ресурсов, поэтому и рекомендовал использовать ExitProcess

tyomitch
Пользователь #1352
Пользователь #1352
Аватара пользователя
 
Сообщения: 12822
Зарегистрирован: 20.10.2002 (Вс) 17:02
Откуда: חיפה

Сообщение tyomitch » 03.05.2007 (Чт) 22:19

jangle писал(а):Если у тебя в конце работы приложения, не вызывается ExitProcess каким образом ты можешь гарантировать, что все отображенные на адресное пространство DLL смогут получить через параметр fdwReason сообщение DLL_PROCESS_DETACH ?

Когда последний поток выходит, ExitProcess вызывается само собой. Сюрприз?

jangle писал(а):коректная выгрузка может быть только через ExitProcess, т.к. эта функция не возвращается до тех пор, пока есть потоки в их инициализациях DLL или отдельном исполнении.

Эта функция вообще никогда не возвращается. Сюрприз?

jangle писал(а):Еще примеры приводить надо?

Обязательно.
Изображение

GSerg
Шаман
Шаман
 
Сообщения: 14286
Зарегистрирован: 14.12.2002 (Сб) 5:25
Откуда: Магадан

Сообщение GSerg » 04.05.2007 (Пт) 14:57

Прекрасный пост в тему: http://blogs.msdn.com/oldnewthing/archi ... 83346.aspx
Как только вы переберёте все варианты решения и не найдёте нужного, тут же обнаружится решение, простое и очевидное для всех, кроме вас

tyomitch
Пользователь #1352
Пользователь #1352
Аватара пользователя
 
Сообщения: 12822
Зарегистрирован: 20.10.2002 (Вс) 17:02
Откуда: חיפה

Сообщение tyomitch » 04.05.2007 (Пт) 15:56

Угу. Это вторая часть серии. Первая: http://blogs.msdn.com/oldnewthing/archi ... 65433.aspx
Я хотел запостить эти ссылки, но решил сначала дождаться обещанного завершения серии.
Изображение

tyomitch
Пользователь #1352
Пользователь #1352
Аватара пользователя
 
Сообщения: 12822
Зарегистрирован: 20.10.2002 (Вс) 17:02
Откуда: חיפה

Сообщение tyomitch » 07.05.2007 (Пн) 6:46

Я не знаю, это уже конец серии или ещё нет, но в пятницу Чен привёл пример программы, которая зависает при выходе именно потому, что выходит через ExitProcess, а не как положено.
http://blogs.msdn.com/oldnewthing/archi ... 02028.aspx
Изображение

jangle
Википедик
Википедик
Аватара пользователя
 
Сообщения: 3013
Зарегистрирован: 03.06.2005 (Пт) 12:02
Откуда: Нидерланды

Сообщение jangle » 07.05.2007 (Пн) 10:07

Я не знаю, это уже конец серии или ещё нет, но в пятницу Чен привёл пример программы, которая зависает при выходе именно потому, что выходит через ExitProcess, а не как положено.


Ну не знаю, я всегда в своих программах использую ExitProcess, глюков никогда не было.

GSerg
Шаман
Шаман
 
Сообщения: 14286
Зарегистрирован: 14.12.2002 (Сб) 5:25
Откуда: Магадан

Сообщение GSerg » 07.05.2007 (Пн) 10:12

Значит не перешли программы определённый рубеж сложности.

Начинай двигаться в правильном направлении.
Как только вы переберёте все варианты решения и не найдёте нужного, тут же обнаружится решение, простое и очевидное для всех, кроме вас

След.

Вернуться в Visual Basic 1–6

Кто сейчас на конференции

Сейчас этот форум просматривают: AhrefsBot и гости: 45

    TopList