Using the SAFEARRAY data type

Posted on 1998-06-26
Last Modified: 2013-12-04
I am using the IE 4.01 WebBrowser control in my MFC/Visual C++ 5.0 SDI application in the View, and it has two functions that require manipulating the SAFEARRAY data type. One needs to set data in it, the other needs to read data from it.

Can someone show me how to do both?

In addition, if you can show me an example of how to use the PostData and Headers field in the Navigate2 method and BeforeNavigate2 event handler, I'll double the points!

Question by:Murali Devarakonda
  • 4
  • 3
  • 3
LVL 11

Expert Comment

ID: 1408733
Go to the online help topic "Array Manipulation API Functions" and check the subtopics following it.  Tere are descriptions of APIs like SafeArrayAccessData(), SafeArrayGetElement(), SafeArrayPutElement(), etc.
LVL 11

Expert Comment

ID: 1408734

In general, the functions you need are:

SafeArrayAccessData      Increments the lock count of an array and returns a pointer to array data.
SafeArrayAllocData      Allocates memory for a safe array based on a descriptor created with SafeArrayAllocDescriptor.
SafeArrayAllocDescriptor      Allocates memory for a safe array descriptor.
SafeArrayCopy      Copies an existing array.
SafeArrayCopyData      Copies a source array to a target array after releasing source resources.
SafeArrayCreate      Creates a new array descriptor.
SafeArrayCreateVector      Creates a one-dimensional array whose lower bound is always zero.
SafeArrayDestroy      Destroys an array descriptor.
SafeArrayDestroyData      Frees memory used by the data elements in a safe array.
SafeArrayDestroyDescriptor      Frees memory used by a safe array descriptor.
SafeArrayGetDim      Returns the number of dimensions in an array.
SafeArrayGetElement      Retrieves an element of an array.
SafeArrayGetElemsize      Returns the size of an element.
SafeArrayGetLBound      Retrieves the lower bound for a given dimension.
SafeArrayGetUBound      Retrieves the upper bound for a given dimension.
SafeArrayLock      Increments the lock count of an array.
SafeArrayPtrOfIndex      Returns a pointer to an array element.
SafeArrayPutElement      Assigns an element into an array.
SafeArrayRedim      Resizes a safe array.
SafeArrayUnaccessData      Frees a pointer to array data and decrements the lock count of the array.
SafeArrayUnlock      Decrements the lock count of an array.

LVL 11

Expert Comment

ID: 1408735
Also, there's a sample program:

Optimizing Cloud Backup for Low Bandwidth

With cloud storage prices going down a growing number of SMBs start to use it for backup storage. Unfortunately, business data volume rarely fits the average Internet speed. This article provides an overview of main Internet speed challenges and reveals backup best practices.


Author Comment

by:Murali Devarakonda
ID: 1408736
I appreciate your time, but I'm familiar with all the "Resources" that you are suggesting. I even have the sample and have compiled and run it. It's for sorting.

None of these resources actually make it easy to understand how to best use the SAFEARRAY (it's preferable to use COleSafeArray).

What I asked for, and need badly is code snippet that shows me simply how to set data, and retrieve data correctly, and efficiently. Specifically, in the WebBrowser supported method Navigate and the BeforeNavigate event (which deserves bonus points!).
LVL 11

Expert Comment

ID: 1408737
I can't believe these "experts" didn't suggest using COleSafeArray. Experts Exchange is a race for points these days, instead of a quality contest.

This function calls the navigate method after converting the C++ data types in the function's prototype to the appropriate automation types. Note the use of COleSafeArray for the post data.

void CYourWindow::Navigate(LPCTSTR lpszURL, DWORD dwFlags,
   LPCTSTR lpszTargetFrameName,
   LPCTSTR lpszHeaders, LPVOID lpvPostData,
   DWORD dwPostDataLen)
   CString strURL(lpszURL);
   BSTR bstrURL = strURL.AllocSysString();

   COleSafeArray vPostData;
   if (lpvPostData != NULL)
      if (dwPostDataLen == 0)
         dwPostDataLen = lstrlen((LPCTSTR) lpvPostData);

      vPostData.CreateOneDim(VT_UI1, dwPostDataLen, lpvPostData);

   // call the browser control (you might have a different name)

      COleVariant((long) dwFlags, VT_I4),
      COleVariant(lpszTargetFrameName, VT_BSTR),
      COleVariant(lpszHeaders, VT_BSTR));

You can hook this function up as your BeforeNavigate2() event handler. The code I've supplied here translates the automation data types to real C++ data types that you can conveniently use.

