首页 新闻 会员 周边

pinvoke的方式操作win32 API操作控件SysListView32,目标程序崩溃,取不到值

0
悬赏园豆:50 [待解决问题]

现在需要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);
    }
}

}

张果的主页 张果 | 初学一级 | 园豆:154
提问于:2023-09-20 15:28
< >
分享
所有回答(1)
0

在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方法释放内存。这样可以避免内存泄漏和其他问题。

lanedm | 园豆:2396 (老鸟四级) | 2023-09-20 23:09
清除回答草稿
   您需要登录以后才能回答,未注册用户请先注册