// This overload method is used to get ListView group data. internal static unsafe bool GetGroupInfo(IntPtr hwnd, ref NativeMethods.LVGROUP group) { ProcessorTypes localBitness; ProcessorTypes remoteBitness; GetProcessTypes(hwnd, out localBitness, out remoteBitness); if (localBitness == remoteBitness) { int result = 0; fixed (NativeMethods.LVGROUP* pGroup = &group) { result = XSendGetIndex(hwnd, NativeMethods.LVM_GETGROUPINFO, new IntPtr(group.iGroupID), new IntPtr(pGroup), Marshal.SizeOf(group.GetType())); } if (result == group.iGroupID) { return true; } } else if (remoteBitness == ProcessorTypes.Processor32Bit) { LVGROUP_32 group32 = new LVGROUP_32(group); int result = XSendGetIndex(hwnd, NativeMethods.LVM_GETGROUPINFO, new IntPtr(group.iGroupID), new IntPtr(&group32), Marshal.SizeOf(group32.GetType())); if (result == group32.iGroupID) { group = (NativeMethods.LVGROUP)group32; return true; } } else if (remoteBitness == ProcessorTypes.Processor64Bit) { LVGROUP_64 group64 = new LVGROUP_64(group); int result = XSendGetIndex(hwnd, NativeMethods.LVM_GETGROUPINFO, new IntPtr(group.iGroupID), new IntPtr(&group64), Marshal.SizeOf(group64.GetType())); if (result == group64.iGroupID) { group = (NativeMethods.LVGROUP)group64; return true; } } return false; }
// This overload method is used to get ListView Group Item text. internal static unsafe string GetItemText(IntPtr hwnd, NativeMethods.LVGROUP item) { ProcessorTypes localBitness; ProcessorTypes remoteBitness; GetProcessTypes(hwnd, out localBitness, out remoteBitness); if (localBitness == remoteBitness) { // obtain group string (header only) if (Environment.OSVersion.Version.Major == 5) { return ListView_V6_GetGroupTextOnWinXp(hwnd, item); } return GetTextWithinStructure(hwnd, NativeMethods.LVM_GETGROUPINFO, new IntPtr(item.iGroupID), new IntPtr(&item), Marshal.SizeOf(item.GetType()), new IntPtr(&item.pszHeader), item.cchHeader); } else if (remoteBitness == ProcessorTypes.Processor32Bit) { LVGROUP_32 item32 = new LVGROUP_32(item); // obtain group string (header only) if (Environment.OSVersion.Version.Major == 5) { return ListView_V6_GetGroupTextOnWinXp(hwnd, item32); } return GetTextWithinStructure(hwnd, NativeMethods.LVM_GETGROUPINFO, new IntPtr(item32.iGroupID), new IntPtr(&item32), Marshal.SizeOf(item32.GetType()), new IntPtr(&item32.pszHeader), item32.cchHeader); } else if (remoteBitness == ProcessorTypes.Processor64Bit) { LVGROUP_64 item64 = new LVGROUP_64(item); // obtain group string (header only) if (Environment.OSVersion.Version.Major == 5) { return ListView_V6_GetGroupTextOnWinXp(hwnd, item64); } return GetTextWithinStructure(hwnd, NativeMethods.LVM_GETGROUPINFO, new IntPtr(item64.iGroupID), new IntPtr(&item64), Marshal.SizeOf(item64.GetType()), new IntPtr(&item64.pszHeader), item64.cchHeader); } return ""; }
private static string ListView_V6_GetGroupTextOnWinXp(IntPtr hwnd, LVGROUP_64 group) { // Due to the ListView Group bug on WinXP we need to have a special implementation // for retrieving a text of the group for WinXP // On WinXP the code to give back the header text looks something like that: // if (plvgrp->mask & LVGF_HEADER) // { // plvgrp->pszHeader = pgrp->pszHeader; // } // Instead of something along the lines of StringCchCopy(plvgrp->pszHeader, plvgrp->cchHeader, pgrp->pszHeader); // Hence after the call to CommCtrl.Common_GetSetText() we will get back an internal buffer pointer // and not the text itself (ref string str will be ""). It makes no sense to call CommCtrl.Common_GetSetText() // Use XSendMessage to get the internal buffer pointer and than "manually" read the string // get internal buffer pointer (group.pszHeader) // NOTE: do no check XSendMessage.XSend since, LVM_GETGROUPINFO returns id of the group which can be 0, hence // can be treated as failure // We will check group.pszHeader to IntPtr.Zero after the call unsafe { XSend(hwnd, NativeMethods.LVM_GETGROUPINFO, new IntPtr(group.iGroupID), new IntPtr(&group), group.cbSize, ErrorValue.NoCheck); } if (group.pszHeader != 0) { // Read the string manually... // allocate memory from the unmanaged memory using (SafeCoTaskMem copyTo = new SafeCoTaskMem(NativeMethods.MAX_PATH)) { if (!copyTo.IsInvalid) { using (SafeProcessHandle hProcess = new SafeProcessHandle(hwnd)) { if (!hProcess.IsInvalid) { int count; if (Misc.ReadProcessMemory(hProcess, new IntPtr(group.pszHeader), copyTo, new IntPtr(NativeMethods.MAX_PATH), out count)) { return copyTo.GetStringAuto(); } } } } } } return ""; }