Доступ к членам структуры Win32 C / C ++ из C # - PullRequest
4 голосов
/ 15 октября 2008

Я перехватываю вызовы Win32 API нативной dll или exe из C # с использованием какого-то перехвата. В данном конкретном случае меня интересует DrawText () в user32.dll. Это объявлено в Win32 API следующим образом:

INT WINAPI DrawTextW(HDC hdc, LPCWSTR str, INT count, LPRECT rect, UINT flags)

Структура LPRECT имеет следующую подпись (также в Win32 API):

typedef struct tagRECT { 
    LONG left;
    LONG top;
    LONG right;
    LONG bottom;
} RECT LPRECT;

LONG - это typedef для 32-битных целых чисел в 32-битных системах (не знаю о 64-битных системах, в данный момент это не имеет значения, потому что я нахожусь на 32-битной Windows). Чтобы иметь доступ к членам этой структуры, я объявил это в своем коде C # ...

[StructLayout(LayoutKind.Sequential, Pack = 1)]
    public struct RECT
    {
        public Int32 left;
        public Int32 top;
        public Int32 right;
        public Int32 bottom;
    }

... и написал подпись P / Invoke, используя эту структуру RECT:

[DllImport("user32.dll", CharSet = CharSet.Unicode, SetLastError = true, CallingConvention = CallingConvention.StdCall)]
static extern IntPtr DrawText(IntPtr HDC, String str, Int32 count, ref RECT rect, UInt32 flags, IntPtr dtp);

Поскольку структуры являются типами значений в C #, а не ссылочными типами, как в C / C ++, здесь необходим модификатор ref.

Однако, когда я использую rect.top rect.left и т. Д., Они почти всегда возвращают 0. Я точно знаю, что это неправильно. Но, потратив бесчисленное количество часов и попробовав много разных вещей, я не смог заставить этот простой материал работать.

Вещи, которые я пробовал:

  • Использование различных примитивов для членов RECT (int, long, short, UInt32 ...). На самом деле это довольно очевидно, что это не проблема типа, потому что в любом случае я должен видеть некоторые искаженные числа, а не 0.
  • Удаление модификатора ref. Это также глупо (отчаянные времена, отчаянные меры), потому что rect.left правильно возвращает указатель на rect вместо его значения.
  • Пробовал unsafe кодовые блоки. Не сработало, но я, возможно, допустил ошибку в реализации (я не помню, что я сделал). Кроме того, этот подход, как правило, зарезервирован для сложных ситуаций с указателями в COM и Win32, в любом случае это излишне для моего случая.
  • Попытка добавления [MarshallAs] перед членами RECT. Не имеет значения.
  • Поиграл со значениями Pack. Без разницы.

Я совершенно уверен, что упускаю что-то очень простое и понятное, но я понятия не имею, что это ...

Любая помощь приветствуется. Спасибо.

Ответы [ 3 ]

3 голосов
/ 15 октября 2008
2 голосов
/ 15 октября 2008

Я заметил, вы сказали, что пытались [MarshallAs], но пытались ли вы [MarshalAs(UnmanagedType.Struct)]?

1 голос
/ 15 октября 2008

Частично проблема заключается в использовании String, где следует использовать StringBuilder.

Попробуйте эту подпись (Сгенерировано с помощью PInvoke Interop Assistant )


[System.Runtime.InteropServices.StructLayoutAttribute(System.Runtime.InteropServices.LayoutKind.Sequential)]
public struct tagRECT {

    /// LONG->int
    public int left;

    /// LONG->int
    public int top;

    /// LONG->int
    public int right;

    /// LONG->int
    public int bottom;
}

public partial class NativeMethods {

    /// Return Type: int
    ///hdc: HDC->HDC__*
    ///lpchText: LPCWSTR->WCHAR*
    ///cchText: int
    ///lprc: LPRECT->tagRECT*
    ///format: UINT->unsigned int
    [System.Runtime.InteropServices.DllImportAttribute("user32.dll", EntryPoint="DrawTextW")]
public static extern  int DrawTextW([System.Runtime.InteropServices.InAttribute()] System.IntPtr hdc, [System.Runtime.InteropServices.MarshalAsAttribute(System.Runtime.InteropServices.UnmanagedType.LPWStr)] System.Text.StringBuilder lpchText, int cchText, ref tagRECT lprc, uint format) ;

}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...