June 2004 - Posts

Retrieving File Information using SHGetFileInfo

This week a colleque of mine needed to retrieve icons associated with a file. So I put together the following piece of code and figured why not share it.

    struct SHFILEINFO
    {
      public IntPtr hIcon;
      public int    iIcon;
      public int    dwAttributes;
      [MarshalAs(UnmanagedType.ByValTStr, SizeConst=260)]
      public string szDisplayName;
      [MarshalAs(UnmanagedType.ByValTStr, SizeConst=80)]  
      public string szTypeName;
    }
    
    [Flags]
    enum FileInfoFlags : int
    {
      SHGFI_ICON              = 0x000000100,     // get icon
      SHGFI_DISPLAYNAME       = 0x000000200,     // get display name
      SHGFI_TYPENAME          = 0x000000400,     // get type name
      SHGFI_ATTRIBUTES        = 0x000000800,     // get attributes
      SHGFI_ICONLOCATION      = 0x000001000,     // get icon location
      SHGFI_EXETYPE           = 0x000002000,     // return exe type
      SHGFI_SYSICONINDEX      = 0x000004000,     // get system icon index
      SHGFI_LINKOVERLAY       = 0x000008000,     // put a link overlay on icon
      SHGFI_SELECTED          = 0x000010000,     // show icon in selected state
      SHGFI_ATTR_SPECIFIED    = 0x000020000,     // get only specified attributes
      SHGFI_LARGEICON         = 0x000000000,     // get large icon
      SHGFI_SMALLICON         = 0x000000001,     // get small icon
      SHGFI_OPENICON          = 0x000000002,     // get open icon
      SHGFI_SHELLICONSIZE     = 0x000000004,     // get shell size icon
      SHGFI_PIDL              = 0x000000008,     // pszPath is a pidl
      SHGFI_USEFILEATTRIBUTES = 0x000000010,     // use passed dwFileAttribute
      SHGFI_ADDOVERLAYS       = 0x000000020,     // apply the appropriate overlays
      SHGFI_OVERLAYINDEX      = 0x000000040,     // Get the index of the overlay in 
                                                 // the upper 8 bits of the iIcon
    }                                                 
    [DllImport("shell32.dll", CharSet=CharSet.Auto)]
    static extern Int64 SHGetFileInfo(string pszPath, int
      dwFileAttributes, out SHFILEINFO psfi, int cbFileInfo, FileInfoFlags uFlags);

To call this function to retrieve the icon information of  file is now as simple as.

SHFILEINFO fi;
SHGetFileInfo(strFile, 0, out fi, Marshal.SizeOf(typeof(SHFILEINFO)), 
FileInfoFlags.SHGFI_ICON );
Then then an icon object can be created using the Icon.FromHandle method as follows
Icon.FromHandle(fi.hIcon);

.NET Parameter Passing

A topic that has been covered on many occasions, yet many developers I come into contact with still fail to grasp is that of .NET parameter passing semantics. I thought I would add to the pile of explanations my own attempt at explaining these intricacies.

Before I get into actual argument passing I want to define a few terms. First of all I want to briefly define reference types and value types. For the purposes of this description I will take a slightly non-standard approach to thier definition and define them in terms of components. Value types are instances that contain thier data, while references type instances hold a reference to the data which is located else where. In simple terms, and instance of a value type has only one component and that is the data held by the instance, while an instance of a reference type has two components, the reference and the data being referenced.

The .NET environment allows the developer to pass parameters in one of two ways, either by value or by reference. In VB.NET and C# the default is pass by value. When a value type is passed by value a new instance of the value type is created which contains a copy of the data contained in the original instance. Each instance can now be manipulated independently from the other.

In contrast, when a reference type is passed by value the called function receives a copy of the reference component of the reference type. Therefore when a function is passed a reference by value, there are at least two references in existence to the same piece of data, namely the original reference and the newly created reference, conversely there is still only one instance of the data that is being referenced.

That covers passing of value types and reference types by value. Now we can look at passing these types using the by reference semantic. Passing data by reference implies that the data itself is not passed, but a reference is passed. This allows the data to be manipulated through the reference rather than manipulating an independent local copy of the data.

When a value type is passed by reference, a reference is created to the data contained in the value type and this reference is then passed to the function. The end result is that we now have only one instance of the value type and the function receives a reference to this instance.

When passing a reference type by reference a new reference is created that references the reference type, this new reference is then passed in to the function which can now manipulate both the original reference and the data being referenced.

Trying to explain this without a board and marker and some of the usual props that I use is quite a challenge and I fully understand why so many developers struggle to grasp these concepts. I only hope that this attempt at a simplified explanation does not add to the confusion.