【问题标题】:How do I go about instantiating a COM Object in C# by CLSID?如何通过 CLSID 在 C# 中实例化 COM 对象?
【发布时间】:2013-03-14 19:03:00
【问题描述】:

如果我的术语有问题,请原谅我,因为这对我来说有点未知。

我有一个程序需要创建一个FolderShortcutMicrosoft has documentation 关于如何在 C++ 中创建它,我正在尝试将方向转换为 C#。指令指出CoCreateInstance 函数需要以CLSID_FolderShortcut 作为参数调用,我推断这意味着它正在实例化一个COM 对象。此对象的 CLSID 是 {0AFACED1-E828-11D1-9187-B532F1E9575D}

我尝试从 COM 选项卡添加对 Shell32.dll 的引用,但 FolderShortcut 对象没有出现在 Intellisense 中(可能它不在类型库中?)。我也想过做一个DLLImport,但是,当然,这只能让我访问函数,而不是对象。

我需要做什么才能在 .Net 中访问此对象?

【问题讨论】:

标签: c# com pinvoke shell32


【解决方案1】:

如果您不想在编译期间导入类,如 Simon Mourier 所述,也可以使用Activator 对 COM 对象进行一些后期绑定。

如果你有你的对象的ProgID,获取类型使用

Type comType = Type.GetTypeFromProgID("MyProg.ProgId");

否则你可以通过CLSID获取类型:

Type comType = 
    Type.GetTypeFromCLSID(new Guid("0AFACED1-E828-11D1-9187-B532F1E9575D"));

使用此类型,您现在可以使用 Activator.CreateInstance 创建 coclass 的实例:

var instance = Activator.CreateInstance(comType);

基本上,您现在可以使用Type.InvokeMember 调用方法。这仅在对象实现 IDispatch 接口时才有效。

但是,对于您的具体示例,您应该能够将实例转换为 System.Runtime.InteropServices.ComTypes.IPersistFile,这会导致对 COM 对象的 QueryInterface 调用。使用这个界面可以很方便的访问IPersistFile的成员。

您可以继续阅读here

【讨论】:

  • 用于 COM 互操作的对象必须实现 IDispatch(又名“自动化”)。 IUnknown 就够了。
  • COM 对象需要公开IDispatch 以启用脚本自动化。如果您没有代理接口的互操作类型(如IPersistFile)并且您想要后期绑定COM类型(使用Activator),则对象需要实现IDispatch才能使用(即)Type.InvokeMember调用.
  • 好吧,但这不是主题,您的“对象应该实现 IDispatch 接口”的说法在上下文中仍然是错误的。没有人在这里谈论自动化。
  • 我已经更新了答案...希望这会让事情变得更清楚:)
【解决方案2】:

这是一段代码,可让您创建文件夹快捷方式。 CoCreateInstance 可以(通常)通过声明一个简单的类来替换,该类装饰有具有所需 CLSID 的 Guid 属性和 ComImport 属性。 new 调用将自动执行 COM 魔术。使用此代码,您甚至不需要 Shell32 引用(如果您愿意,也可以从那里重用 IShellLink 声明)。

用法:

static void Main(string[] args)
{
    CreateFolderShortcut(@"c:\temp", Path.GetFullPath("Shortcut to Temp"));
}

代码:

public static void CreateFolderShortcut(string path, string shortcutPath)
{
    CreateFolderShortcut(path, shortcutPath, null);
}

public static void CreateFolderShortcut(string path, string shortcutPath, string comment)
{
    if (path == null)
        throw new ArgumentNullException("path");

    IShellLink link = (IShellLink)new ShellLinkFolder();

    if (comment != null)
    {
        link.SetDescription(comment);
    }
    link.SetPath(path);

    IPersistFile file = (IPersistFile)link;
    file.Save(shortcutPath, false);
}

[ComImport]
[Guid("00021401-0000-0000-C000-000000000046")]
private class ShellLink
{
}

[ComImport]
[Guid("0AFACED1-E828-11D1-9187-B532F1E9575D")]
private class ShellLinkFolder
{
}

[ComImport]
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
[Guid("000214F9-0000-0000-C000-000000000046")]
private interface IShellLink
{
    void GetPath([Out, MarshalAs(UnmanagedType.LPWStr)] StringBuilder pszFile, int cchMaxPath, out IntPtr pfd, int fFlags);
    void GetIDList(out IntPtr ppidl);
    void SetIDList(IntPtr pidl);
    void GetDescription([Out, MarshalAs(UnmanagedType.LPWStr)] StringBuilder pszName, int cchMaxName);
    void SetDescription([MarshalAs(UnmanagedType.LPWStr)] string pszName);
    void GetWorkingDirectory([Out, MarshalAs(UnmanagedType.LPWStr)] StringBuilder pszDir, int cchMaxPath);
    void SetWorkingDirectory([MarshalAs(UnmanagedType.LPWStr)] string pszDir);
    void GetArguments([Out, MarshalAs(UnmanagedType.LPWStr)] StringBuilder pszArgs, int cchMaxPath);
    void SetArguments([MarshalAs(UnmanagedType.LPWStr)] string pszArgs);
    void GetHotkey(out short pwHotkey);
    void SetHotkey(short wHotkey);
    void GetShowCmd(out int piShowCmd);
    void SetShowCmd(int iShowCmd);
    void GetIconLocation([Out, MarshalAs(UnmanagedType.LPWStr)] StringBuilder pszIconPath, int cchIconPath, out int piIcon);
    void SetIconLocation([MarshalAs(UnmanagedType.LPWStr)] string pszIconPath, int iIcon);
    void SetRelativePath([MarshalAs(UnmanagedType.LPWStr)] string pszPathRel, int dwReserved);
    void Resolve(IntPtr hwnd, int fFlags);
    void SetPath([MarshalAs(UnmanagedType.LPWStr)] string pszFile);
}

【讨论】:

  • 使用... string shortcutPath, string comment = null而不是调用另一个自身重载的重载方法会更短
【解决方案3】:

您是否尝试添加新参考:

  1. 打开解决方案资源管理器
  2. 扩展 C# 项目
  3. 右键单击引用节点并添加新的 COM 引用

【讨论】:

    【解决方案4】:

    听起来您已经尝试使用“添加新的 COM 引用”添加您的 COM。 这些是我会尝试的事情:

    1. 我首先要做的是确保您的 COM DLL 已在您的计算机中注册。如果没有,则注册它,然后尝试使用 COM 选项卡再次添加它。

    2. 您是否在 64 位计算机上运行?还要尝试确保您的项目属性设置为 AnyCPU,以便它能够读取 32 位 COM。

    3. 确保您拥有与您尝试访问的 DLL 等效的互操作。它通常被命名为“Interop.YourDLLName.dll”。添加对该 DLL 的引用,这应该可以工作。

    【讨论】:

    • 我验证了 DLL 已注册。我在 64 位机器上运行;该项目设置为以 AnyCPU 为目标。 Interop.Shell32.dll 文件已创建,并且引用存在。我可以看到 Shell32.dll 中定义的一些类和函数,但不是我要查找的。​​span>
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-11-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-05-07
    相关资源
    最近更新 更多