如何从托管代码中使用win32'IOpenControlPanel'接口?

问题描述 投票:0回答:1

我正在尝试实现IOpenControlPanel接口,这在pinvoke.net这样的站点中没有记录,所以对于这个任务我从头开始构建定义,因为我认为它们应该是,然后我尝试从注册表中手动检索接口CLSID,这似乎成为D11AD862-66DE-4DF4-BF6C-1F5621996AF1,以及实现该表面的类,似乎是06622D85-6856-4460-8DE1-A81921B41C4B

问题是,在下面的代码中,如果我调用GetCurrentView函数,我没有得到预期的值,并且调用Open函数什么都不做(我正在使用Microsoft.DefaultPrograms中的this MSDN article中解释的this list of canonical names等正确的规范名称。)

Dim cp As New COpenControlPanel
Dim view As ControlPanelView
DirectCast(cp, IOpenControlPanel).GetCurrentView(view)
DirectCast(cp, IOpenControlPanel).Open("Microsoft.DefaultPrograms", "", Nothing)

所以,我认为我的定义在某种程度上是错误的,我需要帮助来解决它。


这些是定义:

VB.net:

Friend NotInheritable Class NativeMethods

    Enum ControlPanelView As Integer
        Classic = 0
        Category = 1
    End Enum

    <ComImport()>
    <Guid("06622D85-6856-4460-8DE1-A81921B41C4B")>
    Class COpenControlPanel
    End Class

    <ComImport>
    <InterfaceType(ComInterfaceType.InterfaceIsIUnknown)>
    <Guid("D11AD862-66DE-4DF4-BF6C-1F5621996AF1")>
    Public Interface IOpenControlPanel

        <PreserveSig()>
        Function Open(<MarshalAs(UnmanagedType.BStr)> ByVal name As String,
                      <MarshalAs(UnmanagedType.BStr)> ByVal page As String,
                                                      ByVal punkSite As IntPtr
        ) As Integer ' HResult

        <PreserveSig()>
        Function GetPath(<MarshalAs(UnmanagedType.BStr)> ByVal name As String,
                       <MarshalAs(UnmanagedType.LPWStr)> ByVal path As StringBuilder,
                                                         ByVal bufferSize As Integer
        ) As Integer ' HResult

        <PreserveSig()>
        Function GetCurrentView(ByRef refView As ControlPanelView
        ) As Integer ' HResult

    End Interface

End Class

C#(在线翻译):

internal sealed class NativeMethods {

    public enum ControlPanelView : int {
        Classic = 0,
        Category = 1
    }

    [ComImport()]
    [Guid("06622D85-6856-4460-8DE1-A81921B41C4B")]
    class COpenControlPanel {}

    [ComImport]
    [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
    [Guid("D11AD862-66DE-4DF4-BF6C-1F5621996AF1")]
    public interface IOpenControlPanel
    {

        [PreserveSig()]
        int Open([MarshalAs(UnmanagedType.BStr)] string name, 
                 [MarshalAs(UnmanagedType.BStr)] string page, 
                 IntPtr punkSite);

        [PreserveSig()]
        int GetPath([MarshalAs(UnmanagedType.BStr)] string name, 
                    [MarshalAs(UnmanagedType.LPWStr)] StringBuilder path, 
                    int bufferSize);

        [PreserveSig()]
        int GetCurrentView(ref ControlPanelView refView);

    }
}
c# .net vb.net winapi pinvoke
1个回答
4
投票

您的接口定义是错误的,因为您没有按照与MSDN相同的顺序定义方法(事实上,名称并不重要,接口方法布局的重要性是:以正确的顺序匹配二进制签名)。订单必须与Windows SDK提供的.h文件中的定义完全相同,而不是MSDN显示的内容 - 这实际上是误导性的:-)。在这种情况下,头文件是Shobjidl.h。这是它在C / C ++中的定义:

MIDL_INTERFACE("D11AD862-66DE-4DF4-BF6C-1F5621996AF1")
IOpenControlPanel : public IUnknown
{
public:
    virtual HRESULT STDMETHODCALLTYPE Open( 
        /* [string][unique][in] */ __RPC__in_opt_string LPCWSTR pszName,
        /* [string][unique][in] */ __RPC__in_opt_string LPCWSTR pszPage,
        /* [unique][in] */ __RPC__in_opt IUnknown *punkSite) = 0;

    virtual HRESULT STDMETHODCALLTYPE GetPath( 
        /* [string][unique][in] */ __RPC__in_opt_string LPCWSTR pszName,
        /* [size_is][string][out] */ __RPC__out_ecount_full_string(cchPath) LPWSTR pszPath,
        /* [in] */ UINT cchPath) = 0;

    virtual HRESULT STDMETHODCALLTYPE GetCurrentView( 
        /* [out] */ __RPC__out CPVIEW *pView) = 0;

};

.NET,C#中有多个等价定义,但这里应该有一个:

    [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
    [Guid("D11AD862-66DE-4DF4-BF6C-1F5621996AF1")]
    public interface IOpenControlPanel
    {
        [PreserveSig]
        int Open([MarshalAs(UnmanagedType.LPWStr)] string name,
                 [MarshalAs(UnmanagedType.LPWStr)] string page,
                                                   IntPtr punkSite);
        [PreserveSig]
        int GetPath([MarshalAs(UnmanagedType.LPWStr)] string name,
                    [MarshalAs(UnmanagedType.LPWStr)] StringBuilder refPath,
                                                      int bufferSize);

        // if you remove PreserveSig, you can return the [out] param directly
        // note in this case, the function could throw instead of returning an error int like with PreserveSig
        ControlPanelView GetCurrentView();
    }
© www.soinside.com 2019 - 2024. All rights reserved.