Parks Computing
Pedagogy for the Autodidactic Programmer
Welcome to the personal web site of Paul M. Parks. This is where I keep my web development skills current while sharing snippets of code, utilities, libraries, and what little development wisdom I've gathered in my career. It's also where I show off my family, talk about my hobbies, or just pontificate from time to time.
If you find the articles interesting, or if you'd like more information on a particular topic, let me know [paul@parkscomputing.com].
Buy Some Stuff!

My wife has named him "Smart Sam". I finally applied for a trademark on the drawing, but the funny thing about trademarks is that you have to actually be involved in some kind of trade. So, now you can own your very own Smart Sam Stuff! I opened up a shop on Cafepress a while back but never bothered to publicize it until now. So, go grab a t-shirt, or a coffee mug, or wall clock, or maybe a onesie for Junior. If there is some other bit of clothing or gadget you'd like to see this beautiful face stamped on, let me know!
Labels: merchandise, personal, Smart Sam
Posted February 3, 2010 0 CommentsNew Contract
Labels: consulting, personal, software
Posted December 4, 2009 0 CommentsGWA Football: 2009 State Champs!
The George Walton Academy Bulldogs are GISA state football champions for the 2009 season! They defeated Deerfield-Windsor School in Albany, GA in the class AAA championship game yesterday, with a final score of 42-24. I am so proud of all the parents, grandparents, students, alumni, faculty, and friends who made the trip down to Albany, some of whom (like us) left Thanksgiving vacation early to be there. It felt like a home game: the fans were loud, the cowbells were clanging, the band played, the Dark Army ran up and down by the field, and the cheerleaders nearly fell over from doing high-kicks for every point scored. Hats off to Deerfield-Windsor for playing tough to the very end, and never giving up. Congratulations to both teams for making it to the championship.Next year George Walton Academy will move to the GHSA, and will be returning most of their current team, so we look forward to more exciting football next season.
GO DAWGS!
Labels: football, GWA, personal
Posted November 28, 2009 0 CommentsAct Now Before Price Increase
Talk about a hot sale price! If you're getting a little tired of waiting around, now might be a good time to act. Of course, you probably won't care about the price increase when the time comes.Labels: humor
Posted November 24, 2009 0 CommentsRipsaw Library Implementation
tail utility. This series of articles details my rewrite of the application from the ground up.So far, we have a test script implemented in JavaScript (or JScript, if you want to be really picky) that is intended to exercise our COM interfaces. There is a base interface that represents a generic log that a client might wish to follow, a more specific interface representing a file, and a
dispinterface declaring the events that a Ripsaw library object can fire. In this article we'll start implementing these interfaces, with the goal of providing just enough functionality to allow us to execute the test script.(Click the "Read the full article" link below for more.)
Implementing the COM Interfaces
To briefly recap the design, there will be a Ripsaw COM library that exports objects representing sources of updates, and a Ripsaw client (such as a log viewer or a script) will create objects that fire events whenever the source changes its status. Now that we've specified the interfaces, it's time to implement them just enough to run the test script that we created in the last installment. I like to use ATL to implement the low-level, boilerplate code that's necessary forIUnknown and IDispatch, though once the wizard is done I usually take over and move all the generated code around. I've never liked round-trip development with code generators.There are three interfaces (for now) that need to be implemented:
IRipsawObject, IRipsawFile, and _IRipsawEvents. The first interface is the base interface for not only IRipsawFile but other potential interfaces that might be added later on as the library is developed. That means I want to create the implementation in such a way that I can easily extend it to other sources of data that Ripsaw might use. Unfortunately, if I took the code that the ATL wizard spat out, I'd have a really difficult time reusing it. I need to split the ATL code into a generic interface implementation and a concrete object implementation.In ATL, when implementing an object derived from
IDispatch, you usually get a class definition that looks like this:class ATL_NO_VTABLE RipsawFile :
public CComObjectRootEx<CComMultiThreadModel>,
public CComCoClass<RipsawFile, &CLSID_RipsawFile>,
public ISupportErrorInfo,
public IConnectionPointContainerImpl<RipsawFile>,
public CProxy_IRipsawEvents<RipsawFile>,
public IDispatchImpl<IRipsawFile, &IID_IRipsawFile, &LIBID_RipLib, /*wMajor =*/ 1, /*wMinor =*/ 0>
That works fine, until it doesn't. If you ever want to derive a class from
RipsawFile, you're going to run into problems. What I usually do is replace IDispatchImpl with my own template class that derives from IDispatchImpl and implements the interface that my object is going to expose. In this case, I want my object to expose both IRipsawFile and IRipsawObject, so I'll start by creating a generic template implementation of the base IRipsawObject interface. The template will be defined in a header file named IRipsawObjectImpl.h.#pragma once
#include <comutil.h>
template <class Root, class T, const IID* piid = &__uuidof(T),
const GUID* plibid = &ATL::CAtlModule::m_libid,
WORD wMajor = 1, WORD wMinor = 0,
class tihclass = ATL::CComTypeInfoHolder>
class IRipsawObjectImpl :
public Root,
public ATL::IDispatchImpl<T, piid, plibid, wMajor, wMinor, tihclass>
{
public:
/* Internal public implementation */
IRipsawObjectImpl() : isOpen(FALSE)
{
}
virtual ~IRipsawObjectImpl()
{
}
public:
/* IRipsawObject interface */
HRESULT STDMETHODCALLTYPE get_Name(
__out BSTR* pName)
{
if (!pName)
{
return E_INVALIDARG;
}
{
ObjectLock(this);
*pName = NULL;
}
return S_OK;
}
HRESULT STDMETHODCALLTYPE get_IsOpen(
__out VARIANT_BOOL* pRetVal)
{
if (!pRetVal)
{
return E_INVALIDARG;
}
LONG retVal = 0;
InterlockedExchange(&retVal, isOpen);
*pRetVal = retVal ? VARIANT_TRUE : VARIANT_FALSE;
return S_OK;
}
HRESULT STDMETHODCALLTYPE Close()
{
_bstr_t fileName;
VARIANT_BOOL tmpIsOpen = VARIANT_FALSE;
get_IsOpen(&tmpIsOpen);
if (tmpIsOpen)
{
ObjectLock(this);
put_IsOpen(FALSE);
BSTR name = 0;
get_Name(&name);
Notify_Close(name);
SysFreeString(name);
}
return S_OK;
}
HRESULT STDMETHODCALLTYPE WaitForUpdate(
__in ULONG timeout,
__out BSTR* pNewData)
{
if (!pNewData)
{
return E_INVALIDARG;
}
*pNewData = NULL;
return S_OK;
}
protected:
/* Internal protected implementation */
HRESULT STDMETHODCALLTYPE put_IsOpen(
__in VARIANT_BOOL value)
{
InterlockedExchange(&isOpen, value);
return S_OK;
}
virtual HRESULT Notify_Open(BSTR fileName)
{
return S_OK;
}
virtual HRESULT Notify_Close(BSTR fileName)
{
return S_OK;
}
virtual HRESULT Notify_Update(BSTR updateData)
{
return S_OK;
}
LONG isOpen;
};
There is quite a bit going on in this template, so let's go over its various parts.
The Root Type
If you look back at the example class definition for RipsawFile, you'll see that it derived from CComObjectRootEx<CComMultiThreadModel>. This is because, when the wizard generated the code, the user selected the option to generate an object that was free-threaded. This is an implementation detail of the object, not of the interface, so that's the first thing we need to abstract away from our generic implementation of the IRipsawObject interface. The problem, however, is that CComObjectRootEx provides a lot of useful types that we should take advantage of, such as methods for guarding blocks of code that need to be serialized when accessed from multiple threads. What I decided to do was make Root a template parameter and derive the implementation from that type. The concrete implementation may provide any type for this parameter as long as it implements the definitions expected from that type, such as ObjectLock.The IDispatchImpl Type
This is a class that is provided by ATL to implement the ugly details of IDispatch. While the average COM developer can (usually) implement a workable IUnknown rather easily, implementing IDispatch is a good deal more complicated. We know, based on our IDL, that IRipsawObject is derived from IDispatch, so this is an implementation detail that's appropriate for our generic implementation. Classes that derive from IRipsawObject will also pick up the IDispatch implementation. All of the template parameters to IRipsawObjectImpl after Root are passed along to IDispatchImpl.Notify_Open, Notify_Close, and Notify_Update
All objects that implement the IRipsawObject interface are expected to fire events to notify clients about open, close, and update events. How these events are generated is an implementation detail best left to the concrete object implementation, but I may need to fire events from the generic implementation. I decided to create stub methods that will be overridden in the concrete implementation.The Rest of the Code
The remainder of the header is devoted to minimal implementations of the methods and properties defined in theIRipsawObject interface. Most of these will be overridden in IRipsawFile and other derived interfaces. Note that the implementations use InterlockedExchange and ObjectLock to serialize access to internal data. This is because we want to allow the generic implementation to work for free-threaded object implementations, which may be called by more than one thread at a time. The ObjectLock type is expected to be provided by the Root template parameter.I Could Use Some More Cowbell
This still isn't enough code to create a usableIRipsawFile implementation, but since that's the default interface that we need to expose from our COM object we'll have to derive another generic implementation from IRipsawObject that will let us finally execute our test script. We'll tackle that template class in the next installment in the series. If you want to cheat and peek ahead, look at the file IRipsawFileImpl.h in the source code.Labels: C++, COM, JavaScript, ripsaw, visual studio
Posted November 23, 2009 0 CommentsAndroid is Nice

