【问题标题】:Call function in unmanaged DLL from C# with custom parameter使用自定义参数从 C# 调用非托管 DLL 中的函数
【发布时间】:2021-12-06 09:38:27
【问题描述】:

我一直在尝试从我的 C# 应用程序调用 C++ dll 中的一个函数。这是我到目前为止所拥有的,但我不知道我是否走在正确的道路上,或者我做错了什么。由于函数参数是自定义类型的,我不知道该怎么做。

这是C++中的函数定义

int GetDeviceList(
PRINTER_LIST* pList
);

这些是参数

#define MAX_PRINTER 32
typedef struct {
    WCHAR   name[128];          // printer name
    WCHAR   id[64];             // printer ID
    WCHAR   dev[64];            // device connection
    WCHAR   desc[256];          // description
    int     pid;                // USB product ID
} PRINTER_ITEM;

typedef struct  {
    int                 n;
    PRINTER_ITEM    item[MAX_PRINTER];
} PRINTER_LIST;

到目前为止,我能够转换参数

    [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
    public struct PrinterItem {
        [MarshalAs(UnmanagedType.ByValArray, SizeConst = 128)]
        public string name;
        [MarshalAs(UnmanagedType.ByValArray, SizeConst = 64)]
        public string id;
        [MarshalAs(UnmanagedType.ByValArray, SizeConst = 64)]
        public string dev;
        [MarshalAs(UnmanagedType.ByValArray, SizeConst = 256)]
        public string desc;

        public int pid;
    }

    [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
    public struct PrinterList {
        public int n;
        [MarshalAs(UnmanagedType.ByValArray, SizeConst = 32)]
        public PrinterItem[] item;
    }

我一直在尝试将它实现到我的程序中

public
    class Program
    {
        [DllImport("dllName.dll", CallingConvention = CallingConvention.StdCall)]
        public static extern int GetDeviceList(_____);

        static void Main(string[] args)
        {
            var deviceList = GetDeviceList(____);
        }
    }

【问题讨论】:

  • 问题是什么?

标签: c# c++


【解决方案1】:

我假设您的意图是通过引用传递单个 PrinterList

public
    class Program
    {
        [DllImport("dllName.dll", CallingConvention = CallingConvention.StdCall)]
        public static extern int GetDeviceList(ref PrinterList list);

        static void Main(string[] args)
        {
            PrinterList list = new PrinterList();
            var deviceList = GetDeviceList(ref list);
        }
    }

确保非托管 dll 使用 Standard call 调用(您的 C 声明没有说明)。

它应该可以工作。

【讨论】:

  • 您的第二个项目符号得到保证,因为该函数通过复制接收指针——它无法将指向新分配内存的指针传回给调用者。
  • 你是对的,因为PrinterList 被定义为struct(而不是class)。
  • C++没有区别,就是不能改的部分。
  • 我说的是c#部分。我们拥有指针副本的唯一原因...
  • 存在指针的副本,因为 C++ 函数签名具有指针类型的按值传递参数。 int GetDeviceList( PRINTER_LIST* pList ); Pass-by-value 总是产生一个副本。不存在任何可以在不复制指针的情况下调用此函数的 C# 代码。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2016-02-09
  • 2014-08-18
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多