get_body from IHTMLDocument2 crash program - c++

program crash
First-chance exception at 0x00000000 in MFCApplication4.exe: 0xC0000005: Access violation executing location 0x00000000.
HINSTANCE hInst = ::LoadLibrary(_T("OLEACC.DLL"));
CoInitialize(NULL);
if (hInst != NULL)
{
if (parentWindow != NULL)
{
if (childWindow)
{
CComPtr<IHTMLDocument2> spDoc;
LRESULT lRes;
UINT nMsg = ::RegisterWindowMessage(_T("WM_HTML_GETOBJECT"));
::SendMessageTimeout(childWindow, nMsg, 0L, 0L, SMTO_ABORTIFHUNG, 1000, (DWORD*)&lRes);
LPFNOBJECTFROMLRESULT pfObjectFromLresult = (LPFNOBJECTFROMLRESULT)::GetProcAddress(hInst, LPCSTR("ObjectFromLresult"));
if (pfObjectFromLresult != NULL)
{
HRESULT hr;
hr = (*pfObjectFromLresult)(lRes, IID_IHTMLDocument, 0, (void**)&spDoc);
if (SUCCEEDED(hr))
{
CComPtr<IHTMLElement> pHTMLElement;
hr = spDoc->get_body(&pHTMLElement);// <-this line breaks the program
//BSTR bstrText;
//pHTMLElement->get_innerText(&bstrText);
//edit1->SetWindowTextW(bstrText);
}
}
}
}
::FreeLibrary(hInst);
}
CoUninitialize();
i'm executing this code from a button from MFC dialog app just to test the code
this is the autos
&pHTMLElement 0x00ddeb10 0x00000000
ATL::CComPtr *
hr S_OK HRESULT
pHTMLElement 0x00000000 ATL::CComPtr
spDoc 0x03303f7c {...} ATL::CComPtr
this 0x00ddfbd8 {hWnd=0x001905b6 {unused=??? }} CMFCApplication4Dlg *
i don't know what is the mistake

On this line:
hr = (*pfObjectFromLresult)(lRes, IID_IHTMLDocument, 0, (void**)&spDoc);
You are requesting an IHTMLDocument, but you are giving it a pointer to a IHTMLDocument2.

Related

Why is this Windows API code causing heap corruption?

