如何将使用Shell COM的C#代码转换为F#? [英] How to convert C# code that uses Shell COM to F#?

查看:235
本文介绍了如何将使用Shell COM的C#代码转换为F#?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有以下C#方法:

  private static bool IsLink(string shortcutFilename)
{
var pathOnly = Path.GetDirectoryName(shortcutFilename);
var filenameOnly = Path.GetFileName(shortcutFilename);

var shell = new Shell32.Shell();
var folder = shell.NameSpace(pathOnly);
var folderItem = folder.ParseName(filenameOnly);
return folderItem!= null&& folderItem.IsLink;
}

我已尝试将此转换为F#:



let private isLink filename =
let pathOnly = Path.GetDirectoryName(filename)
let filenameOnly = Path.GetFileName(filename)
let shell = new Shell32.Shell()
let folder = shell.NameSpace(pathOnly)
let folderItem = folder.ParseName(filenameOnly)
folderItem< null&& folderItem.IsLink

但它报告了的错误let shell = new Shell32 .Shell()行,说不能在接口类型上使用。



解决方案

我只是做了一个愚蠢的句法错误,或者有额外的工作需要从F# t知道足够的F#编译器,但你的意见使它足够明显。 C#和VB.NET编译器对COM内置程序有大量的显式支持。请注意,您的语句在接口类型上使用 new 运算符,互操作库中的Shell32.Shell如下所示:

  [ComImport] 
[Guid(286E6F1B-7113-4355-9562-96B7E9D64C54)]
[CoClass(typeof(ShellClass))]
public interface Shell:IShellDispatch6 {}

IShellDispatch6是真正的接口类型,你也可以看到IShellDispatch通过IShellDispatch5接口。这是在过去20年的工作版本,COM接口定义是不可变的,因为更改它们几乎总是导致在运行时不可分辨的硬崩溃。



[CoClass]属性是这是C#编译器寻找您在[ComImport]接口类型上使用 new 的重要一个。通过创建 Shell32.ShellClass 实例并获取Shell接口来创建对象。



ShellClass 是一个假的类,它是由类型库导入器自动生成的。 COM从不暴露具体类,它使用基于超纯接口的编程范例。对象始终由对象工厂创建, CoCreateInstance() 是主力。它本身就是一个方便的功能,真正的工作是由通用的 IClassFactory接口,超纯样式。每个COM coclass实现它的CreateInstance()方法。



类型库导入器使ShellClass看起来像这样:

  [ComImport] 
[TypeLibType(TypeLibTypeFlags.FCanCreate)]
[ClassInterface(ClassInterfaceType.None)]
[Guid(13709620-C279-11CE- A49E-444553540000)]
public class ShellClass:IShellDispatch6,Shell {
//方法
[MethodImpl(MethodImplOptions.InternalCall,MethodCodeType = MethodCodeType.Runtime),DispId(0x60040000)]
public virtual extern void AddToRecent([In,MarshalAs(UnmanagedType.Struct)] object varFile,[In,Optional,MarshalAs(UnmanagedType.BStr)] string bstrCategory);
// Etc,更多方法...
}

火和运动,它不应该被使用。只有属性才提供CoCreateInstance()需要的CLSID,才是真正重要的。它还需要IID,接口的[Guid]由接口声明提供。



所以在F#中的解决方法是创建Shell32.ShellClass对象,只是像C#编译器隐式。虽然技术上你可以保持引用在一个ShellClass变量,你应该强烈赞成接口类型。 COM的方式,纯粹的方式,它避免这种问题。最终,它是完成工作的CLR,它在其 new 运算符实现中识别ShellClass类声明的[ClassInterface]属性。在.NET中更明确的方法是使用Type.GetTypeFromCLSID()和Activator.CreateInstance(),当你只有coclass的Guid。


I have the following C# method:

private static bool IsLink(string shortcutFilename)
{
    var pathOnly = Path.GetDirectoryName(shortcutFilename);
    var filenameOnly = Path.GetFileName(shortcutFilename);

    var shell = new Shell32.Shell();
    var folder = shell.NameSpace(pathOnly);
    var folderItem = folder.ParseName(filenameOnly);
    return folderItem != null && folderItem.IsLink;
}

I have tried converting this to F# as:

let private isLink filename =
    let pathOnly = Path.GetDirectoryName(filename)
    let filenameOnly = Path.GetFileName(filename)
    let shell = new Shell32.Shell()
    let folder = shell.NameSpace(pathOnly)
    let folderItem = folder.ParseName(filenameOnly)
    folderItem <> null && folderItem.IsLink

It however reports an error for the let shell = new Shell32.Shell() line, saying that new cannot be used on interface types.

Have I just made a silly syntactic mistake, or is there extra work needed to access COM from F#?

解决方案

I don't know enough about the F# compiler but your comments makes it obvious enough. The C# and VB.NET compilers have a fair amount of explicit support for COM built-in. Note that your statement uses the new operator on an interface type, Shell32.Shell in the interop library looks like this:

[ComImport]
[Guid("286E6F1B-7113-4355-9562-96B7E9D64C54")]
[CoClass(typeof(ShellClass))]
public interface Shell : IShellDispatch6 {}

IShellDispatch6 is the real interface type, you can also see the IShellDispatch through IShellDispatch5 interfaces. That's versioning across the past 20 years at work, COM interface definitions are immutable since changing them almost always causes an undiagnosable hard crash at runtime.

The [CoClass] attribute is the important one for this story, that's what the C# compiler goes looking for you use new on a [ComImport] interface type. Tells it to create the object by creating an instance of Shell32.ShellClass instance and obtain the Shell interface. What the F# compiler doesn't do.

ShellClass is a fake class, it is auto-generated by the type library importer. COM never exposes concrete classes, it uses a hyper-pure interface-based programming paradigm. Objects are always created by an object factory, CoCreateInstance() is the workhorse for that. Itself a convenience function, the real work is done by the universal IClassFactory interface, hyper-pure style. Every COM coclass implements its CreateInstance() method.

The type library importer makes ShellClass look like this:

[ComImport]
[TypeLibType(TypeLibTypeFlags.FCanCreate)]
[ClassInterface(ClassInterfaceType.None)]
[Guid("13709620-C279-11CE-A49E-444553540000")]
public class ShellClass : IShellDispatch6, Shell {
    // Methods
    [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType=MethodCodeType.Runtime), DispId(0x60040000)]
    public virtual extern void AddToRecent([In, MarshalAs(UnmanagedType.Struct)] object varFile, [In, Optional, MarshalAs(UnmanagedType.BStr)] string bstrCategory);
    // Etc, many more methods...
}

Lots of fire and movement, none of it should ever be used. The only thing that really matters is the [Guid] attribute, that provides the CLSID that CoCreateInstance() needs. It also needs the IID, the [Guid] of the interface, provided by the interface declaration.

So the workaround in F# is to create the Shell32.ShellClass object, just like the C# compiler does implicitly. While technically you can keep the reference in a ShellClass variable, you should strongly favor the interface type instead. The COM way, the pure way, it avoids this kind of problem. Ultimately it is the CLR that gets the job done, it recognizes the [ClassInterface] attribute on the ShellClass class declaration in its new operator implementation. The more explicit way in .NET is to use Type.GetTypeFromCLSID() and Activator.CreateInstance(), handy when you only have the Guid of the coclass.

这篇关于如何将使用Shell COM的C#代码转换为F#?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