【问题标题】:Conversion from c char* to string/IntPtr c#从 c char* 转换为 string/IntPtr c#
【发布时间】:2014-03-19 00:00:02
【问题描述】:

我为一个 c 控制台应用程序创建了一个包装器,我在其中定义了一个结构来将输出传递给 c# windows 窗体。 该结构包含一个必须在 c# 代码中正确解释的 char* 变量。我使用了 IntPtr 类型,但没有得到想要的结果,只有一个我认为是可能的内存地址的数字。

C部分:

struct struct_name{
int a;
char* s;
}

extern __declspec(dllexport) struct_name compute_calc(int opt, char* file_1, char* file_2)

C#部分:

[DllImport("dll_name.dll", CallingConvention = CallingConvention.Cdecl)]
        public static extern struct_name compute_calc(int opt, String file1, String file2)

[StructLayout(LayoutKind.Sequential, Pack = 1, CharSet = CharSet.Auto)]    
public struct struct_name{
        Int32 a;
        IntPtr s;
        }

在应用程序中,我使用以下代码调用函数

struct_name result = levenshtein(1, filePath1, filePath2);

此时我的问题是使用 char*/IntPtr 来提取结构中包含的字符串。我尝试按照How can I convert an unmanaged IntPtr type to a c# string? 中的建议使用编组操作,但我的结果只是一个数字。 有没有其他方法可以将 IntPtr 转换为 c 代码中使用的正确字符串?

edit:结构中的整数被正确传递。问题只在 char*

编辑2:

struct_name result;

{..some code...}--> output int N, char* s0


result.s = (char*)malloc( sizeof(char)*n);

result.a=N;
result.s=_strdup(s0)

return result;

这是建议中要求的 C 部分代码。

【问题讨论】:

  • 元帅.PtrToStringAnsi
  • 我不确定这是否是原因(自​​从我进行互操作编码以来已经有一段时间了),但为什么 char* 参数您传递为 string,而 @987654328 @你声明为IntPtr的结构成员?您是否尝试过将 struct 的成员声明为 string
  • 还将CharSet = CharSet.Ansi 添加到compute_calc PInvoke 声明。
  • 如果我尝试在结构中使用字符串类型,我有一个 System.Runtime.InteropServices.MarshalDirectiveException
  • 本地代码使用什么编译器?

标签: c# c pinvoke


【解决方案1】:

Marshal.PtrToStringAnsi() 是将IntPtr 转换为字符串所需的。 IntPtr 持有 char*Marshal.PtrToStringAnsi() 是你的人。

但是,您已经尝试过,但没有成功。所以我怀疑你的问题更根本。也许您在互操作边界的两侧处理大型结构的方式存在二进制不匹配。这是互操作的一部分,其中不同的工具表现不同。应始终使用 out 参数返回结构。把原生代码改成这样:

__declspec(dllexport) int compute_calc(int opt, const char* file_1, 
    const char* file_2, struct_name* result)

而托管方是:

[StructLayout(LayoutKind.Sequential)]    
public struct struct_name{
    int a;
    IntPtr s;
}

[DllImport("dll_name.dll", CallingConvention = CallingConvention.Cdecl)]
public static extern int compute_calc(int opt, string file1, string file2,
    out struct_name result);

请注意,我还从您的结构声明中删除了Pack = 1。除非 C 代码使用#pragma pack,而且它不应该这样做,否则这将导致 64 位代码下的不匹配。

【讨论】:

  • 我尝试了这个解决方案,我得到了一个 FatalExecutionEngineError,你有没有得到过这样的东西?
  • 是的,我已经看到了。当然,我无法判断您的代码是否正确。
【解决方案2】:

要将IntPtr 转换为String,请使用Marshal.PtrToStringAnsi 方法

struct_name s = compute_calc(...);
string str = Marshal.PtrToStringAnsi(s.s);

请注意,如果compute_calc 函数分配了内存,它可能也需要在托管代码中释放。不能肯定,因为这取决于compute_calc的实现细节

【讨论】:

  • 我尝试了建议的解决方案,但输出字符串是一系列难以理解的字符,例如“ìììììýýýýýýý=e>>Y*”,因此我尝试使用 PtrStringToAuto 方法,但在这种情况下输出是一系列的???
  • @user2893821 该代码应该可以正常工作。 compute_calc 方法是如何创建字符串的?可以出示一下代码吗?
  • struct_name 结果; {..some code...}--> output int N, char* s0 result.s = (char*)malloc( sizeof(char)*n);结果.a=N; result.s=_strdup(s0) 返回结果;在C部分的代码是这样的,对于int值一切都很好,但是对于字符串我有描述的问题
  • @user2893821 _strdup 调用前 s0 的内容是什么?
  • @user2893821 编译项目时使用什么调用约定?
猜你喜欢
  • 2015-08-06
  • 1970-01-01
  • 2012-12-11
  • 2014-11-19
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多