Search code examples
delphicharacter-encodingodbcadodbase

Delphi: ADOConnection, DBASE3 and character set (bug?)


Delphi XE3, Win7 Prof.

I need to write into DBASE 3 (old format) files to export data for a DOS-like application (Clipper?). Ok, I thought: MS DBASE driver can do this.

But I have problem with hungarian accents.

I tried this connection string:

Driver={Microsoft dBASE Driver (*.dbf)};DriverID=21;Dbq=c:\temp;Extended Properties=dBASE III;charSet=CP 852;Locale Identifier=1038;Character Set=CP 852;CODEPAGE=852

As I saw it cannot write only ANSI files (the DOS app accepts CP852 chars).

I tried to convert the content with AnsiToOEM, but some characters lost on save. In the record I see good content, but the saved file contains wrong accents. The test text is "árvíztűrő tükörfúrógép". The "í", "ó", "Ó" is missing from the result.

And I found some strange thing!

If the main form have an opened ADOConnection (the connected property is true in the DFM) then I will read good characters from the DBASE files, and I can write them into the file - the ANSI characters will be converted correctly. "í" is ok, "ó" is ok. This ADOConnection object could be different than the reader.

If I close this ADOConnection in IDE mode, the opened files won't be converted, so I will see some strange accented chars, and I won't write good text into the file.

It is strange, because if I open this connection on FormCreate by code, the problem will appear... I can read and write the ADOQuery records if the resource streamer read the ADOConnection's active (True value) "connected" property from the DFM!

I don't know what happened in the background, and how to force this ADO character transformation routine to work, but I wasted more days to find a working DBASE III exporter, and I have found only a buglike thing...

Does anyone know what is this? Why the ADO character encoder/decoder works only if I had a connected ADOConnection in DFM? Or how I can use ADODB.Connection instead of ADOConnection object to avoid this side effect?

Thanks for every idea!


Solution

  • As I see I need to set the code page to fix the string for ADO.

    var
      s: string;
      aStr1, aStr2: AnsiString;
    
    begin
    ...
    
    s := 'árvíztûrõ tükörfúrógép';
    aStr1 := s;
    SetLength(aStr2, Length(aStr1));
    AnsiToOemBuff(PAnsiChar(aStr1), PAnsiChar(aStr2), Length(aStr1));
    SetCodePage(RawbyteString(aStr2), 852, False); // THIS IS THE SOLUTION
    ADOQuery1.FieldBYName('name').AsAnsiString := aStr2;
    

    Otherwise something is converting my AnsiString again in the background.