2016-09-20 13 views
9

डेल्फी बर्लिन 10.1 [कमजोर] संदर्भ जोड़ता है। Marco Cantu's Blog पर कुछ मूलभूत बातें हैं।डेल्फी [कमजोर] संदर्भ विशेषता "अमान्य वर्ग टाइपकास्ट" उत्पन्न करती है जब कार्यान्वयन एक से अधिक लाइब्रेरी में होता है

मेरे परीक्षण के लिए मैंने दो ऑटो पुस्तकालयों को दो स्वचालन ऑब्जेक्ट प्रकार बनाए रखा। कंटेनर ऑब्जेक्ट में सामग्री ऑब्जेक्ट्स की एक सूची होती है जबकि सामग्री ऑब्जेक्ट्स में उनके कंटेनर का कमजोर संदर्भ होता है।

निम्नलिखित दो परिदृश्यों का परीक्षण किया और सही ढंग से काम किया (कमजोर संदर्भ अशक्त सेट कर रहे हैं और स्मृति जारी की है) गया:

  • एक दोनों इंटरफेस और CoClasses के साथ एकल COM पुस्तकालय।
  • दो COM पुस्तकालयों CoClasses

हालांकि, जब मैं दो अलग पुस्तकालयों में coclasses जगह कोड "अवैध वर्ग समान किरदार" का उत्पादन के साथ इंटरफेस के साथ एक और एक अन्य, त्रुटि दूर चला जाता है जब [कमजोर को हटाने ] विशेषता। अजीब नमूना बहाना कृपया, अपने उद्देश्य समस्या कम से कम करने के लिए बस है और मानक कोडिंग अभ्यास के रूप में नहीं लिया जाना चाहिए

यहाँ

पहले पुस्तकालय .ridl फ़ाइल है कि दोनों इंटरफेस और कंटेनर के लिए CoClass को परिभाषित करता है:

[ 
    uuid(E1EE3651-A400-49BF-B5C5-006D9943B9C0), 
    version(1.0) 

] 
library DelphiIntfComLib 
{ 

    importlib("stdole2.tlb"); 

    interface IMyContainer; 
    interface IMyContent; 
    coclass MyContainer; 


    [ 
    uuid(A7EF86F7-40CD-41EE-9DA1-4D9B7B24F06B), 
    helpstring("Dispatch interface for MyContainer Object"), 
    dual, 
    oleautomation 
    ] 
    interface IMyContainer: IDispatch 
    { 
    [id(0x000000C9)] 
    HRESULT _stdcall Add([in] IMyContent* AMyContent); 
    }; 

    [ 
    uuid(BFD6D976-8CEF-4264-B95A-B5DA7817F6B3), 
    helpstring("Dispatch interface for MyContent Object"), 
    dual, 
    oleautomation 
    ] 
    interface IMyContent: IDispatch 
    { 
    [id(0x000000C9)] 
    HRESULT _stdcall SetWeakReferenceToContainer([in] IMyContainer* AContainer); 
    }; 

    [ 
    uuid(1F56198B-B1BE-4E11-BC78-0E6FF8E55214) 
    ] 
    coclass MyContainer 
    { 
    [default] interface IMyContainer; 
    }; 

}; 

यहाँ मेरी कंटेनर को लागू करने

unit Unit1; 

{$WARN SYMBOL_PLATFORM OFF} 

interface 

uses 
    ComObj, ActiveX, DelphiIntfComLib_TLB, StdVcl, Generics.Collections; 

type 
    TMyContainer = class(TAutoObject, IMyContainer) 
    private 
    FList: TList<IMyContent>; 
    protected 
    procedure Add(const AMyContent: IMyContent); safecall; 
    public 
    Destructor Destroy; override; 

    procedure Initialize; override; 

    end; 

implementation 

uses ComServ; 

procedure TMyContainer.Add(const AMyContent: IMyContent); 
begin 
    FList.Add(AMyContent); 
    AMyContent.SetWeakReferenceToContainer(self); 
end; 

destructor TMyContainer.Destroy; 
begin 
    FList.Free; 
    inherited; 
end; 

procedure TMyContainer.Initialize; 
begin 
    inherited; 
    FList := TList<IMyContent>.create; 
end; 

initialization 
    TAutoObjectFactory.Create(ComServer, TMyContainer, Class_MyContainer, 
    ciMultiInstance, tmApartment); 
end. 

मेरी दूसरी पुस्तकालय संदर्भ पहली और एकमात्र शामिल मेरी सामग्री इंटरफेस के CoClass

