So, driven by a need for such a monitor of high quality (answering the very specific requirements I mentioned in a previous post) I fired up my old'n'dusty Win32 API skills and decided to rewrite the thing in C++.
My relationship with the Win32 API has some roots, and it's not a place to delve too deep into it (I'll dedicate some posts to it in the future). In short, I really like the way Windows GUIs are built, and find the message pump model very intuitive Plus, I have Petzold's excellent Windows Programming book, which makes things quite simple.
The results of this endeavor are well beyond my expectations:
- It took 3 days to develop (comparable to the Perl version).
- It weighs ~1200 LOC (comparable to the Perl version).
- It works fully satisfactorily - both error-handling wise (which is terrific), and speed wise (much faster and sleeker than the Perl version).
- Best of all - the executable takes 120K (compared to the 3MB of PARed Perl).
Now, this would be too surprising (C++ comparable in code size and coding time with Perl ?!?!), but there are some small details that complete the picture and make it more bearable.
Development time wise - I gained a lot of experience from the Perl implementation - I never made so complex a multi-threaded app, and I never worked so seriously with serial ports. The second implementation built heavily on the expertise gained from the first (the prototype).
Code size wise - Visual Studio's resource dialog/menu builder saves quite some code...
But most important - the library I used. While most of my Perl prototype development time was spent struggling with the terrible Win32::SerialPort module, I had much more luck in C++. Google brought up the CSerial class immediately, and this was the beginning of a great friendship...
This class is terrific. It is cleverly designed (actually it's a family of classes), well documented, very intuitive (so the docs aren't really needed) and provides just the things the programmer needs. It is as if its author anticipated all the common uses for the class and implemented them in a convenient way. For my cause, the CSerialWnd wrapper was just perfect. It opens a thread listening on a port, and just sends me normal windows messages whenever it gets data. My code is simple waiting on these messages and taking care of them when they arrive. Usage of this class reduces both the amount of code to be written (I didn't have to implement threading code manually like in Perl), and the development time.
All in all, the shiny new COM Monitor works a treat. It's sleek, fast, small and has more features. I have a few more tests to do and when I'll put it on my website as GPL, like I do with all my code (the CSerial class is LGPL, by the way).
What did I learn from all this ?
- First of all that serial port programming is fun. It's always nice to get "out of the PC" with your code.
- I learned a lot about threads (hadn't had much experience with them before, though it all turned out like I expected).
- My Win32 API experience got some exercise. I recalled once again how much I like the Windows messages model (in contrast with Motif, for example).
- But I also recalled that even with the VC resource editor, manual GUI in Win32 API is a lot of work.
- Unicode stuff is pain in the a**. Much of my first day coding was spent on banging my head against conversions between TCHARs, wstrings, strings, wchar_t-s and chars (and Windows' ever helpful LPCTSTR or whatever). Eventually I got it, however, and wrote some handy utility functions that got me through the rest of it with minimal pain.
- Propotyping is helpful. It might have taken me more time had I just went for the C++ version immediately.
- Libraries are very important ! A good library can make a vast difference over a bad library. I got a *very* strong proof for this concept. I generally enjoy Perl coding much more than C++ coding, but the CSerial class made my coding in C++ far more bearable than Perl with Win32::Serial.