Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/262.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

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/133.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# C++ DLL与C代码间的共享内存_C#_C++ - Fatal编程技术网

C# C++ DLL与C代码间的共享内存

C# C++ DLL与C代码间的共享内存,c#,c++,C#,C++,我目前正在做一个截止期很短的项目,所以我没有太多时间去了解所有的事情。另外,我不是C++开发和内存管理方面的专家。 >,我想做的是用C和C++代码创建一个DLL。然后,我想用C代码调用这个DLL。目前,C++与C之间的通信是可以的。当我试图将一个字符串从DLL传输到C代码时,问题出现了。错误是这样的: System.AccessViolationException: Attempted to read or write protected memory. This is often an in

我目前正在做一个截止期很短的项目,所以我没有太多时间去了解所有的事情。另外,我不是C++开发和内存管理方面的专家。 <> >,我想做的是用C和C++代码创建一个DLL。然后,我想用C代码调用这个DLL。目前,C++与C之间的通信是可以的。当我试图将一个字符串从DLL传输到C代码时,问题出现了。错误是这样的:

System.AccessViolationException: Attempted to read or write protected memory. This is often an indication that other memory is corrupt.
   at Microsoft.Win32.Win32Native.CoTaskMemFree(IntPtr ptr)
   at System.StubHelpers.CSTRMarshaler.ClearNative(IntPtr pNative)
   at NMSPRecognitionWrapper.Program.GetResultsExt()
   at NMSPRecognitionWrapper.Program.<Main>b__0() in <my dir>\Program.cs:line 54
   at NMSPRecognitionWrapper.Program.StartRecognitionExt()
   at NMSPRecognitionWrapper.Program.Main(String[] args) in <my dir>\Program.cs:line 60
C++部分源代码

C部分


我知道问题的出现是因为我使用了一个指针来存储结果char*,但实际上我不知道如何用另一种方式来实现这一点。szResults类型也是char*,我无法更改

>我发现,在C++本地代码周围编写包装器通常更容易。C++/CLI类可以直接调用和使用本机C++,但可以从C和.NET语言访问。在我的经验中,使用DLIMPORT作为您的操作会导致调试困难并发现错误。

< P>我发现在C++本地代码中编写包装器通常更容易。C++/CLI类可以直接调用和使用本机C++,但可以从C和.NET语言访问。根据我的经验,使用DLLImport会导致难以调试和查找错误。

查看:

at Microsoft.Win32.Win32Native.CoTaskMemFree(IntPtr ptr)
at System.StubHelpers.CSTRMarshaler.ClearNative(IntPtr pNative)
at NMSPRecognitionWrapper.Program.GetResultsExt()
我可以看到您的回调被调用,但运行时试图释放一些内存。我认为它假定您的指针指向com内存。尝试自己转换字符串,这很容易

[DllImport("NMSPRecognitionLib.dll", EntryPoint = "GetResults")]
public static extern IntPtr GetResultsExt();

[...]

string result = Marshal.PtrToStringAnsi(GetResultsExt())
没有100%的保证,但值得一试。

查看:

at Microsoft.Win32.Win32Native.CoTaskMemFree(IntPtr ptr)
at System.StubHelpers.CSTRMarshaler.ClearNative(IntPtr pNative)
at NMSPRecognitionWrapper.Program.GetResultsExt()
我可以看到您的回调被调用,但运行时试图释放一些内存。我认为它假定您的指针指向com内存。尝试自己转换字符串,这很容易

[DllImport("NMSPRecognitionLib.dll", EntryPoint = "GetResults")]
public static extern IntPtr GetResultsExt();

[...]

string result = Marshal.PtrToStringAnsi(GetResultsExt())

没有100%的保证,但值得一试。

是的,退货类型是问题所在。pinvoke封送拆收器必须做一些事情来释放为字符串分配的内存。约定是需要调用方释放的内存分配必须从COM堆中分配。本机代码中的CoTaskMemAlloc,在.NET中也以Marshal.allocTaskMem的形式公开

这很少有好的结果,大多数本机代码使用malloc或::operator new进行分配,从C运行时库创建的堆进行分配。错误的堆。因此,CoTaskMemFree调用将不可避免地失败。在Windows XP及更早版本中,Vista及更高版本上的kaboom被默默忽略

您必须阻止pinvoke marshaller尝试释放内存。通过将返回值声明为IntPtr来实现。并使用Marshal.PtrToStringAnsi恢复字符串


您仍然有一个大问题,这种问题困扰着任何试图使用此函数的本机代码。您仍然有一个需要释放的字符串缓冲区。您无法从C中执行此操作,您无法pinvoke free或::operator delete的正确版本。内存泄漏是不可避免的。您唯一希望的是本机代码以某种方式处理它。如果没有,则必须使用C++/CLI与它进行互操作。另外还需要使用相同的编译器重新生成本机代码,以便使用相同的共享CRT。从本机代码中很难正确使用的代码也很难使用pinvoke。这是一个设计缺陷,总是允许调用方传递一个要填充的缓冲区,这样就不会有谁拥有内存的问题。

是的,返回类型就是问题所在。pinvoke封送拆收器必须做一些事情来释放为字符串分配的内存。约定是需要调用方释放的内存分配必须从COM堆中分配。本机代码中的CoTaskMemAlloc,在.NET中也以Marshal.allocTaskMem的形式公开

这很少有好的结果,大多数本机代码使用malloc或::operator new进行分配,从C运行时库创建的堆进行分配。错误的堆。因此,CoTaskMemFree调用将不可避免地失败。在Windows XP及更早版本中,Vista及更高版本上的kaboom被默默忽略

您必须阻止pinvoke marshaller尝试释放内存。通过将返回值声明为IntPtr来实现。并使用Marshal.PtrToStringAnsi恢复字符串

您仍然有一个大问题,这种问题困扰着任何试图使用此函数的本机代码。您仍然有一个需要释放的字符串缓冲区。您无法从C中执行此操作,您无法pinvoke free或::operator delete的正确版本。内存泄漏是不可避免的。您唯一希望的是本机代码以某种方式处理它。如果没有,则必须使用C++/CLI与它进行互操作。另外还需要使用相同的编译器重新生成本机代码,以便使用相同的共享CRT。从本机代码中很难正确使用的代码也很难使用pinvoke。这是一个设计缺陷,永远
允许调用者传递一个要填充的缓冲区,这样就永远不会有谁拥有内存的问题。

您的回答非常清晰,工作非常完美!谢谢你。你的回答非常清楚,非常有效!谢谢你。我不是选民,但我想这是因为你的回答无助于我解决问题;我投了反对票,因为你总是可以用另一种语言实现它,但这并不能回答这个问题。这是一个替代方案,但不是解决OP的即时问题。他已经使用C++和C,所以它不是另一种语言。它提供了一个更简单、更容易出错的方法来解决这个和将来类似的问题。嗯,不,包裹C++代码不是很简单。这是不可能的。只有C代码,或者C++代码,看起来像C,不使用类,很容易包装。使用C++/CLI是一个很好的解决方案。@Ramhound YMMV-我使用C++/CLI包装比直接使用pinvoke有更好的体验。特别是在发现问题和错误的时候,我不是一个悲观的人,但我认为这是因为你的回答不能帮助我解决问题;我投了反对票,因为你总是可以用另一种语言实现它,但这并不能回答这个问题。这是一个替代方案,但不是解决OP的即时问题。他已经使用C++和C,所以它不是另一种语言。它提供了一个更简单、更容易出错的方法来解决这个和将来类似的问题。嗯,不,包裹C++代码不是很简单。这是不可能的。只有C代码,或者C++代码,看起来像C,不使用类,很容易包装。使用C++/CLI是一个很好的解决方案。@Ramhound YMMV-我使用C++/CLI包装比直接使用pinvoke有更好的体验。特别是在发现问题和错误时。我注意到的第一件事是你的呼叫约定不匹配。C的默认调用约定是StdCall,而默认调用约定是Cdecl。您需要自己弄清楚如何解析char指针,因为正确的解析方法已经有了很好的文档。这个问题值得你做更多的研究,CallingConvention可能是你唯一的问题。您应该简单地使用对char[]的引用,而不是字符串数组。非常感谢您的精确性!我会记住这个想法。事实上,有了公认的答案,我的代码现在可以工作了。我知道这不是最好的解决方案,但这是一个有效的解决方案。。。我没有太多时间,所以我将暂时保留此解决方案,稍后再讨论您的想法。无论如何,谢谢你提供的信息。我注意到的第一件事是你的通话习惯不匹配。C的默认调用约定是StdCall,而默认调用约定是Cdecl。您需要自己弄清楚如何解析char指针,因为正确的解析方法已经有了很好的文档。这个问题值得你做更多的研究,CallingConvention可能是你唯一的问题。您应该简单地使用对char[]的引用,而不是字符串数组。非常感谢您的精确性!我会记住这个想法。事实上,有了公认的答案,我的代码现在可以工作了。我知道这不是最好的解决方案,但这是一个有效的解决方案。。。我没有太多时间,所以我将暂时保留此解决方案,稍后再讨论您的想法。无论如何,谢谢你提供的信息。
[DllImport("NMSPRecognitionLib.dll", EntryPoint = "GetResults")]
public static extern IntPtr GetResultsExt();

[...]

string result = Marshal.PtrToStringAnsi(GetResultsExt())