Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/264.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++;使用PInvoke从c#下载dll? < >在C++ DLL中导出函数的定义为 int func1(const char* input,char** output) { int returnCode = 0; std::stringstream xmlInputStream; xmlInputStream<< std::string(input); std::stringstream xmlOutputStream; returnCode = doRequest(xmlInputStream,xmlOutputStream); std::string xmlOutputString =xmlOutputStream.str(); *output=const_cast<char *> (xmlOutputString.c_str()); cout<<xmlOutputString; return returnCode ; }_C#_C++_Interop - Fatal编程技术网

如何导入C++;使用PInvoke从c#下载dll? < >在C++ DLL中导出函数的定义为 int func1(const char* input,char** output) { int returnCode = 0; std::stringstream xmlInputStream; xmlInputStream<< std::string(input); std::stringstream xmlOutputStream; returnCode = doRequest(xmlInputStream,xmlOutputStream); std::string xmlOutputString =xmlOutputStream.str(); *output=const_cast<char *> (xmlOutputString.c_str()); cout<<xmlOutputString; return returnCode ; }

如何导入C++;使用PInvoke从c#下载dll? < >在C++ DLL中导出函数的定义为 int func1(const char* input,char** output) { int returnCode = 0; std::stringstream xmlInputStream; xmlInputStream<< std::string(input); std::stringstream xmlOutputStream; returnCode = doRequest(xmlInputStream,xmlOutputStream); std::string xmlOutputString =xmlOutputStream.str(); *output=const_cast<char *> (xmlOutputString.c_str()); cout<<xmlOutputString; return returnCode ; },c#,c++,interop,C#,C++,Interop,输出是垃圾值 为什么会这样以及如何从c#导入此函数?这很简单,请尝试使用自定义封送处理(特别是如果您想使用字符**指针) 我发现您没有得到“Memory ass dumb”字符串,这是因为doRequest(char*,char**)的一些不正确的实现,以及对结果的赋值没有得到正确的处理 首先,若要在非托管进程中分配内存并将其传递给托管进程,则需要声明一些机制来释放非托管内存。托管GC不知道有关此内存的任何信息,它将因过大而丢失 其次,您需要为结果分配内存,并将其传递给非托管进程,因为原始内存位

输出是垃圾值


为什么会这样以及如何从c#导入此函数?

这很简单,请尝试使用自定义封送处理(特别是如果您想使用字符**指针)

我发现您没有得到“Memory ass dumb”字符串,这是因为doRequest(char*,char**)的一些不正确的实现,以及对结果的赋值没有得到正确的处理

首先,若要在非托管进程中分配内存并将其传递给托管进程,则需要声明一些机制来释放非托管内存。托管GC不知道有关此内存的任何信息,它将因过大而丢失

其次,您需要为结果分配内存,并将其传递给非托管进程,因为原始内存位置可以随时重写

最后,您只获得输入的第一个字符,因为没有为结果分配内存,实际上只传递一个指向第一个输出字符的内存位置的内存指针,比如&array[0]

下面是compete代码(MS VC++/MS C#),它修复了所有问题:

lib.cpp:

#include "stdafx.h"
#include "lib.h"
using namespace std;

int func1(char* input, char** output)
{
    stringstream xmlInputStream, xmlOutputStream;

    xmlInputStream << string(input);    
    int returnCode = doRequest(&xmlInputStream, &xmlOutputStream);
    string xmlOutputString = xmlOutputStream.str();

    //*output=const_cast<char *> (xmlOutputString.c_str());
    long length = sizeof(char) * xmlOutputString.length();
    char* src = const_cast<char *>(xmlOutputString.c_str());
    char* dst = (char*)malloc(length+1);
    memcpy_s(dst, length, src, length);
    dst[length]=0; // 0 byte always ends up given ANSI string
    *output = dst;

    //cout << xmlOutputString;
    return returnCode;
}

int func1_cleanup(char* memptr)
{
    free(memptr);
    return 0;
}


int doRequest(stringstream* xmlInputStream, stringstream* xmlOutputStream)
{
    *xmlOutputStream << "Memory ass dumb";
    return 0;
}
#包括“stdafx.h”
#包括“lib.h”
使用名称空间std;
int func1(字符*输入,字符**输出)
{
stringstream xmlInputStream,xmlOutputStream;

xmlInputStream我认为这应该是可行的

[DllImport("sample.dll")]
public static extern int func1(
    [MarhsalAs(UnmanagedType.LPStr)] String str1,
    [MarshalAs(UnmanagedType.LPStr)] out String str2);
Marshallas属性在控制互操作方面非常强大

<强>编辑< /St>(基于C++代码的更新后的帖子):< /P>

也许类似这样的事情应该有效(我没有VC++在这个计算机上建立一个假C++ DLL来检查)

注意,我把[OUT]添加到STR2,我不确定这是好的还是必要的,所以尝试和不使用它(再次,抱歉,我不能在这里尝试)。此外,您可能需要使用siZePARAMEXTER代替SiZeCOST,我不记得-如果需要SIZE PARAMEXPROTER,您需要改变C++代码以返回1作为数组元素的数量。 这会将str2作为字符串[]传回,但是您可以使用该数组的第一个元素来获取字符串


<>也许有更干净的方法来做这件事——C++中的一个“StringBulder”参数不能很好地翻译成我所记得的C,但是我可能忘记了一些奥卡纳。

不必要;“Word是为OP的问题而设计的。我们不能用字符串而不是ItpTR吗?”ED S旺格伦:你的答案在哪里?我没有头,Y。您可以使用StringBuilder作为char*,char**封送员。给我一个示例,please@user186246:不,因为您有一个字符**@Artur:ptr#str2没有在func1中定义。您在func1 w.r.t str2中做什么?实际上,在func1中,我正在创建另一个字符*并将其分配给str2。这需要从c程序中读取…我对它不太熟悉th c#.@user186246:你终于找到了c#u str()的地址,所以您可以自由地使用我的方法,创建ByteArray结构并将2个参数声明为out ByteArray*char,然后您可以将该数据的apinter作为ByteArray.ptr内存指针获取,并从中提取该数据memory@Artur-我对你的回答感到担心的是,它使用了不安全的代码,国际海事组织应尽可能避免使用这些代码。如果确实是Marsh唉(在我的回答中)是不够的,尽管如此,但不安全的代码和处理托管代码中的指针应该是到目前为止的最后手段。@Austin Lamb:是的,的确如此。有时使用内存指针技术来反转算法真的是最后手段/我必须学习一些完全特殊的东西,比如“编译理论”,了解如何处理内存中指向数据的指针structures@AustinLamb:+1,这会起作用,如果传递给char**的数据结构是有序的,而不是稀疏的数组,例如,如果您遇到异常情况,您将立即陷入我的解决方案中;)说“它不起作用”没有什么帮助-你能详细说明吗?当你尝试它发生了什么?本地方正确地得到STR1吗?你能显示C++中的函数1的代码吗?这样我们就可以理解STR2是如何设置的?在管理端的STR2中又返回了什么?@ USE186246:结果是一个字符数组数组,所以它可能被翻译成(out String)[]str2)…我将处理这个猜测…Console.writeln(str2)的输出在C++程序中给出垃圾值……并且STR1正确地从原生代码中执行C++。再次,我们需要知道C++代码在做什么。你有这个C++函数的来源吗?正如阿图尔指出的,char *可以表示一个char数组,它可以简单地分配一个char ***STR2(DREF的STR2)。,它可以是二进制数据(char*用于二进制数据的次数很多,因为它是1字节的),或者本机函数中可能会发生很多其他事情。
using System;
using System.Runtime.InteropServices;
namespace test
{
    class Program
    {
        [DllImport("lib.dll", EntryPoint = "func1", CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)]
        public static extern unsafe int func1(char* input, char** data);

        [DllImport("lib.dll", EntryPoint = "func1_cleanup", CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)]
        public static extern unsafe int func1_cleanup(char* data);

        static void Main(string[] args)
        {
            string input = "Hello, World!";
            string output;
            int result = func1(input, out output);
        }

        private const int S_OK = 0;

        public static int func1(string input, out string output)
        {
            unsafe
            {
                output = null;
                int result = -1;
                fixed (char* parray1 = &input.ToCharArray()[0])
                {
                    //
                    // if you allocating memory in a managed process, you can use this
                    //
                    //char[] array = new char[0xffffff];
                    //fixed(char* parray = &array[0])
                    {
                        //
                        // if you allocating memory in unmanaged process do not forget to cleanup the prevously allocated resources
                        //
                        char* array = (char*)0; 
                        char** parray2 = &array;
                        result = func1(parray1, parray2);
                        if (result == S_OK)
                        {
                            //
                            // if your C++ code returns the ANSI string, you can skip this extraction code block (it can be useful in Unicode, UTF-8, UTF-7, UTF-32, all C# supported encodings)
                            //
                            //byte* self = (byte*)*((int*)parray2);
                            //byte* ptr = self;
                            //List<byte> bytes = new List<byte>();
                            //do
                            //{
                            //    bytes.Add(*ptr++);
                            //}
                            //while (*ptr != (byte)0);
                            //output = Encoding.ASCII.GetString(bytes.ToArray());
                            output = Marshal.PtrToStringAnsi(new IntPtr(*parray2));
                        }
                        func1_cleanup(array);
                    }
                }
                return result;
            }
        }
    }
}
[DllImport("sample.dll")]
public static extern int func1(
    [MarhsalAs(UnmanagedType.LPStr)] String str1,
    [MarshalAs(UnmanagedType.LPStr)] out String str2);
[DllImport("sample.dll")]
public static extern int func1(
    [MarshalAs(UnmanagedType.LPStr)] String str1,
    [MarshalAs(UnmanagedType.LPArray, ArraySubType=UnmanagedType.LPStr, SizeConst=1), Out] out String[] str2);