在dll中动态创建XmlDoc并操作的接口函数中首尾对应写了ActiveX.Coinitialize与CoUninitialize,结果运行到DLL中的CoUninitialize有无法捕获的异常,如果dll中不加这两句代码而加在Exe中则没有问题.有朋友告诉我说把后面的CoUninitialize代码注释掉.
若在DLL中不调用CoUninitialize会有什么问题?delphi的帮助文档中说
Comments
Typically, CoInitialize is called only once in the process that uses the OLE library. There can be multiple calls, but subsequent calls return S_FALSE. To close the library gracefully, each successful call to CoInitialize, including those that return S_FALSE, must be balanced by a corresponding call to the CoUninitialize function.
最后一句说每个CoInitialize的调用都要有CoUninitialize来一一对应.请高手指点....THX

解决方案 »

  1.   

    不仅仅只是一一对应,并且要求是在同一线程当中。对于DLL,最好放到DllEntry当中
    procedure DllEntry(Reason: Integer);
    begin
      case Reason of
        DLL_PROCESS_ATTACH,
        DLL_THREAD_ATTACH:CoInitialize;    DLL_PROCESS_DETACH,
        DLL_THREAD_DETACH:CoUninitialize;
      end;
    end; 
      

  2.   


    用这样的方法CoUninitialize是不会异常,但为什么写成如下就会有无法捕获的异常了呢?
    function AAA:WideString;stdcall;
    begin
      CoInitializa(nil);
      ......
      ......
      CoUninitialize;  //执行至此则异常
    end;
      

  3.   

    在COM当中大部分用到的是接口,当你的接口还没有释放之前就执行CoUninitialize,那么这些接口就会被释放掉,但是由于这些接口编译器所编译的代码当中就存在释放代码,所以又会去执行这部分代码,如此就异常了。
      

  4.   


    首先感谢您的回复.但还有不明:
    我在function AAA:WideString;stdcall;中动态创建了Component和XmlDocument对象(局部变量),并均在函数体内调free释放,且代码全包含在CoInitialize与CoUninitialize之间,不明白为什么这样也会有问题,而且还是无法捕获的异常.
      

  5.   

    不清楚你具体如何写法。其实个人比较建议的办法是,在线程需要操作COM的线程当中去初始化,即线程的Execute当中。之所以在DLL当中处理,为的是防止别人在使用的时候存在不方便。
      

  6.   

    EXE的窗体中就一个BUTTON及ONCLICKprocedure TForm1.Button1Click(Sender: TObject);
    var
      ret:WideString;
    begin
      ret:=GetXmlStr;  //声明于DLL中的接口
      ShowMessage(ret);
    end;Dll中接口代码function GetXmlStr:WideString;stdcall;
    var
      AComp:TComponent;
      AXml:TXmlDocument;
    begin
      Activex.CoInitialize(nil);
      try
        AComp:=TComponent.Create(nil);
        AXml:=TXmlDocument.Create(AComp);
        try
          AXml.Active:=True;
          AXml.DocumentElement:=AXml.CreateNode('TestRoot');
          AXml.DocumentElement.Attributes['DateTime']:=FormatDateTime('YYYYMMDDHHMMSSZZZ',Now);
          Result:=AXml.XML.Text;
        finally
          AXml.Free;
          AComp.Free;
        end;
      except on e:Exception do
        Result:=e.Message;
      end;
    //  try
        activex.CoUninitialize;
    //  except on e:Exception do
    //    Result:=Result+'===='+e.Message;
    //  end;
    end;
    已经是很简单的了 所以一直想不明白.
      

  7.   

    不知道异常信息是什么样的?AXml.Free;
    后面增加一条
    AXml := Nil;
    看看是否有效。
      

  8.   

    加一句AXml:=Nil;无效
    把AXml.Free改为FreeAndNil(AXml)也无效
    执行到CoUninitialize会报Access Violation
    若将最后的try except取消注释 此处无法捕获取异常信息
      

  9.   

    在调用主程序中添加下面代码试试:
    initialization 
       CoInitializeEx(nil,COINIT_MULTITHREADED);
    finalization
       CoUninitialize;
      

  10.   

    还是建议写到 entry 中,好像 xxx.free 会调用需要系统自动释放的东西
    要把你在 CoUninitialize 之前加 sleep() 和 peekmessage 试一试
      

  11.   

    首先要搞清楚CoInitialize是做什么用的。初始化COM库的。 如果只是在主线程中用到COM组件,当然工作线程就没必要进行CoInitialize。 如果两个线程中要用同一个COM组件,并都是STA的话,那么就是跨套间了。 
    比如在主线程中获得了COM对象的接口,并要把接口传入到工作线程中使用,那么需要对接口进行列集散集 
    用到API为 CoMarshalInterThreadInterfaceInStream 和 CoGetInterfaceAndReleaseStream 对于没有调用CoUninitialize,后面如要再调用CoInitialize时就会失败了。 
    程序不出错不代表没有问题。应当成对调用。