Monday, September 14, 2009

Comments - a good habit

I've just had to re-visit an area of my application which has been static for quite some time and I was glad that I have this great habit of using comments to usefully describe code.

For a long time I've been an advocate, not only in my own code but when mentoring staff in client sites, of commenting code to describe what is actually going on.

It was so easy to go back into the code and read the comments.  I then knew exactly what was going on and why.

I've never really understood the developer who rarely comments code or, when they do, don't reflect the actual logic of the code in the comments.

On client developments useful commenting is a must - after all you have no idea who will be picking up the code for that first amendment.

Setting a deadline

Not only have I set a deadline to have the coding for PexPrint complete but I've told someone about it to make sure there's someone to say "Is it done yet?". 

End of September is the target.

I've also announced the product on my website, well when I say announced it's really a page saying that it's under development with a release date targeted as Q4 2009.  But, it's another date I've said I'm aiming for.

So now I have a lot of work to do!

Monday, June 8, 2009

Feature creep and feature locking.

Progress is slow but continuing.  PexPrint (yes, it now has a working name) is suffering from a touch of over-development.  That is, the developer (me) is doing the "oo, that looks useful, I'll quickly add it" routine.

This is a no-no.  The design has been set for some time and coding is almost complete any new features should be noted and retained for the first post-live release.

To wean myself off the desire to add new features I've been looking at what features to enable for the free version of the package and which features should only be enabled in the Paid/Pro version.

This is proving to be a tricky exercise since I need to try and strike the correct balance between offering something useful in the free version whilst keeping the Paid/Pro version an attractive proposition for those requiring access to a larger feature set.

Still, at least if I'm thinking about that I'm not adding new features!

Friday, April 17, 2009

Back on track

One thing that always gets in the way of developing software as a Micro-ISV is the need to continue to earn a living whilst developing the product, or products, that you hope will move you, full time, into the ISV arena.

The past couple of months have required more effort on the earn-a-living front so the Micro-ISV had to be temporarily sidelined.

But, I'm back on track now and coding away.

One thing the break did do was make me look over the code to re-familiarise myself with where I was.

This highlighted a "Schoolboy Howler" (term we use locally in development when an obvious error is found that should never have been there!).   Note to self - when updating the registry and you need to restore it to the position it was in when you started, make sure you didn't inadvertently create a new value for something you'd assumed would always be there when you started!

Thursday, February 19, 2009

Catch that process

I have an interesting piece of work on the go for a client at the moment which is posing a number of tricky questions.

The client has asked for software to control a web browser on a locked down, Windows based, kiosk PC.  There's nothing special about the PC or the Windows installation, but the browser has to be tightly controlled - way beyond the Internet Explorer Kiosk Mode.

The latest question was how to detect and terminate unauthorised, and unexpected, processes from starting.  For example, despite all the other controls in place what would happen if the kiosk user managed to start Excel?

After much Googling and research I coded a solution based around the Windows Management Instrumentation (WMI)

Once everything is initialised (connecting to the namespace, setting security and building the event sink), using WMI is something that would be familiar to any relational database developer since you set up a query on the data using an RDB type query language - WQL.

In this instance the query was:

SELECT * FROM _InstanceCreationEvent WITHIN 1 WHERE TargetInstance ISA 'Win32_Process'

I'd set up an event sink for the WMI query, based on the IWbemObjectSink interface, so whenever any new process started my event sink was notified and I could take appropriate action.

The action in this case was to compare the process details with a list of processes which were allowed and if it wasn't on the list WMI was instructed to terminate it.

Identifying the process by executable name wasn't always easy since the executable name wasn't always available - but a quick (very quick, since Microsoft recommends returning from the WMI notification within 100ms) check of the process snapshot data, using CreateToolhelp32Snapshot, proved to be a good backup.

As I said, an interesting piece of work for me!

Saturday, January 24, 2009

Printer status monitoring II

Since I developed the small class and application for monitoring the status of printers and jobs I've set upon improving it.  Specifically I was aiming to improve the mechanism it uses to track changes to the printers and print jobs.

There are really two options for this type of processing, you either poll the printers and queues on a regular basis or you make use of some type of notification process which will wake up your processing when an event occurs.

The first incarnation of the printer monitor test application relied on simple polling since I wasn't actually developing that part of the functionality - I was interested in getting the status information for the printers and jobs.

But, having the ability to handle the capture of printer and job state changes looks useful and I set about improving on the simple polling technique.

Windows implements a printer event notification process through the FindFirstPrinterChangeNotification API and its companion API's FindNextPrinterChangeNotification and FindClosePrinterChangeNotifcation.

Prior to calling FindFirst... you need to set up two structures, PRINTER_NOTIFY_OPTIONS_TYPE and PRINTER_NOTIFY_OPTIONS, which state the type of event and information you're interested in.  You also need an open handle for the printer being monitored.

FindFirst... returns a handle which can be used with the Windows wait functions (WaitForSingleObject etc.) which gives you your basic event monitoring process.

With the waitable handle you call the chosen wait API.  On return, and if the event fired, you can call FindNext... to get the event information allowing you to check printer and job status.  Then you're back to the wait function until the next event fires.

Once you're done, a call to FindClose... releases the resources associated with the wait.

Once contained in their own thread with some enable/disable processing you have a very effective and efficient print monitoring capability which isn't going to interfere with the UI threads.

Once these changes were in, and the rudimentary polling code removed, the monitoring application functioned just as before but with a reduction in system resource usage. It also has simpler access to a range of printer and job related status information which can be exposed through the component interface.

Saturday, January 10, 2009

Printer status monitoring

One of the features I want my component to be able to support is the ability for applications to use it to monitor the status of printers and print jobs.  The easiest way to work out how to do this was to write a small application which gathered and displayed the required information. 

It turned out to be a fairly enjoyable little bit of work which provided a print monitoring class ready for inclusion in my component.

Obtaining printer status, for example detecting out of paper conditions, turned out to be trickier than just asking the printer how it's doing.

Printer status under Windows isn't really a regularly updated and accurate property on the printer itself and can't be reliably obtained by just querying the printer information.

The status of the printer is updated and made available when jobs are actively spooling and printing.

The solution was to iterate over the available printers, using the EnumPrinters API, and for each printer returned look at the information for queued jobs using the EnumJobs API.

Then it was just a case of inspecting information from both the printer (using the PRINTER_INFO_2 structure) and the jobs (using the JOB_INFO_2 structure).  Both of these structures contain status information but I found that the jobs reported more accurately.

The small test application I developed to work through the solution has turned out to be a handy little thing.  When started, it just sits quietly in the corner reporting how the printers it can see, including network attached printers, are doing and how many jobs are in each printer's queue.  So handy in fact that I may just add a little help file and throw it up on the website as a free user downloadable utility application.

Website - done.

A positive start to the New Year!

Actually the new site was live in December but I didn't manage to post an updated blog entry.

I've looked at it for so long that it's looking a little old to me already!

But I did get round to finishing all the little tweaks and I published the site, so I've removed the one big excuse that was keeping me away from developing.

New website is here for those of an inquisitive nature.

Friday, December 5, 2008

Inheritance under control.

Well, mostly.

In my last post I spoke about the 21 entry inheritance list on a fairly simple ActiveX control.

I looked through each class in the list and decided that I could live without 10 of them because they were implementing features I don't intend to support.

Most were to do with visual controls, but my control is non-visual so those could go.  Others were there for property page and stock property support which I don't need.

So, the list went down to 11 entries, then I added my sole addition to that list - support for browser events.

The removal of many, and addition of one, had a slightly disappointing effect on the size of the DLL though.  Removing the classes I don't need saved around 45K but adding the browser events in added 20K back in.  Still, a 25K saving is better than nothing.

25K may seem a trivial amount given the multi-gigabyte PC memory and terabyte hard drives we enjoy nowadays but I like to ensure that my applications and components only use what they really need. 

Maybe that's my age telling again though.  When I started programming it was on the Commodore VIC-20.  5K of memory, 3.5K useable.  What a luxury the upgrade to the Commodore 64 was!