|
Post by (X) on Jun 1, 2023 2:31:56 GMT 1
This is the tip of the iceberg, of a way I want to be able to work.
I want to be able to view and edit any object property 'on the fly'.
|
|
|
Post by rogercabo on Jun 11, 2023 23:02:36 GMT 1
Interesting! F5 and i got this screen. Not sure if that's correct?
|
|
|
Post by (X) on Jun 12, 2023 0:26:23 GMT 1
In that demo the treeview lines were not activated and subnodes not expanded. If you dbl click on the root treeview item it will/should show a list of node properties and the values.
This is just the start of what I would like to quickly and easily be able to accomplish 'on the fly' for any control or variable in a running or halted program.
|
|
|
Post by (X) on Jun 12, 2023 0:38:22 GMT 1
I updated the demo to include lines and expanded all nodes in advance. Go to the first post, to download the updated program.
|
|
|
Post by (X) on Jun 16, 2023 12:23:09 GMT 1
The more I look at the OCX Overview built into the GFA-BASIC 32 for Windows Integrated Development Environment Menu; the more I think it is along these lines that I want to expand the programmers scope into runtime access of the OCX properties, adding, removing, moving, resizing etc...
|
|
|
Post by (X) on Jun 27, 2023 2:23:07 GMT 1
I am making progress on listing and storing all the properties for all the declared controls and collections (such as App) in a program. Once I have this worked out I want to be able to display and edit any property "on the fly" and make it persistent for the next time I open the program file. I know this is a bit abstract, but, it fits well with my desire to be able to quickly setup a program with previously prepared libraries and solutions.
This is a function that returns the property value based on a given control and a property string: prop$. Once I have the full demo worked out I will post it. As you can see the number of properties are in the dozens and I am struggling to find a simple way to do all of this..
Function F_Ctrl_Prop(c As Control, prop$) As Variant Try If Lower(prop$) == "" Return c.Name If Lower(prop$) == "align" Return c.Align If Lower(prop$) == "alignment" Return c.Alignment If Lower(prop$) == "appearance" Return c.Appearance If Lower(prop$) == "arguments" Return c.Arguments If Lower(prop$) == "arrowkeys" Return c.ArrowKeys If Lower(prop$) == "autoplay" Return c.Autoplay If Lower(prop$) == "availpagefile" Return Hex(c.AvailPageFile) If Lower(prop$) == "availphys" Return Hex(c.AvailPhys) If Lower(prop$) == "availvirtual" Return Hex(c.AvailVirtual) If Lower(prop$) == "backcolor" Return c.backcolor If Lower(prop$) == "borderstyle" Return c.borderstyle If Lower(prop$) == "buddycontrol" Return c.buddycontrol If Lower(prop$) == "cancel" Return c.cancel If Lower(prop$) == "caption" Return c.caption If Lower(prop$) == "center" Return c.center If Lower(prop$) == "comments" Return c.Comments If Lower(prop$) == "companyname" Return c.CompanyName If Lower(prop$) == "controlbox" Return c.controlbox If Lower(prop$) == "default" Return c.default If Lower(prop$) == "disablenoscroll" Return c.DisableNoScroll If Lower(prop$) == "enabled" Return c.enabled If Lower(prop$) == "filedescription" Return c.FileDescription If Lower(prop$) == "filename" Return c.FileName If Lower(prop$) == "fileversion" Return c.FileVersion If Lower(prop$) == "font" Return c.Font If Lower(prop$) == "forecolor" Return c.forecolor If Lower(prop$) == "format" Return c.format //If Lower(prop$) == "forms" Return c.Forms If Lower(prop$) == "frompage" Return c.frompage If Lower(prop$) == "internalname" Return c.InternalName If Lower(prop$) == "integralheight" Return c.IntegralHeight If Lower(prop$) == "height" Return c.height If Lower(prop$) == "helpbutton" Return c.helpbutton If Lower(prop$) == "helpcontextid" Return c.helpcontextid If Lower(prop$) == "hinstance" Return c.hInstance If Lower(prop$) == "horizontal" Return c.horizontal If Lower(prop$) == "hottracking" Return c.hottracking If Lower(prop$) == "hscmax" Return c.hscmax If Lower(prop$) == "hscmin" Return c.hscmin If Lower(prop$) == "hscpage" Return c.hscpage If Lower(prop$) == "hscstep" Return c.hscstep If Lower(prop$) == "increment" Return c.increment If Lower(prop$) == "index" Return Iif(IsArray(c), c.index, "N/A") If Lower(prop$) == "icon" Return c.icon If Lower(prop$) == "left" Return c.left If Lower(prop$) == "leftalign" Return c.leftalign If Lower(prop$) == "max" Return c.max If Lower(prop$) == "maxbutton" Return c.maxbutton If Lower(prop$) == "mdichild" Return c.mdichild If Lower(prop$) == "mdiparent" Return c.mdiparent If Lower(prop$) == "min" Return c.min If Lower(prop$) == "minbutton" Return c.minbutton If Lower(prop$) == "mouseicon" Return c.mouseicon If Lower(prop$) == "mousepointer" Return c.mousepointer If Lower(prop$) == "moveable" Return c.moveable If Lower(prop$) == "multiline" Return c.multiline If Lower(prop$) == "multirow" Return c.multirow If Lower(prop$) == "name" Return c.name If Lower(prop$) == "owned" Return c.owned If Lower(prop$) == "pgbottom" Return c.pgbottom If Lower(prop$) == "pgleft" Return c.pgleft If Lower(prop$) == "pgminbottom" Return c.pgminbottom If Lower(prop$) == "pgminleft" Return c.pgminleft If Lower(prop$) == "pgminright" Return c.pgminright If Lower(prop$) == "pgmintop" Return c.pgmintop If Lower(prop$) == "pgright" Return c.pgright If Lower(prop$) == "pgscale" Return c.pgscale If Lower(prop$) == "pgtop" Return c.pgtop If Lower(prop$) == "picture" Return c.picture If Lower(prop$) == "picturemode" Return c.picturemode If Lower(prop$) == "placement" Return c.placement If Lower(prop$) == "pushlike" Return c.pushlike If Lower(prop$) == "scrollbars" Return c.scrollbars If Lower(prop$) == "scrollopposite" Return c.scrollopposite If Lower(prop$) == "separators" Return c.separators If Lower(prop$) == "shownintaskbar" Return c.shownintaskbar If Lower(prop$) == "simpletext" Return c.SimpleText If Lower(prop$) == "sizeable" Return c.sizeable If Lower(prop$) == "smallicon" Return c.smallicon If Lower(prop$) == "sorted" Return c.Sorted If Lower(prop$) == "startupmode" Return c.startupmode If Lower(prop$) == "style" Return c.style If Lower(prop$) == "tabfixedheight" Return c.tabfixedheight If Lower(prop$) == "tabfixedwidth" Return c.tabfixedwidth If Lower(prop$) == "tabminwidth" Return c.tabminwidth If Lower(prop$) == "tabstop" Return c.TabStop If Lower(prop$) == "tabwidthstyle" Return c.tabwidthstyle If Lower(prop$) == "tag" Return c.tag If Lower(prop$) == "threestate" Return c.threestate If Lower(prop$) == "tooltiptext" Return c.tooltiptext If Lower(prop$) == "top" Return c.top If Lower(prop$) == "topage" Return c.topage If Lower(prop$) == "transparent" Return c.transparent If Lower(prop$) == "value" Return c.value If Lower(prop$) == "visible" Return c.visible If Lower(prop$) == "vscmax" Return c.vscmax If Lower(prop$) == "vscmin" Return c.vscmin If Lower(prop$) == "vscpage" Return c.vscpage If Lower(prop$) == "vscstep" Return c.vscstep If Lower(prop$) == "whatsthishelpid" Return c.whatsthishelpid If Lower(prop$) == "width" Return c.width If Lower(prop$) == "wrap" Return c.wrap Debug "NO SUCH PROPERTY: " & #34 & c.NAME & "." & prop$ & #34 Return "" Catch 'Debug "ERR$: ";Err$ & ": " & c.name & "." & prop$ Return "" EndCatch EndFunc
|
|
|
Post by dragonjim on Jun 27, 2023 12:54:57 GMT 1
I wrote a program a few years ago which handled properties but in newly created Unicode Controls rather than GFA's OCX ones.
However, what may be useful to you from that project is the means of determining what properties each control type has and/or uses. Extrapolating from the code, you could have a hash table where the key is a property name and the value is a string containing codes showing which controls use that property.
For instance, for the Align property, the Hash entry would be property["align2"] = "*cbx*txt*lbx*cmd*" [and so on]
Then, to work with this, you could create a second Hash table with the control name as the key and the code as the value (so ctrl["combobox"] = "cbx").
That way, you can use Typename to interrogate any control to return the control type like this:
Ocx ComboBox cbx = "", 10, 10, 100, 15 Debug TypeName(cbx) // Returns ComboBox
... and thus create a list of properties by cross referencing with your hash tables.
Thinking about it, you can even miss out the second hash table and just put the control names in full in the value part of the property hash table...
I hope this is helpful.
|
|
|
Post by (X) on Jun 27, 2023 13:55:36 GMT 1
Thanks dj. This project is slowly building steam. I've had it in the back of my mind for years it seems. I am throttled by by the question: "Why are you doing this? It seems like you are re-inventing the wheel! Isn't this overly complicated?" I am encouraged by the answer: "I have a gut feeling that if I can get this to work, then, at the very least I will understand programming a little better, and if things go well, this will be a whole new way for me to build applications from the ground up." The nuts and bolts... I was thinking of sequentially trying to log all the property values for any control I provide, if the property doesn't exist it will simply be ignored. If the property does exist, I will log the control name, property name and it's value likely as a variant. This way I could build a [control + property + value] roster for any control existing in the code. I woke up yesterday with the feeling: "This could be the day!" I will be making trials to iterate over all possible properties for each control and see what comes of it.
I welcome any feedback.
|
|
|
Post by dragonjim on Jun 27, 2023 14:14:51 GMT 1
I can see one practical use for this (I am sure there are many more) if it is called as part of debugging to find out what may or may not be going wrong with controls on a Form.
As I'm sure you're aware, you can process all the controls belonging to any Form using the Controls property, which would be useful for creating such a report that could then be sent to a different, dedicated Form containing your Treeview object.
To facilitate this and any other uses you may think of, you can use the Ocx Timer or any other Timer object to call a second thread to process all the information on a form in real time without having to interrupt the main program flow. You could create two small sub routines to allow this debugging to be switched on and off within the main program and also control the time interval and thus how often it is called (calling this routine too often could cause performance lags and possible crashes - it would also be useful to have a dedicated global variable which alerts these sub routines that the second thread is already in operation so that it does not try to overwrite information already being processed which can cause a crash).
|
|
|
Post by (X) on Jun 27, 2023 14:28:45 GMT 1
Just in case I missed it.
To your knowledge, is there a method 'built-in' to GFA-BASIC 32 to iterate through the properties of a control?
|
|
|
Post by dragonjim on Jun 27, 2023 15:14:45 GMT 1
No, you will need to do this manually, something like:
$Library "gfawinx" $Library "C:\Program Files (x86)\GFABASIC32\Include\UpdateRT.lg32" $Library "C:\Program Files (x86)\GFABASIC32\Include\Variants.lg32" UpdateRuntime ' Patches GfaWin23.Ocx
Dim varr As Variant : varr = Array(0, 0, 0, 0) Dim vsubarr As Variant // 0 - Name, 1 - Type, 2 - Properties Dim vproparr As Variant Dim ct As Int32
OpenW 1 Ocx Command cmd = "Hello", 20, 20, 100, 20 Ocx Command bye = "Goodbye", 20, 45, 100, 20 Ocx Option opt = "Check me...", 20, 70, 100, 15 : opt.Value = 1 Ocx Option op2 = "...no me", 20, 90, 100, 15 Local c As Control For Each c In Win_1.Controls vsubarr = Array("", "", 0) vsubarr(0) = c.name : Trace c.name vsubarr(1) = TypeName(c) : Trace TypeName(c) vproparr = Array("", 0) vproparr(0) = "Align" vproparr(1) = c.align : Trace c.align VarArraySet vsubarr, 2, vproparr VarArraySet varr, ct, vsubarr Inc ct Next Debug.Show Trace VarPrint (varr, VARPRINT_ARRAYINFULL) Do : Sleep : Until Win_1 Is Nothing
Sadly, it does not look like to can assign the controls to a collection through direct transfer either.
|
|
|
Post by dragonjim on Jun 27, 2023 15:18:05 GMT 1
Looking again at my code, you can shorten the creation of vsubarr to:
vsubarr = Array(c.name, TypeName(c), Array("Align", c.align))
and do away with vproparr all together in this example; however, I am guessing that you will want to use a variable length variant array for properties so this would not be practical for your planned program.
|
|
|
Post by (X) on Jun 27, 2023 16:37:09 GMT 1
I am getting hung up on this line:
Dim dw% = StdCall(proc_addr%)( L: hCtrl, Var: prop_val)
// Would it be possible to do something like this? // Where: proc_addr% would be set in advance in the hash table // pa% = ProcAddr(P_Get_Align)
Function F_Return_prop_val(ctrl As Control, prop$) As Variant Dim H_Proc_Addr_by_Prop_Str As Hash Long Dim pa% = ProcAddr(P_Get_Alignment) Trace Hex(pa%) H_Proc_Addr_by_Prop_Str["Alignment"] = pa% Trace Hex(H_Proc_Addr_by_Prop_Str["alignment"]) Dim proc_addr% = H_Proc_Addr_by_Prop_Str[prop$] Trace Hex(proc_addr) Dim prop_val As Variant Dim hCtrl% = ctrl.hWnd Dim dw% = StdCall(proc_addr%)( L: hCtrl, Var: prop_val) Trace dw Trace prop_val Return prop_val EndFunc
// Where: Proc P_Get_Alignment(hCtrl%, ByRef v As Variant) Dim ctrl As Control Set ctrl = OCX(hCtrl) Trace ctrl.name Trace ctrl.alignment v = ctrl.Alignment EndProc
|
|
|
Post by (X) on Jun 27, 2023 16:53:07 GMT 1
Using:
'''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''' ' Init ' Global v As Variant Global H_Proc_Addr_by_Prop_Str As Hash Long H_Proc_Addr_by_Prop_Str["Alignment"] = ProcAddr(P_Get_Alignment) H_Proc_Addr_by_Prop_Str["Caption"] = ProcAddr(P_Get_Caption)
Proc P_Get_Alignment(hCtrl%) Dim ctrl As Control Set ctrl = OCX(hCtrl) v = ctrl.Alignment EndProc
Proc P_Get_Caption(hCtrl%) Dim ctrl As Control Set ctrl = OCX(hCtrl) v = ctrl.Caption EndProc
Function F_Prop_Val(ctrl As Control, prop$) As Variant Dim dw% = StdCall(H_Proc_Addr_by_Prop_Str[prop$])( L:ctrl.hWnd) Return v EndFunc
This works:
Trace F_Prop_Val(lbl(0), "alignment") Trace F_Prop_Val(lbl(0), "caption") Obviously the procedures would be stored in a library ahead of time and Try..Catch.. will probably be necessary for inapporpriate requests.
|
|
|
Post by dragonjim on Jun 27, 2023 17:48:28 GMT 1
There used to be a problem passing the second and later parameters if they were not 32-bit integers, but this has been fixed and, anyway, your code works if v is passed as a Large value.
From what I can see, it seems that StdCall has a problem with passing Variants.
One workaround would be to alter your code, where you are looking to return the align(ment) value in a Variant, as follows:
OpenW 1 Ocx Command cmd = "Hello", 10, 10, 100, 20 : cmd.Align = 1 Trace F_Return_prop_val(cmd, "Align") Do : Sleep : Until Win_1 Is Nothing
// Would it be possible to do something like this? // Where: proc_addr% would be set in advance in the hash table // pa% = ProcAddr(P_Get_Align)
Function F_Return_prop_val(ctrl As Control, prop$) As Variant Dim H_Proc_Addr_by_Prop_Str As Hash Long Dim pa% = ProcAddr(P_Get_Align) Trace Hex(pa%) H_Proc_Addr_by_Prop_Str["Align"] = pa% Trace Hex(H_Proc_Addr_by_Prop_Str["align"]) Dim proc_addr% = H_Proc_Addr_by_Prop_Str[prop$] Trace Hex(proc_addr) Dim prop_val As Variant Dim hCtrl% = ctrl.hWnd Dim dw% = StdCall(proc_addr%)( L: hCtrl, V:prop_val) // <--- Pass the address of the Variant Trace dw Trace prop_val Return prop_val EndFunc
// Where: Proc P_Get_Align(hCtrl%, vv%) Dim ctrl As Control, v As Variant Set ctrl = OCX(hCtrl) Trace ctrl.name Trace ctrl.align v = ctrl.Align BMove V:v, vv%, 16 // <--- Move the value of the local Variant to the address passed for prop_val EndProc
|
|
|
Post by (X) on Jun 27, 2023 18:17:23 GMT 1
Oooooooooooooooooooooooooo!!!!!!!!
I stumbled upon this! It seems to work for getting a property by passing a control name and a property name as a string parameter.
Local idisp As Int32 = _DispID(lbl(0), "Caption") Trace lbl(0).{idisp}
// Which can be shortened to: Trace <some control>.{<some control>,<"some property string">}
Debug output: TRACE:frm1_Close(8):lbl(0).{idisp} = IMG From the Help document:
|
|
|
Post by (X) on Jun 27, 2023 21:51:45 GMT 1
|
|
|
Post by (X) on Jun 28, 2023 13:45:13 GMT 1
There is a way to get the control property value using the control as a variable and property as a string.*
<ctl_val> = <control>.{_DispID(<control>, <property_string>)}
*
Q: Why not use the explicit form of: "<val> = <ctrl>.<property>" e.g.: "w = lbl.width"?
A: By all means do so if you can. I am trying to work with a specific case 'where that won't do'. I am trying to use code to perform the task of getting the control property value. In this case, using a 'property string' parameter works to our advantage.
CODE EXAMPLE:
Function F_Ctl_Prp_Val(c As Control, prop$) As Variant '''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''' ' There is a way to get the control property value using the control and ' property name passed as a string. I know, I didn't believe it myself! ' ' <control>.{_DispID(<control>, <property_string>)} ' Try Return c.{_DispID(c, prop$)} Catch Debug "ERR$: ";Err$ & ": " & c.name & "." & prop$ Return "" EndCatch '''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''' ' This does away with all that follows. I will leave this here as a reminder ' that if you think there is a better way to do things, someone may well have ' thought so too, and with a little looking around you might find it. ' °Try °If Lower(prop$) == "" Return c.Name °If Lower(prop$) == "align" Return c.Align °If Lower(prop$) == "alignment" Return c.Alignment °If Lower(prop$) == "appearance" Return c.Appearance °If Lower(prop$) == "arguments" Return c.Arguments °If Lower(prop$) == "arrowkeys" Return c.ArrowKeys °If Lower(prop$) == "autoplay" Return c.Autoplay °If Lower(prop$) == "availpagefile" Return Hex(c.AvailPageFile) °If Lower(prop$) == "availphys" Return Hex(c.AvailPhys) °If Lower(prop$) == "availvirtual" Return Hex(c.AvailVirtual) °If Lower(prop$) == "backcolor" Return c.backcolor °If Lower(prop$) == "borderstyle" Return c.borderstyle °If Lower(prop$) == "buddycontrol" Return c.buddycontrol °If Lower(prop$) == "cancel" Return c.cancel °If Lower(prop$) == "caption" Return c.caption °If Lower(prop$) == "center" Return c.center °If Lower(prop$) == "comments" Return c.Comments °If Lower(prop$) == "companyname" Return c.CompanyName °If Lower(prop$) == "controlbox" Return c.controlbox °If Lower(prop$) == "default" Return c.default °If Lower(prop$) == "disablenoscroll" Return c.DisableNoScroll °If Lower(prop$) == "enabled" Return c.enabled °If Lower(prop$) == "filedescription" Return c.FileDescription °If Lower(prop$) == "filename" Return c.FileName °If Lower(prop$) == "fileversion" Return c.FileVersion °If Lower(prop$) == "font" Return c.Font °If Lower(prop$) == "forecolor" Return c.forecolor °If Lower(prop$) == "format" Return c.format °//If Lower(prop$) == "forms" Return c.Forms °If Lower(prop$) == "frompage" Return c.frompage °If Lower(prop$) == "height" Return c.height °If Lower(prop$) == "helpbutton" Return c.helpbutton °If Lower(prop$) == "helpcontextid" Return c.helpcontextid °If Lower(prop$) == "hinstance" Return c.hInstance °If Lower(prop$) == "horizontal" Return c.horizontal °If Lower(prop$) == "hottracking" Return c.hottracking °If Lower(prop$) == "hscmax" Return c.hscmax °If Lower(prop$) == "hscmin" Return c.hscmin °If Lower(prop$) == "hscpage" Return c.hscpage °If Lower(prop$) == "hscstep" Return c.hscstep °If Lower(prop$) == "icon" Return c.icon °If Lower(prop$) == "increment" Return c.increment °If Lower(prop$) == "index" Return Iif(IsArray(c), c.index, "N/A") °If Lower(prop$) == "integralheight" Return c.IntegralHeight °If Lower(prop$) == "internalname" Return c.InternalName °If Lower(prop$) == "left" Return c.left °If Lower(prop$) == "leftalign" Return c.leftalign °If Lower(prop$) == "legalcopyright" Return c.LegalCopyright °If Lower(prop$) == "legaltrademarks" Return c.LegalTrademarks °If Lower(prop$) == "max" Return c.max °If Lower(prop$) == "maxbutton" Return c.maxbutton °If Lower(prop$) == "mdichild" Return c.mdichild °If Lower(prop$) == "mdiparent" Return c.mdiparent °If Lower(prop$) == "min" Return c.min °If Lower(prop$) == "minbutton" Return c.minbutton °If Lower(prop$) == "mouseicon" Return c.mouseicon °If Lower(prop$) == "mousepointer" Return c.mousepointer °If Lower(prop$) == "moveable" Return c.moveable °If Lower(prop$) == "multiline" Return c.multiline °If Lower(prop$) == "multirow" Return c.multirow °If Lower(prop$) == "name" Return c.name °If Lower(prop$) == "owned" Return c.owned °If Lower(prop$) == "pgbottom" Return c.pgbottom °If Lower(prop$) == "pgleft" Return c.pgleft °If Lower(prop$) == "pgminbottom" Return c.pgminbottom °If Lower(prop$) == "pgminleft" Return c.pgminleft °If Lower(prop$) == "pgminright" Return c.pgminright °If Lower(prop$) == "pgmintop" Return c.pgmintop °If Lower(prop$) == "pgright" Return c.pgright °If Lower(prop$) == "pgscale" Return c.pgscale °If Lower(prop$) == "pgtop" Return c.pgtop °If Lower(prop$) == "picture" Return c.picture °If Lower(prop$) == "picturemode" Return c.picturemode °If Lower(prop$) == "placement" Return c.placement °If Lower(prop$) == "pushlike" Return c.pushlike °If Lower(prop$) == "scrollbars" Return c.scrollbars °If Lower(prop$) == "scrollopposite" Return c.scrollopposite °If Lower(prop$) == "separators" Return c.separators °If Lower(prop$) == "shownintaskbar" Return c.shownintaskbar °If Lower(prop$) == "simpletext" Return c.SimpleText °If Lower(prop$) == "sizeable" Return c.sizeable °If Lower(prop$) == "smallicon" Return c.smallicon °If Lower(prop$) == "sorted" Return c.Sorted °If Lower(prop$) == "startupmode" Return c.startupmode °If Lower(prop$) == "style" Return c.style °If Lower(prop$) == "tabfixedheight" Return c.tabfixedheight °If Lower(prop$) == "tabfixedwidth" Return c.tabfixedwidth °If Lower(prop$) == "tabminwidth" Return c.tabminwidth °If Lower(prop$) == "tabstop" Return c.TabStop °If Lower(prop$) == "tabwidthstyle" Return c.tabwidthstyle °If Lower(prop$) == "tag" Return c.tag °If Lower(prop$) == "threestate" Return c.threestate °If Lower(prop$) == "tooltiptext" Return c.tooltiptext °If Lower(prop$) == "top" Return c.top °If Lower(prop$) == "topage" Return c.topage °If Lower(prop$) == "transparent" Return c.transparent °If Lower(prop$) == "value" Return c.value °If Lower(prop$) == "visible" Return c.visible °If Lower(prop$) == "vscmax" Return c.vscmax °If Lower(prop$) == "vscmin" Return c.vscmin °If Lower(prop$) == "vscpage" Return c.vscpage °If Lower(prop$) == "vscstep" Return c.vscstep °If Lower(prop$) == "whatsthishelpid" Return c.whatsthishelpid °If Lower(prop$) == "width" Return c.width °If Lower(prop$) == "wrap" Return c.wrap °Debug "NO SUCH PROPERTY: " & #34 & c.NAME & "." & prop$ & #34 °Return "" °Catch °'Debug "ERR$: ";Err$ & ": " & c.name & "." & prop$ °Return "" °EndCatch EndFunc
|
|
|
Post by (X) on Jul 5, 2023 22:55:17 GMT 1
It is a great exercise to be able to layout all the App, Forms, Controls, Printers and all their properties. I am struggling to write a recursive algorithm that doesn't tie itself into knots. This is such a fundamental task that I thought it was going to be easy. Understanding why one gets an Allocation error has stumped me on many occaisions in this project but I am making progress and I think the result will be worth it. A programmer's job is to know how to get results, yes, but, sometimes it seems 99% of the work is learning to avoid and handle every little error and exception that may come along, then find out why, then avoid or handle them completely. :)
|
|
|
Post by (X) on Jul 7, 2023 23:14:55 GMT 1
I finally got over a hump that was a "tough nut to crack" and was stopping me from moving on. It has to do with the use of the TypeName() function applied to a 'Control.Property' pair when the property is '.Picture'.
These are demonstrations of some cases where TypeName() fails, in my opinion, for no good reason. But then, I admit: "I don't know everything."
$Library "gfawinx" $Library "UpdateRT" UpdateRuntime ' Patches GfaWin23.Ocx // // CAN YOU USE TypeName() willy nilly? Short answer NO. // It seems using a picture variable of type New StdPicture fairs // better than New Picture or Picture type. // Try LoadForm frm1 // OK, return: frm1.Picture = Object(:0xb1e0128) Trace frm1.Picture Trace TypeName(frm1.Caption) // Even if there is a Picture assigned to the form... 'Trace TypeName(frm1.Picture) // Access-Violation Dim pic As New StdPicture 'Dim pic As New Picture 'Set pic = Nothing // Not necessary Set pic = frm1.Picture // If Picture : Access-Violation // If StdPicture : OK Trace TypeName(pic) Dim var As Variant Set var = frm1.Picture // Access-Violation 'Trace TypeName(var) Dim o As Object Set o = frm1.Picture // If Picture : Must set to nothing or Access-Violation // If StdPicture : No need to set to nothing. Makes no difference. 'Set pic = Nothing Set pic = o // For StdPicture or Picture type... // If form picture assigned: Picture, else, Nothing. Trace TypeName(pic) // OK Dim c As Control Set c = frm1.Picture // If Picture : Must set to nothing or Access-Violation // If StdPicture : No need to set to nothing. Makes no difference. 'Set pic = Nothing Set pic = c // For StdPicture or Picture type... // If form picture assigned: Picture, else, Nothing. Trace TypeName(pic) // OK Dim v As Variant Set v = frm1.Picture 'Set pic = Nothing Set pic = v // If form picture assigned: Picture, else, Access-Violation. Trace TypeName(pic) Catch Trace Err$ EndCatch
|
|
|
Post by dragonjim on Jul 8, 2023 20:19:43 GMT 1
Not sure if this is the best explanation for why these differences in behaviour occur, but I'll have a go.
A Picture object is a COM Interface, while a StdPicture object is a COM class (or coclass).
To quote from the Microsoft site: "A COM interface is a predefined group of related functions that a COM class implements".
Therefore, the Picture object acts as an interface to the StdPicture class object, but is not technically a (co)class object in itself. Hence, trying to use TypeName to describe it will result in an error because it is not a Picture per se but an interface to one.
Hence, transferring the frm1.Picture object to a Variant with transfer it as an Interface because a Variant can hold a COM Interface, whereas converting it to a control or object first should transfer the object in frm1.Picture as a picture (either an Image control or StdPicture object).
That's the theory, anyway...
I hope that helps.
|
|
|
Post by (X) on Jul 9, 2023 1:48:25 GMT 1
Thanks dj,
I know just a little about the interface concept, the more I read about it, the more I realize it is important and fundamental, it's just not the first concepts one has to master before writing a "Hello World!" program in BASIC.
I find it all fascinating.
|
|