Visual Basic Development

To develop Windows CE applications using Visual Basic, you will need the Windows CE Toolkit for Visual Basic 5. Notice that at the moment the toolkit will not run with any other version of Visual Basic. The toolkit provides the Windows CE-specific functionality and the IDE changes needed to create and build Windows CE applications. In terms of the language, Visual Basic for Windows CE is a subset of Visual Basic, Scripting Edition. This means that much of the Visual Basic 5 language is not supported. However, enhancements have been added to the language in Visual Basic 6, but not Visual Basic 5. This chapter is aimed at developers who are already experienced in Visual Basic 5 development and, therefore, this section focuses mainly on the differences and new features of the language and environment.

The Development Environment

Creating a new Windows CE project is not much different from creating a normal Visual Basic one. A new project type, Windows CE Project, has been added, which configures the Visual Basic IDE for Windows CE development. In standard Visual Basic you can create a number of different types of project, such as Standard EXE, ActiveX EXE, and ActiveX DLL. However, a Windows CE project might only create the equivalent of a Standard EXE, or—to be more precise—a PVB file. Before you commence coding, you must configure your project's properties. The Project Properties dialog box is displayed automatically when you start a new project. Once you have dismissed the Project Properties dialog box, you will notice some changes in the IDE from that of standard Visual Basic. Figure 5-7 shows the major changes to the IDE.

Figure 5-7 Windows CE IDE changes in Visual Basic 5

The first things you will notice are the greatly reduced number of options for the Run and Debug menus. This is because the way that Windows CE programs are run in the development environment is very different from the way a standard Visual Basic project runs. The toolkit provides an emulation environment that allows you to run and debug your applications without actually having an HPC device. I will explain the emulator in more detail later, but essentially, the emulator is part of the Windows CE Platform SDK and is supplied with the Windows CE Toolkit for Visual Basic 5.

A number of new menu options have been added to help with Windows CE development, as listed here.

  • The Application Install Wizard, as the name suggests, provides the equivalent functionality as the Visual Basic Setup Wizard.

  • Books Online contains reference information and is very comprehensive. Additional information can be obtained from the Microsoft Web site.

  • Download Runtime Files transfers the Visual Basic run time files to the emulation and HPC device.

  • Control Manager downloads ActiveX controls to either the emulation or HPC environment. Any controls you use in your application will need to reside in the environment where you choose to run or debug the application.

  • Heap Walker (a scaled-down equivalent of the program supplied for other Windows versions) views the process and "heaps" information for processes running on your HPC.

  • Process Viewer provides the functionality of the PVIEWxx.EXE program supplied with other versions of Visual Basic. Process Viewer lists each module loaded in memory on the HPC. You can use this application to kill processes running on your HPC and you can also view the modules being used by a particular process.

  • The Registry Editor functions the same way as in the other Windows operating systems. This version, however, allows you to edit both the HPC and emulator Registries.

  • The Spy utility allows you to examine details of window objects that are loaded on the HPC. Like the Windows NT/9x version, Spy allows you to view the window and class information and to view the message queue to a particular window on the HPC device.

  • Zoom was originally designed to allow you to zoom in on an area of the screen to view the bit patterns. The Windows CE version has extended this functionality to allow you to also save screen shots of your HPC screen.

Windows CE Application Design Philosophy

Because of the nature of the Windows CE operating system, a new design philosophy is required in order to develop Visual Basic applications for the HPC. The foremost concern is that of memory. With such a potentially small amount of RAM you stand a good chance that your application might run out of memory or be terminated when another application requires memory resources being used by your application. Unlike Windows NT/9x, there is no virtual memory management, so if memory runs out—tough! Once the machine starts running low on memory it will look to see if there are any other applications running. If another application is found, it will be terminated; this will continue until the memory requirement has been satisfied. In effect, any program in memory is in danger of being shut down by the operating system to satisfy memory requirements. A Windows CE application must be designed with this in mind. User transactions must be well designed so that in the event of an application being closed, user data is not left in an unpredictable state. The operating system's transaction mechanism will protect you against data integrity problems at a record level, but you can build certain scenarios into your code that increase the risk of data getting out of sync. For example, if you are writing a series of related records from various sources, it might be a good idea to collect all the data and then apply the changes in a batch, rather than as each individual item becomes available.

Another consideration is that of the power supply. The nature and size of HPC devices means that at some point the battery will run out. HPC devices usually contain backup batteries that are designed to preserve the memory while the main batteries are being changed. However, the backup batteries can be removed as well. An application must allow for the possibility of power loss. In this instance, batch operations will not be of any use. When power is lost, the entire content of the RAM is lost. The only safeguard against losing data is to back up to a PC. Do not confuse loss of power with the user switching off the device. In the latter case, RAM is not destroyed—the HPC merely enters a sleep state. When the HPC is turned on again, the device's previous state will be restored. As a Visual Basic developer, you will very likely be writing high level applications and as such, if there is a loss of power, the application will no longer be in memory. Unless the user's data has been synchronized (saved to a desktop), the data will also be lost.

In terms of visual appearance, the potentially small screen display might mean cutting back on some of the more aesthetic user interface elements—a good practice would be to make sure the elements are functional rather than cosmetic. In most cases I would advise against using unnecessary controls in your application because each control you include in your project will need to be installed on the device. This will leave less working memory. You should also give consideration to the ergonomics of the interface; for example, if you are not using default color schemes, you should make sure that the contrast is sufficient for both gray-scale and color displays.

Your First Windows CE Application

Writing a Windows CE program is much the same as writing any other Visual Basic program. However, you'll have to accustom yourself to many differences in the language and to the development environment. You'll need to carefully consider the structure of your code and the implementation of the finished application. I have written a card game named Pontoon, and I will use this application from time to time to highlight important points. Figure 5-8 shows some screen shots of the application.

Perhaps now might be a good time to explain quickly the rules of the game—it's similar to Blackjack, or 21. The player plays against the computer (dealer) with the aim of attaining a score of 21. If the score goes over 21, the game is lost. The player can choose to be dealt another card, ("twist"), and his or her score is calculated as a sum of the face values of all the player's cards. The ace has a face value of 11 and picture cards have a face value of 10. If the player decides that another card might bring his or her score over 21, he or she might decide to not take anymore cards ("stick"). After a player chooses to stick, all subsequent cards will be dealt to the dealer. If the dealer reaches a score higher than the player's and below 22, the dealer wins. But if the dealer's score exceeds 21, the dealer loses. Before the player makes the first twist he or she must select an amount to gamble. If the game is lost, the player's funds are deducted by that amount. If the player wins, his or her funds are increased by the amount gambled. That's it! The full source code for the Pontoon game is included on the CD-ROM accompanying this book.

Figure 5-8 The Pontoon Windows CE card game in action—I got lucky this time!

General Design Considerations

Building a Windows CE application is essentially a compromise of various factors, more so in Visual Basic because of the small subset of available programming constructs. The common factors that you will need to consider are size, memory, maintainability, and stability. All these factors together determine the quality of the application as shown in Figure 5-9.

Figure 5-9 Design factors in a Windows CE application

For my Pontoon game, the primary goals are good maintainability and small size. Various techniques are used to reduce the program size while trying to keep it reasonably understandable and maintainable; however, this may result in a loss in performance and perhaps in robustness. But the losses are not so great because stability is not a major concern. We can code to avoid obvious errors, but if an error does occur, at worst the user will get an error message. Speed is not really important here because the actual processing cycles are relatively small.

The user interface

The most obvious consideration when writing an HPC application is that of the screen display. The current HPC machines have a relatively small screen resolution, though these do vary between models. Apart from the physical dimensions, color is also an issue. Version 2 of Windows CE introduced support for 16 colors. This has improved the color contrast on monochrome displays, though devices are now available with color displays.

Windows CE supports only two window styles—fixed border or no border—and there is no Minimize or Maximize button. You can set the form's BorderStyle design time property to another style but any styles other than those allowed will be overridden at run time. When creating a new form, Visual Basic defaults to a size near the maximum resolution of the HPC device you are using, but you can change this default size in the Project Properties dialog box. Any size that you set here will be retained as the default for future forms you create.

A new window style has been implemented for message box windows. If you specify a button configuration of vbOKOnly, the message box will be displayed with the OK button in the title bar next to the Close button. Other button configurations will display message boxes in the usual format. The height of the message box has been scaled down to obscure the least amount of space on the screen. While we're on the subject of message boxes, you should be aware of a glitch in the current version of the language. The message box is not modal, but floats above its parent window. The form below the parent window can still respond to mouse events. To avoid this problem you will need to disable your form while the message box is displayed.

When designing a Windows CE form, you should evaluate the need for a border and title bar. Many of the Microsoft applications, such as Pocket Word and Pocket Excel, do not have title bars or borders. This really does increase the amount of usable screen real estate.

In terms of user interface controls, you will find that not all of the intrinsic Visual Basic controls are supported. Rather, the intrinsic user interface controls you can use are:

  • Check Box

  • Combo Box

  • Command Button

  • Frame

  • Horizontal and Vertical Scroll Bars

  • Label

  • Line

  • List Box

  • Option Button

  • Shape

  • Text Box

  • Timer

Although the remaining controls are not removed from the toolbox, a warning message will be displayed and the control will be removed if you attempt to place one of these on your form. Obviously, graphical capabilities must be retained, so two new graphical controls are available from the Components dialog box: PictureBox and ImageCtl.

These two graphical controls are replacements for the standard PictureBox and Image controls, though you should note that their class names have changed. These two controls retain the ability to display images and pictures, although there are some differences from the controls they replace. Apart from being a lightweight control, the PictureBox has undergone some changes to its methods. The methods such as Line, Circle, Point, and PSet have been removed and are now replaced by this new set of methods:

  • DrawCircle

  • DrawLine

  • DrawPicture

  • DrawPoint

  • DrawText

Pontoon, being a card game, relies heavily on graphics. The graphical methods supported by the Form object in other versions of Visual Basic are not available in the Windows CE toolkit. Therefore, the PictureBox control is used for displaying the graphics.

