public static int RunNamedPipeHandler(int parentWindowHandle, String commandPipeName) { int result = -1; int pipe_connect_timeout = 10000; // Millisecond timeout try { _logger.LogMsg(Level.Debug, "Entering RunNamedPipeHandler()."); // Get the (short) pipe name and host name from the full path. // The .NET functions do not want the full path, only the name. Path format: "\\hostname\pipe\mypipename.pip" String host_name = null; String pipe_name = null; if (!ParsePipePath(commandPipeName, out host_name, out pipe_name)) { _logger.LogMsg(Level.Fatal, String.Format("Invalid command pipe path {0}. Connector cannot continue.", commandPipeName)); return result; } // Create the .NET pipe wrapper object. NamedPipeClientStream pipeClientStream = CreatePipeStream(pipe_name, host_name, pipe_connect_timeout); // Read from pipe _logger.LogMsg(Level.Debug, String.Format("Opening .NET StreamReader.")); Boolean keep_on_processing = true; String msg = null; while (keep_on_processing) { // Qlikview seems to need some time to respond so we always sleep a few seconds. if (_messageWaitMilliseconds > 0) { //_logger.LogMsg(Level.Debug, String.Format("Sleeping in message handler loop for {0} milliseconds.", _messageWaitMilliseconds.ToString())); Thread.Sleep(_messageWaitMilliseconds); } // *** Get the next full XML message from the QlikView command pipe. msg = ReadNextCommandMessage(pipeClientStream); if (String.IsNullOrEmpty(msg)) { _logger.LogMsg(Level.Info, "No message received on command pipe."); keep_on_processing = false; //no_response++; //if (no_response > 10) //{ // keep_on_processing = false; //} } else { _logger.LogMsg(Level.Debug, String.Format("Command message received (length {0}). XML follows: \r\n{1}", msg.Length.ToString(), msg)); // *** Handle command message QlikViewMessage command_msg = new QlikViewMessage(); if (command_msg.Load(msg)) { switch (command_msg.MessageType) { case QlikViewCommandTypes.Connect: // Get connection string, send "OK" response. _connectionString = command_msg.GetConnectionString(); _logger.LogMsg(Level.Info, String.Format("Handling QVX_CONNECT. Connection String: {0}", _connectionString)); // TO DO: Test the connection with the Java proxy ? This would be a round trip to // the remote server so it could be a performance issue. String connect_error_msg; String connect_response_xml = QlikViewMessage.MakeGenericReplyMessage(true); if (!Properties.Settings.Default.SimulateConnection) { Boolean success = TestConnection(_driverName, _connectionString, _userName, _password, out connect_error_msg); if (!success) { connect_response_xml = QlikViewMessage.MakeGenericReplyMessage(false, null, connect_error_msg); } } SendCommandMessage(pipeClientStream, connect_response_xml); keep_on_processing = true; break; case QlikViewCommandTypes.Execute: // Get the SQL and data pipe name from the QVX_EXECUTE message. command_msg.GetSQLStatementAndDataPipeName(out _sql, out _dataPipePath); _logger.LogMsg(Level.Debug, String.Format( "Handling QVX_EXECUTE. Data pipe path: [{0}], SQL: [{1}].", _dataPipePath, _sql )); // Send QVX_OK before writing to data pipe. String execute_response_xml = QlikViewMessage.MakeGenericReplyMessage(true); SendCommandMessage(pipeClientStream, execute_response_xml); // TO DO: need to get driver, connectionstring, username, password //String drivername = Properties.Settings.Default.dr // Write data to the data pipe. if (!String.IsNullOrEmpty(_sql) && !String.IsNullOrEmpty(_dataPipePath)) { RunBigDataQueryJava(_dataPipePath, _connectionString, _sql); } // Keep on procressing - there mat be multiple QVX_EXECUTE - one for each SQL statement in the script. keep_on_processing = true; break; case QlikViewCommandTypes.GenericCommand: String generic_val; String generic_response_xml; command_msg.ParseGenericCommand(out generic_val); _logger.LogMsg(Level.Debug, String.Format("Handling QVX_GENERIC_COMMAND: {0}", generic_val)); switch( generic_val ) { case QlikViewGenericCommandValues.GetCustomCaption: // Send the caption? if (!Properties.Settings.Default.DisableCustomSQLButton) { // This causes QlikView to display the custom SQL button. generic_response_xml = QlikViewMessage.MakeGenericReplyMessage(true, new String[] { _customButtonCaption }); } else { // This reply prevents QlikView from displaying the custom SQL button. generic_response_xml = QlikViewMessage.MakeGenericReplyMessage(false); } SendCommandMessage(pipeClientStream, generic_response_xml); keep_on_processing = true; break; case QlikViewGenericCommandValues.DisableQlikViewSelectButton: // NOTE: we disable the "Select" button by default since it appears to an ODBC-only thing. if (Properties.Settings.Default.DisableQlikViewSelectButton) { generic_response_xml = QlikViewMessage.MakeGenericReplyMessage(true, new String[] { "true" }); } else { generic_response_xml = QlikViewMessage.MakeGenericReplyMessage(false); } SendCommandMessage(pipeClientStream, generic_response_xml); keep_on_processing = true; break; case QlikViewGenericCommandValues.HaveStarField: generic_response_xml = QlikViewMessage.MakeGenericReplyMessage(true, new String[] { "true" }); SendCommandMessage(pipeClientStream, generic_response_xml); keep_on_processing = true; break; case QlikViewGenericCommandValues.IsConnected: generic_response_xml = QlikViewMessage.MakeGenericReplyMessage(true, new String[] { "true" }); SendCommandMessage(pipeClientStream, generic_response_xml); keep_on_processing = true; break; default: _logger.LogMsg(Level.Warn, String.Format("Unknown QVX_GENERIC_COMMAND type received: [{0}].", generic_val)); // TO DO: Stop listening because we don't know what to do ? Or just ignore and keep going? keep_on_processing = false; break; } break; case QlikViewCommandTypes.EditConnect: _logger.LogMsg(Level.Debug, String.Format("Handling QVX_EDIT_CONNECT.")); // TO DO / PROBLEM: the connection string parameter in the message is ALWAYS BLANK. There does not appear // to be any way to get the connection string that is currently in the QlikView script. This means we cannot // parse it to get the individual pieces before displaying the dialog. String new_connection_string = command_msg.GetConnectionString(); // Call the dialog and return the modified connection string if OK (skip if Cancel). ShowCustomConnectDialog(ref new_connection_string); if (!String.IsNullOrEmpty(new_connection_string)) { generic_response_xml = QlikViewMessage.MakeGenericReplyMessage(true, new String[] { new_connection_string }); } else { generic_response_xml = QlikViewMessage.MakeGenericReplyMessage(false); } SendCommandMessage(pipeClientStream, generic_response_xml); // Continue listening on the command pipe. keep_on_processing = true; break; case QlikViewCommandTypes.EditSelect: _logger.LogMsg(Level.Debug, String.Format("Handling QVX_EDIT_SELECT.")); // Call the dialog and return the modified SQL string. String new_sql = null; ShowCustomSQLDialog(ref new_sql); if( !String.IsNullOrEmpty(new_sql ) ) { generic_response_xml = QlikViewMessage.MakeGenericReplyMessage(true, new String[] { new_sql }); } else { generic_response_xml = QlikViewMessage.MakeGenericReplyMessage(false); } SendCommandMessage(pipeClientStream, generic_response_xml); // Continue listening on the command pipe. keep_on_processing = true; break; case QlikViewCommandTypes.Disconnect: _logger.LogMsg(Level.Debug, String.Format("Handling QVX_DISCONNECT.")); // There is nothing to parse out since this has no defined parameters // TO DO: Actually do something to disconnect from the data source ? generic_response_xml = QlikViewMessage.MakeGenericReplyMessage(true); SendCommandMessage(pipeClientStream, generic_response_xml); // keep_on_processing = true; break; case QlikViewCommandTypes.Terminate: _logger.LogMsg(Level.Debug, String.Format("Handling QVX_TERMINATE.")); // There is nothing to parse out since this has no defined parameters // TO DO: Actually do something to shut down the Java query if running (async - not yet implemented). generic_response_xml = QlikViewMessage.MakeGenericReplyMessage(true); SendCommandMessage(pipeClientStream, generic_response_xml); // Exit becaue we are shutting down. keep_on_processing = false; break; default: _logger.LogMsg(Level.Warn, String.Format("Connector does not yet support this command message type: {0}.", command_msg.MessageType)); // If we don't know the message type, just exit. // TO DO: Handle all the other QlikView message types. generic_response_xml = QlikViewMessage.MakeGenericReplyMessage(QlikViewResponseTypes.QvxUnknownCommand); SendCommandMessage(pipeClientStream, generic_response_xml); keep_on_processing = true; break; } } else { _logger.LogMsg(Level.Error, "Invalid command message format."); keep_on_processing = false; } if (!keep_on_processing) { _logger.LogMsg(Level.Debug, "Exiting message handler loop. Connector program terminating. "); } } } // end while (keep_on_processing) result = 0; } catch (Exception ex) { _logger.LogMsg(Level.Fatal, "Unexpected error in RunNamedPipeHandler(): " + ex.Message); } return result; }
public static int RunNamedPipeHandler(int parentWindowHandle, String commandPipeName) { int result = -1; int pipe_connect_timeout = 10000; // Millisecond timeout try { _logger.LogMsg(Level.Debug, "Entering RunNamedPipeHandler()."); // Get the (short) pipe name and host name from the full path. // The .NET functions do not want the full path, only the name. Path format: "\\hostname\pipe\mypipename.pip" String host_name = null; String pipe_name = null; if (!ParsePipePath(commandPipeName, out host_name, out pipe_name)) { _logger.LogMsg(Level.Fatal, String.Format("Invalid command pipe path {0}. Connector cannot continue.", commandPipeName)); return(result); } // Create the .NET pipe wrapper object. NamedPipeClientStream pipeClientStream = CreatePipeStream(pipe_name, host_name, pipe_connect_timeout); // Read from pipe _logger.LogMsg(Level.Debug, String.Format("Opening .NET StreamReader.")); Boolean keep_on_processing = true; String msg = null; while (keep_on_processing) { // Qlikview seems to need some time to respond so we always sleep a few seconds. if (_messageWaitMilliseconds > 0) { //_logger.LogMsg(Level.Debug, String.Format("Sleeping in message handler loop for {0} milliseconds.", _messageWaitMilliseconds.ToString())); Thread.Sleep(_messageWaitMilliseconds); } // *** Get the next full XML message from the QlikView command pipe. msg = ReadNextCommandMessage(pipeClientStream); if (String.IsNullOrEmpty(msg)) { _logger.LogMsg(Level.Info, "No message received on command pipe."); keep_on_processing = false; //no_response++; //if (no_response > 10) //{ // keep_on_processing = false; //} } else { _logger.LogMsg(Level.Debug, String.Format("Command message received (length {0}). XML follows: \r\n{1}", msg.Length.ToString(), msg)); // *** Handle command message QlikViewMessage command_msg = new QlikViewMessage(); if (command_msg.Load(msg)) { switch (command_msg.MessageType) { case QlikViewCommandTypes.Connect: // Get connection string, send "OK" response. _connectionString = command_msg.GetConnectionString(); _logger.LogMsg(Level.Info, String.Format("Handling QVX_CONNECT. Connection String: {0}", _connectionString)); // TO DO: Test the connection with the Java proxy ? This would be a round trip to // the remote server so it could be a performance issue. String connect_error_msg; String connect_response_xml = QlikViewMessage.MakeGenericReplyMessage(true); if (!Properties.Settings.Default.SimulateConnection) { Boolean success = TestConnection(_driverName, _connectionString, _userName, _password, out connect_error_msg); if (!success) { connect_response_xml = QlikViewMessage.MakeGenericReplyMessage(false, null, connect_error_msg); } } SendCommandMessage(pipeClientStream, connect_response_xml); keep_on_processing = true; break; case QlikViewCommandTypes.Execute: // Get the SQL and data pipe name from the QVX_EXECUTE message. command_msg.GetSQLStatementAndDataPipeName(out _sql, out _dataPipePath); _logger.LogMsg(Level.Debug, String.Format("Handling QVX_EXECUTE. Data pipe path: [{0}], SQL: [{1}].", _dataPipePath, _sql)); // Send QVX_OK before writing to data pipe. String execute_response_xml = QlikViewMessage.MakeGenericReplyMessage(true); SendCommandMessage(pipeClientStream, execute_response_xml); // TO DO: need to get driver, connectionstring, username, password //String drivername = Properties.Settings.Default.dr // Write data to the data pipe. if (!String.IsNullOrEmpty(_sql) && !String.IsNullOrEmpty(_dataPipePath)) { RunBigDataQueryJava(_dataPipePath, _connectionString, _sql); } // Keep on procressing - there mat be multiple QVX_EXECUTE - one for each SQL statement in the script. keep_on_processing = true; break; case QlikViewCommandTypes.GenericCommand: String generic_val; String generic_response_xml; command_msg.ParseGenericCommand(out generic_val); _logger.LogMsg(Level.Debug, String.Format("Handling QVX_GENERIC_COMMAND: {0}", generic_val)); switch (generic_val) { case QlikViewGenericCommandValues.GetCustomCaption: // Send the caption? if (!Properties.Settings.Default.DisableCustomSQLButton) { // This causes QlikView to display the custom SQL button. generic_response_xml = QlikViewMessage.MakeGenericReplyMessage(true, new String[] { _customButtonCaption }); } else { // This reply prevents QlikView from displaying the custom SQL button. generic_response_xml = QlikViewMessage.MakeGenericReplyMessage(false); } SendCommandMessage(pipeClientStream, generic_response_xml); keep_on_processing = true; break; case QlikViewGenericCommandValues.DisableQlikViewSelectButton: // NOTE: we disable the "Select" button by default since it appears to an ODBC-only thing. if (Properties.Settings.Default.DisableQlikViewSelectButton) { generic_response_xml = QlikViewMessage.MakeGenericReplyMessage(true, new String[] { "true" }); } else { generic_response_xml = QlikViewMessage.MakeGenericReplyMessage(false); } SendCommandMessage(pipeClientStream, generic_response_xml); keep_on_processing = true; break; case QlikViewGenericCommandValues.HaveStarField: generic_response_xml = QlikViewMessage.MakeGenericReplyMessage(true, new String[] { "true" }); SendCommandMessage(pipeClientStream, generic_response_xml); keep_on_processing = true; break; case QlikViewGenericCommandValues.IsConnected: generic_response_xml = QlikViewMessage.MakeGenericReplyMessage(true, new String[] { "true" }); SendCommandMessage(pipeClientStream, generic_response_xml); keep_on_processing = true; break; default: _logger.LogMsg(Level.Warn, String.Format("Unknown QVX_GENERIC_COMMAND type received: [{0}].", generic_val)); // TO DO: Stop listening because we don't know what to do ? Or just ignore and keep going? keep_on_processing = false; break; } break; case QlikViewCommandTypes.EditConnect: _logger.LogMsg(Level.Debug, String.Format("Handling QVX_EDIT_CONNECT.")); // TO DO / PROBLEM: the connection string parameter in the message is ALWAYS BLANK. There does not appear // to be any way to get the connection string that is currently in the QlikView script. This means we cannot // parse it to get the individual pieces before displaying the dialog. String new_connection_string = command_msg.GetConnectionString(); // Call the dialog and return the modified connection string if OK (skip if Cancel). ShowCustomConnectDialog(ref new_connection_string); if (!String.IsNullOrEmpty(new_connection_string)) { generic_response_xml = QlikViewMessage.MakeGenericReplyMessage(true, new String[] { new_connection_string }); } else { generic_response_xml = QlikViewMessage.MakeGenericReplyMessage(false); } SendCommandMessage(pipeClientStream, generic_response_xml); // Continue listening on the command pipe. keep_on_processing = true; break; case QlikViewCommandTypes.EditSelect: _logger.LogMsg(Level.Debug, String.Format("Handling QVX_EDIT_SELECT.")); // Call the dialog and return the modified SQL string. String new_sql = null; ShowCustomSQLDialog(ref new_sql); if (!String.IsNullOrEmpty(new_sql)) { generic_response_xml = QlikViewMessage.MakeGenericReplyMessage(true, new String[] { new_sql }); } else { generic_response_xml = QlikViewMessage.MakeGenericReplyMessage(false); } SendCommandMessage(pipeClientStream, generic_response_xml); // Continue listening on the command pipe. keep_on_processing = true; break; case QlikViewCommandTypes.Disconnect: _logger.LogMsg(Level.Debug, String.Format("Handling QVX_DISCONNECT.")); // There is nothing to parse out since this has no defined parameters // TO DO: Actually do something to disconnect from the data source ? generic_response_xml = QlikViewMessage.MakeGenericReplyMessage(true); SendCommandMessage(pipeClientStream, generic_response_xml); // keep_on_processing = true; break; case QlikViewCommandTypes.Terminate: _logger.LogMsg(Level.Debug, String.Format("Handling QVX_TERMINATE.")); // There is nothing to parse out since this has no defined parameters // TO DO: Actually do something to shut down the Java query if running (async - not yet implemented). generic_response_xml = QlikViewMessage.MakeGenericReplyMessage(true); SendCommandMessage(pipeClientStream, generic_response_xml); // Exit becaue we are shutting down. keep_on_processing = false; break; default: _logger.LogMsg(Level.Warn, String.Format("Connector does not yet support this command message type: {0}.", command_msg.MessageType)); // If we don't know the message type, just exit. // TO DO: Handle all the other QlikView message types. generic_response_xml = QlikViewMessage.MakeGenericReplyMessage(QlikViewResponseTypes.QvxUnknownCommand); SendCommandMessage(pipeClientStream, generic_response_xml); keep_on_processing = true; break; } } else { _logger.LogMsg(Level.Error, "Invalid command message format."); keep_on_processing = false; } if (!keep_on_processing) { _logger.LogMsg(Level.Debug, "Exiting message handler loop. Connector program terminating. "); } } } // end while (keep_on_processing) result = 0; } catch (Exception ex) { _logger.LogMsg(Level.Fatal, "Unexpected error in RunNamedPipeHandler(): " + ex.Message); } return(result); }