in

Platinum Bay

Peace, Love and Visual Studio Team System

.NETicated

December 2007 - Posts

  • Easier ASP.NET Commenting

    In my Visual Studio Tips and Treats talk, I discuss proper code commenting for ASP.NET pages. Let's review.

    It is generally a bad idea to use regular HTML comments to comment out ASP.NET server and user controls. Why? Because the commented controls still be parsed and rendered. Imagine commenting out a large data grid, but still having all that content sent to the client. Worse yet is sensitive information that has been 'removed', but is still showing up in the client-side source.

    Example:

    <!--<asp:Label ID="Label1" runat="server" Text="SocialSecurityNumber" />-->

    The recommended approach is to use server-side comments (Ctrl+K+C). Server-side comments prevent the commented code from being parsed and sent to the client.

    Example:

    <%--<asp:Label ID="Label1" runat="server" Text="SocialSecurityNumber" />--%>

    Now for the good part. I just discovered, by accident, that you don't need to highlight the entire region you want commented. You can simple place the cursor inside the tag you want commented, and use the keyboard command Ctrl+K+C to comment, or Ctrl+K+U to uncomment. Up until now, I had either used the mouse or Shift+[Down|Up]Arrow to select the region I wanted to comment out.

  • Bookmark This

    The bookmark window is something of a red-headed step-child in Visual Studio. No real developer would be caught dead using bookmarks, right? I mean, it makes hoping around large projects so much easier. Therefore it must be cheating, right? I am here to tell you that it is o.k. to use bookmarks. In fact, you should be using bookmarks. Here's why.

    Say you have a large project with a dozen or so solutions and hundreds of thousands of lines of code. Remembering where each and every function is or in what section a logical flow takes place, especially after that two week vacation, can be a little numbing. Further, you may be trying to enhance a large project, with areas you want to modify all over the place. You may also just want to easily jump back and forth between certain places in the code. Enter bookmarks.

    Bookmarks are more than just place markers in your code; they can be named, categorized and organized. And they come with keyboard shortcuts and a tool window to make them oh so easy to use. Just use the keyboard commands to automatically jump around to specific areas in your code.

    Unlike breakpoints, bookmarks can be set (Ctrl+K+K) on any line in the code file, even if the line is blank. You can also name your bookmarks to anything you like to make them easier to remember. Then you can use the keyboard to navigate through the shortcuts (Ctrl+K+P, Ctrl+K+N). Like breakpoints, however, you can enable or disable individual, groups of, or all bookmarks.

    Folders allow you to group related bookmarks which allow you to find them easier. They also let you use the keyboard commands to navigate through bookmarks only within the current bookmark folder (Ctrl+Shift+N, Ctrl+Shift+P).

    Bookmark Gotchas

    There are a couple of gotchas with bookmarks.

    • Bookmark folders cannot be nested, so no organizational hierarchy.
    • The bookmark metadata is stored in the solution user options (.SUO) files, so they won't be automatically checked into source control (TFS, VSS, etc.) to be passed around to your team.
    • You cannot change the icon for bookmarks to give them a more descriptive visual meaning.

    Bookmark Keyboard Shortcuts

    Lastly, here is a simple list of bookmark keyboard shortcuts, along with some helpful hints to help you remember them.

    Description

    Shortcut

    Hint

    Go to Bookmark Tool Window

    Ctrl+K+W

    Window

    Toggle a bookmark on the current line

    Ctrl+K+K

    bookmarK

    New Folder (Bookmark Tool Window must have focus)

    Ctrl+K+F

    Folder

    Move the caret position to the previous bookmark.

    Ctrl+K+P

    Previous

    Move the caret position to the next bookmark.

    Ctrl+K+N

    Next

    Move the caret position to the previous bookmark in the current Folder.

    Ctrl+Shift+K+P

    Same folder Previous

    Move the caret position to the next bookmark in the current Folder.

    Ctrl+Shift+K+N

    Same folder Next

     

  • Visual Studio 2008 Solution File Compatibility

    Leading up to the release of Visual Studio 2008, I heard a couple times that solutions would be compatible between Visual Studio 2005 and Visual Studio 2008. I thought this sounded great. To me this meant that I could open a Visual Studio 2005 solution without the annoying upgrade wizard, work on my web project in the new split view, and then still be able to open it up in Visual Studio 2005. Well, not quite. When I tested this, I do in fact get the upgrade wizard. It appears that while Visual Studio 2008 does have framework targeting, the solution files are not compatible. Bummercrapola.

    Fortunately, there is a fairly easy solution. First, browse to your solution file in Windows Explorer, or by using the Open Project dialog in Visual Studio. Then drag the solution file to an empty area of the window to make a copy of it. Rename it to something like '<solution name> 2005.sln'. Rename the original file to something like '<solution name> 2008.sln. Now you can open your solution in either Visual Studio 2005 or Visual Studio 2008, by selecting the correct solution file.

    There is a downside to this, however. If you add or remove a project from the solution, or make other solution level changes like hiding or showing the solution node, you have to remember to make them in both files.

    [Updated: 4/18/2008]

    Since posting this, I have learned the other downside to this is that in order to open and build the solution after using the above steps, you will need both Visual Studio 2005 and Visual Studio 2008 installed since some of the MSBuild target references are changed.

    One workaround is to use Emmet Gray's utility to switch back and forth as necessary.  You can download it from here:
    http://home.hot.rr.com/graye/Articles/ProjectConverter.htm

  • Swag Scrooges

    A couple weeks back I won two very cool prizes at a .NET Code Camp. I was stoked. The prizes were Enterprise versions of Altova's XMLSpy and MapForce products. I had actually missed these tools since I left my last job, and was looking forward to using them again. There have been a couple times where I wished I had them since.

    The way the prize worked is that I received a piece of paper (two actually) explaining how to contact Altova and get the licenses. I contacted them, and received a reply containing the following text:

    Congratulations! Altova® has been informed that you recently won a free license for Enterprise editions of XMLSpy® and MapForce® by participating in the .NET Code Camp organized by the [removed]. Altova is proud to support this user group and its members.

    We are sending you the Enterprise Edition of the MissionKit for XML Developers instead (valued at $1690), since it includes these two products plus four others which you may find useful.

    Please note: Because this prize is valued at over $600, we are required to request your full name, social security number, and mailing address for tax purposes. (The MissionKit is our product bundle and will lower your overall prize value by $308. If you had won the two separate licenses, your prize would have a value of $1998 vs. $1690). We will need to have the above information before we send you the key code.

    Um, what!? Altova appears to be claiming a deduction on the whole retail cost of the software, which leaves me with a $473.20 tax burden (28% of $1,690). I was heartbroken, and three things strike me as un-cool about this.

    First, this was a code camp – a free event by the community, for the community, with free swag for participants. This was even mentioned at the beginning of the reply above, "free license". I, nor has anyone else I have spoken with, ever heard of a contributor doing this before. All the other contributors seem to eat the cost - maybe as a marketing expense, but noble nonetheless.

    Second, if Altova wishes to write off the cost of prizes, it should be writing off its internal cost, not the retail cost, of its software. Tax deductions on software should be based on manufacturing cost, again, not retail cost. And what is the cost of generating an electronic license key? Maybe 15 minutes of admin salary to fiddle with a license key generator and send it in an email? Ok, so that's a bit naïve, but the cost of providing a piece of software is nowhere near retail.

    Lastly, I'm just a guy sitting at home playing around with software in my own personal time. I'm not making any money with their tools, or anyone else's for that matter. And I really can't afford to buy expensive (or overpriced) software like that. I simply like to develop in an enterprise-like environment, with enterprise tools, since that's where I've spent a lot of my career. I also like to know as much as I can about the tools out there that make developers lives easier. That is, after all, the mission of my Code Camp and User Group presentations – The Power of the Platform. Yes, I am an efficiency geek – I can only do things manually so many times.

    Just so I'm not misunderstood, I have no qualms about paying taxes. Give to Caesar what is Caesar's, right? In all actuality, my wife and I probably pay more in taxes than the average American household (the advantages of living in a suburban area I guess). If I'm against anything, I guess it would have to be paying $5 to 'rent' headphones on an airplane, and then have to turn them in at the end of the flight. But I digress, and I pay for the headphones anyway.

    I simply feel this is uncool and unjust to be burdened with the full retail tax of gift software. I have unfortunately decided to decline the prize altogether to avoid the tax burden. I have also completely removed Altova's software from my system, including Altova XML which is free. I say unfortunately not so much on my behalf, as I can live without the software. It is unfortunate because I am planning my next series of talks, one of which is Tools and Add-Ins for Visual Studio. XMLSpy and MapForce were going to be on that list.

    I'm not asking you to follow suit, or even agree with me. This is just how I feel. And as the old adage goes, "a happy customer tells a friend, an unhappy customer tells everyone they know." I'd be interested in hearing what other folks think though, since I am still kinda bummed about the whole thing.

  • Tool Windows: Object Test Bench

    By and large when I want to test a method in my code, I end up creating a dummy console application in my solution and writing a couple lines of code to execute in the Main method. But this involves a not-so-insignificant amount of work. You know – the boring, repetitive and frankly annoying kind of work. Apart from the effort involved, when you are working with source controlled solutions, you can just add a new project without Visual Studio adding it to the source control system. So while I may still fall back on this method out of habit, I have found a much better way – the Object Test Bench tool window.

    For the purpose of this article, I created a C# class library with a simple class.

    namespace ClassLibrary1
    {
        public class Class1
        {
            public int Add(int num1, int num2)
            {
                return num1 + num2;
            }

            public
    int Subtract(int num1, int num2)
            {
                return num1 - num2;
            }
        }
    }

    The first rule of the Object Test Bench is that the project must be built, so Ctrl+Shift+B. Next, go to the Class View tool window (Ctrl+Shif+C). Then expand the ClassLibrary1 project node and the ClassLibrary1 namespace node. Right-click on the Class1 class node, and choose Create Instance | Class1 (). A window will pop up asking you to name the instance. I usually accept the default, and click OK.

    If it isn't visible already, the Object Test Bench tool window will open, and display a diagramming-type image of your class. The only way to interact with the items, it appears, is to use the right-click context menu. The context menu gives you the option to invoke non-static methods, or remove the item from the Object Test Bench. I wouldn't worry too much about remove though. One of the little nuances of the Object Test Bench is that your objects disappear whenever the project gets built, or when running in debug mode and you kill the debugger.

    So go ahead and choose the Add method. A window will appear asking for our two parameters. Enter 32 for both and click the OK button. Another window will appear showing the result of the method call with your parameters, in our case 64. You now have a choice of clicking the OK button to close the window, clicking the Retry button to try it with different parameters, or checking the 'Save return value' box to save the result in the Object Test Bench tool window. It may seem rather odd to save the result since it is just going to be wiped out the next time you build the project, but it can be rather useful. Let's say you want to test a couple methods, and use the output of one as the input for another. That's where saving the result comes in.

    Click the box to save the result, accept the default name, and now go to invoke the Subtract method. In the parameter dropdown box for either item, you will see the saved result, int321, as an option. Select int321 and the first parameter and enter 16 for the second parameter. The result dialog will show 48 as the result.

    Lastly for results, if you want to tweak your result using some of the built-in class methods, you can right-click on the result and see a list of methods and inherited methods for the result object type.

    It is also possible to use debugging with the Object Test Bench. By setting a breakpoint in our method and invoking a member, Visual Studio will automatically enter debug mode and break on our breakpoint when the method is invoked.

    One of the other interesting things I noted about the Object Test Bench is that it doesn't always throw the expected exception. For instance, the major flaw in my above test code is that if you were to pass int.MaxValue (2,147,483,647) for both parameters of the Add method, an overflow would occur trying to cast the result into an int. Object Test Bench however, returns a result of -2.

    One thing you may have noticed back in the Code View tool window, is that there is also an option to invoke a static method. This works pretty much the same as invoking a non-static method, but no class instance is added to the Object Test Bench.

    The Object Test Bench provides some pretty interesting, albeit quirky, on-the-fly unit testing capabilities.

    Happy test benching!

  • Visual Studio 2008 Options Changes

    A lot of Visual Studio's customization comes from the Options pages (Tools | Options). Curious about what was new in Visual Studio 2008, I did a side-by-side comparison of the Visual Studio 2005 and Visual Studio 2008 Options pages. Here are the differences I found between the Team Editions for Software Developers.

    Note: I actually tested between Visual Studio 2005 Team Edition for Software Developers, and Visual Studio 2008 Team Suite. I attempted to discern which additional options were part of Team Suite, and not additions from Visual Studio 2005. I may have also hosed either environment. Therefore this list may not be conclusive or completely accurate, though every attempt blah blah blah…

    On with it mate!

    Projects and Solutions | VB Defaults

    • A setting was added to allow Option Infer to be turned on or off by default.

    Text Editor

    • Two new sections were added named XAML and XOML.

    Text Editor | C# | Advanced

    • A setting was added under the Refactoring group titled 'Warn on members with compiler generated references'.
    • A new section was added, 'Organize Usings', which contains two new settings:
      • Warn if build errors exist when organizing usings
      • Place 'System' directives first when sorting usings

    Text Editor | C# | Formatting | New Lines

    • Several new settings were added under the 'New line options for braces' group:
      • Place open brace on new line for anonymous types
      • Place open brace on new line for object initializers
      • Place open brace on new line for lambda expressions
    • A new group titled 'New line options for expressions' was added, containing the following settings:
      • Place members in object initializers on new line
      • Place members in anonymous types on new line
      • Place query expression clauses on new line

    Text Editor | C# | Formatting | Spacing

    • In the 'Set other spacing options' group, the following setting was added:
      • Ignore spaces in declaration statements

    Text Editor | C# | IntelliSense

    • In the IntelliSense Member Selection group, the Clear History button was removed.

    Text Editor | HTML | Miscellaneous

    • Removed – Enable property grid in Source view
    • Added – Only use TAB to commit Jscript statement completion

    Text Editor | HTML | Validation

    • In the Options | Show Errors group, the following settings were added:
      • as warnings (HTML, CSS)
      • as warnings (JScript)

    Debugging | General

    • A setting was added titled 'Warn if script debugging is disabled on launch'.

    Debugging | Edit and Continue

    • A setting was added called 'Enable while remote debugging or debugging an application running under another user account.'

    HTML Designer | General

    • In the 'Start Pages in' group, a new option called 'Split View' was added.
    • The Smart Tags group was removed.
    • Three new check options were added:
      • Assign unique IDs to new tables
      • Auto keyboard switching
      • Split views vertically

    HTML Designer | CSS Positioning

    This section was removed.

    HTML Designer | Display

    This section was removed.

    HTML Designer | CSS

    This section was added.

    HTML Designer | CSS Styling

    This section was added.

    HTML Designer | Ruler and Grid

    This section was added.

    HTML Designer | View

    This section was added.

  • Debugging Handled Exceptions

    You know, if it weren't for exceptions our jobs would be so much easier. Of course, if it weren't for our jobs exceptions wouldn't exist either. But they exist. And we cringe.

    Sometimes they are just so very hard to track down –elusive little buggers that they are. You might try debugging your code in Visual Studio, hoping you get a nice little popup to explain an exception has occurred. What you may not know, however, is that Visual Studio only breaks on unhandled exceptions by default. If there is a try-catch block around the exception, the debugger doesn't care and will continue execution until it hits a breakpoint or an unhandled exception.

    There are times however, when breaking on any exception can be helpful, handled or not. For instance, you may be getting an exception which has bubbled up from another exception, and the stack trace isn't enough to figure out exactly where it originated from.

    To do this, you will first need to add the Exceptions… menu item to the Debug menu. You can actually add it anywhere you like, but I prefer the Debug menu. First, right-click on the menu bar and choose Customize… at the bottom of the context menu. Choose the Commands tab, and Debug from Categories. Now in the Commands listbox, you can select the Exceptions… item, and drag it into your Debug menu.

    Here's how it looks for me:

    Now that the menu item is all set up, click to Debug | Exceptions. The following window will appear:

    All that remains now is to select the Thrown checkbox for Common Language Runtime Exceptions, and Visual Studio will break on each and every CLR exception as they happen. Keep in mind that this is a global Visual Studio setting, so you will need to manually change it, or change it back, for each project or debugging session.

    One last note: if you want to get really specific about which exceptions Visual Studio breaks on, you can expand the group, and get a list of assemblies and types, which can further be expanded into specific exceptions:

  • WinForms: Tab Order

    So you've created a great winforms app with loads of controls, you fire it up, start tabbing through fields, and the cursor is jumping all over the place. What a pain. Now you have to go back through each and every control and set the tab order manually in the Properties window. Sound familiar?

    In a stroke of pure genius, Microsoft thought of this too. Visual Studio contains built-in support for graphically setting control tab order – no more properties window.

    To begin, load up your form in the designer view. The go to View >> Tab Order.

    Your form should now have little blue boxes with white numbers over each control. Now you can simply start clicking through the blue boxes to set the tab order. As you set each item, the blue boxes will turn white and display the new tab order. When you have clicked through all the controls, the boxes turn blue again. If you screwed up, you can click through again.

    Click through to View >> Tab Order again to exit this feature.

  • Comment and win!

    The first ten unique people to add a VALID comment on any post in this blog within the next 24 hours get a free Zune* **.

    Conditions:

    * Winner(s) must be a US resident, 18 or older. Void where prohibited. Valid comment determination is at my sole discretion. Shipping and handling fees of $259 is the responsibility of any winner(s). Actual prize may be substituted for a prize of lesser value. Other restrictions may apply

    Standard Terms:

    ** This product is meant for educational purposes only. Any resemblance to real persons, living or dead is purely coincidental. Void where prohibited. Some assembly required. List each check separately by bank number. Batteries not included. Contents may settle during shipment. Use only as directed. No other warranty expressed or implied. Do not use while operating a motor vehicle or heavy equipment. Postage will be paid by addressee. Subject to approval. This is not an offer to sell securities. Apply only to affected area. May be too intense for some viewers. Do not stamp. Use other side for additional listings. For recreational use only. Do not disturb. All models over 18 years of age. If condition persists, consult your physician. No user-serviceable parts inside. Freshest if eaten before date on carton. Subject to change without notice. Times approximate. Simulated picture. No postage necessary if mailed in the United States. Breaking seal constitutes acceptance of agreement. For off-road use only. As seen on TV. One size fits all. Many suitcases look alike. Contains a substantial amount of non-tobacco ingredients. Colors may, in time, fade. We have sent the forms which seem to be right for you. Slippery when wet. For office use only. Not affiliated with the American Red Cross. Drop in any mailbox. Edited for television. Keep cool; process promptly. Post office will not deliver without postage. List was current at time of printing. Return to sender, no forwarding order on file, unable to forward. Not responsible for direct, indirect, incidental or consequential damages resulting from any defect, error or failure to perform. At participating locations only. Not the Beatles. Penalty for private use. See label for sequence. Substantial penalty for early withdrawal. Do not write below this line. Falling rock. Lost ticket pays maximum rate. Your cancelled check is your receipt. Add toner. Place stamp here. Avoid contact with skin. Sanitized for your protection. Be sure each item is properly endorsed. Sign here without admitting guilt. Slightly higher west of the Mississippi. Employees and their families are not eligible. Beware of dog. Contestants have been briefed on some questions before the show. Limited time offer, call now to insure prompt delivery. You must be present to win. No passes accepted for this engagement. No purchase necessary. Processed at location stamped in code at top of carton. Shading within a garment may occur. Use only in well-ventilated area. Keep away from fire or flame. Replace with same type. Approved for veterans. Booths for two or more. Check here if tax deductible. Some equipment shown is optional. Price does not include taxes. No Canadian coins. Not recommended for children. Prerecorded for this time zone. Reproduction strictly prohibited. No solicitors. No alcohol, dogs, or horses. No anchovies unless otherwise specified. Restaurant package, not for resale. List at least two alternate dates. First pull up, then pull down. Call toll free before digging. Driver does not carry cash. Some of the trademarks mentioned in this product appear for identification purposes only. Record additional transactions on back of previous stub. Decision of judges is final.

    This supersedes all previous notices.

    From http://www.efn.org/~dmaring/disclaim.html

  • Taming the Visual Studio WinForms Designer

    Here's a new Visual Studio tip I picked up recently. I have built my share on WinForms apps, and most of them had extraneous labels to denote input fields or other areas of the form. I don't use them, their just placeholders for text.

    It used to be that when I was working on the code side (F7), I would wander through IntelliSense, trying to ignore the Label1, Label2, Label3 suggestions. No more.

    Simply select the items on the form that you don't want to code against, highlighted in red below. Next, go to the Properties tool window and set the GenerateMember property in the Design group to False. If you take a peek in the form's designer file, you will see that the field declarations have been moved into the InitializeComponent method. What this does is remove it from IntelliSense's prying eyes, while still allowing it to be rendered for yours.

    Now, when I am perusing through IntelliSense, I will only see generated members for the fields I actually need (green below).

  • Breakpoint Breakdown

    We are all familiar with the breakpoint, but let's break down some of the advanced breakpoint features.

    Here's the simple class we are going to use. Create a console application and paste the following code into the program.cs file:

    using System;

    namespace BreakpointTester
    {
        class Program
        {
            static void Main(string[] args)
            {
                int i = 0;

                while(i < 10)
                {
                    i = Add(i , 1);
                    Console.WriteLine(i.ToString());
                }
            }

            static int Add(int num1, int num2)
            {
                return num1 + num2; // line 22 – set a breakpoint here
            }
        }
    }

    Breakpoints

    We should all know that if we click once to the left of a line number (you did enable line numbers, right), you can set a breakpoint. Click again, and it goes away. The keystroke F9 also sets and removes a breakpoint wherever the cursor is. But did you know there are a whole slew of other options if you right-click on a breakpoint in the code window? These features are available for the Standard, Professional and Team Editions of Visual Studio.

    Disable Breakpoint

    I find myself using the Disable command, either in the menu or in the Debugging tool window, quite a bit. Why? Sometimes I know I don't need to hit an item during a particular run. I can disable the breakpoint, and the debugger will skip right over. I then won't have to recreate it next time. In the Debugger tool window or the Debug menu, you can also enable and disable all breakpoints at once. I find it a good practice to set breakpoints while I'm writing code if I know there might be issues in the section. I can then disable them if they get in the way of testing other parts of the system.

    Location

    The location dialog allows you to specify the location for a breakpoint. There are four types of Location breakpoints – file, address, function and data.

    File

     

    I don't find this one very useful since I can click in the code window to set and remove breakpoints. However, you can enable the checkbox to allow debugging to step through code that is different from the running version.

     

     

    Address

    Available in: Standard, Professional, Team Editions

    An address Location breakpoint can be set while the debugger is running. Right-click on a line of disassembly, and set the breakpoint. A word of warning from MSDN though, "Avoid setting breakpoints on system components when you are debugging mixed-mode (native and managed) code. Setting a breakpoint on a system component during mixed-mode debugging can cause the common language runtime to break and the debugger to hang."

    Function

    Available in: Standard, Professional, Team Editions

    Again, I don't find this one very beneficial.

    Data

    Available in: Express Standard, Professional and Team Editions for Native C++ only

    A data breakpoint can only be set in Native mode, and causes the debugger to hit when the values stored in a specified memory location changes.

    Condition

    Available in: Standard, Professional, Team Editions

    Conditions allow a breakpoint to only hit when certain variables in the code evaluate to true. For instance, you could enter myColor == Color.Blue, if you happen to have a myColor variable.

    Hit Count

    Available in: Standard, Professional, Team Editions

    Sometimes you just want to break after a certain number of cycles.

    Go ahead and right click on your line 22 breakpoint, and choose Hit Count. You should see the dialog box below. Choose 'break when the hit count is equal to' and enter '7' in the count box. Run the program, and you will see that the debugger only breaks when the variable is equal to 7.

    Filter

    Available in: Express Edition with C++, Standard, Professional, Team Editions

    Breakpoint filters allow you to specify that a breakpoint should only hit when it is accessed by a specific process or thread. This is a great feature for multi-threaded or component-based applications, but you do need to know the process, thread and/or machine name.

    When Hit

    When hit allows you to print a message, or run a macro when the breakpoint is hit. You can also choose whether to continue execution or not.

    Summary

    If you aren't using these advanced breakpoint features, you're missing out on some of the ease baked right into our favorite platform, Visual Studio.

  • May the Source Stay Only With You

    So you've stayed up late every night for the past couple months coding out a sweet new idea. The bits are finally in order; you do a release build, zip it up, and put it on your website with a link to PayPal. "I am so going to retire" you think.

    Next thing you know, folks are posting serial numbers, cracks, and your precious source code out in the cloud. "How did that happen?" you say as a wave of depression sets in. The answer is that, much like Java, .NET is compiled into an intermediate language, not machine code. This makes it easily decompilable. To protect your code, you need to do more than just compile.

    In this post, we are going to examine obfuscation, secure licensing, and several other preventative steps you can take to help reduce the risk of piracy and source code theft of your .NET assemblies. First though, we'll take a look at some code protection myths.

    Strong Names, CAS, and Other Myths

    When folks hear the terms 'strong name' and 'code access security', their first impression is usually that these techniques will help them prevent unwanted access to the underlying source code. However, this is not the purpose of these features.

    The concept of strong names was created to eliminate the problem of 'dll hell'. It allows an assembly to have a unique name for identification purposes. A good way to think about this is to take a look at human names. My name, Stephen Andrews, is not unique. As weird as it seems to me, there are other Stephen Andrews out there. I can not simply be known by my given and family name. More information about me must be provided to uniquely identify me among the other Steves. For the government and financial worlds, this is most commonly a social security number. More casually, a postal address may suffice.

    Code access security, on the other hand, is all about preventing unwanted execution in an assembly. Basically, CAS allows an end user, administrator, or developer to limit the amount of access an assembly has to the underlying operating system, or conversely a minimum of access that is required to run the assembly. Using CAS, you can control whether an assembly has access to protected resources such as your network connection, the file system, registry, or even if it can show a user interface.

    Unfortunately, neither of these methods helps in preventing a user from getting to your source code.

    Obfuscation

    The most common method of code protection, and one of the best, is obfuscation. According to Wikipedia, Obfuscation is 'the concealment of meaning in communication, making it confusing and harder to interpret.' This is certainly true for software obfuscation.

    An obfuscator, a piece of software that performs obfuscation, typically utilizes several core concepts; layout, control flow and data. To understand how obfuscation makes it more difficult for someone to steal your code or hack your assembly, take a look at the following before and after code samples showing control flow modifications:

    Before:

    public class License
    {
        public bool IsValid(string license)
        {
            Regex regex = new Regex(
                "[^a-z0-9]",
                RegexOptions.Singleline
                | RegexOptions.CultureInvariant
                | RegexOptions.IgnorePatternWhitespace
                | RegexOptions.Compiled);

            string result = regex.Replace(license, "");

            double add = 0.0;
            foreach (char c in result)
            {
                add += c;
            }

            return (add == 1054);
        }
    }

    After:

    public class StringFormatter
    {
        public bool IsLEFString(string lefString)
        {
            Regex a1 = new Regex(
                c3.m2("W2F6LV1eLTA5"),
                RegexOptions.Singleline
                | RegexOptions.CultureInvariant
                | RegexOptions.IgnorePatternWhitespace
                | RegexOptions.Compiled);

            string a2 = a1.Replace(lefString, string.Empty);
            int i3 = 169 / 13;
            if (i3==4)
                double a3 = a(a2 + 9);
            else
                double a3 = a((a2 + a2) / 2);

            return a(a3);
        }

        private double a(string a)
        {
            double a1 = 0.0;
            foreach (char a4 in a)
            {
                a1 += a4;
            }

            return a1;
        }

        private bool a(double a)
        {
            double a1 = c3.m2("cw==")[0];
            double a2 = c3.m2("Zg==")[0];
            return ((a1 * a2) / 13.623693379790940766550522648084) == a;
        }
    }

    As you can see, a very simple method of licensing (and one not recommended for actual use), has been made much less obvious. The class, method, parameter and variable names have been changed, the strings encrypted, and control flow expanded across two more methods. This eliminates the most valuable information for a decompiler. If someone were to open this code in Reflector, it would be much harder to understand what it was doing, let alone to try and put it back together and get some use out of it.

    The thing about deobfuscation and decompilation in general is, you can turn apples into applesauce, but you cannot turn applesauce back into apples. This makes it a pretty good tool for code protection.

    To get started with obfuscation, the default Visual Studio installation contains a copy of Dotfuscator Community Edition by PreEmptive Solutions. I also recommend taking a look at Postbuild by Xenocode.

    Code Tips

    There is certainly something to be said for maintainability, but more obtuse code, more object oriented in its structure, the harder it is for someone else to understand. If calls are being made across loosely coupled interfaces and across many classes, it will take someone much longer to understand what and where the code is doing.

    Licensing

    If you plan on selling software, most likely you are planning on licensing it, and implementing licensing checks in your code. Here are a couple tips to keep in mind when implementing licensing.

    Assembly Naming

    A lot of folks seem to like putting their licensing code into an assembly named licening.dll. There are two very big problems with this however.

    First, the licensing assembly, named as such, is easily identifiable if someone decides to browse your program directory. It doesn't take a genius to figure out that licensing.dll may hold some of the licensing functionality in your application. One could very easily open up the licensing assembly in Reflector to see how it works, possibly figuring out how to circumvent it.

    Secondly, one could write their own assembly to match your assembly's signature, and substitute yours for theirs, thereby bypassing your licensing mechanism. And if you think giving it a strong name helps, just remember that one can disassemble the calling assembly using ILDASM, change the IL reference of the licensing assembly to their replacement assembly, and reassemble the calling assembly.

    Bottom line; if you have to compile your licensing code in a separate assembly, at least try not to make it so very obvious. Better yet though would be to include the licensing code in your main assembly.

    By including the licensing code in your main assembly, you are making it harder for someone to circumvent the code protection, especially if it has been obfuscated among the rest of your code, as seen in the previous example.

    RSA Signatures

    RSA is an algorithm for public-private key pair cryptography. In general, the sender uses the receiver's public key to encrypt a message, and the receiver uses their private key to encrypt it.

    This can be turned around, however, making it suitable for licensing protection. Instead of encrypting the whole message, you create a hash of the message and sign the hash using the private key. The data and the encrypted hash are then sent to the receiver, the licensee in this case.

    On the client-side, a hash is made of the sent data, and the signature of the hash is verified using the public key. If the signatures are different, the license is not valid.

    Using the RSA algorithm for licensing provides for one of the most secure licensing schemes available. To boot, the .NET framework includes an RSA algorithm implementation, so all the guts are taken care of for you.

    Summary

    We've looked at strong names and code access security, and while powerful, and misunderstood as providing protection to the underlying source code. We've also looked at the benefits of obfuscation, and the RSA method of licensing.

    Hopefully, these tips will help your source code be only your source code.

    Posted Dec 09 2007, 11:21 PM by Steve with no comments
    Filed under: ,
  • Find Target Registry Code

    It's always such a pain finding a Windows shortcut's target. You have to right-click on the shortcut, choose properties, and then click 'Find Target…'. After Explorer pops up, you still have to close the properties window (Esc key). Wouldn't it be great if there was an easier way, like in the context menu? A while back I found a program you could install to do just that, but I hate installing 'unknown' stuff. Well, I finally found a more transparent solution – a registry hack.

    Simply create a .REG file, paste the following text, and run it. It's awesome, and I find I use it quite a bit. I use the Quick Launch folder in the Task tray, and if, for instance, I would like to navigate to Visual Studio's program folder for some template work, I can right-click on the VS icon in my Quick Launch and choose 'Find Target'. Sweet!

    The usual 'editing the registry at your own risk' warning applies.

    Windows Registry Editor Version 5.00
    [HKEY_CLASSES_ROOT\Directory\shell\Find.Target]
    @="&Find Target"
    [HKEY_CLASSES_ROOT\Directory\shell\Find.Target\command]
    @="\"explorer.exe\" /select,\"%1\""
    [HKEY_CLASSES_ROOT\*\shell]
    [HKEY_CLASSES_ROOT\*\shell\Find.Target]
    @="&Find Target"
    [HKEY_CLASSES_ROOT\*\shell\Find.Target\command]
    @="\"explorer.exe\" /select,\"%1\""

    Hope this helps

    Posted Dec 04 2007, 10:31 PM by Steve with 1 comment(s)
    Filed under: ,
Powered by Community Server (Commercial Edition), by Telligent Systems
© Platinum Bay | Some Rights Reserved Creative Commons License

Disclaimer: The information in this weblog is provided "AS IS" with no warranties, and confers no rights. This weblog does not represent the thoughts, intentions, plans or strategies of my employer. It is solely my opinion. Feel free to challenge me, disagree with me, or tell me I'm completely nuts in the comments section of each blog entry, but I reserve the right to delete any comment for any reason whatsoever (abusive, profane, rude, or annonymous comments) - so keep it polite, please.