2010-12-14 3 views
2

C#에서는 다음 C 메서드를 호출하려고합니다.이 C 함수를 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) 

다음과 같이 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); 

항상 System.AccessViolationException을 생성합니다. 함수를 호출 할 때 여러 값 조합을 시도했지만 더 좋은 결과는 얻지 못합니다. 그것은 데이터 형식을 올바르게 마샬링하는 것처럼 보이는 경우 누구든지 말해 줄 수 있습니까?

디버깅 할 수 있도록 C 소스 코드에 액세스 할 수 있으면 좋겠지 만 타사 DLL 집합입니다. 헤더 파일 만 볼 수 있습니다.

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; 

그리고 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 
} 
+0

해당 C 및 C# 구조체도 게시해야합니다. 값으로 전달되기 때문에 두 구조체의 크기가 완전히 같지 않을 가능성이 있으며,이 경우 인수가 손상되고 모든 인수가 손상됩니다. – cdhowie

+0

C 함수가 유니 코드 또는 Ansi 문자열을 필요로합니까? 또한 여기서'[In]'을 말할 필요도 없습니다. –

+0

C와 C#의 열거 형에 대한 정의를 추가했습니다. Anton, 유니 코드를 기대하는 곳은 어디입니까? –

답변

4

C에서 long 마음에 들지 8 바이트이기 때문에 아니,하지 못했습니다입니다 그것은 C# (그것은 종종 4 바이트)입니다. 또한 string은 변경할 수 없기 때문에 은 반드시 string 일 필요는 없으며이 경우에만 const char*으로 안전하게 마샬링 할 수 있습니다. C 코드가 해당 값을 수정하지 못하도록 보장 할 수 있기 때문입니다. 변경할 수있게하려면 string 대신 StringBuilder을 사용하고 [MarshalAs(UnmanagedType.LPTStr)] 등을 사용하십시오.

+0

그래서 길지 않은 대신 int를 전달해야합니까? –

+0

예, C 컴파일러가 'long'에 32 비트를 사용한다고 가정합니다 (종종 그렇습니다). 또한'char *'는 대개 ANSI이므로 [MarshalAs (UnmanagedType.LPStr)]를 사용하는 것이 좋습니다. – Mehrdad

+0

작은 쪽지이지만 매개 변수가 전달되는 방식 때문에 64 비트 시스템에서 실제로 오류가 발생할 수 있는지 여부를 언급 할 가치가 있다고 생각합니다. 예를 들어 매개 변수가 레지스터에 전달 된 경우 (64 비트 환경에서 처음 몇 가지 논쟁이 일어난다 고 생각합니다), 아키텍처에서 오류가 발생하지는 않지만 다른 아키텍처에서는 오류가 발생할 수 있습니다. 그것에 조심하십시오. – Mehrdad

관련 문제