to: manboo(横刀卫道≈≡仁者无敌√喜欢(⊙)(⊙)我的TmtsServer线程模式是Apartment你说的是不是TmtsClient也需要线程模式是Apartment?

解决方案 »

  1.   

    Sorry:更正贴中procedure TdmAccess.DataModuleCreate(Sender: TObject);
    ...
    FmtsCallBack := TmtsCallBackClient.Create;
    (应为 FmtsClient := TmtsClient.Create;)
    ...
      

  2.   

    那就是你地客户端对Apartment地MTS对象进行了无限制地线程操作,Apartment本身并不是线程安全地,Unleashed Com+上面写一一种自动匹配客户线程访问地方法,是使用ATL实现地,不好转换到Delphi!Apartment只是当每个客户端访问分配一个线程,一个线程并且存在一个对象,还是要进行消息排队地!
      

  3.   

    在你地客户端如果访问地是Apartment地Com对象,你必须在你地线程调用地时候进行初始化你地线程地消息队列Apartment地初始化方法是CoInitialize
    在你地工作完成后释放消息队列UnInitialize,如果是多线程模式地相应地必须初始化多线程地消息队列,在结束地时候释放消息队列!
      

  4.   

    to: manboo(横刀卫道≈≡仁者无敌√喜欢(⊙)(⊙)谢谢。引发我的错误已找到,就是:
    (1) ImtsClient传递到Server.SetCallBack(此时可以回调),
        此时Marshal, 结束本次调用。
    (2) Server.GetData被调用(也可能是另一个Client),此时
        Unmarshal,可以回调。现在的问题是:
    ImtsClient要重复使用,如何保存Marshal后的IStream???
      

  5.   

    如果你是使用的apartment方式的话不可能会产生两个用户访问一个MTS对象的
    ,对象应该是无状态的(理想)。
      

  6.   

    to: manboo(横刀卫道≈≡仁者无敌√喜欢(⊙)(⊙)
    你常在网上?我还怕一时找不到你呢。CSDN有了你才昌盛。是我省略了代码,未表达清我的意图,我的用法是:
    (1)每个Client登陆后,把各自的ImtsClient通过Server.SetCallBack
    传递到Server待用,结束SetCallBack调用;对象是无状态的,那就要保
    存手工保存状态(ImtsClient)。
    (2)当有Client更新数据时,通知所有相关的Client刷新本地数据。保存状态(ImtsClient):
    (1) 用ISharedProperty我不知道如何保存IStream。
    (2) 用文件保存Unmarshal时出错,代码如下:procedure TmtsServer.SetCallBack(vClientName, vCallBack: OleVariant);
    var
      fstm: TFileStream;
      ostm: TOleStream;
      stm: IStream;
    begin
      try
        OleCheck(CoMarshalInterThreadInterfaceInStream 
        (ImtsClient, vCallBack, stm));
        ostm := TOleStream.Create(stm);
        fstm := TFileStream.Create('C:\' + vClientName, fmCreate);
        fstm.Position := 0;
        fstm.CopyFrom(ostm, 0);
        fstm.Free;
        ostm.Free;
        SetComplete;
      except
        SetAbort;
        raise;
      end;
    end;procedure TmtsServer.GetData(out vData: OleVariant); safecall;
    begin
      try
        fstm := TFileStream.Create('C:\' + vClientName,
          fmOpenReadWrite);
        ostm := TOleStream.Create(stm);
        ostm.Position := 0;
        ostm.CopyFrom(fstm, 0);    OleCheck(CoGetInterfaceAndReleaseStream(stm,
           ImtsCallBackClient, mtsCallBack));
        //???报错:读磁盘错        mtsCallBack.SynchNotify(cds.Data);
        fstm.Free;
        ostm.Free;    vData := ...    SetComplete;
      except
        SetAbort;
        raise;
      end;
    end;
      

  7.   

    你有没有查过连接点方面的文档。IConnectionPoint
      

  8.   

    to nealzhao(): 
    不好意思,我用Delphi时间不长,COM了解也不多。简单的CallBack在Win98/2000下都没问题,加入到
    我的应用中后,Server/Client在Win98下不Marshal
    /Unmarshal接口也可以,但Win2000就需要Marshal
    /Unmarshal接口,这就需要保存IStream(也没用过)。这已经折腾我一周了,每每总有希望,实在不甘心放
    弃CallBack方式。看来也只有改用COM事件了,还请你
    多指教。有些文档说COM事件比较复杂,且不能通知多个Client,
    一般避免使用...是这样吗?
      

  9.   

    从COM本身来说是支持CallBack(多客户)方式的。但是我没有实战过。
    我正在查些资料。
    1.你用“msdn wicked code"在MSDN上查一下。有一个Eight Lessons from the COM School of Hard Knocks的文章,先看看。
    2.在www.codeproject.com上有关于IConnectionPoint的文章和例子,也可以参考。
    3.另外你的IStream,可以使用一个全局变量,只有当前的进程没推出,她一直存在。
    希望有些帮助。
      

  10.   

    CallBack是当有Client更新数据时(Server.UpdateData),通知所有
    相关的Client刷新本地数据,这时是另一次Server方法调用。每个Client登陆后,把各自的ImtsClient通过Server.SetCallBack
    传递到Server待用,方法调用结束,对应本次线程是否结束?还是Client端Create一个IServer后,Server就有一个对应线程,直到
    Clientt端Release该IServer?
      

  11.   

    我觉的问题是在客户端。
    将在Client的Create中创建Server对象并且建立与Server的联系。
    将其移到外边(第三方组件,客户端程序中)
      

  12.   

    刚写了半天竟未回复成功!!!
    我还是先用NotePad写比较保险。to nealzhao():你说的我已试过,还是不行。我试了一种方式://保存ImtsClient
    procedure TmtsServer.SetCallBack(vCookie, vCallBack: OleVariant);
    var
      sp: ISharedProperty;
      bExist: WordBool;
      stm, stm2: IStream;
      ostm, ostm2: TOleStream;
      h: HGLOBAL;
    begin
      try
        OleCheck(CoMarshalInterThreadInterfaceInStream(ImtsClient, vCallBack, stm));
        ostm := TOleStream.Create(stm);
        h := GlobalAlloc(GMEM_MOVEABLE + GMEM_NODISCARD + GMEM_SHARE, ostm.Size);
        OleCheck(CreateStreamOnHGlobal(h, False, stm2));
        ostm2 := TOleStream.Create(stm2);
        ostm2.Position := 0;
        ostm2.CopyFrom(ostm, 0);    sp := FspgCallBack.CreateProperty(<ClientName>, bExist);
        sp.Value := Int(h);    SetComplete;
        ostm.Free;
        ostm2.Free;
      except
        SetAbort;
        ostm.Free;
        ostm2.Free;
        raise;
      end;
    end;//回调ImtsClient
    procedure TmtsServer.SynchNotify;
    var
      sp: ISharedProperty;
      bExist: WordBool;
      I: Integer;
      stm: IStream;
      mtsCallBack: ImtsClient;
    begin
      try
        sp := FspgCallBack.CreateProperty(<ClientName>, bExist);
        if bExist and not VarIsNull(sp.Value) then
        begin
          OleCheck(CreateStreamOnHGlobal(LongWord(sp.Value), False, stm));
          OleCheck(CoUnmarshalInterface(stm, ImtsClient, mtsCallBack));
          mtsCallBack.SynchNotify(...);
        end
        else
          sp.Value := Null;
      end;
      finally
        cds.Free;
      end;
    end;但是在第二次回调时出错:“被调用对象已与其客户断开连接”
    我采用了苯法避开,Client在传送一次ImtsClient(用Server.SetCallBack)
    未完全测试,暂时Server/Client在同一PC(Win2000)下通过。我现在担心的是:
    (1)用CoUnmarshalInterface而不用CoGetInterfaceAndReleaseStream
         是否可以?(用CoGetInterfaceAndReleaseStream产生内存存取错)
    (2)CreateStreamOnHGlobal使用是否正确?
    (3)...哎,主要还是我对COM不懂,仅限于用Delphi创建个简单的MTS/COM+应用,
    也没时间学就开做,结果倒误事了,多亏有CSDN的同志们帮忙。还希望继续得到同志们的指教,多谢!!!
      

  13.   

    想提几个问题:
    1,开始时工程时使用的线程模式?
    2,开始时工程使用的实例模式?
    3,apartment 的transaction 模式?suppor?new?...
    4, 我觉得要是保留状态的话,使用shared property group manager 是最好的选择,因为mts内部的很多机制我们也不是很精通?
    5,注意客户端的transaction,否则客户端会去连接一个已经释放的对象,因为mts使用了很多pooling技术。这些都只是参考!
      

  14.   

    to wolfhe(城墙): >1,开始时工程时使用的线程模式?
    >2,开始时工程使用的实例模式?initialization
      TAutoObjectFactory.Create(ComServer, TmtsServer, Class_mtsServer,
        ciMultiInstance, tmApartment);>3,apartment 的transaction 模式?suppor?new?...
    >4, 我觉得要是保留状态的话,使用shared property group manager 是最好
    >的选择,因为mts内部的很多机制我们也不是很精通?
    我把IStream放在HGLOBAL指向的内存中,而在sp.Value中保存HGLOBAL指针,是因为我不知如何用sp.Value保存IStream。我的应用中用了几组 shared property,但其会自动释放,下一步还得这个问题,你是如何解决的?
    >5,注意客户端的transaction,否则客户端会去连接一个已经释放的对象,
    >因为mts使用了很多pooling技术。
    我不理解“客户端的transaction”(因为我对Delphi和MTS/COM+所知有限)。
      

  15.   

    SPGM是MTS/COM+套件组共享的单位,一旦套件组中的MTS/COM+对象释放之后,SPGM中的保留的状态信息也会释放,所以关键问题是让客户端结束方法的调用之后,对象没有被释放.我不知道你的状态是全部客户端结束以后就释放,还是全部客户端结束以后都不要释放,或者叫做永久保留。如果是前一种,可以在显示的进入COM执行环境,然后显示的推出执行环境,推荐在客户端类别声明时声明COM+对象就可以了。
    至于客户端的transaction,如果为new,只要客户端技术以后需要重新连接,那么就要重新建立com+对象,无论原来的是否已经释放,如果suppor,如果还有就使用原来的,如果non_support,那么有就连接,没有就连接失败。我觉得也可能和客户端的transaction有关。
      

  16.   

    我地意思是恐怕有调用重入地问题
    A->B->A这种情况。
    你可否做个判断,不去调用请求数据更新地Client地CallBack。
      

  17.   

    1.你的Client是不是一个COM对象?你为什吗用TmtsClietn.Create实例化一个对象。
    2.也许你可以考虑一下这个结构。
      单独创建一个CallBackServer地MTS对象管理回调问题。
      ICallBackServer = interface
         Advise( aClient : ICallBackIntf; aCookie : PInteger);
         UnAdvise( aCookie : PInteger);
         UpdateClient;
      end;
      这个组件单独地放在一个Package中,TimeOut时间设为无限。
      
      

  18.   

    我做了一个很简单的DEMO。
    一个MTS组建。UpdateData时回调Client更新数据。
    如果要实用还需要加入共享资源保护的代码...
    不知道对你有没有帮助。
    如果需要我可以email给你
      

  19.   

    to 大家: 
    不好意思,刚上网。我周日陪家里客人,未到公司。
    上班比较累,所以我家里未有PC.感谢大家的帮助,我对MTS/COM+还比较模糊,还不能与各位很好对话,
    我先应付任务,然后赶快比较系统地学习MTS/COM+后,再向你们请教,
    并改进我的程序。我想多给分,如何给?如果另贴又怕被删除。to nealzhao() :
    非常需要,我的email:[email protected]
    多谢!!!
      

  20.   

    to nealzhao() :
    我已收到,对我很有用,再次表示感谢!!!
      

  21.   

    为表示感谢,另贴 http://www.csdn.net/expert/topic/975/975901.xml?temp=.4041864 加分,请三位去回复:neelzhao()
    manboo(折翼天使在红叶飞舞)
    wolfhe(城墙)