Delphi Access violation address - delphi

procedure TWebModule2.ClientGetItem(Request: TWebRequest; Response: TWebResponse);
var
o: TJSONObject;
CfKey: string;
a:TjsonArray;
begin
CfKey:='';
CfKey:= Request.QueryFields.Values['CF'] ;
if Request.QueryFields.Count>0 then begin
QryClientParam.SQL.Text := 'select * from TABLE where COD_FISC = :CF';
// qryclient.Params.ParamByName('CF').AsString := Request.QueryFields.Values['CF'];
QryClientParam.Params.ParamByName('CF').AsString := CfKey;
end else begin
QryClientParam.SQL.Text := 'select * from TABLE';
end;
QryClientParam.Active := true;
if QryClientParam.Active then begin
if QryClientParam.RecordCount>0 then begin
QryClientParam.First;
o := TJSONObject.Create;
// o.AddPair('EmployeeNumber',TJSONNumber.Create( qryClient.FieldByName('COD').AsInteger ));
o.AddPair('Descrizione', QryClientParam.FieldByName('DESK').AsString);
o.AddPair('Codice Fiscale', QryClientParam.FieldByName('COD_FISC').AsString);
o.AddPair('CAP', QryClientParam.FieldByName('CAP01').AsString);
o.AddPair('Indirizzo', QryClientParam.FieldByName('INDIRI').AsString);
o.AddPair('Citta', QryClientParam.FieldByName('CITTA01').AsString);
a.AddElement(o);
QryClientParam.Next;
Response.ContentType := 'application/json';
Response.Content := a.ToString;
// TFile.WriteAllText('JasonResult'+ '.json', a.ToString); //Scrivo Array del risultato in file
end;
end;
end;
I get this error:
Access violation at address 00E9D93D in module 'WebServerClienti.exe'. Read of address 00000008
The error is before this line:
a.AddElement(o);
The procedure works fine with my total query without parameter.
I don't understand - please help me

Related

Revisited: TClientDataset "Missing data provider or data packet"

With a dynamically created TFDQuery,TClientDataSet, and TDataSetProvider I bump into the "Missing data provider or data packet" with this code:
procedure ResetSavedPasswords(ADataModuleDataBaseAdmin : TDataModuleDataBaseAdmin);
var
lQuery : TFDQuery;
lCDS : TClientDataSet;
lProvider : TDataSetProvider;
begin
lFrmBezig := TFormBezig.Create(nil);
lQuery := TFDQuery.Create(nil);
lProvider := TDataSetProvider.Create(Application);
lCDS := TClientDataSet.Create(nil);
try
lQuery.Connection := ADataModuleDataBaseAdmin.FDConnectionTimeTell;
lQuery.CachedUpdates := true;
lProvider.Options := lProvider.Options - [poUseQuoteChar];
lProvider.DataSet := lQuery;
lProvider.Name := 'prvResetSavedPW';
lCDS.ProviderName := lProvider.Name;
lQuery.SQL.Text := Format('select %s,%s from <owner>%s',[sMedMedID,sMedSavedPassword,SMedTabelNaam]),ADataModuleDataBaseAdmin;
lCDS.Open;
Note that the created TDataSetProvider has an owner, based on this answer:
If DatasetProvider has no owner, ClientDataSet can not obtain a reference to the provider
But I still get the error. Opening the TFDQuery first shows me it has data.
What can be the reason?
Using FireDAC with Delphi 10.4. Sydney in a Win32 app.
It turns out that TClientDataSet needs an owner too:
lCDS := TClientDataSet.Create(Application);
This is obvious from the code that triggered the exception:
function TCustomClientDataSet.GetAppServer: IAppServer;
var
ProvComp: TComponent;
DS: TObject;
begin
if not HasAppServer then
begin
if ProviderName <> '' then
if Assigned(RemoteServer) then
FAppServer := RemoteServer.GetServer
else if Assigned(ConnectionBroker) then
FAppServer := ConnectionBroker.GetServer
else
begin
if Assigned(Owner) then
begin
ProvComp := Owner.FindComponent(ProviderName);
if Assigned(ProvComp) and (ProvComp is TCustomProvider) then
begin
DS := GetObjectProperty(ProvComp, 'DataSet');
if Assigned(DS) and (DS = Self) then
DatabaseError(SNoCircularReference, Self);
FAppServer := TLocalAppServer.Create(TCustomProvider(ProvComp));
end;
end;
end;
if not HasAppServer then
DatabaseError(SNoDataProvider, Self);
end;
Result := FAppServer;
end;
The Assigned(Owner) fails, so the code does not bother looking for the TDataSetProvider

Is there a way I can send a TFileStream with a httprequest.post method and extract it somehow in my webbroker?

I am trying to allow clients to upload pdf/xls and jpg files to my webbroker server I have running. I think I am sending the correct content but I have no clue on how to extract the received data. I can't find an appropiate method to allow me to do this. I am using the provied Delphi httprequest.post method to connect to the server's back-end.
Below a code snippet:
Client
try
NetHTTPClient.ContentType := 'application/pdf';
//NetHTTPRequest.ResponseTimeout := 600000;
tmpPDFFile := TFileStream.Create(pFilename, fmOpenRead);
//tmpPDFFile.Position:=0;
GetDossierIDAndDagboek;
tmpURL := MyURL + 'uploadAnyFile' + '?key=' + MyAPIKey + '&CLID=' + MyCLID + '&DOSID=' + tmpDOSID + '&JOURNAL=' + tmpDagboek + '&FILETYPE=' + pFileExstension;
NetHTTPRequest.ContentStream := tmpPDFFile;
NetHTTPRequest.Post(tmpURL,tmpPDFFile);
if HTTPLastStatusCode = 500 then begin
WriteToLog('Er ging iets mis bij het verwerken van document ' + pFilename);
end;
if HTTPLastStatusCode = 200 then begin
DeleteFile(pFilename);
end;
except
on e : exception do begin
WriteToLog(e.Message);
end;
end;
Server
procedure TWebModule1.WebModule1UploadAnyFileAction(Sender: TObject; Request: TWebRequest; Response: TWebResponse; var Handled: Boolean);
var
tmpJournal, tmpFileType : string;
tmpCLID, tmpDOSID : integer;
tmpStream : TFileStream;
tmpStr:string;
tmpX:integer;
begin
try
Handled := true;
Response.StatusCode := 200;
tmpCLID := StrToInt(Request.QueryFields.Values['CLID']);
tmpDOSID := StrToInt(Request.QueryFields.Values['DOSID']);
tmpJournal := Request.QueryFields.Values['JOURNAL'];
tmpFileType := Request.QueryFields.Values['FILETYPE'];
CodeSite.Send('bestand opgeslagen');
request.Files.Count;
tmpStream := Response.ContentStream;
// TmpStream := request.ReadString;
if tmpFileType = 'pdf' then begin
//tmpStr.SaveToFile('c:\temp\test.pdf');
end;
if (tmpFileType = 'jpeg') OR (tmpFileType = 'jpg') then begin
end;
if (tmpFileType = 'xlsx') OR (tmpFileType = 'xls') then begin
end;
except
on e : exception do begin
end;
end;
end;

FireDAC BatchMove from MemoryTable

