Sign in to follow this  
Rattrap

Problem With SetWindowLongPtr

Recommended Posts

Rattrap    3385
I've been writing a Win32 wrapper class. I was implementing some code to handle the borders of an object.
void Control::SetBorderStyle(const KS::GUI::BorderStyle _BorderStyle)
{
	//	SetLastError here is to help check for an error if GetWindowLongPtr returns a 0 as the actual value.  If GetLastError also returns a 0 when the original value was 0, then we know it wasn't an error.
	SetLastError(0);
	DWORD _ExtendedWindowStyles(GetWindowLongPtr(m_WindowHandle, GWL_EXSTYLE));
	if(_ExtendedWindowStyles == 0)
	{
		const DWORD _Error(GetLastError());
		if(_Error != 0)
		{
			throw std::exception("GetWindowLongPtr() failed.");
		}
	}

	//	Remove the 3d edge, if it exists
	if((_ExtendedWindowStyles & WS_EX_STATICEDGE) == WS_EX_STATICEDGE)
	{
		_ExtendedWindowStyles -= WS_EX_STATICEDGE;
	}

	SetLastError(0);
	DWORD _WindowStyles(GetWindowLongPtr(m_WindowHandle, GWL_STYLE));
	if(_WindowStyles == 0)
	{
		const DWORD _Error(GetLastError());
		if(_Error != 0)
		{
			throw std::exception("GetWindowLongPtr() failed.");
		}
	}

	//	Remove fixed edgem, if it exists
	if((_WindowStyles & WS_BORDER) == WS_BORDER)
	{
		_WindowStyles -= WS_BORDER;
	}

	switch(_BorderStyle)
	{
	case KS::GUI::BorderStyle::Fixed3D:
		{
			_ExtendedWindowStyles |= WS_EX_STATICEDGE;

			break;
		}

	case KS::GUI::BorderStyle::FixedSingle:
		{
			_WindowStyles |= WS_BORDER;

			break;
		}

	case KS::GUI::BorderStyle::None:
		{
			//	Already removed them
			break;
		}

	default:
		{
			throw std::exception("Unknown BorderStyle value.");
		}
	}

	BOOL _IsWindow(IsWindow(m_WindowHandle));

	SetLastError(0);
	//	Using Boost/config.hpp to detect Visual C++ compiler, to disable the compiler warning (due to how it mishandles the LongPtr() functions).
#if	defined(BOOST_MSVC)	//	Disable C4244 warning
#pragma warning(push)
#pragma warning(disable:4244)
#endif
	if(SetWindowLongPtr(m_WindowHandle, GWL_EXSTYLE, _ExtendedWindowStyles) == 0)
#if	defined(BOOST_MSVC)	//	Renable C4244 warning
#pragma warning(pop)
#endif
	{
		const DWORD _Error(GetLastError());
		//	If Error is 0, then it was a success, since function returned
		//	previous value of 0
		if(_Error != 0)
		{
			const std::string _Message(KS::GUI::Win32::TranslateError(_Error));

			throw std::exception("SetWindowLongPtr() failed.");
		}
	}

	SetLastError(0);
#if	defined(BOOST_MSVC)	//	Disable C4244 warning
#pragma warning(push)
#pragma warning(disable:4244)
#endif
	if(SetWindowLongPtr(m_WindowHandle, GWL_STYLE, _WindowStyles) == 0)
#if	defined(BOOST_MSVC)	//	Renable C4244 warning
#pragma warning(pop)
#endif
	{
		const DWORD _Error(GetLastError());
		//	If Error is 0, then it was a success, since function returned
		//	previous value of 0
		if(_Error != 0)
		{
			throw std::exception("SetWindowLongPtr() failed.");
		}
	}

	if(SetWindowPos(m_WindowHandle, 0, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER | SWP_FRAMECHANGED) == 0)
	{
		const DWORD Error = GetLastError();
		//	If Error is 0, then it was a success, since function returned
		//	previous value of 0
		if(Error != 0)
		{
			throw std::exception("SetWindowPos() failed.");
		}
	}
}




