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

File Hash Generator Shell Extension

By , 10 Apr 2008
 

FileHash.png

Contents

Introduction

File hashes are used to verify the authenticity and integrity of files - especially those transmitted over the internet. When downloading a file from MSDN for instance, you are presented with the SHA-1 Hash - a list of seemingly random characters and numbers that are generated using the SHA-1 encryption algorithm to uniquely identify that file. If even a single bit of that file is changed, the hash itself will change. Most importantly, it is nearly impossible to create a different file that will produce the same hash, making spoofing unfeasable. But the question remains, how can I easily verify that hash against the file that I actually downloaded? This article will present a window shell extension that gives you easy access to the hash of any file quickly and easily.

Background

There are two coding concepts covered in this article. The first is cryptographic hash and the second is windows shell extensions. The cryptographic hash, of which there are many different algorithms, produces the digital fingerprint of a file. The .NET Framework provides 6 System.Security.Cryptography.HashAlgorithm implementations that can be used for generating the digital fingerprint: MD5, SHA-1,SHA-256,SHA-384,SHA-512 and RIPEMD-160. The two most commonly used when downloading a file are MD5 and SHA-1. Windows shell extensions take us beyond the comfortable realm of managed code and force us to implement COM to integrate into the unmanaged world of Win32. For this element of the utility,code is pulled directly from Dino Esposito's article Manage with the Windows Shell: Write Shell Extensions with C#. Dino's explanation of the COM interfaces and sample code were invaluable to this project. To really understand the implemention of a shell extension, I highly recommend his article.

Using the Utility

With the integration into the Windows Explorer context menu, generating the hash as simple as selecting one or more files then right-clicking to display the context menu. From this menu, you can select which type of file hash you want to generate by selecting the sub-menu option. You will then be presented with a window containing the file name, the hash that you selected, plus the full path to the file(s) that you selected. This DataGridView table allows for selecting of the desired values and copying to the clipboard if you need to publish the hash value. It's that easy!

Reviewing the Code

Generating a file hash is a very straighforward task. In the code sample below, the specific implementation of the HashAlgorithm abstract type is created based on a user selected HashType enumeration value. Next, using a System.IO.FileStream object, the file is opened and streamed into the HashAlgorithm object to let it do its magic. The resulting Byte array is then put into a StringBuilder so that the hash string can be returned to the calling object.

    public static string GetFileHash(string filePath, HashType type)
        {
            if (!File.Exists(filePath))
                return string.Empty;

            System.Security.Cryptography.HashAlgorithm hasher;
            switch(type)
            {
                case HashType.SHA1:
                default:
                    hasher = new SHA1CryptoServiceProvider();
                    break;
                case HashType.SHA256:
                    hasher = new SHA256Managed();
                    break;
                case HashType.SHA384:
                    hasher = new SHA384Managed();
                    break;
                case HashType.SHA512:
                    hasher = new SHA512Managed();
                    break;
                case HashType.MD5:
                    hasher = new MD5CryptoServiceProvider();
                    break;
                case HashType.RIPEMD160:
                    hasher = new RIPEMD160Managed();
                    break;
            }
            StringBuilder buff = new StringBuilder();
            try
            {
                using (FileStream f = new FileStream(filePath, FileMode.Open, FileAccess.Read, FileShare.Read, 8192))
                {
                    hasher.ComputeHash(f);
                    Byte[] hash = hasher.Hash;
                    foreach (Byte hashByte in hash)
                    {
                        buff.Append(string.Format("{0:x2}", hashByte));
                    }
                }
            }
            catch
            {
                return "Error reading file." + new System.Random(DateTime.Now.Second * DateTime.Now.Millisecond).Next().ToString();
            }
            return buff.ToString();
    }
     public enum HashType
        {
            [Description("SHA-1")]
            SHA1,
            [Description("SHA-256")]
            SHA256,
            [Description("SHA-384")]
            SHA384,
            [Description("SHA-512")]
            SHA512,
            [Description("MD5")]
            MD5,
            [Description("RIPEMD-160")]
            RIPEMD160
           
        }

The trick comes in when you want to be able to right-click on the file in Windows explorer and generate the hash. This is where Dino Esposito's expertise comes in. By modifying the code found in his article, I was able to hook into the shell context menu and add my menu option along with the sub-menu selections for the various hash types. This code can be found in the FileHashShellExt.cs file in the sample project.The key element for this integration are the IContextMenu interface. The first method, QueryContextMenu, in conjunction with a shell32 DragQueryFile method allows you to interrogate the number and type of files that were selected to determine if the custom menu option should be added. The second method, InvokeCommand provides back the information on the sub-menu item selected so that you can execute the proper hash type.

Now that you have your code ready to go, you need to make Windows aware of your utility. This is handled via the registry. It's easy enough to register an assembly for COM interop, but how do you let Windows know what exactly it's supposed to do with it? By implementing the System.Runtime.InteropServices.ComRegisterFunctionAttribute attribute along with the RegisterServer method. This method will get executed when you register the assembly with regasm.exe to add the needed registry entries that tell the Windows Shell to accept the new extension and present the context menu option for all files.
        
    [System.Runtime.InteropServices.ComRegisterFunctionAttribute()]
    static void RegisterServer(String str1)
    {
        try
        {
            // For Winnt set me as an approved shellex
            RegistryKey root;
            RegistryKey rk;
            root = Registry.LocalMachine;
            rk = root.OpenSubKey("Software\\Microsoft\\Windows\\CurrentVersion\\Shell Extensions\\Approved", true);
            rk.SetValue(guid.ToString(), "FileHash shell extension");
            rk.Flush();
            rk.Close();

            // Set "*\\shellex\\ContextMenuHandlers\\BatchResults" regkey to my guid
            root = Registry.ClassesRoot;
            rk = root.CreateSubKey("*\\shellex\\ContextMenuHandlers\\FileHash");
            rk.SetValue("", guid.ToString());
            rk.Flush();
            rk.Close();
        }
        catch(Exception e)
        {
            System.Console.WriteLine(e.ToString());
        }
    }
There is an associated method UnregisterServer that is called when you unregister the assemply with regasm.exe and the "/u" flag to remove the registry entries. If you install the Shell extension via the demo project installer, all of this is taken care of for you. If you choose to download the code and install it manually, you can use the register.bat and unregister.bat files respectively (you'll want to check that the paths to regasm.exe and gacutil.exe are correct for your environment.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

About the Author

Michael McKechney
Web Developer
United States United States
No Biography provided

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   
GeneralWARNING: Dangerous Bug Could Wreck User's Computer Title is requiredmemberTV Mogul14-Mar-10 8:21 
WARNING: Dangerous Bug Could Cause Serious Problems!!!
 
The line of code:
rk = root.CreateSubKey("*\\shellex\\ContextMenuHandlers\\FileHash");
 
This causes the shell extension for "Run as administor" on Vista to BE DISABLED !!!!
 
You can't use "*\\shellex\\ContextMenuHandlers\\FileHash" and the same problem occurs for "AllFileSystemObjects."
 
You should fix this !!!
http://www.KabbalahCode.com

GeneralPossible Bug in the codememberAndrea mariniello3-Mar-10 4:10 
Hi i think i found a bug in the your shell extension project.
I have tested that the project works well if it the only shell extension installed, but produces serious wirdness if there is more than one.
Let me explain better.
let's start with some documentation from msdn about the IContextMenu interface
 
MSDN:
 
If successful, returns an HRESULT value that has its severity value set to SEVERITY_SUCCESS and its code value set to the offset of the largest command identifier that was assigned, plus one. For example, if idCmdFirst is set to 5 and you add three items to the menu with command identifiers of 5, 7, and 8, the return value should be MAKE_HRESULT(SEVERITY_SUCCESS, 0, 8 - 5 + 1). Otherwise, it returns a COM error value.
 
and dino esposito code
 
int IContextMenu.QueryContextMenu(uint hMenu, uint iMenu, int idCmdFirst, int idCmdLast, uint uFlags)
      {
 
id=1
..
..
..
// Populate the popup menu with file-specific items
                 id = PopulateMenu(hmnuPopup, idCmdFirst + id);
..
..
..
return id
 

let's say that the incoming idCmdFirst parameter was 3000 and the idCmdLast was 3100
and we added 3 menù items
 
from the code above the returning Id should have been
 
3000 +1 (idCmdFirst + id)
3001 +3 (PopulateMenu(3001))
 
result = 3004
 
this is wrong!!
as msdn states the correct result should have been:
 
maximum offset - idCmdFirst + 1
 
3004 - 3000 + 1 = 5
 
otherwise the next call to a IcontextMenu would have weird parameters
in our example they would have been
 
idCmdFirst 6004 // 3000 + 3004
idCmdLast 3100 // same value
 
Please verify and eventually correct the code
Thank you
 
Andrea Mariniello
Connect Informatica s.r.l
Software developer
GeneralGood workmemberSplashBrazil7-Jan-10 12:21 
Good work men! Smile | :)
GeneralWIN+E Key is ignored after install. This extension should not be used in current state under WinXP.membersternenfaenger7713-Aug-09 22:43 
WIN+E Key is ignored after install. This extension should not be used in current state under WinXP.
GeneralPerhaps dotNET is not a good choice for writing shell extensions...mvpStephen Hewitt10-Apr-08 19:43 
See here[^]. Of particular interest is the following quote:
Although multiple versions of the CLR may exist on a given machine, only one version may run in a particular process. So once the host chooses which version to load, all managed code that runs in that process will use that version of the CLR.
 
Another take on this issue can be found here[^]:
Unfortunately unmanaged C++ is really the only way to go here.
 
Writing in-process shell extensions in managed code is actually a very dangerous thing to do because it has the effect of injecting your managed code (and the .NET Framework) into every application on the machine that has a file open dialog.
 
The problems occur because only one version of the .NET Framework can be loaded in a process at any given time (other shared components such as java and msxml have the same property and thus the same restriction).
 
If you write your shell extension using the 2.0 .NET Framework and an application built with the 1.1 .NET Framework uses a file open dialog, your shell extension will fail because it can not run on an earlier version. Things can get even worse if your shell-extension manages to get loaded in a process before another applications managed code does: your extension may force an existing application onto a different runtime version than the one it was expecting and cause it to fail.
 
Because of these problems we strongly recomend against using any single-instance-per-process runtime or library (such as the .NET Framework, java, or msxml) in an in-process shell extension.
 

This presents a serious problem with writing shell extensions with dotNET. What happens if the user is using another extention written using a different version of the CLR? Only one of the extensions will work! What happens if, in a future version of windows, one of explorer's components uses dotNET but again uses a different CLR version? Your extension will be unusable!
 
Steve

GeneralRe: Perhaps dotNET is not a good choice for writing shell extensions...mvpLukasz Swiatkowski14-Apr-08 22:51 
That is right as long the shell extension is using .NET Framework 2.0 or higher, or there are multiple versions of CLR installed.
If the shell extension uses .NET Framework 1.1 (which is forward and backward compatible) or only one version of CLR is installed, then everything should be OK.
 
Lukasz
 
~~~~~~~~~~~~~~~~~~~
My website: www.lukesw.net

GeneralRe: Perhaps dotNET is not a good choice for writing shell extensions...mvpStephen Hewitt14-Apr-08 23:04 
The quotes I gave recommend not programming shell extensions using .NET and for good reason. One of the quotes I gave earlier was from Jesse Kaplan, program manager on the .NET CLR team. I’ll repeat some of it:
 
“Writing in-process shell extensions in managed code is actually a very dangerous thing to do because it has the effect of injecting your managed code (and the .NET Framework) into every application on the machine that has a file open dialog.”
 
I think this guy probably knows what he’s on about!
 
Steve

GeneralRe: Perhaps dotNET is not a good choice for writing shell extensions...mvpLukasz Swiatkowski17-Apr-08 14:14 
I see what you mean, and I understand it. However, dependences of every shell extension are injected into any application which uses a file open dialog. Writing a small and fast shell extension in .NET 1.1 wouldn't have worse effects than a small and fast extension created with C++ (which would require C++ 2005/2008 redistributable libraries which would also be injected into other applications). Remember that .NET only loads necessary dependences when they are required.
 
The only extensions I wouldn't create in .NET are global system hooks which could force an application to load a different CLR version. Any other "simple" shell extensions (like context menu/property sheet/icon/tooltip shell extension) which are loaded after the application has already loaded the appropriate version of CLR, are not that dangerous.
 
Regards,
Lukasz
 
~~~~~~~~~~~~~~~~~~~
My website: www.lukesw.net

GeneralRe: Perhaps dotNET is not a good choice for writing shell extensions...mvpStephen Hewitt17-Apr-08 14:21 
Lukasz Swiatkowski wrote:
Writing a small and fast shell extension in .NET 1.1 wouldn't have worse effects than a small and fast extension created with C++ (which would require C++ 2005/2008 redistributable libraries which would also be injected into other applications).

 
Not true. Firstly you can link statically or dynamically in C++: if you link statically there is no need for a DLL. Secondly multiple versions of the C++ runtimes can coexist in a single progress, in fact this is routine.
 
Steve

GeneralRe: Perhaps dotNET is not a good choice for writing shell extensions...mvpLukasz Swiatkowski17-Apr-08 15:23 
Yes, you can link statically or dynamically, but every dll library written in C++ 2003/5/8 which uses standard windows libraries is dynamically linked to at least an msvcr70/80/90.dll file so it require installing redistributables, and the shell extension would inject them into processes.
 
In my humble opinion maybe it is better to write a shell extensions in C++, but it is not that bad to write properly some kinds of them using .NET 1.1. Either C++ dll's would inject one or more C++ runtimes or .NET dll's would inject the CLR (but always only one).
 
Lukasz
 
~~~~~~~~~~~~~~~~~~~
My website: www.lukesw.net

GeneralRe: Perhaps dotNET is not a good choice for writing shell extensions...mvpStephen Hewitt17-Apr-08 15:45 
Lukasz Swiatkowski wrote:
but every dll library written in C++ 2003/5/8 which uses standard windows libraries is dynamically linked to at least an msvcr70/80/90.dll file

 
Not so. See here[^], specifically the /MT switch.
 
In fact I built an app which requires no runtime just then. Here's a dump using "PEDump":
Dump of file CONSOLE.EXE
 
File Header
  Machine:                      014C (i386)
  Number of Sections:           0005
  TimeDateStamp:                4807FB8B -> Fri Apr 18 11:38:19 2008
  PointerToSymbolTable:         00000000
  NumberOfSymbols:              00000000
  SizeOfOptionalHeader:         00E0
  Characteristics:              0102
    EXECUTABLE_IMAGE
    32BIT_MACHINE
 
Optional Header
  Magic                         010B
  linker version                9.00
  size of code                  12000
  size of initialized data      7400
  size of uninitialized data    0
  entrypoint RVA                453C
  base of code                  1000
  base of data                  13000
  image base                    400000
  section align                 1000
  file align                    200
  required OS version           5.00
  image version                 0.00
  subsystem version             5.00
  Win32 Version                 0
  size of image                 1F000
  size of headers               400
  checksum                      27DA8
  Subsystem                     0003 (Windows character)
  DLL flags                     8140
 
  stack reserve size            100000
  stack commit size             1000
  heap reserve size             100000
  heap commit size              1000
  RVAs & sizes                  10
 
Data Directory
  EXPORT       rva: 00000000  size: 00000000
  IMPORT       rva: 00016ACC  size: 00000028
  RESOURCE     rva: 0001C000  size: 000001B4
  EXCEPTION    rva: 00000000  size: 00000000
  SECURITY     rva: 00000000  size: 00000000
  BASERELOC    rva: 0001D000  size: 000010D8
  DEBUG        rva: 00013190  size: 0000001C
  COPYRIGHT    rva: 00000000  size: 00000000
  GLOBALPTR    rva: 00000000  size: 00000000
  TLS          rva: 00000000  size: 00000000
  LOAD_CONFIG  rva: 00015510  size: 00000040
  BOUND_IMPORT rva: 00000000  size: 00000000
  IAT          rva: 00013000  size: 0000012C
  DELAY_IMPORT rva: 00000000  size: 00000000
  unused       rva: 00000000  size: 00000000
  unused       rva: 00000000  size: 00000000
 
Section Table
  01 .text     VirtSize: 00011F21  VirtAddr:  00001000
    raw data offs:   00000400  raw data size: 00012000
    relocation offs: 00000000  relocations:   00000000
    line # offs:     00000000  line #'s:      00000000
    characteristics: 60000020
      CODE  EXECUTE  READ  ALIGN_DEFAULT(16)
 
  02 .rdata    VirtSize: 00004180  VirtAddr:  00013000
    raw data offs:   00012400  raw data size: 00004200
    relocation offs: 00000000  relocations:   00000000
    line # offs:     00000000  line #'s:      00000000
    characteristics: 40000040
      INITIALIZED_DATA  READ  ALIGN_DEFAULT(16)
 
  03 .data     VirtSize: 00003168  VirtAddr:  00018000
    raw data offs:   00016600  raw data size: 00001400
    relocation offs: 00000000  relocations:   00000000
    line # offs:     00000000  line #'s:      00000000
    characteristics: C0000040
      INITIALIZED_DATA  READ  WRITE  ALIGN_DEFAULT(16)
 
  04 .rsrc     VirtSize: 000001B4  VirtAddr:  0001C000
    raw data offs:   00017A00  raw data size: 00000200
    relocation offs: 00000000  relocations:   00000000
    line # offs:     00000000  line #'s:      00000000
    characteristics: 40000040
      INITIALIZED_DATA  READ  ALIGN_DEFAULT(16)
 
  05 .reloc    VirtSize: 00001AFE  VirtAddr:  0001D000
    raw data offs:   00017C00  raw data size: 00001C00
    relocation offs: 00000000  relocations:   00000000
    line # offs:     00000000  line #'s:      00000000
    characteristics: 42000040
      INITIALIZED_DATA  DISCARDABLE  READ  ALIGN_DEFAULT(16)
 
Debug Formats in File
  Type            Size     Address  FilePtr  Charactr TimeDate Version
  --------------- -------- -------- -------- -------- -------- --------
  CODEVIEW        00000086 00015558 00014958 00000000 4807FB8B 0.00
 
Resources (RVA: 1C000)
ResDir (0) Entries:01 (Named:00, ID:01) TimeDate:00000000 Vers:4.00
    --------------------------------------------------------------
    ResDir (18) Entries:01 (Named:00, ID:01) TimeDate:00000000 Vers:4.00
        ResDir (1) Entries:01 (Named:00, ID:01) TimeDate:00000000 Vers:4.00
            ID: 00000409  DataEntryOffs: 00000048
            DataRVA: 1C058  DataSize: 0015A  CodePage: 4E4
 
Imports Table:
  KERNEL32.dll
  OrigFirstThunk:  00016AF4 (Unbound IAT)
  TimeDateStamp:   00000000 -> Thu Jan 01 11:00:00 1970
  ForwarderChain:  00000000
  First thunk RVA: 00013000
  Ordn  Name
   704  InterlockedIncrement
   700  InterlockedDecrement
  1057  Sleep
   692  InitializeCriticalSection
   190  DeleteCriticalSection
   217  EnterCriticalSection
   751  LeaveCriticalSection
   367  GetCommandLineA
  1069  TerminateProcess
   425  GetCurrentProcess
  1086  UnhandledExceptionFilter
  1045  SetUnhandledExceptionFilter
   721  IsDebuggerPresent
   858  RaiseException
   486  GetLastError
   673  HeapFree
   914  RtlUnwind
   737  LCMapStringA
  1146  WideCharToMultiByte
   794  MultiByteToWideChar
   739  LCMapStringW
   347  GetCPInfo
   669  HeapAlloc
   505  GetModuleHandleW
   544  GetProcAddress
   260  ExitProcess
  1165  WriteFile
   571  GetStdHandle
   500  GetModuleFileNameA
   330  FreeEnvironmentStringsA
   447  GetEnvironmentStrings
   331  FreeEnvironmentStringsW
   449  GetEnvironmentStringsW
  1000  SetHandleCount
   471  GetFileType
   569  GetStartupInfoA
  1076  TlsGetValue
  1074  TlsAlloc
  1077  TlsSetValue
  1075  TlsFree
  1004  SetLastError
   429  GetCurrentThreadId
   671  HeapCreate
  1111  VirtualFree
   852  QueryPerformanceCounter
   614  GetTickCount
   426  GetCurrentProcessId
   591  GetSystemTimeAsFileTime
  1108  VirtualAlloc
   676  HeapReAlloc
   387  GetConsoleCP
   405  GetConsoleMode
   321  FlushFileBuffers
   872  ReadFile
   991  SetFilePointer
    67  CloseHandle
   678  HeapSize
   338  GetACP
   531  GetOEMCP
   731  IsValidCodePage
   488  GetLocaleInfoA
   573  GetStringTypeA
   576  GetStringTypeW
   621  GetUserDefaultLCID
   248  EnumSystemLocalesA
   733  IsValidLocale
   753  LoadLibraryA
   693  InitializeCriticalSectionAndSpinCount
  1154  WriteConsoleA
   409  GetConsoleOutputCP
  1164  WriteConsoleW
  1020  SetStdHandle
   490  GetLocaleInfoW
   120  CreateFileA
 
Note the import table! Only kernel32.dll is needed!
 
But you're missing the main point: it doesn't matter if the DLL runtimes are injected into another process as multiple versions of the C-runtime libraries can exist in a single process. This is not the case with the CLR.
 
Steve

GeneralRe: Perhaps dotNET is not a good choice for writing shell extensions...mvpLukasz Swiatkowski18-Apr-08 2:30 
I have written that an application which is using standard libraries would require msvcrXX.dll file. I know that using compiler and linker switches you can create an app which need only kernel32.dll. But more libraries are needed to create a shell extension.
 
And a shell extension like from this article wouldn't cause anything dangerous on machine with only one CLR installed. Don't demonize .NET shell extension only because one of CLR creators said that they can be dangerous in certain situations.
 
This is exactly like the Office .NET extensions. Loading a plugin which uses CLR 2.0 into e.g. Word would prevent from loading a plugin which would use future CLR's. The only differene is that Office extensions are supported within VS by default and shell extensions are not.
 
Both, Office and shell .NET extensions written properly and used with due caution won't do anything dangerous. You cannot deny it.
 
Lukasz
 
~~~~~~~~~~~~~~~~~~~
My website: www.lukesw.net

GeneralRe: Perhaps dotNET is not a good choice for writing shell extensions...mvpStephen Hewitt20-Apr-08 13:29 
Lukasz Swiatkowski wrote:
I have written that an application which is using standard libraries would require msvcrXX.dll file. I know that using compiler and linker switches you can create an app which need only kernel32.dll. But more libraries are needed to create a shell extension.

 
Like I've said a few times now, the fact that a C++ program depends on the "msvcrXX.dll" DLLs is not a problem: the use of multiple versions of a shared library in a process is only a problem if only one version can exist per process and this simply isn't the case with these libraries as it in with the CLR.
 
Lukasz Swiatkowski wrote:
And a shell extension like from this article wouldn't cause anything dangerous on machine with only one CLR installed.

 
True, but you can't control what other software the user has installed on his computer and which version of the CLR they use.
 
Lukasz Swiatkowski wrote:
Don't demonize .NET shell extension only because one of CLR creators said that they can be dangerous in certain situations.

 
Many experts agree, and Microsoft itself doesn't support the use of dotNET in this context. I'm not demonising dotNET, I'm just saying use the right tool for the right job.
 
Lukasz Swiatkowski wrote:
You cannot deny it.

 
What I deny is that using dotNET to write shell extensions is NOT dangerous.
 
I'm sick of arguing however. I've pointed out the problems and provided references.
 
Steve

GeneralRe: Perhaps dotNET is not a good choice for writing shell extensions...mvpLukasz Swiatkowski21-Apr-08 6:15 
Stephen Hewitt wrote:
Like I've said a few times now, the fact that a C++ program depends on the "msvcrXX.dll" DLLs is not a problem: the use of multiple versions of a shared library in a process is only a problem if only one version can exist per process and this simply isn't the case with these libraries as it in with the CLR.

I didn't say it's a problem. I only meant that these libraries are injected the same way CLR is. The only difference is that the CLR is injected only once.
 
Stephen Hewitt wrote:
True, but you can't control what other software the user has installed on his computer and which version of the CLR they use.
[...]
I'm just saying use the right tool for the right job.

You are right. But almost all .NET shell extensions I have ever seen were created for other developers or advanced users.
Of course I wouldn't use .NET if I had to create e.g. commercial shell extension which would be used by all people.
But if I created free shell extension and post it e.g. to the CodeProject I would attach a warning clause saying that there is recommended to have only one CLR installed in order to safely use this extension.
 
Stephen Hewitt wrote:
Many experts agree, and Microsoft itself doesn't support the use of dotNET in this context.

So unless the next version of CLR will support loading multiple CLR's into a process (like Silverlight CLR does), or the same problems will be occuring with Office .NET extensions. I assume that if Microsoft supports .NET extensions for Office, shell extensions which use CRL 2.0 also will be supported in future (or at least .NET 1.0/1.1 won't be anymore supported and available for download).
 
Stephen Hewitt wrote:
I'm sick of arguing however. I've pointed out the problems and provived references.

I also don't want to argue. I appreciate that you try to warn of improper usage of .NET Framework.
 
I only want to point that .NET shell extensions are not always dangerous, and when created properly and used with due caution, they can be safe.
 
Lukasz
 
~~~~~~~~~~~~~~~~~~~
My website: www.lukesw.net

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.130617.1 | Last Updated 10 Apr 2008
Article Copyright 2008 by Michael McKechney
Everything else Copyright © CodeProject, 1999-2013
Terms of Use
Layout: fixed | fluid