You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

调用LVM_GETCOLUMN获取SysListView32列标题始终返回空的问题

解决SysListView32列标题读取为空的问题

Hey Jan, let's figure out why your GetListViewColumn function is returning empty strings every time. I've gone through your code and spotted a few key issues that are causing this problem:

问题1:Mask参数未包含文本读取标识

You set lvCol.mask = LVCF_FMT; right now, but LVCF_FMT only tells the ListView control you want to retrieve column formatting information. To get the column header text, you need to add the LVCF_TEXT flag to the mask—this tells the control we want to read the text content of the column.

Add this constant and update the mask:

const int LVCF_TEXT = 0x00000002;
lvCol.mask = LVCF_FMT | LVCF_TEXT;

问题2:错误使用了列索引参数

You're setting lvCol.iOrder = Column;, but that's not how you specify which column to read. The iOrder field is for retrieving the column's sort order, not selecting the column index. Instead, you need to pass the column index as the wParam parameter of the SendMessage call.

Remove the lvCol.iOrder = Column; line, and update the SendMessage call to:

SendMessage(hwnd, LVM_GETCOLUMNW, (IntPtr)Column, lpRemoteBuffer);

问题3:编码不匹配(ANSI vs Unicode)

Your code uses LVM_GETCOLUMNA (the ANSI version of the message) but then uses Marshal.PtrToStringUni to read a Unicode string. This mismatch will result in empty or garbled text. Stick with the Unicode version LVM_GETCOLUMNW to match how you're reading the string, just like your working GetListViewItem function does.

问题4:确认内存写入函数的一致性

Make sure your WriteProcessMemoryGETCOLUMN wrapper function works exactly like WriteProcessMemoryGETITEM—if there's a bug in how it writes the LV_COLUMN struct to remote memory, that could also cause the control to not return valid text.


修复后的完整GetListViewColumn函数

[System.Runtime.InteropServices.StructLayout(System.Runtime.InteropServices.LayoutKind.Sequential)]
struct LV_COLUMN
{
    public System.Int32 mask;
    public System.Int32 fmt;
    public System.Int32 cx;
    public System.IntPtr pszText;
    public System.Int32 cchTextMax;
    public System.Int32 iSubItem;
    public System.Int32 iImage;
    public System.Int32 iOrder;
}

public static string GetListViewColumn(System.IntPtr hwnd, uint processId, int Column)
{
    const int dwBufferSize = 2048;
    const int LVM_FIRST = 0x1000;
    const int LVM_GETCOLUMNW = LVM_FIRST + 95;
    const int LVCF_FMT = 0x00000001;
    const int LVCF_TEXT = 0x00000002;
    int bytesWrittenOrRead = 0;
    LV_COLUMN lvCol;
    string retval = string.Empty;
    bool bSuccess;
    System.IntPtr hProcess = System.IntPtr.Zero;
    System.IntPtr lpRemoteBuffer = System.IntPtr.Zero;
    System.IntPtr lpLocalBuffer = System.IntPtr.Zero;
    try
    {
        lvCol = new LV_COLUMN();
        lpLocalBuffer = System.Runtime.InteropServices.Marshal.AllocHGlobal(dwBufferSize);
        hProcess = OpenProcess(Win32ProcessAccessType.AllAccess, false, processId);
        if (hProcess == System.IntPtr.Zero)
            throw new System.ApplicationException("Failed to access process!");
        lpRemoteBuffer = VirtualAllocEx(hProcess, System.IntPtr.Zero, dwBufferSize, Win32AllocationTypes.MEM_COMMIT, Win32MemoryProtection.PAGE_READWRITE);
        if (lpRemoteBuffer == System.IntPtr.Zero)
            throw new System.SystemException("Failed to allocate memory in remote process");
        
        // Include both format and text flags in the mask
        lvCol.mask = LVCF_FMT | LVCF_TEXT;
        lvCol.pszText = (System.IntPtr)(lpRemoteBuffer.ToInt32() + System.Runtime.InteropServices.Marshal.SizeOf(typeof(LV_COLUMN)));
        lvCol.cchTextMax = 500;
        
        bSuccess = WriteProcessMemoryGETCOLUMN(hProcess, lpRemoteBuffer, ref lvCol, (uint)System.Runtime.InteropServices.Marshal.SizeOf(typeof(LV_COLUMN)), out bytesWrittenOrRead);
        if (!bSuccess)
            throw new System.SystemException("Failed to write to process memory");
        
        // Pass column index as wParam and use Unicode message
        SendMessage(hwnd, LVM_GETCOLUMNW, (IntPtr)Column, lpRemoteBuffer);
        
        bSuccess = ReadProcessMemory(hProcess, lpRemoteBuffer, lpLocalBuffer, dwBufferSize, out bytesWrittenOrRead);
        if (!bSuccess)
            throw new System.SystemException("Failed to read from process memory");
        
        // Read the Unicode string from local buffer
        retval = System.Runtime.InteropServices.Marshal.PtrToStringUni((System.IntPtr)(lpLocalBuffer.ToInt32() + System.Runtime.InteropServices.Marshal.SizeOf(typeof(LV_COLUMN))));
    }
    finally
    {
        if (lpLocalBuffer != System.IntPtr.Zero)
            System.Runtime.InteropServices.Marshal.FreeHGlobal(lpLocalBuffer);
        if (lpRemoteBuffer != System.IntPtr.Zero)
            VirtualFreeEx(hProcess, lpRemoteBuffer, 0, Win32AllocationTypes.MEM_RELEASE);
        if (hProcess != System.IntPtr.Zero)
            CloseHandle(hProcess);
    }
    return retval ?? string.Empty;
}

These changes should fix the empty string issue—you're now correctly telling the control you want the column text, passing the right column index, and using matching Unicode encoding throughout the process.

内容的提问来源于stack exchange,提问作者Jan021981

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.15 04:46:10