4

Using Delphi 7, whenever I try to do any database work inside of a thread I get this error:

"CoInitialize has not been called"

I used a simple code containing an ADOConnection.Open inside the thread.

But the same code works fine if it's used in a form any ideas?

LU RD
  • 34,438
  • 5
  • 88
  • 296
riad
  • 361
  • 1
  • 9
  • 19
  • I can't believe the number of people still programming on Delphi 7 (or older) :( PS: just "use" unit "ActiveX", and call CoInitialize (0)! – paulsm4 Jan 13 '13 at 07:30
  • You know, when get used to something, you can't let it go easily, lol – riad Jan 13 '13 at 07:46
  • 1
    @paulsm4: Would using a more recent version of Delphi prevent this particular error? – mghie Jan 13 '13 at 17:21
  • 1
    See also: [When do I need to call CoInitialize() in this scenario?](http://stackoverflow.com/q/9286600/576719). – LU RD Jan 13 '13 at 18:19

3 Answers3

14

@mjn: I'm not allowed to comment your remark in the previous answer, so I created a new answer: calling CoInitialize from the constructor is one of typical error programmers do.

Constructor is executed in a context of another thread, but you need to initialize COM on the current thread (when a thread procedure is running i.e. as part of Execute method) see

pf1957
  • 997
  • 1
  • 5
  • 20
10
procedure TYourThread.execute;
begin
  CoInitialize(nil); 
  FConnection:=TConnection.Create(...);
  try
    ThreadCode ....
  finally
    FConnection.free;
    CoUninitialize;
  end;
end;
kludg
  • 27,213
  • 5
  • 67
  • 118
bummi
  • 27,123
  • 14
  • 62
  • 101
  • @paulsm4 AFAIK Coinitialize has to be called in the threadcontext. – bummi Jan 13 '13 at 07:40
  • it's not about Coinitialize, but about threadcontext: http://embarcadero.newsgroups.archived.at/public.delphi.vcl.components.using/200911/0911093410.html – bummi Jan 13 '13 at 11:53
  • 2
    @mjn, have you tested `GetCurrentThreadId = MainThreadId` inside a subclassed `TThread.Create`? The `TThread` constructor is always executed in the context of the calling thread. – LU RD Jan 13 '13 at 15:11
  • 3
    @mjn my comment about threadcontext was written because I don't agree with the comment: "CoInitialize / CoUninitialize could be called in the thread constructor / destructor" – bummi Jan 13 '13 at 15:29
  • Why do I see many comments about @mjn but see nothing posted them? – Jerry Dodge Jan 14 '13 at 00:17
  • @JerryDodge: Because mjn deleted the comments after people responded to them. – Ken White Jan 14 '13 at 03:54
  • Which IMHO is a ugly practice! (deleting the comments and leave the comment thread incomplete!). @mjn: If you're ashamed of what you said, let it stay and let the world know you're not perfect, and learn to think twice before posting a comment the next time. :) – jachguate Jan 14 '13 at 05:15
  • @mjn, there was a time when the context switch happened immediately after the call `inherited Create(false)`. Before Delphi 6 that was, see [`Recreating a TThread Inside a TThread derived class`](http://stackoverflow.com/q/13561939/576719) and the answer [`Which is the correct way to start a suspended thread in delphi 2007?`](http://stackoverflow.com/a/4206993/576719). If `FreeOnTerminate` is true, the destructor is executed in the thread context. In principal it would have been possible to do CoInitialize/CoUninitialize in the constructor/destructor, but that would anyway be a bad practice. – LU RD Jan 14 '13 at 06:35
  • @LURD: prior to D6, setting `ACreateSuspended=False` would run `Execute()` immediately, even if the constructor was still running. D6 fixed that. But it was **never** possible in any Delphi version to call `CoInitialize()` in the thread constructor and have it take effect inside of `Execute()`. `CoInitialize()` must always be called inside of `Execute()` itself in all Delphi versions. – Remy Lebeau Jan 14 '13 at 20:11
0

Another cause is that Application.Initialize; is missing or commented out in the main application DPR.

Allan F
  • 2,110
  • 1
  • 24
  • 29