UtilMethods.pas 37 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507
  1. unit UtilMethods;
  2. interface
  3. uses
  4. Controls, ZhAPI, ActnList, ZjIDTree, DB, ZjGridDBA, ZjGrid, Windows, Messages,
  5. sdDB, VCLZip, VCLUnZip, Dialogs, Forms, ShlObj, Classes, StrUtils, Math, ADODB,
  6. IdGlobal, uGetMacAddr;
  7. type
  8. TRoundMode = (rmNearest, rmUp, rmDown);
  9. TBookmarkRefreshEvent = procedure (AExpandFrame: Boolean) of object;
  10. function TickCount: Integer;
  11. {RoundTo}
  12. function GetCompareDigitValue(ADigit: Integer): Double;
  13. function QuantityRoundTo(AValue: Double): Double;
  14. function PriceRoundTo(AValue: Double): Double;
  15. function TotalPriceRoundTo(AValue: Double): Double;
  16. function CommonRoundTo(AValue: Double; ADigit: Integer; RoundMode: TRoundMode = rmNearest): Double;
  17. function CommonCalcRoundTo(AValue: Double): Double;
  18. {Interface Control}
  19. procedure AlignControl(AControl, AParent: TWinControl; AAlign: TAlign);
  20. procedure SetDxBtnAction(AAction: TAction; ADxBtn: TObject);
  21. {DataBase Rela}
  22. function GetsdDataSetNewID(ADataSet: TsdDataSet; const AIndex: string): Integer;
  23. procedure ExecuteSql(AConnection: TADOConnection; const ASql: string);
  24. function QueryData(AConnection: TADOConnection; const ASql: string): TADOQuery;
  25. {Message}
  26. procedure WarningMessage(const AMsg: string; AHandle: THandle = 0);
  27. procedure ErrorMessage(const AMsg: string; AHandle: THandle = 0);
  28. function QuestMessage(const AMsg: string; AHandle: THandle = 0): Boolean;
  29. function QuestMessageYesNo(const AMsg: string; AHandle: THandle = 0): Boolean;
  30. procedure TipMessage(const AMsg: string; AHandle: THandle = 0);
  31. procedure DataSetErrorMessage(var Allow: Boolean; const AMsg: string);
  32. {Get Common Path}
  33. function GetAppFilePath: string;
  34. function GetMyProjectsFilePath: string;
  35. function GetEmptyDataBaseFileName: string;
  36. function GetTemplateBillsFileName: string;
  37. function GetTemplateXlsFileName: string;
  38. function GetBackupFilePath: string;
  39. function GetReportTemplatePath: string;
  40. function GetAppTempPath: string;
  41. {Select & Save File Choose}
  42. function GetFilter(AExt: string): string;
  43. function SelectFile(var AFileName: string; const AExt: string): Boolean;
  44. function SelectFiles(AFiles: TStrings; const AExt: string): Boolean;
  45. function SaveFile(var FileName: string; const AExt: string): Boolean;
  46. function SelectExcelFile(var AFileName: string): Boolean;
  47. function SaveExcelFile(var FileName: string): Boolean;
  48. function SelectOutputDirectory(const ATitle: string; var ADirectory: string;
  49. AParentHandle: THandle = 0; AHasNewFolderBtn: Boolean = True): Boolean;
  50. function FixPathByAppPath(AFileName: string): string;
  51. function BrowseFolder(var APath: string; const ATitle: string;
  52. AParentHandle: THandle; AHasNewFolderBtn: Boolean = True): Boolean;
  53. {CheckStrings}
  54. function CheckPeg(const AStr: string): Boolean;
  55. function CheckValidPassword(APassword: string): Boolean;
  56. function ValidInteger(var AKey: Char): Boolean;
  57. function TrimInvalidChar(const AText: string): string;
  58. {MergeStrings}
  59. function MergeRelaBGL(const ABGLCode1, ABGLCode2: string): string;
  60. procedure MergeRelaBGLAndNum(var ABGLCode1, ABGLNum1: string; const ABGLCode2, ABGLNum2: string);
  61. {CodeTransform}
  62. function B_CodeToIndexCode(const AB_Code: string): string;
  63. function ChinessNum(const ADigitNum: Integer): string;
  64. function Num2Peg(ANum: Double): string;
  65. {Compare Code}
  66. //function CompareCodeWithChar(const ACode1, ACode2: string): Integer;
  67. {Tree Relative}
  68. function CreateTree: TZjIDTree;
  69. procedure DisConnectTree(ATree: TZjIDTree);
  70. procedure ConnectTree(ATree: TZjIDTree; ADataset: TDataSet);
  71. procedure InitGridHead(AGridDBA: TZjGridDBA; AGrid: TZJGrid);
  72. {Generate Name/Directory/Path}
  73. function GetTempFileDir: string;
  74. function GetTempFilePath: string;
  75. function GetTempName(ALength: Integer = 8): string;
  76. function GetTempFileName: string; overload;
  77. function GetTempFileName(const APath, AExt: string): string; overload;
  78. function GenerateTempFolder(AGeneratePath: string): string;
  79. function GetNewGUIDFileName(const AGeneratePath: string): string;
  80. function GetMacAddr: string;
  81. {Progress bar Control}
  82. procedure UpdateSysProgress(APosition: Integer; const AHint: string);
  83. procedure UpdateProgress(APosition: Integer; const AHint: string);
  84. procedure DisableSysProgress;
  85. procedure EnableSysProgress;
  86. {Interface RePaint Control}
  87. procedure BeginUpdateWindow(AHandle: THandle);
  88. procedure EndUpdateWindow(AHandle: THandle);
  89. {Zip}
  90. procedure ZipFolder(AFileFolder, AFileName: string; ACheckMode: Integer = 0);
  91. function UnZipFile(AFileName, AFileFolder: string): Boolean;
  92. {Copy By Stream}
  93. procedure CopyFileByStream(const ASourceFile, ADestFile: string);
  94. procedure AppendTestLog(const AFileName, ALog: string);
  95. // From here, Add by chenshilong, 2014-04-11
  96. function GetVersion(APartCount: Integer = 4): string;
  97. function ExtractFileNameWithoutExt(const AFileName: string): string;
  98. function ShortText(AText: string; AWidth: Integer): string; // 文本缩略显示
  99. function CustomWidthText(AText: string; AWidth: Integer): string;
  100. function ReplaceCharsForJson(AText: string): string; // 替换Json文本中的特殊字符
  101. function RecoverCharsFromJson(AText: string): string; // 下载得到的Json文本恢复成用户需要的文本
  102. procedure FindFiles(APath, AExtName: string; AFileList: TStrings);
  103. function DeleteFolder(const FolderStr: string): Boolean;
  104. function HasExt(const AFileName: string): Boolean;
  105. function CopyFolder(const SrcFolder, DstFolder: string): Boolean;
  106. function FileCount(APath, AExt: string): Integer;
  107. function ChangeExt(AFile, ANewExt: string): string;
  108. function CheckExt(AName, AExt: string): string;
  109. function TempName(ALength: Integer): string;
  110. function URLFileName(AURL: string): string;
  111. function ReplaceChars(AStr: string): string;
  112. implementation
  113. uses
  114. SysUtils, dxBar, MainFrm, ConstUnit, Globals, StdCtrls, ShellAPI;
  115. var
  116. SysProgressDisabled: Boolean;
  117. function TickCount: Integer;
  118. begin
  119. Result := GetTickCount;
  120. end;
  121. {RoundTo}
  122. function InnerRoundTo(const AValue: Extended; const ADigit: Integer; RoundMode: TRoundMode): Extended;
  123. var
  124. LFactor, Offset, HFactor: Extended;
  125. begin
  126. LFactor := IntPower(10, ADigit);
  127. HFactor := IntPower(10, abs(ADigit));
  128. Result := AValue;
  129. case RoundMode of
  130. rmNearest:
  131. begin
  132. if AValue >= 0 then
  133. Offset := 0.5
  134. else
  135. Offset := -0.5;
  136. Result := Trunc((AValue * HFactor) + Offset) * LFactor;
  137. end;
  138. rmUP:
  139. begin
  140. if Frac(AValue / LFactor) > 0 then
  141. Result := Trunc(AValue * HFactor + 1) * LFactor
  142. else
  143. Result := Trunc(AValue * HFactor) * LFactor;
  144. end;
  145. rmDown:
  146. begin
  147. Result := Trunc(AValue * HFactor) * LFactor;
  148. end;
  149. end;
  150. end;
  151. function GetCompareDigitValue(ADigit: Integer): Double;
  152. begin
  153. if ADigit > 0 then
  154. Result := IntPower(10, - ADigit - 1)
  155. else
  156. Result := 0.1;
  157. end;
  158. function QuantityRoundTo(AValue: Double): Double;
  159. begin
  160. if Assigned(OpenProjectManager.CurProjectData) then
  161. Result := CommonRoundTo(AValue, -OpenProjectManager.CurProjectData.ProjProperties.QuantityDigit)
  162. else
  163. Result := CommonRoundTo(AValue, iQuantityDigit);
  164. end;
  165. function PriceRoundTo(AValue: Double): Double;
  166. begin
  167. if Assigned(OpenProjectManager.CurProjectData) then
  168. Result := CommonRoundTo(AValue, -OpenProjectManager.CurProjectData.ProjProperties.PriceDigit)
  169. else
  170. Result := CommonRoundTo(AValue, iPriceDigit);
  171. end;
  172. function TotalPriceRoundTo(AValue: Double): Double;
  173. begin
  174. if Assigned(OpenProjectManager.CurProjectData) then
  175. Result := CommonRoundTo(AValue, -OpenProjectManager.CurProjectData.ProjProperties.TotalPriceDigit)
  176. else
  177. Result := CommonRoundTo(AValue, iTotalPriceDigit);
  178. end;
  179. function GetTrueDigit(AValue: Double): Integer;
  180. const
  181. sFormat12 = '0.############';
  182. var
  183. sValue, sDigitValue: string;
  184. iPointPos: Integer;
  185. begin
  186. sValue := FormatFloat(sFormat12, AValue);
  187. iPointPos := Pos('.', sValue);
  188. Result := Min(0, -(Length(sValue) - iPointPos));
  189. end;
  190. function CommonRoundTo(AValue: Double; ADigit: Integer; RoundMode: TRoundMode = rmNearest): Double;
  191. var
  192. X: Double;
  193. P: Pointer;
  194. I: Integer;
  195. Buf: array [0..7] of Byte;
  196. begin
  197. P := @AValue;
  198. CopyMemory(@Buf[0], P, SizeOf(AValue));
  199. // 进位处理,从后往前,如果当前byte为$FF,则往前一byte进1
  200. // 注意到尾数开始的位置停止
  201. // 这里说的前后是二进制串,实际存储前后相反
  202. for I := 0 to 6 do
  203. if (I < 6) and (Buf[I] = $FF) then
  204. Buf[I] := 0
  205. else
  206. begin
  207. Buf[I] := Buf[I] + 1;
  208. Break;
  209. end;
  210. P := @X;
  211. CopyMemory(P, @Buf[0], SizeOf(X));
  212. if (ADigit <= -6) and (ADigit < GetTrueDigit(AValue)) then
  213. Result := AValue
  214. else
  215. Result := InnerRoundTo(X, ADigit, RoundMode);
  216. end;
  217. function CommonCalcRoundTo(AValue: Double): Double;
  218. begin
  219. Result := CommonRoundTo(AValue, -10);
  220. end;
  221. {Interface Control}
  222. procedure AlignControl(AControl, AParent: TWinControl; AAlign: TAlign);
  223. begin
  224. if Assigned(AControl) then
  225. begin
  226. if Assigned(AControl.Parent) then
  227. AControl.Parent.RemoveControl(AControl);
  228. AControl.Parent := AParent;
  229. AControl.Align := AAlign;
  230. end;
  231. end;
  232. procedure SetDxBtnAction(AAction: TAction; ADxBtn: TObject);
  233. begin
  234. if Assigned(ADxBtn) then
  235. if ADxBtn is TdxBarButton then
  236. TdxBarButton(ADxBtn).Action := AAction;
  237. end;
  238. {DataBase Rela}
  239. function GetsdDataSetNewID(ADataSet: TsdDataSet; const AIndex: string): Integer;
  240. var
  241. idx: TsdIndex;
  242. begin
  243. idx := ADataSet.FindIndex(AIndex);
  244. if idx.RecordCount > 0 then
  245. Result := idx.Records[idx.RecordCount - 1].ValueByName('ID').AsInteger + 1
  246. else
  247. Result := 1;
  248. end;
  249. procedure ExecuteSql(AConnection: TADOConnection; const ASql: string);
  250. var
  251. vQuery: TADOQuery;
  252. begin
  253. vQuery := TADOQuery.Create(nil);
  254. try
  255. vQuery.Connection := AConnection;
  256. vQuery.SQL.Add(ASql);
  257. vQuery.ExecSQL;
  258. finally
  259. vQuery.Free;
  260. end;
  261. end;
  262. function QueryData(AConnection: TADOConnection; const ASql: string): TADOQuery;
  263. begin
  264. Result := TADOQuery.Create(nil);
  265. Result.Connection := AConnection;
  266. Result.SQL.Clear;
  267. Result.SQL.Add(ASql);
  268. Result.Open;
  269. end;
  270. {Message}
  271. function GetValidHandle(AHandle: THandle = 0): THandle;
  272. begin
  273. if AHandle = 0 then
  274. begin
  275. if (Screen.ActiveForm <> nil) and (Screen.ActiveForm.HandleAllocated) then
  276. Result := Screen.ActiveForm.Handle
  277. else
  278. Result := Application.Handle;
  279. end
  280. else
  281. Result := AHandle;
  282. end;
  283. procedure WarningMessage(const AMsg: string; AHandle: THandle = 0);
  284. begin
  285. MessageBox(GetValidHandle(AHandle), PChar(AMsg), PChar('警告'), MB_OK or MB_ICONWARNING);
  286. end;
  287. procedure ErrorMessage(const AMsg: string; AHandle: THandle = 0);
  288. begin
  289. MessageBox(GetValidHandle(AHandle), PChar(AMsg), PChar('错误'), MB_OK or MB_ICONERROR);
  290. end;
  291. function QuestMessage(const AMsg: string; AHandle: THandle = 0): Boolean;
  292. begin
  293. Result := MessageBox(GetValidHandle(AHandle), PChar(AMsg), PChar('询问'), MB_OKCANCEL or MB_ICONQUESTION) = IDOK;
  294. end;
  295. function QuestMessageYesNo(const AMsg: string; AHandle: THandle = 0): Boolean;
  296. begin
  297. Result := MessageBox(GetValidHandle(AHandle), PChar(AMsg), PChar('询问'), MB_YESNO or MB_ICONQUESTION) = IDYes;
  298. end;
  299. procedure TipMessage(const AMsg: string; AHandle: THandle = 0);
  300. begin
  301. MessageBox(GetValidHandle(AHandle), PChar(AMsg), PChar('提示'), MB_OK or MB_ICONINFORMATION);
  302. end;
  303. procedure DataSetErrorMessage(var Allow: Boolean; const AMsg: string);
  304. begin
  305. Allow := False;
  306. ErrorMessage(AMsg);
  307. end;
  308. {Get Common Path}
  309. function GetAppFilePath: string;
  310. begin
  311. Result := ExtractFilePath(ParamStr(0));
  312. end;
  313. function GetMyProjectsFilePath: string;
  314. begin
  315. Result := GetAppFilePath + '我的项目\';
  316. end;
  317. function GetEmptyDataBaseFileName: string;
  318. begin
  319. Result := GetAppFilePath + 'Data\Base.dat';
  320. end;
  321. function GetTemplateBillsFileName: string;
  322. begin
  323. Result := GetAppFilePath + 'Data\Template.xls';
  324. end;
  325. function GetTemplateXlsFileName: string;
  326. begin
  327. Result := GetAppFilePath + 'Data\Basic.xls';
  328. end;
  329. function GetBackupFilePath: string;
  330. begin
  331. Result := GetAppFilePath + 'TenderBackup\';
  332. end;
  333. function GetReportTemplatePath: string;
  334. begin
  335. Result := GetAppFilePath + 'ReportTemplates\';
  336. end;
  337. function GetAppTempPath: string;
  338. begin
  339. Result := GetAppFilePath + 'Temp\';
  340. if not DirectoryExists(Result) then
  341. CreateDirectoryInDeep(Result);
  342. end;
  343. {Select & Save File Choose}
  344. function GetFilter(AExt: string): string;
  345. begin
  346. if AExt = '' then
  347. Result := '所有文件(*.*)|*.*'
  348. else
  349. begin
  350. if AExt[1] <> '.' then
  351. AExt := '.' + AExt;
  352. Result := Format('(*%s)|*%s', [AExt, AExt]);
  353. end;
  354. end;
  355. function SelectFile(var AFileName: string; const AExt: string): Boolean;
  356. var
  357. odFile: TOpenDialog;
  358. begin
  359. odFile := TOpenDialog.Create(nil);
  360. try
  361. odFile.Filter := GetFilter(AExt);
  362. if odFile.Execute then
  363. begin
  364. Application.ProcessMessages;
  365. AFileName := odFile.FileName;
  366. Result := True;
  367. end
  368. else
  369. Result := False;
  370. finally
  371. odFile.Free;
  372. end;
  373. end;
  374. function SelectFiles(AFiles: TStrings; const AExt: string): Boolean;
  375. var
  376. odFile: TOpenDialog;
  377. begin
  378. odFile := TOpenDialog.Create(nil);
  379. try
  380. odFile.Options := odFile.Options + [ofAllowMultiSelect];
  381. odFile.Filter := GetFilter(AExt);
  382. if odFile.Execute then
  383. begin
  384. Application.ProcessMessages;
  385. AFiles.Assign(odFile.Files);
  386. Result := True;
  387. end
  388. else
  389. Result := False;
  390. finally
  391. odFile.Free;
  392. end;
  393. end;
  394. function SaveFile(var FileName: string; const AExt: string): Boolean;
  395. var
  396. sdFile: TSaveDialog;
  397. begin
  398. sdFile := TSaveDialog.Create(nil);
  399. try
  400. sdFile.FileName := FileName;
  401. sdFile.DefaultExt := AExt;
  402. sdFile.Filter := GetFilter(AExt);
  403. Result := sdFile.Execute;
  404. if Result then
  405. FileName := sdFile.FileName;
  406. Application.ProcessMessages;
  407. finally
  408. sdFile.Free;
  409. end;
  410. end;
  411. function SelectExcelFile(var AFileName: string): Boolean;
  412. var
  413. odFile: TOpenDialog;
  414. begin
  415. odFile := TOpenDialog.Create(nil);
  416. try
  417. odFile.Filter := 'Excel文件(*.xls)|*.xls;|Excel文件(*.xlsx)|*.xlsx;';
  418. if odFile.Execute then
  419. begin
  420. Application.ProcessMessages;
  421. AFileName := odFile.FileName;
  422. Result := True;
  423. end
  424. else
  425. Result := False;
  426. finally
  427. odFile.Free;
  428. end;
  429. end;
  430. function SaveExcelFile(var FileName: string): Boolean;
  431. function CheckFileName(AFileName: string; AExt: string): string;
  432. begin
  433. if SameText(ExtractFileExt(AFileName), AExt) then
  434. Result := AFileName
  435. else
  436. Result := ExtractFilePath(AFileName) + ExtractFileName(AFileName) + AExt;
  437. end;
  438. var
  439. sdFile: TSaveDialog;
  440. begin
  441. sdFile := TSaveDialog.Create(nil);
  442. try
  443. sdFile.FileName := FileName;
  444. sdFile.Filter := 'Excel文件(*.xls)|*.xls;|Excel文件(*.xlsx)|*.xlsx;';
  445. Result := sdFile.Execute;
  446. if Result then
  447. begin
  448. case sdFile.FilterIndex of
  449. 1: FileName := CheckFileName(sdFile.FileName, '.xls');
  450. 2: FileName := CheckFileName(sdFile.FileName, '.xlsx');
  451. end;
  452. end;
  453. finally
  454. sdFile.Free;
  455. end;
  456. end;
  457. function SelectOutputDirectory(const ATitle: string; var ADirectory: string;
  458. AParentHandle: THandle; AHasNewFolderBtn: Boolean): Boolean;
  459. var
  460. pID: PItemIDList;
  461. bInfo: TBrowseInfo;
  462. AHandle: THandle;
  463. PStr: array[0..1023] of Char;
  464. sPath: string;
  465. function BFCallBack(Hwnd: HWND; uMsg: UINT; lParam, lpData: LPARAM): Integer; stdcall;
  466. begin
  467. if uMsg = BFFM_INITIALIZED then
  468. begin
  469. SendMessage(Hwnd, BFFM_SETSELECTION, 1, lpData);
  470. end;
  471. Result := 0;
  472. end;
  473. begin
  474. Result := False;
  475. if AParentHandle = 0 then
  476. AHandle := Screen.ActiveForm.Handle
  477. else
  478. AHandle := AParentHandle;
  479. if ADirectory = '' then
  480. sPath := GetAppFilePath
  481. else
  482. sPath := ADirectory;
  483. with bInfo do
  484. begin
  485. hwndOwner := AParentHandle;
  486. iImage := 0;
  487. lParam := Integer(PChar(sPath));
  488. lpszTitle := PChar(ATitle);
  489. pidlRoot := nil;
  490. pszDisplayName := nil;
  491. if AHasNewFolderBtn then
  492. ulFlags := BIF_RETURNONLYFSDIRS or BIF_USENEWUI
  493. else
  494. ulFlags := BIF_RETURNONLYFSDIRS;
  495. lpfn := @BFCallBack;
  496. end;
  497. pID := SHBrowseForFolder(bInfo);
  498. if pID <> nil then
  499. begin
  500. SHGetPathFromIDList(pID, PStr);
  501. ADirectory := StrPas(PStr);
  502. if (ADirectory <> '') and (ADirectory[Length(ADirectory)] <> '\') then
  503. ADirectory := ADirectory + '\';
  504. Result := True;
  505. end;
  506. end;
  507. function FixPathByAppPath(AFileName: string): string;
  508. begin
  509. Result := AFileName;
  510. if AnsiPos(':\', Result) = 0 then
  511. begin
  512. if (Result <> '') and (Result[1] = '\') then
  513. Delete(Result, 1, 1);
  514. Result := ExtractFilePath(Application.ExeName) + Result;
  515. end;
  516. end;
  517. var
  518. PathStr: string;
  519. function BrowseFolder(var APath: string; const ATitle: string; AParentHandle: THandle;
  520. AHasNewFolderBtn: Boolean): Boolean;
  521. function BFCallBackFunc(hwnd: HWND; uMsg: UINT; lParam: LPARAM; lpData: LPARAM): Integer; stdcall;
  522. begin
  523. Result := 0;
  524. case uMsg of
  525. BFFM_INITIALIZED : // 初始化设置目录。
  526. begin
  527. SendMessage(Hwnd,BFFM_SETSELECTION,-1,Integer(PathStr));
  528. end;
  529. end;
  530. end;
  531. var
  532. pID: PItemIDList;
  533. bInfo: TBrowseInfo;
  534. PStr: array[0..1023] of Char;
  535. sPath: string;
  536. Hdl: THandle;
  537. begin
  538. Result := False;
  539. PathStr := '';
  540. if AParentHandle = 0 then
  541. Hdl := Screen.ActiveForm.Handle
  542. else
  543. Hdl := AParentHandle;
  544. sPath := FixPathByAppPath(APath);
  545. if DirectoryExists(sPath) then
  546. PathStr := sPath;
  547. bInfo.hwndOwner := Hdl;
  548. bInfo.iImage := 0;
  549. bInfo.lParam := 0;
  550. bInfo.lpszTitle := PChar(ATitle);
  551. bInfo.pidlRoot := nil;
  552. bInfo.pszDisplayName := nil;
  553. if (not AHasNewFolderBtn) then
  554. bInfo.ulFlags := BIF_RETURNONLYFSDIRS
  555. else
  556. bInfo.ulFlags := BIF_RETURNONLYFSDIRS or BIF_USENEWUI;
  557. bInfo.lpfn := @BFCallBackFunc;
  558. pID := SHBrowseForFolder(bInfo);
  559. if pID <> nil then
  560. begin
  561. SHGetPathFromIDList(pID,pStr);
  562. APath := StrPas(pStr);
  563. if (APath <> '') and (APath[Length(APath)] <> '\') then
  564. APath := APath + '\';
  565. Result := True;
  566. end;
  567. end;
  568. {CheckStrings}
  569. function CheckPeg(const AStr: string): Boolean;
  570. function GetPosition(const AName, AStr, AStrSpare: string): Integer;
  571. begin
  572. Result := Pos(AStr, AName);
  573. if Result = 0 then
  574. Result := Pos(AStrSpare, AName);
  575. end;
  576. function CheckPlusPeg(const AStr: string): Boolean;
  577. var
  578. iPosK, iPosPlus: Integer;
  579. fNum: Double;
  580. begin
  581. Result := False;
  582. iPosK := GetPosition(AStr, 'K', 'k');
  583. iPosPlus := GetPosition(AStr, '+', '+');
  584. if (iPosK = 0) or (iPosPlus = 0) or (iPosPlus < iPosK) then Exit;
  585. Result := TryStrToFloat(Copy(AStr, iPosK + 1, iPosPlus - iPosK - 1), fNum) and (fNum >= 0);
  586. end;
  587. // K0-134.5 pass; k-2-134.5 fail;
  588. function CheckMinusPeg(const AStr: string): Boolean;
  589. var
  590. iPosK, iPosMinus: Integer;
  591. fNum: Double;
  592. begin
  593. Result := False;
  594. iPosK := GetPosition(AStr, 'K', 'k');
  595. iPosMinus := GetPosition(AStr, '-', '-');
  596. if (iPosK = 0) or (iPosMinus = 0) or (iPosMinus <= iPosK) then Exit;
  597. Result := TryStrToFloat(Copy(AStr, iPosK + 1, iPosMinus - iPosK - 1), fNum) and (fNum <= 0);
  598. end;
  599. begin
  600. Result := CheckPlusPeg(AStr) or CheckMinusPeg(AStr);
  601. end;
  602. function CheckValidPassword(APassword: string): Boolean;
  603. var
  604. iIndex, iLength: Integer;
  605. begin
  606. Result := True;
  607. if APassword = '' then Exit;
  608. iIndex := 1;
  609. iLength := Length(APassword);
  610. Result := (iLength >= 6) and (iLength <= 16);
  611. while Result and (iIndex < iLength) do
  612. begin
  613. Result := APassword[iIndex] in ['A'..'Z', 'a'..'z', '0'..'9'];
  614. Inc(iIndex);
  615. end;
  616. end;
  617. function ValidInteger(var AKey: Char): Boolean;
  618. begin
  619. if AKey in ['+', '-', '0'..'9', #8, #13, #35, #36,
  620. #37, #38, #39, #40, #46] then
  621. begin
  622. Result := True;
  623. end
  624. else
  625. begin
  626. AKey := #0;
  627. Result := False;
  628. end;
  629. end;
  630. function TrimInvalidChar(const AText: string): string;
  631. var
  632. i, iLength: Integer;
  633. begin
  634. Result := '';
  635. iLength := Length(AText);
  636. for i := 1 to iLength do
  637. begin
  638. if not (AText[i] in [#0]) then
  639. Result := Result + AText[i];
  640. end;
  641. end;
  642. {MergeStrings}
  643. function MergeRelaBGL(const ABGLCode1, ABGLCode2: string): string;
  644. var
  645. sgs1, sgs2: TStrings;
  646. i1, i2: Integer;
  647. bExist: Boolean;
  648. begin
  649. Result := ABGLCode1;
  650. sgs1 := TStringList.Create;
  651. sgs2 := TStringList.Create;
  652. try
  653. sgs1.Delimiter := ';';
  654. sgs2.Delimiter := ';';
  655. sgs1.DelimitedText := ABGLCode1;
  656. sgs2.DelimitedText := ABGLCode2;
  657. for i2 := 0 to sgs2.Count - 1 do
  658. begin
  659. bExist := False;
  660. for i1 := 0 to sgs1.Count - 1 do
  661. if SameText(sgs2[i2], sgs1[i1]) then
  662. begin
  663. bExist := True;
  664. Break;
  665. end;
  666. if not bExist then
  667. sgs1.Add(sgs2[i2]);
  668. end;
  669. Result := sgs1.DelimitedText;
  670. finally
  671. sgs1.Free;
  672. sgs2.Free;
  673. end;
  674. end;
  675. procedure MergeRelaBGLAndNum(var ABGLCode1, ABGLNum1: string; const ABGLCode2, ABGLNum2: string);
  676. var
  677. sgsC1, sgsC2, sgsN1, sgsN2: TStrings;
  678. i1, i2: Integer;
  679. bExist: Boolean;
  680. begin
  681. sgsC1 := TStringList.Create;
  682. sgsC2 := TStringList.Create;
  683. sgsN1 := TStringList.Create;
  684. sgsN2 := TStringList.Create;
  685. try
  686. sgsC1.Delimiter := ';';
  687. sgsC2.Delimiter := ';';
  688. sgsC1.DelimitedText := ABGLCode1;
  689. sgsC2.DelimitedText := ABGLCode2;
  690. sgsN1.Delimiter := ';';
  691. sgsN2.Delimiter := ';';
  692. sgsN1.DelimitedText := ABGLNum1;
  693. sgsN2.DelimitedText := ABGLNum2;
  694. for i2 := 0 to sgsC2.Count - 1 do
  695. begin
  696. bExist := False;
  697. for i1 := 0 to sgsC1.Count - 1 do
  698. if SameText(sgsC2[i2], sgsC1[i1]) then
  699. begin
  700. bExist := True;
  701. Break;
  702. end;
  703. if bExist then
  704. begin
  705. sgsN1[i1] := FloatToStr(StrToFloatDef(sgsN1[i1], 0) + StrToFloatDef(sgsN2[i2], 0))
  706. end
  707. else
  708. begin
  709. sgsC1.Add(sgsC2[i2]);
  710. sgsN1.Add(sgsN2[i2]);
  711. end;
  712. end;
  713. ABGLCode1 := sgsC1.DelimitedText;
  714. ABGLNum1 := sgsN1.DelimitedText;
  715. finally
  716. sgsC1.Free;
  717. sgsC2.Free;
  718. sgsN1.Free;
  719. sgsN2.Free;
  720. end;
  721. end;
  722. function B_CodeToIndexCode(const AB_Code: string): string;
  723. procedure Filter(const AStr: string; var ANum, AError: Integer);
  724. var
  725. i: Integer;
  726. sPart: string;
  727. begin
  728. sPart := '';
  729. AError := 0;
  730. for i := 1 to Length(AStr) do
  731. begin
  732. if AStr[i] in ['0'..'9'] then
  733. begin
  734. sPart := sPart + AStr[i];
  735. end
  736. else
  737. begin
  738. AError := i;
  739. Break;
  740. end;
  741. end;
  742. ANum := StrToIntDef(sPart, 0);
  743. end;
  744. var
  745. sgs: TStrings;
  746. i, iNum, iError: Integer;
  747. sError: string;
  748. begin
  749. sgs := TStringList.Create;
  750. try
  751. Result := '';
  752. sgs.Delimiter := '-';
  753. sgs.DelimitedText := AB_Code;
  754. for i := 0 to sgs.Count - 1 do
  755. begin
  756. Filter(sgs[i], iNum, iError);
  757. if iError = 0 then
  758. sError := ''
  759. else
  760. sError := Copy(sgs[i], iError, Length(sgs[i])-iError+1);
  761. if iError = 0 then
  762. Result := Result + Format('%4d', [iNum]) + Format('%-4s', [sError])
  763. else if iNum = 0 then
  764. Result := Result + '9999' + Format('%-4s', [sError])
  765. else
  766. Result := Result + Format('%4d', [iNum]) + Format('%-4s', [sError]);
  767. end;
  768. finally
  769. sgs.Free;
  770. end;
  771. end;
  772. function ChinessNum(const ADigitNum: Integer): string;
  773. function TransChineseNum(const ANum, AZeroNum: Integer): string;
  774. begin
  775. Result := '';
  776. case ANum of
  777. 1: if AZeroNum <> 1 then Result := '一';
  778. 2: Result := '二';
  779. 3: Result := '三';
  780. 4: Result := '四';
  781. 5: Result := '五';
  782. 6: Result := '六';
  783. 7: Result := '七';
  784. 8: Result := '八';
  785. 9: Result := '九';
  786. end;
  787. if (Result = '') and ((AZeroNum <> 1) or (ANum = 0)) then Exit;
  788. case AZeroNum of
  789. 0: Result := Result;
  790. 1: Result := Result + '十';
  791. 2: Result := Result + '百';
  792. 3: Result := Result + '千';
  793. 4: Result := Result + '万';
  794. end;
  795. end;
  796. var
  797. iBai, iShi, iGe: Integer;
  798. begin
  799. Result := '';
  800. if (ADigitNum < 0) and (ADigitNum > 10000) then Exit;
  801. iBai := ADigitNum div 100;
  802. iShi := (ADigitNum mod 100) div 10;
  803. iGe := (ADigitNum mod 100) mod 10;
  804. Result := TransChineseNum(iBai, 2) + TransChineseNum(iShi, 1) + TransChineseNum(iGe, 0);
  805. end;
  806. function CheckDigit(ANum: Double): Integer;
  807. begin
  808. if abs(ANum - advRoundTo(ANum, -2)) > 0.0001 then
  809. Result := 3
  810. else if abs(ANum - advRoundTo(ANum, -1)) > 0.001 then
  811. Result := 2
  812. else if abs(ANum - AdvRoundTo(ANum, 0)) > 0.01 then
  813. Result := 1
  814. else
  815. Result := 0;
  816. end;
  817. function Num2Peg(ANum: Double): string;
  818. var
  819. fMod: Double;
  820. iK, iDigit: Integer;
  821. sDigit: string;
  822. begin
  823. iK := Trunc(ANum/1000);
  824. fMod := Frac(ANum/1000)*1000;
  825. iDigit := CheckDigit(fMod);
  826. case iDigit of
  827. 3: sDigit := FormatFloat('000.000', AdvRoundTo(fMod, -3));
  828. 2: sDigit := FormatFloat('000.00', AdvRoundTo(fMod, -2));
  829. 1: sDigit := FormatFloat('000.0', AdvRoundTo(fMod, -1));
  830. 0: sDigit := FormatFloat('000', Trunc(AdvRoundTo(fMod, 0)));
  831. end;
  832. { case iDigit of
  833. 3: Result := Format('K%d+%3.3f', [iK, ]);
  834. 2: Result := Format('K%d+%3.2f', [iK, AdvRoundTo(fMod, -2)]);
  835. 1: Result := Format('K%d+%3.1f', [iK, AdvRoundTo(fMod, -1)]);
  836. 0: Result := Format('K%d+%s', [iK, FormatFloat('000', [])]);
  837. end; }
  838. Result := Format('K%d+%s', [iK, sDigit]);
  839. end;
  840. {Tree Relative}
  841. function CreateTree: TZjIDTree;
  842. begin
  843. Result := TZjIDTree.Create;
  844. Result.KeyFieldName := 'ID';
  845. Result.ParentFieldName := 'ParentID';
  846. Result.NextSiblingFieldName := 'NextSiblingID';
  847. Result.AutoCreateKeyID := True;
  848. Result.AutoExpand := True;
  849. end;
  850. procedure DisConnectTree(ATree: TZjIDTree);
  851. begin
  852. ATree.DataSet := nil;
  853. ATree.Active := False;
  854. end;
  855. procedure ConnectTree(ATree: TZjIDTree; ADataset: TDataSet);
  856. begin
  857. ATree.DataSet := ADataset;
  858. ATree.Active := True;
  859. end;
  860. procedure InitGridHead(AGridDBA: TZjGridDBA; AGrid: TZJGrid);
  861. var
  862. I: Integer;
  863. begin
  864. for I := 0 to AGridDBA.Columns.Count - 1 do
  865. AGrid.Cells[I + 1, 0].Text := AGridDBA.Columns[I].Title.Caption;
  866. end;
  867. {Generate Name/Path}
  868. function GetTempFileDir: string;
  869. var
  870. TempPath: string;
  871. begin
  872. TempPath := GetEnvironmentVariable('TMP');
  873. if TempPath = '' then
  874. TempPath := GetEnvironmentVariable('TEMP');
  875. if TempPath = '' then
  876. begin
  877. if not DirectoryExists(ExtractFileDir(ParamStr(0)) + '\Temp') then
  878. CreateDir(ExtractFileDir(ParamStr(0)) + '\Temp');
  879. TempPath := ExtractFileDir(ParamStr(0)) + '\Temp';
  880. end;
  881. Result := TempPath;
  882. end;
  883. function GetTempFilePath: string;
  884. begin
  885. //Result := GetTempFileDir + '\';
  886. Result := GetAppTempPath;
  887. end;
  888. function GetTempName(ALength: Integer): string;
  889. const
  890. CodedBuf: array[0..35] of Char = ('0', '1', '2', '3', '4', '5',
  891. '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I',
  892. 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V',
  893. 'W', 'X', 'Y', 'Z');
  894. var
  895. Temp: string;
  896. Num: Integer;
  897. begin
  898. Randomize;
  899. Temp := '';
  900. while Length(Temp) < ALength do
  901. begin
  902. Num := Random(37);
  903. If Num <> 36 Then
  904. Temp := Temp + CodedBuf[Num]; // 0..35
  905. end;
  906. Result := Temp;
  907. end;
  908. function GetTempFileName: string;
  909. var
  910. TempExt: string;
  911. begin
  912. Result := GetTempFilePath + GetTempName;
  913. TempExt := '.' + GetTempName(3);
  914. while SameText(TempExt, '.mdb') or SameText(TempExt, '.db') or
  915. SameText(TempExt, '.ldb') do
  916. TempExt := '.' + GetTempName(3);
  917. Result := Result + TempExt;
  918. while FileExists(Result) do
  919. begin
  920. Result := GetTempFilePath + GetTempName;
  921. TempExt := '.' + GetTempName(3);
  922. while SameText(TempExt, '.mdb') or SameText(TempExt, '.db') or
  923. SameText(TempExt, '.ldb') do
  924. TempExt := '.' + GetTempName(3);
  925. Result := Result + TempExt;
  926. end;
  927. end;
  928. function GetTempFileName(const APath, AExt: string): string;
  929. begin
  930. Result := APath + GetTempName + AExt;
  931. while FileExists(Result) do
  932. Result := APath + GetTempName + AExt;
  933. end;
  934. function GenerateTempFolder(AGeneratePath: string): string;
  935. begin
  936. Result := AGeneratePath + GetTempName;
  937. while DirectoryExists(Result) do
  938. Result := AGeneratePath + GetTempName;
  939. CreateDirectoryInDeep(Result);
  940. end;
  941. function GetNewGUIDFileName(const AGeneratePath: string): string;
  942. var
  943. gFile: TGUID;
  944. begin
  945. repeat
  946. CreateGUID(gFile);
  947. Result := AGeneratePath + GUIDToString(gFile);
  948. until not FileExists(Result);
  949. end;
  950. function GetMacAddr: string;
  951. var
  952. sgs: TStrings;
  953. begin
  954. sgs := GetMacAddress;
  955. if (sgs.Count > 0) then
  956. Result := sgs[0]
  957. else
  958. Result := '';
  959. end;
  960. {Progress bar Control}
  961. procedure UpdateSysProgress(APosition: Integer; const AHint: string);
  962. begin
  963. if not SysProgressDisabled then
  964. UpdateProgress(APosition, AHint);
  965. end;
  966. procedure UpdateProgress(APosition: Integer; const AHint: string);
  967. begin
  968. MainForm.UpdateProgress(APosition, AHint);
  969. end;
  970. procedure DisableSysProgress;
  971. begin
  972. SysProgressDisabled := True;
  973. end;
  974. procedure EnableSysProgress;
  975. begin
  976. SysProgressDisabled := False;
  977. end;
  978. {Interface RePaint Control}
  979. procedure BeginUpdateWindow(AHandle: THandle);
  980. begin
  981. SendMessage(AHandle, WM_SETREDRAW, 0, 0);
  982. end;
  983. procedure EndUpdateWindow(AHandle: THandle);
  984. begin
  985. SendMessage(AHandle, WM_SETREDRAW, 1, 0);
  986. end;
  987. {Zip}
  988. function ZipComplete(const AFileName: string; ACheckMode: Integer): Boolean;
  989. const
  990. i4k = 4096;
  991. var
  992. iSize1, iSize2: Integer;
  993. begin
  994. iSize1 := FileSizeByName(AFileName);
  995. Sleep(300);
  996. iSize2 := FileSizeByName(AFileName);
  997. Result := (iSize1 = iSize2);
  998. if ACheckMode = 0 then
  999. Result := Result and (iSize1 > i4k);
  1000. end;
  1001. procedure ZipFolder(AFileFolder, AFileName: string; ACheckMode: Integer = 0);
  1002. procedure AppendLog(const ALog: string);
  1003. begin
  1004. if SupportManager.ConfigInfo.IsLog then
  1005. MeasureLog.AppendLogTo(ALog);
  1006. end;
  1007. var
  1008. sTempFile: string;
  1009. vZip: TVCLZip;
  1010. iCount: Integer;
  1011. begin
  1012. AppendLog('Zip');
  1013. sTempFile := GetTempFileName;
  1014. vZip := TVCLZip.Create(nil);
  1015. iCount := 0;
  1016. try
  1017. vZip.FilesList.Clear;
  1018. vZip.ZipName := sTempFile;
  1019. vzip.RootDir := AFileFolder;
  1020. vZip.OverwriteMode := Always;
  1021. //vZip.AddDirEntriesOnRecurse:=True;
  1022. vZip.RelativePaths := True;
  1023. //vZip.RecreateDirs := True;
  1024. vZip.FilesList.Add(AFileFolder + '\*.*');
  1025. vZip.Zip;
  1026. AppendLog(Format('Check Zip File, FileSize - %d', [FileSizeByName(sTempFile)]));
  1027. while not ZipComplete(sTempFile, ACheckMode) and (iCount < 10) do
  1028. begin
  1029. Sleep(200);
  1030. Inc(iCount);
  1031. AppendLog(Format('Check Zip File - %d, FileSize - %d', [iCount + 1, FileSizeByName(sTempFile)]));
  1032. end;
  1033. AppendLog('Check Zip File --> Pass');
  1034. CopyFileOrFolder(sTempFile, AFileName);
  1035. AppendLog('Zip --> Pass');
  1036. finally
  1037. vZip.Free;
  1038. if FileExists(sTempFile) then
  1039. DeleteFile(sTempFile);
  1040. end;
  1041. end;
  1042. function UnZipFile(AFileName, AFileFolder: string): Boolean;
  1043. var
  1044. vUnZip: TVCLZip;
  1045. begin
  1046. Result := True;
  1047. vUnZip := TVCLZip.Create(nil);
  1048. try
  1049. vUnZip.FilesList.Clear;
  1050. vUnZip.ZipName := AFileName;
  1051. vUnZip.ReadZip;
  1052. vUnZip.DestDir := AFileFolder;
  1053. vUnZip.OverwriteMode := Always;
  1054. vUnZip.RecreateDirs := True;
  1055. vUnZip.RelativePaths := True;
  1056. vUnZip.DoAll := True;
  1057. vUnZip.FilesList.Add('*.*');
  1058. try
  1059. vUnZip.UnZip;
  1060. except
  1061. Result := False;
  1062. end;
  1063. finally
  1064. vUnZip.Free;
  1065. end;
  1066. end;
  1067. {Copy By Stream}
  1068. procedure CopyFileByStream(const ASourceFile, ADestFile: string);
  1069. var
  1070. MS: TMemoryStream;
  1071. begin
  1072. MS := TMemoryStream.Create;
  1073. try
  1074. MS.LoadFromFile(ASourceFile);
  1075. if FileExists(ADestFile) then
  1076. DeleteFile(ADestFile);
  1077. MS.SaveToFile(ADestFile);
  1078. finally
  1079. MS.Free;
  1080. end;
  1081. end;
  1082. procedure AppendTestLog(const AFileName, ALog: string);
  1083. var
  1084. f: TextFile;
  1085. begin
  1086. try
  1087. if FileExists(AFileName) then
  1088. begin
  1089. AssignFile(f, AFileName);
  1090. Append(f);
  1091. Writeln(f, ALog);
  1092. end
  1093. else
  1094. begin
  1095. AssignFile(f, AFileName);
  1096. Rewrite(f);
  1097. Writeln(f, ALog);
  1098. end;
  1099. finally
  1100. CloseFile(f);
  1101. end;
  1102. end;
  1103. function GetVersion(APartCount: Integer = 4): string;
  1104. var
  1105. V1, V2, V3, V4: Word;
  1106. FInfoSize, FF: Cardinal;
  1107. FInfo: Pointer;
  1108. FFixed: PVSFIXEDFILEINFO;
  1109. begin
  1110. FInfoSize := GetFileVersionInfoSize(PChar(Application.ExeName), FF);
  1111. FInfo := AllocMem(FInfoSize);
  1112. try
  1113. GetFileVersionInfo(PChar(Application.ExeName), FF, FInfoSize, FInfo);
  1114. VerQueryValue(FInfo, '\', Pointer(FFixed), FInfoSize);
  1115. V1 := FFixed.dwFileVersionMS shr 16;
  1116. V2 := FFixed.dwFileVersionMS and $FFFF;
  1117. V3 := FFixed.dwFileVersionLS shr 16;
  1118. V4 := FFixed.dwFileVersionLS and $FFFF;
  1119. finally
  1120. Dispose(FInfo);
  1121. end;
  1122. Result := '';
  1123. case APartCount of
  1124. 1:
  1125. Result := Format('%d', [V1]);
  1126. 2:
  1127. Result := Format('%d.%d', [V1, V2]);
  1128. 3:
  1129. Result := Format('%d.%d.%d', [V1, V2, V3]);
  1130. 4:
  1131. Result := Format('%d.%d.%d.%d', [V1, V2, V3, V4]);
  1132. end;
  1133. end;
  1134. function ExtractFileNameWithoutExt(const AFileName: string): string;
  1135. var
  1136. sFileName, Ext: string;
  1137. begin
  1138. Result := '';
  1139. if AFileName = '' then
  1140. Exit;
  1141. sFileName := AFileName;
  1142. if sFileName[Length(sFileName)] = '\' then
  1143. Delete(sFileName, Length(sFileName), 1);
  1144. Result := ExtractFileName(sFileName);
  1145. Ext := ExtractFileExt(sFileName);
  1146. Delete(Result, Length(Result) - Length(Ext) + 1, Length(Ext));
  1147. end;
  1148. function ShortText(AText: string; AWidth: Integer): string;
  1149. var vMM: TMemo;
  1150. begin
  1151. if Trim(AText) = '' then
  1152. begin
  1153. Result := '';
  1154. Exit;
  1155. end;
  1156. vMM := TMemo.Create(nil);
  1157. try
  1158. vMM.Visible := False;
  1159. vMM.WordWrap := True;
  1160. vMM.parent := Application.MainForm;
  1161. vMM.Width := AWidth - 10; // 10像素留给3个小点
  1162. vMM.Text := AText;
  1163. if vMM.Lines.Count > 1 then
  1164. Result := vMM.Lines[0] + '...'
  1165. else
  1166. Result := AText;
  1167. finally
  1168. vMM.Free;
  1169. end;
  1170. end;
  1171. function CustomWidthText(AText: string; AWidth: Integer): string;
  1172. var vMM: TMemo;
  1173. i: Integer;
  1174. begin
  1175. if Trim(AText) = '' then
  1176. begin
  1177. Result := '';
  1178. Exit;
  1179. end;
  1180. vMM := TMemo.Create(nil);
  1181. try
  1182. vMM.Visible := False;
  1183. vMM.WordWrap := True;
  1184. vMM.parent := Application.MainForm;
  1185. vMM.Width := AWidth;
  1186. vMM.Text := AText;
  1187. for i := 0 to vMM.Lines.Count - 1 do
  1188. begin
  1189. if i = 0 then
  1190. Result := vMM.Lines[i]
  1191. else
  1192. Result := Result + #10#13 + vMM.Lines[i];
  1193. end;
  1194. finally
  1195. vMM.Free;
  1196. end;
  1197. end;
  1198. function ReplaceCharsForJson(AText: string): string;
  1199. const
  1200. BefChar: array [0..7] of Char = ('{', '}', ',', ':', '"', '[', ']', '%');
  1201. AftChar: array [0..7] of string = ('{', '}', ',', ':', '"', '【', '】', '♂');
  1202. var I: Integer;
  1203. begin
  1204. AText := Trim(AText);
  1205. Result := AText;
  1206. if AText = '' then Exit;
  1207. for I := low(BefChar) to High(BefChar) do
  1208. begin
  1209. if Pos(BefChar[I], AText) > 0 then
  1210. AText := StringReplace(AText, BefChar[I], AftChar[I], [rfReplaceAll]);
  1211. end;
  1212. Result := AText;
  1213. end;
  1214. function RecoverCharsFromJson(AText: string): string;
  1215. const
  1216. BefStr: array [0..3] of string = ('♂', '\r\n', '\r', '\n');
  1217. AftStr: array [0..3] of string = ('%', '', '', '');
  1218. var I: Integer;
  1219. begin
  1220. AText := Trim(AText);
  1221. Result := AText;
  1222. if AText = '' then Exit;
  1223. for I := low(BefStr) to High(BefStr) do
  1224. begin
  1225. if Pos(BefStr[I], AText) > 0 then
  1226. AText := StringReplace(AText, BefStr[I], AftStr[I], [rfReplaceAll]);
  1227. end;
  1228. Result := AText;
  1229. end;
  1230. procedure FindFiles(APath, AExtName: string; AFileList: TStrings);
  1231. var
  1232. SRec: TSearchRec;
  1233. retval: Integer;
  1234. begin
  1235. AFileList.Clear;
  1236. retval := FindFirst(APath + AExtName, faAnyFile, sRec);
  1237. try
  1238. while retval = 0 do
  1239. begin
  1240. if (SRec.Attr and faDirectory) = 0 then
  1241. AFileList.Add(Srec.Name);
  1242. retval := FindNext(SRec);
  1243. end;
  1244. finally
  1245. FindClose(SRec);
  1246. end;
  1247. end;
  1248. function DeleteFolder(const FolderStr: string): Boolean;
  1249. var
  1250. fos: SHFILEOPSTRUCT;
  1251. begin
  1252. ZeroMemory(@fos, SizeOf(fos));
  1253. fos.Wnd := HWND_DESKTOP;
  1254. fos.wFunc := FO_DELETE;
  1255. fos.fFlags := FOF_SILENT OR FOF_ALLOWUNDO OR FOF_NOCONFIRMATION;
  1256. fos.pFrom := PChar(FolderStr + #0);
  1257. Result := SHFileOperation(fos) <> 0;
  1258. end;
  1259. function HasExt(const AFileName: string): Boolean;
  1260. begin
  1261. Result := ExtractFileExt(AFileName) <> '';
  1262. end;
  1263. function CopyFolder(const SrcFolder, DstFolder: string): Boolean;
  1264. var
  1265. fos: SHFILEOPSTRUCT;
  1266. begin
  1267. ZeroMemory(@fos, SizeOf(fos));
  1268. fos.Wnd := HWND_DESKTOP;
  1269. fos.wFunc := FO_COPY;
  1270. fos.fFlags := FOF_SILENT OR FOF_ALLOWUNDO;
  1271. fos.pFrom := PChar(SrcFolder + #0);
  1272. fos.pTo := PChar(DstFolder + #0);
  1273. Result := SHFileOperation(fos) <> 0;
  1274. end;
  1275. function FileCount(APath, AExt: string): Integer;
  1276. var
  1277. vSR: TSearchRec;
  1278. iRetval: Integer;
  1279. vSL: TStringList;
  1280. begin
  1281. vSL := TStringList.Create;
  1282. iRetval := FindFirst(APath + '*' + AExt, faAnyFile, vSR);
  1283. try
  1284. while iRetval = 0 do
  1285. begin
  1286. if (vSR.Attr and faDirectory) = 0 then
  1287. vSL.Add(vSR.Name);
  1288. iRetval := FindNext(vSR);
  1289. end;
  1290. Result := vSL.Count;
  1291. finally
  1292. FindClose(vSR);
  1293. vSL.Free;
  1294. end;
  1295. end;
  1296. function ChangeExt(AFile, ANewExt: string): string;
  1297. var i, iPos: Integer;
  1298. begin
  1299. for i := Length(AFile) Downto 1 do
  1300. begin
  1301. if AFile[i] = '.' then
  1302. begin
  1303. iPos := i;
  1304. Break;
  1305. end;
  1306. end;
  1307. Result := Copy(AFile, 1, iPos - 1) + ANewExt;
  1308. end;
  1309. function CheckExt(AName, AExt: string): string;
  1310. var bHasExt: Boolean;
  1311. begin
  1312. bHasExt := ExtractFileExt(AName) <> '';
  1313. if not bHasExt then
  1314. Result := AName + AExt
  1315. else
  1316. begin
  1317. if (UpperCase(ExtractFileExt(AName)) <> AExt) then
  1318. Result := ChangeExt(AName, AExt)
  1319. else
  1320. Result := AName;
  1321. end;
  1322. end;
  1323. function TempName(ALength: Integer): string;
  1324. const
  1325. CodedBuf: array[0..35] of Char = ('0', '1', '2', '3', '4', '5',
  1326. '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I',
  1327. 'J', 'K', 'L', 'M', 'N',
  1328. 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V',
  1329. 'W', 'X', 'Y', 'Z');
  1330. begin
  1331. Result := '';
  1332. Randomize;
  1333. while Length(Result) < ALength do
  1334. Result := Result + CodedBuf[Random(36)];
  1335. end;
  1336. function URLFileName(AURL: string): string;
  1337. var
  1338. i: integer;
  1339. s: string;
  1340. begin
  1341. s := AURL;
  1342. i := Pos('/', s);
  1343. while i <> 0 do
  1344. begin
  1345. Delete(s, 1, i);
  1346. i := Pos('/', s);
  1347. end;
  1348. Result := s;
  1349. end;
  1350. function ReplaceChars(AStr: string): string;
  1351. var s: string;
  1352. begin
  1353. s := Trim(AStr);
  1354. s := StringReplace(s, '\r\n', #$D#$A, [rfReplaceAll]);
  1355. Result := s;
  1356. end;
  1357. end.