Error in FreeGadget

BlitzPlus Forums/BlitzPlus Beginners Area/Error in FreeGadget

dtukabrl(Posted 2015) [#1]
Sorry for my bad english...

The code below shows errors:

Win  = CreateWindow("Test Window",50,200,400,140,0,17) 
buttonwin1=CreateButton("Win 1",50,10,300,40,Win)
buttonwin2=CreateButton("Win 2",50,60,300,40,Win)

Repeat

event = WaitEvent()

If event = $401
	If EventSource()=buttonwin1
	Win1  = CreateWindow("Window 1",510,200,400,140,0,17)
	CreateLabel("Close this window, please...",10,10,300,100,win1)
	EndIf
	If EventSource()=buttonwin2
	Win2  = CreateWindow("Window 2",510,200,400,140,0,17)
	CreateLabel("Close this window, please...",10,10,300,100,win2)
	EndIf
End If 

If event = $803 And EventSource() = win1 Then FreeGadget win1
If event = $803 And EventSource() = win2 Then FreeGadget win2
If event = $803 And EventSource() = win Then End


Forever

End


Follow the steps after running the code:

1º - Click in the button 'Win 1'
2º - Close the Window 'Window 1'
3º - Click in the button 'Win 2'
4º - Close the Window 'Window 2'

An error message will appear..


Floyd(Posted 2015) [#2]
No error here, version 1.47 of BlitzPlus.

Windows 7 64-bit.


dtukabrl(Posted 2015) [#3]
Thanks.

My Windows is 8 pro 64-bit and in various tests this error is being displayed.

I solved this problem as follows:

Win  = CreateWindow("Test Window",50,200,400,140,0,17) 
buttonwin1=CreateButton("Win 1",50,10,300,40,Win)
buttonwin2=CreateButton("Win 2",50,60,300,40,Win)

Repeat

event = WaitEvent()

If event = $401
	If EventSource()=buttonwin1
	Win1  = CreateWindow("Window 1",510,200,400,140,0,17)
	CreateLabel("Close this window, please...",10,10,300,100,win1)
	EndIf
	If EventSource()=buttonwin2
	Win2  = CreateWindow("Window 2",510,200,400,140,0,17)
	CreateLabel("Close this window, please...",10,10,300,100,win2)
	EndIf
End If 

If event = $803 And EventSource() = win1 Then DestroyWindow(QueryObject(win1,1))
If event = $803 And EventSource() = win2 Then DestroyWindow(QueryObject(win2,1))
If event = $803 And EventSource() = win Then End


Forever

End


And add this lines in User.decls:

.lib "user32.dll"
DestroyWindow%(hwnd):"DestroyWindow"



Floyd(Posted 2015) [#4]
I've just noticed that there is an error after all.

My laptop has Windows 8 64-bit, but doesn't have BlitzPlus installed. So I thought I would test it by compiling on my desktop PC and running the .exe on the laptop.

I built the .exe and first tried it on my desktop. "Invalid Gadget Handle".

There was no such error when running from the IDE.


dna(Posted 2015) [#5]
Hello.
I hate to sound stupid but, I've never understood, or found, any information to explain what user.decls is, where it is or, what it does.

Can someone point me to that link or explain?


dtukabrl(Posted 2015) [#6]
Sorry for my english...

-> Floyd,

The error is show in first or second example?

-> dna,

The user.decls is found in:

C:\Program Files\BlitzPlus\userlibs

this file add others features to Blitz. API's of dlls from Windows or others dlls.

Various examples: http://www.blitzbasic.com/codearcs/codearcs.php?cat=10&order=&asc=&lang_id=1

For example, in this code: http://www.blitzbasic.com/codearcs/codearcs.php?code=3173 you need to add the lines in users.decls:

.lib "shell32.dll"
api_ExtractIcon% ( hWnd%, File$, Index% ) : "ExtractIconA"

.lib "user32.dll"
api_SendMessage% (hwnd%, wMsg%, wParam%, lParam%) : "SendMessageA"


If the line '.lib "shell32.dll"' or '.lib "user32.dll"' exist, you just add the other lines below the correct headers...


Floyd(Posted 2015) [#7]
The error is with the original example. It did not happen running from IDE but did with standalone exe.


To use whatever.dll with Blitz you need a corresponding whatever.decls file, which goes in the \userlibs folder. It is a plain text file created with an editor such as NotePad.

The user32.dll is part of Windows. user32.decls is here: decls for user32.dll

Use this to make a plain text file and save it with the name user32.decls in your BlitzPlus\userlibs folder.

If you just want to try the example code in this thread, using only one function in user32.dll, then you can use a .decls file consisting of just the two lines:

.lib "user32.dll"
DestroyWindow%(hwnd):"DestroyWindow"



_PJ_(Posted 2015) [#8]
I am so sorry for my terrible explanation here, if it really isn't clear, then let me know, I can try to elucidate further!
___________________

I don't believe this is necessarily a bug, but more because there is still a check being made to a populated handle variable although the gadget to which it points no longer exists.

I think it's simply that, on execution, when processing
If event = $803 And EventSource() = win1 Then FreeGadget win1
If event = $803 And EventSource() = win2 Then FreeGadget win2

It is trying to close a window that has already been closed because the handle is recycled for use so both win1 and win2 variables hold the same value.



I could recreate the error message using the compiler in debug mode, but The following works without issue (notwithstanding of course, attempting to open multiple windows of the same # ):

Win  = CreateWindow("Test Window",50,200,400,140,0,17) 
	buttonwin1=CreateButton("Win 1",50,10,300,40,Win)
	buttonwin2=CreateButton("Win 2",50,60,300,40,Win)
	
	Repeat
		
		event = WaitEvent()
		
		If event = $401
			If EventSource()=buttonwin1 And (win1=0)
				win1  = CreateWindow("Window 1",510,200,400,140,0,17)
				CreateLabel("Close this window, please...",10,10,300,100,win1)
				DebugLog win1
			EndIf
			If EventSource()=buttonwin2 And (win2=0)
				win2  = CreateWindow("Window 2",510,200,400,140,0,17)
				CreateLabel("Close this window, please...",10,10,300,100,win2)
				DebugLog win2
			EndIf
		End If 
		If event = $803 
			If (EventSource() = win)
				End
			Else
				If (EventSource()=win1)
					FreeGadget win1
					win1=0
				Else
					If EventSource()=win2
						FreeGadget win2
						win2=0
					End If
				End If
			End If
		End If
		
	Forever



_PJ_(Posted 2015) [#9]
A clearer explanation:

Program is run.
Button 1 is pressed.
window 1 created - win1 populated with handle for gadget window 1.
window 1 closed. win1 freed in memory.
win1 still contains value for handle, although is not longer valid.

Button 2 is pressed.
window 2 created - win2 populated with handle for gadget window 2.
window 2 closed. win2 freed in memory.
win2 still contains value for handle, although is not longer valid.

However a the point in code, "If (EventID=¤803) And EventSource()=win1 Then FreeGadget win1"

Both Win1 and Win2, since they are opened then freed separately, are both given identical handles. (It kinda makes sense to re-use handles once they're freed and done with) However, the win1 and win2 values are still populated. Therefore, regardless of which window is actually closed in which order, provided one is created after the other is freed, the newly opened one will have the same handle as the previously closed one.
Therefore, "win1", being the first check as the program runs, will count as valid, since both will be the same. And the window with that handle will be freed, whether it is window 1 or window 2.
The next line, "If (EventID=¤803) And EventSource()=win2 Then FreeGadget win2" WIll also consider the EventSource as valid, since the 803¤ event had occurred with the win1 or win2 source being exactly the same.
The difference, now, however, is that unfortunately, we've already Freed the actual gadget to which that handle points.
Therefore, ther returned error is "Invalid Gadget Handle"

It is here that the failure of the original code comes in. Essentially there was a memory leak because you had two variables pointing to the same data and neither variable was adjusted to reflect when the data was cleared from memory.

____

So my solution simply ensured that the particular win1 or win2 variable is nullified once the data it points to is cleared and to ensure that the source is accurately considered.


dtukabrl(Posted 2015) [#10]
Thanks.

I had not paid attention to this detail.