接口安全调用,实现不安全

时间:2013-07-26 20:19:08

标签: delphi calling-convention dcom delphi-6

我有一个使用DCOM技术的界面。
接口中定义的所有方法都具有safecall指令。
但是,在客户端,我想在TObject中反映这个对象,以避免每次我需要读取它时都使用接口传输。

例如

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

此接口由TAutoIntfObject实现,在这种情况下,实现保持safecall指令

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

但现在,使用TObject如果我删除safecall:

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

编译器生成以下错误: “Set_fA的声明与接口IMyObject中的声明不同”

我通常可以使用TObject和safecall,如果我保持这种方式会有任何麻烦吗? 在任何情况下,safecall都会产生差异而不是cdecl吗?

我之所以这样做,是因为每次我需要阅读一些TMyAuto实例属性时,我都希望避免转移到服务器。

2 个答案:

答案 0 :(得分:2)

如果数据的规范值在服务器上,但每次要访问该值时都不必访问服务器,则可以在本地缓存它。它看起来像这样:

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;

然后您拥有数据的本地副本,并且您不必每次都从服务器获取它。

缺点是,您的数据已缓存。如果其他人同时访问服务器,并且保持缓存与主数据存储同步,则缓存可能变为陈旧(过时),这两者之一被认为是真正困难的两个之一计算机科学中的问题。

如果您不确定在缓存数据时不会更改数据,则可以通过两种方式对其进行管理。首先,设置一个系统,对主数据存储所做的任何更改都会发送给每个拥有缓存副本的人,以便他们可以更新缓存。这可能是非常复杂和涉及的,如果你有一个具有一定规模和复杂性的系统,它真的是值得的。

或者,第二,不要缓存可能会改变的数据。只是将开销作为开展业务成本的一部分。

您选择哪种解决方案取决于您。不过,请确保在决定之前对事情进行分析。

答案 1 :(得分:2)

继续,将safecall放回你的方法上。界面需要它。该接口还要求您实现IDispatch引入的其余方法,因为TObject本身并未实现它们。

Safecall和cdecl是完全不同的调用约定;他们永远不可互换。它们在清理堆栈方面有所不同,它们在调用者和接收者之间传输错误的方式不同。接口指定了一个,因此在实现时不会选择不同的东西。