การใช้ Delphi เพื่อเขียนส่วนขยายเชลล์ของ Windows
เพื่อนๆ ที่คุ้นเคยกับหลักการของระบบปฏิบัติการจะรู้ว่าระบบปฏิบัติการที่สมบูรณ์จะมอบเชลล์ไว้คอยอำนวยความสะดวกให้กับผู้ใช้ทั่วไป
ใช้ฟังก์ชันต่างๆ ที่ได้รับจากระบบปฏิบัติการ เชลล์ของ Windows (ในที่นี้หมายถึงระบบปฏิบัติการ Windows 95, Windows NT4.0 หรือสูงกว่า) ไม่เพียงแต่ให้
ไม่เพียงแต่ให้อินเทอร์เฟซแบบกราฟิก GUI ที่สะดวกและสวยงามเท่านั้น แต่ยังมีฟังก์ชันส่วนขยายเชลล์ที่มีประสิทธิภาพ คุณอาจเห็นส่วนขยายเชลล์เหล่านี้ในซอฟต์แวร์จำนวนมาก เช่นในของคุณ
หากมีการติดตั้ง Winzip ในระบบ เมื่อคุณคลิกขวาที่โฟลเดอร์หรือไฟล์ใน Windows Explorer ไฟล์ Winzip จะปรากฏในเมนูป๊อปอัป
เมนูย่อ. หรือโฟลเดอร์ไซต์ FTP ที่ปรากฏใน Windows Explorer ใน Bullet FTP
Windows รองรับส่วนขยายเชลล์เจ็ดประเภท (เรียกว่าตัวจัดการ) และฟังก์ชันที่เกี่ยวข้องมีการอธิบายโดยย่อดังนี้:
(1) ตัวจัดการเมนูบริบท: เพิ่มเมนูตามบริบทให้กับออบเจ็กต์ไฟล์ประเภทเฉพาะ
(2) ตัวจัดการแบบลากแล้วปล่อยใช้เพื่อรองรับการส่งข้อมูล OLE เมื่อผู้ใช้ดำเนินการลากแล้วปล่อยบนวัตถุไฟล์บางประเภท
(3) ตัวจัดการไอคอนใช้เพื่อจัดเตรียมไอคอนเฉพาะให้กับวัตถุไฟล์บางไฟล์ และยังสามารถระบุไอคอนสำหรับวัตถุไฟล์บางประเภทได้
(4) ตัวจัดการแผ่นคุณสมบัติจะเพิ่มหน้าคุณสมบัติให้กับออบเจ็กต์ไฟล์ (นั่นคือ คลิกขวาที่ออบเจ็กต์ไฟล์หรือออบเจ็กต์โฟลเดอร์ และเลือกคุณสมบัติในเมนูป๊อปอัป
กล่องโต้ตอบที่ปรากฏขึ้นหลังรายการ) สามารถแชร์หน้าคุณสมบัติได้โดยออบเจ็กต์ไฟล์ประเภทเดียวกัน หรือสามารถกำหนดหน้าคุณสมบัติเฉพาะให้กับออบเจ็กต์ไฟล์ได้
(5) Copy-hook handler จะถูกเรียกโดยระบบเมื่ออ็อบเจ็กต์โฟลเดอร์หรืออ็อบเจ็กต์เครื่องพิมพ์ถูกคัดลอก ย้าย ลบ หรือเปลี่ยนชื่อผ่าน Windows
เพิ่มตัวจัดการ Copy-hook เพื่ออนุญาตหรือห้ามการดำเนินการบางอย่าง
(6) ระบบจะเรียกตัวจัดการเป้าหมายการวางเมื่อมีการลากและวางวัตถุไปยังวัตถุอื่น
(7)ระบบจะเรียกตัวจัดการวัตถุข้อมูลเมื่อมีการลาก วาง คัดลอกหรือวางไฟล์
ส่วนขยายเชลล์ทั้งหมดของ Windows ขึ้นอยู่กับโมเดลส่วนประกอบ COM (Component Object Model) และเชลล์เข้าถึงวัตถุผ่านอินเทอร์เฟซ
ส่วนขยายเชลล์ได้รับการออกแบบให้เป็นโปรแกรมเซิร์ฟเวอร์ในกระบวนการ 32 บิต และให้บริการแก่ระบบปฏิบัติการในรูปแบบของไลบรารีลิงก์แบบไดนามิก ดังนั้นหากคุณต้องการใช้วินโดวส์
ถ้าอินเทอร์เฟซผู้ใช้ถูกขยาย จำเป็นอย่างยิ่งที่จะต้องมีความรู้ในการเขียนออบเจ็กต์ COM เนื่องจากข้อจำกัดด้านพื้นที่ COM จะไม่ถูกนำมาใช้ที่นี่ ผู้อ่านสามารถอ้างอิงถึงได้
ตามไลบรารี MSDN ของ Microsoft หรือเอกสารวิธีใช้ที่เกี่ยวข้อง อินเทอร์เฟซถือได้ว่าเป็นคลาสพิเศษซึ่งประกอบด้วยชุดของฟังก์ชันและขั้นตอนที่สามารถใช้เพื่อควบคุมวัตถุได้
หลังจากที่คุณเขียนส่วนขยายเชลล์แล้ว คุณต้องลงทะเบียนส่วนขยายจึงจะมีผล ส่วนขยายเชลล์ทั้งหมดต้องอยู่ในรีจิสทรีของ Windows ภายใต้คีย์ HKEY_CLASSES_ROOTCLSID
ลงทะเบียนด้านล่าง ภายใต้คีย์นี้ คุณจะพบคีย์จำนวนมากที่มีชื่อ เช่น {0000002F-0000-0000-C000-000000000046} คีย์ดังกล่าวเป็นตัวระบุคลาสที่ไม่ซ้ำกันทั่วโลก
ไกด์. ส่วนขยายของเชลล์ทุกรายการจะต้องมีตัวระบุคลาสที่ไม่ซ้ำกันทั่วโลก ซึ่งเป็นวิธีที่ Windows ค้นหาตัวจัดการส่วนขยายของเชลล์
ตำแหน่งของไลบรารีลิงก์ไดนามิกส่วนขยายเชลล์ในระบบจะถูกบันทึกภายใต้คีย์ย่อย InProcServer32 ภายใต้ตัวระบุคลาส นามสกุลเชลล์ที่เกี่ยวข้องกับประเภทไฟล์ได้รับการลงทะเบียนแล้ว
ภายใต้คีย์หลัก shellex ของประเภทที่เกี่ยวข้อง หากระบบปฏิบัติการ Windows เป็น Windows NT ส่วนขยายของเชลล์จะต้องอยู่ในรีจิสทรีด้วย
ลงทะเบียนภายใต้คีย์หลัก HKEY_LOCAL_MACHINESoftwareMicrosoftWindowsCurrentVersionShellExtensionsApproved
หลังจากคอมไพล์โปรแกรม DLL ส่วนขยายเชลล์แล้ว คุณสามารถใช้ regsvr32.exe ที่ได้รับจาก Windows เองเพื่อลงทะเบียนโปรแกรมเซิร์ฟเวอร์ DLL หากใช้ Delphi คุณก็สามารถทำได้เช่นกัน
หากต้องการลงทะเบียน ให้เลือกลงทะเบียนเซิร์ฟเวอร์ ActiveX ในเมนูเรียกใช้
ก่อนอื่นเรามาแนะนำแอปพลิเคชันส่วนขยายเชลล์ที่ใช้กันทั่วไปก่อน: เมนูตามบริบท ซึ่งจะปรากฏขึ้นเมื่อคุณคลิกขวาที่ไฟล์หรือโฟลเดอร์ใน Windows
เมนูนี้เรียกว่าเมนูตามบริบท หากต้องการเพิ่มรายการเมนูแบบไดนามิกลงในเมนูตามบริบท คุณสามารถเขียน Context Menu Handler ได้ ยกตัวอย่างทุกคน
ซอฟต์แวร์ที่คุ้นเคย เช่น WinZip และ UltraEdit จะเพิ่มรายการเมนูลงในเมนูแบบไดนามิกโดยการเขียน Context Menu Handler หากติดตั้งในระบบ
WinZip จากนั้นเมื่อคุณคลิกขวาที่ไฟล์ (โฟลเดอร์) ชื่อ Windows เมนูตามบริบทของไฟล์จะมีรายการเมนูชื่อ Add to Windows.zip
ตัวจัดการเมนูบริบทที่จะใช้ในบทความนี้จะคล้ายกับเมนูบริบทที่ WinZip ให้มา มันจะเพิ่มก
รายการเมนูการทำงานของไฟล์ เมื่อคลิก โปรแกรมอินเทอร์เฟซจะแสดงหน้าต่างการทำงานของไฟล์ขึ้นมาเพื่อทำการคัดลอกไฟล์ ย้าย และดำเนินการอื่นๆ
การเขียนตัวจัดการเมนูบริบทต้องใช้อินเทอร์เฟซสามแบบ: IShellExtInit, IContextMenu และ TComObjectFactory การใช้งาน IShellExtInit
การเริ่มต้นอินเทอร์เฟซ อ็อบเจ็กต์อินเทอร์เฟซ IContextMenu ใช้งานเมนูตามบริบท และอินเทอร์เฟซ IComObjectFactory ดำเนินการสร้างอ็อบเจ็กต์
มีการแนะนำการใช้งานโปรแกรมเฉพาะด้านล่าง ขั้นแรก คลิกรายการ File|New ของเมนูใน Delphi เลือก DLL ในหน้าต่าง New Item เพื่อสร้างไฟล์โครงการ DLL
จากนั้นคลิกรายการ File|New ของเมนู เลือก Unit ในหน้าต่าง New Item เพื่อสร้างไฟล์ Unit คลิก File|New รายการของเมนู และเลือก Unit ในหน้าต่าง New Item
เลือกแบบฟอร์มเพื่อสร้างหน้าต่างใหม่ บันทึกไฟล์โครงการเป็น Contextmenu.dpr, Unit1 เป็น Contextmenuhandle.pas และบันทึกแบบฟอร์มเป็น
OpWindow.pas.
รายการโปรแกรมของ Contextmenu.dpr มีดังนี้:
เมนูบริบทของห้องสมุด
การใช้งาน
คอมเซิร์ฟ,
เมนูบริบทใน 'contextmenuhandle.pas'
opwindow ใน 'opwindow.pas' {Form2};
การส่งออก
DllGetClassObject,
DllCanUnloadตอนนี้
DllRegisterServer,
DllUnregisterServer;
{$อาร์ *.TLB}
{$อาร์ *.เรส}
เริ่ม
จบ.
รายการโปรแกรม Contextmenuhandle มีดังนี้:
หน่วย ContextMenuHandle;
อินเตอร์เฟซ
ใช้ Windows, ActiveX, ComObj, ShlObj, คลาส;
พิมพ์
TContextMenu = คลาส (TComObject, IShellExtInit, IContextMenu)
ส่วนตัว
FFileName: อาร์เรย์ [0..MAX_PATH] ของ Char;
ได้รับการคุ้มครอง
ฟังก์ชั่น IShellExtInit.Initialize = SEIInitialize; // หลีกเลี่ยงการเตือนคอมไพเลอร์
ฟังก์ชัน SEIInitialize (pidlFolder: PItemIDList; lpdobj: IDataObject;
hKeyProgID: HKEY): HResult;
ฟังก์ชั่น QueryContextMenu (เมนู: HMENU; indexMenu, idCmdFirst, idCmdLast,
uFlags: UINT): HResult;
ฟังก์ชัน InvoidCommand (var lpici: TCMInurgeCommandInfo): 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 ไบต์) ที่ระบุอินเทอร์เฟซโดยไม่ซ้ำกัน}
var
รายการไฟล์:TStringList;
การดำเนินการ
ใช้ ComServ, SysUtils, ShellApi, Registry, UnitForm;
ฟังก์ชัน TContextMenu.SEIInitialize (pidlFolder: PItemIDList; lpdobj: IDataObject;
hKeyProgID: HKEY): HResult;
var
StgMedium: TStgMedium;
FormatEtc: TFormatEtc;
FileNumber,i:จำนวนเต็ม;
เริ่ม
file://If lpdobj เท่ากับ Nil การโทรนี้จะล้มเหลว
ถ้า (lpdobj = ไม่มี) ให้เริ่มต้น
ผลลัพธ์ := E_INVALIDARG;
ออก;
จบ;
file:// เริ่มต้นและล้าง FileList ก่อนเพื่อเพิ่มไฟล์
FileList:=TStringList.Create;
FileList.ล้าง;
file://เตรียมใช้งานไฟล์รูปแบบคลิปบอร์ด
ด้วย FormatEtc จะเริ่มต้น
cfFormat := CF_HDROP;
ptd := ไม่มี;
แคระ := DVASPECT_CONTENT;
ลินเด็กซ์ := -1;
พิมพ์ := TYMED_HGLOBAL;
จบ;
ผลลัพธ์ := lpdobj.GetData(FormatEtc, StgMedium);
ถ้าล้มเหลว (ผลลัพธ์) ให้ออก;
file://First สอบถามจำนวนไฟล์ที่เลือกโดยผู้ใช้
FileNumber := DragQueryFile(StgMedium.hGlobal,$FFFFFFFF,ไม่มี,0);
file:// อ่านแบบวนซ้ำและบันทึกไฟล์ที่ผู้ใช้เลือกทั้งหมดไปยัง FileList
สำหรับ i:=0 ถึง FileNumber-1 จะเริ่มต้น
DragQueryFile(StgMedium.hGlobal, i, FFileName, SizeOf(FFileName));
FileList.Add(FFileName);
ผลลัพธ์ := ไม่มีข้อผิดพลาด;
จบ;
ปล่อยStgMedium(StgMedium);
จบ;
ฟังก์ชั่น TContextMenu.QueryContextMenu (เมนู: HMENU; indexMenu, idCmdFirst,
idCmdLast, uFlags: UINT): HResult;
เริ่ม
ผลลัพธ์ := 0;
ถ้า ((uFlags และ $0000000F) = CMF_NORMAL) หรือ
((uFlags และ CMF_EXPLORE) <> 0) จากนั้นเริ่มต้น
//เพิ่มรายการเมนูลงในเมนูบริบท ชื่อของรายการเมนูคือดูไฟล์บิตแมป
InsertMenu (เมนู, indexMenu, MF_STRING หรือ MF_BYPOSITION, idCmdFirst,
PChar('การทำงานของไฟล์'));
// คืนจำนวนรายการเมนูที่เพิ่ม
ผลลัพธ์ := 1;
จบ;
จบ;
ฟังก์ชัน TContextMenu.InvoidCommand (var lpici: TCMInurgeCommandInfo): HResult;
var
จากOP:TForm1;
เริ่ม
// ขั้นแรกตรวจสอบให้แน่ใจว่ากระบวนการถูกเรียกโดยระบบไม่ใช่โดยโปรแกรม
ถ้า (HiWord(Integer(lpici.lpVerb)) <> 0) แล้ว
เริ่ม
ผลลัพธ์ := E_FAIL;
ออก;
จบ;
// กำหนดความถูกต้องของพารามิเตอร์ที่ส่งผ่าน
ถ้า (LoWord(lpici.lpVerb) <> 0) ให้เริ่มต้น
ผลลัพธ์ := E_INVALIDARG;
ออก;
จบ;
file://สร้างหน้าต่างการดำเนินการไฟล์
frmOP:=TForm1.Create(ไม่มี);
file://เพิ่มรายการไฟล์ทั้งหมดลงในรายการในหน้าต่างการทำงานของไฟล์
frmOP.ListBox1.Items := รายการไฟล์;
ผลลัพธ์ := ไม่มีข้อผิดพลาด;
จบ;
ฟังก์ชั่น TContextMenu.GetCommandString (idCmd, uType: UINT; pwReserved: PUINT;
pszName: LPSTR; cchMax: UINT): HRESULT;
เริ่ม
ถ้า (idCmd = 0) ให้เริ่มต้น
ถ้า (uType = GCS_HELPTEXT) แล้ว
{ส่งคืนข้อมูลวิธีใช้ของรายการเมนูนี้ ข้อมูลวิธีใช้นี้จะปรากฏขึ้นเมื่อผู้ใช้เลื่อนเมาส์
ปรากฏบนแถบสถานะเมื่อย้ายไปยังรายการเมนูนี้ -
StrCopy(pszName, PChar('การคลิกรายการเมนูนี้จะดำเนินการกับไฟล์'));
ผลลัพธ์ := ไม่มีข้อผิดพลาด;
จบ
อื่น
ผลลัพธ์ := E_INVALIDARG;
จบ;
พิมพ์
TContextMenuFactory = คลาส (TComObjectFactory)
สาธารณะ
ขั้นตอน UpdateRegistry (ลงทะเบียน: บูลีน);
จบ;
ขั้นตอน TContextMenuFactory.UpdateRegistry (ลงทะเบียน: บูลีน);
var
ClassID: สตริง;
เริ่ม
ถ้าลงทะเบียนแล้วเริ่มต้น
UpdateRegistry ที่สืบทอดมา (ลงทะเบียน);
ClassID := GUIDToString(Class_ContextMenu);
file://เมื่อลงทะเบียนไฟล์ไลบรารีส่วนขยาย ให้เพิ่มไลบรารีลงในรีจิสทรี
CreateRegKey('*shellex', ', ');
CreateRegKey('*shellexContextMenuHandlers', ', ');
CreateRegKey('*shellexContextMenuHandlersFileOpreation', ', ClassID);
file:// หากระบบปฏิบัติการเป็น Windows NT
ถ้า (Win32Platform = VER_PLATFORM_WIN32_NT) แล้ว
ด้วย TRegistry สร้างทำ
พยายาม
รูตคีย์ := HKEY_LOCAL_MACHINE;
OpenKey('SOFTWAREMicrosoftWindowsCurrentVersionShell Extensions', จริง);
OpenKey('อนุมัติ', จริง);
WriteString(ClassID, 'ส่วนขยายเชลล์เมนูบริบท');
ในที่สุด
ฟรี;
จบ;
จบ
เริ่มอย่างอื่น
DeleteRegKey('*shellexContextMenuHandlersFileOpreation');
UpdateRegistry ที่สืบทอดมา (ลงทะเบียน);
จบ;
จบ;
การเริ่มต้น
TContextMenuFactory.Create (ComServer, TContextMenu, Class_ContextMenu,
', 'ส่วนขยายเชลล์เมนูบริบท', ciMultiInstance, tmApartment);
จบ.
เพิ่มตัวควบคุม TListBox และตัวควบคุม TButton สองตัวลงในหน้าต่าง OpWindow รายการโปรแกรมของ OpWindows.pas มีดังนี้:
หน่วย opwindow;
อินเตอร์เฟซ
การใช้งาน
Windows, ข้อความ, SysUtils, คลาส, กราฟิก, การควบคุม, แบบฟอร์ม, กล่องโต้ตอบ,
ExtCtrls, StdCtrls,shlobj,shellapi,ActiveX;
พิมพ์
TForm1 = คลาส (TForm)
ListBox1: TListBox;
Button1: T ปุ่ม;
Button2: T ปุ่ม;
ขั้นตอน FormCreate (ผู้ส่ง: TObject);
ขั้นตอน FormClose (ผู้ส่ง: TObject; var Action: TCloseAction);
ขั้นตอน Button1Click (ผู้ส่ง: TObject);
ขั้นตอน Button2Click (ผู้ส่ง: TObject);
ส่วนตัว
{ประกาศส่วนตัว}
สาธารณะ
รายการไฟล์:TStringList;
{ประกาศสาธารณะ}
จบ;
var
แบบฟอร์ม 1: TForm1;
การดำเนินการ
{$R *.DFM}
ขั้นตอน TForm1.FormCreate (ผู้ส่ง: TObject);
เริ่ม
FileList:=TStringList.Create;
Button1.Caption :='คัดลอกไฟล์';
Button2.Caption :='ย้ายไฟล์';
แสดงตัวเอง;
จบ;
ขั้นตอน TForm1.FormClose (ผู้ส่ง: TObject; var Action: TCloseAction);
เริ่ม
FileList ฟรี;
จบ;
ขั้นตอน TForm1.Button1Click (ผู้ส่ง: TObject);
var
sPath:สตริง;
fsTemp:SHFILEOPSTRUCT;
ฉัน:จำนวนเต็ม;
เริ่ม
sPath:=InputBox('การทำงานของไฟล์','ป้อนเส้นทางการคัดลอก','c:windows');
ถ้า sPath<>'ให้เริ่มต้น
fsTemp.Wnd := ตนเอง จัดการ;
file://set ประเภทการทำงานของไฟล์
fsTemp.wFunc :=FO_COPY;
file:// อนุญาตให้ยกเลิกการดำเนินการ
fsTemp.fFlags :=FOF_ALLOWUNDO;
สำหรับ i:=0 ถึง ListBox1.Items.Count-1 จะเริ่มต้น
file://ชื่อพาธแบบเต็มของไฟล์ต้นฉบับ
fsTemp.pFrom := PChar(ListBox1.Items.Strings[i]);
file://path ที่จะคัดลอกไป
fsTemp.pTo := PChar(sPath);
fsTemp.lpszProgressTitle:='คัดลอกไฟล์';
ถ้า SHFileOperation(fsTemp)<>0 แล้ว
ShowMessage('การคัดลอกไฟล์ล้มเหลว');
จบ;
จบ;
จบ;
ขั้นตอน TForm1.Button2Click (ผู้ส่ง: TObject);
var
sPath:สตริง;
fsTemp:SHFILEOPSTRUCT;
ฉัน:จำนวนเต็ม;
เริ่ม
sPath:=InputBox('การทำงานของไฟล์','ป้อนเส้นทางการเคลื่อนไหว','c:windows');
ถ้า sPath<>'ให้เริ่มต้น
fsTemp.Wnd := ตนเอง จัดการ;
fsTemp.wFunc :=FO_MOVE;
fsTemp.fFlags :=FOF_ALLOWUNDO;
สำหรับ i:=0 ถึง ListBox1.Items.Count-1 จะเริ่มต้น
fsTemp.pFrom := PChar(ListBox1.Items.Strings[i]);
fsTemp.pTo := PChar(sPath);
fsTemp.lpszProgressTitle:='ย้ายไฟล์';
ถ้า SHFileOperation(fsTemp)<>0 แล้ว
ShowMessage('การคัดลอกไฟล์ล้มเหลว');
จบ;
จบ;
จบ;
จบ.
คลิกโครงการ | สร้างรายการ ContextMenu ในเมนูและ Delphi จะสร้างไฟล์ Contextmenu.dll นี่คือโปรแกรมเมนูที่คำนึงถึงบริบท
ใช้ Regsvr32.exe เพื่อลงทะเบียนโปรแกรม จากนั้นคลิกขวาที่ไฟล์ใดไฟล์หนึ่งหรือหลายไฟล์ใน Windows Explorer จากนั้นไฟล์นั้นจะปรากฏในเมนูบริบท
มีรายการเมนูเพิ่มเติมสำหรับการทำงานของไฟล์ คลิกรายการนี้ และชื่อไฟล์ของไฟล์ทั้งหมดที่คุณเลือกจะปรากฏในรายการในหน้าต่างป๊อปอัป คุณสามารถเลือกปุ่มคัดลอกไฟล์หรือ
ปุ่มย้ายไฟล์ดำเนินการกับไฟล์