【问题标题】:Interface safecall, implementation not safecall接口safecall,实现不是safecall
【发布时间】:2013-07-26 20:19:08
【问题描述】:

我有一个可以通过 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 实例属性时都传输到服务器。

【问题讨论】:

  • TMyObject 没有实现 IDispatch

标签: delphi calling-convention dcom delphi-6


【解决方案1】:

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

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;

那么你就有了数据的本地副本,你不必每次都从服务器获取它。

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

如果您不确定在缓存数据时是否会更改数据,您有两种方法来管理它。首先,建立一个系统,将对主数据存储所做的任何更改发送给拥有缓存副本的每个人,以便他们可以更新他们的缓存。这可能非常复杂和复杂,只有当您拥有一定规模和复杂性的系统时才真正值得。

或者,第二,不要缓存可能发生变化的数据。只需将开销作为业务成本的一部分吞下即可。

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

【讨论】:

  • 在这种情况下你有什么建议?每次我需要读取接口属性时如何避免传输到服务器?
  • @MatheusFreitas:好的。我重写了我的答案以解决您的疑虑。
  • 我想实现接口以确保所有方法都实现,但由于它需要安全调用,我想知道这会给我带来什么麻烦
  • @MatheusFreitas:不,safecall 只是让编译器围绕您的方法构建一个包装器,该包装器在 COM 错误处理约定和 Delphi 异常之间透明地转换。它不应该给您带来任何问题,特别是如果您的实现没有引发任何异常。
【解决方案2】:

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

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-06-20
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-12-02
    • 1970-01-01
    相关资源
    最近更新 更多