在 C++ 项目和 C# 项目之间传递指针而不在 C# 项目上使用不安全

Passing Pointer between C++ Project and C# Project without using unsafe on C# project

陷入非常幼稚的问题。我有两个项目,一个在 C++ 中,另一个在 C# 中。想法是使用 C++ 项目作为一些 C 库的包装器。并在 C# 中执行实际逻辑。

传递Value类型很方便。但是对于参考类型,我很难 WITHOUT USING unsafe or DllImport属性。

C++

Cryptoki.Wrapper.h 文件

using namespace System;
#pragma comment(lib, "legacy_stdio_definitions.lib")

namespace CryptokiWrapper {    
    public ref class CryptokiInit
    {
    public:
        char* TESTString(char* test);           
        double TESTDouble(double test);         
    };    
}

Cryptoki.Wrapper.cpp 文件

#include "stdafx.h"
#include "Cryptoki.Wrapper.h"
using namespace std;
using namespace CryptokiWrapper;   

char* CryptokiInit::TESTString(char* test)
{
    char* r = test;     
    return r;
}

double CryptokiInit::TESTDouble(double test)
{
    unsigned long int r = test;     
    return r;
}

C#代码

using System;
using System.Runtime.InteropServices;

using CryptokiWrapper;

namespace CallCryptoki
{
    class Program
    {   
        //[MarshalAs(UnmanagedType.LPTStr)]
        //public String msg = "Hello World";   

        static void Main(string[] args)
        {
            CryptokiInit ob = new CryptokiInit();
            //This Works
            doubled d = ob.TESTDouble(99);

            //But having hard time accepting the char* reference 
            //or sending string as refrence without using unsafe
            // like
            string text = "Hello World!";
            string res = (*something*)ob.TESTString((*something*)text);
        }
    }
}

是否有任何类型的演员表(即某物)...... 无论如何我可以轻松地执行此操作。 (只有引用传输就足够了,然后我可以构建字符串或对象)

就像另一个函数一样,使用双精度作为参数和 return 类型。

虽然上面的例子只谈到了字符串,但我想理解为概念,这样我就可以为两个项目(即 C# 和 C++)之间的任何引用类型编写互操作

在此先感谢您的帮助!

首先,这不是普通的 C++,而是 C++/CLI - 主要为 managed/unmanaged 代码互操作性而设计。

您的 C++/CLI 函数可以像这样使用 .NET 的字符串类型:

System::String^ TESTString(System::String^ test);

^ 表示 托管引用 ,将其视为 *.

的托管等效项

现在,要在纯 C++ 中使用字符串数据,您有两个选择:

  • 编组它 - 参见 Overview of Marshaling in C++

    例如,如果您需要将其转换为 const char*,请执行以下操作:

    #include <msclr/marshal.h>
    
    msclr::interop::marshal_context ctx;
    auto testCStr = ctx.marshal_as<const char*>(test);
    // testCStr is freed when ctx goes out of scope
    

    这将复制字符串数据,因为内存表示需要从 2 字节 par 字符更改为单个字符。

  • 直接访问内存为const wchar_t*。您需要事先 pin 字符串,这样它就不会被 GC 移动。

    #include <vcclr.h>
    
    pin_ptr<const wchar_t> testCStr = PtrToStringChars(test);
    // testCStr behaves just like a const wchar_t*
    

    不要以这种方式修改字符串数据。

要将字符串发送回托管端,您可以使用 marshal_as<System::String^>(yourCString),或调用 gcnew System::String(yourCString);