Embedded Visual Basic Windows Ce And Pocket Pc Mobile Applications [Electronic resources] نسخه متنی

اینجــــا یک کتابخانه دیجیتالی است

با بیش از 100000 منبع الکترونیکی رایگان به زبان فارسی ، عربی و انگلیسی

Embedded Visual Basic Windows Ce And Pocket Pc Mobile Applications [Electronic resources] - نسخه متنی

Chris Tacke; Timothy Bassett

| نمايش فراداده ، افزودن یک نقد و بررسی
افزودن به کتابخانه شخصی
ارسال به دوستان
جستجو در متن کتاب
بیشتر
تنظیمات قلم

فونت

اندازه قلم

+ - پیش فرض

حالت نمایش

روز نیمروز شب
جستجو در لغت نامه
بیشتر
لیست موضوعات
توضیحات
افزودن یادداشت جدید



eMbedded Visual Basic®: Windows® CE and Pocket PC Mobile Applications

By
Chris Tacke, Timothy Bassett

Table of ContentsChapter 9.
Harnessing the Windows CE API


User-Defined Data Type Workaround


As I mentioned earlier, eVB is somewhat hindered even in the API calls it can make because it doesn't support callback functions or User-Defined Types (UDTs). While there really isn't anything to be done about the lack of callback support, you can work around the lack of UDT support.

Note

We will be doing a lot of bit manipulation throughout this section and therefore will be looking at most numbers in hexadecimal format. Numbers in hexadecimal are prefixed in VB and eVB with &H, so 255 in hexadecimal would be &HFF.

Bit manipulation can be confusing, especially if you've never worked at a binary level before, so I highly recommend researching decimal, hexadecimal, and binary numbers if you're not comfortable with it.

The source for this section is available from www.samspublishing.com. Although you can easily cut and paste the code from this section and it will work fine, understanding what the code is doing will allow you to take advantage of the techniques in other situations.

User-Defined Data Types


You first need to understand that simply put, a UDT is a single, contiguous block of memory that contains linear data.

For example, let's look at the RECT UDT, which will be used in the ClipCursor sample later. A RECT is the definition of a rectangle. If you look in the eMbedded Tools Help, a RECT is defined like this:


typedef struct RECT {
LONG left;
LONG top;
LONG right;
LONG bottom;
} RECT;

Because a RECT can be used in only eMbedded Visual C++, the help file gives the C++ declaration. If it were written in Visual Basic 6, it would look like this:


Public Type RECT
Left As Long
Top As Long
Right As Long
Bottom As Long
End Type

If you looked at this in memory, there would be 16 contiguous bytes (a Long is 32 bits, so it takes up 4) like this:

Bytes 14

Bytes 58

Bytes 912

Bytes 1316

Left
Top
Right
Bottom

To make things even trickier, the bytes aren't in the order you would expect, because x86 type processors (386, 486, Pentium, Athlon, and so on), and therefore all Windows desktop operating systems, use what's known as

Little Endian architecture . This means that the little, or least significant bits are stored first. For example, if you had the short (VB Integer) number &H9832, it would be stored in memory like this:

Byte 1

Byte 2

&H32
&H98

It works similarly with Longs, so &H12345678 would be stored in memory like this:

Byte 1

Byte 2

Byte 3

Byte 4

&H78
&H56
&H34
&H12

Notice I said that all Windows

desktop operating systems use Little Endian architecture. This is simply because the processors used for desktop PCs, and servers for that matter, dictate this. It should also hold true for Windows CE devices, providing the processor uses Little Endian architecture.

Note

Macintosh architecture is Big Endian, so the large end is stored first, and this is why there are no Windows clones for Mac or MacOS for x86 machines.

Looking back at the RECT UDT, if you define a RECT with the following:


Left = 100
Top = 50
Right = 1200
Bottom = 175

It would look like this in memory:

Bytes 14

Bytes 58

Bytes 912

Bytes 1316

Left

Top

Right

Bottom

Decimal
100
50
1200
1175
Hex
&H00000064
&H00000032
&H000004B0
&H00000497
Little Endian
&H64000000
&H32000000
&HB0040000
&H97040000