The class Control has a memeber m_WindowHandle of HWND. The calls to both of the GetWindowLongPtr's at the beginning are successful. When either of the SetWindowLongPtr's get called, GetLastError returns a 6 - Invalid handle. I even tried putting in the IsWindow right before the calls, and it returns true as well. I even tried stripping the code down to just a single GetWindowLongPtr call immediately followed by the matching SetWindowLongPtr, with the same results. Does anyone have any suggestions or seeing something I may be glazing over? [edit] If I comment out the test code, the code seems to execute just fine, and the border appears. So it looks like GetLastError() is reutrning an error, though SetWindowLongPtr is completing successfully... The whole SetLastError/GetLastError is based on the remarks from MSDN for SetWindowLongPtr. [Edited by - Rattrap on November 10, 2009 6:48:55 PM]

Share this post


Link to post
Share on other sites
Rattrap    3385
That would clean that up a little, but as I said before, I had reduced the code to just the Get and an immediate Set, and was still getting the problem. For some reason the combination of

SetLastError(0);
SetWindowLongPtr(...);
GetLastError();

is resulting in an invalid handle error from the GetLastError, even though it seems to be completing successfully (confirmed by another call to GetWindowLongPtr immediately after plus the border appearing visually. I still can't seem to explain why SetWindowLongPtr is setting the last error to a non zero value, even though is seems to be compelting successfully.

Share this post


Link to post
Share on other sites
Rattrap    3385
Quote:
MSDN Documentation on SetWindowLongPtr
If the function succeeds, the return value is the previous value of the specified offset.

If the function fails, the return value is zero. To get extended error information, call GetLastError.

If the previous value is zero and the function succeeds, the return value is zero, but the function does not clear the last error information. To determine success or failure, clear the last error information by calling SetLastError(0), then call SetWindowLongPtr. Function failure will be indicated by a return value of zero and a GetLastError result that is nonzero.


It is returning 0. But since I set the Error code to 0 before the SetWindowLongPtr call with SetLastError(0), then next call to GetLastError() should return 0 if it really was successful, but instead it is returning a 6 (invalid handle). So SetWindowLongPtr seems to be setting an error. Like I said eariler, what is funny is if I remember all of the error checking code, it looks like the function is still succeeding.

Share this post


Link to post
Share on other sites
Erik Rufelt    5901
Sounds strange. If the window handle is faulty it should return 1400, ERROR_INVALID_WINDOW_HANDLE, not 6 ERROR_INVALID_HANDLE, so it's probably complaining about something else. Are you using more than one thread by any chance?

Share this post


Link to post
Share on other sites
Rattrap    3385
Yeah, it just doesn't make sense. I've made calls to SetWindowLongPtr before in the same code (different functions), and not had any issues like this, so it's just really driving me nutes.

This is all single threaded. SetLastError and GetLastError shouldn't be affected by a threading issue anyway, according to MSDN.

Quote:

The last-error code is kept in thread local storage so that multiple threads do not overwrite each other's values.


So even another thread shouldn't be able to affect the value. And there is only one call between them, the SetWindowLongPtr.

Share this post


Link to post
Share on other sites
Erik Rufelt    5901
I see. I was thinking that perhaps the window was created on a different thread and there was a problem with that (not sure if it would be). Perhaps there's something with the window-class, the documentation says for example "If the window has a class style of CS_CLASSDC or CS_PARENTDC, do not set the extended window styles WS_EX_COMPOSITED or WS_EX_LAYERED"..
I would try reproducing it in a minimal application.

Share this post


Link to post
Share on other sites
mattd    1078
Changing a window style (incl. via SetWindowLongPtr) will send at least WM_styleCHANGING and WM_styleCHANGED messages to your window, and maybe others like WM_GETICON (I think) if they're applicable to your new window style.

Maybe the error code 6 is being set in your window's message handler when processing these messages?

Try stepping through the window message handler with "err,hr" in your watch window to see what error codes are being set as it goes along.

(stupid gdnet "style" bug)

Share this post


Link to post
Share on other sites
Rattrap    3385
Well I think I've solved some of the mystery. I recently upgraded to Windows 7 Ultimate. I tried running the code on an XP machine, ran fine. I tried it in Remote Desktop from another pc, still ran fine. Tried running it natively on my pc, got the error again. So I tried disabling Aero, ran fine. So it looks like the handle error is coming from having Aero enabled. I'm going to try and get the latest Platform SDK and see if that helps any. Still looking for any other suggestions if anyone else has ever encountered an issue like this.

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this