Lazarus open XML file in TMemo - pascal

I'm trying to open an XML file in a TMemo as text. Everytime I do this is what it opens:
I know that's not what's in the XML, if I open that file in Notepad it opens fine and shows XML data, plain text.
This is my code:
procedure TForm1.Button7Click(Sender: TObject);
var
ss: string;
sl: TStringList;
begin
ss := '';
runcommand('msinfo32 /nfo pcinfo.xml', ss);
sl:=TStringList.Create;
sl.LoadFromFile('pcinfo.xml');
Memo2.Text := sl.Text;
sl.Free;
end;

The file was saved in Unicode, opening Notepad and Save As the file showed me encoding. So opening the file into a stream, then converting to UTF8 worked like a charm.
stream := TMemoryStream.Create;
try
stream.LoadFromFile('pcinfo.xml');
SetLength(s, stream.Size);
stream.ReadBuffer(s[1], stream.Size);
memo2.Text := ConvertEncoding(s, GuessEncoding(s), EncodingUTF8);
finally
stream.Free;
end;

Related

How to send and receive a TMemoryStream (in a TObject) using DataSnap in Delphi 10.1

I have an application written in Delphi 10.1 using REST Datasnap.
This application includes a Client and Server.
The Client is a mobile application (Android) and the Server is a Windows Service that's is connected to a firebird database.
I have an Object:-
TJob = class(TObject)
private
FID: Integer;
FThe_Name: String;
FImage: TMemoryStream;
public
constructor Create;
destructor Destroy;
end;
constructor TJob.Create;
begin
inherited;
FImage := TMemoryStream.Create;
end;
destructor TJob.Destroy;
begin
FreeAndNil(FImage);
inherited;
end;
I get an access violation when I try to save the image on the server to the DB and when I try and open and display the image on the client.
I have a standalone multidevice application that use the same functionality(Getting, Saving and displaying of an Image) as the Client/Server and works.
Client displaying the image on the form:-
if (Job.Image.Size > 0) then
begin
rectangle.Fill.Kind := TBrushKind.Bitmap;
rectangle.Fill.Bitmap.Bitmap.LoadFromStream(Job.Image);
rectangle.Repaint;
Layout.Repaint;
end;
Client getting the Image from the form:-
if not(rectangle.Fill.Bitmap.Bitmap.IsEmpty) then
begin
Job.Image.Seek(0, soFromBeginning);
rectangle.Fill.Bitmap.Bitmap.SaveToStream(Job.Image);
Job.Image.Position := 0;
end;
Server Saving the Image to DB:-
Job.Image.Position := 0;
(TBlobField(FieldByName('MyImage'))).SaveToStream(Job.Image);
Server getting the Image from DB:-
(TBlobField(FieldByName('MyImage'))).SaveToStream(Job.Image);
The Standalone application works using the same however I get errors when trying to either save or display an image.
I have populated the DB with various formats of images, which I can view in the DB, but not from the Client(AV).
Any ideas on what I've done wrong and examples on how to solve fix?
Thanks
Server getting the Image from DB:-
PngImage := TPngImage.Create;
MemoryStream := TMemoryStream.Create;
try
(TBlobField(FieldByName('Image'))).SaveToStream(MemoryStream);
MemoryStream.Position := 0;
PngImage.LoadFromStream(MemoryStream);
Job.Image_AsStr := Base64FromPngImage(PngImage);
finally
MemoryStream.Free;
end;
Client displaying the image on the form:-
if (Job.Image_AsStr <> '') then
begin
rImage.Fill.Kind := TBrushKind.Bitmap;
rImage.Fill.Bitmap.Bitmap := BitmapFromBase64(Job.Image_AsStr);
rCustomer_Signature.Repaint;
lCustomer_Signature.Repaint;
end;
Client getting the Image from the form:-
if not(rImage.Fill.Bitmap.Bitmap.IsEmpty) then
begin
rImage.Fill.Kind := TBrushKind.Bitmap;
Job.Image_AsStr := Base64FromBitmap(rImage.Fill.Bitmap.Bitmap);
end
else
Job.Image_AsStr := '';
Server Saving the Image to DB:-
if Job.Image_AsStr <> '' then
begin
MemoryStream := TMemoryStream.Create;
try
PngImage := PngImageFromBase64(Job.Image_AsStr);
PngImage.SaveToStream(MemoryStream);
MemoryStream.Position := 0;
Params[1].LoadFromStream(MemoryStream, ftBlob);
finally
MemoryStream.Free;
end;
end
else
Params[1].Clear;
On my experience the image arrives back at the Server as a PngImage even though
its been packaged as a BMP.
I can now confirm that I've installed and tested on a Android phone.
*Note. The original question posted was about using a TMemoryStream, these examples uses a String.

Finding the correct handle of Notepad++ to use in SendMessage()

I'm in my first try with WinAPI and I am trying to send some text from a Delphi program (well Lazarus) to Notepad++.
I already found a good example to use simple Notepad, that goes like this :
Procedure TForm1.Button1Click(Sender: TObject);
var Var1, Var2 : HWND;
Begin
Var1 := FindWindow('notepad', nil);
Var2 := FindWindowEx(Var1, FindWindow('Edit', nil), nil, nil);
Clipboard.AsText:='This is some sample text.';
SendMessage(Var2, WM_PASTE, 0, 0);
End;
So this works fine for Notepad.
Now I would like to adapt it to use with any other program.
Taking Notepad++ for example, how do I find it's equivalent to 'Edit' used there in the FindWindowEx() ? Or let's say the correct cell and workbook to paste in LibreOffice Calc?
Any samples or clues?
Thanks.

Delphi Berlin 10.1 OS X app Decode cyrillic for writing to hardDevice

I have delphi application, i need to rewrite it for OS X.
This app writes/reads data to/from HID-device.
I have issues when i'm trying to write string from mac.
Here is the line that i'm writing(from debugger on windows): 'Новый комплекс 1'
and this works good. Meanwhile if copy this from debugger to somewhere it becomes 'Íîâûé êîìïëåêñ 1'. Device shows it as it was written, in cyrillic. And that's OK.
When i'm trying to repeat this steps on OS X, device shows unreadeble symbols. But if i do hardcode 'Íîâûé êîìïëåêñ 1' from windows example it's OK again.
Give some hints.
How it on windows
Some code:
s:= 'Новый комлекс 1'
s:= AnsiToUtf8(ReplaceNull(s));
Here is ReplaceNULL:
function ReplaceNull(const Input: string): string;
var
Index: Integer;
Res: String;
begin
Res:= '';
for Index := 1 to Length(Input) do
begin
if Input[Index] = #0 then
Res:= Res + #$12
else
Res:= Res + Input[Index];
end;
ReplaceNull:= Res;
end;
this string i put to Tstringlist and then save to file:
ProgsList.SaveToFile(Mwork.pathLibs+'stream.ini', TEncoding.UTF8);
Other program read this list and then writes to device:
Progs:= TStringList.Create();
Progs.LoadFromFile(****);
s:= UTF8ToAnsi(stringreplace(Progs.Strings[i], #$12, #0, [rfReplaceAll, rfIgnoreCase]));
And then write it to device.
So the line wich writes seems like this:
"'þ5'#0'ÿ'#$11'Новый комплекс 1'#0'T45/180;55;70;85;90;95;100;T45/180'#0'ÿ'"
On the mac i succesfully get the same string. But device can't show this in cyrillic.
A Delphi string is encoded in UTF-16 on all platforms. There is no need to convert it, unless you are interacting with non-Unicode data outside of your app.
That being said, if you have a byte array that is encoded in a particular charset, you can convert it to another charset using Delphi's TEncoding.Convert() method. You can use the TEncoding.GetEncoding() method to get a TEncoding object for a particular charset (if different than the standard supported charsets - ANSI, ASCII, UTF-7, UTF-8, and UTF-16 - which have their own property getters in TEncoding).
var
SrcEnc, DstEnc: TEncoding;
SrcBytes, ConvertedBytes: TBytes;
begin
SrcBytes := ...; // Cyrillic encoded bytes
SrcEnc := TEncoding.GetEncoding('Cyrillic'); // or whatever the real name is...
try
DstEnc := TEncoding.GetEncoding('Windows-1251');
try
ConvertedBytes := TEncoding.Convert(SrcEnc, DstEnc, SrcBytes);
finally
DstEnc.Free;
end;
finally
SrcEnc.Free;
end;
// use ConvertedBytes as needed...
end;
Update: To encode a Unicode string in a particular charset, simply call the TEncoding.GetBytes() method, eg:
s := 'Новый комлекс 1';
Enc := TEncoding.GetEncoding('Windows-1251');
try
bytes := Enc.GetBytes(s);
finally
Enc.Free;
end;
s := 'Новый комлекс 1';
bytes := TEncoding.UTF8.GetBytes(s);
You can use the TEncoding.GetString() to decode bytes in a particular charset back to a String, eg:
bytes := ...; // Windows-1251 encoded bytes
Enc := TEncoding.GetEncoding('Windows-1251');
try
s := Enc.GetString(bytes);
finally
Enc.Free;
end;
bytes := ...; // UTF-8 encoded bytes
s := TEncoding.UTF8.GetString(bytes);
The answer was next. Delphi Berlin 10.1 uses KOI8-R, and my device - cp1251.
As i'd wanted to write russian symbols(Cyrillic) i've created table of matches for symbols from KOI8-R and cp1251.
So, i take string in KOI8-R make it in cp1251.
Simple code:
Dict:=TDictionary<String,String>.Create;
Dict.Add(#$439,#$E9);//'й'
Dict.Add(#$44E,#$FE);//'ю'
Dict.Add(#$430,#$E0);//'а'
....
function tkoitocp.getCP1251Code(str:string):string;
var i:integer; res,key,val:string; pair:Tpair<String,String>;
begin
res:='';
for i:=1 to length(str) do
begin
if dict.ContainsKey(str[i]) then
begin
pair:= dict.ExtractPair(str[i]);
res:=res+pair.Value;
dict.Add(pair.Key,pair.Value);
end
else
res:=res+str[i];
end;
Result:=res;
end;

Stored procedure Text saving in Delphi

I need to create stored procedure into oracle from delphi with TQuery.
But the SQL.text is difficult to uunderstand.
Is there any way to store direct text as pl/SQL with out quotes?
'create or replace '+
'function WholeTableRecovery(i_tablname IN varchar) return varchar '+
'as '+
Is it possible with resource file
Thanks in advance
Since you are using Delphi 2010 in the tags (I have no Delphi 7 here to test), a comfortable method would be storing the SQLs in separate textfiles, together with a RC file containing the directives for the resource compiler.
The RC files will contain the names of the resource you want to use together with the filenames containing the SQLs you want to store. The content for the example would look like this:
My_First_Speaking_ResourceName RCDATA "MyFirstSQL.sql"
My_Second_Speaking_ResourceName RCDATA "MySecondSQL.sql"
There is no need to call BRCC32 directly if you include the resource containing RC and resulting RES :
{$R 'MySQLResources.res' 'resources\MySQLResources.rc'}
You might wrap the usage of TResourceStream for your convenience, the way shown in the example would use Strings you might also work with the stream directly as mentioned by TLama MyQuery.SQL.LoadFromStream(rs);
implementation
{$R *.dfm}
{$R 'MySQLResources.res' 'resources\MySQLResources.rc'}
function LoadSqlResource(resourceName: string): string;
var
rs: TResourceStream;
sl: TStringList;
s : string;
begin
sl := TStringList.Create;
try
rs := TResourceStream.Create(hinstance, resourceName, RT_RCDATA);
try
rs.Position := 0;
sl.LoadFromStream(rs);
Result := sl.Text;
finally
rs.Free;
end;
finally
sl.Free;
end;
end;
procedure CallOneSql(Q:TADOQuery;ResourceName:String);
begin
Q.SQL.Text := LoadSqlResource('My_First_Speaking_ResourceName');
Q.ExecSQL;
end;
With a call like CallOneSql(MyQuery,'My_First_Speaking_ResourceName');
Make sure to create the project, not just compile if you made changes on the RC or the SQL files.

Reading from text file into list in FreePascal

I have a text file including:
John###198cm###90kg###19age
Tom###120cm###34kg###8age
And I want to read them from file into two lists in FreePascal.
I have tried to use LoadFromFile function, which should make a line into list, but it is not working for me.
This is a variation of your question Reading from file FreePascal.
Here is an example using ReplaceStr() to convert the ### characters into a CR LF pair.
When assigned to the text property of a new list, it will be splitted into items.
Uses
StrUtils;
procedure HandleText;
var
i : Integer;
sSourceList : TStringList;
sExpandedList : TStringList;
begin
sSourceList := TStringList.Create;
sExpandedList := TStringList.Create;
try
sSourceList.LoadFromFile('MySource.txt');
for i := 0 to sSourceList.Count-1 do begin
sExpandedList.Text := ReplaceStr(sSourceList[i],'###',#13#10);
// Do something with your lists
// sExpandedList[0] = 'John' etc ...
end;
finally
sSourceList.Free;
sExpandedList.Free;
end;
end;

Resources