建立
一、前言
.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_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項下建立一個字串值,其名為{027F9368-A83E-42cc-85B2-1DC5E23C4608},值可以為空白也可以加入一串描述性文字。
五、結 束
這是一個簡單的Shell擴充的例子,雖然不是一個完整的應用,但是作者想通過此執行個體向讀者介紹Shell擴充和.NET平台下的COM組件開發技術,希望它能起拋磚引玉的作用。