今天還是和大家聊點基本功,就是“如何在DLL中活用Interface” DATE :2004-05-21

聊點基本功,就是“如何在DLL中活用Interface”
<Code 1>
{-----------------------------------------------------------------------------
  Unit: dmBaseModule
  Author:    Aleyn.wu
  Date:      2002-05-12
  Descript: Base Module Interface
-----------------------------------------------------------------------------}
unit dmBaseModule;

interface

uses
  Classes, SysUtils, Variants, hmOleDataSet, hmOleVariant;

type
  IBaseOle = interface;

  IBaseService = interface
    ['{D40CB2CF-23FF-4C41-BB7E-C9FCD28AE7E7}']

    //GetSqlLanguage  取得SQL语句
    function GetSqlLanguage(Index: integer; var Params, Body: WideString): Boolean; stdcall;

    //InTranstion 服务层是否已经为事务中
    function InTranstion: WordBool; stdcall;

    //GetInfo 取得服务层信息
    function GetInfo: WideString; stdcall;

    procedure ShowMessage(Msg: WideString); stdcall;
    procedure OpenQuery(Sql: WideString); stdcall;
    procedure CloseQuery; stdcall;

    //Execute 让服务层执行SQL语句
    procedure Execute(Sql: WideString); stdcall;

    //GetFieldNames 取得某个表(Table)的所有栏位名称(FieldName)
    procedure GetFieldNames(TableName: WideString; var FieldNames: WideString); stdcall;

    //BeginTrans 服务层开始事务
    procedure BeginTrans; stdcall;

    //CommitTrans 服务层提交事务
    procedure CommitTrans; stdcall;

    //RollbackTrans 服务层事务回滚(取消事务)
    procedure RollbackTrans; stdcall;

    //ApplyUpdates 直接用Delta更新数据
    procedure ApplyUpdates(const Delta: OleVariant; TableName, KeyField: WideString); stdcall;

    //ApplyUpdatesWithOle  通知服务层 Delta已经在服务层的OleParam里,
    //                      名称为DeltaName 更新方式和ApplyUpdates一样
    procedure ApplyUpdatesWithOle(const DeltaName, TableName, KeyField: WideString); stdcall;

    //ApplyUpdatesRecordInfo 
    procedure ApplyUpdatesRecordInfo(const DeltaName, TableName, KeyField: WideString); stdcall;

    //ApplyUpdatesWithOle  通知服务层 Delta已经在服务层的某一个DataSet里,
    //                      序号为DataSet 更新方式和ApplyUpdates一样
    procedure ApplyUpdatesWithDataSet(const DataSet: integer; TableName, KeyField: WideString); stdcall;

    //ReceiveDataWithDefault 通知服务层,数据已经准备好,在缺省的Query里,请直接返回给客户。
    procedure ReceiveDataWithDefault; stdcall;

    //ReceiveDataWithCustom 通知服务层,数据已经准备好,在OleParam里,请返回给客户。
    procedure ReceiveDataWithCustom; stdcall;

    //ReceiveDataWithResult 通知服务层,数据在DLL函数中定义,请返回给客户。
    procedure ReceiveDataWithResult; stdcall;

    //ReceiveDataWithNoData 通知服务层,DLL函数没有可返回的数据。
    procedure ReceiveDataWithNoData; stdcall;

    //RaiseError 通知服务层产生一个异常信息给客户
    procedure RaiseError(Msg: WideString); stdcall;

    //DropTable 通知服务层删除一个表格(实际上也是执行SQL删除表格语句)
    procedure DropTable(TableName: WideString); stdcall;

    //AssignQueryToDataSet 通知服务层 缺省的Query需要从其它DataSet取得数据
    //             DataSetIndex:DataSet的序号
    //             DataSetField:DataSet Field Name
    //             QueryField :Query FieldName
    procedure AssignQueryToDataSet(DataSetIndex: integer; DataSetField, QueryField: WideString); stdcall;

    //AssignQueryToDataSet 通知服务层 其它DataSet需要从缺省的Query取得数据
    procedure AssignDataSetToQuery(DataSetIndex: integer; DataSetField, QueryField: WideString); stdcall;

    //从服务层取得一个16位的惟一键字串
    function UniKey: WideString; stdcall;

    //取得服务层缺省Query的接口
    function GetQuery: IHMOleADOQuery; stdcall;

    //取得服务层其它ClientDataSet的接口
    function GetDataSet(Index: integer): IHMOleClientDataSet; stdcall;

    //取得服务层返回参数的接口(OLE格式)
    function GetOle: IBaseOle; stdcall;

    //取得服务层客户参数接口(OleVariant格式)
    function GetParams: IHMOleVariant; stdcall;

    //取务服务层刚刚执行的SQL语句所参生的记录总数
    function GetRecordsAffected: integer; stdcall;

    property RecordsAffected: integer read GetRecordsAffected;
    property Query: IHMOleADOQuery read GetQuery;
    property DataSet[index: integer]: IHMOleClientDataSet read GetDataSet;
    property Ole: IBaseOle read GetOle;
    property Params: IHMOleVariant read GetParams;

  end;

  IBaseDataModule = interface
    ['{0CEF4911-3E0C-4AC9-AAD7-69CA907E3979}']

    //取得本规则模块的信息
    function GetModuleInfo: WideString; stdcall;

    //取得或设置服务层接口
    function GetBaseService: IBaseService; stdcall;
    procedure SetBaseService(const Value: IBaseService); stdcall;

    //取得或设置本规则模块的序号
    function GetModule(): integer; stdcall;
    procedure SetModule(const value: integer); stdcall;

    //服务层调用本规则的总入口
    function Operation(var Data, Msg: OleVariant): WordBool; stdcall;

    // LoadOleParam暂时不用
    procedure LoadOleParam(const Param: OleVariant); stdcall;

    property BaseService: IBaseService read GetBaseService write SetBaseService;
    property Module: integer read GetModule write SetModule;
    property ModuleInfo: WideString read GetModuleInfo;
  end;

  IDataModuleInfo = interface
    ['{B1B99EE8-E0B5-475C-9E21-92E6B416065E}']
    function GetModuleName: WideString; stdcall;
    function GetVersion: Widestring; stdcall;
    function GetDesignner: Widestring; stdcall;
    function GetMemo: Widestring; stdcall;
    function GetLastUpdate: WideString; stdcall;
    function GetModuleIndex: Integer; stdcall;
    property ModuleIndex: Integer read GetModuleIndex;
  end;

  IBaseOle = interface
    procedure AddDspAsName(Name: WideString); stdcall;
    procedure Clear; stdcall;
    function GetValue(Name: WideString): OleVariant; stdcall;
    procedure SetValue(Name: WideString; Value: OleVariant); stdcall;
    property Value[Name: WideString]: OleVariant read GetValue write SetValue;
  end;

implementation

end.


<code 2>

unit dmBaseService;

interface
uses
  Classes, Windows, SysUtils, Variants, dmBaseModule, hmUniKey, hmMemTools, DB,
  hmSqlTools, hmOleDataSet, hmOleVariant, hmDateTools;

type
  TReceiveDataType = (rdDefault, rdCustom, rdResult, rdNoData);
  TServiceState = (srStart, srStop, srPause);

type
  TSafeInterfacedObject = class(TObject, IUnknown)
  protected
    function QueryInterface(const IID: TGUID; out Obj): HResult; stdcall;
    function _AddRef: integer; stdcall;
    function _Release: integer; stdcall;
  end;

type
  TBaseOle = class;

  TBaseService = class(TSafeInterfacedObject, IBaseService)
  private
    FParent: TComponent;
    FOle: TBaseOle;
    FReceiveDataType: TReceiveDataType;
    function GetReceiveDataType: TReceiveDataType;
  protected
    procedure InnerApplyUpdates(TableName, KeyField: WideString); stdcall;
    procedure InnerApplyUpdates2(TableName, KeyField: WideString); stdcall;
  public
    constructor Create(AOwner: TComponent);
    destructor Destroy; override;
    procedure Reset;
    function GetSqlLanguage(Index: integer; var Params, Body: WideString): Boolean; stdcall;
    function InTranstion: WordBool; stdcall;
    function GetInfo: WideString; stdcall;
    procedure ShowMessage(Msg: WideString); stdcall;
    procedure OpenQuery(Sql: WideString); stdcall;
    procedure CloseQuery; stdcall;
    procedure Execute(Sql: WideString); stdcall;
    procedure GetFieldNames(TableName: WideString; var FieldNames: WideString); stdcall;
    procedure BeginTrans; stdcall;
    procedure CommitTrans; stdcall;
    procedure RollbackTrans; stdcall;
    procedure ApplyUpdates(const Delta: OleVariant; TableName, KeyField: WideString); stdcall;
    procedure ApplyUpdatesWithOle(const DeltaName, TableName, KeyField: WideString); stdcall;
    procedure ApplyUpdatesRecordInfo(const DeltaName, TableName, KeyField: WideString); stdcall;
    procedure ApplyUpdatesWithDataSet(const DataSet: integer; TableName, KeyField: WideString); stdcall;
    procedure ReceiveDataWithDefault; stdcall;
    procedure ReceiveDataWithCustom; stdcall;
    procedure ReceiveDataWithResult; stdcall;
    procedure ReceiveDataWithNoData; stdcall;
    procedure RaiseError(Msg: WideString); stdcall;
    procedure DropTable(TableName: WideString); stdcall;
    procedure AssignQueryToDataSet(DataSetIndex: integer; DataSetField, QueryField: WideString); stdcall;
    procedure AssignDataSetToQuery(DataSetIndex: integer; DataSetField, QueryField: WideString); stdcall;
    function UniKey: Widestring; stdcall;
    function GetQuery: IHMOleADOQuery; stdcall;
    function GetDataSet(Index: integer): IHMOleClientDataSet; stdcall;
    function GetOle: IBaseOle; stdcall;
    function GetParams: IHMOleVariant; stdcall;
    function GetRecordsAffected: integer; stdcall;
    property ReceiveDataType: TReceiveDataType read GetReceiveDataType;
  end;

  TBaseOle = class(TSafeInterfacedObject, IBaseOle)
  private
    FParent: TComponent;
  protected
    procedure AddDspAsName(Name: WideString); stdcall;
    procedure Clear; stdcall;
    function GetValue(Name: WideString): OleVariant; stdcall;
    procedure SetValue(Name: WideString; Value: OleVariant); stdcall;
  public
    constructor Create(AOwner: TComponent);
  end;

type
  TCreateDataModule = function(const BaseService: IBaseService): IBaseDataModule; stdcall;
  TCreateDataModuleInfo = function(): IDataModuleInfo; stdcall;

  PModuleLibrary = ^TModuleLibrary;
  TModuleLibrary = record
    ModuleIndex: Integer;
    LibHandle: THandle;
    CreateDataModule: TCreateDataModule;
    CreateDataModuleInfo: TCreateDataModuleInfo;
    ModuleState: TServiceState;
    FileName: pChar;
  end;

implementation

uses DataServer_form, swModuleIndex;

{ TSafeInterfacedObject }

function TSafeInterfacedObject._AddRef: integer;
begin
  Result := -1;
end;

function TSafeInterfacedObject._Release: integer;
begin
  Result := -1;
end;

function TSafeInterfacedObject.QueryInterface(const IID: TGUID; out Obj): HResult;
const
  E_NOINTERFACE = $80004002;
begin
  if GetInterface(IID, Obj) then
    Result := 0
  else
    Result := -1; {E_NOINTERFACE}
end;

{ TBaseService }

constructor TBaseService.Create(AOwner: TComponent);
begin
  inherited Create;
  FParent := AOwner;
  FReceiveDataType := rdNoData;
  FOle := TBaseOle.Create(AOwner);
end;

destructor TBaseService.Destroy;
begin
  FOle.Free;
  inherited;
end;

procedure TBaseService.BeginTrans;
begin
  (FParent as TDataServer2).Connection.BeginTrans;
end;

procedure TBaseService.CloseQuery;
begin
  (FParent as TDataServer2).Query.Close;
end;

procedure TBaseService.CommitTrans;
begin
  (FParent as TDataServer2).Connection.CommitTrans;
end;

procedure TBaseService.Execute(Sql: WideString);
begin
  //(FParent as TDataServer2).Cmd.CommandText := Sql;
  (FParent as TDataServer2).Cmd.Execute(Sql);
end;

procedure TBaseService.GetFieldNames(TableName: WideString;
  var FieldNames: WideString);
var
  FieldList: TStringList;
begin
  FieldList := TStringList.Create;
  (FParent as TDataServer2).Connection.GetFieldNames(TableName, FieldList);
  FieldNames := FieldList.Text;
  FieldList.Free;
end;

function TBaseService.GetInfo: WideString;
begin
  Result := 'ClassName:' + (FParent as TDataServer2).ClassName + ';ComponentName:' + (FParent as TDataServer2).Name;
end;

function TBaseService.GetSqlLanguage(Index: integer; var Params,
  Body: WideString): Boolean;
begin
  with (FParent as TDataServer2) do
    begin
      SqlLang.Close;
      SqlLang.SQL.Text := 'Select * from Func..sqlClient where sq_StoreKey=' + inttostr(Index);
      SqlLang.Open;
      if (SqlLang.Active) and (SqlLang.RecordCount > 0) then
        begin
          Params := SqlLang['sq_Param'];
          Body := SqlLang['sq_Body'];
          Result := True;
        end
      else
        Result := False;
    end;
end;

function TBaseService.InTranstion: WordBool;
begin
  Result := (FParent as TDataServer2).Connection.InTransaction;
end;

procedure TBaseService.OpenQuery(Sql: WideString);
begin
  with (FParent as TDataServer2) do
    begin
      Query.Close;
      Query.SQL.Text := Sql;
    end; // with
end;

procedure TBaseService.RaiseError(Msg: WideString);
begin
  raise Exception.Create(Msg);
end;

procedure TBaseService.ReceiveDataWithCustom;
begin
  FReceiveDataType := rdCustom;
end;

procedure TBaseService.ReceiveDataWithDefault;
begin
  FReceiveDataType := rdDefault;
end;

procedure TBaseService.ReceiveDataWithResult;
begin
  FReceiveDataType := rdResult;
end;

procedure TBaseService.RollbackTrans;
begin
  (FParent as TDataServer2).Connection.RollbackTrans;
end;

procedure TBaseService.ShowMessage(Msg: WideString);
begin
  //(FParent as TDataServer2).Memo1.Lines.Add(Msg);
end;

function TBaseService.GetReceiveDataType: TReceiveDataType;
begin
  Result := FReceiveDataType;
end;

procedure TBaseService.Reset;
begin
  FReceiveDataType := rdNoData;
end;

function TBaseService.GetQuery: IHMOleADOQuery;
begin
  Result := (FParent as TDataServer2).Query.IDataSet;
end;

procedure TBaseService.ReceiveDataWithNoData;
begin
  FReceiveDataType := rdNoData;
end;

function TBaseService.UniKey: Widestring;
begin
  Result := hmUniKey.UniKey((FParent as TDataServer2).UKI);
end;

function TBaseService.GetRecordsAffected: integer;
begin
  Result := (FParent as TDataServer2).Cmd.RecordsAffected;
end;

procedure TBaseService.DropTable(TableName: WideString);
begin
  (FParent as TDataServer2).Cmd.Execute('Drop Table ' + TableName);
end;

procedure TBaseService.AssignQueryToDataSet(DataSetIndex: integer; DataSetField, QueryField: WideString); stdcall;
begin
  with (FParent as TDataServer2) do
    case DataSetIndex of //
      0: Pub1[DataSetField] := Query[QueryField];
      1: Pub2[DataSetField] := Query[QueryField];
      2: Pub3[DataSetField] := Query[QueryField];
    else
      raise Exception.Create('(GetDataSet)Pub DataSet Out Bound');
    end; // case
end;

procedure TBaseService.AssignDataSetToQuery(DataSetIndex: integer; DataSetField, QueryField: WideString); stdcall;
begin
  with (FParent as TDataServer2) do
    case DataSetIndex of //
      0: Query[QueryField] := Pub1[DataSetField];
      1: Query[QueryField] := Pub2[DataSetField];
      2: Query[QueryField] := Pub3[DataSetField];
    else
      raise Exception.Create('(GetDataSet)Pub DataSet Out Bound');
    end; // case
end;

function TBaseService.GetOle: IBaseOle;
begin
  Result := FOle;
end;

procedure TBaseService.ApplyUpdatesWithOle(const DeltaName, TableName, KeyField: WideString);
var
  Flag: boolean;
begin

  with (FParent as TDataServer2) do
    begin
      if VarIsNull(OleParams[DeltaName]) then exit;
      cdsDelta.Close;
      cdsDelta.Data := OleParams[DeltaName];
      Flag := cdsDelta.FindField('SYS_STATUS') <> nil;
    end; // with
  if Flag then
    InnerApplyUpdates2(TableName, KeyField)
  else
    InnerApplyUpdates(TableName, KeyField);
end;

procedure TBaseService.ApplyUpdates(const Delta: OleVariant; TableName, KeyField: WideString);
var
  Flag: Boolean;
