unit CoreExports; interface uses Winapi.Windows; function AEW_LogEnable: LongBool; cdecl; function AEW_Connect(Host: PAnsiChar; Index: LongInt): Pointer; cdecl; function AEW_Disconnect(uClientRef: Pointer): LongWord; cdecl; function AEW_SetTimeout(uClientRef: Pointer; TimeoutMS: LongInt): LongWord; cdecl; function AEW_ChangeDeviceIP(uClientRef: Pointer; NewIP: PAnsiChar): LongWord; cdecl; function AEW_ChangeSubnet(uClientRef: Pointer; NewSubnet: PAnsiChar): LongWord; cdecl; function AEW_ChangeGateway(uClientRef: Pointer; NewGateway: PAnsiChar): LongWord; cdecl; function AEW_ChangeNetworking(uClientRef: Pointer; NewIP, NewSubnet, NewGateway: PAnsiChar): LongWord; cdecl; function AEW_GetStatus(uClientRef: Pointer; pStatusBytes: PLongInt; pStatus: PByte): LongWord; cdecl; function AEW_DIO_WriteAll(uClientRef: Pointer; pDataBytes: PLongInt; pData: PByte): LongWord; cdecl; function AEW_DIO_ReadAll(uClientRef: Pointer; pDataBytes: PLongInt; pData: PByte): LongWord; cdecl; function AEW_DEB_StrToStr(uClientRef: Pointer; pSendPacketBytes: PLongInt; pSendPacket: PAnsiChar; pReplyPacketBytes: PLongInt; pReplyPacket: PAnsiChar): LongWord; cdecl; implementation uses System.Math, System.SysUtils, System.Classes, Winapi.WinSock, DClientSocks; function IntAsStr(I: LongWord): AnsiString; begin SetString(Result, PAnsiChar(@I), 4); end; function StrAsInt(S: AnsiString): LongWord; begin case Length(S) of 0: Result := 0; 1: Result := PByte(@S[1])^; 2: Result := PWord(@S[1])^; else Result := PLongWord(@S[1])^; //3 works because non-empty strings are null-terminated end; end; function StrToL8Str(S: AnsiString): AnsiString; var L: Integer; begin L := Length(S); if L > $FF then Result := #$FF + Copy(S, 1, $FF) else Result := AnsiChar(Byte(L)) + S ; end; function ExtractL8StrRaw(var S: AnsiString): AnsiString; var L: Integer; begin Result := ''; if Length(S) = 0 then Exit; L := Byte(S[1]); if Length(S) < 1 + L then Exit; Result := Copy(S, 1, 1 + L); S := Copy(S, 2 + L, MAXINT); end; type TVClientSock = class protected ProCheck: LongWord; public ClientSock: TDClientSock; //bRead: Boolean; InBuf2: AnsiString; hGotDataSem: THandle; Timeout: LongWord; PubCheck: LongWord; constructor Create; destructor Destroy; override; procedure ClientSockGotData(Sender: TObject); end; const ProData = $5C81D234; PubData = $BE4F6552; var bLogging: Boolean = False; LogFil: TFileStream = nil; { TVClientSock } procedure TVClientSock.ClientSockGotData(Sender: TObject); begin ReleaseSemaphore(hGotDataSem, 1, nil); end; constructor TVClientSock.Create; begin inherited; ClientSock := TDClientSock.Create; end; destructor TVClientSock.Destroy; begin ClientSock.Free; inherited; end; { procedure TVClientSock.TryRetry; var pChunk: TDIFFChunk; ChunkBuf: AnsiString; I: Integer; begin InBuf2 := ''; pChunk := TDIFFChunk.Create; pChunk.TagStr := 'RETRY'; ChunkBuf := pChunk.SaveToString; pChunk.Free; for I := 0 to 3 do begin Sleep(0); ClientSock.ReceiveStr; //Try to empty rest of garbage. end; ClientSock.PostSendStr(ChunkBuf); end; } { NotInAClass } { Compiler Doesn't Care } function AEW_LogEnable: LongBool; cdecl; begin Result := False; end; { const LogDirPath = 'C:\AEWLog\'; var Naui: TDateTime; LogFilePath: AnsiString; Year, Month, Day, Hour, Min, Sec, MSec: Word; begin Result := bLogging; if Result then Exit; if not ForceDirectories(LogDirPath) then Exit; Naui := Now; DecodeDate(Naui, Year, Month, Day); DecodeTime(Naui, Hour, Min, Sec, MSec); LogFilePath := LogDirPath + Format('%.4d-%.2d-%.2d %.2d-%.2d-%.2d.txt', [ Year, Month, Day, Hour, Min, Sec ]); try LogFil := TFileStream.Create(LogFilePath, fmCreate); LogFil.Free; LogFil := nil; LogFil := TFileStream.Create(LogFilePath, fmOpenReadWrite or fmShareDenyNone); except try if LogFil <> nil then LogFil.Free; except end; LogFil := nil; Result := False; Exit; end; bLogging := True; Result := True; end; } function AEW_Connect(Host: PAnsiChar; Index: LongInt): Pointer; cdecl; var TarHost: AnsiString; TarPort: Word; ThisClient: TVClientSock; Status: LongWord; begin Result := nil; try TarHost := Host; except SetLastError(ERROR_NOACCESS); Exit; end; TarPort := $CAE0 or (Index and $F); ThisClient := TVClientSock.Create; ThisClient.ProCheck := ProData; ThisClient.PubCheck := PubData; ThisClient.Timeout := 2000; ThisClient.hGotDataSem := CreateSemaphore(nil, 0, 1, nil); ThisClient.ClientSock.OnGotData := ThisClient.ClientSockGotData; Status := ThisClient.ClientSock.ConnectTo(TarHost, TarPort); if Status <> ERROR_SUCCESS then begin ThisClient.Free; SetLastError(Status); Exit; end; Result := ThisClient; SetLastError(ERROR_SUCCESS); end; function VerifyClientRef(uClientRef: Pointer): LongWord; begin try with TVClientSock(Pointer(uClientRef)) do if (ProCheck <> ProData) or (PubCheck <> PubData) then Result := ERROR_INVALID_HANDLE else Result := ERROR_SUCCESS ; except Result := ERROR_INVALID_HANDLE end; end; function ReceivePacket(ViaClient: TVClientSock; var PacketBuf: AnsiString): LongWord; var EndTime, TimeoutLeft: Integer; ThisPacket: AnsiString; begin PacketBuf := ''; EndTime := GetTickCount + ViaClient.Timeout; repeat try ThisPacket := ExtractL8StrRaw(ViaClient.InBuf2); except Result := ERROR_READ_FAULT; Exit; end; if Length(ThisPacket) > 1 then begin Result := ERROR_SUCCESS; PacketBuf := ThisPacket; Exit; end; TimeoutLeft := EndTime - Integer(GetTickCount); if TimeoutLeft < 0 then begin Result := ERROR_TIMEOUT; Exit; end; if Length(ThisPacket) = 1 then Continue; WaitForSingleObject(ViaClient.hGotDataSem, TimeoutLeft); ViaClient.InBuf2 := ViaClient.InBuf2 + ViaClient.ClientSock.ReceiveStr; until False; end; function AEW_Disconnect(uClientRef: Pointer): LongWord; cdecl; var ThisClient: TVClientSock; begin Result := VerifyClientRef(uClientRef); if Result <> ERROR_SUCCESS then Exit; ThisClient := Pointer(uClientRef); ThisClient.ProCheck := 0; ThisClient.PubCheck := 0; CloseHandle(ThisClient.hGotDataSem); ThisClient.Free; end; function AEW_SetTimeout(uClientRef: Pointer; TimeoutMS: LongInt): LongWord; cdecl; var ThisClient: TVClientSock; begin Result := VerifyClientRef(uClientRef); if Result <> ERROR_SUCCESS then begin Exit; end; ThisClient := Pointer(uClientRef); if not ThisClient.ClientSock.bConnected then begin Result := ERROR_NOT_CONNECTED; Exit; end; if TimeoutMS <= 0 then begin Result := ERROR_BAD_LENGTH; Exit; end; ThisClient.Timeout := TimeoutMS; end; function AEW_ChangeDeviceIP(uClientRef: Pointer; NewIP: PAnsiChar): LongWord; cdecl; var ThisClient: TVClientSock; DataBuf, TagBuf: AnsiString; RawIP: LongWord; begin Result := VerifyClientRef(uClientRef); if Result <> ERROR_SUCCESS then Exit; ThisClient := Pointer(uClientRef); if not ThisClient.ClientSock.bConnected then begin Result := ERROR_NOT_CONNECTED; Exit; end; try RawIP := inet_addr(NewIP); except Result := ERROR_NOACCESS; Exit; end; if RawIP = INADDR_NONE then begin Result := ERROR_INVALID_ADDRESS; Exit; end; DataBuf := StrToL8Str('ChIP' + IntAsStr(RawIP)); while WaitForSingleObject(ThisClient.hGotDataSem, 0) = WAIT_OBJECT_0 do ; ThisClient.InBuf2 := ThisClient.InBuf2 + ThisClient.ClientSock.ReceiveStr; ThisClient.ClientSock.PostSendStr(DataBuf); repeat Result := ReceivePacket(ThisClient, DataBuf); if Result <> ERROR_SUCCESS then Break; TagBuf := Copy(DataBuf, 2, 4); DataBuf := Copy(DataBuf, 5, MAXINT); if TagBuf = 'W_OK' then begin Break; end else if TagBuf = '_Err' then begin Result := ERROR_BAD_NET_RESP; SetLastError(StrAsInt(DataBuf)); Break; end else begin Result := ERROR_INVALID_DATA; ThisClient.InBuf2 := ''; Break; end; until False; if (Result = ERROR_TIMEOUT) and not ThisClient.ClientSock.bConnected then Result := ERROR_NOT_CONNECTED; end; function AEW_ChangeSubnet(uClientRef: Pointer; NewSubnet: PAnsiChar): LongWord; cdecl; var ThisClient: TVClientSock; DataBuf, TagBuf: AnsiString; RawSN: LongWord; begin Result := VerifyClientRef(uClientRef); if Result <> ERROR_SUCCESS then Exit; ThisClient := Pointer(uClientRef); if not ThisClient.ClientSock.bConnected then begin Result := ERROR_NOT_CONNECTED; Exit; end; try RawSN := inet_addr(NewSubnet); except Result := ERROR_NOACCESS; Exit; end; if RawSN = INADDR_NONE then begin Result := ERROR_INVALID_ADDRESS; Exit; end; DataBuf := StrToL8Str('ChSN' + IntAsStr(RawSN)); while WaitForSingleObject(ThisClient.hGotDataSem, 0) = WAIT_OBJECT_0 do ; ThisClient.InBuf2 := ThisClient.InBuf2 + ThisClient.ClientSock.ReceiveStr; ThisClient.ClientSock.PostSendStr(DataBuf); repeat Result := ReceivePacket(ThisClient, DataBuf); if Result <> ERROR_SUCCESS then Break; TagBuf := Copy(DataBuf, 2, 4); DataBuf := Copy(DataBuf, 5, MAXINT); if TagBuf = 'W_OK' then begin Break; end else if TagBuf = '_Err' then begin Result := ERROR_BAD_NET_RESP; SetLastError(StrAsInt(DataBuf)); Break; end else begin Result := ERROR_INVALID_DATA; ThisClient.InBuf2 := ''; Break; end; until False; if (Result = ERROR_TIMEOUT) and not ThisClient.ClientSock.bConnected then Result := ERROR_NOT_CONNECTED; end; function AEW_ChangeGateway(uClientRef: Pointer; NewGateway: PAnsiChar): LongWord; cdecl; var ThisClient: TVClientSock; DataBuf, TagBuf: AnsiString; RawGW: LongWord; begin Result := VerifyClientRef(uClientRef); if Result <> ERROR_SUCCESS then Exit; ThisClient := Pointer(uClientRef); if not ThisClient.ClientSock.bConnected then begin Result := ERROR_NOT_CONNECTED; Exit; end; try RawGW := inet_addr(NewGateway); except Result := ERROR_NOACCESS; Exit; end; if RawGW = INADDR_NONE then begin Result := ERROR_INVALID_ADDRESS; Exit; end; DataBuf := StrToL8Str('ChGW' + IntAsStr(RawGW)); while WaitForSingleObject(ThisClient.hGotDataSem, 0) = WAIT_OBJECT_0 do ; ThisClient.InBuf2 := ThisClient.InBuf2 + ThisClient.ClientSock.ReceiveStr; ThisClient.ClientSock.PostSendStr(DataBuf); repeat Result := ReceivePacket(ThisClient, DataBuf); if Result <> ERROR_SUCCESS then Break; TagBuf := Copy(DataBuf, 2, 4); DataBuf := Copy(DataBuf, 5, MAXINT); if TagBuf = 'W_OK' then begin Break; end else if TagBuf = '_Err' then begin Result := ERROR_BAD_NET_RESP; SetLastError(StrAsInt(DataBuf)); Break; end else begin Result := ERROR_INVALID_DATA; ThisClient.InBuf2 := ''; Break; end; until False; if (Result = ERROR_TIMEOUT) and not ThisClient.ClientSock.bConnected then Result := ERROR_NOT_CONNECTED; end; function AEW_ChangeNetworking(uClientRef: Pointer; NewIP, NewSubnet, NewGateway: PAnsiChar): LongWord; cdecl; var ThisClient: TVClientSock; DataBuf, TagBuf: AnsiString; RawIP, RawSN, RawGW: LongWord; begin { Result := AEW_ChangeGateway(uClientRef, NewGateway); if Result <> ERROR_SUCCESS then Exit; Result := AEW_ChangeSubnet(uClientRef, NewSubnet); if Result <> ERROR_SUCCESS then Exit; Result := AEW_ChangeDeviceIP(uClientRef, NewIP); if Result <> ERROR_SUCCESS then Exit; } Result := VerifyClientRef(uClientRef); if Result <> ERROR_SUCCESS then Exit; ThisClient := Pointer(uClientRef); if not ThisClient.ClientSock.bConnected then begin Result := ERROR_NOT_CONNECTED; Exit; end; try RawIP := inet_addr(NewIP); RawSN := inet_addr(NewSubnet); RawGW := inet_addr(NewGateway); except Result := ERROR_NOACCESS; Exit; end; if (RawIP = INADDR_NONE) or (RawSN = INADDR_NONE) or (RawGW = INADDR_NONE) then begin Result := ERROR_INVALID_ADDRESS; Exit; end; DataBuf := StrToL8Str('ChNW' + IntAsStr(RawIP) + IntAsStr(RawSN) + IntAsStr(RawGW)); while WaitForSingleObject(ThisClient.hGotDataSem, 0) = WAIT_OBJECT_0 do ; ThisClient.InBuf2 := ThisClient.InBuf2 + ThisClient.ClientSock.ReceiveStr; ThisClient.ClientSock.PostSendStr(DataBuf); //Sleep(100); //Result := ERROR_SUCCESS; repeat Result := ReceivePacket(ThisClient, DataBuf); if Result <> ERROR_SUCCESS then Break; TagBuf := Copy(DataBuf, 2, 4); DataBuf := Copy(DataBuf, 5, MAXINT); if TagBuf = 'W_OK' then begin Break; end else if TagBuf = '_Err' then begin Result := ERROR_BAD_NET_RESP; SetLastError(StrAsInt(DataBuf)); Break; end else begin Result := ERROR_INVALID_DATA; ThisClient.InBuf2 := ''; Break; end; until False; if (Result = ERROR_TIMEOUT) and not ThisClient.ClientSock.bConnected then Result := ERROR_NOT_CONNECTED; end; function AEW_GetStatus(uClientRef: Pointer; pStatusBytes: PLongInt; pStatus: PByte): LongWord; cdecl; var ThisClient: TVClientSock; DataBuf, TagBuf: AnsiString; L: Integer; begin Result := VerifyClientRef(uClientRef); if Result <> ERROR_SUCCESS then begin pStatusBytes^ := 0; Exit; end; ThisClient := Pointer(uClientRef); if not ThisClient.ClientSock.bConnected then begin Result := ERROR_NOT_CONNECTED; pStatusBytes^ := 0; Exit; end; pStatusBytes^ := pStatusBytes^; if pStatusBytes^ <= 0 then begin Result := ERROR_BAD_LENGTH; pStatusBytes^ := 0; Exit; end; DataBuf := StrToL8Str('RSta'); while WaitForSingleObject(ThisClient.hGotDataSem, 0) = WAIT_OBJECT_0 do ; ThisClient.InBuf2 := ThisClient.InBuf2 + ThisClient.ClientSock.ReceiveStr; ThisClient.ClientSock.PostSendStr(DataBuf); repeat Result := ReceivePacket(ThisClient, DataBuf); if Result <> ERROR_SUCCESS then Break; TagBuf := Copy(DataBuf, 2, 4); DataBuf := Copy(DataBuf, 5, MAXINT); if TagBuf = 'R_OK' then begin if Length(DataBuf) = 0 then pStatusBytes^ := 0 else begin L := Min(pStatusBytes^, Byte(DataBuf[1])); try Move(DataBuf[2], pStatus^, L); pStatusBytes^ := L; except Result := ERROR_NOACCESS; pStatusBytes^ := 0; end; end; Break; end else if TagBuf = '_Err' then begin Result := ERROR_BAD_NET_RESP; pStatusBytes^ := 0; SetLastError(StrAsInt(DataBuf)); Break; end else begin Result := ERROR_INVALID_DATA; pStatusBytes^ := 0; ThisClient.InBuf2 := ''; Break; end; until False; if (Result = ERROR_TIMEOUT) and not ThisClient.ClientSock.bConnected then Result := ERROR_NOT_CONNECTED; end; function AEW_DIO_WriteAll(uClientRef: Pointer; pDataBytes: PLongInt; pData: PByte): LongWord; cdecl; var ThisClient: TVClientSock; DataBuf, TagBuf: AnsiString; //bTriedRetry: Boolean; begin Result := VerifyClientRef(uClientRef); if Result <> ERROR_SUCCESS then begin pDataBytes^ := 0; Exit; end; ThisClient := Pointer(uClientRef); if not ThisClient.ClientSock.bConnected then begin Result := ERROR_NOT_CONNECTED; pDataBytes^ := 0; Exit; end; pDataBytes^ := pDataBytes^; if pDataBytes^ <= 0 then begin Result := ERROR_BAD_LENGTH; pDataBytes^ := 0; Exit; end; try SetString(DataBuf, PAnsiChar(pData), pDataBytes^); except Result := ERROR_NOACCESS; pDataBytes^ := 0; Exit; end; DataBuf := StrToL8Str('WADO' + StrToL8Str(DataBuf)); while WaitForSingleObject(ThisClient.hGotDataSem, 0) = WAIT_OBJECT_0 do ; ThisClient.InBuf2 := ThisClient.InBuf2 + ThisClient.ClientSock.ReceiveStr; ThisClient.ClientSock.PostSendStr(DataBuf); //bTriedRetry := False; repeat Result := ReceivePacket(ThisClient, DataBuf); if Result <> ERROR_SUCCESS then Break; TagBuf := Copy(DataBuf, 2, 4); DataBuf := Copy(DataBuf, 5, MAXINT); if TagBuf = 'W_OK' then begin if Length(DataBuf) = 0 then pDataBytes^ := 0 else pDataBytes^ := Byte(DataBuf[1]) ; Break; end else if TagBuf = '_Err' then begin Result := ERROR_BAD_NET_RESP; pDataBytes^ := 0; SetLastError(StrAsInt(DataBuf)); Break; end { else if not bTriedRetry then begin bTriedRetry := True; ThisClient.TryRetry; end } else begin Result := ERROR_INVALID_DATA; pDataBytes^ := 0; ThisClient.InBuf2 := ''; Break; end; until False; if (Result = ERROR_TIMEOUT) and not ThisClient.ClientSock.bConnected then Result := ERROR_NOT_CONNECTED; end; function AEW_DIO_ReadAll(uClientRef: Pointer; pDataBytes: PLongInt; pData: PByte): LongWord; cdecl; var ThisClient: TVClientSock; DataBuf, TagBuf: AnsiString; //bTriedRetry: Boolean; L: Integer; begin Result := VerifyClientRef(uClientRef); if Result <> ERROR_SUCCESS then begin pDataBytes^ := 0; Exit; end; ThisClient := Pointer(uClientRef); if not ThisClient.ClientSock.bConnected then begin Result := ERROR_NOT_CONNECTED; pDataBytes^ := 0; Exit; end; pDataBytes^ := pDataBytes^; if pDataBytes^ <= 0 then begin Result := ERROR_BAD_LENGTH; pDataBytes^ := 0; Exit; end; try FillChar(pData^, pDataBytes^, 0); except Result := ERROR_NOACCESS; pDataBytes^ := 0; Exit; end; DataBuf := StrToL8Str('RADI'); while WaitForSingleObject(ThisClient.hGotDataSem, 0) = WAIT_OBJECT_0 do ; ThisClient.InBuf2 := ThisClient.InBuf2 + ThisClient.ClientSock.ReceiveStr; ThisClient.ClientSock.PostSendStr(DataBuf); //bTriedRetry := False; repeat Result := ReceivePacket(ThisClient, DataBuf); if Result <> ERROR_SUCCESS then Break; TagBuf := Copy(DataBuf, 2, 4); DataBuf := Copy(DataBuf, 5, MAXINT); if TagBuf = 'R_OK' then begin if Length(DataBuf) = 0 then pDataBytes^ := 0 else begin L := Min(pDataBytes^, Byte(DataBuf[1])); try Move(DataBuf[2], pData^, L); pDataBytes^ := L; except Result := ERROR_NOACCESS; pDataBytes^ := 0; end; end; Break; end else if TagBuf = '_Err' then begin Result := ERROR_BAD_NET_RESP; pDataBytes^ := 0; SetLastError(StrAsInt(DataBuf)); Break; end { else if not bTriedRetry then begin bTriedRetry := True; ThisClient.TryRetry; end } else begin Result := ERROR_INVALID_DATA; pDataBytes^ := 0; ThisClient.InBuf2 := ''; Break; end; until False; if (Result = ERROR_TIMEOUT) and not ThisClient.ClientSock.bConnected then Result := ERROR_NOT_CONNECTED; end; function AEW_DEB_StrToStr(uClientRef: Pointer; pSendPacketBytes: PLongInt; pSendPacket: PAnsiChar; pReplyPacketBytes: PLongInt; pReplyPacket: PAnsiChar): LongWord; cdecl; var ThisClient: TVClientSock; SendBuf, ReplyBuf: AnsiString; //bTriedRetry: Boolean; L: Integer; begin Result := VerifyClientRef(uClientRef); if Result <> ERROR_SUCCESS then begin pReplyPacketBytes^ := 0; Exit; end; ThisClient := Pointer(uClientRef); if not ThisClient.ClientSock.bConnected then begin Result := ERROR_NOT_CONNECTED; pReplyPacketBytes^ := 0; Exit; end; pReplyPacketBytes^ := pReplyPacketBytes^; if pReplyPacketBytes^ <= 0 then begin Result := ERROR_BAD_LENGTH; pReplyPacketBytes^ := 0; Exit; end; try SetString(SendBuf, PAnsiChar(pSendPacket), pSendPacketBytes^); SetString(ReplyBuf, PAnsiChar(pReplyPacket), pReplyPacketBytes^); except Result := ERROR_NOACCESS; pReplyPacketBytes^ := 0; Exit; end; SendBuf := StrToL8Str(SendBuf); ReplyBuf := ''; while WaitForSingleObject(ThisClient.hGotDataSem, 0) = WAIT_OBJECT_0 do ; ThisClient.InBuf2 := ThisClient.InBuf2 + ThisClient.ClientSock.ReceiveStr; ThisClient.ClientSock.PostSendStr(SendBuf); //bTriedRetry := False; repeat Result := ReceivePacket(ThisClient, ReplyBuf); if Result <> ERROR_SUCCESS then Break; ReplyBuf := Copy(ReplyBuf, 2, MAXINT); if Length(ReplyBuf) = 0 then pReplyPacketBytes^ := 0 else begin L := Min(pReplyPacketBytes^, Length(ReplyBuf)); try Move(ReplyBuf[1], pReplyPacket^, L); pReplyPacketBytes^ := L; except Result := ERROR_NOACCESS; pReplyPacketBytes^ := 0; end; end; Break; until False; if (Result = ERROR_TIMEOUT) and not ThisClient.ClientSock.bConnected then Result := ERROR_NOT_CONNECTED; end; end.