现在需要pinvoke的方式操作win32 API操作控件SysListView32,请在namespace QRSTools中定义一个名为ListViewHelper5的类,中间包含静态方法GetRowCount(IntPtr listViewHandle)获取ListView行数,静态方法SetCellValue(IntPtr listViewHandle,int rowIndex,int columnIndex,string value)用于设置指定行与列的值,静态方法GetItemValue(IntPtr listViewHandle, int rowIndex,int columnIndex)用于获取指定行与列的值,静态方法CheckItem(IntPtr listViewHandle,int rowIndex)用于选中指定行
测试下面的代码发现GetRowCount正常,SetCellValue目标程序崩溃没有值,GetItemValue目标程序崩溃没有值,请告诉我问题,或改进的方法,换一种方式也可以
using System;
using System.Runtime.InteropServices;
using System.Text;
namespace QRSTools
{
public static class ListViewHelper5
{
private const int LVM_GETITEMCOUNT = 0x1004;
private const int LVM_GETITEMW = 0x104B;
private const int LVM_SETITEMW = 0x104C;
private const int LVM_SETITEMSTATE = 0x102B;
private const int LVM_GETITEMTEXT = 0x1073; // Add this line
[StructLayout(LayoutKind.Sequential)]
public 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;
}
[DllImport("user32.dll", CharSet = CharSet.Auto)]
public static extern IntPtr SendMessage(IntPtr hWnd, int Msg, int wParam, int lParam);
[DllImport("user32.dll", CharSet = CharSet.Auto)]
public static extern IntPtr SendMessage(IntPtr hWnd, int Msg, int wParam, ref LVITEM lParam);
public static int GetRowCount(IntPtr listViewHandle)
{
return (int)SendMessage(listViewHandle, LVM_GETITEMCOUNT, 0, 0);
}
public static string GetItemValue(IntPtr listViewHandle, int rowIndex, int columnIndex)
{
LVITEM lvi = new LVITEM();
lvi.mask = 1;
lvi.iSubItem = columnIndex;
lvi.iItem = rowIndex;
lvi.cchTextMax = 256;
lvi.pszText = IntPtr.Zero;
SendMessage(listViewHandle, LVM_GETITEMW, rowIndex, ref lvi);
StringBuilder sb = new StringBuilder(lvi.cchTextMax);
SendMessage(listViewHandle, LVM_GETITEMTEXT, rowIndex, ref lvi);
return sb.ToString();
}
public static void SetCellValue(IntPtr listViewHandle, int rowIndex, int columnIndex, string value)
{
LVITEM lvi = new LVITEM();
lvi.mask = 1;
lvi.iSubItem = columnIndex;
lvi.iItem = rowIndex;
lvi.pszText = Marshal.StringToHGlobalAuto(value);
SendMessage(listViewHandle, LVM_SETITEMW, rowIndex, ref lvi);
}
public static void CheckItem(IntPtr listViewHandle, int rowIndex)
{
LVITEM lvi = new LVITEM();
lvi.stateMask = 0x2;
lvi.state = 0x2;
lvi.iItem = rowIndex;
SendMessage(listViewHandle, LVM_SETITEMSTATE, rowIndex, ref lvi);
}
}
}
在GetItemValue方法中,您需要在LVITEM结构体的pszText字段上分配内存来存储文本值。您可以使用Marshal.AllocHGlobal方法为pszText字段分配内存,并在使用完后记得释放内存。
在GetItemValue方法中,您需要在调用SendMessage之前,将LVITEM结构体的pszText字段设置为分配的内存地址。您可以使用Marshal.StructureToPtr方法将结构体转换为指针,并将分配的内存地址分配给pszText字段。
在GetItemValue方法中,您需要在调用SendMessage之后,使用Marshal.PtrToStringAuto方法将返回的指针转换为字符串。
在SetCellValue方法中,您需要在LVITEM结构体的pszText字段上分配内存,并将字符串值复制到分配的内存中。然后,您需要将结构体转换为指针,并将其传递给SendMessage方法。
以下是优化后的代码示例:
public static string GetItemValue(IntPtr listViewHandle, int rowIndex, int columnIndex)
{
LVITEM lvi = new LVITEM();
lvi.mask = 1;
lvi.iSubItem = columnIndex;
lvi.iItem = rowIndex;
lvi.cchTextMax = 256;
lvi.pszText = Marshal.AllocHGlobal(lvi.cchTextMax * 2); // 分配内存
IntPtr lviPtr = Marshal.AllocHGlobal(Marshal.SizeOf(lvi)); // 分配内存
Marshal.StructureToPtr(lvi, lviPtr, false); // 将结构体转换为指针
SendMessage(listViewHandle, LVM_GETITEMW, rowIndex, lviPtr);
Marshal.PtrToStringAuto(lvi.pszText); // 将返回的指针转换为字符串
Marshal.FreeHGlobal(lvi.pszText); // 释放内存
Marshal.FreeHGlobal(lviPtr); // 释放内存
return sb.ToString();
}
public static void SetCellValue(IntPtr listViewHandle, int rowIndex, int columnIndex, string value)
{
LVITEM lvi = new LVITEM();
lvi.mask = 1;
lvi.iSubItem = columnIndex;
lvi.iItem = rowIndex;
lvi.pszText = Marshal.StringToHGlobalAuto(value);
IntPtr lviPtr = Marshal.AllocHGlobal(Marshal.SizeOf(lvi)); // 分配内存
Marshal.StructureToPtr(lvi, lviPtr, false); // 将结构体转换为指针
SendMessage(listViewHandle, LVM_SETITEMW, rowIndex, lviPtr);
Marshal.FreeHGlobal(lvi.pszText); // 释放内存
Marshal.FreeHGlobal(lviPtr); // 释放内存
}
public static void CheckItem(IntPtr listViewHandle, int rowIndex)
{
LVITEM lvi = new LVITEM();
lvi.stateMask = 0x2;
lvi.state = 0x2;
lvi.iItem = rowIndex;
IntPtr lviPtr = Marshal.AllocHGlobal(Marshal.SizeOf(lvi)); // 分配内存
Marshal.StructureToPtr(lvi, lviPtr, false); // 将结构体转换为指针
SendMessage(listViewHandle, LVM_SETITEMSTATE, rowIndex, lviPtr);
Marshal.FreeHGlobal(lviPtr); // 释放内存
}
请注意,在使用完分配的内存后,使用Marshal.FreeHGlobal方法释放内存。这样可以避免内存泄漏和其他问题。