From: Lorne E. <le...@bi...> - 2002-11-01 03:32:48
|
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: min...@li... [mailto:min...@li...]On Behalf Of Lorne Easton Sent: Wednesday, October 30, 2002 11:36 PM To: st...@fu...; min...@li... 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: min...@li... [mailto:min...@li...]On Behalf Of Steve Lee Sent: Wednesday, October 30, 2002 10:35 PM To: min...@li...; 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 Min...@li... 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 Min...@li... You may change your MinGW Account Options or unsubscribe at: https://lists.sourceforge.net/lists/listinfo/mingw-users |