Welcome to Foxite.COM Community Weblog Sign in | Join | Help
<October 2008>
SuMoTuWeThFrSa
2829301234
567891011
12131415161718
19202122232425
2627282930311
2345678

Post Categories

Navigation

Syndication




Sending mails, using NetExtender

I have been playing around a bit with NetExtender by eTechnologia from Colombia, these guys do some nifty work if it comes to opening the .Net framework for vfp users, it also enables us, VFP addicts, to share some of the datapower of the fox with those poor guys and galls who are so sick to use .NET as is.

One of the pretty features I found is that it is possible to send an email with basically 5 lines of code.

It could use a bit of tweaking to make it a bit more robust, but here are the lines:

omail = clrCreateObject("system::net::mail::mailmessage", ;
"MailaddressOfSender",;
"MailaddressOfReceiver",;
"Subject",;
"text to send")

This one line creates a mailmessage object. I found that adding the 4 parameters, while creating the mailmessage object, is the simplest way to create such a mailmessage.

The next line makes clear that this message is in HTML format,

omail.isbodyhtml = .t.

The next line is this:

osmtp = clrCreateObject("system::net::mail::smtpclient", ;
"URLToTheMailServer", 25)

This line creates the smtp client, it takes two parameters, the first one is the URL to the mailserver.
It should look like mail.yourserver.com or
smtp.YourServer.com
The second parameter is the port of the server.

If your server requires authentication to send e-mails you need to use the following code:

ocred = clrCreateObject("system::net::NetworkCredential",;
"YourUserNameOnTheServer", "YourPassword")

Then you need to add the credentials to the smtpclient object, here is the rocket-science line for it:

osmtp.Credentials = ocred

OK, maybe you need to sit back for a moment. The hardest line is this:

osmtp.send( omail )

Wink [;)]

The clrCreateObject() function I used in the code is one of the function provided by eTechnologia. There are a few more. I will show them, and their usage, in following blogs.

I will keep on playing with the NetExtender.
I will keep you bugging with short notices on useful things I found. 
You didn't really think you could get rid of me that easy? NO WAY!
Stick out tongue [:P]

NetExtender really is very affordable. 120 dollars is not much at all, for those in the Euro zone, this comes down to about EUR 75.
By buying the package you not only get the NetExtender for VFP but also the Net Compiler for VFP, It turns VFP code into .NEt assemblies, executables and, since the latest update, it also enables you to use foxcode behind your aspx pages.

The product has now a bit more than 50% of the VFP features implemented and the progress of the work is going on and on. In my opinion this initiative, along with Graig Boyd's VFP Studio makes the fox stronger than ever. Foxes never die, they re-incarnate in new bodies. (Hmmm, or is this a cat in a cloaking device, meaning this fox/cat should have 9 lifes.)

What I see happening here is that due to the support from our own community an interesting development started. MS let us off the leash. At least now we know for sure that there will be no marketing around the best product ever at least from the side of MS. (Not that they ever did much, but that is common knowledge.) Due to the community itself the fox lives on, in another form maybe, but still as productive and fast as we are so used to. With these developments we can blow other developers right out of the water.

posted Wednesday, July 23, 2008 7:48 AM by Boudewijn | 0 Comments
Filed Under: , ,

MVP, I feel pleased and surprised

As was released on the forum I am awarded with the MVP award by Microsoft.

I feel VERY honored and pleased with this, at the same time I am surprised.
Being very bluint in my opinion(s) in the past I had the feeling that I had minimized my chances for becoming MVP to below zero.

Now that I am awarded I will not really stop speaking out as I feel. (You did not expect that did you?)

What I also feel is an extra drive to bring up my ideas about IT in general and creating solutions for the benefit of all, both your customers as well as you as developer.

Hoping to receive feed-back from you all, so I can improve on these efforts.

posted Thursday, April 05, 2007 12:43 PM by Boudewijn | 0 Comments
Filed Under: , , ,

Interesting email exchange

OK, Back home again. A stay in the hospital is bad for my sense of humor. Earlier this week I sat in one of those conversation rooms where two old men were bragging how sick they were and how painful their operations were et cetera. There I was, with a drain. I got so annoyed with these men that I asked, pointing at the bottle from my drain: "Wanna drink?"

They were gone before I could blink my eye.

Anyway. In all the rush around the BAD news I had a short e-mail exchange with Les Pinter.

