home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Monster Media 1993 #2
/
Image.iso
/
business
/
clockin2.zip
/
OEMDATA.C_
/
OEMDATA.bin
Wrap
Text File
|
1993-09-03
|
28KB
|
739 lines
/*
Final Specification for the OEM Direct Link Interface
(c) 1993 Mission Critical Software
Fast direct links are possible between your cooperating Windows program
and Clock-IN! By signing a limited agreement you can arrange a free license
to use and distribute this program when you sell Clock-IN! with it as
a bundle. By using global shared memory, your Terminal Server program
will enjoy the fasted possible bi-directional communication with
Clock-IN!'s time engine.
All you have to do to implement your terminal server is convert your
existing terminal a) communications, and b) terminal key definition
downloading code. Then paste it into this program and test directly
with Clock-IN!
Two global shared memory handles are allocated by Clock-IN! as follows under
Windows:
HGLOBAL hGlobalInputData,hGlobalResponseBuffer;
The OEM program should not allocate the memory, but it does need to declare
the handles above.
Your Windows program must have a Window which handles I/O to Clock-IN!
During WM_CREATE (or WM_INITDIALOG) for that window you will get the
handle to ClockIN!'s "ClockInput" window, and send your Window handle.
You post a message with your Window Handle and Clock-IN! responds by
sending you the handles to the global shared memory objects.
As transactions become available through this OEM program, you fill the
global buffer as indicated by IDD_SENDDATA. Be sure the data is per
the specification in the manual on page 130. EXCEPT that enclosing
the data fields in quotations marks" is PURELY optional. Clock-IN!
strips these marks anyway and uses strtok(",") to break the buffer into
data fields. There must be exactly the 14 commas separating the 15
data fields, however.
When Clock-IN! receives data, it processes the data and clears the first byte
of the global memory buffer. Your program is sent an IDD_ACK, which is
qualified with a response string buffer that you can send back to your
terminal user, if desired. When the OEM program receives the ACK, reset your flag
WAITINGFORCLOCKIN to false.
This working program follows per the above specifications, and does it
all for you. So you can cut and paste your code into this Windows
program.
TIP-Your program downloads function key definitions and prompts to the
terminals, almost exactly like the pre-defined function keys, prompts
and validation file defintions in Clock-IN's two files, funckeys.db
and valfiles.db. RUN OFF THE TWO REPORTS NAMED FUNCKEYS and VALFILES
so you know how to define the prompts for CLOCK_IN!, and what files to
download for validation.
Or use Comm, Function Keys Browse, to browse the table of the definitions.
OPTIONAL FEATURES-Full adjustments, debits/credits, absence entries, etc.
all from your terminals.
This program supports the following structure, which
you can design into your initial implementation if you wish. You can
pass this structure to Clock-IN! to do Adjustments. See the
A)ctions, A)dustments pulldown menu item. All the screens therein allow
the user to do numerous time adjustments. For you to provide these
functions at your terminal, simply design the transactions, and fill in this
simple structure. Tran_types are DCR for debit/credit, ADJ for force
pay hours today to a number, NTE for note, ABS for absence.
You'll get a handle to load the structure to global memory, and then
send a message to Clock-IN! to process it.
*/
#define SIZEOFTIME 24
#define SIZEOFTRANSACCESS 52
#define SIZEOFPW 9
#define SIZEOFDATENTIME 9
#define SIZEOFBADGE 14
#define SIZEID 13
#define SIZEOFCHARGE 17
#define InputArraySize 17
#define SIZEOFTRANSTYPE 4
#define SIZEOFUSERNOTE 80
typedef struct
{
char id[SIZEOFBADGE];
char supervisor[SIZEOFBADGE];
char pw[SIZEOFBADGE];
char note[100];
char postdate[SIZEOFDATENTIME];
char absence[10];
float abshours;
char debit[SIZEOFCHARGE];
float debithours;
char credit[SIZEOFCHARGE];
float credithours;
char forcechg[SIZEOFCHARGE];
float forcehours;
char tran_type[4];
char posttime[SIZEOFDATENTIME];
} adjustment;
adjustment tranadj;
#define STRICT
#include <windows.h>
#ifdef __cplusplus
#error This should compile as a C program
#endif
#ifdef __BORLANDC__
#pragma argsused /* This pragma is used for Borland C++ */
#endif
#include <ctype.h>
#include <dos.h>
#include <errno.h>
#include <time.h>
#include <stdio.h>
#include <string.h>
#define IDS_ERR_REGISTER_CLASS 1
#define IDS_ERR_CREATE_WINDOW 2
LONG FAR PASCAL WndProc(HWND, WORD, WORD, LONG);
int nCwRegisterClasses(void);
void CwUnRegisterClasses(void);
BOOL putGlobalAdjustment(void);
HWND hActive;
char szAppName[14];
HINSTANCE hInst=0;
HWND hWndMain=0;
char szString[256];
HWND gethandlewindow(void);
BOOL CALLBACK AboutDlgProc( HWND hDlg, UINT iMessage, WPARAM wParam, LPARAM lParam );
BOOL getGlobal(void);
#define IDD_SENDDATA 2100
#define IDD_SENDADJ 2101
#define IDD_EXIT 2102
BOOL getOEMdata(char *yourdata,int bufsize);
BOOL putOEMdata(char *yourdata);
BOOL WAITINGFORCLOCKIN=FALSE;
HWND hClockin,hOEMWindow;
HGLOBAL hGlobalInputData,hGlobalResponseBuffer,hGlobalAdjustData;
#define IDD_MEM 9000
#define IDD_DATAREADY 9002
#define IDD_OEMWINDOW 9003
#define IDD_ACK 9004
#define IDD_ABOUT 999
#define IDD_RECONNECT 9001
#define IDD_CLOCKINQUIT 9008
#define IDD_RESPONSEBUFFER 9009
#define IDD_ADJUSTBUFFER 9010
#define IDD_ACKADJ 9011
#define IDD_ADJDATAREADY 9012
#define ACCEPT_MOVE 0 // figurehours totals, stamp up the time
#define ACCEPT_NOMOVE 1
#define REJECT_NOMOVE 2 // no figurehours, carryfwd last stamp
#define BADID 3
#define BADSUPERVISORPW 4
#define QUEUED 5
#define BADFORMAT 6
#define OLDERTRAN 7
#define ACCESSFAIL 1
#define IDFAIL 2
#define DATEFAIL 3
#define ADJUSTOK 0
FILE *fp;
char termdata[256];
char szDisplayString[100];
char respondbuf[64];
int PASCAL WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpszCmdLine, int nCmdShow)
{
/***********************************************************************/
/* HANDLE hInstance; handle for this instance */
/* HANDLE hPrevInstance; handle for possible previous instances */
/* LPSTR lpszCmdLine; long pointer to exec command line */
/* int nCmdShow; Show code for main window display */
/***********************************************************************/
MSG msg; /* MSG structure to store your messages */
int nRc; /* return value from Register Classes */
long nWndunits; /* window units for size and location */
int nWndx; /* the x axis multiplier */
int nWndy; /* the y axis multiplier */
int nX; /* the resulting starting point (x, y) */
int nY,i;
int nWidth; /* the resulting width and height for this */
int nHeight; /* window */
BOOL Msgprocessed;
hActive=GetActiveWindow();
strcpy(szAppName,"OEMDATA\0");
hInst = hInstance;
if(!hPrevInstance)
{
/* register window classes if first instance of application */
if ((nRc = nCwRegisterClasses()) == -1)
{
/* registering one of the windows failed */
LoadString(hInst, IDS_ERR_REGISTER_CLASS, szString, sizeof(szString));
MessageBox(NULL, szString, NULL, MB_ICONEXCLAMATION);
return nRc;
}
} else
{
return 1;
} ;
nWndunits = GetDialogBaseUnits();
nWndx = LOWORD(nWndunits);
nWndy = HIWORD(nWndunits);
nX = 0; // ((1 * nWndx) / 4);
nY = 0; // ((1 * nWndy) / 8);
nWidth = ((236 * nWndx) / 4);
nHeight = ((83 * nWndy) / 8);
hWndMain = CreateWindow(
// WS_EX_TOPMOST , // extended box to force topmost window
//szButtonClassName,
szAppName, /* Window class name */
"OEM Data Interface", /* Window's title */
WS_CAPTION | /* Title and Min/Max */
WS_SYSMENU | /* Add system menu box */
WS_MINIMIZEBOX | /* Add minimize box */
WS_MAXIMIZEBOX | /* Add maximize box */
WS_THICKFRAME | /* thick sizeable frame */
WS_CLIPCHILDREN | /* don't draw in child windows areas */
WS_OVERLAPPED,
nX, nY, /* X, Y */
nWidth, nHeight, /* Width, Height of window */
NULL, /* Parent window's handle */
NULL, /* Default to Class Menu */
hInst, /* Instance of window */
NULL); /* Create struct for WM_CREATE */
if(hWndMain == NULL)
{
LoadString(hInst, IDS_ERR_CREATE_WINDOW, szString, sizeof(szString));
MessageBox(NULL, szString, NULL, MB_ICONEXCLAMATION);
return IDS_ERR_CREATE_WINDOW;
}
ShowWindow(hWndMain, nCmdShow); /* display main window */
//putenv("TZ=GMT0 "); // otherwise it compensates to EST, and makes it 5 hours off
while ( GetMessage( &msg, NULL, 0, 0 ) ) // if any messages, place it in msg
{
Msgprocessed=FALSE;
if (! Msgprocessed ) //message dropped without being processed
// produces WM_CHAR msgs only for ASCII characters
{
TranslateMessage( &msg );
// dispatch the message to main window
DispatchMessage( &msg );
}
}
/* Do clean up before exiting from the application */
CwUnRegisterClasses();
return msg.wParam;
} /* End of WinMain */
/************************************************************************/
/* */
/* Main Window Procedure */
/************************************************************************/
LONG FAR PASCAL WndProc(HWND hWnd, WORD Message, WORD wParam, LONG lParam)
{
char *s;
HDC hDC;
PAINTSTRUCT ps;
char *p;
int dataok;
unsigned long timemark;
unsigned long ticktimer;
switch (Message)
{
case WM_COMMAND:
switch (wParam)
{
case IDD_SENDDATA:
//one of your terminals triggered this message and you
//have data ready
respondbuf[0]='\0';
if (hClockin==NULL || WAITINGFORCLOCKIN )
{
//CLOCKIN could have quit or terminated input
//while the User is doing massive adjustments
//in this latter case, you should only retry every
//several seconds, not continuously
//CLOCKIN will restore the input window when the
//user is done
strcpy(szDisplayString,"Lost connection,retrying");
InvalidateRect(hWnd,NULL,TRUE);
//retry to establish link
hClockin=gethandlewindow(); //get clockins window
InvalidateRect(hWnd,NULL,TRUE);
if (hClockin!=NULL)
PostMessage(hClockin,WM_COMMAND, IDD_OEMWINDOW, (long) hWnd);
break;
}
if (!WAITINGFORCLOCKIN)
{
//sample program reads from a file, instead of from your terminals
termdata[0]=';';
while (termdata[0]==';')
{
s=fgets(termdata,256,fp);
if (s==NULL)
{
strcpy(szDisplayString,"Input file exhausted");
break;
}
}
if (strlen(termdata)<2) break;
//must have null terminated string,overwriting here the carriage return \x0A
p=strchr(termdata,10);
*p='\0';
//sample 1st line is
//"0","05/17/93","06:53:12","ATO","B100","","","","","","","","","",""
//tries until global memory freed
timemark=GetTickCount()+5000;
dataok=FALSE;
while ( !dataok && timemark>GetTickCount() )
dataok=putOEMdata(termdata);
if (dataok)
{
WAITINGFORCLOCKIN=TRUE;
strcpy(szDisplayString,"Sent data record");
}
else
{
strcpy(szDisplayString,"Unable to send data record");
PostMessage(hWnd,WM_COMMAND,IDD_RECONNECT,0L);
}
InvalidateRect(hWnd,NULL,TRUE);
}
break;
case IDD_SENDADJ:
//one of your terminals triggered this message and you
//have data ready
respondbuf[0]='\0';
if (hClockin==NULL || WAITINGFORCLOCKIN )
{
strcpy(szDisplayString,"Lost connection,retrying");
InvalidateRect(hWnd,NULL,TRUE);
//retry to establish link
hClockin=gethandlewindow(); //get clockins window
InvalidateRect(hWnd,NULL,TRUE);
if (hClockin!=NULL)
PostMessage(hClockin,WM_COMMAND, IDD_OEMWINDOW, (long) hWnd);
break;
}
if (!WAITINGFORCLOCKIN)
{
//sample program creates an adjustment
strcpy(tranadj.id,"B100");
strcpy(tranadj.supervisor,"SUPERVIS");
strcpy(tranadj.pw,"MASTER");
strcpy(tranadj.note,"Test adjustment");
strcpy(tranadj.postdate,"08/31/93");
strcpy(tranadj.tran_type,"ABS");
strcpy(tranadj.absence,"AE");
tranadj.abshours=2.0;
timemark=GetTickCount()+5000;
dataok=FALSE;
while ( !dataok && timemark>GetTickCount() )
dataok=putGlobalAdjustment();
if (dataok)
{
WAITINGFORCLOCKIN=TRUE;
strcpy(szDisplayString,"Sent adjust record");
}
else
{
strcpy(szDisplayString,"Unable to send adjust record");
PostMessage(hWnd,WM_COMMAND,IDD_RECONNECT,0L);
}
InvalidateRect(hWnd,NULL,TRUE);
}
break;
case IDD_RECONNECT:
//retry to establish link
hGlobalInputData=NULL;
hClockin=NULL;
hGlobalAdjustData;
hClockin=gethandlewindow(); //get clockins window
InvalidateRect(hWnd,NULL,TRUE);
if (hClockin!=NULL)
PostMessage(hClockin,WM_COMMAND, IDD_OEMWINDOW, (long) hWnd);
break;
case IDD_MEM:
hGlobalInputData=(HGLOBAL) lParam;
strcpy(szDisplayString,"Connected to Clock-IN!");
InvalidateRect(hWnd,NULL,TRUE);
break;
case IDD_RESPONSEBUFFER:
hGlobalResponseBuffer=(HGLOBAL) lParam;
break;
case IDD_ADJUSTBUFFER:
hGlobalAdjustData=(HGLOBAL) lParam;
break;
case IDD_CLOCKINQUIT:
hGlobalInputData=NULL;
hClockin=NULL;
hGlobalAdjustData=NULL;
strcpy(szDisplayString,"Clock-IN! quit");
//set timer for reconnect attempt
ticktimer=GetTickCount()+10000;
WAITINGFORCLOCKIN=FALSE;
break;
case IDD_ACKADJ:
getGlobal();
strcpy(szDisplayString,"Ack for adjustment received");
if (!respondbuf[0])
strcpy(respondbuf,"Ack w/Nothing in reponse buffer");
else
respondbuf[0]='\0';
//do whatever you want with the return values
WAITINGFORCLOCKIN=FALSE;
switch ( (int) lParam)
{
case ADJUSTOK:
strcat(szDisplayString,"/Adjust OK");
break;
case ACCESSFAIL:
strcat(szDisplayString,"/Permission Denied");
break;
case IDFAIL:
strcat(szDisplayString,"/Bad employee badge");
break;
case DATEFAIL:
strcat(szDisplayString,"/Bad date or format");
break;
case QUEUED:
//had to queue transaction for later processing
strcat(szDisplayString,"/Queued");
break;
default:
break;
}
InvalidateRect(hWnd,NULL,TRUE);
break;
case IDD_ACK:
//look in the global buffer to get any text explanation
//that can be sent back to the terminal user
getGlobal();
if (!respondbuf[0])
strcpy(respondbuf,"Ack w/Nothing in reponse buffer");
strcpy(szDisplayString,"Ack");
InvalidateRect(hWnd,NULL,TRUE);
WAITINGFORCLOCKIN=FALSE;
//look in the lParam for the error code
switch ( (int) lParam )
{
case ACCEPT_MOVE:
//processed the transaction,moved the employee clock
//message is in respondbuf
strcat(szDisplayString,"/Accept/moved");
break;
case ACCEPT_NOMOVE:
//processed the transaction,did not move the employee clock
//message is in respondbuf
strcat(szDisplayString,"/Accept/nomove");
break;
case REJECT_NOMOVE:
//rejected the transaction,did not move the employee clock
//rejection reason is in respondbuf
strcat(szDisplayString,"/Reject/nomove");
break;
case BADID:
//bad badge ID failure
strcat(szDisplayString,"/BadID");
break;
case BADSUPERVISORPW:
//override transaction failed with bad username/password
strcat(szDisplayString,"/BadOverride");
break;
case QUEUED:
//had to queue transaction for later processing
strcat(szDisplayString,"/Queued");
break;
case BADFORMAT:
strcat(szDisplayString,"/Bad format");
break;
case OLDERTRAN:
//the employee clock is past that date & time
//you cant send an older transaction, you must
//use an adjustment
strcat(szDisplayString,"/Older tran");
break;
default:
break;
}
break;
case IDD_ABOUT:
Modalbox( (LPSTR) "ABOUT", (FARPROC) AboutDlgProc, TRUE);
break;
case IDD_EXIT:
PostMessage(hWnd,WM_CLOSE,0,0L);
break;
}
break;
case WM_CREATE:
//handshaking
respondbuf[0]='\0';
fp=fopen("importta.txt","r");
hClockin=gethandlewindow(); //get clockins window
InvalidateRect(hWnd,NULL,TRUE);
if (hClockin==NULL)
{
//couyld optionally quit here
//PostMessage(hWnd,WM_CLOSE,0,0L); //cant get a connection, quit
}
else
//notify Clock-IN! of your Window Handle!
//it will send back the global data handle
PostMessage(hClockin,WM_COMMAND, IDD_OEMWINDOW, (long) hWnd);
MoveWindow(hWnd,200,200,420,80,TRUE);
return 0;
case WM_PAINT:
hDC = BeginPaint(hWnd, &ps);
SetBkMode(hDC, OPAQUE);
SetTextColor(hDC,GetSysColor(COLOR_WINDOWTEXT));
SetBkColor(hDC,GetSysColor(COLOR_BTNFACE));
if(szDisplayString[0])
TextOut(hDC,0,0,szDisplayString,lstrlen(szDisplayString));
if (respondbuf[0]);
TextOut(hDC,0,18,respondbuf,lstrlen(respondbuf));
EndPaint(hWnd, &ps);
break;
case WM_CLOSE: /* close the window */
fclose(fp);
if (hWnd == hWndMain)
PostQuitMessage(0); /* Quit the application */
break;
default:
return DefWindowProc(hWnd, Message, wParam, lParam);
}
return 0L;
}
//**********************************************************************************
BOOL putOEMdata(char *yourdata)
{
LPSTR lpv;
if (WAITINGFORCLOCKIN) return FALSE;
lpv=GlobalLock(hGlobalInputData);
if (lpv==NULL) return FALSE; //failed to put the data
//before you copy the data to the buffer, make sure the buffer
//is empty, other Clock-IN! input processes, including DDE use
//the buffer, and the Clock-IN! processor may not have grabbed
//the input there yet
if (lpv[0]!=NULL)
{
GlobalUnlock(hGlobalInputData);
return FALSE;
}
yourdata[lstrlen(yourdata)+1]='\0'; //insure terminating null
_fmemcpy(lpv,(LPSTR) yourdata,lstrlen(yourdata)+1 );
GlobalUnlock(hGlobalInputData);
//lParam must be 1, so Clock-IN! can recognize your processs
PostMessage(hClockin,WM_COMMAND,IDD_DATAREADY,1L);
return TRUE;
}
//**********************************************************************************
BOOL getGlobal(void)
{
LPSTR lpv;
lpv=GlobalLock(hGlobalResponseBuffer);
if (lpv==NULL)
return FALSE; //failed to get the data
_fmemcpy((LPSTR) respondbuf,lpv,64 );
//clear the buffer, in case you get it back again
lpv[0]='\0';
GlobalUnlock(hGlobalResponseBuffer);
return TRUE;
}
//**********************************************************************************
BOOL getOEMdata(char *yourdata,int bufsize)
{
LPSTR lpv;
lpv=GlobalLock(hGlobalInputData);
if (lpv==NULL) return FALSE; //failed to get the data
_fmemcpy((LPSTR) yourdata,lpv,bufsize );
yourdata[bufsize]='\0';
//clear the buffer for use by other processes
lpv[0]='\0';
GlobalUnlock(hGlobalInputData);
PostMessage(hOEMWindow,WM_COMMAND,IDD_ACK,0L);
return TRUE;
}
//**********************************************************************************
BOOL putGlobalAdjustment(void)
{ LPSTR lpv;
lpv=GlobalLock(hGlobalAdjustData);
if (lpv==NULL) return FALSE; //failed to put the data
if (lpv[0]!=NULL)
{
GlobalUnlock(hGlobalInputData);
return FALSE;
}
_fmemcpy(lpv,(LPSTR) &tranadj,sizeof(adjustment) );
GlobalUnlock(hGlobalAdjustData);
PostMessage(hClockin,WM_COMMAND,IDD_ADJDATAREADY,1L);
return TRUE;
}
//****************************************************************************************
HWND gethandlewindow(void)
{
HWND hwndNext;
char workbuf[256];
hwndNext=GetWindow(GetActiveWindow(),GW_HWNDFIRST); //hwndMain your main wdo
while (hwndNext)
{
GetWindowText(hwndNext,(LPSTR)workbuf,256);
if (strcmp(workbuf,"ClockInput")==0) return hwndNext;
hwndNext=GetWindow(hwndNext,GW_HWNDNEXT);
}
strcpy(szDisplayString,"Clock-IN! is not running, cannot establish link");
return NULL;
}
//***************************************************************************************
void CwUnRegisterClasses(void)
{
WNDCLASS wndclass;
memset(&wndclass, 0x00, sizeof(WNDCLASS));
UnregisterClass(szAppName, hInst);
}
//*****************************************************************************************
int nCwRegisterClasses(void)
{
WNDCLASS wndclass;//,buttonwindowclass; /* struct to define a window class */
memset(&wndclass, 0x00, sizeof(WNDCLASS));
/* load WNDCLASS with window's characteristics */
wndclass.style = CS_HREDRAW | CS_VREDRAW | CS_BYTEALIGNWINDOW;
wndclass.lpfnWndProc = WndProc;
/* Extra storage for Class and Window objects */
wndclass.cbClsExtra = 0;
wndclass.cbWndExtra = 0;
wndclass.hInstance = hInst;
wndclass.hIcon = LoadIcon(hInst, "OEMDATA\0");
wndclass.hCursor = LoadCursor(NULL, IDC_ARROW);
/* Create brush for erasing background */
wndclass.hbrBackground = (HBRUSH)( GetStockObject(LTGRAY_BRUSH) );
wndclass.lpszMenuName = szAppName;
wndclass.lpszClassName = szAppName; /* Class Name is App Name */
if(!RegisterClass(&wndclass))
return -1;
return(0);
}
BOOL CALLBACK AboutDlgProc( HWND hDlg, UINT iMessage, WPARAM wParam, LPARAM lParam )
{
switch ( iMessage )
{
case WM_INITDIALOG:
return TRUE;
case WM_COMMAND:
if ( wParam == IDOK )
{
EndDialog( hDlg, TRUE );
return TRUE;
}
break;
case WM_CLOSE:
EndDialog( hDlg, 0 );
break;
}
return FALSE;
}
BOOL Modalbox( LPSTR TemplateName, FARPROC FunctionName, BOOL modal)
{
DLGPROC lpfn;
int retval;
HWND hWnd;
if ( (lpfn=(DLGPROC) MakeProcInstance( (FARPROC) FunctionName, hInst))==NULL)
{
return FALSE;
}
if (modal) hWnd=hWndMain; else hWnd=GetActiveWindow();
//must use getactivewindow to make modal frames work
if ( (retval=DialogBox( hInst, (LPSTR) TemplateName, hWnd, lpfn )) ==-1)
{
retval=FALSE;
}
else retval=TRUE;
FreeProcInstance( (FARPROC)lpfn );
return retval;
}