Imports System.Collections.ObjectModel Imports System.IO Imports System.IO.Compression Imports System.Windows.Threading Imports EgtBEAMWALL.Core Imports EgtBEAMWALL.Core.ConstBeam Imports EgtUILib Imports EgtWPFLib5 Public Class MainMenuVM Inherits VMBase #Region "FIELDS & PROPERTIES" Private CONFIGURATION_IMAGE As String = "pack://application:,,,/Resources/NewPage/configuration.png" Private ISCONFIGURATION_IMAGE As String = "pack://application:,,,/Resources/NewPage/configurationIsChecked.png" Private PADLOCK_IMAGE As String = "pack://application:,,,/Resources/NewPage/padlock.png" Private UNPADLOCK_IMAGE As String = "pack://application:,,,/Resources/NewPage/padlock-unlock.png" Public Enum UserLevel As Integer USER = 1 ADVANCED = 5 ADMINISTRATOR = 10 End Enum Private m_OpenPage_Timer As New DispatcherTimer Private m_bOpenPage As Boolean = False Private m_nPageToOpen As Pages = Pages.MACHINING Private m_MainMenu_IsEnabled As Boolean = True Public ReadOnly Property MainMenu_IsEnabled As Boolean Get Return m_MainMenu_IsEnabled End Get End Property Public Property Optimizer_IsChecked As Boolean Get Return m_SelPage = Pages.OPTIMIZERPAGE End Get Set(value As Boolean) If value Then SelPage = Pages.OPTIMIZERPAGE SetConfigurationImagePath(CONFIGURATION_IMAGE) End If End Set End Property Public Property Supervisor_IsChecked As Boolean Get Return m_SelPage = Pages.SUPERVISOR End Get Set(value As Boolean) If value Then SelPage = Pages.SUPERVISOR SetConfigurationImagePath(CONFIGURATION_IMAGE) End If End Set End Property Public Property Config_IsChecked As Boolean Get Return m_SelPage = Pages.CONFIG End Get Set(value As Boolean) If value Then SelPage = Pages.CONFIG SetConfigurationImagePath(CONFIGURATION_IMAGE) End If End Set End Property Public Property ConfigProgram_IsChecked As Boolean Get Return m_SelPage = Pages.CONFIGPROGRAM End Get Set(value As Boolean) If value Then SelPage = Pages.CONFIGPROGRAM SetConfigurationImagePath(ISCONFIGURATION_IMAGE) Else SetConfigurationImagePath(CONFIGURATION_IMAGE) End If End Set End Property Private m_Supervisor_Visibility As Visibility Public ReadOnly Property Supervisor_Visibility As Visibility Get Return m_Supervisor_Visibility End Get End Property Private m_SelPage As Integer = -1 Public Property SelPage As Integer Get Return m_SelPage End Get Set(value As Integer) ' lancio selezione pagina con verifica file modificato SetSelPage(value) End Set End Property ' funzione che permette di cambiare pagina ' bVerifyModification: se vero verifica modifiche su file e chiede di salvare Friend Sub SetSelPage(Page As Pages, Optional bVerifyModification As Boolean = True) Dim bOk As Boolean = True ' Esco dallo stato corrente Select Case m_SelPage Case Pages.CONFIG, Pages.CONFIGPROGRAM bOk = ExitCONFIG() Case Pages.OPTIMIZERPAGE bOk = ExitOPTIMIZERPAGE(bVerifyModification) End Select If bOk Then ' Entro nel nuovo stato m_SelPage = Page Select Case m_SelPage Case Pages.CONFIG InitCONFIG() Case Pages.OPTIMIZERPAGE, Pages.CONFIGPROGRAM InitOPTIMIZERPAGE() End Select End If ' aggiorno visualizzazione RadioButton NotifyPropertyChanged(NameOf(Supervisor_IsChecked)) NotifyPropertyChanged(NameOf(Config_IsChecked)) NotifyPropertyChanged(NameOf(Optimizer_IsChecked)) NotifyPropertyChanged(NameOf(ConfigProgram_IsChecked)) End Sub Private m_sConfigurationImagePath As String = CONFIGURATION_IMAGE Public ReadOnly Property sConfigurationImagePath As String Get Return m_sConfigurationImagePath End Get End Property Friend Sub SetConfigurationImagePath(value As String) m_sConfigurationImagePath = value NotifyPropertyChanged(NameOf(sConfigurationImagePath)) End Sub Private m_bUserAdmin_IsChecked As Boolean = False Public Property UserAdmin_IsChecked As Boolean Get Return m_bUserAdmin_IsChecked End Get Set(value As Boolean) m_bUserAdmin_IsChecked = value If Not IsNothing(Map.refForcedStrategyPanelVM.SelStrategy) Then ShowParam(Map.refForcedStrategyPanelVM.StrategyList) End If For Each StrategySetupItem As StrategySetup In Map.refStrategyManagerVM.StrategySetupList For Each StrategyFeatureItem As StrategyFeature In StrategySetupItem.StrategyFeatureList For Each TopologyItem As Topology In StrategyFeatureItem.TopologyList ShowParam(TopologyItem.StrategyList) Next Next Next NotifyPropertyChanged(NameOf(UserAdmin_IsChecked)) End Set End Property Friend Sub SetUserAdmin_IsChecked(value As Boolean) m_bUserAdmin_IsChecked = value NotifyPropertyChanged(NameOf(UserAdmin_IsChecked)) End Sub Private m_UserFontWeight As FontWeight = FontWeights.Bold Public ReadOnly Property UserFontWeight As FontWeight Get Return m_UserFontWeight End Get End Property Friend Sub SetUserFontWeight(value As FontWeight) m_UserFontWeight = value NotifyPropertyChanged(NameOf(UserFontWeight)) End Sub Private m_AdminFontWeight As FontWeight = FontWeights.Normal Public ReadOnly Property AdminFontWeight As FontWeight Get Return m_AdminFontWeight End Get End Property Friend Sub SetAdminFontWeight(value As FontWeight) m_AdminFontWeight = value NotifyPropertyChanged(NameOf(AdminFontWeight)) End Sub Private m_UnloackImage As String = PADLOCK_IMAGE Public ReadOnly Property UnloackImage As String Get Return m_UnloackImage End Get End Property Friend Sub SetUnloackImage(value As String) m_UnloackImage = value NotifyPropertyChanged(NameOf(UnloackImage)) End Sub Private m_bUnlockAllIsChecked As Boolean = False Public Property UnlockAllIsChecked As Boolean Get Return m_bUnlockAllIsChecked End Get Set(value As Boolean) m_bUnlockAllIsChecked = value If m_bUnlockAllIsChecked Then If UnLockParameter() Then SetUnloackImage(UNPADLOCK_IMAGE) Else Return End If Else SetUnloackImage(PADLOCK_IMAGE) End If If Not IsNothing(Map.refForcedStrategyPanelVM.SelStrategy) Then If m_bUnlockAllIsChecked Then UnlockAll(Map.refForcedStrategyPanelVM.StrategyList) Else LockAll(Map.refForcedStrategyPanelVM.StrategyList) End If End If For Each StrategySetupItem As StrategySetup In Map.refStrategyManagerVM.StrategySetupList For Each StrategyFeatureItem As StrategyFeature In StrategySetupItem.StrategyFeatureList For Each TopologyItem As Topology In StrategyFeatureItem.TopologyList If m_bUnlockAllIsChecked Then UnlockAll(TopologyItem.StrategyList) Else LockAll(TopologyItem.StrategyList) End If Next Next Next NotifyPropertyChanged(NameOf(UnlockAllIsChecked)) End Set End Property #Region "Messages" Public ReadOnly Property Configuration_Msg As String Get Return EgtMsg(61832) End Get End Property Public ReadOnly Property Supervisor_Msg As String Get Return EgtMsg(62500) End Get End Property Public ReadOnly Property OptimizerPage_Msg As String Get Return EgtMsg(61896) End Get End Property Public ReadOnly Property UserMsg As String Get Return EgtMsg(61748) End Get End Property Public ReadOnly Property AdvanceMsg As String Get Return EgtMsg(61749) End Get End Property #Region "ToolTip" 'Proprietà ToolTip Public ReadOnly Property SendFeedbackToolTip As String Get Return EgtMsg(30513) End Get End Property Public ReadOnly Property ConfigurationProgramToolTip As String Get Return EgtMsg(30515) End Get End Property #End Region ' ToolTip #End Region ' Messages ' Definizione comandi Private m_cmdSupervisor As ICommand Private m_cmdSendFeedback As ICommand #End Region ' Fields & Properties #Region "CONSTRUCTOR" Sub New() ' Creo riferimento a questa classe in EgtCAM5Map Map.SetRefMainMenuVM(Me) ' abilito supervisore If Map.refMainWindowVM.MainWindowM.GetKeyOption(KEY_OPT.SUPERVISOR) Then m_Supervisor_Visibility = Visibility.Visible Else m_Supervisor_Visibility = Visibility.Collapsed End If ' imposto timer di apertura da ottimizzatore m_OpenPage_Timer.Interval = TimeSpan.FromMilliseconds(500) AddHandler m_OpenPage_Timer.Tick, AddressOf OpenPage_Tick m_OpenPage_Timer.Start() End Sub #End Region ' CONSTRUCTOR #Region "METHODS" Friend Sub SetMainMenuIsEnabled(bIsEnabled As Boolean) m_MainMenu_IsEnabled = bIsEnabled NotifyPropertyChanged(NameOf(MainMenu_IsEnabled)) End Sub Private Function InitCONFIG() As Boolean If Not IsNothing(Map.refMachinePanelVM.SelectedMachine) Then EgtSetCurrMachine(Map.refMachinePanelVM.SelectedMachine.Name) Map.refMainWindowVM.NotifyPropertyChanged(NameOf(Map.refMainWindowVM.nSelTabPage)) Return True End Function Private Function ExitCONFIG() As Boolean Map.refConfigurationPageVM.VerifyConfigPageModification() ' resetto flag inserimento password Map.refConfigurationPageVM.bModifyMachParam = False If Not IsNothing(Map.refProjectVM.BTLStructureVM) Then Map.refRawPartListVM.UpdateColumns(Map.refProjectVM.BTLStructureVM.nPROJTYPE) Map.refFeatureInPartInRawPartListVM.UpdateColumns(CurrentMachine.nType) Else Map.refRawPartListVM.UpdateColumns(BWType.BEAM) Map.refFeatureInPartInRawPartListVM.UpdateColumns(CurrentMachine.nType) End If Return True End Function Private Function InitOPTIMIZERPAGE() As Boolean ' Gestione cambio pagina If Not IsNothing(ProjectManagerVM.CurrProd) Then EgtSetCurrMachine(ProjectManagerVM.CurrProd.sMachine) Map.refMainWindowVM.NotifyPropertyChanged(NameOf(Map.refMainWindowVM.nSelTabPage)) Return True End Function Private Function ExitOPTIMIZERPAGE(bVerifyModification As Boolean) As Boolean ' verifico se progetto modificato, e chiedo se salvare If bVerifyModification Then If ProdFileVM.VerifyProjectModification(ProjectManagerVM.CurrProd) = MessageBoxResult.Cancel Then Return False End If End If Return True End Function Public Sub OpenPageFromSupervisor(Page As Pages) If m_SelPage <> Page Then m_nPageToOpen = Page m_bOpenPage = True End If End Sub Public Sub OpenPage_Tick() If Not m_bOpenPage Then Return m_bOpenPage = False ' apro la pagina SelPage = m_nPageToOpen m_nPageToOpen = Pages.MACHINING End Sub ''' ''' Funzione che gestisce la visibilità dei parametri in base al livello utente ''' ''' Friend Sub UserLevelVisibility(Param As StrategyParameter, Visibility As Boolean) Select Case Param.GetType() Case GetType(BooleanStrategyParameter) DirectCast(Param, BooleanStrategyParameter).SetbBooleanVisibility(Visibility) Case GetType(DoubleStrategyParameter) DirectCast(Param, DoubleStrategyParameter).SetbDoubleVisibility(Visibility) Case GetType(ComboStrategyParameter) DirectCast(Param, ComboStrategyParameter).SetbComboBoxVisibility(Visibility) Case GetType(StringStrategyParameter) DirectCast(Param, StringStrategyParameter).SetbStringVisibility(Visibility) Case GetType(ListStrategyParameter) DirectCast(Param, ListStrategyParameter).SetbListBoxVisibility(Visibility) End Select End Sub Friend Sub UserLevelGenericVisibility(Generic As ProjectParameters, Visibility As Boolean) Select Case Generic.GetType() Case GetType(BooleanGenericParameter) DirectCast(Generic, BooleanGenericParameter).SetbBooleanVisibility(Visibility) Case GetType(DoubleGenericParameter) DirectCast(Generic, DoubleGenericParameter).SetbDoubleVisibility(Visibility) Case GetType(ComboGenericParameter) DirectCast(Generic, ComboGenericParameter).SetbComboBoxVisibility(Visibility) Case GetType(StringGenericParameter) DirectCast(Generic, StringGenericParameter).SetbStringVisibility(Visibility) Case GetType(ListGenericParameter) DirectCast(Generic, ListGenericParameter).SetbListBoxVisibility(Visibility) End Select End Sub Friend Sub ShowParam(StrategyList As ObservableCollection(Of Strategy)) SetAdminFontWeight(If(m_bUserAdmin_IsChecked, FontWeights.Bold, FontWeights.Normal)) SetUserFontWeight(If(m_bUserAdmin_IsChecked, FontWeights.Normal, FontWeights.Bold)) For Each StrategyItem As Strategy In StrategyList For Each ParamItem In StrategyItem.ParameterList Select Case ParamItem.sMinUserLevel Case UserLevel.ADVANCED UserLevelVisibility(ParamItem, If(m_bUserAdmin_IsChecked, True, False)) Case UserLevel.ADMINISTRATOR UserLevelVisibility(ParamItem, If(m_bUnlockAllIsChecked, True, False)) Case Else If Not m_bUserAdmin_IsChecked Then UserLevelVisibility(ParamItem, If(ParamItem.sMinUserLevel = UserLevel.USER, True, False)) SetUnloackImage(PADLOCK_IMAGE) End If End Select Next Next If Not IsNothing(Map.refGeneralParametersStrategyVM) Then For Each GenericItem As ProjectParameters In Map.refGeneralParametersStrategyVM.GeneralParametersList Select Case GenericItem.sMinUserLevel Case UserLevel.ADVANCED UserLevelGenericVisibility(GenericItem, If(m_bUserAdmin_IsChecked, True, False)) Case UserLevel.ADMINISTRATOR UserLevelGenericVisibility(GenericItem, If(m_bUnlockAllIsChecked, True, False)) Case Else If Not m_bUserAdmin_IsChecked Then UserLevelGenericVisibility(GenericItem, If(GenericItem.sMinUserLevel = UserLevel.USER, True, False)) SetUnloackImage(PADLOCK_IMAGE) End If End Select Next End If End Sub Friend Function UnLockParameter() As Boolean Dim InputPwdWndVM As New InputPwdWndVM() Dim InputPwdWnd As New InputPwdWndV(Application.Current.MainWindow, InputPwdWndVM) Dim sPwdIni As String = String.Empty If InputPwdWnd.ShowDialog() Then If GetMainPrivateProfileString(S_STRATEGY, K_PARAMPASSWORD, "", sPwdIni) <> 0 Then If sPwdIni <> InputPwdWndVM.sPassword Then EgtBEAMWALL.Core.EgtMessageBoxV.Show(Application.Current.MainWindow, EgtMsg(63040), EgtMsg(15002), MessageBoxButton.OK, MessageBoxImage.Error) Return False End If End If Else Return False End If SetAdminFontWeight(If(m_bUserAdmin_IsChecked, FontWeights.Bold, FontWeights.Normal)) SetUserFontWeight(If(m_bUserAdmin_IsChecked, FontWeights.Normal, FontWeights.Bold)) Return True End Function ''' ''' Funzione sblocca tutti paramatri delle strategie con una password ''' Public Sub UnlockAll(StrategyList As ObservableCollection(Of Strategy)) SetUserAdmin_IsChecked(True) For Each StrategyItem As Strategy In StrategyList For Each ParamItem As StrategyParameter In StrategyItem.ParameterList If ParamItem.sMinUserLevel >= UserLevel.ADVANCED Then ' Rendo visibili i parametri che hanno sMinUserLevel a 10 UserLevelVisibility(ParamItem, True) End If Next Next If Not IsNothing(Map.refGeneralParametersStrategyVM) Then For Each GenericItem As ProjectParameters In Map.refGeneralParametersStrategyVM.GeneralParametersList If GenericItem.sMinUserLevel >= UserLevel.ADVANCED Then ' Rendo visibili i parametri che hanno sMinUserLevel a 10 UserLevelGenericVisibility(GenericItem, True) End If Next End If End Sub ''' ''' Funzione blocca tutti paramatri delle strategie con una password ''' Public Sub LockAll(StrategyList As ObservableCollection(Of Strategy)) SetUserAdmin_IsChecked(False) For Each StrategyItem As Strategy In StrategyList For Each ParamItem As StrategyParameter In StrategyItem.ParameterList If ParamItem.sMinUserLevel >= UserLevel.ADVANCED Then ' Rendo invisibili i parametri che hanno sMinUserLevel a 10 UserLevelVisibility(ParamItem, False) End If Next Next If Not IsNothing(Map.refGeneralParametersStrategyVM) Then For Each GenericItem As ProjectParameters In Map.refGeneralParametersStrategyVM.GeneralParametersList If GenericItem.sMinUserLevel >= UserLevel.ADVANCED Then ' Rendo invisibili i parametri che hanno sMinUserLevel a 10 UserLevelGenericVisibility(GenericItem, False) End If Next End If End Sub #End Region ' METHODS #Region "COMMANDS" #Region "Supervisor" Public ReadOnly Property Supervisor_Command As ICommand Get If m_cmdSupervisor Is Nothing Then m_cmdSupervisor = New Command(AddressOf Supervisor) End If Return m_cmdSupervisor End Get End Property Public Sub Supervisor() Dim sSupervisorName As String = "Aedifica.SupervisorR32" ' recupero processo del supervisore Dim localProc As Process() = Process.GetProcessesByName(sSupervisorName) If localProc.Length > 0 Then For Each p As Process In localProc ' porto in primo piano il Supervisor BringWindowToFront(p.MainWindowHandle) Exit For Next Else Dim sSupervisorPath As String = Path.GetDirectoryName(System.AppDomain.CurrentDomain.BaseDirectory) & "\" & sSupervisorName & ".exe" Try Process.Start(sSupervisorPath, "1 " & CurrProd.nProdId) Catch ex As Exception EgtOutLog("Error: impossible starting supervisor from path " & sSupervisorPath) End Try End If ' mando richiesta di apertura progetto in supervisore DbControllers.m_StatusMapController.UpdateAction(DbControllers.m_SupervisorId, CurrProd.nProdId, CurrProd.nProdId, StatusMapItemType.Comm, StatusMapOpType.ChangeProdInSupervisorRequest, "") End Sub #End Region ' Supervisor #Region "SendFeedbackCommand" Public ReadOnly Property SendFeedbackCommand As ICommand Get If m_cmdSendFeedback Is Nothing Then m_cmdSendFeedback = New Command(AddressOf SendFeedback) End If Return m_cmdSendFeedback End Get End Property Public Sub SendFeedback(ByVal param As Object) If IsNothing(ProjectManagerVM.CurrProd) Then EgtBEAMWALL.Core.EgtMessageBoxV.Show(Application.Current.MainWindow, EgtMsg(61891), EgtMsg(15001), MessageBoxButton.OK, MessageBoxImage.Error) Return End If ' Recupero indirizzo a cui spedire la mail Dim sSupportAddress As String = String.Empty GetMainPrivateProfileString(S_GENERAL, K_SUPPORT, "support@egaltech.com", sSupportAddress) ' se vuoto do messaggio di errore ed esco If String.IsNullOrWhiteSpace(sSupportAddress) Then EgtBEAMWALL.Core.EgtMessageBoxV.Show(Application.Current.MainWindow, EgtMsg(30510), EgtMsg(15001), MessageBoxButton.OK, MessageBoxImage.Error) Return End If ' Recupero numero chiave Dim sKey As String = String.Empty EgtGetKeyInfo(sKey) ' Esporto il progetto Dim ProjFileMList As List(Of ProjFileM) If IsNothing(ProjectManagerVM.CurrProd) Then ProjFileMList = DbControllers.m_ProjController.GetByProdAsc(ProjectManagerVM.CurrProd.nProdId) Map.refProdManagerVM.SetCurrProj(ProjFileMList(0).nProjId) End If Dim sExportFileName = ProjectManagerVM.CurrProd.nProdId.ToString("0000") & " - " & ProjectManagerVM.CurrProj.sBTLFileName & " - ProjectExport" Dim sExpZipToCreate = Map.refProdManagerVM.ExportProject(sExportFileName) ' Creo zip file da allegare Dim sZipToCreate As String = Map.refMainWindowVM.MainWindowM.sTempDir & "\Feedback.zip" If File.Exists(sZipToCreate) Then File.Delete(sZipToCreate) Try Using zipStream As FileStream = New FileStream(sZipToCreate, FileMode.Create) Using archive As ZipArchive = New ZipArchive(zipStream, ZipArchiveMode.Create) If File.Exists(sExpZipToCreate) Then AddFileToZip(archive, sExpZipToCreate, "") End If Dim ProdId As Integer Select Case Map.refMainMenuVM.SelPage Case Pages.VIEW ProdId = ProjectManagerVM.CurrProd.nProjIdList(0) Case Pages.MACHINING, Pages.OPTIMIZERPAGE ProdId = ProjectManagerVM.CurrProd.nProdId End Select If ProdId = 0 Then AddDirectoryToZip(archive, ProjectManagerVM.CurrProd.sProdDirPath, "Projs\" & ProjectManagerVM.CurrProd.nProjIdList(0).ToString("0000")) Else ProjFileMList = DbControllers.m_ProjController.GetByProdAsc(ProdId) If IsNothing(ProjFileMList) Then Return ElseIf ProjFileMList.Count > 0 Then Dim ProjFileVMList As New List(Of ProjectFileVM) For Each Project In ProjFileMList ProjFileVMList.Add(New ProjFileVM(Project)) Next For Each ProjFileVMItem In ProjFileVMList AddDirectoryToZip(archive, ProjFileVMItem.sProdDirPath, "Prods\" & ProjFileVMItem.nProdId.ToString("0000")) Next End If End If Dim sMachineDir As String = Map.refMainWindowVM.MainWindowM.sMachinesRoot & "\" & sMachineName If Directory.Exists(sMachineDir) Then AddDirectoryToZip(archive, sMachineDir, sMachineName) End If If File.Exists(Map.refMainWindowVM.MainWindowM.sLogFile) Then AddFileToZip(archive, Map.refMainWindowVM.MainWindowM.sLogFile, "") End If If File.Exists(BTLIniFile.m_sBTLIniFile) Then AddFileToZip(archive, BTLIniFile.m_sBTLIniFile, "") End If End Using End Using Catch ex1 As Exception EgtOutLog("Exception in zip: " & ex1.ToString()) End Try ' preparo la mail per il supporto Dim bEx As Boolean = False Try Dim sAddressArray As String() = sSupportAddress.Split(CType(",", Char())) Dim SendFeedbackWindow As New EgtWPFLib5.MapiMailMessage("Aedifica Feedback - " & sKey) SendFeedbackWindow.Recipients.Add(sAddressArray(0)) For index As Integer = 1 To sAddressArray.Length() - 1 SendFeedbackWindow.Recipients.Add(sAddressArray(index), EgtWPFLib5.MapiMailMessage.RecipientType.CC) Next If Not String.IsNullOrWhiteSpace(sZipToCreate) AndAlso File.Exists(sZipToCreate) Then SendFeedbackWindow.Files.Add(Map.refMainWindowVM.MainWindowM.sTempDir & "\Feedback.zip") End If SendFeedbackWindow.ShowDialog() Catch ex As Exception EgtOutLog("Feedback exception: " & ex.ToString) bEx = True End Try If bEx OrElse EgtWPFLib5.MapiMailMessage.m_ErrorCode <> 0 Then EgtBEAMWALL.Core.EgtMessageBoxV.Show(Application.Current.MainWindow, String.Format(EgtMsg(30512), sSupportAddress, sZipToCreate), EgtMsg(15003), MessageBoxButton.OK, MessageBoxImage.Information) Else Map.refMyStatusBarVM.SetOutputMessage(EgtMsg(30514)) End If End Sub Private Sub AddFileToZip(archive As ZipArchive, filePath As String, entryRoot As String) Dim entryName As String = If(String.IsNullOrEmpty(entryRoot), Path.GetFileName(filePath), entryRoot.TrimEnd("\"c) & "\" & Path.GetFileName(filePath)) Using fs As New FileStream(filePath, FileMode.Open, FileAccess.Read, FileShare.ReadWrite) Dim entry As ZipArchiveEntry = archive.CreateEntry(entryName, CompressionLevel.NoCompression) Using entryStream = entry.Open() fs.CopyTo(entryStream) End Using End Using End Sub Private Sub AddDirectoryToZip(archive As ZipArchive, folderPath As String, entryRoot As String) Dim files As String() = Directory.GetFiles(folderPath, "*.*", SearchOption.AllDirectories) For Each file As String In files Dim relativePath As String = file.Substring(folderPath.Length).TrimStart("\"c) Dim entryName As String = entryRoot.TrimEnd("\"c) & "\" & relativePath Dim entry As ZipArchiveEntry = archive.CreateEntry(entryName, CompressionLevel.NoCompression) Using entryStream As Stream = entry.Open() Using fileStream As FileStream = System.IO.File.OpenRead(file) fileStream.CopyTo(entryStream) End Using End Using Next End Sub #End Region ' SendFeedbackCommand #End Region ' COMMANDS End Class