Delphi IBX to Firedac Migration For Firebird - delphi

I migrated an IBX application which have 500+ forms to Firedac. I mapped the datatypes with Delphi Help. Here is my data mapping:
with ADB.FormatOptions do
begin
OwnMapRules := True;
DefaultParamDataType := ftVariant;
MapRules.Clear;
with MapRules.Add do
begin
PrecMax := 4;
PrecMin := 0;
ScaleMax := 0;
ScaleMin := 0;
SourceDataType := dtFmtBCD;
TargetDataType := dtInt16;
end;
with MapRules.Add do
begin
PrecMax := 10;
PrecMin := 5;
ScaleMax := 0;
ScaleMin := 0;
SourceDataType := dtFmtBCD;
TargetDataType := dtInt32;
end;
with MapRules.Add do
begin
PrecMax := 18;
PrecMin := 11;
ScaleMax := 0;
ScaleMin := 0;
SourceDataType := dtFmtBCD;
TargetDataType := dtInt64;
end;
with MapRules.Add do
begin
SourceDataType := dtFmtBCD;
TargetDataType := dtDouble;
end;
with MapRules.Add do
begin
SourceDataType := dtDateTimeStamp;
TargetDataType := dtDateTime;
end;
end;
Is this mapping is true? If it's false, how do I it's true?
When a FDQuery has parameters and a parameter has no value on execute the query,an exception occured :
[FireDAC][Phys][FB]-338. Param [XXX] type changed from [ftVariant] to [ftInteger]. Query must be reprepared. Possible reason: an assignment to a TFDParam.AsXXX property implicitly changed the parameter data type. Hint: use the TFDParam.Value or appropriate TFDParam.AsXXX property
How do I solve this problem? Thanks for everything.

I solved my problem by using the mapping below:
with ADB.FormatOptions do
begin
OwnMapRules := True;
with MapRules.Add do
begin
SourceDataType := dtDateTimeStamp;
TargetDataType := dtDateTime;
end;
with MapRules.Add do
begin
SourceDataType := dtDateTime;
TargetDataType := dtDateTimeStamp;
end;
end;
After than I build my application and test it. The Result is OK for me.

Related

Error using datetime parameter on firedac stored procedure component

