Saturday, February 16, 2008

Fixing FrameMaker

It is generally accepted that FrameMaker is one of the best tools for reliably authoring long documents. In this category of software, Microsoft Word isn't even a contender. Yet for all FrameMaker's many strengths, it still suffers from some rather annoying problems that can really throw a spanner into the works that is your writing. One of these FrameMaker problems is the size of some of its dialog windows, especially those used for selecting conditional text settings.

The main problem with these windows is that they are too small to show the full name of defined conditions. To add insult to injury, these dialog windows are not even resizable. What this means, in all practicality, is that if you have multiple conditions that share the first few characters, you will not be able to differentiate the conditions using Frame's dialog windows.

For example, the documents I work on have gone through several technical writers, share content for a variety of outputs (PDF and online Help) and between application families. In an effort to reign in the conditional text chaos, we've standardized our conditional text names. Now, all conditional text names use the following convention "mc_f__". Some typical conditions would be:
  • mc_f_app1_ug
  • mc_f_app1_ug_mac
  • mc_f_app1_ug_win
  • mc_f_app1_uag
  • mc_f_app1_uag_mac
  • mc_f_app1_uag_win
  • mc_f_app2
Granted, this convention is less than ideal for a number of reasons, but it was a big step forward from the hodgepodge of different conditions used previously.

Below is a screen capture of the Show/Hide Conditional Text dialog used to select which conditions to show in a document:

As you can see, this dialog is worse than useless...it is downright frustrating to use. The cells for Show and Hide just don't provide enough horizontal space to show the full names of the conditions. Fortunately, with a little resourcefulness and careful planning, you can resize these windows to just about any size that works for you. All you need is a little application called Resource Hacker and some patience.

Fixing FrameMaker with Resource Hacker
The first thing you'll need to do is to download Resource Hacker. This free tool is available from many sites offering freeware for download. The link at the bottom is just one such site.

Resource Hacker allows you to edit various program resource files (like .dll files) that contain the properties for many of the dialog (and other) windows used in an application. Fortunately for us, the FrameMaker's conditional dialog windows are housed in one such DLL.

Before editing the DLL in question, you first need to find it and make a safe backup copy of it that you can revert to in case of unforeseen problems. Mind you, I've been using a modified version of this DLL for quite some time and have yet to encounter any problem. . .but as with any such modification, your mileage may vary and there is no guarantee that such "hacks" won't result in a core meltdown of your computer, an increase in global warming, the downfall of western civilization, a rise in communism, inflation, etc... Be warned.

So now that you've been warned, here's the info you need to get started. The file you want is called fmdlg.dll and it is usually found in the following location:

C:\Program Files\Adobe\FrameMaker+SGML6.0\fminit\fmdlg.dll

Once you've made a backup copy of it, fire up Resource Hacker. Once it opens, navigate to and open the abovementioned fmdlg.dll file. You'll see that Resource Hacker utilizes the familiar tree/properties presentation scheme where the navigation tree on the left side of the screen allows you to choose between the various resources included in the DLL file while the right side details pane presents information on the selected resource.

Expand the "Dialog" root and look for the COND_TEXT and COND_VISIBILITY branches. These are the two branches that contain the resources for the FrameMaker dialogs for applying conditional text and for showing and hiding conditional text.

Expanding the COND_TEXT and COND_VISIBILITY branches reveals a resource numbered "1033" in each. I don't know what this number signifies. Perhaps it is the answer to life, the universe, and everything. Perhaps it is the number of angels that can dance on the head of a pin. Or perhaps it has some other more mundane significance. In any case, the number isn't important. The fact is that when you click the number, the details for the corresponding dialog window appear in the details pane of Resource Hacker and an editable preview of the selected dialog window also appears below.

Lets edit the Show/Hide Conditional Text window first, since it obscures more of the conditional tags and (AFAIK) there is no hotkey combination for revealing and hiding conditions equivalent to those used to apply and remove conditions. Without full visibility of your conditions, this window is indeed useless.

