Click here to Skip to main content
Click here to Skip to main content

Shell Extensions for .NET Assemblies

By , 17 Nov 2005
 

About the Shell Extensions for .NET Assemblies

These shell extensions were written to help distinguish between .NET assemblies and Win32 libraries, as well as give extra information about the assemblies without having to drop to a command-prompt to use the SDK and CLR tools. These shell extensions function similar to the loader that makes both .NET and VB (pre-.NET) possible as executable code: the PE/COFF header. As such, the library is very fast and won't hinder your file system browsing experience. A recent update further enhances performance by skipping assembly detection on slow paths, such as UNC paths or drive mappings to remote filesystems via VPN.

Provided in this library are:

  1. Overlay icons for .NET assemblies (.dll)

    Overlay icon 

  2. Column handlers to show the public key token and specific type of .NET assemblies.

    Column handlers 

  3. Automation object for getting the above information in your own applications and libraries.

The Automation Object

Not only does this tool help you distinguish between .NET assemblies and Win32 applications and libraries, but it also provides you with a simple automation object that these shell extensions use.

To generate code from the type library, add a reference or #import the type library named "AsmShell 1.0 Type Library". Use the members of the IAssemblyInfo automation interface as follows:

  • IAssemblyInfo::IsAssembly([in]BSTR path, [out, retval]VARIANT_BOOL* retVal)
    Returns true if the specified file is an assembly, false if it is not, and raises errors when problems occur.
  • IAssemblyInfo::GetFileType([in]BSTR path, [out, retval]FileType* retVal)
    Returns a FileType enumeration member depending on the information for the specified file in the PE/COFF header.
  • IAssemblyInfo::GetPublicKeyToken([in]BSTR path, [out, retval]BSTR* retVal)
    Returns the public key token for the specified assembly.
  • IAssemblyInfo::GetPublicKey([in]BSTR path, [out, retval]SAFEARRAY(BYTE)* retVal)
    Returns the public key as a byte array for the specified assembly. This is not supported by JScript or VBScript, both of which only support an array of VARIANTs.

For each method, late-binding languages like Visual Basic will use the return value (marked with [out, retval]) as the return type of the method, also getting rid of the need for the parameter labeled with the specified attributes above.

