Archives

Archives / 2006 / June
  • Visual Studio obstructing DebugView

    I've mentioned it before, but SysInternal's DebugView is a great utility. It allows you to get the Debug.WriteLine() strings from your application even when you're not attached with a debugger, as long as it was compiled in Debug mode. Very convenient.

    Unfortunately, it's a bit hard to use when I'm also actually doing work with Visual Studio. It seems that some bits of VS are also logging calls with the OutputDebugString API call. I can live with the occasional message like this:

    [3448] DllCanUnloadNow called for VSA7.dll
    [3448] DllCanUnloadNow returned S_FALSE

    but getting these:

    [3448] Left. Enter HWND 90ea6

    whenever I do anything in Visual Studio is annoying, and quickly hides any pertinent debug messages I want to see.

    Running  Microsoft Visual Studio 2005 Team Edition for Software Developers
    Version 8.0.50727.51  (QFE.050727-5100)
    Microsoft .NET Framework
    Version 2.0.50727

    Read more...

  • Some thoughts on uninstalling Sharepoint '12' Beta 1

    I'm uninstalling an old beta of the Sharepoint servers from a VPC I have on my computer to make room for the newer Beta 2 servers, and I noticed several things:

    1) The installation originally required a then-current build of Windows Workflow Foundation to install. However, it appears that it also requires it to UNINSTALL. I had to find the old installation of WWF Beta 1.2 and reinstall it. It is no longer available on Microsoft Downloads except as part of the 100MB package containing the Visual Studio extensions. Actual package size - 2.5Mb.

    2) Uninstallation CRAWLS under VPC (512MB RAM, running on a USB2.0 external harddrive).

    3) Is it my imagination? Does it... is it...
    No, it's true. The progress bar for the uninstallation actually does go BACK a few pixels every once in a while. You probably won't notice it if it isn't crawling on a background VPC, but it's true. It's rocking back and forth. Weird.

    Read more...

  • My Singleton is disappearing!

    WCF's Instance Context model allows me to specify my service's instantiation behavior - I can get a new instance for every call, have WCF manage a session for me and keep an instance per session, or just get lazy and have my service instantiated as a singleton object and use the same instance forever and ever. Juval Lowy covered the basics of these features here

    I had a Singleton service defined, exposing several Operations through two different endpoints. After some testing, I noticed that every time a call was received on one of the interfaces the constructor would be called again - my singleton was getting dumped and recreated.

    It turns out the operation that was causing the problems was marked like this:

    [OperationBehavior(TransactionScopeRequired = true, TransactionAutoComplete = true)]

    Since the transaction behavior was the only lead I had, I started to look into it and checked out the other properties of the OperationBehavior attributes. I found the following attribute: (Warning: Links point to a local MSDN installation)

    ReleaseInstanceMode

    Gets or sets a value that indicates when in the course of an operation invocation to recycle the service object.

    This operation allows me to declaratively tell WCF to drop my current instance before, after or before AND after my call. This is to allow stateless service calls to ensure that they will not carry over any state between operations. Unfortunately, the default value for the ReleaseInstanceMode is None - this wasn't the reason I lost my instance.

    The MSDN documentation for ReleaseInstanceMode, however, mentioned the following tidbit of information:

    In transaction scenarios, the ReleaseInstanceMode property is often used to ensure that old data associated with the service object is cleaned up prior to processing a method call. You can also ensure that service objects associated with transactions are recycled after the transaction successfully completes by setting the ReleaseServiceInstanceOnTransactionComplete property to true.

    This led me to the ServiceBehavior's ReleaseServiceInstanceOnTransactionComplete property which set a more general setting that automatically recycled my service instance whenever a transaction completed successfully. Unlike the ReleaseInstanceMode property, this one is by default set to True, meaning that my transactional operation always released my Singleton instance after each successful run.

    The moral of the story? The usual. Always check default values, especially on WCF's Behavior attributes that have lots and lots of properties. Good luck.

    Read more...

  • Hiding properties from the Property Grid

    Taking a break from the main components, I decided to get around to writing a small configuration editor using .NET 2.0's lovely ability to edit .config files from code.

    I have a custom Section Handler defined for my data, and decided the simplest thing to do would be to stick my custom ConfigurationElement objects onto a PropertyGrid and let the user edit the values directly.

    The problem with that is that ConfigurationElement has several public properties that I inherit, and they show up in the grid:

    My first instinct to hide them was to implement ICustomTypeDescriptor on my ConfigurationElement and implement GetProperties() so it only returns the properties I want. This turned out to be a ridiculously complicated endeavor, requiring me to implement many methods I don't care about just so I could get to GetProperties, which in turn required me to subclass the PropertyDescriptor class and override lots of properties that I didn't care about either. This whole design-time framework really needs an overhaul - it's way too complicated and the documentation is vague at best.

    So I abandoned that approach and immediately set off on achieving my goal in the ugliest, hackiest way I could find. The easiest way to hide a property from the propertygrid is using the [Browsable(false)] attribute. Since the properties are unfortunately non-virtual, I had to hide them in order to override their attributes:

    #region Shadow unneeded properties.

    [Browsable(false)]
    public new bool LockItem { get { return base.LockItem; } set { base.LockItem = value; } }

    [Browsable(false)]
    public new ElementInformation ElementInformation { get { return base.ElementInformation; } }

    [Browsable(false)]
    public new ConfigurationLockCollection LockAllAttributesExcept { get { return base.LockAllAttributesExcept; } }

    [Browsable(false)]
    public new ConfigurationLockCollection LockAllElementsExcept { get { return base.LockAllElementsExcept; } }

    [Browsable(false)]
    public new ConfigurationLockCollection LockAttributes { get { return base.LockAttributes; } }

    [Browsable(false)]
    public new ConfigurationLockCollection LockElements { get { return base.LockElements; } }

    #endregion

    I simply hide them behind my new properties, and have those call the base's implementation in case they're actually used for anything.

    Result? Works perfectly. Hardly clean, but it works:

     

     

     

    Read more...

  • URIs are not local paths.

    It's easy to forget that even though a local filesystem path ("C:\MyDir\MyFile.dll") can be represented as a Uri (file://C:/MyDir/MyFile.dll), these two entities are different, and have different rules for validations.

    The problem du jour, the reason I even got into this, was a simple piece of code that was to set the Current Directory to that of the currently executing assembly:

    Uri assemblyPath = new Uri(Assembly.GetExecutingAssembly().CodeBase);
    if (assemblyPath.Scheme == Uri
    .UriSchemeFile)
    {
       string dllPath = Path
    .GetDirectoryName(assemblyPath.PathAndQuery);
       Directory
    .SetCurrentDirectory(dllPath);
    }

    The CodeBase property of the Assembly class gives us the path as a Uri, since assemblies can also be loaded from HTTP paths.

    This worked fine on most machines, but seemed to break on one. The reason? His path was a valid file system path, but not a valid URI:

    G:\C#_Projects\MyFile.dll

    The problem is that the # sign is a valid path, but a delimiter for URIs - it marks the start of a URI fragment, like a named anchor in an HTML file.  Getting PathAndQuery for the URI simply returned "G:/C", and dropped everything after the #.

    The simple solution - rather than attempting to join the URI's Fragment and Path together, is to remove the scheme (file://) from the beginning and consider that a local path:

    Uri assemblyPath = new Uri("file://c:/c#_path/file.dll");
    if (assemblyPath.Scheme == Uri
    .UriSchemeFile)
    {
       // This gives us "c:/c#_path/file.dll".
       string dllPath = assemblyPath.OriginalString.Replace(assemblyPath.Scheme + Uri.SchemeDelimiter, ""
    );

       // This gives us "c:\\c#_path".
          
       dllPath = Path
    .GetDirectoryName(dllPath);
       Directory
    .SetCurrentDirectory(dllPath);
    }

    Read more...

  • ParamArrays and CLS-compliance.

    In my previous post, I noted that when I write this code in C#:

    public void MyMethod (params object[] args) { ... }

    What I actually get in my IL is this:

    public void MyMethod ([System.ParamArray]object[] args) { ... }

    I have this suspicion due to:
    1) The fact that the C# compiler tells me to use params instead of the attribute
    2) The fact that a function with the same signature except for the params keyword results in a duplicate signature
    3) Because I opened up Reflector and saw it happening in the IL.

    The params keyword in C# (and the ParamArray keyword in VB.NET) is a shorthand for applying the ParamArray attribute to the method. I assume the sole reason for the existence of the attribute is to notify the relevant compiler that when parsing a call to that function it should wrap the arguments in an array - nothing happens at runtime at all. It's a language feature of C# and VB that is backed up by an attribute in the BCL, but does not have any representation in the CLR.

    In the comments to that post, Thomas Tomiczek disagreed:

    "Given that the ParamArrayAttribute is defined in System and HAS to be supported by the langauge compilers, basically, it is not a choice of the language. As such, it is not a language feature. It is a requirement.
    WIth the same logic you could say that support for a lot of other things is optional - it is not. "

    I am not sure I agree with this logic. Any .NET language has to support decorating the parameter with the ParamArray attribute of course, but I'm not sure that it's required to be supported by all .NET languages.

    I had a brief glance at the CLS specification and found this paragraph:

    Argument lists

    All

    The only calling convention supported by the CLS is the standard managed calling convention; variable length argument lists are not allowed. (Use the ParamArray keyword in Microsoft Visual Basic and the params keyword in C# for variable number of arguments support.)

    What this seems to mean is that the concept of variable length argument lists do not exist in the CLR, and the only way to pass a variable number of arguments is through arrays. VB.NET and C#, to name particular examples, provide us with language features (in the form of the params and ParamArray keywords) that save us the effort of creating arrays and do the wrapping-up for us.

    The way I see it, the fact that it uses an attribute that's defined in the System namespace, rather than language-specific namespaces (assuming one such would exist for C#) is just a result of the C# and VB teams working closely with the BCL designers.

    Read more...

  • Problems with params array?

    I noticed today that the ever-popular String.Format() method has several overloads - in addition to the Format(string format, params object[] args) overload I was expecting, it seems there are three special-case overloads for one, two or three parameters. A glance with Reflector shows that these three overloads simply instantiate a new object[] with the given args and pass them on to the main overload.

    Does anyone have any idea why it's doing that? Is there some sort of performance penalty involved with using params array that the BCL team decided to bypass by special-casing the most common instances?

    I was given to understand that that params token is a compile-time only feature of the C# language, and shouldn't have any effect after compilation.

    Interesting.

    Read more...

  • Query SUBST information

    For various reasons involving out testing framework, I found myself needing to get the full command-line of the current executing assembly. However, our development environment uses the DOS SUBST command to map a virtual drive letter for our dev files, so we have a consistent environment for all development machines. This is problematic, since I need this command-line to be launched in a different user context, where this SUBST mapping doesn't exist. In short, I needed a way to get the real path to a file beyond the SUBST illusion.

    The answer turned out to be surprisingly easy, and required only a tiny bit of P/Invoking. I've included the signature here and also updated it on pinvoke.net, where it was using a more complicated signature using IntPtr that is only required if we want more than one return value for the function.
    Make sure the ucchMax parameter you pass the function is the same size as you initialize the StringBuilder's buffer:

    private static string GetRealPath(string path)
    {
       
    string
    realPath = path;
       StringBuilder pathInformation = new StringBuilder
    (250);
      
    string driveLetter = Path.GetPathRoot(realPath).Replace("\\", ""
    );
       QueryDosDevice(driveLetter, pathInformation, 250);
       
       
    // If drive is substed, the result will be in the format of "\??\C:\RealPath\".
       
    if (pathInformation.ToString().Contains(\\??\\
    ))
       {
          
    // Strip the \??\ prefix.
          
    string
    realRoot = pathInformation.ToString().Remove(0, 4);
          
          
    //Combine the paths.
          
    realPath = Path.Combine(realRoot, realPath.Replace(Path.GetPathRoot(realPath), ""
    ));
       }

    return
    realPath;
    }

    [DllImport("kernel32.dll")]
    static extern uint QueryDosDevice(string lpDeviceName, StringBuilder lpTargetPath, int ucchMax);

     

    Read more...