2010-12-14 108 views
2

En C#, je suis en train de Pinvoke la méthode C suivant:Est-ce que je mets correctement cette fonction C en 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) 

Je TRIAGE en C# la manière suivante:

// 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); 

Qualifiant produit toujours un System.AccessViolationException. J'ai essayé plusieurs combinaisons de valeurs lors de l'appel de la fonction, mais je n'ai pas obtenu de meilleurs résultats. Quelqu'un peut-il me dire s'il semble que je rassemble correctement les types de données?

Ce serait génial si j'avais accès au code source C afin que je puisse déboguer, mais c'est un ensemble de DLL tiers. Je ne peux voir que les fichiers d'en-tête.

Les énumérations en C sont:

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; 

Et je les ai définis en C# comme:

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 
} 
+0

Vous devrez également afficher les structures C et C# correspondantes. Comme ils sont passés en valeur, il est probable que les tailles des deux structures ne soient pas exactement les mêmes, ce qui entraîne la corruption de cet argument ainsi que de tous les arguments suivants. – cdhowie

+0

Votre fonction C attend-elle des chaînes Unicode ou Ansi? De plus, vous n'avez pas vraiment besoin de dire "[In]" ici. –

+0

J'ai ajouté les définitions pour les énumérations en C et C#. Anton, où est-ce que je regarde pour voir si on attend Unicode? –

Répondre

4

Non, ce qui ne va pas, parce long en C est pas 8 octets comme c'est en C# (c'est souvent 4 octets). En outre, un char* n'est pas nécessairement un string, car string s sont censés être immuables, et vous pouvez seulement les marshaler en toute sécurité à const char*, puisque seulement cela peut garantir que le code C ne les modifiera pas. Si vous devez les rendre modifiables, utilisez StringBuilder au lieu de string et utilisez [MarshalAs(UnmanagedType.LPTStr)] ou similaire.

+0

Donc, au lieu de long je devrais passer int? –

+0

Oui, en supposant que votre compilateur C utilise 32 bits pour 'long' (ce qui est souvent le cas). De même, 'char *' est généralement ANSI, vous pouvez donc utiliser [MarshalAs (UnmanagedType.LPStr)] sur ces paramètres. – Mehrdad

+0

Un petit détail, mais je pense qu'il vaut la peine de mentionner que si vous obtenez une erreur peut être différent sur un système 64 bits, à cause de la façon dont les paramètres sont passés ... si les paramètres sont passés dans les registres, par exemple (ce que je pense qui se produit pour les premiers arguments dans un environnement 64 bits), vous pourriez ne pas avoir d'erreurs dans cette architecture, mais vous pourriez en avoir une autre. Faites attention à cela. – Mehrdad