extres.inc 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660
  1. {
  2. This file is part of the Free Pascal run time library.
  3. Copyright (c) 2008 by Giulio Bernardi
  4. Resource support as external files
  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. This file implements two kinds of external resource support:
  13. - one for systems that support the mmap call (usually unix-like oses)
  14. - one fallback implementation based on pascal files and GetMem/FreeMem
  15. Be sure to define EXTRES_MMAP or EXTRES_GENERIC before including this file!
  16. }
  17. {$IF defined(EXTRES_MMAP) and defined(EXTRES_GENERIC)}
  18. {$FATAL EXTRES_MMAP and EXTRES_GENERIC can't be defined together}
  19. {$ENDIF}
  20. {$IF (not defined(EXTRES_MMAP)) and (not defined(EXTRES_GENERIC))}
  21. {$FATAL EXTRES_MMAP or EXTRES_GENERIC must be defined}
  22. {$ENDIF}
  23. const
  24. FPCRES_MAGIC = 'FPCRES';
  25. FPCRES_VERSION = 1;
  26. {$IFDEF ENDIAN_BIG}
  27. FPCRES_ENDIAN = 1;
  28. {$ENDIF}
  29. {$IFDEF ENDIAN_LITTLE}
  30. FPCRES_ENDIAN = 2;
  31. {$ENDIF}
  32. FPCRES_EXT = '.fpcres';
  33. type
  34. TExtHeader = packed record
  35. magic : array[0..5] of char;//'FPCRES'
  36. version : byte; //EXT_CURRENT_VERSION
  37. endianess : byte; //EXT_ENDIAN_BIG or EXT_ENDIAN_LITTLE
  38. count : longword; //resource count
  39. nodesize : longword; //size of header (up to string table, excluded)
  40. hdrsize : longword; //size of header (up to string table, included)
  41. reserved1 : longword;
  42. reserved2 : longword;
  43. reserved3 : longword;
  44. end;
  45. PExtHeader = ^TExtHeader;
  46. TResInfoNode = packed record
  47. nameid : longword; //name offset / integer ID / languageID
  48. ncounthandle : longword; //named sub-entries count/resource handle
  49. idcountsize : longword; //id sub-entries count / resource size
  50. subptr : longword; //first sub-entry offset
  51. end;
  52. PResInfoNode = ^TResInfoNode;
  53. {$IFDEF EXTRES_GENERIC}
  54. TResHandle = record
  55. info : PResInfoNode;
  56. ptr : Pointer;
  57. end;
  58. PResHandle = ^TResHandle;
  59. {$ENDIF}
  60. var ResHeader : PExtHeader = nil;
  61. usedhandles : longword = 0;
  62. {$IFDEF EXTRES_MMAP}
  63. fd : integer;
  64. fd_size : longword;
  65. reshandles : PPointer = nil;
  66. {$ENDIF}
  67. {$IFDEF EXTRES_GENERIC}
  68. fd : file;
  69. reshandles : PResHandle = nil;
  70. {$ENDIF}
  71. (*****************************************************************************
  72. Private Helper Functions
  73. *****************************************************************************)
  74. //resource functions are case insensitive... copied from genstr.inc
  75. function ResStrIComp(Str1, Str2 : PChar): SizeInt;
  76. var
  77. counter: SizeInt;
  78. c1, c2: char;
  79. begin
  80. counter := 0;
  81. c1 := upcase(str1[counter]);
  82. c2 := upcase(str2[counter]);
  83. while c1 = c2 do
  84. begin
  85. if (c1 = #0) or (c2 = #0) then break;
  86. inc(counter);
  87. c1 := upcase(str1[counter]);
  88. c2 := upcase(str2[counter]);
  89. end;
  90. ResStrIComp := ord(c1) - ord(c2);
  91. end;
  92. {!fixme!}
  93. //function InternalIsIntResource(aStr : pchar; out aInt : PtrUint) : boolean;
  94. function InternalIsIntResource(aStr : pchar; var aInt : PtrUint) : boolean;
  95. var i : integer;
  96. s : shortstring;
  97. code : word;
  98. begin
  99. InternalIsIntResource:=((PtrUInt(aStr) shr 16)=0);
  100. if InternalIsIntResource then aInt:=PtrUInt(aStr)
  101. else
  102. begin
  103. //a string like #number specifies an integer id
  104. if aStr[0]='#' then
  105. begin
  106. i:=1;
  107. while aStr[i]<>#0 do
  108. inc(i);
  109. if i>256 then i:=256;
  110. s[0]:=chr(i-1);
  111. Move(aStr[1],s[1],i-1);
  112. Val(s,aInt,code);
  113. InternalIsIntResource:=code=0;
  114. end;
  115. end;
  116. end;
  117. function GetResInfoPtr(const offset : longword) : PResInfoNode; inline;
  118. begin
  119. GetResInfoPtr:=PResInfoNode(PtrUInt(ResHeader)+offset);
  120. end;
  121. function GetPchar(const offset : longword) : Pchar; inline;
  122. begin
  123. GetPchar:=Pchar(PtrUInt(ResHeader)+offset);
  124. end;
  125. function GetPtr(const offset : longword) : Pointer; inline;
  126. begin
  127. GetPtr:=Pointer(PtrUInt(ResHeader)+offset);
  128. end;
  129. procedure FixResEndian;
  130. var ptr : plongword;
  131. blockend : plongword;
  132. begin
  133. //all info nodes reside in a contiguos block of memory.
  134. //they are all 16 bytes long and made by longwords
  135. //so, simply swap each longword in the block
  136. ptr:=GetPtr(sizeof(TExtHeader));
  137. blockend:=GetPtr(ResHeader^.nodesize);
  138. while ptr<blockend do
  139. begin
  140. ptr^:=SwapEndian(ptr^);
  141. inc(ptr);
  142. end;
  143. end;
  144. function GetExtResPath : pchar;
  145. var len, i : integer;
  146. pathstr : shortstring;
  147. begin
  148. pathstr:=paramstr(0);
  149. len:=byte(pathstr[0]);
  150. i:=len;
  151. //writeln('exe name is ',pathstr);
  152. //find position of extension
  153. while (i>0) and (not (pathstr[i] in ['.',DirectorySeparator])) do
  154. dec(i);
  155. if (i>0) and (pathstr[i]='.') then dec(i)
  156. else i:=len;
  157. pathstr[0]:=Chr(i);
  158. pathstr:=pathstr+FPCRES_EXT;
  159. len:=byte(pathstr[0]);
  160. GetExtResPath:=GetMem(len+1);
  161. Move(pathstr[1],GetExtResPath[0],len);
  162. GetExtResPath[len]:=#0;
  163. //writeln('Resource file is ',GetExtResPath);
  164. end;
  165. function BinSearchStr(arr : PResInfoNode; query : pchar; left, right : integer)
  166. : PResInfoNode;
  167. var pivot, res : integer;
  168. resstr : pchar;
  169. begin
  170. BinSearchStr:=nil;
  171. while left<=right do
  172. begin
  173. pivot:=(left+right) div 2;
  174. resstr:=GetPchar(arr[pivot].nameid);
  175. res:=ResStrIComp(resstr,query);
  176. if res<0 then left:=pivot+1
  177. else if res>0 then right:=pivot-1
  178. else
  179. begin
  180. BinSearchStr:=@arr[pivot];
  181. exit;
  182. end;
  183. end;
  184. end;
  185. function BinSearchInt(arr : PResInfoNode; query : pchar; left, right : integer)
  186. : PResInfoNode;
  187. var pivot : integer;
  188. begin
  189. BinSearchInt:=nil;
  190. while left<=right do
  191. begin
  192. pivot:=(left+right) div 2;
  193. if arr[pivot].nameid<PtrUInt(query) then left:=pivot+1
  194. else if arr[pivot].nameid>PtrUInt(query) then right:=pivot-1
  195. else
  196. begin
  197. BinSearchInt:=@arr[pivot];
  198. exit;
  199. end;
  200. end;
  201. end;
  202. function BinSearchRes(root : PResInfoNode; aDesc : PChar) : PResInfoNode;
  203. var aID : PtrUint;
  204. begin
  205. if InternalIsIntResource(aDesc,aID) then
  206. BinSearchRes:=BinSearchInt(GetResInfoPtr(root^.subptr),PChar(aID),
  207. root^.ncounthandle,root^.ncounthandle+root^.idcountsize-1)
  208. else
  209. BinSearchRes:=BinSearchStr(GetResInfoPtr(root^.subptr),aDesc,0,
  210. root^.ncounthandle-1);
  211. end;
  212. //Returns a pointer to a name node.
  213. function InternalFindResource(ResourceName, ResourceType: PChar):
  214. PResInfoNode;
  215. begin
  216. InternalFindResource:=nil;
  217. if ResHeader=nil then exit;
  218. InternalFindResource:=GetResInfoPtr(sizeof(TExtHeader));
  219. InternalFindResource:=BinSearchRes(InternalFindResource,ResourceType);
  220. if InternalFindResource<>nil then
  221. InternalFindResource:=BinSearchRes(InternalFindResource,ResourceName);
  222. end;
  223. function FindSubLanguage(aPtr : PResInfoNode; aLangID : word; aMask: word) : PResInfoNode;
  224. var arr : PResInfoNode;
  225. i : longword;
  226. begin
  227. FindSubLanguage:=nil;
  228. arr:=GetResInfoPtr(aPtr^.subptr);
  229. i:=0;
  230. while i<aPtr^.idcountsize do
  231. begin
  232. if (PtrUInt(arr[i].nameid) and aMask)=(aLangID and aMask) then
  233. begin
  234. FindSubLanguage:=@arr[i];
  235. exit;
  236. end;
  237. inc(i);
  238. end;
  239. end;
  240. {$IFDEF EXTRES_MMAP}
  241. procedure InitResources;
  242. const
  243. PROT_READ = 1;
  244. PROT_WRITE = 2;
  245. var respath : pchar;
  246. fdstat : stat;
  247. begin
  248. respath:=GetExtResPath;
  249. // writeln('respath ',respath);
  250. fd:=FpOpen(respath,O_RDONLY,0);
  251. // writeln('fpopen returned ',fd);
  252. FreeMem(respath);
  253. if fd=-1 then exit;
  254. if FpFStat(fd,fdstat)<>0 then
  255. begin
  256. // writeln('fpfstat failed');
  257. FpClose(fd);
  258. exit;
  259. end;
  260. // writeln('fpfstat suceeded');
  261. fd_size:=fdstat.st_size;
  262. ResHeader:=PExtHeader(Fpmmap(nil,fd_size,PROT_READ or PROT_WRITE,
  263. MAP_PRIVATE,fd,0));
  264. // writeln('fpmmap returned ',PtrInt(ResHeader));
  265. if PtrInt(ResHeader)=-1 then
  266. begin
  267. FpClose(fd);
  268. exit;
  269. end;
  270. if (ResHeader^.magic<>FPCRES_MAGIC) or
  271. (ResHeader^.version<>fpcres_version) then
  272. begin
  273. FpClose(fd);
  274. exit;
  275. end;
  276. // writeln('magic ok');
  277. if ResHeader^.endianess<>FPCRES_ENDIAN then
  278. begin
  279. ResHeader^.count:=SwapEndian(ResHeader^.count);
  280. ResHeader^.nodesize:=SwapEndian(ResHeader^.nodesize);
  281. ResHeader^.hdrsize:=SwapEndian(ResHeader^.hdrsize);
  282. FixResEndian;
  283. end;
  284. reshandles:=GetMem(sizeof(Pointer)*ResHeader^.count);
  285. FillByte(reshandles^,sizeof(Pointer)*ResHeader^.count,0);
  286. end;
  287. procedure FinalizeResources;
  288. begin
  289. if ResHeader=nil then exit;
  290. FreeMem(reshandles);
  291. Fpmunmap(ResHeader,fd_size);
  292. FpClose(fd);
  293. end;
  294. {$ENDIF}
  295. {$IFDEF EXTRES_GENERIC}
  296. procedure InitResources;
  297. var respath : pchar;
  298. tmp : longword;
  299. tmpptr : pbyte;
  300. label ExitErrMem, ExitErrFile, ExitNoErr;
  301. begin
  302. respath:=GetExtResPath;
  303. // writeln('respath ',respath);
  304. Assign(fd,respath);
  305. FreeMem(respath);
  306. {$I-}
  307. Reset(fd,1);
  308. {$I+}
  309. if IOResult<>0 then exit;
  310. // writeln('file opened');
  311. ResHeader:=GetMem(sizeof(TExtHeader));
  312. if ResHeader=nil then goto ExitErrFile;
  313. {$I-}
  314. BlockRead(fd,ResHeader^,sizeof(TExtHeader),tmp);
  315. {$I+}
  316. if (IOResult<>0) or (tmp<>sizeof(TExtHeader)) then goto ExitErrMem;
  317. if (ResHeader^.magic<>FPCRES_MAGIC) or (ResHeader^.version<>fpcres_version)
  318. then goto ExitErrMem;
  319. // writeln('magic ok');
  320. if ResHeader^.endianess<>FPCRES_ENDIAN then
  321. begin
  322. ResHeader^.count:=SwapEndian(ResHeader^.count);
  323. ResHeader^.nodesize:=SwapEndian(ResHeader^.nodesize);
  324. ResHeader^.hdrsize:=SwapEndian(ResHeader^.hdrsize);
  325. end;
  326. SysReallocMem(ResHeader,ResHeader^.hdrsize);
  327. if ResHeader=nil then goto ExitErrFile;
  328. tmpptr:=pbyte(ResHeader);
  329. inc(tmpptr,sizeof(TExtHeader));
  330. {$I-}
  331. BlockRead(fd,tmpptr^,ResHeader^.hdrsize-sizeof(TExtHeader),tmp);
  332. {$I+}
  333. if (IOResult<>0) or (tmp<>ResHeader^.hdrsize-sizeof(TExtHeader)) then goto ExitErrMem;
  334. if ResHeader^.endianess<>FPCRES_ENDIAN then
  335. FixResEndian;
  336. reshandles:=GetMem(sizeof(TResHandle)*ResHeader^.count);
  337. FillByte(reshandles^,sizeof(TResHandle)*ResHeader^.count,0);
  338. goto ExitNoErr;
  339. ExitErrMem:
  340. FreeMem(ResHeader);
  341. ResHeader:=nil;
  342. ExitErrFile:
  343. {$I-}
  344. Close(fd);
  345. {$I+}
  346. ExitNoErr:
  347. end;
  348. procedure FinalizeResources;
  349. begin
  350. if ResHeader=nil then exit;
  351. FreeMem(reshandles);
  352. FreeMem(ResHeader);
  353. Close(fd);
  354. end;
  355. {$ENDIF}
  356. (*****************************************************************************
  357. Public Resource Functions
  358. *****************************************************************************)
  359. Function ExtHINSTANCE : TFPResourceHMODULE;
  360. begin
  361. ExtHINSTANCE:=0;
  362. end;
  363. function ExtEnumResourceTypes(ModuleHandle : TFPResourceHMODULE; EnumFunc : EnumResTypeProc; lParam : PtrInt) : LongBool;
  364. var ptr : PResInfoNode;
  365. totn, totid, i : longword;
  366. pc : pchar;
  367. begin
  368. ExtEnumResourceTypes:=False;
  369. if ResHeader=nil then exit;
  370. ptr:=GetResInfoPtr(sizeof(TExtHeader));
  371. totn:=ptr^.ncounthandle;
  372. totid:=totn+ptr^.idcountsize;
  373. ptr:=GetResInfoPtr(ptr^.subptr);
  374. ExtEnumResourceTypes:=true;
  375. i:=0;
  376. while i<totn do //named entries
  377. begin
  378. pc:=GetPChar(ptr[i].nameid);
  379. if not EnumFunc(ModuleHandle,pc,lParam) then exit;
  380. inc(i);
  381. end;
  382. while i<totid do
  383. begin
  384. if not EnumFunc(ModuleHandle,PChar(ptr[i].nameid),lParam) then exit;
  385. inc(i);
  386. end;
  387. end;
  388. function ExtEnumResourceNames(ModuleHandle : TFPResourceHMODULE; ResourceType : PChar; EnumFunc : EnumResNameProc; lParam : PtrInt) : LongBool;
  389. var ptr : PResInfoNode;
  390. totn, totid, i : longword;
  391. pc : pchar;
  392. begin
  393. ExtEnumResourceNames:=False;
  394. if ResHeader=nil then exit;
  395. ptr:=GetResInfoPtr(sizeof(TExtHeader));
  396. ptr:=BinSearchRes(ptr,ResourceType);
  397. if ptr=nil then exit;
  398. totn:=ptr^.ncounthandle;
  399. totid:=totn+ptr^.idcountsize;
  400. ptr:=GetResInfoPtr(ptr^.subptr);
  401. ExtEnumResourceNames:=true;
  402. i:=0;
  403. while i<totn do //named entries
  404. begin
  405. pc:=GetPChar(ptr[i].nameid);
  406. if not EnumFunc(ModuleHandle,ResourceType,pc,lParam) then exit;
  407. inc(i);
  408. end;
  409. while i<totid do
  410. begin
  411. if not EnumFunc(ModuleHandle,ResourceType,PChar(ptr[i].nameid),lParam) then exit;
  412. inc(i);
  413. end;
  414. end;
  415. function ExtEnumResourceLanguages(ModuleHandle : TFPResourceHMODULE; ResourceType, ResourceName : PChar; EnumFunc : EnumResLangProc; lParam : PtrInt) : LongBool;
  416. var ptr : PResInfoNode;
  417. tot, i : integer;
  418. begin
  419. ExtEnumResourceLanguages:=False;
  420. ptr:=InternalFindResource(ResourceName,ResourceType);
  421. if ptr=nil then exit;
  422. tot:=ptr^.idcountsize;
  423. ptr:=GetResInfoPtr(ptr^.subptr);
  424. ExtEnumResourceLanguages:=true;
  425. i:=0;
  426. while i<tot do
  427. begin
  428. if not EnumFunc(ModuleHandle,ResourceType,ResourceName,PtrUInt(ptr[i].nameid),lParam) then exit;
  429. inc(i);
  430. end;
  431. end;
  432. Function ExtFindResource(ModuleHandle: TFPResourceHMODULE; ResourceName, ResourceType: PChar)
  433. : TFPResourceHandle;
  434. var ptr : PResInfoNode;
  435. begin
  436. ExtFindResource:=0;
  437. ptr:=InternalFindResource(ResourceName,ResourceType);
  438. if ptr=nil then exit;
  439. //first language id
  440. ptr:=GetResInfoPtr(ptr^.subptr);
  441. if ptr^.ncounthandle=0 then
  442. begin
  443. {$IFDEF EXTRES_MMAP}
  444. reshandles[usedhandles]:=ptr;
  445. {$ENDIF}
  446. {$IFDEF EXTRES_GENERIC}
  447. reshandles[usedhandles].info:=ptr;
  448. {$ENDIF}
  449. inc(usedhandles);
  450. ptr^.ncounthandle:=usedhandles;
  451. end;
  452. ExtFindResource:=ptr^.ncounthandle;
  453. end;
  454. Function ExtFindResourceEx(ModuleHandle: TFPResourceHMODULE; ResourceType,
  455. ResourceName: PChar; Language : word): TFPResourceHandle;
  456. const LANG_NEUTRAL = 0;
  457. LANG_ENGLISH = 9;
  458. var nameptr,ptr : PResInfoNode;
  459. begin
  460. ExtFindResourceEx:=0;
  461. nameptr:=InternalFindResource(ResourceName,ResourceType);
  462. if nameptr=nil then exit;
  463. //try exact match
  464. ptr:=FindSubLanguage(nameptr,Language,$FFFF);
  465. //try primary language
  466. if ptr=nil then
  467. ptr:=FindSubLanguage(nameptr,Language,$3FF);
  468. //try language neutral
  469. if ptr=nil then
  470. ptr:=FindSubLanguage(nameptr,LANG_NEUTRAL,$3FF);
  471. //try english
  472. if ptr=nil then
  473. ptr:=FindSubLanguage(nameptr,LANG_ENGLISH,$3FF);
  474. //nothing found, return the first one
  475. if ptr=nil then
  476. ptr:=GetResInfoPtr(nameptr^.subptr);
  477. if ptr^.ncounthandle=0 then
  478. begin
  479. {$IFDEF EXTRES_MMAP}
  480. reshandles[usedhandles]:=ptr;
  481. {$ENDIF}
  482. {$IFDEF EXTRES_GENERIC}
  483. reshandles[usedhandles].info:=ptr;
  484. {$ENDIF}
  485. inc(usedhandles);
  486. ptr^.ncounthandle:=usedhandles;
  487. end;
  488. ExtFindResourceEx:=ptr^.ncounthandle;
  489. end;
  490. {$IFDEF EXTRES_MMAP}
  491. Function ExtLoadResource(ModuleHandle: TFPResourceHMODULE; ResHandle: TFPResourceHandle): TFPResourceHGLOBAL;
  492. begin
  493. ExtLoadResource:=0;
  494. if ResHeader=nil then exit;
  495. if (ResHandle<=0) or (ResHandle>usedhandles) then exit;
  496. ExtLoadResource:=TFPResourceHGLOBAL(GetPtr(PResInfoNode(reshandles[ResHandle-1])^.subptr));
  497. end;
  498. Function ExtFreeResource(ResData: TFPResourceHGLOBAL): LongBool;
  499. begin
  500. ExtFreeResource:=(ResHeader<>nil);
  501. end;
  502. Function ExtSizeofResource(ModuleHandle: TFPResourceHMODULE; ResHandle: TFPResourceHandle): LongWord;
  503. begin
  504. ExtSizeofResource:=0;
  505. if ResHeader=nil then exit;
  506. if (ResHandle<=0) or (ResHandle>usedhandles) then exit;
  507. ExtSizeofResource:=PResInfoNode(reshandles[ResHandle-1])^.idcountsize;
  508. end;
  509. {$ENDIF}
  510. {$IFDEF EXTRES_GENERIC}
  511. (*
  512. Resource data memory layout:
  513. -2*sizeof(pointer) Reference count
  514. -sizeof(pointer) Pointer to resource info
  515. 0 Resource data
  516. *)
  517. Function ExtLoadResource(ModuleHandle: TFPResourceHMODULE; ResHandle: TFPResourceHandle): TFPResourceHGLOBAL;
  518. var ptr : PPtrUInt;
  519. tmp : longword;
  520. begin
  521. ExtLoadResource:=0;
  522. if ResHeader=nil then exit;
  523. if (ResHandle<=0) or (ResHandle>usedhandles) then exit;
  524. if reshandles[ResHandle-1].ptr=nil then
  525. begin
  526. {$I-}
  527. Seek(fd,reshandles[ResHandle-1].info^.subptr);
  528. {$I+}
  529. if IOResult<>0 then exit;
  530. ptr:=GetMem(reshandles[ResHandle-1].info^.idcountsize+2*sizeof(PtrUint));
  531. if ptr=nil then exit;
  532. ptr^:=1; //refcount
  533. inc(ptr);
  534. ptr^:=PtrUInt(reshandles[ResHandle-1].info); //ptr to resource info
  535. inc(ptr);
  536. {$I-}
  537. BlockRead(fd,ptr^,reshandles[ResHandle-1].info^.idcountsize,tmp);
  538. {$I+}
  539. if (IOResult<>0) or (tmp<>reshandles[ResHandle-1].info^.idcountsize) then
  540. begin
  541. FreeMem(ptr);
  542. exit;
  543. end;
  544. reshandles[ResHandle-1].ptr:=ptr;
  545. end
  546. else
  547. begin
  548. ptr:=reshandles[ResHandle-1].ptr;
  549. dec(ptr,2);
  550. inc(ptr^,1); //increase reference count
  551. end;
  552. ExtLoadResource:=TFPResourceHGLOBAL(reshandles[ResHandle-1].ptr);
  553. end;
  554. Function ExtFreeResource(ResData: TFPResourceHGLOBAL): LongBool;
  555. var ptrinfo : PResInfoNode;
  556. ptr : PPtrUInt;
  557. begin
  558. ExtFreeResource:=(ResHeader<>nil);
  559. if not ExtFreeResource then exit;
  560. ptr:=PPtrUInt(ResData);
  561. dec(ptr,2);
  562. dec(ptr^); //decrease reference count
  563. if ptr^=0 then
  564. begin
  565. inc(ptr);
  566. ptrinfo:=PResInfoNode(ptr^);
  567. dec(ptr);
  568. FreeMem(ptr);
  569. reshandles[ptrinfo^.ncounthandle-1].ptr:=nil;
  570. end;
  571. ExtFreeResource:=true;
  572. end;
  573. Function ExtSizeofResource(ModuleHandle: TFPResourceHMODULE; ResHandle: TFPResourceHandle): LongWord;
  574. var ptrinfo : PResInfoNode;
  575. begin
  576. ExtSizeofResource:=0;
  577. if ResHeader=nil then exit;
  578. if (ResHandle<=0) or (ResHandle>usedhandles) then exit;
  579. ptrinfo:=PResInfoNode(reshandles[ResHandle-1].info);
  580. ExtSizeofResource:=ptrinfo^.idcountsize;
  581. end;
  582. {$ENDIF}
  583. Function ExtLockResource(ResData: TFPResourceHGLOBAL): Pointer;
  584. begin
  585. ExtLockResource:=Nil;
  586. if ResHeader=nil then exit;
  587. ExtLockResource:=Pointer(ResData);
  588. end;
  589. Function ExtUnlockResource(ResData: TFPResourceHGLOBAL): LongBool;
  590. begin
  591. ExtUnlockResource:=(ResHeader<>nil);
  592. end;
  593. const
  594. ExternalResourceManager : TResourceManager =
  595. (
  596. HINSTANCEFunc : @ExtHINSTANCE;
  597. EnumResourceTypesFunc : @ExtEnumResourceTypes;
  598. EnumResourceNamesFunc : @ExtEnumResourceNames;
  599. EnumResourceLanguagesFunc : @ExtEnumResourceLanguages;
  600. FindResourceFunc : @ExtFindResource;
  601. FindResourceExFunc : @ExtFindResourceEx;
  602. LoadResourceFunc : @ExtLoadResource;
  603. SizeofResourceFunc : @ExtSizeofResource;
  604. LockResourceFunc : @ExtLockResource;
  605. UnlockResourceFunc : @ExtUnlockResource;
  606. FreeResourceFunc : @ExtFreeResource;
  607. );