Even though it was conceived as a way to communicate between Aura and LWC, you should be able to get the Lightning Message Service to work for VF as well. (Thanks sfdcfox for the nudge here).
(Shamless plug) I wrote a blog post, here, describing the entire approach in detail but here are the highlights.
1) You create a Message Channel (similar method to a Platform Event). This is a sample file format (you will have to deploy this via workbench or similar to get it to work)
<?xml version="1.0" encoding="UTF-8"?>
<LightningMessageChannel xmlns="http://soap.sforce.com/2006/04/metadata">
<masterLabel>SayWhat</masterLabel>
<isExposed>true</isExposed>
<description>This Lightning Message Channel sends information from VF to LWC and back.</description>
<lightningMessageFields>
<fieldName>messageToSend</fieldName>
<description>The message to communicate to others</description>
</lightningMessageFields>
<lightningMessageFields>
<fieldName>sourceSystem</fieldName>
<description>Who Is Saying This?</description>
</lightningMessageFields>
</LightningMessageChannel>
2) In your first VF page, you can submit the event (using js)
// Load the MessageChannel token in a variable
var SAYWHATMC = "{!$MessageChannel.SayWhat__c}";
var subscriptionToMC;
function publishMessage() {
const payload = {
sourceSystem: "VF",
messageToSend: "Some Message"
};
sforce.one.publish(SAYWHATMC, payload);
}
3) In your second VF page, you can subscribe and process the event (again using JS)
// Load the MessageChannel token in a variable
var SAYWHATMC = "{!$MessageChannel.SayWhat__c}";
var subscriptionToMC;
function subscribeMC() {
if (!subscriptionToMC) {
subscriptionToMC = sforce.one.subscribe(SAYWHATMC, onMCPublished, {scope: "APPLICATION"});
}
}
function unsubscribeMC() {
if (subscriptionToMC) {
sforce.one.unsubscribe(subscriptionToMC);
subscriptionToMC = null;
}
}
function onMCPublished(message) {
var textArea = document.querySelector("#ReceivedMessage");
textArea.innerHTML = message ? 'Message: ' + message.messageToSend + '. Sent From: ' + message.sourceSystem : 'no message payload';
}
Again, the post has a lot more detail and steps, but the gist is above.