The first thing you'll need to do, if you haven't already, is click the "1033" resource in the "COND_VISIBILITY" branch of the Dialogs root in Resource Hacker. The result should be nearly identical to the screen capture above: the properties of the dialog will be displayed in the details pane of resource hacker and an editable preview of the dialog will appear at the bottom. (If you don't immediately notice the preview, check the lower right corner of your screen. For some reason on my machine, this is the default preview location for resources opened in Resource Hacker.)

You can resize the window either by dragging and moving the objects in the preview, or by editing the text in the details view of resource hacker. I'm going to leave it up to you which way you do it. Editing the text is faster for an expert, but if you are new to Resource Hacker, you'll probably want to expirament by resizing in the preview. Just one word of note, when you select an object or control in the preview, a red asterisk will appear next to the object's information line in the details pane. This will allow you to correlate which controls correspond to what information in the preview pane. Change a control (or window's) dimensions in the preview pane will change the information in the control or window's infromation in the preview pane correspondingly. Conversely, changing values directly in the details pane does not immediately update the preview. To see your changed values, you'll need to click the Compile Script button atop the details pane.

After some hacking, here is what I achieved: A window roughly twice as large in both the horizontal and vertical directions As you can see, I've resized the Show and Hide list boxes proportionally.

Once you've finished mucking around with your window, it's time to save your changes back to the fmdlg.dll file and test them out in FrameMaker. This is done by clicking Save in the file menu of Resource Hacker.

Now, the result in FrameMaker:

Ahhh... much better. Finally, I can see the full text of each condition. This makes selecting the which conditional text to show and hide much easier.

By following the same principals, I can resize the Conditional Text window as well:

If you like how I've resized these windows, you can achieve the same results by replacing the details text in Resource Hacker with the appropriate text below, clicking Compile Script, and saving the results.

Conditional Text Dialog Settings


COND_TEXT DIALOG 33, 49, 400, 194
STYLE DS_MODALFRAME | WS_CLIPSIBLINGS | WS_CAPTION
CAPTION "Conditional Text"
LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
FONT 8, "MS Sans Serif"
{
CONTROL "Current Selection Is:", 104, STATIC, SS_LEFTNOWORDWRAP | WS_CHILD | WS_VISIBLE | WS_GROUP, 3, 2, 188, 9
CONTROL "&Unconditional", 105, BUTTON, BS_AUTORADIOBUTTON | WS_CHILD | WS_VISIBLE | WS_GROUP | WS_TABSTOP, 3, 15, 56, 10
CONTROL "&Conditional", 106, BUTTON, BS_AUTORADIOBUTTON | WS_CHILD | WS_VISIBLE, 3, 26, 48, 10
CONTROL "", 107, STATIC, SS_ETCHEDFRAME | WS_CHILD | WS_VISIBLE | WS_GROUP, 3, 39, 393, 135
CONTROL "In:", 108, STATIC, SS_LEFTNOWORDWRAP | WS_CHILD | WS_VISIBLE | WS_GROUP, 9, 42, 56, 9
CONTROL "", 109, LISTBOX, LBS_STANDARD | LBS_OWNERDRAWFIXED | LBS_HASSTRINGS | LBS_NOINTEGRALHEIGHT | WS_CHILD | WS_VISIBLE | WS_GROUP | WS_TABSTOP, 9, 52, 120, 100
CONTROL "Not In:", 110, STATIC, SS_LEFTNOWORDWRAP | WS_CHILD | WS_VISIBLE | WS_GROUP, 141, 42, 56, 9
CONTROL "", 111, LISTBOX, LBS_STANDARD | LBS_OWNERDRAWFIXED | LBS_HASSTRINGS | LBS_NOINTEGRALHEIGHT | WS_CHILD | WS_VISIBLE | WS_GROUP | WS_TABSTOP, 141, 52, 120, 100
CONTROL "As Is:", 112, STATIC, SS_LEFTNOWORDWRAP | WS_CHILD | WS_VISIBLE | WS_GROUP, 271, 42, 56, 9
CONTROL "", 113, LISTBOX, LBS_STANDARD | LBS_OWNERDRAWFIXED | LBS_HASSTRINGS | LBS_NOINTEGRALHEIGHT | WS_CHILD | WS_VISIBLE | WS_GROUP | WS_TABSTOP, 271, 52, 120, 100
CONTROL "<---", 114, BUTTON, BS_PUSHBUTTON | WS_CHILD | WS_VISIBLE | WS_GROUP | WS_TABSTOP, 181, 157, 18, 13 CONTROL "--->", 115, BUTTON, BS_PUSHBUTTON | WS_CHILD | WS_VISIBLE | WS_GROUP | WS_TABSTOP, 211, 157, 18, 13
CONTROL "&Apply", 100, BUTTON, BS_DEFPUSHBUTTON | WS_CHILD | WS_VISIBLE | WS_GROUP | WS_TABSTOP, 3, 179, 50, 13
CONTROL "&Edit Condition Tag...", 101, BUTTON, BS_PUSHBUTTON | WS_CHILD | WS_VISIBLE | WS_GROUP | WS_TABSTOP, 61, 179, 72, 13
CONTROL "&Show/Hide...", 102, BUTTON, BS_PUSHBUTTON | WS_CHILD | WS_VISIBLE | WS_GROUP | WS_TABSTOP, 141, 179, 50, 13
CONTROL " ", 103, STATIC, SS_LEFTNOWORDWRAP | WS_CHILD | WS_VISIBLE | WS_GROUP, 1333, 1231, 0, 0
CONTROL "Conditional Text", 116, STATIC, SS_LEFTNOWORDWRAP | WS_CHILD | WS_VISIBLE | WS_DISABLED | WS_GROUP, 0, 0, 0, 0
}