void CYourWindow::BeforeNavigate2(LPDISPATCH /* pDisp */, VARIANT* URL,
      VARIANT* Flags, VARIANT* TargetFrameName,
      VARIANT* PostData, VARIANT* Headers, BOOL* Cancel)

   VARIANT* vtPostedData = V_VARIANTREF(PostData);
   CByteArray array;
   if (V_VT(vtPostedData) & VT_ARRAY)
      // must be a vector of bytes
      ASSERT(vtPostedData->parray->cDims == 1 && 
         vtPostedData->parray->cbElements == 1);

      vtPostedData->vt |= VT_UI1;
      COleSafeArray safe(vtPostedData);

      DWORD dwSize = safe.GetOneDimSize();
      LPVOID pVoid;

      LPBYTE lpByte = array.GetData();

      memcpy(lpByte, pVoid, dwSize);

   // make real parameters out of the notification

   CString strTargetFrameName(V_BSTR(TargetFrameName));
   CString strURL = V_BSTR(URL);
   CString strHeaders = V_BSTR(Headers);
   DWORD nFlags = V_I4(Flags);

   //**** at this point,
   //   strURL is the URL
   //    nFlags contains the flags
   //    strTargetFrameName has the name of the target frame
   //    array is a CByteArray containing the POST data
   //    strHeaders contains the headers

   // ... write your handler code here...

I'm sure you'll let me know if you have questions.

B ekiM

LVL 11

Accepted Solution

mikeblas earned 200 total points
ID: 1408738
Meant that as an answer, of course.

Author Comment

by:Murali Devarakonda
ID: 1408739
Thanks for your answer. It's exactly what I wanted. But I do have a few simple questions.
I have been using the TargetFrame, and URL fields, but I never used "USES_CONVERSION"- in fact I really don't know what it does or if I need it here. My existing code has been working fine (so far!) without it.

Also, you're doing      CString strURL = V_BSTR(URL);
             I did CString strURL( URL->bstrVal );
Similarily, you have
I suppose they are both equivalent, although I've never used V_BSTR.

Why didn't you use COleVariant here?
   VARIANT* vtPostedData = V_VARIANTREF(PostData);  
I feel more comfortable using MFC classes whenever possible, unless there's a reason not to.

Finally, I'd be really grateful if you can explain the PostData field to me. As I understand it, it's what I have to use to send, essentially a string made of the form data. I may get this from a dialog I present to the user, and build the string. I did gather from the docs that PostData is a single dimensional array of unsigned integer bytes. I hope I'm assuming correctly here that I can pass a pointer to a string for the parameter: LPVOID lpvPostData, in CYourWindow::Navigate function.

LVL 11

Expert Comment

ID: 1408740
USES_CONVERSION isn't necessary in the code I posted; it was left over from the original application of the code.

The BSTR assignment constructor for CString is equivalently invoked both by operator equals and by the constructor syntax.

I don't have time to double-check at this instant, but I think I used VARIANT instead of COleVariant because COleVariant didn't have a constructor to initialize from a variant byref. That just made using VARIANT directly more convenient. Otheriwse, the code is equivalent.

You can pass a pointer to a string for PostData, yes.  If you read the HTTP spec, it wil lgive you info on formulating the string.

B ekiM


Author Comment

by:Murali Devarakonda
ID: 1408741
Thanks for your patience. I am going to close out this question.

I guess you'll give me some info that I asked for in my other question.

I tried to increase the points. Looks like I don't have enough points(only 10 available). I have 400 points locked between these two questions.
Once you're done with the other question, I'll close that out too. That'll give you 400 points for both of them together, which is twice the points I initially allocated to this question (and what I promised for a complete answer, which you've given me).

Please let me know what you think.

Thank you,
Murali Krishna Devarakonda
LVL 11

Expert Comment

ID: 1408742
I think I skipped using COleVariant in the instance you describe because COleVariant doesn't have a constructor which accepts a pointer to a byref variant. (I could be wrong, because I'm not in a position to double-check at the moment.)

The string constructor is the same as the assignment, yes.

The posted data is normally just a string; you can pass along whatever your server expects. What the server expects is completely implementation dependent: if you're talking to an HTML form, or working with a CGI extension, or some other custom software, the exact content of the POST data may be different.

B ekiM

Featured Post

Best Practices: Disaster Recovery Testing

Besides backup, any IT division should have a disaster recovery plan. You will find a few tips below relating to the development of such a plan and to what issues one should pay special attention in the course of backup planning.

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

Suggested Solutions

What my article will show is if you ever had to do processing to a listbox without being able to just select all the items in it. My software Visual Studio 2008 crystal report v11 My issue was I wanted to add crystal report to a form and show…
For most people, the WrapPanel seems like a magic when they switch from WinForms to WPF. Most of us will think that the code that is used to write a control like that would be difficult. However, most of the work is done by the WPF engine, and the W…
This tutorial gives a high-level tour of the interface of Marketo (a marketing automation tool to help businesses track and engage prospective customers and drive them to purchase). You will see the main areas including Marketing Activities, Design …
This is Part 3 in a 3-part series on Experts Exchange to discuss error handling in VBA code written for Excel. Part 1 of this series discussed basic error handling code using VBA.…

810 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question