Advantage Developer Zone

 
 
 

Using Unicode Usernames and Passwords

Thursday, July 05, 2012

We added Unicode field types in Advantage version 11. This allows you to store Unicode strings within Advantage tables. However, database object names are still limited to ANSI character types. This includes usernames and passwords, which can be a problem when distributing to users that require Unicode. You can store the Unicode data in the data dictionary using a UTF8Encoding.

In this tech-tip we will demonstrate how to store and retrieve Unicode strings from a data dictionary. This will allow you to store names and passwords in Unicode allowing users to use their native language when creating data dictionary users.

Encoding

Many development environments, like Visual Studio and Delphi 2009 and newer, store strings in UTF-16. This is the same encoding used by Windows for storing characters. All of the object names in a data dictionary are stored as ANSI characters. However, UTF-8 encoded strings have a very similar format to ANSI and can be stored in the data dictionary with a bit of coaxing.

Using a series of casts you can store a Unicode string in a data dictionary object name. Although this will work for any object name it makes the most sense for usernames, passwords and group names. Advantage Data Architect will not properly display Unicode strings in the various data dictionary property pages. Therefore, any object name that contains Unicode will appear with strange characters on these screens and even in the dictionary tree.

Creating a User

With the basics out of the way let's take a look at the code required to create a user that has a Unicode username and password. The sample code below is in Delphi but the technique is similar for other languages. For example the .NET framework has a UTF8Encoding class that can be used for the same purpose.

In order to create the user we will be using the ACE API directly to ensure that the UTF-8 encoded string is stored in the data dictionary. This is done by casting the string, in this case a UTF-16 encoded string, as a UTF8String. This is then cast as a PAnsiChar which is the data type that AdsDDCreateUser is expecting. The information is preserved and the string can be converted back to UTF-8 when it is retrieved.

procedure TForm1.btnCreateUser(Sender: TObject);
var
  FhConnection   : AdsNativeInt;
  RetVal         : Cardinal;
begin
  //First make an admin connection
  RetVal := ace.AdsConnect60('C:\Data\TestDb\TestDb.add', ADS_REMOTE_SERVER,
                   'adssys', 'password', ADS_DEFAULT, @FhConnection );

  if ( RetVal = AE_SUCCESS ) then
  begin
    // Create the user using the values from edit boxes
    RetVal := ace.AdsDDCreateUser(lHandle, nil, 
                      PAnsiChar( UTF8String( edtUsername.Text ) ),
                      PAnsiChar( UTF8String( edtPassword.Text ) ), 
                      'Unicode username and password' ) ;
    // add error checking here
  end
  else
    showmessage( 'Connection Failed: ' + IntToStr(RetVal));
end;

Once the user has been created we must do the same thing when logging in to ensure that the username and password can be found. The example below demonstrates the use of the AdsConnect60 API.

procedure TForm1.btnLoginClick(Sender: TObject);
var
  FhConnection   : AdsNativeInt;
  RetVal         : Cardinal;
begin
  // Connect using the supplied username and password
  RetVal := ace.AdsConnect60('C:\Data\TestDb\TestDb.add', ADS_REMOTE_SERVER,
                   PAnsiChar( UTF8String( edtUsername.Text ) ),
                   PAnsiChar( UTF8String( edtPassword.Text ) ),
                   ADS_DEFAULT, @FhConnection );

  if ( RetVal = AE_SUCCESS ) then
    showmessage( 'Connection Successful!' );
  else
    showmessage( 'Connection Failed: ' + IntToStr(RetVal));
end;
A Long Term Approach

If you are distributing your application to a country that requires a Unicode language we recommend that you create a descendant of the TAdsConnection component and use the casts we have shown here. You can then use this component instead of the standard TAdsConnection to support the Unicode usernames and passwords.

You can also apply the same techniques for group names. Keep in mind that when you retrieve the group names you need to apply the cast(s) in reverse so the original Unicode string will be displayed properly.

Summary

Although Unicode object names cannot be stored directly in a data dictionary you can still use Unicode in some cases. By using a simple series of casts you can store the Unicode string in the data dictionary.