August 20, 2008
@ 09:43 PM

I'm going to buy one of these just to freak out the neighbors.

 

Links:

http://www.bostondynamics.com/content/sec.php?section=BigDog


 
Categories: Other

CodeRush builds an internal source tree of your C# or VB.NET code. It also has code generating ability - that is, you can take a portion of the tree and generate C# or VB.NET code from it. That got me to thinking about a way of leveraging this ability to build a simple code translator so you could do something like open up a C# file and view the VB.NET equivalent in a tool window (or vice-versa). It turns out the code to do something like this is really straightforward; it's a single method call once you have a reference to the code elements. It doesn't always generate the correct set of code, but it's still really helpful. You basically move the cursor around and the window will display the translated code that is currently "in scope". That is, if you're inside of a method it will show you code for that method. If you move the cursor out to the class, it will show you that class.

To install it, just copy it to your plug-in directory (usually C:\Program Files\Developer Express Inc\DXCore for Visual Studio .NET\2.0\Bin\Plugins\). When you start up Visual Studio a new menu option will appear under DevExpress > Tool Windows > Translator. The window shows a number of different .NET languages, but in reality CR only supports VB.NET and C#.

CR_Translator

BTW - I've mentioned CodeRush/Refactor! and while that's a commercial product you can also download CodeRush by itself for free (and use any third party plug-ins or write your own). You just don't get any of the built-in templates or refactoring tools that the commercial product offers.

Oh, you can download the plug-in from here: http://www.rcs-solutions.com/Download.ashx?File=CR_Translator.zip or from the community plug-in site in a few days.

Links:

http://www.devexpress.com
http://code.google.com/p/dxcorecommunityplugins/


 
Categories: CodeRush | Visual Studio

August 15, 2008
@ 09:48 PM

I've been using a "common" style for my reports for quite a while. I include a report title, then below that I usually have one or more lines which show which filter and sorting criteria were used to generate the report. I include a page X/Y line, usually in the bottom right hand side of the report. At some point I started adding the print date/time, who it was printed by, and the name of the file of the report. All of these fields together have been valuable when making changes and in determining why something isn't working.

The other day I had someone bring a report that was generated last year for the first 6 months of 2007 by an employee who is no longer with the company. They were attempting to tie the summarized numbers back to the detail which generated them and weren't sure how to find the detail. We had recently changed a fundamental aspect of how this particular report and supporting (detail) reports generated some of their numbers so I decided to just run a query against the database to get the information they were looking for. I looked at the timeframe the report was run for and wrote the query - there were no filters so it was really straightforward, or so I thought. When I totaled up the numbers they didn't match the report. Uh oh. I started worrying about what kinds of bad things might have happened that would have changed our historical tables.

Ugh...Then I noticed that the report was printed on the ending date of the report (in this case, it was run for 1/1/2007 - 6/28/2007) and it was printed on 6/28/2007. The light bulb went on. This particular report showed numbers that weren't available until a few months after the month they were applicable to. Essentially, we don't get numbers for January until March (even though they are posted back into January). So when this report was run, the numbers for April forward weren't available yet and weren't included in the report (even though the report range said it was through 6/28/2007). In the meantime those numbers had been posted and since I was pulling these numbers a year later they appeared in my version. I adjusted my query to exclude numbers posted after the report run date/time and suddenly everything balanced. Without knowing when the report was run it would have taken a LOT of work to resolve this (I'm not even sure I would have been able to).

Are there any types of things you're including on reports which have saved you?

In addition to the fields mentioned above, I've recently started including a "key" at the bottom of a number of reports which explain how numbers are generated and a more detailed explanation of their meaning. As questions come up about them I adjust my descriptions so they answer the questions asked. I'm using a really tiny font to keep the amount of space lost to them to a minimum but I'm finding they have also been really valuable since I'm not having to refer to the code as much to explain how some numbers were derived. It also addresses the issue where you use common names for column headers on various reports but the underlying numbers in those columns are actually inclusive or exclude different things.


 
Categories: VFP

August 12, 2008
@ 10:17 PM

I ran across a really cool .NET library on a recent project I've been working on. We have an internal website where we post news, documentation, etc. - basically a Content Management System (CMS). We're working on a new set of documentation that is being done inside of a third party help builder application. We need to import the HTML files it generates into our website (so we get all the things it offers, like security, searching, revision tracking, view statistics, etc.). So basically, I need to run through a lot of HTML files, build a tree of the documents (similar to the help file) and rewrite all of the URL's and image links to point to the correct URL inside of the site. I initially started looking at various regular expressions that I might be able to use over at http://regexlib.com/. Almost every single one of them had some comment about it failing under some circumstances. The HTML is surprisingly clean, but I was still nervous about it. So I looked at using GOLD to parse the HTML. However, from some of the comments I found it still didn't make everything as easy I would have liked. I finally ran across HtmlAgilityPack over on CodePlex . It's a .NET library which lets you read AND write changes to an HTML file via a simple API.

Here's a chunk of code from my importer so you can get a feel for how it works:

HtmlDocument doc = new HtmlDocument();

doc.Load(content.FullDocumentPath);

HtmlNodeCollection linkNodes = doc.DocumentNode.SelectNodes("//a/@href");

 

Content match = null;

// Run only if there are links in the document.

if (linkNodes != null)

{

    // Fix up the URL's

    foreach (HtmlNode linkNode in linkNodes)

    {

        HtmlAttribute attrib = linkNode.Attributes["href"];

        // If it's an internal page anchor, ignore it

        if (attrib.Value.StartsWith("#"))

            continue;

 

        string path = this.GetAbsolutePath(content.DocumentLink, attrib.Value);

        match = this.m_contentList.Find(p => p.DocumentLink == path);

 

        if (match != null)

            attrib.Value = match.GetUrl();

        else if (!path.ToLower().StartsWith("http://") && !path.ToLower().StartsWith("mailto:"))

            Console.WriteLine("Cannot find matching document, searched for " + path);                       

    }

}

 

Basically, doc.DocumentNode.SelectNodes("//a/@href") returns a collection of links in the document (it uses XPath syntax for the selection string). From there, I just iterate through them, build the new URL, then save the modified Url via code that just does: linkNode.Attributes["href"].Value = "New URL Here". I also needed to strip out all the script tags inside of the document, so it uses similar syntax:

private void StripOutScripts(HtmlDocument doc)

{

    // Strip out the scripts

    HtmlNodeCollection scriptNodes = doc.DocumentNode.SelectNodes("//script");

    if (scriptNodes != null)

    {

        foreach (HtmlNode scriptNode in scriptNodes)

        {

            scriptNode.ParentNode.RemoveChild(scriptNode, false);

        }

    }

}

 

I do the same sort of thing - iterate over the collection, except this time tell it to remove the nodes from the document (note that I'm grabbing the parent node, since the current node is everything contained within the script, excluding the <script> tags. By getting the parent, we get that and the tags themselves.

Each collection has a WriteContentTo() method which can write the HTML for that section of the document to a Stream. What's really nice about this entire library (besides how simple it was to use) was the fact that it doesn't seem to mangle the existing HTML when using WriteContentTo() (at least from what I've seen). Only one minor complaint - the docs are a bit weak. It just includes the standard documentation of the classes, not much in the way of examples. However, it's pretty consistent so it doesn't take much to get started with it.

What a great library - it couldn't be simpler. It saved me a ton of time.

Links:

http://www.codeplex.com/htmlagilitypack
http://regexlib.com/
http://www.devincook.com/goldparser/


 
Categories: .NET | C# | Developer Tools

August 10, 2008
@ 05:33 PM

How much memory is "enough"? I've got 4 GB (imagine telling someone 5 years ago you had 4 Gigabytes of memory!) in my machine right now and I'm really wishing I had more. Enough so that I've got (4) 2GB memory sticks in my shopping cart at NewEgg. I'd get 16 GB, but it's just too expensive right now. It would seem like 4 GB would be enough, but when I upgraded my machine a while back to Vista (64-bit) I took a VMWare snapshot of my XP machine before the upgrade. I'm still using that machine since I've got a few apps. that need to run and I haven't really wanted to spend the money upgrade to the new versions. I like to allocate approx. 1.5 GB of memory to that machine. I also maintain a VMWare image of Visual Studio that gets 2 GB of memory. Between the both of them I can't really run them at the same time with any reasonable performance.

How much memory do most developers now run? I'm guessing 2 GB is now "entry level". I can use up 1 GB of memory just with Visual Studio. If I don't close FireFox down regularly it'll keep taking up memory (I've seen it as high as 300-400 MB of memory). Outlook grabs around 130 MB. Add a few other apps. to that and suddenly that doesn't leave much room for the OS.

8 GB should give me a bit of breathing room, at least for a bit. How many years until I'm saying something like, "I've got 4 TB of memory and it's not quite enough..."


 
Categories: Other

August 8, 2008
@ 07:48 PM

It looks like it's the week of CodeRush/DXCore plug-ins (I still have one more plug-in coming up).

This plug-in just lets you collapse an XML comment tag to one line (I'll explain it a bit more below). It was actually written as a Refactoring (so it appears when you hit the refactoring key or wait for the ellipses to appear below the code). I put this one together a few days ago and was planning on releasing it after I had a chance to live with it for a while to see if there were any changes or bugs I needed to address. But someone on the DevExpress forums recently posted about wanting a plug-in which did the same thing so I decided to just release it right now.

So what does this really do?

When you add an XML comment to something like a property or field, you end up with the following (in C#):

/// <summary>
///
/// </summary>
private int m_someValue;

The cursor is positioned on the second line. After installing this refactor, you can hit the Refactor key (which I mapped to just the ` key (instead of Shift or Alt or Ctrl ` , whatever the default is) and this comment will get collapsed down to one line:

/// <summary></summary>

This can help eliminate some of the visual noise of the comment, especially if it's just a short comment.

If you have a muli-line comment, it actually collapses it in two stages (that is, you can issue the refactoring twice), so for example:

/// <summary>
/// This is my multi-line
/// comment about nothing.
/// </summary>

The first time you collapse it you end up with:

/// <summary>This is my multi-line
/// comment about nothing.</summary>

The second time you collapse it you end up with:

/// <summary>This is my multi-line comment about nothing.</summary>

You can download the code from the download section on my site or the community site. Like before, there will probably be a few day delay between when it's available here and when I get it put up on the community site.

To install it, copy it into your C:\Program Files\Developer Express Inc\DXCore for Visual Studio .NET\2.0\Bin\Plugins\ folder.

Links:

http://www.rcs-solutions.com/Download.ashx?File=Refactor_Comments.zip
http://code.google.com/p/dxcorecommunityplugins/


 
Categories: CodeRush | Visual Studio

August 5, 2008
@ 08:48 PM

This was an interesting issue I ran into today. We've got a utility I wrote which can search Outlook MSG files from a desktop interface. As part of the program you can print the results to a PDF - I'm using Crystal Reports to do the printing. We had this application installed on a desktop machine for a while but decided to move it over to one of our servers which had a lot more hard drive space. After moving it, when we attempted to print we'd get the error:

"An error has occurred while attempting to load the Crystal Reports runtime"

At first I thought it might be related to needing the CR DLL's installed instead of just being deployed in the app's directory. We installed them and tried again - same exception. Further down in the error (which was actually helpful - imagine that!), "Please install the appropriate Crystal Reports redistributable (snip) containing the correct version of the Crystal Reports runtime (x86, x64, or Itanium).

Hmm...x86 vs x64 - that has to be it - this was Windows 2003 Server (64 bit) vs. XP. I actually just recently listened to a DotNetRocks podcast which talked about .NET applications running under a 64 bit OS. They mentioned that, by default, most .NET applications are compiled under "Any CPU". That means the code get's JIT'ed to 64 bit code under a 64 bit OS - sounds OK. The only catch is that all the components must also be compiled the same way, otherwise you run into problems. I didn't really want to have two different sets of DLL's so I went back into my application and changed it from "Any CPU" to x86 code and recompiled. Order was restored to the universe.

Links:

http://www.dotnetrocks.com


 
Categories: .NET

I've been meaning to post this up for a while but never seemed to get around to it. I've been using CodeRush/Refactor! (CR/R!) from DevExpress for a few years now and this was actually the first plug-in I wrote for it. If you're not familiar with CR/R! it's sort of Intellisense on steroids with a bunch of refactoring tools thrown in. OK, that description really doesn't do it justice - I'd suggest taking a look at a few of the videos they have available over on the DevExpress site to get a better idea of what it does. I'd put CR/R! in the "must have" category for any .NET developer. It's actually annoying to use Visual Studio without it installed.

At any rate, this plug-in does nothing more than make it easy to insert a comment that contains the developers name or initials and the date of a change. For example:

// PCM - 8/4/2008 -

Or, if you happen to be located on an XML comment line, it inserts the following:

/// <developer>Paul Mrozowski</developer>
/// <created>08/04/2008</created>

It's language agnostic, so this should actually work in VB.NET as well (it uses the '/''' comments instead). I've tied it to the CTRL-Insert keypress but you can set it to whatever you'd like. To install it, copy it into your C:\Program Files\Developer Express Inc\DXCore for Visual Studio .NET\2.0\Bin\Plugins\ folder. Then start up Visual Studio and go to DevExpress, Options. You should see a new tree option, "Developer Initials". Fill in your name and initials and select whether you'd like it to insert your initials for a line comment or your full name. Then go to IDE > Shortcuts. Expand the Code folder. I created a new folder named "Custom". Click on the icon for a new keyboard shortcut. On the right-hand side, enter the keyboard shortcut (mine is Ctrl+Insert), then in the Command combo select "Add Initials". Then hit OK.

CR_Initials

CR_Initials2

Exit out of Visual Studio and go back in. At this point the plug-in should be active. Try it out by hitting your shortcut key on a new line (or, enter an XML comment. Hit enter, on the new XML comment line hit the shortcut key).

You can download it from here (http://www.rcs-solutions.com/Download.ashx?File=CR_Initials.zip) and it may show up on the DX Core Community Plug-ins site at some point.

Links:

http://www.devexpress.com
http://code.google.com/p/dxcorecommunityplugins/


 
Categories: CodeRush | Visual Studio