My incoming data is loaded in a TFDMemTable, (the reader). The writer is a TFDQuery.
Incoming data should be inserted if not in the target, otherwise updated. Matches are based on the UUID field.
I am unable to properly define that the UUID field is the key.
Here is a code example - does not work. FBatchMove.Execute fails because cannot it find any key fields.
procedure TSubDB.FindDestRecord(ASender: TObject; var AFound: Boolean);
var
aSrc: TBytes;
begin
SetLength(aSrc, 16);
aSrc := FReader.DataSet.FieldByName('UUID').AsBytes;
AFound := FWriter.DataSet.Locate('UUID', aSrc, []);
end;
function TSubDB.LoadDB(const aFilename: string): boolean;
var
FQry: TFDQuery;
FBatchMove: TFDBatchMove;
FReader: TFDBatchMoveDataSetReader;
FWriter: TFDBatchMoveDataSetWriter;
FMemTable: TFDMemTable;
begin
FQry := TFDQuery.Create(nil);
FQry.Connection := dmFB.myDB;
FQry.FetchOptions.AssignedValues := [evItems];
FQry.FetchOptions.Items := [fiBlobs, fiDetails];
FBatchMove := TFDBatchMove.Create(nil);
FBatchMove.Analyze := [taDelimSep, taHeader, taFields];
FReader := TFDBatchMoveDataSetReader.Create(FBatchMove);
FWriter := TFDBatchMoveDataSetWriter.Create(FBatchMove);
FMemTable := TFDMemTable.Create(nil);
try
FMemTable.LoadFromFile(aFileName, sfBinary);
//Not sure how to make the BatchMove recognize that UUID is the key for OnFindDestRecord
FMemTable.IndexFieldNames := 'UUID';
with FMemTable.Indexes.Add do
begin
Name :='idxUUID';
Fields := 'UUID';
Active := true;
end;
FMemTable.IndexName := 'idxUUID';
FMemTable.IndexesActive := true;
FMemTable.FieldByName('UUID').ProviderFlags := FMemTable.FieldByName('UUID').ProviderFlags + [pfInKey];
FReader.DataSet := FMemTable;
FQry.SQL.Text := 'select * from test';
FWriter.DataSet := FQry;
FBatchMove.OnFindDestRecord := FindDestRecord;
FBatchMove.Mode := dmAppendUpdate;
//None of the above seems to keep the pfInKey in the UUID field's ProviderFlags
FBatchMove.Execute;
FQry.Open;
FQry.Close;
finally
FMemTable.Free;
FWriter.Free;
FReader.Free;
FBatchMove.Free;
FQry.Free;
end;
end;
I would really appreciate a working example of batch move (where the target has data, so the batch move mode is dmAppendUpdate).
The key here is that the writer needs to be a TFDBatchMoveSQLWriter with a TableName set. This way the destination had the primary key defined and it is then used to decide whether to insert or update.
function TSubDB.LoadDB(const aFilename: string): boolean;
var
FQry: TFDQuery;
FBatchMove: TFDBatchMove;
FReader: TFDBatchMoveDataSetReader;
FWriter: TFDBatchMoveSQLWriter;
FMemTable: TFDMemTable;
begin
FQry := TFDQuery.Create(nil);
FQry.Connection := dmFB.myDB;
FQry.FetchOptions.AssignedValues := [evItems];
FQry.FetchOptions.Items := [fiBlobs, fiDetails];
FBatchMove := TFDBatchMove.Create(nil);
FBatchMove.Analyze := [taDelimSep, taHeader, taFields];
FReader := TFDBatchMoveDataSetReader.Create(FBatchMove);
FWriter := TFDBatchMoveSQLWriter.Create(FBatchMove);
FMemTable := TFDMemTable.Create(nil);
try
FMemTable.LoadFromFile(aFileName, sfBinary);
FReader.DataSet := FMemTable;
FQry.SQL.Text := 'select * from test';
FWriter.Connection := dmFB.myDB;
FWriter.TableName := 'test';
FBatchMove.Mode := dmAppendUpdate;
FBatchMove.Execute;
FQry.Open;
FQry.Close;
finally
FMemTable.Free;
FWriter.Free;
FReader.Free;
FBatchMove.Free;
FQry.Free;
end;
end;

Paypal Payment Request error

