DestroyWindow Access Violation

Started by
12 comments, last by pex22 19 years, 4 months ago
Ok, i dont like this. in my Window::close() function, it does everything ok exept DestroyWindow() i get access violation when i call DestroyWindow, and dont get when i do:
#ifdef hwnd
DestroyWindow(hwnd);
#endif
or
HWND t;
t=this->hwnd;
#ifdef t
DestroyWindow(hwnd);
#endif
but the problem is, it doesn't call DestroyWindow so it looks like nothing happened.. but, i get access violation when i do:
if (hwnd)
DestroyWindow(hwnd);
btw, hwnd = this->hwnd. i already created my window, and i dont get access violation when i call:
	char* h="";
	GetClassName(hwnd,h,256);
what should i do? i really dont get how hwnd isn't defined but it is not a zero and i already used it to get the class name..so why i cant use it to destroy itself (the window)? i have tried to call GetLastError() after DestroyWindow() but it wasn't called. thanks, pex.
pex.
Advertisement
The problem with pre-processor commads is, that they are executed at compile time and thus cannot do anything at runtime.
You can simply use
if (IsWindow(hwnd)) {    DestroyWindow(hwnd);}
Are you sure you are not calling DestroyWindow twice with the same handle? I would set hwnd to NULL after calling DestroyWindow, then worst case and it is getting called twice it would still be safe.

Also, your #ifdef solutions are simple wrong. #ifdef is for testing preprocessor tokens, not variables for being vaild/null. #ifdef hwnd is always evaluating to false, so the DestroyWindow(hwnd) is not even getting compiled into your program.

The best way to figure this out is to set a breakpoint on the DestroyWindow statement. Check that hwnd is still valid, and also check you dont get to that breakpoint twice.

Alan
"There will come a time when you believe everything is finished. That will be the beginning." -Louis L'Amour
ok, i have tried that now (both Alan and darookie tips, thanks).
but i get Access Violation again in same address (cmp dword ptr [eax+58h],0)
i dont have to make hwnd a pointer, right? or i do have?
pex.
You don't need to make hwnd a pointer.

I didn't think you could get access violations, or indeed any other type of exceptions, with DestroyWindow. I thought errors were returned in the return value of the function.

The
(cmp dword ptr [eax+58h],0)
may be part of the windows DLLs.
cmp dword ptr [eax+58h],0 can also be a check if hwnd == 0 or something from hwnd == 0..
the errors returned are in GetLastError(), the function only returns 0 or a nonzero number.
Here is what i did:
main.cpp (console.cpp):
// console.cpp : Defines the entry point for the console application.////#include "stdafx.h"#include "c:\\pex\\tribox\\stdafx.h"//#include <stdio.h>#pragma comment(lib,"c:\\pex\\tribox\\release\\tribox.lib")int main(int argc, char* argv[]){	Window win;	win.createFS();	win.toggle();	win.run();	return 0;}

