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
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;
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.
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 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!
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".