首页 > 编程 > .NET > 正文

NET Framework 用C#创建SHELL扩展

2024-07-21 02:29:44
字体:
来源:转载
供稿:网友

一、前言

.net平台是微软公司推出的作为未来软件运行和开发的环境,c#是微软力荐的在.net平台下开发应用软件的首选语言。本文将讨论在.net环境下如何使用c#语言开发windows shell扩展问题。如今windows家族已发展到xp世代了,想必每个程序员都对shell extension不会感到陌生吧,在这里我不想花太多的时间介绍shell extension的原理知识,本文中将通过一个实例介绍用c#创建一个shell extension,在此过程中也会简单介绍一些shell extension的原理知识(如果想详细了解shell扩展原理知识,请参阅msdn)

二、开发环境

(1)windows2000 专业版。
(2)
visual studio.net beta 2.0或正式版1.0

三、原理介绍

本实例实现一个shellexecuteex win32调用的钩子操作,windows explorer常常会用到这个调用,如打开、编辑、打印等等shell操作都要用到这个调用。在windows注册表hklm/software/microsoft/windows/currentversion/explorer/shellexecutehooks项下安装了所有实现shell扩展的组件信息。当windows explorer执行shell操作前,先在注册中查找到已注册的shell扩展组件,并将其实例化,每个shell扩展组件必须至少实现了ishellexecutehook接口,此接口提供了一个execute()函数,explorer将通过组件实例对象调用execute()函数,如此函数返回为s_false继续后面的操作,如返回s_ok则停止后面的所有操作。根据以上原理,本实例要实现shell扩展就必须要实现一个支持ishellexecutehook接口的com组件。

接口声明

c#不能像c++那样用一句#include "shlguid.h"语句就可以完成ishellexecutehook接口声明,它必须要求在程序中声明接口的具体信息,声明如下:

[comimpor,interfacetype(cominterfacetype.interfaceisiunknown), guid("000214fb-0000-0000-c000-000000000046")]
/* guid("000214fb-0000-0000-c000-000000000046")
相当于shlguid.h中的define_shlguid(iid_ishellexecutehookw, 0x000214fbl, 0, 0); */
public interface ishellexecutehook{
[preservesig()] /*
允许返回值为
com hresult */
int execute(shellexecuteinfo sei);
}

结构声明

execute()方法中有一个shellexecuteinfo结构体参数sei,接下来要声明结构体:
[structlayout(layoutkind.sequential)]
public class shellexecuteinfo {
public int cbsize;
public int fmask;
public int hwnd;
[marshalas(unmanagedtype.lpwstr)]
public string lpverb; /*
动作,如edit,open,print... */
[marshalas(unmanagedtype.lpwstr)]
public string lpfile; /*
根据lpverb的值而定,常为文件名
*/
[marshalas(unmanagedtype.lpwstr)]
public string lpparameters; /*
参数字符串
*/
[marshalas(unmanagedtype.lpwstr)]
public string lpdirectory; /*
路径名
*/
public int nshow;
public int hinstapp;
public int lpidlist;
public string lpclass;
public int hkeyclass;
public int dwhotkey;
public int hicon;
public int hprocess;
}

shellexecuteinfo结构体的元素是不是够多的,它们的具体说明就不一一介绍了,如果你有空的话可以看看msdn

四、实现步骤

介绍了isellexecutehook接口的声明以及shellexecuteinfo结构体的声明后,我们就着手实现这个应用实例,这个实例很简单,每当explorer对一个shell对象执行某动作前将会弹出一个对话框,在其上显示执行的动作内容、对象名以及参数内容。

打开vs.net,按下面步骤工作:

1.新建一个空项目(项目名:extenshell)

2.添加一个新类(类名:extenshell.cs)
  
3.
将下面代码作为extenshell.cs的内容。

   /* extenshell.cs */
   using system;
   using system.reflection;
   using system.runtime.interopservices;
   using system.windows.forms;

   [assembly: assemblykeyfile(@"../../eskey.snk")] /*密钥文件*/
   namespace shellextension
   {
     //
接口声明。

     [comimport,interfacetype(cominterfacetype.interfaceisiunknown), guid("000214fb-0000-0000-c000-000000000046")]
        /* guid("000214fb-0000-0000-c000-000000000046")
相当于shlguid.h中的define_shlguid(iid_ishellexecutehookw, 0x000214fbl, 0, 0); */
     public interface ishellexecutehook
     {
         [preservesig()] /*
允许返回值为
com hresult */
         int execute(shellexecuteinfo sei);
     }

     //结构声明。
     [structlayout(layoutkind.sequential)]
     public class shellexecuteinfo
     {
         public int cbsize;
         public int fmask;
         public int hwnd;
         [marshalas(unmanagedtype.lpwstr)]
         public string lpverb;
         [marshalas(unmanagedtype.lpwstr)]
         public string lpfile;
         [marshalas(unmanagedtype.lpwstr)]
         public string lpparameters;
         [marshalas(unmanagedtype.lpwstr)]
         public string lpdirectory;
         public int nshow;
         public int hinstapp;
         public int lpidlist;
         public string lpclass;
         public int hkeyclass;
         public int dwhotkey;
         public int hicon;
         public int hprocess;
      }

      [guid("027f9368-a83e-42cc-85b2-1dc5e23c4608"), comvisible(true)]
         /*
guid生成工具创建一个新的guid作为类对象的guid标识。 */
      public class extenshell : ishellexecutehook
      {
           private int s_ok=0;
           private int s_false=1;
           public int execute(shellexecuteinfo sei)
           {
               try
               {
                   messagebox.show(null, "[ verb ]: " + sei.lpverb + "/n[ file ]: " + sei.lpfile + "/n[ parameters ]:" + sei.lpparameters + "/n[ directory ]:" + sei.lpdirectory , "shellextensionhook",messageboxbuttons.ok, messageboxicon.information);

               }
               catch(exception e)
               {
                   console.error.writeline("unknown exception : " + e.tostring());
               }

               return s_false;
               //
如果返回值为s_okshell将停止对shell对象的以后的所有动作。
            }
       }
  }

4. 在命令行上运行:sn -k eskey.snk ( sn.exe c:/programe files/microsoft.net/frameworksdk/bin下可以找到 ),将eskey.snk添加到项目中。
 
    5.
打开<项目> --> <属性>,将输出类型改成类库。
 
 
    6.
编译完成。
 
    7.
.net可控代码生成的com组件注册后要到assembly目录中寻找实体执行,故应将编译好的extenshell.dll文件拷贝到c:/winnt/assembly目录中。 

8. 注册组件。在命令行上运行:regasm {项目路径}/bin/debug/extenshell.dll( regasm.exec:/winnt/microsoft.net/framework/v1.0.2914下可以找到)
 

    9.
最后,在hklm/software/microsoft/windows/currentversion/explorer/shellexecutehooks项下新建一个字符串值,其名为{027f9368-a83e-42cc-85b2-1dc5e23c4608},值可以为空也可以加入一串描述性文字。

五、结 束

    这是一个简单的shell扩展的例子,虽然不是一个完整的应用,但是作者想通过此实例向读者介绍shell扩展和.net平台下的com组件开发技术,希望它能起抛砖引玉的作用。



发表评论 共有条评论
用户名: 密码:
验证码: 匿名发表