2

In a small-ish Delphi 11.1 32bit app I've put an instance of TFileOpenDialog on a form, added a couple of fileTypes (*.zip and *. *) and in a button.OnClick handler called its Execute method.

At runtime, clicking the button resulted in nothing happening and application hanging.

Call stack looked like this:

:76fe513c ntdll.NtWaitForMultipleObjects + 0xc
:75763ea4 ; C:\Windows\SysWOW64\combase.dll
:7575d017 ; C:\Windows\SysWOW64\combase.dll
:75761196 ; C:\Windows\SysWOW64\combase.dll
:7575e8c0 ; C:\Windows\SysWOW64\combase.dll
:75791354 ; C:\Windows\SysWOW64\combase.dll
:76ea6163 ; C:\Windows\SysWOW64\RPCRT4.dll
:76ea6e44 RPCRT4.NdrClientCall4 + 0x14
:6e7e241d ; C:\Windows\SysWOW64\OneCoreUAPCommonProxyStub.dll
Vcl.Dialogs.TCustomFileDialog.Execute(1115734)

After wasting a day googling and trying out various solution, I finally (I know, should've done this straight away) made a new VCL app with just a form, button and TFileOpenDialog. This worked as expected and displayed the File Open dialog.

Returning to my hanging app, I eventually spotted that the .dpr had the uROCOMInit, at the beginning of the uses clause, followed by Windows, Classes, Forms. uROCOMInit is a REM Objects unit, which I am probably not allowed to publicly share, but in essence it does only one relevant thing: calls CoInitializeEx(nil, 0) in initialization section.

Owing to a lucky guess I moved the uROCOMInit unit around in uses clause and found the solution; when uROCOMInit was appearing after the Forms in uses clause, TFileOpenDialog.Execute worked as expected.

So it looks like calling CoInitializeEx (or CoInitialize ?) too early, i.e. before the initialization section of Forms unit, breaks Delphi TFileOpenDialog.

Can someone please explain what causes this behaviour ?

Peter
  • 123
  • 1
  • 8
  • 1
    Why do you want to initialise COM in the main thread of a VCL app? That's already done for you by the VCL if your code uses the `ComObj` unit, which I expect it does. Shouldn't you just remove this `uROCOMInit` unit from the project? – David Heffernan Jan 17 '23 at 12:21
  • @DavidHeffernan thanks, you're right, the app works perfectly fine without the uROCOMInit included. The uROCOMInit is put as the first line of .dpr by REM Object Wizard(s) so I did not question its usefulness. Here's some (possibly) relevant discussion from their forums: https://talk.remobjects.com/t/com-error-when-using-urocominit-on-a-new-program/9738/2 – Peter Jan 17 '23 at 12:43
  • the above discussion about removing uses uROCOMInit from .dpr is only valid for client side REM Objects projects. Server side projects that I have tried only work when uROCOMInit is indeed the first uses line in .dpr. Any other configuration I tried fails with : Project ?.exe raised exception class EROException with message 'Invalid SOAP Envelope. SOAP Envelope node missing or not root.'. – Peter Jan 17 '23 at 12:58
  • That's what I meant about a VCL app. The call to `Application.Initialize` in the .dpr file initialises COM. If you aren't calling `Application.Initialize`, for example because you aren't using VCL, then you need to initialise COM somewhere else. – David Heffernan Jan 17 '23 at 13:21
  • REM Objects server projects I use actually have Application.Initialize in .dpr (due to supporting being run as an app with a visible form or as a service). Even if I run the server as an app, showing the form, it still won't work without uROCOMInit being the first line in .dpr uses clause. Possibly other REM Objects units initializations require CoInitialize(Ex) to be called first, and Application.Initialize comes too late for that. – Peter Jan 17 '23 at 13:30
  • just did a test with including my own unit at the top of .dpr in a REM Objects server side project. My unit called CoInitialize in initialization and the server was still failing with the exception mentioned above. Only calling CoInitializeEx(nil, 0) fixed that. Admittedly a very arcane piece of information, but maybe somebody can make use of it.. – Peter Jan 17 '23 at 13:44
  • "Possibly other REM Objects units initializations require CoInitialize(Ex) to be called first" That would be tricky if RO was ever used in a DLL. Initialization code runs inside the loader lock and anything COM related is surely not viable in such a context. – David Heffernan Jan 17 '23 at 14:01
  • I do not know enough about DLL initialization to have an opinion, but I have created a.dll based REM Objects server and it also has uROCOMInit as the first line in .dpr uses. I imagine unit initialization happens before .dll one ? Will read your comment here :) https://stackoverflow.com/questions/70009329/what-can-be-done-in-the-initialization-finalization-section-and-what-must-be-avo – Peter Jan 17 '23 at 14:08
  • In a DLL unit initialization happens in DllMain, under the loader lock, and I'm fairly sure that no COM should be performed there. – David Heffernan Jan 17 '23 at 18:05

0 Answers0