Jump to content

QueryInterface (correct usage)


JohnOne
 Share

Recommended Posts

I'm having some trouble with a project, and unsure if I', doing something correctly because of a failure.

I think I might be doing something wrong, and want to know if I'm using the titled operation correctly.

I'm trying to use getElementById, which is a method of IHTMLDocument6.

The structure I'm using to hold the element pointer is IHTMLElement2 type, and I'm trying to determine if they are compatible with queryinterface.

This completes without error, and pHTMLElement has a pointer value

//IHTMLDocument6 * pHTMLDocument;
//IHTMLElement2 * pHTMLElement;
hRes = pHTMLDocument->QueryInterface(IID_IHTMLDocument6, (void**)&pHTMLElement);
 
 

But this fails, and pHTMLElement is 0x00000000 

hRes = pHTMLDocument->getElementById(L"default-p_13872472" , &pHTMLElement);

I'm not hot on all this COM stuff, but I'm having a pop like, and would appreciate any insight.

EDIT: I should note that the return of the latter is S_OK, but pHTMLElement is not a good pointer

Edited by JohnOne

AutoIt Absolute Beginners    Require a serial    Pause Script    Video Tutorials by Morthawt   ipify 

Monkey's are, like, natures humans.

Link to comment
Share on other sites

MSDN says "The IHTMLDocument6 interface inherits from the IDispatch interface but does not have additional members."

That means you have to call it using dispatch calling sequence. That would be: pHTMLElement->GetIDsOfNames(...) and then pHTMLElement->Invoke(...).

Cheers.

What I cannot get my head around is why it returns S_OK and not some error value if it's not going to give me a pointer to the interface.

AutoIt Absolute Beginners    Require a serial    Pause Script    Video Tutorials by Morthawt   ipify 

Monkey's are, like, natures humans.

Link to comment
Share on other sites

Hope this isn't a dumb question but this has me confused> 

(void**)&pHTMLElement

Is that a reference to a pointer to a pointer to a void?  If so, then why?

As far as I'm aware it's just casting the struct pointer to void** (a pointer to the address of the struct)

AutoIt Absolute Beginners    Require a serial    Pause Script    Video Tutorials by Morthawt   ipify 

Monkey's are, like, natures humans.

Link to comment
Share on other sites

Cheers.

 

What I cannot get my head around is why it returns S_OK and not some error value if it's not going to give me a pointer to the interface.

You shouldn't be trying to get your head around it. Just do what documentation says.

...I have written code for different COM objects myself and few times I was asked to extend the definitions by making the interface dual (google the term if not familiar). Sometimes additional functions are just dummies and are there to avoid unhandled exceptions like your code could create otherwise. Also sometimes that's done for forward compatibiliy reasons.

♡♡♡

.

eMyvnE

Link to comment
Share on other sites

But this fails, and pHTMLElement is 0x00000000 
hRes = pHTMLDocument->getElementById(L"default-p_13872472" , &pHTMLElement);

I'm not hot on all this COM stuff, but I'm having a pop like, and would appreciate any insight.

EDIT: I should note that the return of the latter is S_OK, but pHTMLElement is not a good pointer

 

JohnOne, maybe try this:

BSTR pElementIdBStr = SysAllocString(L"default-p_13872472");
hRes = pHTMLDocument->getElementById(pElementIdBStr , &pHTMLElement);
SysFreeString(pElementIdBStr);

That's missing error checking, but that's the basic pattern for using something that takes BSTR parameters.

Link to comment
Share on other sites

As far as I'm aware it's just casting the struct pointer to void** (a pointer to the address of the struct)

Indeed.  I don't know why I didn't see this.  Thanks!

Link to comment
Share on other sites

JohnOne, maybe try this:

BSTR pElementIdBStr = SysAllocString(L"default-p_13872472");
hRes = pHTMLDocument->getElementById(pElementIdBStr , &pHTMLElement);
SysFreeString(pElementIdBStr);

That's missing error checking, but that's the basic pattern for using something that takes BSTR parameters.

Thanks for input Ascend4nt.

I had tried that, I was just making my example as minimal as possible.

From what I have read,in most cases, using a regular wchar_t* string works just fine for BSTR, and it works just fine for rest of code.

I was using IHTMLDocument2 to begin with which never had method getElementById  listed, and noticed there were several going up to IHTMLDocument7.

IHTMLDocument7 failed, saying it was not compatible with IHTMLElement2, so tried 6, which never failed queryinterface.

I'll explain my thinking with what I'm after.

In _IE UDFs after using $obj = ObjCreate("InternetExplorer.Application") it just uses $obj.document.getelementbyid("id")

So in my minimalistic brain, I thought I could be the same In C++ after Creating an IE instance and getting a pointer to its IWebBrowser2 interface, then the document.

I don't know what come over me thinking it would be that easy. I had already gotten a reference to an element id on a page in another fashion and been able to act on it.

But when an element is in an iFrame that fashion fails, so I thought this IHTMLDocument6 and its listed getElementById() member might have been the answer.

I though that because I don't see _IEGeltElementById() trudging though frames to get at an id in it, it just gets it.

Been at it for about 12 hours solid now :(

EDIT: I'm wondering now, if it uses the web pages Javascript getElementById function, but I just tried

BSTR FuncStr = L"alert('alert')";
BSTR LangStr = L"javascript";
VARIANT vEmpty = {0};

pParentWnd->execScript(FuncStr, LangStr, &vEmpty);

To no effect, pParentWnd is type IHTMLWindow2

Edited by JohnOne

AutoIt Absolute Beginners    Require a serial    Pause Script    Video Tutorials by Morthawt   ipify 

Monkey's are, like, natures humans.

Link to comment
Share on other sites

I haven't messed with IE embedding in GUI's, but I would be certain to make sure to test with BSTR's that use SysAllocString, or Microsoft _bstr_t class, since the 1st 4 bytes of a BSTR are a length prefix.

I assume that, if the COM calls do in fact work without that prefix (and you should verify this with debugging), there is probably a safety measure in place to decide if the length is valid. Since BSTR's are null-terminated, an invoked function can look first for a null-terminator and then decide if the first 4 bytes are valid characters if it doesn't match the actual length.  Whatever the case may be, I haven't tested this myself as I've always used SysAllocString.

As far as embedding the IE object and interacting with it, the links here seem a good place to start

Link to comment
Share on other sites

Thanks for your assistance, I think it probably is something to do with the strings.

I'm almost at a milestone point where I can taste success, I have drilled into the iframe and gotten a reference to an element in it (it is not cross domain iframe).

But having trouble acting on that element.

When I used SysAllocString and SysFreeString, it just error in a different place with different code (access violation x0000005 thing) in comutil.h

inline _variant_t::_variant_t() throw()
{
    ::VariantInit(this); // <========= errord out here
}

 

Thing is, it's breaking out in different places.

I probably just need to get some sleep.

Cheers pal.

AutoIt Absolute Beginners    Require a serial    Pause Script    Video Tutorials by Morthawt   ipify 

Monkey's are, like, natures humans.

Link to comment
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
 Share

  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...