June 25, 2009

Patching a Crash in Kensington MouseWorks

A co-worker had trouble installing the latest version of an application I've been working on. The log file showed that the problem was an access violation when our setup program called MsiInstallProduct. This seemed very unusual, since Windows APIs return error codes instead of crashing. I decided to see where the crash was happening by running the installer under WinDbg.

I set WinDbg to immediately break on exceptions and launched the app. It stopped almost immediately with the following callstack. The crash location is in kwm_dll.dll, which is a hook DLL installed by Kensington MouseWorks.

kmw_dll!CallWndProcFunc+0xa8
USER32!DispatchHookA+0x101
USER32!fnHkINLPCWPSTRUCTA+0x4f
USER32!__fnDWORD+0x24
ntdll!KiUserCallbackDispatcher+0x13
USER32!NtUserSetFocus+0xc
USER32!CreateDialogIndirectParamAorW+0x33
USER32!CreateDialogParamW+0x49
msi!CBasicUI::CreateProgressDialog+0x35
msi!CBasicUI::CheckDialog+0x47
msi!CBasicUI::SetProgressData+0x58
msi!CBasicUI::Initialize+0x11c
msi!MsiUIMessageContext::Initialize+0x230
msi!MsiUIMessageContext::RunInstall+0x22
msi!RunEngine+0xe0
msi!MsiInstallProductW+0xa1
BatchUpd!Application::RunCommandInstall+0x1f5
BatchUpd!Application::Run+0x11e3
BatchUpd!wWinMain+0x102

Disassembling the crash location showed the following (crashing code in bold; ebp does not contain a valid address).

mov     eax,dword ptr [ebp-4]
mov     ecx,dword ptr [eax]
push    ecx
mov     edx,dword ptr [ebp-4]
mov     eax,dword ptr [edx+4]
push    eax
mov     ecx,dword ptr [ebp-4]
mov     edx,dword ptr [ecx+0Ch]
push    edx
call    kmw_dll!CallWndProcFunc+0x12f0 (10004210)
add     esp,0Ch
mov     eax,dword ptr [ebp+10h]
push    eax
mov     ecx,dword ptr [ebp+0Ch]
push    ecx
mov     edx,dword ptr [ebp+8]
push    edx
mov     eax,dword ptr [kmw_dll!ShowOptsProc+0x6b94 (1000e0a4)]
push    eax
call    dword ptr [kmw_dll!ShowOptsProc+0x7c80 (1000f190)]
mov     esp,ebp
pop     ebp
ret     0Ch

One interesting thing about the code is that it looks like a Debug build (or a Release build with no optimizations): the disassembly is straightforward and seems like it has a one-to-one correspondence with the putative source code. The other thing of note (not shown above) is that the base address of the DLL is set to the default 0x10000000, which is a poor choice for a hook DLL that will be loaded into every process on the system.

ebp should be preserved across the function call, so I looked at the function that was just called (at address 0x10004210). I've added a few explanatory comments based on my understanding of what it's doing.

push    ebp				; save caller's value of ebp
mov     ebp,esp				; standard function prologue
sub     esp,offset +0x87 (00000088)	; BOOL bLocal0; char szLocal1[132];
cmp     dword ptr [ebp+0Ch],0		; if (param2 == 0)
je      kmw_dll!CallWndProcFunc+0x130b (1000422b) ; goto label0;
mov     dword ptr [ebp-88h],0		; bLocal0 = FALSE;
jmp     kmw_dll!CallWndProcFunc+0x1315 (10004235) ; goto label1;
label0:
mov     dword ptr [ebp-88h],offset  (00000001) ; bLocal0 = TRUE;
label1:
mov     eax,dword ptr [ebp-88h]		; push bLocal0
push    eax
lea     ecx,[ebp-84h]			; push &szLocal1[0]
push    ecx
mov     edx,dword ptr [ebp+10h]		; push param3
push    edx
mov     eax,dword ptr [ebp+8]		; push param1
push    eax
call    kmw_dll!ShowOptsProc+0x16e0 (10008bf0)	; fn(param1, param3, szLocal1, bLocal0)
add     esp,10h				; clean up parameters (C calling convention)
mov     esp,ebp				; "free" locals
pop     ebp				; restore caller's value of ebp
ret                                                                                                  

