Imports System.IO Imports System.Threading Imports MS.Internal Imports Effector.Plugin.Lib.ThreadData Imports System.Windows.Threading Imports Effector.Plugin.Lib Public Class ExecProcessManager Public Event m_AllArgsProcessed() Public Enum ExecutionThreadStatuses As Integer RUNNING = 1 STOPPED = 2 End Enum Private Enum ProcessManagerStates NULL = 0 OPEN = 1 CLOSE = 2 End Enum Private m_ProcessManagerTimer As New DispatcherTimer Private m_ProcessManagerState As ProcessManagerStates Private m_ProcessManagerV As ProcessManagerV Public ReadOnly Property ProcessManagerV As ProcessManagerV Get Return m_ProcessManagerV End Get End Property ' riferimento al thread principale Private m_ExecutionThread As Thread Private m_ExecutionThreadStatus As ExecutionThreadStatuses = ExecutionThreadStatuses.STOPPED Public ReadOnly Property ExecutionThreadStatus As ExecutionThreadStatuses Get Return m_ExecutionThreadStatus End Get End Property ' array dei thread Private m_ThreadList As Thread() ' array dei dati dei thread Private m_ThreadDataList As ThreadData() Friend ReadOnly Property ThreadDataList As ThreadData() Get Return m_ThreadDataList End Get End Property ' variabile che ferma i processi Private m_bStopProcess As Boolean = False ' variabile che conferma chiusura dei processi Private m_bExecutionThreadStoped As Boolean = False ' numero massimo di istanze del cam Private m_MaxCamInstances As Integer = 1 ' nome dell'eseguibile da lanciare Private m_sProcessFileName As String = "" ' stringa di argomenti dell'eseguibile da lanciare Private m_sProcessArguments As String = "" ' coda delle cose da eseguire Private ArgumentsQueueLock As New Object Private m_ArgumentsQueue As New Queue(Of ProcessArgs) Public ReadOnly Property ArgumentsQueue As Queue(Of ProcessArgs) Get Return m_ArgumentsQueue End Get End Property ' coda dei risultati Private ArgumentsResultQueueLock As New Object Private m_ArgumentsResultQueue As New Queue(Of ProcessArgsResult) Public ReadOnly Property ArgumentsResultQueue As Queue(Of ProcessArgsResult) Get Return m_ArgumentsResultQueue End Get End Property ' funzione che richiede prossimo elemento da processare Private m_delGetNextProcessArgs As Func(Of ProcessArgs) Public Sub SetGetNextProcessArgs(GetNextProcessArgs As Func(Of ProcessArgs)) m_delGetNextProcessArgs = GetNextProcessArgs End Sub ' funzione di pre processing dell'elemento Private m_delPreProcess As Func(Of ProcessArgs, ProcessArgs) Public Sub SetPreProcess(PreProcess As Func(Of ProcessArgs, ProcessArgs)) m_delPreProcess = PreProcess End Sub ' funzione di post processing dell'elemento Private m_delPostProcess As Action(Of ProcessArgsResult) Public Sub SetPostProcess(PostProcess As Action(Of ProcessArgsResult)) m_delPostProcess = PostProcess End Sub Private m_nExecutedArgsCounter As Integer = 0 Public ReadOnly Property nExecutedArgsCounter As Integer Get Return m_nExecutedArgsCounter End Get End Property Public ReadOnly Property nArgsInQueue As Integer Get Return ArgumentsQueueCount() + nCalculatingProcesses End Get End Property Public ReadOnly Property nCalculatingProcesses As Integer Get Return ThreadDataList.Count(Function(x) Not IsNothing(x) AndAlso x.ProcessStatus = ProcessStatuses.WAITINGANSWER) End Get End Property #Region "CONSTRUCTORS" Sub New(sProcessFileName As String, sProcessArguments As String) m_sProcessFileName = sProcessFileName m_sProcessArguments = sProcessArguments m_ProcessManagerTimer.Interval = New TimeSpan(0, 0, 1) AddHandler m_ProcessManagerTimer.Tick, AddressOf ProcessManagerTimer_Tick m_ProcessManagerTimer.Start() End Sub #End Region ' CONSTRUCTORS Private Sub ProcessManagerTimer_Tick(sender As Object, e As EventArgs) Select Case m_ProcessManagerState Case ProcessManagerStates.OPEN ' se in debug If GetPluginPrivateProfileInt(S_DEBUG, K_EXECUTEWINDOW, 0) = 1 Then ' creo finestra statistiche processi m_ProcessManagerV = New ProcessManagerV(Application.Current.MainWindow, New ProcessManagerVM(Me)) ProcessManagerV.Show() m_ProcessManagerState = ProcessManagerStates.NULL End If Case ProcessManagerStates.CLOSE ' chiudo finestra statistiche processi If Not IsNothing(m_ProcessManagerV) Then ProcessManagerV.Close() m_ProcessManagerV = Nothing End If m_nExecutedArgsCounter = 0 m_ProcessManagerState = ProcessManagerStates.NULL End Select End Sub Public Function ArgumentsEnqueue(ProcessArgs As ProcessArgs) As Boolean If ProcessArgs.nId <= 0 OrElse String.IsNullOrWhiteSpace(ProcessArgs.sArgs) Then Return False SyncLock ArgumentsQueueLock m_ArgumentsQueue.Enqueue(ProcessArgs) End SyncLock Return True End Function Public Function ArgumentsDequeue() As ProcessArgs Dim DequeueProcessArgs As ProcessArgs = Nothing SyncLock ArgumentsQueueLock If m_ArgumentsQueue.Count > 0 Then DequeueProcessArgs = m_ArgumentsQueue.Dequeue() End If End SyncLock Return DequeueProcessArgs End Function Public Function ArgumentsQueueCount() As Integer Dim nCount As Integer = 0 SyncLock ArgumentsQueueLock nCount = m_ArgumentsQueue.Count End SyncLock Return nCount End Function Public Function ArgumentsResultEnqueue(ProcessArgsResult As ProcessArgsResult) As Boolean SyncLock ArgumentsResultQueueLock m_ArgumentsResultQueue.Enqueue(ProcessArgsResult) End SyncLock Return True End Function Public Function ArgumentsResultDequeue() As ProcessArgsResult Dim DequeueProcessArgsResult As ProcessArgsResult = Nothing SyncLock ArgumentsResultQueueLock If m_ArgumentsResultQueue.Count > 0 Then DequeueProcessArgsResult = m_ArgumentsResultQueue.Dequeue() End If End SyncLock Return DequeueProcessArgsResult End Function Public Function ArgumentsResultQueueCount() As Integer Dim nCount As Integer = 0 SyncLock ArgumentsResultQueueLock nCount = m_ArgumentsResultQueue.Count End SyncLock Return nCount End Function Public Sub SetMaxCamInstances(nValue As Integer) ' Numero di core logici da utilizzare (minimo tra presenti sul PC e imposti da INI) Dim nMaxThread As Integer = Math.Min(Environment.ProcessorCount, nValue) m_MaxCamInstances = nMaxThread End Sub ' funzione che avvia thread principale Public Sub StartExecutionThread() If m_ExecutionThreadStatus = ExecutionThreadStatuses.RUNNING Then Return m_bStopProcess = False m_bExecutionThreadStoped = False m_ExecutionThread = New Thread(Sub() ExecutionProcess() End Sub) m_ExecutionThread.SetApartmentState(ApartmentState.STA) ' avvio thread di gestione della macchina che avvia la connessione m_ExecutionThread.Start() m_ExecutionThreadStatus = ExecutionThreadStatuses.RUNNING ' lancio apertura finestra statistiche processi m_ProcessManagerState = ProcessManagerStates.OPEN End Sub Public Sub StopExecutionThread() If m_ExecutionThreadStatus = ExecutionThreadStatuses.STOPPED Then Return m_bStopProcess = True While Not m_bExecutionThreadStoped Thread.Sleep(100) End While If Not IsNothing(m_ExecutionThread) Then m_ExecutionThread.Abort() While Not m_ExecutionThread.ThreadState = ThreadState.Aborted Thread.Sleep(100) End While m_ExecutionThread = Nothing End If m_ThreadList = Nothing m_ExecutionThreadStatus = ExecutionThreadStatuses.STOPPED ' lancio chiusura finestra statistiche processi m_ProcessManagerState = ProcessManagerStates.CLOSE End Sub ' funzione di esecuzione del thread principale che gestice i processi Private Sub ExecutionProcess() Dim bStopMainProcess As Boolean = False Dim nStartingProc As Integer = 0 While Not bStopMainProcess bStopMainProcess = m_bStopProcess ' se processo fermato, fermo i thread If bStopMainProcess Then If Not IsNothing(m_ThreadList) AndAlso m_ThreadList.Count > 0 AndAlso Not IsNothing(m_ThreadList(0)) Then ' li fermo m_bStopProcess = True ' verifico siano terminati Dim bOneNotEnded As Boolean = True While bOneNotEnded bOneNotEnded = False For Each Thread In m_ThreadList If Not IsNothing(Thread) Then If Thread.IsAlive Then bOneNotEnded = True End If End If Next End While ' pulisco la lista For ThreadIndex = 0 To m_ThreadList.Count - 1 m_ThreadList(ThreadIndex) = Nothing Next m_bStopProcess = False End If m_bExecutionThreadStoped = True Return End If ' se lista processi nulla o vuota, li faccio partire If (IsNothing(m_ThreadList) OrElse m_ThreadList.Count = 0) Then m_ThreadList = New Thread(m_MaxCamInstances - 1) {} m_ThreadDataList = New ThreadData(m_MaxCamInstances - 1) {} For nThreadIndex = 0 To m_MaxCamInstances - 1 Dim ThreadId As Integer = nThreadIndex m_ThreadList(nThreadIndex) = New Thread(Sub() ThreadFunction(ThreadId) End Sub) m_ThreadList(nThreadIndex).SetApartmentState(ApartmentState.STA) ' avvio thread di gestione della macchina che avvia la connessione m_ThreadList(nThreadIndex).Start() Thread.Sleep(100) Next End If ' se qualche processo in stop, lo faccio ripartire For ThreadIndex = 0 To m_ThreadList.Count - 1 If ThreadIndex < m_ThreadList.Count Then Dim Thread = m_ThreadList(ThreadIndex) If Not IsNothing(Thread) Then If Thread.ThreadState = ThreadState.Stopped OrElse Thread.ThreadState = ThreadState.Aborted OrElse Thread.ThreadState = ThreadState.Suspended OrElse (Not m_ThreadDataList(ThreadIndex).ProcessStatus = ProcessStatuses.TOBESTARTED AndAlso (IsNothing(m_ThreadDataList(ThreadIndex).Process) OrElse (Not IsNothing(m_ThreadDataList(ThreadIndex).Process) AndAlso m_ThreadDataList(ThreadIndex).Process.HasExited))) Then ' inserire un ritardo di rilancio? ' lo chiudo e rilancio 'Thread.Sleep(500) Thread.Abort() Thread.Sleep(100) While Not Thread.ThreadState = ThreadState.Aborted Thread.Sleep(100) End While Thread = Nothing Dim ThreadId As Integer = ThreadIndex m_ThreadList(ThreadIndex) = New Thread(Sub() ThreadFunction(ThreadId) End Sub) m_ThreadList(ThreadIndex).SetApartmentState(ApartmentState.STA) ' avvio thread di gestione della macchina che avvia la connessione m_ThreadList(ThreadIndex).Start() End If Else Dim ThreadId As Integer = ThreadIndex If ThreadIndex < m_ThreadList.Count Then m_ThreadList(ThreadIndex) = New Thread(Sub() ThreadFunction(ThreadId) End Sub) m_ThreadList(ThreadIndex).SetApartmentState(ApartmentState.STA) ' avvio thread di gestione della macchina che avvia la connessione m_ThreadList(ThreadIndex).Start() End If End If End If Next ' verifico se coda vuota e tutti i processi hanno finito Dim nQueueArgs As Integer = 0 SyncLock ArgumentsQueueLock nQueueArgs = m_ArgumentsQueue.Count End SyncLock If nQueueArgs = 0 Then Dim bProcessWaiting As Boolean = False For Each ThreadData In m_ThreadDataList If ThreadData.ProcessStatus = ProcessStatuses.WAITINGANSWER OrElse ThreadData.ProcessStatus = ProcessStatuses.ANSWERRECEIVED Then bProcessWaiting = True Exit For End If Next If Not bProcessWaiting Then ' creo thread per lanciare evento asincrono di fine calcolo Dim AllArgsProcessedThread = New Thread(Sub() RaiseEvent m_AllArgsProcessed() End Sub) AllArgsProcessedThread.SetApartmentState(ApartmentState.STA) AllArgsProcessedThread.Start() End If End If Thread.Sleep(1000) End While End Sub ' funzione di esecuzione del singolo processo che comunica con il programma Private Sub ThreadFunction(ThreadIndex As Integer) Dim MyThreadData As New ThreadData m_ThreadDataList(ThreadIndex) = MyThreadData 'Dim CurrThreadStat As New ThreadStat(ThreadIndex, DateTime.Now) 'HistoryThreadDataList.Add(CurrThreadStat) 'MyThreadData.SetThreadStat(CurrThreadStat) 'Dim sDrive As String = "c" ' If(ThreadIndex Mod 2 = 0, "A", "B") 'Dim sCurrDdfDir As String = sDrive & ":\EgtData\WebDoor\Ddf" 'Dim stopWatch As New Stopwatch() 'Dim lExeTime As Long = 0 'Dim lOtherTime As Long = 0 ' avvio processo Dim Proc As Process = New Process() Proc.StartInfo.FileName = m_sProcessFileName Proc.StartInfo.RedirectStandardInput = True Proc.StartInfo.RedirectStandardOutput = True Proc.StartInfo.Arguments = ThreadIndex.ToString() & " " & m_sProcessArguments Proc.StartInfo.UseShellExecute = False Proc.StartInfo.CreateNoWindow = True AddHandler Proc.OutputDataReceived, AddressOf Thread_OutputDataReceived If Proc.Start() Then 'Dim CurrPocStat As New ProcStat(DateTime.Now) 'CurrThreadStat.ProcExecutionList.Add(CurrPocStat) Proc.BeginOutputReadLine() MyThreadData.SetProcess(Proc) MyThreadData.SetProcessStatus(ProcessStatuses.NULL) 'Dim nProc0Wait As Integer = 0 ' ciclo per leggere coda ed eseguire While Not m_bStopProcess AndAlso Not Proc.HasExited Select Case MyThreadData.ProcessStatus Case ThreadData.ProcessStatuses.NULL 'MyThreadData.SetThreadOperation(ThreadOperations.WaitingData) ' se c'e' qualcosa da processare 'Dim nNumTaskToProcess As Integer = 0 'If ThreadIndex = 0 Then ' nNumTaskToProcess = currWDC.numTask2proc ' If nNumTaskToProcess > 0 Then ' If Not m_bCheckOrder Then m_bCheckOrder = True ' Else ' If m_bCheckOrder Then m_bCheckOrder = False ' Thread.Sleep(100) ' End If 'ElseIf m_bCheckOrder Then ' nNumTaskToProcess = currWDC.numTask2proc ' If nNumTaskToProcess = 0 Then ' m_bCheckOrder = False ' End If 'End If Dim NextProcessArgs As ProcessArgs = Nothing If Not IsNothing(m_delGetNextProcessArgs) Then NextProcessArgs = m_delGetNextProcessArgs() Else NextProcessArgs = ArgumentsDequeue() End If If Not IsNothing(NextProcessArgs) AndAlso NextProcessArgs.nId > 0 AndAlso Not String.IsNullOrWhiteSpace(NextProcessArgs.sArgs) Then If Not IsNothing(m_delPreProcess) Then NextProcessArgs = m_delPreProcess(NextProcessArgs) End If MyThreadData.SetCurrRequest(NextProcessArgs) Proc.StandardInput.WriteLine(ThreadIndex & "," & NextProcessArgs.sArgs) MyThreadData.SetProcessStatus(ThreadData.ProcessStatuses.WAITINGANSWER) End If 'If m_bCheckOrder Then ' Dim LastRequest As Dictionary(Of String, CalcReqtDTO) = currWDC.queueList(1) ' If LastRequest.Count > 0 Then ' MyThreadData.SetThreadOperation(ThreadOperations.FoundRequest) ' Dim ConvItem As KeyValuePair(Of String, String) ' ConvItem = New KeyValuePair(Of String, String)(LastRequest.First().Key, LastRequest.First().Value.DDF) ' MyThreadData.SetCurrRequest(ConvItem) ' ' vecchia versione ' 'MyThreadData.SetCurrRequest(LastRequest.First()) ' Dim Item As KeyValuePair(Of String, String) = MyThreadData.CurrRequest ' Dim bOk As Boolean = Not IsNothing(Item) ' If bOk Then ' ' avvio cronometro ' 'stopWatch.Reset() ' stopWatch.Restart() ' ' svuoto vecchio set file della porta richiesta ' Dim fileList As String() = Directory.GetFiles(sCurrDdfDir, Item.Key + ".*") ' ' elimino vecchi ' If Not IsNothing(fileList) Then ' For Each sFile In fileList ' Try ' File.Delete(sFile) ' Catch ex As Exception ' End Try ' Next ' End If ' ' scrivo ddf ' MyThreadData.SetThreadOperation(ThreadOperations.WritingDdf) ' MyThreadData.SetDdfPath(sCurrDdfDir & "\" & Item.Key & ".ddf") ' Dim sDdfPath As String = MyThreadData.sDdfPath ' Try ' File.WriteAllText(sDdfPath, Item.Value) ' Catch ex As Exception ' bOk = False ' End Try ' If bOk Then ' MyThreadData.SetThreadOperation(ThreadOperations.ProcessingDdf) ' Proc.StandardInput.WriteLine(ThreadIndex & "," & sDdfPath) ' MyThreadData.SetWaitProcAnswer(ThreadData.ProcComm.WaitingAnswer) ' End If ' End If ' Else ' Thread.Sleep(100) ' End If 'Else ' Thread.Sleep(100) 'End If Case ThreadData.ProcessStatuses.WAITINGANSWER Thread.Sleep(10) Case ThreadData.ProcessStatuses.ANSWERRECEIVED Dim NewProcessArgsResult As New ProcessArgsResult(MyThreadData.CurrRequest, MyThreadData.nProcResult) If Not IsNothing(m_delPostProcess) Then m_delPostProcess(NewProcessArgsResult) End If m_nExecutedArgsCounter += 1 ArgumentsResultEnqueue(NewProcessArgsResult) 'Dim Item As ProcessArgs = MyThreadData.CurrRequest 'Dim sDdfPath As String = MyThreadData.sDdfPath 'Dim bOk As Boolean = True '' salvo exe time... 'stopWatch.Stop() 'lExeTime = stopWatch.ElapsedMilliseconds 'stopWatch.Restart() 'Dim procResults As New List(Of CalcResultDTO) 'Dim currRes As New CalcResultDTO 'Dim fContent As String = "" 'MyThreadData.SetThreadOperation(ThreadOperations.ReadingSvg) '' verifico esistenza file svg e lo carico 'bOk = GetFileContent(Path.ChangeExtension(sDdfPath, "svg"), fContent) '' !!! ToDo: inserire TIPO di richiesta secondo quanto ricevuto.... '' invio risposta 'currRes.Validated = MyThreadData.nProcResult = 0 AndAlso bOk 'currRes.DoorIdVers = Item.Key '' per ora cablato a svg, prendere da MimeType richiesta... 'currRes.MimeType = "svg" '' se NON fosse validato --> messo il messaggio... 'If (currRes.Validated) Then ' currRes.RawContent = fContent 'Else ' bOk = GetFileContent(Path.ChangeExtension(sDdfPath, "txt"), fContent) ' currRes.ErrorMsg = fContent 'End If 'MyThreadData.SetThreadOperation(ThreadOperations.SendResult) 'procResults.Add(currRes) 'Dim respPut As String = currWDC.SendProcResults(procResults) 'stopWatch.Stop() 'lOtherTime = stopWatch.ElapsedMilliseconds 'CurrPocStat.IncrementDoneRequest() '' aggiorno thread display... 'UpdateThreadList(Item.Key, lExeTime, lOtherTime) '' cambio nomi file generati in old 'Dim OldSvg As String = Path.ChangeExtension(sDdfPath, "svg") 'Dim NewSvg As String = Path.GetDirectoryName(sDdfPath) & "\" & Path.GetFileNameWithoutExtension(sDdfPath) & "_old.svg" 'Try ' File.Delete(NewSvg) 'Catch ex As Exception 'End Try 'Try ' File.Delete(Path.ChangeExtension(NewSvg, "txt")) 'Catch ex As Exception 'End Try 'Try ' File.Delete(Path.ChangeExtension(NewSvg, "log")) 'Catch ex As Exception 'End Try 'Try ' File.Delete(Path.ChangeExtension(NewSvg, "nge")) 'Catch ex As Exception 'End Try 'Try ' File.Delete(Path.ChangeExtension(NewSvg, "ddf")) 'Catch ex As Exception 'End Try 'Try ' File.Move(OldSvg, NewSvg) 'Catch ex As Exception 'End Try 'Try ' File.Move(Path.ChangeExtension(OldSvg, "txt"), Path.ChangeExtension(NewSvg, "txt")) 'Catch ex As Exception 'End Try 'Try ' File.Move(Path.ChangeExtension(OldSvg, "log"), Path.ChangeExtension(NewSvg, "log")) 'Catch ex As Exception 'End Try 'Try ' File.Move(Path.ChangeExtension(OldSvg, "nge"), Path.ChangeExtension(NewSvg, "nge")) 'Catch ex As Exception 'End Try 'Try ' File.Move(Path.ChangeExtension(OldSvg, "ddf"), Path.ChangeExtension(NewSvg, "ddf")) 'Catch ex As Exception 'End Try MyThreadData.SetProcessStatus(ThreadData.ProcessStatuses.NULL) End Select End While ' CurrPocStat.SetStopProc(DateTime.Now) If m_bStopProcess Then Proc.StandardInput.WriteLine("quit") End If End If ' CurrThreadStat.SetStopThread(DateTime.Now) MyThreadData.SetProcess(Nothing) ' MyThreadData.SetThreadOperation(ThreadOperations.Closed) End Sub Private Sub Thread_OutputDataReceived(sender As Object, e As DataReceivedEventArgs) Dim sResult As String = e.Data If Not String.IsNullOrWhiteSpace(sResult) AndAlso sResult.StartsWith("#42315#,") Then Dim Results() As String = sResult.Split(","c) If Results.Count >= 2 Then Dim nIndex As Integer = -1 Dim nResult As Integer = -1 Dim dResult As Integer = -1 If Integer.TryParse(Results(1), nIndex) AndAlso nIndex >= 0 Then If Integer.TryParse(Results(2), nResult) AndAlso nResult >= 0 Then m_ThreadDataList(nIndex).SetProcResult(nResult) ElseIf StringToDouble(Results(2), dResult) AndAlso dResult >= 0 Then nResult = Math.Floor(dResult) m_ThreadDataList(nIndex).SetProcResult(nResult) End If m_ThreadDataList(nIndex).SetProcessStatus(ThreadData.ProcessStatuses.ANSWERRECEIVED) End If End If End If End Sub End Class Public Class ProcessArgs Private m_nId As Integer Public ReadOnly Property nId As Integer Get Return m_nId End Get End Property Private m_sArgs As String Public ReadOnly Property sArgs As String Get Return m_sArgs End Get End Property Sub New(nId As Integer, sArgs As String) m_nId = nId m_sArgs = sArgs End Sub End Class Public Class ProcessArgsResult Private m_ProcessArgs As ProcessArgs Public ReadOnly Property ProcessArgs As ProcessArgs Get Return m_ProcessArgs End Get End Property Private m_nResult As Integer Public ReadOnly Property nResult As Integer Get Return m_nResult End Get End Property Public Sub SetResult(nResult As Integer) m_nResult = nResult End Sub Sub New(ProcessArgs As ProcessArgs, nResult As Integer) m_ProcessArgs = ProcessArgs m_nResult = nResult End Sub End Class