|
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:
- Overlay icons for .NET assemblies (.dll)
- Column handlers to show the public key token and specific type of .NET assemblies.
- 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.
| You must Sign In to use this message board. |
|
| | Msgs 1 to 25 of 39 (Total in Forum: 39) (Refresh) | FirstPrevNext |
|
 |
|
|
 |
|
|
 |
|
|
After installing your shell extension, my VS 2005 starts to crash. Even trivial application that uses generics causes C# compiler to throw compiler internal error (something like: Error 2 Internal Compiler Error (0xc0000005 at address 5A784161): likely culprit is 'COMPILE' etc.). It’s interesting that simple "Hello, World!" application works OK, but if I add any generic to code, compiler starts crashing.
static void main(string[] args) { // With this line it crashes, without it works fine List<string> strings = new List<string>(); }
After uninstalling this version of your shell extension and installing previous one, everything works OK (again).
Is this version of shell extension tested against v2.0 of Framework?
If it's a girl then they're gonna call it Sigourney, after an actress. If it's a boy, then they're gonna call it Rodney, after Dave!
-- modified at 22:21 Saturday 6th May, 2006
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
|
The new version was written with .NET 2.0 in mind. Previous versions of .NET didn't support specific processor architectures, which support for different architectures of assembles was the focus of the new version.
I don't write any registry keys or files that would cause such behavior. I also use it aon all my machines and most of my team uses it as well.
When you install it do you pass any command-line parameters to msiexec.exe? Are you picking a non-default install location? If so, where?
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]
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
|
After few installs/uninstalls and few reboots it starts work well. During the first-time intallation, I've not passed any command-line parameters to msiexec.exe and have not changed default install location (it could not be changed, or I've missed something?) except that OS is installed on drive E: (it's dual-boot machine and this is second OS). Now it works OK against both OSes.
Anyway, good work!
If it's a girl then they're gonna call it Sigourney, after an actress. If it's a boy, then they're gonna call it Rodney, after Dave!
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
|
Just like to make a comment on how much I have found this project useful. On every box I’ve got or use, this is installed, even on non developmental boxes.
It provides an extra bit of information and can tell you some handy info which you need, primarily if it is or is not a .NET assembly.
Once again, Great work!
Daniel Brown Enterprise Software Architect
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
|
Is an archive of old AsmShell installers (MSI files) available?
Here's why (more details than probably necessary b/c there's two problems here and somebody else may have the same problem in the future).
Explorer.exe has started crashing anytime I try to view a directory that contains a managed DLL. I suspect that a misconfigured or broken AsmShell might be to blame (I had been using it on this computer for a long time before this started happening, but recently had some computer problems that involved reinstalling Windows ("upgrade", not a complete reinstall) at one point). So I went to get the AsmShell installer to reinstall it to fix the broken install.
If I try to uninstall the old (possibly broken) AsmShell (via Add/Remove Programs), after a few moments it prompts me for the location of AsmShell.msi. It appears that the uninstall requires access to the installer originally used to install, but that was two years ago and that .msi file is long gone. I can't point it to a new .msi from the newer version available here -- even if I rename it to AsmShell.msi -- the installer can tell the difference and won't go.
That'd be fine if I could just run the new installer to upgrade without uninstalling the old version, but the new installer apparently kicks off the uninstall for the old version first, so eventually I get the same prompt. I'm pretty sure that's what's happening b/c when I click Cancel (b/c there's no way forward -- it won't accept anything I have on my machine as a valid AsmShell.msi), it says, "The older version of Shell Extensions for .NET Assemblies cannot be removed. Contact your technical support group."
So, is there an archive of old AsmShell.msi installers where I can try to find an .msi that the uninstaller for this old version will recognize? Or other suggestions? (I could go rip out the shell extension registry entries for the old version to see if it's really causing the crash, but that doesn't help me get the new version installed).
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
|
I do not have an archive, but you can remove the information for the broken product without actually having the MSI file. Download msizap.exe - part of the Windows Installer SDK at http://msdn.microsoft.com/library/en-us/msi/setup/platform_sdk_components_for_windows_installer_developers.asp[^].
Find the ProductCode for the MSI by opening regedit.exe (be careful editing the registry, yada yada yada) and go to HKEY_LOCAL_MACHINE\Software\Microsoft\Windows\CurrentVersion\Uninstall. Find the ARP entry for the AsmShell. The registry key name is the ProductCode.
Now run "msizap TW! [ProductCode]" (without quotes) several times until no more errors spew out. This removes information about the package so that the new installer doesn't see the old and won't try to remove it.
As for the crash, it was an bug that has been corrected. IIRC, Explorer was expecting an empty string as opposed to a NULL string pointer. The contents would display correctly but when you sorted by that column the NULL string pointer would crash Explorer.
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]
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
|
Thanks, that worked. Notes for anybody else with this problem below.
To make it clear, the ProductCode mentioned above is the GUID (including braces {}) that is the key name for the entry under HKLM\...\Uninstall. (I initially misread the description above to mean that there was a key named "ProductCode", which is not true). Also, the newest version of the Windows Installer SDK I could easily find at microsoft.com was v1.1 from 2000, which I assume is out of date, but it worked. It doesn't appear to have the W option mentioned above, but it worked just fine without it. So the command line, once the product key had been found, looked something like this:
msizap T {CC6EC5A8-7D88-468A-B6DC-F6F5B3C681E8}
The crash does appear to have been caused by AsmShell, so I assume it was the bug that Heath fixed. I had to restart Windows Explorer to get it to load the new DLL (or, well, actually I "restarted" by trying to view a directory and causing the crash to happen ), but after that, the crash was gone.
-- modified at 13:40 Friday 14th October, 2005
|
| Sign In·View Thread·PermaLink | 3.00/5 (1 vote) |
|
|
|
 |
|
|
You have to install the Platform SDK - or at least the Core and Windows Installer SDK components - from the link I gave you. It's a bit larger than you'd need and I'm not sure why they do that (different group).
Also to "anybody else", that ProductCode that Stephen lists is only for one specific version. Since the Visual Studio Windows Installer products use major upgrades for everything, both the ProductVersion, ProductCode, and PackageCode are changed when you change the ProductVersion and click "Yes" to the following dialog. The current version uses a different product code, and the next will use yet another ProductCode, and so on. This is how MSI works for major upgrades.
For more information on Windows Installer and, more specifically how the Developer Division uses it, see my blog at http://blogs.msdn.com/heaths[^].
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]
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
|
Hi, Great little class. Does anyone know how to make this in c# or vb. I have tried but cant get it to work.
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
|
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]
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
|
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
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
|
 |
|
|
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
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
|
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]
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
|
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
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
|
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]
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
|
 |
|
|
Nice job. Weldone.
I am afraid if there is a way to set the location of the icon? Like by default it is at right bottom, what if I want to put that on top left or top right or bottom left corner?
Any idea?
Best wishes, Sameers
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
|
My extension is not configurable like that. You can change the overlay icon to change the position of the overlay, however. It's just a regular icon with both transparent and non-transparent bitmaps.
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]
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
|
YEs, your extension is not. But I was trying on such extension in C# but I couldnt find anyway int the interface methods/parameters etc to set the location of overlay icon nor the MSDN documentation discuss on this. I know one method could be to have a transparent icon as per location need so we have four different icons which are transparent but icon image is on either corner. But any good solution would be better.
Also, is there anyway to load icon from the application resources and then return that as overlay icon? Currently the interface structure forces to return icon location file name and it's index. Any idea would be appreciated.
Thanks, Sameers
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
|
Again, you can change your icon that you plan on using for the overlay. Look at my icon in the project. It's toward the bottom left. For your icon, move it somewhere else. Your icon dimensions must still be the same as the size of the icon you plan on overlaying, i.e. a 16x16 icon to overlay over 16x16 icons, 32x32 over 32x32 icons, etc. You might also consider different pixel depths that must match up too, including alpha channels for 32-bit icons.
I highly recommend not using managed code for shell extensions. The CLR doesn't require a large working set and when that's loaded into the Explorer process you've increased the working set by many megabytes. Since Explorer is a ubiqitous process that working set will be constant unless the CLR crashes and is unloaded by the default host (mscoree.dll) or a custom host if you're using one. Writing your extensions natively is simple in this case (most shell extensions are) and don't require you to create and deploy interop assemblies because the interfaces are already defined in headers for native compilation (or even for Managed C++, but then you're still utilizing the CLR).
If you insist on using managed code, then you'll need to do one of the following for an overlay extnesions:- Store the .ico separate from your assembly and return the path to it.
- Store the icon in a separate native resource DLL.
- Build your managed assembly, disassemble it using ildasm.exe, add your icon to the RC file, then re-assemble it using ilasm.exe with the appropriate parameters.
If you don't change the assembly attributes that constitute the default RC file you could just make that part of the build process, using the same RC file over and over again. That will embed the icon in the .rsrc section of the PE/COFF executable. You will not be able to use the icon straight from your resources because they are stored in a completely separate fashion.
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]
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
|
Thank you very much for your information. I have written this code in C# .NET (2005) and your descriptions says that there is no way to point icon on specific location (like original icon is of 32*32 and my overlay icon is of 8*8 which I wanted to point on bottom left corner). It also looked to me the same as well as I couldnt find any hint in MSDN and other locations on the net. However, your idea looks interesting regarding getting icon from resource. Thanks again,
Sameers
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
|
You need to make the overlay icon 32x32 and then you can position your non-transparent pixels anywhere. Open my overlay icon in VS and view the 32x32 pixel icon and you'll see the ".net" portion is in the corner. Move that to another portion of the 32x32 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]
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
|
General News Question Answer Joke Rant Admin
|