varutils.inc 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776
  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. Type
  345. TVartypes = varEmpty..varByte;
  346. Const
  347. Supportedpsas : set of TVarTypes =
  348. [varSmallint,varInteger,
  349. {$ifndef FPUNONE}
  350. varSingle,varDouble,varCurrency,varDate,
  351. {$endif}
  352. varOleStr,varDispatch,varError,varBoolean,varVariant,varUnknown,varByte];
  353. psaElementSizes : Array [varEmpty..varByte] of Byte =
  354. (0,0,2,4,4,8,8,8,4,4,4,2,16,4,0,0,0,1);
  355. psaElementFlags : Array [varEmpty..varByte] of Longint =
  356. (ARR_NONE,ARR_NONE,ARR_NONE,ARR_NONE,ARR_NONE,ARR_NONE,ARR_NONE,ARR_NONE,
  357. ARR_OLESTR,ARR_DISPATCH,ARR_NONE,ARR_NONE,ARR_VARIANT,ARR_UNKNOWN,
  358. ARR_NONE,ARR_NONE,ARR_NONE,ARR_NONE);
  359. Function SafeArrayCreate(VarType, Dim: DWord; const Bounds: TVarArrayBoundArray): PVarArray;stdcall;
  360. var
  361. res : HRESULT;
  362. I : DWord;
  363. begin
  364. Result:=nil;
  365. if Not (VarType in Supportedpsas) Then
  366. exit;
  367. Res:=SafeArrayAllocDescriptor(Dim, Result);
  368. if Res<>VAR_OK then
  369. exit;
  370. Result^.DimCount:=Dim;
  371. Result^.Flags:=psaElementFlags[VarType];
  372. Result^.ElementSize:=psaElementSizes[VarType];
  373. Result^.LockCount := 0;
  374. for i:=0 to Dim-1 do
  375. begin
  376. Result^.Bounds[i].LowBound:=Bounds[Dim-I-1].LowBound;
  377. Result^.Bounds[I].ElementCount:=Bounds[Dim-I-1].ElementCount;
  378. end;
  379. res:=SafeArrayAllocData(Result);
  380. if res<>VAR_OK then
  381. begin
  382. SafeArrayDestroyDescriptor(Result);
  383. Result:=nil;
  384. end;
  385. end;
  386. Function SafeArrayAllocDescriptor(DimCount: Dword; var psa: PVarArray): HRESULT;stdcall;
  387. begin
  388. try
  389. { one bound item is included in TVarArray }
  390. psa:=GetMem(SizeOf(TVarArray) + SizeOf(TVarArrayBound)*(DimCount-1));
  391. Result:=VAR_OK;
  392. except
  393. On E : Exception do
  394. Result:=ExceptionToVariantError(E);
  395. end;
  396. end;
  397. Function SafeArrayAllocData(psa: PVarArray): HRESULT;stdcall;
  398. begin
  399. try
  400. With psa^ do
  401. begin
  402. Data:=GetMem(SafeArrayElementTotal(psa)*ElementSize);
  403. fillchar(Data^,SafeArrayElementTotal(psa)*ElementSize,0);
  404. end;
  405. Result:=VAR_OK;
  406. except
  407. On E : Exception do
  408. Result:=ExceptionToVariantError(E);
  409. end;
  410. end;
  411. Function SafeArrayDestroy(psa: PVarArray): HRESULT;stdcall;
  412. begin
  413. Result:=CheckVarArray(psa);
  414. if Result<> VAR_OK then
  415. exit;
  416. Result:=CheckArrayUnlocked(psa);
  417. if Result<> VAR_OK then
  418. exit;
  419. Result:=SafeArrayDestroyData(psa);
  420. if Result<>VAR_OK then
  421. exit;
  422. Result:=SafeArrayDestroyDescriptor(psa);
  423. end;
  424. Function SafeArrayDestroyDescriptor(psa: PVarArray): HRESULT;stdcall;
  425. begin
  426. Result:=CheckVarArray(psa);
  427. if Result<>VAR_OK then
  428. exit;
  429. Result:=CheckArrayUnlocked(psa);
  430. if Result<> VAR_OK then
  431. exit;
  432. try
  433. FreeMem(psa);
  434. except
  435. On E : Exception do
  436. Result:=ExceptionToVariantError(E);
  437. end;
  438. end;
  439. Function SafeArrayDestroyData(psa: PVarArray): HRESULT;stdcall;
  440. begin
  441. Result:=CheckVarArray(psa);
  442. if Result<>VAR_OK then
  443. exit;
  444. Result:=CheckArrayUnlocked(psa);
  445. if Result<> VAR_OK then
  446. exit;
  447. try
  448. Result:=SafeArrayClearDataSpace(psa, False);
  449. if (Result=VAR_OK) and ((psa^.Flags and ARR_FIXEDSIZE)=0) then
  450. begin
  451. FreeMem(psa^.Data);
  452. psa^.Data:=nil;
  453. end;
  454. except
  455. On E : Exception do
  456. Result:=ExceptionToVariantError(E);
  457. end;
  458. end;
  459. Function SafeArrayRedim(psa: PVarArray; const NewBound: TVarArrayBound): HRESULT;stdcall;
  460. var
  461. vat: TVariantArrayType;
  462. i, D,j,count : Integer;
  463. P : Pointer;
  464. begin
  465. Result:=CheckVarArray(psa);
  466. if Result <> VAR_OK then
  467. exit;
  468. if (psa^.Flags and ARR_FIXEDSIZE) <> 0 then
  469. Exit(VAR_INVALIDARG);
  470. Result:=SafeArrayLock(psa);
  471. if Result<>VAR_OK then
  472. exit;
  473. try
  474. D:=NewBound.ElementCount - psa^.Bounds[0].ElementCount;
  475. for i:=1 to psa^.DimCount - 1 do
  476. D:=D*psa^.Bounds[i].ElementCount;
  477. if D<>0 then
  478. begin
  479. Count:=SafeArrayElementTotal(psa);
  480. if D<0 then
  481. begin
  482. vat:=VariantArrayType(psa);
  483. for j:=Count-1 downto Count+D do
  484. begin
  485. P:=SafeArrayCalculateElementAddress(psa,j);
  486. if vat = vatInterface then
  487. IUnknown(PPointer(P)^):=Nil
  488. else if vat=vatWideString then
  489. WideString(PPointer(P)^):=''
  490. else if vat=vatVariant then
  491. VariantClear(PVarData(P)^);
  492. end;
  493. end;
  494. ReAllocMem(psa^.Data,(Count+D)*psa^.ElementSize);
  495. if D>0 then
  496. fillchar((PChar(psa^.Data)+Count*psa^.ElementSize)^,D*psa^.ElementSize,0);
  497. end;
  498. psa^.Bounds[0].ElementCount:=NewBound.ElementCount;
  499. psa^.Bounds[0].LowBound:=NewBound.LowBound;
  500. except
  501. On E : Exception do
  502. Result:=ExceptionToVariantError(E);
  503. end;
  504. SetUnlockResult(psa,Result);
  505. end;
  506. Function SafeArrayCopy(psa: PVarArray; var psaOut: PVarArray): HRESULT;stdcall;
  507. var
  508. i : Integer;
  509. begin
  510. Result:=CheckVarArray(psa);
  511. if Result<>VAR_OK then
  512. exit;
  513. Result:=SafeArrayLock(psa);
  514. if Result<>VAR_OK then
  515. exit;
  516. try
  517. Result:=SafeArrayAllocDescriptor(psa^.DimCount,psaOut);
  518. if Result<>VAR_OK then
  519. Exit;
  520. try
  521. With psaOut^ do
  522. begin
  523. Flags:=psa^.Flags;
  524. ElementSize:=psa^.ElementSize;
  525. LockCount := 0;
  526. DimCount:=psa^.DimCount;
  527. for i:=0 to DimCount-1 do
  528. begin
  529. Bounds[i].ElementCount:=psa^.Bounds[i].ElementCount;
  530. Bounds[i].LowBound:=psa^.Bounds[i].LowBound;
  531. end;
  532. end;
  533. Result:=SafeArrayAllocData(psaOut);
  534. if Result<>VAR_OK then
  535. exit;
  536. Result:=SafeArrayCopyDataSpace(psa, psaOut);
  537. finally
  538. if Result<>VAR_OK then
  539. begin
  540. SafeArrayDestroyDescriptor(psaOut);
  541. psaOut:=nil;
  542. end;
  543. end;
  544. except
  545. On E : Exception do
  546. Result:=ExceptionToVariantError(E)
  547. end;
  548. SetUnlockResult(psa,Result);
  549. end;
  550. Function SafeArrayCopyData(psa, psaOut: PVarArray): HRESULT;stdcall;
  551. var
  552. i : Integer;
  553. begin
  554. Result:=CheckVarArray(psa);
  555. if Result<>VAR_OK then
  556. exit;
  557. Result:=CheckVarArray(psaOut);
  558. if Result<>VAR_OK then
  559. exit;
  560. Result:=SafeArrayLock(psaOut);
  561. if Result<>VAR_OK then
  562. exit;
  563. try
  564. Result:=SafeArrayLock(psa);
  565. if Result<>VAR_OK then
  566. exit;
  567. try
  568. With psaOut^ do
  569. begin
  570. if (psa^.Flags<>Flags) or
  571. (psa^.ElementSize<>ElementSize) or
  572. (psa^.DimCount<>DimCount) then
  573. Exit(VAR_INVALIDARG);
  574. for i:=0 to psa^.DimCount - 1 do
  575. if (psa^.Bounds[i].LowBound<>Bounds[i].LowBound) or
  576. (psa^.Bounds[i].ElementCount<>Bounds[i].ElementCount) then
  577. exit(VAR_INVALIDARG);
  578. end;
  579. Result:=SafeArrayClearDataSpace(psaOut,True);
  580. if Result<> VAR_OK then
  581. exit;
  582. Result:=SafeArrayCopyDataSpace(psa, psaOut);
  583. finally
  584. SetUnlockResult(psa,Result);
  585. end;
  586. finally
  587. SetUnlockResult(psaOut,Result);
  588. end;
  589. end;
  590. Function SafeArrayGetLBound(psa: PVarArray; Dim: DWord; var LBound: 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. LBound:=psa^.Bounds[psa^.dimcount-Dim].LowBound
  597. else
  598. Result:=VAR_BADINDEX;
  599. end;
  600. Function SafeArrayGetUBound(psa: PVarArray; Dim : DWord; var UBound: LongInt): HRESULT;stdcall;
  601. begin
  602. Result:=CheckVarArray(psa);
  603. if Result<>VAR_OK then
  604. exit;
  605. if (Dim>0) and (Dim<=psa^.DimCount) then
  606. UBound:=psa^.Bounds[psa^.dimcount-Dim].LowBound +
  607. psa^.Bounds[psa^.dimcount-Dim].ElementCount-1
  608. else
  609. Result:=VAR_BADINDEX
  610. end;
  611. Function SafeArrayGetDim(psa: PVarArray): HRESULT;stdcall;
  612. begin
  613. if CheckVarArray(psa)<>VAR_OK then
  614. Result:=0
  615. else
  616. Result:=psa^.DimCount;
  617. end;
  618. Function SafeArrayAccessData(psa: PVarArray; var ppvData: Pointer): HRESULT;stdcall;
  619. begin
  620. Result:=SafeArrayLock(psa);
  621. if Result<>VAR_OK then
  622. ppvData:=nil
  623. else
  624. ppvData:=psa^.Data;
  625. end;
  626. Function SafeArrayUnaccessData(psa: PVarArray): HRESULT;stdcall;
  627. begin
  628. Result:=SafeArrayUnlock(psa);
  629. end;
  630. Function SafeArrayLock(psa: PVarArray): HRESULT;stdcall;
  631. begin
  632. Result:=CheckVarArray(psa);
  633. if Result<>VAR_OK then
  634. exit;
  635. InterlockedIncrement(psa^.LockCount);
  636. end;
  637. Function SafeArrayUnlock(psa: PVarArray): HRESULT;stdcall;
  638. begin
  639. Result:=CheckVarArray(psa);
  640. if (Result<>VAR_OK) then
  641. exit;
  642. if InterlockedDecrement(psa^.LockCount)<0 then
  643. begin
  644. InterlockedIncrement(psa^.LockCount);
  645. result:=VAR_UNEXPECTED;
  646. end;
  647. end;
  648. Function SafeArrayGetElement(psa: PVarArray; Indices: PVarArrayCoorArray;
  649. Data: Pointer): HRESULT;stdcall;
  650. var
  651. P: Pointer;
  652. begin
  653. Result:=CheckVarArrayAndCalculateAddress(psa, Indices, P, True);
  654. if Result<>VAR_OK then
  655. exit;
  656. try
  657. case VariantArrayType(psa) of
  658. vatNormal:
  659. Move(P^, Data^, psa^.ElementSize);
  660. vatInterface:
  661. NoInterfaces; // Just assign...
  662. vatWideString:
  663. NoWideStrings; // Just assign...
  664. end;
  665. except
  666. On E : Exception do
  667. Result:=ExceptionToVariantError(E);
  668. end;
  669. SetUnlockResult(psa,Result);
  670. end;
  671. Function SafeArrayPutElement(psa: PVarArray; Indices: PVarArrayCoorArray;
  672. const Data: Pointer): HRESULT;stdcall;
  673. var
  674. P: Pointer;
  675. begin
  676. Result:=CheckVarArrayAndCalculateAddress(psa,Indices,P,True);
  677. if Result<>VAR_OK then
  678. exit;
  679. try
  680. case VariantArrayType(psa) of
  681. vatNormal:
  682. Move(Data^,P^,psa^.ElementSize);
  683. vatInterface:
  684. NoInterfaces;
  685. vatWideString:
  686. NoWideStrings;
  687. end;
  688. except
  689. On E : Exception do
  690. Result:=ExceptionToVariantError(E);
  691. end;
  692. SetUnlockResult(psa,Result);
  693. end;
  694. Function SafeArrayPtrOfIndex(psa: PVarArray; Indices: PVarArrayCoorArray;
  695. var Address: Pointer): HRESULT;stdcall;
  696. begin
  697. Result:=CheckVarArrayAndCalculateAddress(psa,Indices,Address,False);
  698. end;
  699. Function SafeArrayGetElemSize(psa: PVarArray): LongWord;stdcall;
  700. begin
  701. if CheckVarArray(psa)<>VAR_OK then
  702. Result:=0
  703. else
  704. Result:=psa^.ElementSize;
  705. end;