Home Contact Site Map Privacy Policy Rev Search
Volume 4 Issue 3
 

Up
Volume 1 Issue 1
Volume 1 Issue 2
Volume 1 Issue 3
Volume 1 Issue 4
Volume 1 Issue 5
Volume 1 Issue 6
Volume 1 Issue 7
Volume 1 Issue 8
Volume 1 Issue 9
Volume 1 Issue 10
Volume 2 Issue 1
Volume 2 Issue 2
Volume 2 Issue 3
Volume 2 Issue 4
Volume 2 Issue 5
Volume 2 Issue 6
Volume 2 Issue 7
Volume 3 Issue 1
Volume 3 Issue 2
Volume 3 Issue 3
Volume 4 Issue 1
Volume 4 Issue 2
Volume 4 Issue 3
Volume 4 Issue 4


 

 

 S/ENL - The Sprezzatura Electronic Newsletter

(All the RevSoft News That's Fit To Print (And bits that probably aren't as well...))

Contents

Welcome

Debugger of it all

An Introduction to the Use of OLE controls from OpenEngine – Part 1

Introduction

BASIC+ Routines

Exploring OLE Controls

Bugs in the system? How about hobgoblins?

BTREE.EXTRACT Gotchas

ListBox Control Extras – “Select All”

DEP Revisited

Funny Talking Foreigners Try To Destroy US Economy! – Really?

More Consistency

Scales of Coding

XP Edit Control Extras

Cue-Banners

Implementing Balloon-Tips

S/Log – Updating the Windows Event Log from OI – A Free Utility

Introduction

Installation

Using S/Log

EMS Memory Under XP

S/OCKET – A commercial Utility

Use of Hungarian Notation in Untyped languages

Peripheral Trivia

23rd December 2006

S/ENL Volume 4 Issue 3

Click here to view the .PDF version
or right mouse click and 'Save As'
to download the file to read it off-line.

Welcome

Welcome to this special bumper end of year edition of SENL - the journal that just wouldn’t die despite trying very very hard. If I had a pound for every time we’ve said “Must put that in the next SENL” over the past 24 months I’d be considerably richer! The problem is – as most of you will know – getting the work/life balance is tough and sitting down to write when paying clients are knocking on your door is a tough one. Even now our clients may be reading this asking “how can you work on this when you’ve got deliverables due”? If it’s any consolation guys and gals it’s 20:10 on a Monday evening and I’m on a train returning home from a client!

Since we last wrote the product has come in leaps and bounds and there’s even more to come. The management team at Revelation have concentrated on ensuring that destructive bugs in the product are tracked down and squished – witness some particularly elusive memory leaks which have created problems both here and abroad. Very recently the Rev web site listed some of the goodies to come in version 8.0 and to say that the list is extensive would be an understatement.

It has been a bit strange for all of us at Sprezz over the past few years as our relationship with Revelation has become stronger we’ve felt a little uncomfortable in how we represent ourselves to the community so we thought it’d be a nice idea to put to rest a few shibboleths.

Firstly Revelation Software Ltd is NOT Sprezzatura under a different name. Revelation Software is a separate company; set up specifically to distribute Revelation in the EMEA (Europe, Middle East and Africa). It has its own staff, a separate bank account etc. As a courtesy to the Revelation community Sprezzatura make technical resource available to Revelation, sometimes on a commercial basis and other times just in the interests of the community. An example of the former is that Carl Pates (whom many of you will know) was actively involved in the release of 7.2 – specifically in relation to internal issues on UI and editable functionality. This does NOT mean that Sprezz have Revelation Source Code. Revelation US are fiercely protective of their IP and access is granted remotely on a “needs must” basis. Following on from the last conference at Vegas, Sprezz were also tasked with making Carl’s “Drag and Drop” proof of concept a reality for version 8.0 – another task that has made sure our feet don’t hit the ground!

Add to this some of the other exciting projects that we’ve been involved in (a National Web Enabled Secure system for UK Homelands Security springs to mind – enter data at any one of a number of regional centres and as it updates the local database almost immediately you can create web queries against the same data copied to a centralised database) and a huge amount of skunk works projects and utilities and before you know it another year has passed!

