Delphi & Thread-safe COM objects

7 views
Skip to first unread message

John Sotiropoulos

unread,
Mar 7, 1998, 3:00:00 AM3/7/98
to

Are ActiveX servers produced using Delphi (3 C/S with all update/patches
applied) thread-safe?

I have written a simple ActiveX server which has only one member function.
All data in that member function are local variables. Should I still enclose
the code in a TCriticalSection?

The server is used by a partner of ours within their ISAPI extension (using
Visual C++). The problem we get is that frequently COM throws a
E_RPC_WRONG_THREAD ("The application called an interface marshaled for a
different thread") exception

According to our partner this behaviour indicates that our ActiveX server is
not thread-safe (Threads randomly exit before completing). They had the same
behaviour with DAO objects (not thread safe) and switched to ODBC classes
(thread safe) which solved their problems.

How can I make my simple server thread-safe?

Thanks in advance

John

bly

unread,
Mar 8, 1998, 3:00:00 AM3/8/98
to

Hello,

Delphi defaults to producing activex server objects that are
processed/serviced on 1 main thread in 1 single threaded apartment (STA).
Thus, 1 main thread in 1 STA guarantees thread safety for both local and
global variables so you don't need a critical section for your method
variables.

Getting E_RPC_WRONG_THREAD does not mean that your ActiveX server is not
thread-safe; in fact it has nothing to do with whether the server is thread
safe or not. It simply means that if they (the client) manipulate interface
pointers, which your Delphi server provides, across multiple threads in
SEPARATE APARTMENTS, they have to marshal that interface pointer from
apartment to apartment or else they will get the said error: "The
application called an interface marshaled for a different thread".

Again, you don't need to make your simple Delphi server thread-safe. It is
already thread-safe.

--
Binh Ly
Brickhouse Data Systems, Inc
http://www.brickhouse.com

John Sotiropoulos <jo...@sysgenics.com> wrote in article
<6dr7as$sl...@forums.borland.com>...

Patrice Corteel

unread,
Mar 8, 1998, 3:00:00 AM3/8/98
to

Hello,

Here are a few indications for understanding COM threading model and the
error you encountered.

COM supports 3 different threading models :
- single threaded components,
- appartment threaded components,
- free threaded components.

For COM, the threading model is associated to a thread so that components
created by a thread inherit its threading model. In order to select a
threading model for a given thread you MUST call CoInitialize or
CoInitializeEx FOR EACH thread using COM (in the thread main proc).

On the one hand, when calling CoInitialize(nil) or CoInitializeEx with
apartment thread flag set, the corresponding thread is marked as apartment
which means that each call to the components it owns will be run by the
owner thread itself : only the owner thread will run its components methods
which protects them from re-entrance. This way your components don't have to
be thread safe. In this case you can't give directly an interface pointer on
a component to an other thread. The server thread must marshall the
interface and the client has to unmarshall it so that it has a valid
interface pointing on a proxy component rather than on the target component
itself. In order to achieve this you use two COM helper functions :
CoMarshalInterThreadInterfaceInStream and CoGetInterfaceAndReleaseStream.

On the other hand, when calling CoInitializeEx with free thread flag set,
the corresponding thread is marked as free threaded which means that the
components it creates can be run concurrently from several thread. In this
case your components MUST be thread safe and all the COM environment too
including class factories and modules exported functions (for DLLs) :
- function DllGetClassObject(const CLSID, IID: TGUID; var Obj): HResult;
stdcall;
- function DllCanUnloadNow: HResult; stdcall;
- function DllRegisterServer: HResult; stdcall;
- function DllUnregisterServer: HResult; stdcall;

Delphi in version 3.0x (up to 3.02) only provides a convenient framework
for apartment threading model and does not support free threading model (for
example even _AddRef and _Release functions are not thread safe) . It means
that your activeX is implemented to be instanciated from an apartment thread
and DOES NOT HAVE TO BE THREAD SAFE (no CriticalSection or other synchro
object are required). Furthermore, it means that when an other thread has
to call one of its interface member function it MUST get through a
marshalling / unmarshalling process to get a valid interface pointer
otherwise it fires an E_RPC_WRONG_THREAD error.

Now let's go a step further in COM threading model discussion and look at
local and remote servers versus in-proc servers.
A Delphi local or remote exe server has a main thread which calls
CoInitialize which makes it an apartment. And as a default behaviour, every
COM component based on the delphi COM framework is created in this thread
and marked as apartment threaded. If you explicitly spawn new threads you
can initialize them as you want but you must get a marshalled interface to
call components created by your main thread.
If you want to create free threaded components it's far more difficult since
you can't rely directly on Delphi implementation and you have to rewrite
large parts of ComServ and subclass many of ComObj classes. I'm currently
working on this topic and I'll post more on this when I am over with tests.

From an in-proc server point of view (a DLL) you generaly don't handle
threads since you borrow the thread of your host exe except if you spawn a
thread dedicated to one instance of your components (which is the case of
apartment threaded factory posted in this newsgroup by Borland). So in this
case you should indicate in the registry which threading model your
component is designed for (see in registry key named ThreadingModel under
inProcServer32).

So for the problem you reported it is up to your partner to manage its
threads so that other threads than the thread which created your activeX get
a valid interface on your component through use of standard COM marshaling
feature since the component you expose supports apartment threading. Let's
also state that even the factory is an apartment threaded component which
must be handle with the same care !

For ending this discussion let's say that apartment threading model is
Microsoft recommended threading model for all internet extensions such as
MTS or other MS features.

I hope this can help you.

Patrice Corteel

John Sotiropoulos a écrit dans le message


<6dr7as$sl...@forums.borland.com>...
>
>Are ActiveX servers produced using Delphi (3 C/S with all update/patches

>applied) thread-safe? ...


John Sotiropoulos

unread,
Mar 8, 1998, 3:00:00 AM3/8/98
to

Thank you both for your help

John

Sultan Rehman

unread,
Mar 9, 1998, 3:00:00 AM3/9/98
to

>If you want to create free threaded components it's far more difficult
since
>you can't rely directly on Delphi implementation and you have to rewrite
>large parts of ComServ and subclass many of ComObj classes. I'm currently
>working on this topic and I'll post more on this when I am over with tests.


I for one will be waiting anxiously for your post/article regarding writing
free-threaded COM servers in Delphi. I believe it is sorely needed for any
robust servers.

- Sultan Rehman

Tony Lynch

unread,
Mar 10, 1998, 3:00:00 AM3/10/98
to

Thank you for that detailed message - it really helps me with a problem I
have here.

Further to this, is Delphi still OK for the apartment model if I create a
TForm from a COM Server? I'm trying to write a namespace extension and the
IShellView interface demands that I create a window.

Thanks for your (excellent) help.

Tony Lynch.

Ed Mazzocca

unread,
Mar 10, 1998, 3:00:00 AM3/10/98
to

What about global variables in the process that contains multi-STA threads?

These threads need to access these variables. Should they be treated in a
critical section of thread code?

Ed.

Patrice Corteel

unread,
Mar 11, 1998, 3:00:00 AM3/11/98
to

Hi,

>Further to this, is Delphi still OK for the apartment model if I create a
>TForm from a COM Server? I'm trying to write a namespace extension and the
>IShellView interface demands that I create a window.

There's no problem for using a Delphi form in a STA context, provided you
serialize all display stuff through use of synchronize. VCL is not reentrant
and when VCL resources are shared among several threads, display calls
should be synchronized.

Patrice Corteel


*************************************************
Patrice CORTEEL - pcor...@itecor.com
Information Technology Software
30, quai de Dion Bouton
92806 PUTEAUX CEDEX
FRANCE
Tel 33.(0)1.41.02.84.84
Fax 33.(0)1.49.00.49.42
*************************************************

Patrice Corteel

unread,
Mar 11, 1998, 3:00:00 AM3/11/98
to

Hi,

>What about global variables in the process that contains multi-STA threads?
>
>These threads need to access these variables. Should they be treated in a
>critical section of thread code?


They should or I'd rather say they must. Indeed, these global variables
belong to Delphi world and are not protected by COM apartment mechanism so
that there handling should be protected by critical sections.

bly

unread,
Mar 12, 1998, 3:00:00 AM3/12/98
to

Hello,

You "might" run into some real obscure problems (such as access violations)
if the thread that handles your UI is the same thread that handles your STA
objects. In this case, the problem comes from the fact that COM serializes
method calls into the STA thread using the same message loop that your UI
is using and it is possible, for instance, that your object may be created
even before your form gets to completely initialize itself; if this happens
and say in your object's Initialize code, you try to access a form which
has not been fully initialized, you could possibly be accessing the form/or
controls on the form that aren't created yet.

Just something you should be aware of.

--
Binh Ly
Brickhouse Data Systems, Inc
http://www.brickhouse.com

Tony Lynch <tly...@cix.co.uk> wrote in article
<6e4dan$8k...@forums.borland.com>...


> Thank you for that detailed message - it really helps me with a problem I
> have here.
>

> Further to this, is Delphi still OK for the apartment model if I create a
> TForm from a COM Server? I'm trying to write a namespace extension and
the
> IShellView interface demands that I create a window.
>

Tony Lynch

unread,
Mar 14, 1998, 3:00:00 AM3/14/98
to

Thanks, I'll beware of that.

Tony Lynch.

Tony Lynch

unread,
Mar 14, 1998, 3:00:00 AM3/14/98
to

So e.g. TForm.Create should be serialised?

If I understand correctly then the message pump is handled by Explorer so I
don't need to worry about serialiseing message handling on the form?

Thanks for your help,

Tony Lynch.

Reply all
Reply to author
Forward
0 new messages