Science makes it known,
Engineering makes it work,
Art makes it beautiful.
|
|
Using Fujitsu COBOL 3.0 to call the USPS Address Matching System API
This page discusses developing a simple Win32 COBOL main program calling a
C++ function(s) stored
in a .DLL. The COBOL code I developed;
the C++, .DLL, and .LIB files were
obtained from a third party. In
other words, this page discusses how to develop Win32 COBOL code calling
functions in
a 'Black Box'. For developing a more
functional Win32 GUI
COBOL program calling C++ functions, see web page
Combing Fujitsu COBOL 3.0, PowerCOBOL 3.0, and the USPS Address Matching System API.
Fujitsu COBOL
and the USPS Address
Matching System Application Programming Interface are used as the specific
example. In general, this page should be helpful to anyone
developing a
Fujitsu COBOL program that calls a C++ function.
While pursuing my Master's degree at Stevens Institute of Technology,
I was part of a team effort investigating
the possibility of becoming a
Coding Accuracy Support System (CASS)
vendor certified by the United States Postal Service
(USPS). The
USPS provides a myriad of products and services to bulk mailers
(see
Address Quality Solutions page
for additional information about these products/services; or download
'quick and dirty' spreadsheet listing products and descriptions
from this site). Trying to
determine the CASS requirements, how to meet them, and which USPS
product/service to use was challenging.
After some searching,
the USPS Address Matching System Application Programming Interface
(AMS API) looked
promising1. The AMS API is
a Developer's Kit
based on CASS guidelines used in developing address matching
software (the Address Matching System Application Programming Interface
User Guide is available from the
ribbs site). The AMS API
functions can be used to check the integrity of an address, determine ZIP+4,
and mailing list validation. The advantage is a reduction in bulk
mailing costs. The AMS API functions (written in C++) are
in the dynamic link library ZIP4_W32.DLL.
Since the proof-of-concept software was being prototyped in Fujitsu
COBOL2
on a Win32 PC calling the USPS supplied AMS API
32-bit C++ functions,
it added to the challenge. Or perhaps I have been spoiled by
writing COBOL main programs calling FORTRAN subroutines on
midrange and mainframe machines, where the calling/linking procedures are
an order of magnitude simpler than on a Win32 PC. If its
the latter, then I may be stating the obvious with this particular web page.
At any rate, permit me on giving a simple tutorial on using Fujitsu COBOL 3.0 to call
C++ functions in a .DLL. After all, it may prove useful to that
one programmer who finds it necessary to develop in COBOL rather than C++.
Sample COBOL Code
Below is a listing of a test Fujitsu COBOL main program
(AMSTEST.COB) to
call a few of the various AMS API
functions.
000010 IDENTIFICATION DIVISION.
000020 PROGRAM-ID. AMSTEST.
000030 ENVIRONMENT DIVISION.
000040
000050 DATA DIVISION.
000060 WORKING-STORAGE SECTION.
000070
000080 77 DISP-STATUS PIC -9(4).
000090 77 DMY PIC X(004).
000100
000110 01 AMS-VERSION PIC X(32).
000120
000130 INCLUDE "COMDATA.COB".
000140 INCLUDE "AMSZ4PRM.COB".
000150
000160 PROCEDURE DIVISION.
000170 MOVE LOW-VALUES TO AMS-API-ZIP4-PARM.
000180 DISPLAY "Calling z4openSTD".
000190 CALL "z4openSTD" WITH STDCALL LINKAGE.
000200 MOVE PROGRAM-STATUS TO RTRN-INT.
000210 MOVE SHORT-FUNC-VALUE TO Z4-AMS-API-INSTLD-STATUS.
000220 IF Z4-AMS-API-OPEN THEN
000230 DISPLAY "Calling z4verSTD"
000240 CALL "z4verSTD" WITH STDCALL LINKAGE
000250 USING BY REFERENCE AMS-VERSION
000260 DISPLAY AMS-VERSION
000270 MOVE "GREAT NORTHERN COMMERICIAL SERVICES" TO AMS-API-ZP4-IADL2
000280 MOVE "401 GREENWHICH ST" TO AMS-API-ZP4-IADL1
000290 MOVE "BELVIDERE NJ 07823" TO AMS-API-ZP4-ICTYI
000300 MOVE SPACES TO AMS-API-ZP4-IPRURB
000310 DISPLAY "Calling z4adrinqSTD"
000320 CALL "z4adrinqSTD" WITH STDCALL LINKAGE
000330 USING BY REFERENCE AMS-API-ZIP4-PARM
000340 MOVE PROGRAM-STATUS TO RTRN-INT
000350 MOVE SHORT-FUNC-VALUE TO DISP-STATUS
000360 DISPLAY "z4adrinqSTD status" DISP-STATUS
000370 DISPLAY " Return Code :" AMS-API-Z4P-RETCC
000380 DISPLAY " FIRM NAME :" AMS-API-ZP4-DADL2
000390 DISPLAY " Delivery Address Xtra:" AMS-API-ZP4-DADL3
000400 DISPLAY " Delivery Address :" AMS-API-ZP4-DADL1
000410 DISPLAY " Last Line :" AMS-API-ZP4-DCTYA " "
000420 AMS-API-ZP4-DSTAA " " AMS-API-ZP4-ZIPC " " AMS-API-ZP4-ADDON
000430 DISPLAY " eLOT Number :" AMS-API-ZP4-ELOT-NUM
000440 AMS-API-ZP4-ELOT-CODE
000450 DISPLAY " Carrier Route :" AMS-API-ZP4-CRIS
000460 DISPLAY "Calling z4closeSTD"
000470 CALL "z4closeSTD" WITH STDCALL LINKAGE
000480 DISPLAY "Successfully Called z4closeSTD"
000490 ELSE
000500 MOVE SHORT-FUNC-VALUE TO DISP-STATUS
000510 DISPLAY "ERROR OPENING AMS API" DISP-STATUS
000520 END-IF.
000530 ACCEPT DMY.
000540 EXIT PROGRAM.
000550 END PROGRAM AMSTEST.
In this example, AMSTEST is the calling procedure. z4openSTD,
z4verSTD, z4adrinqSTD, and z4closeSTD are the called
procedures in the AMS API.
The AMS API dynamic link library
ZIP4_W32.DLL contains two versions
of each export function - one version has
the '_cdecl' calling
convention, the other has the '_stdcall' calling
convention. The
'_stdcall' calling
convention is used with calling procedures written
in non C and C++
languages. AMSTEST uses the '_stdcall'
functions3. As can be seen above,
the '_stdcall' function
names are suffixed with 'STD'.
PROGRAM-STATUS
PROGRAM-STATUS is a Fujitsu COBOL 3.0 defined field with a
Picture clause of
PIC S9(9) COMP-5 that contains the results of
the last system call. When calling a
C++ function, the function result is stored in
PROGRAM-STATUS. Variables
RTRN-INT and
Z4-AMS-API-INSTLD-STATUS
are then used to check the value of
PROGRAM-STATUS (lines 000200 through
000210). RTRN-INT and
Z4-AMS-API-INSTLD-STATUS
are defined in the include file
COMDATA.COB,
as shown in lines 001100 through 001190 below (inapplicable definitions have
been removed for brevity).
000010**************************************************************
000020* CDS Windows
000030* (C) COPYRIGHT Rodney Roberts 2004
000040* Mailing List Common Data
.
.
.
001100 01 C-PARMS IS GLOBAL IS EXTERNAL.
001110 05 RTRN-INT PIC S9(9) COMP-5.
001120 05 RTRN-INT-2 REDEFINES RTRN-INT.
001130 10 SHORT-FUNC-VALUE PIC S9(4) COMP-5.
001140 10 FILLER PIC 9(4) COMP-5.
001150 05 Z4-AMS-API-INSTLD-STATUS PIC S9(4) COMP-5.
001160 88 Z4-AMS-API-NOT-INSTLD VALUE -10.
001170 88 Z4-AMS-API-OPEN VALUE 0.
001180 88 Z4-AMS-API-UNSYNCHED VALUE 1.
001190 88 Z4-AMS-API-EXPIRED VALUE 2.
001200
.
.
.
001510**************************************************************
Since PROGRAM-STATUS is a long integer and most of the
AMS API C++ functions return a short integer, it is necessary
to manipulate
the returned value as shown in lines 000200 through 000210 of
AMSTEST before checking
the call results. The manipulation is just simply
moving
PROGRAM-STATUS to a
item (RTRN-INT) that is redefined as a
group item with two 2-byte fields
(the first is signed, the second is unsigned and
ignored). The
first 2-byte is then checked for the status of the call.
AMSTEST.COB sequence lines 000320 through 000330 approximate the
following C++ snippet:
SHORT_FUNC_VALUE = z4adrinq (&AMS-API-ZIP4-PARM);
The "WITH STDCALL LINKAGE" clause in sequence line 000320
of AMSTEST.COB simply tells
the compiler to use STDCALL linkage rules for calling
the subprogram. The
"USING BY REFERENCE" clause in
sequence line 000330 serves
the same purpose as the "&" in the above
C++ snippet.
AMS ZIP4 Parameters
AMS-API-ZIP4-PARM
is a group item defined in the include
file AMSZ4PRM.COB,
containing elements AMS-API-ZP4-IADL1,
AMS-API-ZP4-IADL2,
AMS-API-ZP4-ICTYI,
AMS-API-ZP4-IPRURB,
AMS-API-Z4P-RETCC,
AMS-API-ZP4-DADL1,
AMS-API-ZP4-DADL2,
AMS-API-ZP4-DADL3,
AMS-API-ZP4-DCTYA, and so
on. Basically, it is a
COBOL translation of the ZIP4_PARM struct defined within the
header file
ZIP4.H of the AMS API (both the ZIP4_PARM struct and
ZIP4.H are
documented in the
Address Matching System Application Programming Interface User Guide,
available from the
ribbs site).
Below is the COBOL equivalent of the AMS API ZIP4_PARM C++ struct:
000010* ***** ***** ***** ***** *****
000020* Parameter list for z4adrinq() and z4xrfinq() calls. Reserved
000030* fields are for future use, do not access these fields. Size of this
000040* record cannot be changed.
000050* NOTE: Only fields containing +1 in the length are null terminated.
000060
000070 01 AMS-API-ZIP4-PARM.
000080 05 AMS-API-Z4P-INPUT-DATA.
000090 10 AMS-API-Z4P-RSVD0 PIC X(004).
000100 10 AMS-API-ZP4-IADL1-GRP.
000110 15 AMS-API-ZP4-IADL1 PIC X(050).
000120 15 FILLER PIC X(001).
000130 10 AMS-API-ZP4-IADL2-GRP.
000140 15 AMS-API-ZP4-IADL2 PIC X(050).
000150 15 FILLER PIC X(001).
000160 10 AMS-API-ZP4-ICTYI-GRP.
000170 15 AMS-API-ZP4-ICTYI PIC X(050).
000180 15 FILLER PIC X(001).
000190 10 AMS-API-ZP4-ISTAI-GRP.
000200 15 AMS-API-ZP4-ISTAI PIC X(002).
000210 15 FILLER PIC X(001).
000220 10 AMS-API-ZP4-IZIPC-GRP.
000230 15 AMS-API-ZP4-IZIPC PIC X(010).
000240 15 FILLER PIC X(001).
000250 10 AMS-API-ZP4-IPRURB-GRP.
000260 15 AMS-API-ZP4-IPRURB PIC X(028).
000270 15 FILLER PIC X(001).
000280 10 AMS-API-ZP4-IADL3-GRP.
000290 15 AMS-API-ZP4-IADL3 PIC X(050).
000300 15 FILLER PIC X(001).
000310 10 AMS-API-Z4P-RSVD1 PIC X(098).
000320 05 AMS-API-Z4P-RETURN-DATA.
000330 10 AMS-API-ZP4-DADL3-GRP.
000340 15 AMS-API-ZP4-DADL3 PIC X(050).
000350 15 FILLER PIC X(001).
000360 10 AMS-API-ZP4-DADL1-GRP.
000370 15 AMS-API-ZP4-DADL1 PIC X(050).
000380 15 FILLER PIC X(001).
000390* standardized firm name
000400 10 AMS-API-ZP4-DADL2-GRP.
000410 15 AMS-API-ZP4-DADL2 PIC X(050).
000420 15 FILLER PIC X(001).
000430 10 AMS-API-ZP4-DLAST-GRP.
000440 15 AMS-API-ZP4-DLAST PIC X(050).
000450 15 FILLER PIC X(001).
000460 10 AMS-API-ZP4-DPRURB-GRP.
000470 15 AMS-API-ZP4-DPRURB PIC X(028).
000480 15 FILLER PIC X(001).
000490 10 AMS-API-ZP4-DCTYS-GRP.
000500 15 AMS-API-ZP4-DCTYS PIC X(028).
000510 15 FILLER PIC X(001).
000520 10 AMS-API-ZP4-DSTAS-GRP.
000530 15 AMS-API-ZP4-DSTAS PIC X(002).
000540 15 FILLER PIC X(001).
000550 10 AMS-API-ZP4-DCTYA-GRP.
000560 15 AMS-API-ZP4-DCTYA PIC X(028).
000570 15 FILLER PIC X(001).
000580 10 AMS-API-ZP4-ABCTY-GRP.
000590 15 AMS-API-ZP4-ABCTY PIC X(013).
000600 15 FILLER PIC X(001).
000610 10 AMS-API-ZP4-DSTAA-GRP.
000620 15 AMS-API-ZP4-DSTAA PIC X(002).
000630 15 FILLER PIC X(001).
000640 10 AMS-API-ZP4-ZIPC-GRP.
000650 15 AMS-API-ZP4-ZIPC PIC X(005).
000660 15 FILLER PIC X(001).
000670* ZIP+4 addon code
000680 10 AMS-API-ZP4-ADDON-GRP.
000690 15 AMS-API-ZP4-ADDON PIC X(004).
000700 15 FILLER PIC X(001).
000710 10 AMS-API-ZP4-DPBC-GRP.
000720 15 AMS-API-ZP4-DPBC PIC X(003).
000730 15 FILLER PIC X(001).
000740* carrier route
000750 10 AMS-API-ZP4-CRIS-GRP.
000760 15 AMS-API-ZP4-CRIS PIC X(004).
000770 15 FILLER PIC X(001).
000780 10 AMS-API-ZP4-COUNTY-GRP.
000790 15 AMS-API-ZP4-COUNTY PIC X(003).
000800 15 FILLER PIC X(001).
000810 10 AMS-API-Z4P-RESPN PIC S9(4) COMP-5.
000820 10 AMS-API-Z4P-RETCC PIC X(001).
000830 10 AMS-API-Z4P-ADRKEY PIC X(012).
000840 10 AMS-API-Z4P-AUTO-ZONE-IND PIC X(001).
000850 10 AMS-API-ZP4-ELOT-NUM-GRP.
000860 15 AMS-API-ZP4-ELOT-NUM PIC X(004).
000870 15 FILLER PIC X(001).
000880 10 AMS-API-ZP4-ELOT-CODE PIC X(001).
000890 05 AMS-API-Z4P-PARSED-INPUT-DATA.
000900 10 AMS-API-ZP4-PPNUM-GRP.
000910 15 AMS-API-ZP4-PPNUM PIC X(010).
000920 15 FILLER PIC X(001).
000930 10 AMS-API-ZP4-PSNUM-GRP.
000940 15 AMS-API-ZP4-PSNUM PIC X(008).
000950 15 FILLER PIC X(001).
000960 10 AMS-API-ZP4-PROTE-GRP.
000970 15 AMS-API-ZP4-PROTE PIC X(003).
000980 15 FILLER PIC X(001).
000990 10 AMS-API-ZP4-PUNIT-GRP.
001000 15 AMS-API-ZP4-PUNIT PIC X(004).
001010 15 FILLER PIC X(001).
001020 10 AMS-API-ZP4-PPRE1-GRP.
001030 15 AMS-API-ZP4-PPRE1 PIC X(002).
001040 15 FILLER PIC X(001).
001050 10 AMS-API-ZP4-PPRE2-GRP.
001060 15 AMS-API-ZP4-PPRE2 PIC X(002).
001070 15 FILLER PIC X(001).
001080 10 AMS-API-ZP4-PSUF1-GRP.
001090 15 AMS-API-ZP4-PSUF1 PIC X(004).
001100 15 FILLER PIC X(001).
001110 10 AMS-API-ZP4-PSUF2-GRP.
001120 15 AMS-API-ZP4-PSUF2 PIC X(004).
001130 15 FILLER PIC X(001).
001140 10 AMS-API-ZP4-PPST1-GRP.
001150 15 AMS-API-ZP4-PPST1 PIC X(002).
001160 15 FILLER PIC X(001).
001170 10 AMS-API-ZP4-PPST2-GRP.
001180 15 AMS-API-ZP4-PPST2 PIC X(002).
001190 15 FILLER PIC X(001).
001200 10 AMS-API-ZP4-PPNAM-GRP.
001210 15 AMS-API-ZP4-PPNAM PIC X(028).
001220 15 FILLER PIC X(001).
001230* Matched primary number.
001240 05 AMS-API-ZP4-MPNUM-GRP.
001250 10 AMS-API-ZP4-MPNUM PIC X(010).
001260 10 FILLER PIC X(001).
001270 05 AMS-API-ZP4-MSNUM-GRP.
001280 10 AMS-API-ZP4-MSNUM PIC X(008).
001290 10 FILLER PIC X(001).
001300 05 AMS-API-ZP4-PMB-GRP.
001310 10 AMS-API-ZP4-PMB PIC X(003).
001320 10 FILLER PIC X(001).
001330 05 AMS-API-ZP4-PMBNUM-GRP.
001340 10 AMS-API-ZP4-PMBNUM PIC X(008).
001350 10 FILLER PIC X(001).
001360 05 AMS-API-Z4P-RSVD2 PIC X(086).
001370 05 AMS-API-Z4P-FOOTNOTES.
001380* zip corrected
001390 10 AMS-API-ZP4-A PIC X(001).
001400* city/state corrected
001410 10 AMS-API-ZP4-B PIC X(001).
001420* invalid city/state/zip
001430 10 AMS-API-ZP4-C PIC X(001).
001440* no zip assigned
001450 10 AMS-API-ZP4-D PIC X(001).
001460* ZIP assigned for mult response
001470 10 AMS-API-ZP4-E PIC X(001).
001480 10 AMS-API-ZP4-F PIC X(001).
001490 10 AMS-API-ZP4-G PIC X(001).
001500 10 AMS-API-ZP4-H PIC X(001).
001510 10 AMS-API-ZP4-I PIC X(001).
001520 10 AMS-API-ZP4-J PIC X(001).
001530 10 AMS-API-ZP4-K PIC X(001).
001540 10 AMS-API-ZP4-L PIC X(001).
001550 10 AMS-API-ZP4-M PIC X(001).
001560 10 AMS-API-ZP4-N PIC X(001).
001570 10 AMS-API-ZP4-O PIC X(001).
001580 10 AMS-API-ZP4-P PIC X(001).
001590 10 AMS-API-ZP4-Q PIC X(001).
001600 10 AMS-API-ZP4-R PIC X(001).
001610 10 AMS-API-ZP4-S PIC X(001).
001620* multiple caused by magnet rule
001630 10 AMS-API-ZP4-T PIC X(001).
001640 10 AMS-API-ZP4-U PIC X(001).
001650 10 AMS-API-ZP4-V PIC X(001).
001660 10 AMS-API-ZP4-W PIC X(001).
001670 10 AMS-API-ZP4-X PIC X(001).
001680 10 AMS-API-ZP4-Y PIC X(001).
001690 10 AMS-API-ZP4-Z PIC X(001).
001700 10 AMS-API-Z4P-RSVD3 PIC X(006).
001710 05 AMS-API-Z4P-ADDR-REC-STACK.
001720 10 AMS-API-Z4P-STACK OCCURS 10 TIMES
001730 PIC X(203).
001740 05 AMS-API-Z4P-RSVD4 PIC X(194).
001750
The "15 FILLER PIC X(001)" lines (000120, 000150, etc.)
are needed for C++'s char array null terminator (achieving
the same functionality as described in the comment line,
NOTE: Only fields containing +1 in the length are null terminated.).
Compiler Options
C++ is case sensitive, and Fujitsu COBOL changes lower case into
upper case by default. When compiling a Fujitsu COBOL routine calling
a C++ function,
a compiler option (NOALPHAL) to over ride the
upper case default must be specified, as shown in the
two screenshots below:
The screenshot below shows all of the needed compiler options
for the main program AMSTEST.COB:
The MAIN compiler option simply specifies AMSTEST is a main
program; DLOAD
compiler option enables dynamic subprogram calling.
Linker Options
When linking, in addition to specifying the COBOL object file(s),
the .DLL's import library (same name as the .DLL
file but with a .LIB extension) should also be
linked in. For the AMS API,
the library is ZIP4_W32.LIB. See
the below screenshot for an example:
And lastly, the .DLL's entry points must be defined
within the Run-Time Environment Initialization
File COBOL85.CBR. For the AMSTEST
example, ZIP4_W32.DLL's
entry points are defined
in COBOL85.CBR's entry information section,
as shown below (the lines
after [AMSTEST.ENTRY]; only the entry points
actually being used are listed); these take the form of
subprogram-name=dll-name:
[AMSTEST]
@IconName=COB85EXE
@ScrnSize=(80,24)
@CnslWinSize=(80,24)
@CnslBufLine=100
@WinCloseMsg=ON
@EnvSetWindow=USE
@AllFileExclusive=NO
@CBR_PrintTextPosition=TYPE1
@CBR_TextAlign=BOTTOM
[AMSTEST.ENTRY]
z4openSTD=ZIP4_W32.DLL
z4verSTD=ZIP4_W32.DLL
z4closeSTD=ZIP4_W32.DLL
z4adrinqSTD=ZIP4_W32.DLL
ATTENTION:
When doing a Google Search for "COBOL AMS API" you may find several
references for Google Docs with the same
terms and even graphics used in my Fujitsu COBOL web
pages. THE Google Docs ARE NOT MINE. They
may have links for
downloadable executable files which may or may not contain malware,
adware, or other
undesirable features. Example addresses are:
https://docs.google.com/document/d/1eeXg8lPjGBtAdP7IfE5MdebjnEE8X0W3wAyEMWw1eLo/edit?pref=2&pli=1
https://docs.google.com/document/d/1pE3ESiOnkQoowG_XvLoZgxRSXDKnPQw2Drk4EBBe2gY/edit?pref=2&pli=1
https://docs.google.com/document/d/1mjzJ_6pWqFmacRxzD5Fg7Wy7zCjxTVleghVYGsJUaGY/edit?pref=2&pli=1
Exercise Caution
|