?
Solved

Safearrays and IHtmlDocument2 in C

Posted on 2014-01-21
14
Medium Priority
?
558 Views
Last Modified: 2014-01-27
I am using mshtml in a C application. I have an IWebBrowser2 object and an IHtmlDocument2 object, and I want to use the write method instead of navigate2. I used xxd -i to convert the html document to a giant unsigned char (in hex) and saved it in a header file, which is statically linked into the document. Now, I would like to use that giant unsigned char in the document -> write, however it is expecting a safearray.

I would like to know either how to get the unsigned char into the safearray, or another method to achieve the goal of getting an embedded string into the document->write.

Thanks!
Amy
0
Comment
Question by:AmyL
[X]
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
  • 8
  • 5
14 Comments
 
LVL 86

Expert Comment

by:jkr
ID: 39801033
SAFEARRAYs are actually pretty straightfoward to use. The following is a slightly change example taken from existing production code:

#include <windows.h>
#ifdef _DEBUG
#include <assert.h>
#define CHECK( x) assert( x)
#else
#define CHECK( x) x 
#endif

SAFEARRAY* CreateSafeArrayFromUCHARPtr(const unsigned char* puc, const size_t sz) {
    SAFEARRAYBOUND	 saBound[ 1];
    HRESULT			 hres;

    saBound->lLbound		=	0;
    saBound->cElements	=	sz;

    CHECK	(	psa	=	SafeArrayCreate	(	VT_UI1,
                                            1,
                                            saBound
                                        )
            );

    for	(	long	lIndex	=	0;	lIndex	<	sz;	lIndex++)
        {
            hres	=	SafeArrayPutElement	(	 psa,
                                                &lIndex,
                                                 puc + lIndex
                                            );

            CHECK	(	S_OK	==	hres);
        }

    return psa;
}

Open in new window


For cleanup, just call 'SafeArrayDestroy()' (http://msdn.microsoft.com/en-us/library/ms891251.aspx)
0
 

Author Comment

by:AmyL
ID: 39801455
Thank you! That worked for me, except that I realized when looking at the documentation that it has to be a SafeArray of BSTR. (I am referring to the documentation for IHtmlDocument2->write). I'm trying to see if I can convert it now.
0
 

Author Comment

by:AmyL
ID: 39801478
Okay, it will work if I do something like:
OLESTR("<!DOCTYPE html><html lang='en'><head><meta charset='UTF-8'"), because it looks like it just converts it to L"<!DOCTYPE html><html lang='en'><head><meta charset='UTF-8'". My string that I want to use, though, is an unsigned char variable full of hex characters (xxd -i). It doesn't like OLESTR(MyData) because it just literally prepends an "L" to MyData and creates a new variable (LMyData) that has no definition.

Any ideas?

Thanks!
Amy
0
Technology Partners: We Want Your Opinion!

We value your feedback.

Take our survey and automatically be enter to win anyone of the following:
Yeti Cooler, Amazon eGift Card, and Movie eGift Card!

 
LVL 86

Expert Comment

by:jkr
ID: 39801483
For BSTRs, that should just be

#include <windows.h>
#ifdef _DEBUG
#include <assert.h>
#define CHECK( x) assert( x)
#else
#define CHECK( x) x 
#endif

SAFEARRAY* CreateSafeArrayFromUCHARPtrArray(const unsigned char** ppuc, const size_t sz) {
    SAFEARRAYBOUND	 saBound[ 1];
    HRESULT			 hres;

    saBound->lLbound		=	0;
    saBound->cElements	=	sz;

    CHECK	(	psa	=	SafeArrayCreate	(	VT_BSTR,
                                            1,
                                            saBound
                                        )
            );

    for	(	long	lIndex	=	0;	lIndex	<	sz;	lIndex++)
        {
            hres	=	SafeArrayPutElement	(	 psa,
                                                &lIndex,
                                                 *(ppuc + lIndex) // or ppuc[lIndex]
                                            );

            CHECK	(	S_OK	==	hres);
        }

    return psa;
}
                                            

Open in new window

0
 
LVL 86

Expert Comment

by:jkr
ID: 39801485
>>Any ideas?

Since the docs for 'write()' (http://msdn.microsoft.com/en-us/library/ie/ms536782%28v=vs.85%29.aspx) say "A array of String that specifies the text and HTML tags to write", like th eabove - just provide each tag seperately.
0
 

Author Comment

by:AmyL
ID: 39801622
Great, I'll try this tonight. Thanks!!!!
0
 

Author Comment

by:AmyL
ID: 39802075
I'm getting a memory access violation here:
hres =      SafeArrayPutElement      (psa,&lIndex,*(ppuc + lIndex));

I'm not sure if I'm setting the ** correctly:
const unsigned char * cptr;
const unsigned char ** cptrtoptr;
cptr = dhtm;  //dhtm is the unsigned char array of hex
cptrtoptr = &cptr;
0
 

Author Comment

by:AmyL
ID: 39802097
Okay - I got something that almost works. The only thing wrong is when I cast the unsigned char array to LPCTSTR, I get some odd looking characters. I have the project set to use Unicode. (When I changed it to wide char, I created problems in other parts of the code). Anyways, here is what is almost working:

LPCTSTR htf = (LPCTSTR)(const char *)dhtm;

if ((sfArray = SafeArrayCreate(VT_VARIANT, 1, (SAFEARRAYBOUND *)&ArrayBound)))
{

      if (!SafeArrayAccessData(sfArray, (void**)&pVar))
                  {
                        if (sfArray != NULL) {
                              for (l = 0; l < 1; l++) {
                                    VARIANT vOut;
                                    VariantInit(&vOut);
                                    vOut.vt= VT_BSTR;  // set type
                                    vOut.bstrVal = SysAllocString(htf);
                                    aLong[0]= l;  
                                    if (hr= SafeArrayPutElement(sfArray, aLong, &vOut)) {
                                          VariantClear(&vOut);
                                    SafeArrayDestroy(pSA);
                                    
                                    }
                                    else
                                    {
                                    VariantClear(&vOut);
                                    }
                                    }

                              }
                        }
                  }
0
 
LVL 86

Expert Comment

by:jkr
ID: 39803668
>>I have the project set to use Unicode

Then you will have to convert the strings to UNICODE before adding them to the VARIANT, e.g.

    for	(	long	lIndex	=	0;	lIndex	<	sz;	lIndex++)
        {
            size_t len = strlen(*(ppuc + lIndex)) + 1;
            wchar_t* pwsz = (wchar_t*) malloc(len);
            mbstowcs(pwsz,*(ppuc + lIndex),len);
            hres	=	SafeArrayPutElement	(	 psa,
                                                &lIndex,
                                                 pwsz
                                            );

            free(pwsz);

            CHECK	(	S_OK	==	hres);
        }

Open in new window

0
 

Author Comment

by:AmyL
ID: 39804747
Thank you so much for all of your help. I am so close.

Now, I can get it correctly with a small-ish char array, but when I put in my "real" one (size is 3895966), it crashes. Can you please check the values in my function call? (The variable dhtm2 is the small one, which seems to work, if I use dhtm instead, it crashes). When I use dhtm2 (the small one), I set the size values smaller also.

unsigned char dhtm2[] = { 0x3c, 0x21, 0x44, 0x4f, 0x43, 0x54, 0x59, 0x50, 0x45, 0x20, 0x68, 0x74, 0 };
const char *orig = (const char *)dhtm2;
    // Convert to a wchar_t*
    size_t convertedChars = 0;
    wchar_t wcstring[3895966];
    mbstowcs_s(&convertedChars, wcstring, 3895966, orig, _TRUNCATE);
0
 
LVL 86

Accepted Solution

by:
jkr earned 2000 total points
ID: 39805221
Can you try calling 'write()' multiple times and thus breaking down the array to smaller chunks?
0
 

Author Comment

by:AmyL
ID: 39805281
Great idea! I'll try that.
0
 
LVL 35

Expert Comment

by:sarabande
ID: 39806082
size_t len = strlen(*(ppuc + lIndex)) + 1;
wchar_t* pwsz = (wchar_t*) malloc(len);
mbstowcs(pwsz,*(ppuc + lIndex),len);

Open in new window


the code doesn't calculate correct sizes. a wide string needs twice the size of a char array.

you should make the code safer and more robust like ...

if (lIndex < sz) // sz is assumed to be the number of strings
{
      char * p = (char*)ppuc[lIndex];
      if (p != NULL)
      {
           size_t len = strlen(p);
           // when passing NULL for output the required size was returned
          size_t siz = 0;
          if (len > 0)
          {
               siz = mbstowcs(NULL, p, len); 
          }
          // we need 2 bytes more for wchar_t zero termination
          wchar_t * pwsz = (wchar_t*) malloc(siz+sizeof(wchar_t));
           siz = mbstowcs(pwsz, p, len);
           if (siz == (size_t)(-1))
           { 
                // error

Open in new window


Sara
0
 

Author Closing Comment

by:AmyL
ID: 39812562
Here was the final verdict (for anyone else trying to achieve this):
Chunking the wstring and sending multiple write() commands did work in that the document loaded into the browser, however it had many caveats, one being that document events (such as "complete") never fired, and the compatibility was never correctly rendered as IE 10+. So, what I ended up doing, was using IPersistStreamInit and sending the whole char array as a stream. That seems to work as expected, events and all.
Thanks!
Amy
0

Featured Post

On Demand Webinar: Networking for the Cloud Era

Did you know SD-WANs can improve network connectivity? Check out this webinar to learn how an SD-WAN simplified, one-click tool can help you migrate and manage data in the cloud.

Question has a verified solution.

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

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…
Windows programmers of the C/C++ variety, how many of you realise that since Window 9x Microsoft has been lying to you about what constitutes Unicode (http://en.wikipedia.org/wiki/Unicode)? They will have you believe that Unicode requires you to use…
Video by: Grant
The goal of this video is to provide viewers with basic examples to understand and use nested-loops in the C programming language.
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…

765 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