Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/299.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
将带有char*的结构编组为C#_C#_Struct_Pinvoke - Fatal编程技术网

将带有char*的结构编组为C#

将带有char*的结构编组为C#,c#,struct,pinvoke,C#,Struct,Pinvoke,我在C程序中使用了以下结构 typedef enum { ndberror_st_success = 0, ndberror_st_temporary = 1, ndberror_st_permanent = 2, ndberror_st_unknown = 3 } ndberror_status_enum; typedef enum { ndberror_cl_none = 0, ndberror_cl_application = 1, ndberror_cl_

我在C程序中使用了以下结构

typedef enum
{
  ndberror_st_success = 0,
  ndberror_st_temporary = 1,
  ndberror_st_permanent = 2,
  ndberror_st_unknown = 3
} ndberror_status_enum;

typedef enum
{
 ndberror_cl_none = 0,  
 ndberror_cl_application = 1,  
 ndberror_cl_no_data_found = 2,
 ndberror_cl_constraint_violation = 3,
 ndberror_cl_schema_error = 4,
 ndberror_cl_user_defined = 5,
 ndberror_cl_insufficient_space = 6,
 ndberror_cl_temporary_resource = 7,
 ndberror_cl_node_recovery = 8,
 ndberror_cl_overload = 9,
 ndberror_cl_timeout_expired = 10,
 ndberror_cl_unknown_result = 11,
 ndberror_cl_internal_error = 12,
 ndberror_cl_function_not_implemented = 13,
 ndberror_cl_unknown_error_code = 14,
 ndberror_cl_node_shutdown = 15,
 ndberror_cl_configuration = 16,
 ndberror_cl_schema_object_already_exists = 17,
 ndberror_cl_internal_temporary = 18
} ndberror_classification_enum;


typedef struct {
  ndberror_status_enum status;
  ndberror_classification_enum classification;
  int code;
  int mysql_code;
  const char * message;
  char * details;
} ndberror_struct;
我需要在c#program中封送它,c#side声明是:

    public enum ndberror_status
    {
        ndberror_st_success = 0,
        ndberror_st_temporary = 1,
        ndberror_st_permanent = 2,
        ndberror_st_unknown = 3,
    }

    public enum ndberror_classification
    {
        ndberror_cl_none = 0,
        ndberror_cl_application = 1,
        ndberror_cl_no_data_found = 2,
        ndberror_cl_constraint_violation = 3,
        ndberror_cl_schema_error = 4,
        ndberror_cl_user_defined = 5,
        ndberror_cl_insufficient_space = 6,
        ndberror_cl_temporary_resource = 7,
        ndberror_cl_node_recovery = 8,
        ndberror_cl_overload = 9,
        ndberror_cl_timeout_expired = 10,
        ndberror_cl_unknown_result = 11,
        ndberror_cl_internal_error = 12,
        ndberror_cl_function_not_implemented = 13,
        ndberror_cl_unknown_error_code = 14,
        ndberror_cl_node_shutdown = 15,
        ndberror_cl_configuration = 16,
        ndberror_cl_schema_object_already_exists = 17,
        ndberror_cl_internal_temporary = 18,
    }
[System.Runtime.InteropServices.StructLayoutAttribute(System.Runtime.InteropServices.LayoutKind.Sequential)]
    public struct ndberror_struct
    {      
        public ndberror_status status;
        public ndberror_classification classification;
        public int code;
        public int mysql_code;
       [System.Runtime.InteropServices.MarshalAsAttribute(System.Runtime.InteropServices.UnmanagedType.LPStr)]
        public string message;
        [System.Runtime.InteropServices.MarshalAsAttribute(System.Runtime.InteropServices.UnmanagedType.LPStr)]
        public string details;
    }
要调用的方法的C端签名为:

const ndberror_struct __stdcall Ndb_getNdbError(void* obj);
而C侧是:

        [System.Runtime.InteropServices.DllImportAttribute("Ndb_CWrapper.dll", EntryPoint = "Ndb_getNdbError", CallingConvention = System.Runtime.InteropServices.CallingConvention.StdCall,CharSet = CharSet.Ansi)]
        private static extern ndberror_struct Ndb_getNdbError(System.IntPtr obj);
当我尝试从托管代码调用该方法时,会引发MarshalDirectiveException。 我认为问题出在字符串编组的某个地方,但我无法解决这个问题。 本地库是为X64系统的多字节字符集代码(VisualStudio C++ 2012)编写的/P> 另一种方法是在本机代码中执行一些奇怪的操作,我将
NdbError
(在另一个标题中定义)转换为
NdbError\u struct
,代码如下:

Ndb* tmp=(Ndb*)obj;
ndberror_struct tmpRes=(ndberror_struct)tmp->getNdbError();
tmp->getNdbError()
返回的
NdbStruct
重载强制转换操作符(我想),这是声明:

operator ndberror_struct() const {
    ndberror_struct ndberror;
    ndberror.status = (ndberror_status_enum) status;
    ndberror.classification = (ndberror_classification_enum) classification;
    ndberror.code = code;
    ndberror.mysql_code = mysql_code;
    ndberror.message = message;
    ndberror.details = details;
    return ndberror;
}
任何帮助都将不胜感激

编辑: 我试图通过以下方式更改该方法的签名: C方:

C侧:

本机方法返回
&tmpRes
,在托管代码中,我手动封送了结构调用

var tmp=Ndb_getNdbError(raw);
var f = (ndberror_struct)Marshal.PtrToStructure(tmp, typeof(ndberror_struct));

封送处理程序不会将那些
char*
字段从本机代码封送到托管代码。你得自己动手

一种方法是更改C#struct声明,如下所示:

public struct ndberror_struct
{      
    public ndberror_status status;
    public ndberror_classification classification;
    public int code;
    public int mysql_code;
    public IntPtr message;
    public IntPtr details;
}
保持p/invoke声明的原样:

[DllImport("Ndb_CWrapper.dll")]
private static extern ndberror_struct Ndb_getNdbError(IntPtr obj);

您现在可以调用该函数了。要将两个
IntPtr
字段转换为字符串,请调用
marshall.PtrToStringAnsi

使用
MarshalDirectiveException
可以得到什么消息(文本)?消息说:方法的类型签名与PInvoke不兼容。我想我会按照您的建议执行,通过这种方式,我不需要出于兴趣而更改本机代码的签名,谁来处理字符串?到目前为止,我无法给出正确的答案,因为我真的不知道。我是在Oracle(MySQL)提供的NDB API创建包装器的早期阶段:该库是用C++编写的,我需要从C++到C,再从C到C,再做一个双包装。因此,对于这个字符串,当然还有其他一些需要处理的问题,如果目标代码是C++,那么单c++/CLI包装器听起来是最棒的,我需要2个包装器,一个纯C代码/编译器的包装器,一个C++软件包,这样我就可以一石一鸟2……我希望
public struct ndberror_struct
{      
    public ndberror_status status;
    public ndberror_classification classification;
    public int code;
    public int mysql_code;
    public IntPtr message;
    public IntPtr details;
}
[DllImport("Ndb_CWrapper.dll")]
private static extern ndberror_struct Ndb_getNdbError(IntPtr obj);