now, inside the library (i skip functions that weren't used)
	Window()			{hRC=0;hwnd=0;hDC=0; bits=24;						 width=height=250; x=320; y=250;						 title="Tribox Engine Demo";}int Window::createFS(char* t,...){	char text[256];	enumAll();	va_list ap;	fullscreen=0;	if (!t)		t="Tribox Engine Demo";	va_start(ap,t);		wvsprintf(text,t,ap);	va_end(ap);	fullscreen=1;	title = text;	WNDCLASSEX	wc;	DWORD		dwExStyle;	DWORD		dwStyle;    wc.cbSize        = sizeof(WNDCLASSEX);    wc.style         = 0;    wc.lpfnWndProc   = SWndProc;    wc.cbClsExtra    = 0;    wc.cbWndExtra    = 0;    wc.hInstance     = this->hInstance;    wc.hIcon         = LoadIcon(NULL, IDI_APPLICATION);    wc.hCursor       = LoadCursor(NULL, IDC_ARROW);    wc.hbrBackground = (HBRUSH)(COLOR_WINDOW);    wc.lpszMenuName  = NULL;    wc.lpszClassName = title;    wc.hIconSm       = LoadIcon(NULL, IDI_APPLICATION);	if (!RegisterClassEx(&wc))		return 1;	this->wc = wc;	DEVMODE dmScreenSettings;	ZeroMemory(&dmScreenSettings, sizeof(dmScreenSettings));	dmScreenSettings.dmSize = sizeof(dmScreenSettings);	dmScreenSettings.dmPelsWidth = this->width;	dmScreenSettings.dmPelsHeight = this->height;	dmScreenSettings.dmBitsPerPel = bits;	dmScreenSettings.dmFields = DM_BITSPERPEL|DM_PELSWIDTH|DM_PELSHEIGHT;	long ret = ChangeDisplaySettings(&dmScreenSettings,CDS_FULLSCREEN);	if(ret != DISP_CHANGE_SUCCESSFUL)	{		EnumDisplaySettings(0,ENUM_CURRENT_SETTINGS,&dmScreenSettings);		ret = ChangeDisplaySettings(&dmScreenSettings,CDS_FULLSCREEN);		if (ret != DISP_CHANGE_SUCCESSFUL)			return 0;	}	dwExStyle = WS_EX_APPWINDOW;	dwStyle	  = WS_POPUP;	hideMouse();	this->hwnd=CreateWindowEx(dwExStyle,this->wc.lpszClassName,title,							 WS_CLIPSIBLINGS|WS_CLIPCHILDREN|dwStyle,							 0,0,width,height,0,0,hInstance,0);	if (this->hwnd==0)		return 0;	ShowWindow(this->hwnd,SW_SHOW);	UpdateWindow(this->hwnd);	return 1;}int Window::toggle(){	if (fullscreen)		enumAll();	close();	fullscreen=!fullscreen;	WNDCLASSEX	wc;	DWORD		dwExStyle;	DWORD		dwStyle;	hInstance=0;    wc.cbSize        = sizeof(WNDCLASSEX);    wc.style         = 0;    wc.lpfnWndProc   = SWndProc;    wc.cbClsExtra    = 0;    wc.cbWndExtra    = 0;    wc.hInstance     = this->hInstance;    wc.hIcon         = LoadIcon(NULL, IDI_APPLICATION);    wc.hCursor       = LoadCursor(NULL, IDC_ARROW);    wc.hbrBackground = (HBRUSH)(COLOR_WINDOW);    wc.lpszMenuName  = NULL;    wc.lpszClassName = title;    wc.hIconSm       = LoadIcon(NULL, IDI_APPLICATION);	if (!RegisterClassEx(&wc))		return 0;	this->wc = wc;	if (fullscreen)	{		DEVMODE dmScreenSettings;		ZeroMemory(&dmScreenSettings, sizeof(dmScreenSettings));		dmScreenSettings.dmSize = sizeof(dmScreenSettings);		dmScreenSettings.dmPelsWidth = this->width;		dmScreenSettings.dmPelsHeight = this->height;		dmScreenSettings.dmBitsPerPel = bits;		dmScreenSettings.dmFields = DM_BITSPERPEL|DM_PELSWIDTH|DM_PELSHEIGHT;		long ret = ChangeDisplaySettings(&dmScreenSettings,CDS_FULLSCREEN);		if(ret != DISP_CHANGE_SUCCESSFUL)		{			EnumDisplaySettings(0,ENUM_CURRENT_SETTINGS,&dmScreenSettings);			ret = ChangeDisplaySettings(&dmScreenSettings,CDS_FULLSCREEN);			if (ret != DISP_CHANGE_SUCCESSFUL)				return 0;		}		dwExStyle = WS_EX_APPWINDOW;		dwStyle	  = WS_POPUP;		hideMouse();	}	else	{		dwExStyle = WS_EX_APPWINDOW|WS_EX_WINDOWEDGE;		dwStyle   = WS_OVERLAPPEDWINDOW;		RECT winRect;		winRect.left = 0;		winRect.right = width;		winRect.top = 0;		winRect.bottom = height;		AdjustWindowRectEx(&winRect,dwStyle,FALSE,dwExStyle);	}	this->hwnd=CreateWindowEx(dwExStyle,this->wc.lpszClassName,title,							 WS_CLIPSIBLINGS|WS_CLIPCHILDREN|dwStyle,							 x,y,width,height,0,0,hInstance,0);	if (this->hwnd==0)		return 0;	ShowWindow(this->hwnd,SW_SHOW);	UpdateWindow(this->hwnd);	return 1;}void Window::close(){	if (this->hRC)		removeOpengl();	if (fullscreen)	{		ChangeDisplaySettings(0,0);		showMouse();	}	char* h="";	GetClassName(hwnd,h,256);	if (hwnd)		DestroyWindow(hwnd);	hwnd=0;	UnregisterClass(h,hInstance);}void Window::removeOpengl(){	if (hRC)	{		wglMakeCurrent(0,0);		wglDeleteContext(hRC);		hRC=0;	}	if (hwnd && hDC)	{		ReleaseDC(hwnd,hDC);		hDC=0;	}}


thx, pex.
pex.
char text[256];enumAll();va_list ap;fullscreen=0;if (!t)	t="Tribox Engine Demo";va_start(ap,t);	wvsprintf(text,t,ap);va_end(ap);fullscreen=1;title = text;

You leave title pointing to random memory when this function finishes because text is a local array. JUSS (just use std::string)!

Enigma
strcmp(win.getTitle(),"Tribox Engine Demo") returns zero, so what's wrong with title (win.getTitle())?

edit: I just found that I don't get the access violation error if i comment GetClassName(), or if i comment DestroyWindow()
i have an other way to get the class name, so i probably will this way.
but i still cant understand what is the reason for that.
in past i remember i wasn't using GetClassName() but got the access violation error.
weird.

[Edited by - pex22 on December 14, 2004 10:41:26 AM]
pex.
Beware the difference between "working" and "correct". Using a pointer to access a variable that no longer exists is undefined behaviour. Undefined behaviour means it may well do exactly what you want... for now. Observe:
#include <iostream>void func(char*& string){	char text[16];	text[0] = '!';	text[1] = '\0';	string = text;}void print(char*& string){	int dummy[4];	std::cout << string << '\n';}int main(){	char* string;	func(string);	print(string);}

This code "works" on every compiler I tested it on. It prints '!'. However, it is not correct. A small change to the print function yields completely different behaviour:
#include <iostream>void func(char*& string){	char text[16];	text[0] = '!';	text[1] = '\0';	string = text;}void print(char*& string){	int dummy[4];	dummy[0] = 48;	std::cout << string << '\n';}int main(){	char* string;	func(string);	print(string);}

It now prints '0' on every compiler I tested it on.

I just spotted another bug in your code:
char* h="";GetClassName(hwnd,h,256);

GetClassName expects you to pass it a buffer and the number of characters it's allowed to write to that buffer. In this case you've told it that it's safe to write upto 256 characters to the buffer, but the buffer you pass is not 256 characters long. It may not even be writeable! It is a constant array of characters of length 1. This code should be e.g.:
char className[256];GetClassName(hwnd, className, 256);

This correctly passes a 256 character writeable buffer.

Enigma
hm..right...
i used strcpy() instead, is that ok?
and i found that i keep a WNDCLASSEX in Window class so i used it instead of GetClassName
so, now i dont get acceess violation error and all functions works fine [smile], exept one :(
i wrote printf("%d\n",GetLastError()); in the WndProc (SWndProc), and in Window::close() i wrote printf(wc.lpszClassName);printf("\n");

when i call win.create(or createFS)() only, in console i see a lot of 0s and the class name ("Tribox Engine Demo"). (then it quits the program, as it suppose to do)
when i add win.toggle(), i get same chars but now i get it twice (because i first created a window, then closed it and now created again.) (then, quits. of course, no main loop.)
however, when i add win.run(), in the middle of the second window i get "Out of loop!" message and program ends up. (this message is called after:
while(GetMessage(&msg, NULL, 0, 0) > 0)
{
TranslateMessage(&msg);
DispatchMessage(&msg);
})

However, when i just call win.create(or createFS)() and win.run(), everything run fine.
win.toggle now is just:
int Window::toggle(){	if (!togglerogl()) // called to re-initialize opengl automatically		return 0;  // if opengl was called	fullscreen=!fullscreen;	if (fullscreen)		return createFS(title);	else		return create(title);}

the only non-0 i have seen is when i call just create() and run()--and the number is 183 (i think) which means cannot create the file because its already exists, or something like that. so i guess its not something serious, right? i get it only once (per application with just create() and run()).

thanks in advance,
pex.

[Edited by - pex22 on December 15, 2004 4:43:20 AM]
pex.

This topic is closed to new replies.

Advertisement