Tích hợp shell Windows ngày nay ── menu ngữ cảnh, liên kết tệp và những gì đã đổi trên Windows 11

· · Windows, Phần mở rộng shell, Menu ngữ cảnh, Liên kết tệp, COM, Windows 11, File Explorer, MSIX, Phát triển Windows

Tôi được tư vấn với «chúng tôi thay PC bằng Windows 11, và menu ngữ cảnh của ứng dụng bạn làm cho chúng tôi nhiều năm trước đã biến mất». Nghe kỹ hơn thì nó không biến mất. Nhấp phải một tệp, chọn «Hiện thêm tùy chọn» ở cuối menu, và menu quen thuộc xuất hiện y như trước. Nói cách khác, các mục menu của ứng dụng nội bộ bị giấu sâu thêm một lần nhấp. Từ hiện trường chúng tôi nghe «thêm một lần nhấp» và «các câu hỏi không tìm thấy mục đã tăng».

Đây không phải sự cố hay cấu hình sai; đây là thay đổi thiết kế Windows 11. Menu ngữ cảnh File Explorer trở thành cấu trúc hai lớp, cũ và mới, và điều kiện để đặt một mục lên menu mới trở thành thứ hoàn toàn khác trước.

Trong khi đó, máy liên kết tệp và phần mở rộng shell bên dưới vẫn là thế giới cũ của COM và sổ đăng ký. Khóa phần mở rộng trỏ tới ProgID, verb của ProgID giữ dòng lệnh, và phần mở rộng phức tạp hơn chạy như máy chủ COM trong tiến trình (DLL) được nạp vào Explorer — cấu trúc đó không đổi hơn hai mươi năm. Nếu bạn không biết cả nền tảng không đổi lẫn menu mà Windows 11 tách đôi, bạn không thể cô lập «menu không xuất hiện», «bị giấu» hay «xuất hiện hai lần».

Bài này hướng tới nhân viên CNTT ở công ty vừa và nhỏ và nhà phát triển Windows chăm sóc ứng dụng nghiệp vụ. Nó nối, trong một bức tranh, cấu trúc ba lớp của liên kết tệp, lưu ý phần mở rộng shell cổ điển, cách nhắm menu ngữ cảnh mới Windows 11, cùng đăng ký, dọn dẹp và xử lý sự cố của trình cài đặt.

1. Kết luận trước

  • Nền tảng của menu ngữ cảnh và liên kết tệp là cấu trúc sổ đăng ký ba lớp «khóa phần mở rộng → ProgID → verb». Khóa phần mở rộng là con trỏ tới ProgID, ProgID là thực thể, và shell\<verb>\command bên dưới giữ dòng lệnh.1
  • HKEY_CLASSES_ROOT (HKCR) không phải hive độc lập; đó là khung nhìn gộp của HKLM\Software\Classes và HKCU\Software\Classes. Ghi đăng ký mọi người dùng vào HKLM và đăng ký từng người dùng vào HKCU, và coi HKCR chỉ đọc.2
  • Ứng dụng mặc định (ứng dụng mở khi nhấp đôi) được thiết kế do người dùng chọn, và chương trình không thể cướp. HĐH bảo vệ lựa chọn người dùng; việc trình cài đặt có thể làm là đăng ký làm ứng viên.3
  • Phần mở rộng shell cổ điển là DLL COM trong tiến trình được nạp vào Explorer. Sự cố hoặc chậm trong phần mở rộng lan ra toàn Explorer (và các ứng dụng khác dùng shell); môi trường 64-bit cần DLL 64-bit; và triển khai mã quản lý không được hỗ trợ.45
  • Trên Windows 11 menu ngữ cảnh tách đôi. Các lệnh duy nhất xuất hiện trên menu mới là những lệnh đăng ký bằng IExplorerCommand cộng danh tính gói; phần mở rộng IContextMenu cổ điển được chuyển sang menu cũ dưới «Hiện thêm tùy chọn» (Shift+F10).67
  • Đường chính thức để đặt lệnh tùy chỉnh lên menu mới là đăng ký DLL gốc triển khai IExplorerCommand trong manifesto MSIX (desktop4:FileExplorerContextMenus). Ứng dụng không thể trở thành MSIX có thể được cấp riêng danh tính bằng sparse package (MSIX với vị trí ngoài).78
  • Nếu tất cả bạn muốn là «mở bằng ứng dụng này», liên kết và verb tĩnh vẫn đủ. Bạn không cần DLL phần mở rộng shell, và chính Microsoft nói rõ «chọn phương pháp đơn giản nhất đáp ứng yêu cầu (verb tĩnh)».9
  • Sau đăng ký hoặc thay đổi, thông báo bằng SHChangeNotify(SHCNE_ASSOCCHANGED); lúc gỡ, xóa ProgID nhưng đừng xóa giá trị mặc định của khóa phần mở rộng — đó là hướng dẫn chính thức. Tích hợp shell gồm cả thiết kế dọn dẹp.110

Một câu: thế giới liên kết và verb không đổi; chỉ cách menu được hiện là tách đôi trên Windows 11. Dưới đây chúng ta đi từ nền tảng.

2. Liên kết tệp hoạt động thế nào — cấu trúc ba lớp khóa phần mở rộng → ProgID → verb

2.1. Đọc cấu trúc ba lớp từ một ví dụ

Điều xảy ra khi bạn nhấp đôi một tệp của phần mở rộng cho trước do ba lớp khóa sổ đăng ký quyết định.1

HKEY_CLASSES_ROOT
   .kmrpt                                  ← (1) Khóa phần mở rộng
      (Default) = KomuraSoft.Report.1      ←     Con trỏ chỉ đặt tên ProgID
      OpenWithProgids
         KomuraSoft.Report.1               ←     Ứng viên dưới «Mở bằng»
   KomuraSoft.Report.1                     ← (2) ProgID (thực thể liên kết)
      (Default) = Komura Report document
      DefaultIcon
         (Default) = "C:\Program Files\KomuraSoft\Report.exe",0
      shell                                ← (3) Danh sách verb
         open
            command
               (Default) = "C:\Program Files\KomuraSoft\Report.exe" "%1"
  • (1) Khóa phần mở rộng (.kmrpt) chỉ trỏ tới tên ProgID làm giá trị mặc định. Viết lệnh trực tiếp ở đây là sai.
  • (2) ProgID (KomuraSoft.Report.1) là thực thể liên kết; nó giữ tên hiển thị, biểu tượng và danh sách verb.
  • (3) Verb là hành động như «mở» hoặc «in», và giá trị mặc định của shell\open\command là dòng lệnh thực sự được khởi chạy.

Sự tách này cho phép bạn trỏ nhiều phần mở rộng (.kmrpt.kmrpt-file, chẳng hạn) tới cùng ProgID, hoặc đổi ProgID khi nâng cấp ứng dụng.

Cấu trúc ba lớp của liên kết tệpKhóa phần mở rộng là con trỏ có giá trị mặc định đặt tên ProgID; ProgID là thực thể giữ tên hiển thị, biểu tượng và danh sách verb; và giá trị mặc định của command dưới verb là dòng lệnh thực sự được khởi chạyđặt tên ProgID làm mặc địnhKhóa phần mở rộng .kmrptProgID KomuraSoft.Report.1verb(open và khác dưới shell)giá trị mặc định commandReport.exe được khởi chạyCũng giữ tên hiển thị và DefaultIcon

Hình 1: Khóa phần mở rộng là con trỏ, ProgID là thực thể, và command của verb là dòng lệnh thực sự được khởi chạy.

2.2. HKCR là «khung nhìn gộp» — nơi bạn ghi đổi nghĩa

Ví dụ trên được hiện dưới HKEY_CLASSES_ROOT (HKCR), nhưng HKCR không phải vị trí lưu trữ vật lý; đó là khung nhìn gộp của HKLM\Software\Classes và HKCU\Software\Classes. Nếu cùng khóa tồn tại ở cả hai, phía HKCU thắng.2

HKCR là khung nhìn gộpHKCR là HKLM và HKCU Classes chồng lên nhau; nếu cùng khóa tồn tại ở cả hai, HKCU thắng; ghi đăng ký vào HKLM hoặc HKCU một cách tường minh và coi HKCR chỉ đọcHKLM\\Software\\Classes(mọi người dùng)HKCR(khung nhìn gộp)HKCU\\Software\\Classes(từng người dùng)Nếu cùng khóa tồn tại, HKCU thắngCoi là chỉ đọc(để xác nhận)

Hình 2: HKCR là cách HKLM và HKCU Classes trông khi chồng nhau; luôn gọi một trong hai làm đích ghi.

Đích ghi Nghĩa Quyền cần
HKLM\Software\Classes Đăng ký chung mọi người dùng Quản trị viên
HKCU\Software\Classes Đăng ký chỉ cho người dùng đó Không
Ghi thẳng vào HKCR Được phân tùy nơi khóa sẵn đã sống Tùy

Trong thực tế, tách an toàn là luôn ghi đăng ký vào HKLM hoặc HKCU một cách tường minh, và coi HKCR chỉ đọc (để xác nhận). Quan hệ với chuyển hướng sổ đăng ký WOW64 cũng đáng sắp. Dữ liệu liên kết ngay dưới HKLM\Software\Classes như khóa phần mở rộng và ProgID đã chia sẻ giữa khung nhìn sổ đăng ký 32-bit và 64-bit từ Windows 7, nên trình cài đặt 32-bit ghi chúng không thoát sang phía Wow6432Node. Một số khóa con đăng ký COM như Classes\CLSID, ngược lại, bị chuyển hướng, và khi bạn đăng ký phần mở rộng shell (COM trong tiến trình) việc tách ghi 32-bit / 64-bit quan trọng. Chi tiết ở «Registry 32-bit/64-bit Redirection and Virtualization Pitfalls — Wow6432Node and the “The Value I Wrote Isn’t There” Problem».

2.3. Đăng ký phía ứng dụng — App Paths, Applications, RegisteredApplications

Cũng có ba loại đăng ký phía ứng dụng, ghép với phía tệp (phần mở rộng và ProgID).11

  • App Paths (HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\App Paths): đăng ký cho phép ShellExecuteEx khởi chạy chỉ bằng tên tệp thực thi. Microsoft khuyến nghị vì bạn không phải làm bẩn biến môi trường PATH.
  • Applications (HKCR\Applications\<app.exe>): định nghĩa cách mở mặc định khi một tệp tùy ý được giao dưới «Mở bằng», và tên hiển thị của ứng dụng (FriendlyAppName).
  • RegisteredApplications + Capabilities: khai báo các phần mở rộng và kiểu MIME ứng dụng có thể xử lý, và là đăng ký khiến nó xuất hiện ứng viên trên trang cài đặt ứng dụng Mặc định của Windows.

Hầu hết tư vấn «ứng dụng chúng tôi không xuất hiện trong danh sách ứng dụng Mặc định» là trường hợp ProgID đã đăng ký và đăng ký Capabilities này bị bỏ.

Ba loại đăng ký phía ứng dụngĐăng ký phía ứng dụng có ba loại — App Paths, Applications và RegisteredApplications — lần lượt chịu trách nhiệm khởi chạy chỉ bằng tên tệp, cách mở mặc định dưới Mở bằng, và xuất hiện trên trang ứng dụng Mặc địnhĐăng ký phía ứng dụngApp PathsApplicationsRegisteredApplicationsKhởi chạy chỉ bằng tên tệpMặc định dưới Mở bằngXuất hiện trên trang ứng dụng Mặc địnhCần khai báo Capabilities

Hình 3: Có ba loại đăng ký phía ứng dụng, và xuất hiện ứng viên ứng dụng Mặc định cần đăng ký Capabilities.

2.4. Ứng dụng mặc định thuộc về người dùng — bảo vệ UserChoice

Viết ProgID làm giá trị mặc định của khóa phần mở rộng không tự biến nó thành ứng dụng mặc định. Kết quả lựa chọn tường minh của người dùng dưới «Mở bằng» và tương tự được giữ trong HKCU\...\Explorer\FileExts\<extension>\UserChoice, và giải liên kết ưu tiên phía đó.

Và điểm quan trọng là Windows không hỗ trợ đổi lập trình ứng dụng mặc định. Cài đặt ứng dụng mặc định được thiết kế do người dùng làm qua UI Cài đặt hệ thống; dữ liệu UserChoice bị làm rối, và trình điều khiển bộ lọc (UCPD.sys) chặn ghi từ ứng dụng. Trong môi trường quản lý, Chính sách nhóm / chính sách MDM là phương tiện chính thức.3

Việc các công cụ như SetUserFTA, «bắt chước hàm băm rồi viết lại», đã được dùng là mặt kia của bảo vệ này. Điều bạn nên đặt vào trình cài đặt ứng dụng nội bộ không phải cướp mặc định, mà ba (a) đăng ký đúng ProgID và verb, (b) thêm mình vào OpenWithProgIds, và (c) nếu cần, hướng tới trang Cài đặt.

Giải ứng dụng mặc định và bảo vệ UserChoiceKết quả lựa chọn tường minh của người dùng được giữ trong UserChoice và ưu tiên khi giải liên kết; UCPD.sys chặn viết lại từ ứng dụng, nên việc trình cài đặt có thể làm là đăng ký làm ứng viên và hướng tới trang Cài đặtưu tiênUCPD.sys chặnUserChoice(lựa chọn người dùng)Giải liên kếtGiá trị mặc định khóa phần mở rộngViết lại từ ứng dụngViệc của trình cài đặtĐăng ký ProgID và verbThêm vào OpenWithProgIdsHướng tới trang Cài đặt

Hình 4: Giải liên kết ưu tiên lựa chọn người dùng (UserChoice), và HĐH bảo vệ nó khỏi viết lại bởi ứng dụng.

3. Verb khác «Mở» — print, edit, runas, verb tùy chỉnh

Verb không chỉ là open. Verb chuẩn mà HĐH biết nghĩa gồm edit, print, playpreview cũng như open, và verb chuẩn tự động có tên hiển thị theo ngôn ngữ HĐH. Verb mặc định dùng khi nhấp đôi được quyết định theo thứ tự: giá trị mặc định khóa shell → verb đầu trong sổ đăng ký → openopenwith.12