In this issue, we’ve tried to cram in as much as possible without being overwhelming. We’ve combined lighter material (a reprint of an article written for another non-Rev journal on outsourcing) with the highly technical (an article on Windows API tricks). We’ve also included the first part of a 2 part article on using OLE in OpenInsight. We’re hoping that’ll give us the motivation to ensure another SENL comes out soon! We’ve also been playing with a less formal writing style pioneered by our very own Mr Kaplan – blog like, if you will – and we’re going to intersperse a number of these items throughout this SENL.

As the year draws to a close we’ve got an exciting conference to look forward to in Seattle. The Sprezz Team will be represented by our usual lead three of Aaron Andrew and Carl and we look forward to seeing you there! We’ll be arriving the Saturday before conference and leaving the Saturday after conference. It’s amazing what a difference those Saturday night stays make to flights from Europe! As it is we’ll be flying for around 11 hours so the getting there early should see us in good stead for getting onto time zone!

Hopefully we’ll see y’all in Seattle!

[top]

 

Debugger of it all - Aaron Kaplan

The other day at a client site, we came upon a line of code similar to the following:

write record to handle, id else debug

There are many reasons we can think of for putting debug as part of a failure, but none of them are really any good. In fact, there's never any reason to have DEBUG as statement on it's own. Whenever you want to use DEBUG, you should always think of it in one of these ways:

  1. if "My @STATION ID" = @STATION then DEBUG
     

  2. if "My USERNAME" = @USERNAME then DEBUG

This way, if the DEBUG does somehow make it into your production systems, the debugger will not be invoked. Yes, we do know that we can intercept the debugger and display, but this is not the same thing. Breaking to the debugger for a program error is one thing. Breaking to the debugger as a specified command and program feature is quite a different matter.

In general, we prefer to have all of our error handling in common routines. Well before Revelation placed FSMSG back into OI, we created our own routines that read in from REVERROR.DAT and displayed the appropriate error text.

The important thing is that at no time should an end-user be deliberately dropped into the debugger. As programmers, part of our job is handling all possible outcomes of a code statement, prompting and informing the end user appropriately.

[top]

 

An Introduction to the Use of OLE controls from OpenEngine – Part 1 - Andrew McAuley

Introduction

For several releases now, OpenInsight has had the ability to utilize OLE controls from within OpenInsight forms. This implementation called for the use of Presentation Server (a component of OINSIGHT.EXE) to work. Whilst this was effective, it meant that if OINSIGHT was not running then OLE controls could not be used. This introduced a problem for people developing Web applications as the sole mechanism available for the production of complex reports (OIPI – an OLE control) could not be used as OINSIGHT is not running.

Realizing that this was a significant disadvantage, Revelation moved quickly to address the issue and as of 7.1, OLE controls can be run in an engine context. Making it possible to use OIPI in an engine context opens the door on a whole host of opportunities. This article will show both how to use the routines provided in OpenInsight to achieve the use of OLE controls, and  some sample examples of it in use to perform mail merges and spell checks.

OLE controls are essential Windows controls that permit conversations between themselves and other applications as is obvious from the expansion of the acronym – Object Linking and Embedding. The technology behind OLE has undergone many changes since it began with DDE but we’re now at a stage where the underlying technology is mature, robust and easily accessible from OE. Basically the idea is that if an application is sufficiently modular that it might be useful in another application it can be exposed as an OLE control – an example would be the Microsoft Calendar control.

 

BASIC+ Routines

The Basic+ routines provided for manipulating OLE controls are OLECreateInstance, OLEGetProperty, OLEPutProperty and OLECallMethod. These allow the user to do exactly what they say. They are documented well in the online help but for the purposes of ease of use of this article I’ll redocument them here.

Note that all of these functions have been created as opcodes – what this means is that you don’t need to declare them, nor call you CALL them. If you attempt to call the routines, RTP27 will look for them and fail to find them and generate an error.

OLECreateInstance
The OLECreateInstance is used to instantiate an OLE control so that we may communicate with it. The syntax is very straightforward. When we create an OLE instance, we receive a handle which we then use to communicate with the object in subsequent OLE routine calls. This handle is referred to as an “IDispatch” pointer and if you examine it in the debugger you will just see the word “Idispatch” – this is because it is a structure and as such is of little use to access directly. This does lead to slight confusion however if you create multiple handles to different processes as they will all appear as Idispatch in the debugger!

The syntax is

      objectHandle = OLECreateInstance(OLEControlProgId)

Note that the OLEControlProgId is frequently a long confusing string – we’ll deal with finding this later but for now we’ll just use the online help example of VSPRINTER7.VSPRINTER.1 – the OIPI Printer OLE object.

To DELETE an OLE instance one simply sets the objectHandle to null, eg

      objectHandle = “”

 

OLEGetProperty

The OLEGetProperty function returns the property of the OLE control that has been requested. In this it is identical to the OI GET_PROPERTY. Note however that at the time of writing there is a bug extant related to getting and using properties that become IDispatch pointers in themselves. This can GPF the machine – you’ll know soon enough if you encounter this bug J.

The syntax is

      objectProperty = OLEGetProperty(objectHandle, objectPropertyName)

 

OLEPutProperty

The OLEPutProperty is functionally equivalent to the OI SET_PROPERTY function. It permits the SETTING (or PUTTING) of a property of an OLE control.

The syntax is

      void = OLEPutProperty(objectHandle, objectPropertyName, Value)

Note that the objectPropertyName can be modified to point to array elements if necessary – see the online help for details.

 

OLECallMethod

The OLECallMethod permits the running of methods within the OLE control.

The syntax is

      ReturnValue = OLECallMethod(objectHandle, objectMethodName, args)

Where args can be multiple comma delimited arguments.

 

OLEStatus

After any OLE function it is a good idea to check if it worked. This is achieved by calling the function OLEStatus which returns a result indicating the status of the operation. The result (if unsuccessful) is returned as a negative integer which it is the programmer’s responsibility to convert into meaningful text.

The syntax is

OLEStatus = OLEStatus()

 

[top]

 

Exploring OLE Controls

How to find OLE Controls

With the wealth of OLE controls out there it can be difficult to know what’s on your own machine. There are several ways of getting at this information but the way we’re recommending is the use of a Microsoft utility called OLEVIEW. This ships with various Microsoft development environments but not with the operating systems. So to use it you must first download it. At the time of writing this was available from http://support.microsoft.com/default.aspx?scid=kb;en-us;122244

This program locates all of the OLE controls on your machine and provides an interface to get at the information. Running it produces the following screen :-

 

 We’ll leave you free to explore the various options vis-à-vis viewing the Object Classes and go straight to the All Objects view… double clicking this results in

 So let’s scroll down to our VSPRINT object – as this is provided by ComponentOne we’ll look under this in the listing…

 

Now we’re there what can we find out?

The great thing about OLE controls is that they’re self documenting – not to the level that replaces proper documentation but at least to the level where we can get an idea about what’s available to us!

So for starters let’s expand the above screen a little…

 The first bit of information that is immediately useful is the “ProgID” – you’ll recognize this (VSPrinter7.VSPrinter.1) as the OLEControlProgID from earlier. But a quick tip – if all you’re doing is using standard non version specific commands then a better name to use is the VersionIndependentProgID as this will work with all versions of the  VSPrinter control. In this case this is VSPrinter.VSPrinter.  A further tip – if you have multiple OI installations on your machine and one is at a different level to another, the installs from Rev don’t REREGISTER the controls. By which I mean I’m currently doing beta testing on my machine in a subdirectory named appropriately. But in preparing this document I’ve noticed that regardless if I’m running OIPI I’m running the version I installed for a client a while ago!

 The second thing to note is what happens when we double click the control in the left list box to expand it.

 

We see a list of entry points – but due to the way in which OpenEngine has implemented access all we are interested in is the IDispatch entry point so let’s double click that…

And click View TypeInfo…

Double clicking Methods produces a listing of all of the methods that VSPrint exposes

And as you can see the list is comprehensive. But the confusing thing is that some methods are repeated one or more times. As an example take PaperSize. The reason for this is simple – OLE controls expose properties via Methods. So we’ll have a PaperSize Method for getting the PaperSize property and a
Papersize Method for setting (or in OLE terms putting) the PaperSize property. Double clicking on the two methods illustrates this. In the first Method we see

The propGET says that this is the method to get the property. It even contains a help string and a pointer to the help file. In the second we see

Where the propPUT is setting the property.

If we’re actually looking for Methods in the classical sense we’d want to look at those methods which only occur once. Normally these will be callable methods BUT remember that some properties such as the Devices present in the system can only be got so this isn’t an infallible rule of thumb. So for example, KillDoc is a Method which can be called

But Devices is not a method, rather the exposing of a get property.

Naturally we wouldn’t suggest that you use this self documentation as the sole source of information about an OLE control but it does provide pointers to allow you to go off and search the internet for additional help using the keyword that you’ve now found.

[top]

 

Bugs in the system? How about hobgoblins? – Aaron Kaplan

Ralph Waldo Emerson is generally misquoted as "Consistency is the hobgoblin of little minds." In actuality, the quote is "A foolish consistency is the hobgoblin of little minds, adored by little statesmen and philosophers and divines". Some people will take the misquote as license to never do anything the same, since, after all, why would they want to have a little mind? However, there are times when consistency is important, and that's in how you structure your data.

In the Revelation world, we can easily format our data with ready to use ICONVs and OCONVs. Most people automatically put MD2 formatting into all monetary fields, and MD3 in to financial percentages (interest and growth rates, for example). When doing this it should be clear that you'd want all interaction with these data fields to be handled using the proper and consistent conversion. This isn't an Emersonion hobgoblin at all, since the consistency is not foolish, but maintaining data integrity.

We mention this because a client recently suggested that it might be OK to store some information as varying MD3 and MD4, depending on context. Eventually, reason won and an unfoolish consistency was sustained.

[top]

 

BTREE.EXTRACT Gotchas – Andrew McAuley

We were vexed recently by searches that just wouldn’t behave no matter how hard we tried. The results we got back were just not what we were expecting. Time after time we pored over the suspect code but it was no good – the code looked fine. We were getting close to tearing our hair out by this time when we remembered that old programmer’s maxim

“I don’t write buggy code – there must be a problem with the data”

So we took a closer look at what it was we were looking for and noticed that it contained the string “(BLACKBERRY)”. This triggered something in the almost vestigial parts of our brain that deal with seriously deprecated commands within Revelation products and sure enough we were eventually able to establish that in addition to the DOCUMENTED Btree.Extract operators there are other operators that are just sitting there waiting to take the unwary coder by surprise. What was actually going on here was that it wasn’t looking for the string “(BLACKBERRY)” it was looking for something that MATCHED “BLACKBERRY”.

To try to help you avoid falling into the same trap we present below a table of the deprecated operators along with their modern equivalent and some explanatory comments.

(VALUE)%VALUEMatches operator. Double up to escape out – in other words to look for (VALUE) enter ((VALUE))
VALUEFROM^VALUETOVALUEFROM…VALUETONo way to escape out. If you search for A^B it won’t find things containing the string “A^B” it will find things between A and B.

[top]

 

ListBox Control Extras – “Select All” – Carl Pates

One interesting and an undocumented ListBox feature we found recently applies to the SELPOS property.

A simple way to select all the rows in a multi-select ListBox is to set the SELPOS property to “*”

 e.g

   Call Set_Property( @window : “.LIST_1”, “SELPOS”, “*” )

[top]

 

DEP Revisited – Andrew McAuley

Back in March of this year we started to see an increasing number of installation problems with people running Windows 2003 Server or XP Service Pack 2. OpenInsight just wouldn’t start on these boxes – it would abend out with a number of different error messages. We did some initial investigations and documented our findings for the community in a White Paper available at http://www.sprezzatura.com/downloads/dep.pdf

As the year wore on we saw increasingly strange occurrences – Citrix farms where OpenInsight applications would just disappear from memory, AREV applications which would just randomly disappear from memory. We weren’t able to fully grasp what was going on – all we knew was that disabling DEP on the server seemed to be a workaround IF that was an acceptable workaround to the IT Department. Increasingly though this was not an acceptable work around – DEP was put there for a security based reason and most IT literate people weren’t happy with it being disabled.

Finally in a recent installation we came across the proverbial last straw. We were rolling out a local site in what was to be a nationwide rollout of a highly secure “homelands security” type application. This application is the one mentioned earlier in the editorial. At one specific site every time we ran our app it would just crash and burn. At this particular site the IT Department just laughed at our request to disable DEP. They were running other applications on this server – “did we think they were mad?”.

It’s funny how panic can stoke the fires of creativity! Casting our mind back we were able to remember that when we originally reported the DEP problem we believed that for various reasons we’d tied it into the RCL4.DLL Universal Driver client. Quickly we replaced the UD client with the 2.1 client and the problem disappeared.

Having learnt the “trick” we started applying it to other scenarios were we were experiencing failures :- Windows 2000 Citrix Server Farms, AREV databases and sure enough the problems started to disappear.

Please note that we are not definitively saying that we have identified where the problem lies – just identified a work around that helps us out on a number of sites. Of course this then leaves you with the problem of having UD3 files which will no longer be accessible if you switch back to the 2.1 Service.  We expect to have utilities to help cope with this in due course.

[top]

 

Funny Talking Foreigners Try To Destroy US Economy! – Really? Andrew McAuley

A lot has been published recently about outsourcing. The very issue of who outsources, and why? - is such a political hot potato that it can form the basis of entire governmental campaigns. It seems that you can’t open a magazine these days without some attention grabbing headline (such as above) drawing your attention to the fact that your job is under threat from some ill defined foreign enemy who wishes to steal the bread from your table and destroy your well earned way of life. You may even have recently received an email in which you are urged (somewhat xenophobically) to hang up the phone if the person at the other end “sounds foreign”. There goes the entire US call industry from a European perspective.

The reasons behind such fear can be found by studying the following diagrams – firstly let’s look at the projected growth of new white collar jobs in India over the next few years. Note that the growth rate is pretty much exponential! All of these figures and graphs are borrowed from recent articles in Fortune and Wired magazines – lest you think I’m inventing them!

In 2003, 18% of Software Maintenance jobs were sent abroad from the US. It is projected that by 2007 this figure will be 47%. In 2003, 20% of Custom Software Development jobs were sent abroad from the US. It is projected that by 2007 this figure will be 47%.

Now a lot of people reading this article will probably be involved in custom software development so the question comes, how did all this happen? And more importantly –how can we fight back?

So are the foreigners to blame? The author would contend that the blame can actually be laid fairly and squarely at the feet of some companies a little closer to home – namely Microsoft et al.

Consider :-

We’ve now moved into the area where computer systems can reasonably be considered commodities. So let’s take a look at the history of commodities. A simple example would be furniture. When people first began to build furniture it was a very specialist craft and only the rich were able to afford it. Thus furniture became something that was passed down from generation to generation as heirlooms. (This led to a memorable put down in UK politics where a well known but moneyed politician referred to a less wealthy politician as 'the kind of person "who bought his own furniture"').

The specialists were able to charge handsomely for their time and frequently became wealthy in their own right, spawning schools of apprentices and imitators. As more people owned property and had disposable income more people could buy furniture but there weren't enough craftsmen to go around and, in any case, that was still too expensive. As there were so many people wanting to buy, entrepreneurs could invest in mechanized ways of creating furniture and mass production of furniture was born. Bringing this more up to date, we only have to look at cars. Originally the preserve of the very rich, Henry Ford standardized production and brought cars to the masses (as long as you wanted a black car).

Now if you were to plot a curve of skill levels versus cost per hour you would get a normal curve. The really skilled people charge a lot per hour and there are very few of them. The partially skilled people are relatively inexpensive and exist in the industry in greater quantities. The unskilled have no place in the industry.

It therefore follows that if you can make the delivery of software componentized so that the ACTUAL skill levels required to deliver a component are relatively low but specialist, then you can churn out a LOT more components. Take as an example a factory line worker assembling a specific part of a car. The task itself may be complex but it can be learned and once learned repeated ad infinitum.

If there is sufficient demand for standardized custom software (not the oxymoron it appears) then you can set up assembly lines of Business Analysts -> DBAs -> C++ programmers -> VB Programmers -> ISA experts -> IIS Experts -> you get the picture. Each level is specialist BUT you can become an MCP in them in a matter of weeks - not true of truly skilled jobs.

Once at this level you (as the vendor of the tools used) can sell huge amounts of software. It is actually in your interests to keep this componentization as unitised as possible as you will sell more. But once you reach this level where skills may be acquired by rote there is bound to be an outflux of work to where such skills are even cheaper.

Of course the corollary is that the only people who can afford to develop software using this model are the people who can afford the production line, thus effectively alienating the SME who then becomes dependant on other software factories and must reduce their expectations accordingly.

How can ANYONE in their right mind believe that a team of 5-10 people can deliver a custom solution more economically than a team of one? But that is the myth that MS have sold and why? Because then they'll sell 5-10 pieces of software not 1.

So if you’re a small to medium sized shop and you don’t want to invest in the huge capital outlay required to set up a production line facility – and you don’t want to see your work taken over by somebody with less skill but cheaper resources you have to look once again at your skill sets. Looking back at our earlier example – car manufacturers. What car manufacturers continue to do well in these days of cheaper foreign production? I know that many examples exist in the US and in the UK we have manufacturers such as Morgan and Bristol – who not only sell cars successfully but have waiting lists for their products!

