Solved

COM callback with in-process server

Posted on 1998-09-21
9
432 Views
Last Modified: 2010-04-06
We have an in-process server written in D3. We are using connection points to tell the client to take a particular course of action. In order to avoid the server being locked, we had to do run the callback routine on another thread. This I did by marshaling over the interface onto a thread that then makes the callback, and terminates. With an out of process server, all is fine, but with an in-process the problem is that although the reference count is set to 0 (we have tried forcing this) the server does not unload. If it is invoked again, a 2nd instance starts up and so on... We have tried CoFreeUnusedLibraries to no avail. I've tried the same approach in Delphi 4 with mixed results because sometimes it works, sometimes I get an access violation. We are having to go with an out of process server at the moment, but really want to use in-process. Any ideas?
0
Comment
Question by:pythagorus
9 Comments
 
LVL 5

Expert Comment

by:JimBob091197
ID: 1340413
Relating to a recent interesting discussion on Ex-Ex, Madshi pointed out that you don't need to (ever?) call _AddRef or _Release in Delphi, because Delphi handles reference counts for you.  Have you tried removing all calls to _AddRef & _Release in your Delphi 4 project?  It might remove your Access Violations.

Regards,
JB
0
 
LVL 20

Expert Comment

by:Madshi
ID: 1340414
pythagorus,

how do you create your thread? Do do use Delphi's TThread object or win API CreateThread? In the latter case: Have you set the variable "isMultiThread:=true" and have you closed the thread handle that is returned from CreateThread?

If neither JimBob's (hi, JimBob :-) nor my comment helps you, perhaps you can provide some source code?

Regards, Madshi.
0
 

Author Comment

by:pythagorus
ID: 1340415
We are using Delphi threads and have tried both with and without using _AddRef & _Release. The thread executes, does the callback and terminates.


0
 
LVL 20

Expert Comment

by:Madshi
ID: 1340416
Perhaps the thread makes problems? Remember, the Delphi VCL is not thread safe. What are you doing in the thread exactly? Can you please give us the code of the thread creation and of the thread execute function?

Regards, Madshi.
0
What Is Threat Intelligence?

Threat intelligence is often discussed, but rarely understood. Starting with a precise definition, along with clear business goals, is essential.

 
LVL 20

Expert Comment

by:Madshi
ID: 1340417
P.S: As JimBob said, please remove the _AddRef/_Release calls, regardless of your problem. Otherwise Delphi could get problems...
0
 

Author Comment

by:pythagorus
ID: 1340418
I have created a new server, without all my implementation code.
The problem seems to be down to the connection and channel not being freed up.
Connection is of type Iconnection but is created as a Tconnection. Cannot cast the IConnection to a TConnection to free it - that just crashes.

We are using code obtained from Binh Ly which makes use of connection points. We have sent code to Binh, but he does not have a solution. Incidently, we have just found the same problem with an out-of-process server.

constructor TCallbackThread.Create(ConnectData: TConnectData; TaskID: String;
  Message: String; COMObject: IDispatch);
begin
  inherited Create(True);
  // Bring in the Callback Event Interface
  FConnectData := ConnectData;
  // TaskID
  FTaskID := TaskID;
  // And the Message Text itself
  FMessage := Message;
  // Create the Marshaler with the appropriate Interfaces
  FMarshaler := TMarshaler.CreateMarshalObject (IDispatch, COMObject);
  // Now its safe to use the COM interface that was outside the Apartment
end;

procedure TCallbackThread.Execute;
var
  ifDisp: IDispatch;
begin
  // Tell COM whats going on
  CoInitializeEx(nil, COINIT_APARTMENTTHREADED);
  // Get the Interface as IDispatch
  ifDisp := FConnectData.pUnk as IDispatch;
  // Marshall the Interface into this Apartment
  FMarshaler.UnMarshalObject (ifDisp);
  // Do the Callback
  IDispEvent (ifDisp).GotMessage (FTaskID, FMessage);
  // Got control back from the Client - All done
  FMarshaler.Free;
  // ifDisp._Release;
  CoUninitialize;
end;

destructor TCallbackThread.Destroy;
begin
  // Free the TConnectData's Pointer
  FConnectData.pUnk := nil;
end;
---------------------------------------------------------------------------------
unit CMEvent;

interface

type
  TMessageEvent = procedure (const UserName, Message : string) of object;

  TEvent = class (TAutoIntfObject, IEvent)
  protected
    { IEvent }
    procedure GotMessage (const UserName, Message: WideString); safecall;
  protected
    FOnMessage : TMessageEvent;
  public
    constructor Create;
    property OnMessage : TMessageEvent read FOnMessage write FOnMessage;
  end;

implementation

procedure TEvent.GotMessage (const UserName, Message: WideString);
begin
  if Assigned (OnMessage) then
    OnMessage (UserName, Message);
end;

constructor TEvent.Create;
var
  ifTypeLib : ITypeLib;
begin
  OleCheck (LoadRegTypeLib(LIBID_CMServer, 1, 0, 0, ifTypeLib));
  inherited Create (ifTypeLib, IEvent);
  _AddRef;
end;


0
 

Accepted Solution

by:
moomoo earned 200 total points
ID: 1340419
Firstly, for everyones benefit, the address of Bihn's site is

http://www.castle.net/~bly/Programming/Delphi/index.html

I have managed to use objects based on his with excellect results, though it took a while to get it all going. From the code extract it seems that you wish to delegate the callback to a thread off of the main application thread.

The problem here is with the objects that implement the connection and channel interfaces. If you refer to Bihns original code, you will find that the ChatChannel object, the one returned by the ChatConnection.ChatChannel is declared as a const. If you try to hold on to the Connection or Channel objects so that you can "give them" to the thread with the delegation responsibility, then the server, whether in or out of process, will not unload properly even if you assign "Unassigned" to variants or "nil" to interfaces - which one will depend on the types of the Connection/Channel. To do the callback, you only need to use the Channel unit, and call Channel.BroadcastMessage. Try it and see if it works
0
 

Author Comment

by:pythagorus
ID: 1340420
I tried using the const instead of the channel object and it seems to do the trick, though I'm not sure I understand what effect the marshalling has on this. It is presumably messing about with some reference count which I cannot see, because I was checking that the count was 0.
0
 
LVL 13

Expert Comment

by:Mirkwood
ID: 1340421
Bought This Question.
0

Featured Post

Top 6 Sources for Identifying Threat Actor TTPs

Understanding your enemy is essential. These six sources will help you identify the most popular threat actor tactics, techniques, and procedures (TTPs).

Join & Write a Comment

The uses clause is one of those things that just tends to grow and grow. Most of the time this is in the main form, as it's from this form that all others are called. If you have a big application (including many forms), the uses clause in the in…
Introduction Raise your hands if you were as upset with FireMonkey as I was when I discovered that there was no TListview.  I use TListView in almost all of my applications I've written, and I was not going to compromise by resorting to TStringGrid…
This video discusses moving either the default database or any database to a new volume.
When you create an app prototype with Adobe XD, you can insert system screens -- sharing or Control Center, for example -- with just a few clicks. This video shows you how. You can take the full course on Experts Exchange at http://bit.ly/XDcourse.

744 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question

Need Help in Real-Time?

Connect with top rated Experts

8 Experts available now in Live!

Get 1:1 Help Now