Does the WinRT Clipboard History only support text and images? - c++

I'm making a C++/WinRT app that makes use of the Window 10 clipboard history but for some reason I can only grab text and images.
My code is a bit like this..
auto history = Clipboard::GetHistoryItemsAsync().get();
if (history.Status() == ClipboardHistoryItemsResultStatus::Success)
{
auto historyItemList = history.Items();
for (const auto& historyitem : historyItemList)
{
//Works
if (dataPackageView.Contains(StandardDataFormats::Text()))
{
GetClipboardText(dataPackageView);
}
//Works
if (dataPackageView.Contains(StandardDataFormats::Bitmap()))
{
GetClipboardBitmap(dataPackageView);
}
//Never triggers
if (dataPackageView.Contains(StandardDataFormats::Html()))
{
GetClipboardHtml(dataPackageView);
}
//Never triggers
if (dataPackageView.Contains(StandardDataFormats::StorageItems()))
{
GetClipboardStorageItems(dataPackageView);
}
//etc..
I'd like to make use of the other dataformats. EG: For StorageItems, I expected if I CTRL+C an item from my desktop or if I did it programatically with
dataPackage.SetStorageItems({ std::begin(files), std::end(files) });
Clipboard::SetContent(dataPackage);
Clipboard::Flush();
The file would end up in the clipboard history so I could handle it like in the first snippet. But the file never appears in the returned Clipboard::GetHistoryItemsAsync() container. I also don't see the file in the history viewer when you press WIN+V.
So what i'm wondering is;
Does Windows 10 clipboard history "only" support raw text and images? can I not make use of the other dataformat properties? (ApplicationLink, Html, Rtf, StorageItems, Uri, Weblink etc)
I gave StorageItems as an example but it happens with the other formats too. If I CTRL+C a weblink (such as: https://stackoverflow.com/questions/ask), I expected dataPackageView.Contains(StandardDataFormats::WebLink()) Or Uri to trigger, but they don't
If the clipboard history can support other formats, how do you actually make use of it?
Edit:
Forgot to add. When I programatically added a StorageItem to the clipboard I also tried it like below. Don't know why I can't add strings to an IVector though.
auto options = ClipboardContentOptions();
auto formats = Windows::Foundation::Collections::IVector<hstring>();
formats.Append(StandardDataFormats::StorageItems()); //Unhandled Exception
options.IsAllowedInHistory(true);
options.IsRoamable(true);
options.HistoryFormats() = formats;
options.RoamingFormats() = formats;
Clipboard::Clipboard::Clear();
Clipboard::SetContentWithOptions(dataPackage, options);
Clipboard::Flush();

As observed by my esteemed colleague Faywang - MSFT, Windows' clipboard history and cloud clipboard sync implementation supports only a limited number of clipboard data formats, and this is reflected in the UWP clipboard API in the Windows Runtime Clipboard class.
It's important to remember that what clipboard formats are supported by clipboard history is not a contractual detail of clipboard history. Please keep that in mind when you read on:
As of Windows 10 version 2004 (aka build 19041, aka the May 2020 update), clipboard history supports the following clipboard data formats defined in StandardDataFormats:
Plain text: StandardDataFormats.Text
Various URI formats: StandardDataFormats.Uri, StandardDataFormats.WebLink, and StandardDataFormats.ApplicationLink
HTML clipboard format: StandardDataFormats.Html
Bitmaps: StandardDataFormats.Bitmap
For compatibility with classic desktop applications (aka Win32 apps), clipboard history also supports a few clipboard data formats whose names are not in StandardDataFormats, but which the Windows system can auto-convert to and from the above-listed StandardDataFormats formats when needed by an app trying to paste a particular format.
Clipboard history does not support any other custom or well-known clipboard formats.
Given the above, the only thing I see in your results that seems strange is that your app doesn't appear to be reading the HTML format. I don't know of any Windows implementation bugs in this area - try fiddling with your code some more, and if you still have trouble, I'd definitely encourage you to post another question, or contact us at Microsoft another way (such as through Feedback Hub).
I do observe that the Microsoft documentation around clipboard history from a conceptual technical perspective is lacking. I'd also encourage you to file GitHub issues against the places where clipboard history is documented, such as https://github.com/MicrosoftDocs/winrt-api - we're always listening.

Related

How to monitor clipboard changes in X11 Windows?

I am pretty much exhausted all the possibilities of finding an X11 API to perform the following thing.
I have a thread which is trying to monitor for an event or notification to know when anything is copied into clipboard by any X11 client. I do not want to monitor a specific Atom Target (clipboard format), but generally looking for changes in clipboards.
Once, I know that something has changed in the clipboard, I can dive in and perform XConvertSelection() on all the target formats (I want to request server to give me all the possible ways to convert the copied data), and futher process them into SelectionRequest event.
Again, I want to generally get request for all the formats (thinking to enumerate between 1 to 1000 to check target Atoms), and not register changes for one specific format. Based on response from the server, if a particular atom is absent, I can check None as the property member, or else store other target Atom Names in a list.
Can anyone help me with how to monitor for changes in Clipboard? Also, does iterating 1 to 1000 will guarantee exhaustive search of all possible format? Or is there a better way to do just that?
To monitor changes, use XFixes. With XCB it is used like:
// Enable XFixes
auto xfixes = xcb_get_extension_data(connection, &xcb_xfixes_id); // do not free!
ev_selection_change_notify = xfixes->first_event + XCB_XFIXES_SELECTION_NOTIFY;
auto *version = xcb_xfixes_query_version_reply(xcb_xfixes_query_version(connection, XCB_XFIXES_MAJOR_VERSION, XCB_XFIXES_MINOR_VERSION));
// Subscribe to clipboard notifications
xcb_xfixes_select_selection_input(connection, root, clipboard, XCB_XFIXES_SELECTION_EVENT_MASK_SET_SELECTION_OWNER);
// Event loop:
auto *event = xcb_poll_for_event(connection);
int etype = event->response_type & 0x7f;
if (etype == ev_selection_change_notify) {
auto *notification = reinterpret_cast<xcb_xfixes_selection_notify_event_t *>(event);
...
}
...
In Xlib it should be similar.
To check the list of available targets, don’t loop to 1000! Simply query the TARGETS target, it should give you the list of valid targets for the clipboard content.
There is a caveat, though: instead of “the” clipboard, X11 allow applications to use “selections” which can be tagged by arbitrary atoms. Of those CLIPBOARD is of primary interest but PRIMARY and (rarely used) SECONDARY are also there, as well as arbitrary selections for “private communication”.
Reference: https://www.x.org/releases/X11R7.7/doc/xorg-docs/icccm/icccm.html#Use_of_Selection_Atoms

Open a c++ application installed on computer with a custom url in browser [duplicate]

How do i set up a custom protocol handler in chrome? Something like:
myprotocol://testfile
I would need this to send a request to http://example.com?query=testfile, then send the httpresponse to my extension.
The following method registers an application to a URI Scheme. So, you can use mycustproto: in your HTML code to trigger a local application. It works on a Google Chrome Version 51.0.2704.79 m (64-bit).
I mainly used this method for printing document silently without the print dialog popping up. The result is pretty good and is a seamless solution to integrate the external application with the browser.
HTML code (simple):
Click Me
HTML code (alternative):
<input id="DealerName" />
<button id="PrintBtn"></button>
$('#PrintBtn').on('click', function(event){
event.preventDefault();
window.location.href = 'mycustproto:dealer ' + $('#DealerName').val();
});
URI Scheme will look like this:
You can create the URI Scheme manually in registry, or run the "mycustproto.reg" file (see below).
HKEY_CURRENT_USER\Software\Classes
mycustproto
(Default) = "URL:MyCustProto Protocol"
URL Protocol = ""
DefaultIcon
(Default) = "myprogram.exe,1"
shell
open
command
(Default) = "C:\Program Files\MyProgram\myprogram.exe" "%1"
mycustproto.reg example:
Windows Registry Editor Version 5.00
[HKEY_CURRENT_USER\Software\Classes\mycustproto]
"URL Protocol"="\"\""
#="\"URL:MyCustProto Protocol\""
[HKEY_CURRENT_USER\Software\Classes\mycustproto\DefaultIcon]
#="\"mycustproto.exe,1\""
[HKEY_CURRENT_USER\Software\Classes\mycustproto\shell]
[HKEY_CURRENT_USER\Software\Classes\mycustproto\shell\open]
[HKEY_CURRENT_USER\Software\Classes\mycustproto\shell\open\command]
#="\"C:\\Program Files\\MyProgram\\myprogram.exe\" \"%1\""
C# console application - myprogram.exe:
using System;
using System.Collections.Generic;
using System.Text;
namespace myprogram
{
class Program
{
static string ProcessInput(string s)
{
// TODO Verify and validate the input
// string as appropriate for your application.
return s;
}
static void Main(string[] args)
{
Console.WriteLine("Raw command-line: \n\t" + Environment.CommandLine);
Console.WriteLine("\n\nArguments:\n");
foreach (string s in args)
{
Console.WriteLine("\t" + ProcessInput(s));
}
Console.WriteLine("\nPress any key to continue...");
Console.ReadKey();
}
}
}
Try to run the program first to make sure the program has been placed in the correct path:
cmd> "C:\Program Files\MyProgram\myprogram.exe" "mycustproto:Hello World"
Click the link on your HTML page:
You will see a warning window popup for the first time.
To reset the external protocol handler setting in Chrome:
If you have ever accepted the custom protocol in Chrome and would like to reset the setting, do this (currently, there is no UI in Chrome to change the setting):
Edit "Local State" this file under this path:
C:\Users\Username\AppData\Local\Google\Chrome\User Data\
or Simply go to:
%USERPROFILE%\AppData\Local\Google\Chrome\User Data\
Then, search for this string: protocol_handler
You will see the custom protocol from there.
Note: Please close your Google Chrome before editing the file. Otherwise, the change you have made will be overwritten by Chrome.
Reference:
https://msdn.microsoft.com/en-us/library/aa767914(v=vs.85).aspx
Chrome 13 now supports the navigator.registerProtocolHandler API. For example,
navigator.registerProtocolHandler(
'web+custom', 'http://example.com/rph?q=%s', 'My App');
Note that your protocol name has to start with web+, with a few exceptions for common ones (like mailto, etc). For more details, see: http://updates.html5rocks.com/2011/06/Registering-a-custom-protocol-handler
This question is old now, but there's been a recent update to Chrome (at least where packaged apps are concerned)...
http://developer.chrome.com/apps/manifest/url_handlers
and
https://github.com/GoogleChrome/chrome-extensions-samples/blob/e716678b67fd30a5876a552b9665e9f847d6d84b/apps/samples/url-handler/README.md
It allows you to register a handler for a URL (as long as you own it). Sadly no myprotocol:// but at least you can do http://myprotocol.mysite.com and can create a webpage there that points people to the app in the app store.
This is how I did it. Your app would need to install a few reg keys on installation, then in any browser you can just link to foo:\anythingHere.txt and it will open your app and pass it that value.
This is not my code, just something I found on the web when searching the same question. Just change all "foo" in the text below to the protocol name you want and change the path to your exe as well.
(put this in to a text file as save as foo.reg on your desktop, then double click it to install the keys)
-----Below this line goes into the .reg file (NOT including this line)------
REGEDIT4
[HKEY_CLASSES_ROOT\foo]
#="URL:foo Protocol"
"URL Protocol"=""
[HKEY_CLASSES_ROOT\foo\shell]
[HKEY_CLASSES_ROOT\foo\shell\open]
[HKEY_CLASSES_ROOT\foo\shell\open\command]
#="\"C:\\Program Files (x86)\\Notepad++\\notepad++.exe\" \"%1\""
Not sure whether this is the right place for my answer, but as I found very few helpful threads and this was one of them, I am posting my solution here.
Problem: I wanted Linux Mint 19.2 Cinnamon to open Evolution when clicking on mailto links in Chromium. Gmail was registered as default handler in chrome://settings/handlers and I could not choose any other handler.
Solution:
Use the xdg-settings in the console
xdg-settings set default-url-scheme-handler mailto org.gnome.Evolution.desktop
Solution was found here https://alt.os.linux.ubuntu.narkive.com/U3Gy7inF/kubuntu-mailto-links-in-chrome-doesn-t-open-evolution and adapted for my case.
I've found the solution by Jun Hsieh and MuffinMan generally works when it comes to clicking links on pages in Chrome or pasting into the URL bar, but it doesn't seem to work in a specific case of passing the string on the command line.
For example, both of the following commands open a blank Chrome window which then does nothing.
"c:\Program Files (x86)\Google\Chrome\Application\chrome.exe" "foo://C:/test.txt"
"c:\Program Files (x86)\Google\Chrome\Application\chrome.exe" --new-window "foo://C:/test.txt"
For comparison, feeding Chrome an http or https URL with either of these commands causes the web page to be opened.
This became apparent because one of our customers reported that clicking links for our product from a PDF being displayed within Adobe Reader fails to invoke our product when Chrome is the default browser. (It works fine with MSIE and Firefox as default, but not when either Chrome or Edge are default.)
I'm guessing that instead of just telling Windows to invoke the URL and letting Windows figure things out, the Adobe product is finding the default browser, which is Chrome in this case, and then passing the URL on the command line.
I'd be interested if anyone knows of Chrome security or other settings which might be relevant here so that Chrome will fully handle a protocol handler, even if it's provided via the command line. I've been looking but so far haven't found anything.
I've been testing this against Chrome 88.0.4324.182.
open
C:\Users\<Username>\AppData\Local\Google\Chrome\User Data\Default
open Preferences then search for excluded_schemes you will find it in 'protocol_handler' delete this excluded scheme(s) to reset chrome to open url with default application

Can I programmatically use the OneNote printer driver?

I have a system service that handles print requests, and given a printer name from the user, attaches a DC to that printer. It starts a document, ends it, and detatches.
m_PrinterDC.CreateDC (L"WINSPOOL", _printerName.c_str(), NULL, NULL)
m_DC.Attach(m_hprinter)
m_DC.StartDoc(...)
...
mDc.TextOut(...)
...
m_DC.EndDoc()
m_DC.Detatch()
This works fine for normal printers, but when using the "Print to OneNote" functionality (driver name 'Send To OneNote 2010') it doesn't seem to work. I would like to avoid custom logic just for this feature; ideally all printers would work regardless. Any thoughts what might be going wrong? I've tried updating the printer security settings to include Print rights for group everyone; not sure what else to try.
Unfortunately, I have to guess some points, because you seem to avoid detailed description of error condition.
First, if you check all return values are success, just it may be a problem about onenote itself. Check the condition of onenote by printing using other programmes.
Second, did you check if _printerName is exact? If some of users are using other language OS, the driver name, 'Send To OneNote 2010' will be different or depending on version. Of course, if you check all return values of function calls, it recorded in your log file. However, I'm worrying about you used exact printer name by using 'EnumPrinters'.
http://msdn.microsoft.com/en-us/library/windows/desktop/dd162931(v=vs.85).aspx
I hope this helps you a little.

How to Change Default search provider of IE 9 by registry Editing through C++ program?

I want to change the default search provider of IE (9) by editing the registry file. I have followed the steps given in the link: http://www.online-tech-tips.com/internet-explorer-tips/change-default-search-engine-ie/.
But when I change DefaultScope value to a scope in SearchScopes, then restart the computer, or open IE, make a search in address bar, or close IE. The value of DefaultScope is restore to previous value.
Why? Or what is my mistake?
How to change the search provider engine of IE programatically (not in IE, may be through registry, or in my C++ code)? (I write a C++ program that need to change IE's search provider engine)
I have written this function for Firefox or Chrome. It works well.
With Firefox, those information is stored in the prefs.js file. I can
read or write information requisite to this file easily. With Chrome,
those information is stored in two files in user profile folder:
Preferences and Web Data files. The Preferences file is a JSON file. I
get those information easily by parsing this JSON file. But to set
search engine provider information for Chrome. We need to change those
information in Web Data file. Web Data file is a SQLite file. I use
SQLite library to access this.
With Internet Explorer, I can get those information in that registry
path. But I can't set those information with that registry path. So, I
think, like Chrome, IE (or registry) needs to change those information
somewhere. But I don't know where.
Here is a detailed answer to your question.
There are two options you may choose from use IOpenServiceManager:
CComQIPtr<IOpenServiceManager> spManager;
check(spManager.CoCreateInstance(__uuidof(OpenServiceManager), CLSCTX_ALL));
CComQIPtr<IOpenService> spService;
check(spManager->InstallService(PU_POSTINSTALL_ANT_SEARCH_PROVIDER_XML, &spService));
if(makeItDefault)
{
// Request that the user change their search default
check(spService->SetDefault( TRUE, hPromptParent ));
}
or modify the registry:
LPCWSTR searchScopesKeyName = L"Software\\Microsoft\\Internet Explorer\\SearchScopes";
createKey(rootKey, HKEY_CURRENT_USER, searchScopesKeyName);
std::wstring clsidString = findProviderClsid(false);
if( clsidString.empty() )
clsidString = mc_providerClsidString;
if( makeItDefault )
setStringValue( rootKey, mc_defaultScopeValueName, clsidString.c_str() );
ATL::CRegKey subKey;
createKey(subKey, rootKey.m_hKey, clsidString.c_str() );
setStringValue( subKey, mc_displayNameValueName, mc_providerName );
setStringValue( subKey, mc_faviconUrlValueName, mc_providerFaviconURL );
setStringValue( subKey, mc_urlValueName, mc_providerURL );
Just giving a side note that SetDefault function was deprecated on Microsoft Edge browser. Also, after KB3148198 update, it's blocked. Function will return
OS_E_CANCELLED instead.

Outlook 2010 C++ add-in - HTML email body retrieval

I'm writing an outlook 2010 add-in, my add-in appends a footer to emails according to each email format (plain text/HTML), now I just discovered a problem that happens when I enable the outlook "Read emails as plain text" feature (http://support.microsoft.com/kb/831607), what happens is my add-in receives HTML emails as plain text, so it adds the footer and saves them accordingly which is a problem because after saving as plain text, the actual HTML version of the email is completely lost from outlook.
Here's my code (edited for brevity):
void CConnect::OnNewItem(IDispatch* item)
{
if (item)
{
CComQIPtr<Outlook::_MailItem> mailItem(item);
OlBodyFormat bodyFormat;
mailItem->get_BodyFormat(&bodyFormat);
CComBSTR body;
if(bodyFormat == olFormatPlain)
mailItem->get_Body(&body);
if(bodyFormat == olFormatHTML)
mailItem->get_HTMLBody(&body);
//append the footer here
if(bodyFormat == olFormatPlain)
mailItem->put_Body(newBody);
if(bodyFormat == olFormatHTML)
mailItem->put_HTMLBody(newBody);
mailItem->Save();
mailItem->Release();
}
}
I also tried getting the HTML body of emails no matter what their format actually is, but I get a generated HTML version of the plain text version, so all the original CSS and formatting is lost.
What I need is a way to be able to retrieve the original HTML version when the outlook "Read emails as plain text" feature is on, Any help would be greatly appreciated.
A bit dated, but just saw this now...
You are probably going to need to drop down to the MAPI level to do this properly. Something like:
LPMESSAGE MapiMessage;
HRESULT ResultCode = HrGetOneProp(MapiMessage, PR_HTML, &PropertiesValues);
LPSBinary HtmlBodyProperty = (LPSBinary)&PropertiesValues->Value.bin;
Integrating MAPI support into your addin is not as painful as some people might think. A good starting point is "Using MAPI to Create Outlook 2007 Items".