Thursday, December 09, 2010

Another Windows Virtual PC Gotcha

Microsoft Virtual PC, for Windows Vista and earlier, automatically writes changes from the undo disk (VUD file) to the main drive (VHD file) when you shut a virtual machine (VM) down. So, when you’re setting up a VM or otherwise want to make permanent the changes you made while using it, you just shut it down and tell it to save the changes. When you do something where you don’t want the changes saved, such as doing a test install, you shut it down and tell it to discard the changes. Very straightforward.

Windows Virtual PC, for Windows 7, doesn’t automatically write changes from the VUD to the VHD. When you shut a VM down and don’t tell it to discard changes, it continues to build up changes you make over various sessions to the VUD file. When you want to write the changes to the VHD, you have to specifically edit the settings for the VM, choose the Undo Disks page, and click Apply.

Until I realized this, I couldn’t understand why a VM I had set up kept reverting to an earlier state. I started the VM, made some changes I wanted permanent, then shut it down, thinking that the changes would be written to the VHD (although I did notice that the shutdown process was a LOT faster than I was expecting). I then fired it up again, did a test install, and shut it down, discarding changes. When I started it back up again, it was at the original state, without the changes I thought I’d made permanent. I also noticed that the datetime stamp on the VHD file hadn’t changed.

After a couple of rounds of this, I started poking around to see what I had to do to write changes to the VHD. That’s when I discovered the Apply button in the Undo Disks pages of the Settings dialog. Hopefully my pointing this out will save someone else some time.

Updating Integration Components in a Windows Virtual PC VM

I’ve been using Microsoft Virtual PC for several years. It’s great for testing installs, installing applications you don’t want polluting your host system, and lots of other things. I recently bought a new laptop with Windows 7, so I installed the latest version of Virtual PC, renamed to Windows Virtual PC.

When starting some of my existing virtual machines (VMs), I was prompted to upgrade the integration components. Integration components make it easier to work with a VM because they allow access to resources of the host system including (new to the Windows 7 version) USB devices. In Windows XP VMs, it’s easy: choose Yes when asked and follow the prompts. In Windows Vista and Windows 7 VMs, however, it’s a little tricky:

  • Choose Yes when asked to update.
  • In the dialog that appears allowing you to either run Setup.exe or open a folder, choose Open folder.
  • In the Windows Explorer folder that appears, right-click Setup.exe and choose Run as Administrator.
  • Follow the prompts until you get a dialog telling you that certain files are in use. Note the process ID for each one.


  • Click Ctrl+Alt+Del in the VM menu and choose Start Task Manager and select the Processes page.
  • If you don’t see a PID column, select the Select Columns function from the View menu, turn on PID, and click OK.
  • Click the PID column to sort on process ID.
  • Click the Show processes from all users button.
  • Select each of the process IDs for the files in use and click End Process.
  • Carry on with the rest of the installation process (it’ll require a couple of restarts for your VM).

One thing I don’t like about Windows Virtual PC is that it doesn’t support dragging and dropping files from your host system to the VM window and vice versa. Instead, with integration enabled, you have to open Windows Explorer, navigate to the appropriate drive on your host system, and copy files to and from that way. Not a huge problem but more work than with the older Virtual PC.

Wednesday, December 08, 2010

Microsoft Office 2010 Gotcha

I have a nice new shiny toy: an Asus G73JW laptop with an Intel i7-740QM quad core processor, Windows 7 Pro (64-bit), 17.3” LED display, 8 GB of RAM, a 80 GB solid state primary drive, and a 500 GB secondary drive. Of course, the bad thing about getting a new system is the time it takes to get it set up just so, but I have a checklist I work from to make the setup straightforward. Things were going great until today. Emailing from Stonefield Query using MAPI (which means it goes through Outlook) and reading Excel spreadsheets using the Excel ODBC driver no longer work.

Rick Schummer blogged about issues with a client who upgraded to Windows 7 and Microsoft Office 2010. My issues aren’t the same, but are related: I foolishly chose to install the 64-bit version of Office rather than the 32-bit version, and now my 32-bit apps no longer work with it. I guess this falls into the DOH! category. Hopefully if you’re setting up a new system or upgrading an existing one, you’ll be a little smarter than me.

Friday, November 26, 2010

PEM Editor Blog

As you likely already know, Jim Nelson has created what’s probably the most important and time-saving utility for VFP ever: PEM Editor. PEM Editor, available from VFPX, is an incredible kitchen-sink of a tool. It started life as a replacement for the Edit Property/Method dialog but since then has mushroomed into a complete object editing tool. It can replace not only Edit Property/Method but also New Property/Method, the Properties window, the Document View window, the Beautify functionality, and so much more. It has customizable property editors, filters for the PEM list, and hundreds of other features. Jim did a presentation on PEM Editor at Southwest Fox 2009 and several user groups and Cathy Pountney did one at this year’s Southwest Fox as well as the German DevCon and several user groups.

Recently, Jim started a blog for all things related to PEM Editor. He’s posted release notes for new versions, tips and tricks, and other ways to get the most out of this tool. Highly recommended reading!

Tuesday, November 16, 2010

More 2010 Lifetime Achievement Award Recipients

Last week at the German DevCon, two more long-time VFP gurus were given Lifetime Achievement awards: Jürgen Wondzinski (aka wOOdy) and Christof Wollenhaupt. Congratulations to both! The FoxWiki page hasn’t been updated yet but hopefully will soon.

Tuesday, November 09, 2010

Southwest Fox 2010: Days 3 and 4

I woke up Sunday at 4:30 a.m. For reasons I still don’t understand, I was really nervous about the speeches I was to give about Lisa and Rick at the closing session. I had slides showing their bios and photos in the closing session (unbeknownst to Rick, I had slipped in his slide after he, Tamar, and I reviewed them) but wanted to say something personal about both of them, and figured it would work better if Tamar worked the slides while I spoke. It suddenly occurred to me that if Tamar went one slide too far while I was speaking about Lisa, Rick’s slide would appear and spoil the surprise. So, I added a “But wait … there’s more” slide as a buffer between Lisa’s and Rick’s. I think this gives you an idea of how much I was obsessing about this!

After what seemed like forever composing the speeches in my head, I went down for breakfast and my last presentation, the second instance of my Cool Controls session. I was chatting with people between sessions, so I was late coming into Cathy Pountney’s fxReports - Sharing Custom Report Features, but I’m glad I went. Cathy is working on some very cool stuff: a way for VFP developers to share custom reporting features, including reporting effects and custom Report Designer dialog pages. She’s releasing it as a new VFPX project in the next little while. This actually fits perfectly into work I’ve done with Stonefield Query and a new VFPX project I recently launched, FRXTabs. After the session, Cathy and I discussed some ways we can integrate the two.

I then went to Steve Ellenoff’s Integrating Windows 7 Taskbar Functionality into VFP Applications session. From its description, it was the session I was most looking forward to seeing because I want to add Windows 7 functionality to Stonefield Query and figured Steve could jumpstart my work. I wasn’t disappointed; as I told Steve afterward, this session paid for the conference for me. He showed how, using a library he’s created and released as a VFPX project, you can with just a few lines of code support Taskbar jumplists, progress bars, and much more. About every minute in his presentation, I came up with another idea of how to use this library to add new functionality to my apps.

Finally, it was time for the closing session. Rather than describing it in detail, I suggest you watch it and you can read Lisa’s and Rick’s blogs about it. Lisa’s video was great, even if it started on the wrong foot thanks to Windows Media Player changing its mind and deciding to play a comedy audio file on my system instead of Lisa’s video. It was also great seeing the huge ovation Lisa deservedly got, and I was very pleased that her husband Colin Nicholls could be there to watch her receive the award. But the best part was definitely Rick’s reaction to the award. He was literally speechless and quite choked up. I’m amazed he even managed to get through the next part of the session. Afterward, I saw his Mom come up to him and give him a hug; that was my favorite moment of the entire conference.

As usual, Sunday afternoon is pretty anti-climactic: tearing down projectors and stands, cleaning up the registration booth, a post-conference briefing with our main hotel contact Sharon, and a Geek Gatherings meeting to discuss 2011 (yes, we actually start planning for next year the day the conference ends). It’s kind of sad in a way, because we’ve had so much fun over the past several days, talking with friends we only see once a year, knowing that’s it’s over for another year.

However, there was still fun to be had. Shortly after our last meeting ended, we took the speakers out for dinner as a small way of saying thanks for all their hard work preparing and presenting their sessions. This year, we went to Gordon Biersch and had a great meal and some very tasty beer. Afterward, it was out to the poolside again, but I headed to bed about 11:00 exhausted.