Windows CE contains a unique set of constraints or bounds that we must work within. One such constraint is that control arrays are not permitted. You can create control arrays but you will get an error at run time if you do so. In the case of the Pontoon game, the work-around to this problem is to use a PictureBox control and draw the card graphic in the picture box. In other versions of Visual Basic, it might have been easier to simply create a control array of Image controls on the fly, and then load the required images. The Pontoon game uses the Windows CE PictureBox control as a container into which the cards can be drawn. The PictureBox control does not have the ability to be a container object, so a problem arises because you cannot place labels within the PictureBox. Because labels are lower in the z-order, you can't show labels within a picture box. To get around this problem I've used two picture boxes to display the rows of cards and I've used a Shape control to create an area around the picture boxes and labels to form a playing table.

Figure 5-10 shows the Pontoon screen at design time. The number of controls have been kept to a minimum. The screen is built up using only essential controls or elements needed to improve clarity.

Figure 5-10 The design-time layout of the Pontoon game

You will notice that although the design-time form looks like a standard Windows NT/9x form, the form will be displayed using the Windows CE window style when the program is run—that is, with no Minimize or Maximize buttons. We have an interface where all elements are large enough to be clearly visible, resulting in little clutter on the screen.

Another important aspect of the user interface design is that of keyboard ergonomics. If I were sitting on a train playing this game, I might find it uncomfortable trying to use the stylus if the train is swaying. It might also be uncomfortable to use the accelerator keys because two hands are required. One design feature I've implemented to aid keyboard use is the KeyPreview property, which is used to intercept keystrokes and convert them to accelerator key presses. In an ideal world we could simply code the following in the form's KeyPress event, as shown here:

 Private Sub Form_KeyPress(KeyAscii)     SendKeys "%" & Chr(KeyAscii) End Sub 

Alas, this is not possible—the SendKeys statement is not supported. Instead you can achieve the coding using a method like the one I've implemented here:

 Private Sub Form_KeyPress(KeyAscii)     If StrComp(Chr(KeyAscii), "g", vbTextCompare) = 0 Then         txtGambleAmount.SetFocus     End If     If StrComp(Chr(KeyAscii), "t", vbTextCompare) = 0 Then         cmdTwist.Value = True     End If     If StrComp(Chr(KeyAscii), "s", vbTextCompare) = 0 Then         cmdStick.Value = True     End If      End Sub 

Simple routines like this take no time to write but can drastically improve the ergonomics of an interface. I expect many new ideas to be developed in the future that will aid usability.

In addition to the intrinsic controls and the PictureBox and ImageCtl controls that are supplied with the development kit, you can also download a set of controls from the Microsoft Web site at http://www.microsoft.com/windowsce/developer. At this site you can obtain the Microsoft Windows CE ActiveX Control Pack 1.0, which contains many more useful controls. The download is more than 5 MB but is worth downloading, because in this pack you get the following controls:

  • GridCtrl

  • TabStrip

  • TreeViewCtrl

  • ListViewCtrl

  • ImageList

  • CommonDialog

The addition of these controls allows you to create the same interface styles as the controls of full-blown Visual Basic applications. The list of controls will grow and I would expect a lot of new controls to emerge from third-party vendors as well.

Size and memory considerations

I said earlier that one of the goals for the Pontoon game was to be small in size. The word "size" might imply the physical file size, but an important factor is also the memory footprint of the application. You can control the program's memory footprint by enforcing restrictions on functionality and by writing more efficient code. The former method will nearly always be a business issue and, therefore, possibly might be out of the programmer's control. However, using efficient coding techniques is a trade-off against readability and maintainability. However, I'll discuss some techniques that you can use to code more efficiently.

Program variables are the obvious source of memory consumption. The Windows CE Toolkit for Visual Basic 5 allows only Variant type variables. This is a little surprising, given that Variants take more memory than a "typed" variable. Although your variables will be Variant types, you can still coerce them into a subtype using the conversion functions like CLng, CCur, and so forth, although this coercion will be performed automatically when a value is assigned to the variable. The Pontoon game makes extensive use of bit flag variables. This is an efficient way to store multiple values, providing there is no overlap in range of the bit values. By using bit values, the overall memory requirement can be reduced, but you must be careful if creating constants to represent the bits because you might end up using the same or larger amounts of memory. The following is the declaration section from the form:

 Private m_btaDeck(12, 3) Private m_btaPlayerCards        ' Byte Array stores cards held by player. Private m_btaDealerCards        ' Byte Array stores cards held by dealer. Private m_nPlayerScore          ' Player score - total value of cards held. Private m_nDealerScore          ' Dealer score - total value of cards held. Private m_nPlayerFunds          ' Dealer score - total value of cards held. Private m_nGameStatusFlags      ' Long Integer of flags indicating game                                  ' status. ' Constants used with m_nGameStatusFlags. ' Private Const m_GSF_PLAYER_HAS_21 = &H1 Private Const m_GSF_DEALER_HAS_21 = &H2 Private Const m_GSF_PLAYER_HAS_BUST = &H4 Private Const m_GSF_DEALER_HAS_BUST = &H8 Private Const m_GSF_PLAYER_HAS_HIGHER_SCORE = &H10 Private Const m_GSF_DEALER_HAS_HIGHER_SCORE = &H20 Private Const m_GSF_PLAYER_HAS_STUCK = &H40 Private Const m_GSF_IS_DEALER_TURN = &H100 

You should note two points here. First, even though you can declare only Variant variables, it is still good practice to use scope and type prefixes. Because each variable can potentially store any value, you need to be sure that everyone knows what type of value is expected. For example, the variable UserName obviously contains a string, but a variable named ItemId could easily represent a string or numeric value. Second, you'll see that I've used hexadecimal notation to assign the bit flag constants. Bit manipulation often requires mask and other values to extrapolate the individual values within the flag variable. Using hexadecimal notation makes it much easier for others to understand the operations that are being performed, because the conversion from hexadecimal to binary is much easier than from decimal to binary.

Let's look for a moment at the variable m_nGameStatusFlags that I use in the Pontoon game to keep track of the game's progress. The variable is a Long Integer (32 bits) and stores nine separate values, which together provide a complete picture of the game's current status. Figure 5-11 shows how these values are stored.

Figure 5-11 Pontoon game bit flag values

Another technique you can use to reduce memory size is to pass all parameters by reference (ByRef). Doing this means that a pointer to the variable is passed and the procedure does not need to make a local copy of the variable within the procedure it is being passed to. In other versions of Visual Basic, passing by reference would not be good practice because of the potential of inadvertently changing a parameter's value, affecting code outside of a procedure. Many of the Pontoon game's functions are designed to process data that is held in module-scoped variables. However, it is still a good idea to pass the module-level variable into procedures, because this improves reuse as the procedure does not get tied to the module or form where the variable is declared.

A common problem when trying to optimize code is that complex algorithms are often created, which can be very difficult to understand. It is a good idea to encapsulate complex functionality within distinct functions so that if maintenance is required, the functionality is not shrouded by unnecessary code. An example of this encapsulation is the function below that shuffles the deck of cards in our Pontoon game.

 Private Sub ShufflePack(btaDeck, btaHand1, btaHand2, nGameStatus) '''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''' ' Shuffle the pack. We acheive this by marking each byte in the card ' ' deck array as being available (False). Obviously we cannot unmark  ' ' any card that is currently held by the player or dealer.           ' ''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''     Dim bteCard         ' Value of card being processed.     Dim nCard           ' Counter for iterating our card values.     Dim nSuit           ' Counter for iterating suit values.     ' Mark each card in our array as False, meaning available.     For nCard = LBound(btaDeck, 1) To UBound(btaDeck, 1)         For nSuit = LBound(btaDeck, 2) To UBound(btaDeck, 2)             btaDeck(nCard, nSuit) = False         Next     Next     ' Loop through the player's cards. Each of the player's cards      ' must be made unavailable in the deck by marking it True.     If IsEmpty(btaHand1) = False Then         For Each bteCard In btaHand1             ' Calculate the array index for the card and set              ' its element to True, indicating the card is in              ' use. Bit 9 of the card array is the suit and bit              ' 1-8 is the card's value.             btaDeck(bteCard And &HF, (bteCard And &H70) \ &H10) = True         Next     End If     ' Do the same for the dealer's cards.     If IsEmpty(btaHand2) = False Then         For Each bteCard In btaHand2             btaDeck(bteCard And &HF, (bteCard And &H70) \ &H10) = True         Next     End If     nGameStatus = (nGameStatus And &HFF) End Sub 

Looking at the code above you can clearly see all the actions for shuffling the deck. Such a procedure might be called only from one location in your program, but placing the shuffling code in its own procedure will help clarify both its logic and that of the procedure that calls it. Using magic numbers instead of constants in code has always been bad practice; however, we have to consider any memory constraint criteria. In this case, maintainability has been compromised in favor of size. If you choose to make this kind of compromise, try to keep the code simple. Whenever you develop complex logic, always ensure that there are plenty of comments, because code that might be easy to understand a day after you've written it has a habit of becoming quite complex three months later.

Often your application will need to use external files and resources such as Registry entries. Do not forget to consider the size of these elements when you start designing. You will need to think carefully about what you write to storage because this eats into the overall memory of the HPC. The Pontoon game does not use any Registry entries, but it does store the card graphics in bitmap files. We have 52 cards in our deck; each one has a corresponding bitmap file of 2022 bytes. Therefore, the overall storage space required is 105,144 bytes, or 103 KB. Our program file is 24 KB and we are using the PictureBox control, which is 59 KB. We can therefore calculate that the application will require a total of 183 KB. Because the HPC device has the Visual Basic CE run-time files in ROM, we do not need to include these components in our calculation. It would be too difficult to attempt to calculate the absolute total memory requirement because of the other influences, but so long as your program is small enough to run in the available memory and you have allowed for program terminations caused by insufficient memory, you should not have any problems.

