一、前言
.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("
/* 用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_ok则shell将停止对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.exe在c:/winnt/microsoft.net/framework/v1.0.2914下可以找到)
9.最后,在hklm/software/microsoft/windows/currentversion/explorer/shellexecutehooks项下新建一个字符串值,其名为{
五、结 束
这是一个简单的shell扩展的例子,虽然不是一个完整的应用,但是作者想通过此实例向读者介绍shell扩展和.net平台下的com组件开发技术,希望它能起抛砖引玉的作用。
新闻热点
疑难解答
图片精选