none
Interop Struct diferent size RRS feed

  • Question

  • Hello Guys,

    I need some help with interop. I have a COM Server with the struct and interface below: 

    1 typedef struct tag_REG_PRODUTOPS {  
    2  CURRENCY vBaseSubstituicaoTributariaICMS;  
    3  CURRENCY vPrecoVendaV8;  
    4  CURRENCY vIPIProduto;  
    5  CURRENCY vTara;  
    6  CURRENCY vPesoBruto;  
    7  CURRENCY vPesoLiquido;  
    8  CURRENCY vPrazoGarantia;  
    9  CURRENCY vCapacidadeVolumetrica;  
    10  CURRENCY vConversaoUnidadeMedida;  
    11  CURRENCY vFiller[2];  
    12  long lPonteiroProduto;  
    13  long lPonteiroDescricao;  
    14  long lPonteiroFornecimento;  
    15  long lPonteiroItensComposicao;  
    16  long lPonteiroEmbalagem;  
    17  long lPonteiroAliquotasICMS;  
    18  long lPonteiroEmbalagemFormato;  
    19  long lPonteiroIncidenciasPisCofins;  
    20  long lFiller[3];  
    21  unsigned short iPercentualIPI;  
    22  unsigned short iPonteiroUnidadeMedidaEstoque;  
    23  unsigned short iPercentualReducaoIPI;  
    24  unsigned short iDataValidadeReducaoIPI;  
    25  unsigned short iPonteiroMensagemIPI;  
    26  unsigned short iQtdeAliquotasICMS;  
    27  unsigned short iQtdeIncidenciasPisCofins;  
    28  unsigned short iPonteiroGrade1;  
    29  unsigned short iPonteiroGrade2;  
    30  unsigned short iPonteiroGrade3;  
    31  unsigned short iQtdItensComposicao;  
    32  unsigned short iCodigoProdutoDNF;  
    33  unsigned short iQtdProdutosPorEmbalagem;  
    34  unsigned short iCodigoInsumo;  
    35  unsigned short iDescontoSugerido;  
    36  unsigned short iPercentualMarkup;  
    37  unsigned short iDataCadastro;  
    38  unsigned char cNome[52];  
    39  unsigned char cClassificacao[30];  
    40  unsigned char cCodigo[22];  
    41  unsigned char cReferencia[22];  
    42  unsigned char cCodigoClassificacaoFiscal[18];  
    43  unsigned char cCodigoReduzidoClassificacaoFiscal[4];  
    44  unsigned char cCodigoSefaz[16];  
    45  unsigned char cCodigoCategoria[12];  
    46  unsigned char cCodigoScanc[16];  
    47  unsigned char cCodigoItemDF[3];  
    48  unsigned char cFiller1;  
    49  unsigned char cCodigoMapaFisiografico[8];  
    50  unsigned char cInformacaoExtra[3][62];  
    51  unsigned char cCodigoExTIPI[4];  
    52  unsigned char cCodigoExImportacao[4];  
    53  unsigned char cCodigoTributacaoIPI[4];  
    54  unsigned char cClassificacaoEnergiaComunicacao[6];  
    55  unsigned char cMedicamento;  
    56  unsigned char cArmaDeFogo;  
    57  unsigned char cVeiculoNovo;  
    58  unsigned char iQuantidadeCasasDecimais;  
    59  unsigned char iQuantidadeCasasDecimaisCompras;  
    60  unsigned char iQuantidadeCasasDecimaisEstoque;  
    61  unsigned char cPonteiroSituacaoTributaria;  
    62  unsigned char cTipo;  
    63  unsigned char cProdutoDeTerceiros;  
    64  unsigned char cPrevaleceAliquotaICMSDoProduto;  
    65  unsigned char cImunidadeIsencaoNaoTributadaIPI;  
    66  unsigned char cSuspensaoOuAliquotaZeroIPI;  
    67  unsigned char cNaoPossuiBeneficioSuframa;  
    68  unsigned char cEmbalagem;  
    69  unsigned char cInativo;  
    70  unsigned char cPermiteAlterarComposicaoNaMovimentacao;  
    71  unsigned char cKit;  
    72  unsigned char cSituacaoTributarioECF;  
    73  unsigned char cCodigoPosse;  
    74  unsigned char cCodigoTipoItem;  
    75  unsigned char cCodigoApuracaoIPIIN394;  
    76  unsigned char cUnidadeMedidaTara;  
    77  unsigned char cUnidadeMedidaPesoBruto;  
    78  unsigned char cUnidadeMedidaLiquido;  
    79  unsigned char cUnidadeMedidaPrazo;  
    80  unsigned char cCodigoUnidadeMedidaDSTA;  
    81  unsigned char cProdutoBeneficiarioIcmsDispensado;  
    82  unsigned char iCodigoApuracaoPordepeFuncresce;  
    83  unsigned char cProdutoIncentivadoMS;  
    84  unsigned char cDiferimentoParcialdoICMS_PR;  
    85  unsigned char cAplicarSubsTributariaPISCOFINS;  
    86 } _REG_PRODUTOPS;  
    87  
    88  
    89  
    1  
    2 [  
    3   odl,  
    4   uuid(B4931BE0-B475-11D2-A079-00A0C9B6FB26)  
    5 ]  
    6 interface IWKDF_Produto : IUnknown {  
    7     HRESULT _stdcall Inicializa(  
    8                     [in] BSTR bsNome,   
    9                     [in] unsigned short iUsuario,   
    10                     [inlong lNumeroSessao);  
    11     HRESULT _stdcall Le(  
    12                     [inlong lPosicao,   
    13                     [in] unsigned short iTabelaPrecos,   
    14                     [out] _REG_PRODUTOPS* RegProdutops);  
    15 };  
    16  


    I have generated a assembly with TlbImp.exe. After, I have Reflector it, generating this source file:

    1 [StructLayout(LayoutKind.Sequential, Pack = 2)]  
    2 public struct _REG_PRODUTOPS  
    3 {  
    4 [MarshalAs(UnmanagedType.Currency)]  
    5 public decimal vBaseSubstituicaoTributariaICMS;  
    6 [MarshalAs(UnmanagedType.Currency)]  
    7 public decimal vPrecoVendaV8;  
    8 [MarshalAs(UnmanagedType.Currency)]  
    9 public decimal vIPIProduto;  
    10 [MarshalAs(UnmanagedType.Currency)]  
    11 public decimal vTara;  
    12 [MarshalAs(UnmanagedType.Currency)]  
    13 public decimal vPesoBruto;  
    14 [MarshalAs(UnmanagedType.Currency)]  
    15 public decimal vPesoLiquido;  
    16 [MarshalAs(UnmanagedType.Currency)]  
    17 public decimal vPrazoGarantia;  
    18 [MarshalAs(UnmanagedType.Currency)]  
    19 public decimal vCapacidadeVolumetrica;  
    20 [MarshalAs(UnmanagedType.Currency)]  
    21 public decimal vConversaoUnidadeMedida;  
    22 [MarshalAs(UnmanagedType.ByValArray, SizeConst = 2)]  
    23 public decimal[] vFiller;  
    24 public int lPonteiroProduto;  
    25 public int lPonteiroDescricao;  
    26 public int lPonteiroFornecimento;  
    27 public int lPonteiroItensComposicao;  
    28 public int lPonteiroEmbalagem;  
    29 public int lPonteiroAliquotasICMS;  
    30 public int lPonteiroEmbalagemFormato;  
    31 public int lPonteiroIncidenciasPisCofins;  
    32 [MarshalAs(UnmanagedType.ByValArray, SizeConst = 3)]  
    33 public int[] lFiller;  
    34 public ushort iPercentualIPI;  
    35 public ushort iPonteiroUnidadeMedidaEstoque;  
    36 public ushort iPercentualReducaoIPI;  
    37 public ushort iDataValidadeReducaoIPI;  
    38 public ushort iPonteiroMensagemIPI;  
    39 public ushort iQtdeAliquotasICMS;  
    40 public ushort iQtdeIncidenciasPisCofins;  
    41 public ushort iPonteiroGrade1;  
    42 public ushort iPonteiroGrade2;  
    43 public ushort iPonteiroGrade3;  
    44 public ushort iQtdItensComposicao;  
    45 public ushort iCodigoProdutoDNF;  
    46 public ushort iQtdProdutosPorEmbalagem;  
    47 public ushort iCodigoInsumo;  
    48 public ushort iDescontoSugerido;  
    49 public ushort iPercentualMarkup;  
    50 public ushort iDataCadastro;  
    51 [MarshalAs(UnmanagedType.ByValArray, SizeConst = 0x34)]  
    52 public byte[] cNome;  
    53 [MarshalAs(UnmanagedType.ByValArray, SizeConst = 30)]  
    54 public byte[] cClassificacao;  
    55 [MarshalAs(UnmanagedType.ByValArray, SizeConst = 0x16)]  
    56 public byte[] cCodigo;  
    57 [MarshalAs(UnmanagedType.ByValArray, SizeConst = 0x16)]  
    58 public byte[] cReferencia;  
    59 [MarshalAs(UnmanagedType.ByValArray, SizeConst = 0x12)]  
    60 public byte[] cCodigoClassificacaoFiscal;  
    61 [MarshalAs(UnmanagedType.ByValArray, SizeConst = 4)]  
    62 public byte[] cCodigoReduzidoClassificacaoFiscal;  
    63 [MarshalAs(UnmanagedType.ByValArray, SizeConst = 0x10)]  
    64 public byte[] cCodigoSefaz;  
    65 [MarshalAs(UnmanagedType.ByValArray, SizeConst = 12)]  
    66 public byte[] cCodigoCategoria;  
    67 [MarshalAs(UnmanagedType.ByValArray, SizeConst = 0x10)]  
    68 public byte[] cCodigoScanc;  
    69 [MarshalAs(UnmanagedType.ByValArray, SizeConst = 3)]  
    70 public byte[] cCodigoItemDF;  
    71 public byte cFiller1;  
    72 [MarshalAs(UnmanagedType.ByValArray, SizeConst = 8)]  
    73 public byte[] cCodigoMapaFisiografico;  
    74 [MarshalAs(UnmanagedType.ByValArray, SizeConst = 0xba)]  
    75 public byte[] cInformacaoExtra;  
    76 [MarshalAs(UnmanagedType.ByValArray, SizeConst = 4)]  
    77 public byte[] cCodigoExTIPI;  
    78 [MarshalAs(UnmanagedType.ByValArray, SizeConst = 4)]  
    79 public byte[] cCodigoExImportacao;  
    80 [MarshalAs(UnmanagedType.ByValArray, SizeConst = 4)]  
    81 public byte[] cCodigoTributacaoIPI;  
    82 [MarshalAs(UnmanagedType.ByValArray, SizeConst = 6)]  
    83 public byte[] cClassificacaoEnergiaComunicacao;  
    84 public byte cMedicamento;  
    85 public byte cArmaDeFogo;  
    86 public byte cVeiculoNovo;  
    87 public byte iQuantidadeCasasDecimais;  
    88 public byte iQuantidadeCasasDecimaisCompras;  
    89 public byte iQuantidadeCasasDecimaisEstoque;  
    90 public byte cPonteiroSituacaoTributaria;  
    91 public byte cTipo;  
    92 public byte cProdutoDeTerceiros;  
    93 public byte cPrevaleceAliquotaICMSDoProduto;  
    94 public byte cImunidadeIsencaoNaoTributadaIPI;  
    95 public byte cSuspensaoOuAliquotaZeroIPI;  
    96 public byte cNaoPossuiBeneficioSuframa;  
    97 public byte cEmbalagem;  
    98 public byte cInativo;  
    99 public byte cPermiteAlterarComposicaoNaMovimentacao;  
    100 public byte cKit;  
    101 public byte cSituacaoTributarioECF;  
    102 public byte cCodigoPosse;  
    103 public byte cCodigoTipoItem;  
    104 public byte cCodigoApuracaoIPIIN394;  
    105 public byte cUnidadeMedidaTara;  
    106 public byte cUnidadeMedidaPesoBruto;  
    107 public byte cUnidadeMedidaLiquido;  
    108 public byte cUnidadeMedidaPrazo;  
    109 public byte cCodigoUnidadeMedidaDSTA;  
    110 public byte cProdutoBeneficiarioIcmsDispensado;  
    111 public byte iCodigoApuracaoPordepeFuncresce;  
    112 public byte cProdutoIncentivadoMS;  
    113 public byte cDiferimentoParcialdoICMS_PR;  
    114 public byte cAplicarSubsTributariaPISCOFINS;  
    115 }  
    116  
    117  
    118  
    119 [ComImport, Guid("B4931BE0-B475-11D2-A079-00A0C9B6FB26"), InterfaceType((short)1), ComConversionLoss]  
    120 public interface IWKDF_Produto  
    121 {  
    122     [MethodImpl(MethodImplOptions.InternalCall, MethodCodeTypeMethodCodeType = MethodCodeType.Runtime)]  
    123     void Inicializa([In, MarshalAs(UnmanagedType.BStr)] string bsNome, [In] ushort iUsuario, [In] int lNumeroSessao);  
    124     [MethodImpl(MethodImplOptions.InternalCall, MethodCodeTypeMethodCodeType = MethodCodeType.Runtime)]  
    125     void Le([In] int lPosicao, [In] ushort iTabelaPrecos, out _REG_PRODUTOPS RegProdutops);  
    126 }  
    127  
    128  
    129  


    But when I run the code bellow:

                WKDF_ProdutoClass produto = new WKDF_ProdutoClass();  
                  
                produto.Inicializa("DEMO", 1, 666);  
     
                _REG_PRODUTOPS regProduto;  
                  
                for (int i = 1; i < 200; i++)  
                {  
                    produto.Le(i, 0, out regProduto);  
                
                }  
     

    The all fields of struct _REG_PRODUTOPS are wrong values, looks like what the Struct Layout doesn't match.

    Someone can give me a help?

    Att.

    Roosevelt
    Roosevelt dos Santos Júnior
    Monday, August 11, 2008 2:32 PM

Answers

  • You forgot the ArraySubType attribute for the decimal[] vFiller.  CURRENCY is 8 bytes, System.Decimal gets converted to DECIMAL by default which is 16 bytes.
    Hans Passant.
    Tuesday, August 12, 2008 3:48 AM
    Moderator
  •  Sucess!

    I changed my code to:
    [MarshalAs(UnmanagedType.ByValArray, SizeConst = 2, ArraySubType=UnmanagedType.Currency)]  
    public decimal[] vFiller;  
     

    And now it's working.

    Thank's a lot "nobugz".  
    Roosevelt dos Santos Júnior
    Tuesday, August 12, 2008 11:57 AM

All replies

  •    Extra information: The struct in IDL have 606 bytes and in .NET have 622 bytes.
    Roosevelt dos Santos Júnior
    Monday, August 11, 2008 4:37 PM
  • Hello,

    More information

    I changed the following code:
    1         [MarshalAs(UnmanagedType.ByValArray, SizeConst = 2)]  
    2         public decimal[] vFiller;  
    3  

    To:

    1         [MarshalAs(UnmanagedType.ByValArray, SizeConst = 1)]  
    2         public decimal[] vFiller;  
    3  

    And It's working. But I don't know why.
    Roosevelt dos Santos Júnior
    Monday, August 11, 2008 6:04 PM
  • You forgot the ArraySubType attribute for the decimal[] vFiller.  CURRENCY is 8 bytes, System.Decimal gets converted to DECIMAL by default which is 16 bytes.
    Hans Passant.
    Tuesday, August 12, 2008 3:48 AM
    Moderator
  •  Sucess!

    I changed my code to:
    [MarshalAs(UnmanagedType.ByValArray, SizeConst = 2, ArraySubType=UnmanagedType.Currency)]  
    public decimal[] vFiller;  
     

    And now it's working.

    Thank's a lot "nobugz".  
    Roosevelt dos Santos Júnior
    Tuesday, August 12, 2008 11:57 AM