What are the implications of modifying a form's formname_show() function? I want to change the byval UserData as long to byref myarray() as string.
I just studied the FF auto generated code and I'll just have to figure out the code to pass in an array.
There must a better way. I have a form that is called by many other forms. In the forms create function is where I setup everything. "Everything" is usually contained in some array in another function. Being a relative newly minted PB user, I just couldn't figure out how to pass that original array and know it's size. My kludge worked out like this:
Build a single pointer array to pass in...
Function BuildFormData (ByRef arAny() As String, _
ByRef arFormData() As Long) As Long
' Take arAny array and build an array of pointers in arFormData with arFormData(0) containing the size of the array
Local nSize As Long
Local nIndex As Long
nSize = ArrayAttr (arAny(), 4)
If nSize > 0 Then
ReDim arFormData (0 To nSize)
arFormData (0) = nSize
For nIndex = 0 To nSize - 1
arFormData (nIndex + 1) = VarPtr(arAny (nIndex))
Next nIndex
End If
End Function
Showing the form:
FromName_Show (hWnd, %TRUE, ByVal VarPtr(arForm(0)))
Then in the forms create function:
Dim arForm() As String Ptr
Local nSize As Long
ReDim arForm (0 To 0) At UserData
nSize = arForm (0)
Now i can get at the various strings with @arForm() syntax and nSize tells me the array size.
It works and just doens't feel optimal.
That's a tough question. Kind of need to be able to pass two longs/dwords to the form CREATE rather than just one in order to make it work easier. Looks like your approach is about as 'clean' as it could be. Other than using global variables, global classes, or SetProp/GetProp to store the array size/location, I think that your approach is workable.
There is some danger in modifying a FF function to work properly future releases of FF. If something changes inside of FF you will be faced with a maintenance issue for this modified version. If it is too many months or years down the road you won't remember what you did and you may create lots of extra work. Even worse you may create hidden problems that compile without error but don't work as expected.
Lots of people complain about globals but I find them easy and safe to deal with. If you ALWAYS put your globals in the same place in the project they will not get lost. If you use a naming convention that identifies them like gMyArray you can identify them when you see them (globals always start with a lower case g).
Another alternative could be a table of parameters. If you have many many different parameters to pass to lots of different functions you can put them in a global "table of parameters" and pass the array index through the single global allowed by FF.
After many decades in IT of managing software projects, packaged software, and programming tools I avoid making core changes to everything. It will compromise your code and your ability to maintain things in the future.
Information Technology Architecture is a discipline within itself these days for bigger IT development shops. These architects make sure the design of systems and code can survive future changes in software and infrastructure as well as designs that perform well.
One persons opinion.
Likewise, I use globals all the time. They are part of th elanguage and as long as you name them right then you should have no problem using them correctly. It is like anything else in programming - you need to take precautions to ensure that you use the functionality correctly. When I see people like MCM spouting on and on about no globals is a must it just makes me laugh. It is no different than using GOTO incorrectly.
I try to keep all of my globals in one global TYPE struture (declare it something like gApp or similar). Granted, it is too bad that PB never implement dynamic stings and dynamic arrays as part of a TYPE (I stopped voicing my opinions on that matter). These days, it is just as easy to use a global CLASS that holds all of your global numeric, string, array, etc. data.
Have a look on the post here (http://www.jose.it-berater.org/smfforum/index.php?topic=1266.0), it is very handy to replace the use of GLOBALS and to store/retrieve static values.
...
Thank all of you for your feedback. I do use globals and have them all together in FF_AppStart and they work. I have an entire group of "common" forms that I wanted to be "self sufficient" and not rely on globals. In other words, I call the function that starts some common process and then all the forms that may be invoked within that process are all self-contained without reference to anything outside what is passed around in UserData and returned via FF_FormClose. I hold information on forms with hidden labels and I can even store addresses on the form that way. In the app I'm working on, there is an entire section dealing with persons and all the related functions that may be used in their maintenance. If I isolate the pertinent associated functions (i.e. like multiple addresses, phone numbers, contacts, etc) then I can allow my users to work on more than one person at a time and easily switch around to other app capabilities vs forcing them into single threaded activities with modal forms. (Which do have their place and I use them). Listviews are particularly targeted since there is usually a variable amount of rows to be shown. The idea of using a hidden listview form is interesting and I'll take a look at that. I have been looking into using in memory tables in SQLite3 with one associated global counter to ensure unique table names. Now, if only PB would add some more options for building UDT types....
Here is a function and a subroutine i wrote for WinDev, because they do not have built-in static.
It can be use to store/retrieve 32-bit values, either LONG, DWORD or SINGLE.
In this code replace Handle(MyWindow..Name) with the handle of the Parent of the hidden LISTBOX,
and change int to long, END to END IF, PROCEDURE to SUB, and RESULT with FUNCTION =.
// Retrieve static 32-bit value.
FUNCTION GetStaticValue(LOCAL sUseString is string)
sUseString += "|"
nValue is int = 0
nhMain is int = Handle(MyWindow..Name)
nStaticHandle is int = GetDlgItem(nhMain, IDC_STATIC)
IF nStaticHandle THEN
nIndex is int = SendMessage(nStaticHandle, 399, -1, &sUseString)
IF nIndex > -1 THEN // We found it
nValue = SendMessage(nStaticHandle, 409, nIndex, 0)
END
END
RESULT nValue
// Save static 32-bit value.
// Could be used also to save a real as they fit in 32-bit.
PROCEDURE SetStaticValue(LOCAL sUseString is string, LOCAL nValue is int)
sUseString += "|"
nhMain is int = Handle(MyWindow..Name)
nStaticHandle is int = GetDlgItem(nhMain, IDC_STATIC)
IF nStaticHandle = 0 THEN
nStaticHandle = CreateWindowEx(0, "LISTBOX", "", WS_CHILD + LBS_HASSTRINGS, 0, 0, 0, 0, nhMain, IDC_STATIC, Instance, 0)
END
IF nStaticHandle THEN
nIndex is int = SendMessage(nStaticHandle, 399, -1, &sUseString)
IF nIndex > -1 THEN // We found same static
SendMessage(nStaticHandle, 410, nIndex, nValue)
ELSE // Add it to our static list
SendMessage(nStaticHandle, 410, SendMessage(nStaticHandle, 384, 0, &sUseString), nValue)
END
END
...