C dll 的 C++/CLI 包装器

发布于 2024-11-15 20:38:11 字数 1118 浏览 2 评论 0原文

所以我有这个 C .dll 源代码,我想在我的 C# 应用程序中使用它。我决定用 C++/CLI 为其编写一个包装器,而不是执行一堆 DllImports。

我的 C 函数采用一个指向结构体的指针,其中包含 4 个回调函数:

typedef struct
{
 PFN_IN readFp;
 PFN_OUT writeFp;
}OPEN_ARGS;

C++/CLI 共享相同的 .h 文件,因此使用相同的 typedef。

C# 代码有自己的结构定义和 CB 委托,因为我无法将 .h 附加到 C# 项目。

    [UnmanagedFunctionPointer(CallingConvention.Cdecl)]
    public delegate Int32 PFN_OUT(IntPtr arg, IntPtr pSrc, Int32 len);

    [StructLayout(LayoutKind.Sequential)]
    public struct OPEN_ARGS
    {
        public PFN_IN readFp;
        public PFN_OUT writeFp;
    };

因此,当我将我的 C++/CLI dll 显式添加到 C# 项目引用中时,编译器不会接受对 C++/CLI 函数的调用,并表示“

"Error 2 Argument 2: cannot convert from 'WrapperTest.Program.OPEN_ARGS' to 'SAR_OPEN_ARGS'"

但是如果我像这样隐式包含 C++/CLI dll,

[DllImport("Wrapper.dll", CharSet = CharSet.Auto, EntryPoint = "?CLIOpen@@YAHHUOPEN_ARGS@@@Z")]
public static extern int CLIOpen(int a, OPEN_ARGS args);

它将工作得很好”。

那么有没有办法告诉 C# 编译器忽略这个类型转换错误,或者可能是其他方法来包装 C 代码函数?

编辑:清理变量名称以获得更好的可读性

So I have this C .dll source code which I want to use in my C# application. Instead of doing bunch of DllImports I've decided to write a wrapper for it in C++/CLI.

My C function takes a pointer to a struct with 4 callback functions in it:

typedef struct
{
 PFN_IN readFp;
 PFN_OUT writeFp;
}OPEN_ARGS;

C++/CLI shares the same .h file, therefore uses the same typedef.

C# code has it's own definition of this structure and delegates for CBs, because I can't attach .h to C# project.

    [UnmanagedFunctionPointer(CallingConvention.Cdecl)]
    public delegate Int32 PFN_OUT(IntPtr arg, IntPtr pSrc, Int32 len);

    [StructLayout(LayoutKind.Sequential)]
    public struct OPEN_ARGS
    {
        public PFN_IN readFp;
        public PFN_OUT writeFp;
    };

So, when I add my C++/CLI dll explicitly to C# project references, the compliler wouldn't accept calls to C++/CLI functions saying

"Error 2 Argument 2: cannot convert from 'WrapperTest.Program.OPEN_ARGS' to 'SAR_OPEN_ARGS'"

But if I include the C++/CLI dll implicitly like that

[DllImport("Wrapper.dll", CharSet = CharSet.Auto, EntryPoint = "?CLIOpen@@YAHHUOPEN_ARGS@@@Z")]
public static extern int CLIOpen(int a, OPEN_ARGS args);

It will work just fine.

So is there a way to tell C# compiler to ignore this type cast error, or may be other way to wrap C code functions?

EDIT: cleaned up variable names for better readabiltiy

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

酒儿 2024-11-22 20:38:11

如果你用另一种方式来做呢?由于您有一个 C++/CLI DLL 处理 C DLL 和 C# 程序集之间的互操作职责,因此您可以公开等效的 API,仅使用更多类似 .NET 的概念。

例如,您可以公开具有三个事件的类,而不是使用函数指针公开结构。 C# 程序集将为这些事件添加处理程序。在 C++ DLL 内部,它将使用 C DLL 所需的函数指针,但它们的实现将触发 C# 程序集正在处理的 .NET 事件。

这将提供在 C# 端使用 DLL 的更好体验,并且可能消除您遇到的互操作编译器错误。

What if you did this another way. Since you have a C++/CLI DLL handling interop duties between the C DLL and the C# assembly, you could expose an equivalent API, only using more .NET-like concepts.

For example, instead of exposing the struct with function pointers, you could expose a class that has three events. The C# assembly would add handlers for those events. Inside the C++ DLL, it would use the function pointers that the C DLL expects, but their implementation would fire the .NET events that the C# assembly is handling.

This would provide a much better experience using the DLL on the C# side, and likely get rid of the interop compiler errors that you're encountering.

栖迟 2024-11-22 20:38:11

请考虑使用 SWIG 为您的所有 pinvoke 生成包装器代码。

http://www.swig.org/Doc1.3/CSharp.html

Please consider using SWIG to generate the wrapper code for all your pinvoke.

http://www.swig.org/Doc1.3/CSharp.html

噩梦成真你也成魔 2024-11-22 20:38:11

因此,对于托管 C++,您可以使用 #pragma 托管/非托管编译器指令,而不是您正在使用的 pInvoke。然后,您可以将托管代码和本机代码一起编译到同一个程序集中,甚至同一个 CPP 文件中。

然后你可以做类似的事情:

#pragma managed
// include your native headers here
#include "foo.h" // whatever you call it.

#using <System.dll> // what ever else you need here...

// Have to wrap a function in a class, since .NET doesn't allow free standing functions.
public ref class foo
{
public static int sarCLIOpen(int a, SARWrapperTest::Program::SAR_OPEN_ARGS args)
{
// do something to convert your managed args to native args. 
::SAR_OPEN_ARGS native_args = ...
// then call your native function
return sarCLIOpen(a, native_args );
}

};

So for managed C++, you can use the #pragma managed/unmanaged compiler directives instead of pInvoke, which it looks like you are using. Then you can compile managed and native code together into the same assembly, even the same CPP file.

Then you could do something like:

#pragma managed
// include your native headers here
#include "foo.h" // whatever you call it.

#using <System.dll> // what ever else you need here...

// Have to wrap a function in a class, since .NET doesn't allow free standing functions.
public ref class foo
{
public static int sarCLIOpen(int a, SARWrapperTest::Program::SAR_OPEN_ARGS args)
{
// do something to convert your managed args to native args. 
::SAR_OPEN_ARGS native_args = ...
// then call your native function
return sarCLIOpen(a, native_args );
}

};
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文