Check at startup if db is protected or not

Dear Experts,

I have a dialogform called PropertiesDlg. On it is just 1 checkbox called PswChkBx.
The OnClick-event looks like this:

procedure TPropertiesDlg.PswChkBxClick(Sender: TObject);
var
 InputStr1 : string;
 InputStr2 : string;
begin
 if PswChkBx.Checked then
  begin
   InputStr1 := GetInput('Password', 'Please enter new password:');
   if InputStr1 <> '' Then  
    begin
     InputStr2 := GetInput('Password', 'Please confirm new password:');
     if InputStr2 <> '' then  
      begin
       if InputStr1 <> InputStr2  
        then showmessage('The confirmation password was not correct. Password is unchanged.')
        else
         begin
          showmessage('Password successfully changed.');
          MainForm.SetPassword(InputStr2);
          Exit;
         end;
      end;
    end;
   PswChkBx.Checked:=False;
  end;
end;

The procedure above calls for this procedure that actually sets
the password:

procedure TMainForm.SetPassword(aPassword: String);
var  ovConn:        OleVariant;
const
  adModeShareExclusive =  12;
begin
  ADOConnection1.Close;
  ovConn:=CreateOleObject('ADODB.Connection');
  try
     ovConn.Mode:=adModeShareExclusive;
        ovConn.Open(Format('Provider=Microsoft.Jet.OLEDB.4.0;Data Source="%s"', [DBPath+'\'+DBName]));
        ovConn.Execute(Format('ALTER DATABASE PASSWORD `%s` NULL', [aPassword]));
        ovConn.Close;
  finally
     ovConn:=Unassigned;
  end;
end;

Now the I just have one problem to solve:
The programm has to look if the database is protected or not when a db
get loaded with the Open1Click (from the OpenDialog) OR the OpenRecentFileList
procedure (From the recent file list). Both calls for the OpenDatabase-procedure
that I have put in the code-section. This procedures works great. Only there has
to be added some code, and that is when a db is loaded that is protected the
checkbox on the PropertiesDlg have to be checked, and when its not protected
unchecked.

Who can help me to solve this problem?

Peter Kiers

procedure TMainForm.OpenDatabase; 
var 
 i: integer; 
begin 
  if not IsLogin(DBPath+'\'+DBName) then 
  begin 
    PostMessage(Handle, InputBoxMessage, 0, 0); 
    if not IsLogin(DBPath+'\'+DBName, InputBox('Password', 'Please enter password:', '')) then 
    begin 
    showmessage('Invalid Password'); 
    Exit; 
    end; 
   end; 
  with PageControl1 do for i:=Pagecount -1 downto 0 do pages[i].Free;  <== have to stay there 
  ADOTable1.Open; 
  ADOTabs.Open; 
  LoadTree; 
end; 
 
function TMainForm.IsLogin(DatabaseName, Password: string): boolean; 
begin 
    Result := False; 
    ADOConnection1.Close; 
    ADOConnection1.ConnectionString := 'Provider=Microsoft.Jet.OLEDB.4.0;Data ' + 
      'Source='+DatabaseName+';Mode=ReadWrite;Persist ' ; 
    if Password <> '' then ADOConnection1.ConnectionString := 
    ADOConnection1.ConnectionString + 
     'Security Info=False;Jet OLEDB:Database Password='+Password; 
    try 
      ADOConnection1.Open; 
      if ADOConnection1.Connected then Result := True; 
      if Pos('dbtree.pkr', DatabaseName) = 0 then 
      Caption := ExtractFileName(DatabaseName) + ' - ' + 'Personal Knowledgebase'; 
    except 
      Result := False; 
    end; 
end;

Open in new window

LVL 1
peterkiersAsked:
Who is Participating?
I wear a lot of hats...

"The solutions and answers provided on Experts Exchange have been extremely helpful to me over the last few years. I wear a lot of hats - Developer, Database Administrator, Help Desk, etc., so I know a lot of things but not a lot about one thing. Experts Exchange gives me answers from people who do know a lot about one thing, in a easy to use platform." -Todd S.

peterkiersAuthor Commented:
be back in a few hours. PK
0
Emmanuel PASQUIERFreelance Project ManagerCommented:
here is the code.

the ConnectString function that gives the right connect string for all places where it is needed is a must-have, as your current code is doing the format every time. It's getting complex with the password issues.

So your main form will get hold of the last working password along with the DBName.

SetPassword will take care of setting and clearing the password, and maintain the _Password stored in Main form, and also the state of the checkbox in your property dialog.

IsLogin will work as usual, except that it does not need the Database parameter, it uses the DBPath & DBName variables like everything else.


// declare _Password in TMainForm
TMainForm=class(TForm)
//...
 private
  _Password:String;
//...  
 end;

function TMainForm.ConnectString(Password:String=''):String;
begin
 if Password<>'' 
  Then Result:=Format('Provider=Microsoft.Jet.OLEDB.4.0:Database Password=%s;Data Source="%s";Persist Security Info=False;', [Password,DBPath+'\'+DBName]))
  Else Result:=Format('Provider=Microsoft.Jet.OLEDB.4.0;Data Source="%s";Persist Security Info=False;', [DBPath+'\'+DBName]));
end;

function TMainForm.SetPassword(aPassword: String):Boolean;
Var
 OldPass,NewPass:String;
begin
 if _Password<>'' Then OldPass:='`'+_Password+'`' Else OldPass:='NULL';
 if aPassword<>'' Then NewPass:='`'+aPassword+'`' Else NewPass:='NULL';
 With ADOConnection1 do 
  try
   if Connected Then Close;
   ConnectionString:=ConnectString(_Password);
   Mode:=cmShareExclusive;
   Open;
   Execute('ALTER DATABASE PASSWORD '+NewPass+' '+OldPass);
   Result:=True;
  except
   Result:=False;
  end;
 if Result Then _Password:=aPassword;
 IsLogin(_Password); // reconnect
end;

function TMainForm.IsLogin(Password: string): boolean;
begin
 With ADOConnection1 do 
  try
   if Connected Then Close;
   ConnectionString:=ConnectString(Password);
   Mode:=cmReadWrite;
   Open;  
   Result := ADOConnection1.Connected;
   if Result Then _Password:=Password;
   if Pos('dbtree.pkr', DatabaseName) = 0 then
   Caption := ExtractFileName(DatabaseName) + ' - ' + 'Personal Knowledgebase';
  except
   Result := False;
  end;
 PropertiesDlg.PswChkBx.Checked:=_Password<>'';
end;

procedure TMainForm.OpenDatabase;
var
 i: integer;
begin
 if not IsLogin('') then
  begin
   PostMessage(Handle, InputBoxMessage, 0, 0);
   if not IsLogin(InputBox('Password', 'Please enter password:', '')) then
    begin
     showmessage('Invalid Password');
     Exit;
    end;
  end;
 with PageControl1 do for i:=Pagecount -1 downto 0 do pages[i].Free;  <== have to stay there
 ADOTable1.Open;
 ADOTabs.Open;
 LoadTree;
end;

// in PropertiesDlg

procedure TPropertiesDlg.PswChkBxClick(Sender:  TObject);
var
 InputStr1 : string;
 InputStr2 : string;
begin
 if PswChkBx.Checked then
  begin
   InputStr1 := GetInput('Password', 'Please enter new password:');
   if InputStr1 <> '' Then  
    begin
     InputStr2 := GetInput('Password', 'Please confirm new password:');
     if InputStr2 <> '' then  
      begin
       if InputStr1 <> InputStr2  
        then showmessage('The confirmation password was not correct. Password is unchanged.')
        else
         begin
          if MainForm.SetPassword(InputStr2) 
           Then showmessage('Password successfully changed.')
           Else ShowMessage('Password could not be changed!');
          Exit;
         end;
      end;
    end;
  end;
// in all other cases, we remove the password
 MainForm.SetPassword('');
// PswChkBx.Checked:=False; // this will be done by SetPassword
end;

Open in new window

0

Experts Exchange Solution brought to you by

Your issues matter to us.

Facing a tech roadblock? Get the help and guidance you need from experienced professionals who care. Ask your question anytime, anywhere, with no hassle.

Start your 7-day free trial
peterkiersAuthor Commented:
Undeclared identifier: DatabaseName

function TMainForm.IsLogin(Password: string): boolean;
begin
 With ADOConnection1 do
  try
   if Connected Then Close;
   ConnectionString:=ConnectString(Password);
   Mode:=cmReadWrite;
   Open;
   Result := ADOConnection1.Connected;
   if Result Then _Password:=Password;
   if Pos('dbtree.pkr', DatabaseName) = 0 then
   Caption := ExtractFileName(DatabaseName) + ' - ' + 'Personal Knowledgebase';
  except
   Result := False;
  end;
 PropertiesDlg.PswChkBx.Checked:=_Password<>'';
end;
0
Cloud Class® Course: Ruby Fundamentals

This course will introduce you to Ruby, as well as teach you about classes, methods, variables, data structures, loops, enumerable methods, and finishing touches.

peterkiersAuthor Commented:
And a access violation at line:

PropertiesDlg.PswChkBx.Checked:=_Password<>'';
0
peterkiersAuthor Commented:
I have changed Databasename in dbname, so this problem is solved.

P.

0
peterkiersAuthor Commented:
Can someone help me with my EAccessViolation error?

P.
0
Mahdi78Commented:
try this


public
    { Public declarations }
    function IsProtected(FileName: string): boolean;

  end;

var
  MainForm: TMainForm;

implementation

{$R *.dfm}

function TMainForm.IsProtected(FileName: string): boolean;
begin
  try
  ADOConnection1.ConnectionString := Format('provider=Microsoft.Jet.OLEDB.4.0;Persist Security Info=False;Data Source=%s%s;',
    [IncludeTrailingPathDelimiter(ExtractFilePath(FileName)), ExtractFileName(FileName)]);
  ADOConnection1.Connected := False;
  Result := False;
  except
  Result := True;
  end;
end;

Open in new window

0
Mahdi78Commented:
Update in ADOConnection1.Connected := True line

public
    { Public declarations }
    function IsProtected(FileName: string): boolean;

  end;

var
  MainForm: TMainForm;

implementation

{$R *.dfm}

function TMainForm.IsProtected(FileName: string): boolean;
begin
  try
  ADOConnection1.ConnectionString := Format('provider=Microsoft.Jet.OLEDB.4.0;Persist Security Info=False;Data Source=%s%s;',
    [IncludeTrailingPathDelimiter(ExtractFilePath(FileName)), ExtractFileName(FileName)]);
  ADOConnection1.Connected := True;
  Result := False;
  except
  Result := True;
  end;
end;

procedure TMainForm.Button1Click(Sender: TObject);
begin
if OpenDialog1.Execute then
CheckBox1.Checked := IsProtected(OpenDialog1.FileName);
end;

Open in new window

0
Emmanuel PASQUIERFreelance Project ManagerCommented:
> Can someone help me with my EAccessViolation error?
probably your PropertiesDlg is not created when this is called.

Go in your project properties, and check that this form is autocreated. That should be the case already.
in your project main source you should have something like this :
begin
  Application.Initialize;
  Application.MainFormOnTaskbar := True; // or not depending on Delphi version
  Application.CreateForm(TMainForm, MainForm);
  Application.CreateForm(TPropertiesDlg , PropertiesDlg );
  Application.Run;
end.

MOST important thing is to not call your DB loading in the main form CREATE event because the PropertiesDlg is not yet created which cause your access violation error
Easiest way would be to move that part in the onActivate event of your main form, which will be called AFTER all forms have been created

procedure TMainForm.FormActivate(Sender: TObject);
begin
 OpenDatabase;
end;
0
peterkiersAuthor Commented:
Hi mahdi, thanks for your response, but I will go for Epasquier's solution.
Only I get an EAccessError.

Peter
0
peterkiersAuthor Commented:
I have put my oncreate-event in the code-section. Can you tell me exact what do to?
procedure TMainForm.FormCreate(Sender: TObject);
var
  I: Integer;
  SOToken: ISpeechObjectToken;
  SOTokens: ISpeechObjectTokens;
begin
  Caption := 'Untitled - Personal Knowledgebase';      <=================
  DBPath := IncludeTrailingPathDelimiter(ExtractFilePath(Application.Exename));  <=================
  DBName := 'dbtree.pkr';                   <=================
  OpenDatabase;                              <=================
  FRecentFiles := TStringList.Create;
  FRecentFiles.Duplicates := dupIgnore;
  if FileExists(ExtractFilePath(Application.ExeName) + 'MyRecentFileList.txt') then
    FRecentFiles.LoadFromFile(ExtractFilePath(Application.ExeName) + 'MyRecentFileList.txt');
  LoadRecentFileList;
  SpVoice1.EventInterests := SVEAllEvents;
  SOTokens := SpVoice1.GetVoices('', '');
  for I := 0 to SOTokens.Count - 1 do
  begin
    SOToken := SOTokens.Item(I);
    cbVoices.Items.AddObject(SOToken.GetDescription(0), TObject(SOToken));
    SOToken._AddRef;
  end;
  if cbVoices.Items.Count > 0 then
  begin
    cbVoices.ItemIndex := 0;
    cbVoices.OnChange(cbVoices);
  end;
  RateSpEdt.Value := SpVoice1.Rate;
  VolSpEdt.Value:= SpVoice1.Volume;
end;

Open in new window

0
Emmanuel PASQUIERFreelance Project ManagerCommented:
can you post your TMainForm.FormCreate code so that we rearrange it with FormActivate event ?
0
Emmanuel PASQUIERFreelance Project ManagerCommented:
ok
If LoadRecentFileList does not need the DB, then all you have to do is to move OpenDatabase
procedure TMainForm.FormCreate(Sender: TObject);
var
  I: Integer;
  SOToken: ISpeechObjectToken;
  SOTokens: ISpeechObjectTokens;
begin
  Caption := 'Untitled - Personal Knowledgebase';      
  DBPath := IncludeTrailingPathDelimiter(ExtractFilePath(Application.Exename))  DBName := 'dbtree.pkr';
//  OpenDatabase;     <=================  Remove That
  FRecentFiles := TStringList.Create;
  FRecentFiles.Duplicates := dupIgnore;
  if FileExists(ExtractFilePath(Application.ExeName) + 'MyRecentFileList.txt') then
    FRecentFiles.LoadFromFile(ExtractFilePath(Application.ExeName) + 'MyRecentFileList.txt');
  LoadRecentFileList;
  SpVoice1.EventInterests := SVEAllEvents;
  SOTokens := SpVoice1.GetVoices('', '');
  for I := 0 to SOTokens.Count - 1 do
  begin
    SOToken := SOTokens.Item(I);
    cbVoices.Items.AddObject(SOToken.GetDescription(0), TObject(SOToken));
    SOToken._AddRef;
  end;
  if cbVoices.Items.Count > 0 then
  begin
    cbVoices.ItemIndex := 0;
    cbVoices.OnChange(cbVoices);
  end;
  RateSpEdt.Value := SpVoice1.Rate;
  VolSpEdt.Value:= SpVoice1.Volume;
end;

procedure TMainForm.FormActivate(Sender: TObject);
begin
 OpenDatabase;
end;

Open in new window

0
peterkiersAuthor Commented:
OK, now i have no errors anymore, but something really strange happens.
I had my for MainForm the property wsMaximized set. Now it doesn't startup maximized.

Peter
0
peterkiersAuthor Commented:
Is it maybe possible to overrule it with code
0
Emmanuel PASQUIERFreelance Project ManagerCommented:
it is truly strange. Yes you can set it with code :

procedure TMainForm.FormActivate(Sender: TObject);
begin
 OpenDatabase;
 WindowState:=wsMaximized;
end;
0
peterkiersAuthor Commented:
We can do the Maximize issue some other time.
Because I have test it all. I have found one error.
When the database is protected and the user
opens that database the inputquery appears
for the user to enter his password, but even thou
the user enters a right password i still get Invalid Password

Is there maybe something wrong with this procedure:

procedure TMainForm.OpenDatabase;
var
 i: integer;
begin
 if not IsLogin('') then
  begin
   PostMessage(Handle, InputBoxMessage, 0, 0);
   if not IsLogin(InputBox('Password', 'Please enter password:', '')) then
    begin
     showmessage('Invalid Password');
     Exit;
    end;
  end;
 with PageControl1 do for i:=Pagecount -1 downto 0 do pages[i].Free;
 ADOTable1.Open;
 ADOTabs.Open;
 LoadTree;
end;
0
Emmanuel PASQUIERFreelance Project ManagerCommented:
can you check the Connect string used when trying the second IsLogin with the password ?
0
peterkiersAuthor Commented:
To tell you the true, I don't know how to do that?
0
Emmanuel PASQUIERFreelance Project ManagerCommented:
you put a breakpoint in the first line of code of IsLogin, and when you run you will be able to execute it step by step and check the values of the parameters, variables etc..., and see what's going west
0
Emmanuel PASQUIERFreelance Project ManagerCommented:
I'm sorry I can't help you more now, I'll have to go and eat :o)
if you don't know how to debug, post a new question and I'm sure some people out there will explain you all the concept of step-tracing an application with delphi, add some watch to variables (to track their values) etc...
0
peterkiersAuthor Commented:
I did put a breakpoint at the first line of IsLogin then what option do i have to choose?
0
Emmanuel PASQUIERFreelance Project ManagerCommented:
run, it will stop when reaching this point
0
peterkiersAuthor Commented:
The solution Espasquier gave me is the right solutions, even thou I get
more errors than the code that I had before. Never the less I thing
espasquier's solution is the best. The 500 points will be rewarded.

Greetings, Peter Kiers
0
It's more than this solution.Get answers and train to solve all your tech problems - anytime, anywhere.Try it for free Edge Out The Competitionfor your dream job with proven skills and certifications.Get started today Stand Outas the employee with proven skills.Start learning today for free Move Your Career Forwardwith certification training in the latest technologies.Start your trial today
Delphi

From novice to tech pro — start learning today.