So, in VB6 and .NET (C#, VB.NET, et. al.), the methods signatures would look like:

bool IsAssembly(string path);
FileType GetFileType(string path);
string GetPublicKeyToken(string path);
byte[] GetPublicKey(string path);

Requirements

You may be required to reboot if files being installed are currently loaded. If you have Windows XP and the previous condition is false, no reboot should be necessary. If you're using Windows 98, ME, or 2000, you should either log off and back on or reboot your system if the overlay icon is not present; the column handlers should be ready immediately after the installation is finished.

Changes

  • November 17, 2005
    • Note: late article update for an earlier release
    • Added support to display x86 (and MSIL) for assemblies, as well as IA64 and x64
  • May 30, 2005
  • August 29, 2004
    • Added localizability
    • String caching for better performance
    • Support for .NET modules (.netmodule)
  • October 15, 2003
    • Added condition that files should not be parsed for slow paths (ex: VPN)
  • September 19, 2002
    • Initial release to the web on The Code Project

Disclaimer

THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR HIS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

License

This article, along with any associated source code and files, is licensed under The Microsoft Public License (Ms-PL)

About the Author

Heath Stewart
Program Manager Microsoft
United States United States
Member
Heath Stewart is a happily married software engineer originally from the Midwest and a graduate of Iowa State University. Heath start programming early in life and enjoys continuous research and development in new languages, frameworks, and platforms. Fluent in many different programming languages, he has developed many large-scale software solutions for companies in different areas, such as Internet filtering, intrusion detection systems, production management systems, and web applications for various purposes. He also enjoys photography.
 
Currently, Heath is a Program Manager in the Visual Studio Professional Deployment Experience (VSPro DEX) team at Microsoft. Previous to his employment, he was a Microsoft MVP for Visual C#.
 
He is also a CodeProject protector and is happy to help the development community.

Sign Up to vote   Poor Excellent
Add a reason or comment to your vote: x
Votes of 3 or less require a comment

Comments and Discussions

 
You must Sign In to use this message board.
Search this forum  
    Spacing  Noise  Layout  Per page   
GeneralInterfacememberHipSvin29 Sep '05 - 0:41 
Hi,
Great little class. Does anyone know how to make this in c# or vb. I have tried but cant get it to work.
 

AnswerRe: InterfaceprotectorHeath Stewart29 Sep '05 - 5:45 
You have to declare all the shell interfaces in managed code with the correct attributes. It's required - since all the shell interfaces used derive from IUnknown - that you declare the methods in the correct source order, not the documentation order. See Guidelines for COM Interoperability for .NET[^] for more details.
 
The better question is, why would you want to? You'll force the shell to load an additional 10-20 MB of memory in the Explorer.exe process space and for what reason? The extensions are already defined in native code and the source is provided so you can change them however necessary. Managed code isn't the right choice for every situation.
 
This posting is provided "AS IS" with no warranties, and confers no rights.
 
Software Design Engineer
Developer Division Customer Product-lifecycle Experience
Microsoft
 
[My Articles] [My Blog]
GeneralRe: Interfacememberhipsvin29 Sep '05 - 22:39 
Well... i dont know anything about c++. Ive looked at the code but it and cant figure it out. Could you/anybody make this so i can use the interface to return the icon I want to use as the overlay. And in that function retrive the file + path
 
Thanks for the answer,
 
//Magnus
 
-- modified at 5:42 Friday 30th September, 2005
AnswerRe: InterfaceprotectorHeath Stewart30 Sep '05 - 10:33 
You can't return an icon but can return an icon path. See the thread right below this one at http://www.codeproject.com/tools/asmshell.asp?select=1236218&df=100&forumid=6985#xx1236218xx[^] for details. To do this you need to return the path to the icon itself (not in any executable), put it in a native resource DLL, or embed it (using ildasm.exe followed by ilasm.exe) in the native resource section (not managed resource section) of your assembly.
 
For the COM interop declarations for the required interfaces, see http://pinvoke.net/default.aspx/Interfaces.IShellExtInit[^] and http://pinvoke.net/default.aspx/Interfaces/IShellIconOverlayIdentifier.html[^].
 
This posting is provided "AS IS" with no warranties, and confers no rights.
 
Software Design Engineer
Developer Division Customer Product-lifecycle Experience
Microsoft
 
[My Articles] [My Blog]
GeneralRe: Interfacememberhipsvin30 Sep '05 - 13:59 
Hi Heath,
 
What i want is to get the path of the file that the overlay icon is used and the at runtime decide which icon to use.
 
If u look at TortoiseCVS it uses different overlay icons to virtualize which state the file is in. This might be what you are telling me... is it?
 
Thanks again.
 
//Magnus
AnswerRe: InterfaceprotectorHeath Stewart30 Sep '05 - 19:48 
Interfaces are a contract between a client and server (a server implements the interface, the client makes call on the interface). How you implement the interface is entirely up to you. You can return different overlay icons based on some differentiating identifier in the file (Office apps do this for XML files, only using icon provider instead of overlay icons to provide a whole icon).
 
This posting is provided "AS IS" with no warranties, and confers no rights.
 
Software Design Engineer
Developer Division Customer Product-lifecycle Experience
Microsoft
 
[My Articles] [My Blog]
GeneralRe: Interfacememberhipsvin3 Oct '05 - 1:45 
yes. But none of the functions in the interface makes this posible. Im looking for an extra function in the interface that has the file + path in the parameter and the posibillity to return an icon file.
eg.
 
string GetIcon(string fullFileame)
{
if(fullFileame == @"c:\test.xml")
return @"c:\exceloverlay.ico";
else
retrun @"c:\nooverlay.ico"
}
 
the 'string GetIcon' function would be in your interface.
 
//Magnus
AnswerRe: InterfaceprotectorHeath Stewart3 Oct '05 - 8:40 
That's what the IShellIconOverlayIdentifier.GetOverlayInfo method does. You return the icon file path in the first parameter (it's a native out parameter) - either a path to an .ico file or a PE/COFF executable (.dll, .exe, .ocx, etc.) and optionally an index in the third parameter. If you specify a .ico file you need to specify ISIOI_ICONFILE as the last parameter:
string currentPath;
 
// Called first so store the path.
int IShellIconOverlayIdentifier.IsMemberOf(string path, int attributes)
{
  currentPath = path;
}
 
void IShellIconOverlayIdentifier.GetOverlayInfo(
  string path, int max, out int index, out ISIOI flags)
{
  if (Path.GetExtension(currentPath).ToLower() == ".xls")
  {
    path = "c:\excel.ico".Substring(max - 1); // Room for NULL-terminator.
  }
  else
  {
    path = "c:\other.ico".Substring(max - 1); // Room for NULL-terminator.
  }
 
  index = 0;
  flags = ISIOI.ISIOI_ICONFILE;
}
This is just a very basic example, but it's how you can control what icon is returned based on a path. These two methods are called in order as you see them above so just save the path when IsMemberOf is called.
 
This posting is provided "AS IS" with no warranties, and confers no rights.
 
Software Design Engineer
Developer Division Customer Product-lifecycle Experience
Microsoft
 
[My Articles] [My Blog]
GeneralRe: Interfacememberhipsvin3 Oct '05 - 10:36 
As i said im not a C++ shark. Amazing, thank you very much for your big help on this issue.
 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Permalink | Advertise | Privacy | Mobile
Web03 | 2.6.130523.1 | Last Updated 17 Nov 2005
Article Copyright 2002 by Heath Stewart
Everything else Copyright © CodeProject, 1999-2013
Terms of Use
Layout: fixed | fluid