Thứ tự quyết định verb mặc địnhVerb mặc định dùng khi nhấp đôi là cái đầu tiên tìm thấy theo thứ tự giá trị mặc định khóa shell, verb đầu trong sổ đăng ký, open, openwithnếu khôngnếu khôngnếu khônggiá trị mặc định khóa shellVerb đầu trong sổ đăng kýopenopenwith

Hình 5: Verb mặc định khi nhấp đôi là cái đầu tiên tìm thấy theo thứ tự này.

Khi muốn thêm hành động riêng, đăng ký verb tùy chỉnh.

KomuraSoft.Report.1
   shell
      open
         command
            (Default) = "C:\Program Files\KomuraSoft\Report.exe" "%1"
      print
         command
            (Default) = "C:\Program Files\KomuraSoft\Report.exe" /print "%1"
      verify                          ← verb tùy chỉnh
         (Default) = Verify report (&V)   ← tên hiển thị menu
         command
            (Default) = "C:\Program Files\KomuraSoft\Report.exe" /verify "%1"

Ba sự thật nhỏ hữu ích khi biết.

  • Đăng ký verb tên runas và bạn định nghĩa khởi chạy nâng quyền tương đương «Chạy với tư cách quản trị viên», cũng được dùng khi API họ ShellExecute chỉ định runas.
  • Đặt giá trị trống tên Extended trên khóa verb và nó trở thành verb mở rộng chỉ hiện khi Shift+nhấp phải. Tiện để giấu thao tác nguy hiểm ít dùng.12
  • Một số liên kết ứng dụng cũ vẫn có cấu hình gửi tài liệu vào tiến trình sẵn có bằng DDE (khóa ddeexec), nhưng khởi chạy verb qua DDE đã là di sản Deprecated. Không có lý do viết mới.12

Một tai nạn thường gặp nữa là dấu ngoặc trên dòng lệnh. Nếu một phần tử chuỗi lệnh có thể chứa khoảng trắng, bạn phải bọc bằng dấu ngoặc. Điều đó áp dụng cho đường dẫn EXE như C:\Program Files\..., và %1 (đường dẫn tệp đã chọn) luôn phải viết "%1". Bạn không thể đảm bảo đường dẫn tệp người dùng không chứa khoảng trắng. My Program.exe không ngoặc được hiểu là «khởi chạy My với đối số Program.exe».13

Tai nạn dấu ngoặc trên dòng lệnhLệnh không ngoặc bị cắt ở khoảng trắng và hiểu nhầm là khởi chạy My với đối số Program.exe, nên đường dẫn EXE có thể chứa khoảng trắng và %1, đại diện đường dẫn tệp đã chọn, luôn phải bọc dấu ngoặccắt ở khoảng trắngLệnh không ngoặcHiểu nhầm là khởi chạy EXE khácLệnh có ngoặcKhởi chạy đúng ýBọc đường dẫn EXE bằng dấu ngoặcLuôn bọc %1 bằng dấu ngoặc nữa

Hình 6: Lệnh không ngoặc bị cắt sai ở khoảng trắng, nên luôn bọc đường dẫn EXE và %1 bằng dấu ngoặc.

Cơ chế chỉ-sổ-đăng-ký đến đây (verb tĩnh) có thể thực hiện mà không viết một DLL nào, và không rủi ro làm Explorer không ổn định. Chính Microsoft nhắc lại «trước khi viết phần mở rộng shell, hãy xem verb tĩnh đơn giản nhất đáp ứng yêu cầu đã đủ chưa».9

4. Phần mở rộng shell cổ điển — DLL chạy bên trong Explorer

4.1. Các loại phần mở rộng shell

Yêu cầu verb tĩnh không đáp ứng — «đổi menu động tùy lựa chọn», «thay biểu tượng hoặc tờ thuộc tính» — dùng trình xử lý phần mở rộng shell. Các loại tiêu biểu như sau.4

Trình xử lý Giao diện chính Việc có thể làm
Trình xử lý menu ngữ cảnh IContextMenu + IShellExtInit Thêm và điều khiển mục menu động
Trình xử lý biểu tượng / phủ biểu tượng IExtractIcon / IShellIconOverlayIdentifier Biểu tượng từng tệp và phủ
Trình xử lý tờ thuộc tính IShellPropSheetExt Thêm tab vào tờ thuộc tính
Hình thu nhỏ / infotip IThumbnailProvider / IQueryInfo Xem hình thu nhỏ và mô tả khi trỏ
Trình xử lý kéo-thả / copy-hook IDropTarget / ICopyHook Can thiệp lúc thả hoặc sao/chuyển

Tất cả được triển khai như lớp COM và đăng ký trong sổ đăng ký theo CLSID. Ý tưởng COM được nêu trong «What Are COM / ActiveX / OCX? - The Differences and Relationships Explained».

4.2. Ý nghĩa của việc là máy chủ COM trong tiến trình

Bản chất phần mở rộng shell cổ điển là máy chủ COM trong tiến trình (DLL) được nạp vào Explorer (hoặc mọi ứng dụng đã mở hộp thoại tệp chung). Mọi lưu ý theo sau đó.4

  • Nếu phần mở rộng sập, Explorer bị kéo theo. Nếu nó treo, nhấp phải đóng băng vài giây. Thiệt hại cũng không giới hạn ở Explorer; nó tới mọi ứng dụng đã hiện hộp thoại mở tệp.
  • Xây menu xảy ra trên luồng UI, nên bạn không được làm việc chậm như truy cập mạng hoặc I/O tệp lúc hiện menu.
  • Đăng ký mô hình luồng là Apartment theo quy tắc.
Cấu trúc thiệt hại kèm của phần mở rộng trong tiến trìnhDLL phần mở rộng shell được nạp không chỉ vào Explorer mà còn vào tiến trình mọi ứng dụng đã mở hộp thoại tệp, nên sự cố hoặc treo của phần mở rộng lan ra cả tiến trình chủnạp trong tiến trìnhnạp trong tiến trìnhDLL phần mở rộng shellExplorerMọi ứng dụng mở hộp thoạiSự cố hoặc treo lanĐừng làm việc chậm lúc hiện

Hình 7: DLL phần mở rộng chạy bên trong tiến trình chủ, nên sự cố hoặc treo lan ra chủ nói chung.

Điều tra tư vấn như «Explorer đóng băng khi tôi mở một thư mục cụ thể» hoặc «nhấp phải mất năm giây» thì không hiếm nguyên nhân là phần mở rộng shell bên thứ ba chứ không phải ứng dụng nội bộ. Phương pháp cô lập ở Chương 8.

4.3. Khớp bitness — môi trường 64-bit cần DLL 64-bit

DLL trong tiến trình phải khớp bitness của tiến trình nạp nó. Explorer trên Windows 64-bit là tiến trình 64-bit, nên DLL phần mở rộng shell chỉ xây 32-bit không bao giờ được nạp và không bao giờ xuất hiện trên menu. Cũng không có lỗi, nên đây là nguyên nhân quen thuộc của «tôi đã đăng ký nhưng không xuất hiện». Kết hợp thân ứng dụng 32-bit với DLL phần mở rộng shell 64-bit là cấu hình hợp lệ, nhưng bạn cần để ý đăng ký COM tách theo bitness (Wow6432Node). Khởi chạy từ command của verb là EXE tiến trình riêng, nên không chịu ràng buộc này (để lại EXE 32-bit được).

