Не удается считать имя локали, куча повреждается, как исправить 2 метода?

139
08 декабря 2020, 09:00

Имеется следующий интерфейс:

/// <summary>
///     Represents a collection of strings indexed by locale name.
/// </summary>
[ComImport]
[Guid("08256209-099a-4b34-b86d-c22b110e7771")]
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
public interface IDWriteLocalizedStrings
{
    /// <summary>
    ///     Gets the number of language/string pairs.
    /// </summary>
    uint GetCount();
    /// <summary>
    ///     Gets the index of the item with the specified locale name.
    /// </summary>
    /// <param name="localeName">Locale name to look for.</param>
    /// <param name="index">Receives the zero-based index of the locale name/string pair.</param>
    /// <param name="exists">Receives TRUE if the locale name exists or FALSE if not.</param>
    /// <returns>
    ///     Standard HRESULT error code. If the specified locale name does not exist, the return value is S_OK,
    ///     but *index is UINT_MAX and *exists is FALSE.
    /// </returns>
    [PreserveSig]
    int FindLocaleName([MarshalAs(UnmanagedType.LPWStr)] string localeName, out uint index,
        [MarshalAs(UnmanagedType.Bool)] out bool exists);
    /// <summary>
    ///     Gets the length in characters (not including the null terminator) of the locale name with the specified index.
    /// </summary>
    /// <param name="index">Zero-based index of the locale name.</param>
    /// <param name="length">Receives the length in characters, not including the null terminator.</param>
    /// <returns>
    ///     Standard HRESULT error code.
    /// </returns>
    [PreserveSig]
    int GetLocaleNameLength(uint index, out uint length);
    /// <summary>
    ///     Copies the locale name with the specified index to the specified array.
    /// </summary>
    /// <param name="index">Zero-based index of the locale name.</param>
    /// <param name="localeName">Character array that receives the locale name.</param>
    /// <param name="size">
    ///     Size of the array in characters. The size must include space for the terminating
    ///     null character.
    /// </param>
    /// <returns>
    ///     Standard HRESULT error code.
    /// </returns>
    [PreserveSig]
    int GetLocaleName(uint index, [MarshalAs(UnmanagedType.LPArray)] [In] ref byte[] localeName, uint size);
    /// <summary>
    ///     Gets the length in characters (not including the null terminator) of the string with the specified index.
    /// </summary>
    /// <param name="index">Zero-based index of the string.</param>
    /// <param name="length">Receives the length in characters, not including the null terminator.</param>
    /// <returns>
    ///     Standard HRESULT error code.
    /// </returns>
    [PreserveSig]
    int GetStringLength(uint index, out uint length);
    /// <summary>
    ///     Copies the string with the specified index to the specified array.
    /// </summary>
    /// <param name="index">Zero-based index of the string.</param>
    /// <param name="stringBuffer">Character array that receives the string.</param>
    /// <param name="size">
    ///     Size of the array in characters. The size must include space for the terminating
    ///     null character.
    /// </param>
    /// <returns>
    ///     Standard HRESULT error code.
    /// </returns>
    [PreserveSig]
    int GetString(uint index, [MarshalAs(UnmanagedType.LPWStr)] out string stringBuffer, uint size);
}

Но оригинальный интерфейс определен вот так:

/// <summary>
/// Represents a collection of strings indexed by locale name.
/// </summary>
interface DWRITE_DECLARE_INTERFACE("08256209-099a-4b34-b86d-c22b110e7771") IDWriteLocalizedStrings : public IUnknown
{
    /// <summary>
    /// Gets the number of language/string pairs.
    /// </summary>
    STDMETHOD_(UINT32, GetCount)() PURE;
    /// <summary>
    /// Gets the index of the item with the specified locale name.
    /// </summary>
    /// <param name="localeName">Locale name to look for.</param>
    /// <param name="index">Receives the zero-based index of the locale name/string pair.</param>
    /// <param name="exists">Receives TRUE if the locale name exists or FALSE if not.</param>
    /// <returns>
    /// Standard HRESULT error code. If the specified locale name does not exist, the return value is S_OK, 
    /// but *index is UINT_MAX and *exists is FALSE.
    /// </returns>
    STDMETHOD(FindLocaleName)(
        _In_z_ WCHAR const* localeName,
        _Out_ UINT32* index,
        _Out_ BOOL* exists
        ) PURE;
    /// <summary>
    /// Gets the length in characters (not including the null terminator) of the locale name with the specified index.
    /// </summary>
    /// <param name="index">Zero-based index of the locale name.</param>
    /// <param name="length">Receives the length in characters, not including the null terminator.</param>
    /// <returns>
    /// Standard HRESULT error code.
    /// </returns>
    STDMETHOD(GetLocaleNameLength)(
        UINT32 index,
        _Out_ UINT32* length
        ) PURE;
    /// <summary>
    /// Copies the locale name with the specified index to the specified array.
    /// </summary>
    /// <param name="index">Zero-based index of the locale name.</param>
    /// <param name="localeName">Character array that receives the locale name.</param>
    /// <param name="size">Size of the array in characters. The size must include space for the terminating
    /// null character.</param>
    /// <returns>
    /// Standard HRESULT error code.
    /// </returns>
    STDMETHOD(GetLocaleName)(
        UINT32 index,
        _Out_writes_z_(size) WCHAR* localeName,
        UINT32 size
        ) PURE;
    /// <summary>
    /// Gets the length in characters (not including the null terminator) of the string with the specified index.
    /// </summary>
    /// <param name="index">Zero-based index of the string.</param>
    /// <param name="length">Receives the length in characters, not including the null terminator.</param>
    /// <returns>
    /// Standard HRESULT error code.
    /// </returns>
    STDMETHOD(GetStringLength)(
        UINT32 index,
        _Out_ UINT32* length
        ) PURE;
    /// <summary>
    /// Copies the string with the specified index to the specified array.
    /// </summary>
    /// <param name="index">Zero-based index of the string.</param>
    /// <param name="stringBuffer">Character array that receives the string.</param>
    /// <param name="size">Size of the array in characters. The size must include space for the terminating
    /// null character.</param>
    /// <returns>
    /// Standard HRESULT error code.
    /// </returns>
    STDMETHOD(GetString)(
        UINT32 index,
        _Out_writes_z_(size) WCHAR* stringBuffer,
        UINT32 size
        ) PURE;
};

Я понимаю что у меня не правильно определены 2 метода: GetLocaleName и GetString.

Но у меня нет представления что мне передать туда, т.к. как выходная строка, не подходит, а при передачи как указатель на массив, происходит повреждение кучи. Как правильно эти 2 метода перенести в c#?

Answer 1

Массивы тут не нужны. COM Interop умеет работать со строками как с выходными параметрами:

[PreserveSig]
int GetLocaleName(uint index, [MarshalAs(UnmanagedType.LPWStr)] [In, Out] StringBuilder localeName, uint size);

При вызове передать StringBuilder достаточного размера: new StringBuilder(size).

READ ALSO
Как подключить скрипт Python в C#? [дубликат]

Как подключить скрипт Python в C#? [дубликат]

У меня есть некий скрипт на питоне(со сторонними библиотеками)Я хочу его подключить в готовый C# проект

116
Можно ли сделать контроллер синглтоном (Singletone)

Можно ли сделать контроллер синглтоном (Singletone)

Есть "легаси" проект на ASPNET MVC 4 Как я выяснил в отладчике все контроллеры (а также и репозитории) не являются синглтонами, а создаются каждый...

140
Реверс таймера DispatcherTimer

Реверс таймера DispatcherTimer

Подскажите, как заставить таймер DispatcherTimer идти в обратную сторону?

131
Делегат многоадрессный

Делегат многоадрессный

Столкнулся с проблемой не могу понять,как решить, вот, что есть:

116