Extend the Scrollbar's Range
I can't believe VB's native scrollbar controls still offer only an Integer range for their Value property. It's often more convenient for me to have this control scale into the Long range instead. How can I work around this problem?
You said the magic word: scale. I once wrote a class for Visual Basic 4.0 How-To (Waite Group Press) that scaled a native scrollbar's Value property into the Long range. In the VB4 days, this took much more work than today, thanks to VB5's addition of WithEvents. Previously, the client needed to notify the class whenever the user altered a scrollbar's Value. Now the complete solution is drop-in�ready, and requires only a few lines of setup code to initialize.
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
techtips/thevbpro. You can submit your questions, tips, or ideas on the site, or access a comprehensive database of previously answered questions.
CLongScroll offers a Client property, which accepts either a vertical or a horizontal scrollbar for the class to manage. The Client property is interesting because you can pass two different object types to it. This requires two typed object references, each capable of sinking events, and a third generic object reference that you use to access the shared native properties of either specific type (see Listing 1). Other properties of the class mirror those offered by scrollbars: Value, Min, Max, SmallChange, and LargeChange (see Listing A).
The class must track the virtual values for all the standard properties. These, together with cached copies of the actual values, allow easy calculations to determine what new Value should be exposed as the user adjusts a Client scrollbar. Differentiating between a LargeChange and a SmallChange action can be tricky, but it's the only way you can alter the Value appropriately if the user initiates either. My solution: Assign a known value to these properties and compare it to the difference between a new Value and a previous Value.
You manage the virtual value mapping in the ClientChange routine, which is called when either the Change or Scroll events fire. After the required calculations, you assign a new Value to the client. To prevent unwanted recursion, set and check a private flag before this assignment to ensure ClientChange isn't entered endlessly. Clear the flag after assignment (see Listing 2).
To use the CLongScroll class, declare an instance of it in your form, using WithEvents to specify the class as an event sink. During the Form_Load event, assign a native scrollbar to the class's Client property:
' Variable to use for virtual scrollbar
Private WithEvents hsb As CLongScroll
Private Sub Form_Load()
' Create new instance of virtual
' scrollbar, and assign HScroll1.
Set hsb = New CLongScroll
Set hsb.Client = HScroll1
' Set default values for this demo.
.Min = 0
.Max = 10000000 '10 Million!!!
.SmallChange = 1
.LargeChange = 25000
.Value = 0
From there, use the class's Change event as you would that of the native scrollbar.
Q Recover Lost Passwords
Is it just me, or are passwords proliferating with each passing day? I sometimes forget a password, and it grates on me to see it hidden behind those silly asterisks in an unforgiving dialog. Can you tell me how to retrieve the hidden contents of these password fields?
A You've hit on what some might consider a fundamental security flaw in Windows. Applications can provide a password character in place of what's actually typed into standard edit controls (the Textbox in VB). Many developers don't know that this "protection" is no better than the lock on the user's office door. If the PC is accessible, any dialog that prompts with this field already filled in is vulnerable to easy attack.
The plan of attack in this case is simple. I wrote a routine that calls EnumWindows to enumerate all top-level windows. For each returned window, EnumChildWin-dows is called and drills down through that window's children. A quick call to GetWindowLong tells you if the child window has the ES_PASSWORD style. If so, the EM_GETPASSWORDCHAR message reveals whether a password character is assigned. Windows that meet all these criteria show "hidden" text, and are the target of the attack. Believe it or not, sending a WM_GETTEXT message is all it takes to retrieve the actual password (see Listing B).
Call the SniffPasswords routine after bringing up the dialog that contains the password you've forgotten. The string parameter to this function returns the Caption of any top-level windows that meet the criteria, as well as the passwords they contain.
I'm sure I'll take a little heat for publishing this, but let me tell you the value I see in sharing it. As a developer, you need to be aware that these attacks exist. Knowing that, you might choose not to prefill password fields with stored values, or at the least to offer this feature as an option in your application. Users, too, need to be aware of just how vulnerable such passwords are, and to understand that a computer that isn't behind locked doors is simply not secure from snoops. I should also say up front that some of NT's system password dialogs are not affected by this hack; it's primarily useful against application programs, such as Outlook Express.
Q Demonstrate NT's Low System Resources
I've read that system resource issues stem from the small system heaps (blocks of memory) that remain from Windows 3.x to Windows 9x. The authors of such statements nearly always point out that Windows NT doesn't suffer these ludicrous limitations. I have an NT user complaining of symptoms that sound suspiciously like those all too common in 9xgarbled displays, a nonreactive interface, and so on. Is NT also subject to this resource ailment?
A When compared to the 9x platforms, NT is far more robust. Even so, just about everything has limits. NT sets aside space to store &H4000 Graphical Device Interface (GDI) handles. Once NT allocates these, no GUI process can interact with the user. By default, NT limits a single process to a maximum of &H3000 GDI handles, although you can configure this number through the Registry. In theory, this means it would take two or more runaway resource hogs to bring NT to its knees.
To avoid hitting this wall, just do what momma taught you: "Clean up your own mess!" Tools exist to help you pinpoint resource leaks, but in the end, you have to remain vigilant. If you create any sort of GDI object, you must destroy it when you're through with it. I've written a short demo showing how easy it is to render NT inoperable (see Listing 3). The demo allocates GDI pens until CreatePen fails.
To try the demo, start a new project, add two command buttons to the default form, and paste in the sample code. Compile and save your work. Start two instances of the sample and press the first command button on one. At this point, 75 percent of the total GDI heap is consumed. If you now press the first command button on the second instance, the screen will be garbled beyond recognition, and Task Manager won't work. Most users will have to hit the Reset button. If the two runaway processes were the last touched, users can also back out by hitting Alt-F4 twice.
Windows 2000 is still in beta at this writing, but it looks like this limitation will persist through that product's life cycle. I'd like to tell you when you might hit this particular wall, but unfortunately Microsoft doesn't consider it an issue, so it hasn't given developers that information. If you feel otherwise, let them know.
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.