An important point to be aware of is that on the desktop operating system each card would actually take up more space than its physical size; my PC, for example, will store each card in a space 32 KB in size. This size is called an allocation unit. Essentially, when writing files to disk, the operating system always write the data in blocks of a predetermined size (32 KB in my case). If I create a file less than or equal to 32 KB, the amount of disk space allocated for the file will actually be 32 KB. If the file's size is 33 KB, it will occupy two allocation units, or 64 KB. The allocation unit size on the PC is dependent upon the size of the hard disk partition and is configurable, but it can still be quite wasteful. Windows CE does not use allocation units, so my cards will occupy only the space equivalent to the file's actual size.

Programming for Windows CE

The Windows CE Toolkit for Visual Basic 5 is based on a subset of the Visual Basic, Scripting Edition programming language, so many Visual Basic language features available in other versions are not applicable or available when writing Windows CE programs. The Windows CE toolkit uses Visual Basic's code editor and syntax checker, and for this reason you will find that many of the errors caused by using features not available to the Windows CE environment will not be reported by the syntax checker. These errors are reported only at run time. Moreover, these run-time errors do not give specific information—they simply report that an error has occurred. When you run a Windows CE application in the development environment, the Visual Basic interpreter is not used—instead a debug version of your program is created and loaded either in the emulator environment or on the HPC device. Certain errors can be detected only after your application is executed. Once your program has started it has no further interaction with Visual Basic; instead, the Windows CE debugging window interacts with your program. Figure 5-12 illustrates how Visual Basic and the Windows CE toolkit components interact when you run a program. I will explain the emulator and the debugger in more detail later in this chapter.

In a Visual Basic Windows CE program you can create as many forms as you like, but you might have only one standard module. You cannot use class modules or any other type of module, such as User Documents or Property Pages, so you will not be able to create ActiveX components. You can, however, have related documents attached to your project. You need to be careful when using the properties and methods of standard Visual Basic objects, because many of the properties and methods either are not supported or have changed. The Knowledge Base contains articles providing a full list of what has changed or the excluded functionality, so I will not repeat them all here.

Figure 5-12 The Visual Basic debugging environment for Windows CE

What's new or changed in the language?

In addition to changes in the development environment, some new features and changes elsewhere have been added. The Books Online reference provides full documentation of the language, so I won't provide a comprehensive listing here. The following is a description of some elements that are either new or that work differently. Some elements are not new but might have missed your attention in previous versions, and they might now have a more prominent role in your designs.

One of the more common programming elements is the array. A big change here is that the lower bound of an array is always 0—this cannot be changed. A new set of functions has been included, which will make manipulation of arrays an easier task. The Array function was introduced in Visual Basic 5, but it might have gone unnoticed. Arrays will probably player a bigger role in your Windows CE code, so I'll describe the Array function.

Array function

The Array function takes a list of comma-separated arguments and returns an array containing the list of supplied arguments. The syntax of the Array function is variable = Array(arg1 [,arg2…]). The following code shows how you might use the Array function.

 Dim ProductType Dim Item      ProductType = Array("1 - Grocery", 1, "2 - Tobacco", 2, "3 -    Alcohol", 3)     For Each Item In ProductType     If IsNumeric(Item) = False Then         List1.AddItem Item     Else         List1.ItemData(List1.NewIndex) = Item     End If Next 

In the example above, the variable ProductType is initially declared as a Variant. Assigning the result from the Array function causes a coercion to type Variant array. The bounds of the array are 0 to 5 because Windows CE supports only 0 as the lower bound of an array. The same result could be achieved using the more conventional coding technique of declaring the variable as an array and then assigning a value to each element, but the Array function is more efficient for small arrays.

The arguments of the Array function need not be hard-coded "constant" type values, as in our example above. Because the array created is a Variant array, you can use variables or even other arrays as arguments. The example below illustrates this.

 Dim FirstArray Dim SecondArray Dim ThirdVariable FirstArray = Array("A Value", "Another Value") SecondArray = Array(FirstArray, "A Third Value") ThirdVariable = SecondArray(0) Print ThirdVariable(0)         ' Prints "A Value" Print ThirdVariable(1)         ' Prints "Another Value" Print SecondArray(1)           ' Prints "A Third Value" 

When assigning arrays as elements of an array, remember that because the element is, in fact, an array, any variable you assign that element to will also be coerced to an array type. You can assign SecondArray(0) to another variable that would then, in fact, contain FirstArray, or you could interrogate the array in situ:

 Print SecondArray(0)(0)        ' Prints "A Value" Print SecondArray(0)(1)        ' Prints "Another Value" 

For Each statement

The For Each programming construct should be familiar to nearly all programmers. With the increased support functions for array handling, you should be aware that the For Each construct can be used for arrays in addition to objects. (This has been available since Visual Basic 5.)

 Dim ItemPrice Dim Goods Goods = Array(10, 12.54, 9.85) For Each ItemPrice In Goods     ItemPrice = ItemPrice + CalculateTaxOn(ItemPrice) Next 

In the example above, as the loop iterates, ItemPrice evaluates to the actual data in the array Goods for each element in turn.

CreateObject function

