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

Printing with Microsoft print to PDF as admin #3271

Open
ajtruckle opened this issue Mar 6, 2023 · 18 comments
Open

Printing with Microsoft print to PDF as admin #3271

ajtruckle opened this issue Mar 6, 2023 · 18 comments
Assignees
Labels
bug Something isn't working tracked We are tracking this work internally.

Comments

@ajtruckle
Copy link

ajtruckle commented Mar 6, 2023

I can use the "Save as PDF") on the Print window. That is OK.

But if I select the Microsoft Print to PDF driver and click Print it fails.

It shows a popup.

AB#43711489

@ajtruckle ajtruckle added the bug Something isn't working label Mar 6, 2023
@novac42
Copy link
Contributor

novac42 commented Mar 7, 2023

@ajtruckle Thanks for reaching out. Can you send some sample code to replicate the issue? What does the popup look like?

@ajtruckle
Copy link
Author

@novac42 @vickiez
I am using the context menu (based on the samples provided) with some extra items:

void CWebBrowser::AddContextMenuRequestedHandler()
{
	if (m_pImpl->m_webView2_11 != nullptr &&
		m_pImpl->m_webController != nullptr &&
		m_pImpl->m_webController3 != nullptr)
	{
		m_pImpl->m_webView2_11->add_ContextMenuRequested(
			Callback<ICoreWebView2ContextMenuRequestedEventHandler>(
				[this](
					ICoreWebView2* sender,
					ICoreWebView2ContextMenuRequestedEventArgs* eventArgs) {
						wil::com_ptr<ICoreWebView2ContextMenuRequestedEventArgs> args =
							eventArgs;
						wil::com_ptr<ICoreWebView2ContextMenuItemCollection> items;
						CHECK_FAILURE(args->get_MenuItems(&items));
						UINT32 itemsCount;
						CHECK_FAILURE(items->get_Count(&itemsCount));

						wil::com_ptr<ICoreWebView2ContextMenuTarget> target;
						CHECK_FAILURE(args->get_ContextMenuTarget(&target));

						COREWEBVIEW2_CONTEXT_MENU_TARGET_KIND targetKind;
						CHECK_FAILURE(target->get_Kind(&targetKind));
						// Custom UI Context Menu rendered if invoked on selected text
						if (targetKind ==
							COREWEBVIEW2_CONTEXT_MENU_TARGET_KIND_SELECTED_TEXT)
						{
							auto showMenu = [this, args, itemsCount, items, target] {
								CHECK_FAILURE(args->put_Handled(true));


								HMENU hPopupMenu = CreatePopupMenu();
								AddMenuItems(hPopupMenu, items);
								HWND hWnd;
								m_pImpl->m_webController->get_ParentWindow(&hWnd);
								::SetForegroundWindow(hWnd);
								RECT rct;
								::GetClientRect(hWnd, &rct);
								POINT topLeft{};
								topLeft.x = rct.left;
								topLeft.y = rct.top;
								::ClientToScreen(hWnd, &topLeft);
								POINT p;
								CHECK_FAILURE(args->get_Location(&p));
								RECT bounds;
								CHECK_FAILURE(m_pImpl->m_webController->get_Bounds(&bounds));
								double scale;
								m_pImpl->m_webController3->get_RasterizationScale(&scale);
								const INT32 selectedCommandId = ::TrackPopupMenu(
									hPopupMenu,
									TPM_TOPALIGN | TPM_LEFTALIGN | TPM_RETURNCMD,
									bounds.left + topLeft.x + ((int)(p.x * scale)),
									bounds.top + topLeft.y + ((int)(p.y * scale)), 0, hWnd,
									nullptr);
								CHECK_FAILURE(
									args->put_SelectedCommandId(selectedCommandId));
							};
							wil::com_ptr<ICoreWebView2Deferral> deferral;
							CHECK_FAILURE(args->GetDeferral(&deferral));
							RunAsync([deferral, showMenu]() {
								showMenu();
								CHECK_FAILURE(deferral->Complete());
								});
						}
						// Adding a custom context menu item for the page that will display
						// the page's URI.
						else if (targetKind == COREWEBVIEW2_CONTEXT_MENU_TARGET_KIND_PAGE)
						{
							// Custom items should be reused whenever possible.
							if (!m_displayPageUrlContextSubMenuItem)
							{
								wil::com_ptr<ICoreWebView2ContextMenuItem> current;
								std::vector<UINT32> vRemoveIndex;
								int iSepIndex = 0;
								for (UINT32 i = 0; i < itemsCount; i++)
								{
									CHECK_FAILURE(items->GetValueAtIndex(i, &current));
									wil::unique_cotaskmem_string name;
									CHECK_FAILURE(current->get_Name(&name));
									COREWEBVIEW2_CONTEXT_MENU_ITEM_KIND itemKind = {};
									CHECK_FAILURE(current->get_Kind(&itemKind));

									if (std::wstring(L"back") == name.get() ||
										std::wstring(L"forward") == name.get() ||
										std::wstring(L"share") == name.get())
									{
										vRemoveIndex.push_back(i);
									}
									else if (itemKind == COREWEBVIEW2_CONTEXT_MENU_ITEM_KIND_SEPARATOR)
									{
										iSepIndex++;
										if (iSepIndex == 2)
										{
											vRemoveIndex.push_back(i);
										}

									}
									else if (std::wstring(L"other") == name.get())
									{
										INT32 id;
										CHECK_FAILURE(current->get_CommandId(&id));
										//if(id == sha)

									}
									else if (std::wstring(L"inspectElement") == name.get())
									{


									}
								}
								std::reverse(vRemoveIndex.begin(), vRemoveIndex.end());
								for (const auto& iRemoveIndex : vRemoveIndex)
								{
									CHECK_FAILURE(items->RemoveValueAtIndex(iRemoveIndex));
								}
								CHECK_FAILURE(items->get_Count(&itemsCount));

								wil::com_ptr<ICoreWebView2Environment9> webviewEnvironment;
								CHECK_FAILURE(
									m_pImpl->m_webViewEnvironment->QueryInterface(
										IID_PPV_ARGS(&webviewEnvironment)));

								// ===============================================================
								wil::com_ptr<ICoreWebView2ContextMenuItem> itemSep1;
								CHECK_FAILURE(webviewEnvironment->CreateContextMenuItem(
									L"", nullptr,
									COREWEBVIEW2_CONTEXT_MENU_ITEM_KIND_SEPARATOR, &itemSep1));

								CHECK_FAILURE(items->InsertValueAtIndex(itemsCount, itemSep1.get()));
								itemsCount++;
								// ===============================================================

								// ===============================================================
								wil::com_ptr<ICoreWebView2ContextMenuItem> itemViewXML;
								CHECK_FAILURE(webviewEnvironment->CreateContextMenuItem(
									L"View XML", nullptr,
									COREWEBVIEW2_CONTEXT_MENU_ITEM_KIND_COMMAND, &itemViewXML));

								CHECK_FAILURE(itemViewXML->add_CustomItemSelected(
									Callback<ICoreWebView2CustomItemSelectedEventHandler>(
										[appWindow = this, target](ICoreWebView2ContextMenuItem* sender, IUnknown* args)
										{
											appWindow->GetParentWindow()->SendMessage(WM_COMMAND, CUSTOM_MENU_VIEW_XML, NULL);

											return S_OK;
										})
									.Get(), nullptr));

								CHECK_FAILURE(items->InsertValueAtIndex(itemsCount, itemViewXML.get()));
								itemsCount++;
								// ===============================================================

								// ===============================================================
								wil::com_ptr<ICoreWebView2ContextMenuItem> itemViewPageSource;
								CHECK_FAILURE(webviewEnvironment->CreateContextMenuItem(
									L"View Page Source (CTRL + U)", nullptr,
									COREWEBVIEW2_CONTEXT_MENU_ITEM_KIND_COMMAND, &itemViewPageSource));

								CHECK_FAILURE(itemViewPageSource->add_CustomItemSelected(
									Callback<ICoreWebView2CustomItemSelectedEventHandler>(
										[appWindow = this, target](ICoreWebView2ContextMenuItem* sender, IUnknown* args)
										{
											wil::unique_cotaskmem_string pageUri;
											CHECK_FAILURE(target->get_PageUri(&pageUri));
											CString strUrl = L"view-source:" + CString(pageUri.get());

											// Create an array of generic keyboard INPUT structures
											std::vector<INPUT> vIP(4);
											for (int n = 0; n < 4; ++n)
											{
												vIP.at(n).type = INPUT_KEYBOARD;
												vIP.at(n).ki.wScan = 0;
												vIP.at(n).ki.time = 0;
												vIP.at(n).ki.dwFlags = 0; // 0 for key press
												vIP.at(n).ki.dwExtraInfo = 0;
											}

											vIP.at(0).ki.wVk = VK_CONTROL;
											vIP.at(1).ki.wVk = 'U';

											vIP.at(2).ki.wVk = 'U';
											vIP.at(2).ki.dwFlags = KEYEVENTF_KEYUP;

											vIP.at(3).ki.wVk = VK_CONTROL;
											vIP.at(3).ki.dwFlags = KEYEVENTF_KEYUP;

											SendInput(4, vIP.data(), sizeof(INPUT));

											return S_OK;
										})
									.Get(), nullptr));

								CHECK_FAILURE(items->InsertValueAtIndex(itemsCount, itemViewPageSource.get()));
								itemsCount++;
								// ===============================================================

								// ===============================================================
								wil::com_ptr<ICoreWebView2ContextMenuItem> itemSep2;
								CHECK_FAILURE(webviewEnvironment->CreateContextMenuItem(
									L"", nullptr,
									COREWEBVIEW2_CONTEXT_MENU_ITEM_KIND_SEPARATOR, &itemSep2));

								CHECK_FAILURE(items->InsertValueAtIndex(itemsCount, itemSep2.get()));
								itemsCount++;
								// ===============================================================

								// ===============================================================
								// ALT + SHIFT + W
								wil::com_ptr<ICoreWebView2ContextMenuItem> itemOpenFileLocation;
								CHECK_FAILURE(webviewEnvironment->CreateContextMenuItem(
									L"Open File Location (ALT + SHIFT + W)", nullptr,
									COREWEBVIEW2_CONTEXT_MENU_ITEM_KIND_COMMAND, &itemOpenFileLocation));

								CHECK_FAILURE(itemOpenFileLocation->add_CustomItemSelected(
									Callback<ICoreWebView2CustomItemSelectedEventHandler>(
										[appWindow = this, target](ICoreWebView2ContextMenuItem* sender, IUnknown* args)
										{
											appWindow->GetParentWindow()->SendMessage(WM_COMMAND, ID_DISPLAY_WORKING_FOLDER, NULL);

											return S_OK;
										})
									.Get(), nullptr));

								CHECK_FAILURE(items->InsertValueAtIndex(itemsCount, itemOpenFileLocation.get()));
								itemsCount++;
								// ===============================================================

								// ===============================================================
								wil::com_ptr<ICoreWebView2ContextMenuItem> itemExport;
								CHECK_FAILURE(webviewEnvironment->CreateContextMenuItem(
									L"Export", nullptr,
									COREWEBVIEW2_CONTEXT_MENU_ITEM_KIND_COMMAND, &itemExport));

								CHECK_FAILURE(itemExport->add_CustomItemSelected(
									Callback<ICoreWebView2CustomItemSelectedEventHandler>(
										[appWindow = this, target](ICoreWebView2ContextMenuItem* sender, IUnknown* args)
										{
											appWindow->GetParentWindow()->SendMessage(WM_COMMAND, ID_FILE_EXPORT, NULL);

											return S_OK;
										})
									.Get(), nullptr));

								CHECK_FAILURE(items->InsertValueAtIndex(itemsCount, itemExport.get()));
								itemsCount++;
								// ===============================================================

								// ===============================================================
								wil::com_ptr<ICoreWebView2ContextMenuItem> itemFind;
								CHECK_FAILURE(webviewEnvironment->CreateContextMenuItem(
									L"Find (CTRL + F)", nullptr,
									COREWEBVIEW2_CONTEXT_MENU_ITEM_KIND_COMMAND, &itemFind));

								CHECK_FAILURE(itemFind->add_CustomItemSelected(
									Callback<ICoreWebView2CustomItemSelectedEventHandler>(
										[](ICoreWebView2ContextMenuItem* sender, IUnknown* args)
										{
											// Create an array of generic keyboard INPUT structures
											std::vector<INPUT> vIP(4);
											for (int n = 0; n < 4; ++n)
											{
												vIP.at(n).type = INPUT_KEYBOARD;
												vIP.at(n).ki.wScan = 0;
												vIP.at(n).ki.time = 0;
												vIP.at(n).ki.dwFlags = 0; // 0 for key press
												vIP.at(n).ki.dwExtraInfo = 0;
											}

											vIP.at(0).ki.wVk = VK_CONTROL;
											vIP.at(1).ki.wVk = 'F';

											vIP.at(2).ki.wVk = 'F';
											vIP.at(2).ki.dwFlags = KEYEVENTF_KEYUP;

											vIP.at(3).ki.wVk = VK_CONTROL;
											vIP.at(3).ki.dwFlags = KEYEVENTF_KEYUP;

											SendInput(4, vIP.data(), sizeof(INPUT));

											return S_OK;
										})
									.Get(), nullptr));

								CHECK_FAILURE(items->InsertValueAtIndex(itemsCount, itemFind.get()));
								itemsCount++;
								// ===============================================================

								// ===============================================================
								wil::com_ptr<ICoreWebView2ContextMenuItem> itemSaveAsPDF;
								CHECK_FAILURE(webviewEnvironment->CreateContextMenuItem(
									L"Save as PDF", nullptr,
									COREWEBVIEW2_CONTEXT_MENU_ITEM_KIND_COMMAND, &itemSaveAsPDF));

								CHECK_FAILURE(itemSaveAsPDF->add_CustomItemSelected(
									Callback<ICoreWebView2CustomItemSelectedEventHandler>(
										[appWindow = this, target](ICoreWebView2ContextMenuItem* sender, IUnknown* args)
										{
											appWindow->RunAsync([appWindow]()
											{
												CFileDialog	dlgExport(FALSE, _T("PDF"), nullptr,
													OFN_OVERWRITEPROMPT | OFN_HIDEREADONLY, L"PDF Files (*.PDF)|*.PDF||", appWindow);
												dlgExport.m_ofn.lpstrTitle = L"Save as PDF";
												if (dlgExport.DoModal() == IDOK)
												{
													appWindow->PrintToPDF(dlgExport.GetPathName(), true);
												}
											});
											return S_OK;
										})
									.Get(), nullptr));

								CHECK_FAILURE(items->InsertValueAtIndex(itemsCount, itemSaveAsPDF.get()));
								itemsCount++;
								// ===============================================================
							}
						}
						// If type is not an image, video, or page, the regular Edge context
						// menu will be displayed
						return S_OK;
				})
			.Get(),
					&m_contextMenuRequestedToken);
	}
}