This function is allocating 0x88 (i.e., 136) bytes for local variable storage: enough for an int (or BOOL) and a 132 byte buffer. If this buffer were overflowed, the stack would be overwritten and ebp would be corrupted upon return. Some internet searching turns up posts that discuss a similar issue, stating that "Kensington MouseWorks ... crashes ... if the executable path is longer than 128 characters"; this seems to match our situation. Indeed, dumping the bytes at the old value of ebp-84h shows the full path of our setup application, which is too long for the buffer.

Since the buffer is stack allocated, it would be trivial to change its size by editing the instructions that create and reference the local variables. At a minimum, the buffer should be capable of storing MAX_PATH characters. Because this function doesn't supply the actual buffer length to the function it calls, we can make it as long as we (reasonably) want. I decided to increase the size for storage of locals in this function to 300 bytes. In version 6.3.2.4 of kmw_dll.dll (which seems like it may be newer than the latest available version, published in February 2006), this can be accomplished by editing the following bytes in the file. These changes simply change the numbers 136, -136, and -132 (which are the three offsets used in the code above) to 300, -300, and -296.

OffsetNew Bytes
0x42152C 01
0x4221D4 FE
0x422DD4 FE
0x4237D4 FE
0x423ED8 FE

The buffer should now be large enough to hold a file name up to MAX_PATH bytes long. With this new DLL installed in the C:\Windows\System32 folder, the setup program is able to launch the MSI and installation completes successfully.

Posted by Bradley Grainger at 7:45 PM | Comments (2) | TrackBack (0)

June 5, 2009

Using If-Modified-Since in HTTP Requests

Conditionally requesting the download of a web page only if it has been modified after a given time seems like it should be as simple as setting the IfModifiedSince property and making the request:

HttpWebRequest request = (HttpWebRequest) WebRequest.Create(@"http://code.logos.com/blog/");

request.IfModifiedSince = new DateTime(2009, 6, 3);

using (HttpWebResponse response = (HttpWebResponse) request.GetResponse())

{

    if (response.StatusCode == HttpStatusCode.NotModified)

    {

        // page wasn't modified; use cached version

    }

}

But of course it’s not that simple (as some others have noticed).

The designers of HttpWebRequest decided that some particular HTTP status codes would cause a WebException to be thrown. (As far as I can tell, this list is undocumented, but 304 “Not Modified” is one of them.) This is a vexing exception, because the situation is hardly exceptional. In fact, because it can only happen if IfModifiedSince is explicitly set (or if request.Headers were modified), one could argue that it’s quite expected and intentional. To avoid duplicating logic in the try block (for handling 200 “OK”) and in the catch block (for handling “304” Not Modified), I wrote a utility method that swallows any WebException thrown due to a ProtocolError (e.g., an “invalid” HTTP status code):

public static class HttpWebRequestUtility

{

    /// <summary>

    /// Gets the <see cref="HttpWebResponse"/> from an Internet resource.

    /// </summary>

    /// <param name="request">The request.</param>

    /// <returns>A <see cref="HttpWebResponse"/> that contains the response from the Internet resource.</returns>

    /// <remarks>This method does not throw a <see cref="WebException"/> for "error" HTTP status codes; the caller should

    /// check the <see cref="HttpWebResponse.StatusCode"/> property to determine how to handle the response.</remarks>

    public static HttpWebResponse GetHttpResponse(this HttpWebRequest request)

    {

        try

        {

            return (HttpWebResponse) request.GetResponse();

        }

        catch (WebException ex)

        {

            // only handle protocol errors that have valid responses

            if (ex.Response == null || ex.Status != WebExceptionStatus.ProtocolError)

                throw;

 

            return (HttpWebResponse) ex.Response;

        }

    }

}

