LVITEM用于Windows 64位LVITEM、Windows

2023-09-08 00:03:08 作者:小草莓

在很长一段时间,我试图用 LVM_GETITEMW 消息 LVIF_TEXT 面膜得到ListView的文本。在32位,但不是在64位架构我的程序工作。

For a long time I tried to use the LVM_GETITEMW message with LVIF_TEXT mask to get the text of a ListView. My program worked in 32 bit but not in 64 bit architecture.

我发现这个问题是在 LVITEM 结构。不久,我的问题是结构是一个合适的64位和为什么。

I discovered that the problem was at the LVITEM struct. Shortly, my question is which struct is the appropriate one for 64 bit and why.

我作为 LVITEMW 结构的结构有以下字段:

The struct I used as the LVITEMW struct had the following fields:

('mask', c_uint32),
('iItem', c_int32),
('iSubItem', c_int32),
('state', c_uint32),
('stateMask', c_uint32),
('pszText', c_uint32),
('cchTextMax', c_int32),
('iImage', c_int32),
('lParam', c_uint64),
('iIndent', c_int32),
('iGroupId', c_int32),
('cColumns', c_uint32),
('puColumns', c_uint32),
('piColFmt', c_int32),
('iGroup', c_int32)

(使用Python编写的2.7 ctypes的,但是这是写作只是一种形式 - 语言实在是无关紧要的)。

(Written with python 2.7 ctypes, but this is just a form of writing - the language is really irrelevant).

这些领域是一样的记载。

很多谷歌上搜索后,我发现这论坛其中有什么我需要的 - 这64位解决方案

After a lot of googling, I found this forum which had exactly what I needed - the 64 bit solution!

因此​​,在64位的结构应该有更多的空间,而应该是这个样子(指针现在的64位,也是 stateMask 是64位。这是从什么论坛上提出了一个有点不同,但工作太):

So in 64 bit the struct should have more "spaces", and should look something like this (the pointers are now 64 bit and also the stateMask is 64 bit. That's a little bit different from what the forum suggested but works too):

('mask', c_uint32),
('iItem', c_int32),
('iSubItem', c_int32),
('state', c_uint32),
('stateMask', c_uint64), <-- Now 64 bit
('pszText', c_uint64), <-- Now 64 bit which makes sense since this is a pointer
('cchTextMax', c_int32),
('iImage', c_int32),
('lParam', c_uint64),
('iIndent', c_int32),
('iGroupId', c_int32),
('cColumns', c_uint32),
('puColumns', c_uint64), <-- Now 64 bit which makes sense since this is a pointer
('piColFmt', c_int64), <-- Now 64 bit which makes sense since this is a pointer
('iGroup', c_int32)

本次论坛建议有:

The forum suggested having:

('mask', c_uint32),
('iItem', c_int32),
('iSubItem', c_int32),
('state', c_uint32),
('stateMask', c_uint64),
('pszText', c_uint64),
('cchTextMax', c_int32),
('iImage', c_int64), <-- Now 64 bit
('lParam', c_uint32),
('iIndent', c_int32),
('iGroupId', c_int32),
('cColumns', c_uint32),
('puColumns', c_uint32),
('piColFmt', c_int32),
('iGroup', c_int64), <-- Now 128 bit all together
('iGroup2', c_int64) <-- continuation

也可以工作,在名单我需要它是指由pszText文本。

Which also works, at list for my need which is the text pointed by pszText.

和我的问题是:

这个记录任何地方? 为什么要 stateMask c_uint64 - 应该不是总是相同大小的状态? 在哪一个才是真正的结构为64位? Is this documented anywhere? Why should the stateMask be c_uint64 - shouldn't it always be the same size as the state? Which one is the true struct for 64 bit?

感谢您!

推荐答案

由于雷蒙德陈评论我能够找出答案!

Thanks to the comment by Raymond Chen I was able to figure out the answer!

这是关于数据对齐。每个指针应为8字节,并且也应对准于能够由8划分的地址,所以有时应该有指针之前的填充。此外,该结构的大小应该是可分割由分(最大值(sizeof的(在结构中每个字段)),8)这是8中的情况下,由于尺寸一个指针是8。

It's about data alignment. Every pointer should be 8 bytes and should also be aligned to an address that can be divided by 8, so sometimes there should be a padding before the pointer. Also, the size of the struct should be dividable by min(max(sizeof(each field in the struct)), 8) which is 8 in our case since the size of a pointer is 8.

class LVITEMW_explicit(ctypes.Structure):
    _pack_ = 1
    _fields_ = [
        ('mask', c_uint32),         # 0
        ('iItem', c_int32),         # 4
        ('iSubItem', c_int32),      # 8
        ('state', c_uint32),        # 12
        ('stateMask', c_uint32),    # 16
        ('padding1', c_int),
        ('pszText', c_uint64),      # 20 --> 24 after padding (A pointer)
        ('cchTextMax', c_int32),    # 32
        ('iImage', c_int32),        # 36
        ('lParam', c_uint64),       # 40 (On 32 bit should be c_long which is 32 bits)
        ('iIndent', c_int32),       # 48
        ('iGroupId', c_int32),      # 52
        ('cColumns', c_uint32),     # 56
        ('padding2', c_int),
        ('puColumns', c_uint64),    # 60 --> 64 after padding (A pointer)
        ('piColFmt', c_int64),      # 72 (A pointer)
        ('iGroup', c_int32),        # 80
        ('padding3', c_int32),      # The total length was 84 before padding3 was added, which is not dividable by 8
    ]

或者,因为这确实应该写 - 没有 _pack_ = 1

Or as this should really be written - without the _pack_ = 1:

class LVITEMW(ctypes.Structure):
    _fields_ = [
        ('mask', c_uint32),
        ('iItem', c_int32),
        ('iSubItem', c_int32),
        ('state', c_uint32),
        ('stateMask', c_uint32),
        ('pszText', c_uint64),
        ('cchTextMax', c_int32),
        ('iImage', c_int32),
        ('lParam', c_uint64), # On 32 bit should be c_long
        ('iIndent', c_int32),
        ('iGroupId', c_int32),
        ('cColumns', c_uint32),
        ('puColumns', c_uint64),
        ('piColFmt', c_int64),
        ('iGroup', c_int32),
    ]

的确 ctypes.sizeof(LVITEMW)返回88,同 ctypes.sizeof(LVITEMW_explicit)

再次感谢您的有益的意见!

Thanks again for the helpful comments!