Articles   Members Online:
-Article/Tip Search
-News Group Search over 21 Million news group articles.
-Delphi/Pascal
-CBuilder/C++
-C#Builder/C#
-JBuilder/Java
-Kylix
Member Area
-Home
-Account Center
-Top 10 NEW!!
-Submit Article/Tip
-Forums Upgraded!!
-My Articles
-Edit Information
-Login/Logout
-Become a Member
-Why sign up!
-Newsletter
-Chat Online!
-Indexes NEW!!
Employment
-Build your resume
-Find a job
-Post a job
-Resume Search
Contacts
-Contacts
-Feedbacks
-Link to us
-Privacy/Disclaimer
Embarcadero
Visit Embarcadero
Embarcadero Community
JEDI
Links
How to type cast and type check with Interfaces Turn on/off line numbers in source code. Switch to Orginial background IDE or DSP color Comment or reply to this aritlce/tip for discussion. Bookmark this article to my favorite article(s). Print this article
07-Sep-03
Category
OO-related
Language
Delphi 3.x
Views
159
User Rating
No Votes
# Votes
0
Replies
0
Publisher:
DSP, Administrator
Reference URL:
DKB
			Author: William Egge

If you are new to interfaces and you are use to type casting and type checking with 
objects you will find that Interfaces must be dealt with differently.  This artical 
shows you the basics to get started with doing type checking and type casting with 
Interfaces. 

Answer:

If you are like me, you are impatient and can get the point without a bunch of 
explaining and you hate reading of bunch of stuff just to get a couple bits of 
info. So for you guys/girls here is the summary and then if you like you can read 
the rest of the artical: 

SUMMARY 

First off, your interface must have a GUID, use delphi Shift-Ctrl-G to create one. 
It should be entered as the first line in your interface definition, ex: 

1   ITypeX = interface
2     ['{A002AF60-5684-11D5-B4F9-525405F6BE8D}']
3     procedure ShowX;
4   end;
5   
6   //Object Type Cast 
7   
8   Customer := TCustomer(SomeObject);
9   
10  //Interface Way 
11  
12  //You cannot do it this way with interfaces 
13  
14  //Object Type Cast (with type checking) 
15  
16  Customer := SomeObject as TCustomer;


Interface Way 

Customer := SomeInterface as ICustomer; // assuming Customer is declared as 
ICustomer

Object Type Checking 

17  if SomeObject is TCustomer then
18    // Do Something


interface Way
19  
20  if SomeInterface.QueryInterface(ICustomer, Customer) = S_OK then
21  begin
22    Customer.DoSomething;
23  end;


Read further if you like more explaining 

First I will summarize type casting and type checking with objects to get us on the 
same ground and then show how it is done when using interfaces. 

Type casting with objects is done in 2 ways 

Direct without type checking 

Customer := TCustomer(SomeObject);

Using "built in" type checking 

Customer := SomeObject as TCustomer

The second will raise an exception if SomeObject is not a TCustomer object or a 
descendent of one. 

Type checking with objects can be done as.... 

24  if (SomeObject is TCustomer) then
25    // Do something


Now for Interfaces, you MUST have a GUID for your interface before you can do any 
type checking or type casting. To make your interface have a GUID simply insert it 
as the first line in your interface definition like this: 

26  ITypeX = interface
27    ['{A002AF60-5684-11D5-B4F9-525405F6BE8D}']
28    procedure ShowX;
29  end;


First off you may ask where the heck do I get a GUID, in Delphi just put your 
cursor where you want the GUID and then press Shift-Ctrl-G and Delphi will insert 
one for you.  That easy. 

These are the interfaces I will use in my explaining: 

30  ITypeX = interface
31    ['{A002AF60-5684-11D5-B4F9-525405F6BE8D}']
32    procedure ShowX;
33  end;
34  
35  ITypeY = interface
36    ['{56DA8BE0-5685-11D5-B4F9-525405F6BE8D}']
37    procedure ShowY;
38  end;
39  
40  Classes to implement them
41  TTypeX = class(TInterfacedObject, ITypeX)
42  public
43    procedure ShowX;
44  end;
45  
46  TTypeY = class(TInterfacedObject, ITypeY)
47  public
48    procedure ShowY;
49  end;
50  
51  TTypeXY = class(TInterfacedObject, ITypeX, ITypeY)
52  public
53    procedure ShowX;
54    procedure ShowY;
55  end;
56  
57  //Type casting. 
58  
59  //The following code will not work! 
60  
61  procedure TForm_Interfaces.TypeCastXtoY;
62  var
63    X: ITypeX;
64  begin
65    X := TTypeXY.Create;
66    ITypeY(X).ShowY;
67  end;


What happens is that the method ShowX gets called rather than ShowY, I do not know 
the technical reason... but bottom line, it does not work and you should not type 
cast this way. 

The proper way to do it is this way: 

68  procedure TForm_Interfaces.TypeCastXtoY;
69  var
70    X: ITypeX;
71  begin
72    X := TTypeXY.Create;
73    (X as ITypeY).ShowY;
74  end;


You must use the as operator, also this way of doing it will raise an exception if 
X in some way does not implement Y.  If you need to do type checking then read 
more... 

The "is" operator does not work with interfaces, so code like this will not compile 

75  if X is ITypeY then
76    // Do Something
77  
78  //The proper way to do it is this way: 
79  
80  U := TTypeY.Create;
81  
82  if U.QueryInterface(ITypeX, Ret) = S_OK then
83    ShowMessage('Supports ITypeX')
84  else
85    ShowMessage('DOES NOT Support ITypeX');
86  
87  if U.QueryInterface(ITypeY, Ret) = S_OK then
88    ShowMessage('Supports ITypeY')
89  else
90    ShowMessage('DOES NOT Support ITypeY')


Ret will contain a reference to the interface when the result is S_OK. 

Note: If you read the Delphi help for QueryInterface you will see this line 
After successfully obtaining an interface by calling QueryInterface, clients should 
increase the reference count by calling the IUnknown AddRef method. 

I wrote code to verify this statement and found that the reference count was 
incermented and I did not have to call AddRef. 

Full Source of my Research, you can also download the app from my website using the 
component link. 

PAS

91  unit Frm_Interfaces;
92  {
93    Discovery Typecasting interfaces
94  
95    You cannot typecast an interface in this manner, 
96    seems your method pointers are messed up
97    X:= ITypeX(SomeInterface);
98    // See "TypeCastXtoY" method to see the error, notice the message
99  
100   You must type cast in either of 2 ways
101   1. X:= SomeInterface as ITypeX
102   // See "TypeCastXtoY" method, this can raise an exception
103 
104   or
105   2. if SomeInterface.QueryInterface(ITypeX, X) = S_OK then
106        X.ShowX;
107   // See "TypeChecking" method, this does not raise an exception
108 
109   Difference between 1 and 2 is that 1 will raise an exception and 2 will not.
110 
111   *** IMPORTANT ***
112   In order for this to work you MUST include a GUID in your interface, it is
113   the first line in the interface definition, use keyboard Shift-Ctrl-G to
114   create a GUID.
115 }
116 
117 interface
118 
119 uses
120   Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
121   StdCtrls;
122 
123 type
124 
125   ITypeX = interface
126     ['{A002AF60-5684-11D5-B4F9-525405F6BE8D}']
127     procedure ShowX;
128   end;
129 
130   ITypeY = interface
131     ['{56DA8BE0-5685-11D5-B4F9-525405F6BE8D}']
132     procedure ShowY;
133   end;
134 
135   TTypeX = class(TInterfacedObject, ITypeX)
136   public
137     procedure ShowX;
138   end;
139 
140   TTypeY = class(TInterfacedObject, ITypeY)
141   public
142     procedure ShowY;
143   end;
144 
145   TTypeXY = class(TInterfacedObject, ITypeX, ITypeY)
146   public
147     procedure ShowX;
148     procedure ShowY;
149   end;
150 
151   TForm_Interfaces = class(TForm)
152     FbtnTestCreate: TButton;
153     FbtnTypeCastX2Y: TButton;
154     FbtnTypeCastU2Y: TButton;
155     FbtnTypeChecking: TButton;
156     procedure Ev_FbtnTestCreateClick(Sender: TObject);
157     procedure Ev_FbtnTypeCastX2YClick(Sender: TObject);
158     procedure Ev_FbtnTypeCastU2YClick(Sender: TObject);
159     procedure Ev_FbtnTypeCheckingClick(Sender: TObject);
160   private
161     { Private declarations }
162     procedure TestCreate;
163     procedure TypeCastXtoY;
164     procedure TypeCastUnknownToY;
165     procedure TypeChecking;
166   public
167     { Public declarations }
168   end;
169 
170 var
171   Form_Interfaces: TForm_Interfaces;
172 
173 implementation
174 
175 {$R *.DFM}
176 
177 { TTypeX }
178 
179 procedure TTypeX.ShowX;
180 begin
181   ShowMessage('TTypeX.ShowX: Supports "ITypeX" only');
182 end;
183 
184 { TTypeY }
185 
186 procedure TTypeY.ShowY;
187 begin
188   ShowMessage('TTypeY.ShowY: Supports "ITypeY" only');
189 end;
190 
191 { TTypeXY }
192 
193 procedure TTypeXY.ShowX;
194 begin
195   ShowMessage('TTypeXY.ShowX: Supports both "ITypeX" and "ITypeY"');
196 end;
197 
198 procedure TTypeXY.ShowY;
199 begin
200   ShowMessage('TTypeXY.ShowY: Supports both "ITypeX" and "ITypeY"');
201 end;
202 
203 { TForm1 }
204 
205 procedure TForm_Interfaces.Ev_FbtnTestCreateClick(Sender: TObject);
206 begin
207   TestCreate;
208 end;
209 
210 procedure TForm_Interfaces.Ev_FbtnTypeCastX2YClick(Sender: TObject);
211 begin
212   TypeCastXtoY;
213 end;
214 
215 procedure TForm_Interfaces.Ev_FbtnTypeCastU2YClick(Sender: TObject);
216 begin
217   TypeCastUnknownToY;
218 end;
219 
220 procedure TForm_Interfaces.Ev_FbtnTypeCheckingClick(Sender: TObject);
221 begin
222   TypeChecking;
223 end;
224 
225 procedure TForm_Interfaces.TestCreate;
226 var
227   TypeX: ITypeX;
228   TypeY: ITypeY;
229 begin
230   TypeX := TTypeX.Create;
231   TypeX.ShowX;
232 
233   TypeY := TTypeY.Create;
234   TypeY.ShowY;
235 
236   // Implements both
237   TypeX := TTypeXY.Create;
238   TypeX.ShowX;
239 
240   TypeY := TTypeXY.Create;
241   TypeY.ShowY;
242 end;
243 
244 procedure TForm_Interfaces.TypeCastXtoY;
245 var
246   X: ITypeX;
247 begin
248   // Notice the message, this does not work.
249   X := TTypeXY.Create;
250   ITypeY(X).ShowY;
251 
252   // This does work
253   (X as ITypeY).ShowY;
254 end;
255 
256 procedure TForm_Interfaces.TypeCastUnknownToY;
257 var
258   U: IUnknown;
259   Y: ITypeY;
260 begin
261   U := TTypeXY.Create;
262   Y := U as ITypeY;
263   Y.ShowY;
264 end;
265 
266 procedure TForm_Interfaces.TypeChecking;
267 var
268   U: IUnknown;
269   Ret: IUnknown;
270 begin
271   // Select whichever you want below
272 //********************************
273   //  U:= TTypeXY.Create;
274   //  U:= TTypeX.Create;
275   U := TTypeY.Create;
276   //********************************
277 
278     // "Is" does not work with interfaces.
279   {
280     if U is ITypeX then
281       ShowMessage('Supports ITypeX')
282     else
283       ShowMessage('DOES NOT Support ITypeX')
284 
285     if U is ITypeY then
286       ShowMessage('Supports ITypeY')
287     else
288       ShowMessage('DOES NOT Support ITypeY')
289   }
290 
291   if U.QueryInterface(ITypeX, Ret) = S_OK then
292     ShowMessage('Supports ITypeX')
293   else
294     ShowMessage('DOES NOT Support ITypeX');
295 
296   if U.QueryInterface(ITypeY, Ret) = S_OK then
297     ShowMessage('Supports ITypeY')
298   else
299     ShowMessage('DOES NOT Support ITypeY')
300 end;
301 
302 end.


DFM

object Form_Interfaces: TForm_Interfaces
  Left = 273
    Top = 278
    BorderStyle = bsDialog
    Caption = 'Experimenting with Typecasting interfaces'
    ClientHeight = 222
    ClientWidth = 341
    Color = clBtnFace
    Font.Charset = DEFAULT_CHARSET
    Font.Color = clWindowText
    Font.Height = -11
    Font.Name = 'MS Sans Serif'
    Font.Style = []
    OldCreateOrder = False
    Position = poScreenCenter
    PixelsPerInch = 96
    TextHeight = 13
    object FbtnTestCreate: TButton
    Left = 118
      Top = 39
      Width = 105
      Height = 25
      Caption = 'FbtnTestCreate'
      TabOrder = 0
      OnClick = Ev_FbtnTestCreateClick
  end
  object FbtnTypeCastX2Y: TButton
    Left = 118
      Top = 79
      Width = 105
      Height = 25
      Caption = 'FbtnTypeCastX2Y'
      TabOrder = 1
      OnClick = Ev_FbtnTypeCastX2YClick
  end
  object FbtnTypeCastU2Y: TButton
    Left = 118
      Top = 119
      Width = 105
      Height = 25
      Caption = 'FbtnTypeCastU2Y'
      TabOrder = 2
      OnClick = Ev_FbtnTypeCastU2YClick
  end
  object FbtnTypeChecking: TButton
    Left = 118
      Top = 159
      Width = 105
      Height = 25
      Caption = 'FbtnTypeChecking'
      TabOrder = 3
      OnClick = Ev_FbtnTypeCheckingClick
  end
end

Component Download: http://www.eggcentric.com/InterfaceTypeCast.zip

			
Vote: How useful do you find this Article/Tip?
Bad Excellent
1 2 3 4 5 6 7 8 9 10

 

Advertisement
Share this page
Advertisement
Download from Google

Copyright © Mendozi Enterprises LLC