है
[ 
    uuid(65659EE4-1949-4112-88CA-F2D5B5D8DA2C), 
    version(1.0) 

] 
library DelphiImplComLib 
{ 

    importlib("stdole2.tlb"); 
    importlib("DelphiIntfComLib.dll"); 

    coclass MyContent; 


    [ 
    uuid(79D1669A-8EB6-4AE6-8F4B-91137E6E6DC1) 
    ] 
    coclass MyContent 
    { 
    [default] interface IMyContent; 
    }; 

और कमजोर संदर्भ

unit Unit2; 

{$WARN SYMBOL_PLATFORM OFF} 

interface 

uses 
    ComObj, ActiveX, DelphiImplComLib_TLB, StdVcl, DelphiIntfComLib_TLB; 

type 
    TMyContent = class(TAutoObject, IMyContent) 
    private 
    [Weak] //If included will cause "invalid class typecast" error 
    FContainer : IMyContainer; 
    protected 
    procedure SetWeakReferenceToContainer(const AContainer: IMyContainer); safecall; 
    end; 

implementation 

uses ComServ; 

procedure TMyContent.SetWeakReferenceToContainer(const AContainer: IMyContainer); 
begin 
    FContainer := AContainer; 
end; 

initialization 
    TAutoObjectFactory.Create(ComServer, TMyContent, Class_MyContent, 
    ciMultiInstance, tmApartment); 
end. 

जब मैं अपने कार्यान्वयन विभाजित मुझे त्रुटि क्यों मिलता है मैं इस प्रकार

program Project13; 

{$APPTYPE CONSOLE} 

{$R *.res} 

uses 
    System.SysUtils, 
    DelphiImplComLib_TLB in 'impl\DelphiImplComLib_TLB.pas', 
    DelphiIntfComLib_TLB in 'Intf\DelphiIntfComLib_TLB.pas'; 

var 
    GMyContainer : IMyContainer; 
    GMyContent : IMyContent; 
begin 
    GMyContainer := CoMyContainer.Create; 
    GMyContent := CoMyContent.Create; 
    GMyContainer.Add(GMyContent); 
end. 

परीक्षण किया साथ इसके कार्यान्वयन? मैं इस समस्या को कैसे कम कर सकता हूं?

उत्तर

12

एलन Bauer के रूप में अपने जवाब में बताया गया है, [weak], COM इंटरफेस के साथ काम नहीं करता है के रूप में वे डेल्फी TObject व्युत्पन्न कक्षाएं, जो आवश्यक है [weak] संदर्भ ऑटो nil'ed जब वस्तुओं होने के लिए समर्थन हासिल होने की गारंटी नहीं कर रहे हैं मुक्त हैं आरटीएल रनटाइम पर कमजोर संदर्भों का ट्रैक रखता है, लेकिन पुस्तकालयों में कमजोर संदर्भों को ट्रैक नहीं कर सकता है जब तक कि उनके बीच आरटीएल लाइब्रेरी का एक उदाहरण साझा नहीं किया जाता है (यानी यदि आप रनटाइम पैकेज सक्षम के साथ पुस्तकालयों को संकलित करते हैं, और फिर अपने निष्पादन योग्य के साथ आरटीएल बीपीएल को तैनात करते हैं)।

हालांकि, जब तक आप [weak] का स्वत: शून्य कार्यक्षमता का उपयोग करने की जरूरत नहीं है के रूप में, आप एक untyped Pointer बजाय का उपयोग कर सकते हैं:

type 
    TMyContent = class(TAutoObject, IMyContent) 
    private 
    FContainer : Pointer{IMyContainer}; 
    ... 
    end; 

तुम बस IMyContainer जब भी आप करने के लिए FContainer टाइपकास्ट करने के लिए होगा अपने तरीकों/गुण, उपयोग करने की आवश्यकता जैसे:

IMyContainer(FContainer).Add(...); 

10,1 बर्लिन में और बाद में, आप [unsafe] विशेषता के बजाय का उपयोग कर सकते हैं:

type 
    TMyContent = class(TAutoObject, IMyContent) 
    private 
    [Unsafe] FContainer : IMyContainer; 
    ... 
    end; 

मार्को के ब्लॉग पर उल्लेख किया है: वस्तु एक मानक संदर्भ गिनती कार्यान्वयन है और आप एक इंटरफेस संदर्भ कि की कुल संख्या से बाहर रखा गया है बनाना चाहते हैं

Weak and Unsafe Interface References in Delphi 10.1 Berlin

क्या होगा अगर संदर्भ? अब आप इंटरफ़ेस चर घोषणा करने के लिए [असुरक्षित] विशेषता जोड़ने, करने के लिए ऊपर दिए गए कोड को बदलने के द्वारा इस लक्ष्य को हासिल कर सकते हैं:

procedure TForm3.Button2Click(Sender: TObject); 
var 
    [unsafe] 
    one: ISimpleInterface; 
begin 
    one := TObjectOne.Create; 
    one.DoSomething; 
end; 

ऐसा नहीं है कि यह एक अच्छा विचार है, के रूप में कोड के ऊपर एक स्मृति रिसाव का कारण होगा। संदर्भ गिनती को अक्षम करके, जब चर के दायरे से बाहर हो जाता है तो कुछ भी नहीं होता है। कुछ परिदृश्य हैं जिनमें यह फायदेमंद है, क्योंकि आप अभी भी इंटरफेस का उपयोग कर सकते हैं और अतिरिक्त संदर्भ को ट्रिगर नहीं कर सकते हैं। दूसरे शब्दों में, एक असुरक्षित संदर्भ का इलाज किया जाता है ... एक पॉइंटर, बिना अतिरिक्त कंपाइलर समर्थन के।

अब आप गिनती बढ़ाने के बिना संदर्भ रखने के लिए असुरक्षित विशेषता का उपयोग करने पर विचार करने से पहले, मान लें कि ज्यादातर मामलों में एक और बेहतर विकल्प है, जो कमजोर संदर्भों का उपयोग है। कमजोर संदर्भ संदर्भ गणना बढ़ाने से भी बचते हैं, लेकिन वे प्रबंधित होते हैं। इसका मतलब है कि सिस्टम कमजोर संदर्भों का ट्रैक रखता है, और यदि वास्तविक वस्तु हटा दी जाती है, तो यह कमजोर संदर्भ को पर सेट करेगा। एक असुरक्षित संदर्भ के साथ, आपके पास लक्षित ऑब्जेक्ट की स्थिति जानने का कोई तरीका नहीं है (एक परिदृश्य जिसे संदर्भ संदर्भ कहा जाता है)।

+0

मैं ऑटो-एनआईएल सुविधा रखने की उम्मीद कर रहा था, लेकिन मैं असुरक्षित के लिए बस जाऊंगा। मैं उस जोखिम को अन्य तरीकों से कम कर दूंगा –

+1

@ जैस्परशेलिंगरहाउट: ऑटो-नील सुविधा 'टॉब्जेक्ट' विनाशक से आती है। जब किसी ऑब्जेक्ट को नष्ट किया जा रहा है, तो यह कमजोर संदर्भों की वैश्विक तालिका से गुजरता है और उस वस्तु को संदर्भित करने वाले किसी भी संदर्भ को निल्स करता है। तो यदि आपके पास एक COM इंटरफ़ेस है जिसे 'TObject' क्लास द्वारा लागू नहीं किया गया है, तो उस ऑब्जेक्ट के कमजोर संदर्भ ऑटो-शून्य नहीं होंगे। –

+0

इस विशिष्ट नमूना मामले में इसे प्रबंधित करना बहुत मुश्किल नहीं है। विनाश पर कंटेनर बच्चों पर कमजोर संदर्भ को पार कर सकता है और सेट कर सकता है। सामग्री को हटाने के लिए कोई भी तरीका वही कर सकता है। –

16

COM-interfaces के लिए [कमजोर] का उपयोग न करें। यह COM के साथ उपयोग के लिए नहीं है। [कमजोर] केवल आंतरिक गैर-निर्यातित-COM इंटरफेस के लिए उपयोग किया जाना चाहिए।

कारण यह है कि COM-इंटरफेस कार्यान्वयन का कोई तरीका नहीं है, जिसे डेल्फी वर्ग द्वारा भी लागू नहीं किया जा सकता है, [कमजोर] संदर्भों को सही तरीके से संभालने के लिए। इसके अतिरिक्त, आपके पास मौजूद COM पुस्तकालय बेस टॉब्जेक्ट के समान कार्यान्वयन को साझा नहीं कर रहे हैं। आप साझा आरटीएल पैकेज का उपयोग कर सबकुछ बनाने के साथ दूर हो सकते हैं, लेकिन तब भी ... आप भूमि-खान पर नृत्य कर रहे हैं।

+0

मैं आपके बिंदु को समझता हूं। लेकिन इस मामले में मेरी वस्तुएं टॉब्जेक्ट के वंशज हैं। "समान कार्यान्वयन" से आपका क्या मतलब है –

+1

@ जैस्परशेलिंगरहाउट: एलन आधार आरटीएल का जिक्र कर रहा है जो 'TObject' कक्षा लागू करता है। आरटीएल रनटाइम पर कमजोर संदर्भों का ट्रैक रखता है (इसलिए जब यह ऑब्जेक्ट स्मृति से मुक्त होता है तो यह स्वचालित रूप से दिए गए ऑब्जेक्ट के सभी कमजोर संदर्भों को शून्य कर सकता है)। आरटीएल पुस्तकालयों में संदर्भों को ट्रैक नहीं कर सकता है जब तक कि उनके बीच आरटीएल लाइब्रेरी का एक उदाहरण साझा नहीं किया जाता है (यानी आप रनटाइम पैकेज सक्षम के साथ पुस्तकालयों को संकलित करते हैं, और फिर अपने निष्पादन योग्य के साथ आरटीएल बीपीएल तैनात करते हैं)। –

+1

@ जैस्परशेलिंगरहाउट: आपको इन विवरणों को अपने '[कमजोर]' दस्तावेज में जोड़ने के लिए एम्बरकेडरो से पूछना चाहिए। –

संबंधित मुद्दे