Получение элементов из списка управления MFC из .NET - PullRequest
4 голосов
/ 08 июня 2011

У меня есть приложение на C #, которому нужно получить кучу информации из другого окна, написанного на C ++ с использованием MFC.Приложение C # является плагином для продукта, содержащего это другое окно, поэтому они оба работают в одном и том же процессе.

Это другое окно содержит ряд полей, из которых я успешно получил строки, вызвав:

[DllImport( "user32.dll", SetLastError = true )]
        public static extern uint GetDlgItemText( IntPtr hDlg, int nIDDlgItem, [Out] StringBuilder lpString, int nMaxCount );

Но он также содержит 2 элемента управления списком, которые могут содержать несколько строк данных, каждая из которых содержит несколько столбцов.

Как получить эти данные?

Есть ли в user32.dll другая функция, которую я должен использовать?

Можете ли вы получить дескриптор элемента управления списком, используя:

[DllImport( "User32", SetLastError = true )]
        public static extern IntPtr GetDlgItem( IntPtr hwndParent, int ItemId );

, а затем каким-то образом преобразовать его в элемент управления .NET, из которого можно получить строки и столбцы?

1 Ответ

3 голосов
/ 08 июня 2011

Это на самом деле удивительно сложно. Сообщения LVM_ *, которые вы использовали бы для извлечения данных из элементов управления списком, считаются пользовательскими сообщениями, и их параметры нельзя маршалировать через границы процесса с помощью стандартных вызовов Win32.

- это способов сделать это - один - внедрить код в удаленный процесс (используя, скажем, CreateRemoteThread), а затем заставить этот удаленный поток выполнить операцию и записать результаты в общую память - - но они нетривиальны, и у меня нет хорошего примера кода для вас.

Редактировать: ОК, если вы находитесь в том же процессе, вы должны быть в состоянии сделать эту работу. Вот некоторый код (взятый из этой статьи ), который использует сообщения LVM_ * для извлечения выделенного текста из элемента управления списком. Это должно привести вас в правильном направлении. Есть также статья здесь с похожим кодом. Он не мог заставить его работать из-за пересечения границ процесса, но это могло бы сработать для вас.

private string GetSelectedItem()
{
    string item = null;

    IntPtr pStringBuffer = Marshal.AllocHGlobal(2048);
    IntPtr pItemBuffer = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(LVITEM)));

    int selectedItemIndex = SendMessage(base.Handle, LVM_GETNEXTITEM, (IntPtr)(-1), (IntPtr)LVNI_SELECTED).ToInt32();
    if (selectedItemIndex > -1)
    {
        LVITEM lvi = new LVITEM();
        lvi.cchTextMax = 1024;
        lvi.pszText = pStringBuffer;
        Marshal.StructureToPtr(lvi, pItemBuffer, false);
        int numChars = SendMessage(base.Handle, LVM_GETITEMTEXT, (IntPtr)selectedItemIndex, pItemBuffer).ToInt32();
        if (numChars > 0)
        {
            item = Marshal.PtrToStringUni(lvi.pszText, numChars);
        }
    }

    Marshal.FreeHGlobal(pStringBuffer);
    Marshal.FreeHGlobal(pItemBuffer);

    return item;
}

struct LVITEM
{
    public int mask;
    public int iItem;
    public int iSubItem;
    public int state;
    public int stateMask;
    public IntPtr pszText;
    public int cchTextMax;
    public int iImage;
    public IntPtr lParam;
    public int iIndent;
    public int iGroupId;
    int cColumns; // tile view columns
    public IntPtr puColumns;
    public IntPtr piColFmt;
    public int iGroup;

}
...