乡下人产国偷v产偷v自拍,国产午夜片在线观看,婷婷成人亚洲综合国产麻豆,久久综合给合久久狠狠狠9

  • <output id="e9wm2"></output>
    <s id="e9wm2"><nobr id="e9wm2"><ins id="e9wm2"></ins></nobr></s>

    • 分享

      COM深入編程學(xué)習(xí)筆記2

       aaie_ 2012-10-16

      COM深入編程學(xué)習(xí)筆記2 

      0.接口授權(quán)

          假設(shè)讀者有個(gè)經(jīng)過慎重考慮后產(chǎn)生的類叫做TObject1,它實(shí)現(xiàn)Iinterface1。讀者想要?jiǎng)?chuàng)建一個(gè)名為TCombinedObject的
          
      的類,它實(shí)現(xiàn)Iinterface1船1和Iinterface2。好像是需要重新實(shí)現(xiàn)Iinterface1的方法,可能要從TObject1復(fù)制源代碼到

      TCombinedObject,對嗎?

          不必這樣。Delphi可讓讀者把一個(gè)接口的實(shí)現(xiàn)授權(quán)給另一個(gè)類。授權(quán)意味著:一個(gè)類包含針對另—個(gè)類的指針。
          
      內(nèi)部類實(shí)現(xiàn)一個(gè)或多個(gè)接口的功能性。外部類簡單地將這些方法傳遞給內(nèi)部類,而不是重新實(shí)現(xiàn)接口。
          
          下列代碼實(shí)現(xiàn)TObject1類中的Iinterface1接口。TCombinedObject包含Tobject1引用,并且授權(quán)Iinterface1到

      Fobjl的實(shí)現(xiàn)。

        Iinterface1 = interface
          ['{2DE825C1-EADF-11D2-B39F-0040F67455FE}']
          function Dolt1:integer;
        end;

        Iinterface2 = interface
          ['{2DE825C1-EADF-11D2-B39F-0040F67455FE}']
          function Dolt2:integer;
        end;
       
        TObject1 = class(TinterfaceObject,Iinterface1)
          protected
             function Dolt1:integer;
        end;
       
        TCombinedObject = class(TinterfaceObject,Iinterface1,Iinterface1)
          private
            FObj1:Iinterface1;
          public
            function Dolt2:integer;
            property MyIntface:Iinterface1 read FObj1 implements Iinterface1;
        end;
       
        //在使用中可以如下:
       
        procedure TForm1.btn1OnClick(Sender:TObject);
        var
          I1:Iinterface1;
          I2:Iinterface2;
        begin
          I2 := TCombinedObject.Create();
          I2.Dolt2();
          
          I1 := I2 as Iinterface1;
          I1.Dolt1();
        end;

          注意:I2 as Iinterface1語句將Iinterface2接口從TCombinedObject對象中自動(dòng)分離出來即使Iinterface1實(shí)際上

      是由TOjbect1實(shí)現(xiàn)的。這就是授權(quán)的美鈔之處:用戶的代碼不必在意接口實(shí)際上是如何實(shí)現(xiàn)的。

      在windows注冊表(Registry),有一個(gè)鍵HKEY_CLASSES_ROOT\CLSID
      打開該節(jié)點(diǎn),發(fā)現(xiàn)一行行的GUID。

          每個(gè)CLSID或GUID都代表一個(gè)COM接口的實(shí)現(xiàn)。例如,列在CLSID第一個(gè)的是
          {00000010-0000-0010-8000-00AA006D2AE4}
          該CLSID把接口提供給miscrosoft數(shù)據(jù)訪問對象(DAO),即DAO引擎。
          其GUID下面的InprocServer32鍵包含windows使用的信息用來在電腦中定位DA0.DLL。
         
      1.COM對象和類廠(class factories)   
       
          一個(gè)COM對象位于DLL或exe。位于DLL中的COM對象被引用為進(jìn)程內(nèi)服務(wù)器。位于ExE中的COM對象被引用為進(jìn)程外服務(wù)器。

      在本章后面將討論進(jìn)程內(nèi)和進(jìn)程外服務(wù)器。

          COM服務(wù)器可以包含一個(gè)或COM對象。COM對象在下面小節(jié)中討論。
       
        1)COM對象
        //Delphi封裝的可以實(shí)現(xiàn)COM對象的類,不能從TInterfacedObject派生,而是直接從IUnknown接口派生
        TComObject = class(TObject, IUnknown, ISupportErrorInfo) //所有COM對象的基類
        private
          FController: Pointer;
          FFactory: TComObjectFactory;
          FNonCountedObject: Boolean;
          FRefCount: Integer;
          FServerExceptionHandler: IServerExceptionHandler;
          function GetController: IUnknown;
        protected
          { IUnknown }
          function IUnknown.QueryInterface = ObjQueryInterface; //映射IUnknown.QueryInterface方法
          function IUnknown._AddRef = ObjAddRef;                //映射IUnknown._AddRef方法
          function IUnknown._Release = ObjRelease;              //映射IUnknown._Release方法
          { IUnknown methods for other interfaces }
          function QueryInterface(const IID: TGUID; out Obj): HResult; stdcall;
          function _AddRef: Integer; stdcall;
          function _Release: Integer; stdcall;
          { ISupportErrorInfo }
          function InterfaceSupportsErrorInfo(const iid: TIID): HResult; stdcall;
        public
          constructor Create;
          constructor CreateAggregated(const Controller: IUnknown);
          constructor CreateFromFactory(Factory: TComObjectFactory;
            const Controller: IUnknown);
          destructor Destroy; override;
          procedure Initialize; virtual;
          function ObjAddRef: Integer; virtual; stdcall;
          function ObjQueryInterface(const IID: TGUID; out Obj): HResult; virtual; stdcall;
          function ObjRelease: Integer; virtual; stdcall;
      {$IFDEF MSWINDOWS}
          function SafeCallException(ExceptObject: TObject;
            ExceptAddr: Pointer): HResult; override;
      {$ENDIF}
          property Controller: IUnknown read GetController;
          property Factory: TComObjectFactory read FFactory;
          property RefCount: Integer read FRefCount;
          property ServerExceptionHandler: IServerExceptionHandler
            read FServerExceptionHandler write FServerExceptionHandler;
        end;
        {$EXTERNALSYM TComObject}   
       
        2) HResult 和 OleCheck
           在COM編程中,大多數(shù)函數(shù)(除了_AddRef和_Release)都返回HResult類型的一個(gè)值。HResult是一個(gè)特殊的返回值,
        
         意味著函數(shù)調(diào)用成功還是失敗,如果失敗的話它也包含一個(gè)錯(cuò)誤代碼。
       
          OleCheck(MyComObject.SomeFunction);
          OleCheck(MyComObject.SomeOtherFunction);
          當(dāng)調(diào)用返回HResult的COM函數(shù)時(shí)就應(yīng)使用OleCheck()來檢查返回值是否成功。
          {
              procedure OleCheck(Result: HResult);
              begin
                 if not Succeeded(Result) then OleError(Result); //如果成功則返回S_OK =0,否則拋出異常
              end;
             
              procedure OleError(ErrorCode: HResult);
              begin
                    raise EOleSysError.Create('', ErrorCode, 0);
              end;
             
              function Succeeded(Res: HResult): Boolean;
              begin
                    Result := Res and $80000000 = 0;
              end;       
          }
         
         3)類工廠
         
          COM對象不是由應(yīng)用程序直接例示的。相反,COM使用類工廠來創(chuàng)建對象。類工廠是一個(gè)對象,該對象的明確目的就是
         
       創(chuàng)建其它對象。每一個(gè)COM對象都有一個(gè)相關(guān)的類工廠。該類工廠負(fù)責(zé)創(chuàng)建在服務(wù)器中實(shí)現(xiàn)的COM對象。
         
          類廠把COM從實(shí)際構(gòu)造一個(gè)對象的過程中分離出來。如果不是有了類廠.COM就必須直接調(diào)用對象的構(gòu)造函數(shù)以便創(chuàng)建對象。
         
      COM對于如何實(shí)現(xiàn)COM對象沒有任何限制,并其構(gòu)造是實(shí)現(xiàn)過程的完整部分,因此COM沒有對象構(gòu)造過程的直接信息是很重要的。

          盡管DLL可以提供COM可能調(diào)用的來創(chuàng)建一個(gè)對象實(shí)例的標(biāo)準(zhǔn)函數(shù),但EXE并不可以。例如,DLL可能輸出一個(gè)名為
         
      ConstractMyComObject的函數(shù).然后當(dāng)需要?jiǎng)?chuàng)建MyComObject實(shí)例時(shí)告訴COM調(diào)用此函數(shù)。

          當(dāng)創(chuàng)建EXE時(shí)必須注冊它們的類廠,并其COM調(diào)用類廠接口以便創(chuàng)建COM對象。為保持一致,DLL按照和EXE相同的方式創(chuàng)建

      并注冊類廠。  類廠支持IClassFactory接口,它的定義如下:

        IClassFactory = interface(IUnknown)
          ['{00000001-0000-0000-C000-000000000046}']
          function CreateInstance(const unkOuter: IUnknown; const iid: TIID;
            out obj): HResult; stdcall;
          function LockServer(fLock: BOOL): HResult; stdcall;
        end;

          正如讀者所見,IIClassFactory只定義兩個(gè)函數(shù):CreateInstance和LockServer。
         
          CreateInstance是負(fù)責(zé)創(chuàng)建類廠涉及的COM對象的實(shí)例的函數(shù)。一般來說讀者自己不調(diào)用此函數(shù)。將看到的是,
         
      COM為讀者調(diào)用此函數(shù)。

          當(dāng)沒有在運(yùn)行的客戶使用服務(wù)器時(shí),刪服務(wù)器就會(huì)從內(nèi)存中卸載??梢哉{(diào)用LockServer來迫使服務(wù)器保存在內(nèi)存中。
         
      調(diào)用LockServer(TRUE)來增加內(nèi)部鎖的計(jì)數(shù)。調(diào)用LockServer(False)來降低鎖的計(jì)數(shù)。當(dāng)鎖的計(jì)數(shù)為零時(shí),如果沒有

      客戶調(diào)用服務(wù)器的話,就有可能從內(nèi)存中卸裁服務(wù)器。

          注意:必須平衡LockServer(TRUE)和LockServer(FALSE)的調(diào)用才能使系統(tǒng)正常進(jìn)行。向LockServer(TRUE)發(fā)出
         
      調(diào)用而沒有調(diào)用相應(yīng)的LockServer(FALSE)就會(huì)使COM服務(wù)器永遠(yuǎn)駐留在內(nèi)存中。

       

      2.進(jìn)程內(nèi)的服務(wù)器(In-Process COM Server)   
       
         我們要看的第一個(gè)COM服務(wù)器是個(gè)進(jìn)程內(nèi)服務(wù)器。
        
         進(jìn)程內(nèi)服務(wù)器是由于它們在DLL內(nèi)實(shí)現(xiàn)而獲得這個(gè)名稱的。因此,服務(wù)器占據(jù)了和使用它的應(yīng)用程序一樣的地址空間(進(jìn)程)。
        
      所有的進(jìn)程內(nèi)COM服務(wù)器輸出四個(gè)標(biāo)準(zhǔn)函數(shù): 
        DllGetClassObject,
        DllCanUnloadNow,
        DllRegisterServer,
        DllUnregisterServer;
        Borland已在Delphi中提供了這些函數(shù)的缺省實(shí)現(xiàn)。因此,讀者不必自己編碼這些函數(shù),但是應(yīng)該理解它們的用途。
       
        2.1 線程支持(Treading Support)
       
          線程支持只適合于進(jìn)程內(nèi)服務(wù)器,并且不適用于進(jìn)程外服務(wù)器。進(jìn)程內(nèi)服務(wù)器可以附著在幾個(gè)線程模型中的一個(gè)。
         
          進(jìn)程內(nèi)服務(wù)器的線程模型被存在windows注冊表中。接口服務(wù)器可支持的線程模型是:
         
          1)單一的。單線程COM對象實(shí)際上根本沒有線程支持。所有對COM服務(wù)器的訪問都是由windows來順序執(zhí)行的,
                     因此不必?fù)?dān)心多個(gè)線程會(huì)同時(shí)訪問服務(wù)器。所有COM服務(wù)器的訪問都存在于線程,在此創(chuàng)建了COM服務(wù)器DLL。
                    
          2)公寓線程(Apartment)。公寓-線程(或有時(shí)叫做單線程公寓)的COM對象可以只處理來自創(chuàng)建它們的線程的請求。
                                  一個(gè)服務(wù)器可以輸出一些COM對象,并且每個(gè)COM對象可以從一個(gè)不同的線程中創(chuàng)建。
                                  所以,通過使用互斥體、事件、臨界部分或其它同步方法訪問在服務(wù)器中定義的任何
                                  全局?jǐn)?shù)據(jù)必須是同步的。
          3)自由的。自由線程服務(wù)器移走公寓-線程服務(wù)器施加的限制。在自由線程模型中,多個(gè)線程在任何給定COM對象上可以
                     同時(shí)運(yùn)行。因此,不僅必須同步訪問全局?jǐn)?shù)據(jù),而且對于多個(gè)線程訪問的全局?jǐn)?shù)據(jù)訪問必須也是同步的。
                    
          4)同時(shí)公寓線程和自由線程。支持此選項(xiàng)的COM服務(wù)器附著在公寓線程模型和自由線程模型二者之上。這是最難支持的
                                     線性模型,因?yàn)橹С止⒕€程和自由線程二者的COM服務(wù)器必須使他們自己對于公寓線程
                                     對象實(shí)例和整個(gè)線程的排列參數(shù)數(shù)據(jù)的訪問是同步的
                                    
         2.2 注冊服務(wù)器
           
            所有的COM服務(wù)器需要用windows注冊表來正常工作。注冊過程包括創(chuàng)建進(jìn)入windows注冊表所需的條目以便windows知道
           
            服務(wù)器(進(jìn)程內(nèi)的或進(jìn)程外的)的位置和類。
           
            regSvr32  <ServerName>注冊
            regSvr32 -u <ServerName>注銷

          2.3 定制構(gòu)造函數(shù)
           
            不要試圖重載一個(gè)COM對象的構(gòu)造函數(shù)。TComObject中定義的構(gòu)造函數(shù)都調(diào)用了虛方法函數(shù)Initialize。
           
         如果需要為自己的COM對象提供初始化代碼,只需重載Initialize方法。

          2.4 創(chuàng)建一個(gè)進(jìn)程內(nèi)COM對象的實(shí)例
         
           當(dāng)用戶需要在自己的客戶程序代碼中創(chuàng)建一個(gè)進(jìn)程內(nèi)COM對象時(shí),一般會(huì)使用CreateComObject函數(shù):
           function CreateComObject(const ClassID: TGUID): IUnknown;
           //封裝了CoCreateInstance
           function CreateComObject(const ClassID: TGUID): IUnknown;
           begin
               OleCheck(CoCreateInstance(ClassID, nil, CLSCTX_INPROC_SERVER or
              CLSCTX_LOCAL_SERVER, IUnknown, Result));
           end;
         
           //如下也是可以的使用CreateRemoteComObject,多加一個(gè)遠(yuǎn)程機(jī)器的名稱,這樣服務(wù)器端和客戶端可以在兩個(gè)機(jī)器上
           //  ifn := CreateRemoteComObject('DC2D51F3248443E',CLASS_FORMAT) as IFormattedNumber;

          一個(gè)需要注意的是:coCreateInstance內(nèi)部創(chuàng)建負(fù)責(zé)創(chuàng)建COM對象類廠的實(shí)例,然后使用類廠再創(chuàng)建對象。創(chuàng)建完COM對
      像后,類廠就被銷毀。
          顯然,如果要?jiǎng)?chuàng)建相同COM對象的眾多實(shí)例,這不是非常有效的。在這種惜況下,就要自己創(chuàng)建一個(gè)類廠的實(shí)例并在刪除
      它之前使用它的coCreateInstance方法來創(chuàng)建COM對象.
       
        //下面代碼是創(chuàng)建一個(gè)COM對象的類廠 ,他在加載DLL的時(shí)候就已經(jīng)運(yùn)行了,在卸載DLL時(shí)會(huì)自動(dòng)銷毀
        TComObjectFactory.Create(ComServer, TNextFit, Class_NextFit,
          'NextFit', 'Next-fit algorithm', ciMultiInstance, tmApartment);
         
           正因?yàn)橛辛薈OM對象的類廠,在客戶端程序中使用CreateComObject通常返回一個(gè)IUnknown指針。要獲取需要的接口指針,

      應(yīng)使用as操作符,如下所示:
           FOneD := CreateComObject(Class_NextFit) as IOneDBin; //獲取COM對象,并授權(quán)給接口引用

      3.進(jìn)程外COM對象(Out-of-Process COM Server )
       
       
          進(jìn)程外服務(wù)器是由于它們在EXE內(nèi)實(shí)現(xiàn)的。進(jìn)程外COM服務(wù)器不輸出進(jìn)程內(nèi)COM服務(wù)器所需的四個(gè)函數(shù),所以,他們在

      注冊表中使用不同的注冊方法。要注冊一個(gè)進(jìn)程外的COM服務(wù)器,只需運(yùn)行該服務(wù)器,把/RegServer放在命令行中。

      Delphi將注冊服務(wù)器和COM對象,然后就退出。要撤銷注冊服務(wù)器,使用命令行/unregserver
        
          如果正常運(yùn)行服務(wù)器,Delphi也將注冊它而沒有任何命令行選項(xiàng)。然而,服務(wù)器應(yīng)用程序?qū)?huì)繼續(xù)運(yùn)行。

         3.1 實(shí)例化(Instancing)
        
         進(jìn)程外COM服務(wù)器可以支持三個(gè)實(shí)例化方法中的一個(gè)。實(shí)例化指創(chuàng)建多少個(gè)客戶需要的實(shí)例。

         1)單實(shí)例(single Instance):指每個(gè)應(yīng)用程序只允許一個(gè)COM對象的實(shí)例。每個(gè)需要COM對象實(shí)例的應(yīng)用程序?qū)a(chǎn)
                                   生COM服務(wù)器的單獨(dú)拷貝。
        
         2)多實(shí)例(Multiple Instance)是指CDMServer可以創(chuàng)建一個(gè)COM對象的多個(gè)拷貝。
             當(dāng)客戶程序請求COM對象的一個(gè)實(shí)例時(shí),并不是啟動(dòng)一個(gè)新的服務(wù)器(除非服務(wù)器還未運(yùn)行)。相反,由當(dāng)前運(yùn)行的服
             務(wù)器創(chuàng)建COM對象的一個(gè)實(shí)例。
         3)內(nèi)部實(shí)例(Internal Only):用于不被客戶應(yīng)用程序使用的COM對象。能創(chuàng)建這種COM對象的應(yīng)用程序只有包含此COM對象
                                    的COM服務(wù)器。
                                   
          一般來說,讀者希望創(chuàng)建支持多實(shí)例的COM服務(wù)器。例如,假設(shè)讀考已經(jīng)編寫了一個(gè)COM服務(wù)器,它控制對串口的訪問,
       
       需要同時(shí)運(yùn)行兩個(gè)客戶應(yīng)用程序來向串口發(fā)送數(shù)據(jù)(通過COM服務(wù)器)。一個(gè)支持多實(shí)例的COM服務(wù)器可以打開串門并同時(shí)為
       
       兩個(gè)客戶程序服務(wù)。
       
         3.2 創(chuàng)建一個(gè)進(jìn)程外COM對象的實(shí)例
          
           創(chuàng)建一個(gè)進(jìn)程外服務(wù)器的COM對象實(shí)例的方法與創(chuàng)建進(jìn)程內(nèi)服務(wù)器中COM對象實(shí)例的方法是相同的。仍然可以調(diào)用
       
       CreateCOMObject函數(shù),將需要?jiǎng)?chuàng)建的COM對象的GUDI作為一個(gè)參數(shù)傳遞給它。
       
        3.3 調(diào)度數(shù)據(jù)
          
           當(dāng)一個(gè)程序使用一個(gè)進(jìn)程外COM服務(wù)器時(shí),在內(nèi)存的一個(gè)地址上裝載該程序,并且在一個(gè)不向的地址裝載COM服務(wù)器。
          
       在特定的內(nèi)存地址裝載在調(diào)用應(yīng)用程序中聲明的變量,該地址表示虛內(nèi)存中的地址。例如,假設(shè)客戶應(yīng)用程序聲明一個(gè)整
       
       型變量Myht,它的內(nèi)存地址為$00442830。進(jìn)程外COM服務(wù)器不訪問內(nèi)存中的那個(gè)位置。
       
           因?yàn)橐粋€(gè)可執(zhí)行的程序不直接訪問另一個(gè)可執(zhí)行的程序的地址空間,Windows通過個(gè)叫做調(diào)度(marshaling)的進(jìn)程在
          
      調(diào)用應(yīng)用程序和進(jìn)程外COM服務(wù)器之間移動(dòng)數(shù)據(jù)。
        
           Windows可以自動(dòng)調(diào)度下列數(shù)據(jù)類型:   
           Smallint,Integer、Single、Double、Double、Currency、TDatatime、wideString、IDispatch、
           SCODE、WordBool、OleVariant、IUnknown、Shortint和Byte是自動(dòng)化兼容的,意思是它們可以安全地用于自動(dòng)化服
           務(wù)器(COM Automation)。

        本站是提供個(gè)人知識(shí)管理的網(wǎng)絡(luò)存儲(chǔ)空間,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點(diǎn)。請注意甄別內(nèi)容中的聯(lián)系方式、誘導(dǎo)購買等信息,謹(jǐn)防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請點(diǎn)擊一鍵舉報(bào)。
        轉(zhuǎn)藏 分享 獻(xiàn)花(0

        0條評(píng)論

        發(fā)表

        請遵守用戶 評(píng)論公約

        類似文章 更多