INTERMEDIATE  Ask the VB Pro


Load Arrays With Values Quickly

by Karl E. Peterson

  Q. Load Arrays at Startup
Is there a convenient way, besides using the Array function, to initialize an array with values? I have a 512-element array of Longs, whose values are constant. I've been trying to use the Array function, but with so many elements, I keep getting general protection faults in the IDE at design time, as soon as I try to close the function with ")".

About This Column
Ask the VB Pro provides you with free advice on programming obstacles, techniques, and ideas. Read more answers from our crack VB pros on the Web at www.inquiry.com/
techtips/thevbpro/
. You can submit your questions, tips, or ideas on the site, or access a comprehensive database of previously answered questions.
I haven't faced this problem in the past because the array data had a generating function that let me generate the array at run time. But this time the data can't be generated with a simple function. I would prefer not to assign the individual values one at a time. Does VB have something like a Const Array?

A. In the old days, Basic programmers used the Data statement to load values like these. That feature, unfortunately, didn't survive the migration from DOS to Windows. Microsoft added support for resource (RES) files with VB4, and that's the best alternative you have today.

VB6 shipped with a resource file editor add-in, and you can download a similar tool for VB5 from the Visual Studio Owner's Area on Microsoft's Web site (see Links). This tool allows you to include an entire file within a RES file, giving it whatever custom type name you choose. To use my suggestion, you first need to get your array data into a binary file. Use this simple format: one value immediately following the previous, and no header at all (see Listing 1). You might want to write a quick utility app that creates these data files to facilitate easy updating.

After stashing your data to a binary file, load your main project and open the Resource Editor add-in. Select New Resource File from the toolbar if your project doesn't already include one. Then click on Add Custom Resource to bring up a dialog in which you can select your binary file. Next, highlight the addition and select Properties. Assign a custom Type identifier and ID to the new resource. In my example, I used "LongData" as the Type.

Now here's how to assign an entire array quickly: Pass a dynamic byte array to LoadResData to read the entire resource. Size your array of Longs to match the number of bytes—divided by four, given the size of a Long—retrieved from the RES file. Then call CopyMemory to sling the byte array directly into the Long array (see Listing 2).

Yes, it is a bit of work to set up, but the performance in your final EXE can't be beat. 

Q. Add First/Last Properties to Data Classes
I've wrapped up database access within a series of classes to isolate the user interface (UI) from the data access layer, as is often recommended in VBPJ. I designed my UI like the data control, allowing the user to move to the first, previous, next, or last record by pressing a button. I'd like to enable and disable these buttons appropriately, based on the current record. How can my class indicate to the UI whether the current record is first or last in the recordset?

A. When I saw this question posted online, I was surprised by the number of suggestions that pointed to the BOF and EOF properties of the wrapped recordset. There seems to be a good deal of confusion over exactly what those properties indicate. If BOF is True, the current position is before the first record. Similarly, when EOF is True, the current position is after the last record. Clearly, this is not the answer your UI is looking for.

One method that works is to store a unique identifying value for the first and last records each time your class refreshes the recordset. Then, when the current record changes, compare the identifying value of the new record with these stored values. Internal flags, based on this comparison, provide the values returned by the class's First and Last properties (see Listing 3).

In the example I provide here, two fields are combined to create a Long value that uniquely identifies any given record. Many tables already contain a single field, generally the primary key, which serves as a unique ID. You could also store bookmarks for the first and last records, and use those in the UpdateFirstLast routine's comparisons. I avoided the bookmark approach because it restricts this technique to Jet-based recordsets. I also generally prefer numbers to strings when given the option.

In your UI, each time the NewRecordset or Reposition event fires, check the data class's First and Last properties and enable or disable your navigation buttons to match.

Q. Attach Subform to Main Form
I need to float a subform on top of my main form so that the subform—only while visible—stays in a certain position over the main form. Right now I'm using native VB positioning properties (Left and Top) and passing Me as the OwnerForm when showing the subform. The subform then minimizes and maximizes with my main form, but is only properly located when first loaded. Is it possible to make my subform move with my main form in case the user drags the main form somewhere?

A. It's a real shame VB has never exposed a Form_Move event, because this would be the ideal place to code your solution. Instead, you need to subclass your main form and respond to the messages Windows sends whenever the form is moved or resized.

I worked up a quick sample that uses the freeware MsgHook control to catch WM_MOVE, WM_MOVING, WM_SIZE, and WM_SIZING. When one of these messages is received, simply move the subform to its new position (see Listing 4).

Q. Make Two Forms Active
I've prepared various tool windows for an MDI application I'm working on. These float above the main form, minimizing and restoring in sync. How can I make both the main form and the current tool window active simultaneously?

A. It's not technically possible for two or more windows to have focus at any given time. However, you can make it appear that both forms are active with a simple trick. In the tool window's Form_Activate event, send a WM_NCACTIVATE message to the main form (see Listing 5).

The only catch is ensuring the tool window form knows your main form's hWnd. Add an hWndParent property to the tool window form, and set it upon instantiation:

' Create and load a form-level reference to the tool form.
Set Tools = New frmToolWindow
Load Tools
Tools.hWndParent = Me.hWnd
Tools.Show , Me

When the user clicks on your tool window, the window naturally assumes the system's active colors, and the WM_NCACTIVATE message fakes the main form into repainting its titlebar with active colors too.


Karl E. Peterson is a GIS analyst with a regional transportation planning agency and serves as a member of the Visual Basic Programmer's Journal Technical Review and Editorial Advisory Boards. Online, he's a Microsoft MVP and a section leader on several VBPJ forums. Find more of Karl's VB samples at www.mvps.org/vb.

 
Links
• If you have VB5, download a tool similar to the VB6 resource file editor from the Visual Studio Owner's Area on Microsoft's Web site.
Original Code
  Get the code for this article here.
Updated Code
  FormPair