c++到c#包装——如何处理来自c#的双指针数组。

时间:2020-12-07 01:38:11

I've been browsing this site for a long time & taking grateful advantage of your answers to other peoples' questions - now, alas, I have to reveal my ignorance by asking one of my own. I searched for an existing equivalent but couldn't find one; I apologize if this is a duplicate.

我浏览这个网站已经有很长一段时间了,我很感激你对别人问题的回答——现在,唉,我必须通过问我自己的问题来揭示我的无知。我搜索了一个现存的等同物,但找不到;如果这是复制品,我很抱歉。

I'm attempting to use an unmanaged Windows DLL (the Intel Power Gadget 3.0 API, FWIW) from a Visual C# Winforms app under the .Net 4.0 framework. The API is written with C++ implementations in mind, so I'm having to translate as I go. I've been able to wrap and implement most of the functions of the library, but am flummoxed by this one:

我正在尝试使用一个未管理的Windows DLL (Intel Power Gadget 3.0 API, FWIW),它来自一个Visual c# Winforms应用,在。net 4.0框架下。这个API是用c++实现编写的,所以我需要翻译一下。我已经能够包装和实现图书馆的大部分功能,但是我被这个弄糊涂了:

bool GetPowerData(int iNode, int iMSR, double *pResult, int *nResult);

...which is described by the authors thus (my emphasis):

…作者是这样描述的(我的重点):

Returns the data collected by the most recent call to ReadSample(). The returned data is for the data on the package specified by iNode, from the MSR specified by iMSR. The data is returned in pResult, and the number of double results returned in pResult is returned in nResult. Refer Table 1: MSR Functions.

返回最近调用ReadSample()所收集的数据。返回的数据是iNode指定的包上的数据,来自iMSR指定的MSR。在pResult中返回数据,在nResult中返回双结果的数量。参考表1:MSR函数。

(https://software.intel.com/en-us/blogs/2014/01/07/using-the-intel-power-gadget-30-api-on-windows)

(https://software.intel.com/en-us/blogs/2014/01/07/using-the-intel-power-gadget-30-api-on-windows)

Key point: the function returns its main data in the form of a pointer to an array of doubles - or is it an array of pointers to doubles? ...What level of indirection? This is where it all starts to get uncertain for me! :)

关键点:函数以指针的形式返回其主数据到一个双精度浮点数组——还是一个双精度浮点数组?…什么层次的间接这就是我开始不确定的地方!:)

At least some of the input parameters are simple; iNode and iMSR are ints, the value of which I know and can already obtain.

至少有一些输入参数是简单的;iNode和iMSR是ints,我知道它们的值,并且已经可以得到。

I've declared the function in my C# code with this signature:

我在我的c#代码中声明了这个函数,签名如下:

[DllImport("EnergyLib32.dll", CallingConvention = CallingConvention.Cdecl)]
    static extern bool GetPowerData(int iNode, int iMSR, out IntPtr pResult, ref int nResult);

(I'm sure that's my first mistake, right there.)

(我肯定那是我的第一个错误。)

As for actually invoking the function, I've tried various possibilities, all too ugly to even show here.

至于实际调用函数,我已经尝试了各种可能,这些都太难看了,甚至不能在这里显示出来。

Could someone with greater knowledge than mine please suggest the best way to handle this function and its return value?

能不能请比我更有知识的人提出处理这个函数及其返回值的最佳方法?

Thank you in advance.

提前谢谢你。

2 个解决方案

#1


5  

That documentation is unclear. Since it's a double * to be filled with multiple results, you are being required to pass in a preallocated array -- but how big should that array be? The doc says the following:

文档还不清楚。由于它是一个包含多个结果的double *,因此需要传入一个预先分配的数组——但是该数组应该有多大呢?医生说:

An MSR’s function, which the API obtains from GetMsrFunc(), determines the amount and meaning of data returned from GetPowerData() as described in Table 1.

一个MSR的函数(API从GetMsrFunc()获得)确定从GetPowerData()返回的数据的数量和意义,如表1所示。

And in Table 1 we see:

在表1中我们看到:

  • MSR 0: 1 double.
  • MSR 0:1双。
  • MSR 1: 3 doubles.
  • MSR 1:3双打。
  • MSR 2: 2 doubles.
  • MSR 2:2双打。
  • MSR 3: 1 double.
  • MSR 3:1双。

So, an array of 3 doubles should be enough to hold all possible return data. This is borne out by the sample c++ source which does

因此,一个3倍的数组应该足够容纳所有可能的返回数据。这是由示例c++源代码所证明的

        for (int j = 0; j < numMsrs; j++)
        {
            int funcID;
            energyLib.GetMsrFunc(j, &funcID);
            double data[3];
            int nData;
            wchar_t szName[MAX_PATH];

            energyLib.GetPowerData(currentNode, j, data, &nData);
            energyLib.GetMsrName(j, szName);

So you would declare it like:

所以你可以说:

    [DllImport("EnergyLib32.dll", CallingConvention = CallingConvention.Cdecl)]
    static extern bool GetPowerData(int iNode, int iMSR, [In, Out] double [] pResult, out int nResult);

And to call it, use a

叫它a

    double [] result = new double[3];

See here for a discussion of passing arrays to unmanaged code.

有关将数组传递给非托管代码的讨论,请参见这里。

(Note - answer not tested.)

(注:未测试答案。)

#2


0  

The correct answer (in the sense that it worked for me - YMMV! - was posted by DBC, promptly and with clarity. Here's what I used, based on DBC's comments:

正确的答案(在这个意义上它对我有用——YMMV!-由DBC发布,及时、清晰。以下是我根据DBC的评论所使用的:

Declaration:

声明:

[DllImport("EnergyLib64.dll", CallingConvention = CallingConvention.Cdecl)]
    static extern bool GetPowerData(int iNode, int iMSR, [In, Out] double[] pResult, out int nResult);

And usage:

和用法:

double[] result = new double[4];
....
bResult = GetPowerData(0, iModeLocal, result, out nResult); // where iModeLocal is an integer that determines the type of data (MSR) I'm interested in

My only reason for not marking this as "answered" a long time ago is that I didn't realize I hadn't. Whoops. Sorry.

很久以前我没有把这个标记为“回答”的唯一原因是我没有意识到我没有。哎呦。对不起。

#1


5  

That documentation is unclear. Since it's a double * to be filled with multiple results, you are being required to pass in a preallocated array -- but how big should that array be? The doc says the following:

文档还不清楚。由于它是一个包含多个结果的double *,因此需要传入一个预先分配的数组——但是该数组应该有多大呢?医生说:

An MSR’s function, which the API obtains from GetMsrFunc(), determines the amount and meaning of data returned from GetPowerData() as described in Table 1.

一个MSR的函数(API从GetMsrFunc()获得)确定从GetPowerData()返回的数据的数量和意义,如表1所示。

And in Table 1 we see:

在表1中我们看到:

  • MSR 0: 1 double.
  • MSR 0:1双。
  • MSR 1: 3 doubles.
  • MSR 1:3双打。
  • MSR 2: 2 doubles.
  • MSR 2:2双打。
  • MSR 3: 1 double.
  • MSR 3:1双。

So, an array of 3 doubles should be enough to hold all possible return data. This is borne out by the sample c++ source which does

因此,一个3倍的数组应该足够容纳所有可能的返回数据。这是由示例c++源代码所证明的

        for (int j = 0; j < numMsrs; j++)
        {
            int funcID;
            energyLib.GetMsrFunc(j, &funcID);
            double data[3];
            int nData;
            wchar_t szName[MAX_PATH];

            energyLib.GetPowerData(currentNode, j, data, &nData);
            energyLib.GetMsrName(j, szName);

So you would declare it like:

所以你可以说:

    [DllImport("EnergyLib32.dll", CallingConvention = CallingConvention.Cdecl)]
    static extern bool GetPowerData(int iNode, int iMSR, [In, Out] double [] pResult, out int nResult);

And to call it, use a

叫它a

    double [] result = new double[3];

See here for a discussion of passing arrays to unmanaged code.

有关将数组传递给非托管代码的讨论,请参见这里。

(Note - answer not tested.)

(注:未测试答案。)

#2


0  

The correct answer (in the sense that it worked for me - YMMV! - was posted by DBC, promptly and with clarity. Here's what I used, based on DBC's comments:

正确的答案(在这个意义上它对我有用——YMMV!-由DBC发布,及时、清晰。以下是我根据DBC的评论所使用的:

Declaration:

声明:

[DllImport("EnergyLib64.dll", CallingConvention = CallingConvention.Cdecl)]
    static extern bool GetPowerData(int iNode, int iMSR, [In, Out] double[] pResult, out int nResult);

And usage:

和用法:

double[] result = new double[4];
....
bResult = GetPowerData(0, iModeLocal, result, out nResult); // where iModeLocal is an integer that determines the type of data (MSR) I'm interested in

My only reason for not marking this as "answered" a long time ago is that I didn't realize I hadn't. Whoops. Sorry.

很久以前我没有把这个标记为“回答”的唯一原因是我没有意识到我没有。哎呦。对不起。