Home page Home page Home page Home page
Pixel
Pixel Header R1 C1 Pixel
Pixel Header R2 C1 Pixel
Pixel Header R3 C1 Pixel
Pixel
By Captain C | Sunday 20 September 2009 12:05 | 0 Comments
Whenever we have to deal with raw pointers in Basic+, as we did recently, we frequently end up using the GetPointer function. The documentation for GetPointer states that you should always use the LockVariable statement to "lock the string" before retrieving the pointer, but what does that actually mean?


In the beginning...

OpenInsight was originally designed as a 16-bit application running on a 16-bit platform (Windows 3.x), and that platform had a habit of moving chunks of memory around for performance reasons which meant that direct pointers to the memory could be made invalid unless certain steps were taken to guard against this.

So that pointers could be used safely in a Windows 3.x, program memory was tracked by handles instead, and when we wanted a pointer we "locked" the memory via it's handle and got a pointer to it which we could then use, because Windows promised not to pull the bytes out from under our feet.

This is essentially what the Basic+ LockVariable statement did. It marked the memory section used by the Basic+ variable as unmoveable, which meant that a subsequent GetPointer() statement got a valid pointer to it. Afterwards we used the UnlockVariable statement to release the memory section so Windows could move it as needed.


Did you say "did"?

Yep - Memory management changed with the advent of 32-bit Windows operating systems - each application (or "Process" to use the proper term) could access memory in a linear fashion via a virtual address space. This basically meant that the OS handled mapping all pointers to "real memory" internally - no need for any more handle and locking shenanigans.

This of course rendered the primary function of the LockVariable statement obsolete on 32-bit operating systems, but we can't just do away with it entirely because it can perform one other very important function: variable-type coercion.


Basic+ Variable Typing

As we mentioned in our previous post variables in Basic+ are typeless - i.e. they can change their type at runtime based on the context in which they are used. When we're dealing with a typed language like C/C++, we must ensure that any Basic+ variables we pass to a DLL function are actually held internally in the correct binary format.

This is where the other function of the LockVariable statement comes into play - it allows us to specify how we want the Basic+ variable to be typed.

E.g.

0001     * // Example DLL function call with the following prototype
0002     * // that wants a pointer to an Integer
0003     * //
0004     * // VOID STDCALL SomeDLLFunc( LPVOID )
0005      
0006     someArray = "3" : @fm : "43"
0007     
0008     someNum = someArray<1> ; * // someNum is held as a string. To
0009                            ; * // force it to a integer we can do
0010                            ; * // this:
0011                        
0012     * // Call lockVariable to make sure we have an integer
0013     lockVariable someNum as INT
0014    
0015     call someDLLFunc( getPointer( someNum ) )
0016     
0017     unlockVariable( someNum ) 


Likewise for a string we could do this:

0001     * // Example DLL function call with the following prototype
0002     * // that wants a pointer to a string, and it's length in 
0003     * // bytes
0004     * //
0005     * // VOID STDCALL SomeDLLStrFunc( LPVOID, UINT )
0006      
0007     someStr = 3 + 7 + 4567940 ; * // someStr is held as a number. To
0008                               ; * // force it to a string we can do
0009                               ; * // this:
0010                        
0011     * // Call lockVariable to make sure we have a string
0012     lockVariable someStr as CHAR
0013    
0014     call someDLLStrFunc( getPointer( someStr ), getByteSize( someStr ) )
0015     
0016     unlockVariable( someStr ) 


Of course there are other ways of coercing a variable to a certain type:

  1. Adding 0 to a numeric string will ensure it is held in numeric format

  2. Concatenating an empty string to a numeric variable will ensure it's held as a string.

We must beware of using method (1) above to ensure a number however, because Basic+ holds numeric variables in one of two binary formats internally - one as an integer, the other is as a floating point number. The "adding 0" method will not let us specify which one to use - only the LockVariable statement can do that, so when we need to ensure a type we must use it in these circumstances.


So do we really need LockVariable for strings then?

Providing that we're sure of how Basic+ is holding the format of a variable we can actually get away without using the LockVariable statements in our programs, and call GetPointer directly.

However, we would recommend using it in your programs in case the memory model that OpenInsight uses changes at some point in the future. For example, if it changed to a fully garbage-collected environment akin to the .NET runtime, we might need to lock or "pin" the variable in memory. Basically it's just a good habit to adopt.


What about the UnlockVariable statement?

If we're going to use LockVariable then we must also ensure that we call UnlockVariable. Right now it does absolutely nothing whatsoever. Of course that may not always be the case, so we'd recommend you use this too.

Labels: , , ,

0 Comments:

Post a Comment

Subscribe to Post Comments [Atom]



<< Home

Pixel
Pixel Footer R1 C1 Pixel
Pixel
Pixel
Pixel