The CreateObject function is not new; in fact, it has been around for some time, but most Visual Basic programmers probably use the more familiar syntax Set X = New Object. The Windows CE Toolkit for Visual Basic 5 does not allow the declaration of API calls—the Declare keyword is no longer valid, nor is the New keyword. Therefore, it is now necessary to use the CreateObject function to instantiate instances of ActiveX (COM) objects.

If you have created objects in Visual Basic before, you might have noticed that the object reference held in HKEY_CLASSES_ROOT of the Registry identifies your object by ServerName.ClassName. Therefore, if you create an ActiveX component (say, CUSTOMER.DLL) with public classes of Account and History, the entry in HKEY_CLASSES_ROOT would contain the entries shown in Figure 513.

Figure 5-13 Objects are identified by ServerName.ClassName

Although you cannot build objects for Windows CE using Visual Basic, you can still use objects created in another language like Visual C++ 5 with the Windows CE Toolkit. This can be particularly useful because you have the ability to create C++ objects that wrap API functionality.

The syntax of the CreateObject function is CreateObject(ServerName.ClassName). The following code shows how you would normally use this function to create a COM object instance.

 Dim WinCeDB WinCeDB = CreateObject("WinCeAPI.DataBaseFunctions") WinCeDB.OpenDatabase Id, "My Database", 0, 0, vbNull 

Some Microsoft applications like Word and Excel expose objects that you can use. I would strongly recommend using these and other Microsoft objects where possible. I would also expect a plethora of third-party objects to hit the market shortly, though you should apply your usual testing methods before using any of these.

For Next statement

A minor change has been made to the For Next construct. In Windows CE development you are not allowed to specify the counter variable on the Next line. The code

 For Counter = 1 to 100     .     .     . Next Counter 

is invalid and will produce an error. The code would have to be written as

 For Counter = 1 to 100     .     .     . Next 

in order to work.

String functions

Visual Basic string functions can no longer be used with the type suffix. Because the language supports only Variant data types, you will need to use the Variant functions instead, such as Mid instead of Mid$.

File handling

File handling is an intrinsic part of many applications. However, the file handling routines you are probably used to are not included in the language. Instead, a new ActiveX control is provided that wraps all the file functionality. The FileSystem component adds two controls to the toolbox: the FileSystem control and the File control. To use these you need to place them on a form.

The FileSystem control This control provides the means to manipulate the file system, such as creating and deleting files, searching, copying, and getting or setting file attributes. The following code snippet shows how you would use a FileSystem control (fs) to fill a list box with file names.

 Do     If sFile = "" Then sFile = fs.Dir(sPath & "*.*") Else sFile = fs.Dir     If sFile = "" Then Exit Do     List1.AddItem sPath & sFile Loop 

The File control Whereas the FileSystem control provides the functionality to manipulate the file system, the File control allows you to create, read, and write file data. This example writes data to a random access file.

 Dim vData Const REC_LEN = 20 Const ModeInput = 1:  Const LockShared = 1:   Const AccessRead = 1 Const ModeOutput = 2: Const LockRead = 2:     Const AccessWrite = 2 Const ModeRandom = 4: Const LockWrite = 3:    Const AccessReadWrite = 3 Const ModeAppend = 8: Const LockReadWrite = 5 Const ModeBinary = 32 vData = Array("Chris", "John", "Julie") fl.Open "My File", ModeRandom, AccessReadWrite, LockShared, REC_LEN fl.Put vData(0), 1    ' Write record 1 fl.Put vData(1), 2    ' Write record 2 fl.Put vData(2), 3    ' Write record 3 fl.Close 

Language objects

The Windows CE Toolkit for Visual Basic 5 language has seven objects. These are:

  • App

  • Clipboard

  • Err

  • Finance

  • Font

  • Form

  • Screen

Of these objects, the Finance object is new. The other objects are Windows CE implementations with reduced functionality from other Visual Basic versions. The Finance object, as you might expect, provides financial functions, but you must create this object yourself in order to use it, as you can see below:

 Dim oFinance Set oFinance = CreateObject("pVBFinFunc.pVBFinFunc") Text1.Text = oFinance.Pmt(0.0083, 48, 12000) 

I would recommend that you study the Books Online carefully to determine exactly the functionality of these objects.

Dealing with Errors

In terms of error handling you have two choices: don't, or use On Error Resume Next. You cannot use line numbers or labels in your code, so On Error GoTo would not work anyway. If you've been reading the various error handling articles produced by both Peet Morris and me, you are no doubt aware of the broad strategy of inserting generic catch-all error handling code throughout your application and then writing more specific handlers for anticipated errors. With the reduced error handling capabilities, a good scheme for Windows CE applications is to omit the generic handlers and just code for anticipated errors. This is because the Windows CE error handling mechanism has also been changed. If an unhandled error occurs, Visual Basic will display the default error message box; unlike other versions of Visual Basic, however, the program will not be terminated. Instead, the call stack is cleared and your application returns to an idle state (the state you were in before the last event was invoked). Beware! Your application is now in a stable state, not a known state. If you have written some data or manipulated some variables before the error occurred, it is possible that your application will actually be in an invalid state. The following pseudocode illustrates this:

 Private Sub PurchaseItem_Click()     aShoppingBasket = GetShoppingBasketList     aCustomerAcct = GetCustomerAccount     aShipList = GetShipList     For Each Item In aShoppingBasket         If aCustomerAcct(CustomerBalance) _ Item(Price) > 0 Then             AddToShipList Item(ItemCode), aCustomerAcct(CustomerNumber)            *** ERROR ****             DeductFromCustomer Item(ItemPrice), _                                aCustomerAcct(CustomerNumber)         End If     Next End Sub 

