Тема: Сообщения AutoCAD: "ENTERNAL ERROR: !U:\... dbobji.cpp@5619:eNotOpenForWrite" и "Error handler re-entered. Exiting now."

Уважаемые коллеги!
В AutoCAD загружены *.dbx и *.arx приложения.
Все работает нормально, но иногда вдруг выскакивает
сообщение:
"ENTERNAL ERROR: !U:\global\scr\ObjectDbx\DB\IMP\scr\
dbobji.cpp@5619:eNotOpenForWrite"
или:
"Error handler re-entered. Exiting now."
и AutoCAD с грохотом падает.
Перепроверил все что возможно.
Что это все значит?

Re: Сообщения AutoCAD: "ENTERNAL ERROR: !U:\... dbobji.cpp@5619:eNotOpenForWrite" и "Error handler re-entered. Exiting now."

Если это происходит после первого успешного использования какой либо команды, то скорее всего в ней происходит открытие AcDb... для чтения или записи, но после не предусмотрено закрытие ->close(). Повторное открытие базы, на мой взгляд, может породить подобные ошибки.

Re: Сообщения AutoCAD: "ENTERNAL ERROR: !U:\... dbobji.cpp@5619:eNotOpenForWrite" и "Error handler re-entered. Exiting now."

А мне кажется что дело в том что или в одном из arx-файлов (а может и dbx-файлов), которые используют другие custom entity примитив открывается на чтение, но с ним производится операция, которая может выполняться только в режиме записи.
Возможен и даже более вероятен другой вариант - в каком-то из методов custom entity вместо assertReadEnabled() стоит assertWriteEnabled(). Собственно говоря именно эта функция выдает такое сообщение и "роняет" AutoCAD, если объект не открыт для записи.

Re: Сообщения AutoCAD: "ENTERNAL ERROR: !U:\... dbobji.cpp@5619:eNotOpenForWrite" и "Error handler re-entered. Exiting now."

Думаю, что не достаточно тщательно ведётся контроль ошибок. Какой-то вызов прошёл неудачно, что не было вовремя обнаружено. По крайней мере, у меня подобные ошибки часто наблюдались до тех пор, пока я всерьёз не обеспокоился проверкой ошибок. Однозначно, после каждого вызова функции из Arx должен проверяться код ошибки, иначе приложение всегда будет работать нестабильно.

Re: Сообщения AutoCAD: "ENTERNAL ERROR: !U:\... dbobji.cpp@5619:eNotOpenForWrite" и "Error handler re-entered. Exiting now."

Спасибо всем за советы.
Я стараюсь следить за всеми ->close(),
assertReadEnabled(), assertWriteEnabled()и т.д.
Но все может быть, поэтому еще раз тщательно перепроверил: все чисто. Забыл добавить что после "ENTERNAL ERROR: !U:\global\scr\ObjectDbx\DB\IMP\scr\dbobji.cpp@5619:eNotOpenForWrite"
появляется сообщение:
Runtime error!
Program:......\Acad.exe
R6025
-pure virtual function call
(??????!!!!) что за бред
Тяжело смотреть на это. Почему Autodesk не выпустил хотя бы перечень сообщений с их интерпретацией, я уже не говорю об специальном отладчике?

Возможен и даже более вероятен другой вариант - в каком-то из методов custom entity вместо assertReadEnabled() стоит assertWriteEnabled(). Собственно говоря именно эта функция выдает такое сообщение и "роняет" AutoCAD, если объект не открыт для записи.

Сущая правда. В документации так и написано.
Есть правда один момент. Если у меня есть в
custom entity функция-обработчик, где из одних данных получаю другие, то я не  вызовал assertХХХ, как бесмысленную в данном случае. Кроме того, посмотрел некоторые примеры. С другой стороны, как быть в таком случае?
Спасибо

Re: Сообщения AutoCAD: "ENTERNAL ERROR: !U:\... dbobji.cpp@5619:eNotOpenForWrite" и "Error handler re-entered. Exiting now."

Почему Autodesk не выпустил хотя бы перечень сообщений с их интерпретацией, я уже не говорю об специальном отладчике?
-pure virtual function call
помойму тут все понятно. Если вылетает такое сообщение это значит что зовется из виртуальной таблицы метод, тело которого отсутствует.
Теперь по порядку чтоб стало ясно.
У тебя есть твои объекты? Т.е. custom objects?
Наверняка есть... раз летит такое сообщение.
Замени все assertReadEnabled(), assertWriteEnabled(), на assertReadEnabledMy() и assertWriteEnabledMy - поставь там try catch вокруг вызова соотвествующих assert...Enabled(). Теперь пользуй дебаг и call stack.
И еще, юзаешь ли ты чисто виртуальные метода?  интерфейсы?
Короче баг стопудово твой.
вот.

Re: Сообщения AutoCAD: "ENTERNAL ERROR: !U:\... dbobji.cpp@5619:eNotOpenForWrite" и "Error handler re-entered. Exiting now."

> KonstantinM
Спасибо за идею. Сейчас попробую.

И еще, юзаешь ли ты чисто виртуальные метода?

НЕТ

интерфейсы?

Что имеется ввиду под интерфейсом? Есть интерфейсный arx-модуль. В нем есть диалоговый
интерфейс.
Смущает то что если вставить один объект подряд
2-3 раза, то следующий вылетает. Если их вставлять
по одному все работает нормально.
Ощущение что где-то что-то не закрыто.

Re: Сообщения AutoCAD: "ENTERNAL ERROR: !U:\... dbobji.cpp@5619:eNotOpenForWrite" и "Error handler re-entered. Exiting now."

Думаю, что так оно и есть ... у меня было подобное поведение Автокада. Забывал вызывать close() для AcDbDictionary* и как только исправил - всё стало нормально. А, вот ёщё, после получал итератор (AcDbDictionaryIterator*) и забывал вызывать для него delete pIter; Видимо потому, что newIterator() никак не вызывал у меня ассоциацию с оператором new после вызовакоторого надо использовать delete. Ну а аналогичного ->close() для pIter не нашёл и успокоился ... а зря.

Re: Сообщения AutoCAD: "ENTERNAL ERROR: !U:\... dbobji.cpp@5619:eNotOpenForWrite" и "Error handler re-entered. Exiting now."

Сергей пишет:

Думаю, что так оно и есть ... у меня было подобное поведение Автокада

Я уже тоже могу так заявить. Сидя тупо уставившись на комп, прокручивал подряд все функции. И вдруг смотрю что какой-то pLyrTable открывается для чтения, и что-зто не виден ->close()! Глаза квадратными стали. Оказалось, как всегда, все просто. Давно написал функцию setLayer. Недавно решил ее немного подремонтировать и применить в этой проге (в интерфейсном arx приложении). Ну вот и результат ремонта.
Но смущает другое. Часть сообщений теперь понятна. Но причем здесь вызов чистой виртуальной функции? Да и первое сообщение не очень понятно. Эта злополучная функция находится ведь в интерфейсном arx приложении!
Всем огромная благодарность!

Re: Сообщения AutoCAD: "ENTERNAL ERROR: !U:\... dbobji.cpp@5619:eNotOpenForWrite" и "Error handler re-entered. Exiting now."

BS пишет:

Я стараюсь следить за всеми ->close(),

Лучше постарайся переложить этот труд на компилятор и используй интелектуальные указатели smartPointers<>
Окупаемость усилий фантастическая - о подобных багах думать перестанеш, если сделаеш по уму конечно wink

Re: Сообщения AutoCAD: "ENTERNAL ERROR: !U:\... dbobji.cpp@5619:eNotOpenForWrite" и "Error handler re-entered. Exiting now."

> Roman
Конечно, всегда в такой ситуации думаешь почему
компилятор за этим не следит, с другой стороны
он же не знает о существовании ObjectARX.
smartPointers<> я однажды применил (для NULL)
а для такого применения что-то не сообразил.
Где-то есть примеры на эту тему?
Спасибо

Re: Сообщения AutoCAD: "ENTERNAL ERROR: !U:\... dbobji.cpp@5619:eNotOpenForWrite" и "Error handler re-entered. Exiting now."