The code to consume this reads very similarly to the first snippet in this post; you just have to remember that normal errors (e.g., 404 “Not Found”) are reported through a valid HttpWebResponse, so its StatusCode property must be checked before acting on the response.

Posted by Bradley Grainger at 11:36 AM | Comments (3) | TrackBack (0)

June 1, 2009

Enumerable.Sum never returns null

I wrote the following code recently, and was surprised when ReSharper warned me that the condition is always true:

IEnumerable<int?> values = // get some values

int? sum = values.Sum();

if (sum.HasValue) { /* this code is always executed */ }

It’s even more surprising when you consider the following difference:

int?[] values = new int?[] { 1, null };

int? sum1 = values.Sum(); // returns 1

int? sum2 = values[0] + values[1]; // returns null

Here, sum1 is 1, but sum2 is null.

Since Sum<int?> never returns null (not even for any empty sequence, or a sequence containing all nulls), it’s odd that its return type is int?, implying that null is a possible return value. Anders explains that this return type is to keep the pattern of T Sum<T>(IEnumerable<T>) for nullable types.

But what if you want Sum to return null if the sequence contains a null? This is easy to simulate using Aggregate, as C# already propagates nulls properly when using the addition operator:

public static class EnumerableUtility

{

    public static int? NullableSum(this IEnumerable<int?> values)

    {

        return values.Aggregate((int?) 0, (sum, value) => sum + value);

    }

}

The initial value of 0 is specified to force the sum of an empty list to be zero; you could change it to default(int?) to make an empty list sum to null. A possible optimisation would be to rewrite it with a foreach loop that returns null as soon as the first null in the sequence is found.

Update: My very smart coworker points out that changing the initial aggregate value to default(int?) makes the function return null for any input. (This is probably a good reason to include a full unit test suite with every blog post…) A custom enumerator (or test of values.Any() first) could be used if returning null as the sum of an empty sequence is desired.

Posted by Bradley Grainger at 4:55 PM | Comments (0) | TrackBack (0)

May 6, 2009

WrappingStream Implementation

In a previous post, I mentioned that a certain problem could be solved by creating “an implementation of Stream that wraps another stream”. “Anonymous” asked recently, “Can you send me the code of your straightforward solution that is wrapper the class MemoryStream?”. Yes, but first I want to give another example of where such a class is useful.

The first time I used BinaryReader, I wrote code similar to the following:

public void DoSomething(Stream stream)

{

    // read a simple byte

    int value = stream.ReadByte();

 

    // simplify more complex reading by using a BinaryReader

    using (BinaryReader reader = new BinaryReader(stream))

    {

        value = reader.ReadInt32();

        value = reader.ReadInt32();

    }

 

    // back to simple reading

    value = stream.ReadByte();

}

Experienced users of BinaryReader will see the problem here: the BinaryReader class takes ownership of the Stream with which it’s constructed, and disposes it in Dispose. (This somewhat-important detail is only briefly mentioned in the documentation for the Close method.) Thus the last call to ReadByte fails; we have also closed the Stream even though our caller probably expects it to still be open.

While the easy answer is to simply not Close/Dispose the BinaryReader (it holds no unmanaged resources, and so nothing “bad” happens if it’s not disposed), I feel guilty every time I don’t dispose an IDisposable object. Moreover, tools like the .NET Memory Profiler have a profiling mode that lists all non-disposed IDisposable objects (to help find resource leaks); leaving this BinaryReader undisposed generates a false positive and makes it harder to find the real leaks.

The WrappingStream class can be of use in this scenario by providing an implementation of Stream that the BinaryReader can own and Dispose without affecting the real stream:

using (WrappingStream wrapper = new WrappingStream(stream))

using (BinaryReader reader = new BinaryReader(wrapper))

{

    value = reader.ReadInt32();

    value = reader.ReadInt32();

}

 

// 'stream' is still valid here

