MicrosoftEdge / WebView2Browser

A web browser built with the Microsoft Edge WebView2 control.

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

How to create new tab dynamically on ICoreWebView2NewWindowRequestedEventHandler event?

Dave-Jalpan opened this issue · comments

How I can open new tab instead of new window? This is not bug but I am nav to C++ so not sure how to achieve this....

I have written following code to open new window in same tab but I want to open it in new tab instead. So, how to create new tab on ICoreWebView2NewWindowRequestedEvent?

HRESULT BrowserWindow::HandleNewWindowRequested(size_t tabId, ICoreWebView2* webview, ICoreWebView2NewWindowRequestedEventArgs* args)
{
wil::unique_cotaskmem_string uri;
std::wstring str;
if (SUCCEEDED(args->get_Uri(&uri)))
str = uri.get();
m_tabs.at(m_activeTabId)->m_contentWebView->Navigate(uri.get());
ICoreWebView2Deferral *deferral;
args->GetDeferral(&deferral);
return NULL;
}

@peiche-jessica @david-risney @mrsteamfist @champnic
How to create new tab from C++ ICoreWebView2NewWindowRequestedEventHandler?

Hi, @Dave-Jalpan

You should be able to use ICoreWebView2NewWindowRequestedEventArgs::put_NewWindow to pass an ICoreWebView2 to be used for the request. If you create a new tab (e.g., see MG_CREATE_TAB calling Tab::CreateNewTab(...)) you could then use it's m_contentWebView as target for the new window.

You would likely need to add a callback to Tab::CreateNewTab(...) so you can safely access the m_contentWebView; and update the UI for the new tab accordingly.

Hope this helps.
Thanks,
Luis

Hi, @Dave-Jalpan

You should be able to use ICoreWebView2NewWindowRequestedEventArgs::put_NewWindow to pass an ICoreWebView2 to be used for the request. If you create a new tab (e.g., see MG_CREATE_TAB calling Tab::CreateNewTab(...)) you could then use it's m_contentWebView as target for the new window.

You would likely need to add a callback to Tab::CreateNewTab(...) so you can safely access the m_contentWebView; and update the UI for the new tab accordingly.

Hope this helps.
Thanks,
Luis

@Syul968 Thank you for reply, between I had tried following but no success. I am more on to C# so not sure how to achieve what you said in C++ Win32 programming. Could you please help to explain with example?

What I tried so far is

HRESULT BrowserWindow::HandleNewWindowRequested(size_t tabId, ICoreWebView2* webview, ICoreWebView2NewWindowRequestedEventArgs* args)
{
wil::unique_cotaskmem_string uri;
std::wstring str;
if (SUCCEEDED(args->get_Uri(&uri)))
str = uri.get();
m_tabs.at(m_activeTabId)->m_contentWebView->Navigate(uri.get());
ICoreWebView2Deferral *deferral;
args->GetDeferral(&deferral);
return NULL;
}
HRESULT BrowserWindow::HandleNewWindowRequested(size_t tabId, ICoreWebView2* webview, ICoreWebView2NewWindowRequestedEventArgs* args)
{
    args->put_NewWindow(webview);
    return S_OK;
}

when i tried.....

HRESULT BrowserWindow::HandleNewWindowRequested(size_t tabId, ICoreWebView2* webview, ICoreWebView2NewWindowRequestedEventArgs* args)
{
web::json::value jsonObj = web::json::value::parse(L"{}");
    jsonObj[L"message"] = web::json::value();
    jsonObj[L"args"] = web::json::value::parse(L"{}");
    jsonObj[L"args"][L"tabId"] = web::json::value::number(tabId);
    jsonObj[L"args"][L"state"] = TRUE;

   
    wil::unique_cotaskmem_string uri;
    RETURN_IF_FAILED(webview->get_Source(&uri));
            size_t id = tabId + 1;
            bool shouldBeActive = TRUE;
            std::unique_ptr<Tab> newTab = Tab::CreateNewTab(m_hWnd, m_contentEnv.Get(), id, shouldBeActive);

            std::map<size_t, std::unique_ptr<Tab>>::iterator it = m_tabs.find(id);
            if (it == m_tabs.end())
            {
                m_tabs.insert(std::pair<size_t,std::unique_ptr<Tab>>(id, std::move(newTab)));
                m_tabs.at(id)->m_contentWebView->Navigate(uri.get());
            }
            else
            {
                m_tabs.at(id)->m_contentController->Close();
                it->second = std::move(newTab);
            }

   return PostJsonToWebView(jsonObj, m_controlsWebView.Get());
}

it throw exception at m_tabs.at(id)->m_contentWebView->Navigate(uri.get()); saying
Exception thrown: read access violation.
std::map<unsigned __int64,std::unique_ptr<Tab,std::default_delete >,std::less,std::allocator<std::pair<unsigned __int64 const ,std::unique_ptr<Tab,std::default_delete > > >

This is what i am trying to achieve....
Try

@Syul968 Thank you for reply. I managed to open new window as a new tab, but now when I do not complete deferrer then caller tab get hang and if I complete deferrer then two windows (New window and new tab) appears.

So may I know how to complete deferrer without new window?

    wil::unique_cotaskmem_string uri;
    std::wstring strUri;
    if (SUCCEEDED(args->get_Uri(&uri)))
        strUri = uri.get();
    std::wstring  endScript = L"');";
    std::wstring   URL = L"javascript:addTab('" + strUri  + endScript;
   
    m_controlsWebView->ExecuteScript( URL.c_str() ,Callback<ICoreWebView2ExecuteScriptCompletedHandler>(
    [](HRESULT errorCode, LPCWSTR resultObjectAsJson) -> HRESULT {
        return S_OK;
    }).Get());

    args->GetDeferral(&deferral); 
    return S_OK;
commented

See #44 how I solved it.
You do not need any additional callbacks using this method as it's what the app is doing internally.