He wrote to me: "I found out that Bill Gates had said, to a group assembled in his office, "Every time we sell a copy of FoxPro we lose $10,000 in SQL Server royalties."

So in case you have been wondering what the reason was for finally stopping further development on VFP, here it is, plain and simple money... Ah, Liza Minelli already sang that years ago "Money makes the world go 'round" (in the musical "Cabaret")

posted Thursday, March 22, 2007 8:50 AM by Boudewijn | 0 Comments
Filed Under: , , ,

new site

From the hospital, still a bit drousy from last Friday's operation. Thank God they have Internet.

After last weeks devastating news from MS I decided to set up a new site. VFP2dotNJET.com. AND NO that is NOT a typo. I still hate that less than second best framework thought out by a bunch of crappy guys and galls under the heavy influence of last night's drink.
The logo will be a fox with a tear in his eye, kinda Pagliacci. There will, of course, be a rant page where I tell exactly how I feel about those duckheads in Redmond who killed the only good tool they ever created.

YAG told me Perl and Cobol are still going strong.
Well, for his information, COBOL has a .net compiler, meaning there is development going on and Perl is in development by it's maker and many others. Kind of REAL open source.
I just wonder what they think of us. That we are stupid?
Anyway, his argument is swept off the table by a simple fact that can be checked on the internet.

I have no idea yet what to do with 2 other sites, vfpdevelopers-online and teachyourself-vfp.

What do you think. Let me know.

Be back on-line by the end of the week. (I assume).

posted Monday, March 19, 2007 8:39 AM by Boudewijn | 0 Comments
Filed Under: , , ,

VFP can do Double Byte Character Sets

Much has been written about the double byte character sets already.

Steven Black has an excellent article on his site written by margaret Duddy, look at http://www.stevenblack.com/INTLUsingAsianCharacters.asp

 

Also Rick Strahl has written about his thoughts and solutions about this, in one excellent article on http://www.west-wind.com/presentations/foxunicode/foxunicode.asp

 

Both articles helped me in creating the solution I offer here.

About this article.

This article is written with three goals in mind.

First and for all I want to show that it is rather easy to create VFP applications that can display MULTIPLE Double Byte Character Sets AT THE SAME TIME.

Secondly I want to show that accessing non - VFP sources is relatively easy.

Third, I hope to show that “thinking outside the box” can give you results that you cannot achieve with VFP alone.

About the customer.

Some time ago I was approached by a company in the Netherlands that needed an application.
This company manufactures products for leather processing, think of leather tanning, conservation, coloring et cetera. These products are shipped worldwide.

Due to the divers nature of the products they ship these products with product information, information on health issues when using the products, handling of the containers, security descriptions and more.

They ship these products to all kinds of countries, from western countries as well as to Asian countries and Eastern European countries.

 

This brings a special requirement to the labeling process. The labels need to display the text in the written language of the country they ship the products to.

As a matter of fact, Chinese people are really familiar with Chinese characters, Indian people really are far more familiar with Hindi than with English, German or Dutch.

These, and other languages are written in what we call Double Byte Character Sets, from now on I refer to this as DBCS.

I encourage you to read the above articles by both Margaret Duddy and Rick Strahl to get a better understanding on DBCS and unicode.


The challenge.

We all know that VFP does NOT do unicode or DBCS by nature.

What it DOES do is datahandling, like no other!

I did receive an excel spreadsheet with many languages.

That triggered me. A sheet with both Single Byte Character Sets (SBCS) as well as DBCS.

My first little experiment was to copy/paste one of the DBCS fields from the excel-sheet on a word document. That worked well.

My conclusion was that Windows’ memory did NOT alter the content AND that office controls do display the DBCS data well.

 

I did first create a database from the spreadsheet in  Access. (ok i wash my mouth later on). You can also use SQL Server, Oracle or MySQL for storing DBCS values.

The reason for me was that this application had to be low cost and the amount of data was not that much.

I did check the values in the table in the database among those in the excel sheet, they matched. With this the storage problem was solved. No tweaking needed for that, using other databases can thus be a solution for storing these values in a correct way.

 

The second problem was to display the data in the table.

As we all know the VFP controls cannot display DBCS values, what you see then is ??????????.

As I was determined to use VFP forms for this I had to come up with a solution that was available without much or no costs.

After some research I found that there is an ActiveX file that contains everything we need.

I speak about the FM20.dll in the system folder of your machine.

The controls? Microsoft Forms 2.0 xxx controls. Like Checkbox, Textbox, Listbox, SpinButton and others. a picture of the dialogue can be found here

 

These controls do not have the same possibilities as the VFP controls (did you really expect something else? Dream on!) but they are sufficient for most of the stuff like displaying data.

 

And of course, you can always subclass these controls, which I did, for good reason, as I will show later on in this article.

 

Using ADO to access the database and retrieving the record(s) you want brings the data in a result set in memory.

I created one simple form first to see whether I could display the data in memory.

(Simple display form)

 

Subclassing the activeX control and a builder.

When adding activeX controls to forms you have to follow a number of steps.

First you select, from the forms controls toolbar, the OLEControl.

Then you select Insert Control.

From the list that appears select the control and click OK.

 

This adds the activeX control on your form. It might not quite look like what you want.

The form 2.0 controls (at least the textbox I use here) appear like a square box on the form.

You can see the picture of a form with inserted textbox here

As you can see it is not really suitable for one line in a textfield.

 

So I first subclassed the control after resizing it, storing it in a VCX and then tried to drop it on my form… 

Here you see the result.

Not quite my idea of a useful textbox…

 

So I came up with the idea of a simple builder.

The task of this builder would be as follows:

After dropping a VFP based control on the form the builder can be invoked.

It will replace the vfp control with the activeX control.

It will resize the ActiveX textbox with the sizes of the textbox.

It will remove the original textbox from the form.

It will rename the name of the newly added control with the name of the control that is removed form the form.

 

The code was very simple:

LPARAMETERS P1, P2, P3

 

* parameter statement is needed, NOT in use in this tiny builder prg.

 

Local Array laControls[1]

LOCAL lni as Integer, loCntr as Object, lcname as String, lcNewname as String, lofrm as Object

 

IF ASELOBJ(laControls)>0

   FOR lni = 1 TO ALEN( laControls,1)

 

      *Check whether the control is of bl_text class

      *

      IF UPPER(laControls[lni].class) == "BL_TEXT"

         loCntr = lacontrols[lni]

         lcname = loCntr.name

        

         * Create a temp name form the object to insert

         *

         lcNewname = "_"+lcName

 

         WITH loCntr.Parent

           

            * Add a new object

            *

            .NewObject(lcNewName,;

                       "bltext",;

                       "<drive>:\<folder>\blcontrols.vcx")

 

            * Replace drive and folder

            * with the folder of your own settings

 

           

            * Change the characteristics

            * With those of the control that will be removed at the end.

            *

            .&lcNewname..Visible=.T.

            .&lcNewname..left = loCntr.Left

            .&lcNewname..top = loCntr.top

 

            * adjust width and height a bit

            * for better alignment.

            *

            .&lcNewname..width = loCntr.width+4

            .&lcNewname..height = loCntr.height+2

            .&lcNewname..controlsource = loCntr.controlsource

         ENDWITH

        

         * Remove the old control (the normal textbox)

         *

         lofrm = loCntr.Parent

         lofrm.RemoveObject( loCntr.Name)

        

         * Give the newly inserted control the name of the old control

         *

         lofrm.&lcNewname..name = lcname

      ENDIF

   ENDFOR 

ENDIF

 

This builder has no interface at all, I fancy the saying from Alan Cooper, “there is no better user interface than no interface at all.”

You DO need to register the builder in the home()+”wizards\builder.dbf”

 

Since I want to use this builder with a single object as well as with multiple objects I inserted two records in the builder table.

Make sure that the builder itself can be found by VFP, it has to be in one of the folder in the VFP search path.

The code to register the builder is simple.

 

INSERT INTO wizards\builder (name, type, program) ;

     VALUES ("blbuilder", "bl_text", "blbuilder.prg")

 

INSERT INTO wizards\builder (name, type, program) ;

     VALUES ("blbuilder", "MULTISELECT", "blbuilder.prg")

 

The final result is a form that can display different languages in ONE form 

posted Monday, March 12, 2007 10:51 AM by Boudewijn | 0 Comments
Filed Under: , , ,

Working hard on a new site

Years ago, on Profox, Ken Levy suggested a guerilla tactic in marketing to make Visual FoxPro more visible.

So here is my part. I am now working on a site, www.vfpdevelopers-online.com where any self employed Visual FoxPro addict and any software shop, working with Visual FoxPro, can put ads FOR free.

The site is not quite done yet, lots of pages to create.
I hope that this will, eventually, bring Visual FoxPro more to the attention of the world of managers and IT specialists.

The fox will always keep on running...

posted Thursday, February 15, 2007 10:21 AM by Boudewijn | (Comments Off)
Filed Under: , ,

tagged... oh boy... now what

You foxers are a curious kind of human beings. So Eric Tagged me (how dare he). You really want to know 5 things about this doubledutch Dutchman you do not know, always wanted to know but were afraid to ask?

Do I want to tell you all the gory details? YEAH SURE. I am, after all, your worse nightmare. Never say you did not ask for it! Never say I didn't warn yer.

1. Been married for 3 times. had a wife twice. Now I have a buddy, a true friend who stands next to me no matter what is going on, a lover, a sweetheart first class, a person giving me metal wake up calls. This "angel from heaven" is called Elina.
SHE is responsible for me taking up software developing as a job (so blame her for me being here and making your lives miserable). Before doing this I was working in facility management. I lived, at that time in Hellevoetsluis just below Rotterdam when I fell in love in and with Arnhem.

2. There are dogs and there are Border Collies. And among the latter Joey is God's chosen Stud. Joey is my border and I am training him for trialling. He had a nasty accident a few months ago when he was overrun by a mad Bouvier, broke his leg, got operated and is now up and running and fast and furious.

3. I am a Reiki practitioner. What is Reiki? hmmm, good question. I'ld say, clever people these fox developers! It is originally a Japanese "word" consisting of the word "Rei" meaning "higher", "divine" but also "power" and the word "Ki", meaning "lifepower". I had my first initiation 15 years ago and Reiki, the practice, in all its aspects as described by my teacher and Reikimaster, Mrs Phyllis Lei Furumoto, is the leading principle in my life. I have second degree since 1992 and maybe some day I will have third degree as well, although I still feel reluctant to using the title "Master" that goes with this third degree.

4. THE person being responsible for bringing the smart fox in my life is John zijlstra.
He lived just across the street in Arnhem (I moved 8 years ago to Huissen) had his own company and brought me into fox. I fell in love with the fox and stayed with it ever since.
He taught me first, now he occassionally calls me with questions. he moved too, to the beautiful island of Texel (up north in our country). Did he move or was he looking for shelter, away from this mad developer that I am ever since.

5. I like to sing, nothing as good as a barbershop song to start the day.
So, "when a rainy day comes, and a cloud of gray comes, and I lost my sunny day...
Mr music master, make my heart beat faster, you can chase the rain away....
So when you write a melody.
Just add the words and think of me
and give me a song an old barbershop song that I can sing when I am blue
Give me a beat
to start tapping my feet and make my worries fly away...

OK, satisfied? let's see what

Marcia "10 casualties" Akins, Big Smile [:D]has to say. (these poor people and the beamer are now recovered).
Or what about Jamie Osborn, that ozzie is around on foxite for a while already?
Now that we are down under, Bernard Bout, YOU ARE TAGGED MAN!
OK From eastern europe, Borislav Borrisov, I am curious what you got to say.
I am not sure whether this much respected lady has a blog here already, but Tamar Granor, you too are tagged.

No laughing please, signatures after the show. Smile [:)]

Boudewijn Lutgerink

posted Sunday, January 14, 2007 10:25 PM by Boudewijn | 1 Comments
Filed Under: , , ,

The errors MS made in the .NET introduction

No doubt that, as developers, we are adults. Different in age, some are just starting this trade, others have years of experience. 

Thanks to Ken Murphy from Canada I received a book by Dr Jane Vella, Learning to listen, Learning to teach. A book worth reading over and over again. You find someting new every day in those pages. Thanks Ken, this book is a real holidays gift!

This book is all about teaching adults. Reading it was a constant "YES" experience. The materials offered were corroborating each and every time the things I intuitively already knew.

Reading it made me also aware of what MS did wrong to the VFP community when introducing VS.NET to this strong community.

There are several principles Vella teaches throughout this book.

One of them is "Listen to your audience BEFORE writing down your teaching materials".
From what I know, MS never bothered a minute about how we felt, they needed someting new to make money. Where do you want to go today? Actually we don't care, you go where WE want you to go!

One other thing Vells teaches in that book is "immediacy".

When teaching new things to adults they want to see an immediate result from that teaching, they don't have time to loose. Adults want an "AHA" experience. You learn something, see the immediate use for it in your daily life and so you accept it and start thinking about how to smoothly implement it. Whether it is a way to make money (your job), to make your communication ability better (thus enabling you to go up the ladder of your career) or to write better code through a trick you learned (either here on foxite or elsewhere.)

What stunned me at the attempts from MS to introduce .NET to us, VFP developers, is the fact that I saw no immediate use for this new technology or even of parts of it.

All they said, in my experience, was "it is better!", "yeah sure, then how come I can develop software 4 times quicker using VFP than .NET?" was always answered with, "It is better!"

One other principle Vella teaches is "teaching in context".

This means that you have to refer to what adults already know and ADD the new knowledge to this, making the new technology an enrichment. When MS introduced .NET to us they showed completely new code. Fine with me. "How can I use this in the context of VFP is one question I once asked". The reply from the presenter was: "Your attitude has to change buddy!" I told the man I was not his buddy and that I was a paying participant in that particular DevCon (Frankfurt 3 years ago). I left his session immediately.

Yet another principle is "safety".

When confronted with new things we are challenged. HOW the new things are presented makes the difference whether or not the new stuff will be accepted.

Push "new stuff" down the throat of people and they will object, they will object fiercely. It makes them feel UNsafe, thus the defending attitude arises naturally.

Compare this with groups of people protesting against whatever they feel is not right.

They hardly ever are capable to make a real change, they want to PUSH their choice onto other people. REAL changes come from within, because an organization sees the need to change. Individual people are NOT different. PUSH them towards a change and they tend to move away from it. SHOW them how choosing for a change will positively affect them and they still have that "a choice", and the alternative might be accepted much easier. They do not feel pushed, people then do not feel unsafe.

One other thing (of 12 in total) Vella teaches in the book is "leave any of these principles out and you're lost".

Microsoft left something out...

Want to read about adult teaching?
"Learning to Listen, Learning to Teach" by Dr Jane Vella. ISBN10: 0787959677 | ISBN13: 9780787959678

Boudewijn Lutgerink

posted Tuesday, January 02, 2007 8:23 AM by Boudewijn | 2 Comments
Filed Under: , , ,

The added values of visiting DevCons

Although we do work now for near to 2 years in the same version of VFP I found last week that visiting a DevCon is very worthwhile. I was in Frankfurt last week.

Not only did I get the chance to renew contacts and meet new people, more than that I did get new ideas that made my head nearly explode.

I survived Lisa Slater Nicholls 3 sessions on reporting in VFP9, including one session on the new stuff that will be available in SP2, more than that she showed some neat tricks that can be done in the current version that I did NOT know of.
It did take her three sessions to make my brain sizzle with new ideas and she used the last session to shoot them poor brains out.

Or what about taking metadata to the max as Andy Kramek showed here. I decided to rewrite some of my apps so they will be much easier to ship to various clients. I only change some info in my tables and I have a totally different application with new behavior, no need to recompile the exe.

I also survived Marcia Akins' Session on Best practices on Class Design, she started trowing things at people if they gave a good answer, Candy bars that is, only 10 casualties, including the beamer...

Or what About Doug Henning's session on IntelliSense. He showed some cool tricks on implementing IntelliSense in your apps. That is one thing I can and will most definetely implement in my apps as soon as possible. (quite easy actually).

Then there was the session of Beth Massi on LINQ, although I do see some use for that I still have to find usecases for other stuff (running SQL statements against running processes on a computer makes no sense YET for me.)
Although entirely different stuff from VFP I will consider using .net stuff, especially VB.net
It did spark some ideas indeed.

I can go on for hours on the hot and cool stuff I learned there in the 3 days the DevCon did go on. Actually, it does last longer. OK, I was there for the full 3 days it did take, but generating code, based on the ideas I got there makes the energy of the DevCon stay alive much and much longer. I now already know that I will go there next year as well as to Prague. (I did meet Igor Vit, a very, very nice guy.)

The sessions went from early morning till early morning, although the last session were held in the bar. (mostly till way after 1:00h in the morning.)

99% of my work is done in VFP9. Therefore I dare say that I am quite experienced in using the product. Nonetheless I learned so many new thing during the DevCon in Frankfurt last week that this was most definetely a major boost in my insight on the product.

Whenever possible go and visit one DevCon in your neighborhood, you will find it most definetely worthwhile !!! I DO encourage you to seriously consider this, it will make you a better developer.

Last word as a major THANK YOU RAINER BECKER from the bottom of my heart for making this DevCon possible. You are a fantastic host, and as ever the sessions were great! I'll be there next year most definetely!

posted Monday, November 13, 2006 7:33 AM by Boudewijn | 0 Comments
Filed Under: , , ,

getting rid of IntelliSense popup windows is so easy, and still have the sample available

Although IntelliSense is maybe one of the best productivity tools in the long hsitory of VFP it sometimes is very much present in a way that can really bother you. Simple example, type the SELECT command and a huge popup shows up right over your code. Not something you really want. So, you can, of course, disable IntelliSense but that is a disadvantage because then you don't see all the help offered by IntelliSense.

Here is one of the reasons I like DevCons so much, you get tips from your collegues.
Yesterday Simon Arnold and I were talking to Andy Kramek and he showed this cool piece of code.

Here it is:

RELEASE _oFoxCodeTips

PUBLIC _oFoxCodeTips

_oFoxCodeTips = NEWOBJECT( "frmtips", "foxcode.vcx", HOME()+"foxcode.app")

_oFoxCodeTips.show()

Type this in first and then try a select statement in your command window, all the IntelliSense output is redirected to the little window that just popped up.

having another window floating around is not all that good, your IDE gets a bit cluttered then, so you can dock it over the command window, just like any other window like the session window, the property sheet etc...

Even that process can be automated, just use the following command.

DOCK NAME _oFoxCodeTips POSITION 4 window command

Place the above lines of code in a small prg and place that in your home() folder.

So the complete code looks like this:

* Andy Kramek's Code.
RELEASE _oFoxCodeTips
PUBLIC _oFoxCodeTips
_oFoxCodeTips
= NEWOBJECT( "frmtips", "foxcode.vcx", HOME()+"foxcode.app")
_oFoxCodeTips.show()

* Code form Simon Arnold and Boudewijn Lutgerink
DOCK NAME _oFoxCodeTips POSITION 4 window command

Next, in your config.fpw, add one line:
Command = WhatEverYounamedThePRGFile

TIP

DO NOT add that program as the startup program in the file Locations tab under tools->options, it will make then the command window disappear (as Simon and I found out last night.)

posted Sunday, November 12, 2006 5:49 AM by Boudewijn | 0 Comments
Filed Under: ,

cute little tool making you productive

I use this tool for quite a while now. VariSense it is called. So what it does is simple but increases your productivity a lot.

When starting VFP it does start the prg as a typical "on key label" thing.
I personally use ctrl+SPACE for this.

So, here is a sample.

I am in a codesnippet and I declared two variables, as in:

Local lcString as string, lcString2 as string

Any further in the code I type "lc" and then press ctrl+SPACE. VariSense then immediately fills the string up to lcString (common denominator for both variables), pressing CTRL+SPACE again brings up a small popup that has both variables in it. navigating to either one and pressing enter does bring up the right name (even in the case you declared it.)

Another sample:
In the code I have a #DEFINE somevar Value

I also have #INCLUDE MyHeaderFile.h, in that file I have another #DEFINE like

DEFINE somevar2 AnotherValue

In the codesnippet I type "some" and press CTRL+SPACE.

varisense fills that up to somevar, typing ctrl+space again brings up a list of DEFINE'd variables from which you can take a pick;

Here's the code:

********************************************************************************

* Title: VariSense 1.2

* Author: Derek J. Kalweit(dkalweit@sensiblesoftware.com)

* Description: This program belongs under an "ON KEY LABEL" in your development

* environment. When triggered, it will automatically consult your declared

* variables and determine what it can do to complete it for you if possible.

* This can lead to a huge savings in typing, particularly if you routinely use

* long, clear variables with very unique names. This is the functionality

* available with a CTRL+SPACEBAR key combination in VC++, though VC++ is smart

* enough to do this with member variables and functions as well(which this is

* not).

* Terms of use: Freeware. Feel free to use and modify for your needs. Send me

* any useful/interesting enhancements so that I may include them in the main

* version, if appropriate.

********************************************************************************

* Version History:

* 1.2(Released 2003-2-28):

* o Adds support for "DIMENSION" arrays

* o Adds support for function parameters defined in parenthesis versus LPARAMETERS statement

* 1.1(Released 2002-10-18):

* o Added drop-down menu to pick ambigious variables

* 1.0(Released 2002-10-8):

* o Original release

********************************************************************************

* Special Thanks to:

* Ed leafe(ed@leafe.com):

* Contributed code to add drop-down menu for ambiguous variables

* Bo Durban(wdurban@datascantech.com):

* Contributed EditPos() function to get cursor position for drop-down menu

********************************************************************************

SET ECHO OFF

#DEFINE VARIABLE_CHARS "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTYUVWXYZ0123456789_"

SET LIBRARY TO (SYS(2004) + "FoxTools.fll") && foxtools is always in the foxpro dir, right?

DECLARE INTEGER Beep IN KERNEL32 AS Beep INTEGER nFrequecy, INTEGER nDuration

LOCAL hwndCode, laEnv[25]

LOCAL cVariables

LOCAL cProgText, iLastLine, aProgText[1], iLine, cLine

LOCAL liStartParen, liEndParen

LOCAL iOffset

LOCAL aVars[1], y

LOCAL cDeclaredVar

LOCAL cNewVar

LOCAL cChoice, nRow, nCol, iMatch, cOnSelect

hwndCode = _WonTop()

IF 1 == _EdGetEnv(hwndCode, @laEnv) Then

IF 0 == laEnv[12] && AND INLIST(laEnv[25], 0, 1, 8, 10, 12) Then

LOCAL iPos, cVar, aMatches[1], iMatches

iMatches = 0

iPos = laEnv[17]

cVar = GetVariable(@hwndCode, @iPos)

IF NOT EMPTY(cVar) then

*-- get all code from the beginning to our current cursor position, as we care about nothing more.

cProgText = _EdGetStr(hwndCode, 0, iPos)

iLastLine = ALINES(aProgText, cProgText)

FOR iLine = iLastLine TO 1 STEP -1

cVariables = ""

cLine = WSTRIM(aProgText[iLine])

DO CASE

CASE "LOCAL " == UPPER(LEFT(cLine, 6)) AND "ARRAY " == SUBSTR( UPPER(cLine),7,6)

cVariables = WSTRIM(SUBSTR(cLine, 13))

CASE "LOCAL " == UPPER(LEFT(cLine, 6))

cVariables = WSTRIM(SUBSTR(cLine, 7))

CASE "PROC" == UPPER(LEFT(cLine, 4))

EXIT

CASE "FUNCTION " == UPPER(LEFT(cLine, 9))

liStartParen = AT("(", cLine)

liEndParen = AT(")", cLine)

IF liStartParen > 0 AND liEndParen > liStartParen Then

cVariables = WSTRIM(SUBSTR(cLine, liStartParen+1, liEndParen-liStartParen-1))

iLine = 0 && This forces the loop to exit after it does the dirty work...

ELSE

EXIT

ENDIF

CASE "LPARAMETERS " == UPPER(LEFT(cLine, 12))

cVariables = WSTRIM(SUBSTR(cLine, 13))

CASE "PARAMETERS " == UPPER(LEFT(cLine, 11))

cVariables = WSTRIM(SUBSTR(cLine, 12))

CASE "PRIVATE " == UPPER(LEFT(cLine, 8))

cVariables = WSTRIM(SUBSTR(cLine, 9))

CASE "PUBLIC " == UPPER(LEFT(cLine, 7)) AND UPPER(GETWORDNUM(cLine,2)) <> "ARRAY"

cVariables = WSTRIM(GETWORDNUM(cLine, 2))

CASE "PUBLIC " == UPPER(LEFT(cLine, 7)) AND UPPER(GETWORDNUM(cLine,2)) == "ARRAY"

cVariables = WSTRIM(GETWORDNUM(cLine, 3))

CASE "DIMENSION " == UPPER(LEFT(cLine, 10))

cVariables = WSTRIM(SUBSTR(cLine, 11))

CASE "#DEFINE " == UPPER(LEFT(cLine, 8))

cVariables = ReadDefines(cLine)

CASE "DECLARE " == UPPER(LEFT(cLine, 8))

IF INLIST( UPPER(GETWORDNUM(cLine,2)), "SHORT", "INTEGER", "SINGLE", "LONG", "STRING", "OBJECT")

cVariables = WSTRIM(GETWORDNUM(cLine, 3))

ELSE

cVariables = WSTRIM(GETWORDNUM(cLine, 2))

ENDIF

CASE "#INCLUDE " == UPPER(LEFT(cLine, 9))

 

**** Code for ReadInclude taken away here

lcFile2open = GETWORDNUM(cLine,2)

IF FILE( (lcFile2Open) )

ALINES( laINCL, FILETOSTR( lcFile2Open),.T.,CHR(13)+CHR(10))

FOR lnItemsInArray = 1 TO ALEN( laINCL,1)

cVariables = WSTRIM( GETWORDNUM( laINCL[lnItemsInArray], 2))

