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
Welcome to Experts Exchange

Add your voice to the tech community where 5M+ people just like you are talking about what matters.

  • Help others & share knowledge
  • Earn cash & points
  • Learn & ask questions
  • 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:

SharePoint Admin?

Enable Your Employees To Focus On The Core With Intuitive Onscreen Guidance That is With You At The Moment of Need.


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

Instantly Create Instructional Tutorials

Contextual Guidance at the moment of need helps your employees adopt to new software or processes instantly. Boost knowledge retention and employee engagement step-by-step with one easy solution.

Question has a verified solution.

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

Suggested Solutions

Title # Comments Views Activity
Download a file from microsoft that contains all hotfixes and updates 9 76
WPF issue with Trigger 2 130
Input parameteres to DragOver 2 38
Why use this lambda? 12 65
This article shows a few slightly more advanced techniques for Windows 7 gadget programming, including how to save and restore user settings for your gadget and how to populate the "details" panel that is displayed in the Windows 7 gadget gallery.  …
Entering time in Microsoft Access can be difficult. An input mask often bothers users more than helping them and won't catch all typing errors. This article shows how to create a textbox for 24-hour time input with full validation politely catching …
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.…

726 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