In this example the unhandled error causes the procedure to exit, and code after the error will not be executed. If the For Each loop had already performed some iterations before the error, you would effectively have a situation where some of the orders had been placed, but not all of them. The shopping basket data would still contain both processed and unprocessed orders, which means that if the procedure were invoked again for the same customer, you would have doubled some of the orders. You can prevent errors such as this by changing the design of your program. For example, in the code above, a better idea would be to remove the item from the shopping basket immediately after an individual order has been placed, and then write a specific error handler around the transaction.

The default error message box displayed by Windows CE is shown in Figure 5-14. The error message varies depending on where the error has occurred; in this example, the error has occurred after the application's form has loaded. Errors in the Form_Load event procedure are a little harder to trap. This is because the Form_Load event procedure executes before the debugger is loaded. You cannot, therefore, set a breakpoint to trap the error. Remember that Visual Basic debugging is not integrated with the Windows CE environment, so the Break options have no effect. An error that occurs while running your application does not cause the program to break into debug mode. The only way to trap an error is to set a breakpoint in the debugger and then step through the code until the error is reached.

Figure 5-14 An unhandled error message from Visual Basic for Windows CE

The Pontoon application does not contain any error handlers. At design time and during coding, I evaluated the possibility of an error occurring. In this application there are no places where I can anticipate an error, so it would be a waste to code error handlers everywhere just in case. Remember that using On Error Resume Next requires lots of code to implement correctly because you need to check for an error after every line where an error could possibly occur. Another disadvantage is that because you cannot have line labels, you will effectively end up having deeply-nested conditionals. When determining your error handling requirements, it is obviously important to consider how critical the application is. If the Pontoon game has an error, the consequences are not severe. The Err object is available for diagnosing errors, although the Erl property is not present for obvious reasons.

If these limitations seem a little restrictive, I'll remind you again of the types of applications you will be creating at this stage. As Microsoft's goal to allow development for any platform in Visual Basic gets closer to reality and the hardware's capacity grows, I expect the error handling capabilities will grow to comparable levels with that of other versions of Visual Basic (or maybe even C++!).

The Windows CE Desktop Emulator

The Windows CE Desktop Emulator is a program supplied with the Windows CE Platform Software Development Kit (and also supplied with the Windows CE toolkit). The emulator is a program that runs the Windows CE operating system on your desktop. You can start the emulator by running the program manually, or it is started automatically when you run a Windows CE application from Visual Basic after having selected the target device as Emulator. You can write, test, and run your applications wholly within the emulator without having a physical HPC device at all. The Start menu of the emulator is really a dummy menu—you cannot use it to access any of the programs loaded in the emulator. To browse and copy files within the emulator's environment, you need to run the My Handheld PC program from the desktop. Even from here not all the programs will run in the emulator, though your Visual Basic programs will. The emulator's file system is stored in the object store (essentially an OBS file), meaning that you cannot copy or move files between your PC and the emulator using standard methods like drag-and-drop. To do this you need to use the program EMPFILE.EXE, which you can find in the \wce\emul\hpc\Windows folder in the Windows CE Platform SDK folder. The location of the Windows CE Platform SDK folder obviously depends on your installation options. The following listing shows the Help information that the program displays when run from an MS-DOS window:

 C:\Program Files\Windows CE Platform SDK\wce\emul\hpc\windows>empfile USAGE:  EMPFILE [options]... options:  -c SOURCE DEST  ('put' or 'get' a file from object store)  -d FILE         (delete a file on object store)  -e FILE         (check to see if a file exists on object store)  -s              (synchronize object store with wce\emul\PLATFORM\ tree)  -r MYAPP ARGS   (run myapp.exe in the object store with arguments ARGS) examples:    EMPFILE -s            (Synchronize wce\emul\PLATFORM\ tree with object store)    EMPFILE -c c:\test.exe wce:windows\test.exe            (Copy c:\test.exe to object store's Windows\ directory)    EMPFILE -c wce:test.exe c:\test.exe            (Copy test.exe from object store to c:\)    EMPFILE -e windows\text.exe            (verify that test.exe Exists in object store's             Windows\ directory)    EMPFILE -d test.txt            (Delete test.txt from object store root directory)    EMPFILE -r test.exe -10            (Run test.exe from object store with parameter "-10") 

You can use EMPFILE to copy files to and from the emulator and also to synchronize databases between the emulator and your PC. If you write any programs that require external files (such as bitmaps), you need to use EMPFILE to copy those files to the emulator so that these files are available when you run your program under the emulator.

Testing and Debugging Your Application

