Archives

Archives / 2003 / July
  • One Reason why I use Hungarian Notation

    While I adjusted my coding style for "everything publicly visible" to match the Microsoft guidelines, I still use Hungarian Notation internally (in a simplified form). One can argue whether or not it increases the readability of code, resulting in long discussions about the pros and cons.

    One feature of HN I really love (and just don't want to give up) is how well it works in conjunction with Intellisense.

    Example 1: Member variables ("m_" prefix):

    Example 2: Controls ("c_" prefix):

  • ExtractXml: Including Examples in Your API Documentation

    When using an API it's always nice to have some examples showing how the different classes and their methods and properties are actually used. Examples usually come in two flavors:

    • Full projects (more or less) ready to compile
    • Code snippets in the documentation (e.g. generated by NDoc)

    Ok, I have to admit that I tend to ignore the full projects. When I need an example to understand something, I'm often looking for quick answers - not easy to get in an example project sometimes showing several concepts at once.

    The small examples usually consist of maybe only a few lines of code, that in many cases are not ready to be compiled (at least not without adding some more code). But often these examples are exactly what is required to get quick help, getting straight to the point.

    Unfortunately for the API developer, sample code inside the <example> tag of the XML Doc comments is a pain to create and maintain.

    • The code has to be tested.
      A missing semicolon in an example is definitely not the best way to convince the API users of the quality of the documentation. And if the code shows something that simply is not possible (e.g. a feature that was planned, but later cut from the release), people get really upset.
    • The code has to reflect the current state of the API.
      As the work on the API continues, sample code copied and pasted into your documentation has to be updated over and over again.

    With a large number of examples, the only real solution is to take sample code from actually working code (e.g. from some of the NUnit tests for the API) and to automatically insert these code snippets into the doc comments.

    The <include> tag of the XML doc comments allows the inclusion of XML fragments stored in an external XML file. I wrote a small command line tool (ExtractXml) that generates an XML file from a ".cs" file. Read more about it here.

  • ExtractXml: Including Examples in Your API Documentation

    When using an API it's always nice to have some examples showing how the different classes and their methods and properties are actually used. Examples usually come in two flavors:

    • Full projects (more or less) ready to compile
    • Code snippets in the documentation (e.g. generated by NDoc)

    Ok, I have to admit that I tend to ignore the full projects. When I need an example to understand something, I'm often looking for quick answers - not easy to get in an example project sometimes showing several concepts at once.

    The small examples usually consist of maybe only a few lines of code, that in many cases are not ready to be compiled (at least not without adding some more code). But often these examples are exactly what is required to get quick help, getting straight to the point.

    Unfortunately for the API developer, sample code inside the <example> tag of the XML Doc comments is a pain to create and maintain.

    • The code has to be tested.
      A missing semicolon in an example is definitely not the best way to convince the API users of the quality of the documentation. And if the code shows something that simply is not possible (e.g. a feature that was planned, but later cut from the release), people get really upset.
    • The code has to reflect the current state of the API.
      As the work on the API continues, sample code copied and pasted into your documentation has to be updated over and over again.

    With a large number of examples, the only real solution is to take sample code from actually working code (e.g. from some of the NUnit tests for the API) and to automatically insert these code snippets into the doc comments.

    The <include> tag of the XML doc comments allows the inclusion of XML fragments stored in an external XML file. I wrote a small command line tool (ExtractXml, download here) that generates an XML file from a ".cs" file. It's pretty much of a quick hack without much planning, but it's good enough for my own work.

    This is how it works: the ".cs" file is decorated with "////" comments containing XML processing instructions and tags:

    //// <?xml version="1.0" encoding="utf-16" ?>
    //// <Documentation><!--
    using System;
    using System.Diagnostics;
    namespace ExtractXml
    {
        /// <summary>
        /// Summary description for Example.
        /// </summary>
        public class Example
        {
            /// <summary>
            /// Does something really cool.
            /// </summary>
            public void DoSomething()
            {
                //// -->
                //// <Example name="HowToAddStrings">
                //// <example>
                //// <b>How add two strings:</b>
                //// <code>
                //// <![CDATA[
                string str1="Hello ";
                string str2="World";
                string str3=str1+str2;
                //// ]]></code>
                //// </example>
                //// </Example><!--
                Debug.WriteLine(str3);
            }
        }
    }
    //// --></Documentation>
    

    The tool is called like this:

    ExtractXml inputFile.cs outputFile.xml

    It removes the "////" comments, loads the resulting text into an XML document (detecting errors in the XML), removes the XML "<!-- ... -->" comments and saves the result:

    <?xml version="1.0" encoding="utf-16"?>
    <Documentation>
    <Example name="HowToAddStrings">
    <example>
    <b>How add two strings:</b>
    <code>
    <![CDATA[
    string str1="Hello ";
    string str2="World";
    string str3=str1+str2;
    ]]></code>
    </example>
    </Example>
    </Documentation>
    

    In your API code you reference the example like this:

    /// ...
    /// <include file="Example.xml" path="Documentation/Example[@name='HowToAddStrings']/*"/>
    /// ...
    

    Note that you are completely free regarding the structure of the XML tags, as long as the result is a valid XML document.

    Download

    The download contains the executable (for .NET Framework 1.1) and the source (project file for VS.Net 2003).

    Recommended Links

  • Part 2: My First Computer - The "CoCo"

    (continued from part 1, "How it all began")

    My First Computer - The "CoCo"
    So in May 1983 a green screen showing 32x16 black characters appeared on the TV screen in my room. From this day on, I was completely hooked. At first, my father tried to learn BASIC, too, but after some time he lost interest in programming and became what could be best described as an "advanced user". Programming turned out to be very frustrating. With about 5 days of programming experience I tried to write a "Space Invaders" clone - the first of my many software development disasters.

    What became pretty clear after rather short time was that the "TRS-80 Color Computer" was a rare thing in Germany. It was only sold in Tandy stores, definitely not to be found in every town. One day we were told by word-of-mouth that a newspaper shop in Cologne (about 25km from Bonn) sold imported US magazines exclusively covering the Color Computer: "Hot CoCo" and "The Rainbow". That was a turning point, because the program listings where the first "large" programs I could use as programming examples. My father, being a fast typist, did the monotoneous work of typing in the listings line by line, page by page. After playing around with e.g. a game typed in from a magazine for some time, I began modifying the code. I learned a lot reading other people's code, but still it was pretty tough.

    It was a strange situation. More and more people around me started using computers, but no one was seriously into programming. To them, I was the "guy who could really program", but I knew how limited my abilities were. I started project after project, few of them were actually finished. Loss of interest, or code I could not understand myself after a few days - there were many reasons. One of the few projects I did actually finish was the inevitable "Lunar Lander":

    Note that the game used a black/white graphics mode (256x192 Pixels). The colors blue and green are in fact produced by the TV set, depending on the pattern of vertical black and white lines. This trick didn't really work too well on the PAL system used in Europe; in the US, with its NTSC system, a lot more colours could be produced.

    I also attempted to learn assembly language using a book about the 6809 processor - but I simply had too little information about the computer itself to do anything useful. At least I learned the absolute basics (e.g. binary and hexadecial numbers).

    In 1984 I had the opportunity to take a Pascal course. Coming from a completely self-taught BASIC background, without any education about algorithms and data structures, I was pretty much shocked. It was so hard for me to write code without GOTOs. The implementation of the Pascal compiler running on a Philips P2000 machine wasn't too exciting; everything was slow and I didn't really see any advantage over the BASIC of my CoCo. I finished the course to get a certificate, but couldn't envision myself programming in Pascal.

    In fall 1984 it became pretty clear that the CoCo was some kind of a dead-end. The Commodory C64, after dropping in price significantly, became really popular, and games for the C64 showed what this computer could do, pushing the limit more and more. But I wanted a computer that would be easy to write programs on, and that definitely wasn't the case on the C64 (at least compared to my CoCo). To my rescue came a new computer that got a lot of hype in the magazines:  the Schneider CPC 464, the German version of the Amstrad CPC 464. With a monitor showing 80x25 characters included, that machine was pretty hot. It lacked the hardware sprites and the sound capabilities of the C64, but that didn't matter to me. I wanted such a computer so badly, that I cannot count how often I sat on my bed reading every bit of information I could get my hands on over and over again. Fortunately my father got equally excited, so Christmas 1984 a CPC 464 was standing next to the christmas tree.

    (To be continued in part 3: "My Second Computer - Codename Arnold")

  • Part 1: How it all Began

    In fall 1982 the local department began selling strange looking typewriters connected to TV sets - so-called "home computers". Interesting, but not really lighting a burning desire in me to get one of these machines. Sure, I saw that they could be used to play video games, but for a video game, the price was incredibly high. The presentation of the machines wasn't too clever as well. Nobody could really demonstrate anything useful on the computers and the "information" printed on glossy paper didn't generate this "I have to get this" feeling, either. At that time, the computers were either switched off or would run game software from modules, so no chance to watch somebody typing the typical

    10 PRINT "Hello"
    20 GOTO 10

    to impress everybody else (especially parents and salesmen) standing behind.

    In January 1983 German television started broadcasting the "Computer Club". I watched it a couple of times, but this was all a bit too much for me. At age 13, being just an average kid, without anybody around me knowing anything about computers, I just didn't understand what they were talking about on TV. What I needed was somebody giving me an introduction, just for the first, very small steps.

    Arund easter 1983 I spent two weeks at my uncle's house, visiting the youngest of three cousins. At that time the oldest cousin served his (mandatory) military service in the German army. When he came back for the weekend, he showed me what he had bought: a ZX81 computer. Simple, but affordable. I watched him writing small BASIC programs for a whole weekend, tried to write some code on my own and I now knew that this was something I was really interested in.

    My parents weren't too excited though, remembering all too well the money spent on the model railway that was catching dust, never really being used. But my father slowly got interested in computers, too. So the research for the "right computer to buy" began. The ZX81 was not seriously considered, as its limits were already too obvious. The TI99/4a and the VIC20 couldn't convince us, either. Technically, the C64 was an attractive machine (really nice looking graphics), but it did cost around 1400,- DM (714 EUR), which was a lot of money back then. The computer my father eventually bought was a TRS-80 Color Computer (around 800,- DM). The manual was perfect for beginners, even though it was written in English, and the "Extended Color BASIC" had commands for drawing lines and circles (the C64 BASIC did not).

    (continued in part 2: "My First Computer")

  • Getting rid of the 'File' Concept for Source Code?

    Frans writes: After the recent sourcecode control debate I started thinking: why on earth are we still using the 'file' as the base unit to store sourcecode in? The whole 'file' concept is pretty bad and limiting when it comes to sourcecode control, code reuse and overall code management. Much better would it be if we could work with a code repository as the container for our sourcecode which would work with sourcecode elements like we know, e.g.: namespaces, classes, assemblies, resource objects etc. etc.

    Well, I must admit that I'm torn back and forth.

    • I agree that moving away from files could lead to interesting developments, maybe even getting rid of the text-only nature of source code. I'm not only speaking about (gimmicky?) features like photos and drawings inside source code. It's also about getting rid of the need to "serialize" every bit of meta information into stone age raw text.
    • On the other hand, it's just too easy to write or at least use lots of nice little tools outside the IDE that work exactly because of the concept of source code being a bunch of files. And then there's the fear to lose the many workarounds possible with files if things don't work like they should. In case your IDE just won't let you do anything after installing some other software, at least you can copy your source files to some other place and continue your work.

    I honestly don't know. I just can't decide what is better. Maybe it's just the fear to put source "into something I cannot look into using Notepad". Maybe I'm already too traditional. But then I remember the first time I had to trust a new thing called clipboard that text I would "cut" would re-appear using "paste"... so maybe it's time for a different approach.

  • VS.Net and the FontSize Parameter

    Roy wrote about the /fs (FontSize) command line parameter of devenv.exe and using it for presentations: cool feature I didn't know about. Maybe I should have called "devenv.exe /?" before, but it just didn't came to my mind at all, not expecting any interesting parameters. Anyway, first thing I did was to try a large number (/fs 20), but I also tried "/fs 7" which is smaller than the default (/fs 8).

    Font size 7 is kind of interesting. While I use 1280x1024 on a 19" screen both at home and at work, and feeling ok with it (more would be nice, but it's ok), I'm sometimes forced to work with 1024x768 on another computer connected to the same 19" monitor. This is where every pixel in VS.Net counts, especially because you cannot make every window fly-in/out without going mad after some time.

    With "/fs 7" dialogs and helper windows are a bit smaller, while the text editor font remains unchanged. The following screenshots show the solution explorer:

    Default:

    With /fs 7:

    As you can see, you can save a few pixels - with 1280x1024 not really a reason to switch. But if you're in the strange situation of viewing low resolution on a big screen, "/fs 7" is worth giving a try.

  • Nice Buttons

    As I wrote in my first post, I'm currently developing some kind of "DJ software" in my spare time. The first versions grew by adding feature by feature over several years, the new version is a complete rewrite from bottom up. This whole project will take a lot of time, with lots of coding to be done before there's actually something usable.

    While I'm implementing the framework, I also work on "visible" stuff to keep my motivation up (this is a private project, and I don't expect making [much] money from it). Something "visible" is e.g. the audio player control. I don't use the Windows Media Player control directly, instead I'm using the (non-GUI) WMP object hidden behind an abstraction layer, which is accessed by a user control showing the GUI..

    A GUI for a player has to be cool (but no "unusable 1337 skinz", please), including nice looking buttons for "start/stop/pause/etc.". So here's what my buttons look like:

    Nice, huh? So how much effort went into those buttons? Very little. If you're not looking for a "100% perfect" solution, you can get pretty good results just playing around with the properties "BackColor", "BackgroundImage" and "Image" of a WinForms button.

    • Step 1: Decide how high the button will be; for this example, let's choose a height of 32 pixels. The width doesn't play a role as the image can be repeated horizontally without looking bad. Fire up your favorite paint program, create a 32x32 image and perform a vertical gradient fill from white (#FFFFFF) to gray (#C0C0C0):
    • Step 2: Let's try it in VS.Net:
      • Put a button on a form, 32 pixels high.
      • Set the "BackColor" to white
      • Set the "BackgroundImage" property
      This is the result:
    • Step 3: Design the button image:
      and save it as a GIF file with transparent background:
    • Step 4: In VS.Net, clear the button text and set the "Image" property:
    • That's it!

    Remarks:

    • Leave an empty pixel column/row at the right/bottom border of your button image, otherwise the image will not appear centered on the button.
    • Of the background image, the outer 2 pixel rows/columns will not be visible, they are hidden behind the border of the button.
  • Wouldn't it be cool...?

    This is what XML comments look like on my computer today:

    Wouldn't it be cool if someday (in VS.Net 200x?) we could have something like this:

    It's kind of frustrating to see computers rendering 3D worlds with 100s of frames/sec, but source code editors advancing only in very small steps...

  • Better Keyboard Support for #region ... #endregion

    Of all the elements that can be collapsed in the VS.Net editor (namespaces, classes, methods, comments, ...), only regions are of actual importance for my everyday work. Here are three macros that are quite helpful for expanding/collapsing regions using the keyboard:

    Macro Purpose Keys (example)
    ExpandAllRegions expands all regions in the current document Ctrl-Shift-'+'
    CollapseAllRegions collapses all regions in the current document Ctrl-Shift-'-'
    ToggleParentRegion expands/collapses the region the cursor is currently in Ctrl-'+' and Ctrl-'-'

    Installation:

     

    • Open the Macros IDE (Tools - Macros - Macros IDE)
    • Create a new module, replace the code in the created file with the posted source code, save file
    • Assign keys in VS.Net (Tools - Options - Keyboard).

    Tip: type "Region" in the input field under "show commands containing" to limit the list of shown commands (don't laugh, it's always amazing how many people don't know about this rather obvious feature...)

    Known Issues

    • The code runs fine in VS.Net 2003; in VS.Net 2002 I had strange problems with "Selection.FindText" not working reliably.
    • ToggleParentRegion is "good enough", but not perfect; e.g. when the cursor is at the end of a line containing a collapsed region, it won't expand the region, but move the cursor to the start of the line (where a second invocation will work fine).
    • (Update 14.08.2003): The macro ExpandAllRegions does not work in VB.Net (see comments below). The macro ToggleParentRegion didn't work correctly, either, but could be fixed (see "Updated" comment in code).

    Source Code

    Imports EnvDTE
    Imports System.Diagnostics
    ' Macros for improving keyboard support for "#region ... #endregion"
    Public Module RegionTools
    ' Toggles the current region surrounding the cursor
    Sub ToggleParentRegion()
    Dim objSelection As TextSelection
    objSelection = DTE.ActiveDocument.Selection
    Dim objPosition As EnvDTE.TextPoint
    objPosition = objSelection.AnchorPoint
    objSelection.SelectLine()
    If (InStr(objSelection.Text.ToLower(), "#region") <> 0) Then ' Updated 14.08.2003
    objSelection.MoveToPoint(objPosition)
    DTE.ExecuteCommand("Edit.ToggleOutliningExpansion")
    DTE.ActiveDocument.Selection.StartOfLine(vsStartOfLineOptions.vsStartOfLineOptionsFirstColumn)
    ElseIf (objSelection.FindText("#region", vsFindOptions.vsFindOptionsBackwards)) Then
    DTE.ActiveDocument.Selection.StartOfLine(vsStartOfLineOptions.vsStartOfLineOptionsFirstColumn)
    DTE.ExecuteCommand("Edit.ToggleOutliningExpansion")
    DTE.ActiveDocument.Selection.StartOfLine(vsStartOfLineOptions.vsStartOfLineOptionsFirstColumn)
    Else
    objSelection.MoveToPoint(objPosition)
    End If
    End Sub

    ' Expands all regions in the current document
    Sub ExpandAllRegions()
    DTE.ExecuteCommand("Edit.StopOutlining")
    DTE.ExecuteCommand("Edit.StartAutomaticOutlining")
    End Sub

    ' Collapses all regions in the current document
    Sub CollapseAllRegions()
    ExpandAllRegions()
    Dim objSelection As TextSelection
    objSelection = DTE.ActiveDocument.Selection
    objSelection.StartOfDocument()
    While (objSelection.FindText("#region"))
    objSelection.StartOfLine(vsStartOfLineOptions.vsStartOfLineOptionsFirstColumn)
    DTE.ExecuteCommand("Edit.ToggleOutliningExpansion")
    objSelection.StartOfDocument()
    End While
    DTE.ActiveDocument.Selection.StartOfDocument()
    End Sub
    End Module
  • Personal VS.Net Editor Color/Font Settings

    Roy writes "I was fiddling with the color settings for visual studio, and was trying to get a less eye-straining environment for coding in". What he came up with is definitely a matter of personal taste ;-)

     

    Speaking of personal taste, here's a screenshot of my settings:

    Most important for me (and my eyes) is the use of a proportional-width font. Verdana 8pt is the font I use for virtually every editor I use. Unlike e.g. Arial, you can call it a "developer's font", because you can distinguish the small "L" and the large "i".

    Switching to a proportional font wasn't easy for me at first, because I had to break with old habits; most of them (e.g. aligning end-of-line comments running over several lines) were a waste of time, anyway.

  • First entry / Fun with Media Player SDK

    This entry may surprise some people I know that are reading the main feed every day - I didn't tell them I would start a blog... For everybody else some quick info about me: I'm 34 years old, started programming in 1983 on a TRS-80 Color Computer and got my first PC in 1989. I live in Bonn, Germany, working as a software developer for a local company. In my spare time I enjoy writing tools and macros, and - in many iterations over the last years, using different languages/technologies - a kind of DJ'ing software for sports events like basketball games. Currently I'm doing a complete rewrite in C#, using the windows media player 9 SDK.

    So far, my experiences using the media player object, its properties, methods and events have been very good. But yesterday I ran into something rather strange.

    Say you open a sound file like this:

    objPlayer.URL=@"D:\MySound.wav";

    and now you want to know the duration

    double dDuration=objPlayer.currentMedia.duration;

    but dDuration is 0. If you play the sound file, currentMedia.duration contains the correct value. But you want the duration before starting playback. Ok, next try:

    IWMPMedia objMedia = objPlayer.newMedia(filename);&lt;br&gt;objPlayer.currentMedia=objMedia&lt;br&gt;double dDuration=objPlayer.currentMedia.duration;&lt;br&gt;

    Again, dDuration is 0. Now try this:

    IWMPMedia objMedia = objPlayer.newMedia(filename);&lt;br&gt;double dDummy=objMedia.duration;&lt;br&gt;objPlayer.currentMedia=objMedia&lt;br&gt;double dDuration=objPlayer.currentMedia.duration;&lt;br&gt;

    And... dDuration contains the correct value!

    Took me some time to figure out that one...