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);
}
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.
精彩评论