Delphi Unicode string mismatch - delphi

I have a Delphi 7 app using Paradox database via BDE, that I have converted to Delphi XE3 and Firebird. There is a string field in the Paradox database containing an encrypted string that is supposedly used for licensing of the software. The problem is that while a routine that read this string in the old program (D7/Paradox) worked fine, in the new program (XE3/Firebird) the routine is throwing an error. The cause I have found through debugging is that the string after being read from the database is different. How can I fix this?
The string in the old Paradox database:
Ng-DrLrDOtfâtD89D1'D'îu
The string in the new Firebird database:
Ng-DrLrDOtfâtD89D1'D'îu
As you can see above the string is the same in both databases.
In the new Delphi XE3 program, using UniDAC data access components when I try to get the value of the field using FieldByName('fieldname').AsString , this is what is returned:
Ng-DrLrDOtfâtD89D1'D'îu
You can see that a couple of characters are different. This is causing an error in the routine that is checking this string in program. Did you experience this before? What are the possible causes of this problem and what steps can I take to resolve this.
Note 1: I converted the Paradox database to Firebird with a converter that I wrote in Delphi (For the actual code for this converter, see: http://goo.gl/6xu2ST)
Note 2: I have the database created with DEFAULT CHARACTER SET UTF8 and the UniDAC connection component (TUniConnection) has got SpecificOptions CharSet set to 'UTF8'.

I solved the problem by:
In the data-module or code, set the TUniConnection component property SpecificOptions UseUnicode to True.
Close the project and the Delphi IDE. Open WinGrep and do a Find-Replace in all the project PAS and DFM files for the string: TStringField, changing it to TWideStringField.
Re-compile.
And voila, its working perfect! Errors caused at runtime due to incomplete translation/interpretation of Unicode characters from database has gone away.
Thank you everyone who responded earlier.

Related

FireDAC (FDQuery) - database with dot in it's name

I have got this problem with FireDAC -> FDQuery component when it tries to select data from a database with '.' (dot) in its name.
The database name is TEST_2.0 and the error on Opening the dataset says:
Could not find server 'TEST_2' in sys.servers [...]
I have tried {TEST_2.0} (curly brackets) and [TEST_2.0] (square brackets). Also setting QuotedIdentifiers (Format Opetions) property to True does not seem to fix the problem. In SQL query I can add 'SET QUOTED_IDENTIFIER ON;' but this breaks inserts to the dataset.
The FDConnection component can connect to that server and that database using MSSQL driver without problems. It seems it is the dataset that dosn't handle it. UniDAC seems to handle everything without any problems.
I am using RadStudio 10.2.
Has anyone found any solution to this? Thanks in advance for any replies
I got a response from Emarcadero and it works for me:
"The problem is not in FireDAC, but in SQL Server ODBC driver
SQLPrimaryKeys function. It fails to work with a catalog name
containing a dot. FireDAC uses this function to get primary key fields
for a result set, when fiMeta is included into FetchOptions.Items. So,
as a workaround / solution, please exclude fiMeta from
FetchOptions.Items."
What is wrong?
I was able to reproduce what you've described here. I've ended up on metainformation command, specifically the SQLPrimaryKeys ODBC function call. I have used SQL Server Native Client 11.0 driver connected to Microsoft SQL Server Express 12.0.2000.8, local database server instance.
When I tried to execute the following SQL command (with TEST_2.0 database created) through a TFDQuery component instance with default settings (linked connection object was left with empty database connection parameter) in Delphi Tokyo application:
SELECT * FROM [TEST_2.0].INFORMATION_SCHEMA.TABLES
I got this exception raised when the SQLPrimaryKeys function was called with the CatalogName parameter set to TEST_2.0 (from within the metainformation statement method Execute):
[FireDAC][Phys][ODBC][Microsoft][SQL Server Native Client 11.0][SQL
Server]Could not find server 'TEST_2' in sys.servers. Verify that the
correct server name was specified. If necessary, execute the stored
procedure sp_addlinkedserver to add the server to sys.servers.'.
My next attempt was naturally modifying that CatalogName parameter value to [TEST_2.0] whilst debugging, but even that failed with similar reason (just failed for the name [TEST_2), so for me it seems that the SQLPrimaryKeys ODBC function implementation with the driver I've used cannot properly handle dotted CatalogName parameter values (it seems to ignore everything after dot).
What can I do?
The only solution seems to be just fixing ODBC drivers. Workaround I would suggest is not using dots in database names (as discussed e.g. in this thread). Another might be preventing FireDAC from getting dataset object metadata (by excluding fiMeta option from the Items option set). That will bring you the responsability of supplying dataset object metadata by yourself (at this time only primary key definition).

Delphi xe8 error reading textfile created from Delphi 7 version and vice versa

I try to convert a code from Delphi 7 to delphi xe8 and I cannot find a solution to the following case.
Our old application creates a txt file which first row is like that
±HEADER―ID°N1799―USER_ID°N1―PATH_NAME―R_DATABASE°TC:\DATA―R_SERVER°TTEST_SRV―R_COMPUTER°TMYPC―
Char(―) is chr(175).
We tried to read the already created file from our new application with Delphi xe8 like that:
StrData := TStringList.Create;
StrData.LoadFromFile(sFile);
StrData.Text returns the desired text but chr(175) is replaced with chr(8213).
In order to go on I did the followings:
StrData.LoadFromFile(sFile,TEncoding.ANSI);
StrData.Text := StringReplace(StrData.Text,Chr(8213),Chr(175),[rfReplaceAll]);
What I cannot solve is the opposite case.
I have to create that file from Delphi xe8 so as it would be exactly the same with the one produced from the old delphi 7 application.
At the beginning I used the same code we had:
StrData.SavetoFile(sFile); //returns text but chr(175) is replaced with (?)
Also i tried all encodings with no results.
StrData.SavetoFile(sFile,Ansi);//returns text but chr(175) is replaced with (?) etc.
The same results also when converts the code to TStreamFile or textfile.
base64 encode files
Old one - Correct one (StrData.SavetoFile(sFile)) //Delphi 7
wrFIRUFERVLigJVJRMKwTjE4NjbigJVSSUTCsE4zNjHigJVDU0lURV9JRMKwTjHigJVSU0lURV9JRMKwTjEwMeKAlVNTSVRFX0lEwrBOMeKAlVRSTl9EQVRFwrBENDIzODIuNjA2NzkzOTgxNeKAlVVTRVJfSUTCsE4x4oCVUEFUSF9OQU1FwrBUXFxkZWxwaGkyMDEycjJcQkVORUZJVF9URVNUXFBBX09GRklDRV9WU0xcVFJBTlNGRVJcRVhQT1JU4oCVRklMRV9OQU1FwrBUQU5BRDM2MU0udHh04oCVRklMRV9UWVBFwrBO4oCVUENLX1NFTkRFUsKwVEFkbWlu4oCVUENLX05PVEVTwrBU4oCVX1JWX0lEMcKwTuKAlVNWX0lEwrBO4oCVUlZfSUTCsE7igJVSREJfSUTCsE4xMeKAlVNEQl9JRMKwTjEx4oCVUENLX0NOWFTCsFQwMywxNSw3MiwwMOKAlUtFWUlEwrBUezczRDIwMDU3LTM3NTgtNDlDMi05NTlGLTA4QzYxMDY4NEZGNn3igJVGTF9UWVBFwrBOMuKAlUZMX1NUQVRVU8KwTjDigJVTVEFSVF9EVMKwRDQyMzgyLjYwNjQ5MzA1NTbigJVSX1NUQVJUX0RUwrBE4oCVUl9FTkRfRFTCsETigJVSX1VTRVLCsFTigJVSX1BBVEjCsFTigJVTSVpFX1BDS8KwTuKAlVNJWkVfREFUQcKwTuKAlVNJWkVfQVRDSMKwTuKAlVNJWkVfRE9DU8KwTuKAlURBVEVfSU7CsETigJVSX0RBVEFCQVNFwrBU4oCVUl9TRVJWRVLCsFTigJVSX0NPTVBVVEVSwrBU4oCV
StrData.SavetoFile(sFile,Tencoding.Ansi); & StrData.SavetoFile(sFile); //XE8
wrFIRUFERVI/SUTCsE4xODY3P1JJRMKwTjM2Mj9DU0lURV9JRMKwTjE/UlNJVEVfSUTCsE4xMDE/U1NJVEVfSUTCsE4xP1RSTl9EQVRFwrBENDIzODIuNzA3NzA4MzMzMz9VU0VSX0lEwrBOMT9QQVRIX05BTUXCsFRcXGRlbHBoaTIwMTJyMlxCRU5FRklUX1RFU1RcUEFfT0ZGSUNFX1ZTTFxUUkFOU0ZFUlxFWFBPUlQ/RklMRV9OQU1FwrBUQU5BRDM2Mk0udHh0P0ZJTEVfVFlQRcKwTj9QQ0tfU0VOREVSwrBUQWRtaW4/UENLX05PVEVTwrBOP19SVl9JRDHCsE4/U1ZfSUTCsE4/UlZfSUTCsE4/UkRCX0lEwrBOMTE/U0RCX0lEwrBOMTE/UENLX0NOWFTCsFQwMywxNSw3MiwwMD9LRVlJRMKwVHtGQzM1N0QyNC1EQjRBLTRBOUMtQkE3My0xQ0FBMEVFRDUzOUJ9P0ZMX1RZUEXCsE4yP0ZMX1NUQVRVU8KwTjA/U1RBUlRfRFTCsEQ0MjM4Mi43MDcyNjg1MTg1P1JfU1RBUlRfRFTCsEQ/Ul9FTkRfRFTCsEQ/Ul9VU0VSwrBUP1JfUEFUSMKwVD9TSVpFX1BDS8KwTj9TSVpFX0RBVEHCsE4/U0laRV9BVENIwrBOP1NJWkVfRE9DU8KwTj9EQVRFX0lOwrBEP1JfREFUQUJBU0XCsFQ/Ul9TRVJWRVLCsFQ/Ul9DT01QVVRFUsKwVD8=
StrData.SavetoFile(sFile,Tencoding.UTF8); //XE8
wrFIRUFERVLCr0lEwrBOMTg3MMKvUklEwrBOMzY1wq9DU0lURV9JRMKwTjHCr1JTSVRFX0lEwrBOMTAxwq9TU0lURV9JRMKwTjHCr1RSTl9EQVRFwrBENDIzODIuNzIyODEyNcKvVVNFUl9JRMKwTjHCr1BBVEhfTkFNRcKwVFxcZGVscGhpMjAxMnIyXEJFTkVGSVRfVEVTVFxQQV9PRkZJQ0VfVlNMXFRSQU5TRkVSXEVYUE9SVMKvRklMRV9OQU1FwrBUQU5BRDM2NU0udHh0wq9GSUxFX1RZUEXCsE7Cr1BDS19TRU5ERVLCsFRBZG1pbsKvUENLX05PVEVTwrBOwq9fUlZfSUQxwrBOwq9TVl9JRMKwTsKvUlZfSUTCsE7Cr1JEQl9JRMKwTjExwq9TREJfSUTCsE4xMcKvUENLX0NOWFTCsFQwMywxNSw3MiwwMMKvS0VZSUTCsFR7ODE5REQ0NDQtQzEwQi00MTY1LUFEQjAtQkI2NDAyRjA3NUI4fcKvRkxfVFlQRcKwTjLCr0ZMX1NUQVRVU8KwTjDCr1NUQVJUX0RUwrBENDIzODIuNzIyNTIzMTQ4McKvUl9TVEFSVF9EVMKwRMKvUl9FTkRfRFTCsETCr1JfVVNFUsKwVMKvUl9QQVRIwrBUwq9TSVpFX1BDS8KwTsKvU0laRV9EQVRBwrBOwq9TSVpFX0FUQ0jCsE7Cr1NJWkVfRE9DU8KwTsKvREFURV9JTsKwRMKvUl9EQVRBQkFTRcKwVMKvUl9TRVJWRVLCsFTCr1JfQ09NUFVURVLCsFTCrw==
Any ideas?
The file saved by your Delphi 7 program is UTF-8 encoded. I decoded the base64 that you supplied and look at it in a hex editor. It looks like this:
The first two bytes are C2 B1. That is the UTF-8 encoding for ±. You can check that here: https://mothereff.in/utf-8.
Use LoadFromFile(..., TEncoding.UTF8) to load the file, and SaveToFile(..., TEncoding.UTF8) to save it. That's all you need to do. Note that when you save this way then a BOM will be included in the file. If that is not desired then it possible to omit the BOM, as has been covered here before.
Do note that you must remove the call to StringReplace. That modifies the text and serves no useful purpose. You absolutely do not wish to replace U+2015 ― with U+00AF ¯.
Based on the comments to this answer it seems that you have some Delphi 7 code that produced UTF-8 encoded text which behaves incorrectly when executed by Delphi XE8. That's not surprising due to the change from ANSI to UTF-16. You will need to revisit this code and adapt it appropriately. It's impossible for us to say more given the fact the only you have this code.
It feels very much as though you are trying things almost at random and hoping for a quick fix. That is not productive. You will only make progress with a clear understanding of Unicode, and your program. You will need to step back, slow down, and fill in the gaps in your knowledge.

Delphi IBTable readonly error

I just installed the latest version of Embarcadero Delphi XE3. I made a simple form connecting to InterBase Database. I have IBDatabase, IBTable, IBTransaction, Grid and some other components. Everything works fine and it shows data in the grid. But I want to be able to edit this data. So at the IBTable component I set the ReadOnly property to false and every time I do this the program stops working and I get this:
Dynamic SQL Error
SQL error code = - 206
Column unknown
IBTable1
Any idea how to solve this?
It is not recommended to use IBTable component. Usage of IBDataset or IBQuery is advised. Read this

Strange string behaviour with dll call

I have a Delphi 2007 Program, which calls a Delphi 2010 DLL. The Program is big and not yet ported to 2010, so there is no way i can change this right now.
I use SimpleShareMem Unit to pass strings but also tried ShareMem with borlndmm.dll.
For one function i now pass a string from the Delphi 2007 programm to the dll (Therefore AnsiString). When debugging the dll, this AnsiString looks normal and can be viewed in the watch list. But if i do a simple think like
AnAnsiString := PassedAnsiString;
the variable AnAnsistring gets the value '???????'#0#0#0'???A', but PassedAnsiString is still readable in watchlist. Also a string append like
AnAnsiString := PassedAnsiString + NotPassedAnsiString;
uses '???????'#0#0#0'???A' as value.
Where is the problem? Is it a 2007 <-> 2010 issue? How to fix it?
Thanks for help.
This is probably because an encoding field that was added to ansistring in D2009. IOW the record (TAnsiRec) at negative offset of the ansistring pointer is different and shifted between unicode and non unicode Delphi's (ansistring changed too in unicode versions!)
I don't think there is a decent solution for this except dropping back to p(ansi)char level

How does acrobat encode annotations added as sticky notes to pdfs?

We have been reading and writing Sticky Notes/Annotations/Comments to pdfs via an activex control in our application for a number of years. We have recently upgraded to Delphi2009 with Unicode Support. The following is causing problems.
When we call
CAcroPDAnnot.GetContents
The results seem to be rather strange and we lose our Unicode Chars. It is not like saving as an ansi string which would usually result in returning ????? instead we get a string such as
‚És‚­“ú‚É•—Ž×‚ð‚Ђ¢‚½‚ç
For a string of Japanese characters.
However if I save the comments in the pdf to a datafile via the menu in the pdf itself it is written to file as something like
0kˆL0Oeå0k˜¨ª0’0r0D0_0‰
The latter can be export and reimported into an acrobat pdf and will recreate the correct unicode characters. However once I call CAcroPDAnnot.GetContents in my code it is coming back as something else.
Is CAcroPDAnnot.GetContents broken?
Is there an encoding scheme I should be aware of?
Is there an alternative I might be able to do?
Thanks
‚És‚­“ú‚É•—Ž×‚ð‚Ђ¢‚½‚ç
That's the string:
に行く日に風邪をひいたら
in CP-932 aka Shift-JIS encoding, an awful but lamentably still-popular encoding in Japan.
You're currently interpreting it in as CP-1252 (Windows Western European). If your PDF-reading component won't convert it for you automatically, you'll need to find a way to detect what encoding the document is in and convert it manually.
I don't know what Delphi provides for reading encodings, but have you got the encodings for Shift-JIS installed in Windows, from the Control Panel -> Regional Options -> "Install files for East Asian languages" option? If not, that might explain why it'd be failing to convert automatically, perhaps.
You're not exactly giving us a lot of information to work with.
I take it you're talking about the "Acrobat.CAcroPDAnnot" class' method GetContents here. Which version of Acrobat are you using? Have you perhaps switched versions (or run an update) around the time you started programming with Delphi 2009?
Then: how did you instantiate the object? If using a *_TLB.pas file generated from the DLL, are you certain it still matches it? (Try re-generating it, if uncertain).
Third: how are you calling the method? What type of variable are you assigning the result to?
What might also help, is if you could provide a sample of an annotation (preferably including non-ASCII chars); and for that annotation:
what it should look like (and what it does look like inside Reader)
what it returns when using a pre-2009 version of Delphi*
what it returns when using Delphi 2009*
(* preferably the HEX byte codes of the (ansi/wide)strings; but output from the Ctrl-F7 inspector should do)
Then maybe someone could provide a more meaningful answer.
Ok, one of the main differences between Delphi 2009 and the earlier versions is that the default string type is an unicode string. That means that if you use the same ActiveX component as in previous versions, you are passing unicode strings to ascii strings and that is usually not a good idea.
There are a couple of solutions for this problem:
Try if you can upgrade your activeX component so that it supports full unicode strings.
Use AnsiString and not string to communicate with the activeX component. In this case, you can still use the old interface, but you are still bound to the same limitations.
Use an other control that creates pdf. There is a lot to find, but be prepared to change a big chunk of your software. (Some controls are XML based and use encoding. )

Resources