简体   繁体   English

COM互操作和指向C#中的接口的指针的封送处理

[英]COM interop and marshaling of a pointer to a pointer to an interface in C#

I'm attempting to use Microsoft's Text Services Framework in a C# app. 我正在尝试在C#应用程序中使用Microsoft的Text Services Framework。 So far, it's all gone swimmingly, but I've run into something that has me stumped. 到目前为止,一切都进行得很顺利,但是我遇到了让我感到困惑的事情。 According to the MSDN docs, the ITfFnReconversion interface publishes this method: 根据MSDN文档,ITfFnReconversion接口发布了此方法:

    HRESULT GetReconversion(
  [in]   ITfRange *pRange,
  [out]  ITfCandidateList **ppCandList
);

Which I have declared in C# as: 我在C#中声明为:

[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
void GetReconversion([In, MarshalAs(UnmanagedType.Interface)] ITfRange pRange, [Out, MarshalAs(UnmanagedType.Interface)] out ITfCandidateList ppCandList);

And am calling like so: 像这样打电话:

ITfCandidateList candidateList;    
reconversionInstance.GetReconversion(range, out candidateList);

The value of reconversionInstance and range were set earlier and I'm confident that they are valid. reconversionInstance和range的值是较早设置的,我相信它们是有效的。 Every time this line executes, I get an Access Violation error indicating that something attempted to read or write protected memory. 每次执行此行时,我都会收到一个访问冲突错误,表明有人尝试读取或写入受保护的内存。 I'm assuming that this is due to improper marshaling of the candidateList param, but am open to other possibilities. 我假设这是由于对候选人列表参数进行了不正确的封送处理,但是还有其他可能性。

Given that the param is declared as a pointer to a pointer, I also tried passing it as an IntPtr, like so: 鉴于已将参数声明为指向指针的指针,我还尝试将其作为IntPtr传递,如下所示:

[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
void GetReconversion([In, MarshalAs(UnmanagedType.Interface)] ITfRange pRange, [Out, MarshalAs(UnmanagedType.SysInt)] out IntPtr ppCandList);

    IntPtr candidateList;    
    reconversionInstance.GetReconversion(range, out candidateList);

But was left with the same error. 但是却留下了同样的错误。

How can I marshal this correctly so that I can obtain an instance of ITfCandidateList? 我如何正确地将其编组,以便获得ITfCandidateList的实例?

For clarification, here are the interfaces as I've imported them, though as I mentioned, I have tried a few different signatures for GetReconversion: 为了澄清起见,这是我导入它们时的接口,尽管如上所述,我为GetReconversion尝试了一些不同的签名:

    [ComImport, InterfaceType(ComInterfaceType.InterfaceIsIUnknown), Guid("4CEA93C0-0A58-11D3-8DF0-00105A2799B5")]
    public interface ITfFnReconversion : ITfFunction
    {
                [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
        void GetDisplayName([Out, MarshalAs(UnmanagedType.BStr)] out string pbstrName);
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
        void QueryRange([In, MarshalAs(UnmanagedType.Interface)] ITfRange pRange, [In, Out, MarshalAs(UnmanagedType.Interface)] ref ITfRange ppNewRange, [Out, MarshalAs(UnmanagedType.Bool)] out bool pfConvertable);
        [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
        void GetReconversion([In, MarshalAs(UnmanagedType.Interface)] ref ITfRange pRange, [Out, MarshalAs(UnmanagedType.SysInt)] out IntPtr ppCandList);
        [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
        void Reconvert([In, MarshalAs(UnmanagedType.Interface)] ITfRange pRange);
    }
[ComImport, Guid("A3AD50FB-9BDB-49E3-A843-6C76520FBF5D"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
public interface ITfCandidateList
{
    [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
    void EnumCandidates([Out, MarshalAs(UnmanagedType.Interface)] out IEnumTfCandidates ppEnum);
    [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
    void GetCandidate([In] uint nIndex, [Out, MarshalAs(UnmanagedType.Interface)] out ITfCandidateString ppCand);
    [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
    void GetCandidateNum([Out] out uint pnCnt);
    [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
    void SetResult([In] uint nIndex, [In, ComAliasName("TSF.TfCandidateResult")] TfCandidateResult imcr);
}

There is something obviously wrong here. 这里显然有问题。 ITfCandidateList **ppCandList cannot translate to a simple out: this is pointer to a pointer of ITfCandidateList . ITfCandidateList **ppCandList无法转换为简单输出:这是指向ITfCandidateList指针的指针。

In my opinion, you need to define that as IntPtr and then try to read that part of memory using Marshal.PtrToStructure. 我认为,您需要将其定义为IntPtr ,然后尝试使用Marshal.PtrToStructure.读取内存的该部分Marshal.PtrToStructure.

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM