Announcement

Collapse
No announcement yet.

Working with 'Array Descriptor Table' for String Arrays

Collapse
X
 
  • Filter
  • Time
  • Show
Clear All
new posts

    Working with 'Array Descriptor Table' for String Arrays

    Hello,

    I’m converting an old Grid control dll from GFA Basic to PowerBASIC. The dll allows multiple Grids to be run from one parent window. Grid string data is stored in a global string two dimensional array, as in, say, gsGridData(Col, Row). So five Grids would require five ‘instances’ of gsGridData(Col, Row).

    In the past I’ve been able to do this by saving details of the ‘Array Descriptor Table’ (ADT) for each Grid window to cbWndExtra.

    This allowed me to store an ADT by:

    MoveMemory lpArrayAddress, gsGridData(), 16
    SetWindowLong hGridWnd_1, %DESCRIPTOR_TABLE

    and to retrieve another arrays details by:

    lpArrayAddress = GetWindowLong(hGridWnd_2, %DESCRIPTOR_TABLE )
    MoveMemory GridData$(), lpArrayAddress, 16

    What I want to know is can I do this using PowerBASIC?

    Assuming I can, my next question is where is a string array’s ADT located? According to the manual, PB’s Array Descriptor Table is 16 bytes. Please tell it’s located somewhere easy to obtain like:

    lpArrayAddress = VARPTR( gsGridData(0, 0) ) - 16


    Pat Bullman

    #2
    The "ADT" is proprietary, making it silly to think you can do anything with it.

    It's even silly to think the size is fixed at 16 bytes (if that's what it is).

    If you need "portable" arrays, better to allocate the memory yourself , maintain your own control info and use REDIM AT as necessary.

    If that's too broad-based a statement.... what exactly are you trying to do?

    FWIW I know nothing about GFA Basic.

    MCM
    Michael Mattias
    Tal Systems (retired)
    Port Washington WI USA
    [email protected]
    http://www.talsystems.com

    Comment


      #3
      Just use an array with three dimensions?

      Bob Zale
      PowerBAIC Inc.

      Comment


        #4
        Michael,

        Firstly let me explain a little more how I want this to work.

        A calling application, say an account package, creates a child Grid window to display some summary transaction data. While that Grid window is still open, the program needs to open another Grid window to display some other data (say details, on a transaction). In such an application where you can “drill down” through the data, many Grid windows may be needed, from one to …

        The Grid control needs to switch between data for any actions it needs to undertake, like re-painting the Grid window. In the past, I achieved this by when a new grid was created I would:

        1) REDIM a string array to hold the grid data.
        2) Copy the Array Descriptor Table to cbWndExtra.
        3) Restore the Array Descriptor Table as necessary.

        I could do this over and over again.

        So, I don't want to do "anything" with ADT, aside from "save it away" and then later "restore" it. I thought I made that very clear in my post!

        "It's even silly to think the size is fixed at 16 bytes (if that's what it is)." Well maybe, Michael, you should read the manual!

        The REDIM AT... approach, yes, that's good - I'll investigate that further. I had a cursory glance at it before but didn't think it would work with string arrays.

        And while you don't know anything about GFA Basic, I know that many ex users are now with PB - it was their voice, inter alia, that convinced me to move to PB.



        Bob,

        "Just use an array with three dimensions?"

        A bit cryptic, but if I understand you correctly what you're suggesting is that one dimension determines the Grid “instance”, like:

        GridNo = 1

        REDIM gsGridData(GridNo, Cols, Rows) as String

        Then when I need another Grid window I:

        INCR GridNo
        Cols and Rows set to whatever’s needed.
        REDIM PRESERVE gsGridData(GridNo, Cols, Rows)

        OK, but each Grid is likely to have a different number of columns and rows. How do I handle this.

        And what about when I have five Grid windows and then Grid window number three closes.

        I can’t erase the data, unless I copy element 4 to 3, then 5 to 3, then use:

        REDIM PRESERVE gsGridData(4, Cols, Rows)



        Pat

        Comment


          #5
          Pat,

          A multi-dimensional array in PB where you wish to PRESERVE some data, can only be expanded in the outer-most dimension:
          Code:
          'originally
          DIM MyData(1,2,3) AS STRING
          'later
          REDIM PRESERVE MyData(1,2,4) AS STRING  'increased outer dim from 3 to 4
          So your assumption that you can increase the grid number is not going to fly.

          PB stores arrays in colum major order, a concept illustrated in the manual, where all the GridNo data are in memory first, followed by all the Cols data and the followed by all the Rows data.
          GridNo1
          ...
          GridNoN
          Cols1
          ...
          ColsN
          Rows1
          ...
          RowsN

          It appears what you want to achieve is persistant data for each grid window so that if the window is closed, the data is not lost. Is that correct?

          This presumes that the DLL/EXE creates and maintains the persistant data at startup, is that correct? And maybe your child grid windows can change that data too?

          Since you are going to have a function in your DLL/EXE to call to spawn each new type of grid windows you could so the following:
          1. Pass the address of the string array's table ( use VARPTR) as a parameter to the function that creates the child grid window and uses DIM AT
          2. In that function, store the passed VARPTR value in the window/dialog's user memory
          3. In the callback's %WM_INITDIALOG (DDT) or %WM_CREATE (SDK) event, retreive the address to a local variable and setup a STATIC string array at that address. At that point your absolute array can control the underlying data in the primary array located in your DLL/EXE.

          Here's a quick illustration:
          Code:
          #COMPILER PBWIN 8
          #COMPILE EXE
          #DIM ALL
          #INCLUDE "Win32API.inc"
          %IDC_BTN_TEST   = 1001
          %IDC_BTN_QUIT   = 1002
          %IDC_TEB_DATA1  = 1003
          %IDC_BTN_TEST2  = 2001
          %IDC_BTN_QUIT2  = 2002
          
          CALLBACK FUNCTION Child1DlgProc()
              LOCAL  pKidData AS STRING PTR
              SELECT CASE AS LONG CBMSG
                  CASE %WM_INITDIALOG
                      DIALOG GET USER CBHNDL,1 TO pKidData
                      DIM KidData(1 TO 5,1 TO 2) AS STATIC STRING AT pKidData
          
                  CASE %WM_COMMAND
                      SELECT CASE AS LONG CBCTL
                          CASE %IDC_BTN_TEST2
                              IF CBCTLMSG = %BN_CLICKED OR CBCTLMSG = 1 THEN
                                  LOCAL msg$, i&
                                  msg$ = KidData(1,1) + ", " + KidData(1,2)
                                  FOR i& = 2 TO 5
                                      msg$ = msg$ + $CRLF + KidData(i&,1) + ", " + KidData(i&,2)
                                  NEXT i&
                                  msg$ = msg$ + $CRLF + "When you close this MSGBOX"
                                  msg$ = msg$ + $CRLF + "Client 5 will get $50 more
                                  msg$ = msg$ + $CRLF + "Which you will see in the"
                                  msg$ = msg$ + $CRLF + "Primary window on return"
                                  ? msg,%MB_TASKMODAL,"Kid Data for a Grid"
                                  KidData(5,2) = "$1100"
                              END IF
                          CASE %IDC_BTN_QUIT2
                              IF CBCTLMSG = %BN_CLICKED OR CBCTLMSG = 1 THEN
                                  DIALOG END CBHNDL
                              END IF
                      END SELECT
              END SELECT
          END FUNCTION
          FUNCTION MakeKidDlg (BYVAL hParent AS DWORD, BYVAL pSA AS STRING PTR) AS LONG
              LOCAL hDLG AS DWORD
              LOCAL lRslt  AS LONG
              DIALOG NEW PIXELS, hParent, "Child Window",5,5, 300, 300, %WS_CAPTION OR %WS_SYSMENU, 0 TO hDlg
              CONTROL ADD BUTTON, hDlg, %IDC_BTN_TEST2, "The Data?", 10, 10, 100, 100
              CONTROL ADD BUTTON, hDlg, %IDC_BTN_QUIT2, "Quit", 10, 200, 100, 100
              DIALOG SET USER hDlg,1,pSA
              DIALOG SHOW MODAL hDlg, CALL Child1DlgProc TO lRslt
          END FUNCTION
          
          CALLBACK FUNCTION MainDlgProc()
              SELECT CASE AS LONG CBMSG
                  CASE %WM_INITDIALOG
                      ' Initialization handler
                      DIM SomeData(1 TO 5,1 TO 2) AS STATIC STRING
                      ARRAY ASSIGN SomeData() = "Client1","Client2","Client3","Client4","Client5", _
                                                "$50.00","$150.00","$250.00","$350.00","$1050.00"
                    CASE %WM_COMMAND
                      SELECT CASE AS LONG CBCTL
                          CASE %IDC_BTN_TEST
                              IF CBCTLMSG = %BN_CLICKED OR CBCTLMSG = 1 THEN
                                  MakeKidDlg CBHNDL,BYVAL VARPTR(SomeData(1))
                                  ? SomeData(5,2)
                                  ? "Client5 was $1050, now is " + SomeData(5,2),%MB_TASKMODAL,"Persistant Updated"
                                  DIALOG END CBHNDL
                              END IF
                          CASE %IDC_BTN_QUIT
                              IF CBCTLMSG = %BN_CLICKED OR CBCTLMSG = 1 THEN
                                  DIALOG END CBHNDL
                              END IF
                      END SELECT
              END SELECT
          END FUNCTION
          
          FUNCTION PBMAIN () AS LONG
              LOCAL hDLG AS DWORD
              LOCAL lRslt  AS LONG
              DIALOG NEW PIXELS, 0, "Test This",,, 640, 480, %WS_CAPTION OR %WS_SYSMENU, 0 TO hDlg
              CONTROL ADD BUTTON, hDlg, %IDC_BTN_TEST, "Test", 500, 10, 100, 100
              CONTROL ADD BUTTON, hDlg, %IDC_BTN_QUIT, "Quit", 500, 300, 100, 100
              DIALOG SHOW MODAL hDlg, CALL MainDlgProc TO lRslt
          END FUNCTION
          '
          Rick Angell

          Comment


            #6
            You can save the array data as "window data" (unique to each control) as demo'd here among other places: Simple Report Viewer Using Listview Control November 23, 2002; updated 5/30/05 to 'greenbar' file viewer

            That code could be adapted to 'multiple windows' without touching the "load the data" logic.

            In your case, I might create my own little array desciptor...
            Code:
            TYPE MyArrayDesciptor
              nRow  AS LONG
              nCol   AS LONG
              pData   AS  DWORD
            .. allocate my own memory
            Code:
             LOCAL ADT AS MyArrayDescriptor
               ADT.nRow = whatever
               ADT.nCol  = whatever
               ADT.pData = Malloc ( (nRow-1)* (nCol-1) * 4)  '  4 =size of the pointer
            and when I need to access the data as an array I'd just
            Code:
              REDIM GridArray  (ADT.nRow, ADT.nCol) AS DWORD AT ADT.pData
            Save the ADT for each control as extra window bytes (cbWndExtra), it's only 12 bytes .....

            Code:
             LOCAL pADT AS MyArray Descriptor PTR 
             pADT  = VARPTR (ADT)
              duh.. um...
            Darned, I forgot how to set the extra window bytes if it's more than a LONG!
            Do you have to do in in four-byte pieces with SetWindowLong?

            This getting older sucks.

            Oh, well, it's a start. Something like that, anyway.

            MCM
            Michael Mattias
            Tal Systems (retired)
            Port Washington WI USA
            [email protected]
            http://www.talsystems.com

            Comment


              #7
              Buy a grid?

              I personally like making grids, and do that quite often. However, we have several vendors among us here at PowerBASIC who sell very good grid controls for very, very, reasonable prices. I use some of these grids myself, too. To be absolutely honest, I think its pretty hard to justify making your own from scratch, or even converting one from another language, when the most expensive of the three grids that can be bought isn't over $100. And these are all full fledged custom controls that handle memory completely transparently for you, and you can instantiate as many as you wish.
              Fred
              "fharris"+Chr$(64)+"evenlink"+Chr$(46)+"com"

              Comment


                #8
                Richard,

                It appears what you want to achieve is persistant data for each grid window so that if the window is closed, the data is not lost. Is that correct?

                No, imagine if I have x number of Grid windows, each Grid stores data in the Grid cells. For each WM_PAINT operation you need to be able to access that data to repaint the window. There could be 1 to n Grid windows, as Grid’s are created and deleted on the fly. I can store data identifying each Grid in cbWndExtra.

                This presumes that the DLL/EXE creates and maintains the persistant data at startup, is that correct? And maybe your child grid windows can change that data too?

                No, see above.

                Your, and Michael’s, suggestion of using DIM AT appears to be the way to go. What worries me is how do I release memory when finished with a Grid window.

                Michael,

                What you’ve suggested in creating an ‘owner” descriptor is basically what I’ve done. I have a UDT which holds:

                gGd.ArrayDescriptor ( String * 16 )
                gGd.Columns ( LONG )
                gGd.Rows ( LONG )
                gGd.SectedCol ( LONG )
                gGd.SectedRow ( LONG )


                I also allocate sufficient memory to hold attributes for each Grid cell, things like: colours; left, right and centre justification; etc. And like you said the memory requirement for this:

                SIZEOF( UDT1 ) + ( Cols * Rows * SIZEOF ( UDT2 ).

                It’s created as you suggested and the memory pointer is stored in cbWndExtra.

                For info, CbWndExtra can only store 40 bytes with each window “instance” and to answer you question I think the only API’s are SetWindowLong() and SetwindowWord().

                So the problem still exists on how to access each string array as well to resize or delete it.


                Pat

                Comment


                  #9
                  Hello Fred,

                  Buy a grid?

                  I'm using this as more of a learning curve. I have several tools which I'm converting to PB and by the time I'm finished I should have a good idea of PB's strengths and weaknesses. More importantly, I'll have the confidence to start using PB in live work applications.

                  Also, right at the moment I don’t want to be beaten by some “simple” problem. When the problem isn’t so simple anymore, then I might have a different answer


                  Pat

                  Comment


                    #10
                    I recall reading a tutorial on custom controls written by Chris Boss and he stated that that 40 byte limit was a limit only with Win 95?

                    In any case I've never exceeded it anyway. I write grids as custom controls in dlls and store the numbers of rows and columns in cbWndExtra bytes. As part of the CreateWindowEx() call that creates the grid I pass in information on numbers of required rows and columns and buffer sizes. Memory allocations are made during the WM_CREATE processing for the grid and pointers are stored in the cbWndExtra bytes. Also in the WM_CREATE processing I instantiate a window for each grid cell. These calls create further WM_CREATE messages in which a memory allocation is again made to store the data in each cell. When grids are destroyed WM_CLOSE and/or WM_DESTROY messages come through for the main window comprising the grid itself, and for any/all subwindows (cells, buttons, etc) of which the grid (parent container control) may be comprised. Off-loading all this complexity in a dll based custom control eliminates any need for the main app serving as host for the dll's grids to deal with memory allocations/deallocations.

                    I might point out that I store 2 dimensional data linearly in allocated memory. It isn't hard to offset back and forth to get/set row/col locations.
                    Fred
                    "fharris"+Chr$(64)+"evenlink"+Chr$(46)+"com"

                    Comment


                      #11
                      Darned, I forgot how to set the extra window bytes if it's more than a LONG!
                      Do you have to do in in four-byte pieces with SetWindowLong?
                      This assumes the control window might be an SDK style for sure so you can set cbWndExtra up to the maximum of 40 bytes. (So MCM's proposed 12 bytes ... not a problem)

                      Then you would Set or Get by using the byte offset of each 32 bit value (it appears that is MS's intent in their help description). Since it is 0 based you would be setting or getting from an offset of 0,4,8,12, ..., or 36 in the call, depending on the amount allocated when you set up the window and assigned cbWndExtra.

                      SetWindowLong hWnd,offset,dwValue
                      dwValue = GetWindowLong(hWnd,offset)

                      For a quick demo, load up the Samples\SDK\HelloWin.bas.

                      Set the cbWndExtra in WINMAIN to:
                      Code:
                        wce.cbWndExtra    = 12
                      Change the FUNCTION WndProc CASE %WM_CREATE as follows
                      Code:
                      CASE %WM_CREATE
                              SetWindowLong hWnd,0,1000
                              SetWindowLong hWnd,4,2000
                              SetWindowLong hWnd,8,3000
                      and in CASE %WM_PAINT comment out the current DrawText line, adding the following:
                      Code:
                              'DrawText hDC, "Hello, Windows!", -1, tRect, %DT_SINGLELINE OR %DT_CENTER OR %DT_VCENTER
                              DrawText hDC, STR$(GetWindowLong(hWnd,0))+ STR$(GetWindowLong(hWnd,4))+STR$(GetWindowLong(hWnd,8)), -1, tRect, %DT_SINGLELINE OR %DT_CENTER OR %DT_VCENTER
                      Of course the above is just a quick demo of cbWndExtra use, not directly Pat's code needed. Pat's first post indicated a "global string two dimensional array" that the older program copied for use in the child windows, (IOW same data, multiple copies ?). That begs the question WHY copy? If Pat does not want any child window to inadvertently change the "global" data, perhaps while maybe doing some what-if's ... well ok, we would understand that need, or if there is the possibilty of two of the kiddies trying to access the global data at one time because they are crunching data ... as separate threads.

                      Several ways to accomplish the end results, but perhaps we need a bit more from Pat on the data and if the kiddies can change it and need to do so independantly.
                      Rick Angell

                      Comment


                        #12
                        Well, I shouldn't talk!

                        Pat wrote...

                        Also, right at the moment I don’t want to be beaten by some “simple” problem. When the problem isn’t so simple anymore, then I might have a different answer
                        I can't say anything to that because I spent my most productive energies last week essentially working on a non-problem!

                        However, I must say that if you think building grids is a somewhat simple and trivial undertaking, then your normal work flow must be building/designing computer run missle defense systems and things like that! My hats off to you!
                        Fred
                        "fharris"+Chr$(64)+"evenlink"+Chr$(46)+"com"

                        Comment


                          #13
                          Hello All,

                          I’d like to explain in a little more detail how the old grid code worked.

                          The Grid had an UDT for storing the Array Descriptor Table (ADT) and other details, looking like:

                          Code:
                          TYPE ArrayDetails
                            ADT    AS STRING * 16
                            Cols    AS LONG
                            Rows    AS LONG
                          END TYPE
                          GLOBAL gAd as ArrayDetails

                          Then in actual use the old code would go something like the following:

                          Firstly a parent creates the first Grid window and calls a Grid procedure to establish settings:

                          Code:
                          Grid1 = CreateWindow( “”, “Grid_Class” … ) 
                          Cols = 5, Rows = 100
                          GridInitiate Grid1, Cols, Rows
                          Inside the Grid dll, the old Grid reacted by:

                          Code:
                          DIM GridData(Cols, Rows) AS STRING
                          MoveMemory gAd.ADT, VARPTR( GridData(0, 0) ), 16
                          gAd.Cols = Cols
                          gAd.Rows = Rows
                          
                          SetWindowLong hGrid, 0, VARPTR( gAd )
                          This effectively stored the ADT.

                          Then when the parent sends data to the window:

                          Code:
                          FOR c = 1 to Cols
                            FOR r = 1 to Rows
                              GridSetText Grid1, c, r, CellData$
                            NEXT r
                          NEXT c
                          The Grid would first:

                          Code:
                          lpData = GetWindowLong( Grid1, 8 ) 
                          
                          Cols   = @lpData.Cols
                          Rows   = @lpData.Rows
                          MoveMemory VARPTR( GridData(0, 0) ), gAd.ADT, 16
                          therefore restoring the array before storing data sent by GridSetText

                          This allowed the parent to create another Grid window:

                          Code:
                          Grid2 = CreateWindow( “”, “Grid_Class” … ) 
                          Cols = 3, Rows = 50
                          GridInitiate Grid1, Cols, Rows
                          Inside the Grid we could clobber the ADT (details of which were stored away):

                          Code:
                          MoveMemory VARPTR( GridData(0, 0) ), CHR$( 0, 16 ), 16
                          before:

                          Code:
                          DIM GridData(Cols, Rows) AS STRING
                          gAd.Cols = Cols
                          gAd.Rows = Rows
                          SetWindowLong hGrid, 0, VARPTR( gAd )
                          This effectively created another array of data for this Grid window, the ADT of which could stored and retrieved as necessary.

                          The old code allowed for numerous Grid windows to be created and destroyed.

                          The code to destroy a Grid window (following a WM_DESTROY) was like:

                          First restore this windows array detail

                          Code:
                          lpData = GetWindowLong( Grid1, 8 ) 
                          
                          Cols   = @lpData.Cols
                          Rows   = @lpData.Rows
                          MoveMemory VARPTR( GridData(0, 0) ), gAd.ADT, 16
                          Then simply:

                          Code:
                          ERASE GridData
                          Again because ADT for any other open Grid window were stored away, their data was also safe.

                          =====================================

                          This approach was based on the language allowing storing and retrieving ADT’s. This was not a language design but a quirky, a work-around.

                          If PB doesn’t allow this then the options appear to be:

                          1) As Michael suggested, get the parent to send request for individual cell data in the form of:

                          Code:
                            SendMessage hParent, %SEND_CELL_DATA, hGrid1, Cell_Details
                          2) Allocate memory, and manage storing/retrieving string data myself. What a pain! Particularly if a Grid’s cell data is dynamic and changes frequently.

                          3) OK, folks – any good ideas?



                          Pat

                          Comment


                            #14
                            Wow... Every head is a world. I didnt used that method in Egrid32.

                            Pat.. First of, Dont use Movememory(). PowerBasic Supports Pointers (@).
                            This means you can direclty modify the information, without copies.

                            Second, you can create a 1 Dimension array, with a 2 dimension index.

                            For example:

                            Index(5,5) = 1
                            CellText(1) = "The text"

                            Get the text of cell 5, 5:

                            TheText$ = CellText(Index(5, 5))

                            Why? Because its easier and faster to update
                            an index table than all the arrays in a 2 Dimension
                            set of arrays. More efficient.

                            And maybe the best of all advices... Take a look at my grid.
                            It will save you lots of pains.

                            Comment


                              #15
                              OK Elias,

                              Now we're talking. I'll download Egrid32 and take a look.

                              MoveMemory? I'm only moving 16 bytes.

                              Thinking as I'm writing here but I can't see the improvement of using an index array in this situation. I still need to store the string data. I don't envisage the actual data being modified frequently.

                              (In GFA BASIC, the arraysort function could sort an index array instead of the actual array but I can see how you could get the same out of PB using pointers.)

                              Will be spending the next few how studying EGrid32

                              Pat

                              Comment


                                #16
                                Elias

                                And maybe the best of all advices... Take a look at my grid.
                                It will save you lots of pains.
                                I didn’t know what Egrid32 was till I started looking.

                                It's a proprietary system isn't it? I don’t get to see source code!


                                Pat

                                Comment


                                  #17
                                  Pat--

                                  Here's the real problem, in my opinion. You've found an unintended "quirk" in another programming language, and now you're trying to use a large shoehorn to make it work in a similar fashion in PowerBASIC. Truth is, you could actually likely force that to happen, if you try enough, but certain factors in a compiler are undocumented for very good reason: They are subject to change in the future. Change in the future would then break your code.

                                  There are many ways to accomplish your needs within the bounds of documented compiler features:

                                  1- Use a 3-dimension array large enough to hold the largest of your 2 dimension subset array.

                                  2- Reference the array as a parameter to a Sub/Function. The caller would designate the correct argument array.

                                  3- Use string pointer variables with indexed addressing instead of an array.

                                  4- Use a pointer array to select the correct array data area.

                                  5- Use DIM.....AT memoryloc to dynamically reference allocated memory.

                                  6- Create one or more functions which manage all access to your array, and used to read/write/allocate/erase/switch the data (ala oop).

                                  There are probably many more options, but it's late. {smile} You have many powerful tools at your disposal, so you needn't be concerned about some perception of weakness.

                                  Best regards,

                                  Bob Zale
                                  PowerBASIC Inc.

                                  Comment


                                    #18
                                    Just for the record, the PB array descriptor DID change, between 6x and 7x.

                                    No, the size did not change, but something else did, resulting in inability to use the descriptor across modules compiled with different versions of the compiler for a certain thing.

                                    I was told it was an inadvertent change, and I was able to work around it fairly quickly (finding it took a heck of lot longer than working around it).. but.....

                                    .. it does tell you that it is - as I stated earlier - silly to rely on undocumented and proprietary attributes.

                                    (Which I did not do, by the way... even though it would have made this story a much better one).

                                    MCM
                                    Michael Mattias
                                    Tal Systems (retired)
                                    Port Washington WI USA
                                    [email protected]
                                    http://www.talsystems.com

                                    Comment


                                      #19
                                      Bob,

                                      Here's the real problem, in my opinion. You've found an unintended "quirk" in another programming language, and now you're trying to use a large shoehorn to make it work in a similar fashion in PowerBASIC.
                                      You're right of course, to an extent. Although the quirk was something GFA promoted after they saw the use of it but that's all in the past.

                                      What I'm after is a way of the Grid storing the cell data, and being able to switch between data related to different Grids.

                                      The alternative, of the parent providing the data on a needs basis, is a feature already built into the code. It was necessary to overcome 64k data limit in 16 bit dll's (see earlier post).

                                      Code:
                                        SendMessage hParent, %SEND_CELL_DATA, hGrid1, Cell_Details
                                      Also, the idea of the parent passing an array with the cell data is workable as well. Then using REDIM AT appears the next best solution, although I need to think this through more.

                                      Please don't think that I'm not confined to the descriptor table solution though it worked well. What I'm really interested in is a way of of the Grid storing the cell data.

                                      There are many ways to accomplish your needs within the bounds of documented compiler features:

                                      1- Use a 3-dimension array large enough to hold the largest of your 2 dimension subset array.

                                      2- Reference the array as a parameter to a Sub/Function. The caller would designate the correct argument array.

                                      3- Use string pointer variables with indexed addressing instead of an array.

                                      4- Use a pointer array to select the correct array data area.

                                      5- Use DIM.....AT memoryloc to dynamically reference allocated memory.

                                      6- Create one or more functions which manage all access to your array, and used to read/write/allocate/erase/switch the data (ala oop).

                                      There are probably many more options, but it's late. {smile} You have many powerful tools at your disposal, so you needn't be concerned about some perception of weakness.
                                      I’m not sure what you mean here. It’s very late for me (in Australia) and I’ll digest this a bit more later on. I’d love just a little more info on what you mean - any examples you can point me to.

                                      BTW, I dont have any concerns or
                                      some perception of weakness
                                      with PB. The more I use it the more I like it and I've even promoted it to several old GFA users.



                                      And Michael,

                                      Thanks for your comments. They surely must provide help to someone out there but …


                                      Pat

                                      Comment


                                        #20
                                        >It was necessary to overcome 64k data limit in 16 bit dll's (see earlier post).

                                        That's pretty easy to overcome in 32-bit Windows: "DO NOTHING."
                                        Michael Mattias
                                        Tal Systems (retired)
                                        Port Washington WI USA
                                        [email protected]
                                        http://www.talsystems.com

                                        Comment

                                        Working...
                                        X
                                        😀
                                        🥰
                                        🤢
                                        😎
                                        😡
                                        👍
                                        👎