The next day was the VFP to Silverlight workshop presented by Uwe Habermann and Venelina Jordanova. More than half of the attendees stayed for this workshop, which was great to see. Unfortunately, I had a couple of client issues I had to resolve so I didn’t pay as much attention to the presentations as I’d liked. Fortunately, Uwe and Venelina handed out memory sticks with all of the presentations, sample code, and even installers for Microsoft Visual Studio Express and the Silverlight tools, so I can go over the materials when I get a chance. One of the cool things that went on was the back channel of communication using Twitter by some of the attendees. We even picked a place for lunch (In ‘n’ Out Burger, which I hadn’t been to before) without saying a word. That night, a group of about 15 went back to the Mexican restaurant I’d been to Saturday night and we had another fun evening of food, friendship, and margaritas. After we got back to the hotel, a group of us had some drinks, checked out some hilarious but definitely NSFW t-shirts online (I was laughing so hard I almost couldn’t breathe), and checking out some places in Brazil Cesar Chalom showed us on Google Maps.

So, another year of Southwest Fox is over. Every year, the conference seems to get better and better. We had a few challenges this year—a new hotel at the last minute and finding a speaker to replace Craig Boyd late in the game, which Jody Meyer did an excellent job of—but it’s always fun and worth all of the effort we put into planning it. Stay tuned for an announcement about Southwest Fox 2011 and I hope to see you there next year!

Sunday, November 07, 2010

Southwest Fox: Day 2

As I hinted at in my previous blog post, sleeping was an issue for me at Southwest Fox this year. I woke up at 5:00 on Saturday, my head buzzing with what I wanted to say at the closing session on Sunday. I read for an hour or so to calm down.

I had the first timeslot of the day (moving it back from 8:00 to 8:30 last year was a very popular decision!) and presented my Cool Controls for Your Applications session. I was even more nervous about this than the ThemedControl session; again, I’d practiced it several times and had it down cold, but would attendees think the controls were as cool as the title promised? Fortunately, that turned out to be the case; the evals were even more positive than for the ThemedControls session and I’ve had several emails from folks afterward who told me they’ve already implemented some of the ideas presented in their applications.

I started by explaining that this session had the same theme as my ThemedControls session: there’s no excuse for creating boring-looking VFP apps. I presented each of the controls in this session in a similar manner: a demo of what it looks like, a brief discussion of how it works (with a detailed discussion in the white paper for those interested in looking under the hood), and a cookbook-like explanation of how to implement it.

The first was a simple control I wrote several years ago but is used in lots of places (not only my apps but also in the VFPX PEM Editor): a splitter that allows the user to adjust the relative sizes of the resizable controls (listboxes, editboxes, grids, etc.) in your forms. Next, I showed a control I call a “combotree” because it combines a combobox with a TreeView to provide a control you can use to display hierarchical data or a lot of checkboxes without taking up much screen real estate. This control is also used in PEM Editor and lots of places in my apps. I then showed the VFPX PopMenu project and how it can be used to create Microsoft Office-like menus in your apps. I spent some time showing how to use Paul Mrozowski’s RCSDateTimePicker as a replacement for the Microsoft DateTime Picker ActiveX control for date data entry, including some enhancements I added allowing you to select a range of dates. Next up was Ctl32_BalloonTip, one of the many controls in Carlos Alloatti’s definitely cool Ctl32 library. Ctl32_BalloonTip replaces plain old boring tooltips with attractive “balloon” tips that you also have more control over. I finished by showing how another of Carlos’s controls, Ctl32_ProgressBar, gives a Vista/Windows 7 appearance to progress bars in your apps. The images below show some of these controls in action:

Office PopMenu RCSDTPicker Balloon Tips testform1 Progress Bar

I ended up chatting with a few people so I missed a session in the next timeslot. As we told everyone in the keynote, that’s perfectly OK: you often get more out of a conference by the discussions with fellow developers than in the actual sessions, and every session has a white paper so you still have the content. I then presented my ThemedControls session for the second time in the slot before lunch.

After lunch, I went to watch Uwe Habermann and Venelina Jordanova present their Silverlight for Internet Applications session. I’ve known Uwe and Venelina for several years, having met them at conferences in Prague and Germany. I liked the way they presented this session: they took turns talking and led the other into the next topic by asking questions an attendee would ask. I didn’t know much about Silverlight but was planning on attending the post-conference VFP to Silverlight workshop, so this was a good overview of Silverlight and even went into details on creating your first project.

The next session was Tamar’s Collections: Managing Information the Object-Oriented Way. I’ve worked with collections for years, but I saw Tamar’s session on business objects last year and this session was “part 2” of that, plus I enjoy Tamar’s take on things and figured I could pick up a few tips. During the session, I played a trick on Rick Schummer, who was right behind me. He had to leave the room for a couple of minutes, so he left his laptop on the seat and his bag on the floor. As soon as he walked out of the room, I quickly grabbed both and hid them under my chair. Even better, someone came in a moment later and sat on his now abandoned chair. When Rick came in, he looked panic-stricken: he thought the other person was sitting on his laptop, and looked all around for his stuff. I didn’t let him suffer for too long, and he let out a very relieved laugh when I handed him his laptop and bag. Hmm, I hope he doesn’t go all “Boyd” on me for this prank. As for Tamar, she did a nice job explaining the basics of collections and then showed a strong practical example of their use: a VFP version of the popular Sudoku game that uses several collection to manage cells, blocks, rows, columns, and the game itself.

The last session of the day I attended was Toni Feltman’s The Pomodoro Technique session. I was looking forward to seeing this; Steve Bodnar had mentioned Pomodoro to me a couple of years ago so I was interested in learning what it was about. Toni discussed the problems of concentration and focus in a world of email, Twitter, Facebook, telephone calls, and teammate interruptions. Pomodoro was designed to allow you to plan your day in advance and focus on a set of tasks in 25-minute intervals, followed by a 3 to 5 minute break to catch up or relax before starting the next one. The idea is to boost your productivity by not letting distractions pull your concentration away from the tasks you need to get done without eliminating them completely. I know several attendees and speakers who’ve started using Pomodoro since seeing Toni’s presentation. I haven’t yet but hope to once I return from the German DevCon next week.

Rick, his wife Therese, his parents, and I went to a Mexican restaurant at the SanTan mall for an excellent dinner. I had something I’ve never tasted before: a chile relleno enchilada, which was REALLY good. However, the main event of the night was up next: racing at the F1 Race Factory. As usual, a good-sized crowd of Southwest Fox folk showed up for fun and competition. You can see photos from F1 taken by Venelina and Therese on the Southwest Fox photo page. For the past several years, Cathy Pountney, Rick, and I have had a friendly competition at F1 (“friendly” meaning there’s no exchange of gunfire). Cathy actually started it in 2006 by trashing Rick and I to all who’d listen after she beat us that year. Once again, the competition was fierce. None of us actually came in first (Rick Strahl is the perennial winner, followed this year by Cathy’s boyfriend Jim Knight), but we don’t care: it’s a race within a race for us. I had the fastest lap this year, followed by Rick and then Cathy. Because the F1 printer was down, we couldn’t see who had the fastest average lap (another measurement we use), so we assumed it was Rick since that’s a title he usually wins.

Afterward, we headed back to the hotel pool to regale the others with our stories: who took who into the wall, who cut off who in the corner, and so on. I called it a night a little after midnight.

Southwest Fox 2010: Day 1

I had an early start Friday, waking up at 5:30 a.m., partly because I was still on Central time and partly because I was going over in my mind the speeches I was to give at Sunday’s closing session for the FoxPro Lifetime Achievement Award presentations. Unfortunately, today was like sleeping in compared to the next two days.

The first session I attended was Paul Mrozowski’s jQuery for VFP Developers. Although I’ve seen a couple of introductory sessions on jQuery before, I have yet to do anything with it, which I hope to change soon. Paul’s session started by discussing the basics of JavaScript, then quickly moved into the jQuery library. He showed basic jQuery syntax, then discussed more complex uses, and finished the session showing some of the cool add-ons available for jQuery, including date-time controls and grids. This was a very inspiring session and made me wonder why I’ve waited so long to get started with jQuery.

Next I went to Extending VFP using the Web Browser Control, presented by Bo Durban. Although I’ve used the Web Browser ActiveX control in my apps for several years, I’m always looking for new ideas, and definitely got some in this session. Bo showed a subclass of the control he’s created that adds several behaviors, including disabling the shortcut menu so the user can’t do things like View Source. I got several great tips from this session and have already implemented them in my apps.