I have a FDStored procedure that has a datetime parameter:
create procedure [dbo].[p_gl_for_ap]
(#inMode char(1), --I=Invoice, C=Check
#inId_Invoice integer, --reqd for invoice or credit memo maintenance, I
#inReg char(3), --reqd for check update or void, C
#inCheckNo integer, --reqd for check update or void, C
#inIs_Reversal char, --Y only if Invoice Delete or Check Void
#inDt_Rev datetime, --reqd only for reversal
#inDt datetime, --optl G/L tran date; normally null
#inId_glsrcjrn varchar(10),
#inId_create integer,
#ret integer output)
AS
declare....
and I have a FDStoredProc component using the stored procedure:
(following is from component to code)
var
spGLForAP: TFDStoredProc;
spGLForAP := TFDStoredProc.Create(Self);
spGLForAP.Name := 'spGLForAP';
spGLForAP.Connection := dmConnect.cnxData;
with spGLForAP.FormatOptions.MapRules.Add do begin
SourceDataType := dtDateTime;
TargetDataType := dtDateTimeStamp;
end;
spGLForAP.StoredProcName := 'p_gl_for_ap';
with spGLForAP.ParamData.Add do begin
Position := 1;
Name := 'RESULT';
DataType := ftInteger;
ParamType := ptResult;
end;
with spGLForAP.ParamData.Add do begin
Position := 2;
Name := 'inMode';
DataType := ftFixedChar;
ParamType := ptInput;
Size := 1;
end;
with spGLForAP.ParamData.Add do begin
Position := 3;
Name := 'inId_Invoice';
DataType := ftInteger;
ParamType := ptInput;
end;
with spGLForAP.ParamData.Add do begin
Position := 4;
Name := 'inReg';
DataType := ftFixedChar;
ParamType := ptInput;
Size := 3;
end;
with spGLForAP.ParamData.Add do begin
Position := 5;
Name := 'inCheckNo';
DataType := ftInteger;
ParamType := ptInput;
end;
with spGLForAP.ParamData.Add do begin
Position := 6;
Name := 'inIs_Reversal';
DataType := ftFixedChar;
ParamType := ptInput;
Size := 1;
end;
with spGLForAP.ParamData.Add do begin
Position := 7;
Name := 'inDt_Rev';
DataType := ftDateTime;
FDDataType := dtDateTimeStamp;
NumericScale := 3;
ParamType := ptInput;
end;
with spGLForAP.ParamData.Add do begin
Position := 8;
Name := 'inDt';
DataType := ftDateTime;
FDDataType := dtDateTimeStamp;
NumericScale := 3;
ParamType := ptInput;
end;
with spGLForAP.ParamData.Add do begin
Position := 9;
Name := 'inId_glsrcjrn';
DataType := ftString;
ParamType := ptInput;
Size := 10;
end;
with spGLForAP.ParamData.Add do begin
Position := 10;
Name := 'inId_create';
DataType := ftInteger;
ParamType := ptInput;
end;
with spGLForAP.ParamData.Add do begin
Position := 11;
Name := 'ret';
DataType := ftInteger;
ParamType := ptInputOutput;
end;
I am initializing with this code:
function tdmAP.DoGLForAP(whichInvoice: integer; hasDelete: Boolean):
integer;
begin
spGLForAP.Params.ClearValues;
spGLForAP.ParamByName('inMode').AsString := 'I';
spGLForAP.ParamByName('inId_Invoice').AsInteger := whichInvoice;
spGLForAP.ParamByName('inReg').AsString := '';
spGLForAP.ParamByName('inCheckNo').AsInteger := 0;
if hasDelete then
begin
spGLForAP.ParamByName('inIs_Reversal').AsString := 'Y';
spGLForAP.ParamByName('indt_Rev').value := Date;
end
else
begin
spGLForAP.ParamByName('inIs_Reversal').AsString := 'N';
spGLForAP.ParamByName('indt_Rev').AsDateTime := Date;
end;
spGLForAP.ParamByName('indt').AsDateTime := Date;
spGLForAP.ParamByName('inId_glsrcjrn').AsString := '';
spGLForAP.ParamByName('inId_create').AsInteger := LoginRec.LoginUserId;;
try
spGLForAP.Prepare;
spGLForAP.Execute;
Result := spGLForAP.ParamByName('ret').AsInteger;
except
on E:Exception do
begin
ShowMessage('Error executing stored procedure p_gl_for_ap: ' + e.Message);
result := -1;
end;
end;
end;
but I keep getting error back from firedac complaining about the parameter type changing:
error on execute
I have tried using the datatype mapping.
I have tried using this code:
spGLForAP.ParamByName('indt_Rev').value = 0;
and
spGLForAP.ParamByName('indt_Rev').AsDateTime := Date;
and
spGLForAP.ParamByName('indt_Rev').AsDateTime := now;
I have also tried changing the datatypes on the two date parameters from ftTimeStamp to ftDateTime, repreparing the query after setting the parameters types, and just about anything else I can think of. obviously, I'm missing something...
using Delphi 10.2.2 Tokyo, against mssql server 2008R2.
note: in this particular case, I'm trying to set the inDt_rev and inDt to 0. but can't seem to successfully set them to any value.
Try to change this part of your code:
with spGLForAP.ParamData.Add do begin
Position := 7;
Name := 'inDt_Rev';
DataType := ftDateTime;
FDDataType := dtDateTimeStamp;
NumericScale := 3;
ParamType := ptInput;
end;
with spGLForAP.ParamData.Add do begin
Position := 8;
Name := 'inDt';
DataType := ftDateTime;
FDDataType := dtDateTimeStamp;
NumericScale := 3;
ParamType := ptInput;
end;
to this one:
with spGLForAP.Params.Add do begin
Name := '#inDt_Rev';
DataType := ftTimeStamp;
ParamType := ptInput;
end;
with spGLForAP.Params.Add do begin
Name := '#inDt';
DataType := ftTimeStamp;
ParamType := ptInput;
end;
and use Value property instead of .AsDateTime accessor like:
spGLForAP.Params.ParamByName('#inDt').Value := Now;
or use AsSQLTimeStamp accessor:
// uses Data.SqlTimSt;
spGLForAP.Params.ParamByName('#inDt').AsSQLTimeStamp := DateTimeToSQLTimeStamp(Now);
because FireDAC maps such parameter as dtDateTimeStamp type (for which is the AsSQLTimeStamp accessor for).
You can create a custom data type mapping rule:
http://docwiki.embarcadero.com/RADStudio/XE5/en/Data_Type_Mapping_(FireDAC)
And map dtTimeStamp into dtDateTime.
// --------------------------- MAP RULES ------------------------- \\
with dm6.fdDB.FormatOptions do begin
OwnMapRules := True;
with MapRules.Add do begin
SourceDataType := dtDateTimeStamp;
TargetDataType := dtDateTime;
end;
end;

Can TNEF be avoided using MAPI?

I am using this code to send emails through MAPI using Delphi.
A few users who use Microsoft mailing software report that the receipants receive emails with an attachment WinMail.dat. I know that this is an issue with Microsoft Exchange/Outlook and can be corrected by disabling RTF/TNEF. (I don't know for sure because I do not use Microsoft mailing software).
My question is, if I can tell the mailing software to not use TNEF using the MAPI.
function SendEMailUsingMAPI(const Subject, Body, FileName, SenderName, SenderEMail, RecipientName, RecipientEMail: string): Integer;
var
Message: TMapiMessage;
lpSender, lpRecipient: TMapiRecipDesc;
FileAttach: TMapiFileDesc;
SM: TFNMapiSendMail;
MAPIModule: HModule;
FileType: TMapiFileTagExt;
begin
// Source: http://www.stackoverflow.com/questions/1234623/how-to-send-a-mapi-email-with-an-attachment-to-a-fax-recipient
// Modified
FillChar(Message,SizeOf(Message),0);
if (Subject <> '') then begin
Message.lpszSubject := PChar(Subject);
end;
if (Body <> '') then begin
Message.lpszNoteText := PChar(Body);
end;
if (SenderEmail <> '') then
begin
lpSender.ulRecipClass := MAPI_ORIG;
if (SenderName = '') then begin
lpSender.lpszName := PChar(SenderEMail);
end
else begin
lpSender.lpszName := PChar(SenderName);
end;
lpSender.lpszAddress := PChar('smtp:'+SenderEmail);
lpSender.ulReserved := 0;
lpSender.ulEIDSize := 0;
lpSender.lpEntryID := nil;
Message.lpOriginator := #lpSender;
end;
if (RecipientEmail <> '') then
begin
lpRecipient.ulRecipClass := MAPI_TO;
if (RecipientName = '') then begin
lpRecipient.lpszName := PChar(RecipientEMail);
end
else begin
lpRecipient.lpszName := PChar(RecipientName);
end;
lpRecipient.lpszAddress := PChar('smtp:'+RecipientEmail);
lpRecipient.ulReserved := 0;
lpRecipient.ulEIDSize := 0;
lpRecipient.lpEntryID := nil;
Message.nRecipCount := 1;
Message.lpRecips := #lpRecipient;
end
else begin
Message.lpRecips := nil;
end;
if (FileName = '') then begin
Message.nFileCount := 0;
Message.lpFiles := nil;
end
else begin
FillChar(FileAttach,SizeOf(FileAttach),0);
FileAttach.nPosition := Cardinal($FFFFFFFF);
FileAttach.lpszPathName := PChar(FileName);
FileType.ulReserved := 0;
FileType.cbEncoding := 0;
FileType.cbTag := 0;
FileType.lpTag := nil;
FileType.lpEncoding := nil;
FileAttach.lpFileType := #FileType;
Message.nFileCount := 1;
Message.lpFiles := #FileAttach;
end;
MAPIModule := LoadLibrary(PChar(MAPIDLL));
if MAPIModule = 0 then begin
Result := -1;
end
else begin
try
#SM := GetProcAddress(MAPIModule,'MAPISendMail');
if #SM <> nil then begin
Result := SM(0,Application.Handle,Message,
MAPI_DIALOG or MAPI_LOGON_UI,0);
end
else begin
Result := 1;
end;
finally
FreeLibrary(MAPIModule);
end;
end;
if Result <> 0 then begin
raise Exception.CreateFmt('Error sending eMail (%d)', [Result]);
end;
end;
Not in Simple MAPI. If you were using Outlook Object Model or Extended MAPI, you could set a special MAPI property on the message before sending it to disable TNEF format.

Indy SMTP sending email with GMail suddenly stopped working

Using: Delphi XE7, latest daily build of Indy 10.
This code was working 2 months earlier. Now I recompiled my app, and its not working anymore, with the same account details. The exception message is 'Disconnected'.
The SMTP port used is 587.
Code follows:
FIdSMTP := TIdSMTP.Create;
FIdSSLIOHandler := TIdSSLIOHandlerSocketOpenSSL.Create;
FIdMessage := TIdMessage.Create;
FIdAttachment := TIdAttachmentFile.Create(FIdMessage.MessageParts);
if (FEmailServer.SMTPUseSSL) then
begin
FIdSSLIOHandler.SSLOptions.Method := sslvTLSv1;
// FIdSSLIOHandler.SSLOptions.Method := sslvSSLv3;
FIdSMTP.IOHandler := FIdSSLIOHandler;
FIdSMTP.UseTLS := utUseExplicitTLS;
// FIdSMTP.UseTLS := utUseImplicitTLS;
end;
FIdSMTP.Host := FEmailServer.SMTPHost; //smtp.gmail.com
FIdSMTP.Port := FEmailServer.SMTPPort; //587
FIdSMTP.AuthType := satDefault;
FIdSMTP.Username := FEmailServer.SMTPUserName;
FIdSMTP.Password := FEmailServer.SMTPPassword;
FIdMessage.Recipients[0].Address := mailmessage.RecipientEmailAddr;
FIdMessage.From.Name := mailmessage.SenderName;
FIdMessage.Subject := mailmessage.EmailSubject;
FIdMessage.Body.Text := mailmessage.EmailMessage;
FIdAttachment.LoadFromFile(mailmessage.AttachmentFile);
FIdAttachment.FileName := ExtractFileName(mailmessage.AttachmentFile);
try
if (not FIdSMTP.Connected) then
FIdSMTP.Connect;
FIdSMTP.Send(FIdMessage);
except
on E: Exception do
ShowMessage(E.Message);
end;
Do you see anything obvious that could be causing it to not send the email?
Thank you, Remy! Beautiful tip! This code now works:
FIdSMTP := TIdSMTP.Create;
FIdSSLIOHandler := TIdSSLIOHandlerSocketOpenSSL.Create;
FIdMessage := TIdMessage.Create;
FIdAttachment := TIdAttachmentFile.Create(FIdMessage.MessageParts);
FIdSASLCRAMSHA1 := TIdSASLCRAMSHA1.Create;
FIdSASLCRAMMD5 := TIdSASLCRAMMD5.Create;
FIdSASLDigest := TIdSASLDigest.Create;
FIdSASLSKey := TIdSASLSKey.Create;
FIdSASLOTP := TIdSASLOTP.Create;
FIdSASLAnonymous := TIdSASLAnonymous.Create;
FIdSASLExternal := TIdSASLExternal.Create;
FIdSASLLogin := TIdSASLLogin.Create;
FIdSASLPlain := TIdSASLPlain.Create;
if (FEmailServer.SMTPUseSSL) then
begin
FIdSSLIOHandler.SSLOptions.Method := sslvTLSv1;
// FIdSSLIOHandler.SSLOptions.Method := sslvSSLv3;
FIdSMTP.IOHandler := FIdSSLIOHandler;
FIdSMTP.UseTLS := utUseExplicitTLS;
// FIdSMTP.UseTLS := utUseImplicitTLS;
end;
FIdSMTP.Host := FEmailServer.SMTPHost; //smtp.gmail.com
FIdSMTP.Port := FEmailServer.SMTPPort; //587
FIdSMTP.AuthType := satSASL;
FIdSMTP.SASLMechanisms.Add.SASL := FIdSASLCRAMSHA1;
FIdSMTP.SASLMechanisms.Add.SASL := FIdSASLCRAMMD5;
FIdSMTP.SASLMechanisms.Add.SASL := FIdSASLDigest;
FIdSMTP.SASLMechanisms.Add.SASL := FIdSASLSKey;
FIdSMTP.SASLMechanisms.Add.SASL := FIdSASLOTP;
FIdSMTP.SASLMechanisms.Add.SASL := FIdSASLAnonymous;
FIdSMTP.SASLMechanisms.Add.SASL := FIdSASLExternal;
FIdSMTP.SASLMechanisms.Add.SASL := FIdSASLLogin;
FIdSMTP.SASLMechanisms.Add.SASL := FIdSASLPlain;
FIdSMTP.Username := FEmailServer.SMTPUserName;
FIdSMTP.Password := FEmailServer.SMTPPassword;
FIdMessage.Recipients[0].Address := mailmessage.RecipientEmailAddr;
FIdMessage.From.Name := mailmessage.SenderName;
FIdMessage.Subject := mailmessage.EmailSubject;
FIdMessage.Body.Text := mailmessage.EmailMessage;
FIdAttachment.LoadFromFile(mailmessage.AttachmentFile);
FIdAttachment.FileName := ExtractFileName(mailmessage.AttachmentFile);
try
if (not FIdSMTP.Connected) then
FIdSMTP.Connect;
FIdSMTP.Send(FIdMessage);
except
on E: Exception do
ShowMessage(E.Message);
end;
Freeing up the objects:
FIdAttachment.Free;
FIdMessage.Free;
FIdSSLIOHandler.Free;
FIdSMTP.Free;
FIdSASLCRAMSHA1.Free;
FIdSASLCRAMMD5.Free;
FIdSASLDigest.Free;
FIdSASLSKey.Free;;
FIdSASLOTP.Free;
FIdSASLAnonymous.Free;
FIdSASLExternal.Free;
FIdSASLLogin.Free;
FIdSASLPlain.Free;
..the USES list:
uses Classes, SysUtils, Windows, IdSMTP, IdMessage, IdSSLOpenSSL,
IdExplicitTLSClientServerBase, IdAttachmentFile, IdSASL,
IdSASLCollection, IdSASLAnonymous, IdSASLDigest, IdSASLExternal,
IdSASLLogin, IdSASLOTP, IdSASLPlain, IdSASLSKey, IdSASLUserPass,
IdSASL_CRAM_MD5, IdSASL_CRAM_SHA1;

How to create a UIPickerView in Delphi xe6 for iOS

How do I create a UIPickerview in Delphi xe6 for iOS ? When making a selection for a combobox, a UI picker view will appear. How do I create a similar pickerview, but with more control over it? E.g., being able to place it anywhere on the form, customize it, not have to go through a combobox, etc. ?
I have found where in it's unit class where it is created.
FMX.Listbox
constructor TCustomComboBox.Create(AOwner: TComponent);
var
PickerService: IFMXPickerService;
begin
inherited;
if TPlatformServices.Current.SupportsPlatformService(IFMXPickerService, IInterface(PickerService)) then
begin
FListPicker := PickerService.CreateListPicker;
FListPicker.Parent := Self;
FListPicker.OnValueChanged := DoOnValueChangedFromDropDownList;
FListPicker.OnHide := DoClosePicker;
FListPicker.OnShow := DoPopup;
end;
FDropDownKind := TDropDownKind.Custom;
DropDownCount := 8;
FItemWidth := 0;
CanFocus := True;
FDroppedDown := False;
FPopup := TPopup.Create(Self);
FPopup.StyleLookup := 'combopopupstyle';
FPopup.PlacementTarget := Self;
FPopup.Stored := False;
FPopup.Parent := Self;
FPopup.Locked := True;
FPopup.DesignVisible := False;
FPopup.DragWithParent := True;
FPopup.OnClosePopup := DoClosePopup;
FPopup.OnPopup := DoPopup;
FListBox := CreateListBox;
FListBox.Parent := Popup;
FListBox.Stored := False;
FListBox.Align := TAlignLayout.Client;
FListBox.ShowCheckboxes := False;
FItemIndex := -1;
SetAcceptsControls(False);
DropDownKind := TDropDownKind.Native;
end;
I don't need the popup, so I then read about accessing properties and methods via a 'hack-ish' kind of way
Type
THackPicker = class(TCustomComboBox);
....
var
FListBox : TComboListBox;
begin
try
FListBox := THackPicker(FListBox).createListbox;
FListBox := TCustomComboBox.createListbox;
FListBox.Parent := Layout1;
FListBox.Stored := False;
FListBox.Align := TAlignLayout.Client;
FListBox.Items := ComboBox1.Items;
FListBox.OnClick := Button2Click;
except
on E : Exception do begin
showMessage(e.Message);
end;
end;
end;
App crashes here. I'm assuming this is not the correct way to go about it. Any help or direction would be much appreciated!

Why does SendMailMAPI rename file attachments to shorter ones?

I use the following emailing function with Eudora. For some reason the attachment file name is renamed to be something else. How can I make sure the attachment file name remains intact?
function SendMailMAPI(const Subject, Body, FileName, SenderName, SenderEMail,
RecepientName, RecepientEMail: String) : Integer;
var
message: TMapiMessage;
lpSender,
lpRecepient: TMapiRecipDesc;
FileAttach: TMapiFileDesc;
SM: TFNMapiSendMail;
MAPIModule: HModule;
begin
FillChar(message, SizeOf(message), 0);
with message do
begin
if (Subject<>'') then
begin
lpszSubject := PChar(Subject)
end;
if (Body<>'') then
begin
lpszNoteText := PChar(Body)
end;
if (SenderEMail<>'') then
begin
lpSender.ulRecipClass := MAPI_ORIG;
if (SenderName='') then
begin
lpSender.lpszName := PChar(SenderEMail)
end
else
begin
lpSender.lpszName := PChar(SenderName)
end;
lpSender.lpszAddress := PChar('SMTP:'+SenderEMail);
lpSender.ulReserved := 0;
lpSender.ulEIDSize := 0;
lpSender.lpEntryID := nil;
lpOriginator := #lpSender;
end;
if (RecepientEMail<>'') then
begin
lpRecepient.ulRecipClass := MAPI_TO;
if (RecepientName='') then
begin
lpRecepient.lpszName := PChar(RecepientEMail)
end
else
begin
lpRecepient.lpszName := PChar(RecepientName)
end;
lpRecepient.lpszAddress := PChar('SMTP:'+RecepientEMail);
lpRecepient.ulReserved := 0;
lpRecepient.ulEIDSize := 0;
lpRecepient.lpEntryID := nil;
nRecipCount := 1;
lpRecips := #lpRecepient;
end
else
begin
lpRecips := nil
end;
if (FileName='') then
begin
nFileCount := 0;
lpFiles := nil;
end
else
begin
FillChar(FileAttach, SizeOf(FileAttach), 0);
FileAttach.nPosition := Cardinal($FFFFFFFF);
FileAttach.lpszPathName := PChar(FileName);
nFileCount := 1;
lpFiles := #FileAttach;
end;
end;
MAPIModule := LoadLibrary(PChar(MAPIDLL));
if MAPIModule=0 then
begin
Result := -1
end
else
begin
try
#SM := GetProcAddress(MAPIModule, 'MAPISendMail');
if #SM<>nil then
begin
Result := SM(0, Application.Handle, message, MAPI_DIALOG or
MAPI_LOGON_UI, 0);
end
else
begin
Result := 1
end;
finally
FreeLibrary(MAPIModule);
end;
end;
if Result<>0 then
begin
MessageDlg('Error sending mail ('+IntToStr(Result)+').', mtError, [mbOk],
0)
end;
You have to set FileAttach.lpszFileName to the name you want your recipient to see. If you don't do that an attachment like "C:\Document And Settings\MyUser\Local Settings\Temp\Hello.pdf" will look like "C__DOCUME~1_MyUser_LOCALS~1_Temp_Hello.pdf" to the recipient (this is probably different per e-mailclient ).
So set FileAttach.lpszPathName to contain only the filename:
begin
FillChar(FileAttach, SizeOf(FileAttach), 0);
FileAttach.nPosition := Cardinal($FFFFFFFF);
FileAttach.lpszPathName := PChar(FileName);
FileAttach.lpszFileName := PChar(ExtractFileName(FileName)); //add this
nFileCount := 1;
lpFiles := #FileAttach;
end;
The recipient will now see an attachment with the name "Hello.pdf" instead of "C__DOCUME~1_MyUser_LOCALS~1_Temp_Hello.pdf".

Resources