CIS(Clever Internet Suite) form fieldvalue encode - delphi

Delphi XE5 + CIS 7.8 for XE5,when POST use Chinese formfield value like below
clHttpRequest.AddFormField('Status', '待处理');
itAutoStatus := '待处理' ;
mmo1.Lines.Add( ' 汉字为 : <'+ itAutoStatus +'>' ) ; // <待处理>
a2us := AnsiToUtf8(itAutoStatus) ;
mmo1.Lines.Add( ' 汉字AnsiToUtf8为 : <' + a2us +'>' ) ; // <待处理>
gbs := HTTPEncode(itAutoStatus);
mmo1.Lines.Add( ' 汉字HTTPEncode为 : <' + gbs +'>' ) ; // <%B4%FD%B4%A6%C0%ED>
utfs := HTTPEncode(AnsiToUtf8(itAutoStatus));
mmo1.Lines.Add( ' 汉字HTTPEncode(AnsiToUtf8())为 : <' + utfs +'>' ) ; // <%E5%BE%85%E5%A4%84%E7%90%86>
in IE8,right raw stream is : pageNo=1&total=&SortField=&SortType=&PromTitle=&C1=&Status=%E5%BE%85%E5%A4%84%E7%90%86
clHttpRequest.AddFormField('Status', '待处理');
CIS default raw stream is : pageNo=1&total=&SortField=&SortType=&PromTitle=&C1=&Status=%B4%FD%B4%A6%C0%ED
clHttpRequest.AddFormField('Status', HTTPEncode(AnsiToUtf8('待处理')));
Now CIS raw stream is : pageNo=1&total=&SortField=&SortType=&PromTitle=&C1=&Status=%25E5%25BE%2585%25E5%25A4%2584%25E7%2590%2586
clHttpRequest.AddFormField add string '25',so web server will no database query result.
I want to make raw stream like IE8,How to fix this? thanks!!!

solved
clHttpRequest.Header.CharSet := 'UTF-8';

Related

Test existence of nested JSON element (with SuperObject)

