I am trying to implement a Chrome extension using runtime.connectNative and postMessage. I am following the Chrome documentation, downloaded the native messaging example, and changed the native app to using C++.
However, the native app cannot receive the message from the Chrome extension.
Meanwhile, when the native app using the printf function write message to chrome extension, the extension can not receive and the message just shown in the console.
Any ideas how to solve the problem?
You didn't provide a lot information about what you actually tried, so I will do my best to explain the steps needed to implement Chrome Extension, Native Messaging host and establish communication between them. (Please examine the following link to obtain more information about Chrome Native Messaging: Chrome Native Messaging How to.
CHROME EXTENSION
Firstly, we need to set up Chrome extension. As this will be very simple extension, we need only manifest.json file (please note this is extension's manifest file - native host will have its own manifest file as well) and background.js javascript implementation.
The following is sample manifest.json file:
{
"name": "Test extension",
"description": "Native messaging test",
"permissions": [
"nativeMessaging",
"tabs",
"activeTab",
"background",
"http://*/", "https://*/"
],
"background": {
"scripts": ["background.js"]
},
"version": "1.0",
"minimum_chrome_version": "29",
"manifest_version": 2
}
Important things here are that implementation will be provided in background.js, minimum supported Chrome version is 29 and HTTP and HTTPS are both supported.
Next, background.js file has the following content:
var port = chrome.runtime.connectNative('com.dolby.native_messaging_host');
port.onMessage.addListener(function(msg) {
console.log(msg.text);
});
port.onDisconnect.addListener(function() {
console.log("Disconnected");
});
port.postMessage({"text":"This is message from Chrome extension"});
The code itself is pretty self-explanatory - we try to connect to native host identified by com.dolby.native_messaging_host key (I will come to this in a minute). Then, we register a listener for onMessage event (this event is triggered when native host sends a message to the chrome extension). We also register a listener for disconnect event (for example when native host dies this event will be triggered). And finally, we send a message using postMessage method.
NATIVE MESSAGING HOST
Now, native host also has its own manifest.json file. Very simple manifest.json file for native host is as follows:
{
"name": "com.dolby.native_messaging_host",
"description": "Native messaging host",
"path": "C:\\Users\\dbajg\\Desktop\\Native-messaging-host\\Debug\\Native-messaging-host.exe",
"type": "stdio",
"allowed_origins": [
"chrome-extension://bjgnpdfhbcpjdfjoplajcmbleickphpg/"
]
}
Couple of interesting things here: name identifies the key under which this native host is registered. Path is full path to native host executable. Type of communication stdio means we are using standard input/output for communication (only type currently supported). And finally, allowed_origins specify which extensions can communicate with this native host - so you have to find out what is your extension's key!.
The next step is to register this Native Messaging host in registry (for Windows) and specify the location to its manifest file. The following screenshots explains how to this for Windows (examine provided link to find out how to do this in OSX and Linux):
After you've added registry entry for your native host the only remaining thing is to write your native host. The following C++ code implements simple native host that reads messages from the standard input and writes response to standard output (when you send #STOP# message the native host exits):
#include <iostream>
#include <string>
int main(){
std::string oneLine = "";
while (1){
unsigned int length = 0;
//read the first four bytes (=> Length)
/*for (int i = 0; i < 4; i++)
{
int read_char = getchar();
length += read_char * (int) pow(2.0, i*8);
std::string s = std::to_string((long long)read_char) + "\n";
fwrite(s.c_str(), sizeof(char), s.size(), f);
fflush(f);
}*/
//Neat way!
for (int i = 0; i < 4; i++)
{
unsigned int read_char = getchar();
length = length | (read_char << i*8);
}
//read the json-message
std::string msg = "";
for (int i = 0; i < length; i++)
{
msg += getchar();
}
std::string message = "{\"text\":\"This is a response message\"}";
// Collect the length of the message
unsigned int len = message.length();
// Now we can output our message
if (msg == "{\"text\":\"#STOP#\"}"){
message = "{\"text\":\"EXITING...\"}";
len = message.length();
std::cout << char(len>>0)
<< char(len>>8)
<< char(len>>16)
<< char(len>>24);
std::cout << message;
break;
}
// return stdin message
len = length;
std::cout << char(len>>0)
<< char(len>>8)
<< char(len>>16)
<< char(len>>24);
std::cout << msg << std::flush;
// return response message
// std::cout << char(len>>0)
// << char(len>>8)
// << char(len>>16)
// << char(len>>24);
//
// std::cout << message << std::flush;
}
return 0;
}
Messages sent by extension to native host is formed in a way that first byte stores the number of bytes in the message. So the first thing native host must do is to read the first 4 bytes and calculate the size of the message. I explained how to do this in another post that can be found here:
How to calculate size of the message sent by chrome extension
For future Google people, here's how I do it:
C style
Reading
char bInLen[4];
read(0, bInLen, 4); // 0 is stdin
unsigned int inLen = *(unsigned int *)bInLen;
char *inMsg = (char *)malloc(inLen);
read(0, inMsg, inLen);
inMsg[inLen] = '\0';
...
free(inMsg);
Writing
char *outMsg = "{\"text\":\"This is a response message\"}";
unsigned int outLen = strlen(outMsg);
char *bOutLen = (char *)&outLen;
write(1, bOutLen, 4); // 1 is stdout
write(1, outMsg, outLen);
fflush(stdout);
C++ style
Reading
char bInLen[4];
cin.read(bInLen, 4);
unsigned int inLen = *reinterpret_cast<unsigned int *>(bInLen);
char *inMsg = new char[inLen];
cin.read(inMsg, inLen);
string inStr(inMsg); // if you have managed types, use them!
delete[] inMsg;
Writing
string outMsg = "{\"text\":\"This is a response message\"}";
unsigned int outLen = outMsg.length();
char *bOutLen = reinterpret_cast<char *>(&outLen);
cout.write(bOutLen, 4);
cout << outMsg << flush;
Related
I have a MT166-C dispenser. I am writing C ++ code to manage a dispenser.
In development use SDK (attach the link) and I have a problem.
To work with the dispenser, I open the COM port. Code:
int input_port;
string com_str = "\\\\.\\COM";
std::cin >> input_port;
std::cout << "\nInput COM value: " << input_port << std::endl;
com_str = com_str + to_string(input_port);
char* cstr = &com_str[0];
char* port_com = cstr;
HANDLE port = CommOpenWithBaut(port_com, 9600);
if (port == 0)
{
std::cout << "Cannot open connect!\n\n" << std::endl;
return -1;
}
After I use the HANDLE port to call methods.
int iRetn = 0;
BYTE byStatus = 0;
string str = "";
iRetn = MT166_GetStatus(hPortHandle, 0x98, byStatus);
Similar to documentation (p. 3.1 in MT166-C.docx - Link Too)
DLLEXPORT int APIENTRY MT166_GetStatus(HANDLE hComHandle, BYTE CardNum,BYTE &byStatus)
///Parameter:
// hComHandle: Input parameter, serial port handle, obtained by opening the serial port
// CarderNum: Input parameter, card dispenser NO. Default is 0x98
// byStatus: output parameter, card dispenser status word
//Return value:
//Succeed, return value is 0
//failed, return value is not 0 = -1 no communication
In response, I get the code -1 - no communication. For other methods, the situation is the same.
I do not understand why there is no answer from the dispenser (no communication). I would be very grateful for any help.
I use connections via rs232 cable or USB adapter rs232 - without change.
Thank you for your time.
First of all, you need to check the physical availability of an external device.
Check baud speed, data bits, stop bits, row control parameters...
Check the OS hardware list for driver correctness.
I've got C++ code using the Paho MQTTPacket Embedded C++ library to connect to an MQTT broker. When that broker is io.adafruit.com, it works perfectly fine. But when it's my own Mosquitto instance running on my Raspberry Pi, the connection fails. I've narrowed it down to this line in MQTTClient.h, in the MQTT::Client::connect method:
// this will be a blocking call, wait for the connack
if (waitfor(CONNACK, connect_timer) == CONNACK)
The app hangs here for about 30 seconds, and then gets a result other than CONNACK (specifically 0 rather than 2).
I have tried both protocol version 3 (i.e. 3.1) and 4 (i.e. 3.1.1); same result.
My Mosquitto instance has no authentication or passwords set up. I've tried turning on debug messages in the Mosquitto log, but they're not showing anything useful. I'm at a loss. Why might I be unable to connect to Mosquitto from my C++ Paho code?
EDIT: Here's the client code... again, this works fine with Adafruit, but when I point it to my Mosquitto at localhost, it hangs as described. (I've elided the username and password -- I am sending them, but I really don't think those are the issue, since with mosquitto_pub or mosquitto_sub on the command line, I can connect regardless of this, since mosquitto is configured to allow anonymous connections.)
const char* host = "127.0.0.1";
int port = 1883;
const char* clientId = "ZoomBridge";
const char* username = "...";
const char* password = "...";
MQTT::QoS subsqos = MQTT::QOS2;
ipstack = new IPStack();
client = new MQTT::Client<IPStack, Countdown, 30000>(*ipstack);
MQTTPacket_connectData data = MQTTPacket_connectData_initializer;
data.willFlag = 1;
data.MQTTVersion = 3;
data.clientID.cstring = (char*)clientId;
data.username.cstring = (char*)username;
data.password.cstring = (char*)password;
data.keepAliveInterval = 20;
data.cleansession = 1;
int rc = ipstack->connect(host, port);
if (rc != MQTT::SUCCESS) {
cout << "Failed [1] (result " << rc << ")" << endl;
return rc;
}
rc = client->connect(data);
if (rc != MQTT::SUCCESS) {
cout << "Failed [2] (result " << rc << ")" << endl;
ipstack->disconnect();
return rc;
}
As hashed out in the comments.
It looks like you are setting the flag to indicate you want to set a Last Will and Testament for the client (data.willFlag = 1;) but then not passing any topic or payload for the LWT.
If you don't need the LWT then set the flag to 0 (or remove the line settings flag) as it should default to disabled.
Also worth pointing out to clarity, this is all with the Paho Embedded C++ MQTTPacket client not the full blown Paho C++ client.
There are several ways to list serial ports under Windows but I'm not sure what is the proper way: the way that does detect all serial ports that are available.
One good code example is http://www.naughter.com/enumser.html - where there are 9 (nine!) ways of enumerating serial devices.
The question is: what is the optimal way of doing it.
Requirements:
to not open ports in order to check if they are available.
to be able to detect ports with different names than COMx.
to work on Windows XP SP2 or above
void SelectComPort() //added function to find the present serial
{
TCHAR lpTargetPath[5000]; // buffer to store the path of the COMPORTS
DWORD test;
bool gotPort=0; // in case the port is not found
for(int i=0; i<255; i++) // checking ports from COM0 to COM255
{
CString str;
str.Format(_T("%d"),i);
CString ComName=CString("COM") + CString(str); // converting to COM0, COM1, COM2
test = QueryDosDevice(ComName, (LPSTR)lpTargetPath, 5000);
// Test the return value and error if any
if(test!=0) //QueryDosDevice returns zero if it didn't find an object
{
m_MyPort.AddString((CString)ComName); // add to the ComboBox
gotPort=1; // found port
}
if(::GetLastError()==ERROR_INSUFFICIENT_BUFFER)
{
lpTargetPath[10000]; // in case the buffer got filled, increase size of the buffer.
continue;
}
}
if(!gotPort) // if not port
m_MyPort.AddString((CString)"No Active Ports Found"); // to display error message incase no ports found
}
If you can access the registry, the HKEY_LOCAL_MACHINE\HARDWARE\DEVICEMAP\SERIALCOMM key contains a list of COM ports Windows currently supports (in some cases, this information may be stale/incorrect; like, I suspect, when a plug & play device providing serial ports has not completed detection/installation or has been recently removed).
This is the way .NET Framework's SerialPort.GetPortNames() method reports available COM ports, and the above information is derived from the linked page.
Serial ports are very simple devices, dating from the stone age of computing hardware. They don't support Plug & Play, there is no way to tell that somebody plugged in a device. The only thing you can do is discover what ports are available, the SerialPort.GetPortNames() returns the list. Some USB emulators can generate a descriptive name to go with the port name, you can discover those with WMI, Win32_SerialPort class.
None of which helps you discover what COM port is connected to a particular device. Only a human knows, she physically plugged the cable in the connector. You'll need to provide a config UI that lets the user select the port number. A combo box gets the job done. Save the selection in your config data, it is very likely that the device is still connected to the same port the next time your program starts.
This is a modernized version of #michael-jacob-mathew's answer:
#include <iostream>
#include <string>
#include <Windows.h>
bool SelectComPort() //added function to find the present serial
{
char lpTargetPath[5000]; // buffer to store the path of the COMPORTS
bool gotPort = false; // in case the port is not found
for (int i = 0; i < 255; i++) // checking ports from COM0 to COM255
{
std::string str = "COM" + std::to_string(i); // converting to COM0, COM1, COM2
DWORD test = QueryDosDevice(str.c_str(), lpTargetPath, 5000);
// Test the return value and error if any
if (test != 0) //QueryDosDevice returns zero if it didn't find an object
{
std::cout << str << ": " << lpTargetPath << std::endl;
gotPort = true;
}
if (::GetLastError() == ERROR_INSUFFICIENT_BUFFER)
{
}
}
return gotPort;
}
It produces the following output on my computer:
COM1: \Device\Serial0
COM3: \Device\VCP0
Modified #Dženan answer to use wide characters and returning list of ints
#include <string>
#include <list>
list<int> getAvailablePorts()
{
wchar_t lpTargetPath[5000]; // buffer to store the path of the COM PORTS
list<int> portList;
for (int i = 0; i < 255; i++) // checking ports from COM0 to COM255
{
wstring str = L"COM" + to_wstring(i); // converting to COM0, COM1, COM2
DWORD res = QueryDosDevice(str.c_str(), lpTargetPath, 5000);
// Test the return value and error if any
if (res != 0) //QueryDosDevice returns zero if it didn't find an object
{
portList.push_back(i);
//std::cout << str << ": " << lpTargetPath << std::endl;
}
if (::GetLastError() == ERROR_INSUFFICIENT_BUFFER)
{
}
}
return portList;
}
You can check the windows registry base to list all COM ports. Here is my code > github file
CUIntArray ports;
EnumerateSerialPorts(ports);
for (int i = 0; i<ports.GetSize(); i++)
{
CString str;
str.Format(_T("COM%d"), ports.ElementAt(i));
m_ctlPort.AddString(str);
}
I am learning boost::asio network programming and tried to make simple file transfer exercise, using blocking sockets, and so, stuck upon strange issue issue.
Server (receiver) loop is following:
while (true){
int bufSize{ static_cast<int>(pow(2, 18)) };
char* buf{ new char[bufSize] };
__int64 currPos{ 0 };
__int64 fileSize;
std::string fileName;
mSocket->receive(buffer(buf, bufSize)); // here we get pre-defined packet with XML
ParseDescXML(std::string{ buf }, &fileName, &fileSize); // and parse this XML, get name and size
std::ofstream ofs(mSavePath + fileName, std::ios::binary);
if (ofs.is_open()){
while (currPos != fileSize) {
if (bufSize > fileSize - currPos){
delete[] buf;
bufSize = fileSize - currPos;
buf = new char[bufSize];
}
mSocket->receive(buffer(buf, bufSize));
ofs.write(buf, bufSize);
currPos += bufSize;
std::cout << "SERVER " << currPos << std::endl;
}
}
delete[] buf;
ofs.close();
slDebug("Receive completed"); // output some stuff, not related to issue
}
client (sender) loop is following:
mWorkerOccupied = true;
std::ifstream ifs(filePath, std::ios::binary);
if (!ifs.is_open()){
mWorkerOccupied = false;
return false;
}
mFileName = filePath.substr(filePath.find_last_of('\\') + 1, filePath.length());
mCurrPos = 0;
mFileSize = GetFileSize(&ifs);
std::string xmlDesc{ MakeXMLFileDesc(mFileName, mFileSize) }; // here we make XML description
xmlDesc.push_back('\0');
int bufSize{ static_cast<int>(pow(2, 18)) };
char* buf{ new char[bufSize] };
mSocket->send(buffer(xmlDesc.c_str(), bufSize)); // and send it.
while (mCurrPos != mFileSize){
if (bufSize > mFileSize - mCurrPos){
delete[] buf;
bufSize = mFileSize - mCurrPos;
buf = new char[bufSize];
}
ifs.read(buf, bufSize);
mSocket->send(buffer(buf, bufSize));
mCurrPos += bufSize;
std::cout << "CLIENT " << mCurrPos << std::endl;
}
ifs.close();
delete[] buf;
mWorkerOccupied = false;
slDebug("SendFile completed");
All this stuff is running in parallels threads.
From my understanding it should be working this way:
Server thread runs servers and hangs, until incoming connection (working as expected, so I did not include this code here).
Client thread runs after some time and connects to server (working as expected)
Server waiting for first packet, contains XML (working as expected)
Client sends XML, server gets it (working as expected)
Client starts to send actual binary data, server get it. Here we have major problem.
I have a output of current position of file in both client and server loop.
I expect it to be something like:
CLIENT 228 // first we send some data
SERVER 228 // Server gets it and outputs the same file pos
or
CLIENT 228
CLIENT 456
SERVER 228
SERVER 456
But what I am actually getting - confuses me...
SERVER 499384320
SERVER 499646464
CLIENT 88604672
SERVER 499908608
CLIENT 88866816
SERVER 500170752
SERVER 500432896
SERVER 500695040
SERVER 500957184
Far more messages regarding receiving something by server, than client ones about sending. How it can be? Literally, looks like client sent only 80mb of data, while server already received 500mb of data... I thought, that server thread should wait on receive(), since I am using blocking socket, but this is strange. Could someone explain me, why I have this huge desync?
You're assuming that receive reads the entire buffer size at once, but it doesn't necessarily:
The receive operation may not receive all of the requested number of bytes. Consider using
the read function if you need to ensure that the requested amount of data is read before the
blocking operation completes
receive returns the amount of data read, you should change your code to something like:
size_t recvd = mSocket->receive(buffer(buf, bufSize));
ofs.write(buf, recvd);
currPos += recvd;
I am facing issue in passing data between c# and C++ (QT) application through named pipe communication. C# client application connects to NamedPipe server which is in c++ but message is not being parsed correctly on server. Example, I am sending value of short variable = 2 and c++ code parse byte array into unsigned int but value is coming always zero in server. Could you please let me know what I am doing wrong?
Client and server code:
NamedPipe Server code in C++ using QT Library
QLocalSocket *local_socket = _local_server->nextPendingConnection();
if (!local_socket->waitForReadyRead(gft::PROC_TIMEOUT)) {
qDebug() << "gft_plugin: timeout while waiting for data";
return;
}
int bytesavailable = local_socket->bytesAvailable();
QByteArray buffer;
QDataStream in(&buffer, QIODevice::ReadOnly);
buffer.append(local_socket->readAll());
unsigned int msg;
in >> msg;
unsigned int a_id = msg;
NamedPipe Client (C#)
var clientStream = new NamedPipeClientStream("localhost", "gft_plugin_server", PipeDirection.InOut);
clientStream.Connect();
if (clientStream.IsConnected)
{
_stop = false;
UInt16 a_id = 2;
byte[] b = BitConverter.GetBytes(a_id);
clientStream.Write(b, 0, b.Count());
clientStream.Flush();
}
else
{
MessageBox.Show("Could not connected");
}