Delphi 11.1中Forms初始化前调用CoInitializeEx致TFileOpenDialog.Execute挂起
这个问题的核心是COM线程模型初始化顺序与VCL框架要求不匹配导致的,具体拆解如下:
Forms单元的默认COM初始化行为
Delphi的Forms单元在初始化阶段,会自动为主线程执行COM初始化,调用的是CoInitializeEx(nil, COINIT_APARTMENTTHREADED)——也就是将主线程设置为**单线程单元(STA)**模式,这是VCL框架的硬性要求,因为VCL本身是单线程模型的可视化框架。uROCOMInit提前初始化的冲突
你的uROCOMInit单元在Forms之前被加载,它提前调用了CoInitializeEx(nil, 0),这里的0对应的是COINIT_MULTITHREADED(多线程单元(MTA))模式。一旦主线程以MTA模式完成COM初始化,后续Forms单元尝试再以STA模式初始化时,会返回失败(但VCL不会抛出异常,而是继续执行)。TFileOpenDialog的线程模型依赖
TFileOpenDialog是基于Windows Common Dialog COM组件实现的,它要求运行在STA模式的线程中。当主线程处于MTA模式时,调用其Execute方法会触发COM内部的跨线程同步逻辑,最终导致调用阻塞在combase.dll中,表现为程序挂起无响应。调整顺序后的修复原理
当把uROCOMInit移到Forms之后时,Forms已经先完成了STA模式的COM初始化。此时uROCOMInit中的CoInitializeEx调用会返回S_FALSE,表示当前线程已经完成COM初始化,不会改变已有的STA模式。主线程保持STA状态,TFileOpenDialog就能正常执行。
额外注意:CoInitializeEx不允许同一线程多次切换COM模型,第一次成功的调用会永久决定线程的COM模型,后续重复调用只会返回成功或已初始化的状态,无法修改模型。
内容的提问来源于stack exchange,提问作者Peter

