Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/308.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
从托管C#代码调用带有SAFEARRAY**ppsa参数的非托管C方法_C#_Vb6_Pinvoke_Marshalling_Dllimport - Fatal编程技术网

从托管C#代码调用带有SAFEARRAY**ppsa参数的非托管C方法

从托管C#代码调用带有SAFEARRAY**ppsa参数的非托管C方法,c#,vb6,pinvoke,marshalling,dllimport,C#,Vb6,Pinvoke,Marshalling,Dllimport,我一直在努力研究如何将这段VB6代码迁移到C。它包括调用DLL中的函数,传递结构数组等 因此,在VB6中,“struct”声明如下: 'Define structure for RGETDAT_STR procedure call Type rgetdat_str_data_str type As Integer 'data type (set internally) file As Integer

我一直在努力研究如何将这段VB6代码迁移到C。它包括调用DLL中的函数,传递结构数组等

因此,在VB6中,“struct”声明如下:

'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 
EXTERN_C short __loadds CALLBACK rgetdat_str_vb_ansi
                _DECLARE((char *szHostname, short cRequests, SAFEARRAY **ppsa)); 
/* 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; 
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;
一个使用此“struct”的函数的方法声明为:

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
因此,我尝试将这两段代码转换为C。我已经尝试了这么多的变化,但我会在这里张贴我的最新一个。其思想是通过调用函数

C#struct(到目前为止):

以及函数导入(到目前为止):

到目前为止,在我关于使用参数编组属性的各种实验中,什么都不起作用

我设法找到了这个DLL的C头文件,声明如下:

'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 
EXTERN_C short __loadds CALLBACK rgetdat_str_vb_ansi
                _DECLARE((char *szHostname, short cRequests, SAFEARRAY **ppsa)); 
/* 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; 
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;
C世界中的“struct”声明如下:

'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 
EXTERN_C short __loadds CALLBACK rgetdat_str_vb_ansi
                _DECLARE((char *szHostname, short cRequests, SAFEARRAY **ppsa)); 
/* 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; 
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;
在我的挫折中,我试图用itypelibviewer工具打开这个DLL。我很惊讶DLL文件可以打开,即使我不能在我的项目中添加此DLL作为引用。总之,我在观众中观察到了一些事情

该函数具有以下签名:

[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); 
“结构”是这样的:

'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 
EXTERN_C short __loadds CALLBACK rgetdat_str_vb_ansi
                _DECLARE((char *szHostname, short cRequests, SAFEARRAY **ppsa)); 
/* 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; 
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;
基于这些观察,我研究了C#struct的编组属性,例如

1.)将结构的属性更改为[Marshallas(UnmanagedType.BStr)]

2.)将函数的getdat_str_data参数属性更改为MarshalAs(UnmanagedType.SafeArray,SafeArraySubType=VarEnum.VT_记录)

但仍然没有任何效果

这里有一篇博客/文章讨论了一个类似的话题:但我不能只想着它


与使用此DLL函数调用的C#(.Net)相比,VB6似乎可以非常简单地实现这一点。关于如何在C#(.Net)中DLLImport声明此函数,有任何提示或想法吗?

您需要将
MarshalAs
UnmanagedType.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#struct中,错误地处理了
BSTR
成员。应该是

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

谢谢,但不幸的是它仍然不起作用。我仍然得到错误:参数不正确。(HRESULT的例外:0x80070057(E_INVALIDARG))将其分解为更简单的内容。问问自己,如果有
E_INVALIDARG
,你将如何继续?你从哪里开始?创建一个新的DLL,该DLL导出一个函数,该函数对类型为
int
的单个值进行操作。确保你能做到。然后转到
int
SAFEARRAY
。确保你能做到。然后移动到具有单个
int
成员的结构的
SAFEARRAY
。确保你能做到。等等,一步一步地建立起来。当您陷入困境时,请使用调试器提供帮助。re:C#struct已经是一个BStr(正如我问题的最后部分第#1项所指出的)。我所做的唯一更改是从VT_RECORD更改为您建议的VT_USERDEFINED。看起来我在这里真正需要的是,如何处理一个包含用户定义元素(struct)的SAFEARRAY的指针。我将按照您的建议,构建一个虚拟的C DLL并从那里开始。