我在做该书的第9张的时候遇到了以下的问题,请高手指教一下:1、为什么我在把provider.pas 和comobj.pas 文件拷贝到我的正在做的工程目录下,
   然后编译时,会报一些不知是函数、还是过程、还是变量的,说是没有定义,比如:  
   没有定义 VarDispProc。这是怎么会事??
2、我调试了第9章的例子,发现只能查询,不能更新。
   通过跟踪调试发现,更新的数据包无法正确上传,到了负责更新的协调对象那里就出错了,提示Project dllhost.exe raised exception class EOleError with message 'Variant does not //reference an automation object'. Process stopped. Use Step or Run to continue.下面结合代码介绍一下://第一步,客户端更新按钮代码发出更新指令,上传更新数据包
procedure TForm7.btnPubApplyClick(Sender: TObject);
var
  uCoor : ImtsUpdateCoorObj;
  vDatas : OleVariant;
  iErrorCount : Longint;
begin
  uCoor := ComtsUpdateCoorObj.CreateRemote('192.168.4.200');
  uCoor.UpdatePublishers(cdsPublishers.Delta, 0, iErrorCount);//更新指令
end;
//第二步,负责更新的协调对象组件的代码,接受数据包cdsPublishers.Delta:
procedure TmtsUpdateCoorObj.UpdatePublishers(vDatas: OleVariant;
  iMaxError: Integer; var iErrorCount: Integer);
begin
  try
    FMyDM.dcomcPublishers.AppServer.UpdateDatas(vDatas, iMaxError, iErrorCount);//调试到这一步出错,发现传递过来的数据包无法正确给Vdatas
    SetComplete;
  except
    SetAbort;
  end;
end;
//第二步提示的错误为:Project dllhost.exe raised exception class EOleError with message 'Variant does not reference an automation object'. Process stopped. Use Step or Run to continue.//第三步,最靠近数据库的COM+组件的代码,尚未执行到这一步。
procedure TmtsPublishers.UpdateDatas(vDatas: OleVariant;
  iMaxErrors: Integer; var iErrorCount: Integer);
begin
  try
    // statements to try
    dspPublishers.ApplyUpdates(vDatas, iMaxErrors, iErrorCount);
    SetComplete;
  except
    SetAbort;
  end;    // try/except
end;

解决方案 »

  1.   

    provider.pas 和comobj.pas 这两个文件用李维的方法我在D6下调试完全通过。D7没试过。
    就我做COM+的经验,感觉不要用李维的这种方法。书中实际上还说到另一更新方法。不用更改以上两个PAS文件。如果中间层要用DCOM的话可以用以下方法试试。
    另一种方法一会儿发来。//更新函数
    procedure TUpdateDCOM.Update(const strSql: WideString; vDatas: OleVariant;
      IMaxError: Integer; var IErrorCount: Integer);
    var
      ServerProject:Iappserver;  //保存类型的APPServer变量
      OwnerData:olevariant;
    begin
      try
        FMyDM.cdsUpdate.CommandText:=strSql;   //取行字段(用返回记录数为0的SQL语句)
        FMyDM.cdsUpdate.Data:=vDatas;        //
        ServerProject:=FMyDm.DCOMUpdate.GetServer;  //取得对象句柄
        
        ServerProject.AS_ApplyUpdates('dspUpdateDCOM',vDatas,IMaxError,IErrorCount,OwnerData);
        if IErrorCount=0 then
          SetComplete
        else
          SetAbort;
      except
        SetAbort;
      end;
    end;还有一种可能是:你的中间层普通数据模块要动态创建和释放。
    加以下代码。
    type
       public
        procedure Initialize; override;
        Destructor Destroy; override;//释放数据模块
    destructor TUpdateDCOM.Destroy;
    begin
      inherited;
      FMyDM.Free;
    end;
    //建立数据模块
    procedure TUpdateDCOM.Initialize;
    begin
      inherited;
      FMyDM :=TDMUpdateDCOM.Create(Forms.Application);
    end;
      

  2.   

    另一种方法:推荐使用。
    更新对象只放adoconnection,adodataset,datasetprovider并建立三者连接。provider.allowcommandtext设为true;协调对象中这样更新数据procedure TUpdate_AS.Update_AS(const strSql: WideString;
      vDatas: OleVariant; IMaxError: Integer; var IErrorCount: Integer);
    var
      MyConn:IUpdate;    //更新对象
      OwnerData:OleVariant;
    begin
     try
       OleCheck(ObjectContext.CreateInstance(CLASS_Update,IID_IUpdate,MyConn));
       MyConn.AddSql(strSql);  //中心对象方法。目的是使更新方法通用。详见下
       MyConn.AS_ApplyUpdates('dspUpdate',vDatas,IMaxError,IErrorCount,OwnerData);
       if IErrorCount=0 then
         SetComplete
       else
         SetAbort;  
     except
       SetAbort;
     end;
    end;//中心对象方法。目的是使更新方法通用。详见下
    procedure TUpdate.AddSql(const strSql: WideString);
    begin
      adsUpdate.CommandText:=strSql;
    end;同理,查询也推荐这种方法。