How do they manage this? Do they ignore the benefits of componentization in favour of lovingly handcrafting everything? No! The combine the best of both worlds, they source components for basic building blocks then they hand assemble custom deliverables. They provide, as one of our colleagues used to say, “a boutique experience”. And how does Fortune magazine suggest that this issue be addressed? At  http://www.fortune.com/fortune/careers/articles/0,15114,588335,00.html the author says

"The answer for programmers, as for anyone in a competitive business, is to specialize to the point that you offer greater productivity, or change careers,"…And of another worker.. He developed new programming methods, "which allowed him to write certain specialized applications about eight times faster than his typical Bangalore competitor," says Mitchell. "Now he has a cost advantage. But only in those narrow areas."

As a supplier of integrated 4GL technologies Revelation Software believe that 4GLs are once again on the up because they are the only way SMEs can fight back AND the only way skilled programmers can see to their job staying in this country. Note once again that the blame does not lie on the “foreign countries” for taking advantage of the componentization of software. It lies with those who have componentized it. Regretfully as demand exceeds supply this is bound to happen. Our defence ought not to be a Luddite one – of smashing up the means of production in the hope of stemming the tide. Rather we ought to realise that not everyone wants or needs mass produced software. So our defence is to do what we do already but to do it better!

Also, the answer to 'how can a small software house deliver more / faster ' lies in another 1980's maxim:  "Don't automate - obliterate"   The idea is to solve problems by not having them.  In particular, when you have a lot of layers in a process then the cost of handing off between layers can exceed the benefit of the layers.  The Microsoft model of a software factory embeds a very high process cost that can be reduced by cheap labour, but can never be totally removed.

In business this led to the 'caseworker' model, where caseworkers brought knowledge to decision makers.  In computing this has not yet happened.  However a 4GL in competent hands can make it so. Decent 4GLs permit the rapid prototyping of applications with the eventual end user a very real possibility.   An integrated 4GL environment permits the developer to have the best of both worlds – using the 4GL to set up the framework and initial business model and the 3GL to instantiate more complex business rules. Add in the tight coupling of business rules to the database layer and we are able to once again deliver bespoke software applications at near to mass production prices. We keep our jobs and our clients receive a better service!

We’d strongly encourage you to download an evaluation copy of our OpenInsight software which can be found at http://www.revsoft.co.uk. There you’ll also find easy to follow tutorials to help you to get the most from your download. Remember the next time someone tells you that foreign companies are stealing your work remind them it wouldn’t have been possible without the help of an all too American company!

[top]

 

More Consistency – Aaron Kaplan

We were talking the other day about how an application should flow. Some people said that apps should follow Windows standards. The more cynical wondered "what standards?", but we're not here to bash Microsoft. In the end, an application should flow how the user expects it to flow. For example, when you save a row, does the window clear? That depends on what type of application you are writing. If this is an ARev app you are converting, especially one that's living in tandem, then, Windows standards aside, perhaps that window should clear the screen, since that's how users expect it to be.

It's a fine line between F9 for save and Ctrl-S for save. Which is correct is not as much for you to decide, but for the users. Programmers and designers shouldn't force their whims or the flavour of the day on to the end users, but should work in conjunction with them, to ensure that the application does what the users want, and how the users want. This means, that if an end user really, really, really wants a "Are you sure you want to save?" message, then a "Your record has been saved" message, as much as it might gall you to put that in, at the end of the day, it's their system.

Scales of Coding

Our discussions about consistency moved us into two different topic realms. One was about handling maths when working with ICONV data. The other was about Hungarian notation. In the end, most of us were of the opinion that, at least in terms of numbers, ICONV/OCONV is more for data validation and consistency rather than as a storage mechanism. Not that we’re advocating the needless waste of disk space, and I suppose a megabyte here and a megabyte there and soon you’re talking gigs….but, in the end, it’s not as important as it was even five years ago.

The question is really around how to handle the maths. If I have my numerics stored as ICONV MD2, and I do something like

origPrice = record< OrigPrice$ >
reduction = record< Reduction$ >

customerPrice = origPrice – reduction

we’re all pretty set on what the math is.

But, suppose I’m adding in tax, and we’re in one of those places were the tax is variable based on location of the store, the delivery address or the billing address. Suppose now that the tax value is also stored MD2. Our code now reads

origPrice = record< OrigPrice$ >
reduction = record< Reduction$ >
taxAmt = record< TaxAmt$ >
customerPrice = ( origPrice – reduction )
actualPrice = customerPrice + ( customerPrice * taxAmt)

actualPrice is very different if we change that code to

taxAmt = oconv( taxAmt, "MD2" )
actualPrice = customerPrice + ( customerPrice * taxAmt )

The idea is that it’s important, when working with numbers, to ensure that your scaling is correct. The best way to do that is when working with numbers, to always OCONV your data out to the correct scale before working and manipulating them.

How all this relates to Hungarian notation will have to wait until later in SENL.

[top]

 

XP Edit Control Extras – Carl Pates

In the last issue of SENL we took a brief look at enabling OpenInsight applications to use Windows XP visual styles. This capability has become an integral part of OpenInsight since the 7.2 release and along with this change also comes some interesting new capabilities.

In this article we are going to look at two features that Microsoft added to the standard Edit Control that are available to OI systems running with XP visual styles:

“Cue Banner” support
 

“Balloon-Tip” support

Cue-Banners

A Cue Banner is textual information (a cue) that is displayed by the edit control when it contains no data.  It is designed to prompt or help the user to enter information into the control. 

The use of this feature is very common these days – mostly it can be seen in Web Browser search controls such as the IE7 search box shown below.

To implement this feature is quite straightforward and involves sending a simple message, EM_SETCUEBANNER, to the control along with the text that you want to use.  Microsoft documents the message as:

EM_SETCUEBANNER

 

Syntax:

 

   lResult = SendMessage( hwndControl,

                          message,

                          wParam,

                          lParam );

 

Parameters:

 

   hwndControlHandle to target edit control
   messageMessage ID – should be EM_SETCUEBANNER
   wParamNot used – must be zero
   lParamPointer to a Unicode string that contains the text to display as the textual cue

 

Return Value

If the message succeeds, it returns TRUE (1). Otherwise it returns FALSE (0).

One thing to note the EM_SETCUEBANNER message is that the text string must be in Unicode, not ANSI or UTF8, so we will have to do a little pre-processing before we can send it.

Note that this uses the standard Windows API SendMessage function that will already have been prototyped on your OI system so there’s nothing to worry about there.

For those of you not familiar with SendMessage it’s a fundamental part of Windows UI programming and is used by applications to access a control’s functionality.  Every UI object in Windows (i.e. windows and controls) exposes an interface by which it can be manipulated.  This takes the form of a series of messages (identified by a number) that the object responds to and the SendMessage function is used to access this interface.

SendMessage takes four integer arguments and returns an integer that usually indicates success of some sort.

SendMessage

 

Syntax:

 

   lResult = SendMessage( hwndControl,

                          message,

                          wParam,

                          lParam );

 

Parameters

 

   hwndControlHandle to target control
   messageMessage ID
   wParamMessage specific information
   lParamMessage specific information

 

Returns

 

The return value specifies the result of the message processing – it is message dependant

Example

   retVal = SendMessage( hwndObj, WM_GETTEXT, cbText, lpText )

 

EM_SETCUEANNER – an example

The function

function setEditCueBanner( objEdit, cueText )

 

   declare function sendMessage, isUTF8, ANSI_Unicode, UTF8_Unicode

   declare function get_Property

 

   equ ECM_FIRST$        to 0x1500     

   equ EM_SETCUEBANNER$  to ECM_FIRST$ + 1

 

   * // Get the control handle

   hwndEdit = get_Property( objEdit, “HANDLE” )

 

   cueText := \00\ ; * // Null terminate

  

   * // Now translate the text to Unicode

   if isUTF8() then

      cueTextW = UTF8_Unicode( cueText )

   end else

      cueTextW = ANSI_Unicode( cueText )

   end

 

   lockVariable cueTextW as LPWSTR

   lpCueTextW = getPointer( cueTextW )

 

   retVal = sendMessage( hwndEdit, EM_SETCUEBANNER$, 0, lpCueTextW )

  

   unlockVariable cueTextW

 

return retVal

 

To Use

   retVal = setEditCueBanner( @window : “.EDITLINE_1”, “Search” )

 

Implementing Balloon-Tips

The next feature we are going to look at is the Edit control Balloon-Tip.  Basically this is an extended multi-line tooltip control that can optionally display an icon along with the text like so:

Again, this feature is implemented by use of the Windows API SendMessage function but this time it’s a little more complex as we will have to define and use a ‘C’ structure to pass along with the message (EM_SHOWBALLOONTIP) as you can see from the message definition below:

EM_SHOWBALLOONTIP

 

Syntax:

 

   lResult = SendMessage( hwndControl,

                          message,

                          wParam,

                          lParam );

 

Parameters

 

   hwndControlHandle to target edit control
   messageMessage ID – should be EM_SHOWBALLOONTIP
   wParamNot used – must be zero
   lParamPointer to an EDITBALLOONTIP structure that contains information about the balloon tip to display.

 

Return Value

 

If the message succeeds, it returns TRUE (1). Otherwise it returns FALSE (0).

Describing the full use of ‘C’ structures in OI is beyond the scope of this article  so for now we’ll just cover what we need for the EM_SHOWBALLOONTIP message.

 

The EDITBALLOONTIP struct

This is a structure comprised of four separate variables and defined by Microsoft as:

EDITBALLOONTIP

 

   typedef struct tagEDITBALLOONTIP {

      DWORD   dcStruct;

      LPCWSTR pszTitle;

      LPCWSTR pszText;

      INT     ttiIcon;

   } EDITBALLOONTIP, *PEDITBALLOONTIP;

 

Members

 

   cbStruct Contains the size in bytes of the structure

   pszTitle Pointer to a UNICODE string that contains the balloon tip title

   pszText  Pointer to a UNICODE string that contains the balloon tip text

   ttiIcon        Specifies the icon to display:

           

            TTI_ERROR         Use the error icon

TTI_INFO    Use the information icon

            TTI_NONE          Don’t use an Icon

            TTI_WARNING       Use the warning icon

 

C-Structures in OI are created by the DEFINE_STRUCT form, so we need to execute this and translate the definition above to one that OI can understand like so:

Once you have created this we can then use it in our programs to create a balloontip like so:

function setEditBalloonTip( objEdit, tipTitle, tipText, tipIcon )

 

   declare function get_Property, struct_Len, var_To_Struct, isUTF8

   declare function ANSI_Unicode, UTF8_Unicode, SendMessage

 

   equ ECM_FIRST$               to 0x1500     

   equ EM_SHOWBALLOONTIP$       to ECM_FIRST$ + 3

 

   equ TTI_NONE$                to 0

   equ TTI_INFO$                to 1

   equ TTI_WARNING$             to 2

   equ TTI_ERROR$               to 3

 

   hwndEdit  = get_Property( objEdit, “HANDLE” )

   tipTitleW = tipTitle : \00\   ; * // Null terminate

   tipTextW  = tipText : \00\

 

   * // Translate the tip icon to a numeric value to match the

   * // TTI_ equates above

   locate tipIcon in “INFO,WARNING,ERROR” using “,” setting tti else

      tti = 0

   end

 

   * // Translate the two text components to Unicode

   if isUTF8() then

      tipTitleW = UTF8_Unicode( tipTitleW )

      tipTextW  = UTF8_Unicode( tipTextW )

   end else

      tipTitleW = ANSI_Unicode( tipTitleW )

      tipTextW  = ANSI_Unicode( tipTextW )

   end

 

   lockVariable tipTitleW as LPWSTR

   lockVariable tipTextW as LPWSTR

 

   * // Create the EDITBALLOONTIP struct:

   * //

   * // The first member is set to the size of the structure (for

   * // future version change protection)

 

   ebts = “”

   ebts<1> = struct_Len( “EDITBALLOONTIP” )

   ebts<2> = getPointer( tipTitleW )

   ebts<3> = getPointer( tipTextW )

   ebts<4> = tti

 

   * // Translate to it its internal ‘C’ format

   ebts = var_to_Struct( ebts, “EDITBALLOONTIP” )

 

   * // Now get the structure address

   lockVariable ebts as BINARY

   pedts = getPointer( ebts )

 

   * // And set the tooltip …

   retVal = sendMessage( hwndEdit, EM_SHOWBALLOONTIP$, 0, pedts )

 

   unlockVariable ebts

   unlockVariable tipTextW

   unlockVariable tipTitleW

 

return retVal    

 

To use:

retVal = setEditBalloonTip( @window : “.EDITLINE_1”,         |

                          “Tip Title”,                     |

                          “Tip Line 1” : \0D0A\ : “Tip Line 2”, |