У меня есть управляемое MFC основанное на диалоговом окне приложение, созданное с MSVS2005. Вот моя проблема шаг за шагом. У меня есть кнопка на моем диалоговом и соответствующем обработчике щелчка с кодом как это:
int* i = 0;
*i = 3;
Я выполняю отладочную версию программы и когда я нажимаю на кнопку, фокус выгод Visual Studio и предупреждения "Исключение" местоположения записи нарушения прав доступа, программа не может восстановиться с ошибки и всего, что я могу сделать, должен прекратить отлаживать. И это - правильное поведение.
Теперь я включаю некоторый код инициализации OpenGL OnInitDialog()
метод:
HDC DC = GetDC(GetSafeHwnd());
static PIXELFORMATDESCRIPTOR pfd =
{
sizeof(PIXELFORMATDESCRIPTOR), // size of this pfd
1, // version number
PFD_DRAW_TO_WINDOW | // support window
PFD_SUPPORT_OPENGL | // support OpenGL
PFD_DOUBLEBUFFER, // double buffered
PFD_TYPE_RGBA, // RGBA type
24, // 24-bit color depth
0, 0, 0, 0, 0, 0, // color bits ignored
0, // no alpha buffer
0, // shift bit ignored
0, // no accumulation buffer
0, 0, 0, 0, // accum bits ignored
32, // 32-bit z-buffer
0, // no stencil buffer
0, // no auxiliary buffer
PFD_MAIN_PLANE, // main layer
0, // reserved
0, 0, 0 // layer masks ignored
};
int pixelformat = ChoosePixelFormat(DC, &pfd);
SetPixelFormat(DC, pixelformat, &pfd);
HGLRC hrc = wglCreateContext(DC);
ASSERT(hrc != NULL);
wglMakeCurrent(DC, hrc);
Конечно, это не точно, что я делаю, это - упрощенная версия моего кода. Хорошо теперь странные вещи начинают происходить: вся инициализация прекрасна, нет никаких ошибок в OnInitDialog()
, но когда я нажимаю кнопку... никакое исключение не выдается. Ничего не происходит. Вообще. Если я установил точку останова в *i = 3;
и нажмите F11 на нем, функция-обработчик сразу останавливается, и фокус возвращается к приложению, которые продолжают работать хорошо. Я могу нажать кнопку снова, и то же самое произойдет.
Кажется, что кто-то обработал, произошел исключение нарушения прав доступа и тихо возвратил выполнение в цикл получения сообщения главного приложения.
Если я комментирую строку wglMakeCurrent(DC, hrc);
, все хорошо работает как прежде, исключение выдается, и Visual Studio ловит его и показывает окно с сообщением об ошибке, и программа должна быть завершена впоследствии.
Я испытываю эту проблему в соответствии с 64-разрядным Windows 7, NVIDIA GEFORCE 8800 с последними драйверами (от 01.11.2010), доступными в установленном веб-сайте. Мой коллега имеет 32-разрядный Windows Vista и не имеет такой проблемы - исключение выдается и сбои приложения в обоих случаях.
Ну, надеюсь, что хорошие парни помогут мне :)
PS проблема первоначально, где отправлено под этой темой.
Хорошо, я нашел дополнительную информацию об этом. В моем случае это Windows 7, которая устанавливает KiUserCallbackExceptionHandler в качестве обработчика исключений перед вызовом моего WndProc и предоставлением мне управления выполнением. Это делается с помощью ntdll! KiUserCallbackDispatcher . Я подозреваю, что это мера безопасности, принятая Microsoft для предотвращения взлома SEH.
Решение состоит в том, чтобы обернуть ваш wndproc (или hookproc) фреймом try / except, чтобы вы могли поймать исключение до того, как это сделает Windows.
Спасибо Skywing на http://www.nynaeve.net/
Мы связались с nVidia по поводу этой проблемы, но они сказали, что это не их ошибка, а скорее Microsoft. Не могли бы вы рассказать, как вы обнаружили обработчик исключений ? И есть ли у вас дополнительная информация, например какие-то отзывы от Microsoft?
Я использовал команду "! exchangein" в WinDbg, чтобы получить эту информацию.
Во-первых, оба поведения правильные. Разыменование нулевого указателя - это «неопределенное поведение», а не нарушение гарантированного доступа.
Во-первых, выясните, связано ли это с генерацией исключения или только с доступом к нулевой ячейке памяти (попробуйте другое исключение).
Если вы сконфигурируете Visual Studio так, чтобы он останавливался при первом же нарушении доступа, не сломается ли он?
Вызовите VirtualQuery (NULL, ...) до и после glMakeCurrent и сравните. Возможно, нулевая страница драйверов VirtualAlloc nVidia OpenGL (плохая идея, но не невозможная или незаконная).
Вместо того, чтобы оборачивать WndProc или подключать все WndProc, вы можете использовать векторную обработку исключений: