RE: Com Pointers - Again..
Steve Lee <
steve@...>
2002-11-01 10:09:02 GMT
I know nothing about Active Accessibility but am interested as this
is an area I am involved in on a voluntary basis. If you have a child
window that is a IE control (e.g. ) then you may be able to navigate
to the text with COM without using Active Accesiibilty.
From a quick codeinspection:
You are registering a message called WM_HTML_HETOBJECT, if that is
a typo of WM_HTML_GETOBJECT then it will not match the message MSAA
is using for and nothing will work as you are sending another message!
Why are you calling CoCreateInstance()? The iMsgHTMLGetObj message
+ pfObjectFromLresult() pair should probably return you a pointer
to the required interface on an instance of the object for you, so
why create another? In any event you throw away the interface without
calling Release() which is very naughty (probably the second cardinal
sin of COM) :)
BTW you should not need to dereference pfObjectFromLresult to call
through it. i.e pfObjectFromLresult(......) should work fine.
Steve
At Friday, 1 November 2002, "Lorne Easton" <leaston@...>
wrote:
>Hi All,
>
>I am getting mightly sick of looking at this code. :o) I have had
a chance
>to look at some of the rersources on COM, and COM from c/c++. CComPtr
is
>still a mystery to me, though I have tried the function call with and
>without an initialized COM pointer. Since the error from
>"ObjectFromLresult" is the same no matter what, I can only assume
that it is
>unnecessary. Any assistance, or tips on going forward with this
would be
>appreciated. I have attached the code in question.. Any assistance
would be
>greatly appreciated. The code is a simple test class, it's ugly, and I
>apologize:
>
><code>
>#ifndef __WIN32_IE_HPP__
>#define __WIN32_IE_HPP__
>
>#include <string>
>#include <windows.h>
>//#include "psdk_files/oleacc.h"
>#include "../common/win32_common.hpp"
>
>#include <ole2.h>
>#include <mshtml.h>
>
>namespace Win32 {
>
> class IE {
>
> public:
>
> IE(int iMaxBufLen);
> ~IE();
> std::string GetText(HWND hWnd);
>
> private:
>
> int iBufLen;
> TCHAR *szBuffer;
> CLSID CLSID_HTMLDocument;
>
> HINSTANCE hOLEAcc; //oleacc.dll
> typedef HRESULT (STDAPICALLTYPE *LPFNOBJECTFROMLRESULT)(LRESULT
lResult,
>REFIID riid, WPARAM wParam, void** ppvObject);
> LPFNOBJECTFROMLRESULT pfObjectFromLresult; //ObjectFromLresult()
>(oleacc.dll)
> UINT iMsgHTMLGetObj;
>
> };
>
>};
>
>#endif //__WIN32_IE_HPP__
></code>
>
></code> <win32_ie.cpp>
>#include "win32_ie.hpp"
>
>Win32::IE::IE(int iMaxBufLen) {
>
> //MaxBufLen --Init List
> iBufLen = iMaxBufLen;
> szBuffer = new TCHAR[iBufLen];
>
> //Init COM
> ::CoInitialize(NULL);
>
> //Load "Active Accessibility"
> if ( (hOLEAcc = ::LoadLibrary("oleacc.dll")) == NULL) {
>
> ::MessageBoxPrintf(TEXT("Could not Locate \"Active Accessibility\"
>Library"),
> TEXT("Active Accessibility is required for this application to
>operate correctly."));
> return;
> }
>
> //Load ObjectFromLresult()
> if ( (pfObjectFromLresult = reinterpret_cast<LPFNOBJECTFROMLRESULT>
> (::GetProcAddress(hOLEAcc, TEXT("ObjectFromLresult"))) ) == NULL ) {
>
> ::MessageBoxPrintf(TEXT("Could not Locate the \"Active Accessibility\"
>component"),
> TEXT("\"Active Accessibility\" is required for this application
to
>operate correctly."));
> }
>
> if ( (iMsgHTMLGetObj = ::RegisterWindowMessage(
>TEXT("WM_HTML_HETOBJECT") )) == 0 ) {
>
> ::MessageBoxPrintf(TEXT("Register AA window Message"),
> TEXT("\"Active Accessibility\" support could not be loaded.
"));
>
> }
>
> if (::CLSIDFromProgID(OLESTR("htmlfile"), &CLSID_HTMLDocument)
!= S_OK) {
>
> ::MessageBoxPrintf(TEXT("Failed to get CLSID"), TEXT("Could
not get the
>CLSID for \"mshtml\".") );
> }
>
>}
>
>Win32::IE::~IE() {
>
> delete[] szBuffer;
>
> //Clean Up COM and AA
> ::FreeLibrary(hOLEAcc);
> ::CoUninitialize();
>
>}
>
>std::string Win32::IE::GetText(HWND hWnd) {
>
> IHTMLDocument2 *pHTMLDoc = NULL;
> LRESULT LRes;
> HRESULT hr;
>
> if (::SendMessageTimeout(hWnd, iMsgHTMLGetObj, 0L, 0L, SMTO_ABORTIFHUNG,
> 1000, reinterpret_cast<DWORD *>(&LRes) ) != 0 ) {
>
> hr = ::CoCreateInstance(CLSID_HTMLDocument, NULL, CLSCTX_ALL,
> IID_IHTMLDocument2, reinterpret_cast<LPVOID *>(&pHTMLDoc) );
>
> if (SUCCEEDED(hr)) {
>
> pHTMLDoc->AddRef();
> hr = (*pfObjectFromLresult)( LRes, IID_IHTMLDocument2, 0,
>reinterpret_cast<LPVOID *>(&pHTMLDoc));
>
> //
> if ( SUCCEEDED(hr) ) {
>
> MessageBoxPrintf( TEXT("Cool!"), TEXT("Ready to do stuff!"), hr );
> //Do Stuff
> pHTMLDoc->Release();
> }
> else {
>
> switch(hr) {
>
> case E_UNEXPECTED:
>
> ::MessageBoxPrintf(TEXT("ObjectFromLresult() failure:"),
>TEXT("E_UNEXPECTED") );
> break;
>
> case E_NOINTERFACE:
>
> ::MessageBoxPrintf(TEXT("ObjectFromLresult() failure:"),
>TEXT("E_NOINTERFACE") );
> break;
>
> case E_INVALIDARG:
>
> ::MessageBoxPrintf(TEXT("ObjectFromLresult() failure:"),
>TEXT("E_INVALIDARG") );
> break;
>
> default:
>
> ::MessageBoxPrintf(TEXT("ObjectFromLresult() failure:"),
>TEXT("Unrecognized error!\n%X"), hr );
> break;
>
> }
>
> pHTMLDoc->Release();
>
> }
> //
>
> }//CoCreateInstance failed
> else {
>
> ::MessageBoxPrintf( TEXT("Error!"), TEXT("Instance of IHTMLDocument2
coud
>not be created.\nError: %d"),
> ::GetLastError() );
> }
>
> }//Message send failed
> else {
>
> MessageBoxPrintf( TEXT("Error!"), TEXT("Send Message
>(WM_HTML_GETOBJECT) failed.\nError Code: %d"),
> ::GetLastError() );
> }
>
>}
></code>
>
>-----Original Message-----
>From: mingw-users-admin@...
>[mailto:mingw-users-admin@...]On Behalf Of Lorne
>Easton
>Sent: Wednesday, October 30, 2002 11:36 PM
>To: steve@...; mingw-users <at> lists.sourceforge.net
>Subject: RE: [Mingw-users] Com Pointers
>
>Wow! Actually, I'll just send you the source and you can finish
the program
>for me.. *joke* :o) Thanks for a well informed through and downright
helpful
>response. Thanks to Luke also. I will have a work through this tomorrow.
>
>Cheers :o)
>
>-----Original Message-----
>From: mingw-users-admin@...
>[mailto:mingw-users-admin@...]On Behalf Of
Steve Lee
>Sent: Wednesday, October 30, 2002 10:35 PM
>To: mingw-users@...; Lorne Easton
>Subject: RE:[Mingw-users] Com Pointers
>
>Lorne Wrote:
>
>> With no ATL, how do you obtain the com void** that the examples here
>> use ATL for, using API calls alone? ::CoCreateInstance()? Any
>> assistance would be appreciated. If there is some document that
>I sould > be reading, please point me in it's direction. All examples
>
>> that I can find seem to use the ATL.
>
>You are not going to like this answer :)
>
>Rather than using ATL to write code that *uses* COM servers, I usually
>use the Microsoft extension #import that given a type library (perhaps
>in a dll or exe) creates C++ wrapper classes to get at the COM objects
>functionality. It uses smartpointers to take care of all the reference
>counting and throws exceptions to simplify the error handling. It
>also takes care of all the VARIENT packing/unpacking for dispatch
>interfaces (IID_IHTMLDocument is a dispatch interface). I doubt that
>MinGW supports #import or _com_ptr_t extensions. If not you have
>to do it all in raw C/C++ with the APIs as you ask - which is *HARD
>WORK*, especially if you are creating a server! On the client side
>you still have to take care of reference counting (smartpointers
>make life much easier here)! You also need to handle all the possible
>errors that come back in the HRESULT returned from all com functions
>(there are macros for this).
>
>MFC has its own limited COM support.
>
>However your question seems to be a basic COM question - 'how do
>I get at a specific interface?'. The answers is quite simple simple,
>given
>one interface you use the COM interface function QueryInterface()
>(usually known as IUnknown::QueryInterface()) to get any other that
>is
>supported by the object implementing the interface you have. All
>interfaces derive from IUknown and support QueryInterface(). You
>
>obviously need to have a pointer to an interface to start with.
>
>The actual mechanics of how you do that vary depending on what you
>are starting with. Assuming You have a pointer to an interface exposed
>
>by an object that also supports one of the IHTMLDocument family,
>then all you need to do is call ptr->QueryInterface(IID_IHTMLDocument)
>to
>get a pointer to it. Perhaps you can create an instance of the object
>and get the IID_IHTMLDocument ptr all in one step with CoCreateInterface()
>which alows you to specify which interface you want.
>
>As for your specific question you need to don't use CoCreateInstance
>because you have already got a pointer to an interface - you use
>QueryInterface() BTW did you note that the code needs Active Accessibility
>to be installed which I believe may only be true on Windows XP by
>default?
>
>The code used 3 ATL features
>
> CComPtr<IHTMLDocument2> - smart pointer, manages AddRef() and Release()
>automaticall
> CComQIPtr<IHTMLWindow2> - smart point with automatic QueryInterface()
>calls
> CComVariant - varient support need for paraenters for the dispatch
>interface
>
>You need to replace them with the raw API code. I'm not familiar
>with the specifics here but it will be very roughly like this (you'll
>probably need to
>
>play a bit):
>
>in a .cpp (no c) file
>
>#include "mshtml.h" // have a look in this for fun :)
>...
> IXMLDocument* pDoc;
>...
>// CComPtr<IDispatch> spDisp;
> IDispatch* pDisp;
>
>// CComQIPtr<IHTMLWindow2> spWin;
> IHTMLWindow2* pWin;
>
>// spDoc->get_Script( &spDisp );
> HRESULT hr = pDoc->get_Script( &pDisp ); // returns a interface
>to a new object
> if(FAILED(hr))
> // error
>
>// spWin = spDisp;
> hr = pDisp->QueryInterface(IID_IHTMLWindow2, &pWin);
> if(FAILED(hr))
> // error
>
> //spWin->get_document( &spDoc.p ); // reuse of smart pointer I think
> pDoc->Release() // I think
> hr = pWin->get_document( &pDoc )
> if(FAILED(hr))
> // error
>
>// spDoc->put_bgColor( CComVariant("red") );
> VARIANT v;
> ::VariantClear(&v);
> v.vt = VT_BSTR;
> vt.bstrVal = ::SysAllocString(OLESTR("red"));
> if (vt.bstrVal == NULL)
> // error out of mem
> pDoc->put_bgColor( &vt );
> ::VariantClear(&v); // frees the bstrVal
>
> pDoc->Release();
> pDisp->Release();
> pWin->Release();
>
>I know which I prefer! I have probably got the referece counting wrong!
>
>There are many resources on COM programming but raw API is not so
>common as it is such a lot of work and .NET is making COM even easier.
>
>You could try
>
>http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dnguion/htm
>l/msdn_drguion020298.
>asp
>
>as primer or browse from
>
>http://msdn.microsoft.com/library/default.asp?url=/library/en-us/com/comport
>al_3qn9.
>asp.
>
>Perhaps CodeProject or CodeGurU will help.
>
>Finally, here is an example to parse an XML file using the XML DOM
>that I found in the MSDN Lib. I'm not saying it is good, it just
>has the basics you need except variants. But hey it must be good
>as it uses goto :). Note that the XML DOM is similar in concept to
>the HTML DOM which IHTMLDocument is part of.
>
>#define UNICODE
>
>#include <windows.h>
>#include <windowsx.h>
>#include <stdlib.h>
>#include <stdio.h>
>#include <io.h>
>#include <urlmon.h>
>#include <hlink.h>
>#include <dispex.h>
>#include "mshtml.h"
>#include "msxml.h"
>
>#define ASSERT(x) if(!(x)) DebugBreak()
>#define CHECK_ERROR(cond, err) if (!(cond)) {pszErr=(err); goto done;}
>#define SAFERELEASE(p) if (p) {(p)->Release(); p = NULL;} else ;
>
>int _cdecl main (int argc, char **argv)
>{
> PSTR pszErr = NULL;
> IXMLDocument *pDoc = NULL;
> IStream *pStm = NULL;
> IPersistStreamInit *pPSI = NULL;
> CHAR buf[MAX_PATH];
> CHAR *pszURL;
>
> HRESULT hr;
>
> //
> // Check usage.
> //
> if (argc != 2)
> {
> fprintf (stderr, "Usage: %s URL\n", argv[0]);
> fprintf (stderr, "Eg %s c:\\nt\\private\\inet\\xml\\test\\channel.
>cdf\n", argv[0]);
> fprintf (stderr, "or %s http://ohserv/users/julianj/msnbc.
>cdf\n", argv[0]);
> exit (1);
> }
>
> //
> // HACK if passed in a file name; expand if it doesn't look like
>a URL.
> //
> if (CompareStringA(LOCALE_USER_DEFAULT, NORM_IGNORECASE, argv[1],
>7, "http://", 7) == CSTR_EQUAL)
> {
> pszURL = argv[1];
> }
> else
> {
> pszURL = buf;
> GetFullPathNameA(argv[1], MAX_PATH, pszURL, NULL);
> }
>
> hr = CoInitialize(NULL);
> ASSERT(SUCCEEDED(hr));
>
> //
> // Create an empty XML document.
> //
> hr = CoCreateInstance(CLSID_XMLDocument, NULL, CLSCTX_INPROC_SERVER,
> IID_IXMLDocument, (void**)&pDoc);
>
> CHECK_ERROR (pDoc, "CoCreateInstance Failed");
>
> //
> // Synchronously create a stream on a URL.
> //
> hr = URLOpenBlockingStreamA(0, pszURL, &pStm, 0,0);
> CHECK_ERROR(SUCCEEDED(hr) && pStm, "Couldn't open stream on URL")
> //
> // Get the IPersistStreamInit interface to the XML doc.
> //
> hr = pDoc->QueryInterface(IID_IPersistStreamInit, (void **)&pPSI);
> CHECK_ERROR(SUCCEEDED(hr), "QI for IPersistStreamInit failed");
>
> //
> // Init the XML doc from the stream.
> //
> hr = pPSI->Load(pStm);
> //CHECK_ERROR(SUCCEEDED(hr), "Couldn't load XML doc from stream");
>
> if(SUCCEEDED(hr))
> {
> printf("%s : XML File is well formed \r\n",argv[0]);
>
> }
> else
> {
> // Print error information !
> IXMLError *pXMLError = NULL ;
> XML_ERROR xmle;
>
> hr = pPSI->QueryInterface(IID_IXMLError, (void **)&pXMLError);
> CHECK_ERROR(SUCCEEDED(hr), "Couldn't get IXMLError");
>
> ASSERT(pXMLError);
>
> hr = pXMLError->GetErrorInfo(&xmle);
> SAFERELEASE(pXMLError);
> CHECK_ERROR(SUCCEEDED(hr), "GetErrorInfo Failed");
>
> printf("%s :", argv[0]);
> wprintf(TEXT(" Error on line %d. Found %s while expecting
>%s\r\n"),
> xmle._nLine,
> xmle._pszFound,
> xmle._pszExpected);
>
> SysFreeString(xmle._pszFound);
> SysFreeString(xmle._pszExpected);
> SysFreeString(xmle._pchBuf);
> }
>
>done: // Clean up.
> //
> // Release any used interfaces.
> //
> SAFERELEASE(pPSI);
> SAFERELEASE(pStm);
> SAFERELEASE(pDoc);
>
> if (pszErr)
> fprintf (stderr, "%s, last error %d\n", pszErr, GetLastError());
> return 0;
>}
>
>Steve Lee (exhausted)
>
>-------------------------------------------------------
>This sf.net email is sponsored by:ThinkGeek
>Welcome to geek heaven.
>http://thinkgeek.com/sf
>_______________________________________________
>MinGW-users mailing list
>MinGW-users@...
>
>You may change your MinGW Account Options or unsubscribe at:
>https://lists.sourceforge.net/lists/listinfo/mingw-users
>
>-------------------------------------------------------
>This sf.net email is sponsored by:ThinkGeek
>Welcome to geek heaven.
>http://thinkgeek.com/sf
>_______________________________________________
>MinGW-users mailing list
>MinGW-users@...
>
>You may change your MinGW Account Options or unsubscribe at:
>https://lists.sourceforge.net/lists/listinfo/mingw-users
>
-------------------------------------------------------
This sf.net email is sponsored by: See the NEW Palm
Tungsten T handheld. Power & Color in a compact size!
http://ads.sourceforge.net/cgi-bin/redirect.pl?palm0001en
_______________________________________________
MinGW-users mailing list
MinGW-users@...
You may change your MinGW Account Options or unsubscribe at:
https://lists.sourceforge.net/lists/listinfo/mingw-users