COM-взаимодействие и маршалинг указателя на указатель на интерфейс в C # - PullRequest
1 голос
/ 10 октября 2010

Я пытаюсь использовать Microsoft Text Services Framework в приложении C #. Пока что все пошло не так, но я столкнулся с тем, что поставило меня в тупик. Согласно документации MSDN, интерфейс ITfFnReconversion публикует этот метод:

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

Который я объявил в C # как:

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

И звоню вот так:

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

Значения reconversionInstance и range были установлены ранее, и я уверен, что они действительны. Каждый раз, когда эта строка выполняется, я получаю ошибку Access Violation, указывающую, что что-то пыталось прочитать или записать защищенную память. Я предполагаю, что это связано с неправильным маршалингом параметра потенциальных списков, но я открыт для других возможностей.

Учитывая, что параметр объявлен как указатель на указатель, я также попытался передать его как 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);

Но осталась та же ошибка.

Как мне правильно упорядочить это, чтобы я мог получить экземпляр ITfCandidateList?

Для пояснения, вот интерфейсы, которые я импортировал, хотя, как я уже упоминал, я пробовал несколько разных подписей для 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);
}

1 Ответ

0 голосов
/ 10 октября 2010

Здесь явно что-то не так.ITfCandidateList **ppCandList не может перевести на простой выход: это указатель на указатель ITfCandidateList.

По моему мнению, вам нужно определить это как IntPtr, а затем попытаться прочитать эту часть памяти, используя Marshal.PtrToStructure.

...