C#调用C DLL,传递char *作为参数不正确

我在VS2012中用C#语言调用DLL(C写)。 mylib.dll是我要在C#中调用的本机dll,而mylib.dll也会调用另一个mylib_another.dll。

C函数声明为:

extern DECLSPEC_DLL BOOLEAN_TYPE SetConnection(char *dev, char *addr); 

在My C#文件中,我将其声明为:

 [DllImport("C:\\mylib.dll", EntryPoint = "SetConnection", CharSet = CharSet.Auto)] public static unsafe extern int SetConnection(StringBuilder dev, StringBuilder addr); 

当我在代码中调用它时,我发现字符串只传递了一个字符,当我将dev作为“USB”传递时,本机DLL实际上只获得了一个“U”。

如果我将声明改为:

 [DllImport("C:\\mylib.dll", EntryPoint = "SetConnection", CharSet = CharSet.Ansi)] public static unsafe extern int SetConnection(StringBuilder dev, StringBuilder addr); 

然后它将引发System.AccessViolationExceptionexception:

 System.Reflection.TargetInvocationException was unhandled HResult=-2146232828 Message=Exception has been thrown by the target of an invocation. Source=mscorlib StackTrace: at System.RuntimeMethodHandle.InvokeMethod(Object target, Object[] arguments, Signature sig, Boolean constructor) at System.Reflection.RuntimeMethodInfo.UnsafeInvokeInternal(Object obj, Object[] parameters, Object[] arguments) at System.Reflection.RuntimeMethodInfo.Invoke(Object obj, BindingFlags invokeAttr, Binder binder, Object[] parameters, CultureInfo culture) at System.RuntimeType.InvokeMember(String name, BindingFlags bindingFlags, Binder binder, Object target, Object[] providedArgs, ParameterModifier[] modifiers, CultureInfo culture, String[] namedParams) at QC.QTMDotNetKernel.DotNetKernel.RunDotNetTest(Object stateObject) at System.Threading.QueueUserWorkItemCallback.WaitCallback_Context(Object state) at System.Threading.ExecutionContext.RunInternal(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx) at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx) at System.Threading.QueueUserWorkItemCallback.System.Threading.IThreadPoolWorkItem.ExecuteWorkItem() at System.Threading.ThreadPoolWorkQueue.Dispatch() at System.Threading._ThreadPoolWaitCallback.PerformWaitCallback() InnerException: System.AccessViolationException HResult=-2147467261 Message=Attempted to read or write protected memory. This is often an indication that other memory is corrupt. 

关于那个的任何想法?

已解决如下(答案是针对第一个问题,对于第二个问题,那是因为mylib.dll调用另一个本机dll并且系统没有找到它)。

类似的问题在这里:

当您只收到一个这样的字符时,通常意味着您将Unicode(UTF16)字符串传递给期望8位格式的C / C ++函数,如ASCII,UTF8或ANSI。

对于ASCII / ANSI范围内的字符,16位Unicode格式最终将其两个字节的一个字节设置为零,并且因为C / C ++程序将零字节视为字符串结尾字符,所以它会截断字符串。

尝试使用ANSI来查看它是否有帮助很容易; 更改

 CharSet = CharSet.Auto 

 CharSet = CharSet.Ansi 

你的p / invoke有一些问题:

  1. 调用约定看起来像是cdecl 。 它没有在本机代码中指定,最可能的默认值是cdecl
  2. 您正在传递StringBuilder ,它用于out参数。 请注意,我假设这两个参数都是输入参数。
  3. 字符集错误。 本机代码接收8位编码文本。
  4. 您不需要使用unsafe

更正的声明是:

 [DllImport(@"C:\mylib.dll", CallingConvention=CallingConvention.Cdecl)] public static extern int SetConnection(string dev, string addr); 

您可以省略字符集的规范,因为ANSI是默认值。 当然,如果你喜欢明确的话,指定CharSet=CharSet.Ansi也没什么坏处。 如果它与您声明的函数名称相同,则无需指定EntryPoint