.NET Forum / .NET Framework / Interop / June 2005
Struct to API Problems
|
|
Thread rating:  |
Joel Cade - 10 Jun 2005 20:25 GMT I'm trying to wrap calls the USPS Address Matching System API.
Am I missing something in my call to the API?
My calls to the API are declared as follows:
<DllImport("zip4_w32.dll", BestFitMapping:=True, CallingConvention:=CallingConvention.StdCall, CharSet:=CharSet.Auto, _ EntryPoint:="z4openSTD", ExactSpelling:=True, PreserveSig:=True, SetLastError:=True, ThrowOnUnmappableChar:=True)> _ Shared Function Open() As Int32 End Function
<DllImport("zip4_w32.dll", BestFitMapping:=True, CallingConvention:=CallingConvention.StdCall, CharSet:=CharSet.Auto, _ EntryPoint:="z4closeSTD", ExactSpelling:=True, PreserveSig:=True, SetLastError:=True, ThrowOnUnmappableChar:=True)> _ Shared Function Close() As Int32 End Function
<DllImport("zip4_w32.dll", BestFitMapping:=True, CallingConvention:=CallingConvention.StdCall, CharSet:=CharSet.Auto, _ EntryPoint:="z4adrinqSTD", ExactSpelling:=True, PreserveSig:=True, SetLastError:=True, ThrowOnUnmappableChar:=True)> _ Shared Function Inquire(<MarshalAs(UnmanagedType.Struct)> ByRef Zip4Struct As structZIP4_PARM) As Int32 End Function
The zip4.h file defines the structure being passed to the Inquire method as:
/***************************************************************************/ /* Parameter list for z4adrinq() and z4xrfinq() calls. Reserved */ /* fields are for future use, do not access these fields. Size of this */ /* record cannot be changed. */ /* NOTE: Only fields containing +1 in the length are null terminated. */ /***************************************************************************/ typedef struct { /*********** input data ***********/
char rsvd0[4]; /* reserved space */ char iadl1[50+1]; /* input delivery address */ char iadl2[50+1]; /* input firm name */ char ictyi[50+1]; /* input city */ char istai[2+1]; /* input state */ char izipc[10+1]; /* input ZIP+4 code */ char iprurb[28+1]; /* input urbanization name */ char iadl3[50+1]; /* input second address line */ char rsvd1[98]; /*reserved for future use */ /********** returned data *********/ char dadl3[50+1]; /* standardized 2nd delivery addr */ char dadl1[50+1]; /* standardized delivery address */ char dadl2[50+1]; /* standardized firm name */ char dlast[50+1]; /* standardized city/state/zip */ char dprurb[28+1]; /* output PR urbanization name */ char dctys[28+1]; /* main post office city */ char dstas[2+1]; /* main post office state */ char dctya[28+1]; /* standardized city */ char abcty[13+1]; /* standardized city abbreviation */ char dstaa[2+1]; /* standardized state */ char zipc[5+1]; /* 5-digit zip code */ char addon[4+1]; /* ZIP+4 addon code */ char dpbc[3+1]; /* delivery point bar code */ char cris[4+1]; /* carrier route */ char county[3+1]; /* FIPS county code */ short respn; /* number of returned responses */ char retcc; /* return code */ char adrkey[12]; /* address key (for indexing) */ char auto_zone_ind; /* A, B, C or D */ char elot_num[4+1]; /* eLOT Number */ char elot_code; /* eLOT Ascending/Descending Flag */ /******* parsed input data ********/ char ppnum[10+1]; /* Primary Number */ char psnum[8+1]; /* Secondary Number */ char prote[3+1]; /* Rural Route Number */ char punit[4+1]; /* Secondary Number Unit */ char ppre1[2+1]; /* First or Left Pre-direction */ char ppre2[2+1]; /* Second or Right Pre-direction */ char psuf1[4+1]; /* First or Left Suffix */ char psuf2[4+1]; /* Second or Right Suffix */ char ppst1[2+1]; /* First or Left Post-direction */ char ppst2[2+1]; /* Second or Right Post-direction */ char ppnam[28+1]; /* Primary Name */
char mpnum[10+1]; /* Matched primary number. */ char msnum[8+1]; /* Matched secondary number. */ char pmb[3+1]; /* PMB Unit Designator */ char pmbnum[8+1]; /* PMB Number */ char mlevl; /* Reserved Use */ char rsvd2[85]; /* reserved for future use */
struct { /************ footnotes ***********/ char a; /* zip corrected */ char b; /* city/state corrected */ char c; /* invalid city/state/zip */ char d; /* no zip assigned */ char e; /* ZIP assigned for mult response */ char f; /* no zip available */ char g; /* part of firm moved to address */ char h; /* secondary number missing */ char i; /* insufficient/incorrect data */ char j; /* dual input -- used PO BOX */ char k; /* dual input -- used non-PO BOX */ char l; /* del addr component add/del/chg */ char m; /* street name spelling changed */ char n; /* delivery addr was standardized */ char o; /* reserved for future use */ char p; /* better delivery addr exists */ char q; /* reserved for future use */ char r; /* no match due to EWS */ char s; /* invalid secondary number */ char t; /* multiple caused by magnet rule */ char u; /* unofficial po name */ char v; /* unverifiable city/state */ char w; /* small town default */ char x; /* unique ZIP code default */ char y; /* reserved for future use */ char z; /* ZIP move match */ char rsvd3[6]; /* reserved for future use */ } foot;
ADDR_REC stack[10]; /********** record stack **********/ char rsvd4[194]; /* reserved for future use */ } ZIP4_PARM;
and my struct is defined as:
Structure structZIP4_PARM 'Input Data Dim rsvd0 As Char() ' Reserved for Future Use <VBFixedString(50)> Dim iadl1 As String ' Input Delivery Address <VBFixedString(50)> Dim iadl2 As String ' Input Firm Name <VBFixedString(50)> Dim ictyi As String ' Input City <VBFixedString(2)> Dim istai As String ' Input State <VBFixedString(10)> Dim izipc As String ' Input ZIP+4 Code <VBFixedString(28)> Dim iprurb As String ' Input Urbanization Name <VBFixedString(50)> Dim iadl3 As String ' Input Second Address Line Dim rsvd1 As Char() ' Reserved for Future User
'Output Data <VBFixedString(50)> Dim dadl3 As String ' Standardized 2nd Delivery Address <VBFixedString(50)> Dim dadl1 As String ' Standardized Delivery Address <VBFixedString(50)> Dim dadl2 As String ' Standardized Firm Name <VBFixedString(50)> Dim dlast As String ' Standardized City/State/Zip <VBFixedString(28)> Dim dprurb As String ' Output PR Urbanization Name <VBFixedString(28)> Dim dctys As String ' Main Post Office City <VBFixedString(2)> Dim dstas As String ' Main Post Office State <VBFixedString(28)> Dim dctya As String ' Standardized City <VBFixedString(13)> Dim abcty As String ' Standardized City Abbreviation <VBFixedString(2)> Dim dstaa As String ' Standardized State <VBFixedString(5)> Dim zipc As String ' 5-digit zip Code <VBFixedString(4)> Dim addon As String ' ZIP+4 addon Code <VBFixedString(3)> Dim dpbc As String ' Delivery Point Bar Code <VBFixedString(4)> Dim cris As String ' Carrier Route <VBFixedString(3)> Dim county As String ' FIPS County Code Dim respn As Int16 ' Number of Returned Responses Dim retcc As Char ' Return Code Dim adrkey As Char() ' Address Key (for Indexing) Dim auto_zone_ind As Char ' A, B, C, or D <VBFixedString(4)> Dim elot_num As String ' eLOT Number Dim elot_code As Char ' eLOT Ascending/Descending Flag
' Parsed Input Data <VBFixedString(10)> Dim ppnum As String ' Primary Number <VBFixedString(8)> Dim psnum As String ' Secondary Number <VBFixedString(3)> Dim prote As String ' Rural Route Number <VBFixedString(4)> Dim punit As String ' Secondary Number Unit <VBFixedString(2)> Dim ppre1 As String ' First or Left Pre-direction <VBFixedString(2)> Dim ppre2 As String ' Second or Right Pre-direction <VBFixedString(4)> Dim psuf1 As String ' First or Left Suffix <VBFixedString(4)> Dim psuf2 As String ' Second or Right Suffix <VBFixedString(2)> Dim ppst1 As String ' First or Left Post-direction <VBFixedString(2)> Dim ppst2 As String ' Second or Right Post-direction <VBFixedString(28)> Dim ppnam As String ' Primary Name <VBFixedString(10)> Dim mpnum As String ' Matched Primary Number <VBFixedString(8)> Dim msnum As String ' Matched Secondary Number <VBFixedString(3)> Dim pmb As String ' PMB Unit Designator <VBFixedString(8)> Dim pmbnum As String ' PMB Number Dim rsvd2 As Char() ' Reserved for Future User Dim foot As structFoot Dim ADDR_REC() As structADDR_REC ' Record Stack Dim rsvd4 As String ' Reserved for Future Use End Structure
Structure structFoot Dim a As Char ' Zip Corrected Dim b As Char ' City/State Corrected Dim c As Char ' Invalid City/State/Zip Dim d As Char ' No Zip Assigned Dim e As Char ' ZIP Assigned for Mult Response Dim f As Char ' No Zip Available Dim g As Char ' Part of Firm Moved to Address Dim h As Char ' Secondary Number Missing Dim i As Char ' Insufficient/Incorrect Data Dim j As Char ' Dual Input - Used PO Box Dim k As Char ' Dual Input - Used non-PO Box Dim l As Char ' Del Addr Component Add/Del/Chg Dim m As Char ' Street Name Spelling Changed Dim n As Char ' Delivery Addr was Standardized Dim o As Char ' Reserved for Future Use Dim p As Char ' Better Delivery Addr Exists Dim q As Char ' Reserved for Future Use Dim s As Char ' Invalid Secondary Number Dim t As Char ' Magnet Street Dim u As Char ' Unofficial PO Name Dim v As Char ' Unverifiable City/State Dim w As Char ' Small Town Default Dim x As Char ' Unique ZIP Code Default Dim y As Char ' Reserved for Future Use Dim z As Char ' ZIP Move Match Dim rsvd3 As Char() ' Reserved for Future Use End Structure
When I do a call to Inquire, nothing changes in the structure. The structure should be populated with the corrected values, but the struct remains unchanged. Am I missing something?
Thank you for any assistance,
 Signature Joel Cade, MCSD Brinkster Communications http://www.brinkster.com
