home *** CD-ROM | disk | FTP | other *** search
/ The World of Computer Software / World_Of_Computer_Software-02-387-Vol-3of3.iso / v / vb_tips.zip / VB-TIPS.TXT < prev   
Text File  |  1992-06-29  |  264KB  |  7,997 lines

  1.                                    VB-Tips
  2.                                  July 1, 1992
  3.  
  4. CONTENTS:
  5.  
  6. Introductory Information:
  7.   Background
  8.   Using This File
  9.   Using VB-Tips Viewer
  10.   Disclaimers
  11.   CompuServe Acronyms
  12.  
  13. I. PROGRAMMING::
  14.  
  15. Arrays, Data:
  16.   Changing Elements of a Control Array
  17.   Control Array Bug
  18.   Dynamic Arrays
  19.   Huge Array Info
  20.   Huge Array Problem
  21.   Type Variables
  22.   Type Variables, Clearing Of
  23.   Type Variable Number Placement
  24.  
  25. Calls - Controls & Modules:
  26.   Calling Other Form's Controls
  27. | Calling Other Form's Subs/Functions
  28. | Passing Control Arrays
  29. | Passing Variable Arrays
  30.   Passing Form & Controls in CALLs
  31.   Passing Properties
  32.  
  33. DOS Functions:
  34. } File Copying
  35.   Getting File Date & Time
  36.   Getting File Info
  37.   Searching PATH$
  38.  
  39. File I/O, Database:
  40.   Btrieve
  41.   Deleting Data in Sequential File
  42.   MKI$ & CVI in VB
  43.   Objectrieve
  44.  
  45. Focus:
  46. | Control Must Be Visible
  47.   GotFocus Lost Due to MsgBox
  48. | LostFocus Bug
  49.   LostFocus Timing
  50.  
  51. Global.Bas:
  52.   DEFINT Is NOT Global
  53.   Global Const CRLF = chr$(13) + chr$(10)  Not Allowed
  54.   Global.bas Renaming
  55.   WINAPI - "Out of Memory"
  56.  
  57. Keyboard, Mouse, Joystick:
  58. | Alt-F4-Exit Trapping
  59.   Calling the Same Routines
  60. | Ctrl-Alt-Del Can't be Trapped
  61. } Double-Click before Click, Trapping
  62.   INKEY$ Loop Emulation
  63.   Joystick & VB
  64.   Keyboard/Mouse Shortcuts
  65.   Mouse Move Event
  66.   Mouse Pointer Style Setting
  67.   Right Click - Can't Detect
  68.   Using "Enter" in Place of "Tab"
  69.  
  70. Printer:
  71.   Aligning Text of Different Sizes
  72.   Calculating Page Length
  73.   Changing Paper Bins
  74.   EndDoc Makes Temp Files
  75.   EndDoc vs NewPage
  76.   Font Not Available on Printer
  77.   Formfeed Problems
  78.   Getting Available Font Sizes
  79.   Getting List of Installed Printers
  80.   Getting Printer Settings
  81.   Landscape Setting on HPLJ
  82.   Laser Printer Margins
  83.   LaserJet Driver Update
  84.   LaserJet Lost Line Fixed
  85.   LaserJet Offset
  86.   Matching Printer & Screen Fonts
  87.   Not Printing?
  88.   Number of Copies, Setting
  89.   Printer Setup
  90.   Printer Control Codes
  91.   Printer Wordwrap
  92.   Printing Forms
  93.   Printing Problems
  94.   ScaleLeft Errors
  95.   Sending Raw Data to the Printer
  96.   "Printer.TextHeight" Does Formfeed
  97.   TextWidth Improvement
  98.  
  99. Screen (Also see FONTS under CONTROLS):
  100.   Background for VB
  101.   Color Const Declarations
  102.   Displaying "ASCII Graphics"
  103.   Framing Controls (the NEXT Look)
  104. | "Painting" Not Finishing
  105. | Resolution, Determining
  106.   Screen/Window Capture
  107.   Screen Scaling/Form Resizing
  108.   Screen Scaling Tips
  109.   Screen Type
  110.   Screen Wipes
  111.   Stop Flashing During Updates
  112.   Suppress Arrow Cursor
  113.   Testing for 256-Color Display
  114.   Twips to Pixels
  115. | Windows is Device Independent - NOT!
  116.  
  117. VB Environment/Editor & Coding Style:
  118.   Breakpoints Change Processing
  119.   Code Should Go In Modules
  120.   .EXE Size / Junk In EXE's
  121.   Removing Deleted Control's Code
  122.   Saving Your Work
  123. | Splitting Long Lines
  124.  
  125. Programming, General:
  126.   Alias Use in Declares
  127.   API vs VB Routines
  128.   API Errors
  129.   Autoredraw Error Message
  130.   Blanking Out Text
  131.   Branding Your Apps
  132.   Control ID's
  133.   Currency Format vs Date Format
  134.   DateValue Bug
  135. | DoEvents(), Use Of
  136.   Emulating READ-DATA
  137.   Error Messages
  138.   Error Trapping
  139.   Far Pointers
  140.   Help Files
  141.   Interrupting a Routine
  142.   Julian Date Considerations
  143. | Jumping to a Subroutine During Coding
  144. | Memory, Out of
  145.   NEVER USE "END"
  146. | Polygon-Drawing API Call
  147. | Private INI Problem
  148. | RND Seeding
  149.   Slow Loading of App
  150.   Sound Standards
  151.   Telephone Dialing
  152.   "Too Many Files"
  153.   TRUE <> NOT FALSE
  154.   Windows 3.1 Quirks
  155.  
  156. System:
  157.   Calculating System Resources
  158.   Close Another App From Within VB
  159.   Control Box Menu, Adding Items
  160. } Control Box Menu, Removing Items
  161. } Control Box Exit Bug
  162.   Control Accessing Via DDE
  163.   Controlling Apps with SendKeys
  164.   Corrupt VB File Recovery
  165.   Detecting Running Applications
  166.   Detecting the Start-Up Directory
  167.   Exit Windows from VB
  168.   Faster Loading of Apps
  169.   File Creation Delay
  170.   File Handles - Maximum
  171.   Finding Excel
  172.   Linking to Excel
  173.   Get Program's Path & EXE Name
  174.   Get System Focus
  175.   hWnd for a Control
  176.   hWnd for a Control II
  177.   .INI Files
  178.   Mode - Which You Are In
  179.   Multi-Instance App Prevention
  180.   Name in Task List
  181.   Networks & VB
  182.   Norton Desktop vs VB
  183.   "Out of Stack Space" Error
  184. | Program Manager Groups, Getting List of
  185.   Resource Limits
  186.   Restart Windows
  187.   SendMessage
  188.   Shell-to-DOS Problems
  189.   Shell-to-DOS Syntax
  190.   Shell Error Numbers
  191. | Task List Exit Can't Be Stopped
  192.   Temp Files
  193. } VB App Cannot Be Windows 3.0 Shell
  194.   VBRUN100 Must Be on A:?
  195. | Version (of Windows) Detection
  196.   Wallpaper Changing
  197.   Why VB Apps Don't Cascade/Tile
  198.   WIN.INI Warning
  199.  
  200. II. CONTROLS, FORMS, FONTS::
  201.  
  202. Controls, General:
  203.   "&" in Captions
  204.   Aligning Text & Format$ Padding
  205.   Aligning Text on a Form
  206.   Button Colors
  207.   Buttons with Pictures
  208.   Loading Custom Controls
  209.   Modal Bugs
  210. | Modal Form Switching Bug
  211.   MsgBox Limitations
  212.   No DblClick in Directory List Box
  213.   Scroll Bars - Automatic and Manual
  214. | Toolbar Rearranging
  215.  
  216. Combo Boxes:
  217.   Changing Text
  218.   Color
  219.   Detecting Change
  220.   Pseudo Combo Dropdown List Box
  221.   Slow Loading of Combo Boxes
  222.  
  223. Custom Controls & DLL's:
  224.   "Bad DLL Calling Convention"
  225.   Ending an App from a DLL
  226.   Meter From Picture Boxes
  227.   METER1.VBX Bug
  228.   METER1.VBX Display Update
  229.   Sound.DLL
  230.   DLL's Explained
  231.   DLL's Are Slow
  232.   ByVal When Passing Strings
  233.   TPW Framework for DLL's
  234. | Passing Records
  235.   Passing Strings
  236.   SLIDER Control Bug
  237.   VBPro MDI Child Creation at Runtime
  238.  
  239. Form & Control Placement, Sizing:
  240.   Centering a Form on Screen
  241.   Controlling Form Size
  242.   Copying/Moving Controls
  243.   Covered Form?
  244.   Cursor in First Text Box
  245.   "Floating" Window (Forcing Window to Top)
  246.   Form Size and Granularity
  247.   Form Wipes, Fades, Etc.
  248.   Grouped Controls
  249.   Iconizing All Forms in a Project at Once
  250.   Instant Display of Controls
  251. | Minimizing All Forms At Once
  252.   Mouse Pointer, Position
  253.   Move Disabling
  254.   Moving Controls Cleanly
  255.   Moving Form Without Title Bar
  256. | Moving Multiple Forms Together
  257.   Multiple Instances of a Form Not Supported
  258.   Norton's Desktop, Get in Front of
  259.   Control's Coords. Are Relative to Form
  260.   Overlapping Controls
  261.   Placing Forms, Controls
  262. | Property Bar Errors
  263.   Resizing Forms
  264. | ScaleWidth/Height Purpose
  265.   Scrollable Forms
  266.   Unloading Control Arrays
  267.  
  268. Fonts:
  269.   Fixed Width Fonts
  270.   Large Font Bug
  271.   Listing Printer Fonts
  272. | Metafiles in Place of Fonts
  273.   TrueType Fonts Don't All Show Up
  274.   Using Different Fonts, Colors in a Box
  275.   System Font
  276.  
  277. Forms:
  278.   Calling Form_Paint
  279.   Changing Form Name
  280.   Detecting a Form's Getting Focus
  281.   Flashing a Form
  282.   Focus & Order of Execution
  283.   Focus on StartUp
  284.   Form.GotFocus
  285.   Modal Forms, Unloading
  286.   SetFocus Won't Work?
  287.   Unloading Forms Completely
  288.   Unloading Forms From Task Manager
  289.   Unloading Forms on Windows Termination
  290.  
  291. Grid Control:
  292.   What is the Grid Control?
  293. | Alternative to a Grid Control
  294.   Can't Enter "&"
  295. | Graphics in a Grid Cell
  296.   Faster Row Adding/Deleting
  297.  
  298. Icons:
  299.   Changing Icons
  300. } Getting an Icon from an EXE
  301.   Icon Caption Doesn't MOVE
  302.   Icon - Get Rid Of
  303.   Transparent Background
  304.  
  305. Label Boxes:
  306. } An Alternative to Label Boxes
  307. | Captions, Multi-Line
  308.   Label Box Text Background Color
  309.  
  310. List Boxes:
  311.   "AddItem #" Error
  312. | Bitmaps in List Boxes
  313.   Capacities
  314.   Clear a List Box
  315.   Finding an Item Added to a Sorted List Box
  316.   Finding an Item Manually
  317. } Finding an Item via API
  318.   Font Size Changes List Box Size
  319.   Forcing an Item Number to the Top
  320.   Inhibiting Screen Updating
  321.   Linking Sorted and Unsorted List Boxes (or Arrays)
  322.   "ListIndex = -1" Generates Click Event
  323.   Selecting Multiple Items
  324.   Tab Stops
  325.  
  326. Menu Bar:
  327.   AppName.Caption Problem
  328.   Calling Help for Menu Items
  329.   ClipBoard Status
  330.   Disabling Menu Items
  331.   Focus Doesn't Change
  332.   Right Justify "Help"
  333.   Screen Flicker on Selection
  334.  
  335. Picture Boxes:
  336. | An Alternative to Picture Boxes
  337.   As Buttons
  338.   AutoRedraw
  339.   BitBlt to/from Hidden Box
  340.   "Box" Command
  341.   To Clipboard as Metafile?
  342.   Copying a Drawing to Clipboard
  343.   Copying Text in a Picture
  344.   Cutting-Pasting to a Picture Box
  345.   Dragging A Full Picture
  346.   Dragging Text Box in Picture
  347.   Drawing - Scale
  348.   Faster Drawing
  349.   Number of Colors Supported
  350.   Saving Extracted Icons
  351.   Saving Picture Files
  352.   ScaleHeight Negative
  353.   Unloading a Picture
  354.   Zoom In/Out On A Picture
  355.  
  356. Text Boxes:
  357.   255-Character Limit?
  358.   CtlName Access Via CDK
  359.   Cursor (text), Position
  360.   Data Entry Masking
  361.   Data Entry Routine
  362.   Data Entry Text Limit
  363.   Fast Loading
  364.   Flicker
  365.   Flashing/Highlighting Text
  366.   Increasing Line Limit
  367. | Keeping Text Highlighted
  368.   Line Number, Finding
  369.   Number of Lines
  370.   Read-Only Text Box
  371. | Tab Key Trapping
  372.  
  373. Timer:
  374.   DoEvents () in a Timer
  375. | Resolution/Accuracy
  376.   Using the Timer
  377.  
  378. III. OTHER::
  379.  
  380. Knowledge Base:
  381.   What is Knowledge Base?
  382.  
  383. Visual Basic Books:
  384.   VB Book Reviews
  385.  
  386. VB Downloadable Files:
  387.   How to Get the Files
  388.   DLL's, Utilities
  389.   DOS Access/Functions
  390.   Font Utilities
  391.   Networking/Communications
  392.   System
  393.   Time/Date Applications
  394.   Graphics/Video
  395.   Custom Controls
  396.   General Tools/Reference/Info
  397.   Miscellaneous
  398.   Database, Data Entry, Sorting
  399.   Printing
  400.   Other
  401.   PsL's July 1992 Visual Basic Disk
  402.  
  403. ---------------
  404.  
  405.  
  406. Background:
  407.  
  408. This file may be freely shared with others so long as no changes are made to it.
  409. Changes made to this file will likely result in the viewing program not working.
  410.  
  411. Official updates to VB-Tips are available from DL1 of the MSBASIC forum on
  412. CompuServe and from the address below.
  413.  
  414. Compiled and Edited by
  415.   Nelson Ford, 71355,470
  416.   Public (software) Library
  417.   P.O.Box 35705
  418.   Houston, TX 77235-5705
  419.   800-242-4PsL  713-524-6394
  420. NOTE: The above numbers are NOT bbs's.
  421. PsL distributes shareware on disks.
  422.  
  423. New entries in this update are marked with a "|" in the margin in the CONTENTS
  424. section. Updated entries are marked with a "}" in the margin.
  425.  
  426. Updates are presently being posted every month or two. Updates are cumulative,
  427. so if you get an update, there is no point in keeping the old files.
  428.  
  429. This file would not have been possible without the willingness of others to
  430. share their knowledge. Early updates did not include the name of the
  431. contributor with each tip, but the following were, and continue to be, among
  432. the important contributors:
  433.  
  434. Jonathan Zuck
  435. Keith Funk
  436. Mark Novisoff
  437. Ted Young
  438. Dennis Harrington
  439. the Microsoft Section Leaders
  440.  
  441. Sysop of the MSBASIC forum on CompuServe is Jerry Fisher, 76711,22.
  442. ---------------
  443.  
  444.  
  445. Using This File:
  446.  
  447. You can view this file with any file viewing utility such as List; however,
  448. there is a program named VBT-VW on the MSBASIC forum that can make it easier
  449. to work with this file. See VB-Tips Viewer, below.
  450.  
  451. If you are using a file viewer like List, first look up information about a
  452. topic that you see in the CONTENTS section, you can just search for it.
  453.  
  454. The Category headings (eg: "General") in the CONTENTS section are NOT repeated
  455. in the body of the file. You must search on the actual Tip titles.
  456.  
  457. If you cannot find information you need in the CONTENTS, be sure to browse
  458. through the text of the "VB Downloadable Files" section at the end of this
  459. file.
  460.  
  461. Each Tip is separated from the others by a dashed line.
  462. ---------------
  463.  
  464.  
  465. Using VB-Tips Viewer:
  466.  
  467. The VB-Tips Viewer program was written for viewing this file more easily.
  468. See the comments in the Global file of the Viewer code for more information.
  469.  
  470. To save download time, only the source code for VB-Tips was uploaded. You can
  471. easily compile it yourself. Feel free to customize the source for your own
  472. use, such as hard-coding the location of the VB-TIPS.TXT file on your system.
  473.  
  474. WARNING: If you make changes to the CONTENTS section or any of the Tips
  475. captions, the Viewer program may not be able to access this file. Keep a
  476. backup.
  477.  
  478. To use the Viewer, select a Category and its topics will be displayed in the
  479. adjoining window. Select a Topic (Tip) and it will be displayed in the Tips
  480. Window.
  481.  
  482. If you press the Clipboard button, whichever Tip the cursor is in will be
  483. copied to the Windows Clipboard. This is the easiest way to copy a routine to
  484. your own program.
  485. ---------------
  486.  
  487.  
  488. Disclaimers:
  489.  
  490. While I have done my best to test everything that appears in this file, a couple
  491. of typos and other glitches have appeared in previous versions of this file.
  492. Anything that is not marked as being new (with a vertical bar in the left
  493. margin) should be pretty stable. If you have trouble with any of the new stuff
  494. or if you find any errors in this file or if you would like to add info to this
  495. file, please send a message on the MSBASIC forum (sec. 5) to 71355,470.
  496.  
  497. The contents of this file are not warranted in any way. I do not assume any
  498. responsibility for the use of this materials. I am not affiliated in any way
  499. with Microsoft Corporation.
  500. ---------------
  501.  
  502.  
  503. CompuServe Acronyms:
  504.  
  505. Newcomers on the MSBASIC forum and on CompuServe may be puzzled by the
  506. acronyms seen in some of the messages. Here are a few of the more popular
  507. ones, to help you feel more at home:
  508.  
  509. BTW = By the way
  510. FWIW = For what it's worth
  511. <g> = "Grin"
  512. <g,d&r> = Grinning, ducking and running (usually appended to a teasing remark)
  513. IMO = In my opinion
  514. IMHO = In my *humble* opinion
  515. PITA = Pain in the a(natomy)
  516. PMFBI = Pardon me for butting in
  517. PMJI = Pardon my jumping in
  518. ROFL = Rolling on the floor, laughing
  519. ;-) = a smiley face winking (tilt your head to the left and look at it)
  520.  
  521. There are many more. You can usually figure them out - or just ask.
  522. ---------------
  523.  
  524.  
  525. Changing Elements of a Control Array:
  526.  
  527. Q: Is there a way to simultaneously change a property in a control array,
  528. affecting all the elements simultaneously? For example, if I had an array that
  529. had several text labels and I wanted to change all their forecolors to blue.
  530.  
  531. A: No. You have to use a For-Next loop.
  532. ---------------
  533.  
  534.  
  535. Control Array Bug:
  536.  
  537. If you create a control and add code to one of its events and then decide to
  538. make it into a control array, VB does not add the "Index As Integer" argument
  539. to the control's argument list. When you attempt to run the program, VB gives
  540. the error, "Incorrect number of event procedure arguments". (Keith Funk)
  541. ---------------
  542.  
  543.  
  544. Dynamic Arrays:
  545.  
  546. In order to use a dynamic array, you must REDIM it in a module or form:
  547.  
  548. Global:
  549.   Type SomeType
  550.        X As Integer
  551.        etc
  552.   End Type
  553.   Global ArrayName() As SomeType
  554.  
  555. Module or Form:
  556.   Redim ArrayName(x) As SomeType    ' x can be a number or a variable
  557. ---------------
  558.  
  559.  
  560. Huge Array Info:
  561.  
  562. Most VB controls (eg: List & Text boxes) and arrays limit you to 64k of data.
  563. Microsoft gave beta testers a Huge Array DLL, but did not include it in the
  564. finished VB package.
  565.  
  566. The DLL seems to work all right most of the time (see below), but it is
  567. difficult to access and slow to load. See HUGEGR.EXE and RANDGR.EXE comparing
  568. the use of a Huge Array to a Random Access data file. Performance is about the
  569. same, but using a Random Access file means the program starts faster and data
  570. is more secure.
  571. ---------------
  572.  
  573.  
  574. Huge Array Problem:
  575.  
  576. If you DIM a Huge Array (a public domain DLL) to a small number of elements
  577. and later REDIM it to a large number, you will get an Out Of Memory error from
  578. the DLL, even when there is sufficient memory. You can REDIM to a smaller
  579. number of elements with no error.
  580.  
  581. Using a 16-byte TYPE variable, I DIMmed the array to 10000 elements and then
  582. ReDIMmed it to 23864 elements. This worked fine. However, I could not ReDIM
  583. this same array to more than 23864 elements without getting a (-1) Out of
  584. Memory error from HUGEARR.DLL, even though if I initially DIM the array to
  585. 30000 elements it works fine.  - Randy Berry
  586. ---------------
  587.  
  588.  
  589. Type Variables:
  590.  
  591. Unlike QuickBASIC, you cannot use arrays within a TYPE...END TYPE declaration,
  592. such as:
  593.        Type SomeType
  594.           x As Double
  595.           y(100) As SomeOtherType
  596.        End Type
  597.  
  598. You can work around it by putting a variable length STRING in your TYPE and
  599. then storing the information in the string. Not the easiest way to do things,
  600. but in some ways it's more flexible since you don't have to know before hand
  601. how large it should be.
  602. ---------------
  603.  
  604.  
  605. Type Variables, Clearing Of:
  606.  
  607. To clear an entire Type in one shot you can dimension a second Type variable
  608. of the same kind, and use LSet to assign it:
  609.   Dim Inv As Invoice, Dummy As Invoice
  610.   LSet Inv = Dummy
  611. (Ethan Winer)
  612. ---------------
  613.  
  614.  
  615. Type Variable Number Placement:
  616.  
  617. Be sure when using arrays with Type variables to put the variable number
  618. AFTER the type name and BEFORE the element name.
  619.  
  620. Example:
  621.         TypeName(i).string1 = "xyz"  NOT  TypeName.string1(i) = "xyz"
  622. ---------------
  623.  
  624.  
  625. Calling Other Form's Controls:
  626.  
  627. You can invoke a control from another form via the Value property. For
  628. example, in Form2, you can say "Form1.Command1.Value = -1" and this will
  629. invoke Command1_Click on Form1.
  630.  
  631. Normally, if you have a "(general)" routine (ie: not attached to a control)
  632. that you want to access from more than one Form, you should put the code in a
  633. Module (see the VB manuals). However, it *is* possible to put the code in one
  634. Form and call it from others by the method in the previous paragraph. Instead
  635. of putting the routine in "(general)", assign it to a button and set the
  636. button's Visible property to False. Now you can call it as above.
  637. ---------------
  638.  
  639.  
  640. Calling Other Form's Subs/Functions:
  641.  
  642. You cannot directly call a sub or function in another form. Form routines are
  643. "local" to that routine. You have to move your routines into a module, which
  644. makes them "global".
  645.  
  646. One method I use to get around this is to create an invisible textbox or
  647. caption on a form, and then in the textbox_chaged sub for that control, call
  648. the sub. Its a little obtuse, but it works. Simply address the control: sub
  649. text1_change()
  650.         Call some_neat_sub end sub
  651.  
  652. then inside another form, I use:
  653.  
  654.         form1.text1.text="1" REM or whatever the arguments are"
  655.  
  656. This fires the form1.textbox_changed routine, which in turn calls my sub.
  657.  
  658. However, there are lots of good reasons to move routines in a module of thier
  659. own (memory, speed etc..) (hank marquis)
  660. ---------------
  661.  
  662.  
  663. Passing Control Arrays:
  664.  
  665. You can send an a single element of a control array to a Sub, but not a whole
  666. control array. (Ted Young)
  667.  
  668. Example:
  669. For i = 0 to 9
  670.   Call SomeSub(SomeControl(i))
  671. Next
  672. (Jeff Simms)
  673. ---------------
  674.  
  675.  
  676. Passing Variable Arrays:
  677.  
  678. To pass an array to a subroutines, use enpty parentheses:
  679.  
  680.   Call ProcName(Array(), otionalparam1, param2, etc)
  681.  
  682. Inside the called routine you can use LBound and UBound to know how big the
  683. array is. (Ethan Winer)
  684. ---------------
  685.  
  686.  
  687. Passing Form & Controls in CALLs:
  688.  
  689. Often overlooked in the manual is how to pass a control in a CALL. The syntax is
  690.  
  691. SUB SomeSub (Lst as Control)
  692.   Lst.AddItem "abc"
  693.  
  694. In the calling routine, you would say Call SomeSub(List1), for example.
  695.  
  696. You cannot call a Sub that is in another Form. It must be in a module, if not
  697. in the calling Form. There is a kludge for getting around this (it involves
  698. the principle described in Calling Other Form's Controls, above), but why
  699. bother kludging when you can just move the routine into a Module?
  700.  
  701. To pass text from a control, you must use ByVal.
  702. Example:  Sub SomeSub (s as string)
  703.           Call SomeSub(Text1.Text)
  704. ---------------
  705.  
  706.  
  707. Passing Properties:
  708.  
  709. If you have a Sub defined like "Sub Something(a%)", you can pass a control's
  710. property to it by putting it inside parentheses (in addition to any required
  711. parentheses):
  712.  
  713. X = Something((CtlName.ForeColor))
  714.  
  715. If the Sub is defined using "ByVal", such as "Sub Something (ByVal a%)", then
  716. the extra parentheses are not required:
  717.  
  718. X = Something(CtlName.ForeColor)
  719.  
  720. If you need to change the value of a Property in a Sub, you must use the
  721. following syntax:
  722.  
  723. Sub ToggleBoolean (Check As Control)
  724.   Check.Enabled = Not Check.Enabled
  725. End Sub
  726.  
  727. Sub Command1_Click ()
  728.   ToggleBoolean Check1
  729. End Sub
  730. ---------------
  731.  
  732.  
  733. File Copying:
  734.  
  735. 1.
  736. Open "FileIn" for Binary as #1
  737. whole = Lof(1) \ 32000        'numer of whole 32768 byte chunks
  738. part = Lof(1) MOD 32000     'remaining bytes at end of file
  739. buffer$ = string$(32000,0)
  740. start& = 1
  741. Open "FileOut" for Binary as #2
  742. for x=1 to whole                     'this for-next loop will copy 32,000
  743.        get #1, start&, buffer$       'byte chunks at a time. If there is
  744.        Put #2, start&, buffer$       'less than 32,000 bytes in the file,
  745.        start&= start& + 32000        'whole = 0  and the loop is bypassed.
  746. next x
  747. buffer$ = string$(part, 0)           'this part of the routine will copy
  748. get #1, start&, buffer$              'the remaining bytes at the end of the
  749. put #2, start&, buffer$              'file.
  750. close
  751.  
  752. 2.
  753. Here's a routine for file copying using global memory and the new 3.1
  754. functions hread and hwrite which will read/write any size file in one shot as
  755. long as sufficeint global memory is available. You'll want to put error
  756. handling in as needed. I've included the hread & hwrite declarations. You can
  757. get the other function declares and the constants from VBAPI.TXT.
  758.  
  759. Declare Function hread Lib "kernel" Alias "_hread" (ByVal hFile As Integer,
  760.                             lpBuffer As Any, ByVal dwBytes As Long) As Long
  761. Declare Function hwrite Lib "kernel" Alias "_hwrite" (ByVal hFile As Integer,
  762.                             lpBuffer As Any, ByVal dwBytes As Long) As Long
  763.  
  764. inHndl% = lopen(InFile$, OF_READ)   'open source file for reading
  765. size& = llseek(inHndl%, 0, 2)       'find length of file
  766. msg& = llseek(inHndl%, 0, 0)        'reset file pointer to beginning
  767. memHndl% = GlobalAlloc(GHND, size&) 'allocate needed global memory
  768. memAddr& = GlobalLock(memHndl%)     'get global memory address
  769. inBytes& = hread(inHndl%, ByVal memAddr&, size&) 'read in source file
  770. outHndl% = lOpen(outFile$, OF_CREATE Or OF_WRITE) 'open target file
  771. outBytes& = hwrite(OutHndl%, ByVal memAddr&, size&) 'write out target
  772. ok% = lclose(inHndl%)               'close source file
  773. ok% = lclose(OutHndl%)              'close target file
  774. ok% = GlobalUnlock(memHndl%)        'unlock global memory
  775. ok% = GlobalFree(memHndl%)          'free global memory
  776.  
  777. (Dennis Harrington)
  778. ---------------
  779.  
  780.  
  781. Getting File Date & Time:
  782.  
  783. Dennis Harrington, with Costas Kitsos help, came up with the following routine
  784. for getting the date and time of an existing file.
  785.  
  786. Global:
  787. DefInt A-Z
  788. Type OFSTRUCT
  789.    cBytes As String * 1
  790.    fFixedDisk As String * 1
  791.    nErrCode As Integer
  792.    r1 As Integer
  793.    r2 As Integer
  794.    szPathName As String * 128
  795. End Type
  796. Declare Function OpenFile Lib "Kernel" (ByVal lpFileName as String,
  797.                                         lpReOpenBuff As OFSTRUCT,
  798.                                         ByVal wStyle)
  799.  
  800. Form1 General:
  801. DefInt A-Z
  802. Dim FileMonth, FileDay, FileYear
  803. Dim FileHour, FileMinute, FileSecond
  804.  
  805. Sub TestMe(Fi$)
  806.   Dim a As OFSTRUCT
  807.   x = OpenFile(Fi$, a, &H4000)
  808.   FileMonth = ((a.r1 And &H7FFF) \ 32) And &HF
  809.   FileDay = a.r1 And &H1F
  810.   FileYear = (a.r1 And &H7FFF) \ 512 + 80
  811.   FileHour = (a.r2 And &H7FFF) \ 2048
  812.   If a.r2 < 0 Then FileHour% = (FileHour% + 16) - 12 'for PM times
  813.   FileMinute = ((a.r2 And &H7FFF) \ 32) And &H3F
  814.   FileSecond = (a.r2 And &H1F) * 2
  815. End Sub
  816.  
  817. Sub Form_Click:
  818.   Call TestMe("c:\config.sys")
  819.   Print FileMonth "/" FileDay "/" FileYear
  820.   Print FileHour ":" FileMinute ":" FileSecond
  821. End Sub
  822. ---------------
  823.  
  824.  
  825. Getting File Info:
  826.  
  827. VB does not let you get detail about files, such as file date, size, attribute.
  828. (Except through API calls. See above.)
  829. Look for VBDOS on DL1 or DL6. Third-party libraries offer these functions too.
  830. Look for demos of QuickPak for Windows and VB-Muscle.
  831. ---------------
  832.  
  833.  
  834. Searching PATH$:
  835.  
  836. For an example of how to search the directories in the DOS Path for a file,
  837. see the ICONWRKS.BAS module's "Help_File_In_Path". (ICONWRKS is one of the
  838. sample files that comes with VB.)
  839. ---------------
  840.  
  841.  
  842. Btrieve:
  843.  
  844. There are the DLL-Declarations for Btrieve. The requestor must be loaded
  845. before Windows:
  846.  
  847. Declare Function wbtrvinit Lib "wbtrcall.dll" (ByVal init$) As Integer
  848. Declare Sub wbtrvstop Lib "wbtrcall.dll" ()
  849. Declare Function btrcall Lib "wbtrcall.dll" (ByVal a%, ByVal b$, ByVal c$,
  850.   d%, ByVal e$, ByVal f%, ByVal g%) As Integer
  851.  
  852. FIELD and VARPTR are definitely not necessary. You'll need to set up a
  853. user-defined type to work with Btrieve (instead of FIELD). The call syntax for
  854. Win Btrieve takes care of pointing to the record (instead of VARPTR). Just be
  855. sure to pass any variable-length strings (i.e, A$) BYVAL.
  856.  
  857. Owners of versions of Btrieve no longer supported, including the old
  858. single-user DOS version, can upgrade to Btrieve for Windows for $125. If you
  859. have a still-supported version, such as Btrieve/N, you cannot upgrade.
  860. To upgrade, call 800-RED-WORD.
  861.  
  862. If you are using Btrv-Win with a network, the Btrv requestor must be loaded
  863. before Windows, but for single-user set-ups, you do not need anything but the
  864. Btrieve DLL.
  865. ---------------
  866.  
  867.  
  868. Deleting Data in Sequential File:
  869.  
  870. Here's an idea for deleting text in the middle of a sequential file that might
  871. work.  Haven't tried it, but it seems like it would work and wouldn't be
  872. difficult to implement. First, you'll have to save file pointers to the
  873. beginning of each message (e.g., in a Long Int array during message load using
  874. the SEEK function) in MsgPtr&(). Now, if you want to delete message 50 and
  875. there are a total of 200, you'd do the following:
  876.  
  877.  MsgToDelete = 50
  878.  TotMsgs = 200
  879.  BlockSize& = 32768&'-- make this larger or smaller to find optimum size
  880.  Temp$ = Space$(BlockSize&)
  881.  Open "MESSAGE.MSG" For Binary As #1
  882.  
  883.  SizeOfFile& = LOF(1)
  884.  SizeToMove& = SizeOfFile& - MsgPtr&(MsgToDelete + 1)
  885.  NumBlocks = SizeToMove \ BlockSize&
  886.  LeftOver = SizeToMove& - Num32KBlocks * BlockSize&
  887.  FromLoc& = MsgPtr&(MsgToDelete + 1)
  888.  ToLoc& = MsgPtr&(MsgToDelete)
  889.  
  890.  For i = 1 To NumBlocks
  891.      Seek #1, FromLoc& + BlockSize& * (i - 1)
  892.      Get #1, Temp$
  893.      Seek #1, ToLoc& + BlockSize& * (i - 1)
  894.      Put #1, Temp$
  895.  Next
  896.  Temp$ = Space$(LeftOver)
  897.  Seek #1, FromLoc& + BlockSize& * NumBlocks
  898.  Get #1, Temp$
  899.  Seek #1, ToLoc& + BlockSize& * NumBlocks
  900.  Put #1, Temp$
  901.  '-- Now adjust the MsgPtr& array
  902.  TotMsgs = TotMsgs - 1
  903.  Adjust = MsgPtr&(MsgToDelete + 1) - MsgPtr&(MsgToDelete)
  904.  For i = MsgToDelete To TotMsgs
  905.      MsgPtr&(i) = MsgPtr&(i + 1) - Adjust
  906.  Next
  907. ---------------
  908.  
  909.  
  910. MKI$ & CVI in VB:
  911.  
  912. function MKI$ (Work%)
  913.   MKI$ = Chr$ (Work% MOD 256) + Chr$ (Work% \ 256)
  914. end function
  915.  
  916. function CVI% (Work$)
  917.   CVI% = (ASC (Left$ (Work$, 1)) * 256) + ASC (Right$ (Work$, 1))
  918. end function
  919. ---------------
  920.  
  921.  
  922. Objectrieve:
  923.  
  924. ObjectTrieve/VB seems to be the first data manager available to offer Binary
  925. Large Objects (BLOBS). ObjectTrieve is an ISAM file manager based on the
  926. X/OPEN standard. You may want to consider calling Coramandel at 1 800 535-3267
  927. or 718-793-7963. Ask for Narayan Laksham
  928. ---------------
  929.  
  930.  
  931. Control Must Be Visible:
  932.  
  933. If you get an illegal function call when trying to SetFocus to a control, the
  934. reason is probably that the control/form is not visible. This usually happens
  935. in Form_Load. Just add the line: "Form1.Show". (Mark Novisoff)
  936. ---------------
  937.  
  938.  
  939. GotFocus Lost Due to MsgBox:
  940.  
  941. Putting a MsgBox in a Control's LostFocus keeps the GotFocus in the next
  942. Control from being executed:
  943.  
  944. Sub Text1_LostFocus ()
  945.   MsgBox = "Losing Focus"
  946.  
  947. Sub Text2_GotFocus ()
  948.   Text2.Text = "Got Focus"
  949.  
  950. This appears simply to be a bug in VB.
  951. ---------------
  952.  
  953.  
  954. LostFocus Bug:
  955.  
  956. If you have specified a lost focus procedure it is possible that
  957. when the focus is lost, your form will re-load itself if the string
  958. being examined is a null string.  It took me awhile to find the
  959. problem, but if I commented out my code, sure enough everything
  960. worked fine.  I got around it by first specifying in the lost
  961. focus routine that the string I was checking must not be a null
  962. string (if so, exit sub). (Jim Poland)
  963. ---------------
  964.  
  965.  
  966. LostFocus Timing:
  967.  
  968. If one control has focus and you execute another control by clicking on it,
  969. control-1's LostFocus gets executed before control-2's Click event, but if you
  970. use an access key to execute the second control or if you use SetFocus to
  971. change focus, then control-1's LostFocus gets executed AFTER control-2's Click
  972. event.
  973. ---------------
  974.  
  975.  
  976. DEFINT Is NOT Global:
  977.  
  978. DEFINT A-Z in your Global file does NOT have a GLOBAL effect. You must do a
  979. DEFINT A-Z in the General_Declarations of each form.
  980. ---------------
  981.  
  982.  
  983. Global Const CRLF = chr$(13) + chr$(10)  Not Allowed:
  984.  
  985. Several people have complained about the above command not being allowed. (You
  986. cannot use CHR$ in a Global Const.) This is not a bug, but a limitation of the
  987. language. Use the following instead:
  988.  
  989. GLOBAL.BAS
  990.    Global CRLF$
  991.  
  992. Sub Form_Load()   ' Or Sub Main, if you prefer
  993.    CRLF$ = CHR$(13) + CHR$(10)
  994. End Sub
  995. ---------------
  996.  
  997.  
  998. Global.bas Renaming:
  999.  
  1000. VB will not let you load a file and rename it to Global.bas, so you can
  1001. cut-and-paste code, but it's easier to use the Save Text to save the desired
  1002. Global.bas code and then use Load Text (in the Code menu) to Replace or Merge
  1003. it into the new Global.bas. (Jon Wumkes)
  1004. ---------------
  1005.  
  1006.  
  1007. WINAPI - "Out of Memory":
  1008.  
  1009. WINAPI contains all the Declares for the API for VB. However, you can NOT
  1010. simply load this file into Global.Bas or you will get an out of memory error.
  1011. (It is too large, for one thing.)
  1012.  
  1013. Instead, load it into Write or some other editor or word processor with
  1014. sufficient capacity and cut-paste just the Declares that you need into Global.
  1015.  
  1016. A cross-reference file for WINAPI is now available: APIXREF.HLP. To access
  1017. this file, while in VB press F1 for Help, then File-Open from the menu to load
  1018. the file.
  1019. ---------------
  1020.  
  1021.  
  1022. Alt-F4-Exit Trapping:
  1023.  
  1024. To stop the user from quitting your app by pressing Alt-F4 (the shortcut key
  1025. for the System box Close), you can put Cancel=-1 in Form_Unload, but that also
  1026. keeps you from unloading the form when you really want to. You can get around
  1027. this by setting a global flag/variable before unloading the form and checking
  1028. the variable in the Unload sub.
  1029.  
  1030. Another alternative is to remove Close from the Control box. See "Control Box
  1031. Menu, Removing Items" under "Programming - System".
  1032. ---------------
  1033.  
  1034.  
  1035. Calling the Same Routines:
  1036.  
  1037. The easy way to get both the Mouse Click and the Enter key to do the same
  1038. thing is to write a third sub that you call from the other two:
  1039.  
  1040. Sub CommonHandler
  1041.     ' Do your thing here
  1042. End Sub
  1043. Sub Ctlname_Click()
  1044.     Commonhandler
  1045. End Sub
  1046. Sub Text1_KeyPress(....)
  1047.     If KeyAscii = 13 Then
  1048.        KeyAscii = 0
  1049.        CommonHandler
  1050.     End If
  1051. End Sub
  1052. ---------------
  1053.  
  1054.  
  1055. Ctrl-Alt-Del Can't be Trapped:
  1056.  
  1057. Ctrl-Alt-Del cannot be trapped in VB.
  1058. ---------------
  1059.  
  1060.  
  1061. Double-Click before Click, Trapping:
  1062.  
  1063. If you have code assigned to both the Click event AND the Double-Click,
  1064. when you double-click, VB will execute the Click code on the first click of
  1065. the double and the D-C code on the second click.
  1066.  
  1067. Here is a routine for letting you have both (Nelson Ford):
  1068. (A previous routine given here was crocked. Sorry.)
  1069.  
  1070. General_Declarations:
  1071.   Dim DblClk, Reject
  1072.  
  1073. Sub Form_Load()
  1074.   For i = 1 to 20: List1.Additem Str$(i): Next
  1075. End Sub
  1076.  
  1077. Sub List1_Click()
  1078.   If Reject Then Exit Sub Else Reject = True
  1079.   x! = Timer:  Do: y = DoEvents(): Loop While Abs(Timer - x!) < .3
  1080.   'The line above pauses to allow some time for the 2nd click, if any.
  1081.   'You can play with this number to get best results. The larger the
  1082.   'number, the longer the delay when doing a single click. The smaller
  1083.   'the number, the more likely you'll generate an unwanted single click
  1084.   'execution when trying to do a double click.
  1085.   If DblClk Then DblClk = 0: Exit Sub
  1086.   Print "Single Click"
  1087.   Reject = 0
  1088. End Sub
  1089.  
  1090. Sub List1_DblClick()
  1091.   Print "Double Click"
  1092.   DblClk = - 1 'it does help to actually *set* this variable <g>
  1093.   Reject = False
  1094. End Sub
  1095. ---------------
  1096.  
  1097.  
  1098. INKEY$ Loop Emulation:
  1099.  
  1100. In other Basics, you can say:
  1101.  
  1102. WHILE INKEY$ = ""
  1103.   [do stuff]
  1104. WEND
  1105.  
  1106. VB does not support INKEY$, so here's how to emulate the concept of looping
  1107. until a key is pressed:
  1108.  
  1109. GLOBAL.BAS:
  1110.   DefInt A-Z
  1111.   Declare Function PeekMessage Lib "User" (ByVal Msg$, ByVal hWnd, ByVal Min,
  1112.                                            ByVal Max, ByVal Flag)
  1113.   Const WM_KEYFIRST = &H100 Const WM_KEYLAST = &H108
  1114.   Const Msg$ = "XXXXXXXXXXXXXXXX"
  1115.  
  1116. Function NoKeys ()
  1117.   Result = PeekMessage(Msg$, 0, WM_KEYFIRST, WM_KEYLAST, 1)
  1118.   NoKeys = Result -1
  1119. End Function
  1120.  
  1121. SomeSub ():
  1122.   While NoKeys ()
  1123.     [do stuff]
  1124.   Wend
  1125. End Sub
  1126.  
  1127. This function does *NOT* yield to other Win apps like DoEvents does, if you
  1128. want the same functionality then the last parameter passed to PeekMessage
  1129. should be zero (0). -=- Jonathan Zuck
  1130. ---------------
  1131.  
  1132.  
  1133. Joystick & VB:
  1134.  
  1135. You cannot read the joystick port with native VB commands. See MHELP in the
  1136. program listing at the end of this file for a DLL that lets you emulate INP
  1137. and OUT statements that should do the job.
  1138. ---------------
  1139.  
  1140.  
  1141. Keyboard/Mouse Shortcuts:
  1142.  
  1143. Fm: Chris Sacksteder
  1144.  
  1145. 1. To show a control's first event procedure, double-click on the control.
  1146. 2. Use tab to cycle through controls.
  1147. 3. Ctrl+up and Ctrl+down can be used to quickly cycle through procedures.
  1148. 4. Ctrl+right and Ctrl+left move the cursor by word.
  1149. 5. Ctrl+Y cuts the current line to the clipboard.
  1150. 6. Ctrl+N opens a blank line before the current line.
  1151. 7. double-click on a word to mark the whole word.
  1152. 8. select a procedure name (double click on it) and press Shift+F2 to jump
  1153.      to that procedure.
  1154. 9. select several lines and press Tab to indent all of them; Shift+Tab will
  1155.      undent them
  1156. 10. Click-drag down the top of a code box to open a second code box.
  1157. 11. use the keyboard to jump to the first letter of any list (controls,
  1158.       procedures, properties)
  1159. 12. Get help on any keyword by placing the carret anywhere in the word and
  1160.       pressing F1 (in the Immediate window you have to select the entire
  1161.       keyword before pressing F1).
  1162. 13. If you get an error during runtime, press F1 to get more information.
  1163. ---------------
  1164.  
  1165.  
  1166. Mouse Move Event:
  1167.  
  1168. The _MouseMove event is only triggered when the mouse changes position.
  1169. However, there's a bug in VB which causes continuous MouseMove events when
  1170. you're using debug.print within the MouseMove event. (Ted Young)
  1171. ---------------
  1172.  
  1173.  
  1174. Mouse Pointer Style Setting:
  1175.  
  1176. Each form has it's own mouse pointer. If you want to keep the pointer as an
  1177. hourglass, for example, while different forms are loaded, you need to place a
  1178. "_.MousePointer = 11" statement in each Form_Load.
  1179.  
  1180. Alternatively, you can use the Screen.MousePointer object/property to set the
  1181. hour glass for all forms in the Project. (It does not affect the MousePointer
  1182. for other Windows applications that you may be running at the same time.)
  1183. ---------------
  1184.  
  1185.  
  1186. Right Click - Can't Detect:
  1187.  
  1188. VB provides no direct means of detecting a double-click of a right mouse
  1189. button.
  1190. ---------------
  1191.  
  1192.  
  1193. Using "Enter" in Place of "Tab":
  1194.  
  1195. Sub Text1_KeyPress(KeyAscii As Integer)
  1196.     If KeyAscii = 13 Then
  1197.        KeyAscii = 0            ' Avoid the beep
  1198.        SendKeys "{Tab}"        ' Simulate pressing the Tab key
  1199.     End If
  1200. End Sub
  1201. ---------------
  1202.  
  1203.  
  1204. Aligning Text of Different Sizes:
  1205.  
  1206. By default, windows aligns text characters based on the top of each
  1207. character's cell. If you use several fonts, this can result in some funny
  1208. looking typography because their base lines don't lineup, even if they're the
  1209. same point size.
  1210.  
  1211. By using the API call SetTextAlign to reset the text alignment to TA_BASELINE
  1212. which aligns characters on their typographical baselines, you can mix
  1213. different fonts and different sizes and they line up correctly.
  1214.  
  1215. If you do this, remember that with base aligned text, CurrentY is the text
  1216. baseline and not the top of the character cell. Printing the first line with
  1217. CurrentY = 0 will only print the descenders of text characters on that line.
  1218. (Dennis L. Harrington)
  1219. ---------------
  1220.  
  1221.  
  1222. Calculating Page Length:
  1223.  
  1224. If you use GetDeviceCaps to determine the printable page size, you know the
  1225. actual printable page length. It's then easy to adjust your printing to any
  1226. length paper.
  1227.  
  1228. Compute the number of verticle twips on the page and subtract whatever you want
  1229. for top and bottom margins and 1 line of text. Then just print from some form of
  1230. loop and increment the CurrentY yourself by the number of verticle twips
  1231. required for each line.
  1232.  
  1233. Each time you increment the CurrentY, test the new value against the maximum
  1234. computed above. If the new CurrentY is greater than the maximum, you've filled
  1235. the page and it's time to start a new page. This is especially handy with laser
  1236. printers may be use either letter or legal size paper. (Dennis L. Harrington)
  1237. ---------------
  1238.  
  1239.  
  1240. Changing Paper Bins:
  1241.  
  1242. The following is a routine to change paper bins between pages on a laser printer
  1243. (Dennis L. Harrington):
  1244.  
  1245. In Global Module:
  1246.   DefInt A-Z
  1247.   Type BinInfo
  1248.     BinNumber as Integer
  1249.     nBins     as Integer
  1250.     res       as string*8
  1251.   End Type
  1252.   Declare Function Escape Lib "GDI" (ByVal hDc%, ByVal nEscape%,
  1253.                   ByVal nCount%, Indata as Any, OutData as Any) as Integer
  1254.   Global Const GETSETPAPERBINS = 29
  1255.  
  1256. Code for changing the paper bin:
  1257.   Dim BinIn as BinInfo
  1258.   BinIn.BinNumber = {desired bin number} or &H8000
  1259.     'NOTE: You must enter the appropriate bin number for the printer in use.
  1260.     'On a NEC LC890 for example, the top bin is 1 and the bottom bin is 3.
  1261.     'Using "or &H8000" makes the change immediate for the next page.
  1262.     'Omit "or &H8000" and the change does not occur till the next print job.
  1263.   e% = Escape(printer.hDC, GETSETPAPERBINS, 12, BinIn, 0&)
  1264.  
  1265. Code for reading current paper bin status
  1266.    Dim BinOut as BinInfo
  1267.    e% = Escape(Printer.hDc, GETSETPAPERBINS, 12, 0&, BinOut)
  1268.    Current_Bin_Num% = BinOut.BinNumber
  1269.    Num_Available_Bins% = BinOut.nBins
  1270.  
  1271. Note:
  1272. The value for BinNumber is a printer-dependent value. For example, on an NEC
  1273. LC890 in postscript mode, BinNumber = 1 uses the upper bin and BinNumber = 3
  1274. LaserJet IID, BinNumber = 0 uses the upper bin and BinNumber = 1 uses the lower
  1275. bin. Thus, you need to figure out which BinNumber relates to which tray for the
  1276. printer and use those numbers.
  1277. ---------------
  1278.  
  1279.  
  1280. EndDoc Makes Temp Files:
  1281.  
  1282. When you do EndDoc, VB makes a NEW temporary file for the new page. So if you
  1283. use NewPage to do page ejects, say for printing 1500 labels, then you get 1500
  1284. temporary print files!
  1285. ---------------
  1286.  
  1287.  
  1288. EndDoc vs NewPage:
  1289.  
  1290. Use NewPage between pages (if required) and EndDoc at the end of the print. This
  1291. will keep another app from printing in the middle of a long printout. There is
  1292. NO need to put NewPage just before the EndDoc.
  1293.  
  1294. Put DoEvents in your print routine. This will let other apps print, but they
  1295. still won't break up your document. The Windows print buffer and print manager
  1296. are smart enough to know to keep documents together. (Jack Presley)
  1297. ---------------
  1298.  
  1299. Font Not Available on Printer:
  1300.  
  1301. If your VB app uses a font that is not available on a user's printer, the next
  1302. closest font (based on size) will be used instead.  (Robert Eineigl, MS)
  1303. ---------------
  1304.  
  1305.  
  1306. Formfeed Problems:
  1307.  
  1308. I am writing a label printing routine in VB, and in order to align the labels,
  1309. I want to be able to print only one test label. The problem I am seeing is
  1310. that the label won't print until I either close the program completely, or
  1311. send a Printer.NewPage or Printer.EndDoc. However, both of these force a page
  1312. feed (11 inch type) which wastes the next 10 labels. How can I close the Print
  1313. Manager file to force a printout of only 3 lines?
  1314.  
  1315. ---------------
  1316.  
  1317.  
  1318. Getting Available Font Sizes:
  1319.  
  1320. If using PostScript, TrueType, ATM or other scalable fonts, then any size is
  1321. available.
  1322.  
  1323. For raster (fixed-size) fonts, you can use the following:
  1324.  
  1325. For i% = 1 To 30
  1326.   FontSize = i%
  1327.   If FontSize <> LastFontSize Then
  1328.     Print FontSize
  1329.     LastFontSize = FontSize
  1330.   End If
  1331. Next
  1332.  
  1333. This will show you the font sizes that windows will *produce* for you. Note:
  1334.   o  this is NOT the list of exact fonts available
  1335.   o  you *could* miss some sizes here, so if you need more
  1336.         precision then loop with something like For i! = .5 To 30 Step .5
  1337. ---------------
  1338.  
  1339.  
  1340. Getting List of Installed Printers:
  1341.  
  1342. buf$ = String$(2048, 0)
  1343. BufSize% = len(buf$)
  1344. y% = GetProfileString("devices", ByVal 0&, "Error", buf$, BufSize%)
  1345.  
  1346. You'll need to parse through buf$ to find all of the printers. Chr$(0) will
  1347. delimit each printer entry.
  1348. ---------------
  1349.  
  1350.  
  1351. Getting Printer Settings:
  1352.  
  1353. DefInt A-Z
  1354. Type DEVMODE
  1355. DeviceName As String * 32
  1356. SpecVersion As Integer
  1357. DriverVersion As Integer
  1358. Size As Integer
  1359. DriverExtra As Integer
  1360. members As Long
  1361. Orientation As Integer
  1362. PaperSize As Integer
  1363. PaperLength As Integer
  1364. PaperWidth As Integer
  1365. Scale As Integer
  1366. Copies As Integer
  1367. DefaultSource As Integer
  1368. PrintQuality As Integer
  1369. Color As Integer
  1370. Duplex As Integer
  1371.  
  1372. For Win 3.1:
  1373. ''''''''''''
  1374. Declare Function ResetDC Lib "GDI" (ByVal HDC, lpDevMode As DEVMODE)
  1375.  
  1376. Sub Command1_Click ()
  1377.   Dim OrientBuff As DEVMODE
  1378.   OrientBuff.Orientation = 2
  1379.   OrientBuff.members = 1
  1380.   OrientBuff.SpecVersion = &H300
  1381.   OrientBuff.DeviceName = "HP LaserJet Series II"
  1382.   OrientBuff.Size = Len(OrientBuff)
  1383.   ApiErr = ResetDC(Printer.hdc, OrientBuff)
  1384.   Debug.Print ApiErr, Printer.hdc
  1385.   For ncount = 1 To 5
  1386.     printer.Print String$(30, Chr$(64 + ncount))
  1387.   Next
  1388.   Printer.EndDoc
  1389. End Sub
  1390.  
  1391. For Win 3.0:
  1392. ''''''''''''
  1393. Declare Function escape Lib "gdi" (ByVal HDC As Integer,
  1394.         ByVal nEscape As Integer, ByVal ncount As Integer,
  1395.         lpInData As Any, lpoutdata As Any) As Integer
  1396.  
  1397. Sub Form_Click ()
  1398.   Dim RtnCode As Integer
  1399.   Dim ncount As Integer
  1400.   Static Orient(0 To 4) As Long
  1401.   Orient(0) = 2
  1402.   RtnCode = escape(printer.HDC, 30, 10, Orient(0), 0&)
  1403.   For ncount = 1 To 5
  1404.       printer.Print String$(30, Chr$(64 + ncount))
  1405.   Next
  1406.   printer.EndDoc
  1407. End Sub
  1408. (Tony G. Strain)
  1409. ---------------
  1410.  
  1411.  
  1412. Landscape Setting on HPLJ:
  1413.  
  1414. The following code lets you change a LaserJet to landscape mode.
  1415. (From Dennis L. Harrington)
  1416.  
  1417. GLOBAL:
  1418.   Type ORIENT
  1419.     Orientation as Long
  1420.     Pad as string * 16
  1421.   End Type
  1422.   Declare Function PrtOrient% Lib "GDI" Alias "Escape" (ByVal hDc%,
  1423.                                                         ByVal nEsc%,
  1424.                                                         ByVal nLen%,
  1425.                                                         lpData as ORIENT,
  1426.                                                         lpOut as Any)
  1427.   Global prtO as Orient
  1428.  
  1429. Sub Form_Click
  1430.   prtO.Orientation = n  'n=1 for portrait or 2 for landscape
  1431.   x% = PrtOrient%(Printer.hDC, 30, len(prtO), prtO, 0&)
  1432.   Printer.EndDoc   '- required to make the change take effect immediately.
  1433.   'EndDoc usually generates a FormFeed, which would be unwanted here, but in
  1434.   'this case, coming right after the PrtOrinet line, it does not. Thanks to
  1435.   'John Kesler for pointing this out.
  1436.  
  1437.   Printer.Print "whatever text you want to print goes here"
  1438.   Printer.EndDoc    'This EndDoc does do a FF.
  1439. End Sub
  1440. ---------------
  1441.  
  1442.  
  1443. Laser Printer Margins:
  1444.  
  1445. The amount of margin (unprintable area) varies with different laser printers
  1446. and cartridges. One solution is to assume a larger than .25" margin. (George
  1447. Campbell)
  1448.  
  1449. Another solution is to use the Printer.ScaleWidth and Printer.ScaleHeight
  1450. properties instead of Printer.Width & Printer.Height for calculating printable
  1451. area. (Bryon Scott)
  1452.  
  1453. But be careful with these two properties, especially if you're setting
  1454. Printer.CurrentX and CurrentY. If you change these figures, you revert to the
  1455. User setting for ScaleMode, and that can throw your printing off. It's OK,
  1456. however, to read these properties. (George Campbell)
  1457.  
  1458. Sample code (Don Funk):
  1459.    Dim PageNo As String
  1460.    Header$ = "Yess"
  1461.    Printer.CurrentX = 0
  1462.    Printer.Print Date$;
  1463.    Printer.CurrentX = (Printer.ScaleWidth - Printer.TextWidth(Header$))
  1464.    Printer.CurrentX = Printer.CurrentX / 2
  1465.    Printer.Print Header$;
  1466.    PageNo = "Page: " + Format$(12, "###")
  1467.    Printer.CurrentX = Printer.ScaleWidth - Printer.TextWidth(PageNo)
  1468.    Printer.Print PageNo
  1469.    Printer.Print " "
  1470.    Printer.EndDoc
  1471. ---------------
  1472.  
  1473.  
  1474. LaserJet Driver Update:
  1475.  
  1476. The latest version of the LJ III printer driver is 3.86. There were a bunch of
  1477. bugs fixed in this version. It is available over in the HPPER forum LIBS on
  1478. CompuServe.
  1479. ---------------
  1480.  
  1481.  
  1482. LaserJet Lost Line Fixed:
  1483.  
  1484. Using the File menu Print command to print source code will truncate one line of
  1485. code per page of output when printing to a Hewlett-Packard (HP) LaserJet series
  1486. III printer using the HPPCL5A.DRV printer driver. This is a problem with the
  1487. Hewlett-Packard LaserJet series III printer driver version 3.42 for Windows.
  1488.  
  1489. Microsoft has confirmed this to be a problem with the HPPCL5A printer driver
  1490. version 3.42.
  1491.  
  1492. This problem was corrected by the HP III driver version 30.3.85 included with
  1493. Microsoft Word for Windows version 2.0.
  1494. ---------------
  1495.  
  1496.  
  1497. LaserJet Offset:
  1498.  
  1499. VB uses the whole page for figuring offsets, but the HP LaserJet driver, or
  1500. the printer itself, uses the printable area, which is about .25 less on each
  1501. side of the paper. You must allow for this when trying to place printing
  1502. precisely on the page with a LaserJet printer.
  1503. ---------------
  1504.  
  1505.  
  1506. Matching Printer & Screen Fonts:
  1507.  
  1508. Use an On Error Resume Next line before sending the printer font name stuff to
  1509. the screen. If you try to display a printer font for which there's no screen
  1510. equivalent, you'll get an Invalid Property Value error. If, however, you use
  1511. the On Error line to ignore the error, the Windows GDI will attempt it's very
  1512. best to display your font. It actually does a pretty good job, although it
  1513. won't be an accurate representation.
  1514.  
  1515. Same thing applies when setting FontSize, etc. for the printer. If you bypass
  1516. the setting with the On Error line, the printer will go ahead and print, but in
  1517. the font's default size.  It's sloppy programming, but it works.  Just be sure
  1518. to reset your error handling after doing this, or your program will crash
  1519. without a doubt, and you won't be able to spot your other errors.
  1520.  
  1521. With ATM, if a font family doesn't have a separate BOLD, ITALIC, or BOLD
  1522. ITALIC member, you can still print bold, italic and bold italic characters. I
  1523. believe it's the Windows GDI which takes care of that job, but I'm not
  1524. certain. The quality won't be as good as if you actually had the outlines
  1525. available, but it's not bad either. You should see Cooper Black in this fake
  1526. Boldfacing.  (George Campbell)
  1527. ---------------
  1528.  
  1529.  
  1530. Not Printing?:
  1531.  
  1532. If your print routines never make it to the printer, make sure you have done
  1533. the following:
  1534.  
  1535. 1. Make sure you send the Printer.EndDoc property at the end of the print job.
  1536. 2. If you are in a long print job, add "x = DoEvents ()" to allow the Windows
  1537.      Print Manager to get control.
  1538. 3. If you're using a PostScript printer, the Printer.EndDoc isn't enough.
  1539.      You need two lines:
  1540.         Printer.NewPage
  1541.         Printer.Enddoc
  1542.      Without that, you'll put your PS printer into a lock.  Don't put
  1543.      anything between the two commands, or you'll get a blank page.
  1544. ---------------
  1545.  
  1546.  
  1547. Number of Copies, Setting:
  1548.  
  1549. The following routine lets you set the number of copies to be printed:
  1550.  
  1551. Declare Function Escape% Lib "GDI" (ByVal hDC%,ByVal nEscape%,
  1552.                                     ByVal nCount%, lplnData As Any,
  1553.                                     lpOutData As Any)
  1554. Global Const SETCOPYCOUNT = 17
  1555.  
  1556. Sub Command1_Click ()
  1557.    Printer.Print ""
  1558.    NumCopies% = 3  'an example to print 3 copies
  1559.    ActualCopies% = 3
  1560.    X% = Escape%(Printer.hDC, SETCOPYCOUNT, Len(i%), NumCopies%, ActualCopies%)
  1561.    Printer.Print Text1.Text
  1562.    Printer.EndDoc
  1563. End Sub
  1564. ---------------
  1565.  
  1566.  
  1567. Printer Setup:
  1568.  
  1569. Declare Function LoadLibrary Lib "kernel" (Byval LibName$) As Integer
  1570. Declare Function FreeLibrary Lib "kernel" (hLib%) As Integer
  1571. Declare Function DeviceMode Lib "HPPCL.DRV" (hWnd%, hLib%, Dev$, Port$)
  1572.  
  1573. SUB Command1_Click ()
  1574.     hLib% = LoadLib% ("HPPCL.DRV")
  1575.     Result% = DeviceMode (hWnd, hLib%,"HP / PCL LaserJet","LPT1:")
  1576.     Result% = FreeLibrary (hLib%)
  1577. END SUB
  1578.  
  1579. Declare Function LoadLibrary Lib "KERNEL" (ByVal lpLibFileName$) As Integer
  1580. Declare Sub FreeLibrary Lib "KERNEL" (ByVal hLibModule%)
  1581.  
  1582. Then change PSetupMNU_Click to read:
  1583.  
  1584.  Sub PSetupMNU_Click ()
  1585.    RetStr$ = String$(256, 0)
  1586.    RetStrSize% = Len(RetStr$)
  1587.    x% = GetProfileString("windows", "device", "", RetStr$, RetStrSize%)
  1588.  
  1589.    i% = InStr(RetStr$, ",")
  1590.    If i% > 0 Then
  1591.      a$ = Left$(RetStr$, i% - 1)
  1592.      b$ = Right$(RetStr$, Len(RetStr$) - i%)
  1593.      j% = InStr(b$, ",")
  1594.        If j% > 0 Then
  1595.            DriverName$ = Left$(b$, j% - 1)
  1596.            PortName$ = Right$(b$, Len(b$) - j%)
  1597.        End If
  1598.    End If
  1599.  
  1600.    If Len(DriverName$) > 0 And Len(PortName$) > 0 Then
  1601.      LibHandle% = LoadLibrary("PSETUP.DLL")
  1602.         If LibHandle% >= 32 Then
  1603.           r% = DoPrinterSetup(Form1.hwnd, DriverName$, PortName$)
  1604.           FreeLibrary LibHandle%
  1605.           If Not r% Then MsgBox "Can't run Printer Setup", 64, "Printer Setup"
  1606.         End If
  1607.    Else
  1608.         MsgBox "No default printer selected", 64, "Printer Setup"
  1609.    End If
  1610.  End Sub
  1611. ---------------
  1612.  
  1613.  
  1614. Printer Control Codes:
  1615.  
  1616. The normal Print command in VB will not properly send printer control codes
  1617. through to the printer. Here is how to get around VB:
  1618.  
  1619. Open "LPT1" For Binary As #1  'note: no colon on LPT1
  1620. Put #1,,<put your control codes here>
  1621. Close #1
  1622. ---------------
  1623.  
  1624.  
  1625. Printer Wordwrap:
  1626.  
  1627. The following shows how to print text to a printer/form using the line
  1628. wrapping built into a Text box. By calling the API calls, you can printout
  1629. individual lines of text to the form/printer. You only have to add the
  1630. CurrentX/CurrentY to control the location of the print out. This example will
  1631. need one Text box and one Command button. Make sure that you set the
  1632. CurrentX/Y to some location on the form that isn't being covered up by the
  1633. Text box or Command control.
  1634.  
  1635. Declare Function GetFocus% Lib "user" ()
  1636. Declare Function SendMessage% Lib "user" (ByVal hWnd%, ByVal wMsg%,
  1637.                                           ByVal wParam%, ByVal lParam As Any)
  1638.  
  1639. Sub Command1_Click ()
  1640.   Dim i As Long
  1641.   CurrentY = 1000
  1642.   NumberOfLines = GetLineCount(Text1)
  1643.   For i = 0 To NumberOfLines
  1644.      Form1.CurrentX = 1000
  1645.      Print LineOftext$(Text1, i)
  1646.   Next i
  1647. End Sub
  1648.  
  1649. Function LineOftext$ (TextBox As Control, LineNumber As Long)
  1650.   '* This function copies a line of text specified by LineNumber
  1651.   '* from the edit control. The first line starts at zero.
  1652.    Const MAX_CHAR_PER_LINE = 80
  1653.    Const EM_GETLINE = &H414
  1654.    TextBox.SetFocus
  1655.    Buffer$ = Space$(MAX_CHAR_PER_LINE)
  1656.    API_Error% = SendMessage(GetFocus(), EM_GETLINE, LineNumber, Buffer$)
  1657.    LineOftext$ = Buffer$
  1658. End Function
  1659.  
  1660. Function GetLineCount& (TextBox As Control)
  1661.  '* This function will return the number of lines in the edit
  1662.  '* control.
  1663.    Const EM_GETLINECOUNT = &H40A
  1664.    TextBox.SetFocus
  1665.    Pos% = SendMessage(GetFocus(), EM_GETLINECOUNT, 0&, 0&)
  1666.    aGetLineCount.Caption = "GetLineCount = " + Str$(Pos%)
  1667.    fGetLineCount = Pos%
  1668. End Function
  1669. ---------------
  1670.  
  1671.  
  1672. Printing Forms:
  1673.  
  1674. In VB's File menu, there is a Print option for printing forms and code. On an
  1675. HPLJ, the top of forms will be cut off because VB/Windows tries to print in
  1676. the top-most part of the page, which is, of course, unusable on an HPLJ.
  1677.  
  1678. MS acknowledges the problem but has no solution other than printing to disk
  1679. and then using another program to print the disk file. Also see LaserJet Lost
  1680. Line Fixed, above.
  1681. ---------------
  1682.  
  1683.  
  1684. Printing Problems:
  1685.  
  1686. Fm: George Campbell
  1687.  
  1688. 1. The StretchBlt and BitBlt tools don't work on Postscript printers.
  1689.  
  1690. 2. Also, the same tools fail to work with ICO or WMF files. The images appear
  1691. on the screen, but will not print.
  1692. ---------------
  1693.  
  1694.  
  1695. ScaleLeft Errors:
  1696.  
  1697. You have to be careful with ScaleLeft and the other similar properties. If you
  1698. set them at runtime, your ScaleMode reverts to the User setting. What this means
  1699. is that setting any of those properties destroys your original ScaleMode
  1700. settings.
  1701.  
  1702. The documentation on this subject is a disaster. I spent almost an entire day
  1703. fooling with those properties, only to give up trying to use them for setting
  1704. margins on the Printer object.
  1705.  
  1706. Probably the best option is to treat ScaleLeft, etc. as read-only at runtime.
  1707. (George Campbell)
  1708. ---------------
  1709.  
  1710.  
  1711. Sending Raw Data to the Printer:
  1712.  
  1713. Using the PASSTHROUGH Escape function, one *should* be able to print raw data
  1714. on a printer. There has been some discussion about some Postscript drivers not
  1715. supporting the PASSTHROUGH Escape. I don't know. The PASSTHROUGH is kind of
  1716. tricky because of the info required to pass in the string to print. This
  1717. should work...
  1718.  
  1719. 'Declaration section
  1720. Declare Function Escape Lib "GDI" (ByVal hDC As Integer, ByVal nEscape As_
  1721.   Integer, ByVal nCount As Integer, lplnData As Any, lpOutData As Any) As_
  1722.   Integer  ' all on one line
  1723. Const PASSTHROUGH = 19
  1724.  
  1725. String2Pass$ = "This is the string to print."
  1726. InData$ = Chr$(len(String2Pass$) Mod 256) + Chr$(Len(String2Pass$) \ 256)
  1727. InData$ = InData$ + String2Pass$
  1728. Printer.Print " "; ' If you've already printed since last EndDoc, this isn't
  1729.                    '  necessary.
  1730. Result% = Escape(Printer.hDC, PASSTHROUGH, Len(InData$), InData$, 0&)
  1731. Debug.Print Result% ' length of string actually passed to printer.
  1732. Printer.EndDoc
  1733.  
  1734. The calculation to set the first two bytes of InData$ is simpler than it
  1735. looks. The first byte is the low byte of the string length to send. If it's
  1736. less than 256 you can just set it to the Chr$(Len(String2Pass$)) + Chr$(0).
  1737. The high byte would be used if it's longer than 255. (Jack Presley)
  1738. ---------------
  1739.  
  1740.  
  1741. "Printer.TextHeight" Does Formfeed:
  1742.  
  1743. Q: The code "X = Printer.TextHeight("Sample")" causes Print Manager to open,
  1744. and after exiting the VB program, my printer does a form feed. All I want to
  1745. do is set a variable to the TextHeight, but it ejects a piece of paper. (Paul
  1746. Davison)
  1747.  
  1748. A1: In the file EndPrn (see program listings at the end of this file) is a
  1749. method of cancelling a print job. Use this routine to cancel the blank page.
  1750. It takes about half a second. (George Campbell)
  1751.  
  1752. A2:
  1753. Global:
  1754. DefInt A-Z
  1755. Const ABORTDOC=2, Const NULL = 0&
  1756. Declare Function Escape Lib "GDI" (ByVal hDC, ByVal nEscape, ByVal nCount,
  1757.                                    lplnData As Any, lpOutData As Any)
  1758. Form:
  1759. DefInt A-Z
  1760. ...
  1761. printer.scalewidth = 3000
  1762. hite& = printer.TextHeight("I")
  1763. wit& = printer.TextWidth("I")
  1764. Print "hite& "; hite&
  1765. Print "wit& "; wit&
  1766. x% = Escape(printer.hDC, ABORTDOC, NULL, NULL, NULL)
  1767. Print "ABORT"; x%
  1768.  
  1769. The above code worked on PostScript and PCL laser printers. On the PS printer,
  1770. ending caused a "Printer Error" in VB, and that error plus "Can't Quit At This
  1771. Time" error (which nonetheless allowed me to quit after hitting OK) when
  1772. compiled. (Robert Eineigl, MS)
  1773. ---------------
  1774.  
  1775.  
  1776. TextWidth Improvement:
  1777.  
  1778. The following function beats the TextWidth method all to heck. It returns the
  1779. width to 1/1000th of a point with complete accuracy, is device independent,
  1780. accepts very long strings, doesn't initialize the Print Manager, and doesn't
  1781. send a header to the printer. (Walt Wooton)
  1782.  
  1783. Declare Function GetTextExtent Lib "GDI" (ByVal hDC%,
  1784.                                           ByVal lpString$,
  1785.                                           ByVal nCount%) As Long
  1786.  
  1787. Function WidthOfText (text$) As Single
  1788.   r% = GetDeviceCaps%(Printer.hDC, 52)
  1789.   s% = Printer.FontSize
  1790.   Printer.FontSize = 1000
  1791.   Maxchars& = Int(65535 / (r% / 72) / 1000)
  1792.   length% = Len(text$)
  1793.   j% = Abs(Int(length% / Maxchars&))
  1794.   For k% = 0 To j%
  1795.     textpart$ = Mid$(text$, 1 + (Maxchars& * k%), Maxchars&)
  1796.     i& = GetTextExtent(Printer.hDC, textpart$, Len(textpart$))
  1797.     a& = 65535 And i&
  1798.     b& = b& + a&
  1799.   Next k%
  1800.   Printer.FontSize = s%
  1801.   WidthOfText = CInt(b& * (72 / r%)) * .001 * s%
  1802. End Function
  1803. ---------------
  1804.  
  1805.  
  1806. Background for VB:
  1807.  
  1808. Many people have complained about VB not having a background and that seeing
  1809. the Program Mangaer and/or wallpaper in the background is distracting.
  1810.  
  1811. One work-around would be to compile a simple VB app with a form that fills the
  1812. screen up to the space at the top where the VB menu bar appears. Have this app
  1813. shell to VB to get it going.
  1814.  
  1815. An alternative to having a full-screen form would be to have an app that
  1816. minimizes the Program Manager and uses the routine in this file to load a
  1817. blank wallpaper file (a BMP which you can easily create with Paintbrush) and
  1818. then shell to VB.
  1819. ---------------
  1820.  
  1821.  
  1822.  
  1823. Color Const Declarations:
  1824.  
  1825. The following are VB Global Const definitions for the 48 default colors on the
  1826. palette. The constant definitions correspond to the color palette when viewing
  1827. the palette from top-to-bottom and left-to-right.  (Steve Schmidt)
  1828.  
  1829. Global Const Black0 = &HFFFFFF
  1830. Global Const Black2 = &HC0C0C0
  1831. Global Const Black3 = &H808080
  1832. Global Const Black1 = &HE0E0E0
  1833. Global Const Black4 = &H404040
  1834. Global Const Black5 = &H0&
  1835. Global Const Red0 = &HC0C0FF
  1836. Global Const Red1 = &H8080FF
  1837. Global Const Red2 = &HFF&
  1838. Global Const Orange0 = &HC0E0FF
  1839. Global Const Orange1 = &H80C0FF
  1840. Global Const Orange2 = &H80FF&
  1841. Global Const Yellow0 = &HE0FFFF
  1842. Global Const Yellow1 = &H80FFFF
  1843. Global Const Yellow2 = &HFFFF&
  1844. Global Const Green0 = &HC0FFC0
  1845. Global Const Green1 = &H80FF80
  1846. Global Const Green2 = &HFF00&
  1847. Global Const Cyan0 = &HFFFFC0
  1848. Global Const Cyan1 = &HFFFF80
  1849. Global Const Cyan2 = &HFFFF00
  1850. Global Const Blue0 = &HFFC0C0
  1851. Global Const Blue1 = &HFF8080
  1852. Global Const Blue2 = &HFF0000
  1853. Global Const Magenta0 = &HFFC0FF
  1854. Global Const Magenta1 = &HFF80FF
  1855. Global Const Magenta2 = &HFF00FF
  1856. Global Const Red3 = &HC0&
  1857. Global Const Red4 = &H80&
  1858. Global Const Red5 = &H40&
  1859. Global Const Orange3 = &H40C0&
  1860. Global Const Orange4 = &H4080&
  1861. Global Const Orange5 = &H404080
  1862. Global Const Yellow3 = &HC0C0&
  1863. Global Const Yellow4 = &H8080&
  1864. Global Const Yellow5 = &H4040&
  1865. Global Const Green3 = &HC000&
  1866. Global Const Green4 = &H8000&
  1867. Global Const Green5 = &H4000&
  1868. Global Const Cyan3 = &HC0C000
  1869. Global Const Cyan4 = &H808000
  1870. Global Const Cyan5 = &H404000
  1871. Global Const Blue3 = &HC00000
  1872. Global Const Blue4 = &H800000
  1873. Global Const Blue5 = &H400000
  1874. Global Const Magenta3 = &HC000C0
  1875. Global Const Magenta4 = &H800080
  1876. Global Const Magenta5 = &H400040
  1877. ---------------
  1878.  
  1879.  
  1880. Displaying "ASCII Graphics":
  1881.  
  1882. In February 1992's Inside Visual Basic, we printed some code that let's you
  1883. output text using the OEM character set (aka extended ASCII characters):
  1884.  
  1885. DefInt A-Z
  1886. Declare Function GetStockObject Lib "GDI" (ByVal nIndex)
  1887. Declare Function SelectObject Lib "GDI" (ByVal hDC, ByVal hObject)
  1888.  
  1889. SaveScaleMode = Form1.ScaleMode
  1890. Form1.ScaleMode = 3 'Set to Pixel
  1891.  
  1892. nIndex = 10 'OEM-dependent fixed font
  1893. hObject = GetStockObject(nIndex)
  1894.  
  1895. SavedObject = SelectObject(Form1.hDC, hObject)
  1896. For i = 0 to 4
  1897.   For j = 1 to 51
  1898.     Print Chr$(j*51+i);
  1899.   Next
  1900.   Print
  1901. Next
  1902. Form1.ScaleMode = SavedScaleMode
  1903.  
  1904. I put these instructions into Form1's Click event procedure for testing. If you
  1905. want to use them elsewhere, you'll need the hDC% for that item.
  1906. (Blake Ragsdell, Inside Visual Basic)
  1907. ---------------
  1908.  
  1909.  
  1910. Framing Controls (the NEXT Look):
  1911.  
  1912. The following routine adds shading around your controls that gives the look of
  1913. depth to them. Put this routine in a Module and you can call it from any Form.
  1914.  
  1915. Note that this routine puts the shadow on the top and left edges of the
  1916. "recessed box". This is done to match the lighting pattern on the VB buttons.
  1917. Also, the bottom and right edges are drawn first so that the dark edges will
  1918. be drawn over the light edges at the corners to create a natural shadow
  1919. effect.
  1920.  
  1921. DefInt A-Z
  1922. Sub Frame (C As Control)
  1923.   Offset = 20  'try experimenting with this value and the next
  1924.   Screen.ActiveControl.DrawWidth = 3
  1925.   Screen.ActiveControl.forecolor = &HE0E0E0 'you may have to try different color combo's
  1926.   'bottom:
  1927.   Screen.ActiveControl.Line (C.Left, C.Top + C.Height + Offset)
  1928.                            -(C.Left + C.Width, C.Top + C.Height + Offset)
  1929.   'right:
  1930.   Screen.ActiveControl.Line (C.Left + C.Width + Offset, C.Top)
  1931.                            -(C.Left +C.Width +Offset, C.Top +C.Height +Offset)
  1932.   Screen.ActiveControl.forecolor = &H808080
  1933.   'top:
  1934.   Screen.ActiveControl.Line (C.Left - Offset * 1.5, C.Top - Offset * 1.5)
  1935.                            -(C.Left +C.Width +Offset *1.5, C.Top -Offset *1.5)
  1936.   'left:
  1937.   Screen.ActiveControl.Line (C.Left - Offset * 1.5, C.Top - Offset * 1.5)
  1938.                            -(C.Left - Offset * 1.5, C.Top + C.Height + Offset)
  1939. End Sub
  1940.  
  1941. (In Form1, for example:)
  1942. Sub Form_Paint
  1943.   Call Frame(Label1)
  1944.   Call Frame(Text1)
  1945.   Call Frame(List1)
  1946.   Call Frame(Drive1)
  1947.   Call Frame(Dir1)
  1948.   Call Frame(File1)
  1949.   (etc)
  1950. End Sub
  1951.  
  1952. Bonus tip: If you have a row of buttons, put them inside a Picture box. (You
  1953. must draw the button inside the box. You cannot double-click or drag the
  1954. button into the Picture box.)
  1955.  
  1956. Set the Picture box's BackColor to the same as the Forms and the Border to
  1957. none. Now use the routine above to put a frame around the Picture box to make
  1958. it look like the buttons are in a recessed panel.
  1959. ---------------
  1960.  
  1961.  
  1962. "Painting" Not Finishing:
  1963.  
  1964. Changes to forms, etc, may not show up as soon as you might wish if the
  1965. program is involved in heavy processing. To get the changes to show up
  1966. on the screen right away, use .REFRESH, such as List1.Refresh.
  1967. ---------------
  1968.  
  1969.  
  1970. Resolution, Determining:
  1971.  
  1972. The following code returns the dots-per-inch resolution of the display:
  1973.  
  1974. Global (all on one line):
  1975.  
  1976. Declare Function GetDeviceCaps Lib "GDI" (ByVal hDC As Integer,
  1977.                              ByVal nIndex As Integer) As Integer
  1978.  
  1979. Form1_Load:
  1980.   xDPI% = GetDeviceCaps(Form1.hDC, 88)
  1981.  
  1982. This is suffficient for VGA, S-VGA and 8514-A because those resolutions have
  1983. "Square" screen metrics.  I.E. 96X96 DPI or 120X120 DPI.  CGA and EGA, on the
  1984. other hand, use metrics which are not square...CGA is 96X48, EGA is 96X72.  If
  1985. you want to appropriately scale for these resolutions you will need to
  1986. determine the yDPI as well...
  1987.  
  1988.   yDPI% = GetDeviceCaps(Form1.hDC, 90)
  1989.  
  1990. (Bob Scherer)
  1991. ---------------
  1992.  
  1993.  
  1994. Screen/Window Capture:
  1995.  
  1996. PrtSc captures the whole Windows 3 screen to the clipboard. Alt-PrtSc captures
  1997. the contents of the active window to the clipboard.
  1998.  
  1999. For better screen grey scales, load the monochrome display driver first.
  2000. (Jonathan Zuck)
  2001.  
  2002. The shareware program Paint Shop Pro is an easy way to save captured screens
  2003. to disk in a wide variety of graphics formats. From PsL, order disk #3388.
  2004. ---------------
  2005.  
  2006.  
  2007. Screen Scaling/Form Resizing:
  2008.  
  2009. You're on your own in terms of rescaling your forms and controls for different
  2010. resolution screens.  Your best bet is to either design exclusively for 640x480
  2011. screens (though there are people with 640x350 EGA screens), or to have your
  2012. program use the Screen.ScaleWidth/ScaleHeight values and adjust your forms
  2013. appropriately by using percentages of the screen for sizing instead of an
  2014. absolute number of Twips.
  2015.  
  2016. All of the VB scale modes use that wonderful and totally baffling item, the
  2017. "logical inch." A logical inch is defined as an inch as written on paper and not
  2018. on the screen. Thus, all VB scale modes are relative to how big it prints and
  2019. not the video resolution of the screen. As such, twips are not "Physical" units
  2020. of measure with video output, but relative units. This is why forms change
  2021. relative size as you change video resolution.
  2022.  
  2023. As an example, a line of text which is 1" long when PRINTED is 72 points or 1440
  2024. twips. In std vga mode, the screen width is 7680 twips while in 1024x768 hi-res,
  2025. the screen width is 12,288 twips (Assuming you use the same system fonts). In
  2026. VGA, this 1" line of text takes 19% of the screen width to display and in 1024,
  2027. it only takes 12% of the screen width. Thus, this line of text will physically
  2028. change relative size between video resolutions while still being 1" long when
  2029. printed.
  2030.  
  2031. More Input:
  2032.  
  2033.    The physical size of the monitor isn't what's important. It's the actual
  2034. pixel resolution of the monitor that determines how a form or control displays
  2035. on the monitor. I've got a 5D at work and a 4D at home. When in the same
  2036. resolution, a form occupies the same relative area of the screen on both. It's
  2037. when I change resolution from 1024 to 640 that big changes occur.
  2038.    As for twips, they are perfectly consistent -- but on the printer and not
  2039. the screen. Any object 1440 twips wide will print exactly 1" wide. How wide
  2040. 1440 twips is on the screen changes with video resolution.
  2041.  
  2042. More:
  2043.  
  2044. Think in percentages, rather than in terms of absolute measurements. No matter
  2045. what your screen resolution, you can simply make each control's position and
  2046. size a percentage of Screen.Width and Height.
  2047.  
  2048. Form1.Left = Screen.Width * .25
  2049. Form1.Top = Screen.Height * .1
  2050. Form1.Width = Screen.Width * .5
  2051. Form1.Height = Screen.Height *.5
  2052.  
  2053. That's the basic structure of the thing. Font scaling and other items can also
  2054. use the same concept, and your app will look the same no matter what
  2055. resolution your user chooses. (George Campbell)
  2056.  
  2057. Also see the ICONWRKS code (comes with VB) for illustrative code.
  2058. ---------------
  2059.  
  2060.  
  2061. Screen Scaling Tips:
  2062.  
  2063. Here are two pointers if you want to be able to Resize your forms:
  2064.  
  2065. One: Group your controls onto frames or pictures. It is vastly simpler to hide,
  2066. show and move things around if they're in a common control like a frame or
  2067. picture box.
  2068.  
  2069. When I resize a form, I have routines to move the two or three 'container'
  2070. controls; I then call separate subs to resize/reposition the CONTENTS of each of
  2071. those controls if required. It sounds like more code, but it actually ends up
  2072. taking less code and being faster. You do pay a slight memory cost with the
  2073. added control, but the speed increase is worth it.
  2074.  
  2075. (2) To avoid recursion, use a flag in the Resize routine:
  2076.  
  2077.      Sub Form_Resize
  2078.        If AlreadySizing Then Exit Sub
  2079.        AlreadySizing = -1
  2080.        'Code to move controls, etc. goes here.
  2081.        AlreadySizing = 0
  2082.      Exit Sub
  2083.  
  2084. Set the AlreadySizing flag anytime you want to make adjustments to the form size
  2085. without calling the control-moving routines. (Barry Seymour)
  2086. ---------------
  2087.  
  2088.  
  2089. Screen Type:
  2090.  
  2091. z = Screen.Height
  2092. If z = 6000 Then
  2093.   Type$="CGA"
  2094. ElseIf z = 7000 Then
  2095.   Type$ = "EGA"
  2096. ElseIf z > 7000 Then
  2097.   Type$ = "VGA or Better"
  2098. End if
  2099.  
  2100. There's another way to do this, calling GetDeviceCaps to find out the vertical
  2101. resolution; but the above method is a lot easier... BTW, if you want to know
  2102. if it is exactly VGA, not "or better" (i.e., better than 640x480), the number
  2103. for that 7200 if memory serves...
  2104. ---------------
  2105.  
  2106.  
  2107. Screen Wipes:
  2108.  
  2109. You can "draw a curtain" over the screen as follows:   (Don Funk)
  2110.    CONST RESOLUTION = 768   '1024 X 768 in this example
  2111.    For i = 1 to RESOLUTION
  2112.       LINE (i,1)-(i,1024)
  2113.    Next i
  2114. ---------------
  2115.  
  2116.  
  2117. Stop Flashing During Updates:
  2118.  
  2119. Set an object's Visible property to 0 during updates to speed up the process
  2120. and to stop the screen from flashing caused by each update being written to
  2121. the screen. (Set it back to -1 when the update is done, of course.)
  2122. ---------------
  2123.  
  2124.  
  2125. Suppress Arrow Cursor:
  2126.  
  2127. The problem with creating a custom mouse pointer is that VB constantly resets
  2128. it to the arrow shape. The following routine overcomes that problem. (Gregg
  2129. Morris)
  2130.  
  2131. DefInt A-Z
  2132. Declare Function ShowCursor Lib "User" (ByVal bShow)
  2133. Declare Function SetCursor Lib "User" (ByVal hCursor)
  2134. Declare Function LoadCursor Lib "User" (ByVal hInstance,
  2135.                                         ByVal lpCursorName As Any)
  2136. Declare Function GetClassWord Lib "User" (ByVal hWnd, ByVal nIndex)
  2137. Declare Function SetClassWord Lib "User" (ByVal hWnd, ByVal nIndex,
  2138.                                           ByVal nNewWord)
  2139. Global Const IDC_CROSS = 32515&
  2140. Global Const IDC_WAIT = 32514&
  2141. Global Const IDC_ICON = 32641&
  2142. Global Const GCW_HCURSOR = (-12)
  2143. Global Const IDC_ARROW = 32512&
  2144.  
  2145. Sub Text1_LostFocus ()
  2146.   hCursor = LoadCursor(0&, IDC_ICON)
  2147.   h1 = SetCursor(hCursor)
  2148.   h2 = ShowCursor(1)
  2149.   oldcur = GetClassWord(Form1.hWnd, GCW_HCURSOR)
  2150.   newcur = SetClassWord(Form1.hWnd, GCW_HCURSOR, hCursor)
  2151. End Sub
  2152.  
  2153. Sub Text2_LostFocus ()
  2154.   hCursor1 = LoadCursor(0&, IDC_ARROW)
  2155.   h2 = SetCursor(hCursor)
  2156.   h2 = ShowCursor(1)
  2157.   oldcur1 = GetClassWord(Form1.hWnd, GCW_HCURSOR)
  2158.   newcur1 = SetClassWord(Form1.hWnd, GCW_HCURSOR, hCursor1)
  2159. End Sub
  2160.  
  2161. The limitation of this approach is that when you set the class cursor you are
  2162. changing the cursors for every window in that class.  Thus changing the cursor
  2163. for one text box promptly changes it for every text box. (Daniel Appleman)
  2164. ---------------
  2165.  
  2166.  
  2167. Testing for 256-Color Display:
  2168.  
  2169. You need to call GetDeviceCaps to check the RASTERCAPS value and the bit within
  2170. it known as RC_PALETTE.  In order for a vid card to display 256 or more colors
  2171. it needs to support palettes, which is what this bit will reflect.  I'll leave
  2172. it to you to figure out the API call. (Steve Cramp)
  2173. ---------------
  2174.  
  2175.  
  2176. Twips to Pixels:
  2177.  
  2178. Here is a routine for converting twips to pixel.
  2179.  
  2180. Form1 Declarations:
  2181.   Const PIXEL = 3
  2182.   Const TWIP = 1
  2183.  
  2184. Sub Form_Click ()
  2185.    Print "Form Left = "; Twips_To_Pixel(Left)
  2186. End Sub
  2187.  
  2188. Function Twips_To_Pixel& (ByVal N&)
  2189.   ScaleMode = TWIP
  2190.   Scale_Twip = ScaleWidth
  2191.   ScaleMode = PIXEL
  2192.   Scale_Pixel = ScaleWidth
  2193.   Twips_To_Pixel = Scale_Pixel / Scale_Twip * Left
  2194. End Function
  2195. ---------------
  2196.  
  2197.  
  2198. Windows is Device Independent - NOT!:
  2199.  
  2200. A form that you carefully lay out on your monitor can look substantially
  2201. different on other systems' video. John Socha has a full article about this in
  2202. the July 1992 issue of WinTech magazine, so I don't think the problem can be
  2203. fully treated here in VB-Tips.
  2204.  
  2205. The tips in this section can help, but the best bet is to test your program
  2206. on a wide variety of monitors and card types.
  2207. ---------------
  2208.  
  2209.  
  2210. Breakpoints Change Processing:
  2211.  
  2212. Putting a breakpoint ("Stop") in your code can change the way your application
  2213. executes. For example, when you press a key while your app is running, the
  2214. processing normally goes to KeyDown and then to KeyPress.
  2215.  
  2216. If you put a Stop in KeyDown or if you single-step through KeyDown, processing
  2217. will not continue on to KeyPress. The same type of thing happens in other
  2218. situations where a breakpoint has been added.
  2219. ---------------
  2220.  
  2221.  
  2222. Code Should Go In Modules:
  2223.  
  2224. In general, code in modules is less of drag on performance than code in forms;
  2225. therefore, you should consider putting as much code as possible into modules.
  2226. (Robert Eineigl, Microsoft Product Support)
  2227.  
  2228. (1) Module code is more efficient in terms of memory usage and is
  2229.     initialized only one time (i.e., when it is first loaded--although
  2230.     local module variables will be initialized each time the function
  2231.     is called).
  2232.  
  2233. (2) Form code is not unloaded, but is apparently initialized each time
  2234.     the form associated with it is reloaded (a little paradox there).
  2235.  
  2236. (3) Static variables are really static, no matter where they appear.
  2237.  
  2238. (4) It is generally better to put non-event functions into modules.
  2239.  
  2240. (5) It is efficient to unload forms (actually all that really gets
  2241.     unloaded is the display component of the form, which is all that
  2242.     really needs to be unloaded -- more or less).
  2243.  
  2244. (6) it is OK to put DLL defines in any module and the effect is the same
  2245.     as putting them in the global module.  (J.D. Evans, Jr.)
  2246.  
  2247. Variables Dim-ed at the general declarations level persist but variables just
  2248. Dim-ed (as opposed to Static) in a sub are stack variables and thus gone if
  2249. the form is unloaded. (Robert Eineigl)
  2250. ---------------
  2251.  
  2252.  
  2253. .EXE Size / Junk In EXE's:
  2254.  
  2255. 1. Long variable names increase EXE size.
  2256. 2. Comments add a couple of bytes per each comment line to EXE size.
  2257. 3. A Global DIM of an array adds to EXE size.
  2258.    For example:
  2259.      Global Sample as String*20000
  2260.    will add about 20k to the size of the EXE file, but the same DIM
  2261.    in a Form will not.
  2262. 4. VB "accumulates" variable names and other junk that it does not let go
  2263.     of when you delete and save. This can make your EXE file get larger with
  2264.     each compilation. Here is how to solve the problem (repeat for each form):
  2265.     a. Select "Code" on the VB menu.
  2266.     b. Select "Save Text" and save.
  2267.     c. Select "Load Text" and click the Replace button, then load what you
  2268.          just saved.
  2269.     To get the maximum size reduction, exit and restart VB before step c.
  2270.     Note that to Load the text back in, you must be viewing the code window
  2271.       to which you wish to load the code.
  2272.  
  2273. Microsoft's Explanation:
  2274.  
  2275. VB is holding on to all procedure names, variables/consts, control and form
  2276. names; in short everything that potentially would be needed to evaluate
  2277. interactive changes in break mode.
  2278.  
  2279. No question that some mechanism should be in place to purge this before compile.
  2280. However, consider the case where a compile occurs with no save on existing
  2281. changes (some would argue that you should be asked or forced to save changes
  2282. before compile as PDS does): The temp files that VB uses may contain code
  2283. and references that, though now commented out, are part of the threaded
  2284. p-code.
  2285.  
  2286. Rather than dump this and force rethreading of everything, it was decided to
  2287. hold on to all "threads".
  2288.  
  2289. The environment stores all this data from every project loaded in a session
  2290. so if a larger project was loaded prior to the one you're compiling,
  2291. this hangover gets incorporated into the .exe.
  2292.  
  2293. I have heard of situations where the old formname (which matched a presently
  2294. existing one) caused problems when both forms where running in two different
  2295. exe's.
  2296.  
  2297. Doing the Save/Load text and starting your final compile from a clean
  2298. environment should eliminate this. The formname is one of the critical tags
  2299. that the DLL uses to feed itself so in rare circumstances, to apps with
  2300. Form1 formnames could interact. All of these issues are known and will be
  2301. addressed in the next version.
  2302. Robert Eineigl Microsoft Product Support
  2303. ---------------
  2304.  
  2305.  
  2306. Removing Deleted Control's Code:
  2307.  
  2308. When you delete a control, the code goes into the General Procedures list.
  2309. To get rid of it, highlight the entire block of code, including the Sub and
  2310. End Sub lines, and press Delete.
  2311. ---------------
  2312.  
  2313.  
  2314. Saving Your Work:
  2315.  
  2316. Several users have reported losing their work in different ways. If you always
  2317. save before test-running your code, you can prevent most losses. If you get
  2318. any kind of warnings or other indications that something might be wrong with
  2319. your system, try to get into DOS (or use File Manager) and copy your project
  2320. files to a backup directory. Many people have had their project files
  2321. "trashed" when the system went screwy.
  2322.  
  2323. Another good idea is to save the code to a Text file (under the Code menu) to
  2324. protect against your FRM file being trashed.
  2325.  
  2326. There is a utility on the DLs here for copying all the files in a Project -
  2327. very handy to have, although a better idea, generally, is to keep each project
  2328. in its own subdirectory, then you can just copy the entire subdirectory to
  2329. another one.
  2330. ---------------
  2331.  
  2332.  
  2333. Splitting Long Lines:
  2334.  
  2335. VB does not have a line continuation character as does QB.
  2336. The only way to split a long line of code into multiple lines is with kludges.
  2337. Say that you have a long line like:
  2338.  
  2339. If (a=b and not (c=d or e=f) and g=h) or (i=j and k=l) then
  2340.   Call SomeRoutine
  2341. End if
  2342.  
  2343. With descriptive variable names, the line above would be long, as well as being
  2344. difficult to read and follow the logic of. So I would split it up:
  2345.  
  2346. If c=d then
  2347.   'do nothing; this just gets rid of the "not (c=d or e=f)"
  2348. elseif e=f then
  2349.   'do nothing
  2350. elseif a=b then
  2351.   Call SomeRoutine
  2352. elseif i=j then
  2353.   if k=l then
  2354.     Call SomeRoutine
  2355.   end if
  2356. End If
  2357.  
  2358. Note that an "or" in a line can be split into an ElseIf while an "and" must be
  2359. split into an indented "If".
  2360. ---------------
  2361.  
  2362.  
  2363. Alias Use in Declares:
  2364.  
  2365. With the Alias keyword added to Declares, duplicate definitions become apparent
  2366. immediately when the program is run. Otherwise, there is no indication that
  2367. DLL's have been declared in multiple places. (Steve Schmidt)
  2368. ---------------
  2369.  
  2370.  
  2371. API vs VB Routines:
  2372.  
  2373. Given the choice, it's preferable to use VB routines rather than API calls:
  2374. 1. API calls will probably be slower (goes through a p-code declaration).
  2375. 2. API calls require hWnds for everything.
  2376. 3. API calls will not be portable accross different OS.
  2377. - J. Zuck.
  2378. ---------------
  2379.  
  2380.  
  2381. API Errors:
  2382.  
  2383. Errors in WINAPI.TXT can be found in article Q74526 in the Knowledge Base (GO
  2384. MSKB on CompuServe).
  2385. ---------------
  2386.  
  2387.  
  2388. Autoredraw Error Message:
  2389.  
  2390. "Can't create autoredraw image!" means you're out of ram! Virtual (disk)
  2391. memory won't do for creating the persistent bitmap (which is what autoredraw
  2392. is trying to do). You need to unload some hoggish forms or toggle autoredraw
  2393. on and off instead of having it on for several objects that all need
  2394. persistent bitmaps created concurrently. (Robert Eineigl)
  2395. ---------------
  2396.  
  2397.  
  2398. Blanking Out Text:
  2399.  
  2400. You cannot blank out text on the form or picture box by writing blank spaces
  2401. over it as you can in other BASICs. Instead, set the FontTransparent to FALSE
  2402. and you'll be able to overwrite the text that's already there with spaces. Note
  2403. that spaces aren't as wide as most characters (in proportional fonts), so you'll
  2404. have to use more spaces than you might use under a DOS Basic.  (Ted Young)
  2405. ---------------
  2406.  
  2407.  
  2408. Branding Your Apps:
  2409.  
  2410. To brand your application with the user's name, address, whatever, set a
  2411. variable in your app to an identifiable string, such as "ZZZZZZZZZZ". During
  2412. runtime, you can substitute the users's name for the string by opening your
  2413. EXE as Binary, searching for the string, substituting the name, and writing it
  2414. to the file:
  2415.  
  2416. Open MYPROG$ For Binary As #1
  2417. A$ = String$(LOF(1), Chr$(32))
  2418. Get #1, , A$
  2419. If wDlg = 0 Then
  2420.   x& = InStr(A$, DummyString$)
  2421.   UName$ = String$(30, Chr$(90))
  2422. Else
  2423.   x& = InStr(A$, String$(30, Chr$(90)))
  2424. End If
  2425. Seek #1, x&
  2426. Put #1, , UserName$
  2427. Close #1
  2428.  
  2429. If you want to be able to continually replace the string in this location, then
  2430. you will need to leave part of the String the same, say the first 5 'Z''s.
  2431. (Troy G. Strain)
  2432. ---------------
  2433.  
  2434.  
  2435. Control ID's:
  2436.  
  2437. CTLHWND.DLL lets you get a control's handle without having to use the clumsy
  2438. SetFocus method. But its use in your app requires you to distribute yet another
  2439. DLL, which is not desirable either.
  2440.  
  2441. If you wanted to do without CTLHWND.DLL but still benefit from it, you can use
  2442. it to get your control's IDs during development. Then right before making the
  2443. EXE, save the control IDs in global constants and remove CTLHWND.DLL from the
  2444. project (the IDs won't change):
  2445.  
  2446. DefInt A-Z
  2447. Declare Function GetDlgCtrlID Lib "User" (ByVal hWnd)
  2448. Declare Function ControlhWnd Lib "CTLHWND.DLL" (C As Control)
  2449. Dim ID_COMMAND1
  2450. Dim ID_COMMAND2
  2451.  
  2452. Sub Form_Load
  2453.   ID_COMMAND1 = GetDlgCtrlID(ControlhWnd(Command1))
  2454.   ID_COMMAND2 = GetDlgCtrlID(ControlhWnd(Command2))
  2455. End Sub
  2456.  
  2457. Right before making an EXE just replace the two Dim lines with Constants. Once
  2458. you have the control IDs you only need to call GetDlgItem(Form.hWnd, ID) to get
  2459. the hWnd.  (Costas Kitsos)
  2460. ---------------
  2461.  
  2462.  
  2463. Currency Format vs Date Format:
  2464.  
  2465. From Sharon Dooley:
  2466.  
  2467. Once you format a currency variable, the DATE functions no longer work
  2468. correctly. For example:
  2469.         Print Format$(0@,"0.00")
  2470.         Print Year(Now)
  2471. will display
  2472.         0
  2473.         1900
  2474.  
  2475. Microsoft has confirmed this bug. The only way around it is to format some
  2476. non-currency before using the date format:
  2477.         Print Format$(0@,"0.00")
  2478.         Print Year(Now)
  2479.         Print Format$(0%, "###0")
  2480.         Print Year(Now)
  2481. which prints four lines containing 0, 1900, 0 and 1991, respectively.
  2482. ---------------
  2483.  
  2484.  
  2485. DateValue Bug:
  2486.  
  2487. The following code is supposed to create a serial number from a given date.
  2488.      DV# = DateValue("Oct 14")
  2489.  
  2490. The VB Reference manual says that if the year is omitted, the current year is
  2491. used, but if you translate the number back to text with
  2492.      Print Format$(DV#, "mm/dd/yyyy")
  2493. you get:
  2494.      10/01/1914
  2495.  
  2496. If you use "10-14" instead of "Oct 14", it works. --Isaac Rabinovitch
  2497. ---------------
  2498.  
  2499.  
  2500. DoEvents(), Use Of:
  2501.  
  2502. DoEvents allows the user to access other programs (or other parts of
  2503. the current program) while the current app is otherwise tying up the
  2504. CPU in some sort of processing loop.
  2505.  
  2506. You should put "x = DoEvents()" in your code anywhere you don't mind
  2507. having the current operation interrupted.
  2508.  
  2509. There is a risk that if the user clicks a button that causes lengthy
  2510. processing and during that time, clicks the same button again,
  2511. unwanted results could occur.
  2512.  
  2513. To prevent such happenings, you should set a global flag to indicate
  2514. that you are already in that Sub, and then check the flag each time
  2515. the Sub is entered, doing a Sub Exit if it is set.
  2516.  
  2517. Setting MousePointer to an hourglass at the start of long processing
  2518. alerts the user and helps prevent unnecessary extra button clicking.
  2519. ---------------
  2520.  
  2521.  
  2522. Emulating READ-DATA:
  2523.  
  2524. VB does not have READ and DATA. You can emulate this function by assigning data
  2525. to a string and reading it from there:
  2526.  
  2527. MyData$ = "Item1, Item2, ..., ItemN,"
  2528. ReDim Array$(N)
  2529. i = 1
  2530. Do
  2531.   j = Instr(i, MyData$, ",")
  2532.   Array$(x) = Mid$(MyData$, i, j-i)
  2533.   i = x + 2
  2534. Loop while i < Len(MyData$)
  2535. ---------------
  2536.  
  2537.  
  2538. Error Messages:
  2539.  
  2540. When you get an error message while programming or running inside VB, just press
  2541. F1 before pressing the Ok button and an explanation of the error message will be
  2542. shown.
  2543. ---------------
  2544.  
  2545.  
  2546. Error Trapping:
  2547.  
  2548. The error trapping in Visual Basic is local to the Sub or Function and you
  2549. will have to write a general error handler and place a call in every level
  2550. to this error handler.
  2551. ---------------
  2552.  
  2553.  
  2554. Far Pointers:
  2555.  
  2556. Here's a question regarding direct calls to the Windows API from a Visual Basic
  2557. procedure. In trying to set up a call to the API entry "Polygon", I discovered
  2558. that one of the arguments is a far pointer to an array of structures. I've
  2559. searched the VB documentation, but can't find a method that will return the
  2560. run-time address of a variable (or an array element) as a far pointer.
  2561.  
  2562. Is there a VB technique for passing a far pointer as an argument -- if so, how?
  2563. Also, how would such an argument be specified in the corresponding DECLARE
  2564. statement? Many thanks to anyone who can supply this information.
  2565.  
  2566. (Fm: Mark Novisoff (TA) 73047,3706)
  2567.  
  2568. If the structures themselves don't require pointers (which is the case with
  2569. Polygon), then it's a piece of cake. Use TYPE...END TYPE to declare a model
  2570. structure, and then DIM an array of the structures.
  2571.  
  2572. In your Global module Declare statement, use the "As" syntax:
  2573.  
  2574.    Type Points
  2575.      ' Define the structure
  2576.      X As Integer
  2577.      Y As Integer
  2578.    End Type
  2579.    Declare Function Polygon Lib "Gdi" (hDC%, MyStruc As Points, nCount%)
  2580.  
  2581. In your code:
  2582.  
  2583.    ReDim MyStrucArray(0 To 10) As Points
  2584.    ' Set the variables in the array here
  2585.    Result = Polygon(hDC%, MyStrucArray(0), nCount%)
  2586.  
  2587. Note that this results in passing a far pointer to the zeroth element of the
  2588. array. Because the length of the structure is known to the DLL routine, it
  2589. will figure out where the rest of the elements are.
  2590. ---------------
  2591.  
  2592.  
  2593. Help Files:
  2594.  
  2595. 1. You can create Help files more easily and cheaply than with the SDK: use
  2596.    the help compiler (HC.EXE) that comes with Turbo Pascal for Windows and
  2597.    Borland C++.
  2598.  
  2599. 2. A shareware program named Xantippe is a good front-end for making help
  2600.    files.
  2601.  
  2602. 3. Iconwrks, which comes with VB, contains a Sub called Get_Help. This shows
  2603.    how to call the Win API function, WinHelp, to invoke Windows' Help system.
  2604.  
  2605. 4. WordPerfect's RTF format for footnotes is reported not to be compatible
  2606.    with the Help Compiler.
  2607.  
  2608. 5. There are several utilities available for generating Help files without
  2609.    having to learn WFW or other RTF-compatible word processor. They range from
  2610.    very expensive to inexpensive shareware. (See the program listing at the
  2611.    end of the file for shareware solutions.)
  2612. ---------------
  2613.  
  2614.  
  2615. Interrupting a Routine:
  2616.  
  2617. Question:
  2618. I have code attached to a control button called "Start". When you click on it
  2619. it increments a counter to the screen with a FOR loop. I want this to continue
  2620. until I click on a control button called "Stop". VB seems to keep control
  2621. until the loop ends and it does not see the click on the "Stop" button. How
  2622. can I get around this?
  2623.  
  2624. Answer:
  2625. Use a DoEvents (see your manuals for details):
  2626.  
  2627. Example:
  2628.   While DoEvents and CounterOn
  2629.     Counter = Counter + 1
  2630.   Wend
  2631.  
  2632. Where CounterOn is a global variable you set to FALSE from your Stop button.
  2633. ---------------
  2634.  
  2635.  
  2636. Julian Date Considerations:
  2637.  
  2638. RE: Finding out what day of the week July 4th, 1776 was.
  2639.  
  2640. You need to be a little careful about dates when going back that far. Although
  2641. the Gregorian Calendar was invented in 1583, it was not universally and
  2642. immediately accepted. The British didn't adopt it until the second half of the
  2643. 18th century and the U.S. after that (and not all states at the same time).
  2644.  
  2645. In addition, the new year was moved from Mar 25 to Jan 1. Geo Washingtons
  2646. birthday was Feb 11, 1731 O.S. (old style), but was changed to Feb 22, 1732
  2647. N.S. (new style). China didn't change until 1912 and Turkey until 1917.
  2648.  
  2649. The original accumulated error in 1583 was estimated to be 10 days, but this
  2650. expanded to 11 and then 12 days the longer the country waited to adopt the
  2651. standard. To change from old style julian dates to modern gregorian dates, add
  2652. 10 days to dates oct 5, 1582 through feb 28, 1700; 11 days to dates through
  2653. feb28, 1800; 12 days through feb28, 1900; and 13 days through feb28, 2100. If
  2654. you want a program to back it out the other way, you'll need to subtract these
  2655. figures to arrive at the true O.S. date value.  (Bruce Fulton)
  2656. ---------------
  2657.  
  2658.  
  2659. Jumping to a Subroutine During Coding:
  2660.  
  2661. If the cursor is on the name of a sub or function call, you can jump to that
  2662. code simply by pressing Shift-F2. Unfortunately, there is not a key for
  2663. jumping back to where you were. (Kevin Cook)
  2664. ---------------
  2665.  
  2666.  
  2667. Memory, Out of:
  2668.  
  2669. 1. An "Out of Memory" error when you know you have plenty of memory often
  2670. means that you are using up too much of the systems resources. This results
  2671. from using too many controls -- particularly Picture boxes.
  2672.  
  2673. To cut back on Label boxes, see "An Alternative to Label Boxes" under
  2674. "Label Boxes" in this file.
  2675.  
  2676. To cut back on Picture boxes, see "An Alternative to Picture Boxes" under
  2677. "Picture Boxes" in this file.
  2678.  
  2679. 2. You can also get this error if your code gets caught in a recursive loop.
  2680. This usually is the result of a routine calling itself or a routine calling
  2681. another routine that calls another routine (etc) that calls the first
  2682. routine.
  2683.  
  2684. To track down the problem, run your program in the VB environment. When you
  2685. get the error message, use Alt-R, M to move the Next Statement to Exit Sub
  2686. and press F8 to single-step. This will take you to the calling sub. Repeat
  2687. the process of jumping to Exit Sub and see where it takes you. Usually you
  2688. will see that the program flow keeps going back from Exit Sub to the same
  2689. line in the same Sub, then fix that line. If it is a more complex recursion,
  2690. the single-step will flow back to some other Sub, but eventually you can
  2691. spot where the recursion is coming from.
  2692. ---------------
  2693.  
  2694.  
  2695. NEVER USE "END":
  2696.  
  2697. From Mark Novisoff, Microhelp: We found a *terrible* problem with End just
  2698. recently (concerns custom controls).
  2699.  
  2700. Unloading all forms in your apps has the same effect as End and custom controls
  2701. get the required messages correctly.
  2702.  
  2703. Jonathan Zuck adds: I found this problem also when working on a DLL for my
  2704. column. The problem is that End does a FreeLibrary *before* it destroys the
  2705. application windows (including custom controls). This is particularly a problem
  2706. when subclassing. What you need to do is in your WEP, clean up *everything*
  2707. rather than relying on getting the WM_DESTROY message, or whatever, to the
  2708. particular window. I think you will find similar problems if the application is
  2709. ended by choosing "End" from the Run menu of the development environment.
  2710. ---------------
  2711.  
  2712.  
  2713. Polygon-Drawing API Call:
  2714.  
  2715. Global Const gCYAN = &HFFFF00
  2716.  
  2717. Type PointAPI
  2718.   X As Integer
  2719.   Y As Integer
  2720. End Type
  2721.  
  2722. Declare Function Polygon Lib "GDI" (ByVal hDC As Integer,
  2723.     lpPoints As PointAPI, ByVal nCount As Integer) As Integer
  2724.  
  2725. This code will draw your polygon.
  2726. Change the number of points to suit your needs.
  2727.  
  2728. TheForm.FillColor = gCYAN
  2729. ReDim Points(4) As PointAPI
  2730. Points(1).X = 100
  2731. Points(1).Y = 100
  2732. Points(2).X = 200
  2733. Points(2).Y = 100
  2734. Points(3).X = 200
  2735. Points(3).Y = 200
  2736. Points(4).X = 100
  2737. Points(4).Y = 200
  2738. Result% = Polygon(Theform.hDC, Points(1), 4)          .
  2739. (Bob Scherer)
  2740. ---------------
  2741.  
  2742.  
  2743. Private INI Problem:
  2744.  
  2745. If you get bizarre happenings after reading from an INI file (using API
  2746. calls), the most likely reason is that you have not initialized the variable
  2747. used to return the data to a sufficient length.
  2748.  
  2749. For example, if you want to retrieve data of up to 15 characters from an INI
  2750. file, initialize the variable with something like X$ = Space$(15).
  2751. (Mark Novisoff)
  2752. ---------------
  2753.  
  2754.  
  2755. RND Seeding:
  2756.  
  2757. If you need to seed the random number generator ("RND") to a specific series
  2758. of random numbers, such as for being able to duplicate deals in a card game,
  2759. then you should be aware that:
  2760.  
  2761. Randomize n!  'where "n!" is some specific value
  2762.  
  2763. does NOT reseed RND() with n! as the manual implies. (In fact, there is no
  2764. apparent use for "Randomize n!". Instead, use:
  2765.  
  2766. x = RND(-n!)
  2767.  
  2768. (Jim Mack)
  2769.  
  2770. This feature is downplayed, to say the least, in the VB manual. Also, the VB
  2771. manual is a little deceptive in showing the syntax as being RND(-n#). While
  2772. it is true that you can use a double-precision number, the fact is that a
  2773. number longer than 7 digits will not generate a UNIQUE series of numbers.
  2774. That is, if you increment an 8+ digit number by one, the subsequent series
  2775. of numbers may not change from the previous series -- not ideal if you are
  2776. generating card deals. (Nelson Ford)
  2777. ---------------
  2778.  
  2779.  
  2780. Slow Loading of App:
  2781.  
  2782. If your app takes a long time to load, try the following procedure to keep your
  2783. users from getting antsy:
  2784.  
  2785. Create a "Banner" form with only a small label which says "Loading Program" and
  2786. a Timer Control (Enabled). Make this form Borderless, no Max, Min, or Control
  2787. Box. Put a Screen.MousePointer = 11 as the only command in the Load Event.
  2788. Select this as the start-up form. This form will load fast.
  2789.  
  2790. Under the Timer event, disable the timer, Load MainForm (with Visible = False),
  2791. and MainForm.Visible = True. The Load Event of MainForm should Unload Banner.
  2792.  
  2793. The result is that you get a fast mousepointer 11 and a "please wait" message
  2794. which lasts until the main screen gets loaded. (Al E Meadows)
  2795. ---------------
  2796.  
  2797.  
  2798. Sound Standards:
  2799.  
  2800. Now that Windows 3.1 is here, let's all make an effort to observe standards.
  2801. Notably the new sounds for MsgBox dialogs:
  2802.  
  2803. Call MessageBeep before MsgBox dialogs.  Follow the chart below..
  2804.  
  2805.  MsgBox with no icon = 0
  2806.  MsgBox with Stop icon = 16
  2807.  MsgBox with Question mark = 32
  2808.  MsgBox with Exclamation mark = 48
  2809.  MsgBox with lower-case i = 64
  2810.  
  2811. And use the value above for the parameter to pass to MessageBeep.
  2812.  
  2813. The declare for MessageBeep is...
  2814.  
  2815. Declare Sub MessageBeep Lib "User" (ByVal wType As Integer)
  2816.  
  2817. Doing this will make sure that the proper user-assigned sounds are played.
  2818. (Mike Mezaros)
  2819. ---------------
  2820.  
  2821.  
  2822. Telephone Dialing:
  2823.  
  2824. OPEN "COM1" For Output As #1
  2825. Print #1, "ATD 000-0000"
  2826.  
  2827. Here is a more complete routine from Mark Novisoff.
  2828.  
  2829. ' General section
  2830. Dim PortIsOpen As Integer
  2831.  
  2832. Sub Form_Click ()   ' Tells me to dial the phone
  2833.   'get PhoneNumber$ from the form, however you have the user input it.
  2834.   If Not PortIsOpen Then
  2835.      PortIsOpen = -1
  2836.      Open "COM1" For Output As #1
  2837.   End If
  2838.   Print #1, "ATDT" + PhoneNumber$ + Chr$(13)
  2839. End Sub
  2840.  
  2841. Sub Form_DblClick ()  ' Tells me to hang up
  2842.   If PortIsOpen Then
  2843.      Print #1, "ATH" + Chr$(13)
  2844.      Close #1
  2845.      PortIsOpen = 0
  2846.   End If
  2847. End Sub
  2848. ---------------
  2849.  
  2850.  
  2851. "Too Many Files":
  2852.  
  2853. If you get the message "Too many files", try the following:
  2854.  
  2855. General:
  2856.   DEFINT A-Z
  2857.   Declare Function SetHandleCount Lib "Kernel" (ByVal wnumber)
  2858.  
  2859. Form_Load:
  2860.   j = SetHandleCount(32)
  2861.  
  2862. The default number of file handles is 20 (actually 15 because the system uses
  2863. 5). Entering 32 will bump your total number of handles up quite a bit.
  2864. (Todd W. Bristol)
  2865. ---------------
  2866.  
  2867.  
  2868. TRUE <> NOT FALSE:
  2869.  
  2870. The following is a quirk of all versions of MS Basic, not just VB:
  2871.  
  2872. (1) Any non-zero number will return a "true" result with the syntax: "If x..."
  2873.     but only "-1" will work with the syntax: "If NOT x Then ... Else...".
  2874.  
  2875. Example:
  2876.  
  2877. x = 1
  2878. if x then print "x is True"
  2879. if not x then print "x is False" else print "x is True"
  2880. x = -1
  2881. if x then print "x is True"
  2882. if not x then print "x is False" else print "x is True"
  2883.  
  2884. Run this and you get:
  2885.  
  2886. x is True
  2887. x is False
  2888. x is True
  2889. x is True
  2890.  
  2891. Here's a typical example of how you can get caught by this:
  2892.  
  2893. If Not InStr("13579", n$)
  2894.  
  2895. When i is 5, InStr("5", Str$(i)) will have a value of 3, which as we have just
  2896. seen, will not trigger a "Not" test correctly. Instead, you must say
  2897.  
  2898. If InStr("13579", n$) > 0
  2899.  
  2900.  
  2901. (2) Here is related quirk:
  2902.  
  2903. If X and Y are both -1, then the following statement will print "TRUE":
  2904.  
  2905. If X And Y Then Print "TRUE"
  2906.  
  2907. This code will also print "TRUE" for some, BUT NOT ALL, positive values of
  2908. X and Y, such as 2 and 4.  (Nelson Ford)
  2909. ---------------
  2910.  
  2911.  
  2912. Windows 3.1 Quirks:
  2913.  
  2914. 1. A bug in Win31 and/or VB causes your program not to show up when you go to
  2915. make an EXE in the File menu. If you select the form whose icon you want to
  2916. use, it will still use it, you just want be able to see it until run-time.
  2917.  
  2918. 2. The "System" nonproportional 9 point font has been renamed "Fixedsys",
  2919. which could cause problems.
  2920. ---------------
  2921.  
  2922.  
  2923. Calculating System Resources:
  2924.  
  2925. This is an *UNDOCUMENTED* API call which does the trick:
  2926.  
  2927. Declare Function GetModuleHandle Lib "Kernel"
  2928.                  (ByVal lpModuleName As String) As Integer
  2929. Declare Function GetHeapSpaces Lib "Kernel"
  2930.                  (ByVal hModule As Integer) As Long   '*UNDOCUMENTED*
  2931. Function CalcFreeResources (file As String) As Long
  2932. info& = GetHeapSpaces(GetModuleHandle(file))
  2933. CalcFreeResources = (LowWord(info&) / HighWord(info&)) * 100
  2934. End Function
  2935. Function GetSystemResources ()
  2936. gdires = CalcFreeResources("GDI")
  2937. userres = CalcFreeResources("USER")
  2938. If gdires < userres then
  2939.  GetSystemResources = gdires
  2940. Else
  2941.  GetSystemResources = userres
  2942. End Function
  2943. Function LowWord (dlong As Long) As Long
  2944. LowWord = dlong And &HFFFF&
  2945. End Function
  2946. Function HighWord (dlong As Long) As Long
  2947. HighWord = (dlong And Not &HFFFF&) / &H10000 And &HFFFF&
  2948. End Function
  2949. (Hans Peters)
  2950. ---------------
  2951.  
  2952.  
  2953. Close Another App From Within VB:
  2954.  
  2955. Declare Function SendMessage Lib "User" (ByVal hWnd As Integer,
  2956.      ByVal wMsg As Integer,
  2957.      ByVal wParam As Integer,
  2958.      lParam As Any) As Long
  2959.  
  2960. Global Const WM_CLOSE = &H10
  2961.  
  2962. Assuming hWndApp is the handle, then the usage would be:
  2963.   msg = SendMessage(hWndApp, WM_CLOSE, 0, 0&)
  2964.  
  2965. (Keith Pleas)
  2966.  
  2967. Another way to close an already running program is to use AppActivate and
  2968. SendKeys. AppActivate doesn't return a value, but you can use On Error.
  2969.  
  2970. In most cases, you can use the control bar and shut it down. All assuming that
  2971. the program closes gracefully. Oh yeah, you'll want to set the wait argument
  2972. to -1 in the SendKeys command. (George Campbell)
  2973. ---------------
  2974.  
  2975.  
  2976. Control Box Menu, Adding Items:
  2977.  
  2978. The "Control Box" is the box in the upper left corner of a form. Clicking on
  2979. it during run-time brings up a "system menu" (so some people call the box a
  2980. "SysBox").
  2981.  
  2982. You can add items to the Control Box menu, but you can't attach any code to
  2983. it, normally (since VB won't process user-defined WM_SYSCOMMAND events).
  2984.  
  2985. However, you can INDIRECTLY trigger user-specified events by using the SysBox
  2986. CLOSE event (Form_UnLoad) to replace the SysBox Menu with a PopUp Menu of your
  2987. own from which the user can select an action.
  2988.  
  2989. The beauty of this method is that you can use the VB Menu Design Window to
  2990. build your PopUp menu. This simplifies the work as the VB MDW automatically
  2991. maps menu events to procedures. The code is as follows:
  2992.  
  2993. Form_Load:
  2994. 'Use API to get handle to Window Menu Bar (created with VB Menu Design)
  2995. hWndMenu% = GetMenu(hWnd)
  2996. 'Use API to get handle to 1st (and only) submenu on Menu Bar
  2997. hPopUpMenu% = GetSubMenu(hWndMenu, 0)
  2998. 'Use API to get name of submenu which is to replace Control Box 'Close'
  2999. '(MStg$ is name of submenu as it appears on your menu bar)
  3000. nchar% = GetMenuString(hWndMenu, 0, MStg$, Len(MStg$), MF_BYPOSITION)
  3001. 'Use API to modify Control Box (System) Menu to replace 'Close'
  3002. 'with your submenu name
  3003. hSysMenu% = GetSystemMenu(hWnd, FALSE)
  3004. boolean% = ModifyMenu(hSysMenu%, SC_CLOSE, MF_BYCOMMAND, SC_CLOSE, MStg$)
  3005. 'Use API to Remove Menu Bar from Window (this is not an option!)
  3006. If RemoveMenu(hWndMenu, 0, MF_BYPOSITION) Then DrawMenuBar (hWnd)
  3007.  
  3008. Form_Unload:
  3009. 'If UnLoad event is not thru this Window's Control Box Menu then Exit:
  3010. If SetActiveWindow (hWnd) <> hWnd Then End
  3011. 'Otherwise, Replace Control Box Menu with own PopUp Menu
  3012. '(PopUpPosition is declared as 'Dim PopUpPosition As POINTAPI')
  3013. PopUpPosition.x = Screen.ActiveForm.Left 'Position in Twips
  3014. PopUpPosition.y = Screen.ActiveForm.Top
  3015. 'Convert twip position of form to pixel position
  3016. '(TwipsToPixels is Sub of my own design to do this.)
  3017. Call TwipsToPixels(PopUpPosition, PopUpPosition)
  3018. 'Position PopUp Menu where Control Box is
  3019. X% = PopUpPosition.x         'Position in Pixels
  3020. Y% = PopUpPosition.y + GetSystemMetrics(SM_CYSIZE)
  3021. Cancel = TRUE '(Don't forget this! Or your program will exit)
  3022. boolean% = TrackPopupMenu(hPopUpMenu, 0, X%, Y%, 0, hWnd, 0)
  3023.  
  3024. Since you are replacing the "Close" function of the Control Box, you need to
  3025. make "Close" one of the options in your PopUp submenu.
  3026.  
  3027. Also, since the Menu Bar will be deleted as a part of this method, your form
  3028. will adjust itself vertically to replace the missing menu bar. If you set
  3029. AutoSize=True for the form, this is taken care of, otherwise you need to keep
  3030. this in mind when fixing the form borders.
  3031.  
  3032. You must add the necessary DECLARES for the the API functions and constants
  3033. used in the code. They can be found in WINAPI.TXT. This technique can also be
  3034. used to create a 'floating' PopUp Menu just about anywhere. (Gary Williamson)
  3035. ---------------
  3036.  
  3037.  
  3038. Control Box Menu, Removing Items:
  3039.  
  3040. Defint A-Z
  3041. Declare Function RemoveMenu Lib "User" (ByVal hMenu, ByVal nPosition,
  3042.                                         ByVal wFlags)
  3043. Declare Function GetSystemMenu Lib "User" (ByVal hwnd, ByVal bRevert)
  3044. Global Const MF_BYPOSITION = &H400
  3045.  
  3046. Form_Load:
  3047.   HSysMenu = GetSystemMenu(A_Form.Hwnd, 0)
  3048.   R = RemoveMenu(HSysMenu, 7, MF_BYPOSITION) 'Separator
  3049.   R = RemoveMenu(HSysMenu, 6, MF_BYPOSITION) 'Close
  3050. End Sub
  3051. ---------------
  3052.  
  3053.  
  3054. Control Box Exit Bug:
  3055.  
  3056. If you exit a compiled VB app by using Exit from the form's Control Box menu,
  3057. the program may not close down properly and may not free up system resources.
  3058.  
  3059. If there is more than one form in the project and there is no code in that
  3060. forms Unload procedure to unload all other forms or END then the DLL stays
  3061. loaded and the app is still a task so no resources are freed (other than
  3062. those associated with the one unloaded form).
  3063.  
  3064. However, if there is code in the unload (to trigger the exit routine or END)
  3065. it will be executed by the System menu close and has the same effect as
  3066. triggering your exit routine with a button.
  3067.  
  3068. If there are loaded forms orphaned, ending the task from the Task Manager
  3069. frees the resources.
  3070.  
  3071. One of the resources not freed up in some situations is VBRUN100.DLL, which
  3072. Windows does not remove from memory. If you run a VB app from drive A: with
  3073. VBRUN on A: and the forms are not properly unloaded as described above, then
  3074. Windows will continue to look for VBRUN on A: and display an error window if
  3075. it is not still there. However, canceling the error window allows the next
  3076. invocation of a VB app to look for VBRUN on your hard disk again.
  3077. (Robert Eineigl)
  3078. ---------------
  3079.  
  3080.  
  3081. Control Accessing Via DDE:
  3082.  
  3083. A control on a frame cannot be accessed via DDE. I had tested this with three
  3084. applications, WinWord, Superbase and Objectvision. The latter two produce an
  3085. immediate, null result to a DDE request; WinWord seems to recognize the
  3086. control is there and keeps trying to get the data until it eventually times
  3087. out. (George Mair)
  3088. ---------------
  3089.  
  3090.  
  3091. Controlling Apps with SendKeys:
  3092.  
  3093. It is easy to provide buttons for menu items in other apps using the VB
  3094. 'SendKeys' command. For example, attach the following code to a pushbutton to
  3095. cause the Program Manager group windows to be cascaded (using the
  3096. Window/Cascade menu option):
  3097.  
  3098. Sub Command1_Click ()
  3099.   AppActivate "Program Manager"  ' Gives focus to the program manager
  3100.   SendKeys "%Wc"                 ' Sends ALT+W c to progman End Sub
  3101. (Danny Dawes)
  3102. ---------------
  3103.  
  3104.  
  3105. Corrupt VB File Recovery:
  3106.  
  3107. If you get a UAE and have to reboot in the middle of running an app in VB, you
  3108. may get an error message when trying to reload your source code, meaning that
  3109. it has become corrupted.
  3110.  
  3111. The only option at this point, if you do not have backup, is to check for any
  3112. .TMP files left in your Window's TEMP directory and delete them prior to
  3113. loading Windows/VB/project again.
  3114.  
  3115. A good habit before starting a programming session is to archive (using LHA,
  3116. PKZIP, etc) your project files, using the day's date for a name. That way you
  3117. do not risk losing everything.
  3118.  
  3119. Another good habit is to save your code as Text (under the Code menu) before
  3120. ever running the project in the VB environment. Although this will not
  3121. safeguard the forms and controls, the code is normally a lot more work.
  3122. ---------------
  3123.  
  3124.  
  3125. Detecting Running Applications:
  3126.  
  3127. 1. Shelled App Still Running?
  3128.      See "Shelling-To-Dos Problems". The GetModuleUsage can also be used
  3129.      for Windows apps, per Jonathan Zuck.
  3130.  
  3131. 2. To determine if an application is already running, ask Windows to find its
  3132.      title caption. Use this code:
  3133.  
  3134.      DefInt A-Z
  3135.      Declare Function FindWindow Lib "user" (ByVal CName As Any,
  3136.              [all on one line]--->           ByVal Caption As Any)
  3137.  
  3138.     Function Loaded (Caption$)
  3139.         Loaded = FindWindow(0&, Caption$)         'use call
  3140.         If Loaded > 0 Then Loaded = -1            'if caption found
  3141.     End Function
  3142.  
  3143.     Example:
  3144.     If NOT Loaded("Program Manager") Then
  3145.         dummy = Shell("PROGMAN.EXE",1)
  3146.     End If
  3147.  
  3148. 3. Is application already running?
  3149.  
  3150.     Declare Function GetModuleHandle% Lib "Kernel" (ByVal lpProgramName$)
  3151.     Declare Function GetModuleUsage% Lib "Kernel" (ByVal hProgram%)
  3152.  
  3153.     Sub Form_Load ()
  3154.        hw% = GetModuleHandle("project.EXE")
  3155.        If GetModuleUsage(hw%) > 1 Then
  3156.           MsgBox "This program is already loaded!", 16
  3157.           End
  3158.        End If
  3159.     End Sub
  3160. ---------------
  3161.  
  3162.  
  3163. Detecting the Start-Up Directory:
  3164.  
  3165. DefInt A-Z
  3166. Declare Function GetWindowsDirectory Lib "kernel" (ByVal P$, ByVal S)
  3167. Declare Function GetModuleHandle Lib "kernel" (ByVal FileName$)
  3168. Declare Function GetModuleFileName Lib "kernel" (ByVal hModule,
  3169.      ByVal FilName$, ByVal nSize)
  3170. Dim hMod, path As String
  3171.  
  3172. hMod = GetModuleHandle("MyApp.EXE")
  3173. path = String$(145, Chr$(0))
  3174. path = Left$(path, GetModuleFileName(hMod, path, Len(path)))
  3175. VbPos = InStr(path, "\MyApp.EXE")
  3176. If VbPos = 0 Then
  3177.   Dim WinPath As String
  3178.   WinPath = String$(145, Chr$(0))
  3179.   Response = MsgBox("MyApp.EXE is Missing or has been renamed",  48,  "Will
  3180.       use default path")
  3181.   Label1.Caption = Left$(WinPath, GetWindowsDirectory(WinPath,
  3182.       Len(WinPath))) + "\MyApp"
  3183. Else
  3184.   Label1.Caption = Left$(path, (VbPos% - 1))
  3185. End If
  3186. (Arthur Edstrom)
  3187. ---------------
  3188.  
  3189.  
  3190. Exit Windows from VB:
  3191.  
  3192. 1.
  3193. Declare Function ExitWindows% Lib "user" (ByVal dwReserved&, ByVal wReturnCode%)
  3194. Form_Click:
  3195. RetVal% = ExitWindows(0,0)
  3196. or:
  3197.  
  3198. 2.
  3199. Declare Sub ExitWindows Lib "User" (ByVal dwReturn&, ByVal wReserved)
  3200. Const EW_RESTARTWINDOWS = &H42&
  3201. Form_Click:
  3202. RetVal% = ExitWindows(EW_RESTARTWINDOWS, 0)
  3203. ---------------
  3204.  
  3205.  
  3206. Faster Loading of Apps:
  3207.  
  3208. VB apps will load faster if you load VBRUN100.DLL during Windows startup.
  3209.  
  3210. You don't even need a form. You can write a program that has nothing but a Sub
  3211. Main. In that, you will want to call the LoadLibrary API function to load
  3212. VBRUN100.DLL. This increases the lock count on the DLL so that even when you
  3213. exit from your app, the DLL remains loaded. This way, your EXE does not need to
  3214. remain in memory.
  3215.  
  3216. DefInt A-Z
  3217. Declare Sub LoadLibrary Lib "Kernel" (ByVal LibName$)
  3218.  
  3219. Sub Main ()
  3220.    LoadLibrary "VBRUN100.DLL"
  3221.    End
  3222. End Sub
  3223.  
  3224. That's all there is to it. (Jonathan Zuck)
  3225. ---------------
  3226.  
  3227.  
  3228. File Creation Delay:
  3229.  
  3230. If you create a file, eg: for temporary use, and immediately try to use it, it
  3231. may not show in the directory.
  3232.  
  3233. This problem is due to Windows' handling of file buffers. A timer that checked
  3234. for the file's availability using an error trap is one way to overcome this
  3235. problem.  -Robert Eineigl
  3236. ---------------
  3237.  
  3238.  
  3239. File Handles - Maximum:
  3240.  
  3241. Windows Allows a maximum of 255 file handles system wide. It does not matter
  3242. what you have specified in the Config.sys "FILES=".
  3243.  
  3244. The "SetHandleCount" SDK function is the correct way to increase an app's
  3245. default number of 20.
  3246.  
  3247. Windows allocates a default of 20 to any task, or app spawned by it (Windows
  3248. 3.0 is a single task with multiple app's). A task (generally a DOS task) is
  3249. time sliced in 386 enhanced mode according to the parameters set for forground
  3250. and background execution.
  3251.  
  3252. To increase the "TASK" default number set the "PerVMFiles= " parameter in your
  3253. SYSTEM.INI file. Be aware that the 255 available handles are shared by all
  3254. tasks and apps. When you grab a set of handles, they are removed from the
  3255. available pool. It would be a good idea to set the handle count back to the
  3256. default after you are through with them.
  3257.  
  3258. Remember, the return value from the SetHandleCount function is the number
  3259. actually allocated. Also, Windows itself and Visual Basic may have 4 or 5
  3260. files open (like win.ini or GLOBAL.BAS).  (Tony Altwies)
  3261. ---------------
  3262.  
  3263.  
  3264. Finding Excel:
  3265.  
  3266. The parameters that acknowledge Excel's presence are:
  3267.  
  3268. classname$ = "XLMAIN" + chr$(0)
  3269. mywinname$ = "Microsoft Excel"+chr$(0)
  3270.  
  3271. findwindow(classname$,mywinname$)
  3272.  
  3273. The parameters that will work for finding a specific excel window are still
  3274. not settled, but something like:
  3275.  
  3276. classname$ = "EXCEL5" + chr$(0)
  3277. mywinname$ = "DDE1.XLS" + chr$(0)
  3278. ---------------
  3279.  
  3280.  
  3281. Linking to Excel:
  3282.  
  3283. Sharon Dooley 70740,2330
  3284.  
  3285. This fragment shows what I've done to send stuff to Excel, let the user play
  3286. around, and then come back to my program.
  3287.  
  3288. Global:
  3289.   DefInt A-Z
  3290.   Declare Function GetActiveWindow Lib "User" ()
  3291.   Declare Function ShowWindow Lib "user" (ByVal hWnd, ByVal nCmdShow)
  3292.   Declare Function PutFocus Lib "user" Alias "SetFocus" (ByVal hWnd)
  3293.   Declare Function IsWindow Lib "User" (ByVal hWnd)
  3294.  
  3295. Form_Load:
  3296.   ThisApp = StartApp(ToExcel.ExcelBox, "Excel", CurrPath +
  3297.             "expenses.xls", "excel c:\timelog\expenses.xls", 2, hActive)
  3298.   BuildLink ToExcel.ExcelBox, ThisApp, CurrPath + "expenses.xls"
  3299.   '.... here I send my data to Excel '
  3300.   DestroyLink ToExcel.ExcelBox '   transfer control to Excel and wait till
  3301.                                '   the user exits
  3302.   Dummy = ShowWindow(hActive, SW_SHOWNORMAL)  ' and restore its size
  3303.   Dummy = PutFocus(hActive)                   ' give it the system focus
  3304.   Do While IsWindow(hActive)
  3305.      x% = DoEvents()
  3306.   Loop '   when user exits Excel, control returns here
  3307.   MyForm.Show
  3308.  
  3309. Function StartApp (Link As Control, AppName As String, Topic as String,
  3310.                    CommandLine As String, Style As Integer,
  3311.                    Hwnd As Integer) As String
  3312.   On Error GoTo StartUp
  3313.   Link.LinkMode = NONE
  3314.   Link.LinkTopic = AppName + "|" + Topic
  3315.   Link.LinkMode = COLD
  3316.   Exit Function
  3317.   StartUp:
  3318.   If Err = DDE_NO_APP Then
  3319.     T% = Shell(CommandLine, Style)
  3320.     StartApp = "Excel" + LTrim$(Str$(T%))
  3321.     Hwnd = GetActiveWindow()
  3322.     Resume
  3323.   Else
  3324.     MsgBox "UnKnown Error " + Str$(Err) + " in StartApp", \
  3325.       MB_ICONSTOP, "Timelog Error"
  3326.     Status = VBPXExit()
  3327.     Stop
  3328.   End If
  3329. End Function
  3330. ---------------
  3331.  
  3332.  
  3333. Get Program's Path & EXE Name:
  3334.  
  3335. The following routine will get the full path and filename for your program.
  3336. (NOTE: This will not work if the user has renamed the EXE file!)
  3337.  
  3338. DefInt A-Z
  3339. Declare Function GetClassWord Lib "user" (ByVal HWnd, ByVal nIndex)
  3340. Declare Function GetModuleFileName Lib "kernel" (ByVal HWnd, ByVal Fi as String,
  3341.                                                   ByVal FiLen)
  3342. Sub Form_Click ()
  3343.   Const GCW_HMODULE = (-16)
  3344.   Filename$ = Space$(127)
  3345.   hModule = GetClassWord(Form1.hWnd, GCW_HMODULE)  'substitute the form name
  3346.   FLength = GetModuleFileName(hModule, Filename$, 127)
  3347.   Print Left$(Filename$, FLength)
  3348. End Sub
  3349. ---------------
  3350.  
  3351.  
  3352. Get System Focus:
  3353.  
  3354. VB provides no way of detecting when your app has been given the system focus.
  3355. There are a number of Windows messages that the form does not translate into
  3356. events for you.
  3357.  
  3358. For example, you have no way to prevent an iconized program form being opened
  3359. but a C programmer does. Also, you have no way of knowing if a form was moved
  3360. but again, this is a message sent to a form. (Jonathan Zuck)
  3361.  
  3362. Here is a routine for detecting when an app gets/loses system focus (Don Funk):
  3363.  
  3364. Global.Bas:
  3365.   DefInt A-Z
  3366.   Declare Function GetActiveWindow Lib "User" ()
  3367.   Global Focus
  3368.  
  3369. Sub Timer1_Timer ()
  3370.   If Focus Then
  3371.     If GetActiveWindow() <> Form1.hWND Then
  3372.       Print "Lost Focus"
  3373.       Focus = 0
  3374.     End If
  3375.   Else
  3376.     If GetActiveWindow() = Form1.hWND Then
  3377.       Print "Got Focus"
  3378.       Focus = -1
  3379.     End If
  3380.   End If
  3381. End Sub
  3382.  
  3383. Sub Form_Load ()
  3384.   Focus = -1
  3385.   Timer1.Interval = 10
  3386. End Sub
  3387. ---------------
  3388.  
  3389.  
  3390. hWnd for a Control:
  3391.  
  3392. All you have to do is use the Windows API GetFocus call after setting the
  3393. focus to the desired control:
  3394.  
  3395. General Section
  3396.   Declare Function GetFocus% Lib "User" ()
  3397.  
  3398. In your code
  3399.   Command1.SetFocus
  3400.   ButtonHwnd = GetFocus()
  3401. ---------------
  3402.  
  3403.  
  3404. hWnd for a Control II:
  3405.  
  3406. Fm: Costas Kitsos 73667,1755
  3407.  
  3408. Here's yet another way of getting a Control's hWnd without having to use that
  3409. ugly SetFocus method <g>. It will also get hWnds for Labels. If you use
  3410. ClipSib to create overlapping controls, this will not work.
  3411.  
  3412.  Declare Function ChildWindowFromPoint Lib "User" (ByVal hWnd As Integer,
  3413.                                 ByVal dwPoint As Long) As Integer
  3414.  
  3415.  Function GetHwndCtl (FrmhWnd As Integer, Ctl As Control) As Integer
  3416.     OldMode = Scalemode
  3417.     Scalemode = 3
  3418.     GetHwndCtl = ChildWindowFromPoint(FrmhWnd, (Ctl.top * &H10000) + Ctl.left)
  3419.     Scalemode = OldMode
  3420.  End Function
  3421. ---------------
  3422.  
  3423.  
  3424. .INI Files:
  3425.  
  3426. The calls to read/write private ini file are:
  3427.  
  3428. GetPrivateProfileInt - returns int value
  3429.   WORD GetPrivateProfileInt( LPSTR lpApplicationName,
  3430.                              LPSTR lpKeyName,
  3431.                              int nDefault,
  3432.                              LPSTR lpFileName )
  3433.  
  3434. GetPrivateProfileString - returns string
  3435. WritePriviteProfileString
  3436.  
  3437. (The calls to read/write the WIN.INI file are almost the same -- just remove
  3438. the Private.)
  3439.  
  3440. Example:
  3441.   x = GetPrivateProfileInt(APP_NAME, KEY_FrogSpit, DefaultNum%, TEST.INI)
  3442.  
  3443. If the TEST.INI file has a key "FrogSpit", then "x" will be either 0 or -1. If
  3444. the file doesn't yet have a "FrogSpit" key, then the answer will be DefaultNum%.
  3445.  
  3446. As for the result, 0 if value correspponding to keyname is not int or if int is
  3447. negative. Otherwise, returns the value after keyname. Check SDK Windows Prog Ref
  3448. pp. 4-198-199
  3449.  
  3450.  
  3451. NOTICE:
  3452. ======
  3453. Strings passed back from a PrivateProfile and stripped of trailing spaces by
  3454. RTrim$ still have a null character (it tests out to ANSI 000, BTW) stuck on
  3455. the end.
  3456. ---------------
  3457.  
  3458.  
  3459. Mode - Which You Are In:
  3460.  
  3461. In Windows, click on Help and then "About Program Manager". Box will tell you
  3462. what mode you're running in.
  3463. ---------------
  3464.  
  3465.  
  3466. Multi-Instance App Prevention:
  3467.  
  3468. 1. Straightforward method:
  3469.  
  3470. DefInt A-Z
  3471. Declare Function GetActiveWindow Lib "user" ()
  3472. Declare Function IsWindow Lib "user" (ByVal hWnd)
  3473. Declare Function FindWindow Lib "user" (ByVal CName As Any,
  3474.                                         ByVal Caption As Any)
  3475.  
  3476. Wnd = Shell("printman.exe", 1)      'run other app
  3477. Wnd = GetActiveWindow()             'immediatly do this
  3478.  
  3479. 'See if printman is still running:
  3480.     While IsWindow(Wnd)         'API call to determine is Wnd
  3481.         dummy = DoEvents()      ' is valid; then use doevents()
  3482.     Wend                        ' to run other tasks
  3483.  
  3484. 'To determine if an application is already running ask windows to find its
  3485. 'title caption. Use this code...
  3486.  
  3487. Function Loaded (Caption$)
  3488.     Loaded = FindWindow(0&, Caption$)               'use call
  3489.     If Loaded > False Then Loaded = True            'if caption found
  3490. End Function
  3491.  
  3492. example:
  3493. If NOT Loaded("Program Manager") Then dummy = Shell("PROGMAN.EXE",1)
  3494.  
  3495.  
  3496. 2. This example is more specific to someone's application:
  3497.  
  3498. Dim PassString$         ' declare a local string to hold user's password
  3499.  
  3500. Const SW_SHOWNORMAL = 1
  3501. Declare Function GetActiveWindow Lib "User" () As Integer
  3502. Declare Function ShowWindow Lib "user" (ByVal hWnd As Integer,
  3503.                                         ByVal nCmdShow As Integer) As Integer
  3504. Declare Function SetFocusAPI Lib "user" Alias "SetFocus"
  3505.                                        (ByVal hWnd As Integer) As Integer
  3506.  
  3507. Form_Load()                ' this executes when the PassWord form loads
  3508.   On Error GoTo NoLink        ' setup our no-link error handler
  3509.   SystemLink.LinkMode = 1     ' try to establish a hot link with a server
  3510.   On Error GoTo 0             ' disable error trapping
  3511.  
  3512.   MsgBox "A DDE LINK HAS BEEN ESTABLISHED WITH A SERVER!!!"
  3513.  
  3514.   AppActivate "SalHist"                       ' activate the "other" SalHist
  3515.   hActive = GetActiveWindow()                 ' pickup it's hWnd handle
  3516.   Dummy = SetFocusAPI(hActive)                ' give it the system focus
  3517.   Dummy = ShowWindow(hActive, SW_SHOWNORMAL)  ' and restore its size
  3518.   End                                         ' finally, terminate this app!
  3519.  
  3520.   On Error GoTo 0             ' disable our temporary error trapping
  3521.   SystemLink.LinkMode = 0     ' abandon our local DDE connection attempt
  3522.   LinkMode = 1                ' and establish ourselves as a DDE server...
  3523.  
  3524.   CenterForm PassWord         ' (My standard.lib form-centering routine)
  3525.   PassString$ = ""
  3526.   PassWord.Show 1             ' present the PassWord form for user data
  3527.                               ' entry.  The "1" makes it "modal" (stickier)
  3528. End Sub                       ' end of the Form_Load subroutine.
  3529. ---------------
  3530.  
  3531.  
  3532. Name in Task List:
  3533.  
  3534. The name that appears in the Windows Task List for a VB application is what
  3535. you specify under Title in the Make EXE File menu. If you don't specify
  3536. anything, it defaults to the MAK file name.
  3537. ---------------
  3538.  
  3539.  
  3540. Networks & VB:
  3541.  
  3542. VBRUN100.DLL and VB apps (EXE's) should be placed on each machine's hard disk
  3543. to avoid significant performance degradation.
  3544.  
  3545. If you have VB on a network, you may find that it does not write its temporary
  3546. files to the place you would like them. The solution is to set an environment
  3547. variable to specify where the files should be written. Example:
  3548.  
  3549. SET TEMP=C:\
  3550. ---------------
  3551.  
  3552.  
  3553. Norton Desktop vs VB:
  3554.  
  3555. Several Norton Desktop users have reported problems (freezeups) occurring after
  3556. long sessions in Visual Basic.
  3557. ---------------
  3558.  
  3559.  
  3560. "Out of Stack Space" Error:
  3561.  
  3562. This is usually caused by recursion (a loop where the same Sub/Function gets
  3563. called over and over). The easiest way to detect this is to single-step
  3564. through your program using the F8 key. Also see "Memory, Out of".
  3565. ---------------
  3566.  
  3567.  
  3568. Program Manager Groups, Getting List of:
  3569.  
  3570. The following routine will get a list of program groups and their contents
  3571. from Program Manager. This example uses a Text box to grab the data and
  3572. transfers it to a List box array, but you could use other ways to store,
  3573. manipulate, and display the data.
  3574.  
  3575. Text1.LinkTopic = "ProgMan|Progman"
  3576. Text1.LinkItem = "ProgMan"
  3577. Text1.LinkMode = 2
  3578. Text1.LinkRequest
  3579. On Error Resume Next
  3580. Text1.LinkMode = 0
  3581.  
  3582. t$ = Text1.Text + Chr$(13) + "  "
  3583. x = InStr(t$, Chr$(13))
  3584. y = 0
  3585. Do While x > 0
  3586.   List1(0).List(y) = Left$(t$, x - 1)
  3587.   t$ = Mid$(t$, x + 2)
  3588.   y = y + 1
  3589.   x = InStr(t$, Chr$(13))
  3590. Loop
  3591.  
  3592. For z = 0 To List1(0).ListCount - 1
  3593.   Text1.LinkTopic = "ProgMan|Progman"
  3594.   Text1.LinkItem = List1(0).List(z)
  3595.   Text1.LinkMode = 2
  3596.   Text1.LinkRequest
  3597.   On Error Resume Next
  3598.   Text1.LinkMode = 0
  3599.   t$ = Text1.Text + Chr$(13) + "  "
  3600.   x = InStr(t$, Chr$(13))
  3601.   y = 0
  3602.   Do While x > 0
  3603.     List1(z + 1).List(y) = Left$(t$, x - 1)
  3604.     t$ = Mid$(t$, x + 2)
  3605.     y = y + 1
  3606.     x = InStr(t$, Chr$(13))
  3607.   Loop
  3608.   List1(z + 1).Refresh
  3609. Next
  3610.  
  3611. This works for Norton Desktop (from what I understand) also.
  3612. (Link routines by Jeff Simms. List box routines by Nelson Ford)
  3613. ---------------
  3614.  
  3615.  
  3616. Resource Limits:
  3617.  
  3618. You cannot just keep adding boxes and buttons at will. The limit on the number
  3619. of controls on a form is 255, but you'll likely have resource limitation
  3620. problems long before that.
  3621.  
  3622. An example of resource conservation in Windows in general is to get programs
  3623. out of Program Manager that you do not regularly use.
  3624.  
  3625. To conserve resources in a VB app, try using a Grid box instead of a bunch of
  3626. Text or List boxes to display a lot of information. You can also use Print to
  3627. put captions at specific points on a Form instead of using Label boxes.
  3628. ---------------
  3629.  
  3630.  
  3631. Restart Windows:
  3632.  
  3633. Declare Function ExitWindows% Lib "User" (ByVal dwReserved&, ByVal wReturnCode%)
  3634. x% = ExitWindows(66, 66)
  3635. (Paul Smith)
  3636. ---------------
  3637.  
  3638.  
  3639. SendMessage:
  3640.  
  3641. In the Global module:
  3642. 'type the declaration on one line
  3643. Declare Function Sendmessage Lib "user" (ByVal Hwnd%,
  3644.                                          ByVal Msg%,
  3645.                                          ByVal wParam%,
  3646.                                          ByVal lparam As Any) As Long
  3647.  
  3648. Global Const wm_WinIniChange = &H1A
  3649.  
  3650. Then, for example:
  3651. Sub Command1_Click
  3652. x& = Sendmessage(&HFFFF, wm_WinIniChange, 0, ByVal "")
  3653. End Sub
  3654. ---------------
  3655.  
  3656.  
  3657. Shell-to-DOS Problems:
  3658.  
  3659. When you Shell to DOS to execute a command or a DOS application, Windows tends
  3660. to want to iconize the Shell and continue with the rest of the program.
  3661.  
  3662. In the following example, you would get an error in trying to open MYFILE
  3663. because the COPY command has not been executed yet.
  3664.  
  3665. x = Shell(Environ$("COMSPEC") + " /c COPY A:MYFILE C:", 3)
  3666. Open "MYFILE" For Input as #1
  3667.  
  3668. In the next example, you would get a sharing violation and/or a string of DOS
  3669. icons across the screen:
  3670.  
  3671. For i = 1 to 10
  3672.   x = Shell(Environ$("COMSPEC") + " /c dir c:\ >> c:\testshel", 3)
  3673. Next
  3674.  
  3675. The following code has been suggested as a fix. It does not work for me in the
  3676. Standard Mode, but others have said it works for them.
  3677.  
  3678. Declare Function GetModuleUsage Lib "Kernel" (ByVal hModule%) As Integer
  3679.  
  3680. Sub Form_Load ()
  3681.   For i% = 1 To 10
  3682.     s% = Shell(Environ$("COMSPEC") + " /c dir c:\ >> c:\testshel", 1)
  3683.     While GetModuleUsage(s%)
  3684.       x% = DoEvents()
  3685.     Wend
  3686.   Next
  3687. End Sub
  3688.  
  3689. IMPORTANT NOTICE:
  3690.  
  3691. Some machines will crash after shelling to DOS from Windows. It appears to
  3692. happen only when a math chip is in the system and Windows is in the Standard
  3693. mode -- and then not on ALL such systems.
  3694.  
  3695. At first we thought this was a VB problem, but Keith Funk, Costas Kitsos, Ted
  3696. Young and others have continued to dig into the problem and discovered that it
  3697. can be duplicated (on SOME systems) with any program that uses the math chip.
  3698. If you have a math chip, try the following:
  3699.  
  3700. 1. Start Windows in Standard mode (ie: /S).
  3701. 2. Run the Windows Calculator and minimize it to an icon.
  3702. 3. Open and close a DOS window several times.
  3703.  
  3704. After three or four times, if your system is one of the unfortunate ones, you
  3705. should get an UAE. In Visual Basic, the problem manifests itself in this way:
  3706.  
  3707. In Form_Load, put the following lines and run it:
  3708. For i = 1 to 5
  3709.   x = (Environ$("COMSPEC") + " /c dir c:\", 1)
  3710.   y = DoEvents()
  3711. Next
  3712. You might get a spurious "Illegal function call" on the DoEvents line rather
  3713. than a UAE, but if you keep going, you will get the UAE.
  3714.  
  3715. NOTE: Microsoft has acknowledged that this is a bug in Windows. It appears
  3716. that all we can do is wait for Windows 3.1.  Again -- this problem is limited
  3717. to some machines with math chips that run Windows in Standard mode (normally,
  3718. just 286's).
  3719. ---------------
  3720.  
  3721.  
  3722. Shell-to-DOS Syntax:
  3723.  
  3724. To shell to DOS, you could use the syntax:
  3725. x = ("c:\command.com /c ...
  3726. but this might not give you the right location of command.com. Instead, use
  3727. x = (Environ$("COMSPEC") + " /c ...
  3728. as in the previous section. - Ted Young
  3729.  
  3730. Jonathan Zuck has suggested the following method of shelling to DOS:
  3731.  
  3732. In your declarations:
  3733.   DefInt A-Z
  3734.   Declare Function GetModuleUsage Lib "Kernel" (ByVal hInst)
  3735.  
  3736. In your event/procedure code:
  3737.   Go$ = "c:\batfile.bat"
  3738.   hInst = Shell(Go$, 2)
  3739.   While DoEvents() And GetModuleUsage(hInst) > 0
  3740.   Wend
  3741.  
  3742. George Campbell points out that DoEvents() returns a value equal to the
  3743. number of windows open and that if you have none opened or iconized,
  3744. then the above routine will not work because DoEvents will return 0.
  3745. ---------------
  3746.  
  3747.  
  3748. Shell Error Numbers:
  3749.  
  3750. The manual has an example that says:
  3751.  
  3752. If Shell(File1.FileName, 3 - Index) < 32 Then ...
  3753.  
  3754. The "32" is there because "Shell" always returns a value and any value equal
  3755. to or greater than 32 would indicate an error in trying to Shell.
  3756. ---------------
  3757.  
  3758.  
  3759. Task List Exit Can't Be Stopped:
  3760.  
  3761. Even with "Cancel=-1" in your Form_Unload sub, you cannot stop (in VB) someone
  3762. from closing your app via the Windows Task Manager.
  3763. ---------------
  3764.  
  3765.  
  3766. Temp Files:
  3767.  
  3768. If you are using large graphical objects such as bitmaps or many forms
  3769. with many controls, then as you run and edit (even add a control or two), VB
  3770. makes new temp files for each form to track the latest changes (for saving).
  3771.  
  3772. If you use a Ram disk for Temp file space, a large project could easily
  3773. exhaust the space. So either increase the size of the ram disk, or save more
  3774. often, or go to a disk based temp directory. (Robert Eineigl, MS)
  3775. ---------------
  3776.  
  3777.  
  3778. VB App Cannot Be Windows 3.0 Shell:
  3779.  
  3780. You cannot create a Program Manger replacement with a VB application in
  3781. Windows 3.0, but you CAN in Windows 3.1.
  3782. ---------------
  3783.  
  3784.  
  3785. VBRUN100 Must Be on A:?:
  3786.  
  3787. See "Control Box Exit Bug", above.
  3788. ---------------
  3789.  
  3790.  
  3791. Version (of Windows) Detection:
  3792.  
  3793. DefInt A-Z
  3794. Declare Function GetVersion Lib "Kernel" () As Long
  3795.  
  3796. In your code...
  3797.  
  3798. Ver = GetVersion()             '-- Make the API call
  3799. WinVer = Ver Mod &H10000         '-- Extract the Windows version number
  3800. DosVer = Ver \ &H10000         '-- Extract the DOS version number
  3801.                                '-- Extract the Major and Minor
  3802. '      revisions and build the version
  3803. '   strings.
  3804.  
  3805. WinVersion = Format$(WinVer Mod &H100) + "." + Format$(WinVer \ &H100)
  3806. DosVersion = Format$(DosVer \ &H100) + "." + Format$(DosVer Mod &H100)
  3807. (Gregg Irwin)
  3808.  
  3809. The GetVersion API call will report "3.00" for both versions 3.00 and 3.00a
  3810. since the minor version is still 00 for both. There is no way to detect the
  3811. "a". Windows 3.10 should report in hex "A03".
  3812. ---------------
  3813.  
  3814. Wallpaper Changing:
  3815.  
  3816. Routine 1 uses an undocumented feature of Windows 3.0 to change wallpaper.
  3817. This does not change WIN.INI nor the Windows Palette.
  3818.  
  3819. Routine 2 uses a feature of Windows 3.1 to change the wallpaper, as well
  3820. as changing WIN.INI. This feature also changes the Windows Palette. This
  3821. method does not work with Windows 3.0, so you may need to use both versions.
  3822. Try method 1 first and "on error", goto to method 2.
  3823.  
  3824. 1. For Windows 3.0 Only:
  3825. =======================
  3826. Declare Sub SetDeskWallPaper Lib "User" (byval FileName$)
  3827. Call SetDeskWallPaper(f$) 'where f$ is the name of a BMP file
  3828.  
  3829. will change the wallpaper in Windows, but it will not repaint the screen
  3830. (ie: make the new wallpaper visible) automatically. To accomplish that, you
  3831. must use the following:
  3832.  
  3833. Declare Sub ForceRedraw Lib "User" Alias "InvalidateRect"
  3834.         (ByVal hWnd As Integer,     \
  3835.         lpRect As Long,              >-all this on the line above in your app.
  3836.         ByVal bErase As Integer)    /
  3837.  
  3838. Call ForceRedraw(0, 0&, 0)
  3839.  
  3840.  
  3841. 2. For Windows 3.1 only:
  3842. =======================
  3843. Declare Sub SystemParametersInfo Lib "User"
  3844.    (ByVal wAction%, ByVal wParam%, lParam As Any, ByVal fWinIni%)
  3845.  
  3846. Const SPI_SETDESKWALLPAPER = 20
  3847.  
  3848. Const SPIF_UPDATEINIFILE = 1     'update Win.ini Const
  3849. SPIF_SENDWININICHANGE = 2  'update Win.ini and tell everyone
  3850.  
  3851. SystemParametersInfo SPI_SETDESKWALLPAPER, 0, ByVal BMPFile$,_
  3852.       SPIF_UPDATEINIFILE
  3853. (Jonathan Zuck)
  3854. ---------------
  3855.  
  3856.  
  3857. Why VB Apps Don't Cascade/Tile:
  3858.  
  3859. Forms in VB apps are actually pop-up forms. The VB parent form is invisible.
  3860. This is why functions such as Cascade/Tile in Task Manager will not affect VB
  3861. apps.
  3862. ---------------
  3863.  
  3864.  
  3865. WIN.INI Warning:
  3866.  
  3867. If you use WriteProfileString while WIN.INI is also an open file in an app,
  3868. the data being written will end up in a lost chain. - Dennis Harrington
  3869.  
  3870. You can get rid of the lost chain by doing a CHKDSK /F, but don't forget that
  3871. if you do a CHKDSK /F in a Windows 3 DOS window, you will corrupt your hard
  3872. disk, so exit Windows first.
  3873. ---------------
  3874.  
  3875.  
  3876. "&" in Captions:
  3877.  
  3878. When you put "&" in a Caption, it is a sign for VB to use the next letter as a
  3879. shortcut key. If you really want to display "&" as part of the caption, use
  3880. a pair of ampersands:
  3881.  
  3882. For example, Label1.Caption = "&&HFA3" will display the caption "&HFA3".
  3883. ---------------
  3884.  
  3885.  
  3886. Aligning Text & Format$ Padding:
  3887.  
  3888. 1.
  3889. Only one VB control offers the option of text (Left, Center, Right): a Label.
  3890. Third-party controls often add this option to other controls.
  3891.  
  3892. 2.
  3893. You can manually align text using spaces and Format$, but with great
  3894. limitations. First problem: most fonts are not mono-spaced and thus will not
  3895. line up in columns nicely.
  3896.  
  3897. Second problem: Format$ does NOT pad with spaces the way PRINT USING did.
  3898. For example: List1.Additem "X" + Format$(1.2, "#####.##") results in: "X1.2"
  3899. To align numbers, use a mono-spaced font and -
  3900.           Right$( Space$(nn) + Format$(___, "__________"), nn)
  3901. Example:
  3902.           Right$( Space$(10) + Format$(1.2, "#######.00"), 10)
  3903. results in "      1.20"
  3904.  
  3905.  
  3906. 3.
  3907. A method of aligning proportional text is with TextWidth:
  3908.  
  3909. NumFmt$ = "##,###"
  3910. Numb$ = Format$ (Amount, NumFmt$)
  3911. CurrentX = CurrentX + TextWidth (NumFmt$) - TextWidth (Numb$)
  3912. Print Numb$
  3913. ---------------
  3914.  
  3915.  
  3916. Aligning Text on a Form:
  3917.  
  3918. "SetTextAlign" is a superior way to center text. It not only affects the
  3919. output alignment of the API "Textout" call, but the standard VB "Print"
  3920. statement reacts to it as well.
  3921.  
  3922. Use the following to print a centered line of text on your form:
  3923.  
  3924. Global:
  3925. Global Const TA_NOUPDATECP = 0
  3926. Global Const TA_UPDATECP = 1
  3927. Global Const TA_LEFT = 0
  3928. Global Const TA_RIGHT = 2
  3929. Global Const TA_CENTER = 6
  3930. Global Const TA_TOP = 0
  3931. Global Const TA_BOTTOM = 8
  3932. Global Const TA_BASELINE = 24
  3933. Declare Function SetTextAlign Lib "GDI" (ByVal hDC As Integer,
  3934.                           ByVal wFlags As Integer) As Integer
  3935. Form_Click:
  3936. Lbl$ = "Centered title"
  3937. CurrentX = TheForm.ScaleWidth/2
  3938. CurrentY = 100  'or whatever...
  3939. Result% = SetTextAlign(TheForm.hDC, TA_CENTER + TA_BOTTOM)
  3940. Theform.Print Lbl$
  3941. 'centers output; use other constants for other alignments
  3942. (Bob Scherer)
  3943. ---------------
  3944.  
  3945.  
  3946. Button Colors:
  3947.  
  3948. The BackColor property has (virtually) no effect on the color of the button.
  3949. Button colors are controlled by WIN.INI.  See the 6/11/91 issue of PC Mag
  3950. for details. Of course, changes you make there apply globally.
  3951.  
  3952. An alternative is to simulate a button with a Picture box and a bitmap.
  3953. ---------------
  3954.  
  3955.  
  3956. Buttons with Pictures:
  3957.  
  3958. Making a picture control behave like a pushbutton is relatively easy
  3959. (J. D. Evans, Jr.):
  3960.  
  3961. 1. Draw a bitmap.
  3962. 2. Use the bitmap in a picture control with its DrawMode set to Invert.
  3963. 3. On GetFocus and LostFocus, draw a 1 or 2 width line around the picture
  3964.      control to highlight it (use 0,0 and ScaleWidth-ScaleHeight, black,
  3965.      and B options) the way a button normally looks when it gets focus.
  3966. 4. Have the click event call KeyDown and pass it a KEY_ENTER and then
  3967.      make KeyDown do what you would normally do in a pushbutton click
  3968.      for both KEY ENTER and KEY SPACE (to emulate keyboard).
  3969. 5. On MouseDown and MouseUp do the same thing as you did in GotFocus
  3970.      and LostFocus, except specify NO COLOR parameter and use BF option.
  3971.      the INVERT DrawMode (or style or whatever it is) will take care
  3972.      of making the picture look like a button going up and down.
  3973. Note: if you do not actually do anything in the KeyDown (e.g., call
  3974.      a function or display something), then the picture may get
  3975.      confused as to whether it should be up or down, but then why
  3976.      have a button that actually does nothing other than go up and
  3977.      down! It needs to do something to give everything a chance to
  3978.      get thru the message queue in correct sequence.
  3979.  
  3980. This technique is courtesy of Karl Peterson (who told it to me) and results in a
  3981. very efficient graphic pushbutton that paints QUICKLY!
  3982.  
  3983. P.S. Use Windows Paint to make the BMP file. Alt-PrintScrn will capture the
  3984.      current window to the ClipBoard and you can paste it into Paint and make a
  3985.      BMP that looks just like a pushbutton or anything else!
  3986.  
  3987. P.P.S. When I say 'draw a line' (in 2.) I mean use the DrawLine method/function.
  3988.        It will make sense when you look it up. It looks complicated but is about
  3989.        15 lines of code. Actually drawing the bitmap in Paint is the thing that
  3990.        takes the most time, but you can make some really neat looking buttons,
  3991.        and all with vanilla VB controls.
  3992. ---------------
  3993.  
  3994.  
  3995. Loading Custom Controls:
  3996.  
  3997. To save time loading all the custom controls each time you start a project,
  3998. have a "master" app with all the VBX's in it. Load it and save it immediately
  3999. to a new project name.
  4000. ---------------
  4001.  
  4002.  
  4003. Modal Bugs:
  4004.  
  4005. 1. If you call the Printform method from within a modal window, the window then
  4006. loses its modality. (Jack Freudenheim)
  4007.  
  4008. MS has acknowledged this as a bug and offers this work-around (Don Funk):
  4009.  
  4010. 'form that is displayed modally
  4011. Sub Command1_Click()
  4012.  Const GWL_STYLE = -16
  4013.  Const WS_DISABLED = &H8000000
  4014.    MousePointer = 11
  4015.    PrintForm
  4016.    OldStyle& = GetWindowLong(Form1.Hwnd, GWL_STYLE)
  4017.    X& = SetWindowLong(Form1.Hwnd, GWL_STYLE, OldStyle& Or WS_DISABLED)
  4018.    MousePointer = 0
  4019. End Sub
  4020.  
  4021. 2. A call to InputBox$ will also destroy a form's modality. (Bob Kubelka)
  4022. ---------------
  4023.  
  4024.  
  4025. Modal Form Switching Bug:
  4026.  
  4027. A couple of people have reported that if you have one modal form call up
  4028. another modal form (which then exits back to the original modal form) and
  4029. this call-return procedure is repeated several times, you will get an "out
  4030. stack space" error message.
  4031.  
  4032. The fix is to set focus to a 3rd form's control from either of the two
  4033. modal forms so that the two modal forms to not switch focus back and forth.
  4034.  
  4035. Set a global variable called gDirection.  In the event which calls the 2nd
  4036. modal form (like ModalFrm1.cmdModalFrm2_Click), set this variable to "2" and do
  4037. a "MainForm.cmdOK.Setfocus" AFTER your "Unload ModalFrm1" command.  In the
  4038. Gotfocus event of the Mainform.cmdOK, test for the value of gDirection and
  4039. respond with either a "ModalFrm2.Show 1" or a "ModalFrm1.Show 1". You can
  4040. either unload the 1st modal form when switching between the two, or you can
  4041. hide it for faster showing the second time around. If you opt for the hide
  4042. method, be sure to explicitly Unload both modal forms in the Mainform.Unload
  4043. procedure.
  4044.  
  4045. If you do not have that 3rd visible underlying form, then you're out of luck.
  4046. (Bob Scherer)
  4047. ---------------
  4048.  
  4049.  
  4050. MsgBox Limitations:
  4051.  
  4052. You cannot position a MsgBox at will, nor change its colors, etc. As an
  4053. alternative, consider creating your own MsgBox with a small form.
  4054. ---------------
  4055.  
  4056.  
  4057. No DblClick in Directory List Box:
  4058.  
  4059. The documentation for the DblClick event suggests that the directory list box
  4060. gets this event. This is a documentation error.
  4061. ---------------
  4062.  
  4063.  
  4064. Scroll Bars - Automatic and Manual:
  4065.  
  4066. Vertical scroll bars appear automatically in List Boxes and Combo Boxes when
  4067. the amount of data exceeds the space available.
  4068.  
  4069. For an illustration about how to use the Vertical Scroll Bar control to page
  4070. through data in a file or an array and display a little at a time in a box,
  4071. see RANDGR.EXE and HUGEGR.EXE on DL1 or DL6 of the forum.
  4072. ---------------
  4073.  
  4074.  
  4075. Toolbar Rearranging:
  4076.  
  4077. You can't change the shape/size of the toolbar, but you can force VB to do so!
  4078. Move the toolbar down on the screen so that the last row or two of the controls
  4079. is below the visible portion. Then exit and restart VB. VB will reconfigure the
  4080. toolar for you!  (Mark Novisoff)
  4081. ---------------
  4082.  
  4083.  
  4084. Changing Text:
  4085.  
  4086. Text is read-only, but you can change it by using "Combo1.ListIndex = 3".
  4087. This would select and display the 4th item in the list.
  4088. ---------------
  4089.  
  4090.  
  4091. Color:
  4092.  
  4093. BackColor does not apply to the list portion of the combo box, only the 'edit'
  4094. part.
  4095. ---------------
  4096.  
  4097.  
  4098. Detecting Change:
  4099.  
  4100. In a Combo Box, you only get a CHANGE event if the user actually types inside
  4101. the edit control portion of the control, not if they select an item from the
  4102. list.
  4103.  
  4104. To detect that the user has selected an item from the list, you must use
  4105. either the Click or DblClick events. Using the arrow keys has the same effect
  4106. as .Click. Reportedly there is no keyboard equivalent of DblClick, although
  4107. you can simulate it by setting the default to your "OK" button.
  4108.  
  4109. To determine if a Click actually changed what was in the edit box, you will
  4110. have to set up a variable with the initial data and compare it after the
  4111. Click.
  4112. ---------------
  4113.  
  4114.  
  4115. Pseudo Combo Dropdown List Box:
  4116.  
  4117. To implement a pseudo Combo DropDown List Box like the one used in the VB
  4118. Help/Index/Search Window: As you type text in a Text Box, VB hilights the
  4119. first entry in the List Box that matches what you have typed. This can be
  4120. implemented in VB by using a Text Box, a List Box and the API message
  4121. LB_FINDSTRING.
  4122. ---------------
  4123.  
  4124.  
  4125. Slow Loading of Combo Boxes:
  4126.  
  4127. Combo Boxes are much slower to load data into than List Boxes. Some people
  4128. prefer to make their own "Combo Boxes" by combining a Text Box and a List Box.
  4129.  
  4130. The API CB_ADDSTRING loads a Combo Box 5-10 times FASTER than using the VB
  4131. AddItem method. - Bill Reilly
  4132. ---------------
  4133.  
  4134.  
  4135. "Bad DLL Calling Convention":
  4136.  
  4137. If you get the above error message with a Declare like the following:
  4138.  
  4139. Declare Function bitblt Lib "Gdi" (ByVal destHdc, ByVal X, ByVal Y,
  4140.                                    ByVal w, ByVal h, ByVal srcHdc, ByVal srcX,
  4141.                                    ByVal srcY, ByVal Rop As Long)
  4142.  
  4143. it is because you need "%" of "as integer" after some of the arguments.
  4144. Alternatively, you can use DefInt A-Z, but when using Declares, be sure to pay
  4145. attention to the type of each variable.
  4146. ---------------
  4147.  
  4148.  
  4149. Ending an App from a DLL:
  4150.  
  4151. If you have a system menu with the CLOSE option, then you could make the
  4152. following call from within your dll:
  4153.  
  4154.  X& = SendMessage(Handle, WM_SYSCOMMAND, SC_CLOSE, NULL)
  4155.  
  4156. where
  4157.   Const NULL = 0&
  4158.   Const WM_SYSCOMMAND = &H112
  4159.   Const SC_CLOSE = &HF060
  4160.  
  4161. Don Funk
  4162. ---------------
  4163.  
  4164.  
  4165. Meter From Picture Boxes:
  4166.  
  4167. To make a Meter control from Picture boxes, follow these steps:
  4168.  
  4169. 1. Draw a Picture box and adjust it to the size you want.
  4170. 2. With the Picture box selected, press Ctrl+Ins to copy it to Clipboard.
  4171. 3. With the Picture box still selected, press Shift+Ins to create a second
  4172.      box within the first one.
  4173. 4. When asked if this is an array, say No, and it will be named Picture2.
  4174. 5. Set Picture2's BorderStyle to 0 in the attributes menu.
  4175. 6. Set Picture2's BackColor to a contrasting color.
  4176. 7. Declare StepValue and MaxValue as global variables in Global.bas.
  4177. 8. Enter the following code in your app:
  4178. Sub Form_Load ()
  4179.   Picture2.Width = 1
  4180.   MaxValue = (some number)
  4181.   StepValue = Picture1.Width / MaxValue
  4182. End Sub
  4183. To increase/decrease the gauge:
  4184.   Picture2.Width = Picture2.Width +/- StepValue
  4185. (By Jussi Mattila)
  4186. ---------------
  4187.  
  4188.  
  4189. METER1.VBX Bug:
  4190.  
  4191. METER1.VBX is a graphic meter control on DL1 or DL6. It allows specification of
  4192. max items and number of items complete, and it computes percent complete and
  4193. displays graphical Percent Complete bar.
  4194.  
  4195. If the number of max items are greater than 100, than you get inconsistent and
  4196. crazy results (sometimes). I worked around by always using 100 as max items, and
  4197. did the scaling myself.
  4198. ---------------
  4199.  
  4200.  
  4201. METER1.VBX Display Update:
  4202.  
  4203. To get the meter display to reflect changes, add the following in your loop:
  4204. Meter1.Refresh
  4205. ---------------
  4206.  
  4207.  
  4208. Sound.DLL:
  4209.  
  4210. Here's my DLL written in TPW. I had no documentation besides the Windows
  4211. Programmer's Reference so maybe someone here can tell me if I'm on the right
  4212. track. Some questions come to mind such as: how large should I make the voice
  4213. queue? Is it necessary to open and close the sound device every time I want to
  4214. set a note?
  4215.  
  4216. library SoundDLL;
  4217.  
  4218. uses WinTypes, WinProcs;
  4219.  
  4220. procedure PlayNote(Note, nLength, Cdots: Integer);export; begin
  4221.     OpenSound;
  4222.     SetVoiceAccent(1,100,255,S_NORMAL,0);
  4223.     SetVoiceQueueSize(1,1000);
  4224.     SetVoiceNote(1,Note,nLength,Cdots);
  4225.     StartSound;
  4226.     WaitSoundState(S_QueueEmpty);
  4227.     CloseSound;
  4228.     StopSound; end;
  4229.  
  4230. exports PlayNote index 1;
  4231.  
  4232. begin end.
  4233.  
  4234. The declaration in VB (general):
  4235.  
  4236. Declare Sub PlayNote Lib "e:\tpw\output\soundll.dll" (ByVal note%, ByVal
  4237. Length%, ByVal Cdots%)
  4238.  
  4239. (Mark N.):
  4240. The size of the voice queue is one of those numbers that you simply "Pull out
  4241. of thin air". It depends on what you're going to do. For example, in VBTools,
  4242. we set the queue to 8K because we include several large pieces of music.
  4243.  
  4244. OTOH, if you're going to play single notes on an occasional basis, then 1K
  4245. should be plenty.
  4246.  
  4247. It is not necessary to open and close the sound device every time. In fact,
  4248. if you close it while there are notes in the queue, they'll be lost!
  4249. I suggest that you do what we've done in VBTools:
  4250.  
  4251. 1. Open the sound device when the user first calls your proc.
  4252. 2. If the device is open, then close it when your DLL unloads.
  4253. 3. Give the user a method to close it so that sound can be generated by
  4254.    other apps.
  4255. ---------------
  4256.  
  4257.  
  4258. DLL's Explained:
  4259.  
  4260.    A DLL is a dynamic link library which can be loaded and used by numerous
  4261. programs at the same time.  This saves memory since if it is done the "old"
  4262. way by linking in the libraries at compile/link time, every program that
  4263. uses the code would have to have the same code inside the "EXE".  An example
  4264. is the PRINT statement in QBX.  Every program that you have written (except
  4265. the BRUN code) has the same routine that performs the Print routine.  In
  4266. Windows, you can remove this code from your EXE and put it into a DLL.  That
  4267. way when you have several VB programs that use the Print routine, there is
  4268. only one copy of this routine in memeory.
  4269.    There are several DLL's used by Windows.  USER, GENERAL, KERNEL, and GDI
  4270. are the 4 main DLL's used by Windows.  They have in "their" code functions
  4271. used by all programs in the Windows environment.  Things such as positioning
  4272. the window, painting the background, and moving the cursor are a few
  4273. examples of functions used by all the programs in the environment.
  4274.    There is an excellent book called MS Windows Programmer's Reference.
  4275. This manual lists all(well 99% of them) functions that can be called from
  4276. VB.  Not all functions can be called from VB, and not all of them would you
  4277. want to call, but it does list all of them, so you can take your pick.  It's
  4278. a pretty hefty manual but quite easy to read.  You can get it from MS by
  4279. calling 1-800-426-9400 and asking for kit 1-55615-413-5, called "MS Windows
  4280. Programmer's Reference Manual and Online Resource".  It's is 49.95 but well
  4281. worth it.  It's about 800-1000 pages.
  4282. ---------------
  4283.  
  4284.  
  4285. DLL's Are Slow:
  4286.  
  4287. If you call a C routine in a DLL that assigns strings it will be slower than a
  4288. direct assignment in Visual Basic. Even if the assignment routine is just as
  4289. efficient as VB's, you are adding the overhead of extra calls to get the same
  4290. job done. If you wrote the DLL code in pure .asm instead of calling another
  4291. routine it would probably be closer to VB's time.
  4292. ---------------
  4293.  
  4294.  
  4295. ByVal When Passing Strings:
  4296.  
  4297. I have a question regarding the use of 'C' style DLL return structures.
  4298. So far I've figured out that strings can be used to return values by declaring
  4299. them ByVal if the item returned is an array (i.e. char bozo[20]). What I can't
  4300. figure out is how to get a string which is returned as char far *.
  4301.  
  4302. What does ByVal do when passing strings? My understanding is that this means
  4303. that the contents of the var. should not be modifiable, but this does not seem
  4304. to be the case when passed to a DLL.
  4305.  
  4306. When passing non-strings to DLLs, does omitting the ByVal mean that it can be
  4307. updated by the call?? For example, should parameter declared short far * be
  4308. passed with or without ByVal?
  4309.  
  4310. Fm: Jonathan Zuck (UFI) 76702,1605
  4311.  
  4312. Passing a string ByVal tells VB to append a NULL to the end of it and pass an
  4313. LPSTR to the string. It *is* therefore able to be modified by the DLL as long
  4314. as the DLL is capable of looking for the terminating character. These changes
  4315. will get reflected in the VB string.
  4316.  
  4317. This leads me to you next question. The way to deal with functions that return
  4318. a pointer to a string is to use the LSTRCPY API function to which you would
  4319. pass your VB string (padded with enough spaces) ByVal and the LPSTR you got
  4320. back. There is a function in QuickPak/VB that will simply convert an LPSTR to
  4321. a VB string if you have that package.
  4322.  
  4323. Yes, if you want the DLL to be able to change a numeric parameter, you should
  4324. *not* pass it ByVal. Also make certain that the DLL is expecting a pointer and
  4325. not the value. However, if it plans to change the variable, it would be
  4326. expecting this anyway.
  4327. ---------------
  4328.  
  4329.  
  4330. TPW Framework for DLL's:
  4331.  
  4332. From Rick Sands:
  4333. Here is the basic framework for a Turbo Pascal DLL:
  4334.  
  4335. LIBRARY Pas;
  4336. Uses WinTypes, WinProcs;
  4337. Function FileExist(Filename:pChar):Integer;  EXPORT; { <<-- NOTE }
  4338.   var Fp:File;
  4339.   begin
  4340.      assign(Fp, Filename);
  4341.      {$I-} reset(Fp,1); {$I+} { Open file as Binary }
  4342.      if IOResult = 0 then     { Did it open? }
  4343.      begin
  4344.          FileExist := -1;  { VB True }
  4345.          Close(Fp)         { Don't forget to close }
  4346.      end
  4347.      else
  4348.         FileExist := 0  { VB False }
  4349.   end;
  4350. EXPORT FileExist Index 1;  { <<-- NOTE }
  4351. begin
  4352. end.
  4353.  
  4354. In VB,
  4355. Declare Function FileExist Lib "PAS.DLL" (byval Filename as String) as Integer
  4356. ---------------
  4357.  
  4358.  
  4359. Passing Records:
  4360.  
  4361. Type MyType
  4362.    A As Integer
  4363.    B As Long
  4364. End Type
  4365. Dim Foo(10) As MyType
  4366. X = SomeDLLFunction(Foo(1))
  4367.  
  4368. The DLL will receive a pointer to element 1 of the array. Because
  4369. user-defined types are stored one after the other, the DLL needs to know the
  4370. length of each record, which lets it calculate the address of the subsequent
  4371. records. (Mark Novisoff)
  4372. ---------------
  4373.  
  4374.  
  4375. Passing Strings:
  4376.  
  4377. From John Kesler:
  4378.  
  4379. Thanks to Jonathan Zuck and Mark Novisoff for providing the suggestions used
  4380. here to demonstrate a call to the Paradox Engine function pxTblCreate%. This
  4381. workaround addresses the problem that VB cannot directly pass an array of
  4382. strings to a DLL written for C.
  4383.  
  4384. As you can see below, the technique is to append null values to elements in
  4385. string arrays (so they "look" like zStrings) and then build an arrays of Long
  4386. Ints that point to the address of the strings. As I understand it, the DLL
  4387. gets a pointer to the first string element and finds the pointers to the other
  4388. elements one after the other.
  4389.  
  4390. Global:
  4391. Declare Function pxTblCreate% Lib "pxengwin.dll" (ByVal tblname As String,
  4392.                                                   ByVal nflds As Integer,
  4393.                                                   fnames As Long,
  4394.                                                   ftypes As Long)
  4395.  
  4396. 'In your form or module.
  4397. 'create arrays to hold field names and types
  4398. Static vbnames(2) As String
  4399. Static vbtypes(2) As String
  4400.  
  4401. 'append null value to each string element
  4402. vbnames(1) = "First" + Chr$(0)
  4403. vbnames(2) = "Second" + Chr$(0)
  4404. vbtypes(1) = "A1" + Chr$(0)
  4405. vbtypes(2) = "A2" + Chr$(0)
  4406.  
  4407. 'create arrays to hold the segment selector & offset for each element
  4408. Static names(2) As Long
  4409. Static types(2) As Long
  4410.  
  4411. 'MicroHelp function SSEGADD& returns the segment selector & offset of
  4412. 'each string element
  4413. For x% = 1 To 2
  4414.     fnames(x%) = ssegadd&(vbnames(x%))
  4415.     ftypes(x%) = ssegadd&(vbtypes(x%))
  4416. Next x%
  4417.  
  4418. 'call the pxTblCreate% function with the first element of each array
  4419. retval% = pxtblcreate%("Test", 2, names(1), types(1))
  4420.  
  4421. From Jonathan Zuck:
  4422.  
  4423. Great job! Remember that these addresses are subject to change given any
  4424. further string assignments. Make certain to recalc their SSEGADDs each time
  4425. before you use them.
  4426.  
  4427. Also, the Windows API includes a function that can be used as a SSEGADD
  4428. function if you don't have one of the commercial DLLs. The drawback is that it
  4429. capitalizes the strings but that ain't a problem in this context.
  4430.  
  4431. Declare Function SSegAdd& Lib "Kernel" Alias "AnsiUpper" (byval StrVar$)
  4432. ---------------
  4433.  
  4434.  
  4435. SLIDER Control Bug:
  4436.  
  4437. SLIDER is a free custom control. In the SLIDER custom control example, there is
  4438. an error which causes the control to either repeat an erroneous value or show no
  4439. slider knob.
  4440.  
  4441. The MODEL flag MODEl_fLoadMsg has been omitted which suppresses the VBM_CREATED
  4442. message the control is waiting for to reset it's knob=value to zero. Also the
  4443. MODEL_fArrows flag NOT MODEL_fGetArrows flag must be set. (Manfred Waldmeyer)
  4444. ---------------
  4445.  
  4446.  
  4447. VBPro MDI Child Creation at Runtime:
  4448.  
  4449. The MDI children control arrays can be created at run time. Put the seed on
  4450. the form and set the index to 0 and the visible property to false, the
  4451. controlname to z and maximize a form.
  4452.  
  4453. For i% = 0 To 7000 Step 3000
  4454.     For j% = 0 To 3800 Step 1900
  4455.         If i% <> 0 Or j% <> 0 Then
  4456.             Load z(k%)
  4457.             z(k%).caption = Str$(k%)
  4458.             z(k%).left = i%
  4459.             z(k%).top = j%
  4460.             z(k%).visible = -1
  4461.             z(k%).active = -1
  4462.             k% = k% + 1
  4463.         End If
  4464.     Next j%
  4465. Next i%
  4466. (Robert Eineigl)
  4467. ---------------
  4468.  
  4469.  
  4470. Centering a Form on Screen:
  4471.  
  4472. To center a form on screen:
  4473.  
  4474.  Move (Screen.Width - Width) \ 2, (Screen.Height - Height) \ 2
  4475. (Ted Young)
  4476. ---------------
  4477.  
  4478.  
  4479. Controlling Form Size:
  4480.  
  4481. Set MaxButton to False so the user can't maximize the form.
  4482.  
  4483. General_Declarations:
  4484. Dim OldWidth As Single                       '-- width before resizing.
  4485. Dim OldHeight As Single                      '-- height before resizing.
  4486. Const MinWidth = 6000!, MaxWidth = 9000!     '-- change these values to...
  4487. Const MinHeight = 3000!, MaxHeight = 6000!   '-- the ones you want.
  4488.  
  4489. Sub Form_Load ()
  4490.    OldWidth = Width
  4491.    OldHeight = Height
  4492. End Sub
  4493.  
  4494. Sub Form_Resize ()
  4495.   If WindowState <> 1 then        '-- allows user to minimize window.
  4496.     If Width < MinWidth Or Width > MaxWidth Then
  4497.       Width = OldWidth
  4498.     Else
  4499.       OldWidth = Width
  4500.     End If
  4501.     If Height < MinHeight Or Height > MaxHeight Then
  4502.       Height = OldHeight
  4503.     Else
  4504.       OldHeight = Height
  4505.     End If
  4506.   End If
  4507. End Sub
  4508. ---------------
  4509.  
  4510.  
  4511. Copying/Moving Controls:
  4512.  
  4513. You can copy or move one or more controls from one Form, Frame or Picture box
  4514. to another using the Clipboard:
  4515.  
  4516. 1. Click on the source Form, Frame or Picture box.
  4517. 2. Hold the Ctrl key and, one by one, click on all the controls you want
  4518.    to copy.
  4519. 3. Press Shift-Del (to move) or Ctrl-Insert (to copy).
  4520. 4. Click on the destination Form, Frame, or Picture box.
  4521. 5. Press Shift-Insert.
  4522. ---------------
  4523.  
  4524.  
  4525. Covered Form?:
  4526.  
  4527. Q: I would like to know if there is a way to tell if a window is completely or
  4528. partially covered by another window in Visual Basic.  Even if the covering
  4529. window is not in the same application.
  4530.  
  4531. A: No - nothing straightforward and/or foolproof, anyway.
  4532. ---------------
  4533.  
  4534.  
  4535. Cursor in First Text Box:
  4536.  
  4537. Q: When my program starts, how do I get it to put the cursor into the first
  4538. text box so that the user can start entering data in it immediately?
  4539.  
  4540. A: In the design mode, set the boxes TabIndex (in the Properties list) to 0.
  4541.    During runtime, you can say something like: Text1.SetFocus
  4542. ---------------
  4543.  
  4544.  
  4545. "Floating" Window (Forcing Window to Top):
  4546.  
  4547. (Also see "Overlapping Controls", below.)
  4548.  
  4549. Sometimes you may want a small window to show above the current window, but VB
  4550. does not offer this feature. Routine 1 (courtesy of Ted Young) only works with
  4551. Windows 3.0. Routine 2 (from Mike Mezaros) only works with Windows 3.1.
  4552.  
  4553. 1. For Windows 3.0 only:
  4554. =======================
  4555. Global.Bas:
  4556. Declare Sub SetWindowPos Lib "User" (ByVal hWnd As Integer,
  4557.                                      ByVal hWndInsertAfter as Integer,
  4558.                                      ByVal X as Integer,
  4559.           (put this all on  -->      ByVal Y as Integer,
  4560.            one line)                 ByVal cx as Integer,
  4561.                                      ByVal cy as Integer,
  4562.                                      ByVal wFlags as Integer)
  4563. Declare Function GetWindow Lib "User" (ByVal hWnd as Integer,
  4564.                                        ByVal wCmd as Integer) As Integer
  4565. '  Set WindowPos Flags:
  4566. Global Const SWP_Nosize = &H1
  4567. Global Const SWP_NoMove = &H2
  4568. Global Const SWP_NoActivate = &H10
  4569. Global Const SWP_ShowWindow = &H40
  4570.  
  4571. Form1, Load:
  4572.   Form2.Show  ' this is the "Floating" window
  4573. End Sub
  4574.  
  4575. Form1, Timer1  (set Interval to 50 in Properties)
  4576. Sub Timer1_Timer
  4577.   If GetWindow(Form2.hwnd,0) <> Form2.hWnd Then
  4578.     wFlags = SWP_Nomove or Swp_Nosize or Swp_ShowWindow or Swp_NoActivate
  4579.     SetWindowPos Form2.hWnd, 0, 0, 0, 0, 0, wFlags
  4580.   End If
  4581. End Sub
  4582.  
  4583. 2. "Stay on Top" for Win31 only:
  4584. ===============================
  4585. Declare Function SetWindowPos Lib "User" (ByVal hWnd As Integer,
  4586.   ByVal hWndInsertAfter As Integer, ByVal X As Integer, ByVal Y As
  4587.   Integer, ByVal cx As Integer, ByVal cy As Integer, ByVal wFlags As
  4588.   Integer) As Integer
  4589. wFlags = &H2 Or &H1 Or &H40 Or &H10
  4590.  
  4591. On_Top% = SetWindowPos(Form1.hWnd, -1, 0, 0, 0, 0, wFlags)
  4592. Normal% = SetWindowPos(Form1.hWnd, -2, 0, 0, 0, 0, wFlags)
  4593. (Mike Mezaros)
  4594. ---------------
  4595.  
  4596.  
  4597. Form Size and Granularity:
  4598.  
  4599. Check the "Granularity" under the Desktop settings in the Control Panel. If
  4600. this number is anything but zero, you'll get the effect of all windows only
  4601. being able to be sized and placed by increments of 16 pixels multiplied by the
  4602. Granularity number. Set it to zero and this should fix things.
  4603. ---------------
  4604.  
  4605.  
  4606. Form Wipes, Fades, Etc.:
  4607.  
  4608. You cannot "fade out" a form with screen colors, since VB is limited to 16
  4609. colors, even in SuperVGA, but you can do wipes and fades. Example:
  4610.  
  4611. s = 25  'number of steps to use in the wipe
  4612. hx = Form1.Height / s  'size of horizontal steps
  4613. wx = Form1.Width / s   'size of vertical steps
  4614. For i = 1 To s - 1
  4615.   Move Left + wx \ 2, Top + hx \ 2, Width - wx, Height - hx
  4616. Next
  4617. Unload Form1
  4618. (Also see Screen Wipes under "Screen".)
  4619. ---------------
  4620.  
  4621.  
  4622. Grouped Controls:
  4623.  
  4624. If you want to group a set of controls within another control, such as a
  4625. Frame, you cannot do so by double-clicking the control and moving it into the
  4626. Frame. You must single-click the control and then click-and-drag INSIDE the
  4627. frame (or other control) to draw the added control.
  4628. ---------------
  4629.  
  4630.  
  4631. Iconizing All Forms in a Project at Once:
  4632.  
  4633. You can make all the visible windows in your program minimize to one icon when
  4634. a "main" window is minimized, and then all be restored when that icon is
  4635. double clicked.
  4636.  
  4637. Put some code in the main form's Resize event that tests the WindowState to
  4638. see if it's been minimized (WindowState=1), then change the Visible property
  4639. of all your other forms (this would make only the Main form an icon, if you
  4640. want to iconize the other forms instead of hiding them, you'd change the
  4641. WindowState of the other forms). There's an example of this in the VB Lang Ref
  4642. pg 331 (WindowState).
  4643.  
  4644. When you minimize all the forms, an icon will appear for each one. If you only
  4645. want one icon to appear, use the syntax "FormName.Visible = 0" to hide the
  4646. others.
  4647. ---------------
  4648.  
  4649.  
  4650. Instant Display of Controls:
  4651.  
  4652. To make controls appear more quickly, try placing all the controls in a
  4653. Picture box with no border and the same background as the form. Leave the
  4654. picture box invisible until all the controls are drawn, then make it visible.
  4655. (Dennis L. Harrington)
  4656. ---------------
  4657.  
  4658.  
  4659. Minimizing All Forms At Once:
  4660.  
  4661. If you have one main form and several subsidiary ones, you may want to be able
  4662. to minimize all the forms at once when the main form is minimized.
  4663.  
  4664. The easiest way is to set up a Global flag for keeping track of which forms
  4665. are loaded:
  4666.  
  4667. Global:
  4668.   Global Form2Loaded
  4669.   Global Form3Loaded, etc.
  4670.  
  4671. 'in each form:
  4672. Sub Form2_Load:
  4673.   Form2Loaded = -1
  4674.  
  4675. Sub Form2_UnLoad
  4676.   Form2Loaded = 0
  4677.  
  4678. Sub MainForm_Resize:
  4679.   If WindowState = 1 then 'if main form minimized
  4680.     If Form2Loaded then Form2.Visible = 0
  4681.     If Form3Loaded then Form3.Visible = 0
  4682.     etc
  4683.   Else 'main form maximized
  4684.     If Form2Loaded then Form2.Visible = -1
  4685.     etc
  4686.   end if
  4687. ---------------
  4688.  
  4689.  
  4690. Mouse Pointer, Position:
  4691.  
  4692. Sometimes it nice to be able to place the user's mouse cursor for him. One
  4693. example is when the user has to click on a button to continue, you can put the
  4694. cursor on the button for him.
  4695.  
  4696. Declare Sub SetCursorPos Lib "User" (ByVal x%, ByVal y%)
  4697. example:  Call SetCursorPos(100,200)
  4698.  
  4699. The above code will do a rudimentary job of positioning the cursor.
  4700. Here is some more information about positioning:
  4701.  
  4702. Using the Windows API call SetCursorPos, you can move the mouse to any
  4703. location on the screen. Note that the x & y coordinates are *screen*
  4704. coordinates.  You'll need to translate the coordinates in your VB
  4705. program to screen coordinates.  One way is to get the current coordinates of
  4706. the mouse using GetCursorPos, and then moving the mouse in relation to those
  4707. coordinates.  Note that GetCursorPos returns the coordinates in a Type
  4708. structure (see below).  You can also use the API functions ClientToScreen
  4709. and ScreenToClient to convert the coordinates from the Client (your Form) to
  4710. the Screen, and back.  Experiment with the functions to see which suits your
  4711. purpose, and holler if you have any questions.  Also, I'd recommend
  4712. downloading WINAPI.ZIP which has all the Declares necessary for calling the
  4713. API functions.
  4714.  
  4715.  Declare Sub SetCursorPos Lib "User" (byval x as integer, byval y as integer)
  4716.  Declare Sub GetCursorPos Lib "User" (lpPoint as PointAPI)
  4717.  Declare Sub ClientToScreen Lib "User" (ByVal hWnd As Integer,
  4718.                                         lpPoint As PointAPI)
  4719.  Declare Sub ScreenToClient Lib "User" (ByVal hWnd As Integer,
  4720.                                         lpPoint As PointAPI)
  4721.  Type PointAPI
  4722.    x As Integer
  4723.    y As Integer
  4724.  End Type
  4725. ---------------
  4726.  
  4727.  
  4728. Move Disabling:
  4729.  
  4730. You can keep a user from moving a form by setting BorderStyle in the Form's
  4731. Properties list to "0 - None".
  4732. ---------------
  4733.  
  4734.  
  4735. Moving Controls Cleanly:
  4736.  
  4737. When resizing a form and moving the controls around on it, the screen can look
  4738. very messy. Hiding the form causes a lot of flickering.
  4739.  
  4740. Instead of hiding the form, render invisible the controls being moved until they
  4741. are all moved then make them visible. More code but more esthetic too! (Robert
  4742. Eineigl, Microsoft Product Support)
  4743. ---------------
  4744.  
  4745.  
  4746. Moving Form Without Title Bar:
  4747.  
  4748. A user normally moves a form by clicking and dragging on the title bar. If you
  4749. have a form without a title bar, you have to make other arrangements if you
  4750. want to allow the user to move the form.
  4751.  
  4752. Set a flag in the Form_MouseDown event (eg AllowFormMove=TRUE) and store the
  4753. mouse position (eg MStartX=X MStartY=Y). Then in the mouse move event: If
  4754. AllowFormToMove=TRUE then
  4755.         Form.Left=Form.Left+(X-MStartX)
  4756.         Form.Top=Form.Top+(Y-MStartY)
  4757. End If
  4758.  
  4759. In the Form_MouseUp event reset the flag ( AllowFormToMove=FALSE ).
  4760. (Ian Taylor)
  4761. ---------------
  4762.  
  4763.  
  4764. Moving Multiple Forms Together:
  4765.  
  4766. If you have a related set of forms and would like to move them all if the user
  4767. drag-moves any one of them, it is easy enough to do by setting .Top and .Left
  4768. for each form back to their original relative values when you detect a form
  4769. has been moved. The problem is detecting when a form has been moved. Here is
  4770. a method (suggested by Jonathan Zuck):
  4771.  
  4772. Start your program from a Sub_Main and do the checking in there:
  4773.  
  4774. Sub_Main:
  4775.   Load Form1  (and Form2 and Form3, etc)
  4776.   Do
  4777.     x = DoEvents()
  4778.     If Form1.Top <> Form2.Top (etc.) then MoveForms
  4779.   Loop
  4780. End Sub
  4781.  
  4782. Sub MoveForms:
  4783.   (Either use flags to determine which of the three forms has moved,
  4784.    or check to see which 2 forms are in the same place, which means
  4785.    the other form is the one that moved, then move the other forms.)
  4786. End Sub
  4787.  
  4788. The effect is that "Load Form1" starts your program running, but any time
  4789. the program is awaiting user action, program flow will be in the Do-Loop
  4790. in which the control locations are constantly being checked. The DoEvents
  4791. in the loop allows other things to be done in Windows and in your app.
  4792. ---------------
  4793.  
  4794.  
  4795. Multiple Instances of a Form Not Supported:
  4796.  
  4797. Many people have expressed the desire to set up a form and use multiple
  4798. instances of it during run-time to display different data sets. This is known
  4799. as "MDI" and VB does not support it directly, although the MS Professional
  4800. Toolkit and other 3rd-party add-on's support it.
  4801.  
  4802. One alternative to buying add-on's is to make as many duplicate forms as
  4803. you think you might need.
  4804.  
  4805. Another alternative is to make a separate EXE file with the form that you want
  4806. to use multiple times. Then display it by shelling to it, which you can do
  4807. multiple times. You can pass data to it via DDE or a text file.
  4808. ---------------
  4809.  
  4810.  
  4811. Norton's Desktop, Get in Front of:
  4812.  
  4813. If you are using Norton Desktop for Windows and you have a startup form that
  4814. loads your main form, the main form may be displayed *behind* the
  4815. Windows/Norton groups of icons when you SHOW it.
  4816.  
  4817. In your SUB MainForm_Load, put the SHOW statement *before* you UNLOAD
  4818. StartupForm, rather than after. (Bob Craig)
  4819. ---------------
  4820.  
  4821.  
  4822. Control's Coords. Are Relative to Form:
  4823.  
  4824. Note that when you specify coordinates for the placement of controls within a
  4825. Form, the coordinates start with 0,0 at the top, left corner of the Form; they
  4826. are NOT screen coordinates.  (Bob Craig)
  4827. ---------------
  4828.  
  4829.  
  4830. Overlapping Controls:
  4831.  
  4832. (Also see "Floating" Window, above.)
  4833.  
  4834. VB does not directly support overlapping controls. (Controls placed inside
  4835. Frames and Picture boxes are not considered overlapping controls.) Overlapping
  4836. controls were considered not possible in VB at all until Keith Funk came up
  4837. with the following: (for a complete demo program, get CLPSIB)
  4838.  
  4839. 1. Put the following in the form's General Declarations. You can also put it in
  4840. Global.Bas if you change the Declare's, Const's and Dim's to Global's.
  4841.  
  4842. Declare Function GetFocus Lib "User" ()
  4843. Declare Function ControlhWnd Lib "ctlhwnd.dll" (Ctl As Control) As Integer
  4844. Declare Sub SetWindowPos Lib "User" (ByVal hWnd As Integer,
  4845.                                      ByVal hWndInsertAfter As Integer,
  4846.                                      ByVal X As Integer,
  4847.                                      ByVal Y As Integer,
  4848.                                      ByVal cx As Integer,
  4849.                                      ByVal cy As Integer,
  4850.                                      ByVal wFlags As Integer)
  4851. Declare Function GetWindow Lib "User" (ByVal hWnd As Integer,
  4852.                                        ByVal wCmd As Integer) As Integer
  4853. Declare Function GetNextWindow Lib "User" (ByVal hWnd As Integer,
  4854.                                            ByVal wFlag As Integer) As Integer
  4855. Declare Function GetWindowLong Lib "User" (ByVal hWnd As Integer,
  4856.                                            ByVal nIndex As Integer) As Long
  4857. Declare Function SetWindowLong Lib "User" (ByVal hWnd As Integer,
  4858.                                            ByVal nIndex As Integer,
  4859.                                            ByVal dwNewLong As Long) As Long
  4860. Const WS_CLIPSIBLINGS = &H4000000
  4861. Const SWP_NOSIZE = &H1
  4862. Const SWP_NOMOVE = &H2
  4863. Const GW_HWNDNEXT = 2
  4864. Const GW_CHILD = 5
  4865. Const GWL_STYLE = (-16)
  4866. Dim hWndChild As Integer
  4867. Dim Style As Long
  4868.  
  4869. 2. Create the following subroutine:
  4870.  
  4871. Sub SetClipSiblingBit (ByVal hWndParent As Integer)
  4872.   hWndChild = GetWindow(hWndParent, GW_CHILD)
  4873.   Do
  4874.     Style = GetWindowLong(hWndChild, GWL_STYLE)
  4875.     Style = Style Or WS_CLIPSIBLINGS
  4876.     Style = SetWindowLong(hWndChild, GWL_STYLE, Style)
  4877.     If GetWindow(hWndChild, GW_CHILD) <> 0 Then
  4878.       Call SetClipSiblingBit(hWndChild)
  4879.     End If
  4880.     hWndChild = GetNextWindow(hWndChild, GW_HWNDNEXT)
  4881.   Loop Until hWndChild = 0
  4882. End Sub
  4883.  
  4884. 3. Put the following in Form_Load
  4885.  
  4886.   Form1.Show
  4887.   Call SetClipSiblingBit(Form1.hWnd)
  4888.   'get hWnd for the controls:
  4889.      Grid1.SetFocus
  4890.      G = GetFocus()
  4891.      Text1.SetFocus
  4892.      t = GetFocus()
  4893.   Call SetWindowPos(G, t, 0, 0, 0, 0, (SWP_NOSIZE Or SWP_NOMOVE))
  4894.  
  4895. The example above makes a Text box "float" on top of a Grid control.
  4896. ---------------
  4897.  
  4898.  
  4899. Placing Forms, Controls:
  4900.  
  4901. Sub InitializeWindow
  4902.    Height = Screen.Height * .75
  4903.    Width = Screen.Width * .75
  4904.    Top = (Screen.Height - Height) / 2
  4905.    Left = (Screen.Width - Width) / 2 '
  4906. *** Then place and size your controls.
  4907. End Sub
  4908.  
  4909. If you want to make the form a specific size, then Scale it in inches,
  4910. centimeters, points, or twips (a twip is 1/20th of a point), and don't bother
  4911. making references to Screen.Height or .Width.
  4912.  
  4913. Q:
  4914. My application has a background form and pop-up forms. Sometimes, other
  4915. windows, such as Program Manager, and even icons, get stuck in the middle
  4916. between my background and the popups. How can I force some order in this mess?
  4917.  
  4918. A:
  4919. In each form's GetFocus, you could use the Floating Window routine above to
  4920. force each of the forms in your program to the top.
  4921. ---------------
  4922.  
  4923.  
  4924. Property Bar Errors:
  4925.  
  4926. The height read-out in the gray area on the right side doesn't always
  4927. agree with the Height property.  To see this problem in action, try this:
  4928.   1.  Create a text box.
  4929.   2.  Set the Height property to 1385 using the Settings box.  The height
  4930.       read-out will now read 1385.
  4931.   3.  Click on the form to unselect the text box.
  4932.   4.  Click on the text box to select it.  Now the height read-out says
  4933.       1335 (it should say 1385).
  4934. (John Socha)
  4935. ---------------
  4936.  
  4937.  
  4938. Resizing Forms:
  4939.  
  4940. See "Screen Scaling/Form Resizing" under "Screen"
  4941. ---------------
  4942.  
  4943.  
  4944. ScaleWidth/Height Purpose:
  4945.  
  4946. The .Width and .Height properties will give you the external width of the form.
  4947. The .ScaleWidth and .ScaleHeight properties give you the *internal* dimensions
  4948. of the form.  Keep in mind that the .ScaleWidth and .ScaleHeight values are
  4949. given in terms of the current .ScaleMode which is usually TWIPS.  The good
  4950. thing is if you change the .ScaleMode to something else, it won't matter
  4951. because the placement of the controls is based on the Form's .ScaleMode.  So,
  4952. if you want to keep your Picture box at the full area of the form, then
  4953. you'd do the following in your Form_Resize event:
  4954.  
  4955.    Picture1.Move 0, 0, Form.ScaleWidth, Form.ScaleHeight
  4956.  
  4957. (Ted Young)
  4958. ---------------
  4959.  
  4960.  
  4961. Scrollable Forms:
  4962.  
  4963. If you need to make a form larger than the screen, you can do so by making it
  4964. scrollable. Simply put everything in a Picture box and Move it up and down
  4965. and/or left and right using the Picture1.Top and Picture1.Left properties.
  4966. ---------------
  4967.  
  4968.  
  4969. Unloading Control Arrays:
  4970.  
  4971. Q:
  4972. I am using an array of labels on a drawing to provide visual access to CAD data
  4973. for a PCB board viewing app.  With 50 to 100 labels loaded, I find that exiting
  4974. my app and restarting it is faster than looping thru and unloading each element
  4975. before viewing a new drawing. Is there any way to dump and entire control
  4976. array at once?
  4977.  
  4978. A:
  4979. There's no way (besides looping) to delete (unload) all the elements of a
  4980. control array. However, if you've got 50 or 100 labels you're using too many
  4981. labels which can *severely* affect performance and availability of system
  4982. resources for other Windows program. Have you tried simply using the Print
  4983. statement instead of labels?
  4984.  
  4985. Instead of doing loading/unloading and/or restarting your app, have you
  4986. considered simply setting the .Caption property of all the labels to a null
  4987. string. You might also want to set .Visible=False, depending on if you need all
  4988. the labels for the new drawing.
  4989.  
  4990. ---------------
  4991.  
  4992.  
  4993. Fixed Width Fonts:
  4994.  
  4995. Courier, System and Terminal are fixed width fonts.
  4996. ---------------
  4997.  
  4998.  
  4999. Large Font Bug:
  5000.  
  5001. If you use a large font and then backspace over it, traces of the text will be
  5002. left behind. This is a bug in Windows 3.00, by adding a Refresh to the text
  5003. box (in the _KeyUp event) you can correct the problem.
  5004. ---------------
  5005.  
  5006.  
  5007. Listing Printer Fonts:
  5008.  
  5009. Two problems with listing fonts are that (1) you can get duplicate font names
  5010. in the list and (2) it is difficult to determine available font sizes.
  5011.  
  5012. George Campbell offers the following tips:
  5013.  
  5014. The answer to the first problem is to check the current list of fonts before
  5015. adding the next one. It's a bit slow, but it works. Use a For...Next loop with
  5016. the value List.Fontcount -1 to go through the list box and compare the font
  5017. names with the one you're about to add.
  5018.  
  5019. The second problem is more difficult. What I do is to simply use an On Error
  5020. Resume Next line when specifying font sizes. That way, if the font isn't
  5021. available, the size reverts to the last size selected or to a default size in
  5022. the case of fixed-size fonts. I suppose you could do that check in a For...Next
  5023. loop for the sizes you want to test, exiting the loop if an error occurs.
  5024.  
  5025. Dennis Harrington offers the following tip about duplicate font names:
  5026.  
  5027. It's documented somewhere in the MSKB that this is a bug is win 3.0. So until
  5028. win 3.1, we just have to live with it. There's also a little quicker way to
  5029. parse out duplicates when adding them to a list box. First, concetate all the
  5030. fonts names into a simple string:
  5031.  
  5032.     test$ = ""                                'initiallize a null string
  5033.    numFonts = Screen.FontCount               'Use "Printer" for prt fonts
  5034.    For x = 0 to numFonts                     'make string of all font names
  5035.      test$ = test$ + Screen.Fonts(x)
  5036.    Next x
  5037.  
  5038.     For x = 0 to numFonts
  5039.      v = InStr(1, test$, Screen.Fonts(x))    'find 1st occurance of font
  5040.      z = InStr(v+1, test$, Screen.Fonts(x))  'look for a 2nd occurance
  5041.      If z = 0 then                           'if there are no more occur-
  5042.         ListBox.AddItem Screen.Fonts(x)      'rances of the font, add it
  5043.      End if                                  'to the list box.
  5044.    Next x
  5045.  
  5046. Instead of reading the entire list box for each new font (Very slow!), you only
  5047. need to make 2 very fast InStr calls for each font.
  5048. ---------------
  5049.  
  5050.  
  5051. Metafiles in Place of Fonts:
  5052.  
  5053. If you would like to put your name or your company name in an "about" box,
  5054. but you don't want to use a VB label (because you can't guarantee the font you
  5055. want to use will work on other people's machines), and you don't want to use a
  5056. bitmap, or you want to use "curved" lettering but don't have a fancy graphics
  5057. program...
  5058.  
  5059. Well, if you have Microsoft Word for Windows 2.0, you can use its "Word Art"
  5060. and "Microsoft Draw" mini-apps to create metafiles.  You can use Word-Art to
  5061. create your company/organization name or the program name with fancy features
  5062. like curved letters, shadows, "button" styles, etc; and then copy it to the
  5063. clipboard and paste it directly into a VB form or picture control at design time.
  5064.  
  5065. Best of all, metafiles can be sized from very small to very large without
  5066. distortion.  (Raymond W. Six)
  5067. ---------------
  5068.  
  5069. TrueType Fonts Don't All Show Up:
  5070.  
  5071. Only some of the sizes will be shown in the combo box. But you can click in
  5072. the edit part of the combo box and type your own point size. (Mike Mezaros)
  5073. ---------------
  5074.  
  5075.  
  5076. Using Different Fonts, Colors in a Box:
  5077.  
  5078. The only way to have different colors and fonts in a box is with the .Print
  5079. method in a Picture Box or on the Form itself. No other VB boxes allow
  5080. different colors and fonts.
  5081. ---------------
  5082.  
  5083.  
  5084. System Font:
  5085.  
  5086. ALERT: In a List box using the System font, 9 pitch is non-proportional, 9.75
  5087. is proportional.
  5088. ---------------
  5089.  
  5090.  
  5091. Calling Form_Paint:
  5092.  
  5093. You can call Form_Paint from anywhere within the same form as the _Paint
  5094. method. The only thing you have to know, which isn't documented, is that you
  5095. have to use the word "Form" and *not* the actual name of your form. I use
  5096. Form_Paint all the time. (John Socha)
  5097. ---------------
  5098.  
  5099.  
  5100. Changing Form Name:
  5101.  
  5102. To change the name of a form (not the form's FILE name), select the form and
  5103. pick FormName in the Properties list. This is often overlooked, for some
  5104. reason.
  5105. ---------------
  5106.  
  5107.  
  5108. Detecting a Form's Getting Focus:
  5109.  
  5110. The following will detect when a form gets focus:
  5111.  
  5112. Sub Main
  5113.   hMyTask = GetCurrentTask()
  5114.   hOldTask = hMyTask
  5115.   Form1.Show
  5116.   Do
  5117.     Do
  5118.        Ok = DoEvents()
  5119.        hTask = GetWindowTask (GetActiveWindow)
  5120.     Loop Until hTask <> hOldTask
  5121.     If hTask = hMyTask then
  5122.             Form1_GotFocus
  5123.     Else
  5124.             Form1_LostFocus
  5125.     End If
  5126.     hOldTask = hTask
  5127.   Loop
  5128. End
  5129. (J.Zuck)
  5130. ---------------
  5131.  
  5132.  
  5133. Flashing a Form:
  5134.  
  5135. Declare Function FlashWindow% Lib "user" (ByVal hWnd%, ByVal bInvert%)
  5136.  
  5137. Command1_Click
  5138.   Randomize
  5139.   z& = BackColor
  5140.   For i = 1 to 12
  5141.     FlashColor% = Int(7 * Rnd + 1)
  5142.     BackColor = QBColor(FlashColor%)
  5143.     FlashIt% = FlashWindows(hWnd, 1)
  5144.     For j = 1 to 20: Next
  5145.   Next
  5146.   RestoreIt% = FlashWindows(hWnd, 0)
  5147.   BackColor = z&
  5148.   'from Mike Mezaros' "Executive Decision Maker"
  5149. ---------------
  5150.  
  5151.  
  5152. Focus & Order of Execution:
  5153.  
  5154. Some times VB will delay doing something while it executes more code. For
  5155. example, if you write a lot of stuff to a List box in a tight loop, the List
  5156. box display on the screen will not be shown updated until the code comes to a
  5157. "resting point" (ie: waiting for user input).
  5158. ---------------
  5159.  
  5160.  
  5161. Focus on StartUp:
  5162.  
  5163. If you try to display a form on startup that has your logo, copyright notice,
  5164. etc, you may find that the form displays, but the detail on it does not. You
  5165. have to force VB to wait until the detail is displayed. One way to do that is
  5166. do define a Global variable and when you are finished with the Title box, set
  5167. the variable ("Continue", in the example below) to true (-1).
  5168.  
  5169. Form1_Load:
  5170. TitleForm.Show
  5171. Do
  5172.   x = DoEvents() 'allow control to the system
  5173. Loop Until Continue = -1
  5174.  
  5175. Another way is to "Loop Until Len(Label1.Caption) > 0" (You can omit the >0.)
  5176. This assumes you have a Label1 box, of course.
  5177.  
  5178.  
  5179. Another problem is trying to get some other form to load and to transfer focus
  5180. to it during start-up, and then continuing the start-up. What happens is that
  5181. you can do a Form2.Show, for example, but after the Form2_Load code (if any)
  5182. is run, focus will immediately return to the original form. Users don't get a
  5183. chance to interact with Form2. If Form2 is an installation form, for example,
  5184. the installation will never get done.
  5185.  
  5186. The solution is to use Show Modal (eg: Form2.Show 1), with the possible
  5187. drawback being that you have to Unload the form to return to the calling form.
  5188. ---------------
  5189.  
  5190.  
  5191. Form.GotFocus:
  5192.  
  5193. GotFocus will not be executed for a Form that has a control on it.
  5194. ---------------
  5195.  
  5196.  
  5197. Modal Forms, Unloading:
  5198.  
  5199. You can perform a Form.Hide in the modal form and then unload it when you
  5200. return back to the calling form.
  5201. ---------------
  5202.  
  5203.  
  5204. SetFocus Won't Work?:
  5205.  
  5206. You cannot do a SetFocus until a form is visible. Use Show instead.
  5207. ---------------
  5208.  
  5209.  
  5210. Unloading Forms Completely:
  5211.  
  5212. If you have some reason to suspect that your VB apps aren't exiting as
  5213. completely and cleanly as they are supposed to, you may have a hidden form
  5214. lurking around.
  5215.  
  5216. Make it a point in the main form's Unload proc to unload all other forms
  5217. associated with the app:
  5218.  
  5219. Sub Form_Unload(Cancel As Integer)
  5220.     Unload Form2
  5221.     Unload Form3   ' etc.
  5222. End Sub
  5223. ---------------
  5224.  
  5225.  
  5226. Unloading Forms From Task Manager:
  5227.  
  5228. Form_Unload will not be called if you exit a VB app from the Task Manager.
  5229. MS is aware of this problem.
  5230. ---------------
  5231.  
  5232.  
  5233. Unloading Forms on Windows Termination:
  5234.  
  5235. If Windows is about to terminate, it will invoke your Form_Unload procedure. In
  5236. that proc, you can do whatever you want, including telling Windows to *cancel*
  5237. the shutdown!
  5238.  
  5239. To cancel the Form_Unload, use: Cancel=True.
  5240.  
  5241. It is reported that during a Windows Termination shutdown of your app, if your
  5242. Form_Unload tries to unload other forms, you will get a UAE.
  5243.  
  5244. A work-around is to put a timer on all forms that stay loaded other than my
  5245. main form.  The event for that timer is Form_Unload for the form it is on and
  5246. the design time interval is 0 (timer off).  The Form_Unload for the main form
  5247. can change the timer interval on those forms and unload them without the UAE
  5248. while exiting.  (Barry Simon)
  5249. The file RANDGR.EXE on DL6 shows how to manually scroll data through a Grid.
  5250. ---------------
  5251.  
  5252.  
  5253. What is the Grid Control?:
  5254.  
  5255. The Grid Control is like a List Box divided into columns. It is not part of
  5256. VB, but is in the Professional Toolkit and other 3rd-party add-on's.
  5257. ---------------
  5258.  
  5259.  
  5260. Alternative to a Grid Control:
  5261.  
  5262. For anything other than a very simple grid-type display, it makes more sense
  5263. to buy a third-party grid control. The one in VBTools is superior to the one
  5264. in the MS Professional Toolkit, but the PTK is cheaper.
  5265.  
  5266. For very simple grid-type displays, here is an example of how to make your
  5267. own:
  5268.  
  5269. Sub Form_Paint ()
  5270.   Line (100, 100)-(2500, 2500), , B
  5271.   For XPos = 100 To 2100 Step 400
  5272.     Line (XPos, 100)-(XPos, 2500)
  5273.   Next
  5274.   For YPos = 100 To 2100 Step 400
  5275.     Line (100, YPos)-(2500, YPos)
  5276.   Next
  5277. End Sub
  5278.  
  5279. Sub Command1_Click ()
  5280.   i$ = InputBox$("Enter X and Y coordinates separated by a space", "")
  5281.   XCoord% = Val(Left$(i$, 1))
  5282.   YCoord% = Val(Right$(i$, 1))
  5283.   XCoord% = 100 + ((XCoord% - 1) * 400)
  5284.   YCoord% = 100 + ((YCoord% - 1) * 400)
  5285.   Line (XCoord%, YCoord%)-Step(400, 400), RGB(0, 0, 0), BF
  5286. End Sub
  5287. (Ian Taylor)
  5288. ---------------
  5289.  
  5290.  
  5291. Can't Enter "&":
  5292.  
  5293. You cannot put a single "&" as text in a cell of a Grid. You have to put "&&".
  5294. ---------------
  5295.  
  5296.  
  5297. Graphics in a Grid Cell:
  5298.  
  5299. You cannot draw directly to a cell in the PTK's Grid control. Instead, draw
  5300. to an invisible Picture box then assign the image to the the Grid cell:
  5301.  
  5302. Picture1.Autoredraw = -1
  5303. '  draw stuff on Picture1
  5304. Grid1.Picture = Picture1.Image
  5305.  
  5306. The speed issue can be addressed by building the graphs one by one, and
  5307. transferring to a piclip control via an ordinary control. Then load the grid
  5308. in a loop from the piclip. You redraw the next set while the user sees the
  5309. old. THe following loads in 4 seconds:
  5310.  
  5311. grid1.rows = 6:grid1.cols = 8
  5312. For i = 1 To 6
  5313. grid1.rowheight(i - 1) = 1000
  5314. Next i
  5315. For i = 1 To 8
  5316. grid1.colwidth(i - 1) = 1000
  5317. Next i
  5318. grid1.width = 8.4 * grid1.colwidth(1):grid1.height = 6.4 * grid1.rowheight(1)
  5319. picture1.Move form1.width - picture1.width, form1.height - picture1.height,
  5320. grid1.colwidth(1), grid1.rowheight(1)
  5321. picture1.autoredraw = -1         'THIS IS IMPORTANT. The picture property of
  5322. graph1.drawmode = 3              'graph does not contain the bitmap so
  5323. picture1.picture = graph1.picture 'use VB and autoredraw to create and
  5324. picture1.picture = picture1.image 'then assign to the picture property
  5325.        For i = 1 To 5
  5326.         For j = 1 To 7
  5327.          grid1.row = i
  5328.          grid1.col = j
  5329.          grid1.picture = picture1.picture
  5330.         Next j
  5331.        Next i
  5332. (Robert Eineigl)
  5333. ---------------
  5334.  
  5335.  
  5336. Faster Row Adding/Deleting:
  5337.  
  5338. Inserting a blank line (or deleting a line) in a GRID has always been slow. If
  5339. you have a Grid with 300 rows, and you wanted to insert a new line at row 10,
  5340. you'd have to move 290 rows down, one at a time.
  5341.  
  5342. A MUCH faster way is to define the block of rows to move using .SelStartRow and
  5343. .SelEndRow properties, .Clip it, then select the new block (which begins one
  5344. row down from the previous block) and .Clip it again! It reduced the time
  5345. required to do an insert by 90%.
  5346.  
  5347.      InsertRow% = Grid.Row      'insert a new row at the current row.
  5348.      LastRow%   = Grid.Rows     'last row in the grid.
  5349.  
  5350.      Grid.Rows  = LastRow% + 1  'since we are inserting a new row, our Grid
  5351.                                 'is one row larger than before.
  5352.  
  5353.      Grid.SelStartRow = InsertRow%  'select the block that we are going to
  5354.      Grid.SelEndRow   = LastRow%    'move down.
  5355.      Grid.SelStartCol = 0           'in this example, we've got 9 columns
  5356.      Grid.SelEndCol   = 8           'in the grid.
  5357.  
  5358.      Stuff$           = Grid.Clip   'put the contents of the selected rows
  5359.                                     'and columns into Stuff$
  5360.  
  5361.      Grid.SelStartRow = InsertRow% + 1  'define a new block which starts one
  5362.      Grid.SelEndRow   = LastRow%        'row down from the previous block.
  5363.  
  5364.      Grid.Clip        = Stuff$      'and stuff the old block into the new one.
  5365. (Jim Dolson)
  5366. ---------------
  5367.  
  5368.  
  5369. Changing Icons:
  5370.  
  5371. You can select from a set of icons, using Form1.Icon = ... . You can also draw
  5372. on the icon exactly as if it were a normal-sized form by setting
  5373.    Form1.Icon = LoadPicture()
  5374. Then you can draw on it with normal drawing statements (Line, Circle, etc).
  5375. ---------------
  5376.  
  5377.  
  5378. Getting an Icon from an EXE:
  5379.  
  5380. To extract an icon from an EXE file
  5381. 1. Get the handle to the EXE using FindWindow (assuming its up and running)
  5382. 2. Plug the handle into GetWindowWord with the constant GWW_HINSTANCE to get
  5383.      an hInstance.
  5384. 3. Feed the hInstance into LoadIcon to get an HICON (handle).
  5385. 4. Now assuming you have a DC from a picture control or form already, then
  5386.      use that in DrawIcon.
  5387.  
  5388. Global.Bas:
  5389. Declare Function GetWindowWord Lib "User" (ByVal hWnd As Integer, ByVal
  5390.      nIndex As Integer) As Integer
  5391. Declare Function LoadIcon Lib "User" (ByVal hInstance As Integer, ByVal
  5392.      lpIconName As Any) As Integer
  5393. Declare Function DrawIcon Lib "User" (ByVal hDC As Integer, ByVal X As
  5394.      Integer, ByVal Y As Integer, ByVal hIcon As Integer) As Integer
  5395. Declare Function FindWindow Lib "User" (ByVal lpClassName As Any, ByVal
  5396.      lpWindowName As Any) As Integer
  5397. '  Window field offsets for GetWindowLong() and GetWindowWord()
  5398. Global Const GWW_HINSTANCE = (-6)
  5399.  
  5400. Form1_Declare:
  5401. Dim hInstance, handle, HICON As Integer
  5402.  
  5403. Form1_Click:
  5404. 'handle = FindWindow("TheAPP'sClass", "TheApp'sWindowname")
  5405. handle = FindWindow("Progman", "Program Manager")
  5406. hInstance = GetWindowWord(handle, GWW_HINSTANCE)
  5407. Do
  5408.   HICON = LoadIcon(hInstance, n&)
  5409.   n& = n& + 1
  5410. Loop Until HICON <> 0
  5411.  
  5412. Picture1.Autoredraw = -1
  5413. If DrawIcon(picture1.hDC, 10, 10, HICON) Then Print "OK"
  5414. Picture1.Refresh
  5415.  
  5416. Also note that DrawIcon is also in User not GDI.
  5417. (Robert Eineigl, MS)
  5418. ---------------
  5419.  
  5420.  
  5421. Icon Caption Doesn't MOVE:
  5422.  
  5423. If you use the Move method on your form while it's minimized, the icon will
  5424. move as you would expect it to, but the caption doesn't move with it!!!
  5425. I used Spy to determine that the caption is a separate Window (with a style
  5426. name of "#32767"). (Mark Novisoff)
  5427.  
  5428. As long as you don't have the .Move code in the _Resize event, you can force
  5429. the caption to catch up by simply setting WindowState = 1. That will force a
  5430. kind of Refresh, bringing the caption into place. (Jonathan Zuck)
  5431. ---------------
  5432.  
  5433.  
  5434. Icon - Get Rid Of:
  5435.  
  5436. 1. Click on the form
  5437. 2. Select the Icon property from the properties bar.
  5438. 3. Click on the middle portion of the properties bar, where (icon) shows.
  5439. 4. Press the Del key
  5440. ---------------
  5441.  
  5442.  
  5443. Transparent Background:
  5444.  
  5445. If you create an icon with Icon Works (comes with VB), the area behind the
  5446. icon may be colored in. If you try to do animation with an icon, you will find
  5447. that although the background on the icon may be transparent, the Picture
  5448. control is not, so you see a block moving across the screen.
  5449.  
  5450. To make the background invisible, use IconWorks' "screen inverse" setting and
  5451. paint the background. (Marshal Bostwick)
  5452. ---------------
  5453.  
  5454.  
  5455. An Alternative to Label Boxes:
  5456.  
  5457. You can save system resources by printing directly on a form instead of using
  5458. a Label control:
  5459.  
  5460. LabelText$ = "Some text"
  5461. e = FormName.TextWidth(LabelText$)
  5462. FormName.CurrentX = TextControl.Left - e - (the amount desired for spacing)
  5463. FormName.CurrentY = TextControl.Top (+ or - the desired spacing)
  5464. FormName.Print LabelText$;
  5465. (Dennis L. Harrington)
  5466.  
  5467. You can print 3-D or shadowed text on a form as follows:
  5468.  
  5469.  Picture1.ForeColor = &HC0C0C0  'light gray shadow
  5470.  Picture1.CurrentX = 70  'vary depth to taste
  5471.  Picture1.CurrentY = 70
  5472.  Picture1.Print "This is shadowed or 3D text."
  5473.  Picture1.ForeColor = &H0& 'black
  5474.  Picture1.CurrentX = 50  'vary location to taste
  5475.  Picture1.CurrentY = 50
  5476.  Picture1.Print "This is shadowed or 3D text."
  5477. ---------------
  5478.  
  5479.  
  5480. Captions, Multi-Line:
  5481.  
  5482. You can make a label caption multi-line simply by inserting a CHR$(13):
  5483.    Label1.Caption = "This is Line 1" + Chr$(13) + "This is Line 2"
  5484.  
  5485. This can only be done with code during runtime, not design-time.
  5486. During design time, you can force text down to the next line by
  5487. inserting enough spaces, but this may not stay the way you want it
  5488. on different types of monitors.
  5489.  
  5490. This only works with Label boxes, not Button captions; however, you
  5491. can easily emulate Button controls with Picture boxes and put pretty
  5492. much whatever you want on them. (Nelson Ford)
  5493. ---------------
  5494.  
  5495.  
  5496. Label Box Text Background Color:
  5497.  
  5498. With some light backgrounds for a label box, the background behind each
  5499. individual letter in the box is a different (darker) color. This is a
  5500. "feature" and nothing can be done about it.
  5501. ---------------
  5502.  
  5503.  
  5504. "AddItem #" Error:
  5505.  
  5506. You will get an error that may be hard to figure out if you do a
  5507.    List1.Additem x$, n
  5508. and "n" is a value greater than ListCount.
  5509. ---------------
  5510.  
  5511.  
  5512. Bitmaps in List Boxes:
  5513.  
  5514. To display a bitmap in a list box:
  5515.  
  5516. 1) Load a bitmap into a picture control, and set it's AutoRedraw to True
  5517. 2) Set the Left property to a negative number so it resides off the screen.
  5518. 3) Put the following code in the Form_Paint event sub:
  5519.  
  5520.  
  5521. Success = BitBlt (List1.hDC, DestX, DestY, XPixels, YPixels, Picture1.hDC,
  5522.            0, 0, SRCCOPY)
  5523.  
  5524. Where:
  5525.    List1 is the name of the list box control.
  5526.    DestX is the X coordinate inside the List box.
  5527.    DestY is the Y coordinate inside the List box (both X and Y in Pixels)
  5528.    XPixels is the width (in pixels) of the bitmap
  5529.    YPixels is the height (in pixels) of the bitmap
  5530.    Picture1 is the name of the picture control holding the bitmap
  5531.    0 and 0 are the X/Y coordinates within the picture (0,0)=top/left
  5532.    SRCCOPY is a windows constant  &HCC0020 which tells BitBlt to copy the
  5533.       bits verbatim.
  5534.  
  5535. Here is the syntax for declaring BitBlt in VB:
  5536.  
  5537. Declare Function BitBlt Lib "GDI" (ByVal hDestDC As Integer, ByVal X As I
  5538.  ByVal Y As Integer, ByVal nWidth As Integer, ByVal nHeight As Integer,
  5539.  ByVal hSrcDC As Integer, ByVal XSrc As Integer, ByVal YSrc As Integer,
  5540.  ByVal dwRop As Long) As Integer
  5541. (Carl Franklin)
  5542. ---------------
  5543.  
  5544.  
  5545. Capacities:
  5546.  
  5547. The List Box should handle strings up to around 1K in length with a total size
  5548. around 64K. Your mileage may vary, as Bill Reilly discovered: Combo boxes and
  5549. List boxes will only accept up to 5440 lines. Try this:
  5550.  
  5551. For i = 1 to 10000
  5552.   List1.AddItem "x"
  5553. Next
  5554.  
  5555. It will bomb out at i = 5440
  5556. ---------------
  5557.  
  5558.  
  5559. Clear a List Box:
  5560.  
  5561. The following routine will quickly clear a list box:
  5562.  
  5563. Global:
  5564.  Declare Function SendMessage% Lib "user" (ByVal hWnd%,_
  5565.                                            ByVal wMsg%,_
  5566.                                            ByVal wParam%,_
  5567.                                            ByVal lParam&)
  5568.  Declare Function GetFocus% Lib "user" ()
  5569.  Declare Function PutFocus% Lib "user" Alias "SetFocus" (ByVal hWnd%)
  5570.  
  5571. Form Declarations:
  5572.  Const WM_USER = &H400
  5573.  Const LB_RESETCONTENT = WM_USER + 5
  5574.  
  5575. Sub ClearListBox (Ctrl As Control)
  5576.   hWndOld% = GetFocus()
  5577.   Ctrl.SetFocus
  5578.   x = SendMessage(GetFocus(), LB_RESETCONTENT, 0, 0)
  5579.   Suc% = PutFocus(hWndOld%)
  5580. End Sub
  5581. ---------------
  5582.  
  5583.  
  5584. Finding an Item Added to a Sorted List Box:
  5585.  
  5586. When you AddItem to a Sorted List Box, the lines displayed in the List Box do
  5587. not automatically change so that the new item is displayed. You can search for
  5588. the new item manually (see next Tip) or instead of using List.AddItem, use the
  5589. following:
  5590.  
  5591. SendMessage(hWnd, LB_ADDSTRING, wParam, lParam).
  5592.  
  5593. This adds the item to the list and returns the ListIndex of the newly added
  5594. item. Here is the complete routine (from Bob Scherer):
  5595.  
  5596. In the Global module, declare the following constants & functions:
  5597.  
  5598. Global Const WM_USER = &H400
  5599. Global Const LB_ADDSTRING = (WM_USER + 1)
  5600. Declare Function GetFocus Lib "user" () As Integer
  5601. Declare Function SendMessage Lib "User" (ByVal hWnd As Integer,
  5602.                                          ByVal wMsg As Integer,
  5603.        (all this on one line)-->         ByVal wParam As Integer,
  5604.                                          ByVal lParam As Any) As Long
  5605.  
  5606. In the procedure where you want to do the "AddItem" use this code:
  5607.  
  5608. List1.SetFocus
  5609. LbhWnd = GetFocus()
  5610. RetVal& = SendMessage(LbhWnd, Lb_AddString, WParam, MyInput$)
  5611. List1.ListIndex = RetVal&
  5612. ---------------
  5613.  
  5614.  
  5615. Finding an Item Manually:
  5616. (Also see the preceding and following Tips.)
  5617.  
  5618. The following routine uses a binary search to find an item in a sorted List
  5619. box:
  5620.  
  5621. Object: (general)  Proc: FindItem
  5622. Sub FindItem (Lst as Control, a$)
  5623. U = Lst.ListCount
  5624. L = 0
  5625. Do
  5626.   If U < L Then
  5627.     MsgBox "Not Found"
  5628.     Lst.ListIndex = I 'set .ListIndex to nearest match
  5629.     Exit Sub
  5630.   End If
  5631.   I = (L + U) / 2
  5632.   If a$ = Lst.List(I) Then
  5633.     Lst.ListIndex = I  'Found. Set ".ListIndex" accordingly
  5634.     Exit Sub
  5635.   ElseIf a$ > Lst.List(I) Then
  5636.     L = I + 1
  5637.   Else
  5638.     U = I - 1
  5639.   End If
  5640. Loop
  5641. (Nelson Ford)
  5642. ---------------
  5643.  
  5644.  
  5645. Finding an Item via API:
  5646.  
  5647. The following routine will search a List box, sorted or unsorted, for the
  5648. first occurrence of a specified string.
  5649.  
  5650. Declare Function SendMessage& Lib "user" (ByVal hWnd%, ByVal wMsg%,
  5651.                                           ByVal wParam%,
  5652.                                           ByVal lParam As String)
  5653. Declare Function Getfocus% Lib "user" ()
  5654. Dim ListHwnd As Integer
  5655.  
  5656. Sub Form_Click ()
  5657.    List1.AddItem "John"
  5658.    List1.AddItem "George"
  5659.    List1.AddItem "Sue"
  5660. End Sub
  5661.  
  5662. Sub Text1_Change ()
  5663.    Const LB_SELECTSTRING = &H400 + 13
  5664.    Static X As Long
  5665.    wParam = 1
  5666.    lParam$ = Text1.Text + Chr$(0)
  5667.    X = SendMessage(ListHwnd, LB_SELECTSTRING, wParam, lParam$)
  5668.    Print X
  5669. End Sub
  5670.  
  5671. Sub Form_Load ()
  5672.    Form1.Show
  5673.    List1.SetFocus
  5674.    ListHwnd = Getfocus()
  5675. End Sub
  5676.  (Don Funk, MS)
  5677.  
  5678. Note that LB_SelectString will NOT get the index of a string specification
  5679. if it is more than the first word. (eg: finds "John" but not "John Smith".)
  5680. (Robert Werning)
  5681. ---------------
  5682.  
  5683.  
  5684. Font Size Changes List Box Size:
  5685.  
  5686. If you change font sizes during runtime, VB will change the size of the List Box
  5687. to adjust it so that partial lines are not shown. This causes an unwanted
  5688. change in your display, and VB does not let you disable this feature.
  5689.  
  5690. The ratio between 8.25 print size and 9.75 is around 1.2 and if you set the
  5691. number of lines with this ratio in mind, the number of lines displayed can
  5692. change without changing the size of the List Box.
  5693.  
  5694. For example, 6, 11, or 22 lines of 8.25 text will convert to 5, 9, or 18 lines
  5695. at 9.75.  (Keith Funk)
  5696. ---------------
  5697.  
  5698.  
  5699. Forcing an Item Number to the Top:
  5700.  
  5701. To force a particular item number in a List Box to be at the top of the box,
  5702. enter the following two lines:
  5703.  
  5704. List1.ListIndex = List1.ListCount - 1
  5705. List1.ListIndex = ItemNumberWanted
  5706.  
  5707. If you do not enter the first line, the line you want will be in the List Box,
  5708. but not necessarily at the top of it.
  5709. ---------------
  5710.  
  5711.  
  5712. Inhibiting Screen Updating:
  5713.  
  5714. If you are adding a whole bunch of items to a list box all at once like
  5715. assigning items from an array from within a loop, you might want to use the API
  5716. WM_SETREDRAW message to prevent the list box from being continually updated on
  5717. the screen as each item is added. Not only does this stop the flickering, but it
  5718. makes adding the items much faster.
  5719.  
  5720. A simpler method is just set the List box's Visible property to 0 and reset it
  5721. to -1 when done, although this will cause the List box to disappear completely.
  5722. ---------------
  5723.  
  5724.  
  5725. Linking Sorted and Unsorted List Boxes (or Arrays):
  5726.  
  5727. You may need to link data in an array or an unsorted list box to data in a
  5728. sorted List box; however, when an element is added to a sorted List box or if
  5729. you manually sort an unsorted List box, the array or related List box will no
  5730. longer be in sync with the sorted List box..
  5731.  
  5732. There are several ways to keep the two in sync:
  5733.  
  5734. One way is to use the routines under "Finding an Item...", above, and then
  5735. adjust the unsorted array or List box accordingly. The file VBSORT on DL6
  5736. illustrates how to sort a List box and an array at the same time.
  5737.  
  5738. Another way is to add a pointer at the end of each item in the sorted List
  5739. box. By tabbing over far enough, the pointer will not show up in the List box.
  5740. This method is not ideal if the contents of the List box will be approaching
  5741. the 64k space limit, since adding a pointer takes up space in the List box.
  5742.  
  5743. A third way is to append a 4-byte value to each item in a List Box by using
  5744. the LB_SETITEMDATA message and you can retrieve the value using the
  5745. LB_GETITEMDATA message.
  5746.  
  5747. The tag is created when you add an item to the List Box. The value of the tag
  5748. can be retrieved at anytime. This approach requires a good deal of familiarity
  5749. with API calls.
  5750. ---------------
  5751.  
  5752.  
  5753.  
  5754. "ListIndex = -1" Generates Click Event:
  5755.  
  5756. If you use "List1.ListIndex = -1" to unselect a highlighted item in a List
  5757. box, a (probably unwanted) click event will be generated.
  5758.  
  5759. To negate the unwanted click action, add the following line to List1_Click:
  5760. If List1.ListIndex = -1 Then Exit Sub
  5761. (Selden McCabe)
  5762. ---------------
  5763.  
  5764.  
  5765. Selecting Multiple Items:
  5766.  
  5767. The VB List Box does not directly support selecting multiple items.
  5768.  
  5769. MULTIPK is a sample project that shows how to create a VB List box that DOES
  5770. allows selecting multiple items. Look for it in the MSBASIC forum or in PsL.
  5771. ---------------
  5772.  
  5773.  
  5774. Tab Stops:
  5775.  
  5776. Q:
  5777. I have downloaded App Note Q71067 on "How to Set Tab Stops Within a List Box".
  5778. The sample code in the note works fine, but if I change the lengths of the
  5779. quoted elements in the list, the example falls apart. It appears that there are
  5780. pre-existing tab stops *between* the stops I create! Does anyone know if this
  5781. is, indeed, true? And if so, how do I clear the preexisting tab stops before I
  5782. load in my own.
  5783.  
  5784. A:
  5785. The LB_SETTABSTOPS does not use character units, but a Dialog unit based on
  5786. the currect system font width and height.  This means you may have to adjust
  5787. the tabstop values to a larger size depending on the fontname and fontsize.
  5788.  
  5789. Try increasing the values and use a mono-spaced font to get an idea of how it
  5790. works, it is a pain!
  5791. ---------------
  5792.  
  5793.  
  5794. AppName.Caption Problem:
  5795.  
  5796. Page 118 of the Programmer's Guide shows how to dynamically adding items to a
  5797. menu. About 3/4ths of the way down the page, it shows a routine with the last
  5798. line being:  AppName(LMenu).Caption = FileSpec$
  5799.  
  5800. If you follow this example, you will get another separator bar. To get the
  5801. FileSpec$ to show, you must add the following line:
  5802.  
  5803. AppName(LMenu).Separator = 0
  5804. ---------------
  5805.  
  5806.  
  5807. Calling Help for Menu Items:
  5808.  
  5809. It would be nice to be able to call the Windows Help Engine from a menu where,
  5810. if a user has a menu selection highlighted and hits F1 or Sh-F1 then help will
  5811. come up for that menu item.
  5812.  
  5813. Here's how to detect those keypresses:
  5814.  
  5815. 1. Global - declarations
  5816.   Global HelpTopic%
  5817.   ' Also, set up some constants to use for help topics here. It will
  5818.   ' make your program much more readable
  5819.  
  5820. 2. In each menu item's Click proc:
  5821.    Sub Ctlname_Click
  5822.        ' You can also sprinkle statements like this in appropriate
  5823.        ' areas of your code if you like.
  5824.        HelpTopic% = One_of_the_CONST_items
  5825.    End Sub
  5826.  
  5827. 3. In each control's keydown proc:
  5828.    Sub CtlName_Keydown(.....)
  5829.        CheckHelp Shift, KeyCode
  5830.    End Sub
  5831.  
  5832. 4. In a module (or the form, if it's a single form program)
  5833.    Sub CheckHelp(Shift%, KeyDown%)
  5834.        If Shift% = DesiredShiftStatus and KeyDown% = HelpKey Then
  5835.           ' Invoke WINHELP here, passing HelpTopic%
  5836.        End If
  5837.    End Sub
  5838. (Mark Novisoff, MicroHelp)
  5839. ---------------
  5840.  
  5841.  
  5842. ClipBoard Status:
  5843.  
  5844. If you have a menu set like the following:
  5845.  
  5846.   Edit
  5847.     Cut
  5848.     Paste
  5849.     Copy
  5850.  
  5851. and you want to gray out Paste and Copy when the clipboard is empty, then
  5852. check the clipboard's contents as soon as "Edit" is clicked and
  5853. modify the enabled property of the Paste and "Copy selections accordingly.
  5854. ---------------
  5855.  
  5856.  
  5857. Disabling Menu Items:
  5858.  
  5859. There's an example in the VB manual that shows how to enable and disable menu
  5860. items as a menu is opened. Let's say I have a "File" Menu with CtlName
  5861. FileMenu, and "Open" and "Save" items on that menu with CtlNames of FileOpen
  5862. and FileSave respectively, and I want the "Save" Menu item to be Enabled or
  5863. disabled depending upon whether a file is currently open.
  5864.  
  5865. As an extension of the example in the manual, I might intercept the
  5866. FileMenu_Click event, then set the FileSave.Enabled property. This method is
  5867. acceptable, unless there is an accelerator key associated with the FileSave
  5868. menu item. In that case, the FileSave.Enabled property may not have be set
  5869. correctly when the user presses the shortcut key, unless the FileMenu has been
  5870. opened in the mean time. (Steve Schmidt)
  5871. ---------------
  5872.  
  5873.  
  5874. Focus Doesn't Change:
  5875.  
  5876. If you choose a menu item that executes another procedure, the control that
  5877. had focus before the menu selection never loses it; that is: LostFocus for
  5878. that control is not executed before the menu's procedure is executed.
  5879.  
  5880. You can manually trigger it if you know which control had focus by entering,
  5881. for example, Call Text1_LostFocus. You can determine which control had focus
  5882. by setting up a set of flags to keep track of each control. For example:
  5883.  
  5884. Global Command1Focus
  5885.  
  5886. Command1_GotFocus
  5887.   Command1Focus = -1
  5888. ---------------
  5889.  
  5890.  
  5891. Right Justify "Help":
  5892.  
  5893. In Windows 3.0 menu bars, "Help" is right-justified. In past VB-Tips, we had
  5894. some complex ways to right-justify your own Help menu heading, but it turns
  5895. out that you can do it with one line of code added to the Load procedure:
  5896.  
  5897.    Help.Caption = Chr$(8) + Help.Caption
  5898.  
  5899. This came from a suggestion by Michael Partsch. His suggestion included
  5900. setting up all menu headings as an array, but a quick test showed that the
  5901. array is not necessary.
  5902.  
  5903. It should be noted that the preferred design in Windows 3.1 is NOT to right
  5904. justify Help.
  5905. ---------------
  5906.  
  5907.  
  5908. Screen Flicker on Selection:
  5909.  
  5910. Q:
  5911. I have a VB app whose main window has a variable menu. I make some of the
  5912. entries visible or invisible depending upon circumstances. The problem I am
  5913. encountering is the amount of screen flicker when this menu change occurs.
  5914. Dropping one item and adding another on the menu bar causes a lot of flicker on
  5915. the whole screen, and takes display time to boot!
  5916.  
  5917. A:
  5918. You can set the .Visible property of the "main" item to 0, update the menu,
  5919. then set .Visible back to -1.
  5920. ---------------
  5921.  
  5922.  
  5923. An Alternative to Picture Boxes:
  5924.  
  5925. Picture boxes eat up a lot of system resources. An alternative is to put the
  5926. picture directly on the Form rather than using a Picture box. The code is
  5927. fairly simple and straightforward, as shown in the example below which is
  5928. used to perform animation on the About form in one of my apps:
  5929.  
  5930. 'put in your Declares:
  5931. DefInt A-Z
  5932. Declare Function BitBlt Lib "GDI" (ByVal hDestDc, ByVal x, ByVal y,
  5933.    ByVal nWidth, ByVal nHeight, ByVal hSrcDC, ByVal XSrc, ByVal YSrc,
  5934.    ByVal dwRop As Long)  'all on one line, of course
  5935. Global Const SrcCopy& = &HCC0020
  5936.  
  5937. 'animation sub:
  5938. Fsm = Form1.ScaleMode
  5939. Form1.ScaleMode = 3
  5940. Picture1.ScaleMode = 3
  5941. Picture1.AutoRedraw = -1
  5942. SrcCopy& = &HCC0020
  5943. For x = Form1.scalewidth To (Form1.scaleleft - Picture1.scalewidth) Step -1
  5944.   ret = BitBlt(Form1.hdc, x, y, Picture1.Width, Picture1.Height,
  5945.            Picture1.hdc, 0, 0, SrcCopy&)
  5946. Next
  5947. Form1.ScaleMode = Fsm
  5948.  
  5949. The above simply moves the picture from the right of the form to the left.
  5950. "x" and "y" are the locations on the form. Picture1 is located on out of
  5951. sight on the form. Multi-cell animation can be done by using multiple
  5952. pictures. To place a fixed image on a Form, just eliminate the loop, of
  5953. course. (Nelson Ford)
  5954.  
  5955. You can also conserve resources by combining pictures into one Picture1
  5956. box and BitBlt-ing the desired form to the Form or another Picture box.
  5957. The following code by Jeff Simms shows how to use a combined set of 9
  5958. pictures as a tool bar from which the user can select by clicking the
  5959. mouse:
  5960.  
  5961. Picture1 (autoredraw false) stores a bitmap with all the tool icons (9).
  5962. Picture2 (autoredraw true), twice the height of the first one, stores a bitmap
  5963. with all the Up tool icons on the top half of the bitmap and all the Down tool
  5964. icons on the bottom half.
  5965.  
  5966. After setting the scalemode for both boxes to pixels, I used the following code
  5967. to transfer the DOWN tool icon to Picture1:
  5968.  
  5969. Sub Picture1_MouseDown (Button As Integer, Shift As Integer, X As Single,
  5970.      Y As Single)
  5971.  
  5972. N = Int(X / (Picture1.ScaleWidth / 9) + 1) 'icon selected
  5973. Z = Picture1.ScaleWidth / 9 'width of icon
  5974. L = Z * (N - 1) + N  'X for BitBlt - 1 pixel adjustment per icon
  5975. I = BitBlt(Picture1.hdc, L, 0, Z, Picture1.ScaleHeight, Picture2.hdc, =>L,
  5976.      Picture2.ScaleHeight / 2 + 1, SRCCOPY) '1 pixel adjustment for YSrc
  5977.  
  5978. End Sub
  5979.  
  5980. You can also use BitBlt with DSTINVERT and just one picture box
  5981.  
  5982. You can easily combine graphics into a single Picture box by first laying
  5983. them out next to each other on a form using separate Picture boxes, then
  5984. use PrintScreen to capture them and Paintbrush to clip and save them.
  5985. ---------------
  5986.  
  5987.  
  5988. As Buttons:
  5989.  
  5990. You can use a Picture Box to create a button with whatever graphics you want
  5991. on it. However, the Click event code will only be executed only if the mouse
  5992. cursor is still over the control when it is released. This could cause
  5993. problems.
  5994. ---------------
  5995.  
  5996.  
  5997. AutoRedraw:
  5998.  
  5999. BitBlt works faster with AutoRedraw OFF. The problem is that SavePicture
  6000. Picture1.Image only works with AutoRedraw ON. A solution is to leave
  6001. AutoRedraw Off while you do your drawing and then use the following code to
  6002. BitBlt the non-persistent image that you just created to the persistent image.
  6003. Note that AutoRedraw is OFF when this code executes.
  6004.  
  6005. ScrnhDC = Picture1.hDC          'Handle to non-persistent image.
  6006. Picture1.AutoRedraw = True
  6007. PersistenthDC = Picture1.hDC   'Handle to persistent image.
  6008. 'BitBlt from ScrnhDC to the PersistenthDC.
  6009. Picture1.AutoRedraw = False
  6010.  
  6011. In addition, I sometimes follow this with Picture1.Picture = Picture1.Image.
  6012.  
  6013. This gives me three different levels of 'protection'. Picture1.Cls with
  6014. AutoRedraw OFF erases the non-persistent image only. Picture1.Cls with
  6015. AutoRedraw ON erases both the persistent and non-persistent images, but
  6016. preserves the Picture Property image. And Picture1.Picture = LoadPicture() zaps
  6017. all three images.
  6018.  
  6019. This works great for graphics created by VB graphics commands and the API
  6020. PolyLine Function.  - KeithF
  6021. ---------------
  6022.  
  6023.  
  6024. BitBlt to/from Hidden Box:
  6025.  
  6026. If you want to BitBlt from/to a non-visible picture control, make sure the
  6027. AutoRedraw property is set to TRUE.
  6028. ---------------
  6029.  
  6030.  
  6031. "Box" Command:
  6032.  
  6033. There's no explicit BOX command, but it's part of the LINE syntax. Check out the
  6034. manual for the syntax (pg 172).
  6035. ---------------
  6036.  
  6037.  
  6038. To Clipboard as Metafile?:
  6039.  
  6040. Q: How I copy the contents of the picture box to the clipboard as a metafile?
  6041. Just using the metafile parameter doesn't work.
  6042.  
  6043. A: The graphic methods create BMPs, not Metafiles.
  6044. ---------------
  6045.  
  6046.  
  6047. Copying a Drawing to Clipboard:
  6048.  
  6049. The following will work, IF Picture1.AutoRedraw is True.  (J. Zuck)
  6050.  
  6051. Sub Picture1_Click ()
  6052.    ClipBoard.Clear
  6053.    Picture1.Circle (1000, 1000), 500
  6054.    ClipBoard.SetData (Picture1.Image)      'Picture1.Picture won't work.
  6055. End Sub
  6056.  
  6057. Sub Picture2_Click ()
  6058.    Picture2.Picture = ClipBoard.GetData()  'Picture2.Image is illegal.
  6059. End Sub
  6060. ---------------
  6061.  
  6062.  
  6063. Copying Text in a Picture:
  6064.  
  6065. If you use the Print command ("Picture1.Print...") to print text in a Picture
  6066. box, that text will NOT be copied if you use a command like "Picture2.picture
  6067. = Picture1.picture". You have to re-print the text in the second box.
  6068. ---------------
  6069.  
  6070.  
  6071. Cutting-Pasting to a Picture Box:
  6072.  
  6073. Fm: Don Funk (SL) 76701,155
  6074.  
  6075. The code that follows demonstrates how to place the pawn from the CHESSS.BMP
  6076. (that comes with Windows) into a picture control.
  6077.  
  6078. 1. Create the following controls using the Properties Bar:
  6079.  
  6080.      CntlName        Height    Left    Top     Width
  6081.      Form1           4920                      7305
  6082.      Picture1        2295       360    4440    2535
  6083.      Picture2        2415      4080    1560    2535
  6084.      Command1         855      3600     240    1695
  6085.  
  6086.      Form1.Picture = Picture("c:\win\chess.bmp")
  6087.      Picture1.Visible = FALSE
  6088.      Picture1.AutoRedraw = TRUE
  6089.      Picture1.scalemode = PIXEL
  6090.      Picture2.scalemode = PIXEL
  6091.  
  6092. 2. Enter the following code:
  6093.    Global.bas:
  6094.      (Get the Declare Function BitBlt Lib from "Saving Picture Files" further
  6095.       down in the VB-TIPS file.)
  6096.  
  6097.    Sub Command1_Click ()
  6098.      '* Handle for the destination bitmap.
  6099.      hDestDC% = Picture1.Hdc
  6100.     '* X% & Y% coordinates of the invisible bitmap
  6101.      X% = 0: Y% = 0
  6102.      hSrcDC% = Form1.Hdc
  6103.     '* Specified X1 & Y1 coordates of the bitmap to clip.
  6104.      XSrc% = 80
  6105.      YSrc% = 25
  6106.     '* Specify the dimensions of the bitmap to copy.
  6107.      nWidth% = 110
  6108.      nHeight% = 110
  6109.      '* Specify source copy{SRCCOPY}
  6110.      dwRop& = &HCC0020
  6111.      '* Copy section of the bitmap to the hidden picture control.
  6112.      S% = BitBlt%(hDestDC%, X%, Y%, nWidth%, nHeight%,
  6113.                        hSrcDC%, XSrc%, YSrc%, dwRop&)
  6114.      '* Copy to the clipboard.
  6115.      clipboard.SetData Picture1.Image, 2
  6116.      '* Copy to the Picture2 control.
  6117.      Picture2.Picture = clipboard.GetData(2)
  6118. End Sub
  6119. ---------------
  6120.  
  6121.  
  6122. Dragging A Full Picture:
  6123.  
  6124. Q: How can I drag a picture control whole, instead of just the outline, and
  6125. still have all the drag-and-drop functions?
  6126.  
  6127. A: Sorry, you can't have both. See the program Accordian Solitaire in the file
  6128. listing for an example of dragging and dropping.
  6129. ---------------
  6130.  
  6131.  
  6132. Dragging Text Box in Picture:
  6133.  
  6134. The following is code by Don Funk for dragging a Text box in a Picture box:
  6135.  
  6136. Declare Function SetParent% Lib "user" (ByVal H%, ByVal H%)
  6137. Const DRAG_START = 1
  6138. Const DRAG_STOP = 2
  6139.  
  6140. Sub Picture1_DragDrop (Source As Control, X As Single, Y As Single)
  6141.    Print X, Y
  6142.    Source.SetFocus
  6143.    Child% = GetFocus()
  6144.    Picture1.SetFocus
  6145.    NewParent% = GetFocus()
  6146.    X = X - Text1.Width / 2: Y = Y - Text1.Height / 2
  6147.    H% = SetParent(Child%, NewParent%)
  6148.    W% = DoEvents()
  6149.    Text1.Drag DRAG_STOP
  6150.    Source.Move X, Y
  6151. End Sub
  6152.  
  6153. Sub Form_DragDrop (Source As Control, X As Single, Y As Single)
  6154.    Print X, Y
  6155.    Source.SetFocus
  6156.    TextHwnd = GetFocus()
  6157.    H% = SetParent(TextHwnd, Form1.Hwnd)
  6158.    X = X - Text1.Width / 2: Y = Y - Text1.Height / 2
  6159.    Text1.Drag DRAG_STOP
  6160.    Source.Move X, Y
  6161. End Sub
  6162.  
  6163. Sub Command1_Click ()
  6164.    Text1.Drag DRAG_START
  6165. End Sub
  6166. ---------------
  6167.  
  6168.  
  6169. Drawing - Scale:
  6170.  
  6171. You can change the scale for pictures from twips to virtually anything you
  6172. want (100 allows you to do easy percent drawing), but you still have to draw
  6173. by using pixel measurements. I found this out by trying to set DrawWidth to
  6174. draw a line covering the middle 20% of a small picture.
  6175. ---------------
  6176.  
  6177.  
  6178. Faster Drawing:
  6179.  
  6180. You can speed up drawing by having a hidden (.Visible=FALSE) picture box which
  6181. has AUTODRAW=TRUE. You echo your output to this box but the autodraw does not
  6182. slow things down because it is hidden. Then, in the paint method of your
  6183. visible picture box, blast the image from the invisible box to the visible
  6184. box. The whole thing is *very* fast and preserves your work. - J. Zuck
  6185.  
  6186. If the drawing is slow and complex, then bitblt is the best way.
  6187.  
  6188. You won't need a hidden picture control to bitblt to as you already have two
  6189. additional images available that are part of any picture control. They are the
  6190. persistent image (that AutoRedraw uses) and the Picture Property.
  6191.  
  6192. Leave AutoRedraw OFF. Draw on the 'screen' image of the picture control
  6193. (non-persistent image) then bitblt the screen image to the persistent image.
  6194. This is a way of turning AutoRedraw ON after you have drawn the image. It
  6195. makes for fast drawing and a way to protect what you have drawn.
  6196.  
  6197. You can get the hDC of the persistent image by turning AutoRedraw ON, using
  6198. hDC and then turning AutoRedraw OFF.
  6199.  
  6200. You also have available another level of protection. You can copy the persistent
  6201. image to the picture property (ctl.picture = ctl.image). The picture property
  6202. doesn't get erased even if you use CLS with AutoRedraw ON. - Keith Funk
  6203.  
  6204. The following is some actual code for the above:
  6205.  
  6206. 1. Picture.AutoRedraw = 0
  6207. 2. do the .Line statements to draw the stuff
  6208. 3. Now copy the "screen" image to the AutoRedraw "persistant" image:
  6209.  
  6210.  hScreenDC = Picture.hDC  ' get the device context handle of the "screen"
  6211.  Picture.AutoRedraw = -1  ' set it to true, so the hDC points to .Image
  6212.  PrevScaleMode = Picture.ScaleMode
  6213.  Picture.ScaleMode = 3 ' pixels
  6214.  r%=BitBlt(Picture.hDC,0,0,Picture.ScaleWidth,Picture.ScaleHeight,
  6215.            hScreenDC,0,0,SRCCOPY)
  6216.  Picture.ScaleMode = PrevScaleMode
  6217.  
  6218. Make sure to type the "r%=BitBlt..." all on one line, and don't forget the
  6219. declaration for it (and the const SRCCOPY) in your Global code module. You can
  6220. get those declarations from the WINAPI.TXT (stored as WINAPI.ZIP) if you don't
  6221. already have it. Also, if you're using a custom ScaleMode (by setting the
  6222. ScaleTop/Left/etc. yourself), then you'll have to somehow convert the
  6223. measurements to Pixels yourself because BitBlt _requires_ the parameters to be
  6224. in Pixels. (Ted Young)
  6225.  
  6226. Other than the above, the only real way to spead things up is to limit the
  6227. number of pens that are used (a pen includes the color of the line and the
  6228. width) and use API calls to draw the lines. VB does all this dynamically so
  6229. it's slower. (J. Zuck)
  6230.  
  6231. If you set AutoRedraw = -1, Visual Basic transfers the image to the screen
  6232. only during idle periods, so if you're drawing several thousand points, this
  6233. can seem quite slow. I have a program that draws 3000 lines in about 3 seconds
  6234. on my computer, which seems like a lifetime.
  6235.  
  6236. But you can make this "feel" faster with a simple trick. If you call the
  6237. Refresh method periodically, you can provide feedback while you're drawing
  6238. without slowing down the program much. For example, my program that draws 3000
  6239. lines looks something like this:
  6240.  
  6241.     Dim i As Integer
  6242.  
  6243.     pic.CurrentX = points(1).x
  6244.     pic.CurrentY = points(1).y
  6245.  
  6246.     For i = 2 To numPoints
  6247.         pic.Line -(points(1).x, points(2).y)
  6248.         If i Mod 500 = 0 Then
  6249.             pic.Refresh
  6250.         End If
  6251.     Next i
  6252.  
  6253. This will feel faster because your picture will be redrawn every 500 points,
  6254. or about every 1/2 second (on my 25 MHz 386).
  6255.  
  6256. By the way, Polyline is about 5 times faster, but you must work with Pixel
  6257. coordinates.
  6258.  
  6259. More notes:
  6260.  
  6261. 1. Calling Refresh rather than DoEvents tells Visual Basic just to transfer
  6262. your new image to the screen. It won't process any other events, which can be
  6263. good or bad. The good part is that Refresh may be faster. The bad part is that
  6264. you can't have a cancel button to stop long drawing operations.
  6265.  
  6266. 2. Here's how you can set the redraw so it happens after a certain amount of
  6267. time has ellapsed (without using a timer object):
  6268.  
  6269. Dim t As Single                        ' Timer returns a Single
  6270.  
  6271. t = Timer                              ' Get current clock ticks
  6272. For i = 1 To numPoints                 ' Draw all the lines
  6273.   pic.Line ...                         ' Draw a line
  6274.   If (Timer - t) > 0.5 Then            ' Has 1/2 second passed?
  6275.       pic.Refresh                      ' Copy new image to screen
  6276.       t = Timer                        ' New starting time
  6277.   End If
  6278. Next i
  6279.  
  6280. This example updates your image every half second. As you can see, it's almost
  6281. as simple as using a Timer object, but you don't have to call DoEvents.
  6282. (John Socha)
  6283. ---------------
  6284.  
  6285.  
  6286. Number of Colors Supported:
  6287.  
  6288. VB only supports 16-color graphics, even if your system supports 256-colors.
  6289. This is well-documented in the manuals, but a lot of people ask about it.
  6290. ---------------
  6291.  
  6292.  
  6293. Saving Extracted Icons:
  6294.  
  6295. Q: I have used the ExtractIcon function from shell.dll (WIN31) to extract
  6296. icons from *.EXE and *.DLL's. The icons are displayed in a Picture control. I
  6297. can't save the resulting picture. It seems that VB believes the picture
  6298. control has a "none" property, perhaps due to the fact the the API calls
  6299. filled the control.
  6300.  
  6301. A: Put "PicName.Autoredraw = TRUE" and do a "PicName.Picture = PicName.Image"
  6302. after you load the icon.
  6303. ---------------
  6304.  
  6305.  
  6306. Saving Picture Files:
  6307.  
  6308. It seems that SavePicture saves everything when the property is a Picture on a
  6309. Form, but it saves only the original loaded file when the property is a
  6310. Picture on a PictureBox, and it saves only the new drawn lines when the
  6311. property is an Image in a PictureBox.
  6312.  
  6313. The following should fix it:
  6314.  
  6315.   'BMP or WMF loaded into Picture1
  6316.   'Redlines added with Line, Pset, etc., then
  6317.   Form1.Picture = Picture1.Image
  6318.   PictureSave Form1.Image, "TEST1.BMP"
  6319.  
  6320. This works with WMFs but they cannot be changed and saved as WMFs, they get
  6321. saved as BMPs, which may or may not be ok with you.
  6322.  
  6323. Another example was posted:
  6324.  
  6325. Sub SavePicture_Test ()
  6326.   Picture1.Picture = LoadPicture("chess.bmp")
  6327.   Form1.Picture1.Line (1, 1)-(1000, 1000)
  6328.   SavePicture Picture1.Image, "test.bmp"            }"Image" not "picture"!
  6329.   Form1.Picture1.Picture = LoadPicture("test.bmp") End Sub
  6330.  
  6331. More input on the subject:
  6332.  
  6333. 1. Set AutoRedraw to True, and use the .Image property in the SavePicture
  6334. statement.
  6335.  
  6336. 2. If you don't want to use the AutoRedraw property (since it is slower when
  6337. it's True than when it's False), use the following code before your SavePicture
  6338.  
  6339.  hScreenDC = Picture1.hDC 'get the device context handle of the "screen"
  6340.  Picture1.AutoRedraw = -1 'set it to true, so the hDC points to .Image
  6341.  r%=BitBlt(Picture1.hDC,0,0,Picture1.ScaleWidth,Picture1.ScaleHeight,
  6342.     hScreenDC,0,0,SRCCOPY)
  6343.  Picture1.AutoRedraw = 0  'set it back to normal
  6344.  SavePicture Picture1.Image,"test.bmp" 'save the image with all changes
  6345.  
  6346. Note: type the "bitblt" statement all on one line, and don't forget to include
  6347. the following in your Global.Bas code form:
  6348.  
  6349.  'type the following all on one line (this is taken from WINAPI.TXT)
  6350.  Declare Function BitBlt Lib "GDI" (ByVal hDestDC As Integer,
  6351.        ByVal X As Integer, ByVal Y As Integer, ByVal nWidth As Integer,
  6352.        ByVal nHeight As Integer, ByVal hSrcDC As Integer,
  6353.        ByVal XSrc As Integer, ByVal YSrc As Integer, ByVal dwRop As Long)
  6354.        As Integer
  6355.  
  6356.  Global Const SRCCOPY = &HCC0020
  6357. ---------------
  6358.  
  6359.  
  6360. ScaleHeight Negative:
  6361.  
  6362. If you set ScaleHeight negative to get positive Y up on a form or picture, the
  6363. height of a label must be changed in code with a NEGATIVE height. Since the
  6364. object height is explained as being measured positively from the top edge
  6365. down, this is inconsistent.
  6366.  
  6367. If you set the height with a positive number your program MIGHT run with
  6368. garbage on the screen or crash with an error message. - Richard S. Johnson
  6369. ---------------
  6370.  
  6371.  
  6372. Unloading a Picture:
  6373.  
  6374. To unload a picture from a Picture Box:
  6375.  
  6376. Picture1.Picture = LoadPicture ("")
  6377. (Jonathan Zuck)
  6378. ---------------
  6379.  
  6380.  
  6381. Zoom In/Out On A Picture:
  6382.  
  6383. DefInt A-Z
  6384. Declare Function StretchBlt% Lib "GDI" (ByVal hDC, ByVal X, ByVal Y,
  6385.       ByVal nWidth, ByVal nHght, ByVal hSrcDC, ByVal XSrc, ByVal YSrc,
  6386.       ByVal nSrcWidth, ByVal nSrcHeight, ByVal dwRop&)
  6387. Const PIXEL = 3
  6388. Const NULL = 0&
  6389. Const SRCCOPY = &HCC0020
  6390. picture1.ScaleMode = PIXEL
  6391. picture1.autoredraw = 0
  6392. hDestDC = picture1.hDC
  6393. X = 0: Y = 0
  6394. nWidth = picture1.scalewidth
  6395. nHeight = picture1.scaleheight
  6396. hSrcDC = picture1.hDC
  6397. XSrc = 0: YSrc = 0
  6398. dwRop& = SRCCOPY       'stretches an icon to full size
  6399. apierror = StretchBlt(picture1.hDC, 0, 0, picture1.scalewidth,
  6400. picture1.scaleheight, picture1.hDC, 0, 0, 32, 32, SRCCOPY)
  6401. (Robert Eineigl)
  6402. ---------------
  6403.  
  6404.  
  6405. 255-Character Limit?:
  6406.  
  6407. Q: I seem to bump up against a 255 byte limit when a textbox on a VB server is
  6408. hot-linked to a textbox on a VB client.  Am I missing something?
  6409.  
  6410. A: Change the Multiline property to True for the text box. Then you can get
  6411. more than 255 bytes passed. (Art Baron)
  6412. ---------------
  6413.  
  6414.  
  6415. CtlName Access Via CDK:
  6416.  
  6417. You cannot reliably access the CtlName property via a VBGetControlProperty
  6418. function call of the CDK during Run Time. Use the "Tag" property instead.
  6419. ---------------
  6420.  
  6421.  
  6422. Cursor (text), Position:
  6423.  
  6424. You can get the cursor position in a text box as follows:
  6425.  
  6426. CursPos = Text1.SelStart
  6427. ---------------
  6428.  
  6429.  
  6430. Data Entry Masking:
  6431.  
  6432. General - Declarations:
  6433.   Dim Txt as String
  6434.  
  6435. Text1_GotFocus ():
  6436.   Text1.Text = "01/23"
  6437.   Txt$ = Text1.Text    'Txt$ = "01/23". This intitialization keeps KeyUp
  6438.                        '  from kicking in until a key has been pressed.
  6439. Text1_KeyPress:        'Assume cursor is on the "/" and "X" is pressed.
  6440.   Txt$ = Text1.Text    'Note: Text1.Text is still "01/23" at this point.
  6441. Text1_KeyUp
  6442.   If Txt$ <> Text1.Text Then  'now Text1.Text is "01X/23"
  6443.      Call CursPos(Text1)      'and Txt$ is still "01/23"
  6444.   End If
  6445. CursPos(Ctl as Control)
  6446.   i = 0
  6447.   Do While Len(Txt$) > i
  6448.     i = i + 1
  6449.     If Mid$(Txt$, i, 1) <> mid$(Ctl.Text, i, 1) Then
  6450.       pos = i
  6451.       Exit Do
  6452.     End If
  6453.   Loop
  6454.   if pos = 3 then  'Example of preventing an unwanted change:
  6455.     Ctl.Text = Txt$          'Reset Text1.Text and
  6456.     Ctl.SelStart = pos - 1   'put the cursor back where it was.
  6457.   end if
  6458. ---------------
  6459.  
  6460.  
  6461. Data Entry Routine:
  6462.  
  6463. .FRM Code:
  6464. Sub Form_Load ()
  6465.    SomeForm.Show
  6466.    InitStdControl AcctNo1            'Initialize standard edit controls
  6467.    InitStdControl AcctNo2
  6468.    .. etc
  6469. End Sub
  6470.  
  6471. Sub AcctNo1_KeyPress (KeyAscii As Integer)
  6472.    StdEdit AcctNo1, KeyAscii         'Use standard editing procedure
  6473. End Sub
  6474.  
  6475. Module (.BAS) Code:
  6476. DefInt A-Z
  6477. Declare Function GetFocus% Lib "USER" ()
  6478. Declare Function SendMessage& Lib "USER" (ByVal hWnd%, ByVal wMsg%
  6479.                                           ByVal wParm%, ByVal lParm&)
  6480. Const WM_USER = &H400                'Define the message number for
  6481. Const EM_LIMITTEXT = WM_USER + 21    '  limiting the length of an edit
  6482.                                      '  Control
  6483. Sub InitStdControl (Ctrl As Control)
  6484.    Ctrl.Width = 500                  'Make field some standard length
  6485.    Ctrl.SetFocus                     'Allow maximum of 14 characters
  6486.    Ok& = SendMessage(GetFocus(), EM_LIMITTEXT, 14, 0)
  6487.    .. more setup
  6488. End Sub
  6489.  
  6490. Sub StdEdit (Ctrl As Control, KeyAscii%)
  6491.    If KeyAscii >= 48 And KeyAscii <= 57 Then
  6492.       Ctrl.SelLength = 1             'This produces overstrike mode
  6493.    Else
  6494.       KeyAscii = 0                   'Ignore non-numeric keys
  6495.    End if
  6496. End Sub
  6497. ---------------
  6498.  
  6499.  
  6500. Data Entry Text Limit:
  6501.  
  6502. Declare Function GetFocus% Lib "USER" ()
  6503. Declare Function SendMessage& Lib "USER" (ByVal hWnd%, ByVal wMsg%,
  6504.                                           ByVal wParm%, Byval lParm&)
  6505. Const WM_USER = &H400
  6506. Const EM_LIMITTEXT = WM_USER + 21
  6507.  
  6508. In your Form_Load procedure:
  6509. Form1.Show
  6510. MaxLen% = (Whatever number you want)
  6511. Text1.SetFocus
  6512. txhWnd% = GetFocus()
  6513. Ok& = SendMessage(txhWnd%, EM_LIMITTEXT, MaxLen%, 0)
  6514. ---------------
  6515.  
  6516.  
  6517. Fast Loading:
  6518.  
  6519. For fastest loading of a file into a text box, use the following:
  6520.  
  6521. OPEN File2Load$ For Binary as #1
  6522. If LOF(1) > 32768 Then
  6523.   MsgBox "File is too big."
  6524. Else
  6525.   Buffer$ = Space$(LOF(1))
  6526.   Get#1, 1, Buffer$
  6527.   TextBox.Text = Buffer$
  6528. End If
  6529. Close 1
  6530.  
  6531. This routine involves only 1 disk read and two string operations. The old
  6532. WHILE...WEND loop required a disk read and two string operations for *EVERY*
  6533. line in the file. -Jack Presley
  6534.  
  6535. ---------------
  6536.  
  6537.  
  6538. Flicker:
  6539.  
  6540. Concatenating text in a Text Box can cause screen flicker. Instead use
  6541. SelStart and SelLength - no flicker.
  6542.  
  6543. An alternative is to concatenate the text in a string variable and then
  6544. assign the string to the Text box when done. (Mark Novisoff)
  6545. ---------------
  6546.  
  6547.  
  6548. Flashing/Highlighting Text:
  6549.  
  6550. 1.
  6551.   Sub FlashColor ()
  6552.      If FlashState = True Then
  6553.          Label1.BackColor = RGB(255, 0, 0)
  6554.          Label1.ForeColor = RGB(255, 255, 255)
  6555.      Else
  6556.          Label1.BackColor = RGB(255, 255, 255)
  6557.          Label1.ForeColor = RGB(0, 0, 0)
  6558.      End If
  6559.      If FlashState = True Then
  6560.          FlashState = False
  6561.      Else
  6562.          FlashState = True
  6563.      End If
  6564.  End Sub
  6565.  
  6566.  
  6567. 2.
  6568. You can use the .SelLength and .SelStart to highlight and unhighlight a
  6569. section of the text.
  6570. Example of highlighting characters 11 - 15 in a Text box:
  6571. Text1.SelStart = 11
  6572. Text1.SelLength = 5
  6573. ---------------
  6574.  
  6575.  
  6576. Increasing Line Limit:
  6577.  
  6578. On page 320 of the VB Programmer's Guide, it says the maximum length of a file
  6579. that can be edited with Text Editor is approx. 32k bytes because of the
  6580. "default" maximum number of characters you can assign to a VB multiline text box
  6581. control.
  6582.  
  6583. However, using SendMessage with EM_Limittext and &HFFFF I've gotten about 63k
  6584. into one. (Robert Eineigl, Microsoft Product Support)  [See WINAPI for syntax.]
  6585. ---------------
  6586.  
  6587.  
  6588. Keeping Text Highlighted:
  6589.  
  6590. Text in a Text box can be highlighted with SelStart and SelLength or with
  6591. the mouse by the user, but it becomes un-highlighted if the Text box loses
  6592. focus.
  6593.  
  6594. So if you want to display an "are you sure" box before a user deletes
  6595. highlighted text, for example, you have to use a round-about method:
  6596.  
  6597. 1. Make a small form for asking for the confirmation.
  6598. 2. Use the "floating form" routine in VB-Tips to make the form stay
  6599.      on top of the original form.
  6600. 3. Bring the focus back to the original form and Text box and highlight
  6601.      the selected text again.
  6602. 4. Set a flag so that no other processing is done until the confirmation
  6603.      has been done.
  6604. 5. Wait for the user to click on the "Ok" or "No" (or whatever) button
  6605.      on the floating form.
  6606. 6. To the user's eye, it appears that the confirmation box has popped up
  6607.      while the text has remained highlighted. The user can't tell that
  6608.      the floating form does not have the focus.
  6609. (Nelson Ford)
  6610. ---------------
  6611.  
  6612.  
  6613. Line Number, Finding:
  6614.  
  6615. The following code from Don Funk shows how to determine the current line
  6616. number in a text box from the cursor position (also see "Mouse Click
  6617. Detecting" following this tip):
  6618.  
  6619. CharPos& = fGetSel()
  6620. LineNumber& = fLineFromChar(CharPos&)
  6621.  
  6622. Function fLineFromChar& (CharPos&)
  6623.    '* This function will return the line number of the line that
  6624.    '* contains the character whose location(index) specified in the
  6625.    '* third argument of SendMessage.  If the third argument is -1,
  6626.    '* then the number of the line that contains the first character
  6627.    '* of the selected text is returned.  Line numbers start at zero.
  6628.    Const EM_LINEFROMCHAR = &H400 + 25
  6629.    Text1.SetFocus
  6630.    Pos% = SendMessage(GetFocus(), EM_LINEFROMCHAR, CharPos&, 0&)
  6631.    aLineFromChar.Caption = "Current Line = " + Str$(Pos%)
  6632.    fLineFromChar = Pos%
  6633. End Function
  6634.  
  6635. Function fGetLine$ (LineNumber As Long)
  6636.   '* This function returns a line of text specified by LineNumber
  6637.   '* from the edit control. The first line starts at zero.
  6638.  
  6639.    Const MAX_CHAR_PER_LINE = 80
  6640.    Const EM_GETLINE = &H400 + 20
  6641.  
  6642.    Text1.SetFocus
  6643.    Buffer$ = Space$(MAX_CHAR_PER_LINE)
  6644.    Pos% = SendMessage(GetFocus(), EM_GETLINE, LineNumber, Buffer$)
  6645.    fGetLine$ = Buffer$
  6646. End Function
  6647.  
  6648. Function fGetSel& ()
  6649.   '* This function returns the starting/ending position of the
  6650.   '* current selected text.  This is the current location of the
  6651.   '* cursor if start is equal to ending.
  6652.  
  6653.   '* LOWORD-start position of selected text
  6654.   '* HIWORD-first no selected text
  6655.  
  6656.    Const EM_GETSEL = &H400 + 0
  6657.  
  6658.    Text1.SetFocus
  6659.    location& = SendMessage(GetFocus(), EM_GETSEL, 0&, 0&)
  6660.    ending% = location& \ 2 ^ 16
  6661.    starting% = location& Xor high%
  6662.    aGetSel.Caption = "Caret Location = " + Str$(starting%)
  6663.    fGetSel = location&
  6664. End Function
  6665. ---------------
  6666.  
  6667.  
  6668. Number of Lines:
  6669.  
  6670. The following routine from Don Funk returns the number of lines in a Text box:
  6671.  
  6672. Declare Function GetFocus% Lib "user" ()
  6673. Declare Function SendMessage% Lib "user" (ByVal hWnd%, ByVal wMsg%,
  6674.                                           ByVal wParam%,
  6675.                                           ByVal lParam As Any)
  6676. Function fGetLineCount& ()
  6677.    Const EM_GETLINECOUNT = &H400 + 10
  6678.    Text1.SetFocus
  6679.    Pos% = SendMessage(GetFocus(), EM_GETLINECOUNT, 0&, 0&)
  6680.    fGetLineCount = Pos%
  6681. End Function
  6682. ---------------
  6683.  
  6684.  
  6685. Read-Only Text Box:
  6686.  
  6687. In a text box control, if you set Enabled = FALSE and MultiLine = TRUE, the
  6688. contents of the text box control are not greyed and the mousepointer stays an
  6689. arrow when over this text box control. Essentially, it's a read-only text box
  6690. control.
  6691.  
  6692. This way I could make the text box control perform like a normal text box
  6693. control when I want the user to be able to enter info, while other times it
  6694. acts like a label when I don't want the user to be able to enter info.
  6695. (Rick J Andrews)
  6696. ---------------
  6697.  
  6698.  
  6699. Tab Key Trapping:
  6700.  
  6701. VB intercepts Tab and doesn't pass it to either the KeyPress or KeyDown events.
  6702. But if you set the TabStop property on all controls on the form to FALSE, then
  6703. suddenly the Tab key is passed through like a normal character. (Brett Foster)
  6704. ---------------
  6705.  
  6706.  
  6707. DoEvents () in a Timer:
  6708.  
  6709. If you put a DoEvents () in a Timer routine, you allow the Timer to kick in
  6710. again while you may still be in the Timer routine. To avoid this, use a flag to
  6711. indicate if you are already in the Timer routine and if so, to exit the Sub.
  6712. ---------------
  6713.  
  6714.  
  6715. Resolution/Accuracy:
  6716.  
  6717. The TIMER function provides a "tick" resolution (approx. 1/18th of a second),
  6718. but actual mileage may vary due to the way Windows works; ie: if you invoke
  6719. the TIMER function, you'll get an accurate reading of the ticks, but if you
  6720. use a Timer *control*, you most likely won't get a hit exactly every
  6721. TimerInterval milliseconds... (Mark Novisoff)
  6722. ---------------
  6723.  
  6724.  
  6725. Using the Timer:
  6726.  
  6727. If you use a Timer with a small interval (eg: 1) and another application is
  6728. active, Windows may not be able to respond at the specified duration and
  6729. execution of the related code will be postponed until Windows can get to it.
  6730. ---------------
  6731.  
  6732.  
  6733. What is Knowledge Base?:
  6734.  
  6735. Fm: Don Funk (SL) 76701,155
  6736.  
  6737. I work for Microsoft within Product Support. We receive a variety of questions
  6738. over the phone from many customers daily. We have at our disposal a data base
  6739. with a query engine that we can search on key words for a solution.
  6740.  
  6741. You have access to this data base also by typing "GO MSKB" [at a CompuServe
  6742. prompt]. This database not only includes "How to questions" but also includes
  6743. bug reports, press releases, and general questions and documentations about the
  6744. products.
  6745.  
  6746. There are only about 100 articles for VB now but it is growing. The Quick
  6747. Basic includes many many many more articles since it has been around for a
  6748. long time. This Knowledge Base is the source of articles not only for Basic
  6749. but for all the products at Microsoft.
  6750. ---------------
  6751.  
  6752.  
  6753. VB Book Reviews:
  6754.  
  6755.   "Visual Basic Programming" by Douglas Hergert, Bantam:
  6756. Entry-level info for beginning programmers. Good review of fundamentals like
  6757. I/O techniques, data structures, file access, and all VB controls including
  6758. their properties & methods. (Rick Heil)
  6759.  
  6760.   "Visual Basic" by Steve Holzner, Brady Books:
  6761. It assumes a moderate understanding of basic, so if you're totally new to
  6762. basic this probably shouldn't be your first book on the subject. The latter
  6763. half of the book goes deeper into topics like graphics. Good detail on
  6764. advanced data handling, sorting (with algorithms), error handling & DDE.
  6765. (Rick Heil)
  6766.  
  6767. "Microsoft Windows Multimedia Programmer's Reference", available from
  6768. Waldenbooks (ISBN 1-55615-389-9).
  6769.  
  6770. Other recommended books:
  6771.  
  6772. Waite's "Visual Basic How-To", Waite Group Press, ISBN 1-878739-09-3.
  6773.    for intermediate to advanced
  6774.  
  6775. Visual Basic Workshop, MS Press, ISBN 1-55615-386-4. "for getting started"
  6776. ---------------
  6777.  
  6778.  
  6779. How to Get the Files:
  6780.  
  6781. The following files are available on CompuServe on MSBASIC, DL's 1 and 5.
  6782. The files are also available on disk from PsL. The two sources are not
  6783. identical because PsL has screened out some duplication, old version,
  6784. non-working files, etc, and may have files that the authors have not
  6785. uploaded to CIS.
  6786.  
  6787. If you are looking for one particular file and belong to CompuServe, the
  6788. cheapest and fastest way to get it is from MSBASIC's DL's. From any CIS
  6789. prompt, enter GO MSBASIC. From MSBASIC's Forum prompt, enter DL1 or DL5 and
  6790. browse for the file name with the BRO command. For example, to find
  6791. CtlWhWnd, you could enter BRO CTL*.* LIB:ALL to search all the DL's on
  6792. MSBASIC.
  6793.  
  6794. The MSBASIC sysops have also posted an index file of all the programs on
  6795. all of MSBASIC's DL's. That list has the advantage of being more up to date
  6796. than the list that follows, but it offers less information, the VB and
  6797. non-VB files are mixed together, and the files are not categorized in any
  6798. way. Still, it can make it easier to find some of the files listed below.
  6799.  
  6800. To get a disk full of routines from PsL, use the disk number indicated.
  6801. Note that all categories with the same disk number are on the same disk.
  6802. See the "Background" in this file for ordering information.
  6803.  
  6804. Please note that as new files are added to these disks by category each
  6805. month, disks may have to be split up to make room. If ordering a disk for a
  6806. specific file, you must specify that when ordering so that we can verify
  6807. that it is still on the disk. If you specify multiple files and some are
  6808. still on the disk, we will send the requested disk.
  6809.  
  6810. The format for this section is to show the program name followed by the
  6811. name of the file on the PsL disk, the author/publisher of the file, and the
  6812. shareware registration fee, if any. Registration fees are meant to be sent
  6813. directly to the author to become licensed to use a program beyond a
  6814. reasonable evaluation period. Do not send those amounts to PsL. PsL charges
  6815. a flat $5 disk fee.
  6816. ---------------
  6817.  
  6818.  
  6819. DLL's, Utilities:
  6820. PsL Disk #3490
  6821.  
  6822. 256PICBX (256PBX)
  6823.    $0
  6824. is a DLL with source that displays 256 color bitmaps in a VB Picture box
  6825. control. Source for a sample app is included.
  6826.  
  6827. CtlWhWnd (CTLWHWN)
  6828.    User Friendly, Inc.
  6829.    $0
  6830. is a DLL function that returns the hWnd for any control. This makes it easier to
  6831. use API calls that modify controls.
  6832.  
  6833. DSound
  6834.    $0
  6835. is a DLL that allows you to play sound files through a PC's speaker. A sample
  6836. SND file and sample VB code are included. Since digitized sound files from
  6837. various sources (eg: Mac, Sound Blaster, Amiga) are all very similar, virtually
  6838. all of them can be played with DSound.
  6839.  
  6840. Findapp
  6841.    Obeda, Ed
  6842.    $0
  6843. is a DLL and related VB code that prevents users from opening more than one copy
  6844. of your application or of programs such as Calculator.
  6845.  
  6846. GetWindowList 1.1 (GETWLST)
  6847.    Steinwart, Todd
  6848.    $0
  6849. is a DLL that lets you get a list of handles for active, visible windows. Sample
  6850. usage code is included.
  6851.  
  6852. HotKey.DLL (HKEYVB)
  6853.    Zuck, Jonathan
  6854.    $0
  6855. is designed to provide hotkey support to Visual Basic, which is not directly
  6856. supported in VB. You can define multiple hot keys in your application and the
  6857. DLL can be used by multiple applications simultaneously. An executable demo with
  6858. several examples is included.
  6859.  
  6860. HUGEARR.DLL
  6861.    Schmidt, Stephen
  6862.    $0
  6863. is a DLL which contains functions for creation, maintenance, and deletion of
  6864. arrays larger than 64K, with more than 32k elements per dimension.
  6865. It also lets you copy contiguous elements from a Huge Array into a specified
  6866. part of a VB array and vice-versa. C source for the DLL is included.
  6867.  
  6868. InOut
  6869.    Faggart, B.E.
  6870.    $0
  6871. is a DLL for I/O Port control. Sample VB source code is included.
  6872.  
  6873. LZSSLib 1.0
  6874.    Eschalon Development Inc.
  6875.    $25
  6876. is a file compression/decompression DLL for Windows programmers. It uses the
  6877. LZSS algorithm. This should work with any language that supports DLL calling,
  6878. such as Turbo Pascal, C/C++, Actor, Visual Basic, Realizer, and ObjectVision.
  6879.  
  6880. MHelp
  6881.    MicroHelp, Inc.
  6882.    $0
  6883. is a DLL with VB versions of PEEK, POKE, INP, OUT, VARPTR, VARSEG, VARSEGPTR,
  6884. SADD, SSEG and SSEGADD.
  6885.  
  6886. SounDLL
  6887.    White, Bill
  6888.    $0
  6889. is a sound driver (DLL) with VB source code to illustrate its use. TPW source
  6890. code for the DLL is included. (This DLL can be used with other Windows
  6891. languages.)
  6892.  
  6893. Space & Time (SPCTIME)
  6894.    Barrett, Paul James
  6895.    $0
  6896. is a DLL that reports free disk space and will copy the date and/or time to the
  6897. the Clipboard. C source code for the DLL is included, but no source code to
  6898. illustrate calling the DLL from VB, so you will have to study the C code.
  6899.  
  6900. Stsbar 2.0
  6901.    Staffin, Ed
  6902.    $0-$10
  6903. is a DLL for a status bar. This is a bar that is used to display program
  6904. parameter/function status, mouse coordinated, column/row numbers -- or any other
  6905. text you want to assign to it.
  6906.  
  6907. Toolwnd.DLL (TOOLWND)
  6908.    Donahue, Ray
  6909.    $35
  6910. lets you create nice looking toolbars and toolboxes with icons for each
  6911. selection. (Not on this disk. Ask for disk #8807.)
  6912.  
  6913. VBCards 1.01P
  6914.    Sands, Richard R.
  6915.    $0
  6916. is a card-deck DLL for writers of card games for Windows. The author hopes to
  6917. create a public domain standard DLL so that each programmer does not have to
  6918. crowd your hard disk with a new card-deck DLL.
  6919.  
  6920. VBCards contains 52 cards, a Joker, seven card back designs, two indicator
  6921. cards, some support routines, and a short sample program. Although the sample
  6922. code is in Visual Basic, the DLL should be usable with other languages.
  6923.  
  6924. Accordian Solitaire (ACCRDVB)
  6925.    Sands, Richard R.
  6926.    $0
  6927. is the VB source code for a solitaire card game. The uncompiled Help is also
  6928. included. Requires VBCards, which is also on this disk.
  6929.  
  6930. VBPoint
  6931.    Zuck, Jonathan
  6932.    $0
  6933. is a DLL that adds pointer support to VB. LP2Str$ is a string function that
  6934. copies data, pointed to by a so-called "Long Pointer" into a VB proprietary
  6935. string variable. Str2LP is a subroutine that will copy data from one address to
  6936. another. With this function you can create the CV? and BLOAD commands.
  6937.  
  6938. VBSNdex
  6939.    Zuck, Jonathan
  6940.    $0
  6941. is an example for TPW programmers on how to create a string function in a DLL.
  6942. TP source code included.
  6943. ---------------
  6944.  
  6945.  
  6946. DOS Access/Functions:
  6947. PsL Disk #3557 
  6948.  
  6949. DateTime (DATETIM)
  6950.    $0
  6951. shows how to get a file's date/time stamp and file size directly from within
  6952. Visual Basic without resorting to a shell to DOS DIR command.
  6953.  
  6954. Dirscan.BAS
  6955.    Rose, Joel
  6956.    $0
  6957. contains source code for a routine that scans a system's drives for a particular
  6958. file or files.
  6959.  
  6960. Filebox
  6961.    Wykes, Harry JF
  6962.    $0
  6963. shows how to create a Windows style file-open box using List boxes rather than
  6964. the VB DriveBox and DirBox objects.
  6965.  
  6966. VBDOS
  6967.    $0
  6968. is a DLL that allows you to get free disk space, file information, and change
  6969. file attributes. Sample code is included.
  6970. ---------------
  6971.  
  6972.  
  6973. Font Utilities:
  6974. PsL Disk #3557 
  6975.  
  6976.  
  6977. EnumFonts (ENUMFNT)
  6978.    Telelink Systems
  6979.    $8
  6980. is a DLL which allows you to access the Windows API service EnumFonts. A demo is
  6981. provided which shows how to find which typefaces and fonts are supported by the
  6982. default printer. Source code is included.
  6983.  
  6984. Fontro
  6985.    Young, Ted M.
  6986.    $0
  6987. contains VB source code to create a rotatable font that can print sideways.
  6988.  
  6989. FontView 2.0 (FONTVW)
  6990.    Snider, Charles
  6991.    $0
  6992. is code for an application to find, display, and print Windows fonts.
  6993. ---------------
  6994.  
  6995.  
  6996. Networking/Communications:
  6997. PsL Disk #3557 
  6998.  
  6999.  
  7000. ADialer
  7001.    Lamson, George
  7002.    $0
  7003. is the source code and executable for a program to dial the phone.
  7004.  
  7005. ComDemo 1.0
  7006.    $0
  7007. illustrates the use of several COMM API functions. Includes source code and an
  7008. executable file.
  7009.  
  7010. Link'n Load (LINKLOD)
  7011.    Krumsee, Art
  7012.    $0
  7013. is VB code that shows how to establish a network link, run a specified
  7014. application, and when done, unload the link. Network managers with VB only have
  7015. to enter the application name into the code and compile it for this to work.
  7016.  
  7017. NetPrint (NETPRNT)
  7018.    Krumsee, Art
  7019.    $0
  7020. is VB source that allows network users to link and unlink printers from within
  7021. Windows. It includes declarations for 3 undocumented Windows API functions which
  7022. should make this application network independent.
  7023.  
  7024. Novell-VB (NOVL-VB)
  7025.    Johnson, L.J.
  7026.    $0
  7027. contains an example program with source code that allows you to attach to and
  7028. de-attach from multiple servers. You can also set drive mappings on your primary
  7029. server. Many of the basic Novell API's are demonstrated.
  7030.  
  7031. VBMate
  7032.    $0
  7033. contains a library of routines and sample code for interfacing VB with EXTRA!
  7034. for Windows EHLLAPI.DLL. This gives VB the ability to interact with a 3720
  7035. mainframe terminal session.
  7036.  
  7037. VBTerm
  7038.    McGuinness, Charles
  7039.    $0
  7040. is source code for a simple VT100 terminal emulator.
  7041. ---------------
  7042.  
  7043.  
  7044. System:
  7045. PsL Disk #3704
  7046.  
  7047.  
  7048. Fndwnd
  7049.    $0
  7050. shows how to look for a window based on Caption and/or ClassName.
  7051.  
  7052. Ini_Art
  7053.    Jones, Tim
  7054.    $0
  7055. is a tutorial on writing and using INI profile files. Source code examples are
  7056. included.
  7057.  
  7058. KeyCode
  7059.    Mosher, Sue
  7060.    $0
  7061. displays the hex keycode for any key pressed. This is useful for any Windows
  7062. programmer, but the included source code is VB.
  7063.  
  7064. LoadTime
  7065.    $0
  7066. is a text file that tells how to handle slow loading programs to keep the user
  7067. from messing things up.
  7068.  
  7069. ResCheck 1.0 (RESCHEK)
  7070.    Houck, Dan
  7071.    $0
  7072. is source for checking and displaying GDI and User Heap information in an icon.
  7073.  
  7074. SySwitch 2.03 (SYSWTCH)
  7075.    Bonner, Paul
  7076.    $0
  7077. is VB source for a utility for changing Windows configurations.
  7078.  
  7079. VBMem 1.1 (VBMEM-S)
  7080.    Snider, Charles K.
  7081.    $0
  7082. is source for a VB app that displays Windows system information: the operating
  7083. mode, presence of a math chip, and free memory. Compiled and run minimized, the
  7084. display will constantly update the free memory number.
  7085.  
  7086. VBShell 1.0
  7087.    Smith, Paul
  7088.    $0
  7089. is designed to get around the fact that a VB app cannot be used as a Windows
  7090. shell. VBShell can be loaded as a shell; then it loads your VB app and unloads
  7091. itself, leaving the VB app as the functional shell.
  7092.  
  7093. WinAPI
  7094.    Microsoft
  7095.    $0
  7096. is a text file listing all the Windows 3 API declarations for VB. With these
  7097. declarations in your VB code, you can perform many functions not otherwise
  7098. available in VB.
  7099.  
  7100. WndFind
  7101.    User Friendly, Inc.
  7102.    $0
  7103. solves the problem of needing an exact match when using the AppActivate command.
  7104. This can also be used to determine if your application is already running.
  7105. Source is included.
  7106. ---------------
  7107.  
  7108.  
  7109. Time/Date Applications:
  7110. PsL Disk #3704 
  7111.  
  7112.  
  7113. Calendar Program (CAL-PRO)
  7114.    Meadows, Al
  7115.    $0
  7116. is the source code and executable for a calendar program.
  7117.  
  7118. DateTime (DAT-TIM)
  7119.    Michna, Hans-Georg
  7120.    $0
  7121. is VB source to display the date and time in a variety of international or
  7122. custom formats.
  7123.  
  7124. GridCal
  7125.    Meadows/Graves
  7126.    $0
  7127. is source for making a calendar using the Grid custom control.
  7128.  
  7129. SmallCal (SMALCAL)
  7130.    Meadows, Al
  7131.    $0
  7132. is source for a sample application which illustrates how to generate a calendar
  7133. for a user-specified month.
  7134.  
  7135. VB Clock 1.0 (VBCLOCK)
  7136.    Gagliano, Jim
  7137.    $0
  7138. is VB source for an app to display the date and time in a very small window.
  7139.  
  7140. VB Popup Calendar (VBPCAL)
  7141.    Schueler, Don
  7142.    $0
  7143. is source for a small pop-up calendar. It is intended for popping up in date
  7144. fields and returning the value to the field.
  7145. ---------------
  7146.  
  7147.  
  7148. Graphics/Video:
  7149. PsL Disk #3788 
  7150.  
  7151.  
  7152. 3D4VB
  7153.    LAN Services
  7154.    $10
  7155. lets you create beautiful 3-D effects. More than 20 different routines are
  7156. included to draw 3-D frames, shadowed boxes, borders, picture buttons, etched
  7157. and shadowed text, and more. Interestingly, this is all done with VB code - no
  7158. DLL's to keep track of. All source code is included.
  7159.  
  7160. BMPKit
  7161.    Campbell, George
  7162.    $0
  7163. is a set of routines to scale, print, and display bitmaps. A demo and all source
  7164. code are included.
  7165.  
  7166. Burglar & Animate (BURGLAR)
  7167.    Campbell, George
  7168.    $?
  7169. contains source for two demonstrations of simple animation using icons.
  7170.  
  7171. GetPut
  7172.    Martin, Wendell
  7173.    $0
  7174. is a routine that works like the graphic Get and Put statements in DOS Basic.
  7175. Example code is included.
  7176.  
  7177. Icon Browser (ICONBRW)
  7178.    $0
  7179. shows how to more easily extract icons from apps in Windows 3.1.
  7180.  
  7181. IconDemo (ICONDEM)
  7182.    Young, Ted M.
  7183.    $0
  7184. is demo code to show how to draw graphics on a VB app's icon.
  7185.  
  7186. MetaLib 1.0
  7187.    Sygenex
  7188.    $0
  7189. contains a set of routines that will allow you to create, draw, and save SDK
  7190. (vector graphics) metafiles.
  7191.  
  7192. Newstart 1.04 (NEWSTRT)
  7193.    Elkins, Jeff
  7194.    $0
  7195. is VB source for an app that allows you to change the Windows start-up graphic
  7196. from the MS logo. This is also on a Windows application disk.
  7197.  
  7198. PolyGone (POLYGO)
  7199.    Mack, Jim
  7200.    $0
  7201. is the source for an interesting graphics display. It also illustrates the use
  7202. of graphics when iconized.
  7203.  
  7204. Programmer's Workshop 1.0 (PROGWRK)
  7205.    Bushnaq, Firas
  7206.    $10
  7207. is a template that shows all available screen resolutions on your monitor to
  7208. make is easy for you to size your forms and dialogue boxes. It has a ruler scale
  7209. which shows twips, inches, points, picas, and pixels and can be used for
  7210. conversions among those units of measure.
  7211.  
  7212. Rotfont
  7213.    Egger, Fredi
  7214.    $0
  7215. shows how to print text at any angle in VB apps to screen or printer.
  7216.  
  7217. SSave
  7218.    User Friendly, Inc.
  7219.    $0
  7220. is a DLL that allows you to create Windows screen savers (like After Dark) in
  7221. Visual Basic.
  7222.  
  7223. TurboDXF (TURBODX)
  7224.    Dorosh, David
  7225.    $50
  7226. is a DLL that allows you to create standard DXF graphics files with up to 25
  7227. entities per drawing. It works with TP, VB, OV, Excel, C. (Not on this disk.
  7228. Ask for disk #8842.)
  7229.  
  7230. VBFlip
  7231.    $0
  7232. is an outstanding demonstration of using the BitBlt and StretchBlt API
  7233. functions. The demo code displays a grid of tiles which you can flip over to
  7234. show a graphic or which you can X out with a zooming red X. The code also shows
  7235. how to store a series of images in a single picture file and use the individual
  7236. images.
  7237.  
  7238. VBMask
  7239.    $0
  7240. demonstrates how to create a mask from an image and a screen object using
  7241. BitBlt.
  7242.  
  7243. VBMenu
  7244.    $0
  7245. shows how to add graphic bitmaps and check mark substitutes to a menu.
  7246.  
  7247. VBScroll (VBSCROL)
  7248.    $0
  7249. demonstrates an easy way to scroll/pan across a bitmap in a Picture Box.
  7250.  
  7251. Waldo
  7252.    Melanson, Leo
  7253.    $0
  7254. is the source for an animation sequence in which Waldo walks across the form.
  7255.  
  7256. WMFPix
  7257.    $0
  7258. is a set of graphics icons in WMF format for use in your VB programs.
  7259. ---------------
  7260.  
  7261.  
  7262. Custom Controls:
  7263. PsL Disk #3880 
  7264.  
  7265.  
  7266. CBList 1.0.
  7267.    Waldmeyer, Manfred
  7268.    $58
  7269. allows you to create checkboxes or radiobuttons as a single custom control for
  7270. VB. It supports 2D and 3D display, several standard box types, and bitmaps/icons
  7271. picture property. This version works only in design-time.
  7272.  
  7273. ClipSib 1.0
  7274.    Funk, Keith
  7275.    $0
  7276. allows you to have overlapping controls, which VB does not normally support. VB
  7277. code for an excellent demo of the routine is included. This code contains many
  7278. other useful routines as well.
  7279.  
  7280. DropDown (DROPDWN)
  7281.    $0
  7282. shows how to simulate a Combo box with a Text box and a List box.
  7283.  
  7284. Gauge
  7285.    Mattila, Jussi
  7286.    $0
  7287. tells how to create a Meter box from two Picture boxes.
  7288.  
  7289. Graphic 1.1
  7290.    Cramp, Stephen
  7291.    $15
  7292. is a 256-color custom control. It also includes support for OS/2 BMP files. This
  7293. version can only be used within VB. Registration gets a runtime module.
  7294.  
  7295. GridPl
  7296.    $0
  7297. is a routine for entering data into a Grid control and to scroll the Grid with
  7298. Cntl-Arrow or the mouse.
  7299.  
  7300. Huge-MC
  7301.    Marquis Computing
  7302.    $0
  7303. is the VB Source code to a huge array manager for Windows 3.1. You can create
  7304. huge arrays of up to 16MB on 386 and 1 MB on 286.
  7305.  
  7306. MoveTxt
  7307.    Funk, Keith
  7308.    $0
  7309. shows how to use a Picture control to simulate dragging of a Text control (which
  7310. normally cannot be dragged).
  7311.  
  7312. MsgBox Editor (MSGBOX)
  7313.    Buhrer, Richard
  7314.    $0
  7315. makes it easy to set up MsgBoxes. Run this utility, click on the elements you
  7316. want, add the text, and it generates the source code for you on the Clipboard
  7317. for you to paste into your program.
  7318.  
  7319. GrafStat 1.0 (GRAF-ST)
  7320.    Object Productivity, Inc.
  7321.    $22-$32
  7322. is a custom control for displaying the status of a process. Two styles are
  7323. offered: thermometer and needle.
  7324.  
  7325. Grid Routines (GRIDRTN)
  7326.    Ford, Nelson ASP
  7327.    $0
  7328. is a set of routines for use with the Grid custom control. Routines include
  7329. cursor key scrolling of the Grid, direct input to the Grid, add a row, delete a
  7330. row, save to and load from disk, clear the Grid and more.
  7331.  
  7332. Grid-VB
  7333.    $0
  7334. is a single control that lets you display data in columns and rows. This was
  7335. originally given to beta testers by Microsoft, but not included in VB. Jonathan
  7336. Zuck has made enhancements to it.
  7337.  
  7338. HugeGrid (HUGEGRD)
  7339.    Ford, Nelson ASP
  7340.    $0
  7341. is sample code illustrating the integration of a Huge Array with a Grid control.
  7342. Features include sorting, searching, adding, deleting and sorted inserting of
  7343. records into the Huge Array, as well as paging and scrolling through data with
  7344. the Grid.
  7345.  
  7346. Picnic
  7347.    Funk, Keith
  7348.    $0
  7349. allows you to make picture controls look like VB forms. It demonstrates how to
  7350. use the Win3 API functions to add a caption, sizing border and a minimize box
  7351. and system menu to a picture control.
  7352.  
  7353. Prntlbl
  7354.    $0
  7355. shows how to print captions on a Form using API calls instead of Label controls.
  7356. The code looks enormously complicated to us, considering that you can do the
  7357. same thing with a few straight VB commands, but maybe we are missing something.
  7358.  
  7359. PropView (PROPVW)
  7360.    Microsoft
  7361.    $0
  7362. is a Custom Control that can display the properties of the current form and
  7363. allows printing of the control properties.
  7364.  
  7365. RandGrid (RANDGRD)
  7366.    Ford, Nelson ASP
  7367.    $0
  7368. is sample code illustrating the integration of a random access file and a Grid
  7369. control.
  7370.  
  7371. Spin
  7372.    Kitsos, Costas
  7373.    $0
  7374. is commented VB source code to create a Spin Button Control. No DLL/VBX files
  7375. are required.
  7376.  
  7377. ToolBar
  7378.    Murphy, Stephen
  7379.    $0
  7380. walks you through creating a toolbar using a picture box for the bar and BMP
  7381. files for the buttons. Sample source code and BMP files are included.
  7382.  
  7383. VBMeter
  7384.    $0
  7385. is a VBX that lets you create a meter type display with horizontal or vertical
  7386. bars.
  7387. ---------------
  7388.  
  7389.  
  7390. General Tools/Reference/Info:
  7391. PsL Disk #3968 
  7392.  
  7393.  
  7394. Additem
  7395.    $0
  7396. is VB code that illustrates a potential problem with adding fixed length strings
  7397. to a List Box.
  7398.  
  7399. APIFunc
  7400.    Solutions by Smith
  7401.    $15
  7402. is an API function database in Cardfile format. (Not on this Disk. Ask for
  7403. disk #8841.)
  7404.  
  7405. APIXref
  7406.    $0
  7407. is a Help file that cross-references the API calls listed in WINAPI.TXT,
  7408. included on this disk. To use this file, while in VB, press F1 for Help, then
  7409. Alt-F and O to open the file.
  7410.  
  7411. App Shell 1.0 (APPSHEL)
  7412.    Presley, Jim
  7413.    $0
  7414. is VB source code for a sample application that can be used as a starting point
  7415. for file-oriented applications. The app includes forms for file open/save,
  7416. printing, printer selection and setup (including a custom DLL with C source) and
  7417. print canceling and a main form that ties everything together with pull-down
  7418. menus and related code.
  7419.  
  7420. BitMap
  7421.    Young, Ted
  7422.    $0
  7423. is code for an "application" that simply illustrates the use of all the VB
  7424. Picture Box functions.
  7425.  
  7426. Click & Double-Click (CLK-DBL)
  7427.    Ford, Nelson ASP
  7428.    $0
  7429. is code that shows how to trap both the click and double-click events for a
  7430. control.
  7431.  
  7432. Color Calculator (COLCALC)
  7433.    Evers, Dave
  7434.    $0
  7435. displays color number for color combo selected on sliding bars. VB source code
  7436. is included.
  7437.  
  7438. Drag'n'Drop (DRAGDRP)
  7439.    Bonner, Paul
  7440.    $0
  7441. shows how to add support for the Windows 3.1 File Manager drag-and-drop facility
  7442. to a VB program.
  7443.  
  7444. Focus U-Turn (FOCUTRN)
  7445.    $0
  7446. demonstrates techniques for the use of Focus, and what to expect when you use
  7447. it, particularly as it applies to attempts to verify data on exit from a control
  7448. via LostFocus.
  7449.  
  7450. FrameVB
  7451.    Ford, Nelson ASP
  7452.    $0
  7453. is a Module that will draw shadowed frames around controls to create the
  7454. illusion of their being recessed. Also included is a routine for underlining a
  7455. control such as a Text box.
  7456.  
  7457. GetDec
  7458.    MicroHelp, Inc.
  7459.    $0
  7460. eliminates unused DLL declarations from the Global module of your programs,
  7461. resulting in a smaller EXE.
  7462.  
  7463. Hyper (HYPR-VB)
  7464.    Martin, Wendell
  7465.    $0
  7466. shows how to add hypertext to your VB programs.
  7467.  
  7468. Landau
  7469.    $0
  7470. shows how to use drag and drop, how to link to the Windows calculator, notepad
  7471. and winhelp, and how to use the clipboard.
  7472.  
  7473. Refresh
  7474.    $0
  7475. demonstrates the use of VB's implicit refresh versus an explicit refresh of a
  7476. Text Box.
  7477.  
  7478. RTFGen 1.0
  7479.    Baldwin, Dave
  7480.    $0
  7481. converts plain ASCII files into Rich Text Format for use with the Windows Help
  7482. Compiler. This is much easier than learning Word, or its equivalent. (Not on
  7483. this disk. Ask for disk #8842.)
  7484.  
  7485. Setup1
  7486.    Johnson, L.J.
  7487.    $0
  7488. is an enhanced version of the Setup program that comes with the PTK. (Not on
  7489. this disk. Ask for disk #8880.)
  7490.  
  7491. VBAPI 0.2
  7492.    Pruitt, Steve
  7493.    $0
  7494. contains text of the Microsoft WINAPI.TXT file in the Windows .HLP format. It
  7495. includes additions and corrections as of March 9, 1992, and contains
  7496. definitions of functions, constants, and data structure for use within Visual
  7497. Basic.
  7498.  
  7499. VB Assistant (VB-ASST)
  7500.    English, Donald R.
  7501.    $0
  7502. displays a menu that lets you save and run the application you are working on,
  7503. invoke an icon editor, or quickly gain access to all help and text files which
  7504. relate to Visual Basic. Source code and executable are included.
  7505.  
  7506. VBE
  7507.    Digital Solutions
  7508.    $15
  7509. adds two useful text options to VB. It allows you to save selected text to a
  7510. file and to print selected text. These options will appear under the File Menu
  7511. in VB.
  7512.  
  7513. VBFindID (VBFNDID)
  7514.    Kitsos, Costas
  7515.    $0
  7516. is a utility which can be used to determine the IDs of VB Controls during
  7517. design-time. With the ID's known, you can use API calls during run-time without
  7518. having to use the clumsy SetFocus method or to employ an extra DLL for the
  7519. purpose.
  7520. ---------------
  7521.  
  7522.  
  7523. Miscellaneous:
  7524. PsL Disk #3969 
  7525.  
  7526.  
  7527. BaseCnv (BASECN)
  7528.    Lyle Lensen
  7529.    $0
  7530. is a routine for doing number base conversions.
  7531.  
  7532. CFixVB
  7533.    Mack, Jim
  7534.    $0
  7535. is a routine to round Currency variables at a given number of decimal places.
  7536. ASM and OBJ files and sample code included.
  7537.  
  7538. Coerce
  7539.    $0
  7540. is a routine to force Currency variable amounts to 0, 1, 2, or 3 decimal digits
  7541. of accuracy.
  7542.  
  7543. DDE Utility (DDEUTIL)
  7544.    $0
  7545. shows how to do DDE in a generic fashion. Lets you test which DDE commands will
  7546. work with specific applications. Prompts for appname, pathname, topic, item,
  7547. execute string, window mode and attempts to conduct the DDE link. Source code
  7548. included.
  7549.  
  7550. DragForm (DRAGFRM)
  7551.    Simms, Jeff
  7552.    $0
  7553. demonstrates how to drag a form without a title bar and dragging a textbox using
  7554. similar code.
  7555.  
  7556. FixMenu
  7557.    Young, Ted M.
  7558.    $0
  7559. is code that shows how to get/change properties of menu items.
  7560.  
  7561. FOpen 1.1
  7562.    Kitsos, Costas
  7563.    $0
  7564. is a set of forms, VB code, and API calls to create the standard Windows type of
  7565. "Open File" dialog box. A demo is included.
  7566.  
  7567. GPIB
  7568.    $0
  7569. is a sample application that shows how VB can be used as a control and
  7570. monitoring software.
  7571.  
  7572. LstDrag
  7573.    Mosher, Sue
  7574.    $0
  7575. is code for dragging a line in a List box to another line with the mouse or
  7576. cursor keys.
  7577.  
  7578. MultiPik (MULTIPK)
  7579.    Kitsos, Costas
  7580.    $0
  7581. shows how to create a multiple-selection List box with API calls. This is a
  7582. frequently requested feature for VB. Source and demo included.
  7583.  
  7584. NCalc
  7585.    Smaby, Marcus
  7586.    $0
  7587. demonstrates the implementation of a common keyboard handler.
  7588.  
  7589. Numbers
  7590.    Computing, Marquis
  7591.    $0
  7592. is a set of routines to emulate binary coded decimal and IEEE string/numeric
  7593. conversion functions (MKI$, etc.) found in QB and PDS but not in VB.
  7594.  
  7595. PGuide
  7596.    $0
  7597. is the source code for the sample routines in the VB Programmer's Guide.
  7598.  
  7599. Profile.BAS
  7600.    Vance, Rob
  7601. is VB code (API calls) that makes it easy to store program data in WIN.INI.
  7602.  
  7603. SaveMe
  7604.    Irwin, Gregg
  7605.    $0
  7606. provides you with a reminder, as well as the ability, to save a project before
  7607. running it. Forgetting to save before running is a sure way to lose lots of work
  7608. over time. While Irwin designed this as a stand-alone, it seems like it would be
  7609. more effective to make it the start-up form in your program during the design
  7610. and testing period and take it out before compiling.
  7611.  
  7612. Search (SRCH-VB)
  7613.    $0
  7614. contains source code and a sample application for quickly searching a list box.
  7615.  
  7616. Shuffler (SHUFLER)
  7617.    Stine, Brian D.
  7618.    $0
  7619. is VB source code for a utility to shuffle (randomize) sound files assigned to
  7620. system events. Requires Win31 and the Professional Tool Kit for VB.
  7621.  
  7622. Text Style (TXTYLE)
  7623.    Irwin, Gregg
  7624.    $0
  7625. shows how to change the style of Text boxes to allow only uppercase or only
  7626. lowercase letters, to limit the number of characters, and to create a password
  7627. entry box.
  7628.  
  7629. VBArray
  7630.    Kitsos, Costas
  7631. shows how to load/save an array of up to 64k in a single operation.
  7632.  
  7633. VBMPU Demo (VBMPU)
  7634.    $0
  7635. contains an MPU-401 MIDI card demo and play-only source routines. Dynamic MIDI
  7636. channel and velocity change are supported.
  7637.  
  7638. VBXlDem
  7639.    $0
  7640. is source code to show how to access an embedded chart in Excel and link it to a
  7641. basic picture control.
  7642.  
  7643. VB-ISAM
  7644.    Eibl, Gunter
  7645.    $0
  7646. contains the source code for an ISAM-emulation, using the rules of Basic PDS
  7647. 7.1. The emulation needs the Btrieve DLL. An an example is included to see how
  7648. to use Btrieve from Visual Basic.
  7649.  
  7650. VqStrings (VQSTRNG)
  7651.    $0
  7652. allows huge variable and fixed length strings for Visual Basic. VStrings
  7653. delivers fast access and return error codes compatible with Visual Basic's 'On
  7654. Error GoTo'.
  7655.  
  7656.  
  7657. #4062 Miscellaneous, continued
  7658.  
  7659. ComServ
  7660.    Buck, Alan
  7661.    $0
  7662. is the source code for a VB application for keeping track of Zip files. Studying
  7663. other apps is a good way to learn.
  7664.  
  7665. GPMVB1
  7666.    $0
  7667. is source that shows how to use VB to create and edit a form-based document in
  7668. Microsoft Word for Windows.
  7669.  
  7670. GMPVB2
  7671.    $0
  7672. shows how to use DDE to get and manipulate data from Word for Windows.
  7673.  
  7674. MMPVB
  7675.    Turpin, Jerry
  7676.    $0
  7677. shows how to use the MultiMedia Extensions to play MID, WAV, and MMM files.
  7678.  
  7679. VBInst 1.00
  7680.    Kallonen, Jari
  7681.    $0
  7682. is the source code for a VB app to install a program from a floppy to a
  7683. specified subdirectory. It can also create a Program Manager group.
  7684.  
  7685. Winstall.Frm
  7686.    $0
  7687. is source code for a program to find and run installation programs on program
  7688. disks.
  7689. ---------------
  7690.  
  7691.  
  7692. Database, Data Entry, Sorting:
  7693. PsL Disk #4062 
  7694.  
  7695.  
  7696. BtrTest
  7697.    Meyer, David
  7698.    $0
  7699. is source code for a Btrieve for Windows sample program.
  7700.  
  7701. CallBT
  7702.    Kubelka, Bob
  7703.    $0
  7704. contains a function which simplifies using Btrieve with Visual Basic. Requires
  7705. Btrieve for Windows.
  7706.  
  7707. EditDem
  7708.    Milligan, Keith
  7709.    $0
  7710. is a set of data entry control routines for VB: date entry, price/quantity,
  7711. currency, two and four decimal places, string to a specified length, uppercase
  7712. text input, and others.
  7713.  
  7714. Paradox Engine Demo (PDOXED)
  7715.    Jaster, John
  7716. contains a DLL and source code for a simple demonstration of the Paradox engine.
  7717.  
  7718. PXCreate (PXCREAT)
  7719.    Nech, Jim
  7720.    $0
  7721. provides a way to use the Paradox Engine to create Paradox tables in Visual
  7722. Basic. Source Code is included, and VBRUN is required.
  7723.  
  7724. SQL Query (SQLQRY)
  7725.    $0
  7726. is an upgrade of the Query VB program in MS's VB SQL Server DLL kit (required to
  7727. run this file). It improves the handling of returned rows.
  7728.  
  7729. SQLGrid
  7730.    Hyland, Bob
  7731.    $0
  7732. shows how to use a GRID control (on disk #3880) with the VBQSL SQL Server (from
  7733. Microsoft).
  7734.  
  7735. VBDB
  7736.    $0
  7737. is a set of forms and code for a dBase engine. A lot of coding has gone into it.
  7738. The sample application is about 85% complete; the engine is completely done.
  7739.  
  7740. VB-Paradox Engine Interface (VBPXENG)
  7741.    Dooley, Sharon F.
  7742.    $0
  7743. is a set of declarations that create an interface to the Paradox Engine. It will
  7744. translate between VB and Paradox data types.
  7745.  
  7746. VBSort
  7747.    Ford, Nelson
  7748.    $0
  7749. is the code and a sample application for sorting both a List box and an array.
  7750. Testing shows that it takes 8 times longer to sort a List box.
  7751.  
  7752. WinBtrv
  7753.    Novell
  7754.    $0
  7755. is a DLL to allow using Btrieve in VB applications.
  7756.  
  7757. XQLM Declarations (XQLMVB)
  7758.    $0
  7759. are the VB declarations for working with Novell XQL.
  7760. ---------------
  7761.  
  7762.  
  7763. Printing:
  7764. #4226 
  7765.  
  7766.  
  7767. Code.Print 1.6a (CODEPRN)
  7768.    Caladonia Systems, Inc.
  7769.    $35
  7770. lets you print your VB source code with a wide range of options, including
  7771. titles, headers, footers, project name, font control, user-defined pagination,
  7772. margins and line spacing, the ability to print entire applications or single
  7773. modules or routines; to sort source code by subroutine; to serialize backups of
  7774. source code files and to print an index of functions and subroutines.
  7775.  
  7776. Endprn
  7777.    $0
  7778. is source code for a small utility for cancelling a print job.
  7779.  
  7780. HPEnv 2.0 (HPENV-S)
  7781.    Himowitz, Michael J.
  7782.    $0
  7783. is VB source for an application that prints envelopes in landscape mode without
  7784. having to change printer setup. This is also on a Windows applications disk.
  7785.  
  7786. HPESC
  7787.    O'Rourke, Peter
  7788.    $0
  7789. explains how to send ESCape sequences from Visual Basic to an HPIII printer.
  7790.  
  7791. PrSetup
  7792.    Schwartz, Corey
  7793.    $0
  7794. is a DLL and supporting code to add to your applications to allow the user to
  7795. select printers, as well as to adjust printer setup and configuration. All C and
  7796. VB source code is included.
  7797.  
  7798. PrtList
  7799.    Mattila, Jussi
  7800.    $0
  7801. is a set of printer selection procedures for VB.
  7802.  
  7803. Psetup revC
  7804.    Kitsos, Costas
  7805.    $0
  7806. is a DLL that lets you invoke the Windows standard Printer Setup Dialog. Sample
  7807. source code is included.
  7808.  
  7809. PSOut
  7810.    Cramp, Stephen
  7811.    $0
  7812. illustrates a method of printing bitmap files up to 32k in size. It has been
  7813. tested on PostScript and HP LaserJet printers only.
  7814.  
  7815. PWrap
  7816.    Wagner, Richard
  7817.    $0
  7818. is a routine for sending text to the printer with word wrap at word breaks, as
  7819. delimited by spaces.
  7820.  
  7821. VBBook (VBBOOKS)
  7822.    Scott, Dennis
  7823.    $0
  7824. is source code for an app that lets you print ASCII text files to an HPLJ
  7825. printer in booklet format.
  7826.  
  7827. VBPDemo
  7828.    Obeda, Ed
  7829.    $0
  7830. shows how to calculate the default printer's lines per page under the declared
  7831. FONTNAME and FONTSIZE. It will also a allow the user to ABORT the print job,
  7832. thereby flushing the printer buffer.
  7833.  
  7834. VB Printer Control (VBPRINT)
  7835.    Harrington, Dennis
  7836.    $0
  7837. demonstrates how to put a laser printer into Landscape mode and how to select a
  7838. paper bin without going through the Windows print manager.
  7839. ---------------
  7840.  
  7841.  
  7842. Other:
  7843.  
  7844. (The programs in this section are large enough to be on disks by themselves.
  7845.  Their disks numbers are indicated below. The dollar amounts shown are for
  7846.  registering these shareware programs with their authors. PsL charges $5/disk.)
  7847.  
  7848.  
  7849. BasicBasic
  7850.    Davidsaver, Mark
  7851.    $15
  7852.    #4204
  7853. lets you compile BASIC programs for DOS or Windows. Not all "standard" BASIC
  7854. commands are supported. This is a very easy way to develop small programs
  7855. without regard for which environment they will run under. Several sample files
  7856. are included for compiling, and ASCII source code is accepted.
  7857.  
  7858.  
  7859. Quick and Dirty Help
  7860.    Allen, Phil
  7861.    $20
  7862.    #4142
  7863. lets you use any ASCII editor to produce RTF files for the creation of Windows
  7864. 3.0 Help Files. With QDHelp, you can easily create help files with links,
  7865. popups, bitmaps, search keys, and browse sequences. The MS Help Compiler is
  7866. required. (Also see WI-01: #3477, Xantippe, which can create RTF files very
  7867. easily.)
  7868.  
  7869.  
  7870. vxBase
  7871.    Comsoft Inc.
  7872.    $50
  7873.    #7614/3946 [2 disks]
  7874. contains a DLL and sample files for creating dBASE compatible applications.
  7875. Features include up to eight active browse windows, large indexing buffer, memo
  7876. functions, multi-user options, and much more.
  7877.  
  7878. DataWorks 1.25 is on the second disk. It is an xBase power user's tool to be
  7879. used by developers building applications with VXBASE for Visual Basic.
  7880. ---------------
  7881.  
  7882.  
  7883. PsL's July 1992 Visual Basic Disk:
  7884.  
  7885. This disk contains new programs being added to PsL's Visual Basic section.
  7886.  
  7887. Btcreate (BTCREAT)
  7888.    VB: Database/Data
  7889.    J. Highsmith; $0
  7890. is sample source for the use of Btrieve create in VB. Requires 
  7891. the Btrieve for Windows DLL.
  7892.  
  7893. CopyFix
  7894.    VB: System
  7895.    Dan Smith; $0
  7896. explains how to fix a bug in the CopyFile function in the Setup 
  7897. Kit of the PTK.
  7898.  
  7899. ExWait
  7900.    VB: System
  7901.    $0
  7902. demonstates how to use the Windows GetModuleUsage function to 
  7903. cause VB to wait until a SHELL command has finished.
  7904.  
  7905. IcoXtrc
  7906.    VB: Icons
  7907.    $0
  7908. is a routine for extracting icons from executables and DLLs.
  7909.  
  7910. Ini_Mod1 (INIMOD)
  7911.    VB: INI's
  7912.    Forrest Berry; $0
  7913. is a VB module to create, read and update private 
  7914. INI files. You only need to add it to your project and call it. 
  7915. Sample code is inlcuded.
  7916.  
  7917. INotepad 1.0 (INOTPAD)
  7918.    Text Editors
  7919.    Gordon Smith; $0
  7920. is a Windows Notepad look-alike with many improvements, including 
  7921. font selection, word wrap, macros, and the ability to strip carriage 
  7922. returns and linefeeds from text. VBRUN is required.
  7923.  
  7924. MenuOn
  7925.    VB: Menu Bar
  7926.    $0
  7927. shows how to disable and then enable the entire Menu Bar of a Form 
  7928. quickly and without flicker.
  7929.  
  7930. Modalex
  7931.    VB: DLLs
  7932.    $0
  7933. is a DLL that makes a VB app appear modal to the calling app.
  7934.  
  7935. Modified Setup1 (MODIFVB)
  7936.    VB: Custom Controls
  7937.    L.J. Johnson; $0
  7938. adds new features to the PTK Setup program. It provides options 
  7939. to do a Full Installation or Update Files, and allows users to install 
  7940. in either a new program group or an existing group. Other features 
  7941. include many bargraph improvements, 3-D controls, automatic disk space 
  7942. calculation, and much more.
  7943.  
  7944. Pict_t
  7945.    VB: Printing
  7946.    George F. Santamarina; $0
  7947. demonstrates how to print bitmaps using Windows 3.1 Common Dialog 
  7948. routines.
  7949.  
  7950. Print Clipboard (PRINTCB)
  7951.    VB: Printing
  7952.    Clifford P. Barnett; $0
  7953. contains source code and an executable for printing the contents 
  7954. of the Windows Clipboard. Text and graphic dumps are both supported.
  7955.  
  7956. Prnset (PRNSTVB)
  7957.    VB: DLL
  7958.    $0
  7959. is a DLL that allows changes to the default printer settings.
  7960.  
  7961. Shades
  7962.    VB: Graphics
  7963.    Brian Stine; $0
  7964. show how to give your forms a "brushed steel" background like 
  7965. the Borland custom controls.
  7966.  
  7967. VBClean
  7968.    VB: Tools
  7969.    David Hite; $0
  7970. is source for an automatic save/load procedure needed to shrink 
  7971. VB executables.
  7972.  
  7973. VBClock 1.1 (VBCLK)
  7974.    VB: Date/Time
  7975.    Sarah Holland; $0
  7976. contains source code and an executable for a Win31 utility that 
  7977. shows the date, time, and the percentage of free system resources 
  7978. remaining. Options include background/foreground color selection, 
  7979. font selection, alarms, and more.
  7980.  
  7981. VBMacro
  7982.    VB: Tools
  7983.    George Campbell; $0
  7984. is a group of macros for the Windows macro recorder that can 
  7985. save you a lot of keystrokes when writing code in VB.
  7986.  
  7987. WinkDemo (WNKDEMO)
  7988.    VB: Graphics
  7989.    George Campbell; $0
  7990. is source that illustrates how to provide an animated screen 
  7991. while your VB application is loading.
  7992.  
  7993.  
  7994.  
  7995.  
  7996. 
  7997.