2025-08-03

Fixing Right-Aligned labels in VFP9 reports (with or without FoxyPreviewer) - Updated!

Hi folks,

It’s been a while since my last post! I’m still actively working with Visual FoxPro 9 (VFP9), especially in the reports area, but as many of you know, developing and maintaining www.foxypreviewer.com has been taking up most of my free time.

In the meantime, I’ve discovered some neat tricks in VFP reporting—many of which are now baked into the newer versions of FoxyPreviewer. While I haven’t been posting as frequently, I’ve definitely been busy behind the scenes.


What's This About?

One issue that keeps coming up from FoxyPreviewer users is a misalignment between Group Header labels and Detail band fields—especially when labels are right-aligned. This behavior can be frustrating, but it’s actually related to how VFP9 handles reports under REPORTBEHAVIOR 90.

Rather than reinvent the wheel, I highly recommend checking out this very detailed blog post from Colin Nicholls:
🔗 Observations on Right-aligned labels in VFP9 Reports – by Colin Nicholls (April 2006)

In short, Colin explains:

"In Visual FoxPro 9.0, there is a new report engine that uses GDI+ to render output. The older, backward-compatible engine is still supported. You can switch between the two engines using the SET REPORTBEHAVIOR command."

To illustrate, here's what a report might look like:

  • Under SET REPORTBEHAVIOR 80: (everything looks fine)

  • Under SET REPORTBEHAVIOR 90: (right-alignment breaks)




A Word of Thanks

By the way, Colin and Lisa Nicholls' blogs at https://spacefold.com are absolute goldmines for VFP report tips. I often find myself thinking, "Let’s see what Lisa and Colin have to say about this"—and I always walk away with new insights.


So... What's the Fix?

The ideal solution is to replace Group Header labels with right-aligned fields that match the size and alignment of the Detail band fields. This not only solves the alignment issue but also improves the quality of exported Excel files (XLS/XLSX) when using FoxyPreviewer.

However, that’s often not realistic—many users have hundreds (if not thousands) of reports to deal with.

That’s why I created a simple script to automate the fix:

What It Does:

  • Analyzes your .FRX/.FRT files

  • Matches Group Header labels to right-aligned Detail fields

  • Creates two modified versions of the report:

    1. One replacing right-aligned labels with fields

    2. Another adjusting label size and position to align properly

The modified reports are saved in the same folder with a random suffix added to the filename.

The script is intentionally kept as simple as possible so you can adapt and understand it easily. It has been tested successfully on many reports, but there may still be edge cases—please let me know if you encounter any!


Next Steps: Automating with FoxyPreviewer?

Yes, I’ve been considering adding this logic directly into FoxyPreviewer as an optional automatic fix. It wouldn’t be hard to implement—but I still believe developers should review and validate any automated changes to their reports.


Download the Script

You can save the script as FRX_RIGHTALIGNLABELS.PRG, or download it directly here.


Thanks for reading! If you're working with VFP9 reports and run into this alignment issue, I hope this helps smooth things out.

Let me know your feedback—and as always, happy coding!



* File: FRX_RightAlignLabels.prg
* Creates 2 new report copies having its labels right-aligned

* Why? To avoid the known issue explained by Colin Nicholls in his blog
* Article: "Observations on Right-aligned labels in VFP9 Reports" by Colin Nicholls (April 2006)
* https://spacefold.com/colin/archive/articles/vfp9reporting/rightalign/monofonts.html

* The alignment issue is known, and comes from VFP9, not FoxyPreviewer.
* If you run any of your reports with SET REPORTBEHAVIOR 90 without FoxyPreviewer you'll see the issue there as well!

* The main idea is to identify the labels that correspond to Right-Aligned numeric fields in the 'Detail' band,
* and reposition the labels to match the right edge of the field

Local lmMatch

CLEAR
CLOSE ALL


LOCAL lcMyReport
m.lcMyReport = GETFILE("FRX")
IF EMPTY(m.lcMyReport)
	RETURN .F.
ENDIF



* Step 1: Load the FRX file into a ReadWrite cursor
* To ease the manipulation an understanding convert the dimensions o Pixels and store in new fields
USE (m.lcMyReport) ALIAS frx0 SHARED
SELECT 000 AS nRec, 000 AS Match, 00000 AS x, 00000 as y, 00000 as w, 00000 as h, 00000 as R, * FROM FRX0 INTO CURSOR FRX READWRITE

