这个流程图将描述 Marshal2.GetActiveObject
方法的执行过程。
这个流程图描述了以下过程:
开始执行 GetActiveObject
方法。
Start executing the GetActiveObject
method.
调用 GetActiveObject
方法,传入 progID 参数。
Call the GetActiveObject
method with the progID parameter.
ProgID(Programmatic Identifier)是 Windows 编程中的一个重要概念,特别是在 COM(Component Object Model)编程中。让我为您详细解释:
定义:
- ProgID 是一个人类可读的字符串,用于标识一个 COM 类。
- 它是 CLSID(Class Identifier)的一种更友好的别名。
格式:
- 通常采用 “ApplicationName.ObjectType” 的格式。
- 例如:“Excel.Application” 或 “Word.Document”。
用途:
- 提供一种更容易记忆和使用的方式来引用 COM 对象。
- 程序员可以使用 ProgID 来创建或获取 COM 对象实例,而不需要记住复杂的 CLSID。
与 CLSID 的关系:
- 每个 ProgID 都映射到一个特定的 CLSID。
- 系统维护着 ProgID 到 CLSID 的映射关系。
在系统中的存储:
- ProgID 和对应的 CLSID 映射存储在 Windows 注册表中。
- 通常位于 HKEY_CLASSES_ROOT 下。
版本控制:
- 可以包含版本信息,如 “Excel.Application.11”。
- 不带版本号的 ProgID 通常指向最新版本。
在代码中的应用:
- 在您提供的
GetActiveObject
方法中,ProgID 作为参数传入。- 方法内部将 ProgID 转换为对应的 CLSID。
优点:
- 使代码更易读和维护。
- 允许开发者使用描述性名称而不是复杂的 GUID。
示例:
- “Excel.Application” 用于 Microsoft Excel
- “Word.Application” 用于 Microsoft Word
- “Scripting.FileSystemObject” 用于文件系统操作
使用场景:
- 创建 COM 对象实例。
- 获取已运行的 COM 对象(如您代码中的情况)。
- 在脚本语言中引用 COM 对象。
代码中,
GetActiveObject
方法接受一个 ProgID 作为参数,然后内部使用CLSIDFromProgIDEx
或CLSIDFromProgID
方法将其转换为 CLSID。这展示了 ProgID 在简化 COM 编程中的重要作用,使得开发者可以使用更直观的标识符来操作 COM 对象。
尝试使用 CLSIDFromProgIDEx
方法获取 CLSID。
Try to get the CLSID using the CLSIDFromProgIDEx
method.
CLSID(Class Identifier)是一个非常重要的概念,尤其在 Windows 编程和 COM(Component Object Model)技术中。我来为您详细解释一下:
定义:
- CLSID 是 Class Identifier 的缩写。
- 它是一个 128 位的全局唯一标识符(GUID)。
用途:
- CLSID 用于唯一标识 COM 组件中的一个类。
- 它允许 Windows 和其他程序准确地识别和加载特定的 COM 对象。
格式:
- 通常表示为 32 个十六进制数字,分为 5 组,用连字符分隔。
- 例如:{00000000-0000-0000-0000-000000000000}
在系统中的存储:
- CLSID 通常存储在 Windows 注册表中。
- 路径通常是 HKEY_CLASSES_ROOT\CLSID
与 ProgID 的关系:
- ProgID(Programmatic Identifier)是一个更易读的字符串,用于表示 CLSID。
- 系统可以通过 ProgID 查找对应的 CLSID。
在代码中的应用:
- 在您提供的代码中,
CLSIDFromProgIDEx
和CLSIDFromProgID
方法就是用来将 ProgID 转换为 CLSID。- 获取 CLSID 后,可以用它来创建或获取 COM 对象的实例。
重要性:
- CLSID 确保了 COM 组件的唯一性和版本控制。
- 它允许不同版本的同一组件共存,因为每个版本可以有不同的 CLSID。
创建:
- 开发者通常使用工具(如 Visual Studio)自动生成 CLSID。
- 也可以使用专门的 GUID 生成工具创建。
代码中,
GetActiveObject
方法首先尝试通过 ProgID 获取 CLSID,然后使用这个 CLSID 来获取活动的 COM 对象。这个过程展示了 CLSID 在 COM 编程中的核心作用。
如果 CLSIDFromProgIDEx
成功,直接获取 CLSID。
If CLSIDFromProgIDEx
succeeds, directly get the CLSID.
如果 CLSIDFromProgIDEx
失败(抛出异常),则调用 CLSIDFromProgID
方法。
If CLSIDFromProgIDEx
fails (throws an exception), call the CLSIDFromProgID
method.
获取 CLSID 后,调用 COM 接口的 GetActiveObject
方法。
After getting the CLSID, call the COM interface’s GetActiveObject
method.
返回获取到的对象。
Return the obtained object.
方法执行结束。
End of method execution.
这个流程图对应了代码中的主要步骤,特别是 GetActiveObject
方法中的异常处理和备用方法调用。它展示了如何通过 progID 获取 CLSID,然后使用 CLSID 获取活动对象的过程。
public static class Marshal2
{
internal const String OLEAUT32 = "oleaut32.dll";
internal const String OLE32 = "ole32.dll";
// GetActiveObject 方法
[System.Security.SecurityCritical] // auto-generated_required
public static Object GetActiveObject(String progID)
{
Object obj = null;
Guid clsid;
// 首先尝试调用 CLSIDFromProgIDEx,如果失败则回退到 CLSIDFromProgID
// First try CLSIDFromProgIDEx, fall back to CLSIDFromProgID if it fails
try
{
CLSIDFromProgIDEx(progID, out clsid);
}
catch (Exception)
{
CLSIDFromProgID(progID, out clsid);
}
// 使用获取的 CLSID 来获取活动对象
GetActiveObject(ref clsid, IntPtr.Zero, out obj);
return obj;
}
// CLSIDFromProgIDEx 方法
[DllImport(OLE32, PreserveSig = false)]
[ResourceExposure(ResourceScope.None)]
[SuppressUnmanagedCodeSecurity]
[System.Security.SecurityCritical] // auto-generated
private static extern void CLSIDFromProgIDEx([MarshalAs(UnmanagedType.LPWStr)] String progId, out Guid clsid);
// CLSIDFromProgID 方法
[DllImport(OLE32, PreserveSig = false)]
[ResourceExposure(ResourceScope.None)]
[SuppressUnmanagedCodeSecurity]
[System.Security.SecurityCritical] // auto-generated
private static extern void CLSIDFromProgID([MarshalAs(UnmanagedType.LPWStr)] String progId, out Guid clsid);
// GetActiveObject 方法(COM 接口调用)
[DllImport(OLEAUT32, PreserveSig = false)]
[ResourceExposure(ResourceScope.None)]
[SuppressUnmanagedCodeSecurity]
[System.Security.SecurityCritical] // auto-generated
private static extern void GetActiveObject(ref Guid rclsid, IntPtr reserved, [MarshalAs(UnmanagedType.Interface)] out Object ppunk);
}
现在让我们详细解释每个方法:
GetActiveObject(String progID)
方法:
progID
是程序标识符,用于标识特定的 COM 类。CLSIDFromProgIDEx
获取 CLSID。CLSIDFromProgIDEx
不存在),则回退到使用 CLSIDFromProgID
。GetActiveObject
方法获取活动对象。这个方法展示了如何通过 ProgID 获取正在运行的 COM 对象,这在与已打开的应用程序(如 Excel、Word 等)交互时非常有用。
This method demonstrates how to obtain a reference to a running COM object using its ProgID, which is particularly useful when interacting with already open applications like Excel or Word.
CLSIDFromProgIDEx
方法:
[DllImport(OLE32, PreserveSig = false)]
表示这是一个从 OLE32.dll 导入的函数。[MarshalAs(UnmanagedType.LPWStr)]
指定 progId
参数应被封送为宽字符字符串。CLSIDFromProgID
方法:
CLSIDFromProgIDEx
,但用于较旧的系统或不支持 Ex 版本的情况。CLSIDFromProgIDEx
失败时使用。GetActiveObject
方法(COM 接口调用):
GetActiveObject
函数的 P/Invoke 调用。ref Guid rclsid
参数传递 CLSID。IntPtr reserved
保留参数,通常设为 IntPtr.Zero。[MarshalAs(UnmanagedType.Interface)] out Object ppunk
用于接收返回的 COM 对象接口。这些方法共同工作,实现了通过 ProgID 获取正在运行的 COM 对象的功能。这在与 Office 应用程序或其他 COM 对象交互时非常有用,允许程序连接到已经运行的实例,而不是创建新实例。
代码中使用了多个特性(Attributes)来确保安全性和正确的内存管理:
[System.Security.SecurityCritical]
表示这些方法需要完全信任。[SuppressUnmanagedCodeSecurity]
用于提高性能,但可能会降低安全性。[ResourceExposure(ResourceScope.None)]
指示这些方法不暴露任何资源。这段代码展示了如何安全地与底层 Windows API 交互,同时提供了一个高级抽象,使得在 .NET 环境中更容易使用 COM 对象。
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.InteropServices;
using System.Runtime.Versioning;
using System.Security;
using System.Text;
using System.Threading.Tasks;
namespace Bumblebee
{
// Marshal2 类用于处理 COM 对象的封送处理
public static class Marshal2
{
// 定义常量,指定需要调用的 DLL 文件名
internal const String OLEAUT32 = "oleaut32.dll";
internal const String OLE32 = "ole32.dll";
///
/// 获取已经运行的 COM 对象的引用
///
/// COM 对象的程序标识符
/// 返回 COM 对象的引用
[System.Security.SecurityCritical] // 表示此方法需要完全信任
public static Object GetActiveObject(String progID)
{
Object obj = null;
Guid clsid;
// 首先尝试使用 CLSIDFromProgIDEx 方法获取 CLSID
// 如果 CLSIDFromProgIDEx 不存在,则回退到使用 CLSIDFromProgID
try
{
CLSIDFromProgIDEx(progID, out clsid);
}
catch (Exception)
{
// 如果 CLSIDFromProgIDEx 失败,使用 CLSIDFromProgID
CLSIDFromProgID(progID, out clsid);
}
// 使用获取到的 CLSID 来获取活动对象
GetActiveObject(ref clsid, IntPtr.Zero, out obj);
return obj;
}
///
/// 将 ProgID 转换为 CLSID(扩展版本)
///
[DllImport(OLE32, PreserveSig = false)]
[ResourceExposure(ResourceScope.None)]
[SuppressUnmanagedCodeSecurity]
[System.Security.SecurityCritical] // 自动生成的安全关键代码
private static extern void CLSIDFromProgIDEx(
[MarshalAs(UnmanagedType.LPWStr)] String progId,
out Guid clsid
);
///
/// 将 ProgID 转换为 CLSID(标准版本)
///
[DllImport(OLE32, PreserveSig = false)]
[ResourceExposure(ResourceScope.None)]
[SuppressUnmanagedCodeSecurity]
[System.Security.SecurityCritical] // 自动生成的安全关键代码
private static extern void CLSIDFromProgID(
[MarshalAs(UnmanagedType.LPWStr)] String progId,
out Guid clsid
);
///
/// 获取活动对象的 COM 接口
///
[DllImport(OLEAUT32, PreserveSig = false)]
[ResourceExposure(ResourceScope.None)]
[SuppressUnmanagedCodeSecurity]
[System.Security.SecurityCritical] // 自动生成的安全关键代码
private static extern void GetActiveObject(
ref Guid rclsid,
IntPtr reserved,
[MarshalAs(UnmanagedType.Interface)] out Object ppunk
);
}
}
这段代码的主要功能和特点:
命名空间和类:
Bumblebee
命名空间中。Marshal2
是一个静态类,用于处理 COM 对象的封送处理。常量定义:
OLEAUT32
和 OLE32
定义了需要调用的 DLL 文件名。GetActiveObject 方法:
CLSIDFromProgIDEx
,如果失败则回退到 CLSIDFromProgID
。GetActiveObject
方法获取对象引用。CLSIDFromProgIDEx 和 CLSIDFromProgID 方法:
CLSIDFromProgIDEx
是更新的版本,支持更多功能。GetActiveObject 方法(COM 接口调用):
GetActiveObject
函数的 P/Invoke 调用。特性(Attributes)使用:
[DllImport]
:指定要导入的 DLL 和函数。[ResourceExposure]
:指示资源暴露范围。[SuppressUnmanagedCodeSecurity]
:抑制对非托管代码的安全检查,提高性能。[System.Security.SecurityCritical]
:表示这些方法需要完全信任。这段代码展示了如何在 .NET 环境中安全地与 COM 对象交互,特别是如何获取已经运行的 COM 对象的引用。这在与 Office 应用程序或其他 COM 对象交互时非常有用,允许程序连接到已经运行的实例,而不是创建新实例。