Khớp bitness của DLL phần mở rộng shellDLL phần mở rộng shell duy nhất Explorer 64-bit có thể nạp là DLL 64-bit; DLL chỉ-32-bit không bao giờ xuất hiện trên menu và không tạo lỗi; EXE khởi chạy từ command verb là tiến trình riêng và không chịu ràng buộccó thể nạpkhông thể nạptiến trình riêngExplorer 64-bitDLL phần mở rộng shell 64-bitDLL chỉ-32-bitKhông xuất hiện trên menu, không lỗiEXE khởi chạy từ verbĐể 32-bit được

Hình 8: DLL duy nhất được nạp vào Explorer 64-bit là DLL 64-bit; EXE khởi chạy từ verb không chịu ràng buộc này.

4.4. Vì sao không được viết bằng mã quản lý

Tôi thường được hỏi «tôi có thể viết phần mở rộng shell bằng C# không», nhưng Microsoft đã nói rõ rằng viết phần mở rộng shell trong tiến trình bằng mã quản lý (.NET) không được khuyến nghị và ngoài hỗ trợ.5

Lý do là tính chất phần mở rộng được nạp vào tiến trình tùy ý. Xung đột phiên bản CLR (đặc biệt dưới .NET Framework 4), vấn đề CLR tái nhập vòng lặp thông điệp khi chờ khóa, và vòng đời đối tượng không xác định từ thu gom rác va với hợp đồng đếm tham chiếu COM là lý do cấu trúc khiến ứng dụng chủ không ổn định. Một số điểm đã được giảm trên .NET Framework 4 trở đi và .NET hiện đại, nhưng lập trường chính thức không đổi.

Hướng dẫn thực tế đơn giản. Viết phần mở rộng trong tiến trình bằng C++ gốc. Nếu muốn dùng mã quản lý, hãy làm EXE thường khởi chạy từ command của verb, hoặc phần mở rộng ngoài tiến trình chạy trong tiến trình riêng (trình xử lý xem trước và tương tự).5

Đánh giá mã quản lý có được phép khôngPhần mở rộng trong tiến trình chạy bên trong Explorer được viết bằng C++ gốc theo quy tắc; nếu muốn mã quản lý, hãy làm EXE thường khởi chạy từ command verb hoặc phần mở rộng ngoài tiến trình chạy trong tiến trình riêngkhôngChạy trong tiến trình?Viết bằng C++ gốcMã quản lý đượcRủi ro CLR / tái nhập làm chủ không ổn địnhEXE khởi chạy từ verbXem trước ngoài tiến trình

Hình 9: Phần mở rộng trong tiến trình theo quy tắc là C++ gốc; mã quản lý giới hạn ở cấu hình chạy trong tiến trình riêng.

5. Menu ngữ cảnh mới Windows 11 — menu tách đôi

5.1. Điều đã xảy ra

Windows 11 làm mới menu ngữ cảnh File Explorer. Cắt, sao chép và tương tự thành một hàng biểu tượng ở trên; «Mở» và «Mở bằng» được nhóm ở trên; và lệnh ứng dụng thêm được nhóm dưới lệnh chuẩn của shell. Khi một ứng dụng thêm nhiều lệnh, chúng được gom vào flyout (menu con) mang tên ứng dụng.6

Và điểm then chốt là đây. Phần mở rộng shell cổ điển dựa trên IContextMenu không bị xóa; chúng được chuyển sang phía menu cũ mở bằng «Hiện thêm tùy chọn» (Shift+F10) và nạp menu Windows 10 nguyên trạng.6 Bản sắc tư vấn mở đầu «menu bị giấu» là sự tách này.

Menu ngữ cảnh mà Windows 11 tách đôiThứ mở trước khi nhấp phải là menu mới; các lệnh duy nhất xuất hiện ở đó là những lệnh đăng ký bằng IExplorerCommand và danh tính gói; phần mở rộng IContextMenu cổ điển được chuyển sang menu cũ mở bằng Hiện thêm tùy chọnHiện thêm tùy chọn Shift+F10Nhấp phải một tệpMenu mới(Windows 11)Lệnh IExplorerCommand + danh tínhMenu cũ(menu Windows 10)Phần mở rộng IContextMenu cổ điểnNhiều lệnh được gom vào flyout

Hình 10: Các lệnh duy nhất xuất hiện trên menu mới là lệnh IExplorerCommand + danh tính; phần mở rộng cổ điển được chuyển sang phía menu cũ.

5.2. Đường chính thức lên menu mới — IExplorerCommand + đăng ký manifesto

Có một cách đặt lệnh tùy chỉnh lên menu mới. Chuẩn bị DLL gốc triển khai giao diện IExplorerCommand, và khai báo máy chủ COM cùng phần mở rộng menu ngữ cảnh trong manifesto gói MSIX.7

<!-- Manifesto gói (trích) -->
<com:Extension Category="windows.comServer">
  <com:ComServer>
    <com:SurrogateServer DisplayName="Komura commands">
      <com:Class Id="01234567-89AB-CDEF-0123-456789ABCDEF"
                 Path="KomuraCommand.dll" ThreadingModel="STA" />
    </com:SurrogateServer>
  </com:ComServer>
</com:Extension>
<desktop4:Extension Category="windows.fileExplorerContextMenus">
  <desktop4:FileExplorerContextMenus>
    <desktop5:ItemType Type=".kmrpt">
      <desktop5:Verb Id="VerifyReport"
                     Clsid="01234567-89AB-CDEF-0123-456789ABCDEF" />
    </desktop5:ItemType>
  </desktop4:FileExplorerContextMenus>
</desktop4:Extension>

Type của ItemType có thể chỉ định phần mở rộng cụ thể, hoặc * (mọi tệp), Directory (thư mục), hoặc Directory\Background (nền thư mục). Khớp DLL với kiến trúc Explorer (64-bit / ARM64).7

Bản thân IExplorerCommand là giao diện có từ thời Windows 7; bạn triển khai tiêu đề (GetTitle), biểu tượng (GetIcon), trạng thái bật / tắt / ẩn (GetState), và thực thi (Invoke). Phương thức được gọi từ luồng UI, nên truy cập tài nguyên mạng bị cấm, và phương thức xây menu cần trả về nhanh. Làm việc nặng sau Invoke.147

Cấu trúc manifesto của đăng ký menu mớiKhai báo máy chủ COM của manifesto MSIX ánh xạ CLSID tới DLL, và khai báo phần mở rộng menu ngữ cảnh gắn đích với triển khai bằng ItemType và Verb, nên lệnh tùy chỉnh xuất hiện trên menu mớiánh xạ CLSID tới DLLchỉ định bằng ItemType và VerbManifesto MSIXKhai báo máy chủ COMKhai báo phần mở rộng menuDLL triển khai IExplorerCommandLệnh xuất hiện trên menu mớiĐích là phần mở rộng, mọi tệp và tương tự

Hình 11: Hai khai báo trong manifesto gắn DLL triển khai với đích, và lệnh xuất hiện trên menu mới.

5.3. Lựa chọn cho ứng dụng không đóng gói — lấy riêng danh tính bằng sparse package

