Saving and loading jpeg images to database not working DELPHI - database

I'm trying to make a program that saves images in a database. I've pulled together some info on the net and wrote up code that I think is supposed to work, but fails in a completely unique way on either side (the saving and the loading).
Here's my code, could you tell me what I'm doing wrong?
Load from Database, gives me a memory address access violation error:
procedure TfrmMain.btnAddPickT4Click(Sender: TObject);
var
S : TMemoryStream;
ikode : integer;
begin
if cbxDeelnemerT4.ItemIndex < 0 then
begin
MessageDlg('Kies asseblief ''n deelnemer!',mtInformation,[mbOK],1);
Exit;
end;
if OpenPictureDialog1.Execute then
if FileExists(OpenPictureDialog1.FileName) then
Image1.Picture.LoadFromFile(OpenPictureDialog1.FileName)
else
MessageDlg('Die lĂȘer bestaan nie!',mtError,[mbOK],1);
ikode := cbxDeelnemerT4.ItemIndex + 1;
S := TMemoryStream.Create;
ADOQuery1.Close;
ADOQuery1.SQL.Text := 'SELECT * FROM DEELNEMERS WHERE Kode = '+inttostr(ikode);
ADOQuery1.Open;
try
Image1.Picture.Graphic.SaveToStream(S);
S.Position := 1;
ADOQuery1.Insert;
TBLobfield(ADOQuery1.FieldByName('Foto')).LoadFromStream(S);
finally
S.Free;
end;
end;
Saving to the database. This code doesn't give an error as such, but it just doesn't save the image to the database:
procedure TfrmMain.btnOpenProfileT4Click(Sender: TObject);
var
S : TMemoryStream;
ikode : integer;
begin
ikode := cbxDeelnemerT4.ItemIndex + 1;
S := TMemoryStream.Create;
ADOQuery1.Close;
ADOQuery1.SQL.Text := 'SELECT * FROM DEELNEMERS WHERE Kode = '+inttostr(ikode);
ADOQuery1.Open;
try
TBlobField(ADOQuery1.FieldByName('Foto')).SaveToStream(S);
S.Position := 0;
Image1.Picture.Graphic.LoadFromStream(S);
finally
s.Free;
end;
end;

You are calling TGraphic.LoadFromStream() but you are not initializing the TPicture.Graphic property with a valid TGraphic-derived object beforehand, so the property is likely nil, hense the crash.
Also, when saving the TPicture.Graphic to the TMemoryStream, you are skipping the first byte of the graphic when saving it to the DB. All of the bytes are important, so do not skip any of them.
Assuming your images are specifically JPEGs and nothing else (your saving code is not restricting the file type), then try this instead:
procedure TfrmMain.btnAddPickT4Click(Sender: TObject);
var
S : TMemoryStream;
ikode : integer;
begin
if cbxDeelnemerT4.ItemIndex < 0 then
begin
MessageDlg('Kies asseblief ''n deelnemer!',mtInformation,[mbOK],1);
Exit;
end;
if not OpenPictureDialog1.Execute then
Exit;
Image1.Picture.LoadFromFile(OpenPictureDialog1.FileName);
if not (Image1.Picture.Graphic is TJpegImage) then
raise Exception.Create('Sorry, only JPG images can be saved in the DB');
ikode := cbxDeelnemerT4.ItemIndex + 1;
S := TMemoryStream.Create;
try
Image1.Picture.Graphic.SaveToStream(S);
S.Position := 0;
ADOQuery1.Close;
ADOQuery1.SQL.Text := 'SELECT * FROM DEELNEMERS WHERE Kode = '+IntToStr(ikode);
ADOQuery1.Open;
ADOQuery1.Insert;
try
TBlobField(ADOQuery1.FieldByName('Foto')).LoadFromStream(S);
ADOQuery1.Post;
except
ADOQuery1.Cancel;
raise;
end;
finally
S.Free;
end;
end;
uses
..., Jpeg;
procedure TfrmMain.btnOpenProfileT4Click(Sender: TObject);
var
S : TMemoryStream;
ikode : integer;
Jpg: TJPEGImage;
begin
ikode := cbxDeelnemerT4.ItemIndex + 1;
ADOQuery1.Close;
ADOQuery1.SQL.Text := 'SELECT * FROM DEELNEMERS WHERE Kode = ' + IntToStr(ikode);
ADOQuery1.Open;
S := TMemoryStream.Create;
try
TBlobField(ADOQuery1.FieldByName('Foto')).SaveToStream(S);
S.Position := 0;
Jpg := TJPEGImage.Create;
try
Jpg.LoadFromStream(S);
Image1.Picture.Assign(Jpg);
finally
Jpg.Free;
end;
finally
S.Free;
end;
end;
But if your images can be other formats besides JPEG, then you need to store the image type in the DB as well so that you can read it back and instantiate the correct TGraphic class type (TBitmap, TJpegImage, TGifImage, TPNGImage, etc) to handle it as needed, eg:
procedure TfrmMain.btnAddPickT4Click(Sender: TObject);
var
S : TMemoryStream;
ikode : integer;
begin
if cbxDeelnemerT4.ItemIndex < 0 then
begin
MessageDlg('Kies asseblief ''n deelnemer!',mtInformation,[mbOK],1);
Exit;
end;
if not OpenPictureDialog1.Execute then
Exit;
Image1.Picture.LoadFromFile(OpenPictureDialog1.FileName);
ikode := cbxDeelnemerT4.ItemIndex + 1;
S := TMemoryStream.Create;
try
Image1.Picture.Graphic.SaveToStream(S);
S.Position := 0;
ADOQuery1.Close;
ADOQuery1.SQL.Text := 'SELECT * FROM DEELNEMERS WHERE Kode = '+IntToStr(ikode);
ADOQuery1.Open;
ADOQuery1.Insert;
try
// this is just an example, there are other ways to do this
if Image1.Picture.Graphic is TJPEGImage then
ADOQuery1.FieldByName('FotoType').AsString := 'jpg'
else if Image1.Picture.Graphic is TPNGImage then
ADOQuery1.FieldByName('FotoType').AsString := 'png'
else if Image1.Picture.Graphic is TGIFImage then
ADOQuery1.FieldByName('FotoType').AsString := 'gif'
else if Image1.Picture.Graphic is TBitmap then
ADOQuery1.FieldByName('FotoType').AsString := 'bmp'
else
raise Exception.Create('Cannot save unsupported image type to DB');
TBlobField(ADOQuery1.FieldByName('Foto')).LoadFromStream(S);
ADOQuery1.Post;
except
ADOQuery1.Cancel;
raise;
end;
finally
S.Free;
end;
end;
uses
..., Jpeg, GifImg, PngImg;
procedure TfrmMain.btnOpenProfileT4Click(Sender: TObject);
var
S : TMemoryStream;
ikode : integer;
Graphic: TGraphic;
GraphicType: String;
begin
ikode := cbxDeelnemerT4.ItemIndex + 1;
ADOQuery1.Close;
ADOQuery1.SQL.Text := 'SELECT * FROM DEELNEMERS WHERE Kode = ' + IntToStr(ikode);
ADOQuery1.Open;
S := TMemoryStream.Create;
try
TBlobField(ADOQuery1.FieldByName('Foto')).SaveToStream(S);
S.Position := 0;
GraphicType := ADOQuery1.FieldByName('FotoType').AsString;
if GraphicType = 'jpg' then
Graphic := TJPEGImage.Create
ADOQuery1.FieldByName('FotoType').AsString := 'jpg'
else if GraphicType = 'png' then
Graphic := TPNGImage.Create
else if GraphicType = 'gif' then
Graphic := TGifImage.Create
else if GraphicType = 'bmp' then
Graphic := TBitmap.Create
else
raise Exception.Create('Cannot load unsupported image type from DB');
try
Graphic.LoadFromStream(S);
Image1.Picture.Assign(Graphic);
finally
Graphic.Free;
end;
finally
S.Free;
end;
end;
With that said, you should not be accessing TBlobField directly. Use the TDataSet.CreateBlobStream() method instead, let ADO give you a TStream object that is optimized for accessing ADO blob data, eg:
procedure TfrmMain.btnAddPickT4Click(Sender: TObject);
var
S : TStream;
ikode : integer;
begin
if cbxDeelnemerT4.ItemIndex < 0 then
begin
MessageDlg('Kies asseblief ''n deelnemer!',mtInformation,[mbOK],1);
Exit;
end;
if not OpenPictureDialog1.Execute then
Exit;
Image1.Picture.LoadFromFile(OpenPictureDialog1.FileName);
ikode := cbxDeelnemerT4.ItemIndex + 1;
ADOQuery1.Close;
ADOQuery1.SQL.Text := 'SELECT * FROM DEELNEMERS WHERE Kode = '+IntToStr(ikode);
ADOQuery1.Open;
ADOQuery1.Insert;
try
...
S := ADOQuery1.CreateBlobStream(ADOQuery1.FieldByName('Foto'), bmWrite);
try
Image1.Picture.Graphic.SaveToStream(S);
finally
S.Free;
end;
ADOQuery1.Post;
except
ADOQuery1.Cancel;
raise;
end;
end;
procedure TfrmMain.btnOpenProfileT4Click(Sender: TObject);
var
S : TStream;
ikode : integer;
Graphic: TGraphic;
begin
ikode := cbxDeelnemerT4.ItemIndex + 1;
ADOQuery1.Close;
ADOQuery1.SQL.Text := 'SELECT * FROM DEELNEMERS WHERE Kode = ' + IntToStr(ikode);
ADOQuery1.Open;
...
Graphic := ...;
try
S := ADOQuery1.CreateBlobStream(ADOQuery1.FieldByName('Foto'), bmRead);
try
Graphic.LoadFromStream(S);
finally
S.Free;
end;
Image1.Picture.Assign(Graphic);
finally
Graphic.Free;
end;
end;

Related

Is there a way to switch components mid-loop?

I am trying to animate a dropdown menu of 7 images using a for loop, using a different component to change after each iteration of the code inside the for loop. For example, the first time the loop runs: imgCourses7.Top is used, but the second time the loop runs (when I = 1) then imgCourses6.Top should be used instead.
iCoursesCount := 7;
iTotalLength := (6+41)*iCoursesCount;
imgCourses7.Top := 6;
imgCourses6.Top := 6;
imgCourses5.Top := 6;
imgCourses4.Top := 6;
imgCourses3.Top := 6;
imgCourses2.Top := 6;
imgCourses1.Top := 6;
for I := 0 to iCoursesCount -1 do
begin
while not(imgCourses7.Top = iTotalLength - 41*(I+1)) do
begin
imgCourses8.Top := imgCourses8.Top + 6;
sleep(8);
application.ProcessMessages;
if imgCourses7.Top >= iTotalLength - 41*(I+1) then
begin
imgCourses7.Top := iTotalLength - 41*(I+1);
break;
end;
end;
end;
Like #AndreasRejbrand said in a comment, you can use an array, eg:
var
Images: array[0..6] of TImage;
TargetTop: Integer;
...
...
Images[0] := imgCourses7;
Images[1] := imgCourses6;
Images[2] := imgCourses5;
Images[3] := imgCourses4;
Images[4] := imgCourses3;
Images[5] := imgCourses2;
Images[6] := imgCourses1;
iCoursesCount := Length(Images);
TargetTop := 6+(41*iCoursesCount);
for I := 0 to iCoursesCount-1 do begin
Images[I].Top := 6;
end;
for I := 0 to iCoursesCount-1 do
begin
Dec(TargetTop, 41);
while Images[I].Top <> TargetTop do
begin
Images[I].Top := Images[I].Top + 6;
Sleep(8);
Application.ProcessMessages;
if Images[I].Top >= TargetTop then
begin
Images[I].Top := TargetTop;
Break;
end;
end;
end;
That being said, you really shouldn't be using a sleeping loop that requires Application.ProcessMessages() on each iteration. You might consider using a TTimer or TThread.ForceQueue() instead. Don't block the main UI thread unnecessarily. For example:
published
procedure FormCreate(Sender: TObject);
private
Images: array[0..6] of TImage;
TargetTop: Integer;
CurrentImage: Integer;
procedure StartAnimatingMenu;
procedure StartAnimatingNextMenuItem;
procedure StepAnimateCurrentMenuItem;
...
...
procedure TMyForm.FormCreate(Sender: TObject);
begin
Images[0] := imgCourses7;
Images[1] := imgCourses6;
Images[2] := imgCourses5;
Images[3] := imgCourses4;
Images[4] := imgCourses3;
Images[5] := imgCourses2;
Images[6] := imgCourses1;
end;
procedure TMyForm.StartAnimatingMenu;
var
I: Integer;
begin
for I := Low(Images) to High(Images) do begin
Images[I].Top := 6;
end;
TargetTop := 6+(41*Length(Images));
CurrentImage := -1;
StartAnimatingNextMenuItem;
end;
procedure TMyForm.StartAnimatingNextMenuItem;
begin
Inc(CurrentImage);
if CurrentImage < Length(Images) then
begin
Dec(TargetTop, 41);
StepAnimateCurrentMenuItem;
end;
end;
procedure TMyForm.StepAnimateCurrentMenuItem;
begin
if Images[CurrentImage].Top <> TargetTop then
begin
Images[CurrentImage].Top := Images[CurrentImage].Top + 6;
TThread.ForceQueue(nil, StepAnimateCurrentMenuItem, 8);
end
else if Images[CurrentImage].Top >= TargetTop then
begin
Images[CurrentImage].Top := TargetTop;
StartAnimatingNextMenuItem;
end;
end;

Save array of packed record to disk

I am getting crazy.
I am trying to save an array of packed record to disk to be read later on.
The following unit contain mainly two procedures.
The first one InitSaveAndReLoad(), init a packed array of record, save it to the disk and reload from the disk in a new array of packed record and go through the loaded array and print the 20 first value. Works perfectly.
The second one LoadFromFile(), just reload the array from disk. It is even call by InitSaveAndReload() and works perfectly as soon as the file has been created previously by the same instance of the application. I mean if I quit the application and relaunch, the LoadFromFile() procedure which just reload the file in an array of records does not works anymore. I don't understand why.
Any clue?
Thanks for your help. Already spend a full day on this issue and turning crazy!
unit Unit4;
interface
uses
Winapi.Windows, Winapi.Messages, System.SysUtils, System.DateUtils,
System.Variants, System.Classes, Vcl.Graphics,
Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.Menus, Vcl.StdCtrls;
type
TRate = packed record
time : int64;
open : double;
low : double;
high : double;
close : double;
tick_volume : int64;
spread : integer;
real_volume : int64;
end;
PRate = ^TRate;
TForm4 = class(TForm)
MemoLogs: TMemo;
SaveDialog1: TSaveDialog;
edFile: TEdit;
Button1: TButton;
Button2: TButton;
Button3: TButton;
Button4: TButton;
procedure InitSaveAndReload(Sender: TObject);
procedure Reload(Sender: TObject);
procedure SelectFile(Sender: TObject);
procedure LoadFromFile();
procedure Button4Click(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;
var
Form4: TForm4;
implementation
{$R *.dfm}
function TimeElapsedToString(time : int64; show_ms : boolean = false) : string;
var
TmpVal:real;
TmpStr:string;
begin
TmpVal := time;
TmpStr := '';
TmpVal := TmpVal / 3600000;
TmpStr := inttostr(trunc(TmpVal));
if Length(TmpStr) = 1 then TmpStr := '0' + TmpStr;
TmpVal := (TmpVal-trunc(TmpVal))* 3600000;
TmpVal := TmpVal / 60000;
if TmpVal<10 then
TmpStr := TmpStr + ':0' + inttostr(trunc(TmpVal))
else
TmpStr := TmpStr + ':' + inttostr(trunc(TmpVal));
TmpVal := (TmpVal-trunc(TmpVal))*60000;
TmpVal := TmpVal / 1000;
if TmpVal<10 then
TmpStr := TmpStr + ':0' + inttostr(trunc(TmpVal))
else
TmpStr := TmpStr + ':' + inttostr(trunc(TmpVal));
if show_ms then
begin
TmpVal := (TmpVal-trunc(TmpVal))*1000;
TmpVal := TmpVal;
if TmpVal<10 then
TmpStr := TmpStr + ':00' + inttostr(trunc(TmpVal))
else if TmpVal<100 then
TmpStr := TmpStr + ':0' + inttostr(trunc(TmpVal))
else
TmpStr := TmpStr + ':' + inttostr(trunc(TmpVal));
end;
Result := TmpStr;
end;
procedure TForm4.SelectFile(Sender: TObject);
begin
if SaveDialog1.Execute then
edFile.Text := SaveDialog1.FileName;
end;
procedure TForm4.Button4Click(Sender: TObject);
begin
MemoLogs.Lines.Clear;
end;
procedure TForm4.InitSaveAndReload(Sender: TObject);
var
_start : TDatetime;
ARate : PRate;
filename : string;
Stream : TFileStream;
i,L : integer;
rates_M1 : array of PRate;
//rates : array of PRate;
begin
filename := edFile.Text;
MemoLogs.Lines.Add('Initialization of 7 million array of records... Please wait.');
Refresh;
// init array
_start := Now;
SetLength(rates_M1, 7000000);
for i:= 0 to 6999999 do
begin
New(ARate);
ARate.time := DateTimeToUnix(IncMinute(Now, i));
ARate.open := 1.25698;
ARate.low := 1.2574;
ARate.high := 1.2547;
ARate.close := 1.65874;
ARate.tick_volume := 154;
ARate.spread := 5;
ARate.real_volume := 15741;
rates_M1[i] := ARate;
end;
MemoLogs.Lines.Add(IntToStr(Length(rates_M1)) + ' array of records initialized ' + TimeElapsedToString(MilliSecondsBetween(Now, _start), true));
// save array
_start:= Now;
Stream:= TFileStream.Create(filename , fmCreate);
try
L:= Length(rates_M1);
Stream.WriteBuffer(L, SizeOf(L));
Stream.WriteBuffer(Pointer(rates_M1)^, L * SizeOf(ARate));
finally
Stream.Free;
MemoLogs.Lines.Add(IntToStr(Length(rates_M1)) + ' records saved to disk in ' + TimeElapsedToString(MilliSecondsBetween(Now, _start), true));
end;
LoadFromFile();
end;
procedure TForm4.LoadFromFile;
var
_start : TDatetime;
ARate : PRate;
filename : string;
Stream : TFileStream;
i,L : integer;
rates : array of PRate;
begin
// reload array
_start := Now;
filename := edFile.Text;
Stream:= TFileStream.Create(filename , fmOpenRead);
try
Stream.Read(L, SizeOf(L));
//SetLength(rates_M1, L);
// even use another empty array of ARate to be sure I am not using the same filled array!
SetLength(rates, L);
// I don't want to parse all records...
// for i := 0 to L-1 do
// begin
// Stream.Read(rates_M1[i].AID, SizeOf(ARecord.AID));
// Stream.Read(rates_M1[i].time, SizeOf(ARecord.time));
// end;
Stream.Read(Pointer(rates)^, L * SizeOf(ARate));
finally
Stream.Free;
MemoLogs.Lines.Add(IntToStr(Length(rates)) + ' records loaded from disk in ' + TimeElapsedToString(MilliSecondsBetween(Now, _start), true));
end;
// Print 20 first records just reloaded!
MemoLogs.Lines.Add('Print 20 first records just reloaded in another array of records!' + TimeElapsedToString(MilliSecondsBetween(Now, _start), true));
for i := 0 to 20 do
MemoLogs.Lines.Add('i=' + IntToStr(i) + #9
+ IntToStr(rates[i].time) + #9
+ FloatToStr(rates[i].open) + #9
);
end;
procedure TForm4.Reload(Sender: TObject);
begin
LoadFromFile();
end;
end.
Result
When I say 'Does not works anymore', I mean once you called InitSaveAndReload() procedure, you can call LoadFromFile() as many time as you want, but if you to call this procedure just after launching the app, trying to use an old file created by the InitSaveAndReload procedure, then it does not work the same!
The Unit provide is as simple as possible. Just create a new projet add 3 buttons a TMemo and one TEdit. If I could join a .rar I would have enclosed the project...
You are saving the address of each record rather than saving contents of the record. You have an array of pointers, and you save that array to file. With your current data structure you would need to save each record individually, because the actual data does not lie contiguously in memory.

delphi Send a file as byte array to a Rest service

I'm using Delphi 10.1 Berlin
I want to send image data as TBytes to a Rest service using TRestRequest, but I could not find a way to pass a TBytes to the TRestRequest.AddBody() method, or any other method.
POST http://myserver:1111//Openxxx/RecxxxLxxxPxxxx HTTP/1.1
Content-Type: text/json
Host: myserver:1111
Content-Length: 28892
Expect: 100-continue
Connection: Keep-Alive
[255,216,255,224,0,16,74,70,73,70,0,1,1,0,0,1,0,1,0,0,255,219,0,132,0,9,
...
...
...
130,130,252,168,127,164,63,164,41,109,204,245,62,106,51,135,12,146,63,255,217]
TRESTRequest.AddBody() has an overload that accepts a TStream as input. You can wrap your TBytes into a TStream using the TBytesStream class.
procedure TForm1.Button1Click(Sender: TObject);
var
ABytes: TBytes;
AStream: TBytesStream;
begin
ABytes := ...;
try
AStream := TBytesStream.Create(ABytes);
RESTRequest1.AddBody(AStream, ctIMAGE_JPEG);
RESTRequest1.Execute;
finally
AStream.Free;
end;
end;
Alternatively, use TRESTRequestParameterList.AddItem instead, which has an overload for TBytes:
procedure TForm1.Button1Click(Sender: TObject);
var
ABytes: TBytes;
begin
ABytes := ...
RESTRequest1.Params.AddItem('body', ABytes, pkGETorPOST, [poDoNotEncode], ctIMAGE_JPEG);
RESTRequest1.Execute;
end;
That being said, I find TRESTClient to be overly complex and buggy/limiting. More times than not, Indy's TIdHTTP is easier to use, eg:
procedure TForm1.Button1Click(Sender: TObject);
var
ABytes: TBytes;
AStream: TBytesStream;
begin
ABytes := ...;
try
AStream := TBytesStream.Create(ABytes);
IdHTTP1.Request.ContentType := 'image/jpeg';
IdHTTP1.Post('http://myserver:1111//Openxxx/RecxxxLxxxPxxxx', AStream);
finally
AStream.Free;
end;
end;
procedure TForm1.Button1Click(Sender: TObject);
begin
IdHTTP1.Request.ContentType := 'image/jpeg';
IdHTTP1.Post('http://myserver:1111//Openxxx/RecxxxLxxxPxxxx', 'image.jpg');
end;
I've solved my problem like below:
function BytesToStr(abytes: tbytes): string;
var
abyte: byte;
begin
for abyte in abytes do
begin
Result := result + IntToStr(abyte) + ',';
end;
Result := '[' + Copy(Result, 1, Length(Result) - 1) + ']';
end;
procedure TForm1.Button1Click(Sender: TObject);
var
ABytes: TBytes;
begin
ABytes := TFile.ReadAllBytes('images.jpg');
RESTRequest1.Params.AddItem('body', BytesToStr(ABytes), pkREQUESTBODY, [], ctAPPLICATION_JSON);
RESTRequest1.Execute;
end;

TurboPowern OnGuard create license file with machine modifier

I use TurboPower onGuard for licensing and there is an option to specify and generate the machine specific keys for license validation. With following code I create machine modifier based on machineID
const
Ckey :TKey = ($56,$1B,$B0,$48,$2D,$AF,$F4,$E5,$30,$6C,$E5,$3B,$A7,$8E,$1A,$14);
procedure TForm1.FormCreate(Sender: TObject);
var
InfoSet : TEsMachineInfoSet;
MachineID : Longint;
begin
{ initialize the machine information set }
InfoSet := [midUser, midSystem, midNetwork, midDrives];
{ create the machine ID and display in hex }
try
MachineID := CreateMachineID(InfoSet);
Edit1.Text := '$' + BufferToHex(MachineID, SizeOf(MachineID));
except on E:Exception do
ShowMessage(E.Message);
end;
end;
procedure TForm1.Button1Click(Sender: TObject);
var
modifier :LongInt;
key :TKey;
releasecode,unlockcode :TCode;
inexpirydate: TdateTime;
begin
modifier := GenerateMachineModifierPrim ;
ApplyModifierToKeyPrim(Modifier, CKey, SizeOf(CKey));
//HexToBuffer(Ckey, key, SizeOf(TKey));
InitRegCode(Ckey, edit1.Text, inExpiryDate, releaseCode);
Edit2.text := BufferToHex(unlockCode, SizeOf(releaseCode));
end;
On the other hand to validate serial number and relase code I use the following code on client side to validate application, I place SerialNumberCode component to implement that.
Ckey :TKey = ($56,$1B,$B0,$48,$2D,$AF,$F4,$E5,$30,$6C,$E5,$3B,$A7,$8E,$1A,$14);
procedure TForm1.OgSerialNumberCode1GetKey(Sender: TObject; var Key: TKey);
begin
Key := Ckey;
end;
procedure TForm1.OgSerialNumberCode1GetModifier(Sender: TObject;
var Value: LongInt);
begin
Value := GenerateMachineModifierPrim;
end;
function TForm1.GetSNData(var S: string): integer;
var
TC : TCode;
SNC : string;
modifier :LOngInt;
begin
try
modifier := GenerateMachineModifierPrim;
ApplyModifierToKeyPrim(Modifier, CKey, SizeOf(CKey));
IniSNVal := StrToInt(InputBox('Serial number', 'Enter serial Value ', '12345678'));
SNC := (InputBox('release code', 'Enter code ', ''));
{Check that Release Code was entered correctly}
HexToBuffer(SNC, TC, SizeOf(TCode));
if not (IsSerialNumberCodeValid(CKey, TC)) then begin
S := 'Release code not entered correctly';
Result := mrCancel;
end else begin
IniFile := TIniFile.Create(TheDir + 'test.INI');
try
IniFile.WriteInteger('Codes', 'SN', IniSNVal);
IniFile.WriteString('Codes', 'SNCode', SNC);
finally
IniFile.Free;
end;
end;
finally
end;
end;
procedure TForm1.OgSerialNumberCode1GetCode(Sender: TObject; var Code: TCode);
var
S1 : string;
L : integer;
begin
if not (FileExists(TheDir + 'test.INI')) then
Exit;
{open Ini File}
IniFile := TIniFile.Create(TheDir + 'test.INI');
try
{try to read release code}
S1 := IniFile.ReadString('Codes', 'SNCode', '');
IniSNVal := IniFile.ReadInteger('Codes', 'SN', 0);
{convert retrieved string to a code}
HexToBuffer(S1, Code, SizeOf(Code));
finally
IniFile.Free;
end;
end;
procedure TForm1.OgSerialNumberCode1Checked(Sender: TObject; Status: TCodeStatus);
var
S,
C1,
C2 : string;
TC : TCode;
LI : longint;
begin
case Status of
ogValidCode : begin
{check if retrieved Serial Number matches Code}
LI := OgSerialNumberCode1.GetValue;
if (LI <> IniSNVal) then begin
Status := ogInvalidCode;
S := 'The serial number has been changed';
end else begin
ShowMessage('Serial #: ' + IntToStr(IniSNVal));
Exit;
end;
end;
ogInvalidCode : begin
{if INI file doesn't exist, presume this is first run}
if not (FileExists(TheDir + 'test.INI')) then
begin
if not (GetSNData(S) = mrCancel) then begin
{Check the SN/ReleaseCode}
OgSerialNumberCode1.CheckCode(True);
{must Exit since line above began a recursive call}
Exit;
end;
end else
S := 'Invalid Code';
end;
ogCodeExpired : S := 'Evaluation period expired';
end;
ShowMessage(S);
Application.Terminate;
end;
But at the client side machine never accepts the validation and throws Release code not entered correctly. Probably I don't understand usage of machineID exmaple in onguard folder. Please also note that the key for client side and generation for relaease code is same so there shouldn't be any mismatch.

How to send files from two different location with one TCP-Server?

How to send files from two different locations via only one TCP-Server, I managed to send files from one location only.
This the code to send from one directory ...
procedure TForm1.Timer1Timer(Sender: TObject);
var
fs: TFileStream;
fn: string;
sr: TSearchRec;
I: integer;
begin
I := 0;
if FindFirst('C:/*.jpg', faAnyFile, sr) = 0 then
begin
with StringGrid1 do
begin
ListBox1.Items.Add('C:/' + sr.Name);
while FindNext(sr) = 0 do
begin
ListBox1.Items.Add('C:/' + sr.Name);
Inc(I);
if I = 7 then
Break;
end;
FindClose(sr);
idTCPClient1.Connect;
for fn in ListBox1.Items do
begin
fs := TFileStream.Create(fn, fmOpenRead or fmShareDenyWrite);
try
idTCPClient1.IOHandler.WriteLn(ExtractFileName(fn));
idTCPClient1.IOHandler.Write(fs, 0, True);
idUDPClient1.Send(lbLatitude.Text + ',' + lbLongitude.Text);
Finally
fs.Free;
end;
end;
end;
end;
end;
All you have to do (without completely re-writing your code, like DavidH suggested) is simply fill your ListBox with paths from all of the different directories that you want, eg:
procedure TForm1.Timer1Timer(Sender: TObject);
var
fs: TFileStream;
fn: string;
sr: TSearchRec;
I : integer;
begin
I := 0;
if FindFirst('C:/*.jpg', faAnyFile, sr) = 0 then
begin
repeat
ListBox1.Items.Add('C:/' + sr.Name);
Inc(I);
if I = 7 then Break;
until FindNext(sr) <> 0;
FindClose(sr);
end;
if I < 7 then
begin
if FindFirst('C:/Some Other Folder/*.jpg', faAnyFile, sr) = 0 then
begin
repeat
ListBox1.Items.Add('C:/Some Other Folder/' + sr.Name);
Inc(I);
if I = 7 then Break;
until FindNext(sr) <> 0;
FindClose(sr);
end;
end;
idTCPClient1.Connect;
for fn in ListBox1.Items do
begin
fs := TFileStream.Create(fn, fmOpenRead or fmShareDenyWrite);
try
IdTCPClient1.IOHandler.WriteLn(ExtractFileName(fn));
IdTCPClient1.IOHandler.Write(fs, 0, True);
...
finally
fs.Free;
end;
end;
end;

Resources