|
Post by Brandon Parker on Jul 30, 2020 19:48:33 GMT -5
I noticed this strange behaviour several times in these years and frankly this is very frustrating, because to me it seems that LB works very fine when a program is relatively small and simple, but these random issues grow when a program becames more long and complex. I would like to be completely wrong about it (I like LB very, very much), but I couldn't figure out why, till now. Any idea? Large programs that are written correctly and manage resources carefully run successfully in LB. I wrote a commercial program that ran for 10 years with no major issues and it used the "CopyFileA" API call when it needed to automatically update itself while running. If you are getting numbers as output from the string variables then one of two things comes to my mind: 1. You are actually placing those numbers into the call to your CopyFile() function, or ... 2. You are passing a Structure PTR to the function without using Winstring() to get the string object pointed to by the structure element. My money is on #2 ... {:0) Brandon Parker
|
|
|
Post by Fabio Siciliano on Jul 31, 2020 4:24:15 GMT -5
Hi Brandon, yes, I'm pretty sure that it should be my fault, I mean, probably I'm doing something wrong that triggers the problem, but at the moment I can't figure out how and why. And NO, your hypothesis cannot be correct for sure, I'm absolutely sure about it, because I don't pass neither numbers nor struct PTRs to that function (or others), I do pass simple plain strings. Then, if you were correct, the behaviour would be always the same... and it's not the case. This is why I wonder if there could be some obscure trigger so that the SMALLTALK behind the scenes of Liberty BASIC engine does something strange by handling strings passed to functions. I mean, this is just an idea, in some circumstances it could be fail to allocate memory for strings (I'm thinking something like C malloc), so that the called function could receive incorrect memory addresses. It is only an idea, because I don't have any way to verify it. Only the great Carl Gundel could, I immagine...
|
|
|
Post by Fabio Siciliano on Jul 31, 2020 4:53:45 GMT -5
LAST ENTRY: I tried to change the way my function (the one that calls the "CopyFileA" API) receives input strings from default "by value" to "byref"... this time I got a new brand error:
Error log timestamp Friday 31/07/20 11:33:56
Runtime error: index: 107 is outside of collection bounds
Error(Exception)>>defaultAction Error(Exception)>>activateHandler: <anUndefinedObject> Error(Exception)>>handle Error(Exception)>>signal Error class(Exception class)>>signal: <'index: 107 is outsid...'> BasicRunProgram(Object)>>error: <'index: 107 is outsid...'> BasicRunProgram(BasicProgram)>>terminateRun: <anError> [] in BasicProgram>>errorHandlerBlock ExceptionHandler>>evaluateResponseBlock: <aBlockClosure> for: <anError> [] in ExceptionHandler>>handle: ProtectedFrameMarker(BlockClosure)>>setUnwind: <aBlockClosure> BlockClosure>>invisibleEnsure: <aBlockClosure> ExceptionHandler>>handle: <anError> ExceptionHandler>>findHandler: <anError> Error(Exception)>>activateHandler: <anExceptionHandler> Error(Exception)>>handle Error(Exception)>>signal Error class(Exception class)>>signal: <'index: 107 is outsid...'> BasicRunProgram(Object)>>error: <'index: 107 is outsid...'> BasicRunProgram(BasicProgram)>>terminateRun: <anError> [] in BasicProgram>>errorHandlerBlock ExceptionHandler>>evaluateResponseBlock: <aBlockClosure> for: <anError> [] in ExceptionHandler>>handle: ProtectedFrameMarker(BlockClosure)>>setUnwind: <aBlockClosure> BlockClosure>>invisibleEnsure: <aBlockClosure> ExceptionHandler>>handle: <anError> ExceptionHandler>>findHandler: <anError> Error(Exception)>>activateHandler: <anExceptionHandler> Error(Exception)>>handle Error(Exception)>>signal Error class(Exception class)>>signal: <'index: 107 is outsid...'> OrderedCollection(Object)>>error: <'index: 107 is outsid...'> OrderedCollection(IndexedCollection)>>errorInBounds: <107> OrderedCollection>>at: <107> put: <263892> BasicVariableManager>>assign: <107> toBe: <263892> ValueMapper>>mapFrom: <aBasicNumericFnDef> to: <aBasicNumericFnDef> [] in BasicProgram>>mapValuesFrom:to: OrderedCollection>>do: <aBlockClosure> BasicRunProgram(BasicProgram)>>mapValuesFrom: <aBasicNumericFnDef> to: <aBasicNumericFnDef> [] in EndCommand>>withParms: [] in BasicRunProgram>>begin ExceptionHandler>>evaluateProtectedBlock: <aBlockClosure> [] in ExceptionHandler>>activateDuring: ProtectedFrameMarker(BlockClosure)>>setUnwind: <aBlockClosure> BlockClosure>>invisibleEnsure: <aBlockClosure> ExceptionHandler>>activateDuring: <aBlockClosure> ExceptionHandler class>>handle: <anError class> with: <aBlockClosure> during: <aBlockClosure> BlockClosure>>on: <anError class> do: <aBlockClosure> BasicRunProgram>>begin BasicRunProgram(BasicProgram)>>beginCallbackFunction: <'onCtlColorStatic('>
I use "onCtlColorStatic" to change the default background white and foreground black colors in 3 textboxes by using WMLiberty.dll...
Could it be a clue to understand the root of all evils?
Here follows my code for it:
'** set textboxes background and foreground colors up open "WMliberty.dll" for dll as #wmlib : wmlib = 1 cyan = RGB(0, 255, 255) : darkblue = RGB(0, 0, 139) calldll #gdi32, "CreateSolidBrush", darkblue as ulong, hBrush as ulong callback lpfn, onCtlColorStatic(ulong, ulong, ulong, ulong), long call SetWMHandler hMain, _WM_CTLCOLORSTATIC, lpfn, hBrush
This is my RGB function:
[RGB]
function RGB(redValue, greenValue, blueValue) RGB = redValue + greenValue * 256 + blueValue * 256*256 end function
This is my window procedure:
[onCtlColorStatic]
function onCtlColorStatic(hWnd, uMsg, hDC, hControl) select case hControl case hwnd(#main.tb21), hwnd(#main.tb31), hwnd(#main.tb51) call SetTextColor hDC, cyan call SetBkColor hDC, darkblue onCtlColorStatic = hBrush end select end function
And this is my callback setup:
[SetWMHandler]
sub SetWMHandler hWnd, uMsg, lpfnCB, lSuccess calldll #wmlib, "SetWMHandler", hWnd as ulong, uMsg as ulong, lpfnCB as ulong, lSuccess as ulong, r as long end sub
Finally, this is how I change background and foreground colors:
[SetBkColor]
sub SetBkColor hDC, crBack calldll #gdi32, "SetBkColor", hDC as ulong, crBack as ulong, r as ulong end sub
[SetTextColor]
sub SetTextColor hDC, crText calldll #gdi32, "SetTextColor", hDC as ulong, crText as ulong, r as ulong end sub
|
|
|
Post by Brandon Parker on Jul 31, 2020 9:33:33 GMT -5
There are likely issues with the code you just supplied...at least one that I see, but we should stick to one problem at a time.
First, we should figure out what is going on with your CopyFile issue. Just post the code snippets that call your CopyFile() function and we can work backward from there.
{:0)
Brandon Parker
|
|
|
Post by Fabio Siciliano on Jul 31, 2020 10:00:43 GMT -5
Hi Brandon,
Here we are.
global author$ : author$ = "ACMEinc"
(...)
global CommonFiles$, myCommonFiles$ (...)
CommonFiles$ = getCommonFiles$() : myCommonFiles$ = CommonFiles$; "\"; author$
(...)
from$ = DefaultDir$ path$ = myCommonFiles$ file$ = "VBAS31W.SLL" gosub [copyfile]
(...)
[copyfile] fromFile$ = from$; "\"; file$ : toFile$ = path$; "\"; file$ r = copyFile(fromFile$, toFile$, 0) return
The function "getCommonFiles$()" on my system (Windows 10 Home) returns always the string "C:\Program Files (x86)\Common Files".
|
|
cundo
Full Member
Muchas Gracias!!
Posts: 146
|
Post by cundo on Jul 31, 2020 11:36:32 GMT -5
In my very long codes I use my own global tracking variable, this variables reflects what portion of code is being executed, and in case of a crash, printing this variable to a file is of help ( or just a notice dialog for simplicity). Like my own error log file.
|
|
|
Post by Fabio Siciliano on Jul 31, 2020 13:38:52 GMT -5
Folks, I'm quite sure that in some way "WMLiberty.dll" is involved in my troubles.
I tried to disable it by commenting its use out in my program and running it the same way several times and NEVER got problems again.
Anyway, I do need to use "WMLiberty.dll" in my software, not only for changing default colors in textboxes.
Then I notice that...
--------------------------- - Notice - --------------------------- copyFile(2550206814, 9109504, 0) --------------------------- OK ---------------------------
...the two long numbers seems to be a typical "wParam, lParam" couple.
If I'm right, in some quite mysterious circumstances I really don't understand, "WMLiberty.dll" could be able to "dirty" values the program passes to its own functions (please, remember, random and very similar errors and not always in my "copyFile" function, also other functions are involved randomicly)...
|
|
|
Post by Brandon Parker on Jul 31, 2020 15:21:24 GMT -5
Then you have a memory issue where something is writing to the wrong place and then things are randomly working and randomly getting messed up.
Your call to the WMLiberty.dll SetWMHandler function is incorrect ...
Here is the correct way to call it... Replace your subroutine's code with the code inside this function or better yet replace the subroutine with the function altogether and then change all of your subroutine calls to function calls in your code.
Function SetWMHandler(hWnd, uMsg, fPointer, operation) CallDLL #wmlib, "SetWMHandler", hWnd As ulong, _ uMsg As ulong, _ fPointer As ulong, _ operation As long, _ SetWMHandler As long End Function
Another issue and this might be where things get messed up, is in the following line. You are passing "hBrush" (a object pointer) into your SetWMHandler subroutine for the "lSuccess" parameter. This should either be 1 or 0 depending on what you are doing. In your case, it will most likely need to be a 1 since you are messing with drawing messages.
call SetWMHandler hMain, _WM_CTLCOLORSTATIC, lpfn, hBrush
Also, are the "cyan" and "darkblue" variables Global variables in your program? I see you are using them inside the onCtlColorStatic() CallBack function, but there is no way to get them into the scope of that function unless they are Global variables. If that is the only place they are used then you could just replace them inside the onCtlColorStatic() Callback function with the RGB() function that creates them.
Try looking into that and see if you are still having problems. Also, just try to make a very small program that can demonstrate the issue you are having if the problem does not resolve and then post it here; it is much easier for us to help when we have complete working code to debug.
{:0)
Brandon Parker
|
|
|
Post by Fabio Siciliano on Jul 31, 2020 15:29:50 GMT -5
*** SOLVED!!! ***
In some ways I don't understand precisely, the problem was caused by a flow of Windows messages filtered by "WMLiberty.dll" in conjunction with the update of the content of the textbox I use to show the user the install progress (my program is an installer) and the automatic scrolldown I perform by sending the textbox control itself a _WM_VSCROLL message.
I solved it by putting a magic "scan" command after sending the _WM_VSCROLL message.
Without it, sometimes my program crashes with the above described problems or with the "Runtime error: index: 108 is outside of collection bounds" and, in that case, the last line of the "error.log" file shows the following: "BasicRunProgram(BasicProgram)>>beginCallbackFunction: <'onCtlColorStatic('>".
Just in case other people could face similar problems, I share here the following further details about it.
Here you can find the two "GOSUBs" involved when I update the content of the textbox and perform the scrolldown:
[logwrite] print #logfile, trim$(logrec$) install.log$ = install.log$; logrec$ #main.tb51 install.log$ gosub [scrolldown] ' '** BEWARE! Without the following "scan" the program sometimes crashes in "onCtlColorStatic" function with a boring '** "Runtime error: index: 108 is outside of collection bounds" or in other strange ways by replacing string '** arguments in called function with long numbers similar to wParam/lParam (e.g. in "copyFile" function) scan ' return
[scrolldown] if hControl = 0 then hControl = hwnd(#main.tb51) nline = nline + 1 l = SetScrollPos(hControl, _SBS_VERT, nline, 1) b = postMessageLong(hControl, _WM_VSCROLL, _SB_THUMBPOSITION + 65536 * nline, 0) return
Here you can find my "SetScrollPos" function:
[SetScrollPos]
function SetScrollPos(hWnd, nBar, nPos, bRedraw) calldll #user32, "SetScrollPos", hWnd as ulong, nBar as long, nPos as long, bRedraw as long, SetScrollPos as long end function
And, finally, here you can find my "postMessageLong" long:
[postMessageLong]
function postMessageLong(hWnd, uMsg, wParam, lParam) ' PostMessageA sends a message AND DOES NOT WAIT until it is processed by the caller window calldll #user32, "PostMessageA", hWnd as ulong, uMsg as ulong, wParam as long, lParam as long, postMessageLong as long end function
It wasn't a walk...
|
|
|
Post by Fabio Siciliano on Jul 31, 2020 15:47:59 GMT -5
Hi Brandon, First of all, thank you for all your kind and interesting suggestions but, in this case, I cannot agree with you, because the Microsoft documentation says clearly that, about the _WM_CTLCOLORSTATIC message, the brush handle must always be returned to the caller ( docs.microsoft.com/en-us/windows/win32/controls/wm-ctlcolorstatic), in fact in my previous tests some weeks ago I tried the "standard" way you wrote about, but that way it failed in coloring the foreground and background in my textbox as expected. Then, yes, "cyan" and "darkblue" variables are defined as global. Best regards, Fabio
|
|
|
Post by Chris Iverson on Jul 31, 2020 16:46:30 GMT -5
Yeah, unfortunately, weird message processing can cause weird problems. Glad to hear you sorted it out.
As for Brandon's suggestion, it isn't to do with the interface of the WM_CTLCOLORSTATIC message, which you are correct about, and using correctly. His suggestion is due to WMLiberty's interface, and specifically, the way it interjects in between LB's message processing and the system.
Your code as currently written will work, because you're always returning the same brush, and I'm guessing you have hBrush global. However, if you ever wanted to CHANGE the background color dynamically, I believe what you have written may not work.
The reason is, a different color would have a different hBrush value(you'd need to create a separate brush which would have a separate handle).
However, WMLiberty specifically treats the return value from your function as an indicator of whether or not YOU handled the message. When it gives your function a message, you may not always want to handle the message yourself, and want to let the default message handling take place.
WMLiberty looks at the return value to determine this. If it sees the return value you specified, it will assume you fully handled the message, and return from the handler.
If the return value is NOT what you specified, it will assume you DIDN'T handle the message, and it will in turn forward the message to default message processing. In the case of WM_CTLCOLORSTATIC, if it passes the message on to the default message handler, the system text and background colors will be set.
Unfortunately, I don't think there's a way around this, besides maybe having separate handlers set up that you switch between when changing colors.
|
|
|
Post by Fabio Siciliano on Aug 1, 2020 3:42:04 GMT -5
Yes Chris, you're completely right. LB allows to specify the background color for a textbox but not also the foreground one, this is why I was obliged to use WMLiberty.dll. And yes, hBrush is global and no, I don't want to change the background color dynamically (so far). Anyway, thank you all for this very useful brainstorming session... it is always a pleasure to talk about these subjects with clever and creative people like you!
|
|
|
Post by Rod on Aug 2, 2020 3:16:59 GMT -5
John Davidson was a master coder, he posted this a long time ago. It allows varied background and foreground colors with minimal API code. Show and hide would allow on the fly color changes. But you may be using WMLiberty for other reasons.
nomainwin
'|---------- Red Text Controls ----------| ForegroundColor$="red" TextboxColor$="darkblue"
statictext #red.st1,"Red on darkblue", 10, 10, 100, 17 textbox #red.tb1,10, 30, 100, 25
stylebits #red,0,_WS_VISIBLE,0,0 open "Red window" for window_popup as #red
'|-------- green Text Controls -------| ForegroundColor$="darkgreen" TextboxColor$="green"
statictext #green.st1,"Darkgreen on green", 120, 10, 100, 17 textbox #green.tb1,120, 30, 100, 25
stylebits #green,0,_WS_VISIBLE,0,0 open "Green window" for window_popup as #green
'|-------- Normal Text Controls ---------|
'Open the mainGUI WindowWidth = 250 WindowHeight = 160 UpperLeftX=int((DisplayWidth-WindowWidth)/2) UpperLeftY=int((DisplayHeight-WindowHeight)/2)
TextboxColor$="" 'default ForegroundColor$="" 'default
statictext #1.st1,"Normal", 10, 70, 50, 17 textbox #1.tb1,10, 90, 100, 25
open "Main GUI" for window as #1 print #1, "font ms_sans_serif 8" print #1, "trapclose [quit.1]"
'Move the controls from the 'color' windows to the main GUI. ' Parent Child call setParent hWnd(#1) , hWnd(#red.st1) call setParent hWnd(#1) , hWnd(#red.tb1) call setParent hWnd(#1) , hWnd(#green.st1) call setParent hWnd(#1) , hWnd(#green.tb1)
#red.tb1 "123" #green.tb1 "123" #1.tb1 "123" wait
[quit.1] close #green close #red close #1 END
SUB setParent parent,child calldll #user32, "SetParent",_ child as ulong,_ parent as ulong,_ r as long END SUB
|
|
|
Post by Fabio Siciliano on Aug 2, 2020 13:39:48 GMT -5
Yeah, Rod, most interesting...
|
|
|
Post by honkytonk on Aug 4, 2020 4:01:59 GMT -5
I noticed this strange behaviour several times in these years and frankly this is very frustrating, because to me it seems that LB works very fine when a program is relatively small and simple, but these random issues grow when a program becames more long and complex. I would like to be completely wrong about it (I like LB very, very much), but I couldn't figure out why, till now. Any idea? Long and complex programs tire what is between the chair and the keyboard; which causes errors.
|
|