Joel Cade - 10 Jun 2005 20:57 GMT I've actually changed the structure definition to this, which is on the right track, but still not working:
<StructLayout(LayoutKind.Sequential, CharSet:=CharSet.Auto)> _ Structure structZIP4_PARM 'Input Data Public rsvd0 As Char() ' Reserved for Future Use <MarshalAs(UnmanagedType.ByValTStr, SizeConst:=51)> Public iadl1 As String ' Input Delivery Address <MarshalAs(UnmanagedType.ByValTStr, SizeConst:=51)> Public iadl2 As String ' Input Firm Name <MarshalAs(UnmanagedType.ByValTStr, SizeConst:=51)> Public ictyi As String ' Input City <MarshalAs(UnmanagedType.ByValTStr, SizeConst:=3)> Public istai As String ' Input State <MarshalAs(UnmanagedType.ByValTStr, SizeConst:=11)> Public izipc As String ' Input ZIP+4 Code <MarshalAs(UnmanagedType.ByValTStr, SizeConst:=29)> Public iprurb As String ' Input Urbanization Name <MarshalAs(UnmanagedType.ByValTStr, SizeConst:=51)> Public iadl3 As String ' Input Second Address Line Public rsvd1 As Char() ' Reserved for Future User
'Output Data <MarshalAs(UnmanagedType.ByValTStr, SizeConst:=51)> Public dadl3 As String ' Standardized 2nd Delivery Address <MarshalAs(UnmanagedType.ByValTStr, SizeConst:=51)> Public dadl1 As String ' Standardized Delivery Address <MarshalAs(UnmanagedType.ByValTStr, SizeConst:=51)> Public dadl2 As String ' Standardized Firm Name <MarshalAs(UnmanagedType.ByValTStr, SizeConst:=51)> Public dlast As String ' Standardized City/State/Zip <MarshalAs(UnmanagedType.ByValTStr, SizeConst:=29)> Public dprurb As String ' Output PR Urbanization Name <MarshalAs(UnmanagedType.ByValTStr, SizeConst:=29)> Public dctys As String ' Main Post Office City <MarshalAs(UnmanagedType.ByValTStr, SizeConst:=3)> Public dstas As String ' Main Post Office State <MarshalAs(UnmanagedType.ByValTStr, SizeConst:=29)> Public dctya As String ' Standardized City <MarshalAs(UnmanagedType.ByValTStr, SizeConst:=14)> Public abcty As String ' Standardized City Abbreviation <MarshalAs(UnmanagedType.ByValTStr, SizeConst:=3)> Public dstaa As String ' Standardized State <MarshalAs(UnmanagedType.ByValTStr, SizeConst:=6)> Public zipc As String ' 5-digit zip Code <MarshalAs(UnmanagedType.ByValTStr, SizeConst:=5)> Public addon As String ' ZIP+4 addon Code <MarshalAs(UnmanagedType.ByValTStr, SizeConst:=4)> Public dpbc As String ' Delivery Point Bar Code <MarshalAs(UnmanagedType.ByValTStr, SizeConst:=5)> Public cris As String ' Carrier Route <MarshalAs(UnmanagedType.ByValTStr, SizeConst:=4)> Public county As String ' FIPS County Code Public respn As Int16 ' Number of Returned Responses Public retcc As Byte ' Return Code Public adrkey As Char() ' Address Key (for Indexing) Public auto_zone_ind As Char ' A, B, C, or D <MarshalAs(UnmanagedType.ByValTStr, SizeConst:=5)> Public elot_num As String ' eLOT Number Public elot_code As Char ' eLOT Ascending/Descending Flag
' Parsed Input Data <MarshalAs(UnmanagedType.ByValTStr, SizeConst:=11)> Public ppnum As String ' Primary Number <MarshalAs(UnmanagedType.ByValTStr, SizeConst:=9)> Public psnum As String ' Secondary Number <MarshalAs(UnmanagedType.ByValTStr, SizeConst:=4)> Public prote As String ' Rural Route Number <MarshalAs(UnmanagedType.ByValTStr, SizeConst:=5)> Public punit As String ' Secondary Number Unit <MarshalAs(UnmanagedType.ByValTStr, SizeConst:=3)> Public ppre1 As String ' First or Left Pre-direction <MarshalAs(UnmanagedType.ByValTStr, SizeConst:=3)> Public ppre2 As String ' Second or Right Pre-direction <MarshalAs(UnmanagedType.ByValTStr, SizeConst:=5)> Public psuf1 As String ' First or Left Suffix <MarshalAs(UnmanagedType.ByValTStr, SizeConst:=5)> Public psuf2 As String ' Second or Right Suffix <MarshalAs(UnmanagedType.ByValTStr, SizeConst:=3)> Public ppst1 As String ' First or Left Post-direction <MarshalAs(UnmanagedType.ByValTStr, SizeConst:=3)> Public ppst2 As String ' Second or Right Post-direction <MarshalAs(UnmanagedType.ByValTStr, SizeConst:=29)> Public ppnam As String ' Primary Name <MarshalAs(UnmanagedType.ByValTStr, SizeConst:=11)> Public mpnum As String ' Matched Primary Number <MarshalAs(UnmanagedType.ByValTStr, SizeConst:=8)> Public msnum As String ' Matched Secondary Number <MarshalAs(UnmanagedType.ByValTStr, SizeConst:=4)> Public pmb As String ' PMB Unit Designator <MarshalAs(UnmanagedType.ByValTStr, SizeConst:=9)> Public pmbnum As String ' PMB Number Public rsvd2 As Char() ' Reserved for Future User Public foot As structFoot Public ADDR_REC() As structADDR_REC ' Record Stack Public rsvd4 As String ' Reserved for Future Use End Structure
Christian Ehlscheid - 11 Jun 2005 00:16 GMT Hello,
you also have to specify the size of the reserved fields (rsvd0, rsvd1 ..) otherwise the byte offsets of the member's shift, producing a wrong binary layout.
Regards Christian
> I've actually changed the structure definition to this, which is on the right > track, but still not working: [quoted text clipped - 101 lines] > for Future Use > End Structure Joel Cade - 13 Jun 2005 16:23 GMT Thank you for the reply.
I'm not sure which type of attribute to use for the different types of managed types.
Can you help with the attributes to use for the following examples (+1 indicates a null terminator)?
Unmanaged Type -> Managed Type
char iadl1[50+1] -> String char rsvd[98] -> Char() ADDR_REC stack[10] -> structAddr_Rec()
I think this would help get this working.
Thanks again,
 Signature Joel Cade, MCSD