The last session of the morning was Eric Selje's The Amazing VFP2C32 Library. I wanted to see this session for two reasons: Eric was one of our new speakers and although I’ve had a little exposure to VFP2C32 (it’s used in Carlos Alloatti’s excellent Ctl32 library), I didn’t know much about it. Eric started by showing the complexities of calling some Windows API functions in VFP, and then showed how VFP2C32 makes it very easy because it simplifies the calls to those functions through an easy-to-use VFP wrapper. Because he was a little nervous, Eric stumbled on saying “VFP2C32” a couple of times, so he decided to call it “Fred” for the rest of the session. I liked that idea so much that when I mentioned VFP2C32 in my Themed Controls session (because Themed Controls uses Ctl32, which uses VFP2C32) and also stumbled saying it, I called it “Fred” too. Eric classified the various “Fred” functions by functionality and spent the rest of the session showing how it satisfies various needs in typical VFP applications. Eric’s white paper is an excellent resource for “Fred” because he’s documented the library in great detail. I definitely intend to replace some of my ugly Windows API calls with VFP2C32 functions since VFP2C32 is already included in my apps due to my use of Ctl32. Even cooler is thanks to prompting by Eric, the author of VFP2C32, Christian Ehlscheid, has now released it as a VFPX project.

After lunch, I presented my A Deep Dive into the VFPX ThemedControls session. I was a little nervous about this session: I’d practiced it several times and had it down smooth, but I went over the time limit every time because, typical for me, I tried to jam too much information into the session. Sure enough, I had only five minutes left at the end and still had a couple of the themed controls to cover. Fortunately, because I was prepared for this, I left the ones I consider to be less useful for the end, so I quickly skipped through them. Sorry for anyone who wanted to spend more time on those controls; however, the white paper for the session has lots of details and samples you can play with.

Although I didn’t plan this, it turned out that both of my sessions this year had a common theme: there’s no excuse for creating boring looking VFP apps. Using colorful modern icons, attractive fonts like Segoe UI (the system font for Windows Vista and 7), and various VFPX projects like GDIPlusX and ThemedControls, you can create applications that are as great looking as anything written in .Net or any other environment. As its name suggests, this session focused on Emerson Reed’s ThemedControls project. ThemedControls allows you to create themed forms in your application that allow the user to change color schemes as easily as they do in Microsoft Outlook. The image below uses several ThemedControls, including ThemedOutlookNavBar (the Outlook-like control at the left) and ThemedTitlePageFrame (the container at the right doesn’t look like a pageframe but it is).


I went through the basics of the ThemedControls library: how to download and install it, how to add it to your applications, what to deploy to your users, and so on. I then went through each of the controls, starting from the simple ThemedForm and ThemedContainer to the complex ThemedOutlookNavBar and ThemedExplorerBar, blowing through the less useful (in my opinion) ThemedToolbox and ThemedZoomNavBar, and finishing with a demo of the unfinished Ribbon control. Based on the audience feedback during the session and the evals afterward (I love the new online evals Rick, Frank, and Paul implemented this year!), I thought the session went well.

Because I was chatting with folks after my session, I was late getting to Christof Wollenhaupt’s How the Fox is Different session. However, as usual, Christof blew me away with his incredibly deep knowledge of the internals of both VFP and .Net. (After the session, Bill Anderson said to me, “I’ve been working with FoxPro for 20 years. I know nothing.” and I felt as equally humbled.) Christof’s take-away point was that if you’re working in VFP, do it the VFP way, and if you’re working in .Net, do it the .Net way. He showed fundamental differences between VFP and .Net, not in terms of language and syntax, which are relatively easy to learn, but in philosophy, which takes much longer to understand. For example, VFP is object based (we do things with instances of classes) while .Net is class based (classes have a much bigger role than instances in .Net). In VFP, we’re used to using a framework and global objects such as an application object; in .Net, the “framework” is built in and there are no global objects in correctly written applications. This is one of these sessions where I’m going to have to read the white paper several times and think about what Christof has said before it truly sinks in.

The last session of the day was dedicated to “bonus” sessions. I went to the “Show Us Your Apps, Part 1” session and was amazed as everyone else at the cool things people have done using VFP. Among the highlights were Jim Nelson showing his relatively new Code References replacement VFPX project, Cesar Chalom showing his FoxyPreviewer replacement for the VFP report preview toolbar, and Bernard Bout showing some work he’s done recently integrating Silverlight into VFP apps.

The plan was to have a dinner party out on the veranda of the conference center, but some unusual Phoenix weather—a sandstorm with high winds—nixed that at literally the last minute. Fortunately, the SanTan/Elegante staff quickly pulled together and moved everything inside the ballroom at record speed, so the party only started a few minutes late. The food, as it was at other meals, was fabulous, including two kinds of lasagna and an excellent caprese salad.

More bonus sessions followed into the evening. I held a Stonefield Query Developer meeting and went over some of the new features in our 4.0 version, including the brand new interface for Stonefield Query Studio (using many of the controls I covered in my ThemedControls and Cool Controls sessions), application views, new output types including Microsoft Excel PivotTable, and so on. I then showed a couple of new features we’re planning for version 4.1, including drilldown charts, dashboards, and % change between columns in a cross-tab. These got a very enthusiastic response!

The session didn’t wind up until nearly 10:00 p.m., so I was pretty tired by now. I hung out by the pool (the replacement for the “grotto” of the Arizona Golf Resort that became the popular hang-out spot the last couple of years) for a while, but had to call it a night at about 11:30 because I had an 8:30 session.

Saturday, October 23, 2010

Southwest Fox 2010: Pre-Conference

We had an early start on Thursday because registration opened at 7:45 and pre-conference sessions started at 9:00. Thanks to a streamlined registration process we came up with last year, registration was fast and easy. This year, in addition to the conference bag, sponsor materials, conference t-shirt, and other goodies, attendees could take any or all of three books generously provided by Hentzenwerke Publishing: Debugging Visual FoxPro Applications, The Software Developer's Guide, 3rd Edition, and FoxTales: Behind the Scenes at Fox Software. Registration is a fun time for me, as it’s a chance to meet new attendees and renew acquaintances with previous attendees and friends. We spent most of the day in the registration center, catching up on emails or chatting during slow times. Our first taste of the conference center food was a simple lunch of build-your-own sandwiches and salad, which was very tasty.

After the last pre-conference session ended, we met all the speakers at 4:30 for an orientation meeting. Many people were wondering how I was going to get even with Craig Boyd after his only mildly provoked Nerf gun assault on me last year (if you haven’t see it, look for “hennig swfox” on YouTube for one of the several videos available). For a variety of reasons, including the fact that he and I have both had a fairly challenging year personally and that his was about as close to the perfect prank as it comes and would be tough to top, I decided not to do much to him this year. In fact, he was quite concerned about what he thought I had planned, and that by itself seemed like fun. However, one surprise I had for him regarded the speaker shirt. Rick told him that due to his getting on board as the keynote speaker after we’d submitted the order for shirts, we didn’t have one for him. That, of course, was not true. We placed a special order of pink t-shirts for the female speakers this year, and included one for him in the order (we also ordered a regular shirt for him). It was fun seeing his face when I handed him his pink “speaker shirt”. Fortunately, Craig is a great sport and immediately agreed to wear it at the keynote.

After a quick bite to eat, it was time to get the conference started. We started the keynote thanking attendees for coming and pointing out that there were 99 attendees from 16 different countries this year, about a 15% increase from last year’s 87 from 7 countries. We then introduced the speakers and thanked sponsors and other folks who helped us out. After going over some logistics for the conference, I invited Cathy Pountney up to the front, where she presented Rick with the trophy for being the #1 ranked speaker last year. Even better, she filled the trophy with Rick’s favorite snack, Ding Dongs. Rick is a very humble person, so he was embarrassed and immediately pointed out that the difference between first and last is fractions of a point, sort of like the hundredths of a second that separates the fastest runners in the world at the Olympics.

After a few more logistical things, Rick presented the VFPX Administrators Award to Jim Nelson and Francis Faure for their contributions to the VFP community through their projects on VFPX. We then introduced the 2010 Ceil Silver Ambassadors, Bernard Bout and Cesar Chalom. As I’m sure is the case for many others, I was thrilled to meet them both, Cesar for the first time (Rick and I had previously met Bernard at OzFox 2007 in Sydney, Australia).

Finally, the moment everyone was waiting for: Craig Boyd’s keynote. Rick introduced Craig while a couple of funny pictures of Craig, one in bunny ears and the other in a headdress, showed on the screens. In fact, here they are in case you missed them:

image  image

