Я пытался решить проблему, связанную с IWebBrowser2 и веб-сайтом Amazon Japan (http://www.amazon.co.jp). Каждый раз, когда я захожу на этот сайт, происходит сбой моего приложения с веб-браузером.
Это не произошло раньше с этим конкретным сайтом. Фактически, это работало в течение нескольких месяцев до прошлой недели, когда это только продолжало падать. Я мог бы отлично загружать другие сайты, кроме Amazon Japan.
В окне отладки я заметил, что перед тем, как приложение зависло, я получил несколько исключений первого шанса.
Отладочный вывод 1 (Amazon Japan)
First-chance exception at 0x763c4b32 in IWebBrowser2.exe: Microsoft C++ exception: Js::JavascriptExceptionObject at memory location 0x002fd2ac..
First-chance exception at 0x763c4b32 in IWebBrowser2.exe: Microsoft C++ exception: Js::JavascriptExceptionObject at memory location 0x002fd30c..
First-chance exception at 0x763c4b32 in IWebBrowser2.exe: Microsoft C++ exception: Js::JavascriptExceptionObject at memory location 0x002fc844..
Но я не думаю, что это является причиной проблемы, поскольку я также получаю эти исключения при загрузке Amazon US (www.amazon.com). На самом деле, он имеет еще больше, но мое приложение хостинга не падает.
Отладочный вывод 2 (Amazon US)
First-chance exception at 0x763c4b32 in IWebBrowser2.exe: Microsoft C++ exception: Js::JavascriptExceptionObject at memory location 0x00f6cfec..
First-chance exception at 0x763c4b32 in IWebBrowser2.exe: Microsoft C++ exception: Js::JavascriptExceptionObject at memory location 0x00f6d04c..
First-chance exception at 0x763c4b32 in IWebBrowser2.exe: Microsoft C++ exception: Js::JavascriptExceptionObject at memory location 0x00f6c584..
First-chance exception at 0x763c4b32 in IWebBrowser2.exe: Microsoft C++ exception: Js::JavascriptExceptionObject at memory location 0x00f6dd8c..
First-chance exception at 0x763c4b32 in IWebBrowser2.exe: Microsoft C++ exception: Js::JavascriptExceptionObject at memory location 0x00f6db9c..
First-chance exception at 0x763c4b32 in IWebBrowser2.exe: Microsoft C++ exception: Js::JavascriptExceptionObject at memory location 0x00f6e3cc..
First-chance exception at 0x763c4b32 in IWebBrowser2.exe: Microsoft C++ exception: Js::JavascriptExceptionObject at memory location 0x00f6db9c..
First-chance exception at 0x763c4b32 in IWebBrowser2.exe: 0x80040155: Interface not registered.
First-chance exception at 0x763c4b32 in IWebBrowser2.exe: 0x80040155: Interface not registered.
Yahoo.com и некоторые другие сайты, которые я использовал для тестирования, также загружались нормально, несмотря на наличие этих исключений. Также обратите внимание, что во втором отладочном выводе выше показаны два исключения первого шанса с «Интерфейс не зарегистрирован». Я не получил это для yahoo.com и тех других сайтов.
Мои попытки решить проблему
Когда я впервые столкнулся с этим, я подумал, что это просто ошибка сценария на сайте. Тем не менее, я не видел никаких блоков ошибок Javascript от IWebBrowser2, но просто чтобы быть уверенным, я вызвал метод put_silent (…) объекта IWebBrowser2.
m_pWebBrowser->put_silent(VARIANT_TRUE);
Это все еще разбилось. Я также снял флажок «Отключить отладку сценариев (Internet Explorer)» и «Отключить отладку сценариев (другие)» в дополнительных параметрах Internet Explorer. Это тоже не сработало.
Тогда я подумал, что, возможно, IWebBrowser2 должен эмулировать IE8 или какую-то более новую версию IE для обработки Amazon Japan. Итак, я добавил все эмуляции браузера, описанные в этом MSDN ссылка в реестр для моего приложения. И это тоже не летало.
Я также добавил точку останова исключения для «Js :: JavascriptExceptionObject», чтобы Visual Studio остановилась на месте первого исключения Js :: JavascriptExceptionObject. Исключение произошло в моем цикле GetMessage (…).
MSG msg = { 0 };
while(GetMessage(&msg, NULL, 0, 0))
{
TranslateMessage(&msg);
DispatchMessage(&msg); // <--- Js::JavascriptExceptionObject exception was caught here.
}
Это мне совсем не помогло. Затем я искал в Stackoverflow ту же или похожую проблему и нашел несколько записей, опубликованных несколько месяцев назад.
Много исключений при использовании веб-браузера управления c #
Отладка javaScript в Visual studio. Первые шансы исключения
Оба упомянули то же исключение «первого шанса», которое у меня есть. Автор первой ссылки действительно говорил, что его программа потерпела крах после пяти минут непрерывной работы. Шахта падает сразу после нескольких исключений. Второй не упомянул ни о каких авариях. Оба вопроса не имеют принятых решений. Кроме того, на плакатах не было кодов, которые могут помочь в устранении проблемы. Итак, я собираюсь сделать это.
Без лишних слов, вот мои коды.
main.h
#include <string>
#include <windows.h>
#include "WebBrowser.h"
int CALLBACK WinMain(HINSTANCE, HINSTANCE, LPSTR, int);
LRESULT CALLBACK WindowProc(HWND, UINT, WPARAM, LPARAM);
main.cpp
#include "Main.H"
int CALLBACK WinMain(HINSTANCE hInstance, HINSTANCE hPrevInst, LPSTR pszCmdLine, int nCmdShow)
{
OleInitialize(NULL);
std::wstring classname = L"IWebBrowser2 Crash";
WNDCLASS wc = { 0 };
wc.hInstance = hInstance;
wc.style = CS_HREDRAW | CS_VREDRAW;
wc.lpfnWndProc = WindowProc;
wc.hIcon = LoadIcon(NULL, IDI_APPLICATION);
wc.hbrBackground = GetSysColorBrush(COLOR_3DFACE);
wc.lpszClassName = classname.c_str();
if(!RegisterClass(&wc))
return 0;
SIZE size = { 800, 600 };
HWND hWindow = ::CreateWindow(classname.c_str(), classname.c_str(), WS_OVERLAPPEDWINDOW, 0,
0, size.cx, size.cy, NULL, NULL, hInstance, 0);
if(!hWindow)
return 0;
ShowWindow(hWindow, SW_SHOW);
UpdateWindow(hWindow);
MSG msg = { 0 };
while(GetMessage(&msg, NULL, 0, 0))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return 0;
}
LRESULT CALLBACK WindowProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
static WebBrowser web;
switch(uMsg)
{
case WM_CREATE:
{
RECT r = { 0 };
::GetClientRect(hWnd, &r);
if(web.Create(hWnd, r.right, r.bottom, (HINSTANCE)GetModuleHandle(NULL)))
{
web.Show();
// web.Navigate(L"www.yahoo.com");
web.Navigate(L"www.amazon.co.jp");
}
}
return 0;
case WM_CLOSE:
PostQuitMessage(0);
return 0;
}
return DefWindowProc(hWnd, uMsg, wParam, lParam);
}
WEBBROWSER.H
#include <exdisp.h>
#include <MSHTML.H>
#include <initguid.h>
#include <oleidl.h>
#include <ole2.h>
#pragma comment(lib, "ole32.lib")
//
#include <comip.h>
#include <comdef.h>
#include <comutil.h>
#ifdef _DEBUG
#pragma comment(lib, "comsuppwd.lib")
#else
#pragma comment(lib, "comsuppw.lib")
#endif
class WebBrowser: public IOleClientSite, public IOleInPlaceSite, public IOleInPlaceFrame,
public IStorage
{
HWND m_hWindow;
IOleObject * m_ptrOleObj;
ULONG m_refcount;
IWebBrowser2 * m_pWebBrowser;
//
// IUnknown
//
STDMETHODIMP QueryInterface(REFIID riid, void ** ppvObject)
{
if(riid == IID_IUnknown)
*ppvObject = (LPUNKNOWN)(LPVOID)this;
else if(riid == IID_IOleClientSite)
*ppvObject = (LPOLECLIENTSITE)this;
else if(riid == IID_IOleInPlaceSite)
*ppvObject = (LPOLEINPLACESITE)this;
else if(riid == IID_IOleInPlaceFrame)
*ppvObject = (LPOLEINPLACEFRAME)this;
else if(riid == IID_IStorage)
*ppvObject = (LPSTORAGE)this;
else
{
*ppvObject = NULL;
return E_NOINTERFACE;
}
//
((LPUNKNOWN)*ppvObject)->AddRef();
return S_OK;
}
STDMETHODIMP_(ULONG) AddRef(void)
{
return ++m_refcount;
}
STDMETHODIMP_(ULONG) STDMETHODCALLTYPE Release(void)
{
if(--m_refcount <= 0)
m_refcount = 0;
return m_refcount;
}
//
// IOleWindow
//
STDMETHODIMP GetWindow(HWND * phWindow)
{
*phWindow = m_hWindow;
return S_OK;
}
STDMETHODIMP ContextSensitiveHelp(BOOL fEnterMode)
{
return E_NOTIMPL;
}
//
// IOleInPlaceUIWindow
//
STDMETHODIMP GetBorder(LPRECT lpRectBorder)
{ return E_NOTIMPL;
}
STDMETHODIMP RequestBorderSpace(LPCBORDERWIDTHS pborderwidths)
{ return E_NOTIMPL;
}
STDMETHODIMP SetActiveObject(IOleInPlaceActiveObject *pActiveObject, LPCOLESTR pszObjName)
{ return E_NOTIMPL;
}
STDMETHODIMP SetBorderSpace(LPCBORDERWIDTHS pborderwidths)
{ return E_NOTIMPL;
}
//
// IOleInPlaceFrame
//
STDMETHODIMP EnableModeless(BOOL fEnable)
{ return E_NOTIMPL;
}
STDMETHODIMP InsertMenus(HMENU hmenuShared, LPOLEMENUGROUPWIDTHS lpMenuWidths)
{ return E_NOTIMPL;
}
STDMETHODIMP RemoveMenus(HMENU hmenuShared)
{ return E_NOTIMPL;
}
STDMETHODIMP SetMenu(HMENU hmenuShared, HOLEMENU holemenu, HWND hwndActiveObject)
{ return E_NOTIMPL;
}
STDMETHODIMP SetStatusText(LPCOLESTR pszStatusText)
{ return E_NOTIMPL;
}
STDMETHODIMP TranslateAccelerator(LPMSG lpmsg, WORD wID)
{ return E_NOTIMPL;
}
//
// IOleClientSite
//
STDMETHODIMP SaveObject()
{ return E_NOTIMPL;
}
STDMETHODIMP GetMoniker(DWORD dwAssign, DWORD dwWhichMoniker, IMoniker ** ppmk)
{ return E_NOTIMPL;
}
STDMETHODIMP GetContainer(LPOLECONTAINER FAR* ppContainer)
{
* ppContainer = NULL;
return E_NOINTERFACE;
}
STDMETHODIMP ShowObject()
{ return S_OK;
}
STDMETHODIMP OnShowWindow(BOOL fShow)
{ return E_NOTIMPL;
}
STDMETHODIMP RequestNewObjectLayout()
{ return E_NOTIMPL;
}
//
// IOleInPlaceSite
//
STDMETHODIMP CanInPlaceActivate()
{ return S_OK;
}
STDMETHODIMP DeactivateAndUndo()
{ return E_NOTIMPL;
}
STDMETHODIMP DiscardUndoState()
{ return E_NOTIMPL;
}
STDMETHODIMP GetWindowContext(IOleInPlaceFrame **ppFrame, IOleInPlaceUIWindow **ppDoc,
LPRECT prcPosRect, LPRECT prcClipRect, LPOLEINPLACEFRAMEINFO lpFrameInfo)
{
if(m_hWindow)
{
RECT rSize = { 0 };
GetClientRect(m_hWindow, &rSize);
//
*ppFrame = (LPOLEINPLACEFRAME)this;
*ppDoc = NULL;
*prcPosRect = rSize;
*prcClipRect = rSize;
lpFrameInfo->fMDIApp = FALSE;
lpFrameInfo->hwndFrame = m_hWindow;
lpFrameInfo->haccel = NULL;
lpFrameInfo->cAccelEntries = 0;
}
return S_OK;
}
STDMETHODIMP OnInPlaceActivate()
{ return S_OK;
}
STDMETHODIMP OnInPlaceDeactivate()
{ return S_OK;
}
STDMETHODIMP OnPosRectChange(LPCRECT prcPosRect)
{
return S_OK;
}
STDMETHODIMP OnUIActivate()
{ return S_OK;
}
STDMETHODIMP OnUIDeactivate(BOOL fUndoable)
{ return S_OK;
}
STDMETHODIMP Scroll(SIZE scrollExtent)
{ return E_NOTIMPL;
}
//
// IStorage
//
STDMETHODIMP CreateStream(const WCHAR * pwcsName, DWORD dwMode, DWORD dwReserved1,
DWORD dwReserved2, LPSTREAM * ppstm)
{ return E_NOTIMPL;
}
STDMETHODIMP OpenStream(const WCHAR * pwcsName, void * pvReserved1, DWORD dwMode,
DWORD dwReserved2, LPSTREAM * ppstm)
{ return E_NOTIMPL;
}
STDMETHODIMP CreateStorage(const WCHAR * pwcsName, DWORD dwMode, DWORD dwReserved1,
DWORD dwReserved2, LPSTORAGE * ppstg)
{ return E_NOTIMPL;
}
STDMETHODIMP OpenStorage(const WCHAR * pwcsName, LPSTORAGE pstgPriority, DWORD dwMode,
SNB snbExclude, DWORD dwReserved, LPSTORAGE * ppstg)
{ return E_NOTIMPL;
}
STDMETHODIMP CopyTo(DWORD ciidExclude, IID const * rgiidExclude, SNB snbExclude,
LPSTORAGE pstgDest)
{ return E_NOTIMPL;
}
STDMETHODIMP MoveElementTo(const WCHAR * pwcsName, LPSTORAGE pstgDest, LPCWSTR pwcsNewName,
DWORD dwFlags)
{ return E_NOTIMPL;
}
STDMETHODIMP Commit(DWORD dwCommitFlags)
{ return E_NOTIMPL;
}
STDMETHODIMP Revert()
{ return E_NOTIMPL;
}
STDMETHODIMP EnumElements(DWORD dwReserved1, VOID * pvReserved2, DWORD dwReserved3,
IEnumSTATSTG ** ppenum)
{ return E_NOTIMPL;
}
STDMETHODIMP DestroyElement(const WCHAR * pwcsName)
{ return E_NOTIMPL;
}
STDMETHODIMP RenameElement(const WCHAR * pwcsOldName, const WCHAR * pwcsNewName)
{ return E_NOTIMPL;
}
STDMETHODIMP SetElementTimes(const WCHAR * pwcsName, FILETIME const * pctime,
FILETIME const * patime, FILETIME const * pmtime)
{ return E_NOTIMPL;
}
STDMETHODIMP SetStateBits(DWORD dwStateBits, DWORD dwMask)
{ return E_NOTIMPL;
}
STDMETHODIMP Stat(STATSTG * pstatstg, DWORD dwStatFlag)
{ return E_NOTIMPL;
}
STDMETHODIMP SetClass(REFCLSID clsid)
{ return S_OK;
}
public:
WebBrowser() : m_hWindow(NULL), m_refcount(0), m_ptrOleObj(NULL), m_pWebBrowser(NULL) {}
static LRESULT CALLBACK EventHandler(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
return DefWindowProc(hWnd, uMsg, wParam, lParam);
}
bool Create(HWND hParent, int width, int height, HINSTANCE hInstance)
{
WNDCLASS wc = { 0 };
wc.hInstance = hInstance;
wc.style = CS_VREDRAW | CS_HREDRAW;
wc.lpszClassName = L"WebBrowser";
wc.lpfnWndProc = EventHandler;
wc.hbrBackground = GetSysColorBrush(COLOR_3DFACE);
if(!::RegisterClass(&wc))
return false;
m_hWindow = CreateWindow(L"WebBrowser", NULL, WS_BORDER | WS_CHILD, 0, 0, width, height,
hParent, NULL, hInstance, 0);
if(!m_hWindow)
return false;
RECT rSize = { 0, 0, width, height };
// Create the ActiveX WebBrowser control.
HRESULT hres = OleCreate(CLSID_WebBrowser, IID_IOleObject, OLERENDER_DRAW, NULL, this,
(LPSTORAGE)this, (LPVOID*)&m_ptrOleObj);
if(FAILED(hres))
return false;
// Inform the object that it is being embedded in an OLE container.
if(FAILED(OleSetContainedObject(m_ptrOleObj, TRUE)))
return false;
// Show our web browser control.
if(FAILED(m_ptrOleObj->DoVerb(OLEIVERB_SHOW, NULL, this, -1, m_hWindow, &rSize)))
return false;
// Obtain a pointer to an IWebBrowser interface so we can control the browser.
if(FAILED(m_ptrOleObj->QueryInterface(IID_IWebBrowser2, (LPVOID*)&m_pWebBrowser)))
return false;
// Suppress scripting error box
m_pWebBrowser->put_Silent(VARIANT_TRUE);
return true;
}
void Navigate(LPCWSTR pszURL)
{
_ASSERTE(m_pWebBrowser != NULL);
_bstr_t url = pszURL;
variant_t empty;
m_pWebBrowser->Navigate(url, &empty.GetVARIANT(), &empty.GetVARIANT(),
&empty.GetVARIANT(), &empty.GetVARIANT());
}
void Show()
{
ShowWindow(m_hWindow, SW_SHOW);
}
};
ОБНОВЛЕНИЕ: 29 октября 2014 года. Обходной путь.
Хорошо, я нашел обходной путь к этой проблеме — не решение, а обходной путь. И это может сделать для некоторых людей, как и в моем случае.
Что я сделал, вместо того, чтобы разместить в своем приложении элемент управления IWebBrowser2, я использовал OLE Automation для запуска экземпляра Internet Explorer, получил дескриптор окна и установил свое приложение в качестве родительского.
В результате в моем приложении будет размещен веб-браузер. Однако есть одна оговорка. Этот прием не работает в Vista, только в Windows 7 и 8. В Windows Vista Internet Explorer всегда будет открываться отдельно, используя этот метод, независимо от того, получили ли вы его дескриптор окна, добавьте WS_CHILD к его стилю и установите окно в качестве вашего родитель. Вызов IWebBrowser2 :: put_Visible (VARIANT_FALSE) для скрытия окна фрейма веб-браузера не работает ни в Vista, поскольку IE открывается немедленно, независимо от того, вызываете ли вы этот метод до или после успешного вызова CoCreateInstance. Это противоречит тому, что Руководство MSDN говорит об IWebBrowser2.
«Когда объект InternetExplorer создается впервые, окно приложения скрывается. Для отображения приложения необходимо установить IWebBrowser2 :: Visible в VARIANT_TRUE».
Вероятно, можно заставить этот трюк работать в Vista, но он требует большего изучения, и я спешу. Как я уже сказал, это подойдет для моего случая, так как это всего лишь внутренняя программа, а наши основные блоки работают под управлением Windows 7 и 8.
Опять же, это обходной путь. Не решение Итак, я все еще надеюсь, что кто-то может помочь выяснить причину аварии и как ее предотвратить.
WEBBROWSER.H
#include <shlguid.h>
//
#include <comutil.h>
#ifdef _DEBUG
#pragma comment(lib, "comsuppwd.lib")
#else
#pragma comment(lib, "comsuppw.lib")
#endif
class WebBrowser
{
HWND m_hBrowser;
IWebBrowser2 * m_pWebBrowser;
public:
WebBrowser() : m_pWebBrowser(NULL) {}
bool Create(HWND hParent, int width, int height, HINSTANCE hInstance)
{
// Use OLE Automation to control Internet Explorer.
if(FAILED(CoCreateInstance(CLSID_InternetExplorer, NULL, CLSCTX_SERVER, IID_IWebBrowser2,
(LPVOID*)&m_pWebBrowser)))
return false;
IServiceProvider* pServiceProvider = NULL;
if (SUCCEEDED(m_pWebBrowser->QueryInterface(IID_IServiceProvider,
(void**)&pServiceProvider)))
{
IOleWindow* pWindow = NULL;
if (SUCCEEDED(pServiceProvider->QueryService(SID_SShellBrowser, IID_IOleWindow,
(void**)&pWindow)))
{
if (SUCCEEDED(pWindow->GetWindow(&m_hBrowser)))
{
SetWindowLong(m_hBrowser, GWL_STYLE, WS_CHILD);
SetWindowLong(m_hBrowser, GWL_HWNDPARENT, (LONG)hParent);
}
else
{
MessageBox(NULL, L"Unable to obtain window handle of the web browser.",
L"IWebBrowser2", MB_OK);
}
pWindow->Release();
}
pServiceProvider->Release();
}
return true;
}
void Navigate(LPCWSTR pszURL)
{
_bstr_t url = pszURL;
variant_t empty;
empty.scode = DISP_E_PARAMNOTFOUND;
empty.vt = VT_ERROR;
m_pWebBrowser->Navigate(url, &empty.GetVARIANT(), &empty.GetVARIANT(),
&empty.GetVARIANT(), &empty.GetVARIANT());
}
void Show()
{
ShowWindow(m_hBrowser, SW_SHOW);
}
void SetSize(long width, long height)
{
SetWindowPos(m_hBrowser, 0, 0, 0, 0, 0, SWP_NOZORDER | SWP_NOSIZE | SWP_NOREDRAW);
SetWindowPos(m_hBrowser, 0, 0, 0, width, height, SWP_NOZORDER | SWP_NOMOVE |
SWP_NOREDRAW);
}
};
Задача ещё не решена.