> Hello, > [quoted text clipped - 135 lines] > > for Future Use > > End Structure Christian Ehlscheid - 13 Jun 2005 18:13 GMT Hello,
> char iadl1[50+1] -> String correct, has to be used in combination with MarshalAs(Unmanaged.ByValTArray, SizeConst := x)
> char rsvd[98] -> Char() you have to choices .. either use string and ByValTArray or use char[] or byte[] with ByValArray
> ADDR_REC stack[10] -> structAddr_Rec() not sure on this one but i think just declare it as the mangaged type in combination with ByValArray and SizeConst=10
besides this since the struct declarations use the C char datatype they use Ansi character set .. so setting CodePage=CodePage.Ansi in StructLayout would be appropiate.
Regards Christian
Joel Cade - 13 Jun 2005 19:25 GMT Thank you so much for your help.
I'm still have a problem with the array of structs inside the struct. Its throwing an exception:
"Can not marshal field ADDR_REC of type structZIP4_PARM: This type can not be marshaled as a structure field."
I'm declaring the struct as follows:
<StructLayout(LayoutKind.Sequential, CharSet:=CharSet.Ansi)> _ Structure structZIP4_PARM
<MarshalAs(UnmanagedType.ByValArray, sizeConst:=4)> Public rsvd0 As Byte() <MarshalAs(UnmanagedType.ByValTStr, SizeConst:=51)> Public iadl1 As String <MarshalAs(UnmanagedType.ByValArray, SizeConst:=10)> Public ADDR_REC() As structADDR_REC
End Structure
and the structADDR_REC is declared as:
<StructLayout(LayoutKind.Sequential, CharSet:=CharSet.Ansi)> _ Structure structADDR_REC
Dim detail_code As Char <MarshalAs(UnmanagedType.ByValTStr, SizeConst:=6)> Dim addr_code As String
End Structure
The C code is prototyped as:
typedef struct { char rsvd0[4]; char iadl1[50+1]; ADDR_REC stack[10]; } ZIP4_PARAM
typedef struct { char detail_code; char addr_code[5+1]; }
BTW: I didn't see a type called ByValTArray.
Thanks again for all your help,
 Signature Joel Cade, MCSD
