windowsgoogle-chrome-extensionchrome-native-messaging

Windows Chrome extension native messaging can only receive the first response


I am trying to use native messaging to send some data to my native windows application. It works well with the runtime.sendNativeMessage() method. When I am trying to use long lived connections which uses a port, it also can pass data from chrome to my app. However, chrome extension can only receive the first response from my app. I am sure that the port is still open because my app can still receive data from chrome. Following are my code:

Chrome Extension Script:

var port = chrome.runtime.connectNative('com.mydomain.app1');

port.onMessage.addListener(function(msg) {
    console.log("Received from port:", msg);
});

port.onDisconnect.addListener(function() {
    console.log("Disconnected");
});

chrome.tabs.onUpdated.addListener(
    function(tabId, changeInfo, tab) {  
        var param = {};
        param['url'] = tab.url; 
        port.postMessage( param);   
    }
}

My windows app in c++:

int _tmain(int argc, _TCHAR* argv[])
{
    while( true )
    {
         //read the first four bytes (=> Length)
         unsigned int length = 0;
         for (int i = 0; i < 4; i++)
         {
              char c;
              if( ( c=getchar()) != EOF) 
                  length += c<<i*8;
              else return 0;
          }

          //read the json-message
          std::string msg = "";
          for (int i = 0; i < length; i++)
          {
              msg += getchar();
          } 

          //.... do something

          //send a response message
          std::string message = "{\"text\": \"This is a response message\"}";
          unsigned int len = message.length();
          // We need to send the 4 bytes of length information
          std::cout << char(((len>>0) & 0xFF))
                    << char(((len>>8) & 0xFF))
                    << char(((len>>16) & 0xFF))
                    << char(((len>>24) & 0xFF));
           // Now we can output our message
           std::cout << message.c_str();
           std::cout.flush();
          
     }
}   

Notice that the last line "std::cout.flush();", if I comment it out, even the first response won't be shown in chrome. I just couldn't figure out how chrome reads from the app's stdout.


Solution

  • Try with automatic flushing - std::cout.setf( std::ios_base::unitbuf )

    Also, the way you read/write the input/output messages length is incorrect and will fail on long messages.

    This code works well for me:

    int main(int argc, char* argv[])
    {
        std::cout.setf( std::ios_base::unitbuf );
    
        while (true)
        {
            unsigned int ch, inMsgLen = 0, outMsgLen = 0;
            std::string input = "", response = "";
    
            // Read 4 bytes for data length
            std::cin.read((char*)&inMsgLen, 4);
    
            if (inMsgLen == 0)
            {
                break;
            }
            else
            {
                // Loop getchar to pull in the message until we reach the total length provided.
                for (int i=0; i < inMsgLen; i++)
                {
                    ch = getchar();
                    input += ch;
                }
            }
    
            response.append("{\"echo\":").append(input).append("}");
    
            outMsgLen = response.length();
    
            // Send 4 bytes of data length
            std::cout.write((char*)&outMsgLen, 4);
    
            // Send the data
            std::cout << response;
        }
    
        return 0;
    }