Cửa thoát khi «ứng dụng chúng tôi chỉ phân phối được dạng MSI; MSIX không thể» là sparse package (MSIX với vị trí ngoài). Bạn ký một MSIX nhỏ chỉ là manifesto, không có thân ứng dụng, và đăng ký ở cuối trình cài đặt sẵn có. Ứng dụng khi đó có danh tính gói, và đăng ký manifesto ở trên (= xuất hiện trên menu mới) trở nên khả thi. Có từ Windows 10 phiên bản 2004, và gói cần chữ ký bằng chứng chỉ được tin trên máy đích.8

Luồng lấy danh tính bằng sparse packageSau khi trình cài đặt sẵn có đặt thân ứng dụng, đăng ký sparse package chỉ-manifesto với vị trí ngoài cho ứng dụng danh tính gói và làm đăng ký manifesto menu mới khả thiTrình cài đặt sẵn cóĐặt thân ứng dụngSparse packageChỉ manifesto, không thânĐăng ký với vị trí ngoàiCó danh tính góiĐăng ký menu mới trở nên khả thiCần chữ ký được tin

Hình 12: Đăng ký sparse package không chứa thân, với vị trí ngoài, và ứng dụng có danh tính gói.

Lợi thế lớn nhất là bạn không phải thay trình cài đặt; đó là câu trả lời thực tế cho ứng dụng đã có tài sản trình cài đặt MSI/EXE. So sánh với chuyển hết sang MSIX, xem thêm «Choosing a Windows App Distribution Method - MSI/MSIX/ClickOnce/xcopy/Custom Updater».

5.4. Verb liên kết xuất hiện trên menu mới thế nào

Điểm dễ hiểu nhầm: các liên kết Chương 2 và 3 (ProgID và verb) vẫn sống trên menu mới. Verb mặc định khi nhấp đôi, «Mở», và ứng viên «Mở bằng» được giải từ liên kết và hiện ở trên cùng menu mới. Vậy nếu tất cả bạn muốn là «mở được bằng ứng dụng này», Windows 11 không cần việc thêm. Mặt khác, liên kết không phải phần mở rộng menu đa năng, nên nếu muốn lệnh tùy chỉnh tùy ý ở lớp đầu menu mới bạn cần IExplorerCommand cộng danh tính — đó là phân vai.7

Phân vai giữa liên kết và menu mớiLiên kết ProgID-và-verb vẫn được dùng trên menu mới để giải verb mặc định, Mở và Mở bằng, và hiện ở trên; đặt lệnh tùy chỉnh tùy ý ở lớp đầu menu mới cần IExplorerCommand và danh tínhLiên kết(ProgID + verb)Giải mặc định / MởTrên cùng menu mớiKhông việc thêm trên Win11Lệnh tùy chỉnhIExplorerCommand+danh tínhLớp đầu menu mới

Hình 13: Liên kết vẫn xử lý giải họ «Mở» trên menu mới; chỉ lệnh tùy chỉnh mới cần IExplorerCommand cộng danh tính.

6. Bảng quyết định thực tế — chọn phương án nào trong ba

Chúng ta sắp những gì đã có thành lựa chọn thực tế ba ngả.

Việc muốn đạt Phương tiện khuyến nghị Trông thế nào trên Windows 11 Việc và chi phí cần
(a) Khởi chạy ứng dụng nội bộ khi nhấp đôi hoặc «Mở» Liên kết + verb tĩnh (chỉ đăng ký sổ đăng ký) Gắn vào «Mở» và «Mở bằng» trên menu mới Chỉ đăng ký sổ đăng ký của trình cài đặt. Không DLL, không yêu cầu ký thêm
(b) Đặt lệnh tùy chỉnh cho tệp/thư mục đã chọn lên menu mới Triển khai IExplorerCommand + đăng ký manifesto MSIX. Ứng dụng không đóng gói được cấp danh tính bằng sparse package Lớp đầu menu mới (nhiều lệnh được gom vào flyout tên ứng dụng) DLL C++ gốc + danh tính gói + ký mã
(c) Tiếp tục dùng phần mở rộng IContextMenu cổ điển sẵn có Giữ nguyên tạm thời (đừng chọn cho phát triển mới) Chỉ phía menu cũ, dưới «Hiện thêm tùy chọn» (Shift+F10) Duy trì bản dựng 64-bit và đăng ký COM. Lên kế hoạch chuyển sau sang (b)

Có hai điểm phán đoán. Thứ nhất, đừng đưa (b) hay (c) vào yêu cầu mà (a) sẽ đáp ứng. Lúc bạn viết phần mở rộng shell bạn nhận trách nhiệm về ổn định của Explorer. Thứ hai, (c) chỉ là «không hỏng»; về trải nghiệm người dùng vẫn kém một bước. Lệnh dùng càng thường xuyên trong vận hành hằng ngày, lợi tức chuyển sang (b) càng lớn.

Cách chọn trong ba phương ánNếu tất cả bạn muốn là khởi chạy khi nhấp đôi hoặc Mở, liên kết và verb tĩnh đủ; để đặt lệnh tùy chỉnh lên menu mới dùng IExplorerCommand và đăng ký manifesto MSIX; nếu không thể trở thành MSIX, cấp danh tính bằng sparse package; giữ phần mở rộng IContextMenu cổ điển sẵn có ở phía menu cũ tạm thờikhôngkhôngkhôngMở đủ?Liên kết + verb tĩnhTùy chỉnh trên menu mới?Có thể trở thành MSIX?IExplorerCommand+MSIXDanh tính sparse-pkgGiữ cổ điển tạm thờiChỉ phía menu cũKhông DLL, rủi ro nhỏ

Hình 14: Chọn giữa verb tĩnh, IExplorerCommand cộng danh tính, và giữ cái cổ điển, theo yêu cầu.

7. Triển khai và đăng ký trong thực tế — trình cài đặt, sparse package, dọn dẹp

7.1. HKLM hay HKCU

Khớp với hình dạng trình cài đặt. Mọi người dùng (đặt dưới Program Files, quyền quản trị viên) là HKLM\Software\Classes; cài từng người dùng (không nâng quyền) là HKCU\Software\Classes. Trộn chúng và bạn tạo câu hỏi kiểu «A mở được nhưng B không». Với phần mở rộng shell liên quan đăng ký CLSID, Reg-Free COM — loại bỏ nhu cầu đăng ký sổ đăng ký — là lựa chọn hợp lệ cho dùng COM trong ứng dụng, nhưng không áp dụng được cho phần mở rộng shell mà Explorer nạp, nên bạn cần đăng ký thẳng («What Is Reg-Free COM - Using COM Without Registration»).

7.2. Sau thay đổi, thông báo — SHChangeNotify

Sau khi đăng ký, đổi hoặc xóa liên kết, thông báo sự kiện SHCNE_ASSOCCHANGED bằng SHChangeNotify. Bỏ qua và Explorer có thể không nhận ra thay đổi đến khi khởi động lại.110

// Gọi một lần sau khi đổi liên kết, vd. từ hành động tùy chỉnh trình cài đặt
SHChangeNotify(SHCNE_ASSOCCHANGED, SHCNF_IDLIST, nullptr, nullptr);

7.3. Đăng ký và gỡ sparse package

Đăng ký và gỡ sparse package là việc của trình cài đặt. Đăng ký sau khi đặt tệp; gỡ trước khi xóa tệp.8

# Lúc cài: sau khi đặt tệp, đăng ký thư mục cài làm vị trí ngoài
Add-AppxPackage -Path "C:\Program Files\KomuraSoft\KomuraReport.identity.msix" `
                -ExternalLocation "C:\Program Files\KomuraSoft"

# Lúc gỡ: gỡ đăng ký gói trước khi xóa tệp
Remove-AppxPackage <package full name>

Điểm cần để ý: Add-AppxPackage đăng ký cho người dùng đã chạy nó. Nếu bạn gọi từ hành động tùy chỉnh của MSI theo máy, chạy dưới LocalSystem không cấp danh tính cho người dùng đã cài, nên bạn cấu hình chạy dưới mạo danh người dùng. Dù vậy, đăng ký dưới mạo danh chỉ cho người dùng đã chạy lần cài đó. Trên PC nhiều người dùng, người dùng khác và người dùng tạo sau không có danh tính gói, và lệnh không xuất hiện trên menu mới. Để mọi người dùng dùng được, cung cấp cơ chế như kiểm tra đăng ký gói của mình lúc khởi chạy đầu và đăng ký nếu thiếu (đăng ký từng người dùng), và đưa việc gỡ từ mỗi người dùng có đăng ký vào kế hoạch gỡ. Phản ánh đăng ký manifesto cũng có thể cần khởi động lại Explorer (hoặc đăng xuất).7

Thứ tự đăng ký và gỡ sparse packageLúc cài đăng ký sparse package sau khi đặt tệp; lúc gỡ gỡ đăng ký trước khi xóa tệp; để ý đăng ký chỉ có hiệu với người dùng đã chạyCàiĐặt tệpĐăng ký sparse packageGỡGỡ đăng ký góiXóa tệpĐăng ký chỉ có hiệu với người dùng đang chạy

Hình 15: Đăng ký sau khi đặt tệp, gỡ trước khi xóa tệp, và để ý đăng ký theo người dùng đang chạy.

7.4. Dọn dẹp lúc gỡ — xóa gì và để lại gì

Dọn dẹp lúc gỡ có đường hướng dẫn chính thức rõ.1

  • Xóa: toàn bộ khóa ProgID nội bộ, đăng ký Capabilities/RegisteredApplications, đăng ký CLSID của phần mở rộng shell, sparse package (Remove-AppxPackage).
  • Để lại: giá trị mặc định khóa phần mở rộng (.kmrpt). Khuyến nghị chính thức là không xóa dù nó vẫn trỏ tới ProgID nội bộ. Đánh giá sau cài liệu ứng dụng khác đã lấy mặc định thì khó, và Windows đơn giản bỏ qua ProgID giá trị mặc định chưa đăng ký, nên để lại không gây hại thực.
  • Gọi SHChangeNotify(SHCNE_ASSOCCHANGED) cả ở cuối dọn dẹp.

Hầu hết vấn đề «chúng tôi đã gỡ mà menu vẫn còn sót» là rò trong thiết kế dọn dẹp này.

Thiết kế dọn dẹp lúc gỡLúc gỡ bạn xóa khóa ProgID nội bộ, đăng ký CLSID và sparse package; để lại giá trị mặc định khóa phần mở rộng vì ProgID chưa đăng ký bị bỏ qua; thông báo thay đổi bằng SHChangeNotify ở cuối dọn dẹpGỡXóaĐể lạiĐăng ký ProgID và CLSIDSparse packageGiá trị mặc định khóa phần mở rộngProgID chưa đăng ký bị bỏ quaThông báo bằng SHChangeNotify ở cuối

Hình 16: Xóa đăng ký nội bộ, để lại giá trị mặc định khóa phần mở rộng, và thông báo thay đổi ở cuối dọn dẹp.

8. Xử lý sự cố — thiếu, trùng, nặng

8.1. Không xuất hiện trên menu

Cô lập theo thứ tự này.

  1. Menu nào bạn đang xem: đăng ký kiểu cổ điển chỉ xuất hiện ở phía menu cũ dưới Shift+F10. Kiểm tra cả hai trước.
  2. Bitness: DLL phần mở rộng shell chỉ-32-bit không được nạp vào Explorer 64-bit (Mục 4.3).
  3. Đích đăng ký: HKLM/HKCU, nhầm Wow6432Node. Xác nhận khóa thật bằng reg query.
  4. Đăng ký gói: với menu mới, xác nhận sự có mặt bằng Get-AppxPackage, độ tin của chứng chỉ ký, và đường -ExternalLocation, rồi khởi động lại Explorer.7
  5. Thông báo sót: nếu quên SHChangeNotify, bạn biết bằng việc khởi động lại Explorer có làm nó có hiệu không.
Thứ tự cô lập khi không xuất hiện trên menuBắt đầu bằng xác nhận menu nào bạn đang xem, rồi cô lập bitness DLL, đích đăng ký sổ đăng ký, đăng ký gói và chữ ký, và SHChangeNotify bị sót, theo thứ tự đóXác nhận menu nào, cũ hay mớiXác nhận bitness DLLXác nhận đích đăng ký HKLM và HKCUXác nhận đăng ký gói và chữ kýNhận ra thông báo sót bằng khởi động lại

Hình 17: Khi «không xuất hiện», cô lập theo thứ tự menu đang xem, bitness, đích đăng ký, đăng ký gói, thông báo sót.

8.2. Xuất hiện hai lần, hoặc không biến mất

Nguyên nhân điển hình là cùng tồn tại đăng ký sổ đăng ký cổ điển và đăng ký manifesto, rò dọn dẹp lúc gỡ (Mục 7.4), hoặc sót ProgID phiên bản cũ. Nếu xuất hiện hai lần chỉ trên menu cũ, nghĩ tới sót; nếu xuất hiện trên cả cũ và mới, nghĩ tới cùng tồn tại.

Cô lập hiển thị képHai lần chỉ trên menu cũ chỉ tới sót như rò dọn dẹp hoặc ProgID cũ; hai lần trên cả cũ và mới chỉ tới cùng tồn tại đăng ký sổ đăng ký cổ điển và đăng ký manifestochỉ menu cũcả cũ và mớiXuất hiện hai lần trên cái nào?SótCùng tồn tạiRò dọn dẹp hoặc ProgID cũ sótĐăng ký sổ đăng ký cổ điển cùng tồn tại với đăng ký mới

Hình 18: Hai lần chỉ trên menu cũ chỉ tới sót; hai lần trên cả cũ và mới chỉ tới cùng tồn tại.

8.3. Explorer nặng hoặc sập

Khi nhấp phải chậm, hoặc một thư mục cụ thể sập, trước hết kiểm kê phần mở rộng shell đã cài. Liệt kê phần mở rộng không phải Microsoft bằng công cụ như ShellExView của NirSoft, tạm tắt những cái đáng ngờ, và tìm DLL thủ phạm bằng tìm kiếm nhị phân. Khi sập, «Faulting module» của Trình xem sự kiện cũng là manh mối. Nếu phần mở rộng nội bộ là nguyên nhân, nghi I/O đồng bộ hoặc truy cập mạng trên đường xây menu (Mục 4.2 và 5.2).

Xác định DLL thủ phạm khi nặng hoặc sậpLiệt kê phần mở rộng shell không phải Microsoft trong ShellExView, tạm tắt những cái đáng ngờ và tìm DLL thủ phạm bằng tìm kiếm nhị phân; khi sập, faulting module của Trình xem sự kiện cũng là manh mốiKiểm kê phần mở rộng shellLiệt kê những cái không phải MicrosoftTạm tắt và tìm kiếm nhị phânXác định DLL thủ phạmKhi sậpKiểm tra faulting module

Hình 19: Tạm tắt phần mở rộng không phải Microsoft và tìm nhị phân; khi sập, cũng dùng Trình xem sự kiện.

8.4. Windows Sandbox tiện để kiểm tra

Kiểm tra tích hợp shell dựa trên xác nhận «cài trên môi trường sạch → thao tác → gỡ → sót bằng không». Tiện ở đây là Windows Sandbox (Pro/Enterprise/Education): mỗi lần khởi chạy đưa ra Windows dùng một lần hoàn toàn mới trong vài giây, nên bạn có thể chạy thử đăng ký và dọn dẹp trình cài đặt bao nhiêu lần tùy ý. Đóng là mọi thứ biến mất, nên cũng hợp điều tra sổ đăng ký sót.15

9. Tóm tắt

  • Liên kết tệp là cấu trúc ba lớp «khóa phần mở rộng → ProgID → verb», và HKCR là khung nhìn gộp HKLM/HKCU Classes. Gọi đích ghi tường minh, và luôn bọc %1 bằng dấu ngoặc.
  • Ứng dụng mặc định được thiết kế do người dùng chọn và không đổi được từ chương trình. Việc của trình cài đặt là đăng ký đúng làm ứng viên.
  • Phần mở rộng shell cổ điển là DLL COM trong tiến trình được nạp vào Explorer. Sự cố hoặc chậm lan ra toàn bộ; cần 64-bit; mã quản lý không được hỗ trợ; triển khai bằng C++ gốc là quy tắc.
  • Trên Windows 11 menu ngữ cảnh tách đôi. Đặt lệnh tùy chỉnh lên menu mới cần IExplorerCommand cộng manifesto MSIX; IContextMenu cổ điển được chuyển sang phía «Hiện thêm tùy chọn».
  • Với ứng dụng không thể trở thành MSIX, lấy danh tính bằng sparse package (MSIX với vị trí ngoài) là câu trả lời thực tế.
  • Nếu tất cả bạn muốn là «mở bằng ứng dụng này», liên kết và verb tĩnh vẫn đủ. Bắt đầu từ phương tiện đơn giản nhất cũng là hướng dẫn chính thức.
  • Sau đăng ký, thay đổi hoặc xóa, thông báo bằng SHChangeNotify; lúc gỡ, xóa ProgID nhưng để lại giá trị mặc định khóa phần mở rộng. Windows Sandbox tiện để kiểm tra.

Nếu thay PC Windows 11 khiến bạn nhận ra «menu bị giấu», trước hết xác nhận đó là (a), (b) hay (c) trong bảng quyết định Chương 6. Bạn nên ước được quy mô việc tại chỗ.

Bài viết liên quan

Lĩnh vực tư vấn liên quan

KomuraSoft LLC đảm nhận thiết kế và triển khai liên kết tệp, menu ngữ cảnh và phần mở rộng shell cho ứng dụng nghiệp vụ; nhắm menu ngữ cảnh mới Windows 11 (chuyển sang IExplorerCommand, đưa sparse package); xem xét đăng ký và dọn dẹp trình cài đặt sẵn có; và điều tra nguyên nhân Explorer nặng hoặc sập. Có thể bắt đầu từ việc quyết định làm gì với «menu bị giấu dưới Hiện thêm tùy chọn».

Liên kết tham khảo

  1. Microsoft Learn, File Types. Về cấu trúc khóa phần mở rộng trỏ tới ProgID; OpenWithProgIds; tách đăng ký giữa HKLM/HKCU\Software\Classes; gọi SHChangeNotify(SHCNE_ASSOCCHANGED) sau đổi liên kết; và xóa ProgID lúc gỡ trong khi để lại giá trị mặc định khóa phần mở rộng.  2 3 4 5

  2. Microsoft Learn, HKEY_CLASSES_ROOT Key. Về HKEY_CLASSES_ROOT là khung nhìn gộp HKLM\Software\Classes và HKCU\Software\Classes; định nghĩa phía người dùng ưu tiên hơn phía máy; và quy tắc phân khi ghi.  2

  3. Microsoft Learn, Windows app defaults platform. Về đổi ứng dụng mặc định được thiết kế chỉ qua UI Cài đặt hệ thống; dữ liệu cài đặt người dùng bị làm rối và bảo vệ ghi bởi trình điều khiển bộ lọc (UCPD.sys); đổi dựa trên sổ đăng ký không được hỗ trợ; và dùng Chính sách nhóm / chính sách MDM trong môi trường quản lý.  2

  4. Microsoft Learn, Working with Shell Extensions. Về các loại trình xử lý phần mở rộng shell; phần mở rộng là DLL COM trong tiến trình được nạp vào Explorer (và vào tiến trình lưu trữ shell), nên sự cố hoặc treo lan ra toàn Explorer; đăng ký với ThreadingModel=Apartment; và xem xét giải pháp đơn giản hơn trước phần mở rộng shell.  2 3

  5. Microsoft Learn, Guidance for Implementing In-Process Extensions. Về Microsoft không khuyến nghị và không hỗ trợ triển khai phần mở rộng shell trong tiến trình bằng mã quản lý; lý do gồm xung đột phiên bản CLR, tái nhập và vòng đời đối tượng không xác định; và mã quản lý được chấp nhận cho phần mở rộng ngoài tiến trình (trình xử lý xem trước, hoặc khởi chạy từ shell\verb\command).  2 3

  6. Windows Developer Blog, Extending the Context Menu and Share Dialog in Windows 11. Về thiết kế menu ngữ cảnh mới Windows 11; mở rộng qua IExplorerCommand cộng danh tính ứng dụng; đặt «Mở» và «Mở bằng» ở trên; gom nhiều lệnh vào flyout tên ứng dụng; và phần mở rộng IContextMenu cổ điển được nạp như menu Windows 10 dưới «Hiện thêm tùy chọn» (Shift+F10).  2 3

  7. Microsoft Learn, Add a File Explorer context menu command to a packaged desktop app. Về đăng ký trên menu ngữ cảnh mới Windows 11 được làm bằng triển khai IExplorerCommand cộng windows.comServer cộng khai báo manifesto desktop4:FileExplorerContextMenus; ItemType có thể chỉ định *, Directory hoặc Directory\Background; khớp kiến trúc DLL; giữ phương thức xây menu nhanh; bao phủ ứng dụng không đóng gói bằng sparse package; đôi khi cần khởi động lại Explorer để đăng ký có hiệu; và liên kết tệp không phải phần mở rộng menu đa năng.  2 3 4 5 6 7 8

  8. Microsoft Learn, Grant package identity by packaging with external location. Về lấy danh tính gói bằng đăng ký gói vị trí ngoài (sparse package) mà không đổi trình cài đặt sẵn có; sẵn có từ Windows 10 phiên bản 2004; và các tính năng Windows cần danh tính (đăng ký menu ngữ cảnh, thông báo và tương tự) trở nên dùng được.  2 3

  9. Microsoft Learn, Choosing a Static or Dynamic Shortcut Menu Method. Về chọn phương pháp verb tĩnh đơn giản nhất đáp ứng yêu cầu; IContextMenu mạnh nhất nhưng cũng phức tạp nhất và được xếp về phía không khuyến nghị; và IExplorerCommand/IExplorerCommandState là phương pháp khuyến nghị.  2

  10. Microsoft Learn, SHChangeNotify function. Về cách nâng sự kiện SHCNE_ASSOCCHANGED thông báo hệ thống về thay đổi liên kết tệp, và dùng nó để shell nhận ra thay đổi.  2

  11. Microsoft Learn, Application Registration. Về đăng ký tệp thực thi qua khóa con App Paths được khuyến nghị; vai trò khóa con Applications; đăng ký verb qua SystemFileAssociations; và ưu tiên ProgID cùng thông tin liên quan khi ứng dụng mặc định đổi. 

  12. Microsoft Learn, Creating Shortcut Menu Handlers. Về cách đăng ký verb tĩnh; thứ tự quyết định verb mặc định (giá trị mặc định → verb đầu → Open → Open With); tên hiển thị verb chuẩn do HĐH cung cấp; verb mở rộng qua Extended; liên kết với lệnh DDE đã Deprecated; và lưu ý chuyển hướng WOW64 trong môi trường 64-bit.  2 3

  13. Microsoft Learn, Verbs and File Associations. Về verb là hành động cũng được ShellExecuteEx dùng; phần tử chuỗi lệnh có thể chứa khoảng trắng cần bọc dấu ngoặc, và “%1” luôn viết có ngoặc; và đăng ký thủ tục mặc định dưới HKCR\Applications. 

  14. Microsoft Learn, IExplorerCommand interface. Về thành phần phương thức GetTitle, GetIcon, GetState, Invoke, EnumSubCommands và tương tự; phương thức được gọi trên luồng UI nên không được giao tiếp với tài nguyên mạng; và sẵn có từ Windows Vista. 

  15. Microsoft Learn, Windows Sandbox. Về có thể khởi chạy môi trường Windows cô lập dùng một lần trong vài giây, mọi thay đổi bị bỏ khi đóng, phù hợp thử phần mềm và kiểm tra trình cài đặt, và sẵn có trên Pro/Enterprise/Education. 

Các bài viết gần đây có cùng thẻ để tìm hiểu sâu hơn những chủ đề lân cận.

Các trang này đặt chủ đề trong bối cảnh rộng hơn của dịch vụ và quyết định.

Bài viết liên quan trực tiếp đến các dịch vụ sau.

Câu hỏi thường gặp

Các câu hỏi thường gặp khi tư vấn về chủ đề của bài viết.

Vì sao mục menu ngữ cảnh của ứng dụng chúng tôi trên Windows 11 chỉ xuất hiện dưới «Hiện thêm tùy chọn»?
Vì trên Windows 11 menu ngữ cảnh của File Explorer tách thành hai lớp, cũ và mới. Các lệnh duy nhất có thể xuất hiện trên menu mới là những lệnh triển khai giao diện IExplorerCommand và được đăng ký trong manifesto gói MSIX (= có danh tính gói). Phần mở rộng shell cổ điển dựa trên IContextMenu được chuyển sang menu cũ mở bằng «Hiện thêm tùy chọn» (Shift+F10). Bản thân phần mở rộng không hỏng, nên hiện vẫn hoạt động, nhưng nếu muốn nó trên menu mới bạn cần chuyển sang IExplorerCommand và đóng gói MSIX hoặc cấp danh tính bằng sparse package.
Trình cài đặt có thể đặt ứng dụng chúng tôi làm ứng dụng mặc định cho một tệp (ứng dụng mở khi nhấp đôi) không?
Không. Chọn ứng dụng mặc định được thiết kế do người dùng làm, và Windows không hỗ trợ đổi ứng dụng mặc định từ bất kỳ nơi nào ngoài UI Cài đặt hệ thống. Thông tin UserChoice giữ lựa chọn từng người dùng bị làm rối, và trình điều khiển bộ lọc (UCPD.sys) cũng bảo vệ ghi khỏi ứng dụng. Việc trình cài đặt có thể làm là đăng ký ProgID và verb, thêm mình vào OpenWithProgIds để xuất hiện ứng viên dưới «Mở bằng», và hướng người dùng tới trang ứng dụng Mặc định. Cách triển khai đúng không phải cướp mặc định, mà sẵn sàng được chọn.
Tôi có được viết phần mở rộng shell bằng mã quản lý như C# không?
Microsoft đã nói rõ rằng viết phần mở rộng shell trong tiến trình (trình xử lý menu ngữ cảnh, trình xử lý biểu tượng và tương tự) bằng mã quản lý không được khuyến nghị và không được hỗ trợ. Phần mở rộng được nạp vào Explorer và vào tiến trình mọi ứng dụng mở hộp thoại tệp chung, nên xung đột phiên bản CLR, tái nhập và vòng đời đối tượng không xác định làm ứng dụng chủ không ổn định. Quy tắc là triển khai bằng C++ gốc. EXE thường được khởi chạy từ command của verb, hoặc phần mở rộng ngoài tiến trình như trình xử lý xem trước chạy trong tiến trình riêng, thì dùng mã quản lý được.
Sparse package (MSIX với vị trí ngoài) là gì?
Một gói MSIX nhỏ không chứa tệp ứng dụng, chỉ có manifesto (thông tin danh tính). Với ứng dụng cài theo cách thông thường bằng trình cài đặt sẵn có (MSI, Inno Setup và tương tự), bạn đăng ký bằng Add-AppxPackage -ExternalLocation trỏ tới thư mục cài, và ứng dụng có danh tính gói rồi dùng được các tính năng cần danh tính, như đăng ký menu ngữ cảnh mới Windows 11 và thông báo toast. Có từ Windows 10 phiên bản 2004, và gói cần chữ ký mã được tin trên máy đích. Đây là lựa chọn thực tế khi muốn hỗ trợ menu mới mà không chuyển cả phương thức phân phối sang MSIX.
Tôi nên làm gì khi một mục menu ngữ cảnh xuất hiện hai lần, hoặc không biến mất?
Trước hết cô lập nguyên nhân bằng cách kiểm tra nó xuất hiện trên menu nào: menu mới hay menu cũ (Hiện thêm tùy chọn). Hiển thị kép điển hình là đăng ký đăng ký cổ điển và đăng ký manifesto MSIX cùng tồn tại, hoặc đăng ký ProgID hay CLSID phần mở rộng bị sót lúc gỡ. Sau khi đổi liên kết, cũng nghi SHChangeNotify(SHCNE_ASSOCCHANGED) bị quên; ngay sau đăng ký gói, nghi quên khởi động lại Explorer. Nếu vẫn chưa giải quyết, tạm tắt phần mở rộng không phải Microsoft trong ShellExView và tìm DLL thủ phạm bằng tìm kiếm nhị phân.

Hồ sơ tác giả

Trang giới thiệu tác giả bài viết.

Go Komura

Đại diện của KomuraSoft LLC

Chuyên về phát triển phần mềm Windows, tư vấn kỹ thuật và điều tra lỗi, đặc biệt trong các dự án có hệ thống hiện hữu và lỗi khó tái hiện.

Liên kết công khai

Quay lại blog