Here, at long last, is the code for WrappingStream:

/// <summary>

    /// A <see cref="Stream"/> that wraps another stream. The major feature of <see cref="WrappingStream"/> is that it does not dispose the

    /// underlying stream when it is disposed; this is useful when using classes such as <see cref="BinaryReader"/> and

    /// <see cref="System.Security.Cryptography.CryptoStream"/> that take ownership of the stream passed to their constructors.

    /// </summary>

    public class WrappingStream : Stream

    {

        /// <summary>

        /// Initializes a new instance of the <see cref="WrappingStream"/> class.

        /// </summary>

        /// <param name="streamBase">The wrapped stream.</param>

        public WrappingStream(Stream streamBase)

        {

            // check parameters

            if (streamBase == null)

                throw new ArgumentNullException("streamBase");

 

            m_streamBase = streamBase;

        }

 

        /// <summary>

        /// Gets a value indicating whether the current stream supports reading.

        /// </summary>

        /// <returns><c>true</c> if the stream supports reading; otherwise, <c>false</c>.</returns>

        public override bool CanRead

        {

            get { return m_streamBase == null ? false : m_streamBase.CanRead; }

        }

 

        /// <summary>

        /// Gets a value indicating whether the current stream supports seeking.

        /// </summary>

        /// <returns><c>true</c> if the stream supports seeking; otherwise, <c>false</c>.</returns>

        public override bool CanSeek

        {

            get { return m_streamBase == null ? false : m_streamBase.CanSeek; }

        }

 

        /// <summary>

        /// Gets a value indicating whether the current stream supports writing.

        /// </summary>

        /// <returns><c>true</c> if the stream supports writing; otherwise, <c>false</c>.</returns>

        public override bool CanWrite

        {

            get { return m_streamBase == null ? false : m_streamBase.CanWrite; }

        }

 

        /// <summary>

        /// Gets the length in bytes of the stream.

        /// </summary>

        public override long Length

        {

            get { ThrowIfDisposed();  return m_streamBase.Length; }

        }

 

        /// <summary>

        /// Gets or sets the position within the current stream.

        /// </summary>

        public override long Position

        {

            get { ThrowIfDisposed(); return m_streamBase.Position; }

            set { ThrowIfDisposed(); m_streamBase.Position = value; }

        }

 

        /// <summary>

        /// Begins an asynchronous read operation.

        /// </summary>

        public override IAsyncResult BeginRead(byte[] buffer, int offset, int count, AsyncCallback callback, object state)

        {

            ThrowIfDisposed();

            return m_streamBase.BeginRead(buffer, offset, count, callback, state);

        }

 

        /// <summary>

        /// Begins an asynchronous write operation.

        /// </summary>

        public override IAsyncResult BeginWrite(byte[] buffer, int offset, int count, AsyncCallback callback, object state)

        {

            ThrowIfDisposed();

            return m_streamBase.BeginWrite(buffer, offset, count, callback, state);

        }

 

        /// <summary>

        /// Waits for the pending asynchronous read to complete.

        /// </summary>

        public override int EndRead(IAsyncResult asyncResult)

        {

            ThrowIfDisposed();

            return m_streamBase.EndRead(asyncResult);

        }

 

        /// <summary>

        /// Ends an asynchronous write operation.

        /// </summary>

        public override void EndWrite(IAsyncResult asyncResult)

        {

            ThrowIfDisposed();

            m_streamBase.EndWrite(asyncResult);

        }

 

        /// <summary>

        /// Clears all buffers for this stream and causes any buffered data to be written to the underlying device.

        /// </summary>

        public override void Flush()

        {

            ThrowIfDisposed();

            m_streamBase.Flush();

        }

 

        /// <summary>

        /// Reads a sequence of bytes from the current stream and advances the position

        /// within the stream by the number of bytes read.

        /// </summary>

        public override int Read(byte[] buffer, int offset, int count)

        {

            ThrowIfDisposed();

            return m_streamBase.Read(buffer, offset, count);

        }

 

        /// <summary>

        /// Reads a byte from the stream and advances the position within the stream by one byte, or returns -1 if at the end of the stream.

        /// </summary>

        public override int ReadByte()

        {

            ThrowIfDisposed();

            return m_streamBase.ReadByte();

        }

 

        /// <summary>

        /// Sets the position within the current stream.

        /// </summary>

        /// <param name="offset">A byte offset relative to the <paramref name="origin"/> parameter.</param>

        /// <param name="origin">A value of type <see cref="T:System.IO.SeekOrigin"/> indicating the reference point used to obtain the new position.</param>

        /// <returns>The new position within the current stream.</returns>

        public override long Seek(long offset, SeekOrigin origin)

        {

            ThrowIfDisposed();

            return m_streamBase.Seek(offset, origin);

        }

 

        /// <summary>

        /// Sets the length of the current stream.

        /// </summary>

        /// <param name="value">The desired length of the current stream in bytes.</param>

        public override void SetLength(long value)

        {

            ThrowIfDisposed();

            m_streamBase.SetLength(value);

        }

 

        /// <summary>

        /// Writes a sequence of bytes to the current stream and advances the current position

        /// within this stream by the number of bytes written.

        /// </summary>

        public override void Write(byte[] buffer, int offset, int count)

        {

            ThrowIfDisposed();

            m_streamBase.Write(buffer, offset, count);

        }

 

        /// <summary>

        /// Writes a byte to the current position in the stream and advances the position within the stream by one byte.

        /// </summary>

        public override void WriteByte(byte value)

        {

            ThrowIfDisposed();

            m_streamBase.WriteByte(value);

        }

 

        /// <summary>

        /// Gets the wrapped stream.

        /// </summary>

        /// <value>The wrapped stream.</value>

        protected Stream WrappedStream

        {

            get { return m_streamBase; }

        }

 

        /// <summary>

        /// Releases the unmanaged resources used by the <see cref="WrappingStream"/> and optionally releases the managed resources.

        /// </summary>

        /// <param name="disposing">true to release both managed and unmanaged resources; false to release only unmanaged resources.</param>

        protected override void Dispose(bool disposing)

        {

            // doesn't close the base stream, but just prevents access to it through this WrappingStream

            if (disposing)

                m_streamBase = null;

 

            base.Dispose(disposing);

        }

 

        private void ThrowIfDisposed()

        {

            // throws an ObjectDisposedException if this object has been disposed

            if (m_streamBase == null)

                throw new ObjectDisposedException(GetType().Name);

        }

 

        Stream m_streamBase;

    }