begin
  if VarIsNull(Delta) then exit;
  with (FParent as TDataServer2) do
    begin
      cdsDelta.Close;
      cdsDelta.Data := Delta;
      Flag := cdsDelta.FindField('SYS_STATUS') <> nil;
    end; // with
  if Flag then
    InnerApplyUpdates2(TableName, KeyField)
  else
    InnerApplyUpdates(TableName, KeyField);
end;

function TBaseService.GetDataSet(Index: integer): IHMOleClientDataSet;
begin
  with (FParent as TDataServer2) do
    case Index of //
      0: Result := Pub1.IDataSet;
      1: Result := Pub2.IDataSet;
      2: Result := Pub3.IDataSet;
    else
      raise Exception.Create('(GetDataSet)Pub DataSet Out Bound');
    end; // case
end;

function TBaseService.GetParams: IHMOleVariant;
begin
  Result := (FParent as TDataServer2).OleParams;
end;

procedure TBaseService.InnerApplyUpdates(TableName, KeyField: WideString);
var
  i: integer;
  s1, s2: string;
  CmdStr: string;
  FieldList: TStringList;
begin
  with (FParent as TDataServer2) do
    begin
      FieldList := TStringList.Create;
      Connection.GetFieldNames(TableName, FieldList);
      if not cdsDelta.Active then cdsDelta.Open;
      for i := 1 to FieldList.Count do
        if cdsDelta.FindField(FieldList[i - 1]) <> nil then
          cdsDelta.FindField(FieldList[i - 1]).Tag := 1;
      FieldList.Free;
      if cdsDelta.RecordCount > 0 then
        begin
          cdsDelta.First;
          s1 := '';
          s2 := '';
          while not cdsDelta.Eof do
            begin
              CmdStr := '';
              case cdsDelta.UpdateStatus of
                usUnmodified:
                  begin
                    s2 := VarToSql(cdsDelta[KeyField]);
                  end;
                usModified:
                  begin
                    s1 := '';
                    for i := 1 to cdsDelta.FieldCount do
                      if (not cdsDelta.Fields[i - 1].IsNull) and (cdsDelta.Fields[i - 1].Tag = 1) then
                        begin
                          if s1 = '' then
                            s1 := Trim(cdsDelta.Fields[i - 1].FieldName) + ' = ' + VarToSql(cdsDelta.Fields[i - 1].Value)
                          else
                            s1 := s1 + ',' + Trim(cdsDelta.Fields[i - 1].FieldName) + ' = ' + VarToSql(cdsDelta.Fields[i - 1].Value);
                        end;
                    if s1 <> '' then
                      begin
                        CmdStr := 'Update ' + TableName + ' Set ' + s1 + ' Where ' + KeyField + ' = ' + s2;
                      end;
                  end;
                usInserted:
                  begin
                    s1 := '';
                    s2 := '';
                    for i := 1 to cdsDelta.FieldCount do
                      if (not cdsDelta.Fields[i - 1].IsNull) and (cdsDelta.Fields[i - 1].Tag = 1) then
                        begin
                          if s1 = '' then
                            begin
                              s1 := Trim(cdsDelta.Fields[i - 1].FieldName);
                              s2 := VarToSql(cdsDelta.Fields[i - 1].Value);
                            end
                          else
                            begin
                              s1 := s1 + ',' + Trim(cdsDelta.Fields[i - 1].FieldName);
                              s2 := s2 + ',' + VarToSql(cdsDelta.Fields[i - 1].Value);
                            end;
                        end;
                    if s1 <> '' then
                      begin
                        CmdStr := 'Insert into ' + TableName + '(' + s1 + ') Values (' + s2 + ')';
                      end;
                  end;
                usDeleted:
                  begin
                    s2 := VarToSql(cdsDelta[KeyField]);
                    CmdStr := 'Delete ' + TableName + ' Where ' + KeyField + ' = ' + s2;
                  end;
              end;
              if CmdStr <> '' then Cmd.Execute(CmdStr);
              cdsDelta.Next;
            end;
          cdsDelta.First;
          cdsDelta.EmptyDataSet;
          cdsDelta.Close;
        end;
    end;
end;

procedure TBaseService.ApplyUpdatesWithDataSet(const DataSet: integer; TableName, KeyField: WideString);
var
  Flag: boolean;
begin
  with (FParent as TDataServer2) do
    begin
      cdsDelta.Close;
      case DataSet of //
        0: cdsDelta.Data := Pub1.Data;
        1: cdsDelta.Data := Pub2.Data;
        2: cdsDelta.Data := Pub3.Data;
      else
        raise Exception.Create('(ApplyUpdatesWithDataSet) Out of DataSet Index')
      end; // case
      Flag := cdsDelta.FindField('SYS_STATUS') <> nil;
    end; // with
  if Flag then
    InnerApplyUpdates2(TableName, KeyField)
  else
    InnerApplyUpdates(TableName, KeyField);
end;

procedure TBaseService.ApplyUpdatesRecordInfo(const DeltaName, TableName, KeyField: WideString);
var
  s1, s2: string;
  CmdStr: string;
  Flag: Boolean;
  UpdateStatus: TUpdateStatus;
begin
  with (FParent as TDataServer2) do
    begin
      if VarIsNull(OleParams[DeltaName]) then exit;
      cdsDelta.Close;
      cdsDelta.Data := OleParams[DeltaName];
      cdsDelta.Open;
      if cdsDelta.RecordCount > 0 then
        begin
          cdsDelta.First;
          s1 := '';
          s2 := '';
          Flag := cdsDelta.FindField('SYS_STATUS') <> nil;

          while not cdsDelta.Eof do
            begin
              CmdStr := '';
              if Flag then
                UpdateStatus := cdsDelta.UpdateStatus
              else
                UpdateStatus := TUpdateStatus(cdsDelta.IV['SYS_STATUS']);
              case UpdateStatus of
                usUnmodified:
                  begin
                    s2 := VarToSql(cdsDelta[KeyField]);
                  end;
                usModified:
                  begin
                    if Flag then s2 := VarToSql(cdsDelta[KeyField]);
                    s1 := 'ri_ModifyPsn = ' + VarToSql(OleParams['UserID']);
                    s1 := s1 + ', ri_ModifyDate = ' + ToSqlStr(DateToStr(Today));
                    CmdStr := 'Update dlgRecordInfo Set ' + s1 + ' Where ri_UniKey = ' + s2;
                  end;
                usInserted:
                  begin
                    s1 := 'ri_UniKey';
                    s1 := s1 + ', ri_TableName';
                    s1 := s1 + ', ri_CreatePsn ';
                    s1 := s1 + ', ri_CreateDate ';
                    s1 := s1 + ', ri_ModifyPsn ';
                    s1 := s1 + ', ri_ModifyDate ';
                    s2 := VarToSql(cdsDelta[KeyField]);
                    s2 := s2 + ',' + VarToSql(Uppercase(TableName));
                    s2 := s2 + ',' + VarToSql(OleParams['UserID']);
                    s2 := s2 + ',' + ToSqlStr(DateToStr(Today));
                    s2 := s2 + ',' + VarToSql(OleParams['UserID']);
                    s2 := s2 + ',' + ToSqlStr(DateToStr(Today));
                    CmdStr := 'Insert into dlgRecordInfo (' + s1 + ') Values (' + s2 + ')';
                  end;
                usDeleted:
                  begin
                    s1 := 'ri_DeletePsn = ' + VarToSql(OleParams['UserID']);
                    s1 := s1 + ', ri_DeleteDate = ' + ToSqlStr(DateToStr(Today));
                    s1 := s1 + ', ri_Deleted = 1';
                    s2 := VarToSql(cdsDelta[KeyField]);
                    CmdStr := 'Update dlgRecordInfo Set ' + s1 + ' Where ri_UniKey = ' + s2;
                  end;
              end;
              if CmdStr <> '' then Cmd.Execute(CmdStr);
              cdsDelta.Next;
            end;
          cdsDelta.First;
          cdsDelta.EmptyDataSet;
          cdsDelta.Close;
        end;
    end;
end;

procedure TBaseService.InnerApplyUpdates2(TableName, KeyField: WideString);
var
  i: integer;
  s1, s2: string;
  CmdStr: string;
  FieldList: TStringList;
  UpdateStatus: integer;
begin
  with (FParent as TDataServer2) do
    begin
      FieldList := TStringList.Create;
      Connection.GetFieldNames(TableName, FieldList);
      if not cdsDelta.Active then cdsDelta.Open;
      for i := 1 to FieldList.Count do
        if cdsDelta.FindField(FieldList[i - 1]) <> nil then
          cdsDelta.FindField(FieldList[i - 1]).Tag := 1;
      FieldList.Free;
      if cdsDelta.RecordCount > 0 then
        begin
          cdsDelta.First;
          s1 := '';
          s2 := '';
          while not cdsDelta.Eof do
            begin
              CmdStr := '';
              UpdateStatus := cdsDelta.IV['SYS_STATUS'];
              case TUpdateStatus(UpdateStatus) of
                usUnmodified, usModified:
                  begin
                    s1 := '';
                    s2 := VarToSql(cdsDelta[KeyField]);
                    for i := 1 to cdsDelta.FieldCount do
                      if cdsDelta.Fields[i - 1].CanModify and (cdsDelta.Fields[i - 1].Tag = 1) and (UpperCase(cdsDelta.Fields[i - 1].FieldName) <> Uppercase(KeyField)) then
                        begin
                          if s1 = '' then
                            s1 := Trim(cdsDelta.Fields[i - 1].FieldName) + ' = ' + VarToSql(cdsDelta.Fields[i - 1].Value)
                          else
                            s1 := s1 + ',' + Trim(cdsDelta.Fields[i - 1].FieldName) + ' = ' + VarToSql(cdsDelta.Fields[i - 1].Value);
                        end;
                    if s1 <> '' then
                      begin
                        CmdStr := 'Update ' + TableName + ' Set ' + s1 + ' Where ' + KeyField + ' = ' + s2;
                      end;
                  end;
                usInserted:
                  begin
                    s1 := '';
                    s2 := '';
                    for i := 1 to cdsDelta.FieldCount do
                      if (not cdsDelta.Fields[i - 1].IsNull) and (cdsDelta.Fields[i - 1].Tag = 1) then
                        begin
                          if s1 = '' then
                            begin
                              s1 := Trim(cdsDelta.Fields[i - 1].FieldName);
                              s2 := VarToSql(cdsDelta.Fields[i - 1].Value);
                            end
                          else
                            begin
                              s1 := s1 + ',' + Trim(cdsDelta.Fields[i - 1].FieldName);
                              s2 := s2 + ',' + VarToSql(cdsDelta.Fields[i - 1].Value);
                            end;
                        end;
                    if s1 <> '' then
                      begin
                        CmdStr := 'Insert into ' + TableName + '(' + s1 + ') Values (' + s2 + ')';
                      end;
                  end;
                usDeleted:
                  begin
                    s2 := VarToSql(cdsDelta[KeyField]);
                    CmdStr := 'Delete ' + TableName + ' Where ' + KeyField + ' = ' + s2;
                  end;
              end;
              if CmdStr <> '' then Cmd.Execute(CmdStr);
              cdsDelta.Next;
            end;
          cdsDelta.First;
          cdsDelta.EmptyDataSet;
          cdsDelta.Close;
        end;
    end;
end;

{ TBaseOle }

constructor TBaseOle.Create(AOwner: TComponent);
begin
  inherited Create;
  FParent := AOwner;
end;

procedure TBaseOle.AddDspAsName(Name: WideString);
begin
  (FParent as TDataServer2).Ole[Name] := (FParent as TDataServer2).dspTest.Data;
end;

procedure TBaseOle.Clear;
begin
  (FParent as TDataServer2).Ole.Clear;
end;

function TBaseOle.GetValue(Name: WideString): OleVariant;
begin
  Result := (FParent as TDataServer2).Ole[Name];
end;

procedure TBaseOle.SetValue(Name: WideString; Value: OleVariant);
begin
  (FParent as TDataServer2).Ole[Name] := Value;
end;

end.

2004-05-21 14:55:23 煙灰缸(2282902)
我想了想,今天還是和大家聊點基本功,就是“如何在DLL中活用Interface”

2004-05-21 14:56:40  黑夜(13633497)
問一個更基本的問題:
三層分工之前要先定義好接口函數嗎?比如說函數名,參數什麼的 

2004-05-21 14:57:24 煙灰缸(2282902)
 TO黑夜,今天講完這個,明天就講你那個如何?

2004-05-21 14:58:00  黑夜(13633497)
明天週末不上網啊

2004-05-21 14:58:54  黑夜(13633497)
其實回答可以很簡單,是或不是啊,

上一篇:Bitnami-Redmine通过https远程连接svn


下一篇:加深昨天的話題,把一些模糊的概念統一一下 日期:2004-05-19。