2

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:

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.

(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.

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

[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.

5
  • Pointers and arrays are (almost) the same in C++. That's why an array of doubles is returned as a double *. Take a look at cplusplus.com/doc/tutorial/pointers/#arrays. Commented Nov 6, 2014 at 18:51
  • 1
    Thanks rsenna for your quick & helpful response. The article you linked to is one of the better explanations of arrays in C++ I've seen. Unfortunately, you assume I'm more clueful about this than is, in fact the case - I will continue to research :) Commented Nov 6, 2014 at 20:15
  • You're welcome! :) That was the best I could offer at the time, hope it helped somewhat. Commented Nov 7, 2014 at 15:38
  • rsenna> yes, it helped me to understand much more. Thanks again. Commented Nov 7, 2014 at 23:36
  • Dear Visitors-From-The-Future - the correct answer was given by 'DBC', below; I have confirmed that it works. I hope this benefits you. Commented Nov 7, 2014 at 23:37

2 Answers 2

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:

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.

And in Table 1 we see:

  • MSR 0: 1 double.
  • MSR 1: 3 doubles.
  • MSR 2: 2 doubles.
  • MSR 3: 1 double.

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

        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

    double [] result = new double[3];

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

(Note - answer not tested.)

Sign up to request clarification or add additional context in comments.

1 Comment

Thank you. This worked perfectly, and I am now able to obtain values via the GetPowerData() call. I really appreciate your clear and lucid explanation!
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:

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.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.