因为通讯速度慢,所以为了使得客户端不处于傻等状态,我想使用多线程与服务器通讯,但是一开始连接,就出现“尚未调用CoCoInitialize”异常,但是我明明已经调用了,请各位指教。
服务器:dbExpress
客户端:TClientDataSet,TDOMConnect

解决方案 »

  1.   

    CoInitialize需要全局调用,我认为你的com模型是apartment,对吧?这个问题对于VC也是一样,你要用全局调用,而且把ThreadModal设置为Both,你不会在线程代码里边初始化吧?不要写在那里!
      

  2.   

    to lesstif():
    还是不行。另外,“尚未调用CoCoInitialize”异常是客户端产生的,在线程里一连接服务器就产生这个错误,而这时根本就没有连接到服务器,应该不关服务器的事。我跟踪程序,出错的语句是SetAppServer(CreateRemoteComObject(Computer,GetServerCLSID) as IDispatch,位于MConnect单元的DoConnect函数。
      

  3.   

    最终的错误是CoCreateInstanceEx这个API函数,是在CreateRemoteComObject函数中调用的。
      

  4.   

    试试CoInitializeEx(...) 使用 COINIT_MULTITHREADED 参数,我还在看MSDN文档。
      

  5.   

    CoInitializeEx(NULL, COINIT_MULTITHREADED)
                           ^^^^^^^^^^^^^^^^^
                             dwCoInit
    Return Values
    S_OK indicates that the COM library was initialized successfully. S_FALSE indicates that the COM library is already initialized. The standard return values E_INVALIDARG, E_OUTOFMEMORY, and E_UNEXPECTED are also supported.The dwCoInit parameter specifies the type of concurrency control required by objects created by this thread. Windows CE supports only the multi-threaded concurrency control. Thus, COINIT_MULTITHREADED is the only option permitted for the dwCoInit parameter.
      

  6.   

    CoInitializeEx(COINIT_APARTMENTTHREADED)
      

  7.   

    to shines:
    不行。已经加到200分了,如果觉得分少了,还可以再加。
      

  8.   

    看看 http://expert.csdn.net/Expert/topic/1235/1235362.xml?temp=.2096369
      

  9.   

    应该同样道理,就象线程 Execute中 使用 ADO 接口,需要 初始化接口,用完后释放接口 procedure TTest.Execute;
    var
      a : TADOQuery ;
    begin
      CoInitialize(Nil) ;
      a := TADOQuery.Create(Nil) ;
      with a do
      begin
        ... ;
      end ;
      CoUninitialize ;
      a.Free ;
    end ;说的不对莫怪:)
      

  10.   

    http://expert.csdn.net/Expert/topic/237/237948.xml?temp=.8294336
      

  11.   

    请在线程开始执行的地方调用CoInitialize(Nil),这样才对,在主线程中调用是没有用的,实际上主线程在Application初始化的时候就调用过了。wjlsmail(计算机质子)的代码是正确的。如果你用DCOMConnection连接服务器,那么你必须在主线程中进行连接操作,进行连接,就意味着创建com对象,在一个自由线程中创建对象,你要想清楚是不是有必有,主线程则肯定是一个套间线程,他有消息循环,这样无论对于设计com组件还是在其他线程中使用com都会简单化,不会很复杂。不过Dcom通常都是进程外服务器,同步和列集都是要通过套间的,不会有问题。但是如果服务器是一个DLL,也就是说是一个进城内服务器你就要遵守我上面说的原则了。但是不管怎么样,你都要在自己的线程中调用CoInitialize!
      

  12.   

    补充一点,如果你不打算在自己的线程内进行连接,那么就可以不掉用CoInitialize,可以调用CoInitializeEx,而让自己的线程成为自由线程,也不必进行同步处理,因为对象存在于主线程中,对他的调用总是通过消息机制传达的,不存在同步问题。早期的com版本不支持自由线程,所以必须使用CoInitialize,CoInitializeEx的调用可以有选择的让调用线程成为自由线程还是套间线程,如果没有什么很大的必要,就使用CoInitialize让自己的线程成为套间线程。这样com使用也简单了。如果支持自由线程,服务器com的模型就应该是free或者Both,表示支持自由线程或者既支持自由线程也支持套间线程。支持自由线程的com要注意的是,调用不会通过消息机制来串列化,要注意保护内部数据的安全。支持套间线程的com就只需要关心全局数据的安全。
      

  13.   

    先谢谢上面各位。
        我把问题再说说吧,这是我正在编写的CSDN版主管理工具(CSDN在线)的客户端程序,虽然以前程序写过不少,但是MIDAS还是第一次实用,想不到遇到了麻烦。
        因为用到了WebBrowser控件,所以在主线程开始时我调用了OleInitialize。开始还顺利,连接服务器、查询都很好,后来想到网络超时会造成漫长的等待,所以想用线程操作数据通讯,而主线程只处理数据、控制数据交换。这是就出现了上面的问题,我无法用线程操作。
        再说明一下,这是在客户端的代码,同时,上面的各位的方法我都试过了,都无效。我怀疑是否与主线程用了WebBrowser控件有关,因为我在查询线程中调用CoInitialize返回1(无效的操作),我删调主线程的OleInitialize也一样出这个错。
      

  14.   

    还有一个问题,我服务器端用dbExpress控件,发现无法调用存储过程,
    帖子见http://expert.csdn.net/Expert/topic/1477/1477865.xml
    内容如下:
    怎样使用TSQLStoreProc调用SQL Server的存储过程呢(有参数的)?我调用时总是弹出错误窗口:
    List index out of bounds (0)
      

  15.   

    开发语言:服务器用Delphi,客户端用C++ Builder
      

  16.   

    我同意 BlueTrees(蜗牛) 的观点,原因主要在此处,另外,我认为你的线程封装的有问题。
      

  17.   

    下面的在我的电脑上行不通,我试了n遍了
    procedure TTest.Execute;
    var
      a : TADOQuery ;
    begin
      CoInitialize(Nil) ;              // 此处返回1,无效的调用
      a := TADOQuery.Create(Nil) ;
      with a do
      begin
        ... ;
      end ;
      CoUninitialize ;
      a.Free ;
    end ;
      

  18.   

    没有 uses ActiveX ? 下面是我的例子, Delphi 6 通过----------------------------------------------------unit UThTest;interfaceuses
      Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
      Dialogs, StdCtrls, DB, ADODB,ActiveX ;type
      TTest = class(TThread)
      private
        { Private declarations }
        procedure s ;
      protected
        procedure Execute; override;
      end;var
      i : Integer ;implementation{ Important: Methods and properties of objects in VCL or CLX can only be used
      in a method called using Synchronize, for example,      Synchronize(UpdateCaption);  and UpdateCaption could look like,    procedure TTest.UpdateCaption;
        begin
          Form1.Caption := 'Updated in a thread';
        end; }{ TTest }uses Unit1 ;procedure TTest.Execute;
    var
      a : TADOQuery ;
    begin
      { Place thread code here }
      CoInitialize(Nil) ;
      a := TADOQuery.Create(Nil) ;
      with a do
      begin
        ConnectionString := 'Provider=SQLOLEDB.1;Persist Security Info=False;'
                     + 'User ID=sa;Initial Catalog=Test;Data Source=Mine';
        Sql.Text := 'select *  from TableName ' ;
        Open ;
        for i := 0 to 100 do
        begin
          Application.ProcessMessages ;
          Sleep(100) ;
          Synchronize(s) ;
        end ;
      end ;
      CoUninitialize ;
      a.Free ;
    end;procedure TTest.s ;
    begin
      Form1.Label1.Caption := IntToStr(i) ;
    end ;end.
      

  19.   

    to wjlsmail(计算机质子):
    CoInitialize(Nil) ;返回1
    看来有可能是控件之间的冲突引起的。
      

  20.   

    to xingzhou(往事悠悠,网事幽幽) :  在我这边没有问题;要不你给我邮件,程序、数据打包给你,供你参考
      

  21.   

    谢谢 wjlsmail(计算机质子) 
    [email protected]
      

  22.   

    xingzhou(往事悠悠,网事幽幽) :不客气,望对你有帮助
    请收邮件
      

  23.   

    还要啰嗦两句:如果你使用TSocketConnection,那么连接以后就会在客户端生成一个代理接口,这个接口并非通过Com的库生成的,使用它的APPServer,要自己同步,这个接口是delphi生成的伪接口,所以我很奇怪哦!这个接口的使用不需要初始化Com的。
      

  24.   

    to:wjlsmail
    收到了,非常感谢,无论对否,我都至少为你准备100分。
      

  25.   

    应该是因为ADO的线程不安全性,考虑每个线程使用一个会话,使用多个ADOConnection应该可以解决这问题,但不可避免的带来消耗服务器资源过多的问题!
      

  26.   

    建议使用winapi函数建立多线程试试
      

  27.   

    请看看下面的类似代码,就是不能正常,一执行ds->Open,就出错。TReadData *ReadData = NULL;__fastcall TReadData::TReadData(bool CreateSuspended)
        : TThread(false)
    {
    //    m_Result = CoInitialize(NULL);
    //    m_Result = CoInitializeEx(NULL,COINIT_MULTITHREADED );
        m_Result = CoInitializeEx(NULL,COINIT_APARTMENTTHREADED  );
    }
    //---------------------------------------------------------------------------
    __fastcall TReadData::~TReadData()
    {
        if(S_OK == m_Result)
        {
            CoUninitialize();
        }
    }
    //---------------------------------------------------------------------------
    void __fastcall TReadData::Execute()
    {
        //---- Place thread code here ----
        Screen->Cursor = crHourGlass;
        try
        {
                TDCOMConnection *dconn = new TDCOMConnection(Application);
                dconn->ComputerName = "192.168.5.43";
                dconn->ServerGUID = "{F6D531CF-8FF4-4BF6-AC5C-53186CFA4921}";
                TClientDataSet *ds = new TClientDataSet(Application);
                ds->RemoteServer = dconn;
                ds->ProviderName = "dspReadOnly";
                ds->CommandText = "select * from Expert_Big_Class";
                Form1->Caption = ds->CommandText;
                ds->Open();
                Form1->Caption = "成功打开了数据库";
        }__finally
        {
            Screen->Cursor = crDefault;
        }
    }
    //---------------------------------------------------------------------------
      

  28.   

    Form1->Caption = ds->CommandText;
                ds->Open();
                Form1->Caption = "成功打开了数据库";是在这里出错嘛?
    出错信息是什么?
    你的TDataSetProvider的AllowCommandText设为True;了嘛?
      

  29.   

    出错信息是什么?最有可能就是楼上说的低级错误。你的这个300分好难赚啊!呵呵。Execut里面也没有初始化Com库啊?你是不是只摘录了一小段?你不会在TThread的Create里面初始化吧?那个Create是在主线程当中执行的嘛!你在那里面初始化没有用地。把出错的信息也贴出来,这样才好讨论啊!
      

  30.   

    出错的信息就是“尚未调用CoCoInitialize”。
      

  31.   

    to  BlueTrees(蜗牛)
    哎,我的确在这里犯了低级错误,下面这样在测试的小程序里的确可以了,我在原始的工程里试试后再看看。
    void __fastcall TReadData::Execute()
    {
        //---- Place thread code here ----
        Screen->Cursor = crHourGlass;
        m_Result = CoInitializeEx(NULL,COINIT_APARTMENTTHREADED  );
        try
        {
                TDCOMConnection *dconn = new TDCOMConnection(NULL);
                dconn->ComputerName = "192.168.5.43";
                dconn->ServerGUID = "{F6D531CF-8FF4-4BF6-AC5C-53186CFA4921}";
                TClientDataSet *ds = new TClientDataSet(NULL);
                ds->RemoteServer = dconn;
                ds->ProviderName = "dspReadOnly";
                ds->CommandText = "select * from Expert_Big_Class";
                ds->Open();
                Application->MessageBoxA("成功打开了数据库","成功",IDOK);
        }__finally
        {
            Screen->Cursor = crDefault;
            if(S_OK == m_Result)
            {
                CoUninitialize();
            }
        }
    }
      

  32.   

    呵呵,我总算可以查询了,看来解决问题应该没有大问题了。我的原始代码的确也是在线程中调用CoInitializeEx的,但是为什么就是无效的调用呢?可能是其他的地方出现了毛病,但是已经与本贴无关了,散分,本贴的分
    shines(Othelloing) :100
    wjlsmail(计算机质子) :100
    BlueTrees(蜗牛)    :100
    谢谢上面3维,同时谢谢所有其他跟贴的朋友,请你们到http://expert.csdn.net/Expert/topic/1504/1504206.xml领分。
      

  33.   

    蜗牛兄的建议有理,改成这样试过没?void __fastcall TReadData::Execute()
    {
        CoInitializeEx(NULL,COINIT_APARTMENTTHREADED  );
        //---- Place thread code here ----
        Screen->Cursor = crHourGlass;
        try
        {
                TDCOMConnection *dconn = new TDCOMConnection(Application);
                dconn->ComputerName = "192.168.5.43";
                dconn->ServerGUID = "{F6D531CF-8FF4-4BF6-AC5C-53186CFA4921}";
                TClientDataSet *ds = new TClientDataSet(Application);
                ds->RemoteServer = dconn;
                ds->ProviderName = "dspReadOnly";
                ds->CommandText = "select * from Expert_Big_Class";
                Form1->Caption = ds->CommandText;
                ds->Open();
                Form1->Caption = "成功打开了数据库";
        }__finally
        {
            Screen->Cursor = crDefault;
        }
        CoUninitialize();
    }
      

  34.   

    请继续http://expert.csdn.net/Expert/topic/1516/1516023.xml
      

  35.   

    你有TClientDataSet,TDOMConnect是在主线程中创建的,所以在子线程中是不能够调用的,你可以把连接参数传入到子线程中,在子线程创建TClientDataSet,TDOMConnect,想怎么用都OK啦