You can skip straight to the code, if you want to. The leading text is explanation, but not necessary.
I am trying to use SuperObject to parse Delphi.
I was just using the plain JSON classes that come with Delphi 10.4, but had difficulty with some slightly complex functionality.
E.g stuff, such as does a.b.c exist, or a.b.c.d - where d is an array - or a.b.c.d[3].
And how to iterate over a.b.c.d. And to assign a value to a.b.c.d.e, updating it if it exists, creating it if not; and, if only part of the path exists, create it all e.g only a.b exists and I want to assign a value to a.b.c.d[3].e.
If anyone can point me to some examples of that sort of thing, I would be grateful.
Now, to my question. It seemed from various posts that SuperObject would be the answer, but I am failing at my first basic step - to test the existence of a nested JSN element.
Here's my code (is there an online JSON Fiddle site?)
unit fMainForm;
interface
uses
Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,
Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.StdCtrls;
type
TForm1 = class(TForm)
Memo1: TMemo;
procedure FormCreate(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;
var
Form1: TForm1;
implementation
{$R *.dfm}
uses System.IOUtils,
SuperObject;
procedure TForm1.FormCreate(Sender: TObject);
var json: ISuperObject;
jsonString : String;
begin
// Example JSON taken from https://stackoverflow.com/questions/10539797/complex-json-nesting-of-objects-and-arrays
jsonString := '{' +
'"problems": [{' +
' "Diabetes":[{' +
' "medications":[{' +
' "medicationsClasses":[{' +
' "className":[{' +
' "associatedDrug":[{' +
' "name":"asprin",' +
' "dose":"",' +
' "strength":"500 mg"' +
' }],' +
' "associatedDrug#2":[{' +
' "name":"somethingElse",' +
' "dose":"",' +
' "strength":"500 mg"' +
' }]' +
' }],' +
' "className2":[{' +
' "associatedDrug":[{' +
' "name":"asprin",' +
' "dose":"",' +
' "strength":"500 mg"' +
' }],' +
' "associatedDrug#2":[{' +
' "name":"somethingElse",' +
' "dose":"",' +
' "strength":"500 mg"' +
' }]' +
' }]' +
' }]' +
' }],' +
' "labs":[{' +
' "missing_field": "missing_value"' +
' }]' +
' }],' +
' "Asthma":[{}]' +
'}]}';
json := SO(jsonString);
if json.AsObject.Exists('problems') then
Memo1.Lines.Add('"problems" found')
else
Memo1.Lines.Add('"problems" not found');
if json.AsObject.Exists('problems.Diabetes') then
Memo1.Lines.Add('"problems.Diabetes" found')
else
Memo1.Lines.Add('"problems.Diabetes" not found');
end;
end.
When I run it, the memo contains
"problems" found
"problems.Diabetes" not found
How do I test for the existence of problems.Diabetes?
If I can crack that, I will try to update the strength of an associatedDrug, then insert a new key/value pair into the associatedDrug, then extend an existing key by adding several depths.
You've picked one of the worst JSON examples, because its structure needlessly puts everything into arrays (always [{ and ]}) when array elements would be enough already. You should have grabbed an easier example and start with that, to get familiar with what an object is and what an array is. Likewise I restructured and shortened the JSON data to make it tinier and more clear. If you managed to understand that you can go on and reach your strength property:
uses
SuperObject;
var
json, next: ISuperObject;
text: String;
sts: TSuperTableString;
sa: TSuperArray;
i: Integer;
begin
text:=
'{' + // {Object} starts
' "problems": [' + // 1st "property" of object, value is an [array]
' {' + // 1st [element] of array is an {object}
' "Diabetes": "yes"' + // 1st "property" of object is a "text"
' }' + // {Object} ends after just 1 "property"
' ],' + // [Array] ends after just 1 [element]
' "Asthma": [' + // 2nd "property" of object, value is an [array] again
' {}' + // 1st [element] of array is an (empty) {object}
' ]' + // [Array] ends after just 1 [element]
'}'; // {Object} ends after 2 "properties"
json:= SO( text );
if json.IsType( stObject ) then begin // Is this even JSON (which must be an object)?
sts:= json.AsObject;
if sts.Find( 'problems', next ) then begin // Does a property "problems" exist?
if next.IsType( stArray ) then begin // Is its value an array?
sa:= next.AsArray;
for i:= 0 to sa.Length- 1 do begin // Iterate all array elements
next:= sa[i];
if next.IsType( stObject ) then begin // Is this element an object?
sts:= next.AsObject;
sts.S['key']:= 'value'; // Adding our own property "key" to that object
if sts.Find( {'Diabetes'} 'key', next ) then begin // Does a property "key" exist?
Caption:= 'Found it!';
if next.IsType( stString ) then begin // Is the property of type "text"?
Caption:= Caption+ ' Value='+ next.AsString; // Should be "value"
end;
break; // Leave array loop
end;
end;
end;
end;
end;
end;
end;
Single step through it with the debugger to see how every check is necessary to finally even reach the property Diabetes and to then check if its value is actually a text (and not another object/array).
A better format of that initial JSON data would be this, freed from needless arrays and using also numbers as datatypes instead of texts only (the syntax is valid, it may look odd for you but I think this is a more logical display):
{ "problems":
{ "Diabetes":
{ "medications":
[
[
{ "name": "Asprin"
, "strength_mg": 500
}
,
{ "name": "Arsen"
, "strength_mg": 20
}
]
,
[
{ "name": "Toracin"
, "strength_ml": 10
}
,
{ "name": "Ambroxol"
, "strength_mg": 350
}
]
]
, "labs":
{ "test_chamber": 3
}
}
, "Asthma": null
}
, "is_insured": false
}
You have an array problems with an other array Diabetes. You can simply do :
if Assigned(json['problems[0].Diabetes[0]']) then
Memo1.Lines.Add('problems found + Diabetes found');
Or loop inside both array :
if Assigned(json['problems']) then
begin
for i := 0 to json['problems'].AsArray.Length - 1 do
begin
Memo1.Lines.Add('"problems" found');
if Assigned(json['problems'].AsArray[i]['Diabetes']) then
begin
for j := 0 to json['problems'].AsArray[i]['Diabetes'].AsArray.Length - 1 do
Memo1.Lines.Add('"problems.Diabetes" found')
end
else
Memo1.Lines.Add('"problems.Diabetes" not found');
end;
end
else
Memo1.Lines.Add('"problems" not found');
If you are not familiar with Delphi / JSON, use System.JSON is easier to use than this external lib

Why does TFormatSettings use incorrect ShortTimeFormat?

After several hours of investigations and researching the problem, I've found that TFormatSettings returns an incorrect ShortTimeFormat.
To show in TDateTimePicker a short time format with support for 24-hours, I need to use: TDateTimePicker.Format :='H:mm', and this is a default setting for my profile in Windows 10 for a short time.
But TFormatSettings.ShortTimeFormat return me a value of 'h:mm'.
To get the correct value, I should use:
GetLocaleStr(LOCALE_USER_DEFAULT, LOCALE_SSHORTTIME, '');
And this returns a 'H:mm' value.
This is the source of TFormatSettings from SysUtils.pas:
TimePrefix := '';
TimePostfix := '';
if StrToIntDef(GetLocaleStr(Locale, LOCALE_ITLZERO, '0'), 0) = 0 then
HourFormat := 'h'
else
HourFormat := 'hh';
if StrToIntDef(GetLocaleStr(Locale, LOCALE_ITIME, '0'), 0) = 0 then
if StrToIntDef(GetLocaleStr(Locale, LOCALE_ITIMEMARKPOSN, '0'), 0) = 0 then
TimePostfix := ' AMPM'
else
TimePrefix := 'AMPM ';
Result.ShortTimeFormat := TimePrefix + HourFormat + ':mm' + TimePostfix;
Result.LongTimeFormat := TimePrefix + HourFormat + ':mm:ss' + TimePostfix;
As we can see, that always use 'h' or 'hh', no way to get 'H' or 'HH'.
My question is: Why?

Delphi ADODB Create dbf table

I have to create dbf file in my Delphi application.
For this case I use ADODB.
Connection string:
const
ConnStringDBF =
'Driver={Microsoft dBASE Driver (*.dbf)};DriverID=277;Dbq=%s;';
//'Provider=Microsoft.Jet.OLEDB.4.0;Extended Properties=dBASE III;OLE DB Services=-1;Data Source=%s;';
//'Driver={Microsoft Visual Foxpro Driver};SourceType=DBF;SourceDB=%s;';
//Driver='Microsoft.ACE.OLEDB.12.0;Data Source=%s;';
And procedure (which doesn work):
procedure InsertRecordInDBF(file_name: string; DbfRecord: TDbfRecord);
var
ADOConnDBF : TADOConnection;
ADOCommand : TADOCommand;
begin
ADOConnDBF := TADOConnection.Create(nil);
ADOConnDBF.ConnectionString := Format(ConnStringDBF, [data_dir]);
ADOCommand := TADOCommand.Create(nil);
ADOCommand.Connection := ADOConnDBF;
ADOCommand.CommandText := 'Create Table ' + file_name + ' ('
+ 'NUMBER CHAR(11)'
+ ')'
;
ADOCommand.Execute;
end;
The error is:
raised exception class EOleException with message '[Microsoft][Драйвер ODBC dBase] Ошибка синтаксиса при определении поля'.
Which means: syntax error in translation from Russian.
But this CommandText works perfectly:
ADOCommand.CommandText := 'Create Table ' + file_name + ' ('
+ 'NUMBER_ CHAR(11)'
+ ')'
;
The difference in the name of the field (Number_ instead of Number)
How can I create table with field Number?
Maybe I need different connection string?
It seems that I found solution for this problem. The right syntax is:
ADOCommand.CommandText := 'Create Table ' + file_name + ' ('
+ '[NUMBER] CHAR(11)'
+ ')'
;
I added [] to the name of the field
Use VFPOLEDB provider with the following connection string:
Provider=VFPOLEDB.1;Data Source=%s;Password="";Collating Sequence=MACHINE
In this case your CREATE TABLE clause will work fine.

"bpl" load in IntraWeb

I am setting up a module of "bpl" load in IntraWeb, Delphi2010, and I found the following problem:
I don't get to create an instance the application to not to be this is as an internal form.
.
procedure CargaDoSubModulo;
type
TIWFormClass = class of TIWForm;
var
Integra : IIntegracaoIW;
Formulario : TIWForm;
intClas : Integer;
strForm : String;
begin
strForm := srtPacotes + '_' + Copy ( IntToStr ( Rtn_Alternativa) + 10000 ), 2, 4 );
// Descrição do formulário
strDescricaoTela := Des_Tela;
// Nome da classe do formulário
vrtClasseModulo := 'p_' + strForm + '.dll';
// Nome da rotina interna a ser carregada
strForm := 'iwfrm_' + strForm;
// Nome da classe do formulário
vrtNomeFormulario := 'T' + strForm;
// Verificação se a rotina e compativel com o sistema iwfrm_hrb_0010
intClas := -1;
if WebApplication.FindComponent( strForm ) = nil then
begin
Formulario := TIWFormClass(FindClass( vrtNomeFormulario )).Create(WebApplication);
if not Supports (Formulario, IIntegracaoIW) then
begin
WebApplication.ShowMessage(CargaTexto(msnRotIncompIntgra), smAlert);
Exit;
end;
Integra := Formulario as IIntegracaoIW;
with Integra do
begin
SetServidor( ParServidor1.Servidor ); // 1
SetAreaTrabalho( ParServidor1.AreaTrabalho ); // 2
SetIdUsuario( intUsuario ); // 3
SetNomeUsuario( iwlStUsuario.Caption ); // 11
SetAcesso( intAcesso ); // 4
SetEmpresa( ParServidor1.Empresa ); // 5
SetFilial( ParServidor1.Filial ); // 6
SetIdClasse( intClas ); // 8
SetVersao( strVersaoInterna ); // 10
SetDescricao(Des_Tela ); // 7
SetEnderecoIP( strIdentificacaoPorta ); // 13
SetDataTrabalho( DateToStr(dtDataTrabalho) ); // 14
SetIdentificacaoSistema( iwlIdentificacao.Caption ); // 12
SetModuloCarga(Rtn_Busca ); // 9
end;
end;
TIWAppForm(WebApplication.FindComponent( strForm )).Show;
end;
Your question - or actually the exact problem/error - is a bit unclear to me. Locating a form via FindComponent is a bit uncommon. At least you shouldn't call FindComponent more than nessecary, as it is potentially slow.
If you create a Form with WebApplication being the owner, it will be added to WebApplication.Forms
Web Application.FormCount is the number of forms (UserSession is a form in this context). WebApplication.ActiveForm is the form that is currently shown.

