C# C“DLLImport convert”;常量字符*”;串

C# C“DLLImport convert”;常量字符*”;串,c#,marshalling,dllimport,C#,Marshalling,Dllimport,我需要在C中实现这个DLLImport# 可以在此链接中找到Dll 在.RAR\GBASMSB_2-Client\Ofd SDK 0.2 Windows.zip中->GBASMSB_library.dll 我得到报税单的唯一方法是使用以下代码: [DllImport(@"gbasmsb_library.dll")] public static extern char PegaSolicitacao(string CNPJ,

我需要在C中实现这个DLLImport#

可以在此链接中找到Dll

在.RAR\GBASMSB_2-Client\Ofd SDK 0.2 Windows.zip中->GBASMSB_library.dll

我得到报税单的唯一方法是使用以下代码:

        [DllImport(@"gbasmsb_library.dll")]
    public static extern char PegaSolicitacao(string CNPJ,
                                              string CPF,
                                              string CRM,
                                              string UF_CRM,
                                              string DT_Emissao);

但是返回的是字符串而不是字符。 当我尝试在dlliport中返回字符串时,系统会中断,如果我尝试返回char[],我会收到一个异常,告诉我有关封送的信息

我是C#的新人,从未与马歇尔斯合作过,但在论坛上我尝试了以下几种选择:

                [DllImport(@"gbasmsb_library.dll", CharSet = CharSet.Ansi)]
    [return: MarshalAs(UnmanagedType.LPTStr)]
    public static extern char[] PegaSolicitacao([MarshalAs(UnmanagedType.LPArray)]char[] CNPJ,
                                                [MarshalAs(UnmanagedType.LPArray)]char[] CPF,
                                                [MarshalAs(UnmanagedType.LPArray)]char[] CRM,
                                                [MarshalAs(UnmanagedType.LPArray)]char[] UF_CRM,
                                                [MarshalAs(UnmanagedType.LPArray)]char[] DT_Emissao);

还有其他一些变体,但我找不到正确的选项。

使用DLL

我使用了DLL导出查看器来查看导出的函数。快速的谷歌搜索产生了以下C导出定义:

const char*identificataestacao();
const char*PegaSolicitacao(const char*CNPJ,const char*CPF,const char*CRM,const char*UF\u CRM,const char*DT\u EMISSAO);
const char*PegaConfirmacao(const char*CNPJ,const char*NU_autorizao,const char*NU_CUPOM_财政);
由于它的简单性,我决定从
identificataestacao
开始,它应该返回一个标识站点的标识符

我尝试了所有类型的返回
marshallas
CharSet
CallingConvention
值,但无法使用返回
字符串的导入。因此,让我们将返回类型改为
IntPtr

[DllImport(“gbasmsb_library.dll”,CharSet=CharSet.Ansi,CallingConvention=CallingConvention.Cdecl)]
公共静态外部IntPtr identificataestacao();
现在,当调用该函数时,您将返回一个指向内存地址的
IntPtr
。当检查该内存位置的内容时(在断点上暂停时,调试>窗口>内存>内存1),您可以看到一个以null结尾的单字节字符串(看起来像Base64数据)

我试着用
Marshal.Free…
方法之一释放它,但没有成功。我多次调用相同的方法,每次我们在
IntPtr
中返回相同的内存地址,这使我猜测它们使用的是全局分配的字符串,调用方不应释放该字符串(这也可能是
string
返回类型不起作用的原因)

使用下面的代码,我们可以获得站点标识符:

var ptr=identificataestacao();
var stationIdentifier=Marshal.PtrToStringAnsi(ptr);
让我们以相同的方式更改另一个导入的签名:

[DllImport(“gbasmsb_library.dll”,CharSet=CharSet.Ansi,CallingConvention=CallingConvention.Cdecl)]
公共静态外部IntPtr PegaSolicitacao(
[Marshallas(UnmanagedType.LPStr)]字符串CNPJ,
[Marshallas(UnmanagedType.LPStr)]字符串CPF,
[Marshallas(UnmanagedType.LPStr)]字符串CRM,
[Marshallas(UnmanagedType.LPStr)]字符串UF_CRM,
[Marshallas(UnmanagedType.LPStr)]字符串DT_Emissao);
并进行此测试调用:

var ptr=PegaSolicitacao(“31617905000139”,
"99999999484",
"30828",
“SP”,
DateTime.Today.ToString(“d”);
这再次返回一个指向静态字符串的指针(多次调用它会返回相同的内存地址),因此您可以通过调用
Marshal.PtrToStringAnsi(ptr)获得结果再次

作为一个附加测试,我在一个紧密的循环中运行了它,并且似乎没有内存泄漏,因此这应该是调用导入函数的一种非常安全的方法

请注意,我已将
调用约定
StdCall
更改为
Cdecl
,因此我们可以使用
字符串
作为输入参数,而不会出现不平衡堆栈异常

使用EXE

我还注意到,归档文件包含一个可执行文件
gbasmsb_gbas.exe
,它可以执行相同的功能

gbasmsb_gbas.exe--i
提供站点标识符,而
gbasmsb_gbas.exe--requestacao 9999999 484 31617905000139 30828 SP 12/03/2019
返回请求信息


调用EXE并解析输出也是一种可能的集成路径,它不太容易中断更改,以便将来更新该外部库。

返回的
const char*
是如何分配的?我无权访问DLL的源代码,这是一个由巴西政府制作的第三方动态链接库,有任何文档吗?常量char*
只是一个指针。当它是一个参数时,封送处理程序可以处理它,但作为返回值,它需要知道如何处理该内存,否则它会泄漏。@sidprasher将处理封送部分,但可能也会导致内存泄漏,因为指针可能需要释放,但要释放,你需要知道它是如何分配的。你需要阅读DLL的文档。您需要了解返回的字符串是如何分配的。谢谢,我将尝试并报告返回的DLL结果和EXE结果之间存在差异。也许这是一个编码问题。
            var Teste = PegaSolicitacao("31617905000139",
                                    "99999999484",
                                    "30828",
                                    "SP",
                                    DateTime.Today.ToString("d"));
                [DllImport(@"gbasmsb_library.dll", CharSet = CharSet.Ansi)]
    [return: MarshalAs(UnmanagedType.LPTStr)]
    public static extern char[] PegaSolicitacao([MarshalAs(UnmanagedType.LPArray)]char[] CNPJ,
                                                [MarshalAs(UnmanagedType.LPArray)]char[] CPF,
                                                [MarshalAs(UnmanagedType.LPArray)]char[] CRM,
                                                [MarshalAs(UnmanagedType.LPArray)]char[] UF_CRM,
                                                [MarshalAs(UnmanagedType.LPArray)]char[] DT_Emissao);