unit mS4Utils; interface uses {$IFDEF _ScNet} S4Net; //Sense4Net; {$ELSE} //S4Single; Sense4; {$ENDIF} const // 197707074568224603070424 Sense4DevPin = '19770707' + '45682246' + '03070424'; Sense4UserPin = '45682246'; Sense4AuthenPin = '19770707' + '03070424'; Sense4OldDevPin = '12345678' + '12345678' + '12345678'; Sense4OldUserPin = '12345678'; Sense4OldAuthenPin = '12345678' + '12345678'; function OpenSense(var s4Ctx: PSENSE4_CONTEXT): Boolean; procedure CloseSense(var s4Ctx: PSENSE4_CONTEXT); function WriteSenseData(s4Ctx: PSENSE4_CONTEXT; AFileID: string; APData: Pointer; ADataLength: Integer; AIsExe: Boolean; AIsUpdate: Boolean = False): Boolean; function WriteSenseFile(s4Ctx: PSENSE4_CONTEXT; AFileID: string; AFileName: string; AIsExe: Boolean; AIsUpdate: Boolean = False): Boolean; procedure SenseLEDOn(s4Ctx: PSENSE4_CONTEXT); procedure SenseLEDOff(s4Ctx: PSENSE4_CONTEXT); procedure SenseLEDFlash(s4Ctx: PSENSE4_CONTEXT); implementation uses Windows, Classes, SysUtils, Variants; var g_s4Ctx: PSENSE4_CONTEXT = nil; tmp_s4Ctx: PSENSE4_CONTEXT = nil; g_S4Opened: Boolean = False; // 深思4全局数据(特为网络版设计) {网络版应该一套软件占用一个授权,即三个应用程序只占用一个授权, 因此不管启动几个应用程序,都只能使用一次S4Open, 为此必须采用共享内存来存储深思4的数据,提供跨程序的调用。 } type TGlobalS4Data = packed record // 深思网络锁引用计数 SenseNetDogRefCount: Integer; // 深思加密锁数据 SenseData: array [0..91] of Byte; end; PGlobalS4Data = ^TGlobalS4Data; const ScSense4ShareMemoryName = 'SmartCost_Sense4_Data_Handle'; // 返回 0:函数调用失败;1:已存在共享内存对象;2:不存在共享内存对象 function GetGlobalS4Ctx(var s4Ctx: PSENSE4_CONTEXT): Integer; var // 文件映射对象句柄 ShareHandle: THandle; pData: PGlobalS4Data; SA: TSecurityAttributes; begin Result := 0; SA.nLength := SizeOf(SA); SA.lpSecurityDescriptor := nil; SA.bInheritHandle := False; ShareHandle := CreateFileMapping($FFFFFFFF, @SA, PAGE_READWRITE, 0, SizeOf(TGlobalS4Data), PChar(ScSense4ShareMemoryName)); try // 已存在共享内存 if GetLastError = ERROR_ALREADY_EXISTS then begin pData := MapViewOfFile(ShareHandle, File_MAP_WRITE, 0, 0, 0); try if pData <> nil then begin Inc(pData^.SenseNetDogRefCount); CopyMemory(s4Ctx, @(pData^.SenseData[0]), SizeOf(SENSE4_CONTEXT)); Result := 1; end; finally // if pData <> nil then // UnmapViewOfFile(pData); end; end // 尚未存在共享内存 else begin pData := MapViewOfFile(ShareHandle, File_MAP_WRITE, 0, 0, 0); try if pData <> nil then begin ZeroMemory(pData, SizeOf(TGlobalS4Data)); pData^.SenseNetDogRefCount := 1; Result := 2; end; finally // if pData <> nil then // UnmapViewOfFile(pData); end; end; finally //CloseHandle(ShareHandle); end; end; function SetGlobalS4Ctx(var s4Ctx: PSENSE4_CONTEXT): Boolean; var // 文件映射对象句柄 ShareHandle: THandle; pData: PGlobalS4Data; begin Result := False; ShareHandle := OpenFileMapping(FILE_MAP_WRITE, False, PChar(ScSense4ShareMemoryName)); if ShareHandle <> Null then begin try pData := MapViewOfFile(ShareHandle, File_MAP_WRITE, 0, 0, 0); try if pData <> nil then begin CopyMemory(@(pData^.SenseData[0]), s4Ctx, SizeOf(SENSE4_CONTEXT)); Result := True; end; finally if pData <> nil then UnmapViewOfFile(pData); end; finally CloseHandle(ShareHandle); end; end; end; function ReleaseGlobalS4Ctx(var s4Ctx: PSENSE4_CONTEXT): Boolean; var // 文件映射对象句柄 ShareHandle: THandle; pData: PGlobalS4Data; begin Result := False; ShareHandle := OpenFileMapping(FILE_MAP_WRITE, False, PChar(ScSense4ShareMemoryName)); if ShareHandle <> Null then begin try pData := MapViewOfFile(ShareHandle, File_MAP_WRITE, 0, 0, 0); try if pData <> nil then begin Dec(pData^.SenseNetDogRefCount); if pData^.SenseNetDogRefCount = 0 then S4Close(s4Ctx); Result := True; end; finally if pData <> nil then UnmapViewOfFile(pData); end; finally CloseHandle(ShareHandle); end; end; end; function OpenSense(var s4Ctx: PSENSE4_CONTEXT): Boolean; var CtxLength: Cardinal; begin Result := False; CtxLength := 0; {$IFDEF _ScNET} { 网络版为了控制节点数,必须保持OPEN状态, 而原来单机版的做法是OPEN后检查完就CLOSE; 好在OpenSense, CloseSense是成对调用,所以可做如下修改: 为兼容单机版的做法,在这里不每次打开,只是第一次打开, 另创建一个指针,并将传入的指针保存, 再把创建的指针传出去 在CloseSense时,不关闭,只把指针替换为原来传进来的指针} if g_s4Ctx = nil then begin S4Enum(nil, CtxLength); if CtxLength = 0 then Exit; New(g_s4Ctx); try if S4Enum(g_s4Ctx, CtxLength) = S4_SUCCESS then begin if S4Open(g_s4Ctx) = S4_SUCCESS then begin g_S4Opened := True; Result := True; end; end; { case GetGlobalS4Ctx(g_s4Ctx) of // 失败 0: Exit; // 已有其他版本程序打开锁 1: begin g_S4Opened := True; Result := True; end; // 首次打开锁 2: begin if S4Enum(g_s4Ctx, CtxLength) = S4_SUCCESS then begin if S4Open(g_s4Ctx) = S4_SUCCESS then begin g_S4Opened := True; SetGlobalS4Ctx(g_s4Ctx); Result := True; end; end; end; end;} except Result := False; end; end else Result := True; tmp_s4Ctx := s4Ctx; s4Ctx := g_s4Ctx; {$ELSE} S4Enum(nil, CtxLength); if CtxLength = 0 then Exit; try if S4Enum(s4Ctx, CtxLength) = S4_SUCCESS then begin if S4Open(s4Ctx) = S4_SUCCESS then begin Result := True; end; end; except Result := False; end; {$ENDIF} end; procedure CloseSense(var s4Ctx: PSENSE4_CONTEXT); begin {$IFDEF _ScNet} { 网络版为了控制节点数,必须保持OPEN状态, 而原来单机版的做法是OPEN后检查完就CLOSE; 为兼容单机版的做法,在这里不关闭,只是将OPEN时传入的指针再传出去 在程序关闭时再CLOSE} if Assigned(tmp_s4Ctx) then begin s4Ctx := tmp_s4Ctx; tmp_s4Ctx := nil; end else if s4Ctx = g_s4Ctx then begin s4Ctx := nil; New(s4Ctx); end; {$ELSE} S4Close(s4Ctx); {$ENDIF} end; function WriteSenseData(s4Ctx: PSENSE4_CONTEXT; AFileID: string; APData: Pointer; ADataLength: Integer; AIsExe: Boolean; AIsUpdate: Boolean): Boolean; var iBytes: Cardinal; iFileType: Byte; iFlag: Cardinal; iResult: Cardinal; begin {$IFDEF _ScNet} Result := True; {$ELSE} Result := False; if AIsExe then iFileType := S4_EXE_FILE else iFileType := S4_DATA_FILE; if AIsUpdate then iFlag := S4_UPDATE_FILE else iFlag := S4_CREATE_NEW; if S4VerifyPin(s4Ctx, Sense4DevPin, 24, S4_DEV_PIN) = S4_SUCCESS then begin iResult := S4WriteFile(s4Ctx, PChar(AFileID), 0, APData, ADataLength, ADataLength, iBytes, iFlag, iFileType); Result := iResult = S4_SUCCESS; end; {$ENDIF} end; function WriteSenseFile(s4Ctx: PSENSE4_CONTEXT; AFileID: string; AFileName: string; AIsExe: Boolean; AIsUpdate: Boolean): Boolean; var fsFile: TFileStream; pData: Pointer; begin fsFile := TFileStream.Create(AFileName, fmOpenRead); try pData := AllocMem(fsFile.Size); try ZeroMemory(pData, fsFile.Size); fsFile.Seek(0, soFromBeginning); fsFile.Read(pData^, fsFile.Size); Result := WriteSenseData(s4Ctx, AFileID, pData, fsFile.Size, AIsExe, AIsUpdate); finally FreeMem(pData); end; finally fsFile.Free; end; end; procedure SenseLEDOn(s4Ctx: PSENSE4_CONTEXT); var iReturn: Cardinal; begin {$IFNDEF _ScNet} S4Control(s4Ctx, S4_LED_UP, nil, 0, nil, 0, iReturn); {$ENDIF} end; procedure SenseLEDOff(s4Ctx: PSENSE4_CONTEXT); var iReturn: Cardinal; begin {$IFNDEF _ScNet} S4Control(s4Ctx, S4_LED_DOWN, nil, 0, nil, 0, iReturn); {$ENDIF} end; procedure SenseLEDFlash(s4Ctx: PSENSE4_CONTEXT); var iReturn: Cardinal; begin {$IFNDEF _ScNet} S4Control(s4Ctx, S4_LED_WINK, nil, 0, nil, 0, iReturn); {$ENDIF} end; initialization finalization if g_S4Opened and (g_s4Ctx <> nil) then //ReleaseGlobalS4Ctx(g_s4Ctx); S4Close(g_s4Ctx); end.