Details | Last modification | View Log | RSS feed
Rev | Author | Line No. | Line |
---|---|---|---|
616 | bw | 1 | {$mode delphi} |
2 | |||
3 | unit ExeImage; |
||
4 | |||
5 | interface |
||
6 | |||
7 | uses |
||
8 | TypInfo, Classes, SysUtils, Windows, RXTypes; |
||
9 | |||
10 | const |
||
11 | MF_END = $80; |
||
12 | |||
13 | type |
||
14 | |||
15 | { Exceptions } |
||
16 | |||
17 | EExeError = class(Exception); |
||
18 | ENotImplemented = class(Exception) |
||
19 | public |
||
20 | constructor Create(); |
||
21 | end; |
||
22 | |||
23 | { Forward Declarations } |
||
24 | |||
25 | TResourceItem = class; |
||
26 | TResourceClass = class of TResourceItem; |
||
27 | TResourceList = class; |
||
28 | |||
29 | { TExeImage } |
||
30 | |||
31 | TExeImage = class(TComponent) |
||
32 | private |
||
33 | FFileName: string; |
||
34 | FFileHandle: THandle; |
||
35 | FFileMapping: THandle; |
||
36 | FFileBase: Pointer; |
||
37 | FDosHeader: PIMAGE_DOS_HEADER; |
||
38 | FNTHeader: PIMAGE_NT_HEADERS; |
||
39 | FResourceList: TResourceList; |
||
40 | FIconResources: TResourceItem; |
||
41 | FCursorResources: TResourceItem; |
||
42 | FResourceBase: Longint; |
||
43 | FResourceRVA: Longint; |
||
44 | function GetResourceList: TResourceList; |
||
45 | function GetSectionHdr(const SectionName: string; |
||
46 | var Header: PIMAGE_SECTION_HEADER): Boolean; |
||
47 | public |
||
48 | constructor CreateImage(AOwner: TComponent; const AFileName: string); |
||
49 | destructor Destroy; override; |
||
50 | property FileName: string read FFileName; |
||
51 | property Resources: TResourceList read GetResourceList; |
||
52 | end; |
||
53 | |||
54 | { TResourceItem } |
||
55 | |||
56 | TResourceItem = class(TComponent) |
||
57 | private |
||
58 | FList: TResourceList; |
||
59 | FDirEntry: PIMAGE_RESOURCE_DIRECTORY_ENTRY; |
||
60 | function DataEntry: PIMAGE_RESOURCE_DATA_ENTRY; |
||
61 | function FExeImage: TExeImage; |
||
62 | function FirstChildDirEntry: PIMAGE_RESOURCE_DIRECTORY_ENTRY; |
||
63 | function GetResourceItem(Index: Integer): TResourceItem; |
||
64 | function GetResourceType: TResourceType; |
||
65 | protected |
||
66 | function GetName: string; virtual; |
||
67 | function GetResourceList: TResourceList; virtual; |
||
68 | public |
||
69 | constructor CreateItem(AOwner: TComponent; ADirEntry: Pointer); |
||
70 | function IsList: Boolean; virtual; |
||
71 | function Offset: Integer; |
||
72 | function Size: Integer; |
||
73 | function RawData: Pointer; |
||
74 | function ResTypeStr: string; |
||
75 | procedure SaveToFile(const FileName: string); |
||
76 | procedure SaveToStream(Stream: TStream); virtual; |
||
77 | property Items[Index: Integer]: TResourceItem read GetResourceItem; default; |
||
78 | property List: TResourceList read GetResourceList; |
||
79 | property Name: string read GetName; |
||
80 | property ResType: TResourceType read GetResourceType; |
||
81 | end; |
||
82 | |||
83 | { TIconResource } |
||
84 | |||
85 | TIconResource = class(TResourceItem) |
||
86 | protected |
||
87 | function GetResourceList: TResourceList; override; |
||
88 | public |
||
89 | function IsList: Boolean; override; |
||
90 | end; |
||
91 | |||
92 | { TIconResEntry } |
||
93 | |||
94 | TIconResEntry = class(TResourceItem) |
||
95 | protected |
||
96 | FResInfo: PIconResInfo; |
||
97 | function GetName: string; override; |
||
98 | procedure AssignTo(Dest: TPersistent); override; |
||
99 | public |
||
100 | procedure SaveToStream(Stream: TStream); override; |
||
101 | end; |
||
102 | |||
103 | { TCursorResource } |
||
104 | |||
105 | TCursorResource = class(TIconResource) |
||
106 | protected |
||
107 | function GetResourceList: TResourceList; override; |
||
108 | end; |
||
109 | |||
110 | { TCursorResEntry } |
||
111 | |||
112 | TCursorResEntry = class(TIconResEntry) |
||
113 | protected |
||
114 | FResInfo: PCursorResInfo; |
||
115 | function GetName: string; override; |
||
116 | end; |
||
117 | |||
118 | { TBitmapResource } |
||
119 | |||
120 | TBitmapResource = class(TResourceItem) |
||
121 | protected |
||
122 | procedure AssignTo(Dest: TPersistent); override; |
||
123 | public |
||
124 | procedure SaveToStream(Stream: TStream); override; |
||
125 | end; |
||
126 | |||
127 | { TStringResource } |
||
128 | |||
129 | TStringResource = class(TResourceItem) |
||
130 | protected |
||
131 | procedure AssignTo(Dest: TPersistent); override; |
||
132 | end; |
||
133 | |||
134 | { TMenuResource } |
||
135 | |||
136 | TMenuResource = class(TResourceItem) |
||
137 | private |
||
138 | FNestStr: string; |
||
139 | FNestLevel: Integer; |
||
140 | procedure SetNestLevel(Value: Integer); |
||
141 | protected |
||
142 | procedure AssignTo(Dest: TPersistent); override; |
||
143 | property NestLevel: Integer read FNestLevel write SetNestLevel; |
||
144 | property NestStr: string read FNestStr; |
||
145 | end; |
||
146 | |||
147 | { TResourceList } |
||
148 | |||
149 | TResourceList = class(TComponent) |
||
150 | protected |
||
151 | FList: TList; |
||
152 | FResDir: PIMAGE_RESOURCE_DIRECTORY; |
||
153 | FExeImage: TExeImage; |
||
154 | FResType: Integer; |
||
155 | function List: TList; virtual; |
||
156 | function GetResourceItem(Index: Integer): TResourceItem; |
||
157 | public |
||
158 | constructor CreateList(AOwner: TComponent; ResDirOfs: Longint; |
||
159 | AExeImage: TExeImage); |
||
160 | destructor Destroy; override; |
||
161 | function Count: Integer; |
||
162 | property Items[Index: Integer]: TResourceItem read GetResourceItem; default; |
||
163 | end; |
||
164 | |||
165 | { TIconResourceList } |
||
166 | |||
167 | TIconResourceList = class(TResourceList) |
||
168 | protected |
||
169 | function List: TList; override; |
||
170 | end; |
||
171 | |||
172 | { TCursorResourceList } |
||
173 | |||
174 | TCursorResourceList = class(TResourceList) |
||
175 | protected |
||
176 | function List: TList; override; |
||
177 | end; |
||
178 | |||
179 | implementation |
||
180 | |||
181 | constructor ENotImplemented.Create(); |
||
182 | begin |
||
183 | inherited Create('Not Implemented'); |
||
184 | end; |
||
185 | |||
186 | |||
187 | { This function maps a resource type to the associated resource class } |
||
188 | |||
189 | function GetResourceClass(ResType: Integer): TResourceClass; |
||
190 | const |
||
191 | TResourceClasses: array[TResourceType] of TResourceClass = ( |
||
192 | TResourceItem, { rtUnknown0 } |
||
193 | TCursorResEntry, { rtCursorEntry } |
||
194 | TBitmapResource, { rtBitmap } |
||
195 | TIconResEntry, { rtIconEntry } |
||
196 | TMenuResource, { rtMenu } |
||
197 | TResourceItem, { rtDialog } |
||
198 | TStringResource, { rtString } |
||
199 | TResourceItem, { rtFontDir } |
||
200 | TResourceItem, { rtFont } |
||
201 | TResourceItem, { rtAccelerators } |
||
202 | TResourceItem, { rtRCData } |
||
203 | TResourceItem, { rtMessageTable } |
||
204 | TCursorResource, { rtGroupCursor } |
||
205 | TResourceItem, { rtUnknown13 } |
||
206 | TIconResource, { rtIcon } |
||
207 | TResourceItem, { rtUnknown15 } |
||
208 | TResourceItem); { rtVersion } |
||
209 | begin |
||
210 | if (ResType >= Integer(Low(TResourceType))) and |
||
211 | (ResType <= Integer(High(TResourceType))) then |
||
212 | Result := TResourceClasses[TResourceType(ResType)] else |
||
213 | Result := TResourceItem; |
||
214 | end; |
||
215 | |||
216 | { Utility Functions } |
||
217 | |||
218 | function Min(A, B: Integer): Integer; |
||
219 | begin |
||
220 | if A < B then Result := A |
||
221 | else Result := B; |
||
222 | end; |
||
223 | |||
224 | { This function checks if an offset is a string name, or a directory } |
||
225 | {Assumes: IMAGE_RESOURCE_NAME_IS_STRING = IMAGE_RESOURCE_DATA_IS_DIRECTORY} |
||
226 | |||
227 | function HighBitSet(L: Longint): Boolean; |
||
228 | begin |
||
229 | Result := (L and IMAGE_RESOURCE_DATA_IS_DIRECTORY) <> 0; |
||
230 | end; |
||
231 | |||
232 | function StripHighBit(L: Longint): Longint; |
||
233 | begin |
||
234 | Result := L and IMAGE_OFFSET_STRIP_HIGH; |
||
235 | end; |
||
236 | |||
237 | function StripHighPtr(L: Longint): Pointer; |
||
238 | begin |
||
239 | Result := Pointer(L and IMAGE_OFFSET_STRIP_HIGH); |
||
240 | end; |
||
241 | |||
242 | { This function converts a pointer to a wide char string into a pascal string } |
||
243 | |||
244 | function WideCharToStr(WStr: PWChar; Len: Integer): string; |
||
245 | begin |
||
246 | if Len = 0 then Len := -1; |
||
247 | Len := WideCharToMultiByte(CP_ACP, 0, WStr, Len, nil, 0, nil, nil); |
||
248 | SetLength(Result, Len); |
||
249 | WideCharToMultiByte(CP_ACP, 0, WStr, Len, PChar(Result), Len, nil, nil); |
||
250 | end; |
||
251 | |||
252 | { Exceptions } |
||
253 | |||
254 | procedure ExeError(const ErrMsg: string); |
||
255 | begin |
||
256 | raise EExeError.Create(ErrMsg); |
||
257 | end; |
||
258 | |||
259 | { TExeImage } |
||
260 | |||
261 | constructor TExeImage.CreateImage(AOwner: TComponent; const AFileName: string); |
||
262 | begin |
||
263 | inherited Create(AOwner); |
||
264 | FFileName := AFileName; |
||
265 | FFileHandle := CreateFile(PChar(FFileName), GENERIC_READ, FILE_SHARE_READ, |
||
266 | nil, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0); |
||
267 | if FFileHandle = INVALID_HANDLE_VALUE then ExeError('Couldn''t open: '+FFileName); |
||
268 | FFileMapping := CreateFileMapping(FFileHandle, nil, PAGE_READONLY, 0, 0, nil); |
||
269 | if FFileMapping = 0 then ExeError('CreateFileMapping failed'); |
||
270 | FFileBase := MapViewOfFile(FFileMapping, FILE_MAP_READ, 0, 0, 0); |
||
271 | if FFileBase = nil then ExeError('MapViewOfFile failed'); |
||
272 | FDosHeader := PIMAGE_DOS_HEADER(FFileBase); |
||
273 | if not FDosHeader.e_magic = IMAGE_DOS_SIGNATURE then |
||
274 | ExeError('unrecognized file format'); |
||
275 | FNTHeader := PIMAGE_NT_HEADERS(Longint(FDosHeader) + FDosHeader.e_lfanew); |
||
276 | if IsBadReadPtr(FNTHeader, sizeof(IMAGE_NT_HEADERS)) or |
||
277 | (FNTHeader.Signature <> IMAGE_NT_SIGNATURE) then |
||
278 | ExeError('Not a PE (WIN32 Executable) file'); |
||
279 | end; |
||
280 | |||
281 | destructor TExeImage.Destroy; |
||
282 | begin |
||
283 | if FFileHandle <> INVALID_HANDLE_VALUE then |
||
284 | begin |
||
285 | UnmapViewOfFile(FFileBase); |
||
286 | CloseHandle(FFileMapping); |
||
287 | CloseHandle(FFileHandle); |
||
288 | end; |
||
289 | inherited Destroy; |
||
290 | end; |
||
291 | |||
292 | function TExeImage.GetSectionHdr(const SectionName: string; |
||
293 | var Header: PIMAGE_SECTION_HEADER): Boolean; |
||
294 | var |
||
295 | I: Integer; |
||
296 | begin |
||
297 | Header := PIMAGE_SECTION_HEADER(FNTHeader); |
||
298 | Inc(PIMAGE_NT_HEADERS(Header)); |
||
299 | Result := True; |
||
300 | for I := 0 to FNTHeader.FileHeader.NumberOfSections - 1 do |
||
301 | begin |
||
302 | if Strlicomp(Header.Name, PChar(SectionName), IMAGE_SIZEOF_SHORT_NAME) = 0 then Exit; |
||
303 | Inc(Header); |
||
304 | end; |
||
305 | Result := False; |
||
306 | end; |
||
307 | |||
308 | function TExeImage.GetResourceList: TResourceList; |
||
309 | var |
||
310 | ResSectHdr: PIMAGE_SECTION_HEADER; |
||
311 | begin |
||
312 | if not Assigned(FResourceList) then |
||
313 | begin |
||
314 | if GetSectionHdr('.rsrc', ResSectHdr) then |
||
315 | begin |
||
316 | FResourceBase := ResSectHdr.PointerToRawData + LongWord(FDosHeader); |
||
317 | FResourceRVA := ResSectHdr.VirtualAddress; |
||
318 | FResourceList := TResourceList.CreateList(Self, FResourceBase, Self); |
||
319 | end |
||
320 | else |
||
321 | ExeError('No resources in this file.'); |
||
322 | end; |
||
323 | Result := FResourceList; |
||
324 | end; |
||
325 | |||
326 | { TResourceItem } |
||
327 | |||
328 | constructor TResourceItem.CreateItem(AOwner: TComponent; ADirEntry: Pointer); |
||
329 | begin |
||
330 | inherited Create(AOwner); |
||
331 | FDirEntry := ADirEntry; |
||
332 | end; |
||
333 | |||
334 | function TResourceItem.DataEntry: PIMAGE_RESOURCE_DATA_ENTRY; |
||
335 | begin |
||
336 | Result := PIMAGE_RESOURCE_DATA_ENTRY(FirstChildDirEntry.OffsetToData |
||
337 | + Cardinal(FExeImage.FResourceBase)); |
||
338 | end; |
||
339 | |||
340 | function TResourceItem.FirstChildDirEntry: PIMAGE_RESOURCE_DIRECTORY_ENTRY; |
||
341 | begin |
||
342 | Result := PIMAGE_RESOURCE_DIRECTORY_ENTRY(StripHighBit(FDirEntry.OffsetToData) + |
||
343 | FExeImage.FResourceBase + SizeOf(IMAGE_RESOURCE_DIRECTORY)); |
||
344 | end; |
||
345 | |||
346 | function TResourceItem.FExeImage: TExeImage; |
||
347 | begin |
||
348 | Result := (Owner as TResourceList).FExeImage; |
||
349 | end; |
||
350 | |||
351 | function TResourceItem.GetResourceItem(Index: Integer): TResourceItem; |
||
352 | begin |
||
353 | Result := List[Index]; |
||
354 | end; |
||
355 | |||
356 | function TResourceItem.GetResourceType: TResourceType; |
||
357 | begin |
||
358 | Result := TResourceType((Owner as TResourceList).FResType); |
||
359 | end; |
||
360 | |||
361 | function TResourceItem.IsList: Boolean; |
||
362 | begin |
||
363 | Result := HighBitSet(FirstChildDirEntry.OffsetToData); |
||
364 | end; |
||
365 | |||
366 | function TResourceItem.GetResourceList: TResourceList; |
||
367 | begin |
||
368 | if not IsList then ExeError('ResourceItem is not a list'); |
||
369 | if not Assigned(FList) then |
||
370 | FList := TResourceList.CreateList(Self, StripHighBit(FDirEntry.OffsetToData) + |
||
371 | FExeImage.FResourceBase, FExeImage); |
||
372 | Result := FList; |
||
373 | end; |
||
374 | |||
375 | function TResourceItem.GetName: string; |
||
376 | var |
||
377 | PDirStr: PIMAGE_RESOURCE_DIR_STRING_U; |
||
378 | begin |
||
379 | { Check for Level1 entries, these are resource types. } |
||
380 | if (Owner.Owner = FExeImage) and not HighBitSet(FDirEntry.Name) and |
||
381 | (FDirEntry.Name <= 16) then |
||
382 | begin |
||
383 | Result := Copy(GetEnumName(TypeInfo(TResourceType), FDirEntry.Name), 3, 20); |
||
384 | Exit; |
||
385 | end; |
||
386 | |||
387 | if HighBitSet(FDirEntry.Name) then |
||
388 | begin |
||
389 | PDirStr := PIMAGE_RESOURCE_DIR_STRING_U(StripHighBit(FDirEntry.Name) + |
||
390 | FExeImage.FResourceBase); |
||
391 | Result := WideCharToStr(@PDirStr.NameString, PDirStr.Length); |
||
392 | Exit; |
||
393 | end; |
||
394 | Result := Format('%d', [FDirEntry.Name]); |
||
395 | end; |
||
396 | |||
397 | function TResourceItem.Offset: Integer; |
||
398 | begin |
||
399 | if IsList then |
||
400 | Result := StripHighBit(FDirEntry.OffsetToData) |
||
401 | else |
||
402 | Result := DataEntry.OffsetToData; |
||
403 | end; |
||
404 | |||
405 | function TResourceItem.RawData: Pointer; |
||
406 | begin |
||
407 | with FExeImage do |
||
408 | Result := pointer(FResourceBase - FResourceRVA + LongInt(DataEntry.OffsetToData)); |
||
409 | end; |
||
410 | |||
411 | function TResourceItem.ResTypeStr: string; |
||
412 | begin |
||
413 | Result := Copy(GetEnumName(TypeInfo(TResourceType), Ord(ResType)), 3, 20); |
||
414 | end; |
||
415 | |||
416 | procedure TResourceItem.SaveToFile(const FileName: string); |
||
417 | var |
||
418 | FS: TFileStream; |
||
419 | begin |
||
420 | FS := TFileStream.Create(FileName, fmCreate); |
||
421 | try |
||
422 | Self.SaveToStream(FS); |
||
423 | finally |
||
424 | FS.Free; |
||
425 | end; |
||
426 | end; |
||
427 | |||
428 | procedure TResourceItem.SaveToStream(Stream: TStream); |
||
429 | begin |
||
430 | Stream.Write(RawData^, Size); |
||
431 | end; |
||
432 | |||
433 | function TResourceItem.Size: Integer; |
||
434 | begin |
||
435 | if IsList then |
||
436 | Result := 0 |
||
437 | else |
||
438 | Result := DataEntry.Size; |
||
439 | end; |
||
440 | |||
441 | { TBitmapResource } |
||
442 | |||
443 | procedure TBitmapResource.AssignTo(Dest: TPersistent); |
||
444 | {var |
||
445 | MemStr: TMemoryStream; |
||
446 | BitMap: TBitMap;} |
||
447 | begin |
||
448 | raise ENotImplemented.Create(); |
||
449 | |||
450 | {if (Dest is TPicture) then |
||
451 | begin |
||
452 | BitMap := TPicture(Dest).Bitmap; |
||
453 | MemStr := TMemoryStream.Create; |
||
454 | try |
||
455 | SaveToStream(MemStr); |
||
456 | MemStr.Seek(0,0); |
||
457 | BitMap.LoadFromStream(MemStr); |
||
458 | finally |
||
459 | MemStr.Free; |
||
460 | end |
||
461 | end |
||
462 | else |
||
463 | inherited AssignTo(Dest);} |
||
464 | end; |
||
465 | |||
466 | procedure TBitmapResource.SaveToStream(Stream: TStream); |
||
467 | |||
468 | {function GetDInColors(BitCount: Word): Integer; |
||
469 | begin |
||
470 | case BitCount of |
||
471 | 1, 4, 8: Result := 1 shl BitCount; |
||
472 | else |
||
473 | Result := 0; |
||
474 | end; |
||
475 | end; |
||
476 | |||
477 | var |
||
478 | BH: TBitmapFileHeader; |
||
479 | BI: PBitmapInfoHeader; |
||
480 | BC: PBitmapCoreHeader; |
||
481 | ClrUsed: Integer;} |
||
482 | begin |
||
483 | raise ENotImplemented.Create(); |
||
484 | |||
485 | {FillChar(BH, sizeof(BH), #0); |
||
486 | BH.bfType := $4D42; |
||
487 | BH.bfSize := Self.Size + sizeof(BH); |
||
488 | BI := PBitmapInfoHeader(RawData); |
||
489 | if BI.biSize = sizeof(TBitmapInfoHeader) then |
||
490 | begin |
||
491 | ClrUsed := BI.biClrUsed; |
||
492 | if ClrUsed = 0 then |
||
493 | ClrUsed := GetDInColors(BI.biBitCount); |
||
494 | BH.bfOffBits := ClrUsed * SizeOf(TRgbQuad) + |
||
495 | sizeof(TBitmapInfoHeader) + sizeof(BH); |
||
496 | end |
||
497 | else |
||
498 | begin |
||
499 | BC := PBitmapCoreHeader(RawData); |
||
500 | ClrUsed := GetDInColors(BC.bcBitCount); |
||
501 | BH.bfOffBits := ClrUsed * SizeOf(TRGBTriple) + |
||
502 | sizeof(TBitmapCoreHeader) + sizeof(BH); |
||
503 | end; |
||
504 | Stream.Write(BH, SizeOf(BH)); |
||
505 | Stream.Write(RawData^, Self.Size);} |
||
506 | end; |
||
507 | |||
508 | |||
509 | { TIconResource } |
||
510 | |||
511 | function TIconResource.GetResourceList: TResourceList; |
||
512 | begin |
||
513 | if not Assigned(FList) then |
||
514 | FList := TIconResourceList.CreateList(Owner, LongInt(RawData), FExeImage); |
||
515 | Result := FList; |
||
516 | end; |
||
517 | |||
518 | function TIconResource.IsList: Boolean; |
||
519 | begin |
||
520 | Result := True; |
||
521 | end; |
||
522 | |||
523 | { TIconResEntry } |
||
524 | |||
525 | procedure TIconResEntry.AssignTo(Dest: TPersistent); |
||
526 | {var |
||
527 | hIco: HIcon;} |
||
528 | begin |
||
529 | raise ENotImplemented.Create(); |
||
530 | |||
531 | {if Dest is TPicture then |
||
532 | begin |
||
533 | hIco := CreateIconFromResource(RawData, Size, (ResType = rtIconEntry), $30000); |
||
534 | TPicture(Dest).Icon.Handle := hIco; |
||
535 | end |
||
536 | else |
||
537 | inherited AssignTo(Dest);} |
||
538 | end; |
||
539 | |||
540 | function TIconResEntry.GetName: string; |
||
541 | begin |
||
542 | if Assigned(FResInfo) then |
||
543 | with FResInfo^ do |
||
544 | Result := Format('%d X %d %d Colors', [bWidth, bHeight, bColorCount]) |
||
545 | else |
||
546 | Result := inherited GetName; |
||
547 | end; |
||
548 | |||
549 | procedure TIconResEntry.SaveToStream(Stream: TStream); |
||
550 | begin |
||
551 | raise ENotImplemented.Create(); |
||
552 | |||
553 | {with TIcon.Create do |
||
554 | try |
||
555 | Handle := CreateIconFromResource(RawData, Self.Size, (ResType <> rtIcon), $30000); |
||
556 | SaveToStream(Stream); |
||
557 | finally |
||
558 | Free; |
||
559 | end;} |
||
560 | end; |
||
561 | |||
562 | { TCursorResource } |
||
563 | |||
564 | function TCursorResource.GetResourceList: TResourceList; |
||
565 | begin |
||
566 | if not Assigned(FList) then |
||
567 | FList := TCursorResourceList.CreateList(Owner, LongInt(RawData), FExeImage); |
||
568 | Result := FList; |
||
569 | end; |
||
570 | |||
571 | { TCursorResEntry } |
||
572 | |||
573 | function TCursorResEntry.GetName: string; |
||
574 | begin |
||
575 | if Assigned(FResInfo) then |
||
576 | with FResInfo^ do |
||
577 | Result := Format('%d X %d %d Bit(s)', [wWidth, wWidth, wBitCount]) |
||
578 | else |
||
579 | Result := inherited GetName; |
||
580 | end; |
||
581 | |||
582 | { TStringResource } |
||
583 | |||
584 | procedure TStringResource.AssignTo(Dest: TPersistent); |
||
585 | var |
||
586 | P: PWChar; |
||
587 | ID: Integer; |
||
588 | Cnt: Cardinal; |
||
589 | Len: Word; |
||
590 | begin |
||
591 | if (Dest is TStrings) then |
||
592 | with TStrings(Dest) do |
||
593 | begin |
||
594 | BeginUpdate; |
||
595 | try |
||
596 | Clear; |
||
597 | P := RawData; |
||
598 | Cnt := 0; |
||
599 | while Cnt < StringsPerBlock do |
||
600 | begin |
||
601 | Len := Word(P^); |
||
602 | if Len > 0 then |
||
603 | begin |
||
604 | Inc(P); |
||
605 | ID := ((FDirEntry.Name - 1) shl 4) + Cnt; |
||
606 | Add(Format('%d, "%s"', [ID, WideCharToStr(P, Len)])); |
||
607 | Inc(P, Len); |
||
608 | end; |
||
609 | Inc(Cnt); |
||
610 | end; |
||
611 | finally |
||
612 | EndUpdate; |
||
613 | end; |
||
614 | end |
||
615 | else |
||
616 | inherited AssignTo(Dest); |
||
617 | end; |
||
618 | |||
619 | { TMenuResource } |
||
620 | |||
621 | procedure TMenuResource.SetNestLevel(Value: Integer); |
||
622 | begin |
||
623 | FNestLevel := Value; |
||
624 | SetLength(FNestStr, Value * 2); |
||
625 | FillChar(FNestStr[1], Value * 2, ' '); |
||
626 | end; |
||
627 | |||
628 | procedure TMenuResource.AssignTo(Dest: TPersistent); |
||
629 | var |
||
630 | IsPopup: Boolean; |
||
631 | Len: Word; |
||
632 | MenuData: PWord; |
||
633 | MenuEnd: PChar; |
||
634 | MenuText: PWChar; |
||
635 | MenuID: Word; |
||
636 | MenuFlags: Word; |
||
637 | S: string; |
||
638 | begin |
||
639 | if (Dest is TStrings) then |
||
640 | with TStrings(Dest) do |
||
641 | begin |
||
642 | BeginUpdate; |
||
643 | try |
||
644 | Clear; |
||
645 | MenuData := RawData; |
||
646 | MenuEnd := PChar(RawData) + Size; |
||
647 | Inc(MenuData, 2); |
||
648 | NestLevel := 0; |
||
649 | while PChar(MenuData) < MenuEnd do |
||
650 | begin |
||
651 | MenuFlags := MenuData^; |
||
652 | Inc(MenuData); |
||
653 | IsPopup := (MenuFlags and MF_POPUP) = MF_POPUP; |
||
654 | MenuID := 0; |
||
655 | if not IsPopup then |
||
656 | begin |
||
657 | MenuID := MenuData^; |
||
658 | Inc(MenuData); |
||
659 | end; |
||
660 | MenuText := PWChar(MenuData); |
||
661 | Len := lstrlenw(MenuText); |
||
662 | if Len = 0 then |
||
663 | S := 'MENUITEM SEPARATOR' |
||
664 | else |
||
665 | begin |
||
666 | S := WideCharToStr(MenuText, Len); |
||
667 | if IsPopup then |
||
668 | S := Format('POPUP "%s"', [S]) else |
||
669 | S := Format('MENUITEM "%s", %d', [S, MenuID]); |
||
670 | end; |
||
671 | Inc(MenuData, Len + 1); |
||
672 | Add(NestStr + S); |
||
673 | if (MenuFlags and MF_END) = MF_END then |
||
674 | begin |
||
675 | NestLevel := NestLevel - 1; |
||
676 | Add(NestStr + 'ENDPOPUP'); |
||
677 | end; |
||
678 | if IsPopup then |
||
679 | NestLevel := NestLevel + 1; |
||
680 | end; |
||
681 | finally |
||
682 | EndUpdate; |
||
683 | end; |
||
684 | end |
||
685 | else |
||
686 | inherited AssignTo(Dest); |
||
687 | end; |
||
688 | |||
689 | { TResourceList } |
||
690 | |||
691 | constructor TResourceList.CreateList(AOwner: TComponent; ResDirOfs: Longint; |
||
692 | AExeImage: TExeImage); |
||
693 | var |
||
694 | DirEntry: PIMAGE_RESOURCE_DIRECTORY_ENTRY; |
||
695 | begin |
||
696 | inherited Create(AOwner); |
||
697 | FExeImage := AExeImage; |
||
698 | FResDir := Pointer(ResDirOfs); |
||
699 | if AOwner <> AExeImage then |
||
700 | if AOwner.Owner.Owner = AExeImage then |
||
701 | begin |
||
702 | DirEntry := PIMAGE_RESOURCE_DIRECTORY_ENTRY(FResDir); |
||
703 | inc(PIMAGE_RESOURCE_DIRECTORY(DirEntry)); |
||
704 | FResType := TResourceItem(Owner).FDirEntry.Name; |
||
705 | end |
||
706 | else |
||
707 | FResType := (AOwner.Owner.Owner as TResourceList).FResType; |
||
708 | end; |
||
709 | |||
710 | destructor TResourceList.Destroy; |
||
711 | begin |
||
712 | inherited Destroy; |
||
713 | FList.Free; |
||
714 | end; |
||
715 | |||
716 | function TResourceList.List: TList; |
||
717 | var |
||
718 | I: Integer; |
||
719 | DirEntry: PIMAGE_RESOURCE_DIRECTORY_ENTRY; |
||
720 | DirCnt: Integer; |
||
721 | ResItem: TResourceItem; |
||
722 | begin |
||
723 | if not Assigned(FList) then |
||
724 | begin |
||
725 | FList := TList.Create; |
||
726 | DirEntry := PIMAGE_RESOURCE_DIRECTORY_ENTRY(FResDir); |
||
727 | inc(PIMAGE_RESOURCE_DIRECTORY(DirEntry)); |
||
728 | DirCnt := FResDir.NumberOfNamedEntries + FResDir.NumberOfIdEntries - 1; |
||
729 | for I := 0 to DirCnt do |
||
730 | begin |
||
731 | { Handle Cursors and Icons specially } |
||
732 | ResItem := GetResourceClass(FResType).CreateItem(Self, DirEntry); |
||
733 | if Owner = FExeImage then |
||
734 | if (TResourceType(DirEntry.Name) in [rtCursorEntry, rtIconEntry]) then |
||
735 | begin |
||
736 | if TResourceType(DirEntry.Name) = rtCursorEntry then |
||
737 | FExeImage.FCursorResources := ResItem else |
||
738 | FExeImage.FIconResources := ResItem; |
||
739 | Inc(DirEntry); |
||
740 | Continue; |
||
741 | end; |
||
742 | FList.Add(ResItem); |
||
743 | Inc(DirEntry); |
||
744 | end; |
||
745 | end; |
||
746 | Result := FList; |
||
747 | end; |
||
748 | |||
749 | function TResourceList.Count: Integer; |
||
750 | begin |
||
751 | Result := List.Count; |
||
752 | end; |
||
753 | |||
754 | function TResourceList.GetResourceItem(Index: Integer): TResourceItem; |
||
755 | begin |
||
756 | Result := List[Index]; |
||
757 | end; |
||
758 | |||
759 | { TIconResourceList } |
||
760 | |||
761 | function TIconResourceList.List: TList; |
||
762 | var |
||
763 | I, J, Cnt: Integer; |
||
764 | ResData: PIconResInfo; |
||
765 | ResList: TResourceList; |
||
766 | ResOrd: Cardinal; |
||
767 | IconResource: TIconResEntry; |
||
768 | begin |
||
769 | if not Assigned(FList) then |
||
770 | begin |
||
771 | FList := TList.Create; |
||
772 | Cnt := PIconHeader(FResDir).wCount; |
||
773 | PChar(ResData) := PChar(FResDir) + SizeOf(TIconHeader); |
||
774 | ResList := FExeImage.FIconResources.List; |
||
775 | for I := 0 to Cnt - 1 do |
||
776 | begin |
||
777 | ResOrd := ResData.wNameOrdinal; |
||
778 | for J := 0 to ResList.Count - 1 do |
||
779 | begin |
||
780 | if ResOrd = ResList[J].FDirEntry.Name then |
||
781 | begin |
||
782 | IconResource := ResList[J] as TIconResEntry; |
||
783 | IconResource.FResInfo := ResData; |
||
784 | FList.Add(IconResource); |
||
785 | end; |
||
786 | end; |
||
787 | Inc(ResData); |
||
788 | end; |
||
789 | end; |
||
790 | Result := FList; |
||
791 | end; |
||
792 | |||
793 | { TCursorResourceList } |
||
794 | |||
795 | function TCursorResourceList.List: TList; |
||
796 | var |
||
797 | I, J, Cnt: Integer; |
||
798 | ResData: PCursorResInfo; |
||
799 | ResList: TResourceList; |
||
800 | ResOrd: Cardinal; |
||
801 | CursorResource: TCursorResEntry; |
||
802 | begin |
||
803 | if not Assigned(FList) then |
||
804 | begin |
||
805 | FList := TList.Create; |
||
806 | Cnt := PIconHeader(FResDir).wCount; |
||
807 | PChar(ResData) := PChar(FResDir) + SizeOf(TIconHeader); |
||
808 | ResList := FExeImage.FCursorResources.List; |
||
809 | for I := 0 to Cnt - 1 do |
||
810 | begin |
||
811 | ResOrd := ResData.wNameOrdinal; |
||
812 | for J := 0 to ResList.Count - 1 do |
||
813 | begin |
||
814 | if ResOrd = ResList[J].FDirEntry.Name then |
||
815 | begin |
||
816 | CursorResource := ResList[J] as TCursorResEntry; |
||
817 | CursorResource.FResInfo := ResData; |
||
818 | FList.Add(CursorResource); |
||
819 | end; |
||
820 | end; |
||
821 | Inc(ResData); |
||
822 | end; |
||
823 | end; |
||
824 | Result := FList; |
||
825 | end; |
||
826 | |||
827 | end.>>>>=>>>>>=> |