Here is my code regarding the PayPal Payment Request. I am getting a 401 error but I am not sure where it is coming from or how to handle it. I believe it is from my Custom Header configuration.
How to fix it?
FUNCTION GetAccessToken :String ;
Var
AccessToken :TJSONValue ;
BEGIN
AccessToken := PayPalTokenObj.Get('access_token').JsonValue ;
Result := AccessToken.Value ;
PayPalForm.Memo1.Lines.Add('Access Token: ' + Result) ;
END ; {GetAccessToken}
FUNCTION GetTokenType :String ;
Var
AccessTokenType :TJSONValue ;
BEGIN
AccessTokenType := PayPalTokenObj.Get('token_type').JsonValue ;
Result := AccessTokenType.Value ;
PayPalForm.Memo1.Lines.Add('Token Type: ' + Result) ;
END ; {GetTokenType}
procedure SendPayment;
const
PaymentRequest = 'https://api.sandbox.paypal.com/v1/payments/payment';
var
PayPalPaymentRequestObj, PayerObj, AmountObj, TransactionObj, RedirectObj: TJSONObject;
TransactionsArray :TJSONArray ;
InputJSON: TStringStream;
Result :String ;
begin
//Create a JSON object called PayPalPaymentRequest
PayPalPaymentRequestObj := TJSONObject.Create;
try
PayPalPaymentRequestObj.AddPair(TJSONPair.Create('intent', TJSONString.Create('sale'))) ;
RedirectObj := TJSONObject.Create;
try
PayPalPaymentRequestObj.AddPair('redirect_urls', RedirectObj);
RedirectObj.AddPair(TJSONPair.Create('return_url', TJSONString.Create('http://www.SoftwareMomentum.com')));
RedirectObj.AddPair(TJSONPair.Create('cancel_url', TJSONString.Create('http://www.Yahoo.com')));
except
RedirectObj.Free;
raise;
end;
PayerObj := TJSONObject.Create;
try
PayPalPaymentRequestObj.AddPair('payer', PayerObj);
PayerObj.AddPair(TJSONPair.Create('payment_method', TJSONString.Create('paypal')));
except
PayerObj.Free;
raise;
end;
TransactionsArray := TJSONArray.Create;
AmountObj := TJSONObject.Create;
TransactionObj := TJSONObject.Create;
try
PayPalPaymentRequestObj.AddPair('transactions', TransactionsArray) ;
AmountObj.AddPair(TJSONPair.Create('total', TJSONString.Create('7.47')));
AmountObj.AddPair(TJSONPair.Create('currency', TJSONString.Create('USD')));
TransactionObj.AddPair('amount', AmountObj);
TransactionObj.AddPair(TJSONPair.Create('description', TJSONString.Create('payment description')));
// TransactionsArray.Add(AmountObj);
TransactionsArray.Add(TransactionObj);
except
TransactionsArray.Free;
AmountObj.Free;
TransactionObj.Free;
Exit;
end;
with Http do
begin
Request.Clear;
Request.CustomHeaders.Clear ;
Request.BasicAuthentication := False;
Request.CustomHeaders.Values['Authorization'] := Format(GetTokenType + ' %s', [GetAccessToken]);
Request.ContentType := 'application/json';
Request.Accept := 'application/json' ;
Request.ContentLength := 431 ;
Request.UserAgent := 'PayPalSDK/NIW/HATEOAS' ;
end; {with}
InputJSON := TStringStream.Create(PayPalPaymentRequestObj.ToString, TEncoding.UTF8);
try
HTTP.ProtocolVersion := pv1_1 ;
HTTP.AllowCookies := True ;
HTTP.HandleRedirects := True ;
//Result := HTTP.Post(PaymentRequest, PostData);
Result := HTTP.Post(PaymentRequest, InputJSON) ;
finally
InputJSON.Free;
end ; {try-finally}
finally
PayPalPaymentRequestObj.Free;
end ; {try-finally}
end;
You are ignoring the server's actual response. Your code is assuming that the response gets written to the same TStream that the request data is provided from, but that is not the case.
You are calling the version of Post() that takes a TStream as input and returns a String as output:
function Post(AURL: string; ASource: TStream): string; overload;
You are ignoring the returned String and instead using your original request data, thus the echoing that you are experiencing. The server is not echoing the request back to you, you are simply processing whatever you send as if it was returned.
You need to change this code:
HTTP.Post(PaymentRequest, Response) ;
Result := Response.DataString ;
To this instead:
Result := HTTP.Post(PaymentRequest, Response);
You should then rename the Response variable to a more suitable name. And also clean up your memory management as well, as you have some memory leaks if something goes wrong.
Try something like this:
procedure SendPayment;
const
PaymentRequest = 'https://api.sandbox.paypal.com/v1/payments/payment';
var
PayPalPaymentRequestObj, PayerObj, AmountObj, TransactionObj, RedirectObj: TJSONObject;
TransactionsArray: TJSONArray;
InputJSON: TStringStream;
Result: String;
begin
//Create a JSON object called PayPalPaymentRequest
PayPalPaymentRequestObj := TJSONObject.Create;
try
PayPalPaymentRequestObj.AddPair('intent', 'sale');
RedirectObj := TJSONObject.Create;
try
RedirectObj.AddPair('return_url', 'http://www.SoftwareMomentum.com');
RedirectObj.AddPair('cancel_url', 'http://www.Yahoo.com');
PayPalPaymentRequestObj.AddPair('redirect_urls', RedirectObj);
except
RedirectObj.Free;
raise;
end;
PayerObj := TJSONObject.Create;
try
PayerObj.AddPair('payment_method', 'paypal');
PayPalPaymentRequestObj.AddPair('payer', PayerObj);
except
PayerObj.Free;
raise;
end;
TransactionsArray := TJSONArray.Create;
try
TransactionObj := TJSONObject.Create;
try
AmountObj := TJSONObject.Create;
try
AmountObj.AddPair('total', '7.47');
AmountObj.AddPair('currency', 'USD');
TransactionObj.AddPair('amount', AmountObj);
except
AmountObj.Free;
raise;
end;
TransactionObj.AddPair('description', 'payment description');
TransactionsArray.Add(TransactionObj);
except
TransactionObj.Free;
raise;
end;
PayPalPaymentRequestObj.AddPair('transactions', TransactionsArray);
except
TransactionsArray.Free;
raise;
end;
with Http do
begin
ProtocolVersion := pv1_1;
AllowCookies := True;
HandleRedirects := True;
Request.Clear;
Request.BasicAuthentication := False;
Request.CustomHeaders.Values['Authorization'] := Format('%s %s', [GetTokenType, GetAccessToken]);
Request.ContentType := 'application/json';
Request.Accept := 'application/json';
Request.UserAgent := 'PayPalSDK/NIW/HATEOAS';
end;
InputJSON := TStringStream.Create(PayPalPaymentRequestObj.ToString, TEncoding.UTF8);
try
Result := HTTP.Post(PaymentRequest, InputJSON);
finally
InputJSON.Free;
end;
finally
PayPalPaymentRequestObj.Free;
end;
end;

Is there an way to pass a widestring to a TStringStream?

I have this Delphi function:
function DevuelveResumenEventos(cnnBBDD : TADOConnection;sFecha,sHora,sCtrlPac : string) : TStream;
var
sTextoArmado : string;
stCarga : TStringStream;
begin
with TADOTable.Create(Application.MainForm) do
try
sTextoArmado := '';
Connection := cnnBBDD;
TableName := 'EAPC_EVENTOS';
Filter := 'EAPC_FECHA = '+sFecha+' and EAPC_HORA = '+sHora+' and EAPC_CTRL_PAC = '+sCtrlPac;
Filtered := True;
Open;
while not Eof do
begin
sTextoArmado := sTextoArmado + FormatDateTime('dd-mm-yyyy', FieldValues['EAPC_FECHA_EVENTO'])+
' '+MinutsToStr(FieldValues['EAPC_HORA_EVENTO'])+
' ('+Trim(FieldValues['EAPC_LOGIN_USER'])+
') - '+FieldByName('EAPC_EVENTO').AsString+CRLF+CRLF;
Next;
end;
**stCarga := TStringStream.Create(sTextoArmado);
with TRichEdit.Create(Application.MainForm) do
begin
Parent := Application.MainForm;
Text := sTextoArmado;
Lines.SaveToStream(stCarga);
Free;
end;
finally
Close;
Free;
end;
Result := stCarga;**
end;
The intention is to retrieve a series of RTF formated texts, concatenate them with other texts and return them in a single TStringStream to be displayed in a TRichEdit in a form.
How can I skip the "use the on-the-fly RichEdit" and send the resulting texts as a TStringStream?

Resources