varutils.inc 20 KB

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