Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Porting this code from CHtmlView to WebView2 #871

Closed
ajtruckle opened this issue Jan 29, 2021 · 16 comments
Closed

Porting this code from CHtmlView to WebView2 #871

ajtruckle opened this issue Jan 29, 2021 · 16 comments

Comments

@ajtruckle
Copy link

ajtruckle commented Jan 29, 2021

Hi

If I am to consider moving over to WebView2 then I need to be able to port this class over:

// ChristianLifeMinistryView.cpp : implementation file
//

#include "stdafx.h"
#include "Meeting Schedule Assistant.h"
#include "ChristianLifeMinistryHtmlView.h"
#include "ChristianLifeMinistryEntry.h"
#include "HtmlWrapper.h"

#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif

/////////////////////////////////////////////////////////////////////////////
// CMyHtmlView

//Print Preview Dialog Class name
static CString IE_PPREVIEWCLASS = _T("Internet Explorer_TridentDlgFrame");

const int ID_TIMER_ZOOM = 1;

IMPLEMENT_DYNCREATE(CChristianLifeMinistryHtmlView, CHtmlView)

CChristianLifeMinistryHtmlView::CChristianLifeMinistryHtmlView()
	: m_strHtmlFile(CMeetingScheduleAssistantApp::GetTempFilenameEx(_T("MWB"), _T("XML")))
	, m_bPrintPreviewMode(false)
	, m_lZoomFactor(100)
	, m_bEnableZoomFactor(false)
	, m_bShowEditorMWBContextMenu(false)
	, m_lpDisp(nullptr)
{
	//{{AFX_DATA_INIT(CMyHtmlView)
		// NOTE: the ClassWizard will add member initialization here
	//}}AFX_DATA_INIT

	m_bmpPageSetup.LoadBitmap(IDB_BMP_MENU_PAGE_SETUP);
	m_bmpPrintPreview.LoadBitmap(IDB_BMP_MENU_PRINT_PREVIEW);
	m_bmpRefresh.LoadBitmap(IDB_BMP_MENU_REFRESH_VIEW);

	theApp.SetBitmapBackgroundAsMenuColour(m_bmpPageSetup);
	theApp.SetBitmapBackgroundAsMenuColour(m_bmpPrintPreview);
	theApp.SetBitmapBackgroundAsMenuColour(m_bmpRefresh);
}

CChristianLifeMinistryHtmlView::~CChristianLifeMinistryHtmlView()
{
	// Delete temporary HTML file
	if (PathFileExists(m_strHtmlFile))
		::DeleteFile(m_strHtmlFile);
}

void CChristianLifeMinistryHtmlView::DoDataExchange(CDataExchange* pDX)
{
	CHtmlView::DoDataExchange(pDX);
	//{{AFX_DATA_MAP(CMyHtmlView)
		// NOTE: the ClassWizard will add DDX and DDV calls here
	//}}AFX_DATA_MAP
}


BEGIN_MESSAGE_MAP(CChristianLifeMinistryHtmlView, CHtmlView)
	//{{AFX_MSG_MAP(CMyHtmlView)
		// NOTE - the ClassWizard will add and remove mapping macros here.
	//}}AFX_MSG_MAP
	ON_WM_TIMER()
END_MESSAGE_MAP()

/////////////////////////////////////////////////////////////////////////////
// CMyHtmlView diagnostics

#ifdef _DEBUG
void CChristianLifeMinistryHtmlView::AssertValid() const
{
	CHtmlView::AssertValid();
}

void CChristianLifeMinistryHtmlView::Dump(CDumpContext& dc) const
{
	CHtmlView::Dump(dc);
}
#endif //_DEBUG

/////////////////////////////////////////////////////////////////////////////
// CMyHtmlView message handlers

HRESULT CChristianLifeMinistryHtmlView::ExecWB(OLECMDID cmdID, OLECMDEXECOPT cmdexecopt, VARIANT *pvaIn, VARIANT *pvaOut)
{
	HRESULT hr;
	
	ASSERT(m_pBrowserApp != nullptr);

	hr = m_pBrowserApp->ExecWB(cmdID, cmdexecopt, pvaIn, pvaOut);
	return hr;
}

void CChristianLifeMinistryHtmlView::DoPrintPreview()
{
	HWND	  HWND_PP, HWND_FG ;
	TCHAR	  szClassName[256] ;
	ULONGLONG t1, t2 ;
	RECT	  workArea{};
	
	ExecWB(OLECMDID_PRINTPREVIEW, OLECMDEXECOPT_PROMPTUSER, nullptr, nullptr);

    HWND_PP = nullptr ;
	t1 = ::GetTickCount64();
	t2 = ::GetTickCount64(); // Extra line required for 'while' rearrangement.
	while (HWND_PP == nullptr && t2 - t1 <= 6000) // if found or Timeout reached...
	{
		HWND_FG = ::GetForegroundWindow(); // Get the ForeGroundWindow
		if (HWND_FG != nullptr)
		{
			::GetClassName(HWND_FG, szClassName, 256 );
			if (lstrcmp(szClassName, IE_PPREVIEWCLASS) == 0) // Check for Print Preview Dialog
				HWND_PP = HWND_FG ;
		}

		theApp.PumpMessage();
		t2 = ::GetTickCount64();
	}

	if (HWND_PP != nullptr)
	{
		// AJT V3.01 BUG Fix - showing maximized crops bottom of preview dialog
		::SystemParametersInfo( SPI_GETWORKAREA, 0, &workArea, 0 );
		::MoveWindow(HWND_PP, workArea.left, workArea.top,
			workArea.right - workArea.left,	workArea.bottom - workArea.top, TRUE);
		
	}
}


void CChristianLifeMinistryHtmlView::NavigateComplete2(LPDISPATCH pDisp, VARIANT* URL)
{
	CHtmlView::NavigateComplete2(pDisp, URL);
}


void CChristianLifeMinistryHtmlView::DocumentComplete(LPDISPATCH pDisp, VARIANT* URL)
{
	CHtmlView::DocumentComplete(pDisp, URL);

	// AJT v16.0.8
	if (!IsPrintPreviewMode() && IsZoomFactorMode())
	{
		HRESULT hr = SetZoomFactor(m_lZoomFactor);
		if (!SUCCEEDED(hr))
		{
			// #DocumentComplete What do we do?
		}
	}
}


void CChristianLifeMinistryHtmlView::SetPrintPreviewMode(bool bPrintPreviewMode)
{
	m_bPrintPreviewMode = bPrintPreviewMode;
}


bool CChristianLifeMinistryHtmlView::IsPrintPreviewMode()
{
	return m_bPrintPreviewMode;
}


// AJT v16.0.2
void CChristianLifeMinistryHtmlView::CopyToClipboard()
{
	ExecWB(OLECMDID_COPY, OLECMDEXECOPT_DONTPROMPTUSER, nullptr, nullptr);
}


// AJT v16.0.2
void CChristianLifeMinistryHtmlView::SelectAll()
{
	ExecWB(OLECMDID_SELECTALL, OLECMDEXECOPT_DONTPROMPTUSER, nullptr, nullptr);
}


// AJT v16.0.2
void CChristianLifeMinistryHtmlView::PageSetup()
{
	ExecWB(OLECMDID_PAGESETUP, OLECMDEXECOPT_DONTPROMPTUSER, nullptr, nullptr);
}


// AJT v16.0.8
HRESULT CChristianLifeMinistryHtmlView::SetZoomFactor(long iZoom, bool bRefreshBrowser /*true*/)
{
	HRESULT hr = S_OK;
	VARIANT vZoom{};

	m_lZoomFactor = iZoom;

	if (bRefreshBrowser)
	{
		vZoom.vt = VT_I4;
		vZoom.lVal = iZoom;

		hr = ExecWB(OLECMDID_OPTICAL_ZOOM, OLECMDEXECOPT_DONTPROMPTUSER, &vZoom, nullptr);
	}

	return hr;
}


// AJT v16.0.8
long CChristianLifeMinistryHtmlView::GetZoomFactor()
{
	return m_lZoomFactor;
}


// AJT v16.0.8
void CChristianLifeMinistryHtmlView::IncrementZoom(bool bZoomIn)
{
	long lZoomFactor = GetZoomFactor();
	bool bSetZoomFactor = false;

	if (bZoomIn)
	{
		if (lZoomFactor <= 375)
		{
			bSetZoomFactor = true;
			lZoomFactor += 25;
		}
	}
	else
	{
		if (lZoomFactor >= 75)
		{
			bSetZoomFactor = true;
			lZoomFactor -= 25;
		}
	}

	if(bSetZoomFactor)
		SetZoomFactor(lZoomFactor);
}


// AJT v16.0.8
void CChristianLifeMinistryHtmlView::EnableZoomFactor(bool bEnable)
{
	m_bEnableZoomFactor = bEnable;
}


// AJT v16.0.8
bool CChristianLifeMinistryHtmlView::IsZoomFactorMode()
{
	return m_bEnableZoomFactor;
}


// AJT v18.2.2
BOOL CChristianLifeMinistryHtmlView::PreTranslateMessage(MSG* pMsg)
{
	if (pMsg->message == WM_MOUSEWHEEL)
		if (GET_KEYSTATE_WPARAM(pMsg->wParam) & MK_CONTROL)
			SetTimer(ID_TIMER_ZOOM, 1000, nullptr); //start timer for detecting zoom
	return CHtmlView::PreTranslateMessage(pMsg);
}


// AJT v18.2.2
void CChristianLifeMinistryHtmlView::OnTimer(UINT_PTR nIDEvent)
{
	if (nIDEvent == ID_TIMER_ZOOM)
	{
		//get the zoom value
		VARIANT vZoom{};
		vZoom.vt = VT_I4;
		vZoom.lVal = 0;
		ExecWB(OLECMDID_OPTICAL_ZOOM, OLECMDEXECOPT_DONTPROMPTUSER, nullptr, &vZoom);
		TRACE("zoom %d\n", vZoom.lVal);

		//kill the timer
		KillTimer(nIDEvent);

		GetParent()->PostMessage(UWM_HTMLVIEW_CHANGE_ZOOM_MSG, vZoom.lVal);
		return;
	}

	CHtmlView::OnTimer(nIDEvent);
}

HRESULT CChristianLifeMinistryHtmlView::OnShowContextMenu(DWORD dwID, LPPOINT ppt,
	LPUNKNOWN pcmdtReserved, LPDISPATCH pdispReserved)
{
	if(ShowEditorMWBContextMenu())
		return CustomContextMenu(ppt, pcmdtReserved);

	return S_OK; // Eat it
}

HRESULT CChristianLifeMinistryHtmlView::CustomContextMenu(POINT* ppt, IUnknown* pcmdtReserved)
{
	IOleWindow* oleWnd = nullptr;
	HWND		hwnd = nullptr;
	HMENU		hMainMenu = nullptr;
	HMENU		hPopupMenu = nullptr;
	HRESULT		hr = 0;
	INT			iSelection = 0;


	if ((ppt == nullptr) || (pcmdtReserved == nullptr))
		goto error;

	hr = pcmdtReserved->QueryInterface(IID_IOleWindow, (void**)&oleWnd);
	if ((hr != S_OK) || (oleWnd == nullptr))
		goto error;

	hr = oleWnd->GetWindow(&hwnd);
	if ((hr != S_OK) || (hwnd == nullptr))
		goto error;

	// AJT 21.0.0 Bug fix - use the resource handle!
	hMainMenu = LoadMenu(AfxGetResourceHandle(),
		MAKEINTRESOURCE(IDR_MENU_HTML_POPUP));
	if (hMainMenu == nullptr)
		goto error;

	hPopupMenu = GetSubMenu(hMainMenu, 0);
	if (hPopupMenu == nullptr)
		goto error;

	::SetMenuItemBitmaps(hPopupMenu, IDM_PAGESETUP, MF_BYCOMMAND,
		(HBITMAP)m_bmpPageSetup, (HBITMAP)m_bmpPageSetup);
	::SetMenuItemBitmaps(hPopupMenu, IDM_PRINTPREVIEW, MF_BYCOMMAND,
		(HBITMAP)m_bmpPrintPreview, (HBITMAP)m_bmpPrintPreview);
	::SetMenuItemBitmaps(hPopupMenu, IDM_REFRESH, MF_BYCOMMAND,
		(HBITMAP)m_bmpRefresh, (HBITMAP)m_bmpRefresh);

	// Show shortcut menu
	iSelection = ::TrackPopupMenu(hPopupMenu,
		TPM_LEFTALIGN | TPM_RIGHTBUTTON | TPM_RETURNCMD,
		ppt->x,
		ppt->y,
		0,
		hwnd,
		(RECT*)nullptr);

	// Send selected shortcut menu item command to shell
	if (iSelection != 0)
	{
		if (iSelection == IDM_PRINTPREVIEW)
		{
			::SendMessage(GetParent()->GetSafeHwnd(), WM_COMMAND, ID_FILE_PRINT_PREVIEW, NULL);
		}
		else if (iSelection == CUSTOM_MENU_EXPORT)
		{
			::SendMessage(GetParent()->GetSafeHwnd(), WM_COMMAND, ID_FILE_EXPORT, NULL);
		}
		else
		{
			::SendMessage(hwnd, WM_COMMAND, iSelection, NULL);
		}
	}

error:

	if (hMainMenu != nullptr)
		::DestroyMenu(hMainMenu);

	return S_OK;
}



void CChristianLifeMinistryHtmlView::SetEditorMWBContextmenuMode()
{
	m_bShowEditorMWBContextMenu = true;
}


bool CChristianLifeMinistryHtmlView::ShowEditorMWBContextMenu()
{
	return m_bShowEditorMWBContextMenu;
}


// See: https://jeffpar.github.io/kbarchive/kb/220/Q220021/
BOOL CChristianLifeMinistryHtmlView::PreCreateWindow(CREATESTRUCT& cs)
{
	cs.style |= WS_CLIPCHILDREN;

	return CHtmlView::PreCreateWindow(cs);
}

This class is functional and works very well in my application.

  1. Can it be ported?
  2. If some can't be ported, do you have a time frame for it to be to be ported?

I don't want loss of features for migrating to WebView2.

Thanks for your time.

@ajtruckle ajtruckle added the feature request feature request label Jan 29, 2021
@champnic champnic added question and removed feature request feature request labels Feb 2, 2021
@champnic
Copy link
Member

champnic commented Feb 2, 2021

Sorry, I don't have time to look over this whole code, though others on this forum may.

If you have specific feature requests or blockers from trying to port this code please open new issues specific to those requests (and/or check if we already have issues tracking those requests). Thanks!

@ukandrewc
Copy link

@ajtruckle WebView2 is a complete departure from CHtmlView, there is no migration path, it's not possible. Unfortunately, (like all of us) you'll have to start wrestling it into submission ;-)

@ajtruckle
Copy link
Author

ajtruckle commented Feb 2, 2021 via email

@pontusn
Copy link

pontusn commented Feb 3, 2021

Migration is possible.

We have migrated än extremely complex application that previously embedded IE/WebBrowser in numerous places.

Our path:

  • Implement new ActiveX in ATL based on Webview2 with partially compatible automation API (IDispatch and events) to work as drop in replacement in our different hosting scenarios.
  • Bridge API gaps and bugs via injected Javascripts and CSS
  • Patch problems with datatypes and ambiguous API definitions in ATL implementation of IDispatch
  • Provide new alternative APIs to resolve performance issues, mainly due to higher latency compared to IE/WebBrowser. This essentially translates to returning JSON instead of complex structures of COM-objects for read access.
  • Implement session management that synchronise cookies between .Net, WebView2 and WinINET for all legacy code to run smoothly.

We had first proof of concept up and running in less than one week, about one year ago. And spent time on final details ever since.

The only breaking change for our content is support for VBScript.

@ajtruckle
Copy link
Author

Zoom level

Resolved the above using put_ZoomFactor property.

Open xml / xsl transform

This is not possible when the transformation files are local to the PC. Shame. At the moment I have to transform myself to HTML and then load that file. A valid workaround but would be nicer to just use the XML file path like I could in IE.

View source

When you right-click the view there is "Inspect" which is about as good as we will get. So I guess this is OK.

Select all

I have this working using deprecated API (ExecuteScript("execCommand.Copy()")) etc.

Print preview

This works (context menu and on demand) but it is limited to the bounds of the WebPreview2 object - unlike the CHtmlView control. I raised a iossue for this.

Page setup

Not yet found a way to do this.

Customised context menu

To be reviewed.

@ukandrewc
Copy link

@ajtruckle Customised context menu API, is on it's way.

@ajtruckle
Copy link
Author

