如何查询已安装的 "packaged COM" 个扩展点
How to query for installed "packaged COM" extension points
我正在开发一个基于插件的应用程序,该应用程序目前正在扫描 Windows 注册表以查找公开某些“已实施类别”条目的兼容 COM 服务器。这适用于通过 MSI 安装程序安装的“常规”COM 服务器。
但是,我现在遇到了通过 MSIX 安装程序安装的 COM 服务器的问题,这些安装程序通过 https://blogs.windows.com/windowsdeveloper/2017/04/13/com-server-ole-document-support-desktop-bridge/ 中所述的“打包 COM”目录公开 COM 扩展点。这些 COM 服务器仍然可以通过 CoCreateInstance 实例化,但是 RegOpenKey/RegEnumKey 搜索无法检测到它们的存在。
我不确定如何解决这个问题。最好的结果是某种 Windows API 用于查询已安装 COM 服务器的“打包 COM”目录 我可以 运行 另外到注册表搜索。但是,我不知道那是否存在?我也愿意接受其他建议,只要它们仍然允许我的应用程序动态检测是否存在新的基于 COM 的插件。
请忽略此答案。根据下面的 ICatInformation::EnumClassesOfCategories,有一个更好的答案。
用示例代码回答自己以查询已安装 COM 服务器的“打包 COM”目录。根据@SimonMourier 的建议。
using System.Collections.Generic;
using System.IO;
/** Use Target Framework Moniker as described in https://docs.microsoft.com/en-us/windows/apps/desktop/modernize/desktop-to-uwp-enhance */
class PackagedComScan {
static void Main(string[] args) {
var packageManager = new Windows.Management.Deployment.PackageManager();
// this call require the "packageQuery" capability if called from a UWP app (add <rescap:Capability Name="packageQuery" /> to the appxmanifest)
IEnumerable<Windows.ApplicationModel.Package> my_packages = packageManager.FindPackagesForUser("");
foreach (var package in my_packages) {
try {
ParseAppxManifest(package.InstalledLocation.Path + @"\AppxManifest.xml");
} catch (FileNotFoundException) {
// Installed package missing from disk. Can happen after deploying UWP builds from Visual Studio.
}
}
}
static void ParseAppxManifest(string manifest_path) {
var doc = new System.Xml.XmlDocument();
using (var fs = new FileStream(manifest_path, FileMode.Open, FileAccess.Read, FileShare.Read))
doc.Load(fs);
var nsmgr = new System.Xml.XmlNamespaceManager(doc.NameTable);
nsmgr.AddNamespace("a", "http://schemas.microsoft.com/appx/manifest/foundation/windows10"); // default namespace
nsmgr.AddNamespace("com", "http://schemas.microsoft.com/appx/manifest/com/windows10");
// detect exported COM servers
var nodes = doc.SelectNodes("/a:Package/a:Applications/a:Application/a:Extensions/com:Extension/com:ComServer/com:ExeServer/com:Class/@Id", nsmgr);
foreach (System.Xml.XmlNode node in nodes)
System.Console.WriteLine("Exported COM CLSID: {0}", node.Value);
}
}
这确实有点特别,因为它依赖于解析 AppxManifest.xml 文件。不过,它似乎完成了工作。请注意,在沙盒 AppContainer 进程中运行的 UWP 应用程序似乎只有 一些 AppxManifest.xml 文件的读取权限,而不是全部。因此,该代码 仅适用于“常规”Win32 或 .Net 进程。
使用示例代码回答自己以查询所有已安装的 COM 服务器,包括“Packaged COM”目录,使用 ICatInformation::EnumClassesOfCategories. Based on suggestion by Aditi_Narvekar:
#include <atlstr.h>
#include <vector>
static void CHECK(HRESULT hr) {
if (FAILED(hr))
abort(); // TODO: More graceful error handling
}
/** Return COM classes that implement any of the provided "Implemented Categories". */
inline std::vector<CLSID> GetClassesWithAnyOfCategories(std::vector<CATID> impl_categories) {
CComPtr<ICatInformation> cat_search;
CHECK(cat_search.CoCreateInstance(CLSID_StdComponentCategoriesMgr));
CComPtr<IEnumGUID> class_list;
CHECK(cat_search->EnumClassesOfCategories((ULONG)impl_categories.size(), impl_categories.data(), -1, nullptr, &class_list));
std::vector<CLSID> app_clsids;
app_clsids.reserve(64);
for (;;) {
CLSID cur_cls = {};
ULONG num_read = 0;
CHECK(class_list->Next(1, &cur_cls, &num_read));
if (num_read == 0)
break;
// can also call ProgIDFromCLSID to get the ProgID
// can also call OleRegGetUserType to get the COM class name
app_clsids.push_back(cur_cls);
}
return app_clsids;
}
我正在开发一个基于插件的应用程序,该应用程序目前正在扫描 Windows 注册表以查找公开某些“已实施类别”条目的兼容 COM 服务器。这适用于通过 MSI 安装程序安装的“常规”COM 服务器。
但是,我现在遇到了通过 MSIX 安装程序安装的 COM 服务器的问题,这些安装程序通过 https://blogs.windows.com/windowsdeveloper/2017/04/13/com-server-ole-document-support-desktop-bridge/ 中所述的“打包 COM”目录公开 COM 扩展点。这些 COM 服务器仍然可以通过 CoCreateInstance 实例化,但是 RegOpenKey/RegEnumKey 搜索无法检测到它们的存在。
我不确定如何解决这个问题。最好的结果是某种 Windows API 用于查询已安装 COM 服务器的“打包 COM”目录 我可以 运行 另外到注册表搜索。但是,我不知道那是否存在?我也愿意接受其他建议,只要它们仍然允许我的应用程序动态检测是否存在新的基于 COM 的插件。
请忽略此答案。根据下面的 ICatInformation::EnumClassesOfCategories,有一个更好的答案。
用示例代码回答自己以查询已安装 COM 服务器的“打包 COM”目录。根据@SimonMourier 的建议。
using System.Collections.Generic;
using System.IO;
/** Use Target Framework Moniker as described in https://docs.microsoft.com/en-us/windows/apps/desktop/modernize/desktop-to-uwp-enhance */
class PackagedComScan {
static void Main(string[] args) {
var packageManager = new Windows.Management.Deployment.PackageManager();
// this call require the "packageQuery" capability if called from a UWP app (add <rescap:Capability Name="packageQuery" /> to the appxmanifest)
IEnumerable<Windows.ApplicationModel.Package> my_packages = packageManager.FindPackagesForUser("");
foreach (var package in my_packages) {
try {
ParseAppxManifest(package.InstalledLocation.Path + @"\AppxManifest.xml");
} catch (FileNotFoundException) {
// Installed package missing from disk. Can happen after deploying UWP builds from Visual Studio.
}
}
}
static void ParseAppxManifest(string manifest_path) {
var doc = new System.Xml.XmlDocument();
using (var fs = new FileStream(manifest_path, FileMode.Open, FileAccess.Read, FileShare.Read))
doc.Load(fs);
var nsmgr = new System.Xml.XmlNamespaceManager(doc.NameTable);
nsmgr.AddNamespace("a", "http://schemas.microsoft.com/appx/manifest/foundation/windows10"); // default namespace
nsmgr.AddNamespace("com", "http://schemas.microsoft.com/appx/manifest/com/windows10");
// detect exported COM servers
var nodes = doc.SelectNodes("/a:Package/a:Applications/a:Application/a:Extensions/com:Extension/com:ComServer/com:ExeServer/com:Class/@Id", nsmgr);
foreach (System.Xml.XmlNode node in nodes)
System.Console.WriteLine("Exported COM CLSID: {0}", node.Value);
}
}
这确实有点特别,因为它依赖于解析 AppxManifest.xml 文件。不过,它似乎完成了工作。请注意,在沙盒 AppContainer 进程中运行的 UWP 应用程序似乎只有 一些 AppxManifest.xml 文件的读取权限,而不是全部。因此,该代码 仅适用于“常规”Win32 或 .Net 进程。
使用示例代码回答自己以查询所有已安装的 COM 服务器,包括“Packaged COM”目录,使用 ICatInformation::EnumClassesOfCategories. Based on suggestion by Aditi_Narvekar:
#include <atlstr.h>
#include <vector>
static void CHECK(HRESULT hr) {
if (FAILED(hr))
abort(); // TODO: More graceful error handling
}
/** Return COM classes that implement any of the provided "Implemented Categories". */
inline std::vector<CLSID> GetClassesWithAnyOfCategories(std::vector<CATID> impl_categories) {
CComPtr<ICatInformation> cat_search;
CHECK(cat_search.CoCreateInstance(CLSID_StdComponentCategoriesMgr));
CComPtr<IEnumGUID> class_list;
CHECK(cat_search->EnumClassesOfCategories((ULONG)impl_categories.size(), impl_categories.data(), -1, nullptr, &class_list));
std::vector<CLSID> app_clsids;
app_clsids.reserve(64);
for (;;) {
CLSID cur_cls = {};
ULONG num_read = 0;
CHECK(class_list->Next(1, &cur_cls, &num_read));
if (num_read == 0)
break;
// can also call ProgIDFromCLSID to get the ProgID
// can also call OleRegGetUserType to get the COM class name
app_clsids.push_back(cur_cls);
}
return app_clsids;
}