Where can I find a "ESC/POS" Epson Barcode Test Program?

I am struggling to get an Epson "ESC/POS" printer to print barcodes (Using Delphi) and want to test if the printer is not faulty. Do you know where I can find a program to print a barcode in "ESC/POS"? I suppose as a last resort an OPOS program will also be OK.
Also, a demo Delphi Program that works will also be fine. All the Delphi snippets I have so far is not working.
The printer I am using is an Epson TM-L60II
I Have a full tests program written in Delphi 5 for the TMT88's but the source is abit big for here so here is the barcode bits
Please note that as its snippets from the full object some vars/functions may be missing
To get the barcode chars
{**
* #param a ean13 barcode numeric value
* #return the escpos code for the barcode print
* Description uses escpos code, return code needed to print a ean13 barcode
*}
function TPrintEscPosToPort.getBarcodeEscPosCode(l_ean13:String):String;
var
l_return:String;
begin
l_return := CHR(29) + 'k' + CHR(67) + CHR(12);
l_return := l_return + l_ean13; // Print bar code
l_return := l_return + l_ean13; // Print bar code number under thge barcode
Result := l_return
end;
to print to a printer
{**
* #param Printer Name, Item be printed, Cut the papers after the cut, #no of copies to print
* #return boolen, true if it printed
* Description prints a test page to the tysso printer
*}
function TPrintEscPosToPort.escPosPrint(const l_printer, l_textToPrint :String;l_cutPaper:Boolean=true;l_copies:integer=1): Boolean;
var
l_pPort,l_pName,l_tmp:String;
i,x:integer;
PrinterFile: TextFile;
begin
// set result to false so any thing other then a good print will be false
Result:= FALSE;
try
//Find if the printer exists, else set to defult -1
i := Printer.Printers.IndexOf(l_printer);
if (i > -1) then
begin
Printer.PrinterIndex := i;
l_pName := Printer.Printers[i]; //Get the printer name (incase its the defult and not the one passed)
l_pPort := Self.getPrinterPort(l_pName) ; // get the port name from the reg
end;
// If true add headers and footers to the passed text
if (Self.aPrintHeadersFooters) then
begin
l_tmp := Self.getHeader()
+ l_textToPrint + Self.GetFooter();
end
else
begin
l_tmp := l_textToPrint;
end;
//Send the Document To the printer
try
for x:= 1 to l_copies do //Print multi-copies
Begin
//Assign the file to a tmp file in the printer port
if (length(trim(l_pPort)) > 0) then AssignFile(PrinterFile,l_pPort)
else
begin
//only use if we cant get the port
//(may look bad as ctrl codes are still in place)
AssignPrn(PrinterFile);
l_tmp := Self.stripEscPos(l_tmp);
end;
Rewrite(PrinterFile);
try
//Send the passed Text to the printer
WriteLn(PrinterFile,l_tmp);
if (Self.aPrinterReset) then
WriteLn(PrinterFile,escReset); // Reset the printer alignment
if (l_cutPaper) then
WriteLn(PrinterFile,escFeedAndCut); //Cut the paper if needed
finally
CloseFile(PrinterFile);
Result:= true;
end;
end;
except
end;
except
end;
end;
Update
Here is a lost of control code constants from the code above, hopefully the names are descriptive enough.
const
escNewLine = chr(10); // New line (LF line feed)
escUnerlineOn = chr(27) + chr(45) + chr(1); // Unerline On
escUnerlineOnx2 = chr(27) + chr(45) + chr(2); // Unerline On x 2
escUnerlineOff = chr(27) + chr(45) + chr(0); // Unerline Off
escBoldOn = chr(27) + chr(69) + chr(1); // Bold On
escBoldOff = chr(27) + chr(69) + chr(0); // Bold Off
escNegativeOn = chr(29) + chr(66) + chr(1); // White On Black On'
escNegativeOff = chr(29) + chr(66) + chr(0); // White On Black Off
esc8CpiOn = chr(29) + chr(33) + chr(16); // Font Size x2 On
esc8CpiOff = chr(29) + chr(33) + chr(0); // Font Size x2 Off
esc16Cpi = chr(27) + chr(77) + chr(48); // Font A - Normal Font
esc20Cpi = chr(27) + chr(77) + chr(49); // Font B - Small Font
escReset = chr(27) + chr(64); //chr(27) + chr(77) + chr(48); // Reset Printer
escFeedAndCut = chr(29) + chr(86) + chr(65); // Partial Cut and feed
escAlignLeft = chr(27) + chr(97) + chr(48); // Align Text to the Left
escAlignCenter = chr(27) + chr(97) + chr(49); // Align Text to the Center
escAlignRight = chr(27) + chr(97) + chr(50); // Align Text to the Right
Get the Microsoft POS For .Net 1.11, it's got an SDK that includes a sample application that performs all the basic operations on POS hardware. I'm using it all the time to test that cash drawers work ok for example.
There's also a source code included (in .Net), so you can see how they do it.

Resources