Home | Contact Us | FAQ | Search & Site Map | Link to Us
Sign In | Join | Other 45 Sites in Network
HomeAnnouncementsFree MagazinesWhite PapersSubmit Content
Discussion GroupsASP.NETWindows FormsLanguages.NET FrameworkVisual Studio.NET
Articles.NET FrameworkASP.NETToolsWindows Forms
.NET DirectoryOpen Source ProjectsUser GroupsWeb Resources
Related Topics
Visual Basic 6SQL ServerMS AccessOther DB ProductsMS Server ProductsMore Topics ...

.NET Forum / .NET Framework / Interop / June 2005

Tip: Looking for answers? Try searching our database.

Struct to API Problems

Thread view: 
Enable EMail Alerts  Start New Thread
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 Magazines

Get 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 ...

Oracle MagazineNetwork ComputingComputer WorldBio-IT WorldeWeekInformation WeekInfosecurity
 
Sign In
Join
My Latest Posts
My Monitored Threads
My Blog
My Photo Gallery
My Profile
My Homepage

Start New Thread
Enable EMail Alerts
Rate this Thread



©2008 Advenet LLC   Privacy Policy - Terms of Use
This website includes both content owned or controlled by Advenet as well as content owned or controlled by third parties.