> Hello, > [quoted text clipped - 19 lines] > Regards > Christian Christian Ehlscheid - 13 Jun 2005 22:33 GMT Hello,
seems that the Net marshaler cannot marshal array's of structures inside another struct.
but you can workaround this by "flatten" the ADDR_REC members directly into the ZIP4_PARAM struct
e.g.
<StructLayout(LayoutKind.Sequential, CharSet:=CharSet.Ansi)> _ Structure structZIP4_PARM <MarshalAs(UnmanagedType.ByValArray, sizeConst:=4)> Public rsvd0 As Byte() <MarshalAs(UnmanagedType.ByValTStr, SizeConst:=51)> Public iadl1 As String <MarshalAs(UnmanagedType.ByValArray, SizeConst:=10)> Public detail_code1 As Char <MarshalAs(UnmanagedType.ByValTStr, SizeConst:=6)> Public addr_code1 As String
Public detail_code2 As Char <MarshalAs(UnmanagedType.ByValTStr, SizeConst:=6)> Public addr_code2 As String
Public detail_code3 As Char <MarshalAs(UnmanagedType.ByValTStr, SizeConst:=6)> Public addr_code3 As String
Public detail_code4 As Char <MarshalAs(UnmanagedType.ByValTStr, SizeConst:=6)> Public addr_code4 As String
Public detail_code5 As Char <MarshalAs(UnmanagedType.ByValTStr, SizeConst:=6)> Public addr_code5 As String // and so on upto 10 End Structure
> BTW: I didn't see a type called ByValTArray. yes .. my fault .. i meant ByValTStr
Regards Christian
Free MagazinesGet these publications absolutely FREE for up to 12 months. There are no hidden fees and no obligation. Simply choose a title, complete the application form and submit it. Read more ...
|
|
|