|
Storing Numeric Values in Strings
Or Emulating the CVI and MKI$ functions
Or Whatever happened to hmemcpy?
I needed to extract some numbers being presented to an RS232 port as part of a string of bytes. The numbers were in binary format and I had the task of extracting the relevant bits from the string to form integer values. I recalled ancient dialects of Basic that contained in built functions to encode numbers as strings so they could be stored in simple file structures. The MSDN library CD's revealed some emulation functions for these and I decided to bring them up to date.
The problem with "mapping" an integer (say) into the same memory space as a string is that VB's strong data typing gets in the way. The way around this used to be to use a 16 bit call to a windows sub called hmemcpy(). This copied the bytes stored at any given memory location to another. So, to store an integer in a two byte string you just copied the relevant two bytes of the integer to a predefined and sized string in memory. When I came to look for hmemcpy() among the win32 API calls - it was missing. It was also missing from the list of calls that had not survived the transition from 16 to 32 bits. A little research found another MSDN article taken from Bruce McKinney's excellent book "Hardcore Visual Basic". If you can find a copy, then you can follow the trail to Bruce McKinney's replacement for hmemcpy() - CopyMemory(). This is defined as an "alias" for the RtlMoveMemory() function that resides in the Kernel32 library. Bruce gets all of the credit for this and thus for most of what follows, excluding any mistakes - these are all mine.
The code below can be downloaded (with a demonstration screen) as a zip file by clicking here (3 KB). Instructions for the demo can be found towards the end of this page.
In order to use the following functions you will need to declare the following
Declare Sub CopyMemory Lib "KERNEL32" Alias "RtlMoveMemory" _ (hpvDest As Any, hpvSource As Any, ByVal cbCopy As Long)
The functions follow in pairs below:
Public Function MKI(ValToConvert As Integer) As String This function converts an integer to a two byte string Dim WorkString As String WorkString = Space$(2) Get the size right CopyMemory ByVal WorkString, ValToConvert, 2 MKI = WorkString End Function Public Function CVI(ValToConvert As String) As Integer This function extracts an integer from a two byte string Dim WorkInt As Integer CopyMemory WorkInt, ByVal ValToConvert, 2 CVI = WorkInt End Function Public Function MKL(ValToConvert As Long) As String This function converts a Long to a four byte string Dim WorkString As String WorkString = Space$(4) Get the size right CopyMemory ByVal WorkString, ValToConvert, 4 MKL = WorkString End Function Public Function CVL(ValToConvert As String) As Long This function extracts a long from a four byte string Dim WorkLong As Long CopyMemory WorkLong, ByVal ValToConvert, 4 CVL = WorkLong End Function Public Function MKS(ByVal ValToConvert As Single) As String this function converts a single to a four byte string Dim WorkString As String WorkString = Space$(4) CopyMemory ByVal WorkString, ValToConvert, 4 MKS = WorkString End Function Public Function CVS(ValToConvert As String) As Single This function converts the content of a 4 byte string to a single Dim WorkSingle As Single CopyMemory WorkSingle, ByVal ValToConvert, 4 CVS = WorkSingle End Function Public Function MKD(ByVal ValToConvert As Double) As String This function places a double into an 8 byte string Dim WorkString As String WorkString = Space$(8) CopyMemory ByVal WorkString, ValToConvert, 8 MKD = WorkString End Function Public Function CVD(ValToConvert As String) As Double This function extracts a double form an 8 byte string Dim WorkDouble As Double CopyMemory WorkDouble, ByVal ValToConvert, 8 CVD = WorkDouble End Function
A short word of warning. You may not be as "thick" as me but when I was setting up the simple code demo for this cook-book entry I stored the returned strings from the conversions in the relevant Caption property of the labels in the Frames. I noticed, that if the number passed to the floating point conversion functions was in fact an integer the caption stored a zero length string. Took me some minutes to work out why and to change the demo string data storage to a simple array.
The downloadable demo code:
To operate the demo, put your numbers into the text box and then select the conversion type. Then click the "To string" button to encode the number as a string and to put it into storage. Clicking the "To Number" button will extract the selected number type from the relevant storage string (provided there is something in there already). There is an indicator (of sorts) to show which data types have a stored value.
The functions should not be used within a class unless they are ONLY called
from within that class. Using a class to expose them as a function to the
rest of an application will result in a memory bounds error at runtime when
they are used.
As the demo code shows, they work just fine if included within a code
module.
|