Craig did not disappoint. He was his usual manic, hilarious self, showing doctored photos of Tamar as a warrior princess and Rick as an astronaut. However, he saved his best stuff for me, doing a twisted “This is Your Life” presentation. Rather than trying to describe it, it’s probably better if you just watch it: He then got into the real meat of his presentation: the value proposition of VFP. As a vivid demonstration of “value”, Craig and several volunteers blasted the room with thousands of pieces of paper, some of which had prizes written on them. The prizes ranged from an MSDN subscription worth almost $12,000 to “hug from Doug”, which several people did collect on and many of which are hoarding for future reimbursement. Craig did this to point out that although the paper was worthless, there was enough value in the prizes that everyone scrambled to pick them all up. He went on to discuss that although there are alternatives to VFP, you can still make a great living and create great solutions for your clients using this product we know and love. Thanks, Craig, for the best and most entertaining Southwest Fox keynote ever!

Afterward, we all congregated in the adjacent ballroom for the trade show reception. It gave everyone a chance to chat with the exhibitors, a couple of which (Christoph with his Guineu and AFP and Thierry Nivelet of FoxInCloud) were new this year, and hang out with new and old friends. A good-sized group then moved to the bar and pool area for the first of several nights of socializing. I packed it in about midnight after a very long day.

Southwest Fox 2010: Getting Ready

As per usual, Rick Schummer, his wife Therese, Tamar Granor, her husband Marshal, and I arrived in Phoenix on Tuesday, Oct. 12 to get ready for this year’s Southwest Fox conference. We spent Tuesday doing our usual errands: picking up shirts (speaker shirts, conference t-shirts, and polo shirts for those who’d ordered them), picking up sign boards for the rooms, etc. We also met Harold Wong of Microsoft to pick up some giveaways he offered us: a wireless keyboard and mouse, a copy of Windows 7, pens, etc.

While it seemed like we were doing our usual things this year, there were some differences. The main one is that I was keeping a big secret from Rick: while I’d previously told him that Lisa Slater Nicholls was the recipient of the 2010 FoxPro Lifetime Achievement Award, I didn’t tell him that he was also a recipient. This lead to a little bit of anxiety for me: I ordered the awards for the Lifetime Achievement recipients but also for the VFPX Administrators Award, which he was going to hand out. All of our materials are shipped to Frank Perez Sr. (the father of Frank Perez, one of Rick’s employees), who lives in the Phoenix area. Frank Sr. usually delivers the items Tuesday night. Last year, Rick didn’t call me when Frank Sr. arrived and instead loaded everything into his room. I was worried that Rick would see the awards box, open it, and spoil the surprise. Fortunately, Rick and Therese’s room was pretty full with boxes of shirts and materials they’d brought, so I innocently volunteered my room to hold the stuff Frank delivered. Besides, I told Rick, I needed to inventory the raffle prizes sent by the various sponsors.

I was also planning to keep it a secret from Therese, but a golden opportunity presented itself: Rick’s parents, Phil and Carole, were also in Phoenix so they could go to Sedona with Rick and Therese after the conference. It would be perfect if his parents could be there when I presented the award to Rick, so I told Therese about it and she promised to make sure they were at the closing session.

With all the plans in place, we went for a great dinner at the Cheesecake Factory (becoming a Tuesday night tradition with us), including Rick’s parents and Rick Strahl, who was in town for his pre-conference West Wind Web Connection training. As usual, we all turned in early because we had a long day; in Rick’s case, there was no Monday night as he didn’t sleep at all getting ready to leave.

We started Wednesday with a very nice breakfast at the hotel, then met the hotel staff for a briefing. I was a little nervous (which as you may start to realize was an ongoing thing for me this year) because we’d changed hotels very late in the game due to financial problems at our previous location. We’d been at the Arizona Golf Resort the past three years and their excellent service and commitment to ensuring things were perfect for us set the bar very high. That coupled with the fact that the new location, the Legado Hotel and SanTan Conference Center, had only been open for two months and we were their first large conference made me wonder how things would turn out. However, I was impressed at our meeting with the staff: in addition to the people we’d be dealing with daily (Monique, the head of catering, Keith, the operations manager, and the chef whose name I unfortunately forget), the general manager of the hotel and the owner of the property were both there.

We then started organizing for the conference: getting binders put together (we only needed 25 this year because most people went for the green option: the online conference guide), getting projectors set up, assembling bags, going over the opening and closing session contents, and so forth. We also discovered the first benefit of the new location: it’s very close to a large mall with a ton of restaurants, and there’s a free shuttle to and from the mall. We had a very nice lunch at the Paradise Bakery, which specializes in sandwiches, soup, and salads.

We spent the afternoon continuing our preparations, and started to see how committed the staff was to making sure things went well for us. In fact, over the next few days, we discovered that many of the staff worked longer hours than we did. We joked that they must have cots set up because we’d see Monique and Keith before 7:00 a.m. and after 10:00 p.m. at the conference center.

That evening, we met some of the attendees and speakers who started to arrive for the pre-conference day. We ended going out for dinner with a fairly large group at the Brio Italian restaurant at the mall. The meal and company were excellent. Thanks to Dave Hanna for being a good sport, making multiple trips between the hotel and mall with his car to accommodate all of us.

Friday, October 22, 2010

2010 VFPX Administrators Award

The VFPX Administrators Award is an annual award given by the VFPX Administrators (Craig Boyd, Rick Schummer, and Doug Hennig) to recognize those people who made outstanding contributions to the VFP community through their projects on VFPX. The nominees this year were:

  • Jim Nelson for his work on PEM Editor, Code References, and FoxChart Tools (add-ons)
  • David Holden for SubFox
  • Andrew Ross MacNeill for Code Analyst
  • Emerson Santon Reed for Themed Controls
  • Francis Faure for the VFP 9 SP2 Help file and VFP 9.0 Localization in French

At the keynote for Southwest Fox 2010, the awards were given to Jim Nelson and Francis Faure (to be delivered by Thierry Nivelet). You can watch a video of the keynote at

Congratulations to both Jim and Francis and thanks for all your efforts in making VFPX the future of VFP.

Wednesday, October 20, 2010

2010 Lifetime Achievement Award Recipients

It was my great pleasure to announce at Southwest Fox 2010 the recipients of the 2010 Lifetime Achievement Award: Lisa Slater Nicholls and Rick Schummer. The stars must have been perfectly aligned because Lisa’s husband, well-known FoxPro guru Colin, and Rick’s wife Therese and parents Phil and Carole were in attendance. I obviously had to tell Lisa in advance so she could come to Phoenix but Rick was taken completely by surprise. In fact, I’ve never seen him speechless before.

Congratulations, Rick and Lisa; I can’t think of more deserving people and in Lisa’s case, long overdue. Hopefully we'll have some video uploaded soon that shows them receiving their awards; check

Wednesday, October 06, 2010

Southwest Fox is Next Week

Southwest Fox 2010 starts next Thursday, October 14. However, I’m actually heading to Phoenix on Tuesday, as are Rick, Tamar, and their spouses Therese and Marshal, because we have lots of set up and finalizing to do. I’m going to be quite busy during the conference: in addition to my sessions A Deep Dive into the VFPX ThemedControls and Cool Controls for Your Applications, I’m also hosting a Stonefield Query Developer Meeting on Friday night at 8:30, showing some cool new features we’ve planned for version 4.1, and am showing a new VFPX project, FRXTabs, at the Show Us Your Apps session Friday afternoon at 5:15.

I’m looking forward to seeing old friends, meeting new ones, attending sessions, giving sessions, talking to this year’s Ceil Silver ambassadors, handing out the 2010 FoxPro Lifetime Achievement Award, and generally having a great time. See you there next week!

Final Thoughts on Looking at Stonefield Query

George Jensen of CustomerFX has concluded his series of posts about his experience learning Stonefield Query. Check out his articles: part 1, part 2, part 3, part 4, part 5, part 6, and part 7.

Friday, October 01, 2010

MVP Award for 2010

I am once again honored to be named a Microsoft Most Valuable Professional (MVP), for the 15th consecutive year. Congratulations to the other 14 award recipients (down significantly from previous years, I’m afraid); see for a complete list of VFP MVPs.


Thursday, September 16, 2010

Rehearsing is for professionals

Seth Godin’s recent blog post, Rehearsing is for cowards, makes the point that presentations work better when the presenter hasn’t rehearsed but rather “explores” the subject. That’s possibly true for presentations on soft subjects or those given from the heart, although I’d argue that you have to at least have a goal of hitting certain points and moving in a certain direction or else you’re just rambling. However, that’s just wrong for presenters doing technical topics.

Even those new to technical conferences, such as the upcoming Southwest Fox, can spot the difference between rehearsed and unrehearsed sessions. The former go smoothly, the latter are embarrassing and painful for everyone involved. “Hitches”, as Seth calls them, in a technical session do the opposite of “help[ing] us leap forward”. Instead, they convince the audience that either the presenter didn’t care enough about them or their own reputation to ensure they gave a quality session or that the topic is so difficult that even an expert can’t get it right.

