IdBaseComponent.pas 9.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308
  1. {
  2. $Project$
  3. $Workfile$
  4. $Revision$
  5. $DateUTC$
  6. $Id$
  7. This file is part of the Indy (Internet Direct) project, and is offered
  8. under the dual-licensing agreement described on the Indy website.
  9. (http://www.indyproject.org/)
  10. Copyright:
  11. (c) 1993-2005, Chad Z. Hower and the Indy Pit Crew. All rights reserved.
  12. }
  13. {
  14. $Log$
  15. }
  16. {
  17. Rev 1.10 08.11.2004 ã. 20:00:46 DBondzhev
  18. changed TObject to &Object
  19. Rev 1.9 07.11.2004 ã. 18:17:54 DBondzhev
  20. This contains fix for proper call to unit initialization sections.
  21. Rev 1.8 2004.11.06 10:55:00 PM czhower
  22. Fix for Delphi 2005.
  23. Rev 1.7 2004.10.26 9:07:30 PM czhower
  24. More .NET implicit conversions
  25. Rev 1.6 2004.10.26 7:51:58 PM czhower
  26. Fixed ifdef and renamed TCLRStrings to TIdCLRStrings
  27. Rev 1.5 2004.10.26 7:35:16 PM czhower
  28. Moved IndyCat to CType in IdBaseComponent
  29. Rev 1.4 04.10.2004 13:15:06 Andreas Hausladen
  30. Thread Safe Unit initialization
  31. Rev 1.3 6/11/2004 8:28:26 AM DSiders
  32. Added "Do not Localize" comments.
  33. Rev 1.2 2004.04.16 9:18:34 PM czhower
  34. .NET fix to call initialization sections. Code taken from IntraWeb.
  35. Rev 1.1 2004.02.03 3:15:50 PM czhower
  36. Updates to move to System.
  37. Rev 1.0 2004.02.03 2:28:26 PM czhower
  38. Move
  39. Rev 1.4 2004.01.25 11:35:02 PM czhower
  40. IFDEF fix for .net.
  41. Rev 1.3 2004.01.25 10:56:44 PM czhower
  42. Bug fix for InitComponent at design time.
  43. Rev 1.2 2004.01.20 10:03:20 PM czhower
  44. InitComponent
  45. Rev 1.1 2003.12.23 7:33:00 PM czhower
  46. .Net change.
  47. Rev 1.0 11/13/2002 08:38:26 AM JPMugaas
  48. }
  49. unit IdBaseComponent;
  50. // Kudzu: This unit is permitted to viloate IFDEF restriction to harmonize
  51. // VCL / .Net difference at the base level.
  52. interface
  53. {$I IdCompilerDefines.inc}
  54. uses
  55. Classes
  56. {$IFDEF DOTNET}
  57. {$DEFINE IdDEBUG},
  58. System.ComponentModel.Design.Serialization,
  59. System.Collections.Specialized,
  60. System.ComponentModel,
  61. System.Threading,
  62. System.Reflection,
  63. System.IO // Necessary else System.IO below is confused with RTL System.
  64. {$ENDIF};
  65. // ***********************************************************
  66. // TIdBaseComponent is the base class for all Indy components.
  67. // ***********************************************************
  68. type
  69. // TIdInitializerComponent exists to consolidate creation differences between .net and vcl.
  70. // It looks funny, but because of .net restrictions on constructors we have to do some wierdo
  71. // stuff to catch both constructors.
  72. //
  73. // TIdInitializerComponent implements InitComponent which all components must use to initialize
  74. // other members instead of overriding constructors.
  75. {$IFDEF DOTNET}
  76. //IMPORTANT!!!
  77. //Abstract classes should be hidden in the assembly designer.
  78. //Otherwise, you get a mess.
  79. [DesignTimeVisible(false), ToolboxItem(false)]
  80. {$ENDIF}
  81. TIdInitializerComponent = class(TComponent)
  82. private
  83. protected
  84. {$IFDEF DOTNET}
  85. // This event handler will take care about dynamically loaded assemblies after first initialization.
  86. class procedure AssemblyLoadEventHandler(sender: &Object; args: AssemblyLoadEventArgs); static;
  87. class procedure InitializeAssembly(AAssembly: Assembly);
  88. {$ENDIF}
  89. function GetIsLoading: Boolean;
  90. function GetIsDesignTime: Boolean;
  91. // This is here to handle both types of constructor initializations, VCL and .Net.
  92. // It is not abstract so that not all descendants are required to override it.
  93. procedure InitComponent; virtual;
  94. public
  95. {$IFDEF DOTNET}
  96. // Should not be able to make this create virtual? But if not
  97. // DCCIL complain in IdIOHandler about possible polymorphics....
  98. constructor Create; overload; virtual;
  99. // Must be overriden here - but VCL version will catch offenders
  100. {$ELSE}
  101. // Statics to prevent overrides. For Create(AOwner) see TIdBaseComponent
  102. //
  103. // Create; variant is here to allow calls from VCL the same as from .net
  104. constructor Create; reintroduce; overload;
  105. // Must be an override and thus virtual to catch when created at design time
  106. //constructor Create(AOwner: TComponent); overload; override;
  107. {$ENDIF}
  108. constructor Create(AOwner: TComponent); overload; override;
  109. end;
  110. // TIdBaseComponent is the base class for all Indy components. Utility components, and other non
  111. // socket based components typically inherit directly from this. While socket components inherit
  112. // from TIdComponent instead as it introduces OnWork, OnStatus, etc.
  113. TIdBaseComponent = class(TIdInitializerComponent)
  114. protected
  115. function GetIndyVersion: string;
  116. property IsLoading: Boolean read GetIsLoading;
  117. property IsDesignTime: Boolean read GetIsDesignTime;
  118. public
  119. // This is here to catch components trying to override at compile time and not let them.
  120. // This does not work in .net, but we always test in VCL so this will catch it.
  121. {$IFNDEF DOTNET}
  122. constructor Create(AOwner: TComponent); reintroduce; overload;
  123. {$ENDIF}
  124. {$IFNDEF HAS_RemoveFreeNotification}
  125. procedure RemoveFreeNotification(AComponent: TComponent);
  126. {$ENDIF}
  127. property Version: string read GetIndyVersion;
  128. published
  129. end;
  130. implementation
  131. uses
  132. {$IFDEF DOTNET}
  133. System.Runtime.CompilerServices,
  134. {$ENDIF}
  135. IdGlobal;
  136. {$IFDEF DOTNET}
  137. var
  138. GInitsCalled: Integer = 0;
  139. {$ENDIF}
  140. { TIdInitializerComponent }
  141. constructor TIdInitializerComponent.Create;
  142. begin
  143. {-$IFDEF DOTNET}
  144. inherited Create(nil); // Explicit just in case since are not an override
  145. InitComponent;
  146. {-$ELSE}
  147. // Create(nil);
  148. {-$ENDIF}
  149. end;
  150. constructor TIdInitializerComponent.Create(AOwner: TComponent);
  151. begin
  152. inherited Create(AOwner);
  153. // DCCIL will not call our other create from this one, only .Nets ancestor
  154. // so InitComponent will NOT be called twice.
  155. InitComponent;
  156. end;
  157. {$IFDEF DOTNET}
  158. class procedure TIdInitializerComponent.AssemblyLoadEventHandler(sender: &Object;
  159. args: AssemblyLoadEventArgs);
  160. begin
  161. if (args <> nil) then begin
  162. InitializeAssembly(args.loadedAssembly);
  163. end;
  164. end;
  165. class procedure TIdInitializerComponent.InitializeAssembly(AAssembly: Assembly);
  166. var
  167. LTypesList: Array of &Type;
  168. j: integer;
  169. UnitType: &Type;
  170. begin
  171. LTypesList := AAssembly.GetTypes();
  172. for j := Low(LTypesList) to High(LTypesList) do begin
  173. UnitType := LTypesList[j];
  174. // Delphi 9 assemblies
  175. if (Pos('.Units', UnitType.Namespace) > 0) and (UnitType.Name <> '$map$') then begin
  176. RuntimeHelpers.RunClassConstructor(UnitType.TypeHandle);
  177. end;
  178. // Delphi 8 assemblies
  179. // if UnitType.Name = 'Unit' then begin
  180. // RuntimeHelpers.RunClassConstructor(UnitType.TypeHandle);
  181. // end;
  182. end;
  183. end;
  184. {$ENDIF}
  185. procedure TIdInitializerComponent.InitComponent;
  186. {$IFDEF DOTNET}
  187. var
  188. LAssemblyList: array of Assembly;
  189. i: integer;
  190. LM : String;
  191. {$ENDIF}
  192. begin
  193. {$IFDEF DOTNET}
  194. try
  195. // With .NET initialization sections are not called unless the unit is referenced. D.NET makes
  196. // initializations and globals part of a "Unit" class. So init sections wont get called unless
  197. // the Unit class is used. D8 EXEs are ok, but assemblies (ie VS.NET and probably asms in some
  198. // cases when used from a D8 EXE) do not call their init sections. So we loop through the list of
  199. // classes in the assembly, and for each one named Unit we call the class constructor which
  200. // causes the init section to be called.
  201. //
  202. if Interlocked.CompareExchange(GInitsCalled, 1, 0) = 0 then begin
  203. LAssemblyList := AppDomain.get_CurrentDomain.GetAssemblies;
  204. // Becouse this can be called few times we have to exclu de every time
  205. Exclude(AppDomain.get_CurrentDomain.AssemblyLoad, TIdInitializerComponent.AssemblyLoadEventHandler);
  206. Include(AppDomain.get_CurrentDomain.AssemblyLoad, TIdInitializerComponent.AssemblyLoadEventHandler);
  207. for i := low(LAssemblyList) to high(LAssemblyList) do begin
  208. //We do things this way because we do not want to initialize stuff that is not
  209. //ours. That would cause errors. It turns out that "AppDomain.get_CurrentDomain.GetAssemblies;" will
  210. //list stuff that isn't ours. Be careful.
  211. if (Pos('Indy',LAssemblyList[i].GetName.Name)=1) then
  212. begin
  213. initializeAssembly(LAssemblyList[i]);
  214. end;
  215. end;
  216. end;
  217. except
  218. on E : ReflectionTypeLoadException do
  219. begin
  220. LM := EOL;
  221. LM := LM + 'Message: ' + E.Message + EOL;
  222. LM := LM + 'Source: ' + E.Source + EOL;
  223. LM := LM + 'Stack Trace: ' + E.StackTrace + EOL;
  224. for i := Low(E.LoaderExceptions) to High(E.LoaderExceptions) do
  225. begin
  226. LM := LM + EOL;
  227. LM := LM + 'Error #' + i.ToString+EOL;
  228. LM := LM + 'Message: ' + E.LoaderExceptions[i].Message + EOL;
  229. LM := LM + 'Source: ' + E.LoaderExceptions[i].Source + EOL;
  230. LM := LM + 'Stack Trace: ' + EOL+ E.LoaderExceptions[i].StackTrace + EOL;
  231. end;
  232. IndyRaiseOuterException(Exception.Create('Load Error'+EOL+LM));
  233. end;
  234. end;
  235. {$ENDIF}
  236. end;
  237. function TIdInitializerComponent.GetIsLoading: Boolean;
  238. begin
  239. Result := (csLoading in ComponentState);
  240. end;
  241. function TIdInitializerComponent.GetIsDesignTime: Boolean;
  242. begin
  243. Result := (csDesigning in ComponentState);
  244. end;
  245. { TIdBaseComponent }
  246. {$IFNDEF DOTNET}
  247. constructor TIdBaseComponent.Create(AOwner: TComponent);
  248. begin
  249. inherited Create(AOwner); // Explicit just in case since are not an override
  250. end;
  251. {$ENDIF}
  252. {$IFNDEF HAS_RemoveFreeNotification}
  253. procedure TIdBaseComponent.RemoveFreeNotification(AComponent: TComponent);
  254. begin
  255. // this is a no-op for now, as we can't access the private TComponent.FFreeNotifies list
  256. end;
  257. {$ENDIF}
  258. function TIdBaseComponent.GetIndyVersion: string;
  259. begin
  260. Result := gsIdVersion;
  261. end;
  262. end.