This post was created with Android, though not with a phone. I'm planning to upgrade to a Motorola Droid next month, so I've been playing with the SDK and getting familiar with the OS using the emulator. It's pretty nice, except the emulator is painfully slow. I may write a couple of applications for it, since I've been needing a good excuse to fiddle with Java again. Posted November 18, 2009 0 Comments
GWA Band Marches at Walt Disney World
I tried to get some pictures (click the photo below to see them), but they didn't turn out so well. Fortunately another band dad got some good video of the band (below).
Most of the band parents were running along the parade route, taking pictures and video, and when we ran out of sidewalk we just fell in behind the band. In the second video below you'll see Jennifer and I sharing a laugh with some other parents about plowing our way through the crowd to keep up with the band. I sure hope Disney lets us come back!

Labels: band, GWA, personal, video
Posted November 14, 2009 0 CommentsIt's Not a DOS Prompt!
When you click on that shortcut that says, "Command Prompt" in Windows XP, or you run
cmd.exe from the "Run" box, you're not starting a "DOS prompt." What you are starting is a command line interface, or just "command line" if you prefer. If you haven't actually run COMMAND.COM, it's not DOS!.So, please, next time don't tell me to run your favorite utility "at the DOS prompt." Let DOS rest in peace.
The first person to call Powershell a DOS prompt will get the lecture in real time. Posted November 13, 2009 0 Comments
Ripsaw COM Interface, First Pass
(This is a long article, so click the "Read full article" link below for more.)
[
oleautomation,
uuid(2D486A73-E912-4078-9F38-678226E4A0BD),
dual,
pointer_default(unique)
]
interface IRipsawFile : IDispatch
{
}
The interface is also derived from
IDispatch to support late-binding, which means that scripting languages can discover the methods and properties of the interface at runtime.Before we can write the test script we'll need decide what basic methods a Ripsaw object needs to implement. A single Ripsaw object will represent a connection to a file, and the object will fire events whenever the file changes so that listeners can take an action based on the update (change the display, parse the update, etc.). At a minimum, then, we need to be able to open a file and close a file.
interface IRipsawFile : IDispatch
{
[id(1)] HRESULT Open(
[in] BSTR fileName,
[out,retval] VARIANT_BOOL* pSuccess);
[id(2)] HRESULT Close();
}
The
Open method will accept a path to a file and return a Boolean indicating the success or failure of the method call. The Close method will close any existing connection, and we won't bother to check for a return code from that method.Now, it would probably be useful to be able to query a property of the object for the name of the file to which it is connected, and perhaps another property to check if the object is currently opened or closed. Let's add those properties:
interface IRipsawFile : IDispatch
{
[id(1), propget] HRESULT Name(
[out,retval] BSTR* pName);
[id(2), propget] HRESULT IsOpen(
[out,retval] VARIANT_BOOL* pRetVal);
[id(3)] HRESULT Open(
[in] BSTR fileName,
[out,retval] VARIANT_BOOL* pSuccess);
[id(4)] HRESULT Close();
}
Okay, not bad so far. We can open a file, query for the status, query for the name, and close the file. That's no good if we can't catch events fired by the object. We need to define a
dispinterface that specifies the events that the object can fire at its clients:[ uuid(6671C129-C761-42F3-AB2F-D12C33D95160) ]
dispinterface _IRipsawEvents
{
properties:
methods:
[id(1)] HRESULT Open([in] BSTR fileName);
[id(2)] HRESULT Close([in] BSTR fileName);
[id(3)] HRESULT Update([in] BSTR updateData);
};
The
Open event fires when a file is opened successfully, of course. Close fires when a file is closed, and Update naturally fires when the file changes. The Update notification will also pass along the data that was gathered from the last file update.Okay, based on those interfaces, our script might look like this:
var ripsaw = WScript.CreateObject("PMP.RipsawFile", "ripsaw_");
if (ripsaw)
{
ripsaw.Open("testfile.log");
if (ripsaw.IsOpen)
{
WScript.Echo("Ripsaw file is open: '" + ripsaw.Name + "'");
/* Uh-oh... */
ripsaw.Close();
if (!ripsaw.IsOpen)
{
WScript.Echo("Ripsaw file is closed: '" + ripsaw.Name + "'");
}
else
{
WScript.Echo("ERROR: Ripsaw file reported open");
}
}
else
{
WScript.Echo("ERROR: Ripsaw file reported closed");
}
}
else
{
WScript.Echo("ERROR: Failed to create Ripsaw file");
}
function ripsaw_Open(fileName)
{
WScript.Echo("ripsaw_Open(" + fileName + ")")
}
function ripsaw_Close(fileName)
{
WScript.Echo("ripsaw_Close(" + fileName + ")")
}
function ripsaw_Update(data)
{
WScript.Echo("ripsaw_Update(" + data + ")")
}
First of all, I'll explain what all this means for those of you that are new to JavaScript — err, JScript — under Windows Script Host (WSH). The first line creates a COM object based on its ProgID, or programmatic identifier. This is a string that resolves, through the registry, to a GUID that uniquely identifies a COM library that provides the requested functionality.
The second parameter to
CreateObject tells the scripting engine to wire events provided by the object to functions that start with the specified prefix. In our script, we want to handle the Open, Close, and Update notifications, so we created functions named ripsaw_Open, ripsaw_Close, and ripsaw_Update to catch these events. Since they all start with the "ripsaw_" prefix, the script engine will call them when any of the corresponding events are fired by our object.If you looked carefully at the script, you noticed that I inserted a comment: "Uh-oh." That's because the script has no way of sitting and waiting for an update other than looping in a tight loop, and that is almost never a good idea. The script would waste CPU time doing nothing while we wait for the file to be updated. In other languages we have access to message loops,
WaitForSingleObject, and other means of yielding CPU until an event occurs, but not in WSH. We need something better. What we'll do is add a method to our object which, when called, will do absolutely nothing until an update occurs. We'll call it WaitForUpdate.interface IRipsawFile : IDispatch
{
[id(1), propget] HRESULT Name(
[out,retval] BSTR* pName);
[id(2), propget] HRESULT IsOpen(
[out,retval] VARIANT_BOOL* pRetVal);
[id(3)] HRESULT Open(
[in] BSTR fileName,
[out,retval] VARIANT_BOOL* pSuccess);
[id(4)] HRESULT Close();
[id(5)] HRESULT WaitForUpdate(
[in] ULONG timeout,
[out,retval] BSTR* pNewData);
}
The first parameter is a timeout, in milliseconds, so that the function will return if no updates arrive in the specified amount of time. We'll take a page from Win32 and say that a value of 0xFFFFFFFF will tell the method to wait forever. If the timeout expires, the method will return a null
BSTR; otherwise, the return value will be the new data from the last file update. We'll modify the heart of our script to call the new method: WScript.Echo("Ripsaw file is open: '" + ripsaw.Name + "'");
var timeout = 5000;
WScript.Echo("Waiting for data...");
var newData = ripsaw.WaitForUpdate(timeout);
if (newData)
{
WScript.Echo("Waited for data:", newData);
}
else
{
WScript.Echo("Timed out after waiting for data for " + timeout + " milliseconds");
}
ripsaw.Close();
In a real script we'll probably call
WaitForUpdate in a loop, but for now we'll just wait for one update before exiting.Generalizing the Interface
This looks good for files, but perhaps later on we'd like to extend Ripsaw to listen to other sources of events, like the Windows Event Log (the first Ripsaw actually did that for a while, but I backed out the feature to focus on files). It would be a good idea to go ahead and factor out the common methods and properties into a base interface that could be extended by other event sources.[
oleautomation,
uuid(0270FDFF-56AF-42ec-9971-AE8DCB0DAB36),
dual,
pointer_default(unique)
]
interface IRipsawObject : IDispatch
{
[id(1), propget] HRESULT Name(
[out,retval] BSTR* pName);
[id(2), propget] HRESULT IsOpen(
[out,retval] VARIANT_BOOL* pRetVal);
[id(3)] HRESULT Close();
[id(4)] HRESULT WaitForUpdate(
[in] ULONG timeout,
[out,retval] BSTR* pNewData);
};
[
oleautomation,
uuid(2D486A73-E912-4078-9F38-678226E4A0BD),
dual,
pointer_default(unique)
]
interface IRipsawFile : IRipsawObject
{
[id(10)] HRESULT Open(
[in] BSTR fileName,
[out,retval] VARIANT_BOOL* pSuccess);
};
Later on, if we define an interface for listening to event logs, we'll derive that interface from
IRipsawObject and define an Open method specific to event logs. We'll also assign a special ProgID to event log objects so our client applications can create them:var ripsaw = WScript.CreateObject("PMP.RipsawEventLog", "ripsaw_");
Next Steps
Now we have an interface, and we have a script to exercise that interface. What we need next is some real code to implement the interface and a binary that the script can load and run. We'll start on a preliminary implementation in the next article. Until then, you can download the IDL and the script file and look them over. Please leave a comment with any suggestions you may have.Labels: C++, COM, ripsaw, software
Posted November 9, 2009 0 CommentsRefining Ripsaw's Design
To bring you up to speed, Ripsaw is a log-viewing utility for Windows that I initially wrote about six years ago, but never released widely. I've decided to rewrite it and discuss each step of the rewrite here.
Implementing the API
The initial Ripsaw implementation was a monolithic (albeit small) application, but this time I want to separate the log-reading mechanism from the log-viewing UI. There are times when I'd like to use the log-reading capabilities of Ripsaw from JavaScript or PowerShell, and I'd also like to write more than one viewer application around the log reader. There are at least three possible technologies for this API:- C DLL
- COM
- .NET
What About Registration?
I'd still like to be able to run Ripsaw from a USB drive without having to install anything on the machine I'm debugging or examining, which means I'd like to avoid the hassle of having to run regsvr32 on the target machine before I can use Ripsaw. Fortunately, there is registration-free COM, which will let me run a Ripsaw viewer that loads the Ripsaw COM library with the aid of a manifest. This will let me keep a viewer and the Ripsaw library in a directory on my USB drive so I can just plug it in and run the viewer without having to register or install anything.Supporting Scripting in the Viewer
Since Ripsaw's log-reading capability will be implemented in COM, I'll be able to write JavaScript apps that can watch for data from a log file, and these scripts can either parse the data or take actions based on the data. Not only would this be useful apart from a viewer, but it might also be useful inside a viewer. I could define script actions to operate on log lines, highlight them, parse them, etc., while I'm watching a log in the viewer. To take advantage of this I'll add JavaScript support to the Windows Ripsaw viewer, along with the capability to load pre-defined scripts that act on log data.Viewer Implementation
In keeping with my requirement for making Ripsaw light and portable, I don't want to use .NET for the main viewer implementation. I might create a Windows Forms or WPF viewer later on once .NET becomes more widespread on the systems I mainly work on (point-of-sale terminals and servers for grocery stores), or for when I'm debugging in a controlled environment, but for the main console and GUI viewers I'll use C++ as the development language. COM is still a bit of a pain to use from C++, at least compared to JavaScript or .NET, but it won't be too bad.Multiprocessor Support
Fortunately, the newer POS terminals and servers that are being installed today have multi-core processors, and I definitely want to take advantage of that today. I want to architect the core Ripsaw library to take advantage of multiple threads of execution spread across multiple processors or processor cores. I already write multi-threaded, multi-process systems for these machines, and these systems tend to be heavily instrumented, so sometimes I'm watching several different log files at once during a testing or debugging session. I don't want to slow a system down too much when I start up the viewer, and loading down one core of a multi-core processor with a log viewer would certainly be a bad thing.Okay, Can We Start Coding Now?
Actually, I already have been doing some prototyping, which helped me decide on the details I've described above. Now that I've sorted out some of the lower-level requirements, in the next article I'll start defining the Ripsaw log-reader COM interface. Posted November 6, 2009 0 CommentsBusy Until January
Labels: consulting, personal, software
Posted November 2, 2009 0 CommentsGeorge Walton Academy: Champs!

Congratulations to the George Walton Academy Marching Bulldog Band for taking first place in the Group VI Open division of the USSBA Southern States band competition this past weekend in Chattanooga. My elder daughter, Madeline, is a member of the color guard. They put on a fantastic show, winning caption awards for overall effect, percussion, and music. They also won the Marine Corps Esprit de Corps award. Way to go, band!
Update: Photos here. Posted October 27, 2009 0 Comments
Subscribe to Posts [Atom]