The limitations of the current version of the Windows CE toolkit mean that you will have to thoroughly test and debug your code, even more so than you do now. The debugger allows you to debug applications running either in the emulator or on the HPC. Before running your application at design time, you will first need to download the run-time files. This option is available under the Windows CE menu. This process downloads the Visual Basic run-time library files to the emulator environment and to the HPC. Once completed, you will need to be sure that you download the controls required by your application by selecting Control Manager from the Windows CE menu. Figure 5-15 shows the Control Manager screen.

Figure 5-15 Windows CE Control Manager

You need to download only the controls you are using in your project, but they must be downloaded to either the emulator or to the HPC depending on the target you have selected. Select the controls to download and use the Emulation or Device menus to install or uninstall the controls. Once you have completed these steps you can run your program in the normal way—using F5 or the Run command.

Running a Windows CE application in the development environment is a little slower than normal, because the program is downloaded and run within the selected environment. The debugger application interfaces with that environment. The debug facility offers a reduced set of functionality compared to other versions of Visual Basic. Once in the debugger you can set breakpoints, but you cannot change any code. The debugger supports the same debug actions as in other versions. Figure 5-16 shows the debug window.

The biggest difference between this debug window and that which you will become accustomed to is that you cannot change code within it. To change your code you will need to stop the application, close the debugger, amend your code, and then rerun it. Unfortunately, if you keep the debug window open after stopping the application, you need to set your breakpoints again when you restart another instance of the debugger—there's no way around it!

Figure 5-16 The debug window

Run-time errors in the development environment are dealt with differently than what you might be used to. Misspelled variable or function names and parameter constants are not all detected until the procedure is entered. One tip for avoiding these errors is to always type these elements in lowercase. If valid, the capitalization will be changed to that of the declaration; if not, the case will remain unchanged. This will give you a good indication that a variable name is correct.

Sometimes you might find the debug window a distraction. If this happens, you can prevent the debug window from being displayed by deselecting the Build Debug option on the Make tab of the Project Properties dialog box.

Deploying Your Application

You can get your application onto the HPC device in one of two ways, both of which are equally as easy. For one-off installation you can simply copy the application and its data files to the HPC using the Mobile Devices folder. The Mobile Devices folder works in the same way as Windows Explorer, and you can drag-and-drop files as well as create folders and shortcuts. You can also access your HPC device directly through Windows Explorer. Before copying your application you will need to compile it using the Make option, just as with a regular Visual Basic application. There are no optimization options because the compiled program is rather like a P-Code executable. The compiled application has a PVB file extension. If you are using any custom controls, you will need to install these onto the device using the Control Manager, and you will need to register ActiveX components using the REGSVRCE.EXE program (the Windows CE equivalent of REGSVR32.EXE).

For a more formal installation, you will need to use the Application Install Wizard (available from the Windows CE menu), which works in a similar way to the Setup Wizard in other versions of Visual Basic. Installation programs for Windows CE applications follow the same format. When installing from a setup program, the setup checks the status of your device and then prompts you to select the components you want to install. The application's setup files are extracted to a temporary storage area on the HPC. At this point, the PC's work is all but done and you are prompted to check your device for further messages. As soon as the PC has finished the copy process, the HPC starts installing the files. This is normally a fairly quick process; your application is then ready to run.

Extending Visual Basic Using COM DLLs

The Windows CE toolkit does not allow you to declare API functions, but you can use the CreateObject function to create instances of ActiveX components. Therefore, if you want to use any of the Windows CE API functions, you will need to create an ActiveX object that wraps the functionality required. Before embarking on this task, I would advise that you check the necessity for the particular API functions you want to use. Remember that the operating system itself contains only a subset of the Win32 API. Whereas the Win32 API has some 15,000 functions, the Windows CE API has only around 1200—the function you require might not even exist. I can recommend the book Microsoft Windows CE Programmer's Guide (Microsoft Press) as an excellent reference. This book gives complete documentation of the Windows CE API and covers topics such as communications and file and Registry access.

There are two "legitimate" areas of functionality for which you might decide to write ActiveX components. The first is the ActiveSync functionality. The Windows CE databases can be synchronized with a PC using ActiveSync. When your HPC performs its synchronization, what it is actually synchronizing are the databases on your device. The HPC is shipped with the Contacts, Calendar, Inbox, and other databases. In addition, you can create your own databases using the HPC Database application that comes with most HPC devices. The HPC Database application is normally found in the Databases icon on the desktop. You can configure ActiveSync to maintain synchronized copies of any or all these databases. Using the API you can achieve this functionality in code, which is useful if you write applications incorporating the Windows CE database functionality.

The database API functions are another area for which you might want to write wrappers. The API gives you the ability to create, open, enumerate, read, write, and delete the Windows CE database files.

To create an ActiveX wrapper you will need Visual C++ 5 and the Windows CE Toolkit for Visual C++ 5. Using this combination you can create a DLL that implements an Active Template Library (ATL) COM object, and then create instances of that object in your Visual Basic program by using the CreateObject function.



Ltd Mandelbrot Set International Advanced Microsoft Visual Basics 6. 0
Advanced Microsoft Visual Basic (Mps)
ISBN: 1572318937
EAN: 2147483647
Year: 1997
Pages: 168

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net