将位图从 C# 传递到 C++非托管代码

发布于 2024-12-26 13:17:36 字数 2377 浏览 6 评论 0原文

我尝试在 C# 中编写代码以将位图传递给非托管 c++ DLL 并返回 POINT 结构,但没有成功。

我在互联网上做了很多研究,但没有找到“Gotcha”文章或代码片段来帮助我解决问题。

到目前为止,我能想到的最好的方法是一个非托管 c++ DLL,它包含一个托管 c++ dll,由我的 C# 应用程序调用。在测试中,我可以传递简单类型(例如整数)并毫无问题地返回整数。现在我遇到的问题是位图。

我尝试传递 HBITMAP(使用 c# 中位图的 GetHBitmap() 函数),但在编译“无法将参数 1 从 'System::IntPtr' 转换为 'HBITMAP'” 和 “Class1.FindImage( void *、void *) 由于其保护级别而无法访问”。

这是我的一些代码:

Main App:

class Program
{
    [StructLayout(LayoutKind.Sequential)]
    public struct POINT
    {
        public int X;
        public int Y;

        public POINT(int x, int y)
        {
            this.X = x;
            this.Y = y;
        }

        public static implicit operator System.Drawing.Point(POINT p)
        {
            return new System.Drawing.Point(p.X, p.Y);
        }

        public static implicit operator POINT(System.Drawing.Point p)
        {
            return new POINT(p.X, p.Y);
        }
    }

    static void Main(string[] args)
    {
        Image src = Image.FromFile("Pin.png");
        Image tgt = Image.FromFile("screen.png");

        Bitmap bsrc = new Bitmap(src);
        Bitmap btgt = new Bitmap(tgt);

        IntPtr bs = bsrc.GetHbitmap();
        IntPtr bt = btgt.GetHbitmap();

        POINT p = Class1.FindImage(bs, bt);
    }
}

ImportWrap.h:

namespace ImportWrap {

public ref class Class1
{
public:
    static POINT FindImage(IntPtr source, IntPtr target);
};
}

ImportWrap.cpp:

static POINT FindImage(IntPtr source, IntPtr target)
{
return ImgFuncs::MyImgFuncs::FindImage(source, target);
}

ImgFuncs.h

typedef long LONG;
typedef void *PVOID;
typedef PVOID HANDLE;
typedef HANDLE HBITMAP;

typedef struct tagPOINT {
  LONG x;
  LONG y;
} POINT, *PPOINT;

namespace ImgFuncs
{

    class MyImgFuncs
    {
    public:
        static __declspec(dllexport) POINT FindImage(HBITMAP source, HBITMAP target);
    };
}

ImgFuncs.cpp

namespace ImgFuncs
{
POINT MyImgFuncs::FindImage(HBITMAP source, HBITMAP target)
{
    POINT p;

    p.x = 1;
    p.y = 2;
    return p;
}
}

我做错了什么,或者我的方法是否完全偏离了地图? 我很乐意接受有关正确编码我想做的事情的建议。 我有一些 C++ 代码,用于在另一个图像中查找图像,运行速度相当快。不幸的是,即使在 C# 中使用锁位,它也不够快。所以我想利用 C++ 代码进行图像搜索。

我确信我会遇到更多的障碍,但如果我能克服这个绊脚石,也许能够处理它。正如你所看到的,我的 C++ 知识有限。

I am trying without success to write code in C# to pass a bitmap to an unmanaged c++ DLL and return a POINT structure.

I have done a lot of research on the internet, but have not found the "Gotcha" article or piece of code to help me resolve my issue.

The best I have been able to come up with so far is an unmanaged c++ DLL, wrapped with a managed c++ dll, called by my C# app. In testing that, I can pass simple types, such as an integer and return an integer with no problem. Now for the issue I am having, the bitmap.

I have tried passing an HBITMAP (using the GetHBitmap() function of my bitmap in c#), but I get errors during compile of "cannot convert parameter 1 from 'System::IntPtr' to 'HBITMAP'" and "Class1.FindImage(void *, void *) is inaccessible due to it's protection level".

Here is some of my code:

Main App:

class Program
{
    [StructLayout(LayoutKind.Sequential)]
    public struct POINT
    {
        public int X;
        public int Y;

        public POINT(int x, int y)
        {
            this.X = x;
            this.Y = y;
        }

        public static implicit operator System.Drawing.Point(POINT p)
        {
            return new System.Drawing.Point(p.X, p.Y);
        }

        public static implicit operator POINT(System.Drawing.Point p)
        {
            return new POINT(p.X, p.Y);
        }
    }

    static void Main(string[] args)
    {
        Image src = Image.FromFile("Pin.png");
        Image tgt = Image.FromFile("screen.png");

        Bitmap bsrc = new Bitmap(src);
        Bitmap btgt = new Bitmap(tgt);

        IntPtr bs = bsrc.GetHbitmap();
        IntPtr bt = btgt.GetHbitmap();

        POINT p = Class1.FindImage(bs, bt);
    }
}

ImportWrap.h:

namespace ImportWrap {

public ref class Class1
{
public:
    static POINT FindImage(IntPtr source, IntPtr target);
};
}

ImportWrap.cpp:

static POINT FindImage(IntPtr source, IntPtr target)
{
return ImgFuncs::MyImgFuncs::FindImage(source, target);
}

ImgFuncs.h

typedef long LONG;
typedef void *PVOID;
typedef PVOID HANDLE;
typedef HANDLE HBITMAP;

typedef struct tagPOINT {
  LONG x;
  LONG y;
} POINT, *PPOINT;

namespace ImgFuncs
{

    class MyImgFuncs
    {
    public:
        static __declspec(dllexport) POINT FindImage(HBITMAP source, HBITMAP target);
    };
}

ImgFuncs.cpp

namespace ImgFuncs
{
POINT MyImgFuncs::FindImage(HBITMAP source, HBITMAP target)
{
    POINT p;

    p.x = 1;
    p.y = 2;
    return p;
}
}

What am I doing wrong, or am I going completely off the map with my approach?
I would GLADLY entertain any suggestions regarding the correct way to code what I am trying to do.
I have some C++ code that is used to find an image within another image that works quite fast. Unfortunately, even using lockbits in c#, it's not fast enough. So I would like to make use of the c++ code for the image search.

I am sure I will run into further snags, but might be able to handle it if I can get past this stumbling block. As you can see, my C++ knowledge is limited.

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

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

发布评论

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

评论(2

心清如水 2025-01-02 13:17:36

您不能使用本机结构类型作为返回值,C# 无法处理它们。从 IntPtr 到 HBITMAP 的转换需要两次转换。像这样:

static System::Drawing::Point FindImage(IntPtr source, IntPtr target)
{
    POINT retval = ImgFuncs::MyImgFuncs::FindImage((HBITMAP)(void*)source, (HBITMAP)(void*)target);
    return System::Drawing::Point(retval.X, retval.Y);
}

添加对 System.Drawing 的程序集引用。然后,您可能还需要考虑传递 Bitmap^ 而不是 IntPtr,以使其更易于使用。

You cannot use native struct types as a return value, C# can't handle them. Casting from IntPtr to HBITMAP requires a double cast. Like this:

static System::Drawing::Point FindImage(IntPtr source, IntPtr target)
{
    POINT retval = ImgFuncs::MyImgFuncs::FindImage((HBITMAP)(void*)source, (HBITMAP)(void*)target);
    return System::Drawing::Point(retval.X, retval.Y);
}

Add an assembly reference to System.Drawing. You might then also want to consider passing a Bitmap^ instead of an IntPtr to make it even easier to use.

自此以后,行同陌路 2025-01-02 13:17:36

您可能可以完全跳过托管 C++ 包装器,而仅通过 P/Invoke 从 C# 调用非托管 DLL。将类似的内容放入您的 C# 类中

[DllImport("YourUnamangedDll.dll")]
private static extern POINT FindImage(IntPtr source, IntPtr target);

我还没有对此进行测试,因此您可能需要根据需要对其进行调整,但这是总体思路。

You could probably skip the managed C++ wrapper entirely and just call the unmanaged DLL from C# via P/Invoke. Put something like this in your C# class

[DllImport("YourUnamangedDll.dll")]
private static extern POINT FindImage(IntPtr source, IntPtr target);

I haven't tested this, so you may need to tweak it as needed, but that's the general idea.

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