This simple program displays a multi-file properties dialog for a single file.
When I compile this code in Visual Studio 2019 with address sanitizer enabled (/fsanitize=address)), I get the following exception on the line `MessageBoxW(...)' in some system DLL:
Unhandled exception at 0x77BCC97F (ntdll.dll) in ConsoleApplication2.exe: 0xC0000374: A heap has been corrupted (parameters: 0x77C0A918).
There is no error if compiled without sanitizer or with VS2022.
#include <windows.h>
#include <Shlobj.h>
int main()
{
CoInitialize(nullptr);
IShellFolder* pDesktop; // namespace root for parsing the path
HRESULT hr = SHGetDesktopFolder(&pDesktop);
if (!SUCCEEDED(hr)) {
return 0;
}
HWND m_hWnd = {};
LPCWSTR fileName = L"c:\\Windows\\notepad.exe";
LPWSTR fileNameDup = _wcsdup(fileName);
LPITEMIDLIST newPIdL;
IDataObject* pDataObject = {};
hr = pDesktop->ParseDisplayName(m_hWnd, nullptr, fileNameDup, nullptr, &newPIdL, nullptr);
if (SUCCEEDED(hr)) {
LPCITEMIDLIST list[] = { newPIdL };
hr = pDesktop->GetUIObjectOf(m_hWnd, 1, list, IID_IDataObject, nullptr, reinterpret_cast<void**>(&pDataObject));
if (SUCCEEDED(hr)) {
hr = SHMultiFileProperties(pDataObject, 0);
if (SUCCEEDED(hr)) {
MessageBoxW(nullptr, L"Test", L"Test", 0);
}
pDataObject->Release();
}
CoTaskMemFree(newPIdL);
}
pDesktop->Release();
free(fileNameDup);
CoUninitialize();
return 0;
}
Is there something wrong in this code?
What else could be causing this error?

COM IDispatch->Invoke fails with error DISP_E_EXCEPTION

I'm trying to invoke a IDispatch->Invoke call to get the name of the IDispatch object and the method fails with error DISP_E_EXCEPTION.
The property I'm trying to get is "accName".
Below is the code that tries to do this:
HRESULT getParentName(IAccessible* pAcc) {
IDispatch *parent;
HRESULT hr;
if ((hr = pAcc->get_accParent(&parent)) == S_OK) {
DISPID dispid;
WCHAR *member = L"accName";
DISPPARAMS dispparams = { NULL, NULL, 0, 0 };
VARIANT result;
result.lVal = CHILDID_SELF;
result.vt = VT_I4;
hr = parent->GetIDsOfNames(IID_NULL, &member, 1, LOCALE_SYSTEM_DEFAULT, &dispid);
if (SUCCEEDED(hr)) {
//OK till now
EXCEPINFO exc;
UINT numErrs;
hr = parent->Invoke(dispid, IID_NULL, LOCALE_SYSTEM_DEFAULT,
DISPATCH_PROPERTYGET, &dispparams, &result, &exc, &numErrs);
if (hr == S_OK) {
MessageBox(NULL, result.bstrVal, L"Got the name", MB_OK);
} else {
//fails with error DISP_E_EXCEPTION
// exception EXCEPINFO return nothing
}
}

Process remains on app exit

After I close the main window of my app, process remains listed in windows task manager's processes list.
Here's the code below, anyone has an idea what to modify to successfully exit process on app exit (or main window close).
int WINAPI WinMain(HINSTANCE inst,HINSTANCE prev,LPSTR cmd,int show)
{
HRESULT hr = CoInitialize(0); MSG msg={0}; DWORD no;
IGraphBuilder* graph= 0; hr = CoCreateInstance( CLSID_FilterGraph, 0, CLSCTX_INPROC,IID_IGraphBuilder, (void **)&graph );
IMediaControl* ctrl = 0; hr = graph->QueryInterface( IID_IMediaControl, (void **)&ctrl );
ICreateDevEnum* devs = 0; hr = CoCreateInstance (CLSID_SystemDeviceEnum, 0, CLSCTX_INPROC, IID_ICreateDevEnum, (void **) &devs);
IEnumMoniker* cams = 0; hr = devs?devs->CreateClassEnumerator (CLSID_VideoInputDeviceCategory, &cams, 0):0;
IMoniker* mon = 0; hr = cams->Next (1,&mon,0); // get first found capture device (webcam?)
IBaseFilter* cam = 0; hr = mon->BindToObject(0,0,IID_IBaseFilter, (void**)&cam);
hr = graph->AddFilter(cam, L"Capture Source"); // add web cam to graph as source
IEnumPins* pins = 0; hr = cam?cam->EnumPins(&pins):0; // we need output pin to autogenerate rest of the graph
IPin* pin = 0; hr = pins?pins->Next(1,&pin, 0):0; // via graph->Render
hr = graph->Render(pin); // graph builder now builds whole filter chain including MJPG decompression on some webcams
IEnumFilters* fil = 0; hr = graph->EnumFilters(&fil); // from all newly added filters
IBaseFilter* rnd = 0; hr = fil->Next(1,&rnd,0); // we find last one (renderer)
hr = rnd->EnumPins(&pins); // because data we are intersted in are pumped to renderers input pin
hr = pins->Next(1,&pin, 0); // via Receive member of IMemInputPin interface
IMemInputPin* mem = 0; hr = pin->QueryInterface(IID_IMemInputPin,(void**)&mem);
DsHook(mem,6,Receive); // so we redirect it to our own proc to grab image data
hr = ctrl->Run();
while ( GetMessage( &msg, 0, 0, 0 ) ) {
TranslateMessage( &msg );
DispatchMessage( &msg );
}
};
Disclaimer: I made no attempt to make this look pretty or do error checking. It works as far as I can tell (when I close the window, the application ends), but it's not exemplary code at all.
The window does not post a WM_QUIT message on its own; you have to do that yourself. You can do it as follows:
Create a window for messages:
WNDCLASSEX wx = {};
wx.cbSize = sizeof(WNDCLASSEX);
wx.lpfnWndProc = proc; // function which will handle messages
wx.hInstance = GetModuleHandle(0);
wx.lpszClassName = "some class";
RegisterClassEx(&wx);
HWND hwnd = CreateWindowEx(0, "some class", "some name", 0, 0, 0, 0, 0, HWND_MESSAGE, NULL, NULL, NULL);
Make a IMediaEventEx * and use it to direct notifications to the window:
I assume a global IMediaEventEx *event;. Please don't do it the quick dirty way.
graph->QueryInterface(IID_IMediaEventEx, (void **) &event);
event->SetNotifyWindow((OAHWND) hwnd, WM_APP + 1, 0);
Make the window procedure handle the case of the user aborting:
LRESULT CALLBACK proc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) {
if (msg == WM_APP + 1) {
long evt;
LONG_PTR param1, param2;
while (SUCCEEDED(event->GetEvent(&evt, &param1, &param2, 0))) {
event->FreeEventParams(evt, param1, param2);
if (evt == EC_USERABORT) {
PostQuitMessage(0);
}
}
}
return DefWindowProc(hwnd, msg, wParam, lParam);
}

Calling Inherited IUnknown::Release() in a destructor

Why does calling the inherited IUnknown::Release() function on a IWICImagingFactory object in a destructor cause a "CXX0030: Error: expression cannot be evaluated" to be shown each entry in the object's virtual function table (__vfptr)?
This is in reference to an earlier question I posted but I've since realized that the problem only occurs in the destructor. The virtual function table appears valid anywhere else I have checked. However, once in the destructor all entries are shown with the CXX0030 error and attempting to call the inherited IUknown::Release() fails.
Edit: Here is some code to demonstrate:
HRESULT DemoApp::CreateDeviceIndependentResources()
{
HRESULT hr;
hr = D2D1CreateFactory(D2D1_FACTORY_TYPE_SINGLE_THREADED, &mpDirect2DFactory);
if (SUCCEEDED(hr))
{
hr = CoCreateInstance(
CLSID_WICImagingFactory,
NULL,
CLSCTX_INPROC_SERVER,
IID_PPV_ARGS(&mpWICFactory)
);
}
//CoCreateInstance returns S_OK.
//Other unrelated code here.
}
HRESULT DemoApp::CreateDeviceResources()
{
HRESULT hr;
//Other unrelated code here for creating device-dependant resources.
//mpBackgroundBitmap is a ID2D1Bitmap*.
if(SUCCEEDED(hr))
{
hr = LoadBitmapFromFile(
mpRenderTarget,
mpWICFactory,
L".\\background.png",
0,
0,
&mpBackgroundBitmap);
}
}
//The below LoadBitmapFromFile() code is taken directly from an MSDN sample.
//I didn't write it.
HRESULT DemoApp::LoadBitmapFromFile(
ID2D1RenderTarget *pRenderTarget,
IWICImagingFactory *pIWICFactory,
PCWSTR uri,
UINT destinationWidth,
UINT destinationHeight,
ID2D1Bitmap **ppBitmap
)
{
IWICBitmapDecoder *pDecoder = NULL;
IWICBitmapFrameDecode *pSource = NULL;
IWICStream *pStream = NULL;
IWICFormatConverter *pConverter = NULL;
IWICBitmapScaler *pScaler = NULL;
HRESULT hr = pIWICFactory->CreateDecoderFromFilename(
uri,
NULL,
GENERIC_READ,
WICDecodeMetadataCacheOnLoad,
&pDecoder
);
if (SUCCEEDED(hr))
{
// Create the initial frame.
hr = pDecoder->GetFrame(0, &pSource);
}
if (SUCCEEDED(hr))
{
// Convert the image format to 32bppPBGRA
// (DXGI_FORMAT_B8G8R8A8_UNORM + D2D1_ALPHA_MODE_PREMULTIPLIED).
hr = pIWICFactory->CreateFormatConverter(&pConverter);
}
if (SUCCEEDED(hr))
{
// If a new width or height was specified, create an
// IWICBitmapScaler and use it to resize the image.
if (destinationWidth != 0 || destinationHeight != 0)
{
UINT originalWidth, originalHeight;
hr = pSource->GetSize(&originalWidth, &originalHeight);
if (SUCCEEDED(hr))
{
if (destinationWidth == 0)
{
FLOAT scalar = static_cast<FLOAT>(destinationHeight) / static_cast<FLOAT>(originalHeight);
destinationWidth = static_cast<UINT>(scalar * static_cast<FLOAT>(originalWidth));
}
else if (destinationHeight == 0)
{
FLOAT scalar = static_cast<FLOAT>(destinationWidth) / static_cast<FLOAT>(originalWidth);
destinationHeight = static_cast<UINT>(scalar * static_cast<FLOAT>(originalHeight));
}
hr = pIWICFactory->CreateBitmapScaler(&pScaler);
if (SUCCEEDED(hr))
{
hr = pScaler->Initialize(
pSource,
destinationWidth,
destinationHeight,
WICBitmapInterpolationModeCubic
);
}
if (SUCCEEDED(hr))
{
hr = pConverter->Initialize(
pScaler,
GUID_WICPixelFormat32bppPBGRA,
WICBitmapDitherTypeNone,
NULL,
0.f,
WICBitmapPaletteTypeMedianCut
);
}
}
}
else // Don't scale the image.
{
hr = pConverter->Initialize(
pSource,
GUID_WICPixelFormat32bppPBGRA,
WICBitmapDitherTypeNone,
NULL,
0.f,
WICBitmapPaletteTypeMedianCut
);
}
}
if (SUCCEEDED(hr))
{
// Create a Direct2D bitmap from the WIC bitmap.
hr = pRenderTarget->CreateBitmapFromWicBitmap(
pConverter,
NULL,
ppBitmap
);
}
SafeRelease(&pDecoder);
SafeRelease(&pSource);
SafeRelease(&pStream);
SafeRelease(&pConverter);
SafeRelease(&pScaler);
return hr;
}
//Now I call SafeRelease() in my destructor and the virtual function table entires are showing the error.
DemoApp::~DemoApp()
{
SafeRelease(&mpDirect2DFactory);
SafeRelease(&mpWICFactory); //here is the problem apparently
SafeRelease(&mpDWriteFactory);
SafeRelease(&mpRenderTarget);
SafeRelease(&mpBackgroundBitmap);
}
//SafeRelease is defined as:
template<class Interface>
inline void SafeRelease(Interface** ppInterfaceToRelease)
{
if(*ppInterfaceToRelease != NULL)
{
(*ppInterfaceToRelease)->Release();
(*ppInterfaceToRelease) = NULL;
}
}
The problem is when I call SafeRelease() on the WICFactory object, I get:
First-chance exception at 0x0024e135 in DemoApp.exe: 0xC0000005: Access violation reading location 0x6d5c28f0.
Unhandled exception at 0x0024e135 in DemoApp.exe: 0xC0000005: Access violation reading location 0x6d5c28f0.
I struggled with this problem lately too. The problem is that the creation and release of IWICImagingFactory depends on CoInitialize/CoUninitialize being called before and after, respectively. In your application it is likely that CoUninitialize() is called before the IWICImagingFactory is released in the destructor, which causes a crash. Note that ID2D1RenderTarget and such do not seem to be affected and can still be released after CoUninitialize() is called.
Remove the call to CoUninitialize() from RunMessageLoop() or wherever it is and put it after the release call in the destructor and the crash should go away.
Calling virtual functions inside the constructor or destructor does not call the function you assume it will call. It always results in call to the functions of that same class.
You can assume virtual dispatch is disabled in constructor and destructors.
An more appropriate way of saying this is:
During the execution of a constructor or destructor, virtual calls on the object for which the constructor or destructor is run behave as if the dynamic type of the object expression used in the call is equal to the class of the constructor or destructor.
Courtesy: A lengthy discussion in C++ Lounge, Where finally, #JohannesSchaublitb came up with this apt definition, which most of us seemed to agree on.

getElementsByTagName with IHTMLDocument3 randomly returns nothing

I'm trying to fill some form input fields in internet explorer from a c++ program but I'm facing a random bug that I hope is because of my code:
UINT msg = RegisterWindowMessage("WM_HTML_GETOBJECT");
LRESULT result = 0;
SendMessageTimeout(hwnd, msg, NULL, NULL, SMTO_ABORTIFHUNG, 10000, (PDWORD_PTR)&result);
if (!result)
return;
// get main document object
IHTMLDocument3 *doc = NULL;
ObjectFromLresult(result, IID_IHTMLDocument3, NULL, (void**)&doc);
if (!doc)
return;
VARIANT varint, varstr;
varint.vt = VT_I4;
varstr.vt = VT_BSTR;
IHTMLElementCollection* pElemCollections=NULL;
if (FAILED(doc->getElementsByTagName(L"input", &pElemCollections)))
return;
long nelm;
pElemCollections->get_length(&nelm);
...
At this last line and with the same HWND at the same page I sometimes get the good number or input fields and often get 0 for nelm.
Do you see something wrong in my code or is it a bug ?
Note that I verified that the HWND is correct, and the return are never called.
Thanks
I have no more problem by doing that:
UINT msg = RegisterWindowMessage("WM_HTML_GETOBJECT");
LRESULT result = 0;
SendMessageTimeout(hwnd, msg, NULL, NULL, SMTO_ABORTIFHUNG, 10000, (PDWORD_PTR)&result);
if (!result)
return;
// get main document object
IHTMLDocument3 *doc = NULL;
ObjectFromLresult(result, IID_IHTMLDocument3, NULL, (void**)&doc);
if (!doc)
return;
CComVariant varint;
CComVariant varstr;
IHTMLElementCollection* pElemCollections=NULL;
CComBSTR name(L"input")
if (FAILED(doc->getElementsByTagName(name, &pElemCollections)))
return;
long nelm;
pElemCollections->get_length(&nelm);
...