Designer Preview Support for Xbase++

Today, I spoke at the Xbase Forum Meeting in Potsdam, Germany. Besides presenting what our reporting tool can do I had the joy and honor to share my presentation with Tom Liehr, a respected member of the Xbase++ community. Together we've created a modified sample for Xbase++ that shows how to support the designer preview in Xbase++. Or – better said – Tom did most of the hard work while I stood flabbergasted at the sideline. I was only able to give some hints that helped crossing the finish line just in time which was Easter Monday, 10:30 pm.
As the sample shows a generic approach how callbacks and threads can be used in Xbase++ I wanted to share the central parts here as well. First of all, two additional 3rd party packages are required, the Binary Access Package for Xbase++ (BAP) that can be downloaded from Alaska Software and the excellent OT4XB. The first is used to support callbacks, the second helps to work with C++ structures. In order to register for a callback, all that’s needed is:
// Initialize callback function using BAP
nCallBack := BaCallBack("DesignerCallback", BA_CB_GENERIC3)

// Hand callback function handle to LL
LlSetNotificationCallbackExt(hJob,LL_NTFY_DESIGNERPRINTJOB,nCallBack)

DesignerCallback is a function that has a signature like:

FUNCTION DesignerCallback(nNotification,nStructurePtr,xUserParam)
The tricky part now is working with the structure pointer. The structure that’s passed in case of the designer preview can be declared like this using OT4XB:
BEGIN STRUCTURE My_LlCallback
MEMBER UINT _nSize
MEMBER POINTER _nUserParam
MEMBER POINTER32 _pszProjectName
MEMBER POINTER32 _pszOriginalProjectFileName
MEMBER UINT _nPages
MEMBER UINT _nFunction
MEMBER HWND _hWnd
MEMBER HANDLE _hEvent
MEMBER POINTER32 _pszExportFormat
MEMBER BOOL _bWithoutDialog
END STRUCTURE

And the nSturcturePtr that’s received by the DesignerCallback function can then be “marshalled” to the Xbase++ world using:
// Create a local copy of the structure
// get the structure nStructurePtr points to - .F. means: not a copy
oCbLocal := My_LlCallback():New():_link_(nStructurePtr,.F.)
oCbLocal:_lock_()
… // do something with oCbLocal
oCbLocal:_unlock_() // unlock the structure
oCbLocal:_unlink_(.F.) // unlink the structure

An important thing to keep in mind is that you need to copy all members of the structure to local/global variables as the structure will no longer be valid once the callback routine returns. So you cannot rely on the validity of any of the structure members anywhere else in the code. Thus, the sample copies all members and passes these copies to the central printing routine:

// Init values for the print thread
cProjectName := PeekStr(oCbLocal:_pszProjectName,,-1) // filename from structure pointer
cOrgProjectName := PeekStr(oCbLocal:_pszOriginalProjectFileName,,-1) // filename from structure pointer
nProjecthWnd := oCbLocal:_hWnd // window handle
nRecNo := oCbLocal:_nUserParam // record number in INVOICE.DBF
nPages := oCbLocal:_nPages // number of pages to be printed
hEvent := oCbLocal:_hEvent // event handle for synchronization
// Start print thread
oPrintThread := Thread():new()
oPrintThread:start( {||PrintPreviewData(cProjectName,cOrgProjectName,nProjecthWnd,nRecNo,nPages,hEvent)})

The PrintPreviewData routine is more or less identical to the “normal” printing, only the progress box is removed by using LlPrintStart() instead of LlPrintWithBoxStart() and the print code attaches to the designer’s preview window by calling LlAssociatePreviewControl(). We’ll add the full sample to our knowledge base area shortly.

The sample could easily be extended to support the drilldown callback as well, which would enable the report parameter pane in the preview or expandable regions for Xbase++ applications.

Thanks again to the German Xbase-Forum for inviting me to Potsdam (which gives me an opportunity to spend the weekend there <g>) and of course thanks very much to Tom Liehr who really went the extra mile in order to make this happen.

Related Posts

Leave a Comment