====== DLL Prototyping - The LockVariable statement ====== === Published 20 SEP 2009 at 12:05:00PM by Captain C === Whenever we have to deal with raw pointers in Basic+, as we did [[http://www.sprezzatura.com/blog/2009/09/dll-prototyping-strings-and-things-part_15.html|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 [[http://www.sprezzatura.com/blog/2009/09/dll-prototyping-strings-and-things-part_15.html|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: - Adding 0 to a numeric string will ensure it is held in numeric format - 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. === Comments === == Original ID: post-8780916512639161160 ==