DOCUMENT:Q141085 16-JAN-2001 [mspress] TITLE :HARDCORE VISUAL BASIC: Corrections and Comments PRODUCT :Microsoft Press PROD/VER:: OPER/SYS: KEYWORDS:kbdocfix kbdocerr ====================================================================== ------------------------------------------------------------------------------- The information in this article applies to: - MSPRESS Hardcore Visual Basic ISBN 1-55615-667-7 ------------------------------------------------------------------------------- SUMMARY ======= This article contains comments, corrections, and information about known errors relating to the Microsoft Press book Hardcore Visual Basic, ISBN 1-55615-667-7. These errors have been corrected in the second edition of the book. For information about known errors and corrections in the second edition of "Hardcore Visual Basic", please see the following article in the Microsoft Knowledge Base: Q173840 Hardcore Visual Basic 2nd Ed. Comments and Corrections The following topics are covered: - CD-ROM: Various installation issues - WIN32.TLB: Type library errors cause sample function to fail - Page 4: DoCommon should be DoUncommon - Page 87: VBUTIL16.DLL doesn't have type library - Pages 89-119: Miscellaneous minor corrections - Page 128: Performance bug in sorting algorithm - Page 246, 249: Corrections to Callback server information - Page 246, 464: Book title reference updated - Page 302: Bad description of events on a hidden pictureBox - Page 424, 425: You can remove item from collection by key - Page 545: Wrong interface for Quick View - Page 577: ItemDblClick unnecessarily complicated Installation for the "Hardcore Visual Basic" CD-ROM can be confusing because there are three different setup files in the root directory of the CD-ROM: Setup.exe, Setup16.exe, and Setup32.exe. Setup.exe automatically detects and executes the proper setup program for the target computer. To properly install the files in Windows 95 or Windows NT: 1. Click the Start button, then click Run. 2. Type "d:\setup" (without the quotation marks) into the Run input box. Replace d: with the drive letter of your CD-ROM drive if necessary. To properly install the files in Windows 3.1: 1. In the Program Manager, click File, then click Run. 2. Type "d:\setup" (without the quotation marks) into the Run input box. Replace d: with the drive letter of your CD-ROM drive if necessary. NOTE: You must have Visual Basic 4.0 installed on your computer before attempting to install the files from the "Hardcore Visual Basic" CD-ROM. Otherwise errors will occur. WIN32.TLB: Type library errors cause sample function to fail ------------------------------------------------------------ Some of the constants in the 32-bit Windows type library (WIN32.TLB) are wrong. As a result, a function on page 240 (Chapter 5) of the book fails, usually with a very rude error. The function is LookupItem, which is supposed to find the index number of a ListBox entry. Function LookupItem(ctl As Control, sItem As String) As Long LookupItem = SendMessageAsStr(ctl.hWnd, LB_FINDSTRING, -1, sItem) End Function How could such a serious bug find its way in a one-line function? Easy. Just define the constant LB_FINDSTRING with the wrong value in the Windows type library. This function actually sends the LB_GETSELCOUNT message, which does weird things when you pass it real arguments instead of zeros. The easiest way to fix the problem is to simply add a local constant with the correct value to the function: #If Win32 Then Const LB_FINDSTRING = &H18F #EndIf Of course, this doesn't help with the rest of the LB_ constants, which are also off by one. Here are the correct values. As a temporary fix, paste these into the WINTOOL.BAS file and make sure you include it in any project that sends ListBox messages. The correct Basic constants will override the incorrect ones in the type library. ' Temporary fix overrides incorrect values in Windows type library #If Win32 Then Public Const LB_ADDSTRING = &H180 Public Const LB_INSERTSTRING = &H181 Public Const LB_DELETESTRING = &H182 Public Const LB_SELITEMRANGEEX = &H183 Public Const LB_RESETCONTENT = &H184 Public Const LB_SETSEL = &H185 Public Const LB_SETCURSEL = &H186 Public Const LB_GETSEL = &H187 Public Const LB_GETCURSEL = &H188 Public Const LB_GETTEXT = &H189 Public Const LB_GETTEXTLEN = &H18A Public Const LB_GETCOUNT = &H18B Public Const LB_SELECTSTRING = &H18C Public Const LB_DIR = &H18D Public Const LB_GETTOPINDEX = &H18E Public Const LB_FINDSTRING = &H18F Public Const LB_GETSELCOUNT = &H190 Public Const LB_GETSELITEMS = &H191 Public Const LB_SETTABSTOPS = &H192 Public Const LB_GETHORIZONTALEXTENT = &H193 Public Const LB_SETHORIZONTALEXTENT = &H194 Public Const LB_SETCOLUMNWIDTH = &H195 Public Const LB_ADDFILE = &H196 Public Const LB_SETTOPINDEX = &H197 Public Const LB_GETITEMRECT = &H198 Public Const LB_GETITEMDATA = &H199 Public Const LB_SETITEMDATA = &H19A Public Const LB_SELITEMRANGE = &H19B Public Const LB_SETANCHORINDEX = &H19C Public Const LB_GETANCHORINDEX = &H19D Public Const LB_SETCARETINDEX = &H19E Public Const LB_GETCARETINDEX = &H19F Public Const LB_SETITEMHEIGHT = &H1A0 Public Const LB_GETITEMHEIGHT = &H1A1 Public Const LB_FINDSTRINGEXACT = &H1A2 Public Const LB_SETLOCALE = &H1A5 Public Const LB_GETLOCALE = &H1A6 Public Const LB_SETCOUNT = &H1A7 Public Const LB_INITSTORAGE = &H1A8 Public Const LB_ITEMFROMPOINT = &H1A9 #End If An updated version of the Windows API type library with fixes for this and other problems is being created and will be described in a separate entry when it is finished. Page 4: DoCommon should be DoUncommon ------------------------------------- Page 4, second code block line 3 and third code block line 3: Change DoCommon to DoUncommon Page 87: VBUTIL16.DLL doesn't have type library ------------------------------------------------ The text of the book states that Vbutil16.dll has an embedded type library. Actually, Visual Basic has a bug that prevents it from recognizing type libraries for 16-bit DLLs. As a result, the Declare statements for the DLL functions are located in Utility.bas. This is noted in the Readme.txt file on the compact disc included with the book. Pages 89-119: Miscellaneous minor corrections ---------------------------------------------- Page 89, Second paragraph of Inside Declarations sidebar, third sentence. It states that Basic must save the return value for functions, but actually Basic saves the return value type. Sentence should read "Basic must also save the type of each argument, the return value type (for functions), and a pointer (empty at this point) for the address of the procedure. Page 93, Archaeologist's Note near the bottom of the page. The note states that: "REMLINE went on to become the most widely distributed program in the history of the planet." It should say that REMLINE is the most widely distributed source code program in the history of the planet. Page 103, last paragraph, second sentence. The 16-bit declarations for VBUTIL are in UTILITY.BAS, not VBUTIL16.TLB. Sentence should read: "The declarations are in UTILITY.BAS for 16-bit and in the VBUTIL32.TLB file for 32-bit." Page 119, first paragraph, second sentence. The text incorrectly refers to the ShiftRWord function rather than RShiftWord. Sentence should read: "If you ever need to divide by 256 in a very tight loop, you might want to try RShiftWord(i, 8) rather than i / 256." Page 128: Performance bug in sorting algorithm ----------------------------------------------- There is a serious performance bug in the QuickSort algorithm that has been used in many Microsoft language demos over the year and which found its way into Hardcore Visual Basic. The book uses variations of the algorithm to sort arrays, collections, and list boxes. The code works fine, but it runs about four times slower than necessary. The offending code is included at the end of this message, but the heart of the error is this: SortSwap aTarget(iLast), aTarget(iRand) vSplit = aTarget(iLast) #If Bozo Then Do ' Move in from both sides toward pivot element i = iFirst: j = iLast #Else ' Move in from both sides toward pivot element i = iFirst: j = iLast Do #End If ... ' And so on The problem is one of the oldest and dumbest of programming mistakes-- initializing variables inside a loop instead of outside. Thanks to reader David Wilmer for pointing this out. The only excuse for this bug is that the code wasn't originally written for the book. It comes from the old SortDemo program written many years ago for QuickBasic. It was such a cool demo that other Microsoft languages reused it. In a previous job, the author of this book personally translated the code to C and supervised others who translated it to Pascal and FORTRAN. It eventually even appeared in Cobol and in C++ with MFC. The orignal C version has the same stupid bug. The Pascal and FORTRAN versions are OK. The moral of the story is, don't trust anyone else's code. Here's full code with corrections. The small fix makes a surprisingly big performance difference. Try it both ways in the TimeIt program supplied with the book. Remember that this bug appears exactly the same in five different places on the CD. Check sorting arrays and collections in SORT.BAS, sorting arrays and collections polymorphically in SORTPOLY.BAS, and sorting list boxes in SLISTBOX.CLS. The code is quoted on page 129 and referenced but not shown on pages 427 and 452. ' QuickSort algorithm Sub SortArray(aTarget() As Variant, _ iFirst As Integer, iLast As Integer) Dim vSplit As Variant If iFirst < iLast Then ' Only two elements in this subdivision; exchange if ' they are out of order, and end recursive calls If iLast - iFirst = 1 Then ''@B CallSortCompare If SortCompare(aTarget(iFirst), aTarget(iLast)) > 0 Then SortSwap aTarget(iFirst), aTarget(iLast) End If ''@E CallSortCompare Else Dim i As Integer, j As Integer, iRand As Integer ' Pick pivot element at random and move to end ' (consider calling Randomize before sorting) iRand = GetRandom(iFirst, iLast) SortSwap aTarget(iLast), aTarget(iRand) vSplit = aTarget(iLast) #If Bozo Then Do ' Move in from both sides toward pivot element i = iFirst: j = iLast #Else ' Move in from both sides toward pivot element i = iFirst: j = iLast Do #End If Do While (i < j) And _ SortCompare(aTarget(i), vSplit) <= 0 i = i + 1 Loop Do While (j > i) And _ SortCompare(aTarget(j), vSplit) >= 0 j = j - 1 Loop ' If you haven't reached pivot element, it means ' that the two elements on either side are out of ' order, so swap them If i < j Then SortSwap aTarget(i), aTarget(j) End If Loop While i < j ' Move pivot element back to its proper place SortSwap aTarget(i), aTarget(iLast) ' Recursively call SortArray (pass smaller ' subdivision first to use less stack space) If (i - iFirst) < (iLast - i) Then SortArray aTarget(), iFirst, i - 1 SortArray aTarget(), i + 1, iLast Else SortArray aTarget(), i + 1, iLast SortArray aTarget(), iFirst, i - 1 End If End If End If End Sub Page 246, 249: Corrections to Callback server information ---------------------------------------------------------- Page 246, second bulleted item, should be replaced with the following text: " The break mode DLL (VBBRK16.DLL or VBBRK32.DLL) isn't likely to work with the next version of Visual Basic. This DLL uses undocumented techniques, but it only affects debugging under the IDE. If you have working code that uses the Callback server, it should continue to work if recompiled under future versions." (without the quotation marks) Page 249, comment in code near the top of page 249 should read: "Required to prevent painting problems in break mode." (without the quotation marks) The current text incorrectly says that the DebugProc property prevents crashes. Page 246, 464: Book title reference updated ------------------------------------------- Change "Microsoft Guide to Object Programming with Visual Basic 4 and Microsoft Office for Windows 95" To "Object Programming with Visual Basic 4" (without the quotation marks) Page 302: Bad description of events on a hidden pictureBox ----------------------------------------------------------- The section titled "CPictureGlass Events" on page 302 talks about why the internal PictureBox encapsulated by the CPictureGlass class moves around even though it is invisible. The book claims that by moving the PictureBox around, you could get the mouse events that the PictureBox receives. This claim wasn't tested. A reader who tried to take advantage of these events reported that they never occurred. This has been verified. If a PictureBox is invisible, it doesn't generate mouse events. The CPictureGlass class works in samples in the book, but it may be unnecessarily complicated and inefficient. This class will be redesigned for the next edition. Page 424,425: You can remove item from collection by key --------------------------------------------------------- The book claims that you can't remove an item from a collection by its key. This appears in the table on page 424, row 11, column 3. The operation as described in column 1 is Remove item "Pig". Column 3 claims that you can't do this, but should say: n.Remove "Pig". The error is repeated on page 425 in the bulleted list. The first sentence in the fourth bulleted item starts out "List boxes and collections require you...", but this statement actually only applies to List boxes. It should read "List boxes require you...". Page 545: Wrong interface for Quick View ----------------------------------------- Page 545, first paragraph under the heading Faking Quick View, fifth sentence. This paragraph is confusing because it starts talking about Quick View, but then uses shell extensions as an example of OLE interfaces. It should instead discuss the IFileViewer interface. The sentence should read: "Second, file viewers must implement OLE interfaces--IFileViewer and IPersistFile." Page 577: ItemDblClick unnecessarily complicated ------------------------------------------------- The description of a workaround for the lack of an ItemDblClick event on the ListView control is unnecessarily complicated. Page 577 notes that the ListView control doesn't have an ItemDblClick event. Any app that tries to emulate the Windows Explorer needs to identify items that were double clicked, but the DblClick event doesn't tell you the item. The book describes a complicated hack for getting around this limitation. Save the x and y coordinates as Private variables in the Mouse_Down event. In the DblClick event, use the coordinates with the HitTest method to identify which item was double-clicked. In fact, there is a much easier way to identify the item. Use the SelectedItem method: Private Sub lvwFiles_DblClick() Dim item As Object #Const fHard = 1 #If fHard Then Set item = lvwFiles.HitTest(xList, yList) ' x and y saved in Mouse_Down #Else Set item = lvwFiles.SelectedItem #End If If item Is Nothing Then Debug.Print "Double clicked column: ?" Else Debug.Print "Double clicked item: " & item.Text End If End Sub The code works as described in the book and as used in the Columbus application in the book, but code based on the technique shown above is simpler. Microsoft Press is committed to providing informative and accurate books. All comments and corrections listed above are ready for inclusion in future printings of this book. If you have a later printing of this book, it may already contain most or all of the above corrections. MORE INFORMATION ================ In addition to a description of the book's problems, this document might also include sections labeled "Correction" and "Comments." Please note that the "Correction" section is worded for correcting the book and does not necessarily address the problem introduced by the book error. The "Comments" section contains specific information for working around problems. CD-ROM: Various installation issues----------------------------------- Additional query words: ====================================================================== Keywords : kbdocfix kbdocerr Technology : kbMSPressSearch Version : : Issue type : kbinfo ============================================================================= THE INFORMATION PROVIDED IN THE MICROSOFT KNOWLEDGE BASE IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND. MICROSOFT DISCLAIMS ALL WARRANTIES, EITHER EXPRESS OR IMPLIED, INCLUDING THE WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL MICROSOFT CORPORATION OR ITS SUPPLIERS BE LIABLE FOR ANY DAMAGES WHATSOEVER INCLUDING DIRECT, INDIRECT, INCIDENTAL, CONSEQUENTIAL, LOSS OF BUSINESS PROFITS OR SPECIAL DAMAGES, EVEN IF MICROSOFT CORPORATION OR ITS SUPPLIERS HAVE BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. SOME STATES DO NOT ALLOW THE EXCLUSION OR LIMITATION OF LIABILITY FOR CONSEQUENTIAL OR INCIDENTAL DAMAGES SO THE FOREGOING LIMITATION MAY NOT APPLY. Copyright Microsoft Corporation 2001.