Strings


Now you know what a UDT looks like in memory, but how does it help you work around eVB's lack of UDT support? Well, the key is that a String is also a single, contiguous block of memory that contains linear data. What this means is that if you place the data from a UDT into a String, you can pass it as a parameter to an API and the receiver will handle it all the same. You simply need to figure out how to transfer the binary data into a binary string.

You need to be aware of one more thing. PocketPCsand, in fact, all Windows CE devicesuse Unicode for storing strings, which means that each character takes up two bytes, not just one. The reason behind this is that many languages of the world can't be fully represented in 256 characters, but 2 bytes allows for more than 65,000 characters.

What this means is that you can't use standard character manipulation functions to handle binary strings. Left(strMyString, 1) would return 2 bytes, and you need to be able to manipulate one byte at a time to achieve the Little Endian format.

Fortunately, you have binary versions of the String methods Mid, Left, Right, and Asc, which are MidB, LeftB, RightB, and AscB, respectively, and they all work just like their non-binary counterparts.

Getting a Byte Value


To build a binary string in Little Endian format, the first thing you need to be able to do is to extract a single byte from your numeric data. If you consider the previous example and you have &H12345678, you need to extract each byte right to left and append them to a string left to right.

The first step is to isolate the byte you're after. This can be accomplished by simply doing a bitwise And with a number that has only the desired byte's bits turned on. This number is called a

mask. In essence, this means if you want to extract &H34 from your number, you would perform the following:


&H12345678 And &H00FF0000

This results in &H00340000. The only exception is that the most significant bit, position 31 in our example, isn't used for holding a value in Windows, but is used instead to hold the sign. If the bit is on, the number is negative, if it's off, the number is positive. This means that if you want the first byte, &H12 in the example, you turn on all bits in that byte except bit 7 (which is bit 31 in our 4 byte number). This means you And it with &H7F000000.

You can then divide the resulting number by a number with all the bits of lower significance (those to the right of the desired byte) turned on. So in this example of getting the &H34, you would do the following:


&H00340000 / &H0000FFFF

This results in &H00000034 or simply &H34.

So you need a function that performs this. You can make a single function that works both for Integers or Longs, and it looks like the code in Listing 9.11.

Listing 9.11 Extracting the Value at a Specific Byte Position in a Binary String


Public Function GetByteValue(Number As Variant, BytePos As Integer) As Long
Dim mask As Long
On Error Resume Next
' cannot check byte positions other than 0 to 3
If BytePos > 3 Or BytePos < 0 Then Exit Function
If BytePos < 3 Then
' build a mask of all bits on for the desired byte
mask = &HFF * (2 ^ (8 * BytePos))
Else
' the last bit is reserved for sign (+/-)
mask = &H7F * (2 ^ (8 * BytePos))
End If
' turn off all bits but the byte we're after
GetByteValue = Number And mask
' move that byte to the end of the number
GetByteValue = GetByteValue / (2 ^ (8 * BytePos))
End Function

Now to get our &H34 value out of &H12345678, you could call GetByteValue with a BytePos of 2 (you wrote the function zero-based, and you count from the right) like this:


MsgBox(GetByteValue(&H12345678, 2)) 'remember we've number 0 to 3

And you would get a MessageBox with 52, the decimal equivalent of &H34, as its text.

Building a Binary String


Now that you have a function to pull the byte value at a specific position, you need another function that takes the Long or Integer, steps through its bytes, and builds a binary string.

If you could strongly type the variable, you could just check the length in the function, but because all eVB variables are really Variants trying to get the correct length of the variable is unreliable. Instead you'll need to tell the function how long the input number really is.

To make things a little more readable in the calling code, you can declare constants for the only two values you'll ever use, 2 for Integers and 4 for Longs, like this:


Public Const CE_INTEGER = 2
Public Const CE_LONG = 4

The function itself is quite short. The major work is done in a For...Next loop that just iterates through the bytes of the passed in number and appends them to the binary string.

One thing you must do before you start building the string is to handle negative numbers. Negative numbers are easily recognizable because, as I mentioned before, the most significant byte is turned on. In fact, a negative number is stored in memory as the binary complement of the number's absolute value, plus 1. A binary complement is achieved by reversing the values of all the bits in a number, turning off those that are on and vice versa. This is done easily by Xoring the number with a mask number with all bits on.

Look at the number 10 as an example. First, you need the absolute value, which is 10 (&H0A, or 00001010 in binary). We get the complement by Xoring with &HFF to get 11110101 in binary and then add 1 to get 11110110 or &HF6.

"10" in hex
&H0A
"10" in binary
0000 1010
Mask with &HFF
1111 1111
Xor result
1111 0101
Add 1
1111 0110
Back to hex
&HF6

To make things a bit more complex, if you try Xoring the most significant bit of a Long, you get an overflow error, so you have to Xor it as you build the string so that you're Xoring only a single byte.

The resulting function, ToBinaryString, looks like Listing 9.12.

Listing 9.12 Iterating Through the Bytes of an Integer or Long and Returning a Binary String Equivalent


Public Function ToBinaryString(Number As Variant, Bytes As Integer) As String
Dim i As Integer
Dim bIsNegative As Boolean
' cannot check byte positions other than 0 to 3
If Bytes > 4 Or Bytes < 1 Then Exit Function
' If the number is negative, we need to handle it last, _
' so we'll set a flag
If Number < 0 Then
bIsNegative = True
' get the absolute value
Number = Number * -1
' get the binary complement (except the most sign. bit)
Number = Number Xor ((2 ^ (8 * Bytes - 1)) - 1)
' add one
Number = Number + 1
End If
' start at the least significant bit (0) and work backwards
For i = 0 To Bytes - 1
If i = Bytes - 1 And bIsNegative Then
' If the number is negative we must turn on the most
' significant bit and then and append it to the string
ToBinaryString = ToBinaryString _
& (ChrB(GetByteValue(Number, i) + &H80))
Else
' just append the byte to our string
ToBinaryString = ToBinaryString & ChrB(GetByteValue(Number, i))
End If
Next i
End Function

Converting from a Binary String


Now that you can generate a binary string from a number, you can call any API that has UDTs that contain Integers or Longs as well as Strings, but if you need to retrieve a value set by an API in a UDT, you will need ToBinaryString's complementary function.

Here, you can reliably check the length of the variable because it has been strongly typed by the C++ API, so you only need to pass the function the binary string.

Again, this is just reverse engineering the ToBinaryString function. We step through the string, pulling each character (which is actually a byte), determining its numeric value, and adding it to the resulting number. Remember, the rightmost character contains the most significant, or sign, bit, so you have to check for it and if it's on, you have to Xor each byte with &HFF, add one to get the absolute value of the actual number, and then multiply by 1 to make it negative.

Listing 9.13 shows my implementation of FromBinaryString.

Listing 9.13 Iterating Through a Binary String's Bytes and Converting It Back to a Usable Number Format


Public Function FromBinaryString(BString As String) As Variant
Dim i As Integer
Dim bIsNegative As Boolean
bIsNegative = False
' start at the end of the string and work backwards
For i = LenB(BString) - 1 To 0 Step -1
If i = LenB(BString) - 1 And (AscB(MidB(BString, i + 1, 2)) _
And &H80) Then
' check the signigicant bit
' If it's negative, set a flag
bIsNegative = True
End If
If bIsNegative = True Then
' extract the binary complement of the byte
FromBinaryString = FromBinaryString + _
((AscB(MidB(BString, i + 1, 2)) Xor &HFF) * (2 ^ (8 * i)))
Else
' extract the byte
FromBinaryString = FromBinaryString + _
AscB(MidB(BString, i + 1, 2)) * (2 ^ (8 * i))
End If
Next i
' if it is supposed to be negative, make it so
If bIsNegative Then
' Subtract one
FromBinaryString = FromBinaryString + 1
' make it negative
FromBinaryString = FromBinaryString * -1
End If
End Function



    / 108