COM 对象和不同版本的 DLL

发布于 2024-12-11 14:14:13 字数 2266 浏览 0 评论 0原文

我对 DLL 对象非常陌生,我到处搜索但找不到正确的答案。 我对 Microsoft RMS 做了一些插件,它会自动从我的 dll 中调用 Process 函数,并使用传递当前会话详细信息的 IDispach 参数。

我正在使用 QSRules.dll 的接口(组件 > 导入 > 组件 > 类型化库...添加到项目)。 它创建包含所有引用等的 TLB 文件。

procedure TRefreshScreenRefreshScreen.Process(const Session: IDispatch);
begin

  CodeSite.Send( csmLevel1, '(Session as SessionClass).Cashier.Name', (Session as SessionClass).Cashier.Name );
  CodeSite.Send( csmLevel1, '(Session as SessionClass).Cashier.Number', (Session as SessionClass).Cashier.Number );

end;

这与软件版本 2.01 完美配合,但当尝试在版本 2.02 上使用相同的功能时,它会崩溃并显示“接口不支持”。 QSRules.dll 已更新版本,所有类的 GUID 都不同。

我用以下代码尝试了这一点:

procedure TRefreshScreenRefreshScreen.Process(const Session: IDispatch);
begin

  if Supports(Session, QSRules_TLB_2_0_0_151.SessionClass) then
    Begin
      CodeSite.Send( csmLevel1, '(Session as SessionClass).Cashier.Name', (Session as QSRules_TLB_2_0_0_151.SessionClass).Cashier.Name );
      CodeSite.Send( csmLevel1, '(Session as SessionClass).Cashier.Number', (Session as QSRules_TLB_2_0_0_151.SessionClass).Cashier.Number );
    end else

  if Supports(Session, QSRules_TLB_2_0_0_105.SessionClass) then
    Begin
      CodeSite.Send( csmLevel1, '(Session as SessionClass).Cashier.Name', (Session as QSRules_TLB_2_0_0_105.SessionClass).Cashier.Name );
      CodeSite.Send( csmLevel1, '(Session as SessionClass).Cashier.Number', (Session as QSRules_TLB_2_0_0_151.SessionClass).Cashier.Number );
    end

end;

有 4 或 5 个不同版本的 dll 都具有不同的 GUID,但 98% 的代码在所有版本之间都是相同的。 以这种方式做到这一点没有必要增加代码。

有什么办法可以缩短它吗?

我也尝试过

procedure TRefreshScreenRefreshScreen.Process(const Session: IDispatch);
var
 _Session: SessionClass;
begin

  if Supports(Session, QSRules_TLB_2_0_0_151.SessionClass) then
    _Session = (Session as QSRules_TLB_2_0_0_151.SessionClass)

  else if Supports(Session, QSRules_TLB_2_0_0_105.SessionClass) then
      _Session = (Session as QSRules_TLB_2_0_0_105.SessionClass);

  with _Session do
  Begin
      CodeSite.Send( csmLevel1, '_Session.Cashier.Name', Cashier.Name );
      CodeSite.Send( csmLevel1, '_Session..Cashier.Number', Cashier.Number );
  End;

end;

但这不起作用,因为变量类型只能从唯一的单元分配。

任何帮助表示赞赏!

I'm very new to DLL objects and I search everywhere and can't find the right answer.
I doing little addon to Microsoft RMS, it automatically calls function Process from my dll with IDispach parameter passing current session details.

I'm using interface from QSRules.dll (Components > Import > Component > Typed Library ... Add To Project).
It creates TLB file with all references etc.

procedure TRefreshScreenRefreshScreen.Process(const Session: IDispatch);
begin

  CodeSite.Send( csmLevel1, '(Session as SessionClass).Cashier.Name', (Session as SessionClass).Cashier.Name );
  CodeSite.Send( csmLevel1, '(Session as SessionClass).Cashier.Number', (Session as SessionClass).Cashier.Number );

end;

That works perfectly with software version 2.01 but when trying to use the same function on version 2.02 it crash with "Interface not supported".
The QSRules.dll has updated version and GUID's for all classes are different.

I tried that with fallowing code:

