Delphi を使用して Windows シェル拡張機能を作成する
オペレーティング システムの原理に精通している友人なら、完全なオペレーティング システムが一般ユーザーを容易にするシェルを提供することを知っているでしょう。
OSが提供するさまざまな機能を利用します。 Windows のシェル (ここでは、Windows 95、Windows NT4.0 以降のオペレーティング システムを指します) は、次の機能を提供するだけではありません。
便利で美しい GUI グラフィカル インターフェイスを提供するだけでなく、強力なシェル拡張機能も多くのソフトウェアで使用できます。たとえばあなたの場合、
Winzip がシステムにインストールされている場合、Windows エクスプローラーでフォルダーまたはファイルを右クリックすると、Winzip ファイルがポップアップ メニューに表示されます。
短縮メニュー。または、Bullet FTP の Windows エクスプローラーに表示される FTP サイト フォルダー。
Windows は 7 種類のシェル拡張機能 (ハンドラーと呼ばれる) をサポートしており、それらに対応する機能は次のように簡単に説明されています。
(1) コンテキスト メニュー ハンドラー: コンテキスト依存メニューを特定の種類のファイル オブジェクトに追加します。
(2) ドラッグ アンド ドロップ ハンドラーは、ユーザーが特定の種類のファイル オブジェクトに対してドラッグ アンド ドロップ操作を実行するときに OLE データ送信をサポートするために使用されます。
(3) アイコン ハンドラーは、特定のファイル オブジェクトに固有のアイコンを提供するために使用され、特定の種類のファイル オブジェクトのアイコンを指定することもできます。
(4) PROperty シート ハンドラーは、ファイル オブジェクトにプロパティ ページを追加します (つまり、ファイル オブジェクトまたはフォルダー オブジェクトを右クリックし、ポップアップ メニューで [プロパティ] を選択します)
項目の後に表示されるダイアログ ボックス)、プロパティ ページを同じタイプのファイル オブジェクトで共有したり、一意のプロパティ ページをファイル オブジェクトに割り当てることができます。
(5) Windows を通じてフォルダー オブジェクトまたはプリンター オブジェクトがコピー、移動、削除、または名前変更されると、コピーフック ハンドラーがシステムによって呼び出されます。
コピーフックハンドラーを追加して、特定の操作を許可または禁止します。
(6) オブジェクトが別のオブジェクトにドラッグ アンド ドロップされると、ドロップ ターゲット ハンドラーがシステムによって呼び出されます。
(7) ファイルがドラッグ、ドロップ、コピー、またはペーストされると、システムによってデータ オブジェクト ハンドラーが呼び出されます。
Windows のすべてのシェル拡張機能は COM (コンポーネント オブジェクト モデル) コンポーネント モデルに基づいており、シェルはインターフェイスを通じてオブジェクトにアクセスします。
シェル拡張機能は 32 ビットのインプロセス サーバー プログラムとして設計されており、ダイナミック リンク ライブラリの形式でオペレーティング システムにサービスを提供します。したがって、Windowsを使用したい場合は、
ユーザー インターフェイスが拡張される場合は、COM オブジェクトの作成に関するある程度の知識が非常に必要になります。 スペースの都合上、ここでは COM を紹介しません。読者は参照してください。
Microsoft の MSDN ライブラリまたは関連ヘルプ ドキュメントによると、インターフェイスは、オブジェクトの操作に使用できる一連の関数とプロシージャを含む特別なクラスと見なすことができます。
シェル拡張を作成した後、それを有効にするには登録する必要があります。すべてのシェル拡張機能は、Windows レジストリの HKEY_CLASSES_ROOTCLSID キーの下に存在する必要があります。
以下から登録してください。このキーの下には、{0000002F-0000-0000-C000-000000000046} のような名前のキーが多数あります。このようなキーは、グローバルに一意のクラス識別子です。
ガイド。すべてのシェル拡張には、グローバルに一意のクラス識別子が必要です。これにより、Windows はシェル拡張ハンドラーを見つけます。
システム内のシェル拡張ダイナミック リンク ライブラリの場所は、クラス識別子の InProcServer32 サブキーに記録されます。ファイルタイプに関連付けられたシェル拡張子は、
対応するタイプのshellex主キーの下。 Windows オペレーティング システムが Windows NT の場合、シェル拡張子もレジストリに存在する必要があります。
主キー HKEY_LOCAL_MACHINESoftwareMicrosoftWindowsCurrentVersionShellExtensionsApproved の下に登録します。
シェル拡張 DLL プログラムをコンパイルした後、Windows 自体が提供する regsvr32.exe を使用して DLL サーバー プログラムを登録できます。 Delphi を使用している場合は、次のこともできます。
登録するには、[実行] メニューの [ActiveX サーバーの登録] を選択します。
まず、より一般的に使用されるシェル拡張アプリケーション、つまり Windows でファイルまたはフォルダーを右クリックするとポップアップされるコンテキスト依存メニューを紹介します。
このメニューはコンテキスト依存メニューと呼ばれます。コンテキスト依存メニューにメニュー項目を動的に追加するには、コンテキスト メニュー ハンドラーを作成します。たとえば、皆さん
WinZip や UltraEdit などのよく知られたソフトウェアは、コンテキスト メニュー ハンドラーを作成することによって、メニュー項目をメニューに動的に追加します。システムにインストールされている場合
WinZip を使用し、Windows という名前のファイル (フォルダー) を右クリックすると、コンテキスト依存メニューに [Windows.zip に追加] という名前のメニュー項目が表示されます。
この記事で実装するコンテキスト メニュー ハンドラーは、WinZip が提供するコンテキスト メニューに似ています。追加されます
ファイル操作メニュー項目をクリックすると、インターフェイス プログラムはファイル操作ウィンドウをポップアップ表示し、ファイルのコピー、移動などの操作を実行します。
コンテキスト メニュー ハンドラーを作成するには、IShellExtInit、IContextMenu、TComObjectFactory の 3 つのインターフェイスを実装する必要があります。 IShellExtInit の実装
インターフェイスの初期化。IContextMenu インターフェイス オブジェクトはコンテキスト依存メニューを実装し、IComObjectFactory インターフェイスはオブジェクトの作成を実装します。
以下に具体的なプログラム実装を紹介します。まず、Delphi のメニューの [ファイル] | [新規] をクリックし、[新しい項目] ウィンドウで [DLL] を選択して DLL プロジェクト ファイルを作成します。
次に、メニューのファイル | 新規項目をクリックし、新規項目ウィンドウでユニットを選択してユニット ファイルを作成し、メニューのファイル | 新規項目をクリックして、新規項目ウィンドウでユニットを選択します。
「フォーム」を選択して新しいウィンドウを作成します。プロジェクト ファイルを Contextmenu.dpr として保存し、Unit1 を Contextmenuhandle.pas として保存し、フォームを次のように保存します。
OpWindow.pas。
Contextmenu.dpr のプログラムリストは以下のとおりです。
ライブラリのコンテキストメニュー。
用途
コムサーブ、
「contextmenuhandle.pas」の contextmenuhandle、
'opwindow.pas' {Form2} の opwindow;
輸出
DllGetClassObject、
DllCanUnloadNow、
DllRegisterServer、
DllUnregisterServer;
{$R *.TLB}
{$R *.RES}
始める
終わり。
Contextmenuhandleのプログラムリストは以下のとおりです。
ユニットContextMenuHandle;
インタフェース
Windows、ActiveX、ComObj、ShlObj、Classes を使用します。
タイプ
TContextMenu = クラス(TComObject,IShellExtInit,IContextMenu)
プライベート
FFileName: Char の配列[0..MAX_PATH];
保護された
function IShellExtInit.Initialize = SEIInitialize // コンパイラの警告を回避します。
関数 SEIInitialize(pidlFolder: PItemIDList; lpdobj: IDataObject;
hKeyProgID: HKEY): HResult;
関数 QueryContextMenu(メニュー: HMENU;indexMenu、idCmdFirst、idCmdLast、
uFlags: UINT): HResult;
関数 InvokeCommand(var lpici: TCMInvokeCommandInfo): HResult;
関数 GetCommandString(idCmd, uType: UINT; pwReserved: PUINT;
pszName: LPSTR; cchMax: UINT): HResult;
終わり;
定数
Class_ContextMenu: TGUID = '{19741013-C829-11D1-8233-0020AF3E97A0}';
{Globally Unique Identifier (GUID) は、インターフェイスを一意に識別する 16 バイト (128 バイト) の値です}
変数
ファイルリスト:TStringList;
実装
ComServ、SysUtils、ShellApi、Registry、UnitForm を使用します。
関数 TContextMenu.SEIInitialize(pidlFolder: PItemIDList; lpdobj: IDataObject;
hKeyProgID: HKEY): HResult;
変数
StgMedium: TStgMedium;
フォーマットなど: Tフォーマットなど;
ファイル番号、i:整数;
始める
file://lpdobj が Nil に等しい場合、この呼び出しは失敗します
if (lpdobj = nil) から開始
結果 := E_INVALIDARG;
出口;
終わり;
file:// は、ファイルを追加するためにまず FileList を初期化してクリアします
FileList:=TStringList.Create;
FileList.Clear;
file://クリップボード形式ファイルの初期化
FormatEtc で開始します
cfFormat := CF_HDROP;
ptd := nil;
dwaspect := DVASPECT_CONTENT;
lindex := -1;
タイミング:= TYMED_HGLOBAL;
終わり;
結果 := lpdobj.GetData(FormatEtc, StgMedium);
失敗(結果)の場合は終了します。
file://最初にユーザーが選択したファイルの数を問い合わせます
FileNumber := DragQueryFile(StgMedium.hGlobal,$FFFFFFFF,nil,0);
file:// はループで読み取り、ユーザーが選択したすべてのファイルを FileList に保存します
for i:=0 から FileNumber-1 までが始まります
DragQueryFile(StgMedium.hGlobal, i, FFileName, SizeOf(FFileName));
FileList.Add(FFileName);
結果 := エラー;
終わり;
ReleaseStgMedium(StgMedium);
終わり;
function TContextMenu.QueryContextMenu(Menu: HMENU;indexMenu, idCmdFirst,
idCmdLast、uFlags: UINT): HResult;
始める
結果 := 0;
if ((uFlags および $0000000F) = CMF_NORMAL) または
((uFlags および CMF_EXPLORE) <> 0) その後開始
//メニュー項目をコンテキスト メニューに追加します。メニュー項目のタイトルは「ビットマップ ファイルの表示」です。
InsertMenu(Menu、indexMenu、MF_STRING または MF_BYPOSITION、idCmdFirst、
PChar('ファイル操作'));
// 追加されたメニュー項目の数を返す
結果 := 1;
終わり;
終わり;
関数 TContextMenu.InvokeCommand(var lpici: TCMInvokeCommandInfo): HResult;
変数
frmOP:TForm1;
始める
// まず、プロセスがプログラムではなくシステムによって呼び出されていることを確認します。
if (HiWord(Integer(lpici.lpVerb)) <> 0) then
始める
結果 := E_FAIL;
出口;
終わり;
// 渡されたパラメータの有効性を判断します
if (LoWord(lpici.lpVerb) <> 0) then begin
結果 := E_INVALIDARG;
出口;
終わり;
file://ファイル操作画面の作成
frmOP:=TForm1.Create(nil);
file:// ファイル操作ウィンドウのリストにすべてのファイルのリストを追加します
frmOP.ListBox1.Items := ファイルリスト;
結果 := エラー;
終わり;
function TContextMenu.GetCommandString(idCmd, uType: UINT; pwReserved: PUINT;
pszName: LPSTR; cchMax: UINT): HRESULT;
始める
if (idCmd = 0) から開始
if (uType = GCS_HELPTEXT) then
{このメニュー項目のヘルプ情報を返します。このヘルプ情報は、ユーザーがマウスを移動すると表示されます。
このメニュー項目に移動すると、ステータス バーに表示されます。 }
StrCopy(pszName, PChar('このメニュー項目をクリックするとファイル操作が実行されます'));
結果 := エラー;
終わり
それ以外
結果 := E_INVALIDARG;
終わり;
タイプ
TContextMenuFactory = クラス(TComObjectFactory)
公共
プロシージャ UpdateRegistry(Register: Boolean);
終わり;
プロシージャ TContextMenuFactory.UpdateRegistry(Register: Boolean);
変数
クラスID: 文字列;
始める
登録したら開始します
継承された UpdateRegistry(Register);
クラスID := GUIDToString(Class_ContextMenu);
file://拡張ライブラリ ファイルを登録する場合、ライブラリをレジストリに追加します
CreateRegKey('*shellex', ', ');
CreateRegKey('*shellexContextMenuHandlers', ', ');
CreateRegKey('*shellexContextMenuHandlersFileOpreation', ', ClassID);
file:// オペレーティング システムが Windows NT の場合
if (Win32Platform = VER_PLATFORM_WIN32_NT) then
TRegistry.Create を使用して実行します
試す
ルートキー := HKEY_LOCAL_MACHINE;
OpenKey('SOFTWAREMicrosoftWindowsCurrentVersionShell Extensions', True);
OpenKey('承認済み', True);
WriteString(ClassID, 'コンテキスト メニュー シェル拡張');
ついに
無料;
終わり;
終わり
そうでなければ始まる
DeleteRegKey('*shellexContextMenuHandlersFileOpreation');
継承された UpdateRegistry(Register);
終わり;
終わり;
初期化
TContextMenuFactory.Create(ComServer, TContextMenu, Class_ContextMenu,
'、'コンテキスト メニュー シェル拡張機能'、ciMultiInstance、tmApartment);
終わり。
OpWindow ウィンドウに TListBox コントロールと 2 つの TButton コントロールを追加します。OpWindows.pas のプログラム リストは次のとおりです。
ユニットオプウィンドウ;
インタフェース
用途
ウィンドウ、メッセージ、SysUtils、クラス、グラフィックス、コントロール、フォーム、ダイアログ、
ExtCtrls、StdCtrls、shlobj、shellapi、ActiveX;
タイプ
TForm1 = クラス(TForm)
リストボックス1: Tリストボックス;
ボタン 1: T ボタン;
ボタン 2: T ボタン;
プロシージャ FormCreate(Sender: TObject);
プロシージャ FormClose(Sender: TObject; var Action: TCloseAction);
プロシージャ Button1Click(送信者: TObject);
プロシージャ Button2Click(送信者: TObject);
プライベート
{プライベート宣言}
公共
ファイルリスト:TStringList;
{公的宣言}
終わり;
変数
フォーム1: TForm1;
実装
{$R *.DFM}
プロシージャ TForm1.FormCreate(送信者: TObject);
始める
FileList:=TStringList.Create;
Button1.Caption :='ファイルをコピー';
Button2.Caption :='ファイルを移動';
自己.表示;
終わり;
プロシージャ TForm1.FormClose(Sender: TObject; var Action: TCloseAction);
始める
ファイルリスト.無料;
終わり;
プロシージャ TForm1.Button1Click(送信者: TObject);
変数
sPath: 文字列;
fsTemp:SHFILEOPSTRUCT;
i:整数;
始める
sPath:=InputBox('ファイル操作','入力コピーパス','c:windows');
if sPath<>'then begin
fsTemp.Wnd := Self.Handle;
file://set ファイル操作タイプ
fsTemp.wFunc :=FO_COPY;
file:// では元に戻す操作が許可されます
fsTemp.fFlags :=FOF_ALLOWUNDO;
for i:=0 から ListBox1.Items.Count-1 までが始まります
file://ソースファイルのフルパス名
fsTemp.pFrom := PChar(ListBox1.Items.Strings[i]);
file://コピー先のパス
fsTemp.pTo := PChar(sPath);
fsTemp.lpszProgressTitle:='ファイルをコピー';
if SHFileOperation(fsTemp)<>0 then
ShowMessage('ファイルのコピーに失敗しました');
終わり;
終わり;
終わり;
プロシージャ TForm1.Button2Click(送信者: TObject);
変数
sPath:文字列;
fsTemp:SHFILEOPSTRUCT;
i:整数;
始める
sPath:=InputBox('ファイル操作','入力移動パス','c:windows');
if sPath<>'then begin
fsTemp.Wnd := Self.Handle;
fsTemp.wFunc :=FO_MOVE;
fsTemp.fFlags :=FOF_ALLOWUNDO;
for i:=0 から ListBox1.Items.Count-1 までが始まります
fsTemp.pFrom := PChar(ListBox1.Items.Strings[i]);
fsTemp.pTo := PChar(sPath);
fsTemp.lpszProgressTitle:='ファイルの移動';
if SHFileOperation(fsTemp)<>0 then
ShowMessage('ファイルのコピーに失敗しました');
終わり;
終わり;
終わり;
終わり。
メニューで [プロジェクト] | [ContextMenu のビルド] 項目をクリックすると、Delphi によって Contextmenu.dll ファイルが作成されます。これはコンテキスト依存のメニュー プログラムです。
Regsvr32.exe を使用してプログラムを登録し、Windows エクスプローラーで 1 つまたは複数のファイルを右クリックすると、コンテキスト メニューにそのファイルが表示されます。
ファイル操作用の追加メニュー項目があり、この項目をクリックすると、選択したすべてのファイルのファイル名がポップアップ ウィンドウのリストに表示され、ファイルのコピー ボタンを選択することができます。
「ファイルの移動」ボタンはファイル操作を実行します。