views:

53

answers:

1

I'm attempting to use Microsoft's Text Services Framework in a C# app. 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:

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

Which I have declared in C# as:

[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. 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:

[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?

For clarification, here are the interfaces as I've imported them, though as I mentioned, I have tried a few different signatures for 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);
}
A: 

There is something obviously wrong here. ITfCandidateList **ppCandList cannot translate to a simple out: this is pointer to a pointer of ITfCandidateList.

In my opinion, you need to define that as IntPtr and then try to read that part of memory using Marshal.PtrToStructure.

Aliostad
Thanks for the input. I've tried this, and it consistently throws the same error about attempting to read or write protected memory.
Damion