从.NET获取MFC列表控件中的项目

时间:2011-06-08 06:11:29

标签: c# winapi mfc controls

我有一个C#应用程序需要从另一个使用MFC用C ++编写的窗口中检索大量信息。 C#app是包含这个其他窗口的产品的插件,因此它们都在同一个进程中运行。

这个其他窗口包含许多我通过调用成功获取字符串的字段:

[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 个答案:

答案 0 :(得分:3)

这实际上非常困难。用于从listview控件中获取数据的LVM_ *消息被视为用户定义的消息,并且无法使用标准Win32调用跨进程边界封送其参数。

方法来实现这一点 - 一种方法是将代码注入远程进程(比如使用CreateRemoteThread),然后让远程线程执行操作并将结果写入共享内存 - 但它们并不重要,我没有很好的示例代码。

编辑:好的,如果你在同一个过程中,你应该能够做到这一点。以下是一些代码(从this article中提取),它使用LVM_ *消息从列表控件中提取所选文本。这应该让你朝着正确的方向前进。还有一篇文章here有类似的代码。由于跨越过程边界,他无法使其工作,但它可能适合您。

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;

}