2014-10-12 3 views
2

P/Invoke Interop Assistant을 사용하여 C#에서 C++ DLL을 호출하려고합니다. 헤더의 대부분은 잘 변환됩니다하지만이에 문제가 있어요 :P/Invoke 구조체에 대한 포인터를 어떻게 선언 할 수 있습니까?

#define FULLOCTAVE_BINS    12 
#define THIRDOCTAVE_BINS    36 

typedef struct tagTimeHistory 
{ 
    UINT m_nAction; 
    int m_nFlag; 
    int m_nRecordNum; 
    int m_nTimeStamp; 
    int m_nMiscStartIndex; 
    float m_pfTHFloatVals[256]; // Number of valid values given by m_nNumFloatVals in Settings. 
    float m_pfTH11OBAVals[4][FULLOCTAVE_BINS]; // 0-4 spectra given by m_nNumOBA11Vals in Settings 
    float m_pfTH13OBAVals[4][THIRDOCTAVE_BINS]; // 0-4 spectra given by m_nNumOBA13Vals in Settings 
    float m_fDuration; 
} stTimeHistory_t; 

typedef struct tagSlmBulkRecords 
{ 
    int nRecType; 
    union 
    { 
     stTimeHistory_t *m_ThRecs; 
     stInterval_t *m_Interval; 
     stExceedence_t *m_Exceedences; 
     stRunRecord_t *m_RunRecord; 
     stSpeechData_t *m_VoiceRecord; 
     stSpeechData_t *m_AudioRecord; 
    }; 
} stSlmBulkRecord_t; 

이가로 전환 중입니다 :

[System.Runtime.InteropServices.StructLayoutAttribute(System.Runtime.InteropServices.LayoutKind.Explicit)] 
public struct Anonymous_d2bf9406_c664_4664_9196_800cc23f445a { 

    /// stTimeHistory_t* 
    [System.Runtime.InteropServices.FieldOffsetAttribute(0)] 
    public System.IntPtr m_ThRecs; 

    /// stInterval_t* 
    [System.Runtime.InteropServices.FieldOffsetAttribute(0)] 
    public System.IntPtr m_Interval; 

    /// stExceedence_t* 
    [System.Runtime.InteropServices.FieldOffsetAttribute(0)] 
    public System.IntPtr m_Exceedences; 

    /// stRunRecord_t* 
    [System.Runtime.InteropServices.FieldOffsetAttribute(0)] 
    public System.IntPtr m_RunRecord; 

    /// stSpeechData_t* 
    [System.Runtime.InteropServices.FieldOffsetAttribute(0)] 
    public System.IntPtr m_VoiceRecord; 

    /// stSpeechData_t* 
    [System.Runtime.InteropServices.FieldOffsetAttribute(0)] 
    public System.IntPtr m_AudioRecord; 
} 

[System.Runtime.InteropServices.StructLayoutAttribute(System.Runtime.InteropServices.LayoutKind.Sequential)] 
public struct tagSlmBulkRecords { 

    /// int 
    public int nRecType; 

    /// Anonymous_d2bf9406_c664_4664_9196_800cc23f445a 
    public Anonymous_d2bf9406_c664_4664_9196_800cc23f445a Union1; 
} 

하지만 그냥 System.IntPtr 이름이 때 나는 m_ThRecs을 어떻게 사용합니까? 명시 적으로 stTimeHistory_t에 대한 포인터로 선언하는 방법이 있습니까?

stSlmBulkRecord_t bulkRecord; 
bulkRecord.m_ThRecs = new stTimeHistory_t[dataCounts.m_nNumTH]; 

를하지만 C#에서이를 시도하는 경우 : 나는 C#을 포팅하고있어 C++ 코드는 다음과 같이 그것을 사용

tagSlmBulkRecords bulkRecord; 
bulkRecord.Union1.m_ThRecs = new tagTimeHistory[dataCounts.m_nNumTH]; 

내가 얻을 :

오류 1 암시 적으로 변환 할 수 없습니다 'SlmTest.Program.tagTimeHistory []'~ 'SlmTest.Program.tagTimeHistory' "

내가 unsaf를 시도하면 전자 정의 :

[System.Runtime.InteropServices.StructLayoutAttribute(System.Runtime.InteropServices.LayoutKind.Sequential)] 
public struct tagTimeHistory 
{ 
    /// UINT->unsigned int 
    public uint m_nAction; 

    /// int 
    public int m_nFlag; 

    /// int 
    public int m_nRecordNum; 

    /// int 
    public int m_nTimeStamp; 

    /// int 
    public int m_nMiscStartIndex; 

    /// float[256] 
    [System.Runtime.InteropServices.MarshalAsAttribute(System.Runtime.InteropServices.UnmanagedType.ByValArray, SizeConst = 256, ArraySubType = System.Runtime.InteropServices.UnmanagedType.R4)] 
    public float[] m_pfTHFloatVals; 

    /// float[48] 
    [System.Runtime.InteropServices.MarshalAsAttribute(System.Runtime.InteropServices.UnmanagedType.ByValArray, SizeConst = 48, ArraySubType = System.Runtime.InteropServices.UnmanagedType.R4)] 
    public float[] m_pfTH11OBAVals; 

    /// float[144] 
    [System.Runtime.InteropServices.MarshalAsAttribute(System.Runtime.InteropServices.UnmanagedType.ByValArray, SizeConst = 144, ArraySubType = System.Runtime.InteropServices.UnmanagedType.R4)] 
    public float[] m_pfTH13OBAVals; 

    /// float 
    public float m_fDuration; 
} 

