在C#中定义Windows API接口时,是否必须定义所有成员?我只能定义方法I';我要用什么?

在C#中定义Windows API接口时,是否必须定义所有成员?我只能定义方法I';我要用什么?,c#,winapi,interface,C#,Winapi,Interface,例如,这是界面的完整定义,一个Windows Shell界面,取自网站: 如果我只打算从这个接口使用两种方法,我可以这样定义它: [ComImport, Guid ( "d57c7288-d4ad-4768-be02-9d969532d960" ), InterfaceType ( ComInterfaceType.InterfaceIsIUnknown )] interface IFileOpenDialog : IFileDialog { // Defined on IModalWindow

例如,这是界面的完整定义,一个Windows Shell界面,取自网站:

如果我只打算从这个接口使用两种方法,我可以这样定义它:

[ComImport, Guid ( "d57c7288-d4ad-4768-be02-9d969532d960" ), InterfaceType ( ComInterfaceType.InterfaceIsIUnknown )]
interface IFileOpenDialog : IFileDialog
{
// Defined on IModalWindow - repeated here due to requirements of COM interop layer
// --------------------------------------------------------------------------------
[MethodImpl ( MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime ), PreserveSig]
int Show ( [In] IntPtr parent );

[MethodImpl ( MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime )]
void SetOptions ( [In] FOS fos );
}

它会起作用吗?还是必须用所有方法定义完整接口?

如果要定义实现接口的类型,则必须实现接口的所有元素。如果您不这样做,那么最好的情况是您将从代码中获得“不稳定”的行为,最坏的情况是您的应用程序将在您尝试对接口的实现执行任何操作时崩溃

请记住,这两个接口并不相同:

[ComImport, Guid ( "d57c7288-d4ad-4768-be02-9d969532d960" ), InterfaceType ( ComInterfaceType.InterfaceIsIUnknown )]
interface IFileOpenDialog : IFileDialog
{
    [MethodImpl ( MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime ), PreserveSig]
    int Show ( [In] IntPtr parent );
}

[ComImport, Guid ( "d57c7288-d4ad-4768-be02-9d969532d960" ), InterfaceType ( ComInterfaceType.InterfaceIsIUnknown )]
interface IFileOpenDialog : IFileDialog
{
    [MethodImpl ( MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime ), PreserveSig]
    int Show ( [In] IntPtr parent );

    [MethodImpl ( MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime )]
    void SetOptions ( [In] FOS fos );
}
尽管它们具有相同的名称、相同的Guid并且都实现了
Show
,但只有一个实现了
SetOptions
,这一事实使它们有所不同


无论如何,从您未实现的接口的任何方法中抛出一个
NotImplemented
异常,但要说您*实现接口
ISomeInterface
,实际上您必须这样做。
不,这不起作用。CLR基于声明为COM接口构建一个分派表。该表中函数指针的顺序由声明中方法定义的顺序设置。Show()方法在这两种情况下都会占用第一个插槽,没有问题。然而,SetOptions()最终将调用第二个,实际上是SetFileTypes()。它们有不同的参数,当实现获得垃圾参数并且堆栈变得不平衡时,它们将以一种令人讨厌的方式被破坏

您可以省略尾部的任何声明。还要注意,当您不调用该方法时,该方法的实际声明并不重要。这允许你撒谎,避免声明他们的参数类型。请确保该方法显然不起作用,将其命名为void DontCallMe2()


请注意,这些接口已经包装在Windows API代码包以及.NET 4.0版本的Microsoft.Win32.OpenFileDialog和.NET 3.5版本的System.Windows.Forms.OpenFileDialog中,这正是我的代码中发生的情况:如果我只调用Show方法,它会工作,如果我尝试调用SetOptions,我会遇到一个异常:“试图读取或写入受保护的内存。这通常表示其他内存已损坏。“就是这样?没有办法作弊吗?我必须定义SetOptions之前的所有方法吗?其中一些可能需要额外的WinAPI类型定义,因此代码将快速增长…请注意,我编辑我的帖子是为了指出这些内容已经为您完成了。是的,谢谢,但是我正在尝试在.NET 2.0中工作,因为我认为它有更大的安装用户群(即使在Vista上也必须安装3.5,而在Windows 7上也必须安装4.0)。我认为更多的XP机器使用.NET 2.0而不是3.5或4.0。因此,如果我使用.NET 2.0,该程序将直接运行在Windows 7、Windows Vista和许多已经使用.NET 2.0的XP机器上。NET版本与Windows版本无关,在XP上安装4.0不是问题。请权衡维护此代码的成本和简单的升级日期是只有你才能做的事情。不,它没有属性。你可以用一个伪方法填充插槽,当你不调用它时,它不必是准确的。这样可以避免声明它们的参数类型,我想这才是你真正想要的。一定要为它们使用一个名称,使它明显是一个伪方法,比如“DontCallMe2()”。是的,如果我只调用Show方法,它就会工作。如果我尝试调用SetOptions,我会得到一个异常:“试图读取或写入受保护的内存。这通常表示其他内存已损坏。”这实际上不是真的。调用Show()具有任一声明的方法都可以正常工作。COM接口由其Guid标识,而不是由其声明类型标识。这使.NET 4.0类型等效功能成为可能,通过程序集引用的新“嵌入互操作类型”属性可见。
[ComImport, Guid ( "d57c7288-d4ad-4768-be02-9d969532d960" ), InterfaceType ( ComInterfaceType.InterfaceIsIUnknown )]
interface IFileOpenDialog : IFileDialog
{
    [MethodImpl ( MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime ), PreserveSig]
    int Show ( [In] IntPtr parent );
}

[ComImport, Guid ( "d57c7288-d4ad-4768-be02-9d969532d960" ), InterfaceType ( ComInterfaceType.InterfaceIsIUnknown )]
interface IFileOpenDialog : IFileDialog
{
    [MethodImpl ( MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime ), PreserveSig]
    int Show ( [In] IntPtr parent );

    [MethodImpl ( MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime )]
    void SetOptions ( [In] FOS fos );
}