special symbols

Every now and then I find myself looking for that special drawing that seems so hard to get.

yesterday i was playing with Paint.Net, a freeware image processing application that comes pretty close to Photoshop (so I heard, never used Photoshop to start with).

The nice thing is that there are many plug-ins for effects available for this application, so yesterday I found a plug-in to create buttons. Shiny, good looking button pictures that you can use in your applications.

Though the UI, the maker of this particular plug-in created, adds text to the button, based on the special characters that are available in fonts like WebDings, wingdings etc.

As I simply refuse to remember all the special characters that are in the different fonts (I have other things on my mind) I created a simple table, with all ASCII chars from 1to 255 and put that in a grid with for each column another fontname.

I included it for your use here.

have fun

 

Detecting rightclick in an ActiveX Treeview control, revisited

march 2005 Rino Veryser wrote in his blog about the problems he had detecting a right-click in a treeview control.

I am currently working on an app that uses the treeview extensively.

I too needed that right-click. And this is what I came up with:

LPARAMETERS tnButton, shift, x, y

#DEFINE MOUSE_LEFT 1

#DEFINE MOUSE_RIGHT 2

#DEFINE TwipsCalc 96*1440

IF tnButton == MOUSE_RIGHT

   oNode=this.Hittest(x / TwipsCalc, y / TwipsCalc)

   IF TYPE("oNode")="O" AND !ISNULL(oNode)

      this.DropHighlight = oNode

      WAIT WINDOW oNode.Text TIMEOUT .5

   ENDIF

ELSE

   DODEFAULT()

ENDIF

This does detect the rightclick like a charm.

calculation for the x and y position is because of the fact that the treeview control uses twips, instead of pixels.

You can read more about that in the article by DOug Hennog, download ID 48 of the download page of this fine site.

Some more info I found in one of the forms that ships with the samples.

c:\program files\microsoft visual foxpro 9\samples\solution\tahoe\listdd.scx

I can at least go ahead.

Cheers and happy foxing.

 

Boudewijn

Creation date is not always the creation date

Rereading Ken Murphy's post on software protection (see message ID 133912 of the forum) I was stunned that he had some logic against the creation date of the exe file.

In my opinion, and I have to confess I never took a closer look at it, the creation date is the date the exe was compiled as such at a given time.

Well, I was wrong, THAT is reflected in the modified date.

The creation date is the date the exe is copied onto the disk.

This works only when you unzip a file, using an installer appearantly touches the creation date and sets it to the date it is actually compiled.

I just wanted to share this with you all maybe old news for some of you, maybe I helped some with this.

The skinny fox

Sexy sells.

Yep, again I bother you with a whitepaper, a weird name, by the way, for a piece of paper, covered with black spots called letters, what is so white on these kind of papers? Wink [;)]

Each and every salesman can tell you that sexy sells.
Coming from the battleship gray colors of windows 95 with dull icons we came into the colorful world of XP and Vista (the latter for those who like pain).

The old way of creating applications will not do you any good in terms of sales these days.

Of course, good functionality has the highest priority in software development. It does not really matter how sexy your application looks, if the functionality is not good then your customers won’t be happy either.

Personal confession.

I have to confess that the way my apps looked could not bother me for a minute in the past, it  just was not important in my book. That attitude went on until I read the book “Mastering the Requirements Process” by Suzanne and James Roberts (ISBN: 0-201-36046-2).

In Chapter 7 of that must read book they write:
“You might think of non functional requirements as those that give character to the work”.
Things like speed, security et cetera are non functional, but they add to the user’s acceptance of your application. Let’s face it, if you application is as slow as a drunken snail in thick mud, as stable as quick sand and shows C5 errors every hour or so your users would not be very happy.

Another big point they make is the look and feel of a product. (page 115 to 118)
In this era of attractive looking applications you should also take into consideration the audience of your applications. Maybe not so much when you work as an in-house developer, although your users may like the work you do (take a look for some cool samples on Bernard Bout’s Weblog (
http://weblogs.foxite.com/bernardBout), but even more so when you develop applications for commercial sales. I talk YOUR money here. 

The aforementioned book, along with some conversations I had with (potential) customers, showed me that giving this some attentention could very well help me sell more of my applications in the markets.

The target of this whitepaper

This whitepaper covers only a part of making your applications look better.
I show here a way of adding skins to your applications.

In this article I will show some forms with a skin, no doubt that some of you will recognize the skins, as they are taken from the samples that were once available on vfpskin.com.ar. Unfortunately that site is under construction for quite a while and it is still unclear when they’ll be back. Hence the motivation for my project.

I do not claim it is perfect and complete, far from that, it is just a way to get things started from what I hope may be a way to give the VFP community some extra zest to their applications. I know that there are some great graphical artists out there, so maybe they too can give us some nifty skins to add to our apps.

Graig Boyd put it so well during one of his sessions at the SouthWest Fox 2008 conference, “creating modern looking applications is a must these days if you want to sell them. (and along with that, your services as a developer.)”

The source of all evil.

For those of you who never visited http://www.news2news.com/vfp/index.php,, you have been missing quite something. The site owner, Anatoliy Mogylevets, maintains a lot of code and samples, showing what cool things you can do with the windows API. Some code is only accessible if you take a subscription to that site, but that still leaves many samples accessible. Speaking for myself I can say that taking a year subscription to this site was and is worth each and every €uro I paid for it.
If you even dare to tell that you never heard of that site then that makes me wonder on what planet you have been living.

Based on the sample on http://www.news2news.com/vfp/?function=-1&example=499, “How to draw custom Window Caption on FoxPro form” I created a class that handles most of the skinning itself.

I’d like to share this code with you all so you can take advantage of this. (I hope).
For my own usage I did make some changes to the code. The main advantage as I see it is that the way I do things now makes skiining the fox very open to new input so the fox can cunningly disguise himself as a gentleman.

This is a project under construction, so if you have any ideas and improvements, let me know, I am open to suggestions. Before sending me suggestions read also the todo list at the end of this article, I can be found at: B.Lutgerink@betuwe.net

So what is skinning anyway?

The whole idea is very simple.
Put some pictures at the very edges of a form, cut off the titlebar and borders of that form and voila, you have a new border around your forms.
Sure enough that does take some real estate off the form, but the gain is a better looking form.
The other gain is that you can create your own borderstyles.
So if you are a graphical artist (besides being a helluvaDatabaseGeekWhoProgramsCirclesAroundTheCompetition) go as you please and share your art with us all.
 

In the above picture I stretched the form a bit here so you can see the effect of a new border. Normally the picture will show at the very edges of the form. As shown in this article.

There are 8 pictures involved in this, starting at the top left going clockwise you see:

·         TopLeft.gif;

·         TopBar.bmp;

·         TopRight.gif;

·         RightBar.bmp;

·         RightBottom.gif;

·         BottomBar.bmp;

·         LeftBottom.gif;

·         LeftBar.bmp

Notice that for the corners I use GIF files, the reason for that is that since they fill in a corner I don’t want to see the inner and outer parts of the picture, So I made those parts of the pictures transparent. Gif is supporting transparancy.

 vs

The topbar, rightbar, bottombar and leftbar are BMP files, the reason for that is that when these files get stretched (image property stretch set to 2) they don’t fade, as some other graphical filetypes do.

On the above picture you see the individual parts of the border on the form.
Before going REALLY technical I show you what the form looks like when it runs:

I did not add any code to adjust the backcolor of the form, that is all in the class I created.

It reads an ini file and there are the settings for these types of data.

Since ini files are very easy to change this gives you a chance to create and add your own skins to your applications. Very open source and extensible to your own liking and taste.

Now, are you ready to roll? Here comes the technique:

Teach me the Magic

Some  assumptions first. So that there will no misunderstanding of how I work.

You might need to adjust the code if you do things differently.

·         When starting my applications I alway create a public application object that handles most of the behavior of the application.
That is also the place where I put the name of the skin I want to see. This makes it very easy to simply drop one object on the form where I want the skin to appear. So my application class has one property named “skin”.

·         The value of this property is also the name of a folder under the application folder where all pictures reside. As well a a skin.ini file. More on that later.

·         Besides the property “skin” my application object also has a method SetSkin.
This method reads my application ini file, locates the SKIN section and reads the SKIN key.

Using an ini file makes it easy for you to change the behavior of an application

without having to compile the project again.

I use Simon Arnold’s initoobject class for this, in the original the classname in the

prg is ClsinitoObject, I seem to have sticky fingers so I often made the typo

clsInitobject (one o), therefore I changed the classname to clsini2Object.

(look at download ID 106 on the download page of foxite.

In the SetSkin method of the application object, the ini file is read and if the Skin

section and the skin key are there the value of skin is put in the skin property of

the application object. Here is the code:

LOCAL loini as clsini2object OF ini2obj.prg

 

loini = NEWOBJECT("clsini2object","ini2obj.prg","",this.cIniFile)

 

lcSkin = loini.readvalue("Skin", "Skin")

 

IF NOT ISNULL( lcSkin)

   this.skin = lcSkin

ENDIF

 

 

For the remainder of this article I will assume that you drop the formskinning object on the form itself.
I adjusted the code a bit so you can use it by dropping the object on your form.

So here’s the piece of code you need in the init of the form:

IF PEMSTATUS( goapp, "skin", 5) ;

   AND NOT EMPTY( goapp.skin) ;

   AND DIRECTORY( goapp.skin)

  

   FOR EACH loControl IN this.Controls

      IF UPPER(loControl.class) == "FORMSKINNING"

         loControl.FormInit()

         exit

      ENDIF

   ENDFOR

ENDIF

First the existence of the skin property is checked, if that is not empty AND there is a folder with the name of that skin only then the remainder of the code will run.

In the for … endfor loop the controls on the form are checked, if one of them is of the formskinning class the forminit method of that class will run.

Here’s the forminit:

LOCAL lcColor AS STRING

 

LOCAL loini as clsini2object OF initoobj.prg

 

loini = NEWOBJECT("clsini2object","initoobj.prg","", goapp.cInifile)

 

THIS.DECLARE()

WITH THISFORM

   .ADDPROPERTY("ProxyBorderStyle",3)

   .ADDPROPERTY("StartX",0)

   .ADDPROPERTY("StartY",0)

ENDWITH

 

WITH this  

   .AddImages()

   .ActivateImages()

   .SetMousePointer()

   .PositionImages()

   .AddButtons()

   .PositionButtons()

   .AdjustProxyCaption()

ENDWITH

BINDEVENT( THISFORM, "resize", THIS, "cutframe")

BINDEVENT( thisform, "resize", THIS, "PositionButtons")

THISFORM.RESIZE()

·         First the declare method is called, here the API functions needed for the skinning process are called.

·         It adds three properties to the form

·         then it adds the pictures, activates the images, this means that there is a bindevent for each of the images 1 to 6;

·         It sets the mousepointers for each of the images 4 to 6,

·         In the next step the close, max and min button are added.

·         The buttons are positioned.
Mind you, since the position of the “buttons” (just shapes actually) are determined on the position of the righttop image (img3) the images need to be positioned first.
If you forget about this order things turn out to be so messy, and for sure, the fox doesn’t like messy workers.

·         The next step is to adjust the captioncontrol, this is just a label that:

Ø  takes over the caption of the form and;

Ø  mimics the dragging of the form once you click with the mouse on that and drag the form.

·         In the last steps there is a bindevent between the form’s resize event and the skincontrol cutframe method, as well as the forms resize event and the positioning of the buttons.

·         Then the form is resized to cut away the frame.
This cutting away of the frame means that the borders and the titlebar are actually cut from the form. This is not the same as setting titlebar and borderstyle to 0 (zero), property settings that switch off the titlebar and borders.

All the pictures are subclasses of the SkinImage class. The name of the skin is passed as parameter, in the init of that class, the imagename is determined, based on the name of the class, and the correct image is added to the imagecontrol.

LPARAMETERS tcSkinName

WITH this

   .top = 0

   .left = 0

   .BackStyle= 0

 

   DO CASE

      CASE UPPER(.Name) = "IMG1"

         lcImage = "LEFTTOP.gif"

        

      CASE UPPER(.Name)= "IMG2"

         lcImage = "TOPBAR.BMP"

     

      CASE UPPER(.Name)= "IMG3"

         lcImage = "RIGHTTOP.gif"

     

      CASE UPPER(.Name)= "IMG4"

         lcImage = "RIGHTBAR.BMP"

     

      CASE UPPER(.Name)= "IMG5"

         lcImage = "RIGHTBOTTOM.gif"

     

      CASE UPPER(.Name)= "IMG6"

         lcImage = "BOTTOMBAR.BMP"

     

      CASE UPPER(.Name)= "IMG7"

         lcImage = "LEFTBOTTOM.gif"

     

      CASE UPPER(.Name) = "IMG8"

         lcImage = "LEFTBAR.BMP"

 

   ENDCASE

 

   .Picture = tcSkinName+"\"+lcImage

   .Visible = .T.  

Next, a caption is added, it  takes the text from the form caption.

In the activateImages method the images are activated, basically this means that they will respond to mouse actions, here’s the code:

WITH thisForm

 

* pics 1 to 3 are the top 3 img's and the caption control.
* They will respond to the mousedown.

   * basically this means they will make dragging of the form possible.

   *

 

   BINDEVENT( .img1,         "MouseDown", this, "OnMouseDownMove")

   BINDEVENT( .img2,         "MouseDown", this, "OnMouseDownMove")

   BINDEVENT( .img3,         "MouseDown", this, "OnMouseDownMove")

   BINDEVENT( .proxycaption, "mousedown", this, "OnMouseDownMove")

 

   * images 4, 5 and 6 are the right side, bottomright and the bottombar.

   * they make resizing of the control possible.

   *

   BINDEVENT( .img4,         "MouseDown", this, "BeforeMouseDownResize")

   BINDEVENT( .img4,         "MouseMove", this, "AfterMouseDownResize")

   BINDEVENT( .img5,         "MouseDown", this, "BeforeMouseDownResize")

   BINDEVENT( .img5,         "MouseMove", this, "AfterMouseDownResize")

   BINDEVENT( .img6,         "MouseDown", this, "BeforeMouseDownResize")

   BINDEVENT( .img6,         "MouseMove", this, "AfterMouseDownResize")  

  

This is the code of the OnMouseDownMove method:

LPARAMETERS tnButton, tnShift, tnXCoord, tnYCoord

* emulate the ability to drag the form using mouse

 

#DEFINE WM_SYSCOMMAND 0x112

#DEFINE WM_LBUTTONUP 0x202

#DEFINE MOUSE_MOVE 0xf012

 

IF tnButton = 1

   ReleaseCapture()

   SendMessage(ThisForm.HWnd, WM_SYSCOMMAND, MOUSE_MOVE, 0)

   SendMessage(ThisForm.HWnd, WM_LBUTTONUP, 0, 0)

ENDIF


Here is the code for the BeforeMouseDownResize method:
LPARAMETERS tnButton, tnShift, tnXCoord, tnYCoord

 

IF tnButton=1

   ThisForm.StartX = tnXCoord

   ThisForm.StartY = tnYCoord

ENDIF


All it does is adding the coordinates to the startX and startY properties of the form.

The AfterMouseDownResize:

LPARAMETERS tnButton, tnShift, tnXCoord, tnYCoord

 

WITH ThisForm

   IF tnButton=1 AND .ProxyBorderStyle=3

      .Width  = .Width  + tnXCoord - .StartX

      .Height = .Height + tnYCoord - .StartY

      .StartX = tnXCoord

      .StartY = tnYCoord

   ENDIF

ENDWITH
The form is resized and startX and startY are refreshed.

Then the mousepointer is set for the images on the form:

* mousepointer with two arrowheads, pointing left and right

#DEFINE MP_WE 9 

* mousepointer with two arrowheads, pointing left-up and right-down

#DEFINE MP_NW_SE 8

* mousepointer with two arrowheads, pointing Up and Down

#DEFINE MP_NS 7 

 

WITH thisForm

   .LockScreen = .T.

   .img4.mousepointer = 0

   .img5.mousepointer = 0

   .img6.MousePointer=  0

 

   IF .Borderstyle == 3

      * only if the form is resizable.

      *

      .img4.mousepointer = MP_WE

      .img5.mousepointer = MP_NW_SE

      .img6.MousePointer=  MP_NS

   ENDIF

   .lockScreen = .F.

ENDWITH

When the pictures are positioned this means that clockwise, the topleft, topbar, righttop, rightbottom, bottombar, leftBottom and leftbar are put in position.

The img1 doesn’t need positioning. When adding an object to a form its top left is always 0 (zero), there for we start with img2, being the topbar

    WITH thisform.img2  && top bar

        .Left = thisform.img1.Width

        .Width = thisform.Width - thisform.img1.Width - thisform.img3.Width

        .anchor = 11

    ENDWITH

 

    WITH thisform.img3  && top right corner

        .Left = thisform.Width - .Width

        .anchor = 9

    ENDWITH

 

    WITH thisform.img4  && right side bar

        .Left = thisform.Width - .Width 

        .Top = thisform.img3.Height

        .Height = thisform.Height - thisform.img3.Height - thisform.img5.Height

        .anchor=13

    ENDWITH

 

    WITH thisform.img5  && right bottom corner

        .Left = thisform.Width - .Width

        .Top = thisform.Height - .Height

        .anchor = 12

    ENDWITH

    WITH thisform.img6  && bottom bar

        .Left=thisform.img7.Width

        .Width = thisform.Width - thisform.img5.Width - thisform.img7.Width

        .Top = thisform.Height - .Height

        .anchor = 14

    ENDWITH

 

    WITH thisform.img7  && left bottom corner

        .Top = thisform.Height - .Height 

        .anchor = 6

    ENDWITH

 

    WITH thisform.

prague day 3

After last nights dinner I went to bed but hardly could sleep.

Up at 5 for the last day.

Yesterday I had a session on software protection. Not all things went as good as I wished. So this morning I did work on the loose ends because I had the same session today again.

Now everything went smooth, actually so smooth that I had to invent some last minute things as otherwise my session would end too early.

Good thing that Venelina Jordanova was in that same session together with Uwe Habermann.

They came up with some question that really took me some time to answer.

Yet, the session was over in 65 minutes. 10 minutes earlier than expected.

The session on the first day, on VFP.Net was a very good one. It took me not too long to prepare for that and there was an enormos amount of information to share, so filling that session was more like leaving out things.

I spend the rest of the afternoon in Prague and go back tomorrow early afternoon.

This was a nice experience, the Prague DevCon is a very intimate one with nice folks around and a loose atmosphere. I was honored to be here.


 

Prague day 2

Day 2 in Praha.

Day 1 of the DevCon.

I had two session today, one on the VFPCompiler and one on the NetExtender

The Compiler session was visited by 60 people, the extnder session was visited by 30 people. All in all it was quite an experience to speak for 75 minutes.

I can suggest to anybody to prepare a session and speak even for a smaller group.
That will most definetely raise your awareness of the enormous task to prepare and perform such a session.

This experience made me more aware of what welll known speakers like Doug Hennig, Andy and Marcia, Cathy Pountney, Tamar Granor and all those other big names are or were doing year after year. (Please don't be offended if I did not mention your name, that was no on purpose!)

But at the same time I have to warn for the addition level of this experience. If you don't watch out you'll be hooked before you know. Just like creating applications this is most addictive.

Tomorrow I do a session on Protecting your software. Mind you, today I was telling about the NetExtender and showed the encryption/decryption possibilities. The combination with writing data in an absolute unreadable way came up and I will use this in my tomorrow's session as well.

Some new ideas for sessions came up.

Keeping you updated. See you.

 

 

Prague day 1

Up at 3 in the morning to catch a plane at 7 is beyond human efforts for me, but I did it.

Right now I am in my hotelroom, looking out over a street and a small park playground.

Plane took off at 7:05 exact and landed 1h 10mins later at Ruzyne (the name of the Praha airport)

I will keep you all updated about my days here. Looking forward to the events.

 

 

One app, many faces

Since VFPSkins is no longer available I have been looking for other ways to skin the beloved fox.

I found a way. Pretty soon I will show the code and make this available to all of you.

All we need now is some creative minds that can create other skins.

Oh, and sure enough this project needs some improvements. SO be my guest

BL

 

VFP die-hard going into a VB.NjET adventure

Yes, I know, this is like swearing in church. This VFP die-hard is doing a VB project.....

But I need some money coming in, so I take what I can get.
Today I ran into a weird problem that I was not able to solve yet.

don't say this problem is nothing, because THAT is what it is all about.

I have this grid, basically it works well.

depending on the value of one of the columns a dataset is filled with a subst from another table. Working still very well. UNTIL!! the field with the value for the subset is empty, null, or, in VB speak NOTHING!

So I check for the fact that the value can be nothing, as in:

IF not (grdOrderMain.currentrow.cells("ordNummer").value.ToString = Nothing) then ...

Well, I get "a bit" a weird errormessage.

 

 

As you can see at the bottom of this screen I get this message: "Referenced object has a value of 'Nothing' "

Well, I know that this can happen, I actually checked for that, so please don't you bother me and get on with it. Angry [:@]

But no this is VB as in Very Bad. Oh VS makes me Very Sad Crying [:'(]

Why sad? you might ask. Well, take a look at the picture again. As you can see at the bottom of the screen I checked for this value before, in a previous run. So, being used to the debugger of VFP I expect to see the value there. Well this is VS folks. It wants you to suffer, have pain but no gain, see blood but no money, suffer till the end of your days. Be miserable and sick but never expect mercy from Redmond. They are the snipers! If they can they will shoot you, not to death oh no, 'cause then they would NOt have a toy to toss around.

OH NO, evaluating this automatically could cause side effects, like the developer being productive!! They don't want that, in the MS "wisdom" the decision was made to make the developer do something extra, (s)he needs to reactivate this evaluation.

I would like to tell you that the syllable "dom" is also a Dutch word, it means DUMB!!Devil [6]

Speaking with Gordon Ramsey, it is a f**cking shame!!

OK, after speaking with Simon Arnold I found some other ways to check for values.

none of them worked well:

I just am wondering why I ever would want to be productive???? It would mean I could make a lot of money. I must have gone nuts to wish just that.

Angry [:@] Devil [6]

 

VFP Die-hard going into VB.NjET

As some of you may have noticed on the forum I am currently involved with a project that does VB.

So far I found it a Very userUNfriendly environment (to say the least).

Being a part of VS (2008) I find VB Very Bad and VS Very Sad where it comes to datahandling.

In the upcoming posts I will keep yer all informed about my findings. Hopefully some of you, working with VB as well, can have a profit from all this. I will NOT refrain from telling about the mistakes I made, so maybe you do not need to make them, speeding up your learning curve.

So far I found that EVERYTHING in Net is an object. It feels for me as doing OOP for the sake of OOP, not always for practical reasons.

Face it, what use is that a table is an object as well as a field and that it take a whole lotta code to simple get the value IN that field. Doing something like cSomeValue = table.field to get the content of that field is just not working.

< sigh > VS has a long way to go before it can even stand in the shade of VFP when it comes to datahandling flexibility.

-- more2come --

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.

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.

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")

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).

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