在COM对象上使用早期绑定

4
我有一段代码,它运行良好并给出用户开始菜单的路径:
    Dim oShell As Object = CreateObject("Shell.Application")
    MsgBox(oShell.NameSpace(11).Self.Path)

显然,这里使用了后期绑定。现在假设我想在C#或VB.NET严格模式下执行此操作,但两种语言都不支持使用后期绑定的这种语法。

是否有可能实现?如何实现?

谢谢你的帮助!

4个回答

5

如果你想用COM方式解决这个问题,你需要弄清楚在VB项目中添加哪个COM引用。

打开注册表编辑器,导航到 HKEY_CLASSES_ROOT\<class id>\CLSID,例如:

HKEY_CLASSES_ROOT\Shell.Application\CLSID

你可以找到唯一标识COM组件的类别ID。

HKEY_CLASSES_ROOT\CLSID 下面,现在可以查找COM组件背后的文件:

HKEY_CLASSES_ROOT\CLSID\{13709620-C279-11CE-A49E-444553540000}\InProcServer32

显示以下值:
%SystemRoot%\system32\SHELL32.dll

现在打开Visual Studio,在“添加引用”对话框的“浏览”选项卡中添加对此文件的引用。如果您打开项目属性,您实际上会看到添加的COM组件的漂亮名称是“Microsoft Shell Controls and Automation”。
一旦添加了引用,您可以按以下方式使用“Shell.Application”对象:
Option Strict On

Module PrintStartMenuLocation

    Sub Main()
        Dim shell As New Shell32.Shell
        Dim folder As Shell32.Folder
        Dim folderItem As Shell32.FolderItem
        Dim startMenuPath As String

        folder = shell.NameSpace(Shell32.ShellSpecialFolderConstants.ssfSTARTMENU)
        folderItem = CType(folder.Items(0), Shell32.FolderItem)
        startMenuPath = folderItem.Path

        Console.WriteLine(startMenuPath)
    End Sub

End Module

一份C#版本的代码如下所示:
class Program
{
    static void Main(string[] args)
    {
        Shell32.Shell shell = new Shell32.Shell();
        Shell32.Folder folder = shell.NameSpace(Shell32.ShellSpecialFolderConstants.ssfSTARTMENU);
        Shell32.FolderItem folderItem = folder.Items().Item(0) as Shell32.FolderItem;
        string startMenuPath = folderItem.Path;

        Console.WriteLine(startMenuPath);
    }
}

然而,如果您只需要检索“开始菜单”文件夹的位置,则可以直接在.NET中执行相同的操作。

Dim path As String = System.Environment.GetFolderPath(Environment.SpecialFolder.StartMenu)

3

实际上,您可以使用反射:

Type shellType = Type.GetTypeFromProgID("Shell.Application", true);
object shell = Activator.CreateInstance(shellType);
object folder = shellType.InvokeMember("NameSpace", BindingFlags.InvokeMethod, null, shell, new object[] { 11 });
object self = folder.GetType().InvokeMember("Self", BindingFlags.GetProperty, null, folder, new object[] { });
object path = self.GetType().InvokeMember("Path", BindingFlags.GetProperty, null, self, new object[] { });
Console.WriteLine(path);

虽然我不太喜欢这种代码,但在C# 4.0中,您可以使用动态类型来清理这个混乱的代码。


据我理解,这个问题的 OP 想要使用早期绑定。 - Dirk Vollmar

2
Dim DirPath As String = _
    System.Environment.GetFolderPath(Environment.SpecialFolder.StartMenu)

点击此处了解更多信息。


0

如果我记得正确,你所要做的就是将对象引用强制转换为相应的接口。如果你在 .NET 中使用 COM 对象,通常会导入类型库,然后接口就可以随时使用了。


但是我不知道那个接口会是什么,实际上我甚至不确定返回的接口一定总是相同的... - Laurent
如果你对接口不确定,那么早期绑定并不适合你。这就是早期绑定的意义所在——编译器必须知道它是什么接口,并且可以检查参数的有效性和生成调用。否则,你必须使用晚期绑定。 - sharptooth
我理解这一点,但假设我正在使用C#编程,我就不能使用晚期绑定。在C#中完成这个任务的唯一方法是找出接口名称吗? - Laurent
这个问题似乎与以下内容相关:https://dev59.com/SHRB5IYBdhLWcg3w3K8J - sharptooth
你可以使用反射在C#中进行后期绑定(但是这可能会有些痛苦)。 - Dirk Vollmar
显示剩余2条评论

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