procedure TRefreshScreenRefreshScreen.Process(const Session: IDispatch);
begin

  if Supports(Session, QSRules_TLB_2_0_0_151.SessionClass) then
    Begin
      CodeSite.Send( csmLevel1, '(Session as SessionClass).Cashier.Name', (Session as QSRules_TLB_2_0_0_151.SessionClass).Cashier.Name );
      CodeSite.Send( csmLevel1, '(Session as SessionClass).Cashier.Number', (Session as QSRules_TLB_2_0_0_151.SessionClass).Cashier.Number );
    end else

  if Supports(Session, QSRules_TLB_2_0_0_105.SessionClass) then
    Begin
      CodeSite.Send( csmLevel1, '(Session as SessionClass).Cashier.Name', (Session as QSRules_TLB_2_0_0_105.SessionClass).Cashier.Name );
      CodeSite.Send( csmLevel1, '(Session as SessionClass).Cashier.Number', (Session as QSRules_TLB_2_0_0_151.SessionClass).Cashier.Number );
    end

end;

There is 4 or 5 different versions of dll all with different GUID's bu 98% of code is the same between all of them.
Doing that in this way is unnessesary multiplying the code.

Is there any way that I can shorten it ?

I also tried

procedure TRefreshScreenRefreshScreen.Process(const Session: IDispatch);
var
 _Session: SessionClass;
begin

  if Supports(Session, QSRules_TLB_2_0_0_151.SessionClass) then
    _Session = (Session as QSRules_TLB_2_0_0_151.SessionClass)

  else if Supports(Session, QSRules_TLB_2_0_0_105.SessionClass) then
      _Session = (Session as QSRules_TLB_2_0_0_105.SessionClass);

  with _Session do
  Begin
      CodeSite.Send( csmLevel1, '_Session.Cashier.Name', Cashier.Name );
      CodeSite.Send( csmLevel1, '_Session..Cashier.Number', Cashier.Number );
  End;

end;

But this not work because variable type can be assigned only from only unit.

Any help appreciated !

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

殊姿 2024-12-18 14:14:13

你说不同版本的接口有不同的guid。只要新的接口是从旧的接口派生出来的,那就完全没问题。事实真的是这样吗?如果这样做,那么您可以通过将 Session 对象强制转换为实际定义 Cashier 成员的任何接口来简化代码。您不需要将其转换为每个单独的接口类型,除非这些接口不是相互派生的。你能展示实际的接口声明吗?

You say that the interfaces have different guids in different versions. That is perfectly fine as long as the newer interfaces derive from the older interfaces. Is that actually the case? If they do, then you can simplify your code by casting your Session object to whatever interface actually defines the Cashier member. You do not need to cast it to each individual interface type unless the interfaces do not derive from each other. Can you show the actual interface declarations?

情绪失控 2024-12-18 14:14:13

从 v2.0.0.105 开始的 Cashier 声明

_Cashier = interface(IDispatch)
    ['{AA84B4FB-AA41-4423-A763-59D0723ED52B}']
    function Get_Session: _SessionClass; safecall;
    function Get_CashDrawer: _CashDrawer; safecall;
    function Get_OverShortLimitType: overshortlimitEnum; safecall;
    function Get_MaxOverShortAmount: Currency; safecall;
    function Get_MaxOverShortPercent: Double; safecall;
    function Get_SecurityLevel: Smallint; safecall;
    function Get_HasPrivilege(var CashierPrivilege: cashierprivilegesEnum): WordBool; safecall;
    function Get_FailedLogOnAttempts: Integer; safecall;
    function Get_EmailAddress: WideString; safecall;
    function Get_Messages: _CashierMessages; safecall;
    function Get_UnreadMessageCount: Integer; safecall;
    function Get_Name: WideString; safecall;
    function Get_FirstName: WideString; safecall;
    function Get_LastName: WideString; safecall;
    function Get_ReturnLimit: Currency; safecall;
    function Get_FloorLimit: Currency; safecall;
    function Get_ID: Integer; safecall;
    function Get_CashDrawerNumber: Smallint; safecall;
    function Get_Loaded: WordBool; safecall;
    function Get_Number: WideString; safecall;
    property Session: _SessionClass read Get_Session;
    property CashDrawer: _CashDrawer read Get_CashDrawer;
    property OverShortLimitType: overshortlimitEnum read Get_OverShortLimitType;
    property MaxOverShortAmount: Currency read Get_MaxOverShortAmount;
    property MaxOverShortPercent: Double read Get_MaxOverShortPercent;
    property SecurityLevel: Smallint read Get_SecurityLevel;
    property HasPrivilege[var CashierPrivilege: cashierprivilegesEnum]: WordBool read Get_HasPrivilege;
    property FailedLogOnAttempts: Integer read Get_FailedLogOnAttempts;
    property EmailAddress: WideString read Get_EmailAddress;
    property Messages: _CashierMessages read Get_Messages;
    property UnreadMessageCount: Integer read Get_UnreadMessageCount;
    property Name: WideString read Get_Name;
    property FirstName: WideString read Get_FirstName;
    property LastName: WideString read Get_LastName;
    property ReturnLimit: Currency read Get_ReturnLimit;
    property FloorLimit: Currency read Get_FloorLimit;
    property ID: Integer read Get_ID;
    property CashDrawerNumber: Smallint read Get_CashDrawerNumber;
    property Loaded: WordBool read Get_Loaded;
    property Number: WideString read Get_Number;
  end;

