2014-11-06 6 views
0

이 VB6 코드를 C#으로 마이그레이션하는 방법에 어려움을 겪고 있습니다. DLL 내부에서 구조체의 배열을 전달하는 함수를 호출하는 것을 포함합니다. 나는, 그래서관리되는 C# 코드에서 SAFEARRAY ** ppsa 인수로 관리되지 않는 C 메서드 호출

Public Declare Function rgetdat_str Lib "hscnetapi.dll" _ 
    Alias "rgetdat_str_vb" _ 
    (ByVal Server As String, ByVal num_points As Integer, _ 
    getdat_str_data() As rgetdat_str_data_str) As Integer 

:

'Define structure for RGETDAT_STR procedure call 
Type rgetdat_str_data_str 
    type As Integer          'data type (set internally) 
    file As Integer          'file in database 
    rec As Integer          'record in file 
    word As Integer          'word offset in record 
    start_bit As Integer        'UNUSED 
    length As Integer         'length of string 
    flags As Integer         'flags 
    padding1 As Integer         'UNUSED 
    value As String          'database value 
    status As Integer         'return status 
    padding2 As Integer         'UNUSED 
End Type 

이 "구조체"를 사용하여 하나 개의 기능이로 선언하는 방법이 있습니다

그래서 VB6에서 "구조체"선언은 다음과 같다 이 두 조각의 코드를 C#으로 변환하려고 시도했습니다. 나는 많은 변형을 시도했지만, 내가 가지고있는 최신 것을 여기 게시 할 것이다. 아이디어는 P/Invoke을 통해 함수를 호출하는 것입니다.

(지금까지)는 C# 구조체 :

[StructLayout(LayoutKind.Sequential, Pack = 1)] 
public struct rgetdat_str_data_str 
{ 
    public short type; 
    public short file; 
    public short rec; 
    public short word; 
    public short start_bit; 
    public short length; 
    public short flags; 
    public short padding1; 
    [MarshalAs(UnmanagedType.LPStr)] 
    public string value; 
    public short status; 
    public short padding2; 
} 

과 (지금까지) 기능 가져 오기 :

[DllImport("hscnetapi.dll", EntryPoint = "rgetdat_str_vb")] 
    public static extern short rgetdat_str(
     [MarshalAs(UnmanagedType.LPTStr)] 
     string Server, 
     short num_points, 
     [In,Out, MarshalAs(UnmanagedType.LPArray)] 
     ref rgetdat_str_data_str[] getdat_str_data); 

아무것도 마샬링 내 다양한 ​​실험에서 지금까지 일하지는 매개 변수 속성.

나는이 DLL의 C 헤더 파일을 찾을 관리하고, 선언은 다음과 같습니다

/* define union used in rgetdat_value in RGETDAT procedure call */ 
typedef union rgetdat_value_str 
{ 
    n_short   int2; 
    n_long   int4; 
    n_float   real4; 
    n_double  real8; 
    n_char   *str; 
    n_ushort  bits; 
} rgetdat_value; 

/* define structure for RGETDAT procedure call */ 
typedef struct rgetdat_data_str 
{ 
    n_ushort   type; 
    n_ushort   file; 
    n_ushort   rec; 
    n_ushort   word; 
    n_ushort   start_bit; 
    n_ushort   length; 
    n_short    flags; 
    rgetdat_value  value; 
    n_short    status; 
} rgetdat_data; 
: 다음과 같이 선언

EXTERN_C short __loadds CALLBACK rgetdat_str_vb_ansi 
       _DECLARE((char *szHostname, short cRequests, SAFEARRAY **ppsa)); 

와 C의 세계에서 "구조체"

필자는 필자의 좌절감으로 ITypeLib 뷰어 도구를 사용하여이 DLL을 열려고 시도했습니다. 나는이 DLL을 내 프로젝트의 참조로 추가 할 수 없더라도 DLL 파일을 열 수 있다는 것에 놀랐다. 어쨌든, 내가 관찰자 안에서 관찰 한 몇 가지. , 나는 C#을 구조체의 마샬링 속성으로 주위 재생,