Сообщение о выове чисто виртуальной функции может лететь по трем случаям (как минимум).
1) Есть две завязанных dll - одну пересобрал, одну нет - получается что одна dll может дергать какое-нибудь гавно из другой.
2) Баг С++ компилятора.
Допустим есть интерфейс:
interface ISample
{
   void testFunc(MyType) = 0;
}
при этом в From1dll.h
#include "ISample.h"
#include "MyType.h"
class SampleSingleton : public ISample
{
void testFunc(MyType myType)
{
...
}
}
в From2dll.cpp
№include "ISample.h"
#include "MyType.h"
ISample* pSample = getSampleSingleton();
pSample->testFunc(myType);
Ну дак вот получается что компайлер и линкер все это прохавывает. Но есть в С++ такая особенность что если тип не указан, то переменная считается типом int. Вот и получается что ISample - компиляется с функцией которая принимает переменную int MyType - после этого при создании класса появляется метод уже с переменной MyType myType - все это компиляеца и компайлер не выдает баг что пытаетесь проинстанциировать абстрактный объект. При этом в виртуальной таблице есть абстрактный метод - который никуда ни указывает (чисто абстрактный). При попытке вызвать этот метод - появляется вышеследующее сообщение
-pure virtual function call
3) Третья причина - самая распространенная - это грязная кастовка указателей - с последующим дерганием методов и созерцанием оного сообщения.
4) По третьей причине может происходить такая ситуация. Указатель на что-то указывает в "жопу" (сорри, т.е. не инициализирован). Вы пытаетесь сделать что-то чтоб этот указатель присвоить (типа открыть объект и установить объект). Но !вдруг! объект не открывается - вы делаете return из метода и указатель продолжает указывать в "жопу". Далее этот указатель кастуется к чему то и у него дергаются метода... получается опять же знакомая картина.
Причем баг по причине 4) очень свойственен нутрям автокада. Т.е. стоит только что-то забыть закрыть - акад может вылететь N-различными способами.
Один из самых показательных примеров. Выделяем в акаде >2 объектов. Программно через erase() один объект убиваем. Далее пытаемся в акаде сдвинуть оставшиеся объекты... акад вылетает сразу и молча - даже не успевает оставить предсмерный assert/exception или табличку с предложением отправить информацию об ошибке - на деревню дедушке, не делает аварийные логи, не пытается аварийно записать файлики - короче смерть мгновенна и фатальна.

Re: Сообщения AutoCAD: "ENTERNAL ERROR: !U:\... dbobji.cpp@5619:eNotOpenForWrite" и "Error handler re-entered. Exiting now."

Если я не ошибаюсь - smartPointers<> из раздела COM программирования ... И кто б чего ни говорил, но программировать COM приложения на С++ не очень завидное занятие ... следить и проверять придётся не меньше, плюс наложаться баги от Autodesk и Microsoft (я имею ввиде не только падения приложения или клиента, но и торможение в непонятных случаях). Добавлю также, что COM слассы, предоставляемые Autodesk - это те же wrappers, а внутри всё то же, с чем имеем дело в ObjectARX классах. Поэтому если уж использовать wrappers, то .NET поудобнее будет, да и посвежее. А лучше ни то и ни другое не использовать, когда речь не идёт о пользовательском интерфейсе.

Re: Сообщения AutoCAD: "ENTERNAL ERROR: !U:\... dbobji.cpp@5619:eNotOpenForWrite" и "Error handler re-entered. Exiting now."

> Сергей
>Если я не ошибаюсь - smartPointers<> из раздела COM программирования
Вы ошибаетесь. Интелектуальные указатели одна из стандартных и широко используемых идиом С++. В том числе, они широко используют при программировании СОМ. Лично я не представляю, как можно программировать arx-приложения и не использовать интелектуальные указатели: отслеживания правильности вызововов close будет занимать все основные силы. Широкое использование интелектуальных указателей не требует каких-либо дополнительных усилий, но одним махом снимает проблему close.

Re: Сообщения AutoCAD: "ENTERNAL ERROR: !U:\... dbobji.cpp@5619:eNotOpenForWrite" и "Error handler re-entered. Exiting now."

> archimag
>Широкое использование интелектуальных
>указателей не требует каких-либо
>дополнительных усилий, но одним махом снимает проблему close.
Согласен, проблему close() снимает одним махом, но мир многообразен и появляется другая проблема - это области видимости и умения пользовать интел. указ. :)
Волей судьбы приходится еще работать и преподователем по С++ и С# - ну дак вот стал замечать, что люди которые пришли к C# минуя С++ - это те же самые Visual Basic Developers, которые могут что-то быстро слабать на коленках, но при этом ,во-первых, слабо представляют что же там внутрях реально происходит (доходит до того что люди могут писать серьезные программки, но не знать что такое куча и динамическая память), во-вторых, как-только натыкаются на баг типа - pure virtual function call, который летит из недр "НЕ МОЕГО КОДА", то честно думают что "БАГ ЛЕТЯЩИЙ НЕ ИЗ МОЕГО КОДА - ЭТО НЕ МОЙ БАГ, А БАГ МАЙКРОСОФТА!!!" и выглядят как безпомощные котята и не знают что делать...
Умение искать баги - это отдельный навык, который приобретается при использование "неусложненных" конструкций. Посему человек BS идет в правильном направлении :) Щас попарится с указателями и освобождением ресурса в виде close(), а потом уже дойдет и до и. указателей. Будет знать откуда у них ноги растут и зачем их едят :)

Re: Сообщения AutoCAD: "ENTERNAL ERROR: !U:\... dbobji.cpp@5619:eNotOpenForWrite" и "Error handler re-entered. Exiting now."

> archimag
"Лично я не представляю, как можно программировать arx-приложения и не использовать интелектуальные указатели"
Легко и непринуждённо, вопрос дисциплины: открыл закрыл, зато понятно когда AcDb...* , будет прибит. Смарт указатели это конечно удобно, но за удобство приходиться платить, как всегда. Кстати, а как насчёт отладки? Она столь же проста и удобна как "умные" указатели?

Re: Сообщения AutoCAD: "ENTERNAL ERROR: !U:\... dbobji.cpp@5619:eNotOpenForWrite" и "Error handler re-entered. Exiting now."

> Сергей
> зато понятно когда AcDb...* , будет прибит
При использовании интелектуальных указателей тоже ВСЕГДА понятно, когда объект будет "прибит": при выходе за пределы области видимости и это не такой сложный вопрос, как об этом говорит KonstantinM smile - это основа основ С++. Писать с использованием прямого вызова close относительно легко только небольшие функции, а в сложных, с возоможностью множественного выхода из функции (например, при возбуждении исключения), это просто кошмар.
>но за удобство приходиться платить
ЧЕМ? Они не занимают больше места, чем простые указатели. Даже стоимость вызова функции будет для большинства реализаций такой же, как для встроенных. Т.е. по эффективности они не уступают обычным, и при всём при этом сбывается "голубая мечта" - close вызывается компилятором! Это значительно упрощает алгоритмы и кардинально снижает количество ошибок.
>а как насчёт отладки
Кстати, интелектуальные указатели могут значительно облегчить отладку! В отладочной версии можно в реалзацию operator->() вставить проверку предусловия с выводом соответствующих диагностических сообщений.

Re: Сообщения AutoCAD: "ENTERNAL ERROR: !U:\... dbobji.cpp@5619:eNotOpenForWrite" и "Error handler re-entered. Exiting now."

> archimag
Абсолютно согласен
Чтобы долго не спорить мини-пример:

template<typename T>
class MySmartPrt
{
public:
    MySmartPrt() : object_(NULL) {}
    ~MySmartPrt()    {  close();    }
    Acad::ErrorStatus open(AcDbObjectId id, AcDb::OpenMode mode)
    {
        close();
        object_=0;
        return acdbOpenObject(object_, id, mode);
    }
    void close()
    {    
        if(object_){    object_->close(); object_=0;    }
    }
    T* operator->()        {    return object_;    }
    const T* operator->()const    {    return object_;    }    
private:
   T* object_;
};
//Теперь используем - Вариант1
void someFunc1(AcDbObjectId id)
{
    MySmartPrt<AcDbLine> line;
    if(line.open(id, AcDb::kForWrite)!=Acad::eOk) return;
    line->setStartPoint(...);
    line->setColorIndex(...);
    line.close();//закрываем принудительно
}
//Теперь используем - Вариант2
void someFunc2(AcDbObjectId id)
{
    MySmartPrt<AcDbLine> line;
    if(line.open(id, AcDb::kForWrite)!=Acad::eOk) return;
    /*some new logic
    */
    return;[b]//вот тут вся красота!!! Если использовать стандартный способ линия останется открытой
           //В нашем же случае всю работу сделает деструктор MySmartPrt[/b]
    line->setStartPoint(...);
    line->setColorIndex(...);
    line.close();[b]//закрываем принудительно
                //Наличие указателя не мешает мне принудительно закрывать объект[/b]
}

Re: Сообщения AutoCAD: "ENTERNAL ERROR: !U:\... dbobji.cpp@5619:eNotOpenForWrite" и "Error handler re-entered. Exiting now."

> Roman
Впечатляет. Хочу только добавить, что пока Microsoft и Autodesk не создадут специальный компилятор для ObjectARX эти и другие ошибки будут встречаться. Особенно у длинных и накрученных функций (+ комментарии). Все таки, мне кажется, это искусственный метод, за этим должен следить все таки компилятор.
Кому интересно, тема интелектуальных указателей хорошо описана в переводном издании книги Джефф Элджер, С++, Библиотека программиста. Хотя примеров там маловато.

Re: Сообщения AutoCAD: "ENTERNAL ERROR: !U:\... dbobji.cpp@5619:eNotOpenForWrite" и "Error handler re-entered. Exiting now."

Кстати в ObjectArx есть готовая реализация "умного" указателя. Это шаблон, называется AcDbObjectPointer и лежит в
dbobjptr.h.

Re: Сообщения AutoCAD: "ENTERNAL ERROR: !U:\... dbobji.cpp@5619:eNotOpenForWrite" и "Error handler re-entered. Exiting now."

При работе с базой данных Autodesk рекомендует  как можно скорее закрывать базу (не думаю, что они оберегают новичков от забывчивости). В этом случае, всё продемонстрированоо ранее изящество сводится на нет, т.к. принудительно вызвать close() интеллектуального указателя ничто не мешает, но только вот зачем ещё один "фантик" и в без того нешибко стройной конструкции как ObjectArx(). Эффективным применением обобщённого программирования в системе с ...тилетним наследием не разбалуешься.

Re: Сообщения AutoCAD: "ENTERNAL ERROR: !U:\... dbobji.cpp@5619:eNotOpenForWrite" и "Error handler re-entered. Exiting now."

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

Re: Сообщения AutoCAD: "ENTERNAL ERROR: !U:\... dbobji.cpp@5619:eNotOpenForWrite" и "Error handler re-entered. Exiting now."

Г-н Джон Роббинс (консультант по отладке) считает catch весьма полезным для своего банковского счёта, но очень небезопасным и рекомендует воздерживаться от использования.

Re: Сообщения AutoCAD: "ENTERNAL ERROR: !U:\... dbobji.cpp@5619:eNotOpenForWrite" и "Error handler re-entered. Exiting now."

> Сергей
>При работе с базой данных Autodesk
>рекомендует как можно скорее закрывать базу
Да кто-же спорит. Ну поставь, просто, в нужном месте пару фигурных скобок, ограничивающих область видимости, и всё! Это же элементарно...
>Эффективным применением обобщённого >программирования в системе с ...тилетним >наследием не разбалуешься.
Вы не любите кошек? Вы просто не умеете их готовить!!! Ещё как разболуешься! Я занимаюсь этим последний год и очень доволен результатом. Обобщённое программирование рулит даже применительно к такому диназавру как ObjectArx (кстати, вы не замечали, что Autodesk тоже его использует?).
>Г-н Джон Роббинс...
Да бог с ним, с этим господином (никогда о нём не слышал), весь мир уже понял, что исключения весьма эффективный инструмент, значительно облегчающий такое нелёгкое дело, как обработка ошибок и значительно повышающий надёжность программ (естественно, при грамотном использовании). Я уже как то говорил, что комбинация интелектуальных указателей и исключений, применительно к ObjectArx, способна по крайней мере вдвое сократить размер код и многократно повысить его надёжность. Проверено на собственном опыте.

Re: Сообщения AutoCAD: "ENTERNAL ERROR: !U:\... dbobji.cpp@5619:eNotOpenForWrite" и "Error handler re-entered. Exiting now."

> archimag
Безспорный плюс иу - в том что при вылетании исключения - таки будет закрыт объект.
Но могу поспорить что в надежности программы иу играют далеко не главную роль. Есть набор элементарных правил при написании кода, соблюдая которе ваша программа без STL, шаблонов, иу и прочего - станет гораздо надежней чем та же программа написанная со всеми этими прибамбасами, но без использования этих правил.
В частности есть набор правил конечного автомата. 1) Все возможные ветки конечного автомата, которые вы не обрабатываете - должны быть перекрыты assert-ом. 2) При использовании критического ресурса конечный автомат должен иметь обязательно одну точку входа и выхода и исполнение кода должно обязательно пройти через эти точки.
В соответсвтии с пунктом два - если внутри функции с критическим ресурсом есть >1 return, то это так же небезопасно как есть грязными руками - в большенстве случаев прокатит, но может и не повезти.
ИУ - это совсем не плохо, но вот плох лозунг, что "используя ИУ - вы можете забыть о ..." Нельзя забывать... Лучше написать такой ИУ, который будет проверять в деструкторе, что Ваш объект все еще открыт, а ссылок вроде на него уже как и нет и кидать assert...  разбирайтесь мол где у Вас что-то не закрылось.
Методы типа:
f()
{
SmartPtr<CriticalResource*> pSrc(resId);
...
return;
if (...)
   return;
for(...)
{
   if ( ... )
      return;
}
return;
}
надо гнобить на корню, ИУ - в этом случае это гнилая отмазка!!!