CnASInvoker.pas 40 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452
  1. {******************************************************************************}
  2. { CnPack For Delphi/C++Builder }
  3. { 中国人自己的开放源码第三方开发包 }
  4. { (C)Copyright 2001-2018 CnPack 开发组 }
  5. { ------------------------------------ }
  6. { }
  7. { 本开发包是开源的自由软件,您可以遵照 CnPack 的发布协议来修 }
  8. { 改和重新发布这一程序。 }
  9. { }
  10. { 发布这一开发包的目的是希望它有用,但没有任何担保。甚至没有 }
  11. { 适合特定目的而隐含的担保。更详细的情况请参阅 CnPack 发布协议。 }
  12. { }
  13. { 您应该已经和开发包一起收到一份 CnPack 发布协议的副本。如果 }
  14. { 还没有,可访问我们的网站: }
  15. { }
  16. { 网站地址:http://www.cnpack.org }
  17. { 电子邮件:master@cnpack.org }
  18. { }
  19. {******************************************************************************}
  20. unit CnASInvoker;
  21. {* |<PRE>
  22. ================================================================================
  23. * 软件名称:不可视工具组件包
  24. * 单元名称:根据接口动态调用方法单元
  25. * 单元作者:由 周劲羽 移植自 Delphi 7 Source
  26. * 备 注:该单元通过修改和移植自 Delphi 7 中的 Source\Soap 下的
  27. * IntfInfo, Invoker, InvokeRegistry, InvRules, TypeTrans 等单元。
  28. * 注:该单元不支持 Delphi/BCB 5,仅支持 Delphi/BCB 6 以上版本。
  29. * 开发平台:PWin2K SP3 + Delphi 7
  30. * 兼容测试:PWin9X/2000/XP + Delphi 6/7
  31. * 本 地 化:该单元中的字符串均符合本地化处理方式
  32. * 单元标识:$Id$
  33. * 修改记录:2003.07.08
  34. * 创建单元
  35. ================================================================================
  36. |</PRE>}
  37. interface
  38. {$I CnPack.inc}
  39. {$IFNDEF COMPILER6_UP}
  40. 'Error: This unit can used only for Delphi / C++Builder 6 or up.'
  41. {$ENDIF COMPILER6_UP}
  42. uses
  43. Sysutils, Classes, TypInfo, Variants;
  44. type
  45. //==============================================================================
  46. // 接口 RTTI 相关定义,移植自 IntfInfo
  47. //==============================================================================
  48. PIntfParamEntry = ^TIntfParamEntry;
  49. TIntfParamEntry = record
  50. Flags: TParamFlags;
  51. Name: string;
  52. Info: PTypeInfo;
  53. end;
  54. TIntfParamEntryArray = array of TIntfParamEntry;
  55. TCallConv = (ccReg, ccCdecl, ccPascal, ccStdCall, ccSafeCall);
  56. PIntfMethEntry = ^TIntfMethEntry;
  57. TIntfMethEntry = record
  58. Name: string;
  59. CC: TCallConv; { Calling convention }
  60. Pos: Integer; { Index (relative to whole interface VMT) }
  61. ParamCount: Integer;
  62. ResultInfo: PTypeInfo;
  63. SelfInfo: PTypeInfo;
  64. Params: TIntfParamEntryArray;
  65. HasRTTI: Boolean;
  66. end;
  67. TIntfMethEntryArray = array of TIntfMethEntry;
  68. TPIntfMethEntryArray = array of PIntfMethEntry;
  69. { Governs show the MDA array is filled }
  70. TFillMethodArrayOpt = (fmoAllBaseMethods, fmoRTTIBaseMethods, fmoNoBaseMethods);
  71. PIntfMetaData = ^TIntfMetaData;
  72. TIntfMetaData = record
  73. Name: string;
  74. UnitName: string;
  75. MDA: TIntfMethEntryArray;
  76. IID: TGUID;
  77. Info: PTypeInfo;
  78. AncInfo: PTypeInfo;
  79. NumAnc: Integer; { #Methods in base interfaces }
  80. end;
  81. EInterfaceRTTIException = class(Exception);
  82. TDynToClear = record
  83. P: Pointer;
  84. Info: PTypeInfo;
  85. end;
  86. //==============================================================================
  87. // 用于动态方法调用的临时数据类,移植修改自 InvokeRegistry
  88. //==============================================================================
  89. { TDataContext }
  90. TDataContext = class
  91. protected
  92. DataOffset: Integer;
  93. Data: array of Byte;
  94. DataP: array of Pointer;
  95. VarToClear: array of Pointer;
  96. DynArrayToClear: array of TDynToClear;
  97. StrToClear: array of Pointer;
  98. WStrToClear: array of Pointer;
  99. public
  100. constructor Create;
  101. destructor Destroy; override;
  102. function AllocData(Size: Integer): Pointer;
  103. procedure SetDataPointer(Index: Integer; P: Pointer);
  104. function GetDataPointer(Index: Integer): Pointer;
  105. procedure AddDynArrayToClear(P: Pointer; Info: PTypeInfo);
  106. procedure AddVariantToClear(P: PVarData);
  107. procedure AddStrToClear(P: Pointer);
  108. procedure AddWStrToClear(P: Pointer);
  109. end;
  110. { TInvContext }
  111. TInvContext = class(TDataContext)
  112. private
  113. ResultP: Pointer;
  114. public
  115. procedure SetMethodInfo(const MD: TIntfMethEntry);
  116. procedure SetParamPointer(Param: Integer; P: Pointer);
  117. function GetParamPointer(Param: Integer): Pointer;
  118. function GetResultPointer: Pointer;
  119. procedure SetResultPointer(P: Pointer);
  120. procedure AllocServerData(const MD: TIntfMethEntry);
  121. end;
  122. //==============================================================================
  123. // 动态接口方法调用器类,移植修改自 Invoke
  124. //==============================================================================
  125. { TInterfaceInvoker }
  126. TInterfaceInvoker = class
  127. public
  128. procedure Invoke(const Obj: TObject; IntfMD: TIntfMetaData;
  129. const MethNum: Integer; const Context: TInvContext);
  130. constructor Create;
  131. end;
  132. //==============================================================================
  133. // 类型转换器类,移植修改自 TypeTrans
  134. //==============================================================================
  135. ETypeTransException = class(Exception);
  136. { TTypeTranslator }
  137. TTypeTranslator = class
  138. public
  139. constructor Create;
  140. destructor Destroy; override;
  141. procedure CastVariantToNative(Info: PTypeInfo; const Value: OleVariant;
  142. NatData: Pointer);
  143. procedure CastNativeToVariant(Info: PTypeInfo; var Value: OleVariant;
  144. NatData: Pointer);
  145. end;
  146. procedure GetIntfMetaData(Info: PTypeInfo; var IntfMD: TIntfMetaData;
  147. MethodArrayOpt: TFillMethodArrayOpt); overload;
  148. procedure GetIntfMetaData(Info: PTypeInfo; var IntfMD: TIntfMetaData;
  149. IncludeAllAncMethods: Boolean = False); overload;
  150. function GetMethNum(const IntfMD: TIntfMetaData; const MethName: string;
  151. ParamCount: Integer = -1): Integer;
  152. function TypeNamesMatch(const RegName: string; const OtherName: string): Boolean;
  153. function OtherTypeName(const TypeName: string): string;
  154. function SameTypeInfo(const RegInfo: PTypeInfo; const OtherInfo: PTypeInfo):
  155. Boolean;
  156. function InterfaceInvoker: TInterfaceInvoker;
  157. function TypeTranslator: TTypeTranslator;
  158. implementation
  159. const
  160. KindNameArray: array[tkUnknown..tkDynArray] of string =
  161. ('Unknown', 'Integer', 'Char', 'Enumeration', 'Float',
  162. 'String', 'Set', 'Class', 'Method', 'WChar', 'LString', 'WString',
  163. 'Variant', 'Array', 'Record', 'Interface', 'Int64', 'DynArray');
  164. CallingConventionName: array[ccReg..ccSafeCall] of string =
  165. ('REGISTER', 'CDECL', 'PASCAL', 'STDCALL', 'SAFECALL');
  166. TypeInfoNames: array[0..33] of string = ('Boolean', 'bool',
  167. 'Char', 'char',
  168. 'Char', 'signed char',
  169. 'Byte', 'unsigned char',
  170. 'SmallInt', 'short',
  171. 'Word', 'unsigned short',
  172. 'Integer', 'int',
  173. 'Cardinal', 'unsigned int',
  174. 'Integer', 'long',
  175. 'Cardinal', 'unsigned long',
  176. 'Int64', '__int64',
  177. 'Int64', 'unsigned __int64',
  178. 'Single', 'float',
  179. 'Double', 'double',
  180. 'Extended', 'long double',
  181. 'String', 'AnsiString',
  182. 'WideString', 'WideString');
  183. CCMap: array[0..4] of TCallConv = (ccReg, ccCdecl, ccPascal, ccStdCall,
  184. ccSafeCall);
  185. resourcestring
  186. SNoInterfaceGUID = 'Class %s does not implement interface GUID %s';
  187. SUnsupportedCC = 'Unsupported calling convention: %s';
  188. SVariantCastNotSupported = 'Type cannot be cast as Variant';
  189. SUnexpectedDataType = 'Internal error: data type kind %s not expected in this context';
  190. SNoRTTI = 'Interface %s has no RTTI';
  191. SNoRTTIParam = 'Parameter %s on Method %s of Interface %s has no RTTI';
  192. var
  193. FInterfaceInvoker: TInterfaceInvoker;
  194. FTypeTranslator: TTypeTranslator;
  195. function InterfaceInvoker: TInterfaceInvoker;
  196. begin
  197. if not Assigned(FInterfaceInvoker) then
  198. FInterfaceInvoker := TInterfaceInvoker.Create;
  199. Result := FInterfaceInvoker;
  200. end;
  201. function TypeTranslator: TTypeTranslator;
  202. begin
  203. if not Assigned(FTypeTranslator) then
  204. FTypeTranslator := TTypeTranslator.Create;
  205. Result := FTypeTranslator;
  206. end;
  207. //==============================================================================
  208. // 接口 RTTI 相关定义,移植自 IntfInfo
  209. //==============================================================================
  210. function ReadString(var P: Pointer): string;
  211. var
  212. B: Byte;
  213. begin
  214. B := Byte(P^);
  215. SetLength(Result, B);
  216. P := Pointer(Integer(P) + 1);
  217. Move(P^, Result[1], Integer(B));
  218. P := Pointer(Integer(P) + B);
  219. end;
  220. function ReadByte(var P: Pointer): Byte;
  221. begin
  222. Result := Byte(P^);
  223. P := Pointer(Integer(P) + 1);
  224. end;
  225. function ReadWord(var P: Pointer): Word;
  226. begin
  227. Result := Word(P^);
  228. P := Pointer(Integer(P) + 2);
  229. end;
  230. function ReadLong(var P: Pointer): Integer;
  231. begin
  232. Result := Integer(P^);
  233. P := Pointer(Integer(P) + 4);
  234. end;
  235. procedure FillMethodArray(P: Pointer; IntfMD: PIntfMetaData; Offset, Methods:
  236. Integer);
  237. var
  238. S: string;
  239. I, J, K, L: Integer;
  240. ParamCount: Integer;
  241. Kind, Flags: Byte;
  242. ParamInfo: PTypeInfo;
  243. ParamName: string;
  244. IntfMethod: PIntfMethEntry;
  245. IntfParam: PIntfParamEntry;
  246. begin
  247. for I := 0 to Methods - 1 do
  248. begin
  249. IntfMethod := @IntfMD.MDA[Offset];
  250. IntfMethod.Name := ReadString(P);
  251. Kind := ReadByte(P); { tkKind }
  252. IntfMethod.CC := CCMap[ReadByte(P)];
  253. ParamCount := ReadByte(P); { Param count including self }
  254. IntfMethod.ParamCount := ParamCount - 1;
  255. IntfMethod.Pos := Offset;
  256. IntfMethod.HasRTTI := True;
  257. SetLength(IntfMethod.Params, ParamCount);
  258. K := 0;
  259. for J := 0 to ParamCount - 1 do
  260. begin
  261. Flags := ReadByte(P); { Flags }
  262. ParamName := ReadString(P); { Param name }
  263. S := ReadString(P); { Param type name }
  264. L := ReadLong(P); { Param Type Info }
  265. if L <> 0 then
  266. ParamInfo := PPTypeInfo(L)^
  267. else
  268. raise EInterfaceRTTIException.CreateFmt(SNoRTTIParam, [ParamName,
  269. IntfMethod.Name, IntfMD.UnitName + '.' + IntfMd.Name]);
  270. if J = 0 then
  271. IntfMethod.SelfInfo := ParamInfo
  272. else
  273. begin
  274. IntfParam := @IntfMethod.Params[K];
  275. IntfParam.Flags := TParamFlags(Flags);
  276. IntfParam.Name := ParamName;
  277. IntfParam.Info := ParamInfo;
  278. Inc(K);
  279. end;
  280. end;
  281. if Kind = Byte(mkFunction) then
  282. begin
  283. S := ReadString(P);
  284. IntfMethod.ResultInfo := PPTypeInfo(ReadLong(P))^;
  285. end;
  286. Inc(Offset);
  287. end;
  288. end;
  289. function WalkAncestors(PP: PPTypeInfo; AddMeths: Boolean; IntfMD: PIntfMetaData;
  290. WithRTTIOnly: Boolean): Integer;
  291. var
  292. S: string;
  293. AncTP: Pointer;
  294. P: Pointer;
  295. B: Byte;
  296. NumMethods, NumAncMeths, I: Integer;
  297. HasRTTI: Boolean;
  298. begin
  299. P := Pointer(PP^);
  300. ReadByte(P); // Kind
  301. S := ReadString(P); // Symbol name
  302. AncTP := Pointer(ReadLong(P)); // Ancestor TypeInfo
  303. P := Pointer(Integer(P) + 17); // Intf.flags and GUID
  304. B := Byte(P^); // Length
  305. P := Pointer(Integer(P) + B + 1); // Unit name and count
  306. NumMethods := ReadWord(P); // # methods
  307. I := ReadWord(P); // $FFFF if no RTTI, # methods again if has RTTI
  308. HasRTTI := (I <> $FFFF);
  309. { Compute the number of methods }
  310. if (AncTP <> nil) and (HasRTTI or (WithRTTIOnly = False)) then
  311. begin
  312. NumAncMeths := WalkAncestors(AncTP, False, nil, WithRTTIOnly);
  313. end else
  314. NumAncMeths := 0;
  315. { Ancestor count }
  316. Result := NumAncMeths;
  317. { Plus our own }
  318. if (HasRTTI or (WithRTTIOnly = False)) then
  319. Result := Result + NumMethods;
  320. { Do we need to fill in method information too? }
  321. if AddMeths then
  322. begin
  323. if HasRTTI then
  324. begin
  325. FillMethodArray(P, IntfMD, NumAncMeths, NumMethods);
  326. if NumAncMeths > 0 then
  327. WalkAncestors(AncTP, AddMeths, IntfMD, WithRTTIOnly);
  328. end;
  329. end;
  330. end;
  331. function GetNumAncMeths(P: Pointer; WithRTTIOnly: Boolean = False): Integer;
  332. var
  333. B: Byte;
  334. Anc: Pointer;
  335. begin
  336. Result := 0;
  337. ReadByte(P); // tkKind
  338. B := Byte(P^); // Symbol length
  339. P := Pointer(Integer(P) + B + 1); // Skip sym name and count
  340. Anc := Pointer(ReadLong(P)); // Ancestor pointer
  341. if Anc <> nil then
  342. Result := WalkAncestors(Anc, False, nil, WithRTTIOnly);
  343. end;
  344. procedure GetIntfMetaData(Info: PTypeInfo; var IntfMD: TIntfMetaData;
  345. MethodArrayOpt: TFillMethodArrayOpt);
  346. var
  347. I, Offset: Integer;
  348. Methods: Integer;
  349. BaseRTTIMethods: Integer;
  350. HasRTTI: Integer;
  351. PP: PPTypeInfo;
  352. P: Pointer;
  353. SelfMethCount: Integer;
  354. begin
  355. P := Pointer(Info);
  356. { Get total number of ancestor methods }
  357. IntfMD.NumAnc := GetNumAncMeths(P);
  358. { Get base methods we could expose }
  359. BaseRTTIMethods := GetNumAncMeths(P, True);
  360. IntfMD.Info := Info;
  361. { tkKind }
  362. ReadByte(P);
  363. IntfMD.Name := ReadString(P);
  364. PP := PPTypeInfo(ReadLong(P));
  365. { Ancestor typeinfo }
  366. if PP <> nil then
  367. IntfMD.AncInfo := PP^
  368. else
  369. IntfMD.AncInfo := nil;
  370. { Interface flags }
  371. ReadByte(P);
  372. IntfMD.IID.D1 := Longword(ReadLong(P));
  373. IntfMD.IID.D2 := ReadWord(P);
  374. IntfMD.IID.D3 := ReadWord(P);
  375. for I := 0 to 7 do
  376. IntfMD.IID.D4[I] := ReadByte(P);
  377. IntfMD.UnitName := ReadString(P);
  378. Methods := ReadWord(P); { # methods }
  379. HasRTTI := ReadWord(P); { $FFFF if no RTTI, # methods again if has RTTI }
  380. if HasRTTI = $FFFF then
  381. raise EInterfaceRTTIException.CreateFmt(SNoRTTI, [IntfMD.UnitName + '.' +
  382. IntfMd.Name]);
  383. { Save my method count }
  384. SelfMethCount := Methods;
  385. { Update count of methods }
  386. if (MethodArrayOpt = fmoAllBaseMethods) then
  387. begin
  388. Methods := Methods + IntfMD.NumAnc;
  389. Offset := IntfMD.NumAnc;
  390. end else
  391. if (MethodArrayOpt = fmoRTTIBaseMethods) then
  392. begin
  393. Methods := Methods + BaseRTTIMethods;
  394. Offset := BaseRTTIMethods;
  395. end else
  396. Offset := 0;
  397. { Size array and fill in information }
  398. SetLength(IntfMD.MDA, Methods);
  399. FillMethodArray(P, @IntfMD, Offset, SelfMethCount);
  400. { Include method info. of base methods too?? }
  401. if (MethodArrayOpt = fmoAllBaseMethods) or
  402. (MethodArrayOpt = fmoRTTIBaseMethods) then
  403. begin
  404. if PP <> nil then
  405. WalkAncestors(PP, True, @IntfMD, (MethodArrayOpt = fmoRTTIBaseMethods));
  406. end;
  407. end;
  408. procedure GetIntfMetaData(Info: PTypeInfo; var IntfMD: TIntfMetaData;
  409. IncludeAllAncMethods: Boolean);
  410. var
  411. FillMethodArrayOpt: TFillMethodArrayOpt;
  412. begin
  413. if (IncludeAllAncMethods) then
  414. FillMethodArrayOpt := fmoAllBaseMethods
  415. else
  416. FillMethodArrayOpt := fmoRTTIBaseMethods;
  417. GetIntfMetaData(Info, IntfMD, FillMethodArrayOpt);
  418. end;
  419. function GetMethNum(const IntfMD: TIntfMetaData; const MethName: string;
  420. ParamCount: Integer = -1): Integer;
  421. function CalcParamCount(const Start: Integer; const entry: TIntfMethEntry):
  422. Integer;
  423. var
  424. I: Integer;
  425. begin
  426. Result := Start;
  427. { Not needed for C++Builder }
  428. { TODO -oBB : The range of this loop looks suspicious - investigate ParamCount & confirm accuracy!! }
  429. for I := 0 to entry.ParamCount do
  430. if pfOut in entry.Params[I].Flags then
  431. Inc(Result);
  432. end;
  433. var
  434. I, NumNames, ExpCount: Integer;
  435. begin
  436. NumNames := 0;
  437. Result := -1;
  438. for I := 0 to Length(IntfMD.MDA) - 1 do
  439. begin
  440. { TODO OWNER:BB How will this fare under C++ where symbols are case-sensitive ??
  441. ??????? }
  442. if SameText(IntfMD.MDA[I].Name, MethName) then
  443. begin
  444. if ParamCount <> -1 then
  445. begin
  446. ExpCount := CalcParamCount(ParamCount, IntfMD.MDA[I]);
  447. if ExpCount <> IntfMD.MDA[I].ParamCount then
  448. Continue;
  449. end;
  450. Result := I;
  451. Inc(NumNames);
  452. end;
  453. end;
  454. if (NumNames = 0) and (ParamCount <> -1) then
  455. Result := GetMethNum(IntfMD, MethName, -1);
  456. if NumNames > 1 then
  457. Result := -1;
  458. end;
  459. function SameTypeInfo(const RegInfo: PTypeInfo; const OtherInfo: PTypeInfo):
  460. Boolean;
  461. begin
  462. Result := (RegInfo = OtherInfo) or
  463. ((RegInfo.Kind = OtherInfo.Kind) and TypeNamesMatch(RegInfo^.Name,
  464. OtherInfo^.Name));
  465. end;
  466. function TypeNamesMatch(const RegName: string; const OtherName: string): Boolean;
  467. var
  468. I: Integer;
  469. begin
  470. Result := (RegName = OtherName);
  471. if (not Result) then
  472. begin
  473. I := 1; { Start at one since we check OtherName first }
  474. while (I < Length(TypeInfoNames)) do
  475. begin
  476. if (OtherName = TypeInfoNames[I]) then
  477. begin
  478. Result := (RegName = TypeInfoNames[I - 1]);
  479. Exit;
  480. end;
  481. I := I + 2;
  482. end;
  483. end;
  484. end;
  485. function OtherTypeName(const TypeName: string): string;
  486. var
  487. I: Integer;
  488. begin
  489. I := 0;
  490. while (I < (Length(TypeInfoNames) - 1)) do
  491. begin
  492. if (TypeName = TypeInfoNames[I]) then
  493. begin
  494. Result := TypeInfoNames[I + 1];
  495. Exit;
  496. end;
  497. I := I + 2;
  498. end;
  499. end;
  500. //==============================================================================
  501. // 参数处理规则相关过程,移植自 InvRules
  502. //==============================================================================
  503. function IsParamByRef(Flags: TParamFlags; ParamInfo: PTypeInfo; CC: TCallConv):
  504. Boolean;
  505. begin
  506. Result := (pfVar in Flags) or (pfOut in Flags);
  507. if (not Result) and (ParamInfo.Kind = tkVariant) then
  508. Result := (pfConst in Flags) or (CC = ccPascal);
  509. if ParamInfo.Kind = tkString then
  510. Result := True;
  511. end;
  512. function GetTypeSize(P: PTypeInfo): Integer;
  513. var
  514. TypeData: PTypeData;
  515. begin
  516. Result := 4;
  517. TypeData := GetTypeData(P);
  518. case P.Kind of
  519. tkInteger:
  520. case TypeData^.OrdType of
  521. otSByte, otUByte:
  522. Result := SizeOf(Byte);
  523. otSWord, otUWord:
  524. Result := SizeOf(Word);
  525. otSLong, otULong:
  526. ;
  527. end;
  528. tkFloat:
  529. case TypeData.FloatType of
  530. ftSingle:
  531. Result := SizeOf(Single);
  532. ftDouble:
  533. Result := SizeOf(Double);
  534. ftComp:
  535. Result := SizeOf(Comp);
  536. ftCurr:
  537. Result := SizeOf(Currency);
  538. ftExtended:
  539. Result := SizeOf(Extended);
  540. end;
  541. tkChar:
  542. Result := 1;
  543. tkWChar:
  544. Result := 2;
  545. tkInt64:
  546. Result := SizeOf(Int64);
  547. tkVariant:
  548. Result := SizeOf(TVarData);
  549. tkEnumeration:
  550. Result := 1;
  551. end;
  552. end;
  553. function IsRetInAXDX(Info: PTypeInfo): Boolean;
  554. begin
  555. Result := False;
  556. if Info <> nil then
  557. case Info.Kind of
  558. tkInt64:
  559. Result := True;
  560. end;
  561. end;
  562. function RetOnStack(Info: PTypeInfo): Boolean;
  563. begin
  564. Result := False;
  565. if Info <> nil then
  566. case Info.Kind of
  567. tkLString,
  568. tkString,
  569. tkWString
  570. {$IFDEF UNICODE_STRING}, tkUString{$ENDIF}:
  571. Result := True;
  572. tkVariant:
  573. Result := True;
  574. tkDynArray:
  575. Result := True;
  576. end;
  577. end;
  578. function RetInFPU(Info: PTypeInfo): Boolean;
  579. begin
  580. Result := False;
  581. if Info <> nil then
  582. case Info.Kind of
  583. tkFloat: Result := True;
  584. end;
  585. end;
  586. {
  587. GetStackTypeSize
  588. Returns the size that is actually allocated on the stack for a given
  589. type. This is frequently different than the heap allocation for
  590. an object, because all stack pointers are allocated on 4 byte boundaries.
  591. So for example, the Extended type might occupy 10 bytes, but we will
  592. always allocate 12 bytes on the stack for it.
  593. }
  594. function GetStackTypeSize(P: PTypeInfo; CC: TCallConv): Integer;
  595. var
  596. TypeData: PTypeData;
  597. begin
  598. Result := 4;
  599. TypeData := GetTypeData(P);
  600. case P.Kind of
  601. tkFloat:
  602. case TypeData.FloatType of
  603. ftSingle:
  604. ;
  605. ftDouble, ftComp, ftCurr:
  606. Result := 8;
  607. ftExtended:
  608. Result := 10;
  609. end;
  610. tkInt64:
  611. Result := 8;
  612. tkVariant:
  613. if CC in [ccCdecl, ccStdCall, ccSafeCall] then
  614. Result := SizeOf(TVarData);
  615. end;
  616. // Make sure we're aligned on a 4 byte boundary
  617. Result := (Result + 3) and $FFFFFFFC;
  618. end;
  619. //==============================================================================
  620. // 用于动态方法调用的临时数据类,移植修改自 InvokeRegistry
  621. //==============================================================================
  622. { TDataContext }
  623. procedure TDataContext.SetDataPointer(Index: Integer; P: Pointer);
  624. begin
  625. DataP[Index] := P;
  626. end;
  627. function TDataContext.GetDataPointer(Index: Integer): Pointer;
  628. begin
  629. Result := DataP[Index];
  630. end;
  631. procedure TDataContext.AddVariantToClear(P: PVarData);
  632. var
  633. I: Integer;
  634. begin
  635. for I := 0 to Length(VarToClear) -1 do
  636. if VarToClear[I] = P then
  637. Exit;
  638. I := Length(VarToClear);
  639. SetLength(VarToClear, I + 1);
  640. VarToClear[I] := P;
  641. end;
  642. procedure TDataContext.AddStrToClear(P: Pointer);
  643. var
  644. I: Integer;
  645. begin
  646. { If this string is in the list already, we're set }
  647. for I := 0 to Length(StrToClear) -1 do
  648. if StrToClear[I] = P then
  649. Exit;
  650. I := Length(StrToClear);
  651. SetLength(StrToClear, I + 1);
  652. StrToClear[I] := P;
  653. end;
  654. procedure TDataContext.AddWStrToClear(P: Pointer);
  655. var
  656. I: Integer;
  657. begin
  658. { If this WideString is in the list already, we're set }
  659. for I := 0 to Length(WStrToClear) -1 do
  660. if WStrToClear[I] = P then
  661. Exit;
  662. I := Length(WStrToClear);
  663. SetLength(WStrToClear, I + 1);
  664. WStrToClear[I] := P;
  665. end;
  666. constructor TDataContext.Create;
  667. begin
  668. inherited;
  669. end;
  670. destructor TDataContext.Destroy;
  671. var
  672. I: Integer;
  673. P: Pointer;
  674. begin
  675. { Clean Variants we allocated }
  676. for I := 0 to Length(VarToClear) - 1 do
  677. begin
  678. if Assigned(VarToClear[I]) then
  679. Variant( PVarData(VarToClear[I])^) := NULL;
  680. end;
  681. SetLength(VarToClear, 0);
  682. { Clean up dynamic arrays we allocated }
  683. for I := 0 to Length(DynArrayToClear) - 1 do
  684. begin
  685. if Assigned(DynArrayToClear[I].P) then
  686. begin
  687. P := Pointer( PInteger(DynArrayToClear[I].P)^);
  688. DynArrayClear(P, DynArrayToClear[I].Info)
  689. end;
  690. end;
  691. SetLength(DynArrayToClear, 0);
  692. { Clean up strings we allocated }
  693. for I := 0 to Length(StrToClear) - 1 do
  694. begin
  695. if Assigned(StrToClear[I]) then
  696. PString(StrToClear[I])^ := '';
  697. end;
  698. SetLength(StrToClear, 0);
  699. { Clean up WideStrings we allocated }
  700. for I := 0 to Length(WStrToClear) - 1 do
  701. begin
  702. if Assigned(WStrToClear[I]) then
  703. PWideString(WStrToClear[I])^ := '';
  704. end;
  705. SetLength(WStrToClear, 0);
  706. inherited;
  707. end;
  708. procedure TDataContext.AddDynArrayToClear(P: Pointer; Info: PTypeInfo);
  709. var
  710. I: Integer;
  711. begin
  712. for I := 0 to Length(DynArrayToClear) -1 do
  713. if DynArrayToClear[I].P = P then
  714. Exit;
  715. I := Length(DynArrayToClear);
  716. SetLength(DynArrayToClear, I + 1);
  717. DynArrayToClear[I].P := P;
  718. DynArrayToClear[I].Info := Info;
  719. end;
  720. function TDataContext.AllocData(Size: Integer): Pointer;
  721. begin
  722. Result := @Data[DataOffset];
  723. Inc(DataOffset, Size);
  724. end;
  725. { TInvContext }
  726. const
  727. MAXINLINESIZE = sizeof(TVarData) + 4;
  728. procedure TInvContext.SetMethodInfo(const MD: TIntfMethEntry);
  729. begin
  730. SetLength(DataP, MD.ParamCount + 1);
  731. SetLength(Data, (MD.ParamCount + 1) * MAXINLINESIZE);
  732. end;
  733. procedure TInvContext.SetParamPointer(Param: Integer; P: Pointer);
  734. begin
  735. SetDataPointer(Param, P);
  736. end;
  737. function TInvContext.GetParamPointer(Param: Integer): Pointer;
  738. begin
  739. Result := GetDataPointer(Param);
  740. end;
  741. function TInvContext.GetResultPointer: Pointer;
  742. begin
  743. Result := ResultP;
  744. end;
  745. procedure TInvContext.SetResultPointer(P: Pointer);
  746. begin
  747. ResultP := P;
  748. end;
  749. procedure TInvContext.AllocServerData(const MD: TIntfMethEntry);
  750. var
  751. I: Integer;
  752. Info: PTypeInfo;
  753. P: Pointer;
  754. begin
  755. for I := 0 to MD.ParamCount - 1 do
  756. begin
  757. P := AllocData(GetTypeSize(MD.Params[I].Info));
  758. SetParamPointer(I, P);
  759. if MD.Params[I].Info.Kind = tkVariant then
  760. begin
  761. Variant(PVarData(P)^) := NULL;
  762. AddVariantToClear(PVarData(P));
  763. end else if MD.Params[I].Info.Kind = tkDynArray then
  764. begin
  765. AddDynArrayToClear(P, MD.Params[I].Info);
  766. end else if MD.Params[I].Info.Kind = tkLString then
  767. begin
  768. PString(P)^ := '';
  769. AddStrToClear(P);
  770. end else if (MD.Params[I].Info.kind = tkWString) {$IFDEF UNICODE_STRING} or (MD.Params[I].Info.kind = tkUString) {$ENDIF} then
  771. begin
  772. PWideString(P)^ := '';
  773. AddWStrToClear(P);
  774. end;
  775. end;
  776. if MD.ResultInfo <> nil then
  777. begin
  778. Info := MD.ResultInfo;
  779. case Info^.Kind of
  780. tkLString:
  781. begin
  782. P := AllocData(sizeof(PString));
  783. PString(P)^ := '';
  784. AddStrToClear(P);
  785. end;
  786. tkWString {$IFDEF UNICODE_STRING}, tkUString{$ENDIF}:
  787. begin
  788. P := AllocData(sizeof(PWideString));
  789. PWideString(P)^ := '';
  790. AddWStrToClear(P);
  791. end;
  792. tkInt64:
  793. P := AllocData(sizeof(Int64));
  794. tkVariant:
  795. begin
  796. P := AllocData(sizeof(TVarData));
  797. Variant( PVarData(P)^ ) := NULL;
  798. AddVariantToClear(PVarData(P));
  799. end;
  800. tkDynArray:
  801. begin
  802. P := AllocData(GetTypeSize(Info));
  803. AddDynArrayToClear(P, MD.ResultInfo);
  804. end;
  805. else
  806. P := AllocData(GetTypeSize(Info));
  807. end;
  808. SetResultPointer(P);
  809. end;
  810. end;
  811. //==============================================================================
  812. // 动态接口方法调用器类,移植修改自 Invoke
  813. //==============================================================================
  814. constructor TInterfaceInvoker.Create;
  815. begin
  816. inherited Create;
  817. end;
  818. {
  819. PushStackParm
  820. Copies an aligned number of bytes specified by ByteCount from the Parm
  821. to the current stack. N.B. We leave the bytes on the stack when we
  822. exit!
  823. Stack parameters come in many different sizes, ranging from 4 bytes to
  824. 16 bytes. This function copies a parameter of arbitrary
  825. size from a prior stack location (assumed the stack), onto the current
  826. stack. On exit, we leave the additional bytes on the stack. We use this
  827. to build the parameter list to the server side functions.
  828. We don't have to worry about copying bytes at the end of a page, because
  829. we assume that Parm is pointing to something higher up on the stack, and
  830. aligned on a proper stack boundary.
  831. }
  832. procedure PushStackParm(Parm: Pointer; ByteCount: Integer);
  833. asm
  834. {
  835. EAX -> Parm (the parameter to be copied)
  836. EDX -> ByteCount (the number of bytes of data in Parm)
  837. }
  838. { We just use a jump table to copy the bits }
  839. LEA ECX, @JT
  840. {$IFDEF PIC}
  841. ADD ECX, EBX
  842. ADD ECX, EDX // Assume that ByteCount is a DWORD multiple
  843. POP EDX // Remove and save the return address
  844. MOV ECX, [ECX]
  845. ADD ECX, EBX
  846. JMP ECX
  847. {$ELSE}
  848. ADD ECX, EDX // Assume that ByteCount is a DWORD multiple
  849. POP EDX // Remove and save the return address
  850. JMP [ECX]
  851. {$ENDIF}
  852. @L4:
  853. PUSH [EAX+12]
  854. @L3:
  855. PUSH [EAX+8]
  856. @L2:
  857. PUSH [EAX+4]
  858. @L1:
  859. PUSH [EAX]
  860. PUSH EDX // Push back the saved ret addr
  861. RET // All done
  862. @JT:
  863. DD 0 // 0 bytes (never happens)
  864. DD @L1 // 4 bytes
  865. DD @L2 // 8 bytes
  866. DD @L3 // 12 bytes
  867. DD @L4 // 16 bytes
  868. end;
  869. {
  870. GetFloatReturn
  871. Handles the nuances of retrieving the various different sized floating
  872. point values from the FPU and storing them in a buffer.
  873. }
  874. procedure GetFloatReturn(RetP: Pointer; FloatType: TFloatType);
  875. asm
  876. CMP EDX, ftSingle
  877. JE @@Single
  878. CMP EDX, ftDouble
  879. JE @@Double
  880. CMP EDX, ftExtended
  881. JE @@Extended
  882. CMP EDX, ftCurr
  883. JE @@Curr
  884. CMP EDX, ftComp
  885. JE @@Curr { Same as Curr }
  886. { Should never get here :) }
  887. @@Single:
  888. FSTP DWORD PTR [EAX]
  889. WAIT
  890. RET
  891. @@Double:
  892. FSTP QWORD PTR [EAX]
  893. WAIT
  894. RET
  895. @@Extended:
  896. FSTP TBYTE PTR [EAX]
  897. WAIT
  898. RET
  899. @@Curr:
  900. FISTP QWORD PTR [EAX]
  901. WAIT
  902. end;
  903. procedure TInterfaceInvoker.Invoke(const Obj: TObject;
  904. IntfMD: TIntfMetaData; const MethNum: Integer;
  905. const Context: TInvContext);
  906. var
  907. MethPos: Integer;
  908. Unk: IUnknown;
  909. IntfEntry: PInterfaceEntry;
  910. IntfVTable: Pointer;
  911. RetIsOnStack, RetIsInFPU, RetInAXDX: Boolean;
  912. I: Integer;
  913. RetP: Pointer;
  914. MD: TIntfMethEntry;
  915. DataP: Pointer;
  916. Temp, Temp1: Integer;
  917. RetEAX: Integer;
  918. RetEDX: Integer;
  919. TotalParamBytes: Integer;
  920. ParamBytes: Integer;
  921. begin
  922. {$IFDEF LINUX}
  923. try
  924. {$ENDIF}
  925. TotalParamBytes := 0;
  926. MD := IntfMD.MDA[MethNUm];
  927. if not Obj.GetInterface(IntfMD.IID, Unk) then
  928. raise Exception.CreateFmt(SNoInterfaceGUID,
  929. [Obj.ClassName, GuidToString(IntfMD.IID)]);
  930. IntfEntry := Obj.GetInterfaceEntry(IntfMD.IID);
  931. IntfVTable := IntfEntry.VTable;
  932. MethPos := MD.Pos * 4; { Pos is absolute to whole VMT }
  933. if MD.ResultInfo <> nil then
  934. begin
  935. RetIsInFPU := RetInFPU(MD.ResultInfo);
  936. RetIsOnStack := RetOnStack(MD.ResultInfo);
  937. RetInAXDX := IsRetInAXDX(MD.ResultInfo);
  938. RetP := Context.GetResultPointer;
  939. end else
  940. begin
  941. RetIsOnStack := False;
  942. RetIsInFPU := False;
  943. RetInAXDX := False;
  944. end;
  945. if MD.CC in [ccCDecl, ccStdCall, ccSafeCall] then
  946. begin
  947. if (MD.ResultInfo <> nil) and (MD.CC = ccSafeCall) then
  948. asm PUSH DWORD PTR [RetP] end;
  949. for I := MD.ParamCount - 1 downto 0 do
  950. begin
  951. DataP := Context.GetParamPointer(I);
  952. if IsParamByRef(MD.Params[I].Flags, MD.Params[I].Info, MD.CC) then
  953. asm
  954. PUSH DWORD PTR [DataP]
  955. end
  956. else
  957. begin
  958. ParamBytes := GetStackTypeSize(MD.Params[I].Info, MD.CC);
  959. PushStackParm(DataP, ParamBytes);
  960. Inc(TotalParamBytes, ParamBytes);
  961. end;
  962. end;
  963. asm PUSH DWORD PTR [Unk] end;
  964. if RetIsOnStack and (MD.CC <> ccSafeCall) then
  965. asm PUSH DWORD PTR [RetP] end;
  966. end
  967. else if MD.CC = ccPascal then
  968. begin
  969. for I := 0 to MD.ParamCount - 1 do
  970. begin
  971. DataP := Context.GetParamPointer(I);
  972. if IsParamByRef(MD.Params[I].Flags, MD.Params[I].Info, MD.CC) then
  973. asm
  974. PUSH DWORD PTR [DataP]
  975. end
  976. else
  977. begin
  978. // PushStackParm(DataP, GetStackTypeSize(MD.Params[I].Info, MD.CC));
  979. ParamBytes := GetStackTypeSize(MD.Params[I].Info, MD.CC);
  980. PushStackParm(DataP, ParamBytes);
  981. Inc(TotalParamBytes, ParamBytes);
  982. end;
  983. end;
  984. if RetIsOnStack then
  985. asm PUSH DWORD PTR [RetP] end;
  986. asm PUSH DWORD PTR [Unk] end;
  987. end else
  988. raise Exception.CreateFmt(SUnsupportedCC, [CallingConventionName[MD.CC]]);
  989. if MD.CC <> ccSafeCall then
  990. begin
  991. asm
  992. MOV DWORD PTR [Temp], EAX
  993. MOV DWORD PTR [Temp1], ECX
  994. MOV EAX, MethPos
  995. MOV ECX, [IntfVtable]
  996. MOV ECX, [ECX + EAX]
  997. CALL ECX
  998. MOV DWORD PTR [RetEAX], EAX
  999. MOV DWORD PTR [RetEDX], EDX
  1000. MOV EAX, DWORD PTR [Temp]
  1001. MOV ECX, DWORD PTR [Temp1]
  1002. end;
  1003. end else
  1004. begin
  1005. asm
  1006. MOV DWORD PTR [Temp], EAX
  1007. MOV DWORD PTR [Temp1], ECX
  1008. MOV EAX, MethPos
  1009. MOV ECX, [IntfVtable]
  1010. MOV ECX, [ECX + EAX]
  1011. CALL ECX
  1012. CALL System.@CheckAutoResult
  1013. MOV DWORD PTR [RetEAX], EAX
  1014. MOV DWORD PTR [RetEDX], EDX
  1015. MOV EAX, DWORD PTR [Temp]
  1016. MOV ECX, DWORD PTR [Temp1]
  1017. end;
  1018. end;
  1019. // If we're cdecl, we're responsible for cleanup up the stack.
  1020. if MD.CC = ccCDecl then
  1021. asm
  1022. MOV EAX, DWORD PTR [TotalParamBytes]
  1023. ADD ESP, EAX
  1024. end;
  1025. if MD.ResultInfo <> nil then
  1026. begin
  1027. if MD.CC <> ccSafeCall then
  1028. begin
  1029. if RetIsInFPU then
  1030. begin
  1031. GetFloatReturn(RetP, GetTypeData(MD.ResultInfo).FloatType);
  1032. end else if not RetIsOnStack then
  1033. begin
  1034. if RetInAXDX then
  1035. asm
  1036. PUSH EAX
  1037. PUSH ECX
  1038. MOV EAX, DWORD PTR [RetP]
  1039. MOV ECX, DWORD PTR [RetEAX]
  1040. MOV [EAX], ECX
  1041. MOV ECX, DWORD PTR [RetEDX]
  1042. MOV [EAX + 4], ECX
  1043. POP ECX
  1044. POP EAX
  1045. end
  1046. else
  1047. asm
  1048. PUSH EAX
  1049. PUSH ECX
  1050. MOV EAX, DWORD PTR [RetP]
  1051. MOV ECX, DWORD PTR [RetEAX]
  1052. MOV [EAX], ECX
  1053. POP ECX
  1054. POP EAX
  1055. end;
  1056. end;
  1057. end;
  1058. end;
  1059. {$IFDEF LINUX}
  1060. except
  1061. // This little bit of code is required to reset the stack back to a more
  1062. // resonable state since the exception unwinder is completely unaware of
  1063. // the stack pointer adjustments made in this function.
  1064. asm
  1065. MOV EAX, DWORD PTR [TotalParamBytes]
  1066. ADD ESP, EAX
  1067. end;
  1068. raise;
  1069. end;
  1070. {$ENDIF}
  1071. end;
  1072. //==============================================================================
  1073. // 类型转换器类,移植修改自 TypeTrans
  1074. //==============================================================================
  1075. { TTypeTranslator }
  1076. function GetEnumValueEx(TypInfo: PTypeInfo; const Name: string): Integer;
  1077. var
  1078. PName: string;
  1079. begin
  1080. PName := Name;
  1081. if SameTypeInfo(TypeInfo(System.Boolean), TypInfo) or
  1082. SameTypeInfo(TypeInfo(System.ByteBool), TypInfo) or
  1083. SameTypeInfo(TypeInfo(System.WordBool), TypInfo) or
  1084. SameTypeInfo(TypeInfo(System.LongBool), TypInfo) then
  1085. begin
  1086. if SameText(Name, 'true') or SameText(Name, '1') then { Do not localize }
  1087. PName := 'True' { Do not localize }
  1088. else if SameText(Name, 'false') or SameText(Name, '0') then { Do not localize }
  1089. PName := 'False'; { Do not localize }
  1090. Result := GetEnumValue(TypeInfo(System.Boolean), PName);
  1091. end else
  1092. begin
  1093. Result := GetEnumValue(TypInfo, PName);
  1094. end;
  1095. end;
  1096. // 转换一个集合值为字符串
  1097. function SetToStr(TypeInfo: PTypeInfo; Value: TIntegerSet): string;
  1098. var
  1099. EnumValue: 0..SizeOf(Integer) * 8 - 1;
  1100. begin
  1101. Assert(TypeInfo^.Kind in [tkEnumeration, tkSet]);
  1102. if TypeInfo^.Kind = tkSet then
  1103. TypeInfo := GetTypeData(TypeInfo)^.CompType^;
  1104. Result := '';
  1105. for EnumValue := GetTypeData(TypeInfo)^.MinValue to
  1106. GetTypeData(TypeInfo)^.MaxValue do
  1107. if EnumValue in Value then
  1108. if Result = '' then
  1109. Result := GetEnumName(TypeInfo, EnumValue)
  1110. else
  1111. Result := Result + ', ' + GetEnumName(TypeInfo, EnumValue);
  1112. Result := '[' + Result + ']';
  1113. end;
  1114. // 转换一个字符串到集合
  1115. function StrToSet(TypeInfo: PTypeInfo; const Value: string): TIntegerSet;
  1116. resourcestring
  1117. SInvalidSetStr = '''%s'' is not a valid set string';
  1118. var
  1119. EnumValue: 0..SizeOf(Integer) * 8 - 1;
  1120. S: string;
  1121. Strings: TStrings;
  1122. i: Integer;
  1123. begin
  1124. Assert(TypeInfo^.Kind in [tkEnumeration, tkSet]);
  1125. if TypeInfo^.Kind = tkSet then
  1126. TypeInfo := GetTypeData(TypeInfo)^.CompType^;
  1127. Result := [];
  1128. S := Trim(Value);
  1129. if (S[1] = '[') and (S[Length(S)] = ']') then
  1130. begin
  1131. S := Copy(S, 2, Length(S) - 2);
  1132. Strings := TStringList.Create;
  1133. try
  1134. Strings.CommaText := S;
  1135. for i := 0 to Strings.Count - 1 do
  1136. begin
  1137. EnumValue := GetEnumValue(TypeInfo, Trim(Strings[i]));
  1138. if (EnumValue < GetTypeData(TypeInfo)^.MinValue) or
  1139. (EnumValue > GetTypeData(TypeInfo)^.MaxValue) then
  1140. raise EConvertError.Create(Format(SInvalidSetStr, [Value]));
  1141. Include(TIntegerSet(Result), EnumValue);
  1142. end;
  1143. finally
  1144. Strings.Free;
  1145. end;
  1146. end;
  1147. end;
  1148. // 转换一个标识符为整数(Color、CharSet等)
  1149. function IdentToInt(TypeInfo: PTypeInfo; const Value: string): Integer;
  1150. var
  1151. IdToInt: TIdentToInt;
  1152. IntValue: Integer;
  1153. begin
  1154. Assert(TypeInfo^.Kind = tkInteger);
  1155. IdToInt := FindIdentToInt(TypeInfo);
  1156. if Assigned(IdToInt) and IdToInt(Value, IntValue) then
  1157. Result := IntValue
  1158. else
  1159. Result := StrToInt(Value);
  1160. end;
  1161. constructor TTypeTranslator.Create;
  1162. begin
  1163. inherited Create;
  1164. end;
  1165. destructor TTypeTranslator.Destroy;
  1166. begin
  1167. inherited;
  1168. end;
  1169. type
  1170. PWideChar = ^WideChar;
  1171. procedure TTypeTranslator.CastVariantToNative(Info: PTypeInfo; const Value:
  1172. OleVariant; NatData: Pointer);
  1173. var
  1174. ParamTypeData: PTypeData;
  1175. AnsiStr: string;
  1176. WideStr: WideString;
  1177. Int: Integer;
  1178. begin
  1179. if VarIsNull(Value) or VarIsEmpty(Value) then
  1180. Exit;
  1181. ParamTypeData := GetTypeData(Info);
  1182. case Info^.Kind of
  1183. tkInteger:
  1184. begin
  1185. // 处理 TColor、CharSet 等标识符
  1186. Int := IdentToInt(Info, Value);
  1187. case ParamTypeData^.OrdType of
  1188. otSByte,
  1189. otUByte:
  1190. PByte(NatData)^ := Int;
  1191. otSWord,
  1192. otUWord:
  1193. PSmallint(NatData)^ := Int;
  1194. otSLong,
  1195. otULong:
  1196. PInteger(NatData)^ := Int;
  1197. end;
  1198. end;
  1199. tkFloat:
  1200. case ParamTypeData^.FloatType of
  1201. ftSingle:
  1202. PSingle(NatData)^ := Value;
  1203. ftDouble:
  1204. begin
  1205. if Info = TypeInfo(TDateTime) then
  1206. PDateTime(NatData)^ := Value
  1207. else
  1208. PDouble(NatData)^ := Value;
  1209. end;
  1210. ftComp:
  1211. PComp(NatData)^ := Value;
  1212. ftCurr:
  1213. PCurrency(NatData)^ := Value;
  1214. ftExtended:
  1215. PExtended(NatData)^ := Value;
  1216. end;
  1217. tkInt64:
  1218. PInt64(NatData)^ := Value;
  1219. tkChar:
  1220. begin
  1221. AnsiStr := Value;
  1222. if AnsiStr <> '' then
  1223. PChar(NatData)^ := AnsiStr[1];
  1224. end;
  1225. tkWChar:
  1226. begin
  1227. WideStr := Value;
  1228. if WideStr <> '' then
  1229. PWideChar(NatData)^ := WideStr[1];
  1230. end;
  1231. tkWString:
  1232. PWideString(NatData)^ := Value;
  1233. {$IFDEF UNICODE_STRING}
  1234. tkUString:
  1235. PUnicodeString(NatData)^ := Value;
  1236. {$ENDIF}
  1237. tkString:
  1238. PShortString(NatData)^ := Value;
  1239. tkLString:
  1240. PString(NatData)^ := Value;
  1241. tkEnumeration:
  1242. { NOTE: Here we assume enums to be byte-size; make sure (specially for C++)
  1243. that enums have generated with the proper size }
  1244. PByte(NatData)^ := GetEnumValueEx(Info, Value);
  1245. tkClass:
  1246. PInteger(NatData)^ := Value;
  1247. tkSet, tkMethod, { TODO -oyygw : 增加对集合类型的处理 }
  1248. tkArray, tkRecord, tkInterface,
  1249. tkDynArray:
  1250. raise ETypeTransException.CreateFmt(SUnexpectedDataType,
  1251. [KindNameArray[Info.Kind]]);
  1252. tkVariant:
  1253. Variant(PVarData(NatData)^) := Value;
  1254. end;
  1255. end;
  1256. procedure TTypeTranslator.CastNativeToVariant(Info: PTypeInfo;
  1257. var Value: OleVariant; NatData: Pointer);
  1258. var
  1259. TypeData: PTypeData;
  1260. begin
  1261. TypeData := GetTypeData(Info);
  1262. case Info.Kind of
  1263. tkInteger:
  1264. case TypeData.OrdType of
  1265. otSByte, otUByte:
  1266. Value := Byte(NatData^);
  1267. otSWord, otUWord:
  1268. Value := SmallInt(NatData^);
  1269. otSLong, otULong:
  1270. Value := Integer(NatData^);
  1271. end;
  1272. tkFloat:
  1273. case TypeData.FloatType of
  1274. ftSingle:
  1275. Value := Single(NatData^);
  1276. ftDouble:
  1277. begin
  1278. if Info = TypeInfo(TDateTime) then
  1279. Value := TDateTime(NatData^)
  1280. else
  1281. Value := Double(NatData^);
  1282. end;
  1283. ftComp:
  1284. Value := Comp(NatData^);
  1285. ftCurr:
  1286. Value := Currency(NatData^);
  1287. ftExtended:
  1288. Value := Extended(NatData^);
  1289. end;
  1290. tkInt64:
  1291. Value := Int64(NatData^);
  1292. tkChar:
  1293. Value := Char(NatData^);
  1294. tkWChar:
  1295. Value := WideChar(NatData^);
  1296. tkWString:
  1297. Value := PWideString(NatData)^;
  1298. {$IFDEF UNICODE_STRING}
  1299. tkUString:
  1300. Value := PUnicodeString(NatData)^;
  1301. {$ENDIF}
  1302. tkString:
  1303. Value := PShortString(NatData)^;
  1304. tkLString:
  1305. Value := PAnsiString(NatData)^;
  1306. tkEnumeration:
  1307. { NOTE: Here we assume enums to be byte-size; make sure (specially for C++)
  1308. that enums have generated with the proper size }
  1309. Value := GetEnumName(Info, PByte(NatData)^);
  1310. tkClass:
  1311. Value := PInteger(NatData)^; // 对象按指针(整数)处理
  1312. tkSet, tkMethod, { TODO -oyygw : 增加对集合类型的处理 }
  1313. tkArray, tkRecord, tkInterface,
  1314. tkDynArray:
  1315. raise ETypeTransException.CreateFmt(SUnexpectedDataType,
  1316. [KindNameArray[Info.Kind]]);
  1317. tkVariant:
  1318. Value := Variant(PVarData(NatData)^);
  1319. end;
  1320. end;
  1321. initialization
  1322. finalization
  1323. if Assigned(FInterfaceInvoker) then
  1324. FreeAndNil(FInterfaceInvoker);
  1325. if Assigned(FTypeTranslator) then
  1326. FreeAndNil(FTypeTranslator);
  1327. end.