Great! Concerning "View Page Source" ... on reflection ... browsers offer two distinct choices (page source / inspect). Microsoft Edge context menu includes both of these. And I can click my WebView2 and press CTRL + U to display the page source. So:

  1. Will View Page Source be added to the context menu by default?
  2. Can we programmatically add it via a setting?
  3. Or is it part of the features you just referred to?

Also, can we programmatically trigger the View Page Source?

@ukandrewc
Copy link

@ajtruckle I assume the ContexMenu API will solve those three. Use the view-source: protocol e.g. Source="view-source:https://uk.yahoo.com"

@ajtruckle
Copy link
Author

I'll investigate that, thanks.

As for Page Setup - the current system lacks features. If we click the Print button (apart from teh size constraints to the webview2 object) we can click More Settings and the check box to include headers and footers. But there is no way to configure the text like you used to in IE PageSetup.

@champnic
Copy link
Member

champnic commented Feb 3, 2022

Closing old questions - let me know if you think this should stay open. Thanks!

@champnic champnic closed this as completed Feb 3, 2022
@ajtruckle
Copy link
Author

@champnic It may be old but these issues are not resolved to my knowledge. I am still not using WebView2 because of these various issues.

@champnic champnic reopened this Feb 3, 2022
@champnic
Copy link
Member

champnic commented Feb 3, 2022

Reopening - thanks for the ping!

There are a bunch of issues listed here, some of which have been resolved - would you mind sharing which ones are still blocking you?

@ajtruckle
Copy link
Author

Off the top of my head:

  1. Right-click customisation of context menu.
  2. Page Setup reinstates all the missing configuration properties for header / footer that were in ChtmlView.
  3. The print popup window (with the preview etc) should be full screen. My browser window is the right half of my application but the print preview should be resized for the whole screen and not forced to the browser window. That is plain ugly.
  4. Does it now support Find? Like you can find / find next in chtmlview?
  5. If I have the print preview open I can still close my main application - can't we detect the print preview window is visible to prevent this?
  6. Some times I want to display a HTML file in a hidden browser control, and still be able to display a print preview window full screen. Can't work out how to do that.

All of those things to my knowledge can't be done yet with WebView2 and would cripple my application behaviour. It seems that the developers are thinking it just the terms of a browser and thus you will probably have it maximised anyway. But it is also being used as a control - so not always full screen. And this forcing the print preview to the confines of the browser makes it not useable.

I have raised all of these things before and to my knowledge there have been no fixes for any of them???

@champnic
Copy link
Member

champnic commented Feb 3, 2022

  1. Right-click customisation of context menu.

This is currently available as an experimental API:
https://docs.microsoft.com/en-us/dotnet/api/microsoft.web.webview2.core.corewebview2.contextmenurequested?view=webview2-dotnet-1.0.1133-prerelease
I'm looking into why this hasn't made it to stable yet...

  1. Does it now support Find? Like you can find / find next in chtmlview?

We are tracking better Find support in #1737

  1. The print popup window (with the preview etc) should be full screen. My browser window is the right half of my application but the print preview should be resized for the whole screen and not forced to the browser window. That is plain ugly.
  1. Some times I want to display a HTML file in a hidden browser control, and still be able to display a print preview window full screen. Can't work out how to do that.

We have this tracked in the #1488 you opened.

For the remaining print issues:

  1. Page Setup reinstates all the missing configuration properties for header / footer that were in ChtmlView.
  1. If I have the print preview open I can still close my main application - can't we detect the print preview window is visible to prevent this?

I don't think we have those captured yet. I'll move those to a dedicated Feature Request issue and then we can close this aggregate issue if that's ok with you.

@champnic
Copy link
Member

champnic commented Feb 3, 2022

You are right though that we haven't done much in the print space overall, and for that I apologize, as it seems to be a big part of your application or at least continues to block you from using WebView2.

@ajtruckle
Copy link
Author

Thanks for the links and creating the tickets so you can close the thread here.

Yes, the browser control is what I use as my schedule display in my editor. See:
My Editor

So unless WebView2 caters for all the features it will be a step backwards and not forwards.
For example, with the context menu I like to display my own and show my own items and some browser ones. It is all details in the help documentation for my application.

@champnic champnic closed this as completed Feb 4, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants