varutils.inc 20 KB

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