Domanda

I have an interface to use over DCOM technology.
All methods defined in the interface have safecall directive.
However, in a client side, I want to reflect this object in an TObject to avoid transit with the interface each time I need read them.

For example

IMyInterface = interface(IDispatch);
  procedure Set_fA(const Value: WideString); safecall;
  function Get_fA: WideString; safecall;
end;

This interface is implemented by a TAutoIntfObject, in this case the implementation keep safecall directive

TMyAuto = class(TAutoIntfObject, IMyInterface)
private
  fA : WideString;  
public
  procedure Set_fA(const Value: WideString); safecall;
  function Get_fA: WideString; safecall;
end;

But now, with TObject If I remove safecall:

TMyObject = class(TObject, IMyInterface)
private
  fA : WideString;  
public
  procedure Set_fA(const Value: WideString); //??
  function Get_fA: WideString; //??
  procedure CopyFromServer(Original: OleVariant); 
end;

The compiler generates the following error: "Declaration of Set_fA differs from declaration in interface IMyObject"

I can normally use TObject with safecall, there will be any trouble if I keep this way?
There is any case where safecall makes all the difference instead of cdecl?

The reason why I'm doing this is because I want avoid transit to the server every time I need to read some TMyAuto instance properties.

È stato utile?

Soluzione

If the canonical value of your data is on the server, but you don't have to hit the server every time you want to access the value, you can cache it locally. It would look something like this:

TMyObject = class(TObject)
private
  fServerInterface: IMyInterface;
  fDataLoaded: boolean;

  //cached data
  fA : WideString;  
  procedure LoadAllData;
public
  procedure Set_fA(const Value: WideString);
  function Get_fA: WideString;
end;

function TMyObject.Get_fA: WideString;
begin
   if not fDataLoaded then
      LoadAllData;
   result := fA;          
end;

procedure TMyObject.Set_fA(const Value: WideString);
begin
   fServerInterface.Set_fA(value);
   fA := value;
end;

procedure TMyObject.LoadAllData;
begin
   fA := fServerInterface.Get_fA;
   fDataLoaded := true;
end;

Then you have a local copy of the data, and you don't have to fetch it from the server every time.

The downside is, your data is cached. Caches can become stale (out of date) if other people are accessing the server at the same time as you, and keeping a cache in sync with the main data store has been called one of the two truly hard problems in Computer Science.

If you're not sure that the data won't be changed while you're caching it, you have two ways to manage it. First, set up a system where any changes made to the main data store get sent out to everyone who's got a cached copy so they can update their caches. This can be very complicated and involved, and is really only worth it if you have a system of a certain size and complexity.

Or, second, don't cache data that's likely to change. Just swallow the overhead as part of the cost of doing business.

Which solution you pick is up to you. Make sure you analyze things really well before deciding, though.

Altri suggerimenti

Go ahead and put safecall back on your methods. The interface requires it. The interface will also require that you implement the rest of the methods introduced by IDispatch since TObject doesn't implement them itself.

Safecall and cdecl are entirely different calling conventions; they're never interchangeable. They differ in who cleans up the stack, and they differ in how errors are transmitted between caller and receiver. The interface specifies one, so you don't get to choose something different when you implement it.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top