home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Visual Basic 4 Unleashed
/
Visual_Basic_4_Unleashed_SAMS_Publishing_1995.iso
/
repease
/
demo.c
< prev
next >
Wrap
C/C++ Source or Header
|
1995-08-14
|
46KB
|
1,193 lines
/*==============================================================================
DEMO.C :- FORM Demo Program (MS Windows Version)
Sub Systems, Inc.
Software License Agreement (1989)
----------------------------------
This is a demo program. The program shows how you can utilize the Report
Ease routines to perform develop report templates and execute the reports.
===============================================================================*/
#include "windows.h"
#include "stdio.h"
#include "stdlib.h"
#include "fcntl.h"
#include "sys\types.h"
#include "sys\stat.h"
#include "io.h"
#include "dos.h"
#include "string.h"
#include "math.h"
#if defined(__TURBOC__)
#include "dir.h"
#include "mem.h"
#else
#include "memory.h"
#endif
/******************************************************************************
WIN32 specific defines
*******************************************************************************/
#if defined (_WIN32)
#if !defined(WIN32)
#define WIN32
#endif
#endif
#if defined (WIN32)
#undef huge
#define huge
#undef FreeProcInstance
#define FreeProcInstance(x)
#define COMMAND_ID(wp,lp) LOWORD(wp)
#define CONTROL_ID(wp,lp) LOWORD(wp)
#define NOTIFY_MSG(wp,lp) HIWORD(wp)
#undef farmalloc
#define farmalloc malloc
#undef farrealloc
#define farrealloc realloc
#undef farfree
#define farfree free
#else
#define COMMAND_ID(wp,lp) (wp)
#define CONTROL_ID(wp,lp) (wp)
#define NOTIFY_MSG(wp,lp) HIWORD(lp)
#endif
/******************************************************************************
DLL and demo program specific includes
*******************************************************************************/
#include "rep.h"
#include "demo.h"
#include "util.h" // need only by the demo program
/****************************************************************************
Main Fuction
******************************************************************************/
int PASCAL WinMain(HANDLE hInstance,HANDLE hPrevInstance,LPSTR lpCmdLine,int nCmdShow)
{
MSG msg;
hPrevInst=hPrevInstance;
if (!hPrevInstance)
if (!InitApplication(hInstance))
return (FALSE);
if (!InitInstance(hInstance, nCmdShow))
return (FALSE);
while (GetMessage(&msg, NULL, 0, 0)) {
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return (msg.wParam);
}
/****************************************************************************
Initialize window data and register window class
****************************************************************************/
BOOL InitApplication(HANDLE hInstance)
{
WNDCLASS wc;
wc.style = 0;
wc.lpfnWndProc = (void far *)DemoWndProc;
wc.cbClsExtra = 0;
wc.cbWndExtra = 0;
wc.hInstance = hInstance;
wc.hIcon = LoadIcon(NULL, IDI_APPLICATION);
wc.hCursor = LoadCursor(NULL, IDC_ARROW);
wc.hbrBackground = GetStockObject(WHITE_BRUSH);
wc.lpszMenuName = "DemoMenu";
wc.lpszClassName = "ReDemoClass";
return (RegisterClass(&wc));
}
/****************************************************************************
Save instance handle and create main window
****************************************************************************/
BOOL InitInstance(HANDLE hInstance,int nCmdShow)
{
HWND hDemoWin;
int i;
hInst = hInstance;
hDemoWin = CreateWindow(
"ReDemoClass",
"Report Ease Demo",
WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT,
CW_USEDEFAULT,
CW_USEDEFAULT,
CW_USEDEFAULT,
NULL,
NULL,
hInstance,
NULL
);
if (!hDemoWin)
return (FALSE);
ShowWindow(hDemoWin, nCmdShow);
UpdateWindow(hDemoWin);
//****** initialize the structure variables *********
FormParm.open=FALSE; // all windows closed in the beginning
FormParm.x=0; // Initial X position of FORM edit window
FormParm.y=0; // Initial Y position of FORM edit window
FormParm.width=GetSystemMetrics(SM_CXSCREEN); // Initial edit window width
FormParm.height=(GetSystemMetrics(SM_CYSCREEN)*9)/10; // Initial edit window height
FormParm.ShowMenu=TRUE; // display menu
FormParm.ShowVerBar=TRUE; // display vertical scroll bar
FormParm.ShowHorBar=TRUE; // display horizontal scroll bar (N/A with word wrap)
strcpy(FormParm.file,""); // Text file name if the input type is 'F'
FormParm.hInst=hInst; // Current application instant handle
FormParm.hPrevInst=hPrevInst; // Previous application instant handle
FormParm.hParentWnd=hDemoWin; // let this be the parent of the editor window
FormParm.style=WS_OVERLAPPEDWINDOW; // Editor window style
strcpy(FormParm.DataSetName,"CUSTOMER");
//***** pass the pointer to the call back routines
/** The field selection and verification routines must be included in the
export section of your applications definition file **/
FormParm.UserSelection=(USER_SELECTION)MakeProcInstance(UserFieldSelection,hInst); // field selection routine
FormParm.VerifyField=(VERIFY_FIELD)MakeProcInstance(VerifyField,hInst); // field verification routine
if (!FormParm.UserSelection || !FormParm.VerifyField) return FALSE;
//**** copy the parameters to the RepParam structure *********
RepParm.hInst=FormParm.hInst;
RepParm.hPrevInst=FormParm.hPrevInst;
RepParm.hParentWnd=FormParm.hParentWnd;
RepParm.style=FormParm.style;
strcpy(RepParm.SwapDir,""); // screen page swap location
RepParm.DrawPicture=(DRAW_PICTURE)MakeProcInstance(DrawPicture,hInst); // field verification routine
if (!RepParm.DrawPicture) return FALSE;
//********** read field name for the files *******************
strcpy(DataFile[0].name,"CUSTOMER");
strcpy(DataFile[1].name,"SALES");
for (i=0;i<MAX_FILES;i++) {
if (!ReadFields(i)) return FALSE;
}
// load the customer logo bitmap
hLogoBM=LoadBitmap(hInst,"LogoBM");
Bitmap2DIB(); // extract bits from the bitmap
return (TRUE);
}
/****************************************************************************
Process Main Window messages
****************************************************************************/
long FAR PASCAL _export DemoWndProc(HWND hWnd,UINT message,WPARAM wParam,LPARAM lParam)
{
FARPROC lpProcParam;
switch (message) {
case WM_COMMAND:
switch (COMMAND_ID(wParam,lParam)) {
case IDM_EDITOR: // open a new window
if (FormParm.open) {
MessageBox(hDemoWin,"A Form Editor Window Already Open!",NULL,MB_OK);
break;
}
CallEditor(); // call the form editor
break;
case IDM_EXECUTER: // run a form template
if (FormParm.open) {
MessageBox(hWnd,"A Form Editor Window Already Open!",NULL,MB_OK);
break;
}
RunReport(); // run the report
break;
case IDM_OPTIONS: // accept editor window options
if (FormParm.open) {
MessageBox(hWnd,"A Form Editor Window Already Open!",NULL,MB_OK);
break;
}
lpProcParam = MakeProcInstance(DemoOptions, hInst);
DialogBox(hInst,"DemoOptions",hWnd,lpProcParam);
FreeProcInstance(lpProcParam);
break;
case IDM_EXIT: // quit demo
if (FormParm.open) {
if (!SendMessage(FormParm.hFrWnd,WM_QUERYENDSESSION,0,0L)) break;
}
PostQuitMessage(0);
default:
return (DefWindowProc(hWnd, message, wParam, lParam));
}
break;
case WM_DESTROY:
if (FormParm.open) {
if (!SendMessage(FormParm.hFrWnd,WM_QUERYENDSESSION,0,0L)) break;
}
// release demo bitmap data
if (hLogoBM) DeleteObject(hLogoBM);
GlobalUnlock(hImage);
GlobalUnlock(hInfo);
GlobalFree(hImage);
GlobalFree(hInfo);
PostQuitMessage(0);
break;
/********************************************************************
Messages coming from the form editor Window
*********************************************************************/
case REP_CLOSE: // REP sends this message before closing
FormParm.open=FALSE; // mark Report Ease as closed
break;
default:
return (DefWindowProc(hWnd, message, wParam, lParam));
}
return (LRESULT)(NULL);
}
/****************************************************************************
CallEditor:
This function calls the form editor.
****************************************************************************/
CallEditor()
{
int result;
char string[80];
if (GetFormSelection(FormParm.file,TRUE)>=0) { // select a form file
//*** let form designer use the default fonts ******
FormParm.FontTypeFace[0]=0; // default font type faces for report
result=form(&FormParm); // call the form editor
if (result!=0) { // print error if any
wsprintf(string,"Error calling the form editor, code: %d",result);
MessageBox(NULL,string,NULL,MB_OK);
}
}
return TRUE;
}
/****************************************************************************
DemoOptions:
This dialog box allows the user to change the editor window options.
****************************************************************************/
BOOL FAR PASCAL _export DemoOptions(HWND hDlg,unsigned message,WPARAM wParam,LPARAM lParam)
{
switch (message) {
case WM_INITDIALOG:
// Set initial values of the parameters
SetDlgItemInt(hDlg,IDC_X,FormParm.x,0);
SetDlgItemInt(hDlg,IDC_Y,FormParm.y,0);
SetDlgItemInt(hDlg,IDC_WIDTH,FormParm.width,0);
SetDlgItemInt(hDlg,IDC_HEIGHT,FormParm.height,0);
SendMessage(GetDlgItem(hDlg,IDC_MENU),BM_SETCHECK, FormParm.ShowMenu, 0L);
SendMessage(GetDlgItem(hDlg,IDC_VER_BAR),BM_SETCHECK, FormParm.ShowVerBar, 0L);
SendMessage(GetDlgItem(hDlg,IDC_HOR_BAR),BM_SETCHECK, FormParm.ShowHorBar, 0L);
return (TRUE);
case WM_COMMAND:
switch (CONTROL_ID(wParam,lParam)) {
case IDOK:
if (!GetNumVal(hDlg,IDC_X,&FormParm.x)) return (TRUE);
if (!GetNumVal(hDlg,IDC_Y,&FormParm.y)) return (TRUE);
if (!GetNumVal(hDlg,IDC_WIDTH,&FormParm.width)) return (TRUE);
if (!GetNumVal(hDlg,IDC_HEIGHT,&FormParm.height)) return (TRUE);
FormParm.ShowMenu=SendMessage(GetDlgItem(hDlg,IDC_MENU),BM_GETCHECK, 0, 0L);
FormParm.ShowVerBar=SendMessage(GetDlgItem(hDlg,IDC_VER_BAR),BM_GETCHECK, 0, 0L);
FormParm.ShowHorBar=SendMessage(GetDlgItem(hDlg,IDC_HOR_BAR),BM_GETCHECK, 0, 0L);
EndDialog(hDlg, TRUE);
return (TRUE);
case IDCANCEL:
EndDialog(hDlg, FALSE);
return (TRUE);
default:
;
}
break;
}
return (FALSE);
}
/******************************************************************************
GetFormSelection:
Shows available report forms and let user select one.
In form edit mode, the user has two additional selections to
create a new report form.
******************************************************************************/
GetFormSelection(char *CurFile,int FormEdit)
{
int select;
FARPROC lpProcParam;
TotalForms=0;
strcpy(CurFile," ");
#if defined (WIN32)
GetFormFiles("*.FPC"); // get the report form files
#else
GetFormFiles("*.FP"); // get the report form files
#endif
if (FormEdit) { // allow the user to create new forms
NewReport=TotalForms; // append the new report selection
TotalForms++;
strcpy(FormName[NewReport],"New Report Form");
strcpy(FormFile[NewReport]," ");
}
else NewReport=TotalForms;
//***** show the file seletion box and let user select a file *****
lpProcParam = MakeProcInstance(DemoForms, hInst);
select=DialogBox(hInst,"DemoForms",hDemoWin,lpProcParam);
FreeProcInstance(lpProcParam);
if (select>=0) {
strcpy(CurFile,"");
if (select!=NewReport) strcpy(CurFile,FormFile[select]); // pass the file name
}
return select;
}
/****************************************************************************
DemoForms:
This dialog box allows the user to select a form file.
****************************************************************************/
BOOL FAR PASCAL _export DemoForms(HWND hDlg,unsigned message,WPARAM wParam,LPARAM lParam)
{
int i,idx;
switch (message) {
case WM_INITDIALOG:
// Set initial values of the parameters
for (i=0;i<TotalForms;i++) {
idx=(int)SendMessage(GetDlgItem(hDlg,IDC_FILE_BOX),LB_ADDSTRING, 0, (DWORD)(LPSTR)FormName[i]);
SendMessage(GetDlgItem(hDlg,IDC_FILE_BOX),LB_SETITEMDATA, idx, i);
}
SendMessage(GetDlgItem(hDlg,IDC_FILE_BOX),LB_SETCURSEL, 0,0L);
SetFocus(GetDlgItem(hDlg,IDC_FILE_BOX));
return (FALSE);
case WM_COMMAND:
switch (CONTROL_ID(wParam,lParam)) {
case IDC_FILE_BOX:
if (NOTIFY_MSG(wParam,lParam)!=LBN_DBLCLK) break;
case IDOK:
i=SendMessage(GetDlgItem(hDlg,IDC_FILE_BOX),LB_GETCURSEL, 0,0L); // index into the list box
i=SendMessage(GetDlgItem(hDlg,IDC_FILE_BOX),LB_GETITEMDATA, i,0L); // index into our table
EndDialog(hDlg, i);
return (TRUE);
case IDCANCEL:
EndDialog(hDlg, -1);
return (TRUE);
default:
;
}
break;
}
return (FALSE);
}
/****************************************************************************
DemoFileField:
This dialog box allows the user to select a data file or to select
a field for a data file. When lParam is -1, the dialog box shows
the data files to select from. When lParam is zero or greater than
zero, the dialog box shows the fields for the file to select from. The
lParam, then specifies the index of the data file to choose the
fields from.
****************************************************************************/
int FAR PASCAL _export DemoFileField(HWND hDlg,unsigned message,WPARAM wParam,LPARAM lParam)
{
int i;
switch (message) {
case WM_INITDIALOG:
// Set initial values of the parameters
if (lParam<0) { // stuff the list box with data file names
SetWindowText(hDlg,"Select Data File"); // set the header
for (i=0;i<MAX_FILES;i++) {
SendMessage(GetDlgItem(hDlg,IDC_FILE_BOX),LB_ADDSTRING, 0, (DWORD)(LPSTR)DataFile[i].name);
}
}
else { // stuff the list box with data field names
if (GetSortField) SetWindowText(hDlg,"Select Sort Field");// set the header
else SetWindowText(hDlg,"Select Data Field");// set the header
for (i=0;i<DataFile[lParam].TotalFields;i++) {
SendMessage(GetDlgItem(hDlg,IDC_FILE_BOX),LB_ADDSTRING, 0, (DWORD)(LPSTR)DataField[lParam][i].ShortName); // load the field names
}
}
SendMessage(GetDlgItem(hDlg,IDC_FILE_BOX),LB_SETCURSEL, 0,0L);
SetFocus(GetDlgItem(hDlg,IDC_FILE_BOX));
return (FALSE);
case WM_COMMAND:
switch (CONTROL_ID(wParam,lParam)) {
case IDC_FILE_BOX:
if (NOTIFY_MSG(wParam,lParam)!=LBN_DBLCLK) break;
case IDOK:
i=SendMessage(GetDlgItem(hDlg,IDC_FILE_BOX),LB_GETCURSEL, 0,0L);
EndDialog(hDlg, i);
return (TRUE);
case IDCANCEL:
EndDialog(hDlg, -1);
return (TRUE);
default:
;
}
break;
}
return (FALSE);
}
/******************************************************************************
GetFormFiles:
This routine scans the current directory for the files matching the
specified template.
******************************************************************************/
GetFormFiles(char *template)
{
unsigned done;
FILE *iStream;
struct StrFormHdr hdr;
#if defined (WIN32)
HANDLE hFindFile;
WIN32_FIND_DATA blk;
done=FALSE;
if (INVALID_HANDLE_VALUE==(hFindFile=FindFirstFile(template,&blk))) done=TRUE;
#else
#if defined(__TURBOC__)
struct ffblk blk;
done=findfirst(template,&blk,FA_RDONLY);
#else
struct find_t blk;
done=_dos_findfirst(template,_A_NORMAL,&blk);
#endif
#endif
while(!done) {
if (TotalForms==MAX_FORMS) {
return FALSE;
}
#if defined (WIN32)
strcpy(FormFile[TotalForms],blk.cFileName);
done=!FindNextFile(hFindFile,&blk);
#else
#if defined(__TURBOC__)
strcpy(FormFile[TotalForms],blk.ff_name);
done=findnext(&blk); // get the next file
#else
strcpy(FormFile[TotalForms],blk.name);
done=_dos_findnext(&blk);
#endif
#endif
//*************** get the form name ****************************
if (NULL==(iStream=fopen(FormFile[TotalForms],"r+b"))) continue;
if (fread(&hdr,sizeof(struct StrFormHdr),1,iStream)!=1
|| hdr.FormSign!=FORM_SIGN ) {
fclose(iStream);
continue;
}
fclose(iStream);
strcpy(FormName[TotalForms],hdr.name);
TotalForms++;
}
return TRUE;
}
/******************************************************************************
ReadFields:
Read the field definitions for a file. The argument specifies the index
into the DataFile structure.
The field definitions are stored in files with the extension .DF, whereas
the data is stored in the files with the extension .DB.
******************************************************************************/
ReadFields(int idx)
{
char name[64],line[300],CharReturn[300],*result;
FILE *iStream;
int CurLen,CurField=0,LineIdx;
int ExtractField(char *,int *,int,char *);
strcpy(name,DataFile[idx].name);
strcat(name,".DF"); // file extension
iStream=fopen(name,"r+t");
if (iStream==NULL) {
wsprintf(line,"Error while opening file %s ",(LPSTR)name);
MessageBox(hDemoWin,line,NULL,MB_OK);
return FALSE;
}
READ_LINE:
result=fgets(line,300,iStream);
if (ferror(iStream)) {
wsprintf(line,"Error while reading file %s ",(LPSTR)name);
MessageBox(hDemoWin,line,NULL,MB_OK);
return FALSE;
}
if (feof(iStream)) goto END_FILE; // end of file
if (result==NULL) {
wsprintf(line,"Error while reading file %s ",(LPSTR)name);
MessageBox(hDemoWin,line,NULL,MB_OK);
return FALSE;
}
CurLen=strlen(line); // exclude new line character
if (CurLen>0 && line[CurLen-1]==0xA) CurLen--;
line[CurLen]=0;
LineIdx=0; // prepare to scan the line
// extract the field name
if (!ExtractField(line,&LineIdx,CurLen,CharReturn)) { // extract field name
wsprintf(line,"Invalid format, file: %s, field# %d\n",(LPSTR)name,1);
MessageBox(hDemoWin,line,NULL,MB_OK);
return FALSE;
}
StringTrim(CharReturn); // trim space
strcpy(DataField[idx][CurField].ShortName,CharReturn);
strcpy(DataField[idx][CurField].FullName,DataFile[idx].name);
strcat(DataField[idx][CurField].FullName,"->");
strcat(DataField[idx][CurField].FullName,CharReturn);
// extract the field width
if (!ExtractField(line,&LineIdx,CurLen,CharReturn)) { // extract field name
wsprintf(line,"Invalid format, file: %s, field# %d\n",(LPSTR)name,1);
MessageBox(hDemoWin,line,NULL,MB_OK);
return FALSE;
}
DataField[idx][CurField].width=atoi(CharReturn);
// extract the field type
if (!ExtractField(line,&LineIdx,CurLen,CharReturn)) { // extract field name
wsprintf(line,"Invalid format, file: %s, field# %d\n",(LPSTR)name,1);
MessageBox(hDemoWin,line,NULL,MB_OK);
return FALSE;
}
if (CharReturn[0]=='T') DataField[idx][CurField].type=TYPE_TEXT;
else if (CharReturn[0]=='N') DataField[idx][CurField].type=TYPE_NUM;
else if (CharReturn[0]=='F') DataField[idx][CurField].type=TYPE_DBL;
else if (CharReturn[0]=='D') DataField[idx][CurField].type=TYPE_DATE;
else if (CharReturn[0]=='L') DataField[idx][CurField].type=TYPE_LOGICAL;
else if (CharReturn[0]=='P') DataField[idx][CurField].type=TYPE_PICT;
else {
wsprintf(line,"Invalid field type, file: %s, field# %d\n",(LPSTR)name,1);
MessageBox(hDemoWin,line,NULL,MB_OK);
return FALSE;
}
// extract the default decimal places
if (!ExtractField(line,&LineIdx,CurLen,CharReturn)) { // extract field name
wsprintf(line,"Invalid format, file: %s, field# %d\n",(LPSTR)name,1);
MessageBox(hDemoWin,line,NULL,MB_OK);
return FALSE;
}
DataField[idx][CurField].DecPlaces=atoi(CharReturn);
CurField++;
goto READ_LINE;
END_FILE:
fclose(iStream);
DataFile[idx].TotalFields=CurField;
return TRUE;
}
/******************************************************************************
ExtractField:
This routine scans a text line to extract the next field.
The fields are assumed to be of character type.
******************************************************************************/
ExtractField(char *line,int *idx,int LineLen,char *CharReturn)
{
char quote='"',comma=',',string[300],*ptr,SaveChar;
int i,j;
i=(*idx);
while (i<LineLen && line[i]==' ') i++; // go past the spaces
if (i>=LineLen) return FALSE; // past the end of the line
if (line[i]==quote) {
i++; // skip over the first quote
if (NULL==(ptr=memchr(&line[i],quote,LineLen-i))) return FALSE;
j=1;
while (ptr[j]!=',' && ptr[j]!=0) j++;// locate the next comma
SaveChar=ptr[0]; // extract the string
ptr[0]=0;
strcpy(string,&line[i]);
ptr[0]=SaveChar;
(*idx)=i+strlen(string)+1+j; // index to the next field
}
else {
if (NULL==(ptr=memchr(&line[i],comma,LineLen-i))) ptr=&line[LineLen]; // field spans the end of the line
SaveChar=ptr[0]; // extract the string
ptr[0]=0;
strcpy(string,&line[i]);
ptr[0]=SaveChar;
(*idx)=i+strlen(string)+1; // index to the next field
}
strcpy(CharReturn,string);
return TRUE;
}
/******************************************************************************
Call back routines.
The following routines are called by Report Ease to select an application
field or to verify an application field.
******************************************************************************/
/******************************************************************************
UserFieldSelection:
This routine is called by the FORM_FLD module to allow user to select
a data field. This routine can be programmed by your application in
any way as long as it returns the data about the selected field using
the argument pointer. If the user chose not to select a field after all,
the function should return with a FALSE value. Otherwise it should return
with a TRUE value.
In this routine, we will allow the user to first select a file, and
then select a field from the chosen file. The required data about the
selected field is filled into the 'field' structure. Your program may
also optionally fill other remaining 'field' structure variables.
The first parameter contains the handle of the Form Editor window.
The third parameter specifies the sort field number if this field will
be used for section breaks. If your application will not sort on all
fields, you can restrict the fields that can be selected by the user.
For non-sort fields, this paramter is set to 0. In this demo program,
we will allow only the fields from the primary file (CUSTOMER) to be
used as sort fields.
******************************************************************************/
int FAR PASCAL _export UserFieldSelection(HWND hWnd,struct StrField huge *field,int SortFieldNo)
{
int CurFile,CurField;
FARPROC lpProc;
SELECT_FILE:
if (SortFieldNo==0) {
lpProc = MakeProcInstance(DemoFileField, hInst);
CurFile=DialogBoxParam(hInst,"DemoFileField",hWnd,lpProc,(long)-1);
FreeProcInstance(lpProc); // set back the old window
if (CurFile<0) return FALSE;
}
else CurFile=0; // Allow sort fields only from the customer file
// SELECT FIELD
if (SortFieldNo==0) GetSortField=FALSE; // global flag
else GetSortField=TRUE;
lpProc = MakeProcInstance(DemoFileField, hInst);
CurField=DialogBoxParam(hInst,"DemoFileField",hWnd,lpProc,(long)CurFile);
FreeProcInstance(lpProc); // set back the old window
if (CurField<0) {
if (GetSortField) return FALSE;
else goto SELECT_FILE;
}
// fill the required 'field' variables
lstrcpy(field->name,DataField[CurFile][CurField].FullName); // field name
field->type=DataField[CurFile][CurField].type; // alpha/num etc
field->width=DataField[CurFile][CurField].width; // display width
field->DecPlaces=DataField[CurFile][CurField].DecPlaces; // decimal places for display
// specify new paragraph indicator field. Used only for a word/wrapped
// text type fields.
field->ParaChar[0]='|';
/****** fill up these OPTIONAL fields also. This information will be
used by our report executer demo program to identfy the
fields quickly. *****/
field->FileId=CurFile; // Information only
field->FieldId=CurField; // information only
return TRUE;
}
/******************************************************************************
VerifyField:
This routine is called by the FORM1 module to validate a field. The field
name is given by the 'name' variable in the StrField structure. It
contains the full name including the file prefix (if your application allows
it). The input field is always in the upper case. The required data about the
current field is filled into the 'field' structure. Your program may
also optionally fill other remaining 'field' structure variables.
The second argument indicates if the field can be
used as a sort field. This parameter indicates the sort field number.
1 indicates the first sort field, 2 the second, ... A zero for this
field indicates a non-sort field. In this demo program, we will allow
only the fields from the primary file (CUSTOMER) to be used as sort fields.
The function returns TRUE if the field is valid, otherwise it returns
a FALSE value.
******************************************************************************/
int FAR PASCAL _export VerifyField(struct StrField huge *field,int SortFieldNo)
{
int CurFile,CurField,MaxFiles;
if (SortFieldNo==0) MaxFiles=MAX_FILES;
else MaxFiles=1; // allow sort fields from the customer file only
for (CurFile=0;CurFile<MaxFiles;CurFile++) {
for (CurField=0;CurField<DataFile[CurFile].TotalFields;CurField++) {
if (lstrcmp(DataField[CurFile][CurField].FullName,field->name)==0) {
//* fill up the mandatory data *
field->type=DataField[CurFile][CurField].type; // alpha/num etc
field->width=DataField[CurFile][CurField].width; // display width
field->DecPlaces=DataField[CurFile][CurField].DecPlaces; // decimal places for display
/****** fill up these OPTIONAL fields also. This information will be
used by our report executer demo program to identfy the
fields quickly. *****/
field->FileId=CurFile; // Information only
field->FieldId=CurField; // information only
return TRUE;
}
}
}
return FALSE; // not a valid field
}
/******************************************************************************
DrawPicture:
This routine is called by the report executor to draw a specified
picture type field. The first argument specifies the device context
of the reporting device. If the report output is directed to a printer,
this device context belongs to a printer, otherwise it specifies a
device context for a metafile. You application should draw the picture
on this device context within the specified rectangle (last argument).
The device context is in ANISOTROPIC mode. The resolution in the X and
Y direction is given by the UNITS_PER_INCH constant.
The second argument is the picture id. The third and fourth arguments
are the file and field id for the picture field.
The function returns TRUE if successful.
In this demo program, this routine draws a logo for a given picture id.
This program uses only one bitmap, and draws different part of the same
bitmap for different picture id.
******************************************************************************/
int FAR PASCAL _export DrawPicture(HDC hDC, int PictId, int FileId, int FieldId, RECT far * rect)
{
BITMAP bm;
int SourceWidth,SourceX;
// get the bitmap information
GetObject(hLogoBM,sizeof(BITMAP),&bm);
// Select part of the bitmap to display for this picture id
SourceWidth=bm.bmWidth/10; // divide picture into 10 equal parts
if (PictId<1) PictId=1;
if (PictId>10) PictId=10;
SourceX=SourceWidth*(PictId-1);
// copy the bitmap
StretchDIBits(hDC,rect->left,rect->top,rect->right-rect->left,rect->bottom-rect->top,
SourceX,0,SourceWidth,bm.bmHeight,pImage,(LPBITMAPINFO)pInfo,DIB_RGB_COLORS,SRCCOPY);
return TRUE;
}
/******************************************************************************
Report Executer Interface Routines.
******************************************************************************/
/******************************************************************************
RunReport: The following routines demonstrate the process of calling the
report executor.
******************************************************************************/
RunReport()
{
int PrintRecords(struct StrField huge *,int);
if (GetFormSelection(RepParm.file,FALSE)>=0) { // select a form file
//********* Initialize the argument parameters *************
RepParm.device='A'; // ask user
RepParm.x=FormParm.x; // specify the window coordinates for screen output
RepParm.y=FormParm.y; // these fields needed only for screen output
RepParm.width=FormParm.width;
RepParm.height=FormParm.height;
if (RepInit(&RepParm)!=0) return FALSE;// Intialize the report
PrepareFile(); // sort and join files if needed
PrintRecords(RepParm.field,RepParm.TotalFields); // read and print each record
RepExit(); // print footers and exit
}
return TRUE;
}
/******************************************************************************
PrepareFile: Sort and join the CUSTOMER and SALES files if needed.
******************************************************************************/
PrepareFile()
{
int i,SalesFileUsed,SortKey[10];
char InputFile1[80],InputFile2[80],OutputFile[80];
lstrcpy(InputFile1,DataFile[0].name);
lstrcat(InputFile1,".DB "); // apped the data file extension
for (i=0;i<RepParm.TotalSortFields;i++) {// extract each sort field
SortKey[i]=RepParm.SortField[i].FieldId+1;
}
FileSort(InputFile1,RepParm.TotalSortFields,SortKey);
// the output is in the CUSTOMER.SRT file
// determine if the sales file is used
SalesFileUsed=FALSE;
for (i=0;i<RepParm.TotalFields;i++) {
if ((RepParm.field[i].FileId)==1) { /* id =0 is customer file, and
id=1 is the sales file,
see the UserFieldSeletion routine */
SalesFileUsed=TRUE;
break;
}
}
if (SalesFileUsed) { // join SALES file with CUSTOMER FILE
lstrcpy(InputFile1,DataFile[0].name);
lstrcat(InputFile1,".SRT "); // first file
lstrcpy(InputFile2,DataFile[1].name);
lstrcat(InputFile2,".DB "); // second file
lstrcpy(OutputFile,DataFile[0].name);
lstrcat(OutputFile,".SRT "); // output file
FileJoin(InputFile1,1,InputFile2,1,OutputFile);
/* customer and sales file have field number 1 in common. The output
is stored in the "CUSTOMER.SRT file.
*/
}
return TRUE;
}
/******************************************************************************
PrintRecords:
This routine follows these step:
1. Open the data set file.
2. For each record of data set:
a. Initialize the fields in the field structure. IMPORTANT: Initialize
only the fields where source = SRC_APPL. All other fields are
for internal use of ReportEase.
b. Parse each field from the data record and stuff into the
field structure. One field may be stuffed in more than one
place in field structure. Stuff only those structure fields where
source = SRC_APPL
c. Call the RepRec routine to print this record.
This routine returns a TRUE value after all records are printed. If
the user hit escape during printing, then the return result will be a FALSE
value.
******************************************************************************/
PrintRecords(struct StrField huge *field,int TotalFields)
{
FILE *iStream;
int i,CurLen,FileNo,FieldNo,RecNo=1,LineIdx;
char DataSetName[64],line[300],string[300],*result;
//*** open the data set file ***
strcpy(DataSetName,DataFile[0].name);
strcat(DataSetName,".SRT");
if (NULL==(iStream=fopen(DataSetName,"rt"))) {
MessageBox(hDemoWin,"Can Not Open The Data Set File!",NULL,MB_OK);
return FALSE;
}
READ_LINE:
result=fgets(line,300,iStream);
if (ferror(iStream)) {
MessageBox(hDemoWin,"Error in reading file",NULL,MB_OK);return FALSE;
}
if (feof(iStream)) goto END_FILE; // end of file
if (result==NULL) {
MessageBox(hDemoWin,"Error in reading file",NULL,MB_OK);return FALSE;
}
CurLen=strlen(line); // exclude new line character
if (CurLen>0 && line[CurLen-1]==0xA) CurLen--;
line[CurLen]=0;
//********** initialize the field structure *************
for (i=0;i<TotalFields;i++) {
if (field[i].source==SRC_APPL) {
if (field[i].type==TYPE_TEXT) field[i].CharData[0]=0;
if (field[i].type==TYPE_NUM) field[i].NumData=0;
if (field[i].type==TYPE_PICT) field[i].NumData=0;
if (field[i].type==TYPE_DBL) field[i].DblData=0;
}
}
//************ parse the record to get each field ********
FileNo=0;
FieldNo=0;
LineIdx=0; // prepare to scan the line
while (TRUE) {
// extract the fields
if (!ExtractField(line,&LineIdx,CurLen,string)) break;
if (FileNo>=MAX_FILES) {
wsprintf(line,"Too many fields in the data record number: %d\n",RecNo);
MessageBox(hDemoWin,line,NULL,MB_OK);
goto END_FILE;
}
// stuff this field into the field structure
for (i=0;i<TotalFields;i++) {
if (field[i].source==SRC_APPL
&& field[i].FileId==FileNo && field[i].FieldId==FieldNo) {
if (field[i].type==TYPE_TEXT) {
if ((int)strlen(string)>field[i].width) string[field[i].width]=0; // truncate oversize data
lstrcpy(field[i].CharData,string);
}
else if (field[i].type==TYPE_NUM) field[i].NumData=atol(string);
else if (field[i].type==TYPE_DBL) field[i].DblData=(double)atof(string);
else if (field[i].type==TYPE_DATE) field[i].NumData=atol(string); // date shoule be YYMMDD or YYYYMMDD
else if (field[i].type==TYPE_PICT) field[i].NumData=atol(string); // date shoule be YYMMDD or YYYYMMDD
else if (field[i].type==TYPE_LOGICAL) {
if (string[0]=='Y' || string[0]=='y') field[i].NumData=1;
else field[i].NumData=0;
}
}
}
// advance to the next field number
FieldNo++;
if (FieldNo>=DataFile[FileNo].TotalFields) {
FieldNo=0;
FileNo++;
}
}
if (RepRec()!=0) goto END_FILE; // print this record
RecNo++;
goto READ_LINE;
END_FILE:
fclose(iStream);
return TRUE;
}
/******************************************************************************
Support Routines.
******************************************************************************/
/*****************************************************************************
StringTrim:
Remove spaces from the left and right of a NULL terminated string.
******************************************************************************/
void StringTrim(LPSTR string)
{
RightTrim(string);LeftTrim(string);
}
/******************************************************************************
RightTrim:
Remove spaces on the right of a string.
******************************************************************************/
void RightTrim(LPSTR string)
{
int i,TempLen;
TempLen=lstrlen(string);
for (i=TempLen-1;i>=0 && string[i] == ' ';i--);
string[i+1] = '\0';
}
/******************************************************************************
LeftTrim:
Trim initial spaces from the string.
*******************************************************************************/
void LeftTrim(LPSTR string)
{
int i,TempLen,BeginPoint;char TempStr[300];
TempLen=lstrlen(string);
for (i=0;i < TempLen && string[i] == ' ';i++);
BeginPoint=i;
for (i=BeginPoint;i<TempLen;i++) TempStr[i-BeginPoint]=string[i];
TempStr[TempLen-BeginPoint] = '\0';
lstrcpy(string,TempStr);
}
/******************************************************************************
GetNumVal:
Extract a numeric value from the dialog item. Display error if a non-
numeric value is encountered and return a false result.
*******************************************************************************/
BOOL GetNumVal(HWND hWin,int ControlId,int *pInt)
{
BOOL ErrorFlag;
*pInt=GetDlgItemInt(hWin,ControlId,&ErrorFlag,(BOOL) 0);
if (!ErrorFlag) {
MessageBox(hWin,"Must Enter a Valid Number",NULL,MB_OK);
SetFocus(GetDlgItem(hWin,ControlId));
return (FALSE);
}
return TRUE;
}
/******************************************************************************
Bitmap2DIB:
Extract device indepedent bits from the bitmap.
*******************************************************************************/
Bitmap2DIB()
{
DWORD InfoSize,ImageSize;
BITMAP bm;
HDC hDC;
GetObject(hLogoBM,sizeof(BITMAP),(LPSTR)&bm); // get the dimension of bit map
//********** create the device independent bitmap ***********************
InfoSize=sizeof(BITMAPINFOHEADER)+256*sizeof(RGBQUAD); // create a 256 color bitmap structure
if (NULL==(hInfo=GlobalAlloc(GMEM_MOVEABLE,InfoSize))
||NULL==(pInfo=(LPBITMAPINFOHEADER)GlobalLock(hInfo)) ) {
MessageBox(hDemoWin,"Ran out of memory for Bitmap Info!",NULL,MB_OK);
return -1;
}
//***** fill in the info structure ******
pInfo->biSize=sizeof(BITMAPINFOHEADER);
pInfo->biWidth=bm.bmWidth;
pInfo->biHeight=bm.bmHeight;
pInfo->biPlanes=1; // DIB have plane = 1
pInfo->biBitCount=8; // 8 bits per pixel or color
pInfo->biCompression=BI_RGB; // no compression - needed for compatibility for all devices
pInfo->biSizeImage=0; // initialize to zero
pInfo->biXPelsPerMeter=0;
pInfo->biYPelsPerMeter=0;
pInfo->biClrUsed=0; // depends on biBitCount
pInfo->biClrImportant=0; // all colors important
hDC=GetDC(hDemoWin);
if (!GetDIBits(hDC,hLogoBM,0,bm.bmHeight,NULL,(LPBITMAPINFO)pInfo,DIB_RGB_COLORS)) {
MessageBox(hDemoWin,"Error Creating Device Independent Bitmap Structure!",NULL,MB_OK);
return -1;
}
ImageSize=pInfo->biSizeImage;
if (NULL==(hImage=GlobalAlloc(GMEM_MOVEABLE,ImageSize))
||NULL==(pImage=GlobalLock(hImage)) ) {
MessageBox(hDemoWin,"Ran out of memory for Bitmap Image!",NULL,MB_OK);
return -1;
}
if (!GetDIBits(hDC,hLogoBM,0,bm.bmHeight,pImage,(LPBITMAPINFO)pInfo,DIB_RGB_COLORS)) {
MessageBox(hDemoWin,"Error Creating Device Independent Bitmap Image!",NULL,MB_OK);
return -1;
}
// release the common device context
ReleaseDC(hDemoWin,hDC);
return TRUE;
}
/******************************************************************************
OurPrintf:
This routine formats and display a given set of arguments. The format
is given by the first argument. The argument 2 to n contain the
arguments for the specified format. The function uses MessageBox to
display the formatted string.
******************************************************************************/
OurPrintf(LPSTR fmt,...)
{
LPSTR ArgStart;
char string[256];
ArgStart=(LPSTR) &fmt; // pointer to first argument
ArgStart=&ArgStart[4]; // go past the first argument
wvsprintf(string,fmt,ArgStart);
if (FindWindow("DBWin",NULL)) { // debug window open
lstrcat(string,"\n");
OutputDebugString(string); // send to the debug terminal
}
else MessageBox(NULL,string,NULL,MB_OK);
return TRUE;
}