从 v2.0.0.151 开始的 Cashier 声明

_Cashier = interface(IDispatch)
    ['{39B2C128-00F1-4834-B1A4-05197C708BD9}']
    function Get_Session: _SessionClass; safecall;
    function Get_CashDrawer: _CashDrawer; safecall;
    function Get_OverShortLimitType: overshortlimitEnum; safecall;
    function Get_MaxOverShortAmount: Currency; safecall;
    function Get_MaxOverShortPercent: Double; safecall;
    function Get_SecurityLevel: Smallint; safecall;
    function Get_HasPrivilege(var CashierPrivilege: cashierprivilegesEnum): WordBool; safecall;
    function Get_FailedLogOnAttempts: Integer; safecall;
    function Get_EmailAddress: WideString; safecall;
    function Get_Messages: _CashierMessages; safecall;
    function Get_UnreadMessageCount: Integer; safecall;
    function Get_Name: WideString; safecall;
    function Get_FirstName: WideString; safecall;
    function Get_LastName: WideString; safecall;
    function Get_ReturnLimit: Currency; safecall;
    function Get_FloorLimit: Currency; safecall;
    function Get_ID: Integer; safecall;
    function Get_CashDrawerNumber: Smallint; safecall;
    function Get_Loaded: WordBool; safecall;
    function Get_Number: WideString; safecall;
    function Get_PasswordAge: Integer; safecall;
    function Get_ReminderPeriod: Integer; safecall;
    function Get_PasswordResetFlag: WordBool; safecall;
    function Get_IsPasswordChanged: WordBool; safecall;
    procedure Set_IsPasswordChanged(var Param1: WordBool); safecall;
    function Get_TimecardID: Integer; safecall;
    procedure Set_TimecardID(var Param1: Integer); safecall;
    function ValidatePassword(var Password: WideString): WordBool; safecall;
    function IsPwdDuplicated(var CashierNumber: Integer; var Password: WideString): WordBool; safecall;
    property Session: _SessionClass read Get_Session;
    property CashDrawer: _CashDrawer read Get_CashDrawer;
    property OverShortLimitType: overshortlimitEnum read Get_OverShortLimitType;
    property MaxOverShortAmount: Currency read Get_MaxOverShortAmount;
    property MaxOverShortPercent: Double read Get_MaxOverShortPercent;
    property SecurityLevel: Smallint read Get_SecurityLevel;
    property HasPrivilege[var CashierPrivilege: cashierprivilegesEnum]: WordBool read Get_HasPrivilege;
    property FailedLogOnAttempts: Integer read Get_FailedLogOnAttempts;
    property EmailAddress: WideString read Get_EmailAddress;
    property Messages: _CashierMessages read Get_Messages;
    property UnreadMessageCount: Integer read Get_UnreadMessageCount;
    property Name: WideString read Get_Name;
    property FirstName: WideString read Get_FirstName;
    property LastName: WideString read Get_LastName;
    property ReturnLimit: Currency read Get_ReturnLimit;
    property FloorLimit: Currency read Get_FloorLimit;
    property ID: Integer read Get_ID;
    property CashDrawerNumber: Smallint read Get_CashDrawerNumber;
    property Loaded: WordBool read Get_Loaded;
    property Number: WideString read Get_Number;
    property PasswordAge: Integer read Get_PasswordAge;
    property ReminderPeriod: Integer read Get_ReminderPeriod;
    property PasswordResetFlag: WordBool read Get_PasswordResetFlag;
    property IsPasswordChanged: WordBool read Get_IsPasswordChanged write Set_IsPasswordChanged;
    property TimecardID: Integer read Get_TimecardID write Set_TimecardID;
  end;

