open database with initfile - database

how to open a database local or remote with IniFile.
something like the below.
vBanco : String;
IniFileName : TIniFile;
begin
IniFileName := TIniFile.Create(ExtractFilePath(ParamStr(0))+FileName);
Try
if FileExists (remote+'db\ado.mdb') then
begin
vBanco := Trim(IniFileName.ReadString('acesso','BancoRemto',''));
Dirlocal := Trim(IniFileName.ReadString('acesso','PastasRemto',''));
frmPrincipal.Edit1.text := Dirlocal;
Dirtrabalho := (ExtractFilePath(Application.ExeName));
Conection.ConnectionString := vBanco;
end
else
begin
Try
vBanco := Trim(IniFileName.ReadString('acesso','banco',''));
Dirlocal := Trim(IniFileName.ReadString('acesso','PastasLocais',''));
frmPrincipal.Edit1.text := Dirlocal;
Dirtrabalho := (ExtractFilePath(Application.ExeName));
Finally
end;
end;
Finally
IniFileName.Free;
end;
end;

It seems as if you have your code correct, if you are running into problems make sure the value of the INI Connection string is valid. A Good way to get a valid connect string is to setup the connection at design time then copy and paste it to your config file.

If your problem is with FileExists, here's how you track it down.
Put a breakpoint on the if FileExists line. When it breaks to the debugger, hit CTRL-F7, which will bring up the Evaluate/Modify dialog. Type remote+'db\ado.mdb' into the input box and see what it gives. It'll most likely give you a bad filename.
For example, if remote doesn't end in a backslash, then that will yield an invalid path. You can fix this with the IncludeTrailingPathDelimiter function. Hard to be certain without seeing more of your code, but from my experience that's probably what's going on.

I found my mistake. Instead of checking the existence of a file named "ado.mdb" in a directory based on the global variable remote, I should have been looking for a file named "base_dados.mdb" in a directory determined by a value I read from an INI file.
procedure TfrmDados.ConectionBeforeConnect(Sender: TObject);
const
FileName = 'config.ini';
var
vBanco : String;
IniFileName : TIniFile;
LBasedados : String;
begin
IniFileName := TIniFile.Create(ExtractFilePath(ParamStr(0))+FileName);
vBanco := Trim(IniFileName.ReadString('acesso','BDtrabalho',''));
Dirlocal := Trim(IniFileName.ReadString('acesso','Pastrabalho',''));
LBasedados := Dirlocal+'db\base_dados.mdb';
frmPrincipal.Edit1.text := Dirlocal;
Dirtrabalho := (ExtractFilePath(Application.ExeName));
if FileExists(LBasedados) then
Conection.ConnectionString := vBanco
else
begin
Application.MessageBox('Bade dados do servidor não encontrada vai trabalhar neste Computador!','Ligação Remota FALHOU');
vBanco := Trim(IniFileName.ReadString('acesso','BD_local',''));
Dirlocal := Trim(IniFileName.ReadString('acesso','Pasta_local',''));
frmPrincipal.Edit1.text := Dirlocal;
Dirtrabalho := (ExtractFilePath(Application.ExeName));
Conection.ConnectionString := vBanco;
end;
IniFileName.Free;
end;

Related

Delphi Text File and Array

I have the following Scenario: In a textfile (justin#us883) the program must extract the password - us883 check if the password typed in is correct to the one in the list and then make a button visible to enter program: Code that is not working:
var
textf:textfile;
oneline,spass,scheck :string;
place,i,icount :integer;
Arrpass : array[1..Maxnames] of string;
begin
scheck := edtpass.Text;
assignfile(textf,'Userlist.txt');
reset(textf);
if fileExists('Userlist.txt')= false then
exit;
while not eof(textf) do
begin
Readln(textf, oneline);
place := pos('#',oneline);
delete(oneline,1,place);
spass := copy(oneline,1,place-1); // get the us883
Arrpass[i] := spass;
for i := Low(Arrpass) to High(Arrpass) do
if Arrpass[i] = spass then
begin
btnenter.Visible := true
end
else
btnenter.Visible := False;
Showmessage('Wrong Password');
end;
closefile(textf);
end;
Maybe you want to do it more delphi like:
var
list : TStringList;
user, password : String;
i : Integer;
begin
user := 'user1';
if fileExists('Userlist.txt')= false then exit;
list := TStringList.create();
list.NameValueSeparator := '#';
list.LoadFromFile('Userlist.txt');
i := list.IndexOfName(user);
if i >=0 then begin
password := list.Values[user];
// check password
end;
Issue 1:
place := pos('#',oneline);
delete(oneline,1,place);
spass := copy(oneline,1,place-1); // get the us883
The third line uses position of # that is not more actual (after deletion).
If you don't expect more symbols after password, just use
spass := oneline;
Issue 2:
How Arrpass array sould be filled?
This line Arrpass[i] := spass; uses uninitialized variable i. And what is a logic to compare just inserted value with itself? Perhaps you want to fill ArrPass before text reading.
Issue 3:
It is worth to check if fileExists before file handling.

Delphi TRichEdit to Array and local storage

I'm looking for informations on how to put TRichEdit into an Array and save it to Local file (ex: File.dat).
The goal is to store a number of text, with a description, and the 'name' of it.
I think I have to start with:
type
TMessage = record
Name : string;
Desc : string;
Text : TMemoryStream;
end;
var ARListMessages: array[1..50] of TMessage
And add data with something like:
richedit.Lines.SaveToStream( ARListMessages[i].Text );
How to create the Array, and make manipulations on it (Add, remove
...) with the 'name'?
How can I save it (Array), and load it easily from local storage ? (Ex:
File.dat)
I've found some informations here, without beeing able to make something working.
Thanks for your time.
[EDIT 18/09/2017]
I'm Still looking to find a solution, and try to find a way to save my informations to a local file.
My actual code to test is :
var
MessageArray : array of TMessage;
// // // //
SetLength(MessageArray, 1);
MessageArray[0].Name := 'Hey You';
MessageArray[0].Desc := 'Im here and will stay here, just in case';
MessageArray[0].Text := TMemoryStream.Create;
MessageArray[0].Text.Position := 0;
RichEdit1.plaintext := false;
RichEdit1.Lines.SaveToStream( MessageArray[0].Text );
So, looking to save MessageArray, but haven't find how to do that yet.
I've take a look on SuperObjet, but can't find how to deal with it.
Omxl was looking Great and easy, but free trial ... :(
I've been able to have an answer.
I share it here if someone need the solution.
program Project1;
{$APPTYPE CONSOLE}
{$R *.res}
uses
System.SysUtils, System.Generics.Collections, Classes, System.Zip;
type
TPersonne = class
strict private
FNom : string;
FPrenom: string;
public
property Nom: string read FNom write FNom;
property Prenom: string read FPrenom write FPrenom;
end;
TFamille = class(TDictionary<string, TPersonne>)
private
procedure LoadFromStream(stream: TStream);
procedure SaveToStream(stream: TStream);
public
procedure LoadFromFile(const AFileName: string);
procedure SaveToFile(const AFileName: string);
end;
procedure TFamille.SaveToStream(stream: TStream);
var
i: Integer;
Personne: TPersonne;
Pair: System.Generics.Collections.TPair<string, TPersonne>;
Writer: TWriter;
begin
Writer := TWriter.Create(stream, 4096);
try
Writer.WriteListBegin;
for Pair in Self do
begin
Writer.WriteString(Pair.Key);
Writer.WriteListBegin;
Personne := Pair.Value;
Writer.WriteString(Personne.Nom);
Writer.WriteString(Personne.Prenom);
Writer.WriteListEnd;
end;
Writer.WriteListEnd;
finally
Writer.Free;
end;
end;
procedure TFamille.LoadFromStream(stream: TStream);
var
Personne: TPersonne;
Reader: TReader;
sKey: string;
begin
Clear;
Reader := TReader.Create(stream, 1024);
try
Reader.ReadListBegin;
while not Reader.EndOfList do
begin
sKey := Reader.ReadString;
Personne := TPersonne.Create;
Reader.ReadListBegin;
while not Reader.EndOfList do
begin
Personne.Nom := Reader.ReadString;
Personne.Prenom := Reader.ReadString;
end;
Reader.ReadListEnd;
Add(sKey, Personne);
end;
Reader.ReadListEnd;
finally
Reader.Free;
end;
end;
procedure TFamille.LoadFromFile(const AFileName: string);
var
Stream: TStream;
begin
Stream := TFileStream.Create(AFileName, fmOpenRead);
try
LoadFromStream(Stream);
finally
Stream.Free;
end;
end;
procedure TFamille.SaveToFile(const AFileName: string);
var
stream: TStream;
begin
stream := TFileStream.Create(AFileName, fmCreate);
try
SaveToStream(stream);
finally
stream.Free;
end;
end;
var
Famille: TFamille;
Personne: TPersonne;
begin
try
Famille := TFamille.Create;
try
Personne := TPersonne.Create;
Personne.Nom := 'Julie';
Personne.Prenom := 'Albertine';
Famille.Add('1', Personne);
Famille.SaveToFile('D:\famille.txt');
finally
FreeAndNil(Famille);
end;
Famille := TFamille.Create;
try
Famille.LoadFromFile('D:\famille.txt');
if Famille.Count > 0 then
Writeln(Famille['1'].Nom + ' ' + Famille['1'].Prenom);
finally
FreeAndNil(Famille);
end;
Readln;
except
on E: Exception do
Writeln(E.ClassName, ': ', E.Message);
end;
end.
Thanks all for your Help !
How to create the Array, and make manipulations on it (Add, remove
...) with the 'name'?
From your first code the array is already created. No further work is needed. And even if you use dynamic arrays you still don't have to do any thing just declaring it will suffice.
If you are asking "How to create the array ?" as in "How to create such a list, so I could add, remove with the 'name' field" then I would suggest TDictionary (instead of the city names use your field 'name' as a key) to do the manipulations and then when saving use this
How can I save it (Array), and load it easily from local storage ?
(Ex: File.dat)
You can't directly just like array.savetofile;.You need to use one of file handling methods like TFileStream to store the array.
Note: in your edit the memory stream will cause you only trouble because each time you create it you will need to free it after its use instead use these functions to extract formatted text and change the field Text : TMemoryStream; to Text : string;
RichTextToStr: Convert the rich format text to a string.
function RichTextToStr(RichEdit:TRichEdit):string;
var
SS : TStringStream;
begin
SS := TStringStream.Create('');
try
RichEdit.Lines.SaveToStream(SS);
Result := SS.DataString;
finally
SS.Free;
end;
end;
loadToRichedit: Load the formatted text to the RichEdit again.
procedure loadToRichedit(Const St:string;RichEdit:TRichEdit);
var
SS : TStringStream;
begin
SS := TStringStream.Create(St);
try
RichEdit.Lines.LoadFromStream(SS);
finally
SS.Free;
end;
end;

Moving the content of a folder to another one

Using Delphi 7, I need to move all the content (files, folders and subfolders) from one folder to another one. After some research, SHFileOpStruct seems to be the best option. Here is what I got so far:
function MoveDir(SrcDir, DstDir: string): Boolean;
var
FOS: TSHFileOpStruct;
begin
ZeroMemory(#FOS, SizeOf(FOS));
with FOS do
begin
wFunc := FO_MOVE; // FO_COPY;
fFlags := FOF_FILESONLY or
FOF_ALLOWUNDO or FOF_SIMPLEPROGRESS;
pFrom := PChar(SrcDir + #0);
pTo := PChar(DstDir + #0);
end;
Result := (SHFileOperation(FOS) = 0);
end;
But when using this function, the entire folder is moved to destination, not only it content. For example, if I use MoveDir('c:\test', 'd:\test') I get d:\teste\teste.
I already tried to change this line bellow, and it works when coping the files (FO_COPY) but not when moving.
pFrom := PChar(SrcDir + '\*.*' + #0);
Please, can someone help me with this? Would be great if I can do this without moving file by file, folder by folder...
Thanks!!
You should use your second version, without FOF_FILESONLY flag:
function MoveDir(SrcDir, DstDir: string): Boolean;
var
FOS: TSHFileOpStruct;
begin
ZeroMemory(#FOS, SizeOf(FOS));
with FOS do
begin
wFunc := FO_MOVE; // FO_COPY;
fFlags := FOF_ALLOWUNDO or FOF_SIMPLEPROGRESS;
pFrom := PChar(IncludeTrailingPathDelimiter(SrcDir) + '*.*'#0);
pTo := PChar(DstDir + #0);
end;
Result := (SHFileOperation(FOS) = 0);
end;

Login display error message

I need my program to log a user in from a database. This entails a diver number (like a username) and a password which is already in the database. Unfortunately, I don't know SQL right now and would rather use a technique similar to the one I've done here. I get an error message in run time that says: adotblDiversInfo: Cannot perform this operation on a closed dataset. Thank you so much for your help in advance (:
This is my code:
procedure TfrmHomeScreen.btnLogInClick(Sender: TObject);
var
iDiverNumber : Integer;
sPassword, sKnownPassword : String;
bFlagDiverNumber, bFlagPassword, Result : Boolean;
begin
iDiverNumber := StrToInt(ledDiverNumber.Text);
sPassword := ledPassword.Text;
with frmDM do
adotblDiversInfo.Filtered := False;
frmDM.adotblDiversInfo.Filter := 'Diver Number' + IntToStr(iDiverNumber);
frmDM.adotblDiversInfo.Filtered := True;
if frmDM.adotblDiversInfo.RecordCount = 0 then
ShowMessage(IntToStr(iDiverNumber) + ' cannot be found')
else
begin
sKnownPassword := frmDM.adotblDiversInfo['Password'];
if sKnownPassword = sPassword then
ShowMessage('Login successful')
else
ShowMessage('Incorrect password. Please try again');
end;
end;
The error you're getting is because you've forgotten to open the dataset before attempting to access it. Use frmDM.adoTblDiversInfo.Open; or frmDM.adoTblDiversInfo.Active := True; to do so before trying to use the table.
Your code could be much simpler (and faster) if you change it somewhat. Instead of filtering the entire dataset, simply see if you can Locate the proper record.
procedure TfrmHomeScreen.btnLogInClick(Sender: TObject);
var
iDiverNumber : Integer;
begin
if not frmDM.adoTblDiversInfo.Active then
frmDM.adoTblDiversInfo.Open;
iDiverNumber := StrToInt(ledDiverNumber.Text);
sPassword := ledPassword.Text;
if frmDM.adoTblDiversInfo.Locate('Diver Number', iDiverNumber, []) the
begin
if frmDM.adoTblDiversInfo['Password'] = ledPassword.Text then
ShowMessage('Login successful')
else
ShowMessage('Invalid password. Please try again.');
end
else
ShowMessage(ledDiverNumber.Text);
end;

What is the proper way to dynamically create and call a stored procedure in Delphi using FireDac?

I am relatively new to FireDAC. I want to be able to call a stored procedure "on the fly", dynamically. So far I have the following:
function TForm21.ExecuteStoredProc(aSPName: string; aParams: TADParams): Boolean;
var
LSP: TADStoredProc;
i: Integer;
begin
LSP := TADStoredProc.Create(nil);
try
LSP.Connection := ADConnection1;
LSP.StoredProcName := aSPName;
LSP.Prepare;
for i := 0 to aParams.Count - 1 do
begin
LSP.Params[i].Value := aParams[i].Value;
end;
LSP.ExecProc;
finally
LSP.Free;
end;
Result := True;
end;
I call it with
procedure TForm21.Button1Click(Sender: TObject);
var
LParams: TADParams;
begin
LParams := TADParams.Create;
LParams.Add.Value := 612;
LParams.Add.Value := '2008';
ExecuteStoredProc('HDMTEST.dbo.spARCHIVE_HISTORY_DATA', LParams);
end;
However, the stored procedure fails to execute. That is, the code runs fine, no error message is shown, but the stored procedure doesn't run.
Further info -- it runs fine if I drop a component and set up the params in code.
Anyone have any idea what I am missing?
Seeing as this q has been left unanswered for a while, I thought I'd try to get the code working without using the clues from the comments and found it not quite as easy as I'd imagined.
I immediately got stuck with the SP params. I found this
http://docwiki.embarcadero.com/RADStudio/XE5/en/TFDQuery,_TFDStoredProc_and_TFDUpdateSQL_Questions
which says
"If you have difficulties with manual definition of parameters,
populate the Params collection automatically and check how the
parameters are defined. Then compare that to your code. "
but I couldn't find a way of "automatically" populating the Params. I asked on the EMBA
FireDac newsgroup and the FD author, Dimitry Arefiev, kindly explained that
you can do that by checking that the FetchOptions include fiMeta, and then clearing and setting the FDStoredProc's StoredProcName.
Using a StoredProc in the pubs demo database on my SqlServer defined as follows:
create procedure test(#ANumber int, #AName varchar(20))
as
begin
select
#ANumber * 2 as "Number",
#AName + #AName as "Name"
end
I changed a couple of sections of the OP's code like this
[...]
LSP.Params.Clear;
LSP.StoredProcName := '';
LSP.FetchOptions.Items := LSP.FetchOptions.Items + [fiMeta];
LSP.StoredProcName := aSPName;
LSP.Prepare;
Assert(LSP.ParamCount > 0);
for i := 0 to aParams.Count - 1 do
begin
LSP.Params.ParamByName(aParams[i].Name).Value := aParams[i].Value;
end;
[...]
procedure TForm21.Button1Click(Sender: TObject);
var
LParams: TFDParams;
Param : TFDParam;
begin
LParams := TFDParams.Create;
Param := LParams.Add;
Param.Name := '#ANumber';
Param.Value := 612;
Param := LParams.Add;
Param.Name := '#AName';
Param.Value := '2008';
ExecuteStoredProc('test', LParams);
end;
and it worked fine.
The OP mentions in the q he'd first had the problem that the SP failed to execute
but that he'd found that it worked if he "[dropped] a component and set up the params in code" so I thought I'd include here a console application where of course necessarily everything is done in code. This wasn't difficult, but the time it took me to get the Uses clause right is my main reason for posting this as an answer, for future reference. W/o the correct uses, you get errors complaining about various class factories being missing.
Console app (created and tested in XE6):
program ConsoleStoredProcProject3;
{$APPTYPE CONSOLE}
{$R *.res}
uses
System.SysUtils, FireDac.DApt, FireDAC.Stan.Def, FireDAC.Stan.ASync,
FireDAC.Stan.Param, FireDAC.Stan.Option, FireDAC.Comp.Client,
FireDAC.Phys.MSSQL, VCL.ClipBrd;
procedure TestSP;
var
Connection : TFDConnection;
StoredProc : TFDStoredProc;
Param : TFDParam;
begin
Connection := TFDConnection.Create(Nil);
Connection.DriverName := 'MSSQL';
Connection.Params.Values['Server'] := // your server name'';
Connection.Params.Values['Database'] := 'pubs';
Connection.Params.Values['user_name'] := 'user'; // adjust to suit
Connection.Params.Values['password'] := 'password'; // ditto
Connection.LoginPrompt := False;
Connection.Connected := True;
StoredProc := TFDStoredProc.Create(Nil);
StoredProc.Connection := Connection;
StoredProc.FetchOptions.Items := StoredProc.FetchOptions.Items + [fiMeta];
StoredProc.StoredProcName := 'test';
StoredProc.Prepare;
Param := StoredProc.Params.ParamByName('#ANumber');
Param.Value := 333;
Param := StoredProc.Params.ParamByName('#AName');
Param.Value := 'A';
StoredProc.Active := True;
WriteLn(StoredProc.FieldByName('Number').AsInteger);
WriteLn(StoredProc.FieldByName('Name').AsString);
ReadLn;
end;
begin
try
TestSP;
except
on E: Exception do
Clipboard.AsText := E.Message;
end;
end.

Resources