varutils.inc 21 KB

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