如何在C#中通过CLSID实例化COM对象?

6

如果我的术语不正确,请原谅,因为对我来说这是一片相对未知的领域。

我有一个需要创建FolderShortcut的程序。 Microsoft提供了文档,说明如何在C++中创建它,我正在尝试将指示翻译成C#。指令声明需要使用CLSID_FolderShortcut作为参数调用CoCreateInstance函数,我推断这意味着它实例化了一个COM对象。此对象的CLSID是{0AFACED1-E828-11D1-9187-B532F1E9575D}

我尝试从COM选项卡添加对Shell32.dll的引用,但FolderShortcut对象没有出现在Intellisense中(也许它不在类型库中?)。我还考虑过使用DLLImport,但是,当然,这只给我提供了访问函数而不是对象的权限。

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


1
问题“在 .Net 中为 64 位机器创建快捷方式 - 只编译为 64 位应用程序”与 FolderShortcut 类无关。FolderShortcut 类与 ShellLinkObject 类不同,编译器无法直接访问它。 - bshacklett
你应该将问题标题更改为类似“如何创建文件夹快捷方式”的内容,以我的看法。 - Simon Mourier
4个回答

12
如果您不想在编译时导入类,如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的成员。

您可以继续阅读以获取更多信息。


用于COM互操作的对象不一定要实现IDispatch(又称“自动化”)。IUnknown就足够了。 - Simon Mourier
1
COM对象需要公开IDispatch以启用脚本自动化。如果您没有代理接口的Interop类型(如IPersistFile),并且想要使用Activator进行后期绑定COM类型,则对象需要实现IDispatch以使用(例如)Type.InvokeMember进行调用。 - Carsten
好的,但这不是主题,你的陈述“对象应该实现IDispatch接口”在这个上下文中仍然是错误的。没有人在谈论自动化。 - Simon Mourier
我已经更新了答案...希望这能让事情变得更清晰一些 :) - Carsten

7
这里有一段代码,可以让你创建一个文件夹快捷方式。通常情况下,CoCreateInstance可以被用简单的类来替代,该类需要使用Guid属性声明必需的CLSID以及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 比调用另一个重载的方法来缩短代码更为简洁。 - kwyntes

1

你是否尝试添加新的引用:

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

0

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

  1. 首先,我会确保你的COM DLL已经在你的电脑上注册。如果没有,那么请先注册,然后再尝试使用COM选项卡进行添加。

  2. 你是否在64位机器上运行?也要确保你的项目属性设置为AnyCPU,以便它能够读取32位的COM。

  3. 确保你有与你要访问的DLL相对应的interop文件。它通常被命名为“Interop.YourDLLName.dll”。添加对该DLL的引用即可。


我已验证DLL已注册。我正在运行64位机器;项目设置为目标AnyCPU。Interop.Shell32.dll文件已创建,引用存在。我可以看到Shell32.dll中定义的一些类和函数,但不是我要找的。 - bshacklett

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接