--------------------------------------------------------------------------- --------------------------------------------------------------------------- NNNNNNNNNNNN NNNNNNNNNNNN NNNNNNN NNNNNN NNNNNNN NNNNNN NNNNNNNNNNNNNN NNNNNNNNNNNNNN NNNNNNNN NNNNNN NNNNNNNN NNNNNNN NNNNNN NNNNN NNNNNNNNNN NNNNNNNNN NNNNNN NNNNNNNNN NNNNNNN NNNNNN NNNNN NNNNNNNN NNNNNNNNNN NNNNNN NNNNNNNNNNNNNNNNN NNNNNNNNNNNN NNNNNN NNNNNNNNNNNNNNNNN NNNNNNNNNNNNNNNNN NNNNNN NNNNNN NNNNNNN NNNNNN NNNNNNNNNN NNNNNN NNNNNNNNNN NNNNNN NNNNNN NNNNNNNN NNNNNN NNNNNNNN NNNNNN NNNNNNNN NNNNNNNNNNNNNN NNNNNNNNNNNNN NNNNNN NNNNNNN NNNNNN NNNNNNN NNNNNNNNNNNNN NNNNNNNNNNN NNNNNN NNNNNN NNNNNN NNNNNN --------------------------------------------------------------------------- --------------------------------------------------------------------------- Boston Computer News Network September, 1994 A Service of the Boston Computer Society, USA Vol.3 No.9 Sponsored by the Xbase Language Group Clipper Version --------------------------------------------------------------------------- 1. ** Developer Poll ** What's Your Assessment of New Orleans Technicon? ----------------------------------------------------------------------- ReplyTo: Les Squires bcnn@WJI.Com [73020,3435] Reminders: Expect one reminder. Visual Objects, Clipper 5.3, Client/Server . . . What did you think about this year's Technicon? I heard all kinds of opinions, from 'think thoughts, 30 lines max. Next month BCNN/Clipper will publish 15-20 of the most representative statements. Be sure to praise where praise is due and to criticize where criticism is due. And, as always, please distinguish between for-publication and not-for- publication remarks. By the way, I learned at Technicon that a single Bulletin Board in South America logs 2,000 downloads of the BCNN monthly. I'd like to ask a big favor. If you do NOT receive the BCNN directly to your email mail box, but receive it through a secondary source such as a BBS, please find the most beautiful postcard you can of your homeland and send it to BCNN/Clipper at P. O. Box 126, Center Harbor, New Hampshire 03226-0126 USA. Perhaps we'll digitize the photographs and make them available via FTP! At least we can make better estimates of readership. 2. New CompuServe Forum for Visual Objects. (c) CompuServe ----------------------------------------------------------------------- ReplyTo: Ginny Caughey, External Sysop [70714,1741] Welcome to the new CA-Visual Objects Forum! CA is presently shipping the pre-release version of CA-Visual Objects. If you're attending one of our Technicon conferences, you can purchase the pre-release software at the conference. If you prefer, you can call . Comments and suggestions regarding CA-Visual Objects or this forum should be directed to "Sysop" or to one of the individual sysops listed in the Sysop Roster for this forum. 3. A Tour of CA-Visual Objects (September Meeting). -------------------------------------------------------------------------- ReplyTo: Chris Pels <73777.3562@compuserve.com> ReplyTo: Darren J Forcier djf@WJI.Com Meeting: September 20, 1994, 6:30 p.m. Place: Boston Computer Society, Waltham, MA USA 617-290-5700 Now is your chance to see the "Pre-Release" version of Computer Associate's Visual Objects (VO). Darren Forcier and Chris Pels will share their experiences with this much anticipated object-oriented Windows programming tool for our September meeting. A small application will be created and the major features of the product will be reviewed (System repository, Application browser, Module browser, Entity browser, Class browser, Error browser, GUI classes, DBF classes, SQL classes, Report classes, and System classes). The presentation will emphasize the strengths and weaknesses of VO, compared to other currently available Windows development tools. In addition, we'll discuss the transition from Clipper S87 or 5.2 to VO. Come see if VO will be the right tool for your Windows development. Not--------------------------------------------- ReplyTo: David Debus <100241.1325@compuserve.com> I have found a solution for the problem I reported when trying to save BCNN Newsletters to the Filing cabinet using Compuserve WINCIM. It has been acknowledged that the WINCIM filing cabinet has problems handling message files that approach 30K. The solution is very simple. Create a BCNN-News subdirectory and save all newsletters to it by opening the file in the In-Basket and Choosing File-SaveAs-Text. Giving each file a month and serial name actually makes it easy to locate individual issues. Is is also handy for cutting and pasting. The original layout/format of the incoming file is preserved. 5. New Book Due Later this Fall: Windows Multi-DBMS Programming. ----------------------------------------------------------------------- ReplyTo: Ken North of Oceanside California USA <71301,1306> I'm finishing a book that may be of interest to you. The title is Windows Multi-DBMS Programming (John Wiley & Sons, 1994). It includes programming with C++, Visual Basic, Access, SQLWindows, PowerBuilder, ObjectView, Visual AppBuilder and other client tools. It covers ODBC, Q+E Database Library, Oracle Glue and a variety of SQL servers and engines. I've got lots of source code, SQL scripts , evaluaBoduch 72610.444@Compuserve.Com ReplyTo: Hans Conzett of Oberwil-lieli, Switzerland <100015,146> Re: BCNN August UDF showcase EndOfMonth() function problem. >> function EndOfMonth(Date) //--Returns last day of month. >> return BegOfMonth(Date+45) - day(BegOfMonth(Date+45)) The original function definition for EndOfMonth() shown above will produce incorrect results for dates already at or near the end of the month. For example, EndOfMonth(ctod("01/30/94")) would result in ctod("02/28/94"). Here are two ways to code this without running into this problem: o Making use of both the BegOfMonth() and the Clipper sample function AddMonth(): function EndOfMonth(Date) return ( AddMonth(BegOfMonth(Date),1) - 1 ) o Using the built-in Month() function only: function EndOfMonth(Date) LOCAL d := Date, nMonth := Month(Date) while Month(++d) == nMonth ; end return --d 7. Internet UseNet NewsGroups Now Available via CompuServe. ----------------------------------------------------------------------- ReplyTo: Steve Silverwood [CA] 76703,3035 Replyto: Pierce Reid, CompuServe Incorporated, 614/538-4571. Forum: GO INETFORUM COLUMBUS, Ohio, August 15, 1994 -- Access to one of the Internet's most popular services, USENET Newsgrouer (CIM) graphical user interface, making it easy for members to interact with millions of Internet users. Newsgroup topics range from applied research and academic subjects such as quantum physics, weather forecasting and astronomy to social, recreational and entertainment areas such as gardening, music and current events. Participants in USENET Newsgroups contribute knowledge and opinions to create discussions that are both up-to-the-minute and worldwide in scope. The USENET service has been under test at CompuServe since early this summer and user feedback has been very positive. "CompuServe's USENET interface compares very favorably with the more powerful UNIX newsreaders," said Bryan Pfaffenberger, beta-tester and author of The USENET Book: The Definitive Guide to Finding, Using and Surviving Electronic Newsgroups on the Internet, to be published by Addison Wesley this fall. "For anyone interested in accessing USENET discussion areas on the Internet -- from beginners to experienced net surfers -- CompuServe is an excellent choice!" Editor's Note. More enhancements to follow. 8. UDF Showcase. Improvements to Color String UDF. ----------------------------------------------------------------------- ReplyTo: Roy Corneloues, xWare Solutions Limited <100016,63> ReplyTo: Ocizing the sample functions that people submit to BCNN, I'm sorry. It's just that after spending so long at Nantucket/CA I find it difficult not to comment when I can see a better way to do something! Using the supplied sample functions and the settings from "COLOR.CH" the following function is more generic and will return any of the colour attributes. This function uses the sample function ListAsArray(), found in SAMPLES.LIB and the ability to reference arrays returned by functions. COLOR.CH starts at 0 and CA-Clipper arrays start at 1. So as long as the parameter passed is between 0 and 4 we can add 1 to it to get the correct colour setting from the array. #include "Color.Ch" #include "Common.Ch" FUNCTION ClrExtract( nAttr ) LOCAL cColor DEFAULT cColor TO CLR_STANDARD IF nAttr >= CLR_STANDARD .AND. nAttr <= CLR_UNSELECTED cColor := ListAsArray(SETCOLOR())[nAttr + 1] ENDIF RETURN (cColor) 9. UDF Showcase. Determine Row and Column of TBrowse Mouse-Click. ----------------------------------------------------------------------- * File......: SETTBRC.PRG * Author....: Luca Monteleone, CH-8038 Zurich, Switzerland * CIS.......: 100140,1545 * Internet..: GLM@ezinfo.vmsmail.ethz.ch * Date......: 20.02.1994 * Revision..: 1.0 * Compind col of a TBrowse according to a mouse-click * $SYNTAX$ * SetTbRowCol( oTb ) * $ARGUMENTS$ * oTb : TBrowse-object * $DESCRIPTION$ * The function sets oTb:rowPos and oTb:colPos according to a * mouse-click on a TBrowse. It needs a TBrowse _with_ column- * separators, the type of column-separator is not important. * It also sets oTb:refreshAll() if a full-stabilize will be * necessary. As well it can handle "frozen" columns. * $EXAMPLES$ * IF nKey == K_MOUSE * oTb := SetTbRowCol( oTb ) * ENDIF * $INCLUDE$ * * $SEEALSO$ * NUMTOKEN(), ATTOKEN() [Clipper Tools] * $END$ */ *-------------------------- FUNCTION SetTbRowCol( oTb ) *-------------------------- //Determine in which row and column of a TBrowse a mouse-click happend LOCAL nBrTop := oTb:nTop + IIF( oTb:headSep # NIL, 2, 1 ) LOCAL nBrLeft := oTb:nLeft LOCAL nBrBot := oTb:nBottom - IIF( oTb:footSep # NIL, 3, 2 ) LOCAL nBrRight := oTb:nRight - 3 //-Adjust the above four coordinates to your specific needs. I'm using //-scroll-bars and other fancy stuff, so I had to adjust them _this_ //-way! Maybe you want to pass them as parameters ? No problem! LOCAL nFrozen := oTb:freeze //-how many col's were frozen LOCAL nMsew := .F. //-was mouse-click on same row ? LOCAL lSameCol := .F. //-was mouse-click on same col ? LOCAL cLine //-the TB-row where the mouse-click was LOCAL cColSep //-oTb:colSep without spaces and others LOCAL nColBefore //-where have we been before LOCAL nFrom, nTo //-"segments" of cLine q= col's LOCAL nWidth //-width of token from nBrLeft LOCAL nXCol //-this is it ! the new col LOCAL i //-a counter, just that //-Calculate new row, if necessary IF ( nMseRow - nBrTop ) + 1 = oTb:rowPos lSameRow := .T. ENDIF IF ! lSameRow oTb:rowPos := ( nMseRow - nBrTop ) + 1 ENDIF //-Calculate new col: //-Get the TB-row of the mouse-click (we get it _double_ as long as //-it really is, because of SAVESCREEN, remember this further down) cLine := SAVESCREEN( nMseRow, nBrLeft, nMseRow, nBrRight ) //-Get the colSep from the TB-object without spaces or others cColSep := SUBSTR( oTb:colSep, 2, 1 ) //-Save the column before the mouse-click nColBefore := oTb:colPos //-Start and initialize nFrom := nBrLeft nTo := 0 /* //- Do this as many times as there are colSep's (#) in cLine (...) i = 1 i = ^-----------------------------^nBrLeft+nWidth<2> nBrLeft */ FOR i := 1 TO NUMTOKEN( cLine, cColSep ) IF i > 1 //-for i=1 nFrom is initialized as nBrLeft nFrom := nTo + 1 //-take next one _after_ colSep ENDIF nWidth := INT( ( ATTOKEN( cLine, cColSep, i+1 ) ) / 2 ) /* if we're looking for the last token and we don't find it, set nWidth equal to nBrRight */ nWidth := IIF( nWidth = 0, nBrRight, nWidth ) nTo := nBrLeft + nWidth /* And now the deciding part: if the mouse-click was _between_ our nFrom and nTo, take that column ! */ IF nMseCol >= nFrom .AND. nMseCol <= nTo nXCol := oTb:leftVisible - nFrozen + i - 1 //-Did user hit a frozen col ? IF nXCol < oTb:leftVisible .AND. nFrozen > 0 nXCol = nXCol - oTb:leftVisible + nFrozen + 1 ENDIF oTb:colPos := nXCol lSameCol := IIF( i = nColBefore, .T., .F. ) EXIT ENDIF NEXT i //-Stabilize next time oTb ? IF ! ( lSameRow .AND. lSameCol ) oTb:refreshAll() ENDIF RETURN( oTb ) 10. Tips in Indexing, FOR's, and TBrowse. ----------------------------------------------------------------------- ReplyToition to obtain the top of the file each time an index is opened. set index to emplbadg, emplname, emplssn set filter to badge > '099999' dbGoTop() is preferable to: set filter to badge > '099999' set index to emplbadg, emplname, emplssn // in this case dbGoTop() is unnecessary... o FOR Conditions. When performing operations on multiple records based upon a 'FOR' condition, set the index order to an index beginning with the key field of the 'FOR' condition, and perform the operation 'WHILE' the key is true. For example: dbselectarea(0) // grab open work area... use PUNCHES set index to punchbdg, punchdat // set order to 1 ... not necessary select EMPLOYEE DbSetOrder(1) // Employee Badge DbGoTop() Do While !EMPLOYEE->( EOF() ) select PUNCHES nHours := 0 DbSeek( EMPLOYEE->Badge, .f. ) // Seek badge, not soft SUM PUNCHES->Hours TO nHours ; WHILE PUNCHES->Badge = cBadge ; FOR PUNCHES->Badge = cBadge ; .and. !Deleted() Select EMPLOYEE Replace EMPLOYEE->Hours with nHours EMPLOYEE->( DbSkip(1) ) EndDo This is much faster on a large database (i.e. "PUNCHES") since it will o ReFreshAll(). The current implementation of the tBrowse()::refreshAll() operation will update the screen immediately, not waiting for the next ::stabilize() operation. o Current TBROWSE Row. To reset the current tBrowse() row to the current record after a non-browse movement, create a function which will reposition the tbrowse row to the current record. Note#1: It is advisable to disable screen output to decrease the time and to better 'feel' via the Clipper DISPBEGIN() and DISPEND() functions. Note#2: It is easier to set the tBrowse()::row to the top row of the browse, then redisplay the rest of the rows. *----------------------------------------------------------- Function TBrRecPos( oBr, nRec, lRefresh, lStabilize, lHide ) *----------------------------------------------------------- Local nTmp1 // oBr = Browse object // nRec = current record number If lHide // lRefresh = Do we need to invoke refresh? DispBegin() // lStabilize = Do we want to stabilize? EndIf // lHide = Do we want to hide operation oBr:RowPos := 1 // Force to top row If lRefresh oBr:RefreshAll() EndIf Do While RecNo() != nRec oBr:Down() If lStabilize ForceStable( oBr ) ---------------------------- ReplyTo: Roy Corneloues, xWare Solutions Limied <100016,63> Maybe its just me, but I am concerned about the number of third parties distributing their add-ons as .DLLs. Why? Because .DLLs have to distributed with the application. This in effect is like giving the product away to all of your clients. If you develop an app for a company which also has its own development team, as soon as you hand over the final build, what's to stop them from re-using the .DLLs. All they need is the documentation, they don't even need to have a particular development product, most Windows IDEs support .DLLs The use of electronic documentation is also an issue. Its far easier to copy than printed docs, easier to hide from watching eyes and is literally a copy of the original docs. In the CA-Clipper world everyone raves about .DLLs because they will be able to create smaller .EXEs. Big Deal. That was only an issue when memory was a problem. This is no longer the case with Windows. Don't get me wrong. I think that .DLLs are cool if used for the right reasons. I myself will probably use a .DLL for common routines, which aren't damaging to my company, so that updates become much easier if I were to find a bug in one of them. Code which can be exchanged transparently, s protect my own investment. Lets take an example of how I feel it should be done. Let's take Microsoft (they should know what they're doing) and one of their products Word for Windows. If .DLLs are so magical why is the .EXE nearly 2Mb in size? Because all the proprietary code is in the .EXE. Microsoft don't want to give any clues away to its competition. The only parts provided as .DLLs are replaceable components; drivers or third party tools such as spelling checkers. If Microsoft were to place all their code in a .DLL it wouldn't be long before everyone else ripped it off for their own use. Windows is a perfect example of this, and this is how its meant to be. By making all the Windows API calls available from Windows own .DLLs it enables the rest of us the ability to develop Windows apps. Without this we would all be cursing Microsoft. Are you developing a vertical market product? How would you feel having to provide a multitude of .DLLs with every installation? What happens if they are already using the same .DLLs but different versions? Are we back to the days of royalties for every application we install? Will we have to purchase runtimes so that sites are able to use these third party .DLLs? Until someone proves me otherwise, I am not convinced that .DLLs are personal. 12. Clipper Printing Problem. ----------------------------------------------------------------------- ReplyTo: Douglas Schwarz <70474.2520@compuserve.com> I'm in need of a brilliant idea. I've inherited a Clipper program (v 5.0) which prints forms on a bubblejet printer. (The program is used on laptops in the field, and the client is committed to the bubblejet for its portability and clarity.) The program compiles a form and outputs it as an ascii file, with embedded format control codes for the bubblejet. Then the program calls the Clipper Tools function SpoolAdd(), which places the file in the DOS PRINT queue. The DOS PRINT command (issued in a batch file before the Clipper program is launched) then takes care of printing the form in the background, while the user contines to work with the program. The problem is that the print process itself is too slow -- about 2 minutes for a single page form, with minimal graphics and occasional bolding. If the same form is created in and printed from Word Perfect, it emerges from the printer in about half the time, so we know the printer itself is not causing the problem. I have tried using the Clipper TYPE TO PRINTER command to print the file, but the embedded formatting codes do not seem to work right, and in any rameters of the DOS PRINT command -- increasing /M (the number of ticks the PRINT command uses before turning control back to the foreground program) to the max, and /B (the buffer size) to greater than the size of the file to be printed. None of this seems to have any effect on the print speed. So . . . why can't Clipper and/or DOS commands print the file at a speed comparable to Word Perfect? Any suggestions for how to approach this problem? 13. Usability Testing at Kodak (Massachusetts). ----------------------------------------------------------------------- ReplyTo: Alyse Tartell Kodak is seeking interested computer users to come to our facility to "test-drive" our prototype software. Testing offers computer users the opportunity to determine how well the software meets their needs, and to provide valuable feedback before beta testing. The Kodak Usability Lab is located in Billerica, just a mile and a half northwest of the Burlington Mall on the Middlesex Turnpike. All usability tests take place at the usability lab. Interested users will be asked to sign a non-disclosure agreement, complete a brief questionnaire, and to be open and honest in their response. Right now we especially need Windows users, but Mac folks are encouraged to call tuse state of the art hardware and software, which may involve the Kodak Photo CD, image editing or OCR. Usability testing is fun and a fascinating process to be involved in. If you, or an associate, is interested in learning more about this opportunity, please call me at 508-262-2048, or send E-mail. ----------------------------------------------------------------------- 14. UDF Showcase. SeekLast () Seeks Last Record Matching a Given Index Key. ----------------------------------------------------------------------- ReplyTo: O. Douglas Schwarz of Penacook, NH 03303 < 70474,2520> *----------------------- FUNCTION SEEKLAST(s_key) *----------------------- *Seek last record matching a given index key. *If found, position on that record; if not, position on EOF. * PARAMS: S_KEY = Search key * * Example: use orders * set index to custdate // on custno + dtos(orderdate) * seeklast(thiscust) // find last order received from * // customer # THISCUST * *Notes: Assumes the current dbf is indexed such that a normal SEEK * for S_KEY would succeed. Works only for character keys. * RETURNS: .T. if found, else .F. *----------------------- FUNCTION SEEKLAST(s_key) *----------------------- local len_key,if &(indexkey(0)) = s_key return (.t.) else go lastrec() + 1 return (.f.) endif 15. UDF Showcase. vDate() Auto Fills Current Year on GET. ----------------------------------------------------------------------- ReplyTo: Andre Roy Programmer/Analyst Nipissing University, North Bay Ontario, Canada vDate() adds the current year to a date input on a read. This way, if the date format is set to mm/dd/yy, the user would only have to type in 01/27, and this function defaults the year to the current year. For example: dDate := ctod( "" ) @10,10 get dDate valid { | oGet | vDate( oGet ) } read Yes, you have to call it as a code block. This only works if the date format is one in which the year is the last field, so it's not to good for ANSI style dates. Also, any other validation should take place in another function. #translate sz( ,

) => padl( ltrim( str( )),

, "0" ) *--------------------- function vDate( oGet ) *--------------------- local dd := oGet:varGet() local rr := "" local sCent, sDate, m, d, y if oGet:changed //-never mind if no change sCent := __SetCentury( .t. ) //-!! INTERNAL !!//-nothing entered rr := "" else rr := sz( d, 2 ) + "." + sz( m, 2 ) + "." if sCent rr += sz( year( date()), 4 ) else rr += sz( int( year( date()) % 100 ), 2 ) endif endif oGet:varPut( ctod( rr )) //-put the new value into the get endif set( _SET_DATEFORMAT, sDate ) //-restore this stuff __SetCentury( sCent ) //-!! INTERNAL !! endif //-oGet:changed return .t. //-Always 16. BCNN Statement of Ownership, Copyright, and Responsibility. -------------------------------------------------------------------------- The BCNN Newsletter is sponsored by the Xbase User Group of the Boston Computer Society. BCNN is dedicated to keeping professional database developers (both consultants and corporate employees) informed about educational events, meetings, job openings, world events, notable articles, technical tips, new and 'must have' products, etc. As an electronic network, organized by interest rather than geography, BCNN is also a hub where developers can address world class issues to fellow developers around the world. Recipients agree to respond via Email to periodic polls of their directions, opinions, and nescussions on CA-Clipper, Microsoft Access, FoxPro, Gupta SQLWindows, and Suiteware. The newsletter is distributed monthly by electronic mail via CompuServe, Internet, FidoNet, and other electronic gateways. It is free of charge to individual developers. Modest fees are charged to corporations for job placement and third-party announcements. Opinions expressed are solely expressed by the authors or by the Xbase Language Group of the Boston Computer Society, even in cases where 'Xbase Language Group' is abbreviated to 'BCS'. All materials are copyrighted by the BCS, unless otherwise indicated, and free for any user group to redistribute via BBS or newsletter on the condition that a by-line referencing the BCNN and the individual author are included. Les Squires, Director Xbase User Group c/o Word Jenny, Incorporated P. O. Box 126 29 Brick Kiln Road, Kilnwood Center Harbor, New Hampshire 03226-0126 USA 603-253-6109 //-Primary Phone & Messages 24 hours 603-253-7214 //-Messages Only 24 hours 603-253-9864 //-Fax 24 hours a day INTERNET:LSquires@WJI.Com //-First choice for Email. CIS:73020,3435 //-Second choice for Email. Boston Computer Society, Inc. 101 First Avenue, Suite 2 Waltham, MA 0215s@WJI.Com. Address Change: Email using OLD Address. Indicate New Address. Back Issues: FTP WJI.Com, Login as FTP, use your ID as the password, cd clipper, copy all back issues. BCNN Email Services donated by Word Jenny, Inc. LSquires@WJI.Com (c) 1994 Boston Computer Society, Inc.