REPLACE ALL y WITH FLOOR(vPos * .0096), H WITH FLOOR(Height * .0096), ;
	x WITH FLOOR(hPos * .0096), W WITH FLOOR(Width * .0096), ;
	nRec WITH RECNO(), R WITH (x + w) ;
	FOR INLIST(OBJTYPE, 5, 6, 8, 9) IN Frx


* Step 2: Capture full band vertical positions (TOP + HEIGHT)
LOCAL lnTitle, lnMainHeader, lnColHeader, lnGrpHeader, lnDetail
STORE 0 TO m.lnMainHeader, m.lnGrpHeader, m.lnTitle, m.lnColHeader, m.lnDetail
SELECT frx



LOCAL llHasHeader, llHasGrpHeader, llHasDetail
SCAN FOR OBJTYPE = 9 AND h > 0 && AND INLIST(OBJCODE, 1, 2, 3, 9, 4)
	DO CASE

		CASE Objcode = 0
			m.lnTitle  = h + 20

		CASE Objcode = 1
			m.lnMainHeader = h + 20
			m.llHasHeader = .T.

		CASE Objcode = 2
			m.lnColHeader = h + 20

		CASE Objcode = 3
			m.lnGrpHeader = h + 20
			m.llHasGrpHeader = .T.

		CASE Objcode = 4
			m.lnDetail = h + 20
			m.llHasDetail = .T.

		OTHERWISE

	ENDCASE
ENDSCAN


* Step 3: Determine the starting and ending of each band
LOCAL lnTitle0, lnTitle1
LOCAL lnMainHeader0, lnMainHeader1
LOCAL lnColHeader0, lnColHeader1
LOCAL lnGrpHeader0, lnGrpHeader1
LOCAL lnDetail0, lnDetail1

m.lnTitle0 = 0
m.lnTitle1 = m.lnTitle

m.lnMainHeader0 = m.lnTitle1
m.lnMainHeader1 = m.lnMainHeader0 + m.lnMainHeader

m.lnColHeader0 = m.lnMainHeader1
m.lnColHeader1 = m.lnColHeader0 + m.lnColHeader

m.lnGrpHeader0 = m.lnColHeader1
m.lnGrpHeader1 = m.lnGrpHeader0 + m.lnGrpHeader

m.lnDetail0 = m.lnGrpHeader1
m.lnDetail1 = m.lnDetail0 + m.lnDetail


*  Step 5: Assign each field to its Band type
LOCAL lcBand, lcBandIndex
SELECT frx
SCAN FOR INLIST(OBJTYPE, 5, 8)
	DO CASE

		CASE Frx.y >= m.lnGrpHeader1 AND Frx.y <= m.lnDetail1 AND Frx.OBJTYPE = 8 AND Frx.FILLCHAR = "N" AND Frx.OFFSET = 1 && Only the numeric fields, and right aligned
			m.lcBand = "Detail"
			m.lcBandIndex = "4"

		CASE Frx.y < m.lnTitle1 AND Frx.OBJTYPE = 5
			m.lcBand = "Title"
			m.lcBandIndex = "0"

		CASE Frx.y < m.lnMainHeader1 AND m.llHasDetail = .F. AND Frx.OBJTYPE = 8
			m.lcBand = "Header"
			m.lcBandIndex = "1"

		CASE Frx.y < m.lnMainHeader1 AND Frx.OBJTYPE = 5
			m.lcBand = "Header"
			m.lcBandIndex = "1"

		CASE Frx.y < m.lnColHeader1 AND Frx.OBJTYPE = 5
			m.lcBand = "ColHeader"
			m.lcBandIndex = "2"

		CASE Frx.y < m.lnGrpHeader1 AND Frx.OBJTYPE = 5
			m.lcBand = "GrpHeader"
			m.lcBandIndex = "3"

		OTHERWISE
			m.lcBand = ""

	ENDCASE

	IF NOT EMPTY(m.lcBand)
		* Reuse the 'Platform' and 'BoxChar' fields to store in which band each field resides
		REPLACE Frx.Platform WITH m.lcBand, Frx.BOXCHAR WITH m.lcBandIndex IN Frx
	ENDIF
ENDSCAN


* If the FRX does not have a 'GroupHeader-3' band, then we pick the labels from the 'Title-1' band
DO CASE

	CASE NOT m.llHasDetail && No detail band, so we work only at the Title
		SELECT * FROM FRX WHERE BOXCHAR = "1" AND OBJTYPE = 5 INTO CURSOR "FrxLabels" READWRITE

	CASE m.llHasGrpHeader
		SELECT * FROM FRX WHERE BOXCHAR = "3" AND OBJTYPE = 5 INTO CURSOR "FrxLabels" READWRITE

	CASE m.llHasHeader
		* BROWSE FOR INLIST(BOXCHAR, "1", "4")
		SELECT * FROM FRX WHERE BOXCHAR = "1" INTO CURSOR "FrxLabels" READWRITE

	OTHERWISE
		CLOSE ALL
		MESSAGEBOX("Unable to create the new report", 48)
		RETURN

ENDCASE


* Step 6: Find the matching Labels and Fields
LOCAL laLabels(1, 2), lnLabels, loField, lnNewRight, lnRight
m.lnLabels = 0

SELECT FRX
* Let's find the matches
LOCAL lcDetailChar
IF m.llHasDetail
	m.lcDetailChar = "4"
ELSE
	m.lcDetailChar = "1"
ENDIF



* Scan through all labels and find if there are matching fields for them
LOCAL laMatches(1), lnMatches, lnMatch
m.lnMatches = 0
m.lmMatch = 0

SELECT FrxLabels
SCAN
	m.lnRight = FrxLabels.R
	SELECT FRX
	LOCATE FOR Frx.BOXCHAR = m.lcDetailChar AND OBJTYPE = 8 AND BETWEEN(FRX.R, m.lnRight - 2, m.lnRight + 2)

	IF NOT EOF()
		m.lnMatch = Frx.nRec
		REPLACE FRXLabels.Match WITH m.lnMatch IN FrxLabels
		m.lnLabels = m.lnLabels + 1
		DIMENSION m.laLabels(m.lnLabels, 2)
		m.laLabels(m.lnLabels, 1) = FrxLabels.nRec
		SCATTER NAME m.loField MEMO
		m.laLabels(m.lnLabels, 2) = m.loField
	ENDIF
	SELECT FrxLabels
ENDSCAN



LOCAL laMatches(1), lnMatches, lnMatch
m.lnMatches = 0
m.lmMatch = 0
SCAN FOR BOXCHAR = m.lcDetailChar AND OBJTYPE = 8 && Detail Numeric and right aligned fields
	m.lnRight = FRX.R
	SELECT FrxLabels
	LOCATE FOR BETWEEN(FRXLabels.R, m.lnRight - 2, m.lnRight + 2)
	IF NOT EOF()
		m.lnMatch = FrxLabels.nRec

		IF ASCAN(m.laMatches, m.lnMatch) = 0
			m.lnMatches = m.lnMatches + 1
			DIMENSION m.laMatches(m.lnMatches)
			m.laMatches(m.lnMatches) = m.lnMatch
			REPLACE FRX.Match WITH m.lnMatch IN FRX


			m.lnLabels = m.lnLabels + 1
			DIMENSION m.laLabels(m.lnLabels, 2)
			m.laLabels(m.lnLabels, 1) = FrxLabels.nRec
			SELECT Frx
			SCATTER NAME m.loField MEMO
			m.laLabels(m.lnLabels, 2) = m.loField

		ENDIF
	ENDIF
	SELECT Frx
ENDSCAN
SELECT Frx



IF VARTYPE(m.laLabels(1, 1)) = "L"
	MESSAGEBOX("No changes to apply", 32)
	CLOSE ALL
	RETURN
ENDIF



* Now we are ready to create our new report copies
LOCAL lnField, n

* Step 7: Create a new Report Copy with a replaced field instead of the original label

* Replace the Label with a Field object, right aligned and resized
LOCAL lcNewReport8  && OBJTYPE 8 = Field
m.lcNewReport8 = ADDBS(JUSTPATH(m.lcMyReport)) + JUSTSTEM(m.lcMyReport) + "_8" + SYS(2015) + ".frx"
SELECT * FROM FRX0 INTO TABLE (m.lcNewReport8)
USE (m.lcNewReport8) ALIAS frxNew8 SHARED
SELECT FrxNew8

FOR m.n = 1 TO m.lnLabels
	* Change the label to field
	m.lnField = m.lalabels(m.n, 1)
	m.loField = m.lalabels(m.n, 2)
	GO (m.lnField)

	LOCAL lnOldLeft, lnOldWidth, lnNewLeft, lnNewWidth
	m.lnOldLeft  = FrxNew8.hPos
	m.lnOldWidth = FrxNew8.Width

	IF (m.lnOldWidth + 500) > m.loField.Width
		m.lnNewWidth = m.lnOldWidth + 1000
		m.lnNewRight = FrxNew8.hPos + FrxNew8.Width
		m.lnNewLeft  = m.lnNewRight - m.lnNewWidth
	ELSE
		m.lnNewWidth = m.loField.Width
		m.lnNewLeft  = m.loField.hPos
	ENDIF

	REPLACE OBJTYPE WITH 8, Width WITH m.lnNewWidth, height WITH m.loField.Height, hPos WITH m.lnNewLeft, FILLCHAR WITH "C", OFFSET WITH 1 STRETCH WITH .T. IN FrxNew8
ENDFOR


* Step 8: Create a new Report Copy with a a Right aligned label instead of the original

* Enlarge the label
* Reposition to the right-most position aligned to the relative field
* Ensure right aligned
LOCAL lcNewReport5  && OBJTYPE 5 = Label
m.lcNewReport5 = ADDBS(JUSTPATH(m.lcMyReport)) + JUSTSTEM(m.lcMyReport) + "_5" + SYS(2015) + ".frx"
SELECT * FROM FRX0 INTO TABLE (m.lcNewReport5)
USE (m.lcNewReport5) ALIAS frxNew5 SHARED
SELECT FrxNew5

FOR m.n = 1 TO m.lnLabels
	* Change the label to field
	m.lnField = m.lalabels(m.n, 1)
	m.loField = m.lalabels(m.n, 2)
	GO (m.lnField)

	LOCAL lnOldLeft, lnOldWidth, lnNewLeft, lnNewWidth
	m.lnOldLeft  = FrxNew5.hPos
	m.lnOldWidth = FrxNew5.Width

	IF (m.lnOldWidth + 500) > m.loField.Width
		m.lnNewWidth = m.lnOldWidth + 1000
		m.lnNewRight = FrxNew5.hPos + FrxNew5.Width
		m.lnNewLeft  = m.lnNewRight - m.lnNewWidth
	ELSE
		m.lnNewWidth = m.loField.Width
		m.lnNewLeft  = m.loField.hPos
	ENDIF

	* Picture field
	* For Report Labels, this field is empty for left justified (default), contains @I for centered or contains @J for right justified.
	REPLACE Width WITH m.lnNewWidth, hPos WITH m.lnNewLeft, PICTURE WITH ["@J"] IN FrxNew5
ENDFOR


* Step 9: Close
USE IN SELECT("frx")
USE IN SELECT("frx0")
USE IN SELECT("FrxLabels")
USE IN SELECT("frxNew5") && Labels
USE IN SELECT("frxNew8") && Fields


MESSAGEBOX("A report copy was created having " + TRANSFORM(m.lnLabels) + ;
	  " label(s) replaced as fields under the file name:" + CHR(13) + CHR(13) + m.lcNewReport8, 64)

MESSAGEBOX("A report copy was created having " + TRANSFORM(m.lnLabels) + ;
	  " label(s) repositioned under the file name:" + CHR(13) + CHR(13) + m.lcNewReport5, 64)


* Show the original Report, and then, the 2 new versions
MODIFY REPORT (m.lcMyReport)
MODIFY REPORT (m.lcNewReport5)
MODIFY REPORT (m.lcNewReport8)

RETURN






2024-05-21

FoxyPreviewer 3 - Sending E-mails

 FoxyPreviewer brings 5 ways for you to send emails:

1 – MAPI - Uses the WinAPI MapiSendMail to try to send the current report as an attachment.
This setting sends a standard message, with one or more attached files and a cover note. The cover note is a dialog box that allows the user to enter a list of recipients and an optional message and other sending options. It will open a dialog email sending message, waiting for a user interaction. The message will not be sent automatically. It’s up to the user to veryfy the information ofthe message and to click at the “Send” button. 
This function tries to establish a session using the messaging system's shared session. If no shared session exists, it will fail sending the message.
This works pretty well if you have your default account set using MS Outlook Express, MS Outlook or Windows Live Mail. Definitely, it’s the easiest way to send your messages, because this way, FoxyPreviewer will use the default Email configuration of the computer.

You can set this mode by:

_Screen.oFoxyPreviewer.nEmailMode = 1 && MAPI


2 - MAPI Alternative – Uses the WinAPI MapiSendDocuments to try to send the current report as an attachment.
The MAPISendDocuments function sends a standard message with one or more attached files and a cover note. The cover note is a dialog box that allows the user to enter a list of recipients and an optional message and other sending options.
This function tries to establish a session using the messaging system's shared session. If no shared session exists, it will fail sending the message.
This works pretty well if you have your default account set using MS Outlook Express, MS Outlook or Windows Live Mail. Definitely, it’s the easiest way to send your messages, because this way, FoxyPreviewer will use the default Email configuration of the computer.
Although MS says that “The use of this function is discouraged. It may be altered or unavailable in subsequent versions of Windows.”, it’s been working well in all OS’s, from WinNT to WinSeven


_Screen
.oFoxyPreviewer.nEmailMode = 5 && MAPI Alternative


3 – Custom Procedure
You can use your own procedure to send the current report. use foxypreviewer property "cEmailPrg", and fill it with the name of the prg responsible for sending emails. This PRG receives as a parameter the file name of the file created that you will send as attachment. Have a look at the samples provided, the file MYSENDMAIL.PRG shows how you would need to make your custom procedure. The idea is that when your user clicks in the "Sent to E-mail" button from the Preview, the generated output file will be sent using your own pocedure.

* THIS BRINGS YOU AN OPTION TO CONTROL WHAT FUNCTIONS EACH USER WILL HAVE AVAILABLE
WITH _Screen.oFoxyPreviewer
    .cEmailPrg = "MYSENDMAIL.PRG" && This is your PRG with your custom procedure
    .nEmailMode = 4 && CUSTOM PROCEDURE
    .cEmailType  = "PDF"   
ENDWITH

REPORT FORM (_Samples + "\Solution\Reports\percent.frx") PREVIEW

Then, in your PRG - AKA "MYSENDMAIL.PRG", add in the 1st line:

LPARAMETERS tcFileToSend


And add all code you need to send your messages the way you need.

 

4 – CDO
Uses the CDO2000 component included in windows 2000 and later. It allows you to send emails using a SMTP server. All settings must be accurate in order to make this work. 

The usage was really simple, but it's not compatible with TLS - evolved from the good and old SSL protocol, providing more security to the process. That means that the main SMTP servers are not compatible with it any more - Outlook.com and Gmail.com use the Port 587 that is not supported. But This way to send mails is still valid for several other E-mail servers.

 

5 – POWERSCRIPT MAIL
Uses PowerScript to access the "SendMail-Message" function from .NET
This is a very nice, up to date way to send your e-mails. The best is that it is compatible with all e-mail servers and Smtp ports.

_Screen.oFoxyPreviewer.nEmailMode = 7 && Powerscript mail

The easiest way to configure your e-mails is from the settings form from the Preview Screen:

You can set all properties, and even test your SMTP server settings, in CDO or Powerscript to be sure they work!

Below is a short animation showing dynamically how it works. Once you set them, the same settings will be available for the next reports!

 


Of course you can set it all programatically as well! See:

WITH _SCREEN.oFoxyPreviewer
	.cEmailPRG 		= "MySendPSEmail2.PRG"
	.nEmailMode     = 7     && 1 = MAPI, 2 = CDOSYS HTML, 3 = CDOSYS TEXT, 4 = Custom procedure, 6=CustomProc 7=Powerscript
	.cEmailTo       = "destination@hotmail.com"
	.cEmailFrom     = "you@hotmail.com"
	.cEmailSubject  = "Subject test"
	.nSMTPPort      = 587 && TLS
	.lSMTPUseSSL    = .T.
	.cSMTPUserName  = .cEmailFrom
	.cSMTPServer    = "smtp.office365.com"
	.cSMTPPassword  = "yourpwd"
	.lEmailAuto     = .T.   && Automatically generates the report output file
	.cEmailType     = "PDF" && The file type to be used in Emails (PDF, RTF, HTML or XLS)
	.cEmailBody     = "<BR>Email Test with <b>FoxyPreviewer</b>"
ENDWITH

REPORT FORM (_Samples + "\Solution\Reports\percent.frx") PREVIEW


And finally, here are the E-mail properties that you can set in FoxyPreviewer3:


Generic Email settings

  •  nEmailMode - numeric, the email type (1 = MAPI, 2 = CDOSYS HTML, 3 = CDOSYS TEXT, 4 = Custom procedure)
  •  lEmailAuto - logical, Automatically generates the report output file. The file name to be used is determined by the property "cSaveDefName".
  •  cEmailType - character, the file type to be used in Emails (PDF, RTF, HTML or XLS)
  •  cEmailPRG - character, the name of a PRG that will fire your custom email. In this PRG, you need to receive one parameter, tcFiIle, that is the temporary output file that you'll send by email. A complete sample, "MYSENDMAIL.PRG" is available, showing you how you can send your emails. To use it, you need to set the value of this property, for instance: .cEmailPrg = "MySendMail.Prg"
  •  cSaveDefName - character, the default name of the save file. Available in the SAVE AS dialog OR automatically used if lEmailAuto
  •  cTempDestFile - character, the temporary destination file (image, htm, pdf, etc). Its contents will be wiped after the 1st report run. That means that the default file name will return to be empty after the report run. (FPv3)
     cFaxPRG - character, the custom procedure name responsible for sending faxes. For example: _Screen.oFoxyPreviewer.cFaxPrg = "mySendFax.prg"

CDOSYS EMAIL PROPERTIES
  •  cSMTPServer - character, the SMTP server address. Applicable when ".nEmailMode=2 or 3"
  •  nSMTPPort - numeric, the SMTP port (usually 25). Applicable when ".nEmailMode=2 or 3"
  •  lSMTPUseSSL - logical, determines if the SMTP server requires SSL (security connection). Applicable when ".nEmailMode=2 or 3"
  •  cSMTPUserName - character, the SMTP user name. Applicable when ".nEmailMode=2 or 3"
  •  cSMTPPassword - character, the SMTP password. Applicable when ".nEmailMode=2 or 3"
  •  cEmailTo - character, the destination email. You may use the comma "," separator to use more than one address
  •  cEmailCC - character, the destination COPY email. You may use the comma "," separator to use more than one address. Applicable when ".nEmailMode=2 or 3"
  •  cEmailBCC - character, the destination BLIND COPY email. You may use the comma "," separator to use more than one address. Applicable when ".nEmailMode=2 or 3"
  •  cEmailReplyTo - character, the email to be used for replies. Applicable when ".nEmailMode=2 or 3"
  •  cEmailSubject - character, the email subject. Applicable when ".nEmailMode=2 or 3"
  •  cEmailBody - character, the email text body. Applicable when ".nEmailMode=2 or 3"
  •  cEmailFrom - character, the email sender information. You may add some custom captions, eg: 'FoxyPreviewer team<foxyteam@hotmail.com>'. Applicable when ".nEmailMode=2 or 3"
  •  cEmailBodyFile - character, the HTML file to be used as email body. Applicable when ".nEmailMode=2 or 3"
  •  lReadReceipt - logical, determines if the message will ask for a read receipt. Applicable when ".nEmailMode=2 or 3"
  •  lPriority - logical, determines if the priority level will be high. Applicable when ".nEmailMode=2 or 3"
  •  cEncryptProcedure - character, The programmer can apply his own Scrambling method on the password string (for advanced users). Applicable when ".nEmailMode=2 or 3"
  •  cDecryptProcedure - character, The programmer can apply his own Scrambling method on the password string (for advanced users). Applicable when ".nEmailMode=2 or 3"
  •  cCryptKey - character, the crypt key used to encrypt the SMTP password stored in the settings table (for advanced users). Applicable when ".nEmailMode=2 or 3"
  •  cAttachments - character, the fullpath of the files to be attached to the email message. Use a comma "," as a delimiter between files (for advanced users). Applicable when ".nEmailMode=2 or 3"
  •  cAdressTable - character, the name of the alias or FullPath of a table that contains an adress book with emails to be used when sending email messages using the provided form. This table MUST contain a Field of Character type, named "email". Apart from that, it can contain any other data that you want to be visible in a search grid, helping the users to choose the destination. For a better comprehension, please refer to the samples provided and the FAQS. (for advanced users). Applicable when ".nEmailMode=2 or 3"
  •  cAdressSearch - character, optional, the name of the field to be used for making searches. (for advanced users). Applicable when ".nEmailMode=2 or 3"