typedef struct tagrGetdat_Str_Data_Str { 
    short type; 
    short file; 
    short rec; 
    short word; 
    short start_bit; 
    short length; 
    short flags; 
    short padding1; 
    BSTR value; 
    short status; 
    short padding2; 
} rGetdat_Str_Data_Str; 

이러한 관찰을 바탕으로 :

[entry("rgetdat_str_vb"), helpstring("...")] 
short _stdcall rGetdat_Str(
       [in] LPSTR Server, 
       [in] short num_points, 
       [in, out] SAFEARRAY(rGetdat_Str_Data_Str)* getdat_str_data); 

이 같은 "구조체"보고 :

기능이 서명이 예를 들어,

1.) 구조체의 속성을 으로 변경 [MarshalAs (Unman agedType.BStr)] 함수의 getdat_str_data 매개 변수 속성을 변경

2) 에 MarshalAs (UnmanagedType.SafeArray, SafeArraySubType = VarEnum.VT_RECORD)

여전히 아무것도 작동하지 않습니다.

여기에 비슷한 주제에 대해 이야기하는 블로그/기사가 있습니다. http://limbioliong.wordpress.com/2012/02/28/marshaling-a-safearray-of-managed-structures-by-pinvoke-part-1/하지만 내 머리를 감쌀 수 없습니다.

VB6은 C# (.닷넷)이 DLL 함수 호출. 어떤 힌트 또는 아이디어 DLLImport하는 방법에 C# (. 닷넷) 에서이 함수를 선언?

답변

1

MarshalAsUnmanagedType.SafeArray을 사용해야 마샬 러에게 배열을 마샬링하여 SAFEARRAY으로 지정해야한다고 알릴 수 있습니다.

[DllImport("hscnetapi.dll", EntryPoint = "rgetdat_str_vb")] 
public static extern short rgetdat_str(
    [MarshalAs(UnmanagedType.LPStr)] 
    string Server, 
    short num_points, 
    [MarshalAs(UnmanagedType.SafeArray, SafeArraySubType=VT_USERDEFINED)] 
    ref rgetdat_str_data_str[] getdat_str_data 
); 

C# 구조체에서 BSTR 멤버를 잘못 처리합니다. 그것은이어야한다

[MarshalAs(UnmanagedType.BStr)] 
public string value; 
+0

감사하지만 불행히도 여전히 작동하지 않습니다. 오류가 계속 발생합니다. 매개 변수가 잘못되었습니다. (HRESULT 예외 : 0x80070057 (E_INVALIDARG)) – alpinescrambler

+0

더 간단하게 해체하십시오. 'E_INVALIDARG'를 어떻게 진행할 것인가? 어디서 시작하니? 'int' 타입의 단일 값에서 작동하는 함수를 내보내는 새로운 DLL을 만드십시오. 그렇게 할 수 있는지 확인하십시오. 그런 다음'int'의'SAFEARRAY'로 이동하십시오. 그렇게 할 수 있는지 확인하십시오. 그런 다음 단일 'int'멤버가있는 구조체의 'SAFEARRAY'로 이동하십시오. 그렇게 할 수 있는지 확인하십시오. 그리고 계속해서 단계적으로 구축하십시오. 걸릴 때 디버거를 사용하여 도움을 받으십시오. –

+0

re : C# struct는 이미 BStr입니다 (내 질문의 마지막 부분 인 item # 1에서 지적했듯이). 내가 한 유일한 변경 사항은 제안한대로 VT_RECORD에서 VT_USERDEFINED까지입니다. 그것은 내가 여기 실제로 필요로하는 것처럼, 사용자 정의 요소 (구조체)가있는 SAFEARRAY의 포인터를 마샬링하는 방법입니다. 나는 당신이 제안한 것처럼, 더미 C DLL을 빌드하고 거기에서 갈 것이다. – alpinescrambler