• Status: Solved
  • Priority: Medium
  • Security: Public
  • Views: 404
  • Last Modified:

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

0
peterkiers
Asked:
peterkiers
  • 13
  • 9
  • 2
1 Solution
 
peterkiersAuthor Commented:
be back in a few hours. PK
0
 
epasquierCommented:
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
 
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
Get expert help—faster!

Need expert help—fast? Use the Help Bell for personalized assistance getting answers to your important questions.

 
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
 
epasquierCommented:
> 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
 
epasquierCommented:
can you post your TMainForm.FormCreate code so that we rearrange it with FormActivate event ?
0
 
epasquierCommented:
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
 
epasquierCommented:
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
 
epasquierCommented:
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
 
epasquierCommented:
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
 
epasquierCommented:
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
 
epasquierCommented:
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

Featured Post

Learn to develop an Android App

Want to increase your earning potential in 2018? Pad your resume with app building experience. Learn how with this hands-on course.

  • 13
  • 9
  • 2
Tackle projects and never again get stuck behind a technical roadblock.
Join Now