/jcl/examples/windows/delphitools/peviewer/PeGenDef.pas

https://github.com/the-Arioch/jcl · Pascal · 365 lines · 303 code · 34 blank · 28 comment · 23 complexity · 4a7eeac24b657c4a5d11af3e7e96f856 MD5 · raw file

  1. {**************************************************************************************************}
  2. { }
  3. { Project JEDI Code Library (JCL) - Delphi Tools }
  4. { }
  5. { The contents of this file are subject to the Mozilla Public License Version 1.1 (the "License"); }
  6. { you may not use this file except in compliance with the License. You may obtain a copy of the }
  7. { License at http://www.mozilla.org/MPL/ }
  8. { }
  9. { Software distributed under the License is distributed on an "AS IS" basis, WITHOUT WARRANTY OF }
  10. { ANY KIND, either express or implied. See the License for the specific language governing rights }
  11. { and limitations under the License. }
  12. { }
  13. { The Original Code is PeGenDef.pas. }
  14. { }
  15. { The Initial Developer of the Original Code is Petr Vones. Portions created by Petr Vones are }
  16. { Copyright (C) of Petr Vones. All Rights Reserved. }
  17. { }
  18. { Contributor(s): }
  19. { }
  20. {**************************************************************************************************}
  21. { }
  22. { Last modified: $Date$ }
  23. { }
  24. {**************************************************************************************************}
  25. unit PeGenDef;
  26. {$I JCL.INC}
  27. interface
  28. uses
  29. Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
  30. JclPeImage, ComCtrls, StdCtrls, Spin;
  31. type
  32. TPeUnitGenFlags = set of (ufDecorated, ufDuplicate, ufVariable);
  33. TPeUnitGenerator = class(TJclPeImage)
  34. private
  35. FUnitGenFlags: array of TPeUnitGenFlags;
  36. function GetUnitGenFlags(Index: Integer): TPeUnitGenFlags;
  37. public
  38. procedure GenerateUnit(Strings: TStrings; const LibConst: string; WrapPos: Integer);
  39. procedure ScanExports;
  40. property UnitGenFlags[Index: Integer]: TPeUnitGenFlags read GetUnitGenFlags;
  41. end;
  42. TPeGenDefChild = class(TForm)
  43. PageControl1: TPageControl;
  44. TabSheet1: TTabSheet;
  45. TabSheet2: TTabSheet;
  46. FunctionsListView: TListView;
  47. UnitRichEdit: TRichEdit;
  48. GroupBox1: TGroupBox;
  49. Label1: TLabel;
  50. LibConstNameEdit: TEdit;
  51. WrapSpinEdit: TSpinEdit;
  52. WrapCheckBox: TCheckBox;
  53. SaveDialog: TSaveDialog;
  54. procedure FormClose(Sender: TObject; var Action: TCloseAction);
  55. procedure FormCreate(Sender: TObject);
  56. procedure FormDestroy(Sender: TObject);
  57. procedure FunctionsListViewData(Sender: TObject; Item: TListItem);
  58. procedure FunctionsListViewCustomDrawItem(Sender: TCustomListView;
  59. Item: TListItem; State: TCustomDrawState; var DefaultDraw: Boolean);
  60. procedure PageControl1Change(Sender: TObject);
  61. procedure WrapCheckBoxClick(Sender: TObject);
  62. private
  63. FPeUnitGenerator: TPeUnitGenerator;
  64. procedure SetFileName(const Value: TFileName);
  65. function GetFileName: TFileName;
  66. procedure GenerateUnit;
  67. public
  68. function CanSave: Boolean;
  69. procedure SaveUnit;
  70. property FileName: TFileName read GetFileName write SetFileName;
  71. end;
  72. var
  73. PeGenDefChild: TPeGenDefChild;
  74. implementation
  75. uses PeViewerMain, JclFileUtils, ToolsUtils, JclSysUtils;
  76. {$R *.DFM}
  77. const
  78. nfDecoratedName = $01;
  79. nfAnsiUnicodePair = $02;
  80. function PascalizeName(const Name: string): string;
  81. function CharIsValidLeadingChar(const C: Char): Boolean;
  82. begin
  83. case C of
  84. 'A'..'Z',
  85. 'a'..'z':
  86. Result := True;
  87. else
  88. Result := False;
  89. end;
  90. end;
  91. function CharIsStripLeadingChar(const C: Char): Boolean;
  92. begin
  93. Result := C = '_';
  94. end;
  95. function CharIsValid(const C: Char): Boolean;
  96. begin
  97. case C of
  98. 'A'..'Z',
  99. 'a'..'z',
  100. '0'..'9':
  101. Result := True;
  102. else
  103. Result := False;
  104. end;
  105. end;
  106. const
  107. InvalidCharReplacement = '_';
  108. StopChar = '@';
  109. var
  110. I: Integer;
  111. C: Char;
  112. begin
  113. SetLength(Result, Length(Name));
  114. Result := '';
  115. for I := 1 to Length(Name) do
  116. begin
  117. C := Name[I];
  118. if I = 1 then
  119. begin
  120. if CharIsValidLeadingChar(C) then
  121. Result := Result + C
  122. else
  123. if not CharIsStripLeadingChar(C) then
  124. Break; // probably MS C++ or Borland name decoration
  125. end else
  126. begin
  127. if CharIsValid(C) then
  128. Result := Result + C
  129. else
  130. if C = StopChar then
  131. Break
  132. else
  133. Result := Result + InvalidCharReplacement;
  134. end;
  135. end;
  136. I := Length(Result);
  137. while I > 0 do
  138. if Result[I] = InvalidCharReplacement then
  139. begin
  140. Delete(Result, I, 1);
  141. Dec(I);
  142. end
  143. else
  144. Break;
  145. end;
  146. function PossiblyAnsiUnicodePair(const Name1, Name2: AnsiString): Boolean;
  147. const
  148. AnsiUnicodeSuffixes = ['A', 'W'];
  149. var
  150. L1, L2: Integer;
  151. Suffix1, Suffix2: AnsiChar;
  152. begin
  153. Result := False;
  154. L1 := Length(Name1);
  155. L2 := Length(Name2);
  156. if (L1 = L2) and (L1 > 1) then
  157. begin
  158. Suffix1 := Name1[L1];
  159. Suffix2 := Name2[L2];
  160. Result := (Suffix1 in AnsiUnicodeSuffixes) and (Suffix2 in AnsiUnicodeSuffixes) and
  161. (Suffix1 <> Suffix2) and (Copy(Name1, 1, L1 - 1) = Copy(Name2, 1, L2 - 1));
  162. end;
  163. end;
  164. function IsDecoratedName(const Name: string): Boolean;
  165. begin
  166. Result := (Length(Name) > 1) and (Name[1] = '?') and (Name[1] = '@');
  167. end;
  168. { TPeUnitGenerator }
  169. procedure TPeUnitGenerator.GenerateUnit(Strings: TStrings; const LibConst: string;
  170. WrapPos: Integer);
  171. var
  172. I: Integer;
  173. S: string;
  174. begin
  175. Strings.Add('implementation');
  176. Strings.Add('');
  177. Strings.Add('const');
  178. Strings.Add(Format(' %s = ''%s'';', [LibConst, ExtractFileName(FileName)]));
  179. Strings.Add('');
  180. for I := 0 to ExportList.Count - 1 do
  181. with ExportList[I] do
  182. if FUnitGenFlags[I] = [] then
  183. begin
  184. S := Format('function %s; external %s name ''%s'';', [PascalizeName(Name), LibConst, Name]);
  185. if WrapPos > 0 then
  186. S := WrapText(S, #13#10' ', [' '], WrapPos);
  187. Strings.Add(S);
  188. end;
  189. Strings.Add('');
  190. Strings.Add('end.');
  191. end;
  192. function TPeUnitGenerator.GetUnitGenFlags(Index: Integer): TPeUnitGenFlags;
  193. begin
  194. Result := FUnitGenFlags[Index];
  195. end;
  196. procedure TPeUnitGenerator.ScanExports;
  197. var
  198. I: Integer;
  199. PascalName, LastName, FirstSectionName: string;
  200. LastAddress: DWORD;
  201. Flags: TPeUnitGenFlags;
  202. begin
  203. SetLength(FUnitGenFlags, ExportList.Count);
  204. ExportList.SortList(esName);
  205. LastName := '';
  206. LastAddress := 0;
  207. FirstSectionName := ImageSectionNames[0]; // The first section is code section
  208. for I := 0 to ExportList.Count - 1 do
  209. with ExportList[I] do
  210. begin
  211. Flags := [];
  212. if SectionName <> FirstSectionName then
  213. Include(Flags, ufVariable)
  214. else
  215. if IsDecoratedName(Name) then
  216. Include(Flags, ufDecorated)
  217. else
  218. begin
  219. PascalName := PascalizeName(Name);
  220. if (LastAddress = Address) and (LastName = PascalName) then
  221. Include(Flags, ufDuplicate);
  222. LastName := PascalName;
  223. LastAddress := Address;
  224. end;
  225. FUnitGenFlags[I] := Flags;
  226. end;
  227. end;
  228. { TPeGenDefChild }
  229. procedure TPeGenDefChild.FormClose(Sender: TObject; var Action: TCloseAction);
  230. begin
  231. Fix_ListViewBeforeClose(Self);
  232. Action := caFree;
  233. end;
  234. procedure TPeGenDefChild.FormCreate(Sender: TObject);
  235. begin
  236. FPeUnitGenerator := TPeUnitGenerator.Create;
  237. end;
  238. procedure TPeGenDefChild.FormDestroy(Sender: TObject);
  239. begin
  240. FreeAndNil(FPeUnitGenerator);
  241. end;
  242. function TPeGenDefChild.GetFileName: TFileName;
  243. begin
  244. Result := FPeUnitGenerator.FileName;
  245. end;
  246. procedure TPeGenDefChild.SetFileName(const Value: TFileName);
  247. begin
  248. Screen.Cursor := crHourGlass;
  249. try
  250. FPeUnitGenerator.FileName := Value;
  251. FPeUnitGenerator.ScanExports;
  252. LibConstNameEdit.Text := PathExtractFileNameNoExt(Value) + 'Lib';
  253. FunctionsListView.Items.Count := FPeUnitGenerator.ExportList.Count;
  254. FunctionsListView.Invalidate;
  255. finally
  256. Screen.Cursor := crDefault;
  257. end;
  258. end;
  259. procedure TPeGenDefChild.FunctionsListViewData(Sender: TObject; Item: TListItem);
  260. var
  261. Flags: TPeUnitGenFlags;
  262. begin
  263. Flags := FPeUnitGenerator.UnitGenFlags[Item.Index];
  264. with Item, FPeUnitGenerator.ExportList[Item.Index] do
  265. begin
  266. Caption := Name;
  267. SubItems.Add(PascalizeName(Name));
  268. SubItems.Add(AddressOrForwardStr);
  269. if ufDuplicate in Flags then
  270. ImageIndex := icoWarning
  271. else
  272. if Flags * [ufDecorated, ufVariable] = [] then
  273. ImageIndex := icoExports
  274. else
  275. ImageIndex := -1;
  276. end;
  277. end;
  278. procedure TPeGenDefChild.FunctionsListViewCustomDrawItem(Sender: TCustomListView;
  279. Item: TListItem; State: TCustomDrawState; var DefaultDraw: Boolean);
  280. var
  281. Flags: TPeUnitGenFlags;
  282. begin
  283. Flags := FPeUnitGenerator.UnitGenFlags[Item.Index];
  284. if Flags * [ufDecorated, ufVariable] <> [] then
  285. Sender.Canvas.Font.Style := [fsStrikeOut];
  286. end;
  287. procedure TPeGenDefChild.GenerateUnit;
  288. var
  289. SL: TStringList;
  290. WrapColumn: Integer;
  291. begin
  292. Screen.Cursor := crHourGlass;
  293. SL := TStringList.Create;
  294. try
  295. if WrapCheckBox.Checked then
  296. WrapColumn := WrapSpinEdit.Value
  297. else
  298. WrapColumn := 0;
  299. FPeUnitGenerator.GenerateUnit(SL, LibConstNameEdit.Text, WrapColumn);
  300. UnitRichEdit.Text := SL.Text;
  301. finally
  302. SL.Free;
  303. Screen.Cursor := crDefault;
  304. end;
  305. end;
  306. procedure TPeGenDefChild.PageControl1Change(Sender: TObject);
  307. begin
  308. if PageControl1.ActivePage = TabSheet1 then
  309. LibConstNameEdit.SetFocus
  310. else
  311. if PageControl1.ActivePage = TabSheet2 then
  312. GenerateUnit;
  313. end;
  314. procedure TPeGenDefChild.WrapCheckBoxClick(Sender: TObject);
  315. begin
  316. WrapSpinEdit.Enabled := WrapCheckBox.Checked;
  317. end;
  318. function TPeGenDefChild.CanSave: Boolean;
  319. begin
  320. Result := PageControl1.ActivePage = TabSheet2;
  321. end;
  322. procedure TPeGenDefChild.SaveUnit;
  323. begin
  324. with SaveDialog do
  325. begin
  326. FileName := PathExtractFileNameNoExt(FPeUnitGenerator.FileName);
  327. if Execute then
  328. UnitRichEdit.Lines.SaveToFile(FileName);
  329. end;
  330. end;
  331. end.