One of the worst sessions I ever attended was by someone who had spoken before so had no excuse for his shoddy preparation. This clueless speaker spent half of the session looking for the menu items that lead to the dialogs he wanted to show. It was excruciating watching him move the mouse to the first item, move up and down the list, then move to the next one and repeat the process. Practicing the session even once would have eliminated that problem. The result: I got nothing from the session other than the resolution to never hear him speak again.

Fortunately, that’s not a problem you’ll encounter at Southwest Fox. Every speaker is a professional. By “professional”, I don’t mean someone who gets paid to speak. Rather, I mean someone who cares about their craft and their audience enough to work and polish and tune and hone their session until it’s as good as can be.

Now, I don’t think rehearsing means you don’t vary your sessions. Every time I present a session, I think of different ways to get the point across, different jokes to tell at certain places, and sometimes (not too often) even different samples to show. After all, you wouldn’t want to see a completely canned session given by a robot. In fact, I’d argue that practicing your session until you have it down cold gives you the freedom to improvise when appropriate because you have the confidence you can stay on track.

Southwest Fox starts four weeks from today and I can’t wait!

Monday, September 13, 2010

FoxPro Lifetime Achievement Award

The committee has selected multiple FoxPro Lifetime Achievement Award recipients for 2010. The names will be announced at the closing session (Sunday) of Southwest Fox in October and during the German DevCon in November. I will post in the various VFP forums (my blog, the Universal Thread, Foxite, FoxWiki, etc.) after each conference.

Thanks to everyone who submitted nominations.


Wednesday, September 08, 2010

More Southwest Fox News

We are disappointed that Craig Boyd will be unable to present at Southwest Fox 2010; we look forward to his return in the future. We are delighted that Jody Meyer has agreed to step in. She'll present two topics: Web Development using CSS - 101 and It's Easy & It's Green: PDF Output. Jody did a terrific job when she presented at last year's Southwest Fox and we're happy to have her back.

Listen to FoxShow #68, in which Eric Selje discusses his sessions on extending web applications with VFP and getting into the VFP2C32 library.

Amongst our more than $65,000 in door prizes are four copies of Visual Studio 2010 Ultimate with MSDN, worth $11,899 each!

Kevin Ragsdale has another gem in his series of posts on Southwest Fox, this time discussing the Ceil Silver Ambassador Fund.

Only five weeks until Southwest Fox!

Thursday, September 02, 2010

More Southwest Fox Links

Kevin Ragsdale has two more excellent blog posts about Southwest Fox sessions he’s been at in the past and what he’s looking forward to seeing this year: Christof Is A Freaking Genius and My Favorite Teacher Is Speaking At Southwest Fox.

The FoxShow has three episodes related to Southwest Fox: FoxShow #65, with Rick Schummer, Tamar Granor, and me discussing this year’s conference, FoxShow #66, in which Toni Feltman discusses her Lean/Agile and Pomodoro sessions, and FoxShow #67, in which Rick Borup discusses his Design Patterns and Ruby and Rails sessions. Andrew apparently has another one coming up featuring Eric Selje.

Southwest Fox starts six weeks from today. Have you registered yet?

More Looking at Stonefield Query

George Jensen of CustomerFX has added several more posts about his experience learning Stonefield Query. Check out his articles: part 1, part 2, part 3, part 4, and part 5.

Tuesday, August 31, 2010

Quote of the Conference

Kevin once again has a great blog post, this time about Tamar’s Southwest Fox session on business objects. His “kick me in the gut” moment was when Tamar pointed out that by separating user interface from business logic, you free your application from the limitations of the UI, making redesign and testing much easier (I’m paraphrasing and extrapolating from what Kevin said).

Like Kevin, I’m looking forward to Tamar’s Collections: Managing Information the Object-Oriented Way session at this year’s conference.

Friday, August 27, 2010

Southwest Fox 2010 Early-Bird Deadline Next Week

There is still time before September 1st to get in on the Early-Bird Registration for Southwest Fox 2010! The Early-Bird discount saves you $50 over our regular conference registration.

This year's conference, held October 14-17, includes 15 speakers, 26 different sessions in the main conference, 4 pre-conference topics, and a free one-day VFP to Silverlight post-conference workshop. Plus, if you're a member of a registered VFP user group, when you attend Southwest Fox, your user group receives $25.

In case you haven’t heard, we made a change in venue back in late July. The conference moved to a new location: SanTan Elegante Conference & Reception Center/Legado Hotel. Room rates are "run of the house" at $119 a night. You can find all the details at The room block for the conference is held through September 13th; after that room availability and pricing is determined by the hotel.

We are planning to add a "Show Us Your App" bonus session based on the success of the session the last couple of years.

Got suggestions? Got questions? Got registrations?, or you can call the Geek Gatherings' World Headquarters at 586.254.2530.

Read about the registration process and get the registration application here:

Follow the news about the conference on our blog:

Use our brochure to convince your boss (or spouse or SO) to let you go:

Only 48 days until we meet in Gilbert. Hope to see you there.

Wednesday, August 18, 2010

Two Great Reasons to Attend Southwest Fox

Kevin Ragsdale blogged about two good reasons to attend Southwest Fox this year. His reasons were the previews Bo Durban and Steve Ellenoff give for their Southwest Fox sessions. I especially liked these comments:

“During Bo’s session, my mind was spinning with new ways of approaching the web browser control in my apps. I couldn’t wait to get home so I could start working on them. Some of them I’ve already tried, and the speed increase on displaying HTML in my app is incredible. And this means Bo’s session alone is worth the cost of the conference to me.”

“In short, Steve’s done a ton of work that I have avoided like the plague.”

Of course, I think there’s a lot more than two good reasons: more like 200! One for each session (you learn a lot in each one), one for each speaker (you get to hang out with and pick the brains of the brightest VFP developers on the planet for free!), one for each attendee (networking with other developers is one of the most important reasons to attend any conference), plus the food, the fun (don’t forget go-karts this year!), and the gorgeous Phoenix weather.

If you haven’t already registered for Southwest Fox, check out the session line-up and who else is coming that you might like to meet or renew acquaintances with, then sign up for Southwest Fox before the September 1 early-bird deadline.

Monday, August 02, 2010

Looking at Stonefield Query

George Jensen of CustomerFX has been blogging about his experience learning Stonefield Query (specifically the SalesLogix version but it’s applicable to all versions). Check out his articles: part 1 and part 2.

Tuesday, July 13, 2010

2010 FoxPro Lifetime Achievement Award Nominations

The FoxPro Lifetime Achievement Award honors those individuals who have contributed a great deal to the FoxPro community over the years. See for previous award recipients.

These recipients wish to continue the award and have created a committee to select one or more recipients for 2010. The committee consists of previous recipients Whil Hentzen, Rick Strahl, Doug Hennig, Tamar Granor, and Rainer Becker, as well as Alan Griver (yag) of Microsoft and Naomi Nosonovsky representing the FoxPro community.

To submit your nominations for the 2010 recipients, please email me (dhennig AT stonefield DOT com) by August 15, 2010.

Stonefield Query 4.0 Released

We are pleased to announce the immediate release of the Stonefield Query SDK version 4.0. There are lots of new and improved features in version 4.0; see the Stonefield Query blog for details.

We have videos covering the new features in the SDK and in the Report Designer.

Wednesday, July 07, 2010

Why Community and Conferences are Important

Dave Aring of Visionpace just blogged about why community and attending conferences are important (his post is actually about solving a specific problem but the last two paragraphs are the key). Of course, he’s referring specifically to the VFP community, but I think it holds true in any community.

Friday, June 25, 2010

Gotcha with Custom Report Memberdata Attribute Names in VFP 9 SP 2

(That must be the longest blog title in history!)

I’ve been (finally) implementing VFP 9 SP2 features in Stonefield Query (version 4.0 is due to be released next week) and, while doing some final testing, ran into an error when editing a certain object in the Report Designer. The error was 1712, “Field name is a duplicate or invalid”. In tracking the error down, it occurred in the XMLStrToCursor method of _FRXCursor, one of the report helper classes in the FFC. The statement causing the error was ALTER TABLE … ADD COLUMN … It’s not actually a table that columns are being added to but a cursor. The weird thing is that the columns being added didn’t exist in the cursor, so they certain weren’t duplicates.

I tweeted about this and Frank Perez Jr. responded “I think you also get that error if the field name is invalid (i.e. more than 10 characters in a free table).” Sure enough, that was the problem. Even though cursors can have field names longer than ten characters, ALTER TABLE can’t handle them, and given that there’s no ALTER CURSOR command, we’re stuck with it.

What lead to the error was that I added custom report memberdata to the specific object causing the problem. The custom memberdata had an attribute named “adjustwidth”, which is more than ten characters long. Changing it to “adjwidth” solved the problem. So, important safety rule (channelling Venkman here): don’t use names more than ten characters for your custom report memberdata attributes.

Thanks to Frank for pointing me in the right direction. Another reminder of the usefulness of Twitter.

Thursday, June 24, 2010

2010 Ceil Silver Ambassadors

Yes, that title is plural: thanks to the generosity of the VFP community, we have enough money to bring two developers to Southwest Fox as 2010 Ceil Silver Ambassadors. Geek Gatherings is pleased to announce that César Chalom and Bernard Bout have been selected as the ambassadors for Brazil and Australia, respectively. We are very excited that César and Bernard can attend Southwest Fox 2010 and know that many attendees are looking forward to meeting them in person.

Tuesday, June 15, 2010

Southwest Fox on the FoxShow

Andrew MacNeill interviews Rick Schummer, Tamar Granor, and I about Southwest Fox 2010 in FoxShow #65. As usual, it was a fun interview and he asked lots of interesting questions about what attendees can expect to see.

Friday, June 04, 2010

New VFP 9 SP2 and Sedna Book Available

After a really long time in gestation, “Making Sense of Sedna and SP2” has finally been published by dFPUG in both English and German. This book, co-authored by Tamar E. Granor, Toni Feltman, Cathy Pountney, Rick Schummer, Bo Durban, and me, goes into tremendous depth on VFP 9 Service Pack 2 and Sedna, including installation gotchas, things that work, things that almost work, and how to make the use of the new features in both products. “Making Sense of Sedna and SP2” is available now from Hentzenwerke Publishing as an e-book and will be available in printed version in July.


Friday, May 14, 2010

New FoxShow

Good news, everyone (any Futurama fans out there?): Andrew MacNeill has a new FoxShow discussing integrating VFP and Silverlight with Uwe Habermann. Uwe and Venelina Jordanova are presenting several sessions on this topic at Southwest Fox 2010, including a free one-day post-conference workshop I’m sure will be very popular (I’m planning on attending it).

Performing Queries Asynchronously

VFP makes it easy to perform asynchronous queries against remote databases such as SQL Server. Why would you want to do that? With a synchronous query (the default), you have to wait until SQLEXEC() returns before you can execute any other code. What if you want to display the progress of record retrieval? What if you want to give the user the opportunity to stop a long query, especially if they realize they made a mistake and don’t want to wait a long time and retrieve a lot of records because of it? Asynchronous queries give you these abilities because execution returns to VFP after retrieving a configurable number of records.

You can switch to async mode any time, even after opening a connection, using SQLSETPROP(). You likely also want to configure how many records to retrieve at a time using CURSORSETPROP(). Here’s an example (this code assumes the connection handle is stored in lnHandle and lnAsyncRecords contains the number of records to retrieve):

sqlsetprop(lnHandle, 'Asynchronous', .T.)
cursorsetprop('FetchSize', lnAsyncRecords, 0)

You might also want to set the packet size; you may have to use trial and error to determine the optimum size for your network:

sqlsetprop(lnHandle, 'PacketSize', 12288)

When you’re in async mode, you have to retrieve records in a loop until either the query finishes or you decide to cancel it. You can tell when SQLEXEC() has completed because it returns a non-zero value; positive means it was successful, negative means it failed for some reason. You can also check to see how many records were retrieved on each pass by passing an array to SQLEXEC(); the second element in that array contains the number of records.

Here’s an example. This code assumes the SQL statement to execute is in lcSelect, the cursor to put the results into is in lcCursor, and the connection handle is in lnHandle. The commented area is where you’ll put code specific to your application to see if the user wants to cancel, such as if they click the Cancel button in a progress dialog you’ve displayed (such a dialog could also show the total number of records retrieved so far; that value is in lnCount). Once the loop is done, llReturn is .T. if the query succeeded, llCancelled is .T. if the user cancelled the process, and lnCount is the total number of records fetched (which of course you can also get from RECCOUNT(lcCursor)).

llDone      = .F.

lnCount     = 0

llCancelled = .F.
llReturn = .F.
do while not llDone
lnStatus = sqlexec(lnHandle, lcSelect, lcCursor, laInfo)
    if lnStatus <> 0
llDone   = .T.
        llReturn = lnStatus > 0
    endif lnStatus <> 0
    if laInfo[2] > 0
lnCount = lnCount + laInfo[2]
* see if user wants to cancel e.g. press Esc or click Cancel
* set llContinue to .F. if we’re supposed to cancel
        if not llContinue
            llDone      = .T.
            llReturn    = .F.
            llCancelled = .T.
        endif not llContinue
    endif laInfo[2] > 0
enddo while not llDone

There’s one caveat to this approach: some database engines don’t like it when you use SQLCANCEL() on the connection handle. With Pervasive, for example, the next time you use SQLEXEC(), you get an “invalid cursor state” error. The only solution in that case is to close and reopen the connection.

Fortunately, there’s a workaround for this. Rather than performing a query on the connection handle, use a new statement handle. To do that, start by making the connection handle sharable by passing .T. as the last parameter in SQLCONNECT() or SQLSTRINGCONNECT(). Then, just before starting the loop, get a new statement handle by calling SQLCONNECT() with the existing connection handle. In the following code, assume the connection handle is stored in lnConnectionHandle rather than in lnHandle:

lnHandle = sqlconnect(lnConnectionHandle)

Now SQLEXEC() is using a new statement handle shared from the original connection handle.

At the end of the loop, close the statement handle using SQLDISCONNECT(lnHandle); that doesn’t disconnect the connection, it just frees the resources used by the statement handle.

Tuesday, May 04, 2010

Southwest Fox 2010 News

Some exciting news about Southwest Fox 2010:

  • Speakers and sessions have been announced. Organizers once again had a very tough time selecting from the excellent submissions. I’m personally really looking forward to the Windows 7 sessions presented by Craig Boyd and Steve Ellenoff and Bo Durban’s Direct2D session. Actually, I want to see every session, but of course that’s not possible. Thank goodness one of the requirements of speaking at Southwest Fox is providing white papers so you still get the content from every session, even those you miss.
  • New this year is a Web Development track with seven regular sessions, two pre-conference sessions, and four post-conference sessions (see below) in this track alone.
  • We also have three new (well, new to Southwest Fox) speakers, continuing our tradition of trying to invite new speakers every year: Kevin Cully, Uwe Habermann, and Venelina Jordanova. Kevin is likely familiar to many people, as he has attended Southwest Fox before and hosted a conference himself a few years ago. Although Uwe and Venelina are new to North American conferences, they both are veteran speakers at European conferences, including both German and Prague DevCons.
  • A free one-day "VFP to Silverlight" workshop is being held the day after Southwest Fox ends (Monday, October 18), sponsored by the German FoxPro User Group (dFPUG) and presented by Uwe and Venelina. I’m planning on attending this and suspect it’ll be very popular.
  • Southwest Fox platinum sponsor Tomorrow's Solutions, LLC is offering a scholarship of $150 for one new attendee. Also, White Light Computing has changed their scholarship to cover TWO attendees this year.

See you in Phoenix in October!

Tuesday, March 30, 2010

Fixing a Report Designer Bug

A bug in the VFP Report Designer has always, ahem, bugged me: something seems to turn on the Printer Environment setting for a report. Unless you want a report to always use a certain printer, that setting should be off. Turning it on can make a report much slower to open (for example, if the printer saved with the report isn’t available on your system) and can cause other problems.

I don’t remember who discovered this (sorry) but the cause turned out to be clicking the font button in the Field or Label Properties dialogs, even if you then choose Cancel. But how would that affect the Printer Environment setting?

Tired of having to deal with this, I decided to track it down. Fortunately, the source code for the Report Designer dialogs is included with VFP (unzip HOME() + “TOOLS\XSource\XSource.ZIP” and look in the resulting VFPSource\ReportBuilder folder). After some digging, I found the culprit in the ChooseFont method of FRXFormatUtil (in FRXBuilder.VCX), which is called when you click the font button. That method checks whether the TAG memo field in the header record of the FRX is empty or not. If not, it uses SYS(1037, 3) to update TAG and TAG2 from the current printer environment (the code is actually in FRXCursor.PopPrintEnv, which ChooseFont calls). The idea is that if the report has a saved printer environment, that environment should be used since it may impact which fonts are available. However, here’s the bug: TAG may not be empty even when TAG2 (which contains the binary printer environment) is. I’ve seen a single CHR(8) in TAG when TAG2 is empty, which means there is no saved printer environment, but it passes the NOT EMPTY(TAG) check in ChooseFont so the printer environment of the report is overwritten.

The solution is simple: change the test in ChooseFont from IS NOT EMPTY(TAG) to IS NOT EMPTY(TAG2), then rebuild ReportBuilder.APP. I’ve already made this change in the upcoming Stonefield Query version 4.0.

Wednesday, March 17, 2010

Taking out the Slow Parts, Again

While looking up something else, I came across Brad Martinez’s article on extending the functionality of the TreeView control. One of his points about how to load the TreeView more quickly caught my eye:

Make sure the parent Node's Sorted property is set to False: If Sorted = True, the TreeView must sort every Node as it is added under the parent Node. Make Sorted = True after all child Nodes are added.

I wondered how much of an improvement it would make, so I changed some generic TreeView loading code I use in lots of places to follow his advice. Loading 1,329 nodes dropped from 4.128 to 0.533 seconds, which is almost eight times faster!

As I’ve said before, I love taking out the slow parts!

Monday, February 22, 2010

TRY … CATCH and text merge

I recently ran into a problem with some text merge code. Under certain conditions, the text merge file contained only the first part of the text being output. I had a hard time tracking it down until I found this article in which someone else ran into the same problem. The culprit was a function I called from within the text merge code; that function has a TRY … CATCH structure and under some conditions, an error occurred and the CATCH caught it. The issue is that when CATCH fires, it sets _TEXT, the variable containing the handle for the text merge output file, to –1, preventing further output to the file.

The solution is to save the current value of _TEXT, set it to –1, execute the code with the TRY … CATCH structure, and reset _TEXT to the saved value at the end. Temporarily setting _TEXT to –1 prevents the file from being closed if an error occurs.

lnText = _text
_text = -1
* some code here
* some code here
_text = lnText

Thursday, February 04, 2010

A Replacement for FULLPATH()

Are you as annoyed as I am that FULLPATH() returns the full path for a file as upper-case? That makes it a little hard to respect the case of a user-entered filename. Fortunately, the GetFullPathName Windows API function doesn’t change the case. Here’s a little function that accepts a filename and returns the full path using that API function:

lparameters tcName
local lcBuffer1, ;
lcBuffer2, ;
#define MAX_PATH 260
declare long GetFullPathName in Win32API ;
string lpFileName, long nBufferLength, string @lpBuffer, ;
string @lpFilePart
store space(MAX_PATH) to lcBuffer1, lcBuffer2
lnLen = GetFullPathName(tcName, MAX_PATH, @lcBuffer1, @lcBuffer2)
return left(lcBuffer1, lnLen)

Wednesday, February 03, 2010

Multiple Monitor Class

Almost three years ago, I wrote a blog post on handling multiple monitors. Since then, I’ve refactored the code so all the monitor-handling code is in one place.

There are actually two classes: SFSize, which simply has properties that represent the dimensions of a monitor, and SFMonitors, which does the work. SFMonitors is actually a subclass of SFSize because it uses those same properties for the virtual desktop (all combined monitors if there’s more than one).

Here’s the code for SFSize:

define class SFSize as Custom
nLeft = -1
nRight = -1
nTop = -1
nBottom = -1
nWidth = 0
nHeight = 0

function nLeft_Assign(tnValue)
This.nLeft = tnValue

function nRight_Assign(tnValue)
This.nRight = tnValue

function nTop_Assign(tnValue)
This.nTop = tnValue

function nBottom_Assign(tnValue)
This.nBottom = tnValue

function SetWidth
with This
.nWidth = .nRight - .nLeft

function SetHeight
with This
.nHeight = .nBottom - .nTop

SFMonitors has several methods. Init sets up the Windows API functions we’ll need and gets the dimensions for the primary monitor:

define class SFMonitors as SFSize
nMonitors = 0
&& the number of monitors available

function Init
local loSize

* Declare the Windows API functions we'll need.

declare integer MonitorFromPoint in Win32API ;
long x, long y, integer dwFlags
declare integer GetMonitorInfo in Win32API ;
integer hMonitor, string @lpmi
declare integer SystemParametersInfo in Win32API ;
integer uiAction, integer uiParam, string @pvParam, integer fWinIni
declare integer GetSystemMetrics in Win32API integer nIndex

* Determine how many monitors there are. If there's only one, get its size.
* If there's more than one, get the size of the virtual desktop.

with This
.nMonitors = GetSystemMetrics(SM_CMONITORS)
if .nMonitors = 1
loSize = .GetPrimaryMonitorSize()
.nRight = loSize.nRight
.nBottom = loSize.nBottom
store 0 to .nLeft, .nTop
.nLeft = GetSystemMetrics(SM_XVIRTUALSCREEN)
.nTop = GetSystemMetrics(SM_YVIRTUALSCREEN)
.nRight = GetSystemMetrics(SM_CXVIRTUALSCREEN) - abs(.nLeft)
.nBottom = GetSystemMetrics(SM_CYVIRTUALSCREEN) - abs(.nTop)
endif .nMonitors = 1

GetPrimaryMonitorSize returns an SFSize object for the primary monitor. Note that this takes into account the Windows Taskbar and any other desktop toolbars, which reduce the size of the available space.

  function GetPrimaryMonitorSize
local lcBuffer, ;
lcBuffer = replicate(chr(0), 16)
SystemParametersInfo(SPI_GETWORKAREA, 0, @lcBuffer, 0)
loSize = createobject('SFSize')
with loSize
.nLeft = ctobin(substr(lcBuffer, 1, 4), '4RS')
.nTop = ctobin(substr(lcBuffer, 5, 4), '4RS')
.nRight = ctobin(substr(lcBuffer, 9, 4), '4RS')
.nBottom = ctobin(substr(lcBuffer, 13, 4), '4RS')
return loSize

Pass GetMonitorSize X and Y coordinates and it’ll figure out what monitor contains that point and return an SFSize object containing its dimensions, again accounting for the Taskbar.

  function GetMonitorSize(tnX, tnY)
local loSize, ;
lhMonitor, ;
loSize = createobject('SFSize')
lhMonitor = MonitorFromPoint(tnX, tnY, MONITOR_DEFAULTTONEAREST)
if lHMonitor > 0
lcBuffer = bintoc(40, '4RS') + replicate(chr(0), 36)
GetMonitorInfo(lhMonitor, @lcBuffer)
with loSize
.nLeft = ctobin(substr(lcBuffer, 21, 4), '4RS')
.nTop = ctobin(substr(lcBuffer, 25, 4), '4RS')
.nRight = ctobin(substr(lcBuffer, 29, 4), '4RS')
.nBottom = ctobin(substr(lcBuffer, 33, 4), '4RS')
endif lHMonitor > 0
return loSize

SFMonitors uses the following constants:


#define SM_XVIRTUALSCREEN 76 && virtual left
#define SM_YVIRTUALSCREEN 77 && virtual top
#define SM_CXVIRTUALSCREEN 78 && virtual width
#define SM_CYVIRTUALSCREEN 79 && virtual height
#define SM_CMONITORS 80 && number of monitors

Here’s some code that uses SFMonitors. Code (not shown here) before the following code reads a form’s previous Height, Width, Top, and Left from somewhere (such as the Registry) from the last time the user had it open into custom nHeight, nWidth, nTop, and nLeft properties, and then sizes and moves the form (referenced in loForm) to those values. This code makes sure the form isn’t off the screen, which can happen if, for example, the user had the form open on a second monitor but now only has one monitor, such as an undocked laptop. Note that this code uses several SYSMETRIC() functions to determine the height and width of the window border and title bar, since those values aren’t included in a form’s Height and Width. Also note in the comment a workaround for a peculiarity with an “in top-level form” being restored to a different monitor than the top-level form it’s associated with.

loMonitors = newobject('SFMonitors', 'SFMonitors.prg')

* For desktop or dockable forms, get the size of the virtual desktop. If
* there's only one monitor, use the primary monitor size. Otherwise, use the
* size of whichever monitor the form is on.

if pemstatus(loForm, 'Desktop', 5) and (loForm.Dockable = 1 or ;
loForm.Desktop or loForm.ShowWindow = 2)
if loMonitors.nMonitors = 1
loSize = loMonitors
loSize = loMonitors.GetMonitorSize(.nLeft, .nTop)
endif loMonitors.nMonitors = 1
lnMaxLeft = loSize.nLeft
lnMaxTop = loSize.nTop
lnMaxWidth = loSize.nWidth
lnMaxHeight = loSize.nHeight
lnMaxRight = loSize.nRight
lnMaxBottom = loSize.nBottom

* For any other forms, use the size of _screen.

lnMaxLeft = 0
lnMaxTop = 0
lnMaxWidth = _screen.Width
lnMaxHeight = _screen.Height
lnMaxRight = lnMaxWidth
lnMaxBottom = lnMaxHeight
endif pemstatus(loForm ...

* Only restore Height and Width if the form is resizable.

llTitleBar = pemstatus(loForm, 'TitleBar', 5) and loForm.TitleBar = 1
lnBorderStyle = iif(pemstatus(loForm, 'BorderStyle', 5), ;
loForm.BorderStyle, 0)
if lnBorderStyle = 3
loForm.Width = min(max(.nWidth, 0, loForm.MinWidth), lnMaxWidth)
loForm.Height = min(max(.nHeight, 0, loForm.MinHeight), lnMaxHeight)
endif lnBorderStyle = 3

* Calculate the total width of the form, including the window borders.

if llTitleBar
lnTotalWidth = loForm.Width + ;
iif(loForm.BorderStyle = 3, sysmetric(3), sysmetric(12)) * 2
lnTotalWidth = loForm.Width + ;
icase(lnBorderStyle = 0, 0, ;
lnBorderStyle = 1, sysmetric(10), ;
lnBorderStyle = 2, sysmetric(12), ;
sysmetric(3)) * 2
endif llTitleBar
do case

* If we're past the left edge, move it to the left edge.

case .nLeft < lnMaxLeft
loForm.Left = lnMaxLeft

* If we're past the right edge of the screen, move it to the right edge.

case .nLeft + lnTotalWidth > lnMaxRight
loForm.Left = lnMaxRight - lnTotalWidth

* We're cool, so put it where it was last time. If this form has ShowWindow
* set to 1-In Top-Level Form and the current top-level form is on a
* different monitor than the saved position, do this code twice; the first
* time, it gives a value that places the form on the wrong monitor but it
* works the second time.

loForm.Left = .nLeft
loForm.Left = .nLeft

* Calculate the total height of the form, including the title bar and window
* borders.

if llTitleBar
lnTotalHeight = loForm.Height + sysmetric(9) + ;
icase(lnBorderStyle = 3, sysmetric(4), sysmetric(13)) * 2
lnTotalHeight = loForm.Height + ;
icase(lnBorderStyle = 0, 0, ;
lnBorderStyle = 1, sysmetric(11), ;
lnBorderStyle = 2, sysmetric(13), ;
sysmetric(4)) * 2
endif llTitleBar
do case

* If we're past the top edge, move it to the top edge.

case .nTop < lnMaxTop
loForm.Top = lnMaxTop

* If we're past the bottom edge of the screen, move it to the bottom edge.
* Note that we have to account for the height of the title bar and top and
* bottom window frame.

case .nTop + lnTotalHeight > lnMaxBottom
loForm.Top = lnMaxBottom - lnTotalHeight

* We're cool, so put it where it was last time.

loForm.Top = .nTop

Wednesday, January 20, 2010

My First HTML Help Builder Add-In

Although I’ve used West Wind HTML Help Builder to create HTML Help (CHM) files for my applications for more than 10 years, and have done lots of advanced things such as supporting dynamic text and generating help projects programmatically, I haven’t created an add-in for it. HTML Help Builder supports add-ins using a simple mechanism: once you’ve registered an add-in, it appears in the Tools, Add-Ins menu, ready to run whenever you need it.

The add-in I created does two things:

  • Fixes the icon for the INDEX topic. Every HTML Help Builder project has one topic of type INDEX, and I use that as the “welcome to this help file” topic. Unfortunately, when it builds the CHM, HTML Help Builder uses the wrong icon for that topic. I always had to manually run HTML Help Workshop, edit the icon for that topic (from “11” to “auto”), and rebuild the CHM file. My add-in does that automatically.
  • Turns on searching for the HTML content. In addition to providing CHM files, we post our help files as HTML on our Web site (for example, the Stonefield Query SDK help file), both so Google can index it and so we can provide links to help topics in support messages without having to say “open the help file, open the “How To” heading, then navigate to the “Whatever” topic”. HTML Help Builder recently added a search function to the HTML files it generates, but the generation of that function is turned off by default and I often forget to turn it on. My add-in automatically changes one of the generated files to enable search.

Add-ins can be VFP code (PRG or APP/EXE), a .Net assembly, or a COM object. You register an add-in using the Tools, Add-In Manager function. This is the only cumbersome part of the process: because the add-ins registry table (AddIns.DBF) is stored in the program folder, under Vista or Windows 7 it’s read-only, so you have to launch HTML Help Builder as administrator. Perhaps in a future release, author Rick Strahl will move this file to a writable folder so this isn’t necessary.


In my case, I created a class named FixHelp in FixHelp.PRG, and put the code for the add-in into the Activate method. Here’s the code for the class (thanks to Chris Wolf for handling the 64-bit stuff). It should be easy enough to follow.

#define CSIDL_PROGRAM_FILES 0x0026
#define HKEY_LOCAL_MACHINE -2147483646

define class FixHelp as custom
function Activate(toHelpForm)
local loHelp, ;
lcProjectFile, ;
lcPath, ;
lcFile, ;
lcText, ;
lcProgramFiles, ;
lcRegVCX, ;
loRegistry, ;
lcKey, ;
llGotPath, ;

* Get a reference to the help object, then figure out the path for the
* current project.

loHelp = toHelpForm.oHelp
lcProjectFile = loHelp.cFileName
lcPath = addbs(justpath(lcProjectFile))

* Turn on searching in case it wasn't turned on when the files were
* generated.

lcFile = lcPath + 'index2.htm'
lcText = filetostr(lcFile)
lcText = strtran(lcText, 'var AllowSearch = false;', ;
'var AllowSearch = true;')
strtofile(lcText, lcFile)

* Remove the image number for the root node so it defaults to "auto".

lcFile = forceext(lcProjectFile, 'hhc')
lcText = filetostr(lcFile)
lcText = strtran(lcText, '' + ;
chr(13) + chr(10), '', 1, 1)
strtofile(lcText, lcFile)

* Find the location of HTML Help Workshop. Try the 32-bit registry key
* first. If that doesn't work, try the 64-bit key.

lcProgramFiles = This.GetSpecialFolder(CSIDL_PROGRAM_FILES)
lcRegVCX = addbs(lcProgramFiles) + ;
'Microsoft Visual FoxPro 9\FFC\Registry.vcx'
loRegistry = newobject('Registry', lcRegVCX)
lcPath = ''
lcKey = '\Microsoft\Windows\CurrentVersion\App Paths\hhw.exe'
llGotPath = loRegistry.GetRegKey('Path', @lcPath, ;
if not llGotPath
llGotPath = loRegistry.GetRegKey('Path', @lcPath, ;
'\SOFTWARE\Wow6432Node' + lcKey, HKEY_LOCAL_MACHINE) = 0
endif not llGotPath

* Compile the CHM file if we found it. Log the results.

if llGotPath
lcPath = This.ShortPath(forcepath('hhc.exe', lcPath))
lcProjectFile = '"' + forceext(lcProjectFile, 'hhp') + '"'
lcLogFile = '"' + addbs(justpath(lcProjectFile)) + 'log.txt"'
erase (lcLogFile)
run &lcPath &lcProjectFile > &lcLogFile
if file(lcLogFile)
declare integer ShellExecute in SHELL32.DLL ;
integer nWinHandle, string cOperation, string cFileName, ;
string cParameters, string cDirectory, integer nShowWindow
ShellExecute(0, 'Open', lcLogFile, '', '', 1)
erase (lcLogFile)
endif file(lcLogFile)
messagebox('Cannot locate HTML Help Workshop')
endif llGotPath
return .T.

* Get the short (8.3) path for the specified path.

function ShortPath(tcPath)
local lcPath, ;
lnLength, ;
lcBuffer, ;
declare integer GetShortPathName in Win32API ;
string @lpszLongPath, string @lpszShortPath, integer cchBuffer
lcPath = tcPath
lnLength = 260
lcBuffer = space(lnLength)
lnResult = GetShortPathName(@lcPath, @lcBuffer, lnLength)
return iif(lnResult = 0, '', left(lcBuffer, lnResult))

* Get the location of the specified "special" folder.

function GetSpecialFolder(tnFolder)
local lcSpecialFolderPath, ;
lcSpecialFolderPath = space(255)
declare SHGetSpecialFolderPath in shell32.dll ;
long hwndOwner, string @cSpecialFolderPath, long nWhichFolder
SHGetSpecialFolderPath(0, @lcSpecialFolderPath, tnFolder)
lcPath = alltrim(lcSpecialFolderPath)
return lcPath

Now when I want to generate a help file, I click Build Help, select the “Don’t build Help file” option (since my add-in will generate the CHM, there’s no need to do it twice), and let it run. I then choose Tools, Add-Ins, Generate Help File (my add-in) to tweak the generated files and build the CHM. There’s a couple of less manual tasks for my build process.