简体   繁体   English

我可以在C#中正确编组此C函数吗?

[英]Am I marshalling this C function correctly in C#?

In C#, I am trying to PInvoke the following C method: 在C#中,我试图P调用以下C方法:

// C code:
BOOL VstSetLineDetail(
   tVstHdl pDataHdl, // type is void*
   long pLineItemNo, 
   tVstTransType pTransType, // enum type
   tVstTransSubType pTransSubType, // enum type
   tVstTransCd pTransCd, // enum type
   char *pTransDate, 
   tVstTaxedGeo *pTaxedGeoFlag, // enum type
   double *pExtdAmt, 
   double *pTotalTax, 
   double *pCombRate, 
   char *pUserArea, 
   tVstTaxingJuris *pTaxingJuris, // enum type
   char *pCustExmtCertifNum, 
   char *pDivCd, 
   char *pStoreCd, 
   char *pGLAcct)

I am marshalling it in C# the following way: 我将以以下方式在C#中将其编组:

// C# code:
[DllImport(@"VertexNative\Vst.dll")]
public static extern bool VstSetLineDetail(
   [In]IntPtr dataHandle, 
   [In]long lineItemNumber, 
   [In]VstTransactionType transactionType, // an enum I defined in C#
   [In]VstTransactionSubtype transactionSubtype, // C# enum
   [In]VstTransactionCode transactionCode, // C# enum
   [In]string transactionDate, 
   [In]ref VstTaxedGeo taxedGeo, // C# enum
   [In]ref double totalAmount, 
   [In]ref double totalTax, 
   [In]ref double combinedTaxRate, 
   [In]string userArea, 
   [In]ref VstTaxingJurisdiction jurisdiction, // C# enum
   [In]string exceptionCertificate, 
   [In]string divisionCode, 
   [In]string storeCode, 
   [In]string generalLedgerAccount);

Calling it always produces a System.AccessViolationException. 调用它总是会产生一个System.AccessViolationException。 I've tried many combinations of values when calling the function, but get no better results. 调用函数时,我尝试了多种值的组合,但没有得到更好的结果。 Can anyone tell me if it looks like I am marshalling the data types correctly? 谁能告诉我我是否在正确整理数据类型?

It would be great if I had access to the C source code so I could debug, but it's a third-party set of DLLs. 如果可以访问C源代码以便进行调试,那就太好了,但这是第三方DLL集。 I can only see the header files. 我只能看到头文件。

The enums in C are: C中的枚举是:

typedef enum
{
    eVstTransTypeIgnore = 99,   /* Means ignore this parameter */
    eVstTransTypeSale = 0,
    eVstTransTypePurchase,
    eVstTransTypeService,
    eVstTransTypeRentalLease,
    eVstTransTypeNumElems,
    eVstTransTypeFirstElem = eVstTransTypeSale
} tVstTransType;

typedef enum
{
    eVstTransSubTypeIgnore = 99,    /* Means ignore this parameter */
    eVstTransSubTypeNone = 0,
    eVstTransSubTypeProperty,
    eVstTransSubTypeFreight,
    eVstTransSubTypeService,
    eVstTransSubTypeRentalLease,
    eVstTransSubTypeExpense,
    eVstTransSubTypeMisc,
    eVstTransSubTypeNumElems,
    eVstTransSubTypeFirstElem = eVstTransSubTypeNone
} tVstTransSubType;

typedef enum
{
    eVstTransCdIgnore = 99, /* Means ignore this parameter */
    eVstTransCdNormal = 0,
    eVstTransCdAdjustment,
    eVstTransCdTaxOnlyDebit,
    eVstTransCdTaxOnlyCredit,
    eVstTransCdDistributeRate,
    eVstTransCdDistributeTax,
    eVstTransCdNumElems,
    eVstTransCdFirstElem = eVstTransCdNormal
} tVstTransCd;

typedef enum
{
    eVstTaxedGeoNone = 0,
    eVstTaxedGeoDetermine,
    eVstTaxedGeoShipTo,
    eVstTaxedGeoShipFrom,
    eVstTaxedGeoOrderAccept,
    eVstTaxedGeoNumElems,
    eVstTaxedGeoFirstElem = eVstTaxedGeoNone
} tVstTaxedGeo;

typedef enum {  
    eVstTaxingJurisPrimary,
    eVstTaxingJurisAddtl,
    eVstTaxingJurisNumElems,
    eVstTaxingJurisFirstElem = eVstTaxingJurisPrimary
} tVstTaxingJuris;

And I've defined them in C# as: 我在C#中将它们定义为:

public enum VstTransactionType
{
      Sale,
      Purchase,
      Service,
      RentalLease,
      Ignore = 99
}

public enum VstTransactionSubtype
{
     None,
     Property,
     Freight,
     Service,
     RentalLease,
     Expense,
     Misc,
     Ignore = 99
}

public enum VstTransactionCode
{
     Normal,
     Adjustment,
     TaxOnlyDebit,
     TaxOnlyCredit,
     DistributeRate,
     DistributeTax,
     Ignore = 99
}

public enum VstTaxedGeo
{
     None,
     Determine,
     ShipTo,
     ShipFrom,
     OrderAccept
}

public enum VstTaxingJurisdiction
{
      Primary,
      Additional
}

No, it's not right, because long in C isn't 8 bytes like it is in C# (it's often 4 bytes). 不,这是不对的,因为C中的long不像C#中的8个字节(通常为4个字节)。 Also, a char* isn't necessarily a string , because string s are meant to be immutable, and you can only safely marshal them to const char* , since only that can guarantee that the C code won't modify them. 另外, char*不一定是string ,因为string s是不可变的,并且您只能安全地将它们编组为const char* ,因为只有这样才能保证C代码不会修改它们。 If you need to make them mutable, use StringBuilder instead of string , and use [MarshalAs(UnmanagedType.LPTStr)] or the like. 如果需要使它们可变,请使用StringBuilder而不是string ,并使用[MarshalAs(UnmanagedType.LPTStr)]等。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM