- android - 多次调用 OnPrimaryClipChangedListener
- android - 无法更新 RecyclerView 中的 TextView 字段
- android.database.CursorIndexOutOfBoundsException : Index 0 requested, 光标大小为 0
- android - 使用 AppCompat 时,我们是否需要明确指定其 UI 组件(Spinner、EditText)颜色
我目前正在做一个期限非常短的项目,所以我没有太多时间了解所有内容。此外,我不是 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++ 公开了两个方法: StartRecognition()
启动操作以从麦克风获取一些数据,然后处理它们并存储结果。 GetResults()
返回先前存储的结果的实例。 WrapperCallback()
允许在 Result 能够进行处理时调用 C# 部分。 C# 部分,当调用回调时,将要求使用 GetResults()
方法获取结果。
我知道这个架构在这个演示中可能看起来真的不合适,但我不想解释整个项目来验证模型,请确保一切正确。
最后,问题出在 C# 回调调用 GetResults()
方法时。尝试从 C# 访问 resultsForCS
似乎是不可能的。
C++ 部分 - header
// NMSPRecognitionLib.h
#pragma once
#include <iostream>
using namespace std;
extern "C" __declspec(dllexport) char* GetResults();
extern "C" static void DoWork();
extern "C" __declspec(dllexport) void StartRecognition();
C++ 部分 - 来源
#include "stdafx.h"
#include "NMSPRecognitionLib.h"
static char * resultsForCS;
static SUCCESS ProcessResult(NMSPCONNECTION_OBJECTS *pNmspConnectionObjects, LH_OBJECT hResult)
{
[...]
char* szResult;
[...]
resultsForCS = szResult;
DoWork();
[...]
return Success;
error:
return Failure;
} /* End of ProcessResult */
extern "C" __declspec(dllexport) char* GetResults()
{
return resultsForCS;
}
extern "C"
{
typedef void (*callback_function)();
callback_function gCBF;
__declspec(dllexport) void WrapperCallback(callback_function callback) {
gCBF = callback;
}
static void DoWork() {
gCBF();
}
}
extern "C" __declspec(dllexport) void StartRecognition()
{
char* argv[] = { "path", "params" };
entryPoint(2, argv);
}
C# 部分
class Program
{
[DllImport("NMSPRecognitionLib.dll", EntryPoint = "GetResults")]
[return: MarshalAs(UnmanagedType.LPStr)]
public static extern string GetResultsExt();
public delegate void message_callback_delegate();
[DllImport("NMSPRecognitionLib.dll", EntryPoint = "WrapperCallback")]
public static extern void WrapperCallbackExt(message_callback_delegate callback);
[DllImport("NMSPRecognitionLib.dll", EntryPoint = "StartRecognition")]
public static extern void StartRecognitionExt();
static void Main(string[] args)
{
WrapperCallbackExt(
delegate()
{
Console.WriteLine(GetResultsExt());
}
);
StartRecognitionExt();
Console.WriteLine("\nPress any key to finish... ");
var nothing = Console.ReadLine();
}
}
我知道问题是因为我使用指针来存储结果(char *
),但我实际上不知道如何用另一种方式来做到这一点。 szResults
类型也是 char *
,我无法更改它!
最佳答案
是的,返回类型是问题所在。 pinvoke 编码器必须做一些事情来释放分配给字符串的内存。契约是调用者需要释放的内存分配必须从 COM 堆中分配。 native 代码中的 CoTaskMemAlloc(),也在 .NET 中公开为 Marshal.AllocCoTaskMem()。
这很少有好结果,大多数 native 代码使用 malloc() 或::operator new 进行分配,从 C 运行时库创建的堆中进行分配。错误的堆。因此 CoTaskMemFree() 调用不可避免地会失败。在 Windows XP 和更早版本中被静默忽略,在 Vista 和更高版本中是一个 kaboom。
您必须阻止 pinvoke 编码器尝试释放内存。通过将返回值声明为 IntPtr 来实现。并使用 Marshal.PtrToStringAnsi() 来恢复字符串。
您仍然有一个大问题,这种问题困扰着任何试图使用此功能的 native 代码。您仍然有一个需要释放的字符串缓冲区。您不能从 C# 执行此操作,您不能调用正确版本的 free() 或::operator delete。内存泄漏是不可避免的。您唯一可以希望的是 native 代码以某种方式处理它。如果没有,那么您必须使用 C++/CLI 与其进行互操作。额外的要求是需要使用相同的编译器重建 native 代码,以便它使用相同的共享 CRT。难以从 native 代码中正确使用的代码也很难调用。这是一个设计缺陷,始终允许调用者传递要填充的缓冲区,这样就不会出现谁拥有内存的问题。
关于c# - C++ DLL 和 C# 代码之间的共享内存,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/16715985/
我尝试理解[c代码 -> 汇编]代码 void node::Check( data & _data1, vector& _data2) { -> push ebp -> mov ebp,esp ->
我需要在当前表单(代码)的上下文中运行文本文件中的代码。其中一项要求是让代码创建新控件并将其添加到当前窗体。 例如,在Form1.cs中: using System.Windows.Forms; ..
我有此 C++ 代码并将其转换为 C# (.net Framework 4) 代码。有没有人给我一些关于 malloc、free 和 sprintf 方法的提示? int monate = ee; d
我的网络服务器代码有问题 #include #include #include #include #include #include #include int
给定以下 html 代码,将列表中的第三个元素(即“美丽”一词)以斜体显示的 CSS 代码是什么?当然,我可以给这个元素一个 id 或一个 class,但 html 代码必须保持不变。谢谢
关闭。这个问题不符合Stack Overflow guidelines .它目前不接受答案。 我们不允许提问寻求书籍、工具、软件库等的推荐。您可以编辑问题,以便用事实和引用来回答。 关闭 7 年前。
我试图制作一个宏来避免重复代码和注释。 我试过这个: #define GrowOnPage(any Page, any Component) Component.Width := Page.Surfa
我正在尝试将我的旧 C++ 代码“翻译”成头条新闻所暗示的 C# 代码。问题是我是 C# 中的新手,并不是所有的东西都像 C++ 中那样。在 C++ 中这些解决方案运行良好,但在 C# 中只是不能。我
在 Windows 10 上工作,R 语言的格式化程序似乎没有在 Visual Studio Code 中完成它的工作。我试过R support for Visual Studio Code和 R-T
我正在处理一些报告(计数),我必须获取不同参数的计数。非常简单但乏味。 一个参数的示例查询: qCountsEmployee = ( "select count(*) from %s wher
最近几天我尝试从 d00m 调试网络错误。我开始用尽想法/线索,我希望其他 SO 用户拥有可能有用的宝贵经验。我希望能够提供所有相关信息,但我个人无法控制服务器环境。 整个事情始于用户注意到我们应用程
我有一个 app.js 文件,其中包含如下 dojo amd 模式代码: require(["dojo/dom", ..], function(dom){ dom.byId('someId').i
我对“-gencode”语句中的“code=sm_X”选项有点困惑。 一个例子:NVCC 编译器选项有什么作用 -gencode arch=compute_13,code=sm_13 嵌入库中? 只有
我为我的表格使用 X-editable 框架。 但是我有一些问题。 $(document).ready(function() { $('.access').editable({
我一直在通过本教程学习 flask/python http://blog.miguelgrinberg.com/post/the-flask-mega-tutorial-part-i-hello-wo
我想将 Vim 和 EMACS 用于 CNC、G 代码和 M 代码。 Vim 或 EMACS 是否有任何语法或模式来处理这种类型的代码? 最佳答案 一些快速搜索使我找到了 this vim 和 thi
关闭。这个问题不符合Stack Overflow guidelines .它目前不接受答案。 想改进这个问题?更新问题,使其成为 on-topic对于堆栈溢出。 7年前关闭。 Improve this
这个问题在这里已经有了答案: Enabling markdown highlighting in Vim (5 个回答) 6年前关闭。 当我在 Vim 中编辑包含 Markdown 代码的 READM
我正在 Swift3 iOS 中开发视频应用程序。基本上我必须将视频 Assets 和音频与淡入淡出效果合并为一个并将其保存到 iPhone 画廊。为此,我使用以下方法: private func d
pipeline { agent any stages { stage('Build') { steps { e
我是一名优秀的程序员,十分优秀!