4

I'm trying to get the elements from a SAFEARRAY (returned as output of a function) in Visual C++.

I've never ever used a SAFEARRAY before, so I don't know how to deal with it. Should I convert the SAFEARRAY into a long array (how?) or can I simply use the index of the values inside the SAFEARRAY?

Amal Murali
  • 75,622
  • 18
  • 128
  • 150
merch
  • 945
  • 8
  • 19

2 Answers2

6

You should probably familiarise yourself with the SafeArray documentation on MSDN.

What you probably want to do is call SafeArrayAccessData() to obtain a pointer to the safe array's memory buffer and then iterate the values directly. This is likely the most efficient way to access the values. The code below assumes a lot, you should make sure that you understand these assumptions (by reading the safe array docs) and that they hold for your particular situation...

void Func(SAFEARRAY *pData)
{
   void *pVoid = 0;

   HRESULT hr = ::SafeArrayAccessData(pData, &pVoid);

   MyErrorCheck::ThrowOnFailure(hr);

   const long *pLongs = reinterpret_cast<long *>(pVoid);

   for (int i = 0; i < pData->rgsabound[0].cElements; ++i)
   {
      const long val = pLongs[i];

      DoThingWithLong(val);          
   }

   hr = ::SafeArrayUnaccessData(pData);

   MyErrorCheck::ThrowOnFailure(hr);
}

Note that the code above hasn't seen a compiler...

Len Holgate
  • 21,282
  • 4
  • 45
  • 92
  • Ok! I'm going to read the documentation on MSDN. But what I really need is the second element of the SAFEARRAY, can't i just call it with using the index? Do I have to iterate it? – merch Nov 26 '13 at 14:16
  • No, you don't have to iterate it, you DO need to understand about the rgsabound[] part of the safe array. And, as Igor said, you will probably be responsible for destroying the array that was passed to you. If you ONLY need to access the 2nd element then use SafeArrayGetElement(). – Len Holgate Nov 26 '13 at 14:29
  • I am trying to iterate the entire array to have a better understanding of SAFEARRAYs, using the code below; could you tell me why it doesn't work? `code : long lBound; long uBound; SafeArrayGetUBound(info, 1, &uBound); SafeArrayGetLBound(info, 1, &lBound); float item; for (long ind = lBound; ind < uBound; ind++) { SafeArrayGetElement(info, &ind, (void*)&item); array_tmp[ind] = item; }` – merch Nov 27 '13 at 00:03
  • Should do. There are examples on the MSDN pages and plenty of example code on the web which google should find. – Len Holgate Nov 27 '13 at 07:17
2

See SafeArrayGetElement or SafeArrayAccessData. The former retrieves elements one by one. The latter gives you a pointer to a flat C-style array that this SAFEARRAY instance wraps (don't forget to SafeArrayUnaccesData when you are done).

Note also that, most likely, you are responsible for destroying the array (with SafeArrayDestroy) once you no longer need it.

Igor Tandetnik
  • 50,461
  • 4
  • 56
  • 85
  • Thank you very much. I have just seen these functions, but I can't figure it out the problem; could you make me (or link me) an example of both the functions? – merch Nov 26 '13 at 14:06