ScEncryptUnit.pas 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736
  1. unit ScEncryptUnit;
  2. interface
  3. uses
  4. Windows, SysUtils, Forms, Classes, ScUtils;
  5. const
  6. // Hasp锁
  7. DT_HASP = 0;
  8. // Sense IV单机锁
  9. DT_S4 = 1;
  10. // Sense IV网络锁
  11. // 按用户授权(不分模块,三个版本都占用总授权)
  12. DT_S4_Net_User = 2;
  13. // 按模块授权(三个版本分别按三个模块授权)
  14. DT_S4_Net_Module = 3;
  15. // SafeNet(彩虹)SoftDog(软件狗)
  16. DT_SN_SD = 5;
  17. // 飞天R1
  18. DT_FT_R1 = 6;
  19. CS_Error = -5;
  20. CS_NeedAuthorize = -4;
  21. CS_NoDog = -3;
  22. CS_DogTypeError = -2;
  23. CS_VerifyError = -1;
  24. CS_Ignore = 0;
  25. CS_Success = 1;
  26. CS_WantAuthorize = 2;
  27. CS_NeedUpdate = -6;
  28. CS_EndDate = -7;
  29. CS_CloseToLimitDate = -8;
  30. // CS_BillsDog = 1;
  31. // CS_BudgetDog = 2;
  32. // 0:因某些原因(如加密够忙)而忽略检查,-1:加密检查错误,-2:狗类型不正确;1:清单狗,2:预算狗
  33. function CheckDog: Integer;
  34. function CheckDog1: Integer;
  35. function SimpleCheck: Boolean;
  36. function CheckTimes(AIsOnOpen: Boolean = False): Integer;
  37. function CheckHours: Integer;
  38. function CheckEdition: Integer;
  39. function CheckLimitDate: Integer;
  40. function CheckData: Integer;
  41. function CheckDogAndHint: Boolean;
  42. function DelayCheckDog: Boolean;
  43. function CheckDogErrorCountAndHint: Boolean;
  44. function GetReportOprList: TStrings;
  45. function GetReportOprNum(AOpr: string): Integer;
  46. procedure ClearReportOprList;
  47. function GetReportFuncList: TStrings;
  48. function GetReportFuncNum(AOpr: string): Integer;
  49. procedure ClearReportFuncList;
  50. procedure DogError;
  51. function DogIsBusy: Boolean;
  52. function OpenDog: Integer;
  53. function IsDogExists: Boolean;
  54. procedure SaveDog;
  55. function UserAuthorize(AAuthorize: array of Byte): Boolean;
  56. function UserUpdateLock(AUpdateData: array of Byte): Boolean;
  57. function EncryptKey: string;
  58. function AuthorizeKey: string;
  59. function IsLimitedFixedBills: Boolean;
  60. function CanOpenFixedBills: Boolean;
  61. var
  62. strHASPID: string;
  63. bAuthorized: Boolean = True;
  64. Activations: Integer;
  65. StartTime, RunTime, LastTime: LongWord;
  66. EncryptLog: TStringList;
  67. DogType: Byte = $FF;
  68. DogEdition: Byte = $FF;
  69. // 加密锁版本号
  70. _DogEdition: Byte = 0;
  71. // 容错次数
  72. _MaxErrorCount: Integer = 5;
  73. procedure CreateEncryptLog;
  74. procedure AddEncryptLog(ALog: string);
  75. implementation
  76. uses
  77. Math, CommonMessages, ScHaspEncrypt, ScS4Encrypt, CryptUtils,
  78. ScHaspPwd, ScSNSEncrypt, ConstVarUnit, ScAuthFrm, ScR1Encrypt,
  79. ScEncryptEditions;
  80. const
  81. MutexAddressName = 'SmartCost_Mutex_Address_Name';
  82. var
  83. DogErrorCount: Integer;
  84. MutexHandle: THandle;
  85. ReportOprList: TStringList = nil;
  86. ReportFuncList: TStringList = nil;
  87. // 需要记录加密日志的话,改为TRUE;
  88. // 目前仅为深思网络版写了记录日志的代码
  89. function NeedLog: Boolean;
  90. begin
  91. Result := False;
  92. // Result := ConfigInfo.IsWriteEncryptLog;
  93. end;
  94. procedure CreateEncryptLog;
  95. begin
  96. EncryptLog := TStringList.Create;
  97. end;
  98. procedure AddEncryptLog(ALog: string);
  99. begin
  100. if (EncryptLog <> nil) and NeedLog then
  101. EncryptLog.Add(ALog);
  102. end;
  103. procedure FreeAndSaveEncryptLog;
  104. begin
  105. if EncryptLog <> nil then
  106. begin
  107. if NeedLog then
  108. EncryptLog.SaveToFile(ExtractFilePath(ParamStr(0)) + 'EncryptLog.log');
  109. FreeAndNil(EncryptLog);
  110. end;
  111. end;
  112. function EncryptKey: string;
  113. var
  114. arrResult: array of Byte;
  115. iOutputLength: Integer;
  116. begin
  117. iOutputLength := GetOutputLength(ScEncryptKey);
  118. SetLength(arrResult, iOutputLength);
  119. Decrypt_Simple(ScEncryptKey, Length(ScEncryptKey), arrResult, iOutputLength);
  120. SetString(Result, PChar(@arrResult[0]), iOutputLength);
  121. end;
  122. function AuthorizeKey: string;
  123. var
  124. arrResult: array of Byte;
  125. iOutputLength: Integer;
  126. begin
  127. iOutputLength := GetOutputLength(ScAuthorizeKey);
  128. SetLength(arrResult, iOutputLength);
  129. Decrypt_Simple(ScAuthorizeKey, Length(ScAuthorizeKey), arrResult, iOutputLength);
  130. SetString(Result, PChar(@arrResult[0]), iOutputLength);
  131. end;
  132. function DogIsBusy: Boolean;
  133. var
  134. WaitFlag: DWORD;
  135. begin
  136. if MutexHandle = 0 then
  137. begin
  138. Result := False;
  139. Exit;
  140. end;
  141. WaitFlag := WaitForSingleObject(MutexHandle, 0);
  142. Result := (WaitFlag <> WAIT_OBJECT_0) and (WaitFlag <> WAIT_ABANDONED);
  143. end;
  144. function SimpleCheck: Boolean;
  145. var
  146. iPort: Integer;
  147. begin
  148. Result := False;
  149. if SimpleR1Check = DT_FT_R1 then
  150. begin
  151. DogType := DT_FT_R1;
  152. Result := True;
  153. end;
  154. if (not Result) and (SimpleSNSCheck = DT_SN_SD) then
  155. begin
  156. DogType := DT_SN_SD;
  157. Result := True;
  158. end;
  159. if (not Result) and SimpleHaspCheck(iPort) then
  160. begin
  161. DogType := DT_Hasp;
  162. Result := True;
  163. end;
  164. if not Result then
  165. case SimpleS4Check of
  166. DT_S4:
  167. begin
  168. DogType := DT_S4;
  169. Result := True;
  170. end;
  171. DT_S4_Net_User:
  172. begin
  173. DogType := DT_S4_Net_User;
  174. Result := True;
  175. end;
  176. DT_S4_Net_Module:
  177. begin
  178. DogType := DT_S4_Net_Module;
  179. Result := True;
  180. end;
  181. end;
  182. AddEncryptLog('[S] SimpleCheck: DogType = ' + IntToStr(DogType));
  183. end;
  184. function CheckTimes(AIsOnOpen: Boolean): Integer;
  185. begin
  186. Result := CS_Error;
  187. case DogType of
  188. DT_FT_R1:
  189. Result := CheckR1Times(AIsOnOpen);
  190. DT_SN_SD:
  191. Result := CheckSNSTimes(AIsOnOpen);
  192. DT_HASP:
  193. Result := CheckHaspTimes(AIsOnOpen);
  194. DT_S4:
  195. Result := CheckS4Times(AIsOnOpen);
  196. DT_S4_Net_Module, DT_S4_Net_User:
  197. Result := CS_Success;
  198. end;
  199. end;
  200. function CheckHours: Integer;
  201. begin
  202. Result := CS_Error;
  203. case DogType of
  204. DT_FT_R1:
  205. Result := CheckR1Hours;
  206. DT_SN_SD:
  207. Result := CheckSNSHours;
  208. DT_HASP:
  209. Result := CheckHaspHours;
  210. DT_S4:
  211. Result := CheckS4Hours;
  212. DT_S4_Net_Module, DT_S4_Net_User:
  213. Result := CS_Success;
  214. end;
  215. end;
  216. function CheckLimitDate: Integer;
  217. begin
  218. Result := CS_Error;
  219. case DogType of
  220. DT_FT_R1:
  221. Result := CheckR1LimitDate;
  222. DT_SN_SD:
  223. Result := CheckSNSLimitDate
  224. else
  225. Result := CS_Ignore;
  226. end;
  227. end;
  228. function CheckEdition: Integer;
  229. begin
  230. Result := CS_Error;
  231. SimpleCheck;
  232. case DogType of
  233. DT_FT_R1:
  234. Result := CheckR1Edition;
  235. DT_SN_SD:
  236. Result := CheckSNSEdition;
  237. DT_HASP:
  238. Result := CheckHaspEdition;
  239. DT_S4, DT_S4_Net_Module, DT_S4_Net_User:
  240. Result := CheckS4Edition;
  241. end;
  242. // 广西养护不检查升级信息
  243. {$IFDEF _ScYangHu_GuangXi}
  244. Exit;
  245. {$ENDIF}
  246. {$IFDEF _ScYS2007}
  247. if Result >= 0 then
  248. case DogType of
  249. DT_FT_R1:
  250. Result := CheckR1AdditionEdition;
  251. DT_SN_SD:
  252. Result := CheckSNSAdditionEdition;
  253. DT_HASP:
  254. Result := CheckHaspAdditionEdition;
  255. DT_S4{, DT_S4_Net_Module, DT_S4_Net_User}:
  256. Result := CheckS4AdditionEdition;
  257. end;
  258. {$ENDIF}
  259. end;
  260. function CheckData: Integer;
  261. begin
  262. Result := CS_NoDog;
  263. SimpleCheck;
  264. case DogType of
  265. DT_FT_R1:
  266. Result := CheckR1Data;
  267. DT_SN_SD:
  268. Result := CheckSNSData;
  269. DT_HASP:
  270. Result := CheckHaspData;
  271. DT_S4, DT_S4_Net_Module, DT_S4_Net_User:
  272. Result := CheckS4Data;
  273. end;
  274. end;
  275. function CheckDog1: Integer;
  276. begin
  277. Result := Checkdog;
  278. end;
  279. function CheckDog: Integer;
  280. var
  281. iResult: Integer;
  282. begin
  283. {$IFDEF _ScInternal}
  284. Result := CS_Ignore;
  285. {$ELSE}
  286. if DogIsBusy then
  287. begin
  288. Result := CS_Ignore;
  289. Exit;
  290. end;
  291. try
  292. Result := CheckData;
  293. if (Result = CS_Ignore) or (Result = CS_Success) then
  294. begin
  295. iResult := CheckLimitDate;
  296. if iResult = CS_EndDate then
  297. Result := iResult;
  298. end;
  299. if Result = CS_Success then
  300. DogErrorCount := 0;
  301. finally
  302. ReleaseMutex(MutexHandle);
  303. end;
  304. {$ENDIF}
  305. end;
  306. function DelayCheckDog: Boolean;
  307. begin
  308. Result := True;
  309. case CheckDog of
  310. CS_VerifyError, CS_DogTypeError, CS_Error, CS_NoDog, CS_NeedAuthorize:
  311. begin
  312. Inc(DogErrorCount);
  313. if DogErrorCount > _MaxErrorCount then
  314. Result := False;
  315. end;
  316. end;
  317. end;
  318. function GetReportOprList: TStrings;
  319. begin
  320. if not Assigned(ReportOprList) then
  321. ReportOprList := TStringList.Create;
  322. Result := ReportOprList;
  323. end;
  324. procedure ClearReportOprList;
  325. var
  326. iCheckData: Integer;
  327. begin
  328. case DogType of
  329. DT_FT_R1, DT_SN_SD:
  330. GetReportOprList.Clear;
  331. DT_HASP:
  332. LoadHaspReportOprs;
  333. DT_S4:
  334. GetReportOprList.Clear;
  335. DT_S4_Net_Module, DT_S4_Net_User:
  336. begin
  337. Randomize;
  338. iCheckData := RandomRange(8000, 11050);
  339. case iCheckData of
  340. 8050..9020, 10011..11030:
  341. GetReportOprList.Clear;
  342. end;
  343. end;
  344. end;
  345. end;
  346. function GetReportOprNum(AOpr: string): Integer;
  347. begin
  348. Result := -1;
  349. case DogType of
  350. DT_FT_R1:
  351. Result := GetR1ReportOprNum(AOpr);
  352. DT_SN_SD:
  353. Result := GetSNSReportOprNum(AOpr);
  354. DT_HASP:
  355. Result := GetReportOprList.IndexOf(AOpr);
  356. DT_S4, DT_S4_Net_Module, DT_S4_Net_User:
  357. Result := GetS4ReportOprNum(AOpr);
  358. end;
  359. end;
  360. function GetReportFuncList: TStrings;
  361. begin
  362. if not Assigned(ReportFuncList) then
  363. ReportFuncList := TStringList.Create;
  364. Result := ReportFuncList;
  365. end;
  366. procedure ClearReportFuncList;
  367. var
  368. iCheckData: Integer;
  369. begin
  370. case DogType of
  371. DT_FT_R1, DT_SN_SD:
  372. GetReportFuncList.Clear;
  373. DT_HASP:
  374. LoadHaspReportFuncs;
  375. DT_S4:
  376. GetReportFuncList.Clear;
  377. DT_S4_Net_Module, DT_S4_Net_User:
  378. begin
  379. Randomize;
  380. iCheckData := RandomRange(8000, 11050);
  381. case iCheckData of
  382. 8080..9000, 9071..10000:
  383. GetReportFuncList.Clear;
  384. end;
  385. end;
  386. end;
  387. end;
  388. function GetReportFuncNum(AOpr: string): Integer;
  389. begin
  390. Result := -1;
  391. case DogType of
  392. DT_FT_R1:
  393. Result := GetR1ReportFuncNum(AOpr);
  394. DT_SN_SD:
  395. Result := GetSNSReportFuncNum(AOpr);
  396. DT_HASP:
  397. Result := 900 + GetReportFuncList.IndexOf(AOpr);
  398. DT_S4, DT_S4_Net_Module, DT_S4_Net_User:
  399. Result := GetS4ReportFuncNum(AOpr);
  400. end;
  401. end;
  402. procedure DogError;
  403. begin
  404. CommonMessage(pmtError, [pmbOk], '没有检查到加密锁,或加密锁类型不正确。'#13#10'请购买正版SmartCost。'
  405. + #13#10'如果插上加密锁后仍有问题,请拨打产品注册电话:' + LoadAuthorizePhone + '。');
  406. Application.Terminate;
  407. end;
  408. procedure DogVerifyError;
  409. begin
  410. CommonMessage(pmtError, [pmbOk], '没有检查到加密锁。'#13#10'请购买正版SmartCost。'
  411. + #13#10'如果插上加密锁后仍有问题,请拨打产品注册电话:' + LoadAuthorizePhone + '。');
  412. Application.Terminate;
  413. end;
  414. procedure DogTypeError;
  415. begin
  416. CommonMessage(pmtError, [pmbOk], '加密锁类型不正确,请检查。'
  417. + #13#10'如果插上正确的加密锁后仍有问题,请拨打产品注册电话:' + LoadAuthorizePhone + '。');
  418. Application.Terminate;
  419. end;
  420. procedure DogEndDate;
  421. begin
  422. CommonMessage(pmtError, [pmbOk], '加密锁使用时间限制已到。'
  423. + #13#10'如果需延长使用时间,请与客服中心联系。');
  424. Application.Terminate;
  425. end;
  426. function CheckDogAndHint: Boolean;
  427. begin
  428. Result := True;
  429. case CheckDog of
  430. CS_Error:
  431. begin
  432. DogError;
  433. Result := False;
  434. end;
  435. CS_NoDog:
  436. begin
  437. DogError;
  438. Result := False;
  439. end;
  440. CS_NeedAuthorize:
  441. begin
  442. DogVerifyError;
  443. Result := False;
  444. end;
  445. CS_VerifyError:
  446. begin
  447. DogVerifyError;
  448. Result := False;
  449. end;
  450. CS_DogTypeError:
  451. begin
  452. DogTypeError;
  453. Result := False;
  454. end;
  455. CS_EndDate:
  456. begin
  457. DogEndDate;
  458. Result := False;
  459. end;
  460. end;
  461. end;
  462. function CheckDogErrorCountAndHint: Boolean;
  463. begin
  464. Result := True;
  465. if DogErrorCount > _MaxErrorCount then
  466. begin
  467. DogError;
  468. Result := False;
  469. end;
  470. end;
  471. procedure CreateDogMutex;
  472. var
  473. SA: TSecurityAttributes;
  474. begin
  475. SA.nLength := SizeOf(SA);
  476. SA.lpSecurityDescriptor := nil;
  477. SA.bInheritHandle := False;
  478. MutexHandle := CreateMutex(@SA, False, PChar(MutexAddressName));
  479. end;
  480. function OpenDog: Integer;
  481. var
  482. iCheckResult1, iCheckresult2, iEditionResult, iLimitDate: Integer;
  483. begin
  484. Result := CS_NoDog;
  485. if DogIsBusy then
  486. begin
  487. Result := CS_Ignore;
  488. Exit;
  489. end;
  490. try
  491. SimpleCheck;
  492. StartTime := GetTickCount;
  493. if DogType in [DT_FT_R1, DT_SN_SD, DT_S4, DT_S4_Net_Module, DT_S4_Net_User] then
  494. StartTime := StartTime div 1000;
  495. if (CheckData in [CS_Success, CS_Ignore]) then
  496. begin
  497. iEditionResult := CheckEdition;
  498. if iEditionResult < 0 then
  499. begin
  500. if iEditionResult = CS_NeedUpdate then
  501. Result := CS_NeedUpdate
  502. else
  503. Result := CS_DogTypeError;
  504. end
  505. else
  506. begin
  507. iCheckResult1 := CheckHours;
  508. iCheckResult2 := CheckTimes(True);
  509. iLimitDate := CheckLimitDate;
  510. if iLimitDate = CS_Success then
  511. Result := iLimitDate
  512. else if iLimitDate = CS_CloseToLimitDate then
  513. Result := iLimitDate
  514. else if iLimitDate = CS_EndDate then
  515. begin
  516. Result := iLimitDate;
  517. Exit;
  518. end
  519. else if iLimitDate = CS_Ignore then
  520. begin
  521. if (iCheckResult1 = CS_NeedAuthorize) or (iCheckResult2 = CS_NeedAuthorize) then
  522. Result := CS_NeedAuthorize
  523. else if (iCheckResult1 = CS_WantAuthorize) or (iCheckResult1 = CS_WantAuthorize) then
  524. Result := CS_WantAuthorize
  525. else
  526. Result := CS_Success;
  527. end;
  528. end;
  529. end;
  530. if not ((Result = CS_Success) or (Result = CS_WantAuthorize)
  531. or (Result = CS_NeedAuthorize) or (Result = CS_Ignore)
  532. or (Result = CS_NeedUpdate) or (Result = CS_CloseToLimitDate)) then
  533. Exit;
  534. case DogType of
  535. DT_FT_R1:
  536. if OpenR1Dog <> CS_Success then
  537. Result := CS_Error;
  538. DT_SN_SD:
  539. if OpenSNSDog <> CS_Success then
  540. Result := CS_Error;
  541. DT_HASP:
  542. if OpenHaspDog <> CS_Success then
  543. Result := CS_Error;
  544. DT_S4, DT_S4_Net_Module, DT_S4_Net_User:
  545. if OpenS4Dog <> CS_Success then
  546. Result := CS_Error;
  547. end;
  548. finally
  549. ReleaseMutex(MutexHandle);
  550. end;
  551. end;
  552. function IsDogExists: Boolean;
  553. var
  554. bWantauthorize: Boolean;
  555. begin
  556. Result := False;
  557. bWantauthorize := False;
  558. case OpenDog of
  559. CS_NeedAuthorize:
  560. begin
  561. CommonMessage(pmtError, [pmbOk], '您的试用时间已到,需要进行注册。');
  562. if not Authorize then
  563. begin
  564. Exit;
  565. end;
  566. end;
  567. CS_Error, CS_NoDog, CS_DogTypeError, CS_VerifyError:
  568. begin
  569. CommonMessage(pmtError, [pmbOk], '没有检查到加密锁。'#13#10'请购买正版SmartCost。'
  570. + #13#10'如果插上加密锁后仍有问题,请拨打客服热线:' + LoadServicePhone + '。');
  571. Exit;
  572. end;
  573. CS_WantAuthorize:
  574. bWantAuthorize := True;
  575. end;
  576. if CheckDog = CS_VerifyError then
  577. begin
  578. CommonMessage(pmtError, [pmbOk], '没有检查到加密锁。'#13#10'请购买正版SmartCost。'
  579. + #13#10'如果插上加密锁后仍有问题,请拨打客服热线:' + LoadServicePhone + '。');
  580. Exit;
  581. end;
  582. if CheckDog = CS_DogTypeError then
  583. begin
  584. CommonMessage(pmtError, [pmbOk], '加密锁类型不正确,请检查。'
  585. + #13#10'如果插上加密锁后仍有问题,请拨打客服热线:' + LoadServicePhone + '。');
  586. Exit;
  587. end;
  588. if bWantAuthorize then
  589. begin
  590. CommonMessage(pmtHint, [pmbOk], '感谢您购买SmartCost!'#13#10'目前本产品处于试用状态,需要进行注册'
  591. + #13#10'了解详细信息请进入菜单“帮助”->“产品注册”。');
  592. end;
  593. Result := True;
  594. end;
  595. procedure SaveDog;
  596. begin
  597. case DogType of
  598. DT_FT_R1:
  599. SaveR1Dog;
  600. DT_SN_SD:
  601. SaveSNSDog;
  602. DT_HASP:
  603. SaveHaspDog;
  604. DT_S4:
  605. SaveS4Dog;
  606. end;
  607. FreeAndSaveEncryptLog;
  608. end;
  609. function UserAuthorize(AAuthorize: array of Byte): Boolean;
  610. begin
  611. Result := False;
  612. case DogType of
  613. DT_FT_R1:
  614. Result := R1UserAuthorize(AAuthorize);
  615. DT_SN_SD:
  616. Result := SNSUserAuthorize(AAuthorize);
  617. DT_HASP:
  618. Result := HaspUserAuthorize(AAuthorize);
  619. DT_S4:
  620. Result := S4UserAuthorize(AAuthorize);
  621. end;
  622. end;
  623. function UserUpdateLock(AUpdateData: array of Byte): Boolean;
  624. begin
  625. Result := False;
  626. case DogType of
  627. DT_FT_R1:
  628. Result := R1UserUpdateLock(AUpdateData);
  629. DT_SN_SD:
  630. Result := SNSUserUpdateLock(AUpdateData);
  631. DT_HASP:
  632. Result := HaspUserUpdateLock(AUpdateData);
  633. DT_S4:
  634. Result := S4UserUpdateLock(AUpdateData);
  635. end;
  636. end;
  637. function IsLimitedFixedBills: Boolean;
  638. begin
  639. Result := _DogEdition in [eidLimitedFixBills];
  640. end;
  641. function CanOpenFixedBills: Boolean;
  642. begin
  643. Result := not (_DogEdition in [0, eidStandard]);
  644. end;
  645. initialization
  646. DogErrorCount := 0;
  647. CreateDogMutex;
  648. finalization
  649. CloseHandle(MutexHandle);
  650. MutexHandle := 0;
  651. end.