Solved

Using the SAFEARRAY data type

Posted on 1998-06-26
10
843 Views
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!

Thanks
0
Comment
Question by:MuraliKrishna
  • 4
  • 3
  • 3
10 Comments
 
LVL 11

Expert Comment

by:alexo
Comment Utility
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.
0
 
LVL 11

Expert Comment

by:alexo
Comment Utility

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.

0
 
LVL 11

Expert Comment

by:alexo
Comment Utility
Also, there's a sample program:
  ftp://ftp.microsoft.com/SOFTLIB/MSLFILES/SAFEARAY.EXE
 

0
 
LVL 1

Author Comment

by:MuraliKrishna
Comment Utility
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!).
0
 
LVL 11

Expert Comment

by:mikeblas
Comment Utility
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)

   m_browser.Navigate(bstrURL,
      COleVariant((long) dwFlags, VT_I4),
      COleVariant(lpszTargetFrameName, VT_BSTR),
      vPostData,
      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)
{
   USES_CONVERSION;

   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;
      safe.AccessData(&pVoid);

      array.SetSize(dwSize);
      LPBYTE lpByte = array.GetData();

      memcpy(lpByte, pVoid, dwSize);
      safe.UnaccessData();
   }

   // 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

0
What Security Threats Are You Missing?

Enhance your security with threat intelligence from the web. Get trending threat insights on hackers, exploits, and suspicious IP addresses delivered to your inbox with our free Cyber Daily.

 
LVL 11

Accepted Solution

by:
mikeblas earned 200 total points
Comment Utility
Meant that as an answer, of course.
0
 
LVL 1

Author Comment

by:MuraliKrishna
Comment Utility
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.

Thanks!
Murali
0
 
LVL 11

Expert Comment

by:mikeblas
Comment Utility
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


0
 
LVL 1

Author Comment

by:MuraliKrishna
Comment Utility
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
0
 
LVL 11

Expert Comment

by:mikeblas
Comment Utility
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
0

Featured Post

IT, Stop Being Called Into Every Meeting

Highfive is so simple that setting up every meeting room takes just minutes and every employee will be able to start or join a call from any room with ease. Never be called into a meeting just to get it started again. This is how video conferencing should work!

Join & Write a Comment

Suggested Solutions

This article surveys and compares options for encoding and decoding base64 data.  It includes source code in C++ as well as examples of how to use standard Windows API functions for these tasks. We'll look at the algorithms — how encoding and decodi…
After several hours of googling I could not gather any information on this topic. There are several ways of controlling the USB port connected to any storage device. The best example of that is by changing the registry value of "HKEY_LOCAL_MACHINE\S…
It is a freely distributed piece of software for such tasks as photo retouching, image composition and image authoring. It works on many operating systems, in many languages.
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. http://www.experts-exchange.com/videos/1478/Excel-Error-Handlin…

763 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

Need Help in Real-Time?

Connect with top rated Experts

6 Experts available now in Live!

Get 1:1 Help Now