正如你所看到的,在更高版本中添加了一些东西,但毫无疑问,我在调用它们的函数时需要检查软件版本。 Cashier 只是 25-30 种类型中的一种,所以如果我必须为所有版本编写相同的基本实现......艰巨的任务,以及后期修改的可怕代码。

Cashier declaration from v2.0.0.105

_Cashier = interface(IDispatch)
    ['{AA84B4FB-AA41-4423-A763-59D0723ED52B}']
    function Get_Session: _SessionClass; safecall;
    function Get_CashDrawer: _CashDrawer; safecall;
    function Get_OverShortLimitType: overshortlimitEnum; safecall;
    function Get_MaxOverShortAmount: Currency; safecall;
    function Get_MaxOverShortPercent: Double; safecall;
    function Get_SecurityLevel: Smallint; safecall;
    function Get_HasPrivilege(var CashierPrivilege: cashierprivilegesEnum): WordBool; safecall;
    function Get_FailedLogOnAttempts: Integer; safecall;
    function Get_EmailAddress: WideString; safecall;
    function Get_Messages: _CashierMessages; safecall;
    function Get_UnreadMessageCount: Integer; safecall;
    function Get_Name: WideString; safecall;
    function Get_FirstName: WideString; safecall;
    function Get_LastName: WideString; safecall;
    function Get_ReturnLimit: Currency; safecall;
    function Get_FloorLimit: Currency; safecall;
    function Get_ID: Integer; safecall;
    function Get_CashDrawerNumber: Smallint; safecall;
    function Get_Loaded: WordBool; safecall;
    function Get_Number: WideString; safecall;
    property Session: _SessionClass read Get_Session;
    property CashDrawer: _CashDrawer read Get_CashDrawer;
    property OverShortLimitType: overshortlimitEnum read Get_OverShortLimitType;
    property MaxOverShortAmount: Currency read Get_MaxOverShortAmount;
    property MaxOverShortPercent: Double read Get_MaxOverShortPercent;
    property SecurityLevel: Smallint read Get_SecurityLevel;
    property HasPrivilege[var CashierPrivilege: cashierprivilegesEnum]: WordBool read Get_HasPrivilege;
    property FailedLogOnAttempts: Integer read Get_FailedLogOnAttempts;
    property EmailAddress: WideString read Get_EmailAddress;
    property Messages: _CashierMessages read Get_Messages;
    property UnreadMessageCount: Integer read Get_UnreadMessageCount;
    property Name: WideString read Get_Name;
    property FirstName: WideString read Get_FirstName;
    property LastName: WideString read Get_LastName;
    property ReturnLimit: Currency read Get_ReturnLimit;
    property FloorLimit: Currency read Get_FloorLimit;
    property ID: Integer read Get_ID;
    property CashDrawerNumber: Smallint read Get_CashDrawerNumber;
    property Loaded: WordBool read Get_Loaded;
    property Number: WideString read Get_Number;
  end;

Cashier declaration from v2.0.0.151

_Cashier = interface(IDispatch)
    ['{39B2C128-00F1-4834-B1A4-05197C708BD9}']
    function Get_Session: _SessionClass; safecall;
    function Get_CashDrawer: _CashDrawer; safecall;
    function Get_OverShortLimitType: overshortlimitEnum; safecall;
    function Get_MaxOverShortAmount: Currency; safecall;
    function Get_MaxOverShortPercent: Double; safecall;
    function Get_SecurityLevel: Smallint; safecall;
    function Get_HasPrivilege(var CashierPrivilege: cashierprivilegesEnum): WordBool; safecall;
    function Get_FailedLogOnAttempts: Integer; safecall;
    function Get_EmailAddress: WideString; safecall;
    function Get_Messages: _CashierMessages; safecall;
    function Get_UnreadMessageCount: Integer; safecall;
    function Get_Name: WideString; safecall;
    function Get_FirstName: WideString; safecall;
    function Get_LastName: WideString; safecall;
    function Get_ReturnLimit: Currency; safecall;
    function Get_FloorLimit: Currency; safecall;
    function Get_ID: Integer; safecall;
    function Get_CashDrawerNumber: Smallint; safecall;
    function Get_Loaded: WordBool; safecall;
    function Get_Number: WideString; safecall;
    function Get_PasswordAge: Integer; safecall;
    function Get_ReminderPeriod: Integer; safecall;
    function Get_PasswordResetFlag: WordBool; safecall;
    function Get_IsPasswordChanged: WordBool; safecall;
    procedure Set_IsPasswordChanged(var Param1: WordBool); safecall;
    function Get_TimecardID: Integer; safecall;
    procedure Set_TimecardID(var Param1: Integer); safecall;
    function ValidatePassword(var Password: WideString): WordBool; safecall;
    function IsPwdDuplicated(var CashierNumber: Integer; var Password: WideString): WordBool; safecall;
    property Session: _SessionClass read Get_Session;
    property CashDrawer: _CashDrawer read Get_CashDrawer;
    property OverShortLimitType: overshortlimitEnum read Get_OverShortLimitType;
    property MaxOverShortAmount: Currency read Get_MaxOverShortAmount;
    property MaxOverShortPercent: Double read Get_MaxOverShortPercent;
    property SecurityLevel: Smallint read Get_SecurityLevel;
    property HasPrivilege[var CashierPrivilege: cashierprivilegesEnum]: WordBool read Get_HasPrivilege;
    property FailedLogOnAttempts: Integer read Get_FailedLogOnAttempts;
    property EmailAddress: WideString read Get_EmailAddress;
    property Messages: _CashierMessages read Get_Messages;
    property UnreadMessageCount: Integer read Get_UnreadMessageCount;
    property Name: WideString read Get_Name;
    property FirstName: WideString read Get_FirstName;
    property LastName: WideString read Get_LastName;
    property ReturnLimit: Currency read Get_ReturnLimit;
    property FloorLimit: Currency read Get_FloorLimit;
    property ID: Integer read Get_ID;
    property CashDrawerNumber: Smallint read Get_CashDrawerNumber;
    property Loaded: WordBool read Get_Loaded;
    property Number: WideString read Get_Number;
    property PasswordAge: Integer read Get_PasswordAge;
    property ReminderPeriod: Integer read Get_ReminderPeriod;
    property PasswordResetFlag: WordBool read Get_PasswordResetFlag;
    property IsPasswordChanged: WordBool read Get_IsPasswordChanged write Set_IsPasswordChanged;
    property TimecardID: Integer read Get_TimecardID write Set_TimecardID;
  end;

As you can see there is few things added in the later version but there is no doubt that I need to check the software version when calling them functions. Cashier that's only one of 25-30 types there so if I have to write the same basic implementation for all versions .... big task, and horrible code for modifications in later stage.

や莫失莫忘 2024-12-18 14:14:13

终于整理好了!只需分享答案,以防其他人寻找答案。

成功的关键是“后期绑定”,这意味着你不使用接口。

procedure TRefreshScreenRefreshScreen.Process(const Session: IDispatch);
var
 _Session: Variant;
begin

  _Session := Session;

  CodeSite.Send( csmLevel1, '_Session.Cashier.Name', _Session.Cashier.Name );
  CodeSite.Send( csmLevel1, '_Session.Cashier.Number', _Session.Cashier.Number );

end;

对于变体变量,函数不会由编译器检查,而是在运行时检查,因此您必须确保拼写正确,因为智能感知不会检查它。

就像做梦一样!

不管怎样,谢谢大家!

Finally got it sorted ! Just share the answer in case anyone else looking for it.

The key for success is "late binding", that means you don't use interface.

procedure TRefreshScreenRefreshScreen.Process(const Session: IDispatch);
var
 _Session: Variant;
begin

  _Session := Session;

  CodeSite.Send( csmLevel1, '_Session.Cashier.Name', _Session.Cashier.Name );
  CodeSite.Send( csmLevel1, '_Session.Cashier.Number', _Session.Cashier.Number );

end;

With variant variable the functions are not check by compiler but in runtime, so you have to make sure that the spelling is correct because intellisense is not checking it.

Works like a dream !

Thanks all of you anyway !

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文