请问我用以下的方法去取数据为什么不行呀?
自定义消息:
const
  THREAD_GETDATA = WM_USER+1;
  THREAD_UPDATEDATA = WM_USER+2;
  THREAD_TERMINATE = WM_USER+3;以下是自己定义的多线程类:
  TDataThread = class(TThread)
  private
    FStream: Pointer;
    IAppData: IAppServer;
    FDelta: OleVariant;
    FData: OleVariant;
    FcdsData: TClientDataSet;    Function GetData(Fcds: TClientDataSet):OleVariant;
    Procedure UpdateData(Fcds: TClientDataSet);
  protected
    Procedure Execute;override;
  public
    Constructor Create(Fcds: TClientDataSet);
    Property Delta: OleVariant read FDelta write FDelta;
    Property Data: OleVariant read FData write FData;
  end;
constructor TDataThread.Create(Fcds: TClientDataSet);
var
  Res: HRESULT;
begin
  FreeOnTerminate := True;
  OleCheck(CoInitialize(Nil));
  Self.FcdsData := Fcds;
  try
    Res:= CoMarshalInterThreadInterfaceInStream(IID_IAppserver,   //用来注册线程。
    FcdsData.AppServer,IStream(FStream));  //OleCheck( )AppInteface:=IappServer(IDispatch(DataModule1.skc1.AppServer));
    case res of
      E_OUTOFMEMORY:
        Dialogs.ShowMessage('There was not enough memory to complete the call.');
      E_INVALIDARG:
        Dialogs.ShowMessage('One or more arguments are invalid. ');  //相当于ShowMessage.
    end;
  except
    On e: Exception do
    Begin
      CoUninitialize;
      Dialogs.ShowMessage(E.Message);
      exit;
    end;
  end;
  try
   Res:= CoGetInterfaceAndReleaseStream(IStream(FStream),IID_IAppServer,IAppData);
    case res of
      E_INVALIDARG:
        Dialogs.ShowMessage('Indicates that input arguments are invalid.');
    end;
  except
    On e: Exception do
    Begin
      CoUninitialize;
      Dialogs.ShowMessage(E.Message);
      exit;
    end;
  end;
  Inherited Create(False);
end;procedure TDataThread.Execute;
var
  Event: THandle;
  Msg: TMsg;
  cdsTemp: TClientDataSet;
begin
  Event:= Self.Handle;
  CoInitialize(Nil);
  try
    While Not Terminated do
    begin
      case MsgWaitForMultipleObjects(0,Event,False,INFINITE,QS_ALLINPUT) of
      WAIT_OBJECT_0:
      begin
        While PeekMessage(Msg,0,0,0,PM_REMOVE) do
        begin
          if Msg.hwnd = 0 Then
          begin
            Case Msg.message of
            THREAD_GETDATA:
            begin
              cdsTemp:=TClientDataSet(Pointer(Msg.wParam));
              Self.Data := Self.GetData(cdsTemp);
            end;
            THREAD_UPDATEDATA:
            begin
              cdsTemp:=TClientDataSet(Pointer(Msg.wParam));
              Self.UpdateData(cdsTemp);
            end;
            THREAD_TERMINATE:
              Terminate;
            end;
          end;
        end;
      end;
      end;
    end;
  finally
    CoUnInitialize();
  end;
end;function TDataThread.GetData(Fcds: TClientDataSet): OleVariant;
var
  ResCount: Integer;
  Params: OleVariant;
  OwerData: OleVariant;
begin
  Result:=IAppData.AS_GetRecords(Fcds.ProviderName,Fcds.PacketRecords,ResCount,1,Fcds.CommandText,Params,OwerData);
end;procedure TDataThread.UpdateData(Fcds: TClientDataSet);
var
  iErrCount: Integer;
  OwnerData: OleVariant;
begin
  IAppData.AS_ApplyUpdates(Fcds.ProviderName,Fcds.Delta,-1,iErrCount,OwnerData);
end;调用:
var
  DataThread: TDataThread;我用发送消息的形式:PostThreadMessage(DataThread.ThreadID,THREAD_GETDATA,Integer(Pointer(ClientDataSet1)),0);
来取数据:提老是在SConnect的单元里为提示出一个错误,说什么‘Invalid argument’

解决方案 »

  1.   

    自已先Top一下,兄弟们来吧,我真的没了办法了。
      

  2.   

    来不及细看,刚看一眼,发现个问题。你的这句是写在TThread.Create里面
       Res:= CoGetInterfaceAndReleaseStream(IStream(FStream),IID_IAppServer,IAppData);可是,TThread.Create。。只是创建这个线程对象,并不是这个线程的执行。。
    你至少应该写在TThread.Execute里面
      

  3.   

    谢谢兄弟,有时间帮我看看吧。还有就是
       Res:= CoGetInterfaceAndReleaseStream(IStream(FStream),IID_IAppServer,IAppData);
    不是为了线程转接用吗?他不是为了把我们传过去的FCDS的AppServer转接到我们线程类里的IAppData变量里吗?而且如果我把那个私有函数GetData(fcds:TClientDataSet)放到公共接口区,有人为调用就不会有出错,而且能取到数据。
      

  4.   

    楼主没有明白我的意思。
    我明白你是想把接口Marshal到工作线程,
    可是在TThread.Create...是在调用它的线程。。我猜你这儿是主线程。呵呵。
    并不是在你要用接口的那线程
    在TThread.Execute才是那线程执行的地方!!!要在这里面MARSHAL才对啊。
      

  5.   

    我有跟踪过,出错的地方是在SConnect单元里。出错的。我按你的意思看一下在Execute里去Marshal一下,看能不能成。谢谢了。
      

  6.   

    拜托,老兄SCONNECT单元二千多行代码,你只说异常出在里面。。
    而且你的代码有好几个地方调用进入了这个单元。。
    你难道不能跟踪到你代码中的一个准确位置吗?另外,‘Invalid argument’这东西是Variant类型检查时候报的异常,
    你特别注意检查一下用到变体类型时候。
      

  7.   

    GetData里面加上这句试试吧.Params:=Unassigned;
      

  8.   

    兄弟,你能不能把我的代码拿到机子调试一下呀。我看跟进去时,每次出错都是在:
    function TDataBlockInterpreter.LockObject(ID: Integer): IDispatch;
    begin
    -》  Result := FDispList[ID];
    end;
      

  9.   

    TO: halfdream,我按你的方法试过了,把下面的代码放到Execute里后可以执行一次,但第二次再去执行时就会出现前面的错误。
    Res:= CoGetInterfaceAndReleaseStream(IStream(FStream),IID_IAppServer,IAppData);
      

  10.   

    呵呵。。CoGetInterfaceAndReleaseStream
    你看这函数的名字,取得接口后就释放STREAM,能让你用第二次吗??
    你就不能if not Assigned(IAppData) then
                 CoGetInterfaceAndReleaseStream.....
      

  11.   

    建议用COM时避免多线程,
    很容易发生错误,又难调试
    象你的程序客户端就不能用socketConnection来连接
    你却用了SocketConnection线程间列集的问题,应该在线程的Execute代码里面coGetInterfaceAndReleaseStream,
    而不是在Create方法里面,因为调用Create方法的是主线程象你的问题,完全没有必要Marshal,直接传递一个ServerName和ServerGUID给工作线程
    然后由工作线程来创建IAppServer实例再服务主线程就可以了如果多线程概念不是很清晰就不要用COM,或者用COM就避免多线程,
    很多时候测试不充分,到用户手上的时候就容易出错
      

  12.   

    楼上的兄弟,你说我这个程序可以不用Marshal,你的那种方法我有点不懂,因为我也是开始接触这方面的知识,能不能帮我举点代码呢?我会不盛感激的。先谢了。
      

  13.   

    我改了一下您老的代码,如下:const
      THREAD_GETDATA = WM_USER+1;
      THREAD_UPDATEDATA = WM_USER+2;
      THREAD_TERMINATE = WM_USER+3;以下是自己定义的多线程类:
      TDataThread = class(TThread)
      private    IAppData: IAppServer;
      
        fHost: string;
        fPort: Integer;
        fServerGUID: string;    Function GetData(Fcds: TClientDataSet):OleVariant;
        Procedure UpdateData(Fcds: TClientDataSet);
      protected
        Procedure Execute;override;
      public
        constructor TDataThread.Create(
          //假设你用的是SocketConnection
          const Host: string;
          const Port: Integer;
          const ServerGUID: string);    end;
    constructor TDataThread.Create(
      //假设你用的是SocketConnection
      const Host: string;
      const Port: Integer;
      const ServerGUID: string);  
    var
      Res: HRESULT;
    begin
      inherited Create(False);
      FreeOnTerminate := True;
      fHost := Host; fPort := Port; fServerGUID := ServerGUID;  
    end;procedure TDataThread.Execute;
    var
      Event: THandle;
      Msg: TMsg;
      cdsTemp: TClientDataSet;  
    begin
      //在工作线程内创建一个连接,那就不必marshal了
      Event:= Self.Handle;
      CoInitialize(nil);
      try
        SocketConn := TSocketConnection.Create(nil);
        try
          SocketConn.Host := fHost;
          SocketConn.Port := fPort;
          SocketConn.ServerGUID := fServerGUID;
        
          SocketConn.Connected := True; //如果连接失败,自己找一个机制反馈给主线程吧
        
          IAppData := SocketConn.GetServer();
        
          if IAppData = nil then
            raise Exception.Create('GetServer error'); //如果失败,自己找一个机制反馈给主线程吧
          
          while not Terminated do
          begin
            case ... of
              ... //你原来的代码
          end;
        
        finally
          SocketConn.Destroy();
        end;
      finally
        CoUninitialize();
      end;
    end;function TDataThread.GetData(Fcds: TClientDataSet): OleVariant;
    var
      ResCount: Integer;
      Params: OleVariant;
      OwerData: OleVariant;
    begin
      Result:=IAppData.AS_GetRecords(Fcds.ProviderName,Fcds.PacketRecords,ResCount,1,Fcds.CommandText,Params,OwerData);
    end;procedure TDataThread.UpdateData(Fcds: TClientDataSet);
    var
      iErrCount: Integer;
      OwnerData: OleVariant;
    begin
      IAppData.AS_ApplyUpdates(Fcds.ProviderName,Fcds.Delta,-1,iErrCount,OwnerData);
    end;我也是菜鸟一个,所以你只能参考,如果不行也别骂我
    另外,没功劳也有苦劳,给分的时候,请适当给点
      

  14.   

    谢谢dbexpress,我会参考你的代码的。
      

  15.   

    看样子,这个问题也只能这样子了,不过我我还有一个问题,不知各位有没有遇到过,那就是在做三层数据库开发时,为什么数据库服务器的数据大了,就在客户端连接时会显示‘灾难性错误’呢不然就是TSocketConnect会出现'Read Socket Error'