[System.Runtime.InteropServices.StructLayoutAttribute(System.Runtime.InteropServices.LayoutKind.Explicit)] 
public unsafe struct Anonymous_d2bf9406_c664_4664_9196_800cc23f445a 
{ 
    /// stTimeHistory_t* 
    [System.Runtime.InteropServices.FieldOffsetAttribute(0)] 
    public tagTimeHistory *m_ThRecs; 
    /// stInterval_t* 
    [System.Runtime.InteropServices.FieldOffsetAttribute(0)] 
    public System.IntPtr *m_Interval; 
    /// stExceedence_t* 
    [System.Runtime.InteropServices.FieldOffsetAttribute(0)] 
    public System.IntPtr m_Exceedences; 
    /// stRunRecord_t* 
    [System.Runtime.InteropServices.FieldOffsetAttribute(0)] 
    public System.IntPtr m_RunRecord; 
    /// stSpeechData_t* 
    [System.Runtime.InteropServices.FieldOffsetAttribute(0)] 
    public System.IntPtr m_VoiceRecord; 
    /// stSpeechData_t* 
    [System.Runtime.InteropServices.FieldOffsetAttribute(0)] 
    public System.IntPtr m_AudioRecord; 
} 

내가 얻을 :

오류 CS0208 : 관리 형

+0

'stSlmBulkRecord_t'는 C#의'struct' 또는'class'로 선언 되었습니까? –

+0

stSlmBulkRecord_t는 C#에서는 선언되지 않았으며 위에 표시된 구조체 인 tagSlmBulkRecords만이 선언되었습니다. – parsley72

+0

여기 안전하지 않은 분명한 이유는 없습니다 –

답변

2

에 대한 포인터를의 크기를 얻을의 주소를 가지고, 또는 선언 할 수 없습니다 당신이 만약 실제로은 기본 코드와 상호 운용되고 싶다면 fixed 연산자를 사용할 수 있습니다.

var array = new tagTimeHistory[dataCounts.m_nNumTH]; 
fixed (tagTimeHistory* ptr = array) 
{ 
    // do anything with the raw pointer 
} 

fixed C#의 연산자 및 포인터 형식에는 unsafe 기능이 필요합니다. 그리고 IntPtr을 포인터 유형으로 바꾸어 올바른 유형의 포인터로 바꾸고 싶을 수도 있습니다 (포인터를 IntPtr으로 변환하고 다시 변환하는 방법이 있지만).

동일한 작업을 수행하는 또 다른 방법은 Marshal class의 방법을 사용하는 것입니다.

EDIT. 여기은 재미라는 이름의 조합 구조의 개정 안전하지 않은 정의의 샘플입니다

[StructLayout(LayoutKind.Explicit)] 
public unsafe struct Anonymous_d2bf9406_c664_4664_9196_800cc23f445a 
{ 
    [FieldOffset(0)] 
    public stTimeHistory_t* m_ThRecs; 

    [FieldOffset(0)] 
    public stInterval_t* m_Interval; 

    [FieldOffset(0)] 
    public stExceedence_t* m_Exceedences; 

    [FieldOffset(0)] 
    public stRunRecord_t* m_RunRecord; 

    [FieldOffset(0)] 
    public stSpeechData_t* m_VoiceRecord; 

    [FieldOffset(0)] 
    public stSpeechData_t* m_AudioRecord; 
} 
당신은 당신의 코드에서 stTimeHistory_t 모든 구조를 정의 (또는 일반적인 IntPtr와 상관 없어 사람을 교체해야

에스).

Marshal으로 구조 배열을 생성하는 경우 : 네이티브 메모리 풀에는 structure array과 같은 개념이 없습니다. 모든 것은 단지 바이트입니다.

IntPtr myPtr = Marshal.AllocHGlobal(Marshal.SizeOf<tagTimeHistory>() * dataCounts.m_nNumTH); 
// ... write something to an array, use it 
// And don't forget to free it to prevent memory leaks! 
Marshal.FreeHGlobal(myPtr); 

편집 2 : 그래서 당신은, 예를 들어, Marshal.AllocHGlobal method를 사용할 수 있습니다. "주소를 가져올 수 없거나 관리되는 유형에 대한 포인터를 가져올 수 없거나 포인터를 선언 할 수 없습니다"오류 - 정의가 완전히 관리되지 않습니다. 안전하지 않은 정의와 마샬링 논리를 사용하는 정의가 항상 동일하지는 않습니다. 여기에 클래스 참조가 있기 때문에 클래스가 "관리"되고 있다고 생각합니다. 고정 배열을 시도해보십시오 :

[StructLayout(LayoutKind.Sequential)] 
public unsafe struct tagTimeHistory 
{ 
    public uint m_nAction; 
    public int m_nFlag; 
    public int m_nRecordNum; 
    public int m_nTimeStamp; 
    public int m_nMiscStartIndex; 
    public fixed float m_pfTHFloatVals[256]; 
    public fixed float m_pfTH11OBAVals[48]; 
    public fixed float m_pfTH13OBAVals[144]; 
    public float m_fDuration; 
} 
+0

"당신은 더 많은 타입 안전을 위해 'IntPtr 's를 적절한 포인터 타입으로 대체하고 싶을 것입니다. 또는 마샬링을 사용하여 구조체 배열을 만드는 방법은 무엇입니까? – parsley72

+0

안전하지 않은 정의를 시도했지만 "오류 CS0208 : 주소를 가져올 수 없거나 관리되는 유형의 포인터를 가져 오거나 포인터를 선언 할 수 없습니다." – parsley72

+0

@ parsley72 질문에 'tagTimeHistory'의 정의를 표시하십시오. 클래스의 것이고 구조체는 아닙니다. – ForNeVeR

관련 문제