Show/Hide Conditional Text Dialog Settings


COND_VISBILITY DIALOG 33, 49, 372, 230
STYLE DS_MODALFRAME | WS_CLIPSIBLINGS | WS_CAPTION
CAPTION "Show/Hide Conditional Text"
LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
FONT 8, "MS Sans Serif"
{
CONTROL "Show &All", 103, BUTTON, BS_AUTORADIOBUTTON | WS_CHILD | WS_VISIBLE | WS_GROUP | WS_TABSTOP, 3, 2, 180, 10
CONTROL "Sho&w:", 104, BUTTON, BS_AUTORADIOBUTTON | WS_CHILD | WS_VISIBLE, 3, 16, 33, 10
CONTROL "", 105, LISTBOX, LBS_STANDARD | LBS_OWNERDRAWFIXED | LBS_HASSTRINGS | LBS_NOINTEGRALHEIGHT | WS_CHILD | WS_VISIBLE | WS_GROUP | WS_TABSTOP, 3, 27, 152, 146
CONTROL "<---", 106, BUTTON, BS_PUSHBUTTON | WS_CHILD | WS_VISIBLE | WS_GROUP | WS_TABSTOP, 178, 33, 18, 13 CONTROL "--->", 107, BUTTON, BS_PUSHBUTTON | WS_CHILD | WS_VISIBLE | WS_GROUP | WS_TABSTOP, 178, 50, 18, 13
CONTROL "Hide:", 108, STATIC, SS_LEFTNOWORDWRAP | WS_CHILD | WS_VISIBLE | WS_GROUP, 216, 17, 18, 9
CONTROL "", 109, LISTBOX, LBS_STANDARD | LBS_OWNERDRAWFIXED | LBS_HASSTRINGS | LBS_NOINTEGRALHEIGHT | WS_CHILD | WS_VISIBLE | WS_GROUP | WS_TABSTOP, 216, 27, 152, 146
CONTROL "Show &Condition Indicators", 110, BUTTON, BS_AUTOCHECKBOX | WS_CHILD | WS_VISIBLE | WS_GROUP | WS_TABSTOP, 3, 182, 180, 10
CONTROL "", 111, STATIC, SS_ETCHEDHORZ | WS_CHILD | WS_VISIBLE | WS_GROUP, 3, 196, 179, 1
CONTROL "&Set", 100, BUTTON, BS_DEFPUSHBUTTON | WS_CHILD | WS_VISIBLE | WS_GROUP | WS_TABSTOP, 3, 203, 30, 13
CONTROL "Cancel", 101, BUTTON, BS_PUSHBUTTON | WS_CHILD | WS_VISIBLE | WS_GROUP | WS_TABSTOP, 339, 203, 30, 13
CONTROL "(No Undo)", 113, STATIC, SS_LEFTNOWORDWRAP | WS_CHILD | WS_VISIBLE | WS_GROUP, 3, 219, 34, 9
CONTROL "&Help", 112, STATIC, SS_LEFTNOWORDWRAP | WS_CHILD | WS_VISIBLE | WS_GROUP, 1333, 1231, 0, 0
CONTROL "Show/Hide Conditional Text", 102, STATIC, SS_LEFTNOWORDWRAP | WS_CHILD | WS_VISIBLE | WS_DISABLED | WS_GROUP, 0, 0, 0, 0
}


