如何将指针函数从C ++导出到C#? [英] How to export pointer function from C++ to C#?

查看:346
本文介绍了如何将指针函数从C ++导出到C#?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我使用DllImport从C#调用C ++的函数。

I'm using DllImport to call the functions of C++ from C#.

#if defined(__cplusplus)
extern "C" {
#endif

__declspec(dllexport) int __stdcall ABC(int i);

__declspec(dllexport) char* __stdcall C(int i);

#if defined(__cplusplus)
}
#endif

int __stdcall ABC(int i)

{
    return i;
}

char* __stdcall C(int i)
{
    char* n = new char[i];
    memset(n, 9, i);
    return n;
}

C#中的代码为:

using System.Runtime.InteropServices;
using System;

namespace DepartmentStore
{
    class Exercise
    {
        [DllImport("library.dll")]
        public static extern int ABC(int i);

        [DllImport("library.dll")]
        public static extern char* C(int i);

        static int Main()
        {
            int k = ABC(10);
            byte[] b = C(1024);

            return 0;
        }
    }
}

函数 ABC(int i)可以,但是 C(int i)函数在构建时产生了以下错误:

The function ABC(int i) is OK, but the function C(int i) yielded the following error when building:


指针和固定大小的缓冲区只能在不安全的上下文中使用

"Pointers and fixed size buffers may only be used in an unsafe context"

我想我不知道如何导出函数的指针返回。

I guess that I didn't understand how to export a pointer return of functions.

May有人可以告诉我正确的方式C#返回类型作为指针?

May Someone please tell me the correct way C# invokes functions with the return type as a pointer?

推荐答案

P / Invoke后来不知道如何编组C风格的数组从非托管到被管理侧;与 不同SAFEARRAY ,没有嵌入在C风格数组中的信息,P / Invoke以后可以使用它来确定应该复制多少字节。

The P/Invoke later doesn't know how to marshal C-style arrays from the unmanaged to the managed side; unlike SAFEARRAY, there is no information embedded in C-style arrays that the P/Invoke later can use to determine how many bytes should be copied.

因此,您需要声明您的 C 函数返回 IntPtr ,然后调用 Marshal.PtrToStrAnsi 方法将指针转换为字符串如下:

Because of this, you'll want to declare your C function to return an IntPtr and then call the Marshal.PtrToStrAnsi method to convert the pointer to a string on the managed side like so:

[DllImport("library.dll")]
public static extern IntPtr C(int i);

static int Main()
{
    int k = ABC(10);
    IntPtr b = C(1024);

    string s = Marshal.PtrToStrAnsi(b);

    // Problem: How do you release what is pointed to
    // by IntPtr?

    return 0;
}

此外,您必须传递 IntPtr 回到非托管方,以释放您分配的内存 new ;

Additionally, you'll have to pass the IntPtr back to the unmanaged side to deallocate the memory that you allocated with new; if you don't you'll have a memory leak.

一个更容易的选择是为C ++中的非托管库创建一个托管包装,它暴露托管函数,调用并执行转换为 String ^ (使用 marshal_as )如下:

An easier option is to create a managed wrapper for your unmanaged library in C++ that exposes managed functions which make the calls and perform the conversion to a String^ (using marshal_as) like so:

// compile with: /clr
#include <stdlib.h>
#include <string.h>
#include <memory>
#include <msclr\marshal.h>

using namespace System;
using namespace msclr::interop;

String^ WrappedC(int i) {
   // Make the call to the native function.
   // Let's store in an auto_ptr to handle
   // cleanup when the wrapper is exited.
   auto_ptr<char> c(C(i));

   // Convert to a managed string and
   // return.
   return marshal_as<String^>(c.get());
}

如果你不想组织一个 string ,然后替换为一个 byte 数组,然后我仍然推荐wrapper方法(虽然在这种情况下,一些特定的知识为了创建要返回的管理数组):

If you didn't want to marshal back a string, and instead marshal back a byte array, then I'd still recommend the wrapper approach (although in this case, it requires you to have some specific knowledge in order to create the managed array to return):

// compile with: /clr
#include <stdlib.h>
#include <memory>

using namespace System;
using namespace msclr::interop;

String^ WrappedC(int i) {
   // Make the call to the native function.
   // Let's store in an auto_ptr to handle
   // cleanup when the wrapper is exited.
   auto_ptr<char> c(C(i));

   // Copy the pointer.
   char* p = c.get();

   // The byte array to return.
   // i is the size of the array, as per the call
   // to C.
   array<byte>^ a = gcnew array<byte>(i); 

   // Populate.
   for (int index = 0; index < i; ++index) 
       a[index] = (byte) *p++; 

   // Return the array.
   return a;
}

这些是比托管代码完全处理更好的选择,不必担心在管理和非管理之间连续编组以处理在非托管空间中分配的内存的指针。

These are better options than handling it in managed code completely, as you don't have to worry about continuously marshalling between managed and unmanaged to handle pointers to memory allocated in the unmanaged space.

这篇关于如何将指针函数从C ++导出到C#?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