|
|||||||
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:
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: DLL, DLL Prototyping, OpenInsight, Windows API |
|||||||
| |||||||
0 Comments:
Post a Comment
Subscribe to Post Comments [Atom]
<< Home