如何将字符串参数从C ++传递到托管的C#DLL [英] How to pass a string argument from C++ to a managed C# DLL

查看:128
本文介绍了如何将字符串参数从C ++传递到托管的C#DLL的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在编写一个C ++程序,该程序需要调用用C#编写的DLL。我按照以下说明创建了C#DLL并从C ++链接到它。

I'm writing a C++ program that needs to call a DLL written in C#. I followed these instructions for creating my C# DLL and linking in to it from my C++.

https://support.microsoft.com/en-us/kb/828736

我有一个将字符串作为参数的C#函数。如何将C ++中的字符串传递到C#中?

I have a C# function that takes a string as an argument. How do I pass a string out of C++ into my C#?

推荐答案

我找不到这个问题的简明答案,因此,我将解决方案放在这里,希望它对将来的人有所帮助。

I couldn't find a concise answer to this question, so I'm putting my solution here in the hope that it helps someone in the future.

TL; DR:您需要使用BSTR在C#和C ++之间来回传递字符串。

TL;DR: You need to use a BSTR to pass strings back and forth between C# and C++.

这是我的操作方式。

这是我的C#代码的示例。注意事项:

Here is a sample of my C# code. A few things to note:


  • 您想从C ++调用的任何函数都必须放在界面部分。

  • 注意我在接口和函数定义中声明 stringToPrint 参数的方式。在 string 前面加上 [MarshalAs(UnmanagedType.BStr)] 至关重要。

  • 一旦在函数中,您就可以使用 string 参数,就好像它是普通字符串一样。您无需像在C ++中那样在C#中将 from BSTR 转换。

  • Any function you want to be able to call from the C++ Must be delcared in the interface section.
  • Notice the way I declare the stringToPrint argument both in the interface and the function definition. Prefacing string with [MarshalAs(UnmanagedType.BStr)] is crucial.
  • Once in the function you can use the string argument as if it were a normal string. You don't need to convert from BSTR in C# the way you do in C++. More on that below.
//Reference where I got all this:
//https://support.microsoft.com/en-us/kb/828736

// Class1.cs
// A simple managed DLL that contains a method to add two numbers.
using System;
using System.Runtime.InteropServices;


namespace ManagedDLL
{
    // Interface declaration.
    public interface ICalculator
    {
        //Test functions
        int Add(int Number1, int Number2);
        int ReturnAge();
        string StringTest();
        void PrintAString([MarshalAs(UnmanagedType.BStr)] string stringToPrint);
    };

    // Interface implementation.
    public class ManagedClass : ICalculator
    {
        //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
        //Test functions
        public int Add(int Number1, int Number2)
        {
            return Number1 + Number2;
        }

        public int ReturnAge()
        {
            return 35;
        }

        public string StringTest()
        {
            return "Can you hear me now?";
        }

        public void PrintAString([MarshalAs(UnmanagedType.BStr)] string stringToPrint)
        {
            Console.WriteLine("Trying to print a BSTR in C#");

            Console.WriteLine(stringToPrint);
            Console.WriteLine("Done printing");
        }
    }
}



C ++代码



C ++中的一些注意事项:

C++ Code

A few things to notice in the C++:


  • #标头中的import 调用。在这里,您可以告诉C ++如何查找C#库。我在问题中链接到的教程中提到了这一点。

  • 如果您的C#函数之一具有返回值,则该值不会作为返回值传递给C ++。相反,在进行调用时,您需要包含指向C ++变量的指针作为参数。有关此示例,请参见 AddTest()函数。

  • 字符串必须以的形式传递给C#。 BSTR 类型变量。将 std :: string 转换为 BSTR 相当容易,我具有在任一方向进行转换的函数。

  • The #import call in the header. This is where you tell the C++ how to find your C# library. This is mentioned in the tutorial I link to in the question.
  • If you have a return value in one of your C# functions, it won't come through to the C++ as a return. Instead you'll need to include a pointer to a C++ variable as a parameter when you make the call. See the AddTest() function for an example of this.
  • Strings must be passed to the C# as BSTR type variables. It's fairly easy to convert a std::string to a BSTR, I have functions for doing the conversion in either direction.
//csLink.h

#include <windows.h>
#include <iostream>
#include <string>

#import "path/to/C#/dll.tlb" raw_interfaces_only

using namespace std;

namespace Sample{

    class CSLink {
    public:
        CSLink();
        //Test functions
        int AddTest(int i1, int i2);
        int AgeTest();
        string StringTestCall();
        void stringArgTest(string s);

    private:
        ICalculatorPtr pCalc;
        long lResult;

        string convertBSTR(BSTR *s);
        BSTR convertBSTR(string s);

    };
}



源文件



Source file

//csLink.cpp

#include "stdafx.h"
#include "csLink.h"

using namespace std;

namespace Sample{
    //Constructor
    CSLink::CSLink(){
        cout << "You have created a CS Link" << endl;

        //https://support.microsoft.com/en-us/kb/828736
        HRESULT hr = CoInitialize(NULL);

        pCalc = ICalculatorPtr(__uuidof(ManagedClass));

        lResult = 0;
    }

    //Test functions
    int CSLink::AddTest(int i1, int i2){
        cout << "you are adding " << i1 << " and " << i2 << endl;

        pCalc->Add(i1, i2, &lResult);

        cout << "The result should have been " << i1 + i2 << " and it was " << lResult << endl;

        return 0;
    }

    int CSLink::AgeTest(){
        cout << "Trying to get my age" << endl;

        pCalc->ReturnAge(&lResult);

        return lResult;
    }

    string CSLink::StringTestCall(){
        BSTR s;
        pCalc->StringTest(&s);

        return convertBSTR(&s);
    }

    void CSLink::stringArgTest(string s)
    {
        //References I used figuring this all out:
        //http://stackoverflow.com/questions/28061637/how-to-pass-string-parameters-between-c-and-c
        //https://msdn.microsoft.com/en-us/library/system.runtime.interopservices.marshalasattribute(v=vs.110).aspx
        //http://forums.codeguru.com/showthread.php?193852-How-to-convert-string-to-wstring
        //http://stackoverflow.com/questions/6284524/bstr-to-stdstring-stdwstring-and-vice-versa

        BSTR bSTR = convertBSTR(s);

        cout << "~~~~~~~~~~~~~~~~~~~~~~~" << endl;
        cout << "Testing conversion: " << convertBSTR(&bSTR) << "|end test" << endl;
        pCalc->PrintAString(bSTR);
        cout << "~~~~~~~~~~~~~~~~~~~~~~~" << endl;
    }

    //Utility functions
    string CSLink::convertBSTR(BSTR *s){
        if (*s == nullptr){
            return "NULL STRING";
        }
        else{
            wstring ws(*s, SysStringLen(*s));
            string ss(ws.begin(), ws.end());
            return ss;
        }
    }

    BSTR CSLink::convertBSTR(string s){
        wstring wStr = wstring(s.length(), L' ');
        copy(s.begin(), s.end(), wStr.begin());

        return SysAllocStringLen(wStr.data(), wStr.size());
    }
}

就是这样。如有任何问题,请发表评论。

That's about it. Comment with any questions, I'll do my best to answer.

这篇关于如何将字符串参数从C ++传递到托管的C#DLL的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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