• Status: Solved
  • Priority: Medium
  • Security: Public
  • Views: 460
  • Last Modified:

COM callback with in-process server

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
pythagorus
Asked:
pythagorus
1 Solution
 
JimBob091197Commented:
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
 
MadshiCommented:
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
 
pythagorusAuthor Commented:
We are using Delphi threads and have tried both with and without using _AddRef & _Release. The thread executes, does the callback and terminates.


0
Concerto's Cloud Advisory Services

Want to avoid the missteps to gaining all the benefits of the cloud? Learn more about the different assessment options from our Cloud Advisory team.

 
MadshiCommented:
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
 
MadshiCommented:
P.S: As JimBob said, please remove the _AddRef/_Release calls, regardless of your problem. Otherwise Delphi could get problems...
0
 
pythagorusAuthor Commented:
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
 
moomooCommented:
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
 
pythagorusAuthor Commented:
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
 
MirkwoodCommented:
Bought This Question.
0

Featured Post

Concerto Cloud for Software Providers & ISVs

Can Concerto Cloud Services help you focus on evolving your application offerings, while delivering the best cloud experience to your customers? From DevOps to revenue models and customer support, the answer is yes!

Learn how Concerto can help you.

Tackle projects and never again get stuck behind a technical roadblock.
Join Now