一、前言
.net平臺(tái)是微軟公司推出的作為未來軟件運(yùn)行和開發(fā)的環(huán)境,c#是微軟力薦的在.net平臺(tái)下開發(fā)應(yīng)用軟件的首選語言。本文將討論在.net環(huán)境下如何使用c#語言開發(fā)windows shell擴(kuò)展問題。如今windows家族已發(fā)展到xp世代了,想必每個(gè)程序員都對(duì)shell extension不會(huì)感到陌生吧,在這里我不想花太多的時(shí)間介紹shell extension的原理知識(shí),本文中將通過一個(gè)實(shí)例介紹用c#創(chuàng)建一個(gè)shell extension,在此過程中也會(huì)簡單介紹一些shell extension的原理知識(shí)(如果想詳細(xì)了解shell擴(kuò)展原理知識(shí),請參閱msdn)。
二、開發(fā)環(huán)境
(1)、windows2000 專業(yè)版。
(2)、visual studio.net beta 2.0或正式版1.0。
三、原理介紹
本實(shí)例實(shí)現(xiàn)一個(gè)shellexecuteex win32調(diào)用的鉤子操作,windows explorer常常會(huì)用到這個(gè)調(diào)用,如打開、編輯、打印等等shell操作都要用到這個(gè)調(diào)用。在windows注冊表hklm/software/microsoft/windows/currentversion/explorer/shellexecutehooks項(xiàng)下安裝了所有實(shí)現(xiàn)shell擴(kuò)展的組件信息。當(dāng)windows explorer執(zhí)行shell操作前,先在注冊中查找到已注冊的shell擴(kuò)展組件,并將其實(shí)例化,每個(gè)shell擴(kuò)展組件必須至少實(shí)現(xiàn)了ishellexecutehook接口,此接口提供了一個(gè)execute()函數(shù),explorer將通過組件實(shí)例對(duì)象調(diào)用execute()函數(shù),如此函數(shù)返回為s_false繼續(xù)后面的操作,如返回s_ok則停止后面的所有操作。根據(jù)以上原理,本實(shí)例要實(shí)現(xiàn)shell擴(kuò)展就必須要實(shí)現(xiàn)一個(gè)支持ishellexecutehook接口的com組件。
接口聲明
因c#不能像c++那樣用一句#include "shlguid.h"語句就可以完成ishellexecutehook接口聲明,它必須要求在程序中聲明接口的具體信息,聲明如下:
[comimpor,interfacetype(cominterfacetype.interfaceisiunknown), guid("000214fb-0000-0000-c000-000000000046")]
/* guid("000214fb-0000-0000-c000-000000000046") 相當(dāng)于shlguid.h中的define_shlguid(iid_ishellexecutehookw, 0x000214fbl, 0, 0); */
public interface ishellexecutehook{
[preservesig()] /* 允許返回值為com hresult */
int execute(shellexecuteinfo sei);
}
結(jié)構(gòu)聲明
在execute()方法中有一個(gè)shellexecuteinfo結(jié)構(gòu)體參數(shù)sei,接下來要聲明結(jié)構(gòu)體:
[structlayout(layoutkind.sequential)]
public class shellexecuteinfo {
public int cbsize;
public int fmask;
public int hwnd;
[marshalas(unmanagedtype.lpwstr)]
public string lpverb; /* 動(dòng)作,如edit,open,print... */
[marshalas(unmanagedtype.lpwstr)]
public string lpfile; /* 根據(jù)lpverb的值而定,常為文件名 */
[marshalas(unmanagedtype.lpwstr)]
public string lpparameters; /* 參數(shù)字符串 */
[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結(jié)構(gòu)體的元素是不是夠多的,它們的具體說明就不一一介紹了,如果你有空的話可以看看msdn。
四、實(shí)現(xiàn)步驟
介紹了isellexecutehook接口的聲明以及shellexecuteinfo結(jié)構(gòu)體的聲明后,我們就著手實(shí)現(xiàn)這個(gè)應(yīng)用實(shí)例,這個(gè)實(shí)例很簡單,每當(dāng)explorer對(duì)一個(gè)shell對(duì)象執(zhí)行某動(dòng)作前將會(huì)彈出一個(gè)對(duì)話框,在其上顯示執(zhí)行的動(dòng)作內(nèi)容、對(duì)象名以及參數(shù)內(nèi)容。
打開vs.net,按下面步驟工作:
1.新建一個(gè)空項(xiàng)目(項(xiàng)目名:extenshell)。
2.添加一個(gè)新類(類名:extenshell.cs)。
3.將下面代碼作為extenshell.cs的內(nèi)容。
/* 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") 相當(dāng)于shlguid.h中的define_shlguid(iid_ishellexecutehookw, 0x000214fbl, 0, 0); */
public interface ishellexecutehook
{
[preservesig()] /* 允許返回值為com hresult */
int execute(shellexecuteinfo sei);
}
//結(jié)構(gòu)聲明。
[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生成工具創(chuàng)建一個(gè)新的guid作為類對(duì)象的guid標(biāo)識(shí)。 */
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將停止對(duì)shell對(duì)象的以后的所有動(dòng)作。
}
}
}
4. 在命令行上運(yùn)行:sn -k eskey.snk ( sn.exe在 c:/programe files/microsoft.net/frameworksdk/bin下可以找到 ),將eskey.snk添加到項(xiàng)目中。
5. 打開<項(xiàng)目> --> <屬性>,將輸出類型改成類庫。
6. 編譯完成。
7. 因.net可控代碼生成的com組件注冊后要到assembly目錄中尋找實(shí)體執(zhí)行,故應(yīng)將編譯好的extenshell.dll文件拷貝到c:/winnt/assembly目錄中。
8. 注冊組件。在命令行上運(yùn)行:regasm {項(xiàng)目路徑}/bin/debug/extenshell.dll。( regasm.exe在c:/winnt/microsoft.net/framework/v1.0.2914下可以找到)
9.最后,在hklm/software/microsoft/windows/currentversion/explorer/shellexecutehooks項(xiàng)下新建一個(gè)字符串值,其名為{
五、結(jié) 束
這是一個(gè)簡單的shell擴(kuò)展的例子,雖然不是一個(gè)完整的應(yīng)用,但是作者想通過此實(shí)例向讀者介紹shell擴(kuò)展和.net平臺(tái)下的com組件開發(fā)技術(shù),希望它能起拋磚引玉的作用。
新聞熱點(diǎn)
疑難解答
圖片精選