Delphi COM对象和不同版本的DLL
我对DLL对象非常陌生,我到处搜索,找不到正确的答案。 我在Microsoft RMS上做了一个小插件,它会自动从我的dll调用函数进程,并使用IDisPath参数传递当前会话的详细信息 我正在使用QSRules.dll(组件>导入>组件>类型库…添加到项目)中的接口。 它创建包含所有引用的TLB文件等Delphi COM对象和不同版本的DLL,delphi,dll,Delphi,Dll,我对DLL对象非常陌生,我到处搜索,找不到正确的答案。 我在Microsoft RMS上做了一个小插件,它会自动从我的dll调用函数进程,并使用IDisPath参数传递当前会话的详细信息 我正在使用QSRules.dll(组件>导入>组件>类型库…添加到项目)中的接口。 它创建包含所有引用的TLB文件等 procedure TRefreshScreenRefreshScreen.Process(const Session: IDispatch); begin CodeSite.Send(
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;
但这不起作用,因为变量类型只能从一个单元分配
感谢您的帮助 您说这些接口在不同版本中有不同的guid。只要较新的接口是从较旧的接口派生出来的,这就完全可以了。真的是这样吗?如果他们这样做了,那么您可以通过将会话对象强制转换到实际定义出纳成员的接口来简化代码。您不需要将其强制转换为每个单独的接口类型,除非这些接口不是彼此派生的。能否显示实际的接口声明?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;
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;
正如您所看到的,在以后的版本中添加了一些东西,但毫无疑问,在调用它们的函数时,我需要检查软件版本。这只是25-30种类型中的一种,所以如果我必须为所有版本编写相同的基本实现。。。。任务艰巨,后期修改的代码也很糟糕。最终完成了排序!分享答案,以防其他人寻找 成功的关键是“后期绑定”,这意味着您不使用接口
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;
对于variant变量,编译器不会检查函数,而是在运行时检查,因此您必须确保拼写正确,因为intellisense不会检查它
像做梦一样工作
无论如何,谢谢大家 听起来像是一个非常糟糕的COM接口!你不能用一个DLL版本发布你的应用程序,并使用并行COM来确保你得到你想要的版本。支持多个版本将是可怕的。你会如何测试?