Resources Mentioned in this Article

Sunday, February 10, 2008

Simultaneous Document Development and Production

One major flaw I've found with many documentation packages is the fact that you cannot work on your source documents while you are building your documents. Let's take Web Works Publisher 2003 (WWP2003) for example. It's one of the better Help Application Tools (HATs) out there, and due to the early teething problems exhibited by its replacement (ePublisher 9.x), I'm still not ready to migrate from WWP2003 to its more recent replacement. For those of you that don't know, WWP2003 integrates with FrameMaker or (*gasp*) Microsoft Word. To use it, you define your output format (WebHelp, CHM, JavaHelp, etc...) and map all your source FrameMaker styles to your WWP2003 output styles.

When it's time to build your project, you simply press the build button in WWP2003, and it churns away for an inexorably long period of time while building your project. Unfortunately, while it is churning away, you can't continue to work in FrameMaker. That means lots of down-time while you are waiting for projects to build. If you have a number of projects to build, it can easily mean that you are stuck for possibly several days just building your projects. What's worse is because Quadralay wants to sell you additional applications, you can't tell WWP2003 to build several of your projects. You have to let it build one project, wait, then open another project and click Build, wait, then open another project and click Build, etc... This is an intolerable problem with many (most?) HATs out there. I draw attention to WWP2003 not because it is unique in this respect, but because it is the HAT I am currently using.

The problem with this approach is twofold: First, since it essentially locks FrameMaker, you can't continue your development work while it is building. This means that even if WWP2003 is building Project 1, you can't even work on Project 2 until it finishes building. Ack. Secondly, if you need to build multiple projects, you have to actively monitor the build process so that when it finishes building Project 1, you can manually open and start building Project 2. This sucks...but there is a way around it.

Virtualize your Build Environments

You can virtualize your build environment and free yourself from the tedium of waiting for your projects to build. If you haven't yet worked with virtualization, it sounds much more complex than it really is. Virtualization essentially allows you to run a "virtual" operating system in a window on your host operating system. This host operating system can be your development computer, or it can be hosted on another server or computer in your environment. Though the virtual operating system runs in a window on another operating system, it is for all intents and purposes another computer...only a virtual one, since it shares the hardware of an already existing computer. OK, it still sounds pretty complex if you haven't done it before...but trust me, it is pretty easy and your learning curve is likely to be more than a few minutes once you see how it all works.

When virtualizing your build environments, you'll need to make sure you do a few things right off the bat:

1) Mirror your directory structures
What is important here is that you mirror your documentation directory structures on your Virtual Machine. By this I mean that if you keep all your files for your projects in D:\Projects\Layouts and D:\Projects\Artwork...you'll want to create duplicate folders (even if empty) on your Virtual Machine.

2) Install your HAT software
Install your HAT software on the virtual machine. If you are using WWP2003, you'll need to install WebWorks Publisher Pro 2003 and FrameMaker. Depending on the licenses of your HAT software, you may have to shell out some money for this. If you need to justify the expense of this to management (who doesn't?), just figure out how much time it takes you to build each project and figure out how much time you'll be able to recapture per week, month, year, etc... by being able to work and build your output simultaneously. The RoI should be pretty low and easy to calculate.

3) Install Microsoft SyncToy
Microsoft SyncToy is an "intelligent" file copy tool. What's more, it is free. There are only a few options to it, and even fewer that you'll need to use. I've set mine up to copy the root directory of my development folder structure (D:\Projects\) using "Echo" copy. What this will do is mirror all the files and folders on the D:\Projects directory of my development machine to the D:\Projects directory of my Virtual Machine. If I delete a file on my development machine, it gets deleted on my virtual machine the next time I run SyncToy. If I create a new file on my development machine, it gets copied over to my Virtual Machine the next time I run SyncToy. What's more important, SyncToy is smart enough to only copy the files from my development machine that are no longer identical to those found on my virtual machine. Since my development folder contains about 12Gigs of FrameMaker files and source (.eps) graphic files, its a relief not to have to copy ALL of them over when I need to make some new builds.

4) Keep it lean
You are going to be using the VM only to build your projects. You don't need to install your favorite media player, or your favorite image editing software. Only install those components that you need to actually build (not develop) your projects. Use Add/Remove Programs to remove any crapwhere that gets installed by default.

Once you've set up your Virtual Machine, you are pretty much good to go. When you want to build a bunch of projects, just launch your VM, use SyncToy to sync your development files to the VM, and start building your projects. You can continue working on your development machine because your HAT on your build machine is working from a duplicate set of files.

There are, of course, some drawbacks to this approach. The first is cost. Due to licensing restrictions, you may have to pay for extra licenses for Windows and your HAT software. For me this was a non-issue because we have access to licenses for Windows through our development group (of which I am a part) and we had some older licenses for our HATT software that were not being used. Your mileage may vary though. The second potential problem with this setup is resource consumption. If you are hosting your Virtual Machine on your development box, you'll want to make sure you have lots of RAM and some extra CPU cycles to spare. I've done this in the past and while I've found my development machine to be somewhat slowed down, it was still perfectly usable so long as I didn't open Photoshop and decide that I wanted to edit a bunch of .eps files. If possible, consider hosting your VM on a spare computer somewhere. Your engineering group may even have some servers dedicated to hosting virtual machines somewhere. Depending on their hardware, you may even find building your projects on the VM is faster than building them on your production machine!

Some of you might be asking the obvious right about now, "If I have an extra computer laying around, why should I much around creating a Virtual Machine?" Well, the answer to that will depend on a few things I suppose. First off, there's no reason why you can't just use your spare hardware as duplicate build machine and use sync toy to keep them both in sync. In 99% of the cases, using dedicated hardware will improve your build times. However, with a Virtual Machine you will have increased portability. As you retire and aquire new computers, you won't have to consistenly recreate a duplicate build machine. All you'll have to do is copy your VM over to the new computer and launch it. Going to be on the road for a while, just copy your VM to a laptop and take your projects and HAT with you. For me, the portability issue outweighs the speed issue. Once I offload my builds to my Virtual Machine, I don't really care that it takes 25% more time to build since I can continue working while things are building. If I have something that needs to be built ASAP, there's no reason why I can't build it directly on my production machine...and sometimes I have to this.

One last thing I'd like to mention in regards to "Why Virtualize?" This may be a huge deal to some, and not at all interesting to others...but the last reason to consider virtualizing a build machine is Operating System Independence. When you have a VM, you can run your Windows build machine on any OS that can run a virtual machine. (...providing that you stick within the same virtualization player vendor. For example, I wouldn't expect to be able to run a Parallels Virtual Machine on VMWare Player.) . At home, my OS is Ubuntu...but I can still work/build my projects on Linux using VMWare server to launch my virtual build machine. As of today, VMWare provides virtual machine players for a host of operating systems including Mac OS X, Linux (many flavors), Windows, Sun, etc... Chances are that if you use it, there's a VM player for it.

The one downside not addressed thus far by using a Virtual Machine is the fact that you still have to manually monitor your VM if you are building multiple projects. This is somewhat alleviated by the fact that you can still work on your development machine while building projects on your virtual machine...but is still somewhat of a pain. Fortunately, there is help in this regard.

Automate your Build Processes
You can "easily" automate building multiple projects using some pretty simple scripting tools. I kind of fell in to using AutoIT to automate my builds, but there are other tools out there to accomplish the same thing. I'm working on an article right now that explores using AutoIt for build automation. I'm not done with it yet, but if interested, keep your eyes on the blog.

Resources Mentioned in this Article