【问题标题】:How to call C ++ method in C # using Invoke如何在 C# 中使用 Invoke 调用 C++ 方法
【发布时间】:2021-06-06 21:01:27
【问题描述】:

我做得对吗?我有两个并行项目,第一个是用 C++ 编写的代码,第二个项目(在 AspNetCore v3.1 中制作的控制台)是尝试调用 C++ 代码中的方法。 我需要在 C# 项目中调用 C++ 方法“解密”。我该怎么做?

C++ 代码

#include <stdlib.h>
#include <string.h>
#include<windows.h>
#include "bascript.hpp"

extern "C"
int FAR PASCAL _export
Decript( const LPSTR name, const LPSTR passwordWithCript,
             LPSTR passwordWithoutCript, unsigned int sizeSpaceRetorn ) {

    LPSTR result = lpDecript( name, passwordWithCript);
    if ( sizeSpaceRetorn < strlen(result) )
       return 0;
       
    strcpy( passwordWithoutCript, result );
    delete result;
    return 1;
}

C#

class Program
{
    [DllImport(@"C:\MS\VS\TesteDLLCentura\TesteDLLCentura\bin\Debug\netcoreapp3.1\Sises.DLL", CharSet = CharSet.Auto, EntryPoint = "Decript")]
        private static extern string Decript(string name, string passwordWithCript, string passwordWithoutCript, uint sizeSpaceRetorn);

        static void Main(string[] args)
        {
            string retorno = Decript("<user>", "<cript_password>", "", 0);
            Console.WriteLine(retorno);

            Console.ReadLine();
        }
}

【问题讨论】:

  • 您是否尝试过使用相对路径? IE。 [DllImport("Sises.dll", CharSet = CharSet.Auto, EntryPoint = "Decript")]
  • @Timothy G,不管有没有相对路径,都会出错。 (进程 27840)以代码 -1073740940 退出。
  • 您需要声明StringBuilder passwordWithoutCript,将其预初始化为特定大小,并将该大小传递给sizeSpaceRetorn。这将包含实际结果,以 NUL (0) 字符结尾。返回类型应该是int 而不是string

标签: c# c++ asp.net-core console pinvoke


【解决方案1】:

只要您使用与 .NET 兼容的内存分配器,您就可以从原生世界(C/C++ 等)返回一个指针。在 Windows 上,这将是 COM 分配器。

所以这里有 3 种返回字符串的方法:Ansi、Unicode 和 BSTR(unicode)。注意:您应该避免在 Windows 上使用 Ansi。

C++ 方面:

extern "C"  __declspec(dllexport) void* DecryptA(const char* name, const char* password)
{
    char str[] = "hello ansi world";
    int size = (lstrlenA(str) + 1) * sizeof(char); // terminating zero

    // use .NET compatible allocator
    void* buffer = CoTaskMemAlloc(size);
    CopyMemory(buffer, str, size);
    return buffer;
}

extern "C"  __declspec(dllexport) void* DecryptW(const wchar_t* name, const wchar_t* password)
{
    wchar_t str[] = L"hello unicode world";
    int size = (lstrlenW(str) + 1) * sizeof(wchar_t); // terminating zero

    // use .NET compatible allocator
    void* buffer = CoTaskMemAlloc(size);
    CopyMemory(buffer, str, size);
    return buffer;
}

extern "C"  __declspec(dllexport) BSTR DecryptBSTR(const wchar_t* name, const wchar_t* password)
{
    wchar_t str[] = L"hello BSTR world";

    // use .NET compatible allocator and COM coolness
    return SysAllocString(str);
}

C#端:

[DllImport("mydll", CharSet = CharSet.Ansi)]
private static extern string DecryptA(string name, string password);

[DllImport("mydll", CharSet = CharSet.Unicode)]
private static extern string DecryptW(string name, string password);

[DllImport("mydll", CharSet = CharSet.Unicode)]
[return: MarshalAs(UnmanagedType.BStr)]
private static extern string DecryptBSTR(string name, string password);

...

static void Main()
{
    Console.WriteLine(DecryptA("name", "password"));
    Console.WriteLine(DecryptW("name", "password"));
    Console.WriteLine(DecryptBSTR("name", "password"));
}

【讨论】:

    【解决方案2】:

    您的 C++ 函数不返回 string 或等效值。它返回一个int 结果(成功或失败),实际结果进入passwordWithoutCript 缓冲区。

    所以你需要创建缓冲区并传入。

    因为你在 C++ 端使用LPSTR,所以你需要CharSet.Ansi

    [DllImport(@"C:\MS\VS\TesteDLLCentura\TesteDLLCentura\bin\Debug\netcoreapp3.1\Sises.DLL", CharSet = CharSet.Ansi, EntryPoint = "Decript")]
    private static extern int Decript(string name, string passwordWithCript, StringBuilder passwordWithoutCript, uint sizeSpaceRetorn);
    
    static void Main(string[] args)
    {
        var sb = new StringBuilder(1000);  // or whatever size
        if(Decript("<user>", "<cript_password>", sb, sb.Length) == 1)
            Console.WriteLine(retorno);
    
        Console.ReadLine();
    }
    

    【讨论】:

    • 即使根据上面的代码进行更改,应用程序也会返回以下消息:“此表达式会导致副作用,不会被计算”
    • 该消息是一个调试器消息,告诉您它不会从 Watch 或 Immediate 窗口执行某些类型的代码。您将需要实际执行它。你得到一个实际的错误吗?
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-01-21
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多