varutils.inc 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798
  1. {
  2. This file is part of the Free Pascal run time library.
  3. Copyright (c) 1999-2001 by the Free Pascal development team
  4. Variant routines for non-windows oses.
  5. See the file COPYING.FPC, included in this distribution,
  6. for details about the copyright.
  7. This program is distributed in the hope that it will be useful,
  8. but WITHOUT ANY WARRANTY; without even the implied warranty of
  9. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  10. **********************************************************************}
  11. { ---------------------------------------------------------------------
  12. Some general stuff: Error handling and so on.
  13. ---------------------------------------------------------------------}
  14. { we do ugly things with tvararray here }
  15. {$PUSH}
  16. {$RANGECHECKS OFF}
  17. Procedure SetUnlockResult (P : PVarArray; Res : HResult);
  18. begin
  19. If Res=VAR_OK then
  20. Res:=SafeArrayUnlock(P)
  21. else
  22. SafeArrayUnlock(P);
  23. end;
  24. Procedure MakeWideString (Var P : PWideChar; W : WideString);
  25. begin
  26. P:=PWideChar(W);
  27. end;
  28. Procedure CopyAsWideString (Var PDest : PWideChar; PSource : PWideChar);
  29. begin
  30. WideString(Pointer(PDest)):=WideString(Pointer(PSource));
  31. end;
  32. { ---------------------------------------------------------------------
  33. Basic variant handling.
  34. ---------------------------------------------------------------------}
  35. procedure VariantInit(var Varg: TVarData); stdcall;
  36. begin
  37. With Varg do
  38. begin
  39. FillChar(VBytes, SizeOf(VBytes), 0);
  40. VType:=varEmpty;
  41. end;
  42. end;
  43. function VariantClear(var Varg: TVarData): HRESULT;stdcall;
  44. begin
  45. With Varg do
  46. if (VType and varArray)=varArray then
  47. begin
  48. Result:=SafeArrayDestroy(VArray);
  49. if Result<>VAR_OK then
  50. exit;
  51. end
  52. else
  53. begin
  54. if (VType and varByRef) = 0 then
  55. case VType of
  56. varEmpty, varNull, varSmallint, varInteger, varWord,
  57. {$ifndef FPUNONE}
  58. varSingle, varDouble, varCurrency, varDate,
  59. {$endif}
  60. varError, varBoolean, varByte,VarShortInt,
  61. varInt64, VarLongWord,VarQWord:
  62. ;
  63. varOleStr:
  64. WideString(Pointer(VOleStr)):='';
  65. varDispatch,
  66. varUnknown:
  67. iinterface(vunknown):=nil;
  68. else
  69. exit(VAR_BADVARTYPE)
  70. end;
  71. end;
  72. VariantInit(Varg);
  73. Result:=VAR_OK;
  74. end;
  75. function VariantCopy(var VargDest: TVarData; const VargSrc: TVarData): HRESULT;stdcall;
  76. begin
  77. if @VargSrc = @VargDest then
  78. Exit(VAR_OK);
  79. Result:=VariantClear(VargDest);
  80. if Result<>VAR_OK then
  81. exit;
  82. With VargSrc do
  83. begin
  84. if (VType and varArray) <> 0 then
  85. Result:=SafeArrayCopy(VArray,VargDest.VArray)
  86. else
  87. begin
  88. if (VType and varByRef) <> 0 then
  89. VArgDest.VPointer:=VPointer
  90. else
  91. case (VType and varTypeMask) of
  92. varEmpty, varNull:;
  93. varSmallint, varInteger, varWord,
  94. {$ifndef FPUNONE}
  95. varSingle, varDouble, varCurrency, varDate,
  96. {$endif}
  97. varError, varBoolean, varByte,VarShortInt,
  98. varInt64, VarLongWord,VarQWord:
  99. Move(VBytes, VargDest.VBytes, SizeOf(VargDest.VBytes));
  100. varOleStr:
  101. CopyAsWideString(VargDest.VOleStr,VOleStr);
  102. varDispatch:
  103. IUnknown(VargDest.vdispatch):=IUnknown(VargSrc.vdispatch);
  104. varUnknown:
  105. IUnknown(VargDest.vunknown):=IUnknown(VargSrc.vunknown);
  106. else
  107. Exit(VAR_BADVARTYPE);
  108. end;
  109. end;
  110. VargDest.VType:=VType;
  111. end;
  112. end;
  113. function VariantCopyInd(var VargDest: TVarData; const VargSrc: TVarData): HRESULT;stdcall;
  114. begin
  115. if (VargSrc.VType and varByRef) = 0 then
  116. Exit(VariantCopy(VargDest, VargSrc));
  117. With VargSrc do
  118. begin
  119. if (VType and varArray) <> 0 then
  120. Exit(VAR_INVALIDARG);
  121. case (VType and varTypeMask) of
  122. varEmpty, varNull:;
  123. varSmallint : VargDest.VSmallInt:=PSmallInt(VPointer)^;
  124. varInteger : VargDest.VInteger:=PLongint(VPointer)^;
  125. {$ifndef FPUNONE}
  126. varSingle : VargDest.VSingle:=PSingle(VPointer)^;
  127. varDouble : VargDest.VDouble:=PDouble(VPointer)^;
  128. varCurrency : VargDest.VCurrency:=PCurrency(VPointer)^;
  129. varDate : VargDest.VDate:=PDate(VPointer)^;
  130. {$endif}
  131. varBoolean : VargDest.VBoolean:=PWordBool(VPointer)^;
  132. varError : VargDest.VError:=PError(VPointer)^;
  133. varByte : VargDest.VByte:=PByte(VPointer)^;
  134. varWord : VargDest.VWord:=PWord(VPointer)^;
  135. VarShortInt : VargDest.VShortInt:=PShortInt(VPointer)^;
  136. VarInt64 : VargDest.VInt64:=PInt64(VPointer)^;
  137. VarLongWord : VargDest.VLongWord:=PCardinal(VPointer)^;
  138. VarQWord : VargDest.VQWord:=PQWord(VPointer)^;
  139. varVariant : Variant(VargDest):=Variant(PVarData(VPointer)^);
  140. varOleStr : CopyAsWideString(VargDest.VOleStr,PVarData(VPointer)^.VoleStr);
  141. varDispatch,
  142. varUnknown : IInterface(VargDest.vUnknown):=IInterface(PInterface(VargSrc.VPointer)^);
  143. else
  144. Exit(VAR_BADVARTYPE);
  145. end;
  146. VargDest.VType:=VType and VarTypeMask;
  147. end;
  148. Result:=VAR_OK;
  149. end;
  150. Function VariantChangeTypeEx(var VargDest: TVarData; const VargSrc: TVarData;
  151. LCID: Integer; Flags: Word; VarType: Word): HRESULT; stdcall;
  152. var
  153. Tmp : TVarData;
  154. begin
  155. if ((VarType and varArray) <> 0) or
  156. ((VargSrc.VType and varArray) <> 0) or
  157. ((VarType and varByRef) <> 0) then
  158. Exit(VAR_INVALIDARG);
  159. Result:=VariantCopyInd(Tmp, VargSrc);
  160. if Result = VAR_OK then
  161. try
  162. Result:=VariantClear(VargDest);
  163. {$RANGECHECKS ON}
  164. if Result = VAR_OK then
  165. try
  166. case Vartype of
  167. varSmallInt : VargDest.VSmallInt:=VariantToSmallInt(Tmp);
  168. varInteger : VargDest.VInteger:=VariantToLongint(Tmp);
  169. {$ifndef FPUNONE}
  170. varSingle : VargDest.VSingle:=VariantToSingle(Tmp);
  171. varDouble : VargDest.VDouble:=VariantToDouble(Tmp);
  172. varCurrency : VargDest.VCurrency:=VariantToCurrency(Tmp);
  173. varDate : VargDest.VDate:=VariantToDate(tmp);
  174. {$endif}
  175. varOleStr : MakeWideString(VargDest.VoleStr, VariantToWideString(tmp));
  176. varDispatch : Result:=VAR_TYPEMISMATCH;
  177. varUnknown : Result:=VAR_TYPEMISMATCH;
  178. varBoolean : VargDest.VBoolean:=VariantToBoolean(Tmp);
  179. varByte : VargDest.VByte:=VariantToByte(Tmp);
  180. VarShortInt : VargDest.VShortInt:=VariantToShortInt(Tmp);
  181. VarInt64 : VargDest.Vint64:=VariantToInt64(Tmp);
  182. VarLongWord : VargDest.VLongWord:=VariantToCardinal(Tmp);
  183. VarQWord : VargDest.VQWord:=VariantToQword(tmp);
  184. else
  185. Result:=VAR_BADVARTYPE;
  186. end;
  187. If Result = VAR_OK then
  188. VargDest.VType:=VarType;
  189. except
  190. On E : EVariantError do
  191. Result:=E.ErrCode;
  192. else
  193. Result:=VAR_INVALIDARG;
  194. end;
  195. finally
  196. VariantClear(Tmp);
  197. end;
  198. {$RANGECHECKS OFF}
  199. end;
  200. { ---------------------------------------------------------------------
  201. Variant array support
  202. ---------------------------------------------------------------------}
  203. Function CheckArrayUnlocked (psa : PVarArray) : HResult;
  204. begin
  205. If psa^.LockCount = 0 Then
  206. Result:=VAR_OK
  207. else
  208. Result:=VAR_ARRAYISLOCKED;
  209. end;
  210. Function CheckVarArray(psa: PVarArray ): HRESULT;
  211. begin
  212. If psa=nil then
  213. Result:=VAR_INVALIDARG
  214. else
  215. Result:=VAR_OK;
  216. end;
  217. Function SafeArrayCalculateElementAddress(psa: PVarArray; aElement: SizeInt): Pointer;
  218. begin
  219. Result:=Pointer(psa^.Data)+(aElement*psa^.ElementSize);
  220. end;
  221. Function CheckVarArrayAndCalculateAddress(psa: PVarArray;
  222. Indices: PVarArrayCoorArray; var Address: Pointer; Lockit: Boolean): HRESULT;
  223. var
  224. I,D,Count,Idx : LongInt;
  225. begin
  226. Result:=CheckVarArray(psa);
  227. Address:=nil;
  228. Count:=0;
  229. If Result<>VAR_OK then
  230. exit;
  231. D:=0;
  232. for I:=0 to psa^.DimCount-1 do
  233. begin
  234. Idx:=Indices^[psa^.DimCount-I-1] - psa^.Bounds[I].LowBound;
  235. if (Idx<0) or (Idx>=psa^.Bounds[I].ElementCount) then
  236. Exit(VAR_BADINDEX);
  237. if I=0 then
  238. Count:=Idx
  239. else
  240. Inc(Count,Idx*D);
  241. Inc(D,psa^.Bounds[I].ElementCount);
  242. end;
  243. Address:=SafeArrayCalculateElementAddress(psa, Count);
  244. if LockIt then
  245. Result:=SafeArrayLock(psa);
  246. end;
  247. Function SafeArrayElementTotal(psa: PVarArray): Integer;
  248. var
  249. I: Integer;
  250. begin
  251. Result:=1;
  252. With psa^ do
  253. for I:=0 to DimCount - 1 do
  254. Result:=Result*Bounds[I].ElementCount;
  255. end;
  256. type
  257. TVariantArrayType = (vatNormal, vatInterface, vatWideString, vatVariant);
  258. Function VariantArrayType(psa: PVarArray): TVariantArrayType;
  259. begin
  260. if ((psa^.Flags and ARR_DISPATCH) <> 0) or
  261. ((psa^.Flags and ARR_UNKNOWN) <> 0) then
  262. Result:=vatInterface
  263. else if (psa^.Flags AND ARR_OLESTR) <> 0 then
  264. Result:=vatWideString
  265. else if (psa^.Flags and ARR_VARIANT) <> 0 then
  266. Result := vatVariant
  267. else
  268. Result:=vatNormal;
  269. end;
  270. Function SafeArrayClearDataSpace(psa: PVarArray; WipeBytes: Boolean {= True}): HRESULT;
  271. var
  272. vat: TVariantArrayType;
  273. P : Pointer;
  274. J,Count : Integer;
  275. begin
  276. try
  277. count:=SafeArrayElementTotal(psa);
  278. vat:=VariantArrayType(psa);
  279. case vat of
  280. vatNormal : FillChar(psa^.Data^,Count*psa^.ElementSize,0);
  281. vatInterface :
  282. for j := 0 to Count - 1 do
  283. begin
  284. P := SafeArrayCalculateElementAddress(psa,j);
  285. IUnknown(PUnknown(P)^):=Nil
  286. end;
  287. vatWideString :
  288. for j := 0 to Count - 1 do
  289. begin
  290. P := SafeArrayCalculateElementAddress(psa,j);
  291. WideString(PPointer(P)^):='';
  292. end;
  293. vatVariant :
  294. for j := 0 to Count - 1 do
  295. begin
  296. P := SafeArrayCalculateElementAddress(psa,j);
  297. VariantClear(PVarData(P)^);
  298. end;
  299. end;
  300. Result:=VAR_OK;
  301. except
  302. On E : Exception do
  303. Result:=ExceptionToVariantError (E);
  304. end;
  305. end;
  306. Function SafeArrayCopyDataSpace(psa, psaOut: PVarArray): HRESULT;
  307. var
  308. vat: TVariantArrayType;
  309. P1,P2 : Pointer;
  310. J,Count : Integer;
  311. begin
  312. try
  313. Count:=SafeArrayElementTotal(psa);
  314. vat:=VariantArrayType(psa);
  315. case vat of
  316. vatNormal: Move(psa^.Data^,psaOut^.Data^,Count*psa^.ElementSize);
  317. vatInterface :
  318. for j := 0 to Count - 1 do
  319. begin
  320. P1 := SafeArrayCalculateElementAddress(psa,j);
  321. P2 := SafeArrayCalculateElementAddress(psaout,j);
  322. IUnknown(PUnknown(P2)^):=IUnknown(PUnknown(P1)^);
  323. end;
  324. vatWideString :
  325. for j := 0 to Count - 1 do
  326. begin
  327. P1 := SafeArrayCalculateElementAddress(psa,j);
  328. P2 := SafeArrayCalculateElementAddress(psaOut,j);
  329. WideString(PPointer(P2)^):=WideString(PPointer(P1)^);
  330. end;
  331. vatVariant :
  332. for j := 0 to Count - 1 do
  333. begin
  334. P1 := SafeArrayCalculateElementAddress(psa,j);
  335. P2 := SafeArrayCalculateElementAddress(psaOut,j);
  336. VariantCopy(PVarData(P2)^,PVarData(P2)^);
  337. end;
  338. end;
  339. Result:=VAR_OK;
  340. except
  341. On E : Exception do
  342. Result:=ExceptionToVariantError(E);
  343. end;
  344. end;
  345. Const
  346. Supportedpsas = [varSmallint,varInteger,
  347. {$ifndef FPUNONE}
  348. varSingle,varDouble,varCurrency,varDate,
  349. {$endif}
  350. varOleStr,varDispatch,varError,varBoolean,varVariant,varUnknown,varShortInt,varByte,
  351. varWord,varLongWord,varInt64,varQWord];
  352. psaElementFlags : Array [varEmpty..varQWord] of Longint =
  353. (ARR_NONE,ARR_NONE,ARR_NONE,ARR_NONE,ARR_NONE,ARR_NONE,ARR_NONE,ARR_NONE,
  354. ARR_OLESTR,ARR_DISPATCH,ARR_NONE,ARR_NONE,ARR_VARIANT,ARR_UNKNOWN,
  355. ARR_NONE,ARR_NONE,ARR_NONE,ARR_NONE,ARR_NONE,ARR_NONE,ARR_NONE,ARR_NONE);
  356. psaElementSizes : Array [varEmpty..varQWord] of Byte =
  357. (0,0, // varempty, varnull
  358. SizeOf(SmallInt), // varsmallint
  359. SizeOf(Integer), // varinteger
  360. SizeOf(Single), // varsingle
  361. SizeOf(Double), // vardouble
  362. SizeOf(Currency), // varcurrency
  363. SizeOf(TDateTime), // vardate
  364. SizeOf(PWideString), // varolestr
  365. SizeOf(IInterface), // vardispatch
  366. SizeOf(TError), // varerror
  367. SizeOf(Boolean), // varboolean
  368. SizeOf(TVarData), // varvariant
  369. SizeOf(IUnknown), // varunknown
  370. 0, // Decimal // vardecimal
  371. 0, // Unused
  372. SizeOf(ShortInt), // varshortint
  373. SizeOf(Byte), // varbyte
  374. SizeOf(Word), // varword
  375. SizeOf(LongWord), // varlongword
  376. SizeOf(Int64), // varint64
  377. SizeOf(QWord)); // varqword
  378. Function SafeArrayCreate(VarType, Dim: DWord; const Bounds: TVarArrayBoundArray): PVarArray;stdcall;
  379. var
  380. res : HRESULT;
  381. I : DWord;
  382. begin
  383. Result:=nil;
  384. if Not (VarType in Supportedpsas) Then
  385. exit;
  386. Res:=SafeArrayAllocDescriptor(Dim, Result);
  387. if Res<>VAR_OK then
  388. exit;
  389. Result^.DimCount:=Dim;
  390. Result^.Flags:=psaElementFlags[VarType];
  391. Result^.ElementSize:=psaElementSizes[VarType];
  392. Result^.LockCount := 0;
  393. for i:=0 to Dim-1 do
  394. begin
  395. Result^.Bounds[i].LowBound:=Bounds[Dim-I-1].LowBound;
  396. Result^.Bounds[I].ElementCount:=Bounds[Dim-I-1].ElementCount;
  397. end;
  398. res:=SafeArrayAllocData(Result);
  399. if res<>VAR_OK then
  400. begin
  401. SafeArrayDestroyDescriptor(Result);
  402. Result:=nil;
  403. end;
  404. end;
  405. Function SafeArrayAllocDescriptor(DimCount: Dword; var psa: PVarArray): HRESULT;stdcall;
  406. begin
  407. try
  408. { one bound item is included in TVarArray }
  409. psa:=GetMem(SizeOf(TVarArray) + SizeOf(TVarArrayBound)*(DimCount-1));
  410. Result:=VAR_OK;
  411. except
  412. On E : Exception do
  413. Result:=ExceptionToVariantError(E);
  414. end;
  415. end;
  416. Function SafeArrayAllocData(psa: PVarArray): HRESULT;stdcall;
  417. begin
  418. try
  419. With psa^ do
  420. begin
  421. Data:=GetMem(SafeArrayElementTotal(psa)*ElementSize);
  422. fillchar(Data^,SafeArrayElementTotal(psa)*ElementSize,0);
  423. end;
  424. Result:=VAR_OK;
  425. except
  426. On E : Exception do
  427. Result:=ExceptionToVariantError(E);
  428. end;
  429. end;
  430. Function SafeArrayDestroy(psa: PVarArray): HRESULT;stdcall;
  431. begin
  432. Result:=CheckVarArray(psa);
  433. if Result<> VAR_OK then
  434. exit;
  435. Result:=CheckArrayUnlocked(psa);
  436. if Result<> VAR_OK then
  437. exit;
  438. Result:=SafeArrayDestroyData(psa);
  439. if Result<>VAR_OK then
  440. exit;
  441. Result:=SafeArrayDestroyDescriptor(psa);
  442. end;
  443. Function SafeArrayDestroyDescriptor(psa: PVarArray): HRESULT;stdcall;
  444. begin
  445. Result:=CheckVarArray(psa);
  446. if Result<>VAR_OK then
  447. exit;
  448. Result:=CheckArrayUnlocked(psa);
  449. if Result<> VAR_OK then
  450. exit;
  451. try
  452. FreeMem(psa);
  453. except
  454. On E : Exception do
  455. Result:=ExceptionToVariantError(E);
  456. end;
  457. end;
  458. Function SafeArrayDestroyData(psa: PVarArray): HRESULT;stdcall;
  459. begin
  460. Result:=CheckVarArray(psa);
  461. if Result<>VAR_OK then
  462. exit;
  463. Result:=CheckArrayUnlocked(psa);
  464. if Result<> VAR_OK then
  465. exit;
  466. try
  467. Result:=SafeArrayClearDataSpace(psa, False);
  468. if (Result=VAR_OK) and ((psa^.Flags and ARR_FIXEDSIZE)=0) then
  469. begin
  470. FreeMem(psa^.Data);
  471. psa^.Data:=nil;
  472. end;
  473. except
  474. On E : Exception do
  475. Result:=ExceptionToVariantError(E);
  476. end;
  477. end;
  478. Function SafeArrayRedim(psa: PVarArray; const NewBound: TVarArrayBound): HRESULT;stdcall;
  479. var
  480. vat: TVariantArrayType;
  481. i, D,j,count : Integer;
  482. P : Pointer;
  483. begin
  484. Result:=CheckVarArray(psa);
  485. if Result <> VAR_OK then
  486. exit;
  487. if (psa^.Flags and ARR_FIXEDSIZE) <> 0 then
  488. Exit(VAR_INVALIDARG);
  489. Result:=SafeArrayLock(psa);
  490. if Result<>VAR_OK then
  491. exit;
  492. try
  493. D:=NewBound.ElementCount - psa^.Bounds[0].ElementCount;
  494. for i:=1 to psa^.DimCount - 1 do
  495. D:=D*psa^.Bounds[i].ElementCount;
  496. if D<>0 then
  497. begin
  498. Count:=SafeArrayElementTotal(psa);
  499. if D<0 then
  500. begin
  501. vat:=VariantArrayType(psa);
  502. for j:=Count-1 downto Count+D do
  503. begin
  504. P:=SafeArrayCalculateElementAddress(psa,j);
  505. if vat = vatInterface then
  506. IUnknown(PPointer(P)^):=Nil
  507. else if vat=vatWideString then
  508. WideString(PPointer(P)^):=''
  509. else if vat=vatVariant then
  510. VariantClear(PVarData(P)^);
  511. end;
  512. end;
  513. ReAllocMem(psa^.Data,(Count+D)*psa^.ElementSize);
  514. if D>0 then
  515. fillchar((PChar(psa^.Data)+Count*psa^.ElementSize)^,D*psa^.ElementSize,0);
  516. end;
  517. psa^.Bounds[0].ElementCount:=NewBound.ElementCount;
  518. psa^.Bounds[0].LowBound:=NewBound.LowBound;
  519. except
  520. On E : Exception do
  521. Result:=ExceptionToVariantError(E);
  522. end;
  523. SetUnlockResult(psa,Result);
  524. end;
  525. Function SafeArrayCopy(psa: PVarArray; var psaOut: PVarArray): HRESULT;stdcall;
  526. var
  527. i : Integer;
  528. begin
  529. Result:=CheckVarArray(psa);
  530. if Result<>VAR_OK then
  531. exit;
  532. Result:=SafeArrayLock(psa);
  533. if Result<>VAR_OK then
  534. exit;
  535. try
  536. Result:=SafeArrayAllocDescriptor(psa^.DimCount,psaOut);
  537. if Result<>VAR_OK then
  538. Exit;
  539. try
  540. With psaOut^ do
  541. begin
  542. Flags:=psa^.Flags;
  543. ElementSize:=psa^.ElementSize;
  544. LockCount := 0;
  545. DimCount:=psa^.DimCount;
  546. for i:=0 to DimCount-1 do
  547. begin
  548. Bounds[i].ElementCount:=psa^.Bounds[i].ElementCount;
  549. Bounds[i].LowBound:=psa^.Bounds[i].LowBound;
  550. end;
  551. end;
  552. Result:=SafeArrayAllocData(psaOut);
  553. if Result<>VAR_OK then
  554. exit;
  555. Result:=SafeArrayCopyDataSpace(psa, psaOut);
  556. finally
  557. if Result<>VAR_OK then
  558. begin
  559. SafeArrayDestroyDescriptor(psaOut);
  560. psaOut:=nil;
  561. end;
  562. end;
  563. except
  564. On E : Exception do
  565. Result:=ExceptionToVariantError(E)
  566. end;
  567. SetUnlockResult(psa,Result);
  568. end;
  569. Function SafeArrayCopyData(psa, psaOut: PVarArray): HRESULT;stdcall;
  570. var
  571. i : Integer;
  572. begin
  573. Result:=CheckVarArray(psa);
  574. if Result<>VAR_OK then
  575. exit;
  576. Result:=CheckVarArray(psaOut);
  577. if Result<>VAR_OK then
  578. exit;
  579. Result:=SafeArrayLock(psaOut);
  580. if Result<>VAR_OK then
  581. exit;
  582. try
  583. Result:=SafeArrayLock(psa);
  584. if Result<>VAR_OK then
  585. exit;
  586. try
  587. With psaOut^ do
  588. begin
  589. if (psa^.Flags<>Flags) or
  590. (psa^.ElementSize<>ElementSize) or
  591. (psa^.DimCount<>DimCount) then
  592. Exit(VAR_INVALIDARG);
  593. for i:=0 to psa^.DimCount - 1 do
  594. if (psa^.Bounds[i].LowBound<>Bounds[i].LowBound) or
  595. (psa^.Bounds[i].ElementCount<>Bounds[i].ElementCount) then
  596. exit(VAR_INVALIDARG);
  597. end;
  598. Result:=SafeArrayClearDataSpace(psaOut,True);
  599. if Result<> VAR_OK then
  600. exit;
  601. Result:=SafeArrayCopyDataSpace(psa, psaOut);
  602. finally
  603. SetUnlockResult(psa,Result);
  604. end;
  605. finally
  606. SetUnlockResult(psaOut,Result);
  607. end;
  608. end;
  609. Function SafeArrayGetLBound(psa: PVarArray; Dim: DWord; var LBound: LongInt): HRESULT;stdcall;
  610. begin
  611. Result:=CheckVarArray(psa);
  612. if Result<>VAR_OK then
  613. exit;
  614. if (Dim>0) and (Dim<=psa^.DimCount) then
  615. LBound:=psa^.Bounds[psa^.dimcount-Dim].LowBound
  616. else
  617. Result:=VAR_BADINDEX;
  618. end;
  619. Function SafeArrayGetUBound(psa: PVarArray; Dim : DWord; var UBound: LongInt): HRESULT;stdcall;
  620. begin
  621. Result:=CheckVarArray(psa);
  622. if Result<>VAR_OK then
  623. exit;
  624. if (Dim>0) and (Dim<=psa^.DimCount) then
  625. UBound:=psa^.Bounds[psa^.dimcount-Dim].LowBound +
  626. psa^.Bounds[psa^.dimcount-Dim].ElementCount-1
  627. else
  628. Result:=VAR_BADINDEX
  629. end;
  630. Function SafeArrayGetDim(psa: PVarArray): HRESULT;stdcall;
  631. begin
  632. if CheckVarArray(psa)<>VAR_OK then
  633. Result:=0
  634. else
  635. Result:=psa^.DimCount;
  636. end;
  637. Function SafeArrayAccessData(psa: PVarArray; var ppvData: Pointer): HRESULT;stdcall;
  638. begin
  639. Result:=SafeArrayLock(psa);
  640. if Result<>VAR_OK then
  641. ppvData:=nil
  642. else
  643. ppvData:=psa^.Data;
  644. end;
  645. Function SafeArrayUnaccessData(psa: PVarArray): HRESULT;stdcall;
  646. begin
  647. Result:=SafeArrayUnlock(psa);
  648. end;
  649. Function SafeArrayLock(psa: PVarArray): HRESULT;stdcall;
  650. begin
  651. Result:=CheckVarArray(psa);
  652. if Result<>VAR_OK then
  653. exit;
  654. InterlockedIncrement(psa^.LockCount);
  655. end;
  656. Function SafeArrayUnlock(psa: PVarArray): HRESULT;stdcall;
  657. begin
  658. Result:=CheckVarArray(psa);
  659. if (Result<>VAR_OK) then
  660. exit;
  661. if InterlockedDecrement(psa^.LockCount)<0 then
  662. begin
  663. InterlockedIncrement(psa^.LockCount);
  664. result:=VAR_UNEXPECTED;
  665. end;
  666. end;
  667. Function SafeArrayGetElement(psa: PVarArray; Indices: PVarArrayCoorArray;
  668. Data: Pointer): HRESULT;stdcall;
  669. var
  670. P: Pointer;
  671. begin
  672. Result:=CheckVarArrayAndCalculateAddress(psa, Indices, P, True);
  673. if Result<>VAR_OK then
  674. exit;
  675. try
  676. case VariantArrayType(psa) of
  677. vatNormal:
  678. Move(P^, Data^, psa^.ElementSize);
  679. vatInterface:
  680. IInterface(PInterface(Data)^) := IInterface(PInterface(P)^);
  681. vatWideString:
  682. CopyAsWideString(PWideChar(Data^), PWideChar(P^));
  683. vatVariant:
  684. VariantCopy(PVarData(Data)^, PVarData(P)^);
  685. end;
  686. except
  687. On E : Exception do
  688. Result:=ExceptionToVariantError(E);
  689. end;
  690. SetUnlockResult(psa,Result);
  691. end;
  692. Function SafeArrayPutElement(psa: PVarArray; Indices: PVarArrayCoorArray;
  693. const Data: Pointer): HRESULT;stdcall;
  694. var
  695. P: Pointer;
  696. begin
  697. Result:=CheckVarArrayAndCalculateAddress(psa,Indices,P,True);
  698. if Result<>VAR_OK then
  699. exit;
  700. try
  701. case VariantArrayType(psa) of
  702. vatNormal:
  703. Move(Data^,P^,psa^.ElementSize);
  704. vatInterface:
  705. IInterface(PInterface(P)^):=IInterface(Data);
  706. vatWideString:
  707. CopyAsWideString(PWideChar(P^), PWideChar(Data));
  708. vatVariant:
  709. VariantCopy(PVarData(P)^, PVarData(Data)^); // !! Untested
  710. end;
  711. except
  712. On E : Exception do
  713. Result:=ExceptionToVariantError(E);
  714. end;
  715. SetUnlockResult(psa,Result);
  716. end;
  717. Function SafeArrayPtrOfIndex(psa: PVarArray; Indices: PVarArrayCoorArray;
  718. var Address: Pointer): HRESULT;stdcall;
  719. begin
  720. Result:=CheckVarArrayAndCalculateAddress(psa,Indices,Address,False);
  721. end;
  722. Function SafeArrayGetElemSize(psa: PVarArray): LongWord;stdcall;
  723. begin
  724. if CheckVarArray(psa)<>VAR_OK then
  725. Result:=0
  726. else
  727. Result:=psa^.ElementSize;
  728. end;
  729. {$POP}