US Tray Menu 2: cmd problem
US Tray Menu 2 : Introduction | Implementation | Language support | cmd problem | Defensive | Binaries
|
|
UniServer 5-Nano US Tray Menu 2. UniServer 6-Carbo |
US Tray Menu 2 CMD Problem
Introduction
This page is a slight digression it covers dreaded command window pop-ups.
Without a viable solution our tray menu would remained a proof of concept.
Background
During development tray menu is started using file UniServer\unicon\tray_menu_2\ z_tray_menu_test.bat. It directly runs our main menu file UniTray.phpw and displays any test message we wish to print and error messages produced by the PHP interpreter.
Our tray menu has been converted now displays server status in real time. To achieve this runs functions apache_running() and mysql_running() these in turn run file pskill.exe (dual purpose program) to check if servers are running.
Starting our tray menu with z_tray_menu_test.bat it worked as expected. However starting menu with UniServer\Start_UniTray_2.exe unexpectedly produced a dreaded command window pop-up every time pskill.exe was run.
Not a real problem just an annoyance only became an issue when all attempts to hide the command window failed.
Dirty tricks
As a last resort we can open up a bag of dirty tricks, have a rummage around to see if a solution can be found!
Dirty trick 1 - Run second instance of php5ts.dll
Running pskill.exe from a separate instance of php5ts.dll allows the command window to be hidden. Using this method introduces its own problems! How to report information gathered back to the main menu script.
Dirty trick 2 - Use file to exchange data
Another dirty trick, write gathered information to a file. Main menu script waits for this file to be created, reads information from it and deletes file.
Although a convoluted solution it works perfectly for hiding command window pop-ups. Unfortunately there is a price to pay, it takes time to run a new instance of php5ts.dll and to write and read a file. This translates into a sluggish menu response, clicking a menu item a noticeable delay is encountered while current server information is being obtained.
That said it is a viable solution, files can be found in folder UniServer\unicon\tray_menu_2\status_file_alternative saved for an emergency back-up solution.
I mentioned in the introduction without a viable solution our tray menu would remain a proof of concept. In all honesty the above solution is semi-viable even after a short period of use any delay will become annoying.
Solution
Real solution is to have a WinBinder equivalent of Uniform Server’s pskill.exe. This would run from the same instance of php5ts.dll avoiding the above mess.
I rarely give up on a problem hence I posted on WinBinder’s forum for any help or suggestions. That information was forth coming and I spent a weekend trying to convert a Microsoft example to WinBinder’s format as suggested.
I conceded defeat decided to post another request only to find “frantic” had posted a working example. Ran the script as is, worked perfectly just what was needed.
From a working reference it was easy to hack the code into a format suitable for our tray menu.
Working script
File: running_status.php
<?php /* ############################################################################### # Name: running_status.php # Web: http://www.uniformserver.com # V1.0 1-6-2010 # Comment: Uniform Server Tray Menu # Original running process detection code by "frantik" # WinBinder Wiki ref: http://winbinder.org/forum/viewtopic.php?f=3&t=1186 ############################################################################### */ chdir(dirname(__FILE__)); // Change wd to this files location include_once "winbinder/winbinder.php"; include_once "../main/includes/config.inc.php"; include_once "../main/includes/functions.php"; include_once "WinAPI.php"; include_once "cStruct.php"; define ('PROCESS_QUERY_INFORMATION', 0x0400); define ('PROCESS_VM_READ',0x0010); define ('MAX_PATH', 260); cStruct::define('PROCESS_ARRAY','DWORD aProcesses[1024];'); // === GET SERVERS CURRENT RUNNING TATUS ===================================== function get_running_status(){ $apache_tracker = get_apache_tracker(); // Current status Apache tracker $mysql_tracker = get_mysql_tracker(); // Current status MySQL tracker $apahe_name =get_apache_exe(); // Returns Apache executable file name $myql_name = get_mysql_exe(); // Returns MySQL executable file name // Apache running as program shortcut if(is_process_running($apahe_name) && ($apache_tracker == 'program')){ $AP = "running"; } else{ $AP = "notrunning"; } // MySQL running as program shortcut if(is_process_running($myql_name) && ($mysql_tracker == 'program')){ $MY = "running"; } else{ $MY = "notrunning"; } // Apache running as service shortcut if(is_process_running($apahe_name) && ($apache_tracker == 'service')){ $APS = "running"; } else{ $APS = "notrunning"; } // MySQL running as service shortcut if(is_process_running($myql_name) && ($mysql_tracker == 'service')){ $MYS = "running"; } else{ $MYS = "notrunning"; } $status['AP'] = $AP; $status['APS'] = $APS; $status['MY'] = $MY; $status['MYS'] = $MYS; return $status; } // ===================================== GET SERVERS CURRENT RUNNING STATUS == //=== Process status ========================================================== function PrintProcessNameAndID( $processID ){ global $process_list; // List of processes $szProcessName = "<unknown>"; $szProcessName = str_pad($szProcessName, MAX_PATH, "\0"); $hProcess = Kernel32::OpenProcess (PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, false, $processID ); if ( null != $hProcess ){ $hMod = 0; $cbNeeded = 0; if (Psapi::EnumProcessModules( $hProcess, wb_get_address($hMod), \cStruct\HMODULE::sizeOf(), wb_get_address($cbNeeded) )){ Psapi::GetModuleBaseName( $hProcess, $hMod, $szProcessName, strlen($szProcessName)); } $szProcessName = \cStruct\rtrim($szProcessName); //echo "$szProcessName (PID: $processID)\n"; $process_list[] = $szProcessName; // Create list of processes } } function is_process_running($proces_name){ global $process_list; $process_list = array(); $aProcesses = new PROCESS_ARRAY(); $cbNeeded = 0; if (! Psapi::EnumProcesses( $aProcesses, $aProcesses->sizeOf(), wb_get_address($cbNeeded))){ echo "Enum Processes failed"; exit; } $cProcesses = $cbNeeded / \cStruct\DWORD::sizeOf(); // use DWORD in the cStruct namespace to get the size of for ($i = 0; $i < $cProcesses; $i++){ if( $aProcesses->aProcesses[$i] != 0){ PrintProcessNameAndID( $aProcesses->aProcesses[$i] ) ; } } foreach($process_list as $txt){ if ($txt == $proces_name){ return true; } } return false; }// end ia_proges_running //========================================================== Process status === ?>
With that script in place there is no noticeable delay; real time menu update works as expected.
Note: Script structure matches that of our semi-viable solution. Reason for retaining this structure if required it can easily be regressed.
Summary
An interesting digression, it shows things never run smoothly or as expected.
It also highlights one advantage and power of the open source community. If you get stuck there is always someone willing to help.
At this stage we have a working menu it’s a starting point where additional features and functions can be added.
Next page looks a defensive code in particular initialisation pre-checks.