As far as I am aware it is using the built-in core functionality here. So I right-click and choose Print:
Snap1

Then, I change it to print to the Microsoft PDF printer:
Snap2

After hitting Print:
Snap3

As previously mentioned, I can use Save as PDF on the Print window and it behaves fine.

@ajtruckle
Copy link
Author

I should also point out that my own "Save as PDF" at the bottom of the context menu works correctly and shows a file dialog and saves as PDF and then opens in the external PDF viewer. So, it is just this concept of displaying the Print window and choosing "Microsoft Print to PDF" that it does not like.

@ajtruckle
Copy link
Author

I forgot this function that is used in creating the menu:

void CWebBrowser::AddMenuItems(HMENU hPopupMenu, wil::com_ptr<ICoreWebView2ContextMenuItemCollection> items)
{
	wil::com_ptr<ICoreWebView2ContextMenuItem> current;
	UINT32 itemsCount;
	CHECK_FAILURE(items->get_Count(&itemsCount));
	for (UINT32 i = 0; i < itemsCount; i++)
	{
		CHECK_FAILURE(items->GetValueAtIndex(i, &current));
		COREWEBVIEW2_CONTEXT_MENU_ITEM_KIND kind;
		CHECK_FAILURE(current->get_Kind(&kind));
		wil::unique_cotaskmem_string label;
		CHECK_FAILURE(current->get_Label(&label));
		std::wstring labelString = label.get();
		wil::unique_cotaskmem_string shortcut;
		CHECK_FAILURE(current->get_ShortcutKeyDescription(&shortcut));
		std::wstring shortcutString = shortcut.get();
		if (!shortcutString.empty())
		{
			// L"\t" will right align the shortcut string
			labelString = labelString + L"\t" + shortcutString;
		}
		BOOL isEnabled;
		CHECK_FAILURE(current->get_IsEnabled(&isEnabled));
		BOOL isChecked;
		CHECK_FAILURE(current->get_IsChecked(&isChecked));
		INT32 commandId;
		CHECK_FAILURE(current->get_CommandId(&commandId));
		if (kind == COREWEBVIEW2_CONTEXT_MENU_ITEM_KIND_SEPARATOR)
		{
			AppendMenu(hPopupMenu, MF_SEPARATOR, 0, nullptr);
		}
		else if (kind == COREWEBVIEW2_CONTEXT_MENU_ITEM_KIND_SUBMENU)
		{
			HMENU newMenu = CreateMenu();
			wil::com_ptr<ICoreWebView2ContextMenuItemCollection> submenuItems;
			CHECK_FAILURE(current->get_Children(&submenuItems));
			AddMenuItems(newMenu, submenuItems);
			AppendMenu(hPopupMenu, MF_POPUP, (UINT_PTR)newMenu, labelString.c_str());
		}
		else if (kind == COREWEBVIEW2_CONTEXT_MENU_ITEM_KIND_COMMAND)
		{
			if (isEnabled)
			{
				AppendMenu(
					hPopupMenu, MF_BYPOSITION | MF_STRING, commandId, labelString.c_str());
			}
			else
			{
				AppendMenu(hPopupMenu, MF_GRAYED | MF_STRING, commandId, labelString.c_str());
			}
		}
		else if (
			kind == COREWEBVIEW2_CONTEXT_MENU_ITEM_KIND_CHECK_BOX ||
			kind == COREWEBVIEW2_CONTEXT_MENU_ITEM_KIND_RADIO)
		{
			if (isEnabled)
			{
				if (isChecked)
				{
					AppendMenu(
						hPopupMenu, MF_CHECKED | MF_STRING, commandId, labelString.c_str());
				}
				else
				{
					AppendMenu(
						hPopupMenu, MF_BYPOSITION | MF_STRING, commandId, labelString.c_str());
				}
			}
			else
			{
				if (isChecked)
				{
					AppendMenu(
						hPopupMenu, MF_CHECKED | MF_GRAYED | MF_STRING, commandId,
						labelString.c_str());
				}
				else
				{
					AppendMenu(
						hPopupMenu, MF_GRAYED | MF_STRING, commandId, labelString.c_str());
				}
			}
		}
	}
}

@ajtruckle
Copy link
Author

Update ....

If I run the same steps outside of Visual Studio environment it is fine. It displays a file selection window for me to save the file.

It is when I run it in Visual Studio that it fails.

@vickiez
Copy link
Contributor

vickiez commented Mar 8, 2023

@ajtruckle thanks for sharing your code, I'm having some trouble reproducing the issue. Can you share your SDK and WebView2 Runtime versions?

@ajtruckle
Copy link
Author

@vickiez

Sure! Here you go:

SDK build
1671.0
Runtime version
110.0.1587.63

I can replicate this with the sample WebView2APISample project. But, the key is that the application (or Visual Studio) must be running with elevation as Administrator.

We used to have a similar problem with Save as PDF where it would not show the Save Dialog in Admin mode but the issue was fixed. My gut is telling me that this is exactly the same. When using Microsoft Print to PDF it will invoke a File Dialog and this will fail when you are running in Admin mode.

@vickiez vickiez changed the title Printing with Microsoft print to PDF Printing with Microsoft print to PDF as admin Mar 9, 2023
@vickiez vickiez added the tracked We are tracking this work internally. label Mar 9, 2023
@vickiez
Copy link
Contributor

vickiez commented Mar 9, 2023

Ah thanks for the extra info @ajtruckle. I've opened a bug on our backlog, will let you know as soon as there is an update.

@ajtruckle
Copy link
Author

@vickiez Awesome! Thank you, Have a fab day.

@icnocop
Copy link

icnocop commented Apr 4, 2023

This also happens when using WPF and CoreWebView2PrintDialogKind.System.

@ajtruckle
Copy link
Author

@vickiez Hi! Hope you are well. Any timeframe for this?

@vickiez
Copy link
Contributor

vickiez commented May 22, 2023

Hi! The bug is lower priority at the moment and there is no set time frame, but will keep you updated

@ajtruckle
Copy link
Author

Hi @vickiez I assume no movement on this one?

@vickiez
Copy link
Contributor

vickiez commented Aug 21, 2023

Hi @ajtruckle, no update unfortunately. Will keep you posted

@ajtruckle
Copy link
Author

Hi @vickiez

This is another of these open tickets that I am concerned will just drop off the radar.

The WV2 team encourage us to provide feedback but it seems there is so many issues open and unresolved, months or years later.

Wouldn't it be great if they could all be hit on the head! 🛠️

@victorhuangwq
Copy link
Collaborator

Hi @ajtruckle, this item is still being tracked on our backlog, and there's no progress being made here.
Our team prioritize issues to decide where to best place our efforts, and unfortunately it does mean that there will be items that end up not being addressed for a long time, even though it is a valid issue.

@ajtruckle
Copy link
Author

Hi @victorhuangwq , is this moving up the list ? 🤔❓

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working tracked We are tracking this work internally.
Projects
None yet
Development

No branches or pull requests

5 participants