IF UPPER(cVar) == SUBSTR(UPPER(cVariables), 1, LEN(cVar)) Then

* Add Match to list

iMatches = iMatches + 1

DIMENSION aMatches[iMatches]

aMatches[iMatches] = cVariables

ENDIF

ENDFOR

ENDIF

ENDCASE

 

* addToArray(@cVariables, @aMatches, @avars, cVar)

* Let's handle multi-line definitions...

iOffset = 0

DO WHILE ";" == RIGHT(cVariables, 1)

iOffset = iOffset + 1

cVariables = LEFT(cVariables, LEN(cVariables)-1) + WSTRIM(aProgText[iLine+iOffset])

ENDDO

 

FOR y = 1 TO ASPLIT(@aVars, cVariables, ",")

cDeclaredVar = WSTRIM(aVarsYes [Y])

IF " " $ cDeclaredVar Then && Don't include anything beyond the space; Strong-typing comes to mind

cDeclaredVar = LEFT(cDeclaredVar, AT(" ", cDeclaredVar)-1)

ENDIF

IF CHR(9) $ cDeclaredVar Then && Don't include anything beyond the tab

cDeclaredVar = LEFT(cDeclaredVar, AT(CHR(9), cDeclaredVar)-1)

ENDIF

IF "[" $ cDeclaredVar Then && Don't include anything beyond the array subscript; We could set this up to include the array subscript, as it will be used most places...

cDeclaredVar = LEFT(cDeclaredVar, AT("[", cDeclaredVar)-1)

ENDIF

IF "(" $ cDeclaredVar Then && Don't include anything beyond the array subscript(some people use these parentheses for arrays!!!)

cDeclaredVar = LEFT(cDeclaredVar, AT("(", cDeclaredVar)-1)

ENDIF

IF UPPER(cVar) == SUBSTR(UPPER(cDeclaredVar), 1, LEN(cVar)) Then

* Add Match to list

iMatches = iMatches + 1

DIMENSION aMatches[iMatches]

aMatches[iMatches] = cDeclaredVar

ENDIF

NEXT

NEXT

* Now we go to the head of the prg to look at the #defined vars in the file and in the #includes

* cProgText = _EdGetStr(hwndCode, 0, iPos)

* iLastLine = ALINES(aProgText, cProgText)

* Need to solve this problem

* BL * FOR lnI = 1 TO ALEN( aProgText,1)

* BL * lcLine = aProgText[ lnI ]

* BL *

* BL * DO CASE

* BL * CASE "#DEFINE " == UPPER(LEFT(lcLine, 8))

* BL * cVariables = ReadDefines(lcLine)

* BL * CASE "#INCLUDE " == UPPER(LEFT(lcLine, 9))

* BL * ReadInclude( lcLine, cVar, @cVariables )

* BL * CASE ("FUNC" $ UPPER(lcLine) OR "PROC" $ UPPER(lcLine)) AND ;

* BL * LEFT( lcLine, 1) <> "*"

* BL * EXIT

* BL * ENDCASE

* BL * ENDFOR

* BL * addToArray(@cVariables, @aMatches, @avars, cVar)

iMatches = ACleanUp( @amatches )

IF iMatches > 0 AND VARTYPE( aMatches[1]) <> "L" Then && we have at least one match!

cNewVar = GetBestMatch(@aMatches, cVar)

IF UPPER(cVar) == UPPER(cNewVar) THEN

IF iMatches > 1 Then

cChoice = ""

nRow = 0

nCol = 0

EditPos(@nRow, @nCol, @laEnv)

DEFINE POPUP shortcut shortcut && RELATIVE FROM MROW(),MCOL()

FOR iMatch = 1 TO iMatches

DEFINE BAR iMatch OF shortcut PROMPT aMatches[iMatch]

cOnSelect = [ON SELECTION BAR iMatch OF shortcut cChoice = "] + aMatches[iMatch] + ["]

&cOnSelect

ENDFOR

ACTIVATE POPUP shortcut AT nRow, nCol

cNewVar = cChoice

ENDIF

ENDIF

ChangeText(@hwndCode, laEnv[17], cVar, cNewVar)

ELSE

* If there's no match, BEEP!!!

??CHR(7)

ENDIF

ENDIF

ENDIF

ENDIF

RETURN .T.

 

FUNCTION GetBestMatch

LPARAMETERS taMatches, cVar

LOCAL cMatch, iMatches,