我有一个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控件,您可以从中获取行和列?
答案 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;
}