You’ll note that this class isn’t sealed; that’s because it can be a useful base class for more specialised wrappers, some of which I hope to cover in future posts.

Posted by Bradley Grainger at 10:12 AM | Comments (2) | TrackBack (0)

April 28, 2009

How to use UMDH to find native memory leaks

The Debugging Tools for Windows packages come with a tool—UMDH.exe—that makes finding memory leaks in native code really pretty easy. There’s a Microsoft Knowledgebase Article that gives an overview of how to use the tool but it’s a little out of date. (It’s also very detailed, and I usually just want a summary.)

All these steps assume you have the latest Debugging Tools package installed and in your path. (Note that you need to run the tools for the same platform (x86 vs x64) as the target executable.)

Start Collecting Data

At an Administrator command prompt, run gflags.exe to start collecting stack traces for user-mode allocations:

gflags –i Program.exe +ust

Collect Snapshots

Start Program.exe running, and collect a baseline snapshot (this can be done from a regular command prompt):

umdh –pn:Program.exe –f:Dump1.txt

Perform the action that leaks memory, and collect a second snapshot:

umdh –pn:Program.exe –f:Dump2.txt

(If “Program.exe” is not a unique process name, the “-p:” command line argument can select a process by ID.)

Compare Snapshots

umdh –d Dump1.txt Dump2.txt > Diff.txt

