在很长一段时间,我试图用 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!