Announcement

Collapse
No announcement yet.

Passing Parameters..

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

  • Passing Parameters..

    As I've said on many posts prior, I am trying to convert my VB16/PowerBasic 2.0
    project to 32bit VB/PB.. And I am having GREAT difficulty..

    I am starting to realize that it will be impossible. There are certain
    limitations that I can't overcome. For instance:

    I stated that in 16bit, I could pass UDT arrays to powerbasic ONCE
    and have the .DLL remember the pointer location throughout the
    whole execution of the code. Thus, enabling the DLL, and VB to edit/manage
    and use data from the same source. (memory location)

    Well VB5/32bit doesn't allow this because it moves variables around
    in memory while the program is operating.. <<to me this is very unstable>>

    So I attempted to rebuild my .DLL's to accept the parameters that it
    needs..And creating a long list of UDT parameter passes for
    my .DLL calls.. I read a thread on this forum about "Declare error.."
    and found out that PB can only pass 16 variables..

    While my maximum pass may be close to 16.. I am getting an unusual
    error when I try to pass alot of junk to a .DLL

    Call MonsterActions(MapInfo(0), MCmd, ViewPort, FollowMode(0), Players(0), Attacker, Defender, CurrentPlayer, CurrentObject)
    Call PlayerActions(MapInfo(0), MCmd, ViewPort, FollowMode(0), Players(0), Attacker, Defender, CurrentPlayer, CurrentObject, Active_User%)

    When VB tries to execute this code it accepts the first line and give
    an error : "Compile Error - Too many local, non-static variables."

    The funny part about this error is NONE of the variables are local. They are
    all global to VB..

    I am beginning to think my approach is incorrect. And I may have to totally
    re-write this entire application. Can 32bit .DLLs access/share large
    amounts of memory/variables with VB applications?

    This is beginning to be garbage..

    ------------------
    Explorations v3.0 RPG Development System
    http://www.explore-rpg.com
    Explorations v9.10 RPG Development System
    http://www.explore-rpg.com

  • #2
    Almost all versions of BASIC, from Apple II and TRS-80 on up through the
    latest Windows versions of BASIC, have supported dynamic memory management
    for strings and, often, arrays as well. This dynamic memory management has
    always meant moving variables around in memory while the program is operating.
    There's nothing unstable about it. If you need a block of memory that won't
    move, however, there's no reason you can't allocate one directly from the
    operating system.

    The maximum number of parameters for a PB routine, 16, is rarely an issue
    because it's most unusual that anyone would need more. When you see that
    many parameters, it's time to consider the virtues of UDTs.

    The CALL syntax is quite dated and may be overriding the safety checks that
    VB normally provides to DECLAREd routines. You might want to pull the CALL
    out and see if this gets you a more meaningful error message:

    MonsterActions MapInfo(0), MCmd, ViewPort, FollowMode(0), Players(0), Attacker, Defender, CurrentPlayer, CurrentObject

    ...etc...

    ------------------
    Tom Hanlin
    PowerBASIC Staff

    Comment


    • #3
      Surely your not serious?

      How can a programming statement be "dated"? I don't know if I should
      take that as an insult or not... but surely you have a better
      solution than that.

      I remove the call and recieved the same error.. (not that it mattered).

      The real wierd part is that the first line accepts the call
      while the second produces a bogus error. -Ahh.. I think this 32bit
      conversion is a waste, and I may just re-write the whole thing.



      ------------------
      Explorations v3.0 RPG Development System
      http://www.explore-rpg.com
      Explorations v9.10 RPG Development System
      http://www.explore-rpg.com

      Comment


      • #4
        I'm always serious. And don't call me Shirley!

        Line numbers became "dated" when alphanumeric labels were introduced. DEF FN
        became "dated" when FUNCTIONs became available. And so on...

        CALL became "dated" when DECLARE came around. It's not just unnecessary,
        like LET. Using CALL may turn off the error-checking that is normally
        afforded you by using DECLARE. I'm not sure about how VB6 in particular
        handles that, so it may not be an issue in this particular case.

        The problem is apparently in your VB code, so perhaps you would do better
        to try a VB forum. However, I do have one further suggestion. The error
        message you're getting sounds like you may have too much on the stack. You
        might try making a chunk of your local variables into global variables and
        see if that makes a difference. (If VB thinks you have local variables and
        you disagree, be advised that VB wins: you might investigate what VB
        considers "local").

        I understand that moving to a new programming environment can be frustrating.
        But, what you're trying to do is far from impossible. Stick with it and,
        ahh... try to maintain your sense of humor!

        ------------------
        Tom Hanlin
        PowerBASIC Staff

        Comment


        • #5
          Well VB5/32bit doesn't allow this because it moves variables around
          in memory while the program is operating.. <<to me this is very unstable
          Win/32 may "physically" move memory, but it does not move the logical address (unless you tell Windows its OK to do so. Even then Windows provides the tools to tell you if it did).

          The data isolation across processes works in Win/32 is in my view a massive enhancement over Win/16.

          The way your program chose to share data across the address space in the 16-bit software was an unfortunate design decision.

          This is just one more case in support of my general opposition to trying verb-for-verb 'ports' of software. If you just go in to code and change integers to longs and so on, you really haven't ported. If you have a new environment, you have to do some things a new way.

          MCM



          [This message has been edited by Michael Mattias (edited May 11, 2001).]
          Michael Mattias
          Tal Systems Inc. (retired)
          Racine WI USA
          [email protected]
          http://www.talsystems.com

          Comment


          • #6
            Using CALL may turn off the error-checking that is normally
            afforded you by using DECLARE.
            Really?

            On all my PB compilers, parameter checking is done unless you override with a BYVAL directive.

            It does not matter if there is a DECLARE or simple procedure precedence in the file. (OK, i "beat" the compiler by passing CINT(x) to a function which wanted a LONG).

            Here's some code you can use to check..

            [code]

            FUNCTION DOGGY (X AS LONG) As LONG

            FUNCTION = 2
            END FUNCTION

            FUNCTION PBMAIN AS LONG

            DIM STAT AS LONG

            LET STAT = DOGGY(1,2,3) ' <<< compile error
            LET STAT = DOGGY(CINT(1)) ' << compiles, works

            END FUNCTION
            [code]


            MCM

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

            Comment


            • #7
              Michael, you are quoting out of context - Tom was discussing the VB end, not PowerBASIC.

              ------------------
              Lance
              PowerBASIC Support
              mailto:[email protected][email protected]</A>
              Lance
              mailto:[email protected]

              Comment


              • #8
                Tyrone,

                Does VB have a limit on the number of parameters allowed? Your
                two sub/function calls use 9 & 10 params respectively...

                You might also consider storing all your params into a string
                variable and passing that. Something like...

                Code:
                'Code following in VB - use VB equivalents for the following PB code
                MonsterActionsParams$ = MKL$( VARPTR( MapInfo(0))) + _
                                        MKL$( MCmd) + _
                                        MKL$( ViewPort) + _
                                        ... etc.
                
                Call MonsterActions( MonsterActionsParams$)
                
                ....
                
                'In PB DLL
                MapInfoArrayPtr = CVL( MonsterActionsParams$)
                Mcmd            = CVL( MonsterActionsParams$, 5)
                ViewPort        = CVL( MonsterActionsParams$, 9)
                ... etc.

                ------------------
                Bernard Ertl
                Bernard Ertl
                InterPlan Systems

                Comment


                • #9
                  Nahh.. The problem is Microsoft.. And here is the lovely article to
                  prove it..
                  http://support.microsoft.com/support.../q179/1/40.asp

                  If this doesn't load go to the MS Knowledge base and search for
                  "Too many local nonstatic" and see what u get.. Apprently, this is
                  a bug left in VB5. It occurs when the compiler tries to alot
                  space for passing UDT's to .DLL's -The part about this article
                  that I find most amuzing is that they claim this error will occur when
                  your variable size approaches 64K - Well my UDT is only 2K.

                  Furthermore, it appears that VB Compiler is trying to sum up all the
                  variables calls within a given application. And if the sum is > 64K it
                  causes an error. Because the sample code provided within this
                  Knowledge base page has a subroutine with 10 or so calls
                  to a DLL passing a UDT of aprox 4K.

                  The 11th call is commented out. When the ' is removed the
                  compiler will yield the error on the 11th line. Why? To me, the
                  compiler should look at each call independantly. So if the 11th call
                  causes an error it means the presence of the previous 10 has
                  some bearing on the condition of the 11th.. *LAME*

                  The solution is to store your UDT is a string? And pass the first
                  byte to the DLL. (This is ridiculous!)

                  I heard there was a secret VB VARPTR command that will return the
                  pointer to a variable.. but its undocumented. If I can
                  find out how to use it, I'll take that approach.

                  * This is a NOTE for 32bit moving variables..

                  I wrote a PB application that would output to a file the pointer
                  of a UDT passed from VB.

                  When I application ran the output file had several different memory
                  addresses for the same GLOBAL variable. So either VB, or the fact
                  that the OS is 32bit means that the variables address is being
                  moved.

                  I guess I didn't understand what u meant by "logical address" and
                  "physical address". When a VARPTR command is executed in PB does it give
                  the Windows/VB logical or physical address? - This sound like a
                  very unstable way to maintain an OS.. which explains why Windows crashes
                  soo much.

                  Maybe I'm being a little tough on Microsoft, but this article really
                  insulted my intelligence. Why create a VB/DLL link to pass UDT's if its
                  going to fail the 11th time its called? Thats NOT a development
                  platform. Thats russian roullette development..


                  ------------------
                  Explorations v3.0 RPG Development System
                  http://www.explore-rpg.com
                  Explorations v9.10 RPG Development System
                  http://www.explore-rpg.com

                  Comment


                  • #10
                    And furthermore,

                    Microsoft offers this little piece of code as a fix for this problem.
                    You use the CopyMemory command from KERNEL to create this little
                    piece of code.


                    CopyMemory ab(0), aLargeUDT, UDT_SIZE
                    MySub ab(0)
                    CopyMemory aLargeUDT, ab(0), UDT_SIZE


                    CopyMemory is a KERNEL DLL routine.
                    Mysub is your DLL procedure.

                    But what I'm trippin on is this... If you can pass the UDT *unlimitted*
                    times to the CopyMemory routine and the compiler doesn't crash
                    why is Mysub treated any differently?



                    ------------------
                    Explorations v3.0 RPG Development System
                    http://www.explore-rpg.com
                    Explorations v9.10 RPG Development System
                    http://www.explore-rpg.com

                    Comment


                    • #11
                      'Physical' addresses are not of any concern to the programmer - the Windows memory manager maps memory into and out of process address space transparently. All you need to deal with is the address passed to or from the VB code. Assuming you can get the VB code to compile that is!

                      Internally, VB stores strings in Unicode. When passing a dynamic string to a DLL (BYVAL), VB converts the string to ANSI and passes the address of the ANSI copy to the DLL. Therefore, for each successive call to a DLL, the target strings memory location is almost guaranteed to change because of this "hidden" Unicode<->ANSI conversion process.

                      While I'm not a VB programmer, it does seem quite likely that VB has to do a similar thing to UDT's, since VB supports dynamic strings within a UDT (although it actually stores pointers to the string data in the UDT and the actual string data is stored elsewhere). Therefore, it seems likely that each time you pass a UDT, you actually get the address of a "translated" copy of the UDT, so it's address will move around too.

                      It also seems to me that you may want to make the job easier on yourself and move the complete application into PowerBASIC where you control memory allocation and addressing in a consistent manner.


                      ------------------
                      Lance
                      PowerBASIC Support
                      mailto:[email protected][email protected]</A>
                      Lance
                      mailto:[email protected]

                      Comment


                      • #12
                        If this doesn't load go to the MS Knowledge base and search for
                        "Too many local nonstatic" and see what u get.. Apprently, this is
                        a bug left in VB5. It occurs when the compiler tries to alot
                        space
                        While PB will use the "l" word (limitation), the same "b" word is in the PB compilers.

                        The PB compilers will not report an error when you define too many local nonstatic variables; instead, you wait for run-time and get a GPF. Of course, with PB, you get 1 1Mb stack space, so it doesn't show up. (64K? Is that for real? What a poor design decision by the Lords of Redmond!)

                        I posted in some thread here not too long ago the same fix: instead of doing a LOCAL (bigvar), you create a LOCAL array(0) AS BigVar. This moves the allocation except for the array descriptor off the stack and onto the heap.

                        MCM
                        (yes, I've already filed a formal "b-word" report to the correct department)


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

                        Comment


                        • #13
                          When passing strings to PB I use something like this:

                          DECLARE ReadObject Lib "DATABASE.DLL" (ByVal Rec%, ByVal file$, vbObject AS ObjDataType)

                          On the PB side I use

                          Sub ReadObject(ByVal Rec%, File As ASCIIZ, vbObject as ObjDataType)

                          blah blah..
                          End Sub

                          So I have a PB DLL of hundreds of re usable & veryu handy DOS, MATH,
                          2D/3D point equations, gaming FUNCTION, and MAPPING.

                          The routines are very fast, isolated to the .DLL, and in theory totally
                          dependent of a UDT pass. Just as many of the Win API calls are dependent
                          on a UDT pass.

                          When operating on VB3, I could pass a UDT to the DLL, alter or update
                          values to the UDT and the VB side would be able to view it. This
                          function call doesn't require alot of stack space if the UDT is
                          small. And to tell you the truth, passing UDT's is the entire
                          strength of using DLL's without a UDT pass DLL's are useless.


                          Think about it, without being able to pass and recieve a UDT from a
                          DLL the only method of information transfer between these two
                          program states is BYTE, LONG, INTEGER, and STRING. Returning a sting
                          implies a possible UDT, but its still not quite as good.


                          Moving variables around in memory..
                          It is understood, that using a ByVal parameter will make a copy of
                          the item passed. Thus giving a new VARPTR location for the
                          parameter passed. But when using a UDT, I do NOT use a ByVal
                          declaration so I *EXPECT* the location to be identical to the
                          original UDT so The DLL can return/adjust any values within the
                          UDT.

                          A great Example. I have a great 3D polygon filling routine. The routine
                          allows me to take a simple POINTAPI Type foundation. And
                          use it to create a very powerful UDT for Line calculation.

                          Without a solid UDT pass, I would have to pass these small UDTs
                          as individual variables and *QUICKLY* reach the 16variable limit
                          of PB/VB- Thus, making this type of DLL impossible to create on a 32bit
                          platform.

                          Except for making more DLL subroutines.. I'll make a routine to
                          recieve/calculate the first 16 variables called Calc1 and the
                          other routine will calculate the second 16values. -Thats ridiculous.

                          I have a Pentium 1.5Ghz machine but can only make a program to pass
                          16 variables at a time.. haha - who writes this stuff?


                          *This alone is VERY VERY lame, and is clearly showing an unexcusable
                          limit to 32bit Windows development..



                          ------------------
                          Explorations v3.0 RPG Development System
                          http://www.explore-rpg.com
                          Explorations v9.10 RPG Development System
                          http://www.explore-rpg.com

                          Comment


                          • #14
                            Maybe I'm overlooking something here, but if since you are passing the UDT structure BYREF, you are actually passing a pointer to the UDT storage. PB can access the UDT memory, regardless of where it happens to be stored with each instance of the DLL call.

                            So, I have to ask: Why are you concerned with the location changing each time? (Remember, it is VB doing this to you, not PowerBASIC!).

                            I'm sure R&D could make PB handle more than 16-parameters, but they chose that particular limit for a reason (probably a performance issue). Actually, passing large numbers of parameters adds overhead to the application (stack frame set up time, etc), so if you are after performance (which your comments on a "moving" UDT suggest), then using large numbers of sub/function parameters is slightly counter-productive.

                            In summary, the issue here is primarily VB. VB has to jump through a few hoops to pass some types of data to a DLL (it is 'documented' VB behavior). I'm afraid I just don't understand why you are so concerned.

                            ------------------
                            Lance
                            PowerBASIC Support
                            mailto:[email protected][email protected]</A>
                            Lance
                            mailto:[email protected]

                            Comment


                            • #15
                              Lance,

                              This thread has two conversation going on at the same time, and you just
                              managed to blend them.. hehe

                              Originally, VB3/PB2.0 - Could pass a UDT ByRef to PowerBasic and the
                              DLL could edit it throughout the programs entire execution.
                              I only had to pass the parameter once and the two programs. (VB/PB DLL)
                              were actually using the same variable.

                              I need to convert to 32bit because Win2000 is not accepting 16bit
                              code very well.

                              So It requires me to pass the parameters for every .DLL call. This
                              caused my list of parameter to pass to grow considerably. So I
                              have to make sure I am under 16 parameters PLUS/on the VB side if I
                              call a DLL routine and pass a UDT it gives a bogus error. The Microsoft
                              article above documents this error.


                              BUT CHECK THIS!

                              I think its a *count* within VB to determine how many times you
                              call a DLL within your code. If the count is >10 : bogus error and
                              crash.

                              My original though was brought about by Microsofts suggested solution
                              to bypass this error. They suggest you pass the UDT to a KERNEL.DLL
                              function.. Well if the system is going to crash on a DLL pass, it should
                              crash on *ANY* DLL crash unless its something intentional..!??!

                              And to test this little idea, I made a redirection routine..

                              I call this function 62 times in my code and I recieve that bogus
                              error.

                              Call GetPlayer(idx%, PlayerType)

                              So I wrote a simple VB routine called..

                              Sub vbGetPlayer(idx, PT as PlayerType)
                              GetPlayer idx%, PT
                              End Sub

                              And I global search and replaced the original calls with a call to
                              my new vbGetPlayer to redirect the number of calls to the .DLL ....And GUESS WHAT?!?! It works.. Not one error..

                              Seems like MS is counting the number of times you call a DLL
                              routine..and specifically the number of times you call *non-system*
                              DLL's..

                              Something smells a little fishy in here.. Anyone wann shed light on
                              why a compiler would want to monitor the # of calls to a function
                              in a DLL.. From my experience with compiler design- who cares
                              how many times u call a function in a DLL?


                              ------------------
                              Explorations v3.0 RPG Development System
                              http://www.explore-rpg.com
                              Explorations v9.10 RPG Development System
                              http://www.explore-rpg.com

                              Comment


                              • #16
                                Tyrone,

                                It sounds like what you are really after is making your UDTs GLOBAL
                                to the VB app & PB DLL. Perhaps you can use an API call to
                                allocate a memory block, store all your UDT(s?) info in the memory block
                                in a predefined order and just pass the address of the memory block
                                to the DLL subs/Fns.



                                ------------------
                                Bernard Ertl
                                Bernard Ertl
                                InterPlan Systems

                                Comment


                                • #17
                                  All of my UDT's are GLOBAL.. Which is why the VB error was bogus.
                                  The fix that I came posted works and my application is running..

                                  Though its not faster than my 16bit version.. A guess I have a new
                                  question..

                                  ------------------
                                  Explorations v3.0 RPG Development System
                                  http://www.explore-rpg.com
                                  Explorations v9.10 RPG Development System
                                  http://www.explore-rpg.com

                                  Comment


                                  • #18
                                    Originally posted by Tom Hanlin:
                                    CALL became "dated" when DECLARE came around. It's not just unnecessary,
                                    like LET. Using CALL may turn off the error-checking that is normally
                                    afforded you by using DECLARE. I'm not sure about how VB6 in particular
                                    handles that, so it may not be an issue in this particular case.
                                    Are you really sure that CALL became dated? I guess you need to revise your opinion after looking at
                                    http://msdn.microsoft.com/vbasic/tec...de/calling.asp

                                    CALL will be *required* in the upcoming VB.NET when calling a procedure (SUB) that you pass at least one parameter...

                                    Knuth

                                    ------------------
                                    http://www.softAware.de

                                    Comment


                                    • #19
                                      Knuth, I think you misread that. To the best of my knowledge, it's parentheses that
                                      the vb.net beta requires, not CALL:
                                      Code:
                                         CALL MySub (Parameter)  ' oldest calling method (still available)
                                         MySub Parameter         ' current BASIC practice
                                         MySub (Parameter)       ' vb.net beta required calling method
                                      I consider CALL obsolete because it has been superfluous for, oh, let's see... maybe
                                      15 years? But the main consideration here is that using CALL tells some BASICs
                                      to turn off the parameter checking that they'd otherwise supply. There is no good
                                      reason to use CALL (unless you're using CALL DWORD), and adequate reason to avoid it.

                                      ------------------
                                      Tom Hanlin
                                      PowerBASIC Staff

                                      Comment

                                      Working...
                                      X