Open Diff.txt in your favourite text editor (that can handle large files!). The memory leaks are listed in descending order of bytes leaked; each should be followed by the complete stack trace of the allocation call. Depending on the cause, this may either pinpoint the bug, or at least show a good place to set a breakpoint for debugging.

Stop Data Collection

The most important step in the whole process is to turn off the data collection for your application (once the memory leak is fixed), or else your program will run slowly while the OS kernel logs every memory allocation:

gflags –i Program.exe -ust

Posted by Bradley Grainger at 4:05 PM | Comments (0) | TrackBack (0)

April 14, 2009

DateTime and ISO8601

The ISO 8601 standard for representing dates and times defines a (large) number of string formats for serializing dates. One of the more common formats in use (certainly here at Logos) uses the “extended format”, specifies the full date and time (but only in whole, not fractional, seconds) and always uses UTC. A string in this format looks like “2009-04-14T16:19:58Z”.

The standard date and time format strings for .NET don’t include a pattern that uses this precise format. The round-trip date/time pattern (specified by “o”) includes fractional seconds (e.g., “2009-04-14T16:19:58.0785018Z”), whereas the universal sortable date/time pattern (specified by “u”) has a space instead of a ‘T’ between the date and the time (e.g., “2009-04-14 16:19:58Z”).

We wrote the following utility methods to parse and render DateTimes in our preferred format:

/// <summary>

/// Provides methods for manipulating dates.

/// </summary>

public static class DateTimeUtility

{

    /// <summary>

    /// Converts the specified ISO 8601 representation of a date and time

    /// to its DateTime equivalent.

    /// </summary>

    /// <param name="value">The ISO 8601 string representation to parse.</param>

    /// <returns>The DateTime equivalent.</returns>

    public static DateTime ParseIso8601(string value)

    {

        return DateTime.ParseExact(value,

            Iso8601Format, CultureInfo.InvariantCulture,

            DateTimeStyles.AssumeUniversal | DateTimeStyles.AdjustToUniversal);

    }

 

    /// <summary>

    /// Formats the date in the standard ISO 8601 format.

    /// </summary>

    /// <param name="value">The date to format.</param>

    /// <returns>The formatted date.</returns>

    public static string ToIso8601(this DateTime value)

    {

        return value.ToUniversalTime().ToString(Iso8601Format, CultureInfo.InvariantCulture);

    }

 

    /// <summary>

    /// The ISO 8601 format string.

    /// </summary>

    public const string Iso8601Format = "yyyy'-'MM'-'dd'T'HH':'mm':'ss'Z'";

}

Posted by Bradley Grainger at 9:24 AM | Comments (2) | TrackBack (0)

April 8, 2009

Creating Mixins with T4 in Visual Studio

One of the (few) features I really miss from C++ is the ability to use multiple inheritance to create mixins, particularly with the Curiously Recurring Template Pattern.

Scott Hanselman blogged about T4 (Text Template Transformation Toolkit) a few months back, but only recently it hit me that T4 could be combined with partial classes to create a poor man's mixin system in C# 3.0.

For a simple example, let's consider a class that supports IEquatable<T>. The logic that’s specific to computing equality for this class will be in the Equals and GetHashCode methods:

public class TestObject : IEquatable<TestObject>

{

    public TestObject(int value)

    {

        Value = value;

    }

 

    public bool Equals(TestObject other)

    {

        return other != null && Value == other.Value;

    }

 

    public override int GetHashCode()

    {

        return Value;

    }

 

    public int Value { get; set; }

}

To round out this class, we really should implement Equals(object) and overload the equality operators. This is exactly where a mixin would be useful, because that code is exactly the same in every implementation of an equatable object.

Firstly, prepare TestObject to support mixins by making it a partial class:

public partial class TestObject : IEquatable<TestObject>

Secondly, create the mixin source: the templated methods of the equatable implementations. Add a new item to the project, and set the name to “EquatableClass.tt”. (This implementation will be for classes only; a separate mixin would need to be created for structs since they can’t ever be null.)

Open the Properties window for this new file, and clear the Custom Tool property. This prevents an output file being generated for this template.

Fill in the EquatableClass.tt file with this code, a templated version of standard equality methods.

namespace <#= NamespaceName #>

{

    partial class <#= ClassName #>

    {

        public override bool Equals(object other)

        {

            return Equals(other as <#= ClassName #>);

        }

 

        public static bool operator==(<#= ClassName #> left, <#= ClassName #> right)

        {

            if (ReferenceEquals(left, right))

                return true;

            else if (ReferenceEquals(left, null) || ReferenceEquals(right, null))

                return false;

            else

                return left.Equals(right);

        }

 

        public static bool operator!=(<#= ClassName #> left, <#= ClassName #> right)

        {

            if (ReferenceEquals(left, right))

                return false;

            else if (ReferenceEquals(left, null) || ReferenceEquals(right, null))

                return true;

            else

                return !left.Equals(right);

        }

    }

}

<#+

    public void SetClassName(string namespaceName, string className)

    {

        NamespaceName = namespaceName;

        ClassName = className;

    }

 

    string NamespaceName;

    string ClassName;

#>

This template (when included in another template) outputs the standard equality methods and also provides a way for the including template to customize the output.

Lastly, write the including template. Add another file to the project, this time named “TestObjectEquatable.tt”. Paste the following code into that file:

<#@template language="C#"#>

<#@output extension="g.cs" #>

<# SetClassName("Mixins", "TestObject"); #>

<#@include file="EquatableClass.tt"#>

These four lines have the following effects:

  1. Instructs the T4 engine that code in this template is written in C#.
  2. Sets the extension of the file to “.g.cs”; this clearly identifies the output as generated code.
  3. Calls the SetClassName method defined in the first template so that the right namespace and class name are used in the generated code.
  4. Includes the first template, causing all the code it defines to be generated.

When the project is built, the TestObjectEquatable.tt template will be processed to generate a partial class containing the supporting equality methods. The C# compiler will compile this with the primary partial class, giving a complete implementation of the standard equality methods.

Now that the template is defined, only the four lines in the second template need to be copied to add equatable methods to a new class, instead of the 25 lines of boilerplate code that the template generates.

One significant drawback with this approach is that a template is only reprocessed when it changes; the template engine isn't aware that TestObjectEquatable.tt depends on EquatableClass.tt, and that it should be reprocessed if the latter changes. For this reason, it’s probably best to keep the included template rather simple; it would be better to have the generated methods delegate to composed objects or static methods on utility classes rather than including a lot of complicated logic in the template itself.

To learn more about T4, I highly recommend Oleg Sych’s blog, which contains many tutorials, examples, and information about his T4 Toolbox project.

Posted by Bradley Grainger at 8:51 AM | Comments (3) | TrackBack (0)

March 17, 2009

ReadOnlyObservableCollection anti-pattern

I recently fixed a bug that was a result of a subtle misuse of the ReadOnlyObservableCollection<T> class. The code in question was structured as follows: The Source class has a collection of Items. Clients should be able to observe but not modify the collection, so it’s exposed as a ReadOnlyObservableCollection. The Client class adds an event handler to this collection, and removes it at the appropriate time (to prevent a possible memory leak).

class Source

{

    Source()

    {

        m_collection = new ObservableCollection<int>();

    }

 

    public ReadOnlyObservableCollection<int> Items

    {

        get

        {

            // this is the bug

            return new ReadOnlyObservableCollection<int>(m_collection);

        }

    }

 

    readonly ObservableCollection<int> m_collection;

}

 

class Client

{

    // obtain Source instance from somewhere

    Source m_source;

 

    void Subscribe()

    {

        ((INotifyCollectionChanged) m_source.Items).CollectionChanged += SourceItems_CollectionChanged;

    }

 

    void Unsubscribe()

    {

        ((INotifyCollectionChanged) m_source.Items).CollectionChanged += SourceItems_CollectionChanged;

    }

 

    void SourceItems_CollectionChanged(object sender, NotifyCollectionChangedEventArgs e) { }

}

The bug is that the Source.Items property creates a new ReadOnlyObservableCollection instance each time it’s accessed, which means that the calls to add and remove the event handler happen on two different objects; the event handler is never actually removed.

One solution is for the Client class to cache the exact INotifyCollectionChanged object it subscribed to, so it can be sure to unsubscribe from the same object. The other (and better) solution is for the Source class to create and hold a ReadOnlyObservableCollection, and return the same object each time the Items property is accessed:

public class Source

{

    Source()

    {

        m_collection = new ObservableCollection<int>();

        m_collectionReadOnly = new ReadOnlyObservableCollection<int>(m_collection);

    }

 

    public ReadOnlyObservableCollection<int> Items

    {

        get { return m_collectionReadOnly; }

    }

 

    readonly ObservableCollection<int> m_collection;

    readonly ReadOnlyObservableCollection<int> m_collectionReadOnly;

}

This solves the initial bug and also has the benefit of allowing all clients to share the same ReadOnlyObservableCollection instance (instead of creating one per client).

Posted by Bradley Grainger at 9:02 AM | Comments (2) | TrackBack (0)

March 9, 2009

Subtle Differences

What’s the difference between the values generated by the following statements?

    long ticks1 = stopwatch.ElapsedTicks;

    long ticks2 = stopwatch.Elapsed.Ticks;

While the latter uses the standard 100-nanosecond intervals (used by FILETIME, DateTime, etc.) as its units, the former reports the number of ticks as measured by the system’s high-resolution performance counter, and is not very meaningful until divided by Stopwatch.Frequency. The use of the noun ‘ticks’ to describe both is unfortunate.

Here’s another difference, which turns out to not be so significant after all:

    using System.Linq;

    // ...

    bool contains1 = dictionary.ContainsKey(value);

    bool contains2 = dictionary.Keys.Contains(value);

I initially assumed that the second statement—which invokes the Enumerable.Contains extension method—would perform a linear search over a copy of all the keys in the Dictionary. However, some exploration with Reflector showed that Enumerable.Contains first checks if its parameter implements ICollection<T>. The KeyCollection returned by Dictionary<K, V>.Keys does implement this interface, and its implementation of Contains simply delegates to ContainsKey. Experimentation showed that the latter statement only takes twice as long as the first—not the O(1) vs O(n) difference I was expecting. While API duplication should be avoided, some overlap is inevitable when retrofitting extension methods to an existing codebase; it’s very nice that the LINQ to Objects design allows for an efficient implementation to be chosen when it’s available.

Posted by Bradley Grainger at 8:25 AM | Comments (0) | TrackBack (0)

January 14, 2009

CHARINDEX ?

CHARINDEX. Yeah. That's right. It is one of my favorite SQL functions. I rarely see it used and most people I know don't even know about it. Consequently, I must blab about it a little.

CHARINDEX returns the index of a successful string match.

For example:

print charindex('cat','my cat is king')

Returns: 4


The searches can also be case sensitive:

print charindex('king','my cat is KING!' COLLATE Latin1_General_CS_AS)

returns: 0


Here is a little function I use from time to time. It grabs the text in between two characters:

Create Function [dbo].[fnBetweenCharacters](@text ntext, @startChar nchar(1), @endChar nchar(1))

 

RETURNS nvarchar(4000)

 

AS

 

BEGIN

 

declare @startIndex int

declare @endIndex int

 

set @startIndex = charindex(@startChar, @text, 1)

set @endIndex = charindex(@endChar, @text, @startIndex+1)

 

return substring(@text,@startIndex+1, @endIndex - @startIndex-1)

 

END


It can be used like this:

print [dbo].[fnBetweenCharacters](N'asdkljasd@I need this text*k;lk', '@', '*')

returns: I need this text


Pass it on!

Posted by Bill Simpkins at 5:32 PM | Comments (1) | TrackBack (0)