<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>Mark Nelson &#187; Work</title>
	<atom:link href="http://marknelson.us/category/work/feed/" rel="self" type="application/rss+xml" />
	<link>http://marknelson.us</link>
	<description>Programming, mostly.</description>
	<lastBuildDate>Fri, 13 Apr 2012 19:25:26 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.2.1</generator>
		<item>
		<title>GCC Tries to Help &#8211; With Mixed Results</title>
		<link>http://marknelson.us/2011/08/15/gcc-tries-to-help-with-mixed-results/</link>
		<comments>http://marknelson.us/2011/08/15/gcc-tries-to-help-with-mixed-results/#comments</comments>
		<pubDate>Mon, 15 Aug 2011 11:38:49 +0000</pubDate>
		<dc:creator>Mark Nelson</dc:creator>
				<category><![CDATA[C/C++]]></category>
		<category><![CDATA[Computer Science]]></category>
		<category><![CDATA[Work]]></category>

		<guid isPermaLink="false">http://marknelson.us/?p=589</guid>
		<description><![CDATA[<div class="addthis_toolbox addthis_default_style" addthis:url='http://marknelson.us/2011/08/15/gcc-tries-to-help-with-mixed-results/' addthis:title='GCC Tries to Help &#8211; With Mixed Results' ><a class="addthis_button_twitter"></a><a class="addthis_button_favorites"></a><a class="addthis_button_print"></a><a class="addthis_button_facebook_like"></a><a class="addthis_button_google_plusone"></a><a class="addthis_button_compact"></a></div>One of the great things about C, and even more so for C++, is its strong type checking mechanisms. In general a lot of bugs are caught at compile time, and experienced programmers are able to recognize and fix these types of errors quickly. Unfortunately, there are plenty of places in any C program where [...]]]></description>
			<content:encoded><![CDATA[<div class="addthis_toolbox addthis_default_style" addthis:url='http://marknelson.us/2011/08/15/gcc-tries-to-help-with-mixed-results/' addthis:title='GCC Tries to Help &#8211; With Mixed Results' ><a class="addthis_button_twitter"></a><a class="addthis_button_favorites"></a><a class="addthis_button_print"></a><a class="addthis_button_facebook_like"></a><a class="addthis_button_google_plusone"></a><a class="addthis_button_compact"></a></div><p>One of the great things about C, and even more so for C++, is its strong type checking mechanisms. In general a lot of bugs are caught at compile time, and experienced programmers are able to recognize and fix these types of errors quickly.</p>
<p>Unfortunately, there are plenty of places in any C program where type checking disappears. The GNU C compiler, gcc, goes above and beyond the call of duty to help in these areas. But sometimes that help can be a can of worms all of its own.<br />
<span id="more-589"></span></p>
<h4>An Example of Type Safety MIA</h4>
<p>A classic example of type safety gone into hiding is found with the formatted I/O functions in C: <code>s/f/printf()</code> and <code>s/f/scanf()</code>. These function families take a formatted string that defines what type of arguments they are expecting to either read or write, followed by a variable length list of arguments. The arguments passed in must match up precisely with the formatted argument string in type and quantity. The problem is that the traditional compiler, which is concerned with the language, doesn&#8217;t really know how to check that argument list.</p>
<p>Over the years this has lead to many spectacular bugs, when an original programmer or someone doing maintenance inserts a mismatch:</p>
<pre>
    int parse_user_name( char *name, size_t namel )
    {
        printf( "Please provide a name:" );
        sscanf( "%s", namel );
    }
</pre>
<p>In some cases, such as the simple one character typo shown above, you now have a system that can be easily exploited using off-the-shelf tools for code injection. Very bad stuff.</p>
<h4>GNU to the Rescue</h4>
<p>Traditional C compilers have let this kind of bad code go by without a second glance. Back in the day, the responsibility for this deeper type of checking rested with a useful program called <a href="http://en.wikipedia.org/wiki/Lint_(software)" class="newpage">lint</a>. But as the C standard tightened up over the years, fewer people saw a need for lint, and routine checks for these types of problems often disappeared from the build process.</p>
<p>Somewhere along the way, (I first started noticing in the 4.x era) the GNU compiler people began inserting some proactive code to flag errors that once where the province of lint. Just as an example, this short piece of broken code compiles with no warnings when using default settings for gcc 3.4, 4.1, and the Sun C compiler v5.7:</p>
<pre>
#include <stdio.h>

int main()
{
    printf( "%s\n", 1.2 );
    return 0;
}
</pre>
<p>But gcc 4.5.2 correctly sees a big problem, and issues a warning:</p>
<pre>
gcc.c: In function 'main':
gcc.c:5:5: warning: format '%s' expects type 'char *', but argument 2 has type 'double'
</pre>
<p>Since it is valid C code, the compilation proceeds, but at this point it is caveat emptor.</p>
<h4>How Far Do You Go?</h4>
<p>I ran into trouble with this GCC feature when working up an in-class demonstration of redirected  I/O on a Linux system. I hypothesized that the early, paleolithic code to redirect standard output for a child process might have looked something like this:</p>
<pre>
#include &lt;unistd.h&gt;
#include &lt;stdio.h&gt;
#include &lt;fcntl.h&gt;

int main (int argc, char *argv[]) {
  if ( argc &lt;= 2 ) {
    printf( "Usage: test command file\n"
            "The command will be executed"
            "with stdout going to file\n" );
    return -1;
  }
  if (fork() == 0) {
    close(STDOUT_FILENO);
    open(argv[2], O_WRONLY | O_CREAT, 0744);
    printf( "About to execute %s\n", argv[1] );
    fflush( stdout );
    execl(argv[1], 0);
    printf("I will never be called\n");
  }
  sleep ( 2 );
  printf("Execution continues in"
         " the parent process\n");
  return 0;
}
</pre>
<p>This code does just what we want when executed with a command like: <code>./a.out /bin/ls output.txt</code>. The <code>ls</code> command is executed, and its standard output is redirected to the file output.txt.</p>
<p>However, several of my students reported that they were getting mysterious compiler errors on this same code. Sure enough, when running under gcc 4.5, we get this:</p>
<pre>
exec.c: In function 'main':
exec.c:17:6: warning: not enough variable arguments to fit a sentinel
</pre>
<p>For beginning C programmers, this kind of error can be a real time sink. The error message uses terminology that is compiler-specific, it doesn&#8217;t provide a detailed description of exactly what it doesn&#8217;t like, and it doesn&#8217;t recommend a solution. Google searches for this specific error do lead to a solution, but they will ask a bit of work from the novice.</p>
<p>The first lesson my students picked up is that you need at least one more argument to this function call. While it is true that people normally call <code>execl()</code> with <code>arg0</code> set to the filename, this is by no means required. And in fact, most programs will work just fine with an argument count of 0. There is really no good way to know which programs require <code>arg0</code>, or further args, without reading the documentation. In any case, gcc is pushing things a bit by insisting on this.</p>
<p>So changing the line of code that calls exec to:</p>
<pre>
    execl(argv[1], argv[1], 0);
</pre>
<p>should fix the problem, right?</p>
<p>Wrong. This reconfiguration gets a slightly different error:</p>
<pre>
exec.c: In function 'main':
exec.c:17:6: warning: missing sentinel in function call
</pre>
<p>As it turns out, gcc really wants you to cast the literal value 0 to a pointer:</p>
<pre>
    execl(argv[1], argv[1], (char*) 0);
</pre>
<p>Which finally makes the error go away.</p>
<p>This is a bit annoying, because both my C and C++ standards clearly say that a constant integral value of 0 can convert to any pointer type without any fuss. So why should I have cast it to a <code>char *</code> before passing it to execl?</p>
<p>Well, it won&#8217;t make a difference on any of the computers I use, but if you are on a computer where an integral type is passed on the stack with fewer bytes than a pointer, you may run into trouble. <code>execl()</code> is not smart enough to know that the 0 you are passing is actually terminating the argument list &#8211; it may just be an integer &#8211; so an integer is what is pushed on the stack.</p>
<h4>Confusion</h4>
<p>So yes, gcc&#8217;s lint-like characteristics made my lecture a bit more complicated. I had to explain a few things that I had hoped to gloss over. But on the other hand, the casting of 0 to a pointer type is actually a pretty important thing, and I&#8217;m glad gcc reminded me of it.</p>
<p>Requiring a value of <code>arg0</code> when using <code>execl()</code> seems to me less like something that requires reminding, but nonetheless, it certainly won&#8217;t do any harm to follow this advice.</p>
<p>C++ does a good job of inserting type safety into places where it hasn&#8217;t been seen before. For example, you can do all your I/O in C++ with some assurance that you are not making those traditional mistakes seen with <code>scanf</code> or <code>printf</code>. However, the C++ standard library is not likely to tackle the APIs for Linux or Unix system calls, meaning we should be appreciative of the help we get from gcc.</p>
<p>So to whoever wrote the code that checks for sentinels in gcc, I thank you.</p>
]]></content:encoded>
			<wfw:commentRss>http://marknelson.us/2011/08/15/gcc-tries-to-help-with-mixed-results/feed/</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
		<item>
		<title>More on Sending Mail With Linux &#8211; Postfix Tweaks and Mailjet</title>
		<link>http://marknelson.us/2011/07/31/more-on-sending-mail-with-linux-postfix-tweaks-and-mailjet/</link>
		<comments>http://marknelson.us/2011/07/31/more-on-sending-mail-with-linux-postfix-tweaks-and-mailjet/#comments</comments>
		<pubDate>Sun, 31 Jul 2011 18:42:03 +0000</pubDate>
		<dc:creator>Mark Nelson</dc:creator>
				<category><![CDATA[Linux]]></category>
		<category><![CDATA[Networking]]></category>
		<category><![CDATA[Work]]></category>

		<guid isPermaLink="false">http://marknelson.us/?p=530</guid>
		<description><![CDATA[<div class="addthis_toolbox addthis_default_style" addthis:url='http://marknelson.us/2011/07/31/more-on-sending-mail-with-linux-postfix-tweaks-and-mailjet/' addthis:title='More on Sending Mail With Linux &#8211; Postfix Tweaks and Mailjet' ><a class="addthis_button_twitter"></a><a class="addthis_button_favorites"></a><a class="addthis_button_print"></a><a class="addthis_button_facebook_like"></a><a class="addthis_button_google_plusone"></a><a class="addthis_button_compact"></a></div>In my last post I showed a particularly easy way to to set up an SMTP server so postfix could send mail from your Linux system. In this post I&#8217;m going to add a few tips that might help you get through some rough spots in the whole process. Results From the Field After writing [...]]]></description>
			<content:encoded><![CDATA[<div class="addthis_toolbox addthis_default_style" addthis:url='http://marknelson.us/2011/07/31/more-on-sending-mail-with-linux-postfix-tweaks-and-mailjet/' addthis:title='More on Sending Mail With Linux &#8211; Postfix Tweaks and Mailjet' ><a class="addthis_button_twitter"></a><a class="addthis_button_favorites"></a><a class="addthis_button_print"></a><a class="addthis_button_facebook_like"></a><a class="addthis_button_google_plusone"></a><a class="addthis_button_compact"></a></div><p>In my <a href="http://marknelson.us/2011/07/06/sendmail-on-linux-the-easy-way/" class="newpage">last post</a> I showed a particularly easy way to to set up an SMTP server so postfix could send mail from your Linux system. In this post I&#8217;m going to add a few tips that might help you get through some rough spots in the whole process.<br />
<span id="more-530"></span></p>
<h4>Results From the Field</h4>
<p>After writing a HOWTO page, there is no better test of its quality than to try it out with a group of students performing the task for the first time. That&#8217;s just what I did with my SMTP configuration post &#8211; I created a homework problem that asked my students to set up outbound email on their personal Linux systems.</p>
<p>Their resulting glitches highlighted a few rough spots in the process, most of which can be handled pretty easily.</p>
<h4>Debian Package Configuration</h4>
<p>When you install postfix on Ubuntu, you will normally get kicked into a simple package configuration dialog after the package has been downloaded and installed. This final step performs some very basic setup on postfix, getting into a roughly functional state.</p>
<p>If this configuration doesn&#8217;t run, postfix seems to be configured to only handle local mail &#8211; messages from one user to another. In some cases this may be just what you want, but normally it is not all that useful.</p>
<p>For unknown reasons, this configuration pass doesn&#8217;t always kick off properly. I&#8217;ve seen it fail to run, and some students have as well. Fortunately, you can execute the same process by hand from the command line:</p>
<pre>
sudo dpkg-reconfigure postfix
</pre>
<p>Running through this, I take the default settings for everything except <em>Root and postmaster mail recipient</em>, which I change to <em>student</em>, the name of my account on this system. After this is complete, following the instructions from my previous post will give you a proper Internet email setup.</p>
<h4>Using Mailjet instead of SendGrid</h4>
<p>After some glitches getting accounts on SendGrid, I had a couple of students decide to use <a href="http://mailjet.com/" class="newpage">Mailjet</a> as an STMP provider. Registering with Mailjet <i>is</i> easier, as it an automated process. However, using Mailjet as your SMTP provider comes with a couple of interesting twists.</p>
<p>First, instead of using your Mailjet account credentials to authenticate with their SMTP server, Mailjet gives you  a set of strong credentials specifically for SMTP authentication. You have to copy these from your Account Info page. No problem there, as long as you RTFM.</p>
<p>Slight more problematic is that Mailjet insists that the return address you use in your outbound emails must be an authenticated address. In other words, you have to be able to receive an email sent to that address and click on an authentication link.</p>
<p>When using postfix&#8217;s default settings, email sent by my students was going out with a return address of student@ubuntu, and there is obviously no way to authenticate that address. So we have to rewrite that address to something usable.</p>
<p>After taking that additional requirement into account, my changes to /etc/postfix/main.cf for Mailjet are shown below. The file had a default relayhost entry, which is replaced, and the remaining lines are all new. The username and password have to be replaced with the ones from your Mailjet account page:</p>
<pre>
smtp_sasl_auth_enable = yes
smtp_sasl_password_maps = static:username:password
smtp_sasl_security_options = noanonymous
smtp_tls_security_level = may
relayhost = [in.mailjet.com]:587
smtp_generic_maps=texthash:/etc/postfix/generic
</pre>
<p>The last line I added to the configuration tells postfix to look in a file called /etc/postfix/generic for a list of substitutions to make to email addresses found in headers being processed. I create a single line in this file:</p>
<pre>
student@ubuntu yourmail@yourprovider.tld
</pre>
<p>This entry in the map file changes the local student account to an authenticated email address. After making this change, emails sent from the student account will have their headers rewritten to give a sender identity of your personal email address, which means Mailjet will happily forward your messages to their final destination.</p>
<p>Once that&#8217;s done, I restart postfix and send a test message:</p>
<pre>
sudo /etc/init.d/postfix restart
echo hello | mailx -s "test mail" myemailaddress
</pre>
<p>The headers on my received email show that things worked more or less as expected:</p>
<table border="0">
<tr>
<td width="100%"><center><image src="/attachments/2011/postfix-tweaks/headers.png"/><center></td>
</tr>
</table>
<p>One nice thing about using the generic substitution file is that now you can accommodate different sender email addresses for every account on your system. Since you have to enter account info by hand, this doesn&#8217;t scale to a large enterprise, but it works just fine for your personal system.</p>
<p>There&#8217;s no doubt that the complexities of managing mail on a Linux system is still a bit daunting, but at least the process of simply getting outbound mail working is manageable. Give it a shot!</p>
]]></content:encoded>
			<wfw:commentRss>http://marknelson.us/2011/07/31/more-on-sending-mail-with-linux-postfix-tweaks-and-mailjet/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Don Killen RIP</title>
		<link>http://marknelson.us/2006/08/25/don-killen-rip/</link>
		<comments>http://marknelson.us/2006/08/25/don-killen-rip/#comments</comments>
		<pubDate>Fri, 25 Aug 2006 20:02:50 +0000</pubDate>
		<dc:creator>Mark Nelson</dc:creator>
				<category><![CDATA[People]]></category>
		<category><![CDATA[Work]]></category>

		<guid isPermaLink="false">/2006/08/25/don-killen-rip/</guid>
		<description><![CDATA[<div class="addthis_toolbox addthis_default_style" addthis:url='http://marknelson.us/2006/08/25/don-killen-rip/' addthis:title='Don Killen RIP' ><a class="addthis_button_twitter"></a><a class="addthis_button_favorites"></a><a class="addthis_button_print"></a><a class="addthis_button_facebook_like"></a><a class="addthis_button_google_plusone"></a><a class="addthis_button_compact"></a></div>I worked for Don Killen at Greenleaf Software for quite a few years in the late 80s and 90s. Don was a pioneer in the world of commercial C and C++ libraries, and I received the sad news that he passed away this week.]]></description>
			<content:encoded><![CDATA[<div class="addthis_toolbox addthis_default_style" addthis:url='http://marknelson.us/2006/08/25/don-killen-rip/' addthis:title='Don Killen RIP' ><a class="addthis_button_twitter"></a><a class="addthis_button_favorites"></a><a class="addthis_button_print"></a><a class="addthis_button_facebook_like"></a><a class="addthis_button_google_plusone"></a><a class="addthis_button_compact"></a></div><p><img src="http://marknelson.us/attachments/2006/misc/don.gif" class="alignleft">I received a sad email from Andy Johnson of <a href="http://www.greenleafsoft.com/" class="newpage">Greenleaf Software</a> yesterday, giving me the news that Greenleaf&#8217;s founder <a href="http://www.donkillen.com/" class="newpage">Don Killen</a> died in his sleep Monday, August 21, 2006. </p>
<p>Don was a pioneer in the world of desktop C and C++ programming, since he sat down in 1982 and hammered out his flagship product, Greenleaf Functions. Back in the days when MS-DOS programmers still had to use the Lattice C compiler, Don saw that there was potential big market for a library that provide glue between the BIOS, the DOS API, and C programmers. Armed with references and a copy of MASM, he created the product, placed a few ads, and found himself with enough orders to go into the business full time. (Mind you, this was back in the early 80s, and Don was managing to get over $200 a pop for this library.) You can follow Don&#8217;s version of that history <a href="http://www.donkillen.com/personal.asp" class="newpage">here</a>.</p>
<p>I went to work for Greenleaf in 1989 after burning most of my bridges with telephony startup SRX (later absorbed by <a href="http://www.teltronics.com/" class="newpage">Teltronics</a>.) It was a big change for me &#8211; Greenleaf was a small family business and I had to try to learn how to operate in that kind of environment. During all my years with Greenleaf, I could never forget that it was Don&#8217;s world, and we were lucky to get to play in it.</p>
<p>Greenleaf had quite a few good years, but as the 90s waxed the product mix wasn&#8217;t attracting the kind of sales that it needed to keep the place going, and Don&#8217;s health was always an issue. Despite a fortunate kidney transplant, as he got older, I don&#8217;t think he had the energy and vigor he needed to reinvent the company for the new millenium. Seeing the writing on the wall, the development team branched off to form a contract programming company called <a href="http://addisoft.com/" class="newpage">Addisoft Consulting</a>. Tammie Williams, Patrick Little and Ruby Hjelte are still there, and worked with Don and Greenleaf from time to time.</p>
<p>Working with Don was a great experience, and I can honestly say that I learned more about the software business from both him and Tammie than I could have managed anywhere else. It was a rare opportunity for an inexperienced programmer, and I really feel luck to have had the opportunity, and to have gotten to know Don.</p>
<p>May he rest in peace.</p>
]]></content:encoded>
			<wfw:commentRss>http://marknelson.us/2006/08/25/don-killen-rip/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Fun With Version Control</title>
		<link>http://marknelson.us/2000/06/01/version-control/</link>
		<comments>http://marknelson.us/2000/06/01/version-control/#comments</comments>
		<pubDate>Thu, 01 Jun 2000 15:01:37 +0000</pubDate>
		<dc:creator>Mark Nelson</dc:creator>
				<category><![CDATA[Magazine Articles]]></category>
		<category><![CDATA[Work]]></category>

		<guid isPermaLink="false">/2000/06/01/version-control/</guid>
		<description><![CDATA[<div class="addthis_toolbox addthis_default_style" addthis:url='http://marknelson.us/2000/06/01/version-control/' addthis:title='Fun With Version Control' ><a class="addthis_button_twitter"></a><a class="addthis_button_favorites"></a><a class="addthis_button_print"></a><a class="addthis_button_facebook_like"></a><a class="addthis_button_google_plusone"></a><a class="addthis_button_compact"></a></div>An article written with Ping Ni in which we describe some of the joys of keeping versions straight when developing complex Windows programs.]]></description>
			<content:encoded><![CDATA[



<div class="addthis_toolbox addthis_default_style" addthis:url='http://marknelson.us/2000/06/01/version-control/' addthis:title='Fun With Version Control' ><a class="addthis_button_twitter"></a><a class="addthis_button_favorites"></a><a class="addthis_button_print"></a><a class="addthis_button_facebook_like"></a><a class="addthis_button_google_plusone"></a><a class="addthis_button_compact"></a></div><table border="0">
<tr>
<td style="width: 33%"><img alt="DDJ Cover from June, 2000" src="http://marknelson.us/attachments/2000/version-control/ddj_2000_06.jpg" /></td>
<td style="width: 66%"><strong>Dr. Dobb's Journal</strong> June, 2000<br/>by Mark Nelson and Ping Ni</td>
</tr>
</table>
<p>Windows users are all familiar with the concept of DLL hell. This occurs when applications try to work with mismatched versions of DLLs, resulting in bugs, poor performance, and even system crashes. Although all operating systems are vulnerable to versioning troubles, Windows seems to be particularly prone to problems in this area.</p>
<p>Under certain circumstances, DLL hell can become magnified to an excruciating level. We found ourselves in position over the last several months while working on a large development project. This project involves geographically scattered teams of programmers, distributed object technology, and dozens of DLLs and executables.  With interfaces and capabilities changing on a daily basis, we found that a good system of version management was crucial to our continued progress. When the system breaks down, mass confusion can idle dozens of highly paid programmers and Q/A personnel. This is not a good thing.</p>
<h4>Where we need it</h4>
<p>To get this problem under control, we first identified four critical places where we need to know the version of an executable or DLL.</p>
<h4>1: When looking directly at a file</h4>
<p>Working with developers when a project is changing rapidly can be very frustrating for Q/A people. It seems that no matter what sort of problem they report, the immediate response from development goes something like “You need to get the latest version, that bug has been fixed.”</p>
<p>Because of this sort of response, it is vital that end users be able to easily determine what version of a DLL or executable is installed on their system. To make this as easy as possible, Microsoft created a standardized method for setting product versions under Windows. One of the standard resource types that can be bound to a project is a Version resource. Our project is built using Visual C++, which stores the version resource in an RC file. Figure 1 shows a typical view of this version information from the IDE.</p>
<p><center><br />
<img src="http://marknelson.us/attachments/2000/version-control/Figure1.gif"><br />
Figure 1<br />
Version information in a Visual Studio project<br />
</center></p>
<p>Note that the resource shown in Figure 1 appears to have duplicates of the version information. The Key values named <span class="inline_code">FILEVERSION </span>and <span class="inline_code">PRODUCTVERSION </span>in the upper half of the display are in the fixed-info section of the resource. These two values are stored as <span class="inline_code">DWORDs </span>in the EXE or DLL file, and as such are useful for using in numerical tests of version properties. The values labeled <span class="inline_code">FileVersion </span>and <span class="inline_code">ProductVersion </span>are string parameters, and are useful for displaying to end users or printing in trace files. Keeping numbers in two places certainly makes us more vulnerable to mistakes, but sometimes we have to make compromises to do things the Microsoft way!</p>
<p>Once the version information is bound into the executable or DLL, an end user can view it by simply asking for the properties of the file from an Explorer view. Figure 2 shows the version information that Windows displays from this view. (Note that the O/S shows the string values, not the fixed-info numeric values.)</p>
<p><center><br />
<img src="http://marknelson.us/attachments/2000/version-control/Figure2.gif"><br />
Figure 2<br />
The Win32 file properties dialog<br />
</center></p>
<h4>2: When reading trace files</h4>
<p>One very common technique used to capture debugging information is the use of a trace or log file. This is usually a simple ASCII text file that can be easily viewed or printed out. Q/A testers know that if they can attach a trace file to a bug report the odds of a fix improve greatly. Unfortunately, developers will always want to know what version of the program was used to create the trace file.</p>
<p>A proactive way to deal with this question is to always print the component version number as one of the first lines in a trace file. That can be done with a line as simple as this:</p>
<div class="igBar"><span id="lcode-1"><a href="#" onclick="javascript:showPlainTxt('code-1'); return false;">PLAIN TEXT</a></span></div>
<div class="syntax_hilite"><span class="langName">CODE:</span>
<div id="code-1">
<div class="code">
<ol>
<li class="li1">
<div class="de1">Log &lt;&lt;<span class="st0">"FOO.EXE version 1.2<span class="es0">\n</span>"</span>; </div>
</li>
</ol>
</div>
</div>
</div>
<p></p>
<h4>3: Checking versions at run time</h4>
<p>A standard part of any Windows program is the generic About Box. Good programmers always take care to include version information in the About Box. Figure 3 shows a sample of this dialog from a typical Windows application.</p>
<p><center><br />
<img src="http://marknelson.us/attachments/2000/version-control/Figure3.gif"><br />
Figure 3<br />
The About Box from Microsoft Outlook Express<br />
</center></p>
<p>The About Box is just a simple Windows Dialog, which is usually defined in the RC file along with other resource information. The simplest (and probably most common) way to put the version information in the dialog is to create a static text resource that contains the ASCII text verbatim.</p>
<h4>4: Checking out modules from source code control</h4>
<p>Source code control is a key component of modern team-based development. Every source code control system in use today allows programming teams to label a package of files with a version number. That package can then be retrieved by name at any time in the future, which gives developers an easy way to follow the life history of bugs. We frequently find that Q/A is testing a product release that is a few versions behind what development is presently testing.</p>
<p>We use Visual Source Safe for our source code control system. Most of our development staff uses the GUI based front end for this program. When we want to identify a particular version of our package, we right click on a project, and then select the Label menu item. This brings up a dialog box as shown in Figure 4. Typing in the version number causes Visual Source Safe to create a checkpoint for every file in that project. At any time in the future we can ask VSS for copies of all the files for that particular version. (This can include executable and DLL versions as well.) </p>
<p><center><br />
<img src="http://marknelson.us/attachments/2000/version-control/Figure4.gif"><br />
Figure 4<br />
Labeling a project in Visual Source Safe<br />
</center></p>
<h4>What’s wrong with this picture?</h4>
<p>At this point it might seem that we’ve got our version control problem pretty well under control. But experienced programmers should see right away that we’ve got a real problem. We’ve got one piece of data, the version number, and it has to be stored in four different places. This situation should set off alarms any time you see it, because we’ve set up a system that only works if we have perfect adherence to a multi-step procedure. Updating version numbers means editing an RC file in at least two places, locating and editing trace file function calls, and correctly determining the projects to label in the source code control system.</p>
<p>A typical situation we run into at work might have a team of ten people working on the release of fifteen or twenty components. To make sure that we update all version information correctly might involve as many as fifty separate procedures. What are the chances that someone might forget to update the version number in a single About Box, or incorrectly label the VSS project in question? A single mistake such as this can cause immense confusion the next time a bug is reported for a incorrectly identified component.</p>
<p>While it would be possible to create a written procedure list and require people to verify each and every step, it’s infinitely better to set up a system that allows for one-step version setting system. By updating all version information in one step, we are no longer vulnerable to human frailty. If the process is set up properly one time, it should work correctly every time it is used in the future.</p>
<h4>The Perl Solution</h4>
<p>Physicists have been battling for years to unify the four fundamental forces of nature: gravity, electromagnetism, the weak force, and the strong force. While it may have been hubris on our part, we were determined to find a unified way to set the versions in the four different areas of our development process.</p>
<p>The key to the solution was finding a programmatic way to update the version numbers used everywhere in the program. The only thing we needed to do in order to make this happen was to modify the version resource in each component’s RC file. This meant doing a bit of simple parsing and text modification. And without a doubt, the tool most suitable to this task has to be Perl.</p>
<p>Using Perl, it was a quick matter to write a script that we now use to increment either the major or minor version of an entire batch of components. The resulting script, <em>IncVersion.pl</em>, is shown in Listing 1.</p>
<p><em>IncVersion.pl</em> is invoked with an initial argument of major or minor, followed by a list of projects. It then works its way through each of the projects, modifying the RC file for each project. There are two lines in each RC file that need to be modified. The first looks something like this:</p>
<div class="igBar"><span id="lcode-2"><a href="#" onclick="javascript:showPlainTxt('code-2'); return false;">PLAIN TEXT</a></span></div>
<div class="syntax_hilite"><span class="langName">CODE:</span>
<div id="code-2">
<div class="code">
<ol>
<li class="li1">
<div class="de1">FILEVERSION&nbsp; &nbsp; &nbsp; &nbsp;<span class="nu0">5</span>,<span class="nu0">0</span>,<span class="nu0">1</span>,<span class="nu0">0</span> </div>
</li>
</ol>
</div>
</div>
</div>
<p></p>
<p>And the second looks like this:</p>
<div class="igBar"><span id="lcode-3"><a href="#" onclick="javascript:showPlainTxt('code-3'); return false;">PLAIN TEXT</a></span></div>
<div class="syntax_hilite"><span class="langName">CODE:</span>
<div id="code-3">
<div class="code">
<ol>
<li class="li1">
<div class="de1">VALUE <span class="st0">"FileVersion"</span>,&nbsp; &nbsp; &nbsp;<span class="st0">"5.1<span class="es0">\0</span>"</span> </div>
</li>
</ol>
</div>
</div>
</div>
<p></p>
<p>The Perl script locates this line in each RC file, and updates the version number in one of two ways. If the initial argument is minor, the last digit in the version is incremented. For example, the version in the lines shown above will change from 5.1 to 5.2. If the initial argument is major, the first digit in the version is incremented. The version above would change from 5.1 to 6.0. (Note that this simple example uses version numbers with just two components.) The <span class="inline_code">FILEVERSION </span>string in the two examples would change to either 5,0,2,0 or 6,0,0,0.</p>
<h4>Some programming details</h4>
<p>The Perl script <em>IncVersion.pl</em> provides an automated way to change the version resource for a given DLL or EXE. By executing it with the correct list of projects, it's possible to automatically update all the components of a big project in an automated way. This is clearly going to cut down on procedural and typing mistakes. But it is still a long way from a unified version system. This only affects the first place where we need version information, which is in the Windows property view. The remaining three cases don't get any help from this at all.</p>
<p>As it turns out, two of the remaining cases are fixed with just a bit of code. In the strategy we were using previously, the version numbers sent to the trace file and shown in the About Box were both hard-coded. A better strategy is to extract the version information from the RC file. Listing 2 shows a C++ routine that can be used to get the version number from the RC file for a given module. We provide routines to read the version information from either the fixed-info or string version resources. (In practice you can arbitrarily choose one or the other.) Now my logging output should look something like this:</p>
<div class="igBar"><span id="lcode-4"><a href="#" onclick="javascript:showPlainTxt('code-4'); return false;">PLAIN TEXT</a></span></div>
<div class="syntax_hilite"><span class="langName">CODE:</span>
<div id="code-4">
<div class="code">
<ol>
<li class="li1">
<div class="de1">Log &lt;&lt;<span class="st0">"FOO.EXE version "</span> &lt;&lt;StringModuleVersion<span class="br0">&#40;</span><span class="br0">&#41;</span> &lt;&lt;<span class="st0">"<span class="es0">\n</span>"</span>; </div>
</li>
</ol>
</div>
</div>
</div>
<p></p>
<p>Likewise, the About Box code can be generated dynamically as well. If your About Box is a standard Windows Dialog, you only have to override the <span class="inline_code">WM_INITDIALOG</span> message and insert the appropriate text into a static text control. In an MFC app, the code might look something like this:</p>
<div class="igBar"><span id="lcpp-5"><a href="#" onclick="javascript:showPlainTxt('cpp-5'); return false;">PLAIN TEXT</a></span></div>
<div class="syntax_hilite"><span class="langName">C++:</span>
<div id="cpp-5">
<div class="cpp">
<ol>
<li class="li1">
<div class="de1"><span class="kw4">BOOL</span> CAboutDlg::<span class="me2">OnInitDialog</span><span class="br0">&#40;</span><span class="br0">&#41;</span> </div>
</li>
<li class="li2">
<div class="de2"><span class="br0">&#123;</span></div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; stringstream s;</div>
</li>
<li class="li2">
<div class="de2">&nbsp; &nbsp; s &lt;&lt;<span class="st0">"GuiFoo.exe version "</span> &lt;&lt;ModuleVersion<span class="br0">&#40;</span><span class="br0">&#41;</span>;</div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; SetDlgItemText<span class="br0">&#40;</span> IDC_VERSION_BOX, s.<span class="me1">str</span><span class="br0">&#40;</span><span class="br0">&#41;</span>.<span class="me1">c_str</span><span class="br0">&#40;</span><span class="br0">&#41;</span> <span class="br0">&#41;</span>;</div>
</li>
<li class="li2">
<div class="de2">&nbsp; &nbsp; CDialog::<span class="me2">OnInitDialog</span><span class="br0">&#40;</span><span class="br0">&#41;</span>;i</div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; <span class="kw1">return</span> <span class="kw2">TRUE</span>;</div>
</li>
<li class="li2">
<div class="de2"><span class="br0">&#125;</span> </div>
</li>
</ol>
</div>
</div>
</div>
<p></p>
<h4>BAT file considered helpful</h4>
<p>By using these minor modifications, we now have automatic version number control in three of the four designated places. Unfortunately, the fourth target of our version control system is a little more difficult to deal with. Remember that each new version of our project needs to have a label associated with it under our version control system. It would be nice if Visual Source Safe could just read the contents of the version resource in each project's RC file, but at this time it doesn't know how to do that. Accordingly, we have to manually label each new version of our project after it has been checked in.</p>
<p>Although we usually use Visual Source Safe's GUI interface, it can also be invoked from the command line. We make use of this in our versioning system by having <em>IncVersion.pl</em> generate a BAT file that will apply the appropriate label to the currently selected project in Visual Source Safe. A typical <em>LABEL.BAT</em> file will look like this:</p>
<div class="igBar"><span id="lcode-6"><a href="#" onclick="javascript:showPlainTxt('code-6'); return false;">PLAIN TEXT</a></span></div>
<div class="syntax_hilite"><span class="langName">CODE:</span>
<div id="code-6">
<div class="code">
<ol>
<li class="li1">
<div class="de1">ss label -C -L<span class="st0">"PROJECT 2.1"</span> </div>
</li>
</ol>
</div>
</div>
</div>
<p></p>
<p>The Perl script can be modified to generate the project label you want, the important thing is that the version number in the label is identical to that placed in the RC files.</p>
<p>Given the existence of <em>LABEL.BAT</em>, tying all the pieces of the puzzle together is done via one master BAT file. Ours is called <em>UPDATE.BAT</em>, and it looks something like this:</p>
<div class="igBar"><span id="lcode-7"><a href="#" onclick="javascript:showPlainTxt('code-7'); return false;">PLAIN TEXT</a></span></div>
<div class="syntax_hilite"><span class="langName">CODE:</span>
<div id="code-7">
<div class="code">
<ol>
<li class="li1">
<div class="de1">call checkout.<span class="me1">bat</span></div>
</li>
<li class="li2">
<div class="de2">IncVersion.<span class="me1">pl</span> minor FOO_A FOO_B FOO_C FOO_D </div>
</li>
<li class="li1">
<div class="de1">all makeall.<span class="me1">bat</span></div>
</li>
<li class="li2">
<div class="de2">call checkin.<span class="me1">bat</span></div>
</li>
<li class="li1">
<div class="de1">ss CP $/Projects/FOO</div>
</li>
<li class="li2">
<div class="de2">call label.<span class="me1">bat</span> </div>
</li>
</ol>
</div>
</div>
</div>
<p></p>
<p>The BAT files called to check out the projects, build the components, then check them back in are all very specific to our projects, and will need to be tailored to each projects needs. <em>CHECKIN.BAT</em> and <em>CHECKOUT.BAT</em> just make calls to the command line interface of Visual Source Safe. <em>MAKEALL.BAT</em> invokes the command line <em>NMAKE</em> tool supplied with Visual Source Safe.</p>
<h4>Conclusion</h4>
<p>Managing version information in a large project doesn't have a nice tidy management solution, at least not with our Win32 development tools. However, by making a few modifications to our source code, and resorting to some old-fashioned command line tools, we have developed a system that does a great job of protecting us from minor version snafus. It does this by doing all version updates in one fell swoop, which makes sure that the process occurs across all components of the system at once. It isn't perfect, and may not even be ideal, but it's working for us. </p>
<h4>Listings</h4>
<p>Listing 1<br />
<em>IncVersion.pl</em>:</p>
<div class="igBar"><span id="lperl-8"><a href="#" onclick="javascript:showPlainTxt('perl-8'); return false;">PLAIN TEXT</a></span></div>
<div class="syntax_hilite"><span class="langName">PERL:</span>
<div id="perl-8">
<div class="perl">
<ol>
<li class="li1">
<div class="de1"><span class="co1">#####################################################################################</span></div>
</li>
<li class="li2">
<div class="de2"><span class="co1"># This program will change the FileVersion and FILEVERSION accordingly and set them</span></div>
</li>
<li class="li1">
<div class="de1"><span class="co1"># consistently across all the directories.</span></div>
</li>
<li class="li2">
<div class="de2"><span class="co1">#</span></div>
</li>
<li class="li1">
<div class="de1"><span class="co1"># To use this program, run as</span></div>
</li>
<li class="li2">
<div class="de2"><span class="co1">#&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;IncVersion.pl major project-1 project-2 ...</span></div>
</li>
<li class="li1">
<div class="de1"><span class="co1">#&nbsp; or</span></div>
</li>
<li class="li2">
<div class="de2"><span class="co1">#&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;IncVersion.pl minor project-1 project-2 ...</span></div>
</li>
<li class="li1">
<div class="de1"><span class="co1">#</span></div>
</li>
<li class="li2">
<div class="de2"><span class="co1"># The version info will be used to generate label.bat that can be call to label files</span></div>
</li>
<li class="li1">
<div class="de1"><span class="co1">#&nbsp; &nbsp; &nbsp; &nbsp;in SourceSafe.</span></div>
</li>
<li class="li2">
<div class="de2"><span class="co1">#####################################################################################</span></div>
</li>
<li class="li1">
<div class="de1">&nbsp;</div>
</li>
<li class="li2">
<div class="de2">&nbsp; <span class="re0">$maxMajor</span> = <span class="nu0">0</span>;</div>
</li>
<li class="li1">
<div class="de1">&nbsp; <span class="re0">$maxMinor</span> = <span class="nu0">0</span>;</div>
</li>
<li class="li2">
<div class="de2">&nbsp; <span class="re0">$count</span> = <span class="nu0">1</span>;</div>
</li>
<li class="li1">
<div class="de1">&nbsp;</div>
</li>
<li class="li2">
<div class="de2"><span class="co1"># find the max of major and minor version number</span></div>
</li>
<li class="li1">
<div class="de1">&nbsp; <span class="kw1">while</span> <span class="br0">&#40;</span><span class="re0">$count</span> &lt;= $<span class="co1">#ARGV) {</span></div>
</li>
<li class="li2">
<div class="de2">&nbsp; &nbsp; <span class="re0">$file1</span> = <span class="re0">$ARGV</span><span class="br0">&#91;</span><span class="re0">$count</span><span class="br0">&#93;</span>.<span class="st0">"<span class="es0">\\</span>"</span>.<span class="re0">$ARGV</span><span class="br0">&#91;</span><span class="re0">$count</span><span class="br0">&#93;</span>.<span class="st0">".rc"</span>;</div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; <a href="http://www.perldoc.com/perl5.6/pod/func/eval.html"><span class="kw3">eval</span></a> <span class="br0">&#123;</span> SetMax<span class="br0">&#40;</span><span class="br0">&#41;</span> <span class="br0">&#125;</span>;</div>
</li>
<li class="li2">
<div class="de2">&nbsp; &nbsp; <a href="http://www.perldoc.com/perl5.6/pod/func/print.html"><span class="kw3">print</span></a> $@;</div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; <span class="re0">$count</span>++;</div>
</li>
<li class="li2">
<div class="de2">&nbsp; <span class="br0">&#125;</span></div>
</li>
<li class="li1">
<div class="de1">&nbsp;</div>
</li>
<li class="li2">
<div class="de2">&nbsp; <span class="kw1">if</span> <span class="br0">&#40;</span><span class="re0">$ARGV</span><span class="br0">&#91;</span><span class="nu0">0</span><span class="br0">&#93;</span> eq <span class="st0">"major"</span><span class="br0">&#41;</span> <span class="br0">&#123;</span></div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; <span class="re0">$maxMajor</span>++;</div>
</li>
<li class="li2">
<div class="de2">&nbsp; &nbsp; <span class="re0">$maxMinor</span> = <span class="nu0">0</span>;</div>
</li>
<li class="li1">
<div class="de1">&nbsp; <span class="br0">&#125;</span> <span class="kw1">else</span> <span class="br0">&#123;</span></div>
</li>
<li class="li2">
<div class="de2">&nbsp; &nbsp; <span class="re0">$maxMinor</span>++;</div>
</li>
<li class="li1">
<div class="de1">&nbsp; <span class="br0">&#125;</span></div>
</li>
<li class="li2">
<div class="de2">&nbsp;</div>
</li>
<li class="li1">
<div class="de1"><span class="co1"># write a batch file to be called later to set labels in SourceSafe</span></div>
</li>
<li class="li2">
<div class="de2">&nbsp;</div>
</li>
<li class="li1">
<div class="de1">&nbsp; <span class="re0">$labelFile</span> = <span class="st0">"label.bat"</span>;</div>
</li>
<li class="li2">
<div class="de2">&nbsp; <a href="http://www.perldoc.com/perl5.6/pod/func/open.html"><span class="kw3">open</span></a><span class="br0">&#40;</span>OutLabel, <span class="st0">"&gt;$labelFile"</span><span class="br0">&#41;</span> || <a href="http://www.perldoc.com/perl5.6/pod/func/die.html"><span class="kw3">die</span></a> <span class="st0">"Failed to open $labelFile to write<span class="es0">\n</span><span class="es0">\t</span>$!<span class="es0">\n</span>"</span>;</div>
</li>
<li class="li1">
<div class="de1">&nbsp; <a href="http://www.perldoc.com/perl5.6/pod/func/print.html"><span class="kw3">print</span></a> OutLabel <span class="st0">"ss label -C- -L<span class="es0">\"</span>PROJECT $maxMajor<span class="es0">\.</span>$maxMinor<span class="es0">\"</span><span class="es0">\n</span>"</span>;</div>
</li>
<li class="li2">
<div class="de2">&nbsp; <a href="http://www.perldoc.com/perl5.6/pod/func/close.html"><span class="kw3">close</span></a><span class="br0">&#40;</span>OutLabel<span class="br0">&#41;</span>;</div>
</li>
<li class="li1">
<div class="de1">&nbsp;</div>
</li>
<li class="li2">
<div class="de2">&nbsp; <span class="re0">$count</span> = <span class="nu0">1</span>;</div>
</li>
<li class="li1">
<div class="de1">&nbsp; <span class="kw1">while</span> <span class="br0">&#40;</span><span class="re0">$count</span> &lt;= $<span class="co1">#ARGV) {</span></div>
</li>
<li class="li2">
<div class="de2">&nbsp; &nbsp; <span class="re0">$file1</span> = <span class="re0">$ARGV</span><span class="br0">&#91;</span><span class="re0">$count</span><span class="br0">&#93;</span>.<span class="st0">"<span class="es0">\\</span>"</span>.<span class="re0">$ARGV</span><span class="br0">&#91;</span><span class="re0">$count</span><span class="br0">&#93;</span>.<span class="st0">".rc"</span>;</div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; <span class="re0">$file2</span> = <span class="re0">$ARGV</span><span class="br0">&#91;</span><span class="re0">$count</span><span class="br0">&#93;</span>.<span class="st0">"<span class="es0">\\</span>"</span>.<span class="re0">$ARGV</span><span class="br0">&#91;</span><span class="re0">$count</span><span class="br0">&#93;</span>.<span class="st0">".tmp"</span>;</div>
</li>
<li class="li2">
<div class="de2">&nbsp; &nbsp; <a href="http://www.perldoc.com/perl5.6/pod/func/eval.html"><span class="kw3">eval</span></a> <span class="br0">&#123;</span> ProcessFile<span class="br0">&#40;</span><span class="br0">&#41;</span><span class="br0">&#125;</span>;</div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; <span class="kw1">if</span> <span class="br0">&#40;</span>$@<span class="br0">&#41;</span> <span class="br0">&#123;</span> </div>
</li>
<li class="li2">
<div class="de2">&nbsp; &nbsp; &nbsp; <a href="http://www.perldoc.com/perl5.6/pod/func/print.html"><span class="kw3">print</span></a> $@;</div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; <span class="br0">&#125;</span> <span class="kw1">else</span> <span class="br0">&#123;</span></div>
</li>
<li class="li2">
<div class="de2">&nbsp; &nbsp; &nbsp; <a href="http://www.perldoc.com/perl5.6/pod/func/eval.html"><span class="kw3">eval</span></a> <span class="br0">&#123;</span> CopyFile<span class="br0">&#40;</span><span class="br0">&#41;</span><span class="br0">&#125;</span>;</div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; &nbsp; <a href="http://www.perldoc.com/perl5.6/pod/func/print.html"><span class="kw3">print</span></a> $@;</div>
</li>
<li class="li2">
<div class="de2">&nbsp; &nbsp; <span class="br0">&#125;</span></div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; <span class="re0">$count</span>++;</div>
</li>
<li class="li2">
<div class="de2">&nbsp; <span class="br0">&#125;</span></div>
</li>
<li class="li1">
<div class="de1">&nbsp;</div>
</li>
<li class="li2">
<div class="de2"><span class="kw2">sub</span> SetMax <span class="br0">&#123;</span></div>
</li>
<li class="li1">
<div class="de1">&nbsp; <a href="http://www.perldoc.com/perl5.6/pod/func/print.html"><span class="kw3">print</span></a> <span class="st0">"Find the max in $file1<span class="es0">\n</span>"</span>;</div>
</li>
<li class="li2">
<div class="de2">&nbsp; <a href="http://www.perldoc.com/perl5.6/pod/func/open.html"><span class="kw3">open</span></a><span class="br0">&#40;</span>InRC, <span class="st0">"$file1"</span><span class="br0">&#41;</span> || <a href="http://www.perldoc.com/perl5.6/pod/func/die.html"><span class="kw3">die</span></a> <span class="st0">"Failed to open $file1 to read<span class="es0">\n</span><span class="es0">\t</span>$!<span class="es0">\n</span>"</span>;</div>
</li>
<li class="li1">
<div class="de1">&nbsp; <span class="kw1">while</span> <span class="br0">&#40;</span><span class="re0">$_</span> = <span class="re4">&lt;InRC&gt;</span><span class="br0">&#41;</span>&nbsp; <span class="br0">&#123;</span></div>
</li>
<li class="li2">
<div class="de2">&nbsp; &nbsp; <span class="kw1">if</span> <span class="br0">&#40;</span><span class="re0">$_</span> =~/FILEVERSION/<span class="br0">&#41;</span> <span class="br0">&#123;</span></div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; &nbsp; <span class="re0">@currentLine</span> = <a href="http://www.perldoc.com/perl5.6/pod/func/split.html"><span class="kw3">split</span></a><span class="br0">&#40;</span><span class="st0">' '</span>, <span class="re0">$_</span><span class="br0">&#41;</span>;</div>
</li>
<li class="li2">
<div class="de2">&nbsp; &nbsp; &nbsp; <span class="re0">@oldVersion</span>&nbsp; = <a href="http://www.perldoc.com/perl5.6/pod/func/split.html"><span class="kw3">split</span></a><span class="br0">&#40;</span><span class="st0">','</span>, <span class="re0">$currentLine</span><span class="br0">&#91;</span><span class="nu0">1</span><span class="br0">&#93;</span><span class="br0">&#41;</span>;</div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; &nbsp; <span class="kw1">if</span> <span class="br0">&#40;</span><span class="re0">$oldVersion</span><span class="br0">&#91;</span><span class="nu0">0</span><span class="br0">&#93;</span>&gt; <span class="re0">$maxMajor</span><span class="br0">&#41;</span> <span class="br0">&#123;</span></div>
</li>
<li class="li2">
<div class="de2">&nbsp; &nbsp; &nbsp; &nbsp; <span class="re0">$maxMajor</span> = <span class="re0">$oldVersion</span><span class="br0">&#91;</span><span class="nu0">0</span><span class="br0">&#93;</span>;</div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; &nbsp; <span class="br0">&#125;</span></div>
</li>
<li class="li2">
<div class="de2">&nbsp; &nbsp; &nbsp; <span class="kw1">if</span> <span class="br0">&#40;</span><span class="re0">$oldVersion</span><span class="br0">&#91;</span><span class="nu0">2</span><span class="br0">&#93;</span>&gt; <span class="re0">$maxMinor</span><span class="br0">&#41;</span> <span class="br0">&#123;</span></div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; &nbsp; &nbsp; <span class="re0">$maxMinor</span> = <span class="re0">$oldVersion</span><span class="br0">&#91;</span><span class="nu0">2</span><span class="br0">&#93;</span>;</div>
</li>
<li class="li2">
<div class="de2">&nbsp; &nbsp; &nbsp; <span class="br0">&#125;</span></div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; <span class="br0">&#125;</span> <span class="kw1">elsif</span> <span class="br0">&#40;</span><span class="re0">$_</span>&nbsp; =~/FileVersion/<span class="br0">&#41;</span> <span class="br0">&#123;</span></div>
</li>
<li class="li2">
<div class="de2">&nbsp; &nbsp; &nbsp; <span class="re0">@currentLine</span> = <a href="http://www.perldoc.com/perl5.6/pod/func/split.html"><span class="kw3">split</span></a><span class="br0">&#40;</span><span class="st0">' '</span>, <span class="re0">$_</span><span class="br0">&#41;</span>;</div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; &nbsp; <span class="re0">@item</span>&nbsp; &nbsp; &nbsp; &nbsp; = <a href="http://www.perldoc.com/perl5.6/pod/func/split.html"><span class="kw3">split</span></a><span class="br0">&#40;</span><span class="st0">'&quot;'</span>, <span class="re0">@currentLine</span><span class="br0">&#91;</span><span class="nu0">2</span><span class="br0">&#93;</span><span class="br0">&#41;</span>;</div>
</li>
<li class="li2">
<div class="de2">&nbsp; &nbsp; &nbsp; <span class="re0">@vItem</span>&nbsp; &nbsp; &nbsp; &nbsp;= <a href="http://www.perldoc.com/perl5.6/pod/func/split.html"><span class="kw3">split</span></a><span class="br0">&#40;</span>/\\/, <span class="re0">@item</span><span class="br0">&#91;</span><span class="nu0">1</span><span class="br0">&#93;</span><span class="br0">&#41;</span>;</div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; &nbsp; <span class="re0">@version</span>&nbsp; &nbsp; &nbsp;= <a href="http://www.perldoc.com/perl5.6/pod/func/split.html"><span class="kw3">split</span></a><span class="br0">&#40;</span><span class="st0">'<span class="es0">\.</span>'</span>, <span class="re0">$vItem</span><span class="br0">&#91;</span><span class="nu0">0</span><span class="br0">&#93;</span><span class="br0">&#41;</span>;</div>
</li>
<li class="li2">
<div class="de2">&nbsp; &nbsp; &nbsp; <span class="kw1">if</span> <span class="br0">&#40;</span><span class="re0">$version</span><span class="br0">&#91;</span><span class="nu0">0</span><span class="br0">&#93;</span>&gt; <span class="re0">$maxMajor</span><span class="br0">&#41;</span> <span class="br0">&#123;</span></div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; &nbsp; &nbsp; <span class="re0">$maxMajor</span> = <span class="re0">$version</span><span class="br0">&#91;</span><span class="nu0">0</span><span class="br0">&#93;</span>;</div>
</li>
<li class="li2">
<div class="de2">&nbsp; &nbsp; &nbsp; <span class="br0">&#125;</span></div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; &nbsp; <span class="kw1">if</span> <span class="br0">&#40;</span><span class="re0">$version</span><span class="br0">&#91;</span><span class="nu0">1</span><span class="br0">&#93;</span>&gt; <span class="re0">$maxMinor</span><span class="br0">&#41;</span> <span class="br0">&#123;</span></div>
</li>
<li class="li2">
<div class="de2">&nbsp; &nbsp; &nbsp; &nbsp; <span class="re0">$maxMinor</span> = <span class="re0">$version</span><span class="br0">&#91;</span><span class="nu0">1</span><span class="br0">&#93;</span>;</div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; &nbsp; <span class="br0">&#125;</span></div>
</li>
<li class="li2">
<div class="de2">&nbsp; &nbsp; <span class="br0">&#125;</span></div>
</li>
<li class="li1">
<div class="de1">&nbsp; <span class="br0">&#125;</span></div>
</li>
<li class="li2">
<div class="de2">&nbsp; <a href="http://www.perldoc.com/perl5.6/pod/func/close.html"><span class="kw3">close</span></a> <span class="br0">&#40;</span>InRC<span class="br0">&#41;</span>;</div>
</li>
<li class="li1">
<div class="de1"><span class="br0">&#125;</span></div>
</li>
<li class="li2">
<div class="de2">&nbsp;</div>
</li>
<li class="li1">
<div class="de1"><span class="kw2">sub</span> ProcessFile <span class="br0">&#123;</span></div>
</li>
<li class="li2">
<div class="de2">&nbsp; <a href="http://www.perldoc.com/perl5.6/pod/func/print.html"><span class="kw3">print</span></a> <span class="st0">"Converting $file1 to $file2<span class="es0">\n</span>"</span>;</div>
</li>
<li class="li1">
<div class="de1">&nbsp; <a href="http://www.perldoc.com/perl5.6/pod/func/open.html"><span class="kw3">open</span></a><span class="br0">&#40;</span>InRC, <span class="st0">"$file1"</span><span class="br0">&#41;</span> || <a href="http://www.perldoc.com/perl5.6/pod/func/die.html"><span class="kw3">die</span></a> <span class="st0">"Failed to open $file1 to read<span class="es0">\n</span><span class="es0">\t</span>$!<span class="es0">\n</span>"</span>;</div>
</li>
<li class="li2">
<div class="de2">&nbsp; <a href="http://www.perldoc.com/perl5.6/pod/func/open.html"><span class="kw3">open</span></a><span class="br0">&#40;</span>OutRC, <span class="st0">"&gt;$file2"</span><span class="br0">&#41;</span> || <a href="http://www.perldoc.com/perl5.6/pod/func/die.html"><span class="kw3">die</span></a> <span class="st0">"Failed to open $file2 to write<span class="es0">\n</span><span class="es0">\t</span>$!<span class="es0">\n</span>"</span>;</div>
</li>
<li class="li1">
<div class="de1">&nbsp; <span class="kw1">while</span> <span class="br0">&#40;</span><span class="re0">$_</span> = <span class="re4">&lt;InRC&gt;</span><span class="br0">&#41;</span>&nbsp; <span class="br0">&#123;</span></div>
</li>
<li class="li2">
<div class="de2">&nbsp; &nbsp; <span class="kw1">if</span> <span class="br0">&#40;</span><span class="re0">$_</span> =~/FILEVERSION/<span class="br0">&#41;</span></div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; &nbsp; <span class="br0">&#123;</span></div>
</li>
<li class="li2">
<div class="de2">&nbsp; &nbsp; &nbsp; <a href="http://www.perldoc.com/perl5.6/pod/func/print.html"><span class="kw3">print</span></a> OutRC <span class="st0">" FILEVERSION $maxMajor,0,$maxMinor,0<span class="es0">\n</span>"</span>;</div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; &nbsp; <span class="br0">&#125;</span></div>
</li>
<li class="li2">
<div class="de2">&nbsp; &nbsp; <span class="kw1">elsif</span> <span class="br0">&#40;</span><span class="re0">$_</span>&nbsp; =~/FileVersion/<span class="br0">&#41;</span></div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; &nbsp; <span class="br0">&#123;</span></div>
</li>
<li class="li2">
<div class="de2">&nbsp; &nbsp; &nbsp; <a href="http://www.perldoc.com/perl5.6/pod/func/print.html"><span class="kw3">print</span></a> OutRC <span class="st0">"<span class="es0">\t</span>&nbsp; &nbsp; VALUE <span class="es0">\"</span>FileVersion<span class="es0">\"</span>, <span class="es0">\"</span>$maxMajor.$maxMinor<span class="es0">\\</span>0<span class="es0">\"</span><span class="es0">\n</span>"</span>;</div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; &nbsp; <span class="br0">&#125;</span></div>
</li>
<li class="li2">
<div class="de2">&nbsp; &nbsp; <span class="kw1">else</span></div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; &nbsp; <span class="br0">&#123;</span></div>
</li>
<li class="li2">
<div class="de2">&nbsp; &nbsp; &nbsp; <a href="http://www.perldoc.com/perl5.6/pod/func/print.html"><span class="kw3">print</span></a> OutRC <span class="st0">"$_"</span>;</div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; &nbsp; <span class="br0">&#125;</span></div>
</li>
<li class="li2">
<div class="de2">&nbsp; <span class="br0">&#125;</span></div>
</li>
<li class="li1">
<div class="de1">&nbsp; <a href="http://www.perldoc.com/perl5.6/pod/func/close.html"><span class="kw3">close</span></a> <span class="br0">&#40;</span>InRC<span class="br0">&#41;</span>;</div>
</li>
<li class="li2">
<div class="de2">&nbsp; <a href="http://www.perldoc.com/perl5.6/pod/func/close.html"><span class="kw3">close</span></a> <span class="br0">&#40;</span>outRC<span class="br0">&#41;</span>;</div>
</li>
<li class="li1">
<div class="de1"><span class="br0">&#125;</span></div>
</li>
<li class="li2">
<div class="de2">&nbsp;</div>
</li>
<li class="li1">
<div class="de1"><span class="kw2">sub</span> CopyFile <span class="br0">&#123;</span></div>
</li>
<li class="li2">
<div class="de2">&nbsp; <a href="http://www.perldoc.com/perl5.6/pod/func/print.html"><span class="kw3">print</span></a> <span class="st0">"Copying $file2 to $file1<span class="es0">\n</span>"</span>;</div>
</li>
<li class="li1">
<div class="de1">&nbsp; <a href="http://www.perldoc.com/perl5.6/pod/func/unlink.html"><span class="kw3">unlink</span></a><span class="br0">&#40;</span><span class="re0">$file1</span><span class="br0">&#41;</span>;</div>
</li>
<li class="li2">
<div class="de2">&nbsp; <a href="http://www.perldoc.com/perl5.6/pod/func/open.html"><span class="kw3">open</span></a><span class="br0">&#40;</span>InRC, <span class="st0">"$file2"</span><span class="br0">&#41;</span> || <a href="http://www.perldoc.com/perl5.6/pod/func/die.html"><span class="kw3">die</span></a> <span class="st0">"Failed to open $file2 to read<span class="es0">\n</span><span class="es0">\t</span>$!<span class="es0">\n</span>"</span>;</div>
</li>
<li class="li1">
<div class="de1">&nbsp; <a href="http://www.perldoc.com/perl5.6/pod/func/open.html"><span class="kw3">open</span></a><span class="br0">&#40;</span>OutRC, <span class="st0">"&gt;$file1"</span><span class="br0">&#41;</span> || <a href="http://www.perldoc.com/perl5.6/pod/func/die.html"><span class="kw3">die</span></a> <span class="st0">"Failed to open $file1 to write<span class="es0">\n</span><span class="es0">\t</span>$!<span class="es0">\n</span>"</span>;</div>
</li>
<li class="li2">
<div class="de2">&nbsp; <span class="kw1">while</span> <span class="br0">&#40;</span><span class="re0">$_</span> = <span class="re4">&lt;InRC&gt;</span><span class="br0">&#41;</span>&nbsp; <span class="br0">&#123;</span></div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; <a href="http://www.perldoc.com/perl5.6/pod/func/print.html"><span class="kw3">print</span></a> OutRC <span class="st0">"$_"</span>;</div>
</li>
<li class="li2">
<div class="de2">&nbsp; &nbsp; <span class="br0">&#125;</span></div>
</li>
<li class="li1">
<div class="de1">&nbsp; <a href="http://www.perldoc.com/perl5.6/pod/func/close.html"><span class="kw3">close</span></a> <span class="br0">&#40;</span>InRC<span class="br0">&#41;</span>;</div>
</li>
<li class="li2">
<div class="de2">&nbsp; <a href="http://www.perldoc.com/perl5.6/pod/func/close.html"><span class="kw3">close</span></a> <span class="br0">&#40;</span>outRC<span class="br0">&#41;</span>;</div>
</li>
<li class="li1">
<div class="de1"><span class="br0">&#125;</span> </div>
</li>
</ol>
</div>
</div>
</div>
<p></p>
<p>Listing 2<br />
Getting VersionInfo in C++:</p>
<div class="igBar"><span id="lcpp-9"><a href="#" onclick="javascript:showPlainTxt('cpp-9'); return false;">PLAIN TEXT</a></span></div>
<div class="syntax_hilite"><span class="langName">C++:</span>
<div id="cpp-9">
<div class="cpp">
<ol>
<li class="li1">
<div class="de1"><span class="co2">#include &lt;string&gt;</span></div>
</li>
<li class="li2">
<div class="de2"><span class="co2">#include &lt;vector&gt;</span></div>
</li>
<li class="li1">
<div class="de1"><span class="kw2">using</span> <span class="kw2">namespace</span> std;</div>
</li>
<li class="li2">
<div class="de2">&nbsp;</div>
</li>
<li class="li1">
<div class="de1"><span class="co1">//</span></div>
</li>
<li class="li2">
<div class="de2"><span class="co1">// This routine will extract the fixed-info version</span></div>
</li>
<li class="li1">
<div class="de1"><span class="co1">// information from the version resource in the RC</span></div>
</li>
<li class="li2">
<div class="de2"><span class="co1">// file for the current module. The four integers</span></div>
</li>
<li class="li1">
<div class="de1"><span class="co1">// that make up the fixed-info version information are</span></div>
</li>
<li class="li2">
<div class="de2"><span class="co1">// formatted into a string and returned to the caller.</span></div>
</li>
<li class="li1">
<div class="de1"><span class="co1">//</span></div>
</li>
<li class="li2">
<div class="de2">string FixedModuleVersion<span class="br0">&#40;</span><span class="br0">&#41;</span></div>
</li>
<li class="li1">
<div class="de1"><span class="br0">&#123;</span></div>
</li>
<li class="li2">
<div class="de2">&nbsp; &nbsp; <span class="kw4">char</span> file_name<span class="br0">&#91;</span> MAX_PATH <span class="br0">&#93;</span>;</div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; GetModuleFileName<span class="br0">&#40;</span> ::<span class="me2">GetModuleHandle</span><span class="br0">&#40;</span> <span class="kw2">NULL</span> <span class="br0">&#41;</span>, file_name, MAX_PATH <span class="br0">&#41;</span>;</div>
</li>
<li class="li2">
<div class="de2">&nbsp; &nbsp; DWORD dwDummyHandle; </div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; DWORD len = GetFileVersionInfoSize<span class="br0">&#40;</span> file_name, &amp;dwDummyHandle <span class="br0">&#41;</span>;</div>
</li>
<li class="li2">
<div class="de2">&nbsp; &nbsp; vector&lt;BYTE&gt; buf<span class="br0">&#40;</span> len <span class="br0">&#41;</span>;</div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; ::<span class="me2">GetFileVersionInfo</span><span class="br0">&#40;</span> file_name, <span class="nu0">0</span>, len, buf.<span class="me1">begin</span><span class="br0">&#40;</span><span class="br0">&#41;</span> <span class="br0">&#41;</span>;</div>
</li>
<li class="li2">
<div class="de2">&nbsp; &nbsp; <span class="kw4">unsigned</span> <span class="kw4">int</span> ver_length;</div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; LPVOID lpvi;</div>
</li>
<li class="li2">
<div class="de2">&nbsp; &nbsp; ::<span class="me2">VerQueryValue</span><span class="br0">&#40;</span> buf.<span class="me1">begin</span><span class="br0">&#40;</span><span class="br0">&#41;</span>,</div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;<span class="st0">"<span class="es0">\\</span>"</span>, </div>
</li>
<li class="li2">
<div class="de2">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&amp;lpvi,</div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&amp;ver_length <span class="br0">&#41;</span>;</div>
</li>
<li class="li2">
<div class="de2">&nbsp; &nbsp; VS_FIXEDFILEINFO fileInfo;</div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; fileInfo = *<span class="br0">&#40;</span>VS_FIXEDFILEINFO*<span class="br0">&#41;</span>lpvi;</div>
</li>
<li class="li2">
<div class="de2">&nbsp; &nbsp; stringstream s;</div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; s &lt;&lt;HIWORD<span class="br0">&#40;</span>fileInfo.<span class="me1">dwFileVersionMS</span><span class="br0">&#41;</span> &lt;&lt;<span class="st0">"."</span></div>
</li>
<li class="li2">
<div class="de2">&nbsp; &nbsp; &nbsp; &lt;&lt;LOWORD<span class="br0">&#40;</span>fileInfo.<span class="me1">dwFileVersionMS</span><span class="br0">&#41;</span> &lt;&lt;<span class="st0">"."</span></div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; &nbsp; &lt;&lt;HIWORD<span class="br0">&#40;</span>fileInfo.<span class="me1">dwFileVersionLS</span><span class="br0">&#41;</span> &lt;&lt;<span class="st0">"."</span></div>
</li>
<li class="li2">
<div class="de2">&nbsp; &nbsp; &nbsp; &lt;&lt;LOWORD<span class="br0">&#40;</span>fileInfo.<span class="me1">dwFileVersionLS</span><span class="br0">&#41;</span>;</div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; <span class="kw1">return</span> s.<span class="me1">str</span><span class="br0">&#40;</span><span class="br0">&#41;</span>;</div>
</li>
<li class="li2">
<div class="de2"><span class="br0">&#125;</span></div>
</li>
<li class="li1">
<div class="de1">&nbsp;</div>
</li>
<li class="li2">
<div class="de2"><span class="co1">//</span></div>
</li>
<li class="li1">
<div class="de1"><span class="co1">// This routine will extract the version string from the</span></div>
</li>
<li class="li2">
<div class="de2"><span class="co1">// string version resource in the RC file for the current module.</span></div>
</li>
<li class="li1">
<div class="de1"><span class="co1">// Note that you must add version.lib to your project to</span></div>
</li>
<li class="li2">
<div class="de2"><span class="co1">// link to the Win32 versioning API calls. The actual call</span></div>
</li>
<li class="li1">
<div class="de1"><span class="co1">// VerQueryValue() uses a value of 040904B0 for the language</span></div>
</li>
<li class="li2">
<div class="de2"><span class="co1">// and character set. This value is equivalent to English</span></div>
</li>
<li class="li1">
<div class="de1"><span class="co1">// language text encoded using Unicode.</span></div>
</li>
<li class="li2">
<div class="de2"><span class="co1">//</span></div>
</li>
<li class="li1">
<div class="de1">string StringModuleVersion<span class="br0">&#40;</span><span class="br0">&#41;</span></div>
</li>
<li class="li2">
<div class="de2"><span class="br0">&#123;</span></div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; <span class="kw4">char</span> file_name<span class="br0">&#91;</span> MAX_PATH <span class="br0">&#93;</span>;</div>
</li>
<li class="li2">
<div class="de2">&nbsp; &nbsp; GetModuleFileName<span class="br0">&#40;</span> ::<span class="me2">GetModuleHandle</span><span class="br0">&#40;</span> <span class="kw2">NULL</span> <span class="br0">&#41;</span>, file_name, MAX_PATH <span class="br0">&#41;</span>;</div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; DWORD dwDummyHandle; </div>
</li>
<li class="li2">
<div class="de2">&nbsp; &nbsp; DWORD len = GetFileVersionInfoSize<span class="br0">&#40;</span> file_name, &amp;dwDummyHandle <span class="br0">&#41;</span>;</div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; vector&lt;BYTE&gt; buf<span class="br0">&#40;</span> len <span class="br0">&#41;</span>;</div>
</li>
<li class="li2">
<div class="de2">&nbsp; &nbsp; ::<span class="me2">GetFileVersionInfo</span><span class="br0">&#40;</span> file_name, <span class="nu0">0</span>, len, buf.<span class="me1">begin</span><span class="br0">&#40;</span><span class="br0">&#41;</span> <span class="br0">&#41;</span>;</div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; <span class="kw4">char</span> *version;</div>
</li>
<li class="li2">
<div class="de2">&nbsp; &nbsp; <span class="kw4">unsigned</span> <span class="kw4">int</span> ver_length;</div>
</li>
<li class="li1">
<div class="de1">&nbsp;</div>
</li>
<li class="li2">
<div class="de2">&nbsp; &nbsp; ::<span class="me2">VerQueryValue</span><span class="br0">&#40;</span> buf.<span class="me1">begin</span><span class="br0">&#40;</span><span class="br0">&#41;</span>, </div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;<span class="st0">"<span class="es0">\\</span>StringFileInfo<span class="es0">\\</span>040904B0<span class="es0">\\</span>FileVersion"</span>,</div>
</li>
<li class="li2">
<div class="de2">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;<span class="br0">&#40;</span><span class="kw4">void</span> **<span class="br0">&#41;</span> &amp;version,</div>
</li>
<li class="li1">
<div class="de1">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&amp;ver_length <span class="br0">&#41;</span>;</div>
</li>
<li class="li2">
<div class="de2">&nbsp; &nbsp; <span class="kw1">return</span> string<span class="br0">&#40;</span> version, ver_length <span class="br0">&#41;</span>;</div>
</li>
<li class="li1">
<div class="de1"><span class="br0">&#125;</span> </div>
</li>
</ol>
</div>
</div>
</div>
<p></p>
]]></content:encoded>
			<wfw:commentRss>http://marknelson.us/2000/06/01/version-control/feed/</wfw:commentRss>
		<slash:comments>6</slash:comments>
		</item>
	</channel>
</rss>

