我必须使用 C++Builder。根据心情,IDE 会更改 DFM 文件中的十六进制编码位图属性。即使我没有在 GUI 中更改任何内容。
我一直在使用 GIT,这将导致
.dfm
(很难看)的差异。
这是一个带有一些表格的VCL项目。随机变化的
Bitmap
值来自TImageList
.
有什么办法可以防止IDE一直改DFM吗?
这是一个已知问题。
最初在 XE 中报告,并作为“Wont Do”关闭(存档链接):
QC 92769:每次将表单视为文本时,dfm 中 TImageList 的位图数据都会发生变化(alt-F12)
后来又在XE8报错了,10.3就固定关闭了,至少VCL是这样的:
RSP-13666:TImageList 的位图数据不断变化
所以,要回答你的问题——确保你使用的是 C++Builder 10.3 或更高版本,因为问题已经得到纠正。
无论如何,至少对于 VCL 而言。 FMX 仍有类似的报告:
RSP-11259:每个 FMX 表单保存都会更改 FMX 中的二进制图像数据
一些背景资料:
在内部,
Bitmap
属性使用 TFiler::DefineBinaryProperty()
方法通过 DFM 系统流式传输。这会导致 DFM 系统使用内部 TMemoryStream
从/向 DFM 读取/写入 Bitmap
数据。
TImageList
实际上并不包含位图图像,它包含一个 Win32 ImageList
控件 作为 HIMAGELIST
句柄(存储在 TImageList::Handle
属性中)。 Win32 API 在内部处理实际的位图。
写入DFM时,
TImageList
用TMemoryStream
包裹TStreamAdapter
得到Win32IStream
接口,然后调用Win32ImageList_Write/Ex()
函数将HIMAGELIST
的数据写入 TMemoryStream
(pre-ComCtrl32v6格式),然后将TMemoryStream
中的字节写入DFM。 49 4C
数据开头的字节Bitmap
是Win32 API的IL
流格式的标识符,字节42 4D
是HIMAGELIST
保存的实际位图图像的标识符。
在您的屏幕截图中,只有 1 个字节被更改(在过去的其他报告中,有更多字节被更改)。根据 this WineHQ 代码(以及我发现的各种其他第 3 方回购协议),更改的字节属于
ILHEAD::cGrow
流标头的 HIMAGELIST
字段:
当系统需要为新图像腾出空间时,图像列表可以增长的图像数量。该参数表示调整后的图像列表可以包含的新图像的数量。
TImageList::AllocBy
属性:
设置图像列表在需要为新图像腾出空间时增长的图像数量。
当
TImageList
将其 HIMAGELIST
写入 DFM 时,它首先让 Windows 根据需要将 HIMAGELIST
数据写入 IStream
。然后,在 XE4 和 10.3 之间的某个时间(我没有消息来源来确定确切的版本),添加了新逻辑以具有 TImageList
然后返回并用它自己的 cGrow
值覆盖 AllocBy
值。添加此内容是为了解决 RSP-13666 中提到的这个问题:
在上一期的最后评论中,您指出问题的根本原因是
API 似乎更新了一个未记录的计数器。这与我自己对该问题的调查一致。ImageList_WriteEx
在那个“上一期”(QC #92769)中,它说:
Wine 写入一个 _ILHEAD 结构,该结构中发生变化的违规字节是 WORD cMaxImage 和 WORD cGrow。这些对应于列表中当前分配的图像数量,理论上,一旦您添加超过该数量,列表将增长多少。 每次流式传输图像列表时,cGrow 似乎都会增加 4,这让我觉得 Windows 可能实际上并没有使用该字段。
这正是您所看到的 -
cGrow
(632) 的早期 78 02
值被替换为 7C 02
(636) 的新值。
QC票还写着:
似乎 事后调整流并将其更改为 0 不会立即中断它。但正如我们所说,这似乎有风险
和:
不幸的是,报告的问题是由本机 Win32 ImageList 控件引起的,该控件恰好在方法 ImageList_WriteEx() 中找到,它将图像列表写入流。它不是 Rad Studio 错误,那么它的解决方案不是简单的修复。
微软报告了一个与此问题相关的错误(ID:428868),但在 VS 中
并且,如上所述,
TImageList
在写入 DFM 流时确实使用了 ImageList_WriteEx()
。而 Embarcadero 最终决定冒险并修补ImageList_WriteEx()
写入的流数据。