2013-07-10 2 views
1

Я использую MSVS 9 (VS 2008). Мое приложение, а также общая библиотека (dll) (я использую для связи с моим приложением) также имеют среду C++. Теперь соблюдайте следующие случаи:Режим деблокирования Vs Режим DEbug в MS Visual Studio Windows

  1. когда разделяемая библиотека/DLL построен в режиме отладки и мое приложение также встроена в режиме отладки Результат: Приложение успешно выполнена

  2. когда разделяемой библиотеки/DLL построен в режиме выпуска и мое приложение также встроен в режиме выпуска Результат: Приложение успешно выполнена

  3. когда разделяемая библиотека/DLL построен в режиме выпуска и мое приложение также встроена в режиме отладки Результат: приложение терпит крах без загрузки каких-либо символов из стека вызовов.

    стека вызовов:!

    ntdll.dll 76e94684()
    [Фреймы ниже могут быть неправильными и/или отсутствует, никакие символы, загруженные для ntdll.dll]

    ntdll.dll 76e7d55f()
    ntdll.dll! 76e5fa18()
    ntdll.dll! 76e2b3c8()

Эта проблема наблюдается, когда я пытаюсь использовать следующую SetName () и GetName() в моем приложении.

using namespace std; 
    void main() 
    { 
     Schema * schemaExp = new Schema(); 
     schemaExp -> SetName("ExpSchema"); 
     string srctable; 
     srctable=schemaExp->GetName(); 
     cout <<"\nConnection EXPORT using the target table:" << srctable.c_str() << endl; 
     delete schemaExp; 
    } 

схемы Определение класса:

using namespace std; 
    class Schema 
    { 
     public: 
     TELAPI_EXPORT void SetName(char *name); 
     TELAPI_EXPORT string  GetName(); 
     protected: 
     string tableName; 
    }; 
    void Schema::SetName(char *name) 
    { 
     string str(name); 
     tableName = str; 
    } 
    string Schema::GetName() 
    { 
     return tableName; 
    } 

Примечание: Выше один лишь часть из моего приложения и мое приложение получает сбой только в # 3 и работает нормально с # 1 и # 2 случаи выше

Пожалуйста, помогите мне в решении этой проблемы. Любая помощь очень ценится.

Заранее благодарен.

ответ

3

, когда разделяемая библиотека/dll построена в режиме деблокирования, и мое приложение также построено в режиме отладки. Результат: приложение разбивается без загрузки каких-либо символов из стека вызовов.

Это потому, что это не поддерживаемая конфигурация. По умолчанию целевые параметры отладки и выпуска ссылаются на разные версии CRT, которые (среди прочего) используют разные стратегии для выделения памяти и несовместимы друг с другом.

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

Для этого есть обходные пути, но для них нужно много работать. По сути, вы убедитесь, что все выделение памяти изолировано в пределах одной DLL, так что ничто не пересекает границы модулей.Вам нужно будет экспортировать определенные функции из библиотеки DLL, чтобы выделить и освободить память, чтобы гарантировать, что диспетчер кучи, который выделяет память, является тем же самым, который уничтожает его. Вы не можете полагаться на это, когда вы используете операторы new и delete. Честно говоря, в этом случае я не вижу, как все эти усилия покупают вам что-нибудь полезное.

Обратите внимание, что это не связано с включением или отключением оптимизаций (по умолчанию они предназначены для версий Release и не находятся в сборках Debug). Этот параметр является ортогональным к версии CRT, которая связана. Так получилось, что цели «Отладка» и «Релиз» подразумевают несколько вариантов. Вы можете включить оптимизацию для одного проекта и отключить его для другого, и это должно работать, если вы убедитесь, что оба они ссылаются на одну и ту же версию CRT. Но опять же, я не могу понять, что нужно делать, и hellip: если вы хотите, чтобы оптимизация была включена для одного, почему вы хотите, чтобы они были подавлены для другого?

Похожие: Mixing debug and release library/binary - bad practice?

+0

, когда я комментирую *** delete schemaExp; ***, я не получаю вышеуказанную ошибку ... полностью путают с таким поведением – ybc

+1

Это имеет смысл, если проблема заключается в несоответствии стратегий распределения памяти. Удаление памяти, выделенной другим менеджером кучи, является неопределенным поведением. –

+0

для вас вопрос: если вы хотите, чтобы оптимизация была включена для одного, почему вы хотите, чтобы они были подавлены для другого? Я хочу сказать, если предоставленные dlls построены в режиме выпуска, и я написал собственное приложение и построил приложение, связанное с DLL, теперь, если мне нужно отлаживать собственный код для любой проблемы, мне нужно создать мое приложение в режиме Debug и как вы сказали, это приводит к конфликту с ЭЛТ. Как действовать в таком случае? – ybc

1

Это не должно быть сбой, только все же, как правило, вы получите перерыв отладки внутри диспетчера памяти Windows, чтобы предупредить вас, что ваша программа разрушает кучу. Особенность отладочной кучи в Windows, доступная в Vista и выше. Посмотрите в окне вывода сообщения.

Также важно включить сервер символов, чтобы трассировка стека стала читаемой и точной. Сделайте это с помощью Tools + Options, Debugging, Symbols и установите флажок перед предопределенным именем сервера msdl.microsoft.com. Выберите хороший каталог для хранения символов. Когда вы снова запустите свою программу, она будет катиться на некоторое время, прежде чем она начнет работать, загрузив файлы символов. Это происходит только один раз. Теперь вы должны получить высокочитаемую трассировку стека, которая теперь также возвращается к вашему методу main().

Что вы в общем открываете, так это то, что разоблачение классов C++ через границы модулей - сложный бизнес. Более чем одно может пойти не так, один из режимов отказа здесь состоит в том, что объект класса Schema не имеет одинакового размера по обе стороны границы DLL. Это связано с настройкой сборки Debug, вопрос _HAS_ITERATOR_DEBUGGING #define. Он включен по умолчанию в сборке Debug, отключен в сборке Release. Хорошая функция отладки, но единственным способом, который они могли реализовать, было добавление полей в стандартные классы библиотеки C++. Что делает std :: string больше в сборке Debug. Это делает ваш класс Scheme более крупным. Вы сейчас обходите эту проблему, режим сбоя - это версия Debug DLL с версией Release EXE. Конструктор класса Scheme затем испортит кучу, когда она инициализирует строку, потому что распределение для объекта было недостаточно большим.

Еще один режим отказа - это то, что у вас есть две версии CRT в вашем процессе, отладочная версия вашего приложения и версия выпуска в вашей DLL. Они не будут использовать одну и ту же кучу для выделения. Который пойдет не так, когда вы выделите в одном и выпустите в другом. Строка, возвращаемая вашим методом GetName(), страдает от этой проблемы, она была создана в методе GetName() внутри DLL и будет уничтожена после вызова метода в вашем EXE. Неправильным распределителем. Повреждение кучи этих причин не обнаружено, пока вы снова не сделаете что-то с кучей, например, удалите объект Scheme. Вы также вызовете этот режим сбоя, если вы не создадите код с помощью/MD. Эта проблема была рассмотрена в VS2012, все распределения теперь сделаны из кучи процесса по умолчанию.

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

Но обратите внимание, что в будущем у вас могут быть проблемы, у DLL есть возможность жить собственной жизнью и может когда-нибудь использоваться приложением, которое было создано с другой версией компилятора. Тогда Кабум.Проектирование вашего DLL-интерфейса, так что это может быть никогда не возможно, возможно, вам придется отказаться от выставления объектов C++. Интерфейс C-стиля - это откат, так как COM работает для поднятия этого объекта в объектную модель, также является хорошим подходом. Конечно, это довольно драконов, только подумайте об этом, если вы не можете гарантировать, что EXE и DLL всегда создаются и развертываются одновременно.

+0

Для того, чтобы вы предложили включить сервер символов (Инструменты + Параметры, Отладка, Символы и отметьте флажок перед предопределенным именем сервера msdl.microsoft.com.) Я не могу наблюдать за каким-либо предопределенным именем сервера в символов. – ybc

Смежные вопросы