2016-02-23 2 views
0

Некоторое время назад я написал приложение Windows Form C++ CLI, которое отлично скомпилировано в Visual Studio 2013. Теперь мне захотелось перекомпилировать его в Visual Studio 2015 Update 1, но я столкнувшись с проблемой, и после нескольких часов испытаний я выяснил, что виновником является afxwin.h.Проблемы с afxwin.h в Visual Studio 2015 Приложение Windows Form


TL; DR - Есть ли способ, что я могу использовать stdafx.h (так afxwin.h и все другие виды импорта, приезжающие с ним) в приложении форме Windows, скомпилированные с помощью Visual Studio 2015 без необходимости аварии приложение при запуске?

Вот как воспроизвести те же проблемы, с которыми я столкнулся в своем приложении.

Поскольку форма Windows, больше не доступен в качестве шаблона проекта в VS2015, я создал CLR Пустой проект под названием Test

Ctrl-Shift-A добавить UI>Windows Form под названием MyForm

В MyForm.cpp я добавил этот:

#include "MyForm.h" 

using namespace System; 
using namespace System::Windows::Forms; 

[STAThread] 
int main(cli::array<System::String^>^ args) 
{ 
    Application::EnableVisualStyles(); 
    Application::SetCompatibleTextRenderingDefault(false); 
    Test::MyForm form; 
    Application::Run(%form); 
} 

Под Configuration Properties>Linker>Расширенный я установить точки входа в главный

Под Свойства конфигурации>Linker>системы я установить Subsystem до Windows (/ SUBSYSTEM/WINDOWS)

COMPILE (DEBUG КОНФИГУРАЦИЯ): компилируется без ошибок/предупреждений

RUN: работает без каких-либо проблем.

Теперь попробуйте добавить afxwin.h в MyForm.каст:

#include <afxwin.h> 

Под Свойства конфигурации>Генеральный я установить Использование MFC для использования MFC в общей библиотеке DLL

COMPILE (DEBUG КОНФИГУРАЦИЯ): не компилируется нет ошибки/предупреждения

RUN: приложение обыкновение даже начать, он просто показывает Debug Assertion Failed ошибка в выражении _CrtIsValidHeapPointer (блок)

enter image description here enter image description here enter image description here Теперь, чтобы исправить эту ошибку, я обнаружил, что это необходимо, чтобы удалить точки входа, так:

Под Свойства конфигурации>Linker>Расширенный я извлекал Точка входа значение (которое я ранее установлен в основной)

COMPILE (DEBUG КОНФИГУРАЦИЯ): компилируется без ошибок/предупреждений

RUN: снова приложение обыкновение даже начать, он больше не показывает Сбой отладки, но System.AccessViolationException в неизвестном модуле и «Попытка чтения или записи защищенной памяти. Это часто указывает на то, что другая память повреждена.»

enter image description here enter image description here enter image description here enter image description here Эти ошибки я получаю в мое приложение, и я задаюсь вопросом, как это возможно, что просто в том числе afxwin.h дает все эти проблемы в VS2015 в то время как оно не в VS2013.

что я могу сделать, чтобы исправить это, не возвращаясь к VS2013?

ответ

1

: C во время выполнения библиотека была значительно переписана для VS2015 Джеймсом Макнеллисом. Он большой поклонник C++, новый код, который он написал, страдает от хронической проблемы SIOF, которая так распространена в программе на C++. Статический порядок инициализации Fiasco, безусловно, присутствовал и в вашем проекте VS2013, но, возможно, не байт, исходный код CRT был выставлен SIOF в течение многих лет, поэтому он мог бы вести себя лучше.

Чрезмерно сложно отладить в этом случае код, который не работает, происходит из файла исходного кода CRT, который не включен в установку с именем thread_safe_statics.cpp. Не 100% уверены, что он дал, что нет исходного кода для просмотра, но имя файла оставляет мало для воображения.

MFC имеет статическое состояние, которое должно быть инициализировано до его использования.В частности, программа должна иметь статическую переменную CWinApp, которая инициализируется в Just Right Right. Для этого требуется, чтобы точка входа была WinMain(), реализованная в MFC, и явное объявление экземпляра CWinApp в исходном коде. Как это:

[STAThread] 
int main(cli::array<System::String^>^ args) 
{ 
    Application::EnableVisualStyles(); 
    Application::SetCompatibleTextRenderingDefault(false); 
    Application::Run(gcnew Test::MyForm); 
} 

class MyMfcApp : public CWinApp { 
public: 
    virtual int Run() override { 
     return main(__nullptr); 
    } 
} MyApp; 

Сброс EntryPoint компоновщика задерживая его по умолчанию (пустой), так что CRT инициализируется первой и функции WinMain МФЦ проходит рядом. И будьте осторожны, я взял ярлык, вы не получите args. И я исправил ошибку в вашей функции main(), она неправильно использовала семантику стека.

Этот хак снова запускает вашу программу. Является ли это фактически правильным является довольно сомнительным. Это страдает от синдрома «Кто такой босс», который связан с большими каркасами. Не зависимо от того, какое окно MFC работает правильно, поскольку это Winforms, который отправляет сообщения. Но у вас также должна была быть проблема в VS2013. «Не делай этого» - единственный солидный совет.

+0

Спасибо за подробное объяснение, приведенный вами код исправляет проблему, и мое приложение снова работает! Просто небольшое примечание: необходимо оставить поле * Entry Point * ** пустым ** в * Linker *> * Advanced * configuration, в противном случае ** Debug Assertion Failed ** ошибка повторится. – Fabius

+0

Извините, вы правы, я действительно тестировал его по умолчанию. Инициализация CRT должна быть первой, WinMain MFC должен быть следующим. –

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