axmol/cocos/ui/UIWebViewImpl_win32.cpp

843 lines
26 KiB
C++

#include "platform/CCPlatformConfig.h"
#if CC_TARGET_PLATFORM == CC_PLATFORM_WIN32
#include <atlbase.h>
#include <atlwin.h>
#include <ExDispid.h>
#include <UrlMon.h>
#include "UIWebViewImpl_win32.h"
#include "UIWebView.h"
#include "base/CCDirector.h"
#include "platform/CCFileUtils.h"
#include "platform/CCGLView.h"
class Win32WebControl : public DWebBrowserEvents2
{
public:
Win32WebControl();
bool createWebView(
const std::function<bool (const std::string &)> &shouldStartLoading,
const std::function<void (const std::string &)> &didFinishLoading,
const std::function<void (const std::string &)> &didFailLoading,
const std::function<void (const std::string &)> &onJsCallback);
void removeWebView();
void setWebViewRect(const int left, const int top, const int width, const int height);
void setJavascriptInterfaceScheme(const std::string &scheme) const;
void loadData(const std::string &data, const std::string &MIMEType, const std::string &encoding, const std::string &baseURL) const;
void loadHTMLString(const std::string &html, const std::string &baseURL);
void loadURL(const std::string &url) const;
void loadFile(const std::string &filePath) const;
void stopLoading() const;
void reload() const;
bool canGoBack() const;
bool canGoForward() const;
void goBack() const;
void goForward() const;
void evaluateJS(const std::string &js) const;
void setScalesPageToFit(const bool scalesPageToFit) const;
void setWebViewVisible(const bool visible) const;
// Implement IUnknown
virtual HRESULT STDMETHODCALLTYPE QueryInterface(REFIID riid, void **ppvObject);
virtual ULONG STDMETHODCALLTYPE AddRef(void);
virtual ULONG STDMETHODCALLTYPE Release(void);
// Implement IDispatch
virtual HRESULT STDMETHODCALLTYPE GetTypeInfoCount(UINT *pctinfo);
virtual HRESULT STDMETHODCALLTYPE GetTypeInfo(UINT iTInfo, LCID lcid, ITypeInfo **ppTInfo);
virtual HRESULT STDMETHODCALLTYPE GetIDsOfNames(
REFIID riid,
LPOLESTR *rgszNames,
UINT cNames,
LCID lcid,
DISPID *rgDispId);
virtual HRESULT STDMETHODCALLTYPE Invoke(
DISPID dispIdMember,
REFIID riid,
LCID lcid,
WORD wFlags,
DISPPARAMS *pDispParams,
VARIANT *pVarResult,
EXCEPINFO *pExcepInfo,
UINT *puArgErr);
private:
CAxWindow _winContainer;
IWebBrowser2 *_webBrowser2;
IConnectionPoint *_connectionPoint;
IDispatch *_htmlDoc;
bool _goBackEnabled;
bool _goForwardEnabled;
DWORD _cookie;
ULONG _reference;
std::function<bool (const std::string &)> _shouldStartLoading;
std::function<void (const std::string &)> _didFinishLoading;
std::function<void (const std::string &)> _didFailLoading;
std::function<void (const std::string &)> _onJsCallback;
std::string _htmlWillLoad;
static bool s_isInitialized;
static CComModule s_module;
static void lazyInit();
void _loadHTMLString(const std::string &html) const;
void loadURL(BSTR url) const;
void loadURL(const std::wstring &url) const;
};
namespace cocos2d {
namespace experimental {
namespace ui {
WebViewImpl::WebViewImpl(WebView *webView) : _createSucceeded(false), _systemWebControl(nullptr), _webView(webView)
{
_systemWebControl = new Win32WebControl();
if (_systemWebControl == nullptr)
{
return;
}
_createSucceeded = _systemWebControl->createWebView(
[this](const std::string &url)->bool {
std::function<bool (WebView *sender, const std::string &url)> shouldStartLoading = _webView->getOnShouldStartLoading();
if (shouldStartLoading != nullptr)
{
return onShouldStartLoading(_webView, url);
}
return true;
},
[this](const std::string &url) {
WebView::ccWebViewCallback didFinishLoading = _webView->getOnDidFinishLoading();
if (didFinishLoading != nullptr)
{
didFinishLoading(_webView, url);
}
},
[this](const std::string &url) {
WebView::ccWebViewCallback didFinishLoading = _webView->getOnDidFailLoading();
if (didFailLoading != nullptr)
{
didFailLoading(_webView, url);
}
},
[this](const std::string &url) {
WebView::ccWebViewCallback onJsCallback = _webView->getOnJSCallback();
if (onJsCallback != nullptr)
{
onJsCallback(_webView, url);
}
});
}
WebViewImpl::~WebViewImpl()
{
if (_systemWebControl != nullptr)
{
_systemWebControl->removeWebView();
delete _systemWebControl;
_systemWebControl = nullptr;
}
}
void WebViewImpl::loadData(const Data &data, const std::string &MIMEType, const std::string &encoding, const std::string &baseURL)
{
if (_createSucceeded)
{
std::string dataString(reinterpret_cast<char *>(data.getBytes()), static_cast<unsigned int>(data.getSize()));
_systemWebControl->loadData(dataString, MIMEType, encoding, baseURL);
}
}
void WebViewImpl::loadHTMLString(const std::string &string, const std::string &baseURL)
{
if (_createSucceeded)
{
_systemWebControl->loadHTMLString(string, baseURL);
}
}
void WebViewImpl::loadURL(const std::string &url)
{
if (_createSucceeded)
{
_systemWebControl->loadURL(url);
}
}
void WebViewImpl::loadFile(const std::string &fileName)
{
if (_createSucceeded)
{
std::string fullPath = FileUtils::getInstance()->fullPathForFilename(fileName);
_systemWebControl->loadFile(fullPath);
}
}
void WebViewImpl::stopLoading()
{
if (_createSucceeded)
{
_systemWebControl->stopLoading();
}
}
void WebViewImpl::reload()
{
if (_createSucceeded)
{
_systemWebControl->reload();
}
}
bool WebViewImpl::canGoBack()
{
if (_createSucceeded)
{
return _systemWebControl->canGoBack();
}
return false;
}
bool WebViewImpl::canGoForward()
{
if (_createSucceeded)
{
return _systemWebControl->canGoForward();
}
return false;
}
void WebViewImpl::goBack()
{
if (_createSucceeded)
{
_systemWebControl->goBack();
}
}
void WebViewImpl::goForward()
{
if (_createSucceeded)
{
_systemWebControl->goForward();
}
}
void WebViewImpl::setJavascriptInterfaceScheme(const std::string &scheme)
{
if (_createSucceeded)
{
_systemWebControl->setJavascriptInterfaceScheme(scheme);
}
}
void WebViewImpl::evaluateJS(const std::string &js)
{
if (_createSucceeded)
{
_systemWebControl->evaluateJS(js);
}
}
void WebViewImpl::setScalesPageToFit(const bool scalesPageToFit)
{
if (_createSucceeded)
{
_systemWebControl->setScalesPageToFit(scalesPageToFit);
}
}
void WebViewImpl::draw(Renderer *renderer, Mat4 const &transform, uint32_t flags)
{
if (_createSucceeded && (flags & Node::FLAGS_TRANSFORM_DIRTY))
{
Director *directorInstance = cocos2d::Director::getInstance();
GLView *glView = directorInstance->getOpenGLView();
const Size &frameSize = glView->getFrameSize();
const Size &winSize = directorInstance->getWinSize();
Vec2 leftBottom = this->_webView->convertToWorldSpace(Point::ZERO);
Vec2 rightTop = this->_webView->convertToWorldSpace(Point(_webView->getContentSize().width, _webView->getContentSize().height));
float uiLeft = frameSize.width / 2 + (leftBottom.x - winSize.width / 2) * glView->getScaleX();
float uiTop = frameSize.height / 2 - (rightTop.y - winSize.height / 2) * glView->getScaleY();
_systemWebControl->setWebViewRect(uiLeft, uiTop,
(rightTop.x - leftBottom.x) * glView->getScaleX(),
(rightTop.y - leftBottom.y) * glView->getScaleY());
}
}
void WebViewImpl::setVisible(bool visible)
{
if (_createSucceeded)
{
_systemWebControl->setWebViewVisible(visible);
}
}
} // namespace ui
} // namespace experimental
} //namespace cocos2d
//
// Implement Win32WebControl
//
bool Win32WebControl::s_isInitialized = false;
CComModule Win32WebControl::s_module;
void Win32WebControl::lazyInit()
{
HWND hwnd = cocos2d::Director::getInstance()->getOpenGLView()->getWin32Window();
LONG style = GetWindowLong(hwnd, GWL_STYLE);
SetWindowLong(hwnd, GWL_STYLE, style | WS_CLIPCHILDREN);
HINSTANCE hInstance = GetModuleHandle(NULL);
CoInitialize(NULL);
s_module.Init(NULL, hInstance);
AtlAxWinInit();
}
static HGLOBAL globalAllocWstringFromString(const std::string &str)
{
int len = MultiByteToWideChar(CP_UTF8, 0, str.c_str(), -1, NULL, 0);
if (len <= 0)
{
return NULL;
}
HGLOBAL wstr = GlobalAlloc(GMEM_FIXED | GMEM_ZEROINIT, (len + 1) * sizeof(WCHAR));
if (wstr == NULL)
{
return NULL;
}
MultiByteToWideChar(CP_UTF8, 0, str.c_str(), -1, (WCHAR *)wstr, len);
return wstr;
}
static std::string bstr2string(BSTR bstr)
{
wchar_t *str = OLE2W(bstr);
std::string ret;
int len = WideCharToMultiByte(CP_UTF8, 0, str, -1, NULL, 0, NULL, NULL);
if (len > 0)
{
HGLOBAL utf8Str = GlobalAlloc(GMEM_FIXED | GMEM_ZEROINIT, len + 1);
if (utf8Str != NULL)
{
WideCharToMultiByte(CP_UTF8, 0, str, -1, (char *)utf8Str, len, NULL, NULL);
ret.assign((char *)utf8Str);
GlobalFree(utf8Str);
}
}
return ret;
}
static bool isUrlJs(BSTR url)
{
return wcsncmp(OLE2W(url), L"javascript:", 11) == 0;
}
Win32WebControl::Win32WebControl()
: _webBrowser2(NULL)
, _connectionPoint(NULL)
, _htmlDoc(NULL)
, _goBackEnabled(true)
, _goForwardEnabled(true)
, _cookie(0)
, _reference(0)
, _shouldStartLoading(nullptr)
, _didFinishLoading(nullptr)
, _didFailLoading(nullptr)
{
if (!s_isInitialized)
{
lazyInit();
}
}
bool Win32WebControl::createWebView(
const std::function<bool (const std::string &)> &shouldStartLoading,
const std::function<void (const std::string &)> &didFinishLoading,
const std::function<void (const std::string &)> &didFailLoading,
const std::function<void (const std::string &)> &onJsCallback)
{
bool ret = false;
IConnectionPointContainer *container = NULL;
do
{
HWND hwnd = cocos2d::Director::getInstance()->getOpenGLView()->getWin32Window();
_winContainer.Create(hwnd, NULL, NULL, WS_CHILD | WS_VISIBLE);
HRESULT hr;
hr = _winContainer.CreateControl(L"shell.Explorer.2");
CC_BREAK_IF(FAILED(hr));
hr = _winContainer.QueryControl(__uuidof(IWebBrowser2), (void **)&_webBrowser2);
CC_BREAK_IF(FAILED(hr) || _webBrowser2 == NULL);
_webBrowser2->put_Silent(VARIANT_TRUE);
VARIANT var;
VariantInit(&var);
var.vt = VT_BSTR;
var.bstrVal = SysAllocString(L"about:blank");
hr = _webBrowser2->Navigate2(&var, NULL, NULL, NULL, NULL);
SysFreeString(var.bstrVal);
VariantClear(&var);
CC_BREAK_IF(FAILED(hr));
hr = _webBrowser2->QueryInterface(IID_IConnectionPointContainer, (void **)&container);
CC_BREAK_IF(FAILED(hr));
hr = container->FindConnectionPoint(DIID_DWebBrowserEvents2, &_connectionPoint);
CC_BREAK_IF(FAILED(hr));
hr = _connectionPoint->Advise(this, &_cookie);
CC_BREAK_IF(FAILED(hr));
hr = _webBrowser2->get_Document(&_htmlDoc);
CC_BREAK_IF(FAILED(hr));
ret = true;
} while (0);
if (!ret)
{
removeWebView();
}
if (container != NULL)
{
container->Release();
container = NULL;
}
_shouldStartLoading = shouldStartLoading;
_didFinishLoading = didFinishLoading;
_didFailLoading = didFailLoading;
_onJsCallback = onJsCallback;
return ret;
}
void Win32WebControl::removeWebView()
{
if (_connectionPoint != NULL)
{
_connectionPoint->Unadvise(_cookie);
_connectionPoint->Release();
_connectionPoint = NULL;
}
if (_htmlDoc != NULL)
{
_htmlDoc->Release();
_htmlDoc = NULL;
}
if (_webBrowser2 != NULL)
{
_webBrowser2->Release();
_webBrowser2 = NULL;
}
_winContainer.DestroyWindow();
}
void Win32WebControl::setWebViewRect(const int left, const int top, const int width, const int height)
{
_winContainer.MoveWindow(left, top, width, height);
}
void Win32WebControl::setJavascriptInterfaceScheme(const std::string &scheme) const
{
}
void Win32WebControl::loadData(const std::string &data, const std::string &MIMEType, const std::string &encoding, const std::string &baseURL) const
{
}
void Win32WebControl::loadHTMLString(const std::string &html, const std::string &baseURL)
{
//if (baseURL.empty())
//{
_loadHTMLString(html);
//}
//else
//{
// _htmlWillLoad = html;
// loadURL(baseURL);
//}
}
void Win32WebControl::_loadHTMLString(const std::string &html) const
{
bool flag = false;
HGLOBAL htmlText = globalAllocWstringFromString(html);
if (htmlText != NULL)
{
IStream *stream = NULL;
if (SUCCEEDED(CreateStreamOnHGlobal(htmlText, FALSE, &stream)))
{
IPersistStreamInit *persistStreamInit = NULL;
if (SUCCEEDED(_htmlDoc->QueryInterface(IID_IPersistStreamInit, (void **)&persistStreamInit)))
{
if (SUCCEEDED(persistStreamInit->InitNew()) && SUCCEEDED(persistStreamInit->Load(stream)))
{
flag = true;
}
persistStreamInit->Release();
}
stream->Release();
}
GlobalFree(htmlText);
}
if (flag)
{
if (_didFinishLoading != nullptr)
{
std::string str("data:text/html,");
str.append(html);
_didFinishLoading(str);
}
}
else
{
if (_didFailLoading != nullptr)
{
std::string str("data:text/html,");
str.append(html);
_didFailLoading(str);
}
}
}
void Win32WebControl::loadURL(BSTR url) const
{
VARIANT var;
VariantInit(&var);
var.vt = VT_BSTR;
var.bstrVal = url;
_webBrowser2->Navigate2(&var, NULL, NULL, NULL, NULL);
VariantClear(&var);
}
void Win32WebControl::loadURL(const std::wstring &url) const
{
BSTR bstr = SysAllocString(url.c_str());
loadURL(bstr);
SysFreeString(bstr);
}
void Win32WebControl::loadURL(const std::string &url) const
{
HGLOBAL unicodeStr = globalAllocWstringFromString(url);
if (unicodeStr != NULL)
{
loadURL(std::wstring((WCHAR *)unicodeStr));
GlobalFree(unicodeStr);
}
}
void Win32WebControl::loadFile(const std::string &filePath) const
{
HGLOBAL unicodeStr = globalAllocWstringFromString(filePath);
if (unicodeStr != NULL)
{
loadURL(std::wstring((WCHAR *)unicodeStr));
GlobalFree(unicodeStr);
}
}
void Win32WebControl::stopLoading() const
{
_webBrowser2->Stop();
}
void Win32WebControl::reload() const
{
_webBrowser2->Refresh();
}
bool Win32WebControl::canGoBack() const
{
return _goBackEnabled;
}
bool Win32WebControl::canGoForward() const
{
return _goForwardEnabled;
}
void Win32WebControl::goBack() const
{
_webBrowser2->GoBack();
}
void Win32WebControl::goForward() const
{
_webBrowser2->GoForward();
}
void Win32WebControl::evaluateJS(const std::string &js) const
{
std::string url("javascript:");
url.append(js);
loadURL(url);
}
void Win32WebControl::setScalesPageToFit(const bool scalesPageToFit) const
{
}
void Win32WebControl::setWebViewVisible(const bool visible) const
{
_webBrowser2->put_Visible(visible ? VARIANT_TRUE : VARIANT_FALSE);
}
// Implement IUnknown
HRESULT STDMETHODCALLTYPE Win32WebControl::QueryInterface(REFIID riid, void **ppvObject)
{
BOOL isBadPtr = FALSE;
CCASSERT(!(isBadPtr = IsBadWritePtr(ppvObject, sizeof(void *))), "");
if (isBadPtr)
{
return E_POINTER;
}
*ppvObject = NULL;
if (IsEqualIID(riid, IID_IUnknown) || IsEqualIID(riid, IID_IDispatch) || IsEqualIID(riid, DIID_DWebBrowserEvents2))
{
AddRef();
*ppvObject = this;
return S_OK;
}
return E_NOINTERFACE;
}
ULONG STDMETHODCALLTYPE Win32WebControl::AddRef(void)
{
InterlockedIncrement(&_reference);
return _reference;
}
ULONG STDMETHODCALLTYPE Win32WebControl::Release(void)
{
CCASSERT(_reference > 0, "reference count should greater than 0");
InterlockedDecrement(&_reference);
// do not delete this if _reference == 0, otherwise, it will crash when call removeWebView
return _reference;
}
// Implement IDispatch
HRESULT STDMETHODCALLTYPE Win32WebControl::GetTypeInfoCount(UINT *pctinfo)
{
*pctinfo = 0;
return S_OK;
}
HRESULT STDMETHODCALLTYPE Win32WebControl::GetTypeInfo(UINT iTInfo, LCID lcid, ITypeInfo **ppTInfo)
{
UNREFERENCED_PARAMETER(iTInfo);
UNREFERENCED_PARAMETER(lcid);
*ppTInfo = NULL;
return E_NOTIMPL;
}
HRESULT STDMETHODCALLTYPE Win32WebControl::GetIDsOfNames(
REFIID riid,
LPOLESTR *rgszNames,
UINT cNames,
LCID lcid,
DISPID *rgDispId)
{
UNREFERENCED_PARAMETER(riid);
UNREFERENCED_PARAMETER(rgszNames);
UNREFERENCED_PARAMETER(cNames);
UNREFERENCED_PARAMETER(lcid);
UNREFERENCED_PARAMETER(rgDispId);
return E_NOTIMPL;
}
HRESULT STDMETHODCALLTYPE Win32WebControl::Invoke(
DISPID dispIdMember,
REFIID riid,
LCID lcid,
WORD wFlags,
DISPPARAMS *pDispParams,
VARIANT *pVarResult,
EXCEPINFO *pExcepInfo,
UINT *puArgErr)
{
if (!IsEqualIID(riid, IID_NULL)) // riid should always be IID_NULL
{
return DISP_E_UNKNOWNINTERFACE;
}
switch (dispIdMember)
{
case DISPID_COMMANDSTATECHANGE:
if (pDispParams != NULL && pDispParams->cArgs == 2)
{
const VARIANTARG *rgvarg = pDispParams->rgvarg;
if (rgvarg[0].vt == VT_BOOL && rgvarg[1].vt == VT_I4)
{
switch (rgvarg[1].intVal)
{
case CSC_NAVIGATEFORWARD:
_goForwardEnabled = (rgvarg[0].boolVal != VARIANT_FALSE); // VARIANT_TRUE is -1
return S_OK;
case CSC_NAVIGATEBACK:
_goBackEnabled = (rgvarg[0].boolVal != VARIANT_FALSE); // VARIANT_TRUE is -1
return S_OK;
default:
break;
}
}
}
break;
case DISPID_BEFORENAVIGATE2:
if (pDispParams != NULL && pDispParams->cArgs == 7)
{
VARIANTARG *rgvarg = pDispParams->rgvarg;
if (rgvarg[6].vt == VT_DISPATCH && rgvarg[6].pdispVal == _webBrowser2)
{
if (rgvarg[0].vt == (VT_BYREF | VT_BOOL) && rgvarg[5].vt == (VT_BYREF | VT_VARIANT))
{
VARIANT_BOOL *cancel = rgvarg[0].pboolVal;
BSTR url = rgvarg[5].pvarVal->bstrVal;
*cancel = VARIANT_FALSE;
if (isUrlJs(url))
{
if (_onJsCallback != nullptr)
{
_onJsCallback(bstr2string(url));
}
}
else
{
if (_shouldStartLoading != nullptr)
{
*cancel = _shouldStartLoading(bstr2string(url)) ? VARIANT_FALSE : VARIANT_TRUE; // VARIANT_TRUE is -1
}
}
return S_OK;
}
}
}
break;
case DISPID_DOCUMENTCOMPLETE:
if (pDispParams != NULL && pDispParams->cArgs == 2)
{
const VARIANTARG *rgvarg = pDispParams->rgvarg;
if (rgvarg[1].vt == VT_DISPATCH && rgvarg[1].pdispVal == _webBrowser2 && rgvarg[0].vt == (VT_BYREF | VT_VARIANT))
{
READYSTATE state;
if (SUCCEEDED(_webBrowser2->get_ReadyState(&state)) && state == READYSTATE_COMPLETE)
{
BSTR url = rgvarg[0].pvarVal->bstrVal;
if (_didFinishLoading != nullptr && !isUrlJs(url)) // ignore js
{
_didFinishLoading(bstr2string(url));
}
if (!_htmlWillLoad.empty())
{
_loadHTMLString(_htmlWillLoad);
_htmlWillLoad.clear();
}
return S_OK;
}
}
}
break;
case DISPID_NAVIGATECOMPLETE2:
if (pDispParams != NULL && pDispParams->cArgs == 2)
{
const VARIANTARG *rgvarg = pDispParams->rgvarg;
if (rgvarg[1].vt == VT_DISPATCH && rgvarg[1].pdispVal == _webBrowser2)
{
if (rgvarg[0].vt == (VT_BYREF | VT_VARIANT))
{
BSTR url = rgvarg[0].pvarVal->bstrVal;
return S_OK;
}
}
}
break;
case DISPID_NAVIGATEERROR:
if (pDispParams != NULL && pDispParams->cArgs == 5)
{
const VARIANTARG *rgvarg = pDispParams->rgvarg;
if (rgvarg[4].vt == VT_DISPATCH && rgvarg[4].pdispVal == _webBrowser2)
{
if (rgvarg[3].vt == (VT_BYREF | VT_VARIANT) && rgvarg[1].vt == (VT_BYREF | VT_VARIANT) && rgvarg[0].vt == (VT_BYREF | VT_BOOL))
{
VARIANT_BOOL *cancel = rgvarg[0].pboolVal;
HRESULT codes = rgvarg[1].pvarVal->lVal;
BSTR url = rgvarg[3].pvarVal->bstrVal;
if (_didFailLoading != nullptr && !isUrlJs(url)) // ignore js
{
_didFailLoading(bstr2string(url));
}
*cancel = VARIANT_FALSE;
return S_OK;
}
}
}
break;
case DISPID_PROGRESSCHANGE:
if (pDispParams != NULL && pDispParams->cArgs == 2)
{
const VARIANTARG *rgvarg = pDispParams->rgvarg;
if (rgvarg[0].vt == VT_I4 && rgvarg[1].vt == VT_I4)
{
LONG maxProgress = rgvarg[0].lVal;
LONG curProgress = rgvarg[1].lVal;
return S_OK;
}
}
break;
case DISPID_NEWWINDOW2:
if (pDispParams != NULL && pDispParams->cArgs == 2)
{
const VARIANTARG *rgvarg = pDispParams->rgvarg;
if (rgvarg[0].vt == (VT_BYREF | VT_BOOL) && rgvarg[1].vt == (VT_BYREF | VT_DISPATCH))
{
VARIANT_BOOL *cancel = rgvarg[0].pboolVal;
IDispatch **dis = rgvarg[1].ppdispVal;
*dis = NULL;
*cancel = VARIANT_TRUE; // forbit to create new window
return S_OK;
}
}
break;
case DISPID_NEWWINDOW3:
if (pDispParams != NULL && pDispParams->cArgs == 5)
{
const VARIANTARG *rgvarg = pDispParams->rgvarg;
if (rgvarg[0].vt == VT_BSTR && rgvarg[1].vt == VT_BSTR && rgvarg[2].vt == VT_I4
&& rgvarg[3].vt == (VT_BYREF | VT_BOOL) && rgvarg[4].vt == (VT_BYREF | VT_DISPATCH))
{
BSTR url = rgvarg[0].bstrVal;
BSTR urlContext = rgvarg[1].bstrVal;
LONG flags = rgvarg[2].lVal;
VARIANT_BOOL *cancel = rgvarg[3].pboolVal;
IDispatch **dis = rgvarg[4].ppdispVal;
*dis = NULL;
*cancel = VARIANT_TRUE; // forbit to create new window
loadURL(url);
return S_OK;
}
}
break;
default:
break;
}
return E_NOTIMPL;
}
#endif // CC_TARGET_PLATFORM == CC_PLATFORM_WIN32