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

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


Channels ▼
RSS

Tech Tips


Tips

Purging Zero-Version-Only Elements in ClearCase

George F. Frazier
[email protected]

An annoyance with the Windows version of Rational ClearCase is that it is easy to accidentally create a branch of an element whose only version is 0. If you use ClearCase for version control, you'll know that version 0 of an element has exactly the same contents as its parent. This seems harmless. But consider this typical config spec:

element * CHECKEDOUT 
element * .../mybranch/LATEST 
mkbranch mybranch 
element * .../myparentbranch/LATEST 
element * /main/LATEST 
end mkbranch 

Suppose element myfile.cpp has the following versions:

myfile.cpp@@/main/1 
myfile.cpp@@/main/myparentbranch/1 
myfile.cpp@@/main/myparentbranch/mybranch/0 

Here myfile.cpp@@/main/myparentbranch/mybranch/0 branches from myfile.cpp@@/main/myparentbranch/1. Now in a different view, suppose you or someone else creates myfile.cpp@@/main/myparentbranch/2. In this case, 99 percent of the time you want to select this new version, but your config spec still selects myfile.cpp@@/main/myparentbranch/mybranch/0, which is equivalent to myfile.cpp@@/main/myparentbranch/1!

ClearCase site administrators can configure the installation to make this less likely to occur, but developers usually don't have "super-user" access to large ClearCase installations. I've found that this situation is particularly problematic on Windows. By default, if you uncheckout the first version of an element on a new subbranch, you are left with the zero version. This is not a problem: You can just delete the subbranch — if you remember to. However, I've run into thornier situations when using the GUI version of the Windows ClearCase Merge Manager:

  1. Invoke FindWizard and accept the defaults — this includes "Automatically Merge Directories."

  2. Let the merge manager find elements to merge and then before doing the merge, exit the merge manager (this is a reasonable activity; sometimes you just want to know what the merge candidates are).

  3. Notice that many directories might be checked out after exiting. Now use the Find Checked Out Files tool to find and then uncheckout those directories.

Now all new directories on the "from target" of the merge have zero-only versions of mybranch. Depending on what you're doing, this could be thousands of elements. You can compound this by actually running the entire merge and then bailing out without checking in the files.

So what's the fix? If you can convince your configuration management team to provide tools that automatically delete these zero-version items, then you are in great shape. If you're on your own, though, you need to purge your view of those troublesome entities. Run the following command to find all zero-version elements:

cleartool find -avobs -branch'{
    brtype(mybranch)&&!
    (version(.../mybranch/1))}' 
     -print > c:\files.txt 

This will find all elements with no version 1 on mybranch (if you read closely you'll notice it doesn't do the right thing if you have removed the 1 version of an element that already has versions greater than or equal to 2 — this is a rare situation though). Once finished, it's simply a matter of using rmbranch to nuke the elements (make sure you know what you're doing here!). There are many ways to do that; since I run the MKS toolkit, I execute the following from a command window:

cleartool rmbranch -f 'cat c:\files.txt' 

A printf for Message Boxes

Matthew Wilson
[email protected]

The Windows MessageBox() function provides a standard form of dialog interaction with the user for the purpose of posing simple interrogatives, where the answer can be expressed in terms of the provided responses (OK, Cancel, Yes, No, Retry, Ignore, and Abort).

MessageBox() is also useful as a crude but accessible debugging aid, as shown in Listing 1. This is a fair amount of additional typing, but it is not (yet) onerous. Often in such cases, however, there is a requirement to provide more detailed feedback by "sprintf-ing" information into the MessageBox text, as in Listing 2. The situation gets even worse when you want to load a string as the format string or the title.

The (pretty obvious) answer to this is a function, MessageBox_printf(), which I wrote after getting very tired of such verbosity. Presented here is the 32-bit ANSI version, using the ANSI versions of the requisite API functions (see Listing 3).

The function effectively "sprintfs" the variable arguments, if any, into a buffer according to the format string lpszFmt, and then displays a message box with the resultant buffer as the message box text using the given hwnd, lpszTitle, and uType parameters.

If either or both of the lpszFmt and lpszTitle parameters are actually string resource ids (by dint of having 0 in their upper 16-bits), then they are loaded from the given instance handle hinst. If hinst is NULL, then it is derived either as the GWL_HINSTANCE attribute of the given window (if any), or otherwise as the instance handle of the calling process. The function returns the MessageBox() return value, not that of the wsprintf() call, so that the function can be used to interrogate the user in the same way as MessageBox() itself.

The implementation is pretty straightforward. Local buffers are used in order to provide some memory substance to any text strings loaded from the resources. The only notable feature is the sizes of these buffers. wsprintf() will printf a maximum of 1024 destination characters (including NULL), so szText is of that dimension. The sizes of szFmt and szCaption are 768 and 128, respectively. These seem to be arbitrary but are, in fact, derived through trial and error such that this function does not precipitate the Visual C++ compiler to attempt to insert the _chkstk function (due to the stack potentially exceeding the boundary of the guard page), which then precludes the practice (common in my libraries and simple programs) of excluding the C Runtime Library. These limits have not yet caused any restriction of utility in the long time that I've been using these functions.

Included in this month's archive is a sample main that exercises the functionality, and a Visual C++ 5.0 project.

Customizing the Visual Studio IDE (VS6 and VS.NET)

Glenn Pope
[email protected]

Most Windows applications (including VS6 and VS.NET) maintain a Most Recently Used (MRU) list that allows you to open files or projects without having to search around for the location of source files. This is nice until you need to copy the DLL or exe that you just compiled.

Once done, you have to fire up Windows Explorer (or one of its brethren) and navigate to your project directory. If you are like me, your project directories can be nested several levels deep and possibly on differing drives. Can you say network storage? With mapped drives and multiple code repositories, locating the source can be frustrating. Don't count on the MRU list either because it will only show the name of the project without the path once the project is opened.

I could write a script to do this, or add a postbuild step, but I like using Explorer because I often do a bunch of cleanup and copying that I can't easily automate when I'm iterating through a build/debug/install process. A solution that works for me is to customize Visual Studio with a simple button that launches Explorer with the target directory preselected. While not profound in and of itself, it is worth reviewing how to do this since, with a few customized menu options or tool buttons, you can standardize a build process across an entire team of programmers.

For the simple case of launching Explorer, start by pulling down the Tools menu and selecting External Tools. Click the Add button, and enter:

Title: Explorer Target, 
    Command: explorer.exe, 
    Arguments: /e,/Select,$(TargetDir)

Click OK and you now have an external tool you can invoke from the Tools menu. While we are reviewing the ABCs of Visual Studio IDE customization, we can take it one step further and add the command to the toolbar by selecting Customize from the Tools menu. On the Commands Tab, in the listbox on the left select Tools. In the listbox on the right, scroll down until you find External Command xx, where xx is the index number of your new command (start counting at 1). Select the proper External Command xx with the left mouse button and drag it onto your toolbar in the IDE. The text will update once you close all customize dialogs.

Of course, there is nothing magic about using this process to launch Explorer; you can customize the IDE as necessary based on your requirements. This can be a particularly effective way to train a new programmer about a particular build system. Just provide buttons for each step they need to perform after building, such as producing an install, firing up test or profiling tools, using source code control, running regression tests, etc. Order these buttons from left to right based on the natural order in which the steps should be taken, and you've turned Visual Studio into a visual README file of your configuration management process.

A Shareable Approach to Debugging Additional DLLs

Matthew Wilson
[email protected]

The June 2002 edition of WDM contained the tip "Setting Breakpoints in Additional DLLs with VC++" by Gigi Sayfan, which described how to use the support built into Visual C++ (available since 2.0).

There are circumstances, however, where the use of the built-in support is inadequate or undesirable. This is because the Additional DLL's information is stored in Visual Studio in the corresponding .opt file for a particular workspace.

If part of one's development practice is to regularly clean out the working directory tree (it is, right?), then this information will be lost. An alternative to this is to store it along with the project workspace in source control. But this is troublesome, not just because the .opt file appears to accrete (often erroneous) content throughout the lifetime of the active project, but also because such an approach would limit the developer(s) sharing this file to a single working directory for the Additional DLLs themselves (which precludes freedom for projects that generate output via relative path). This restriction is onerous for an individual, and positively untenable for most collaborative environments.

The solution that has found application in such collaborative circumstances is to force the explicit libraries to be loaded implicitly by the operating system when the application being debugged is loaded. This means that any breakpoints set in a prior execution will remain set (unless the code itself has changed, of course) in a subsequent one.

To do this, one must explicitly link in a function exported by each additional DLL. For example, a library BASESTD.dll could export the function:

void __stdcall linkBASESTD(void)
{
}

which can be referenced in the application code in the following way:

#ifdef _DEBUG
static /* Can put in unnamed namespace in C++ */
 void func_never_called()
{
    void (__stdcall *_linkBASESTD)(void) = linkBASESTD;
}
#endif /* _DEBUG */

This has no run-time cost, and only links in for debug builds. It has the effect of linking to BASESTD.dll, which is, therefore, implicitly loaded, and its breakpoints are preserved.

This technique is very useful for solving the breakpoint issue in collaborative projects, but it should be pointed out that its use does change program behavior, due to the loading of all such linked libraries at application load. Subtle library-load ordering issues can be masked. I would therefore strongly recommend disabling the implicit loading prior to moving to a release-testing phase, specifically to detect any ordering issues.


George Frazier is a software engineer in the System Design and Verification group at Cadence Design Systems Inc. and has been programming for Windows since 1991. He can be reached at [email protected].


Related Reading


More Insights






Currently we allow the following HTML tags in comments:

Single tags

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

<br> Defines a single line break

<hr> Defines a horizontal line

Matching tags

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

<a> Defines an anchor

<b> Defines bold text

<big> Defines big text

<blockquote> Defines a long quotation

<caption> Defines a table caption

<cite> Defines a citation

<code> Defines computer code text

<em> Defines emphasized text

<fieldset> Defines a border around elements in a form

<h1> This is heading 1

<h2> This is heading 2

<h3> This is heading 3

<h4> This is heading 4

<h5> This is heading 5

<h6> This is heading 6

<i> Defines italic text

<p> Defines a paragraph

<pre> Defines preformatted text

<q> Defines a short quotation

<samp> Defines sample computer code text

<small> Defines small text

<span> Defines a section in a document

<s> Defines strikethrough text

<strike> Defines strikethrough text

<strong> Defines strong text

<sub> Defines subscripted text

<sup> Defines superscripted text

<u> Defines underlined text

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

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