Dr. Dobb's is part of the Informa Tech Division of Informa PLC

This site is operated by a business or businesses owned by Informa PLC and all copyright resides with them. Informa PLC's registered office is 5 Howick Place, London SW1P 1WG. Registered in England and Wales. Number 8860726.


Channels ▼
RSS

C/C++

Apr02: C Programming


Apr02: C Programming

Al is DDJ's senior contributing editor. He can be contacted at [email protected].


You're about to read of how I learned to build application installation programs, had the side of my house torn out, and almost had my cat killed. How, you ask, could these three things have anything to do with one another? Read on.

I've always been interested in what we call "setup." Maybe that's because, over the years, I've had review copies of software that wouldn't install correctly. In the old days, setup was a simple task. Copy some files from a diskette to the hard drive, add the installation subdirectory to the PATH environment variable, and that was it. Setup on MS-DOS machines was typically implemented with batch scripts; I wrote a few of them myself. Knowing how simple the process was, I refused to look further at applications that got it wrong. If they can't do setup right, how can I trust their software, I asked myself.

As operating systems grow in complexity, so do the problems associated with setup. A setup program for the Win32 platform has a lot to do: It has to copy the correct application files from the distribution medium to the hard drive, display the end-user license, collect and validate product keys, search for earlier installed versions, decompress and copy distribution files, initialize entries in the Registry, ensure that common files do not interfere with previously installed ones, associate document types with the application, put shortcuts on the Start menu and Desktop, present and collect a variety of setup options, determine whether the system has sufficient resources to support the application, manage online registration and upgrade, present readme information, install device drivers, and so on. Not only that, but an application must support a standard way for users to uninstall it, removing all the files its setup copied to your system and its operation added, and resetting all the settings it made during installation and operation.

When I built the first version of Quincy, a Win32 IDE that hosts the free GCC and BCC 5.5 compilers, I wrote my own setup and uninstall programs and wrote about them in this column. As I built other applications, I used modifications of these programs. And, as operating environments gain complexity, the changes make these programs more unwieldy and difficult to maintain. I'm ready for a different solution.

Several years ago a tool named "InstallShield" (http://www.installshield.com/) came out to automate the setup process, making it easier for developers to build comprehensive setup programs and giving users a common setup user interface. Some compiler products include an early version of InstallShield to make it easier for developers to distribute the programs they build with the compilers. While useful, that version is sparse and does not support many of the things you might want for a contemporary setup.

The current version of InstallShield supports virtually everything you need, including a script language that lets you write custom setup procedures that can access the Win32 API. The full setup process is so complex that InstallShield offers an IDE application called "InstallShield Developer" to assist developers build setup.exe distribution files for their applications. In December, I attended a four-day class conducted by InstallShield on how to use InstallShield Developer. If you plan to build a complex Win32 or .NET application, I recommend not only InstallShield as your setup method, but InstallShield Developer as the way to go. If possible, get your employer to spring for one of these classes. I suppose you could learn this complex development environment on your own, but I wouldn't want to. The class will save you countless hours of experimentation and exploration.

The first day of the class, our instructor, Dave Ashelman, did the usual survey of the eight attendees, asking who we were, where we hailed from, and what experience we had with InstallShield and setup in general. Class experience ranged from zero to extensive.

For the most part the class members were not programmers, but they were expected to build setup programs for their employers or clients. We frequently discussed the necessary interaction between setup specialists and programmers, which was generally agreed to be a disagreeable experience due to the typical programmer's low regard for those who do not write code. But one attendee, who has extensive experience with earlier versions of InstallShield Developer and who also programs in and teaches C++, offered the opinion that building setup is, in many cases, more complex than building the application. So, if you're writing code in a shop that uses nonprogrammers to build setup, cut them a little slack. Their job just might be more technical (and more secure) than yours.

I really enjoyed this class. Davey knows his subject, teaches it with enthusiasm, and cares intensely about the quality of the product and of the class itself. InstallShield Developer is a deeply complex subject. Fall behind in one lesson and you could become bewildered by the ones that follow. Davey saw to it that everyone was caught up before he'd move on. A complex subject such as this one can cure chronic insomnia, too. I'm one of those guys who slips off into slumber when the drone of a dull presentation pounds on my eyelids. Davey kept me on the edge of my seat. His enthusiasm is catching.

You might wonder why I call him Davey. I never met him before the first day of this class and would not normally use a familiar nickname in a professional association with a stranger, but Davey, as it turns out, is the son of a family friend. Dave Ashelman, Sr., aka Dave, is a proud papa who has bragged about Davey to us for years. When Davey e-mailed to say he'd be nearby teaching a class and would like to meet his pop's friends, Judy and me, I grabbed the opportunity to attend his class, a coincidence of convenience. You see, I had only recently approached the problem of setup for my next project and had decided to learn something about InstallShield. Davey's timing was perfect.

Mr. Ashelman, Tear Down That Wall!

But what, you ask, about the house? Well, while I was contentedly learning the ins and outs of InstallShield Developer, Davey's dad, Dave, decided to help me out. Dave is a retired correctional officer with too much time on his hands. My own father was a retired CO, and he occupied his spare time by drinking beer and playing pool and poker at the Moose Lodge. The role of CO is a noble career, but it doesn't prepare you for much else when you retire. Dave, a self-taught handyman, prefers to use his time more productively. Based only on a casual comment I'd made about getting rid of some pesky pine trees on my property, Dave decided to surprise me and cut 'em down.

Professional tree removers have careful procedures and specific equipment for felling tall trees. They climb the trees, remove the branches, and top the trees in short lengths, ensuring that each falling trunk segment does not endanger life and property. They have spikes and straps for climbing those trees, guy wires to ensure that the trees fall in the proper direction, and helpers to make the job safe. Retired COs don't work that way. They eliminate all that extra effort and stuff and wade in with a chain saw chewing and gnawing away at the trunk close to the ground. They understand gravity, which is why trees fall when you cut them, but they do not understand center of gravity, which is why trees fall in the direction they do. They cut until the tree starts falling, then run like hell to get out of the way of the tree. I know this is how they work because Judy described it in detail after the fact. Dave was careful to ensure that none of the trees would reach the house if they fell in that direction, falling direction being a random factor, you see. But he failed to see the power, telephone, and TV cable lines that reached from a pole on the edge of the property to the side of the house, lines that crossed the path that one particular tree chose for its falling direction. Dave sawed, the tree fell, Dave ran like a sumbitch, the tree hit the lines, and its weight pulled the AC, cable, and telephone distribution boxes off the side of the wall along with most of the siding and sheathing that, until then, had been the end wall of my house.

The Cats and Jammer Kid

Being a handyman, Dave decided he'd better fix the damage before I got home. He jumped into the truck and hit the ignition. The motor turned over once and jammed. Now, Dave knew about that cat, but in his haste to get to the hardware store for nails and wire and I don't know what all, Dave forgot about that cat.

Judy had warned Dave many times that Max the cat likes to curl up in the cooling fan shroud of my pickup and that we always look under the hood before starting the truck. Don't ask me how a three-pound cat can arrest the starter motor of a GMC 350 V8 by blocking the fan, but it can. Judy saw it all. She reports that when Dave realized what he'd done and backed off of the starter, poor old Max dropped down onto the driveway, wandered out from under the truck with a glazed look, and limped erratically away into the brush to stay out of the way of chain saws, falling trees, truck engine fan blades, and crazy humans for several days.

By the time I got home, with Davey coming along to visit with his dad and enjoy one of Judy's famous dinners, I found a morose Dave looking repentant and contrite, a weepy, worried Judy searching through the palmetto brush and calling Max's name, and the cable guy, telephone guy, electric company guy, and several neighbors standing around, looking at the wreckage, and laughing uncontrollably.

Davey, who is used to his Dad's adventures, said only, "Maybe we ought to eat out?"

As I write this, the wall is back up and Dave, ever the helpful handyman, is clearing out some brush and burning it in my front yard. I've alerted the fire department to stand by. Max returned several days later a little the worse for wear, but mostly an unimpaired cat. Except that he gives Dave and the truck a wide berth now.

Wading Back Into the Waves

In my February column I described Wave audio classes that encapsulate audio recording and playback on the Win32 platform. I developed these classes to support an application I'm building. (To follow along, understand that I am writing this column for the April issue in January and the February issue has only recently come out. Readers are now responding to that column.) In the March column, not yet available as I write this, but already old stuff as you read this, I republished the class library to repair a flaw that kept it from working with Windows XP and, probably, 2000 and NT. Your humble C Columnist dutifully reported this oversight and corrected it. This month finds crow on the menu again following e-mail from several readers who spotted a serious bug in the WavePlayer and WaveRecorder classes, not the one I found and fixed, but another bug, one that I ought to have avoided because the API documentation is clear.

How can there be a bug in software that works on all the systems at my house? Because my house, even with one wall torn out, isn't big enough to hold every possible PC configuration with which to test stuff. My audio class library and, consequently, my application will freeze up on PCs that have certain sound cards installed.

Both classes use callback procedures to intercept completion of a block of audio input or playback. When the system is ready for the application to send more sound to play or ready to deliver more recorded sound to the application, the system calls callback functions that the classes provide. The WavePlayer class's callback function calls its derived application class's function to get more samples, then calls waveOutWrite to send those samples to the system to be played. The WaveRecorder class's callback function calls its derived application class to store the samples coming in from the recorder. Reading and writing samples uses other system calls. But the API documentation specifically warns that a callback function may call only certain system functions, and the system functions that my classes call are not among the permitted ones. Calling forbidden functions from within a callback function can create havoc, depending, I suppose, on the sound device driver. All my drivers are havoc-sanitized, so I did not know about my insidious bug. I would have if I had bothered to read the documentation, but that's another story.

The solution is to use a thread. At the start of playback or recording, the classes launch threads with the AfxBeginThread function. The threads monitor events by using the WaitForMultipleEvents function. There are three events being watched. Two are for the two sample buffers. (Recording and playback both use an overlapped, two-buffer approach.) The third event indicates that recording or playback is completed and tells the thread to exit from itself. When one of the first two events occurs, the thread calls the functions formerly called by the callback functions. The new callback function, now located in the base Wave class, simply sets the appropriate event based on which buffer is ready to be processed.

You can once again download the files wave.h, waveplayer.h, waverecorder.h, wave.cpp, waveplayer.cpp, and waverecorder.cpp (see "Resource Center," page 5). I hope this is the last time you need to do that. My thanks to those readers who pointed out this problem.

An Audio Engineering Challenge

Over the past several months, I described my audio project and the techniques I explored in an attempt to encode multiple logical audio channels into the two stereo channels of a waveform file. I specifically need the ability to selectively eliminate any one of six channels during playback. I call the project, "Music Minus Whatever."

Each experiment I published generated comments and advice from readers who know a lot more about digital signal processing and audio engineering than I. Most of these comments were constructive and changed my direction or reinforced my belief in some particular approach.

But some readers sent mathematical proofs that what I want to do is impossible. Sometimes knowledge inhibits innovation. I explained earlier that you read this column several months after I write it. In most cases, the mathematical proofs arrived well after I'd already achieved what the math proved was not possible. If I were a theoretical mathematician, I probably would have convinced myself that my goals were unattainable and might not have blundered along making discoveries based in ignorance. Isn't that how we got the light bulb? Many worthwhile inventions are the products of stubborn inventors who hadn't been told or refused to believe that it couldn't be done.

I have not published the approach I settled on, first because it revealed itself only in the past several weeks, but also for another reason that I'll explain soon. The algorithm does far more than I hoped for. I described it to a couple of audio engineers, and they firmly and with authority pronounced my results theoretically and mathematically impossible. They'd never try to do what I wanted because, you see, it can't be done.

Except that it already works.

I'll explain the effect and wait for the cries of disbelief. Begin with a standard .WAV file recorded at 16 bits per sample, 44,100 samples per second, two channels. The recording contains six instruments, three on each channel. You can play this file with any media player program. When you pass the file against my algorithm, you can do a full audio mix on its six logical audio channels, changing the volume and pan of any and all six channels in real time during playback.

If you are an audio engineer, chances are you do not believe me. Your mission, if you choose to accept it, is to figure out how I did it. A free DDJ T-shirt to the first five readers who figure it out. I'll not publish the algorithm at this time because, horror of horrors, I might patent it. Not because there's any money to be made from licensing this particular algorithm but because I want to learn the mechanics of software patents, something I oppose in principle but do not understand in practice.

If you are a disbelieving audio engineer, you'll just have to take my word for it. I'll provide a demonstration later when it's appropriate to do so. My project uses the algorithm, so you can see it in operation for yourself when that work is completed.

But if you know about software patents, I'd sure like to hear from you. Some lawyer might tell me it can't be done.

DDJ


Related Reading


More Insights






Currently we allow the following HTML tags in comments:

Single tags

These tags can be used alone and don't need an ending tag.

<br> Defines a single line break

<hr> Defines a horizontal line

Matching tags

These require an ending tag - e.g. <i>italic text</i>

<a> Defines an anchor

<b> Defines bold text

<big> Defines big text

<blockquote> Defines a long quotation

<caption> Defines a table caption

<cite> Defines a citation

<code> Defines computer code text

<em> Defines emphasized text

<fieldset> Defines a border around elements in a form

<h1> This is heading 1

<h2> This is heading 2

<h3> This is heading 3

<h4> This is heading 4

<h5> This is heading 5

<h6> This is heading 6

<i> Defines italic text

<p> Defines a paragraph

<pre> Defines preformatted text

<q> Defines a short quotation

<samp> Defines sample computer code text

<small> Defines small text

<span> Defines a section in a document

<s> Defines strikethrough text

<strike> Defines strikethrough text

<strong> Defines strong text

<sub> Defines subscripted text

<sup> Defines superscripted text

<u> Defines underlined text

Dr. Dobb's encourages readers to engage in spirited, healthy debate, including taking us to task. However, Dr. Dobb's moderates all comments posted to our site, and reserves the right to modify or remove any content that it determines to be derogatory, offensive, inflammatory, vulgar, irrelevant/off-topic, racist or obvious marketing or spam. Dr. Dobb's further reserves the right to disable the profile of any commenter participating in said activities.

 
Disqus Tips To upload an avatar photo, first complete your Disqus profile. | View the list of supported HTML tags you can use to style comments. | Please read our commenting policy.