繁体   English   中英

从 windows 表单调用 c++ function 时出现错误

[英]When calling c++ function from windows form gets error

我的 c++ function 如下

# define MyFunction _declspec(dllexport)
extern "C" {

MyFunction int SubtractNumbers(int a, int b)
{
    return a - b;
}

MyFunction const char* GetStringKey()
{
    return "My String";
}
}

从 windows 调用 c++ function 形式如下,

    [DllImport(cppFunctionsDll, CallingConvention = CallingConvention.Cdecl)]

    private const string DllFilePath = @"D:\\Projects\\December\\17-12-2020\\project-device- 
    setup\\Debug\\AccurynCPP.dll";

    [DllImport(DllFilePath, CallingConvention = CallingConvention.Cdecl)]
    public static extern int SubtractNumbers(int a, int b);

    [DllImport(DllFilePath, CallingConvention = CallingConvention.Cdecl)]
    public static extern string GetStringKey();
    
    public void GetSubtract()
    {
        lblSubtract.Text= Convert.ToString(SubtractNumbers(1, 2));
        
    }
    public void GetStringFunction()
    {
        lblstringKey.Text= GetStringKey();
        
    }

从上面的 function 中,GetSubtract() 工作得很好。 但是 GetStringKey() 不起作用。 当它在调试时到达它的 function 时,它会在 Visual Studio 中自动取消运行模式。 我该如何解决这个问题。

调用约定向编译器和 linker 描述了如何处理参数、堆栈和寄存器。 因此,如果这些不匹配,则将无法正常工作或 memory 可能已损坏。 例如,如果调用者认为第一个参数应该在寄存器 eax 中传递,但被调用者认为它在堆栈上。 事情显然不会奏效。 有关调用约定的更多信息 Wikipedia 在此处有很好的描述。 您选择的调用约定不是很重要,除非编译器强制您使用。 例如,据我所知,对于 64 位程序,微软只使用一个。 所以,我建议在你写的函数前面加上__cdecl 并在DLLImport行上使用CallingConvention.Cdecl

此外,所有数据类型必须完全匹配。 例如:

[DllImport(DllFilePath, CallingConvention = CallingConvention.Cdecl)]
public static extern string GetStringKey();

这表示它正在返回一个字符串,但是尽管我们使用术语字符串来表示一系列字符,然后是 null。 在这种情况下,字符串是一种正式类型。 他们键入std :: string。 这不是 C 代码返回的内容。 C 代码返回一个指向字符的指针。

通常,基于库传递复杂类型有点不确定。 那是因为它要求两种语言都使用准确的数据结构来表示类型。 因此,当跨越语言边界时,保留您自己的自定义结构和非常原始的类型通常很有用。

所以我推荐你的 C function 是这样的:

__cdecl bool GetStringKey(char *buffer, int maximumLength)
{
    // Write code here to copy all the characters from your "My String"
    // to the buffer or use a standard library function for copying char * strings (often called C strings) when copying make sure to copy the null character at the end. It's definitely needed.
    return true; // Yes it fit
}

您将需要更改您的 DllImport 以匹配。 一旦工作正常,您可以将代码添加到从不超过最大缓冲区长度的 go (以防止 memory 损坏),并可能将 bool 更改为字符串的长度或 -1 以表示失败。

我建议使用这个特殊的 function 原型,因为它不会在语言之间传递 memory。 而是 C 代码填充 C++ 代码的缓冲区。 这是做某事最安全的方法。 在不相关的模块之间传递 memory(在这种情况下 C 和 C++ 并不总是有效)。 虽然我怀疑在这种情况下你的 C 和 C++ 编译器和库足够相似。 你可以切换到返回一个 std::string。 只要双方完美匹配。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM