diff --git a/HowToBuild.txt b/HowToBuild.txt index 258d090d4..ed17b456c 100644 --- a/HowToBuild.txt +++ b/HowToBuild.txt @@ -1,7 +1,6 @@ How to Build Rapid SCADA ------------------------ -Microsoft Visual Studio 2010 Professional or higher is needed. -Visual Studio Community 2013 is also acceptable. +Microsoft Visual Studio 2015 or higher is needed. Visual Studio Community is OK. 1. Download the source code from SCADA and DLL repositories: https://github.com/RapidScada/scada @@ -18,4 +17,6 @@ Visual Studio Community 2013 is also acceptable. ScadaWeb, ScadaScheme. -3. Enjoy the binaries builded by yourself. \ No newline at end of file + Use the Release configuration so that the links are correct. + +3. Enjoy the binaries built by yourself. diff --git a/LangPack/readme.txt b/LangPack/readme.txt index 882e840db..3a7a3c91b 100644 --- a/LangPack/readme.txt +++ b/LangPack/readme.txt @@ -4,4 +4,18 @@ Language Installation 2. Copy the language files from the folder SCADA of the language pack to the installation directory of Rapid SCADA maintaining the hierarchy of the directories. 3. Run SCADA-Administrator application. 4. Go to Settings -> Language and type the culture name, e.g. es-LA, and click OK button. -5. Restart Rapid SCADA applications to apply changes. \ No newline at end of file +5. Restart Rapid SCADA applications to apply changes. + + +How to Localize UI to Any Language +---------------------------------- +Most of Rapid SCADA applications contain special localization files. Usually they are located in a Lang folder: +C:\SCADA\ScadaAdmin\Lang +C:\SCADA\ScadaComm\Lang +C:\SCADA\ScadaSchemeEditor\Lang +C:\SCADA\ScadaServer\Lang +C:\SCADA\ScadaTableEditor\Lang +C:\SCADA\ScadaWeb\lang + +To add a new language support, create copies of *.en-GB.xml files and give the file names according to your culture. In this example en means English language and GB is Great Britain. +Using your favorite text editor (Notepad++ is OK) translate the phrases in the created xml files. Then open the Administrator application, go to Settings > Language menu and enter your localization name, for example, es-LA diff --git a/LangPack/v5.x/Spanish/ScadaAdmin/Lang/ScadaAdmin.es-LA.xml b/LangPack/v5.x/Spanish/ScadaAdmin/Lang/ScadaAdmin.es-LA.xml index 4122b75d2..55fd3e006 100644 --- a/LangPack/v5.x/Spanish/ScadaAdmin/Lang/ScadaAdmin.es-LA.xml +++ b/LangPack/v5.x/Spanish/ScadaAdmin/Lang/ScadaAdmin.es-LA.xml @@ -1,4 +1,4 @@ - + El archivo de base de datos de la configuración en el formato de SDF {0} no encontrado. @@ -12,7 +12,7 @@ El archivo de la importación es indefinido. El archivo de la importación no existe. Importar configuracion de Base de Datos - Importar tabla de configuracion Base de Datos; "{0}"Importar tabla de configuracion Base de Datos; "{0}" Archivo de Origen: Error al Importar carga de tabla Columnas de la tabla de la Origen diff --git a/LangPack/v5.x/Spanish/ScadaAdmin/Lang/ScadaData.es-LA.xml b/LangPack/v5.x/Spanish/ScadaAdmin/Lang/ScadaData.es-LA.xml index c50ac008d..12fe3cc3c 100644 --- a/LangPack/v5.x/Spanish/ScadaAdmin/Lang/ScadaData.es-LA.xml +++ b/LangPack/v5.x/Spanish/ScadaAdmin/Lang/ScadaData.es-LA.xml @@ -1,4 +1,4 @@ - + Información diff --git a/LangPack/v5.x/Spanish/ScadaComm/Lang/AddressBook.es-LA.xml b/LangPack/v5.x/Spanish/ScadaComm/Lang/AddressBook.es-LA.xml index 8c204b177..237a776aa 100644 --- a/LangPack/v5.x/Spanish/ScadaComm/Lang/AddressBook.es-LA.xml +++ b/LangPack/v5.x/Spanish/ScadaComm/Lang/AddressBook.es-LA.xml @@ -1,4 +1,4 @@ - + Error al cargar agenda de direcciones diff --git a/LangPack/v5.x/Spanish/ScadaComm/Lang/KpEmail.es-LA.xml b/LangPack/v5.x/Spanish/ScadaComm/Lang/KpEmail.es-LA.xml index a3a80a700..908d88af3 100644 --- a/LangPack/v5.x/Spanish/ScadaComm/Lang/KpEmail.es-LA.xml +++ b/LangPack/v5.x/Spanish/ScadaComm/Lang/KpEmail.es-LA.xml @@ -1,4 +1,4 @@ - + Email - Dispositivo {0} Configuracion diff --git a/LangPack/v5.x/Spanish/ScadaComm/Lang/KpModbus.es-LA.xml b/LangPack/v5.x/Spanish/ScadaComm/Lang/KpModbus.es-LA.xml index d78ab7ec5..ef075a93b 100644 --- a/LangPack/v5.x/Spanish/ScadaComm/Lang/KpModbus.es-LA.xml +++ b/LangPack/v5.x/Spanish/ScadaComm/Lang/KpModbus.es-LA.xml @@ -1,4 +1,4 @@ - + MODBUS. Editor de la plantilla del dispositivo diff --git a/LangPack/v5.x/Spanish/ScadaComm/Lang/KpOpc.es-LA.xml b/LangPack/v5.x/Spanish/ScadaComm/Lang/KpOpc.es-LA.xml index a5bfdfb43..de2c41e66 100644 --- a/LangPack/v5.x/Spanish/ScadaComm/Lang/KpOpc.es-LA.xml +++ b/LangPack/v5.x/Spanish/ScadaComm/Lang/KpOpc.es-LA.xml @@ -1,4 +1,4 @@ - + 0} configuraciones del dispositivo { diff --git a/LangPack/v5.x/Spanish/ScadaComm/Lang/KpSnmp.es-LA.xml b/LangPack/v5.x/Spanish/ScadaComm/Lang/KpSnmp.es-LA.xml index 63cd6b548..4528fde49 100644 --- a/LangPack/v5.x/Spanish/ScadaComm/Lang/KpSnmp.es-LA.xml +++ b/LangPack/v5.x/Spanish/ScadaComm/Lang/KpSnmp.es-LA.xml @@ -1,4 +1,4 @@ - + SNMP - {0} configuraciones del dispositivo diff --git a/LangPack/v5.x/Spanish/ScadaComm/Lang/ScadaComm.es-LA.xml b/LangPack/v5.x/Spanish/ScadaComm/Lang/ScadaComm.es-LA.xml index 365ba687d..cfe65de70 100644 --- a/LangPack/v5.x/Spanish/ScadaComm/Lang/ScadaComm.es-LA.xml +++ b/LangPack/v5.x/Spanish/ScadaComm/Lang/ScadaComm.es-LA.xml @@ -1,4 +1,4 @@ - + Importación de líneas y dispositivos de comunicación @@ -234,8 +234,8 @@ Comportamiento Master - SCADA-Communicator envía solicitud a un dispositivo y recibe respuesta. Slave - SCADA-Communicator espera pasivamente los datos de un dispositivo. Selección del dispositivo - Por dirección IPDLL determinado + Por dirección IP + DLL determinado El método de enlazar los datos recibidos a un dispositivo en modo esclavo: Por dirección IP: la dirección IP remota equivale a un número de llamada del dispositivo. DLL Determined - algoritmo se implementa en la biblioteca de dispositivos. Puerto local de UDP Puerto UDP local para conexiones entrantes. Las conexiones entrantes deben ser permitidas por un firewall. diff --git a/LangPack/v5.x/Spanish/ScadaComm/Lang/ScadaData.es-LA.xml b/LangPack/v5.x/Spanish/ScadaComm/Lang/ScadaData.es-LA.xml index b6e9742b2..1659e43d9 100644 --- a/LangPack/v5.x/Spanish/ScadaComm/Lang/ScadaData.es-LA.xml +++ b/LangPack/v5.x/Spanish/ScadaComm/Lang/ScadaData.es-LA.xml @@ -1,4 +1,4 @@ - + Información diff --git a/LangPack/v5.x/Spanish/ScadaSchemeEditor/lang/ScadaData.es-LA.xml b/LangPack/v5.x/Spanish/ScadaSchemeEditor/lang/ScadaData.es-LA.xml index 0ea99d03e..171c5d36b 100644 --- a/LangPack/v5.x/Spanish/ScadaSchemeEditor/lang/ScadaData.es-LA.xml +++ b/LangPack/v5.x/Spanish/ScadaSchemeEditor/lang/ScadaData.es-LA.xml @@ -1,4 +1,4 @@ - + Información diff --git a/LangPack/v5.x/Spanish/ScadaSchemeEditor/lang/ScadaSchemeEditor.es-LA.xml b/LangPack/v5.x/Spanish/ScadaSchemeEditor/lang/ScadaSchemeEditor.es-LA.xml index 3f2c743c2..c8dfbef0b 100644 --- a/LangPack/v5.x/Spanish/ScadaSchemeEditor/lang/ScadaSchemeEditor.es-LA.xml +++ b/LangPack/v5.x/Spanish/ScadaSchemeEditor/lang/ScadaSchemeEditor.es-LA.xml @@ -1,4 +1,4 @@ - + SCADA-Scheme Editor @@ -36,7 +36,7 @@ Seleccionar elemento para editar sus propiedades Esquemas (*.sch)|*.sch|Todos los Archivos (*.*)|*.* El esquema a sido modificado. Guardar los cambios? - Utilice las llaves de flecha para mover el elemento seleccionado. + Utilice las llaves de flecha para mover el elemento seleccionado. Error al cargar el esquema de archivo diff --git a/LangPack/v5.x/Spanish/ScadaServer/Lang/ScadaData.es-LA.xml b/LangPack/v5.x/Spanish/ScadaServer/Lang/ScadaData.es-LA.xml index b2d3dea40..4575ea8c0 100644 --- a/LangPack/v5.x/Spanish/ScadaServer/Lang/ScadaData.es-LA.xml +++ b/LangPack/v5.x/Spanish/ScadaServer/Lang/ScadaData.es-LA.xml @@ -1,4 +1,4 @@ - + Información diff --git a/LangPack/v5.x/Spanish/ScadaTableEditor/Lang/ScadaData.es-LA.xml b/LangPack/v5.x/Spanish/ScadaTableEditor/Lang/ScadaData.es-LA.xml index 6f7630a4e..19482da3d 100644 --- a/LangPack/v5.x/Spanish/ScadaTableEditor/Lang/ScadaData.es-LA.xml +++ b/LangPack/v5.x/Spanish/ScadaTableEditor/Lang/ScadaData.es-LA.xml @@ -1,4 +1,4 @@ - + Información diff --git a/Log/Log.Std/Log.Std.csproj b/Log/Log.Std/Log.Std.csproj new file mode 100644 index 000000000..20401feb0 --- /dev/null +++ b/Log/Log.Std/Log.Std.csproj @@ -0,0 +1,13 @@ + + + + netstandard2.0 + + + + + + + + + diff --git a/Log/Log.sln b/Log/Log.sln index 3a0d4a4de..9a2a7bbc3 100644 --- a/Log/Log.sln +++ b/Log/Log.sln @@ -1,9 +1,11 @@  Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio 2013 -VisualStudioVersion = 12.0.31101.0 +# Visual Studio 15 +VisualStudioVersion = 15.0.27428.2005 MinimumVisualStudioVersion = 10.0.40219.1 -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Log", "Log.csproj", "{A05EA084-E509-4025-9241-6A5BE5C2B328}" +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Log", "Log\Log.csproj", "{A05EA084-E509-4025-9241-6A5BE5C2B328}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Log.Std", "Log.Std\Log.Std.csproj", "{8D5B84EB-11D8-4B4E-80A0-E51966863149}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution @@ -15,8 +17,15 @@ Global {A05EA084-E509-4025-9241-6A5BE5C2B328}.Debug|Any CPU.Build.0 = Debug|Any CPU {A05EA084-E509-4025-9241-6A5BE5C2B328}.Release|Any CPU.ActiveCfg = Release|Any CPU {A05EA084-E509-4025-9241-6A5BE5C2B328}.Release|Any CPU.Build.0 = Release|Any CPU + {8D5B84EB-11D8-4B4E-80A0-E51966863149}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {8D5B84EB-11D8-4B4E-80A0-E51966863149}.Debug|Any CPU.Build.0 = Debug|Any CPU + {8D5B84EB-11D8-4B4E-80A0-E51966863149}.Release|Any CPU.ActiveCfg = Release|Any CPU + {8D5B84EB-11D8-4B4E-80A0-E51966863149}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {EA8D43F9-5D59-4AEA-A084-86003618EEA5} + EndGlobalSection EndGlobal diff --git a/Log/ILog.cs b/Log/Log/ILog.cs similarity index 100% rename from Log/ILog.cs rename to Log/Log/ILog.cs diff --git a/Log/Log.cs b/Log/Log/Log.cs similarity index 100% rename from Log/Log.cs rename to Log/Log/Log.cs diff --git a/Log/Log.csproj b/Log/Log/Log.csproj similarity index 100% rename from Log/Log.csproj rename to Log/Log/Log.csproj diff --git a/Log/LogStub.cs b/Log/Log/LogStub.cs similarity index 100% rename from Log/LogStub.cs rename to Log/Log/LogStub.cs diff --git a/Log/Properties/AssemblyInfo.cs b/Log/Log/Properties/AssemblyInfo.cs similarity index 100% rename from Log/Properties/AssemblyInfo.cs rename to Log/Log/Properties/AssemblyInfo.cs diff --git a/ScadaAdmin/Res/file.png b/ScadaAdmin/Res/file.png new file mode 100644 index 000000000..2283e3d88 Binary files /dev/null and b/ScadaAdmin/Res/file.png differ diff --git a/ScadaAdmin/Res/folder_closed2.png b/ScadaAdmin/Res/folder_closed2.png new file mode 100644 index 000000000..546f85ed2 Binary files /dev/null and b/ScadaAdmin/Res/folder_closed2.png differ diff --git a/ScadaAdmin/Res/folder_open2.png b/ScadaAdmin/Res/folder_open2.png new file mode 100644 index 000000000..6ef88e9e6 Binary files /dev/null and b/ScadaAdmin/Res/folder_open2.png differ diff --git a/ScadaAdmin/Res/key.png b/ScadaAdmin/Res/key.png new file mode 100644 index 000000000..1d388f0bf Binary files /dev/null and b/ScadaAdmin/Res/key.png differ diff --git a/ScadaAdmin/ScadaAdmin/AppCode/AppData.cs b/ScadaAdmin/ScadaAdmin/AppCode/AppData.cs index be64f13c6..de7173b2e 100644 --- a/ScadaAdmin/ScadaAdmin/AppCode/AppData.cs +++ b/ScadaAdmin/ScadaAdmin/AppCode/AppData.cs @@ -1,5 +1,5 @@ /* - * Copyright 2014 Mikhail Shiryaev + * Copyright 2018 Mikhail Shiryaev * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -20,7 +20,7 @@ * * Author : Mikhail Shiryaev * Created : 2010 - * Modified : 2014 + * Modified : 2018 */ using System.Data; @@ -50,18 +50,24 @@ internal static class AppData /// static AppData() { - ExeDir = ScadaUtils.NormalDir(Path.GetDirectoryName(Application.ExecutablePath)); - ErrLog = new Log(Log.Formats.Full); - ErrLog.FileName = ExeDir + ErrFileName; - ErrLog.Encoding = Encoding.UTF8; + AppDirs = new AppDirs(); + AppDirs.Init(Path.GetDirectoryName(Application.ExecutablePath)); + + ErrLog = new Log(Log.Formats.Full) + { + FileName = AppDirs.LogDir + ErrFileName, + Encoding = Encoding.UTF8 + }; + + Settings = new Settings(); Conn = new SqlCeConnection(); } /// - /// Получить директорию исполняемого файла приложения + /// Получить директории приложения /// - public static string ExeDir { get; private set; } + public static AppDirs AppDirs { get; private set; } /// /// Получить журнал ошибок приложения @@ -69,6 +75,11 @@ static AppData() public static Log ErrLog { get; private set; } + /// + /// Получить настройки приложения + /// + public static Settings Settings { get; private set; } + /// /// Получить соединение с БД /// @@ -89,11 +100,13 @@ public static bool Connected /// /// Соединиться с БД, используя заданную в файле Web.Config строку связи /// - public static void Connect(string baseSdfFileName) + public static void Connect() { if (Conn.State != ConnectionState.Closed) Disconnect(); + string baseSdfFileName = Settings.AppSett.BaseSDFFile; + if (!File.Exists(baseSdfFileName)) throw new FileNotFoundException(string.Format(AppPhrases.BaseSDFFileNotFound, baseSdfFileName)); diff --git a/ScadaAdmin/ScadaAdmin/AppCode/AppDirs.cs b/ScadaAdmin/ScadaAdmin/AppCode/AppDirs.cs new file mode 100644 index 000000000..800abde43 --- /dev/null +++ b/ScadaAdmin/ScadaAdmin/AppCode/AppDirs.cs @@ -0,0 +1,81 @@ +/* + * Copyright 2018 Mikhail Shiryaev + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * + * Product : Rapid SCADA + * Module : SCADA-Administrator + * Summary : Application directories + * + * Author : Mikhail Shiryaev + * Created : 2018 + * Modified : 2018 + */ + +using Scada; +using System.IO; + +namespace ScadaAdmin +{ + /// + /// Application directories + /// Директории приложения + /// + public class AppDirs + { + /// + /// Конструктор + /// + public AppDirs() + { + ExeDir = ""; + ConfigDir = ""; + LangDir = ""; + LogDir = ""; + } + + + /// + /// Получить директорию исполняемого файла + /// + public string ExeDir { get; protected set; } + + /// + /// Получить директорию конфигурации + /// + public string ConfigDir { get; protected set; } + + /// + /// Получить директорию языковых файлов + /// + public string LangDir { get; protected set; } + + /// + /// Получить директорию журналов + /// + public string LogDir { get; protected set; } + + + /// + /// Инициализировать директории на основе директории исполняемого файла приложения + /// + public void Init(string exeDir) + { + ExeDir = ScadaUtils.NormalDir(exeDir); + ConfigDir = ExeDir + "Config" + Path.DirectorySeparatorChar; + LangDir = ExeDir + "Lang" + Path.DirectorySeparatorChar; + LogDir = ExeDir + "Log" + Path.DirectorySeparatorChar; + } + } +} diff --git a/ScadaAdmin/ScadaAdmin/AppCode/AppPhrases.cs b/ScadaAdmin/ScadaAdmin/AppCode/AppPhrases.cs index 6d1b4f31c..96fca355b 100644 --- a/ScadaAdmin/ScadaAdmin/AppCode/AppPhrases.cs +++ b/ScadaAdmin/ScadaAdmin/AppCode/AppPhrases.cs @@ -1,5 +1,5 @@ /* - * Copyright 2016 Mikhail Shiryaev + * Copyright 2018 Mikhail Shiryaev * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -20,7 +20,7 @@ * * Author : Mikhail Shiryaev * Created : 2014 - * Modified : 2016 + * Modified : 2018 */ using Scada; @@ -42,13 +42,34 @@ static AppPhrases() public static string BaseSDFFileNotFound { get; private set; } public static string RefreshRequired { get; private set; } + // Словарь ScadaAdmin.DownloadUpload + public static string DownloadTitle { get; private set; } + public static string ConnectionName { get; private set; } + public static string SessionCreated { get; private set; } + public static string UnableCreateSession { get; private set; } + public static string LoggedOn { get; private set; } + public static string UnableLogin { get; private set; } + public static string ConnectAgentError { get; private set; } + public static string DownloadDataEmpty { get; private set; } + public static string DownloadSuccessful { get; private set; } + public static string DownloadError { get; private set; } + public static string UploadTitle { get; private set; } + public static string NoConfigInSrc { get; private set; } + public static string ConfigUploaded { get; private set; } + public static string ServerRestarted { get; private set; } + public static string UnableRestartServer { get; private set; } + public static string CommRestarted { get; private set; } + public static string UnableRestartComm { get; private set; } + public static string UploadSuccessful { get; private set; } + public static string UploadError { get; private set; } + // Словарь ScadaAdmin.ImportExport public static string ChooseBaseTableFile { get; private set; } - public static string ChooseBaseArchiveFile { get; private set; } + public static string ChooseArchiveFile { get; private set; } public static string BaseTableFileFilter { get; private set; } - public static string BaseArchiveFileFilter { get; private set; } - public static string ImportFileUndefied { get; private set; } + public static string ArchiveFileFilter { get; private set; } public static string ImportFileNotExist { get; private set; } + public static string ImportDirNotExist { get; private set; } public static string ImportTitle { get; private set; } public static string ImportTableTitle { get; private set; } public static string ImportSource { get; private set; } @@ -65,6 +86,7 @@ static AppPhrases() public static string ImportTableResult { get; private set; } public static string ImportTableErrors { get; private set; } public static string ImportTableError { get; private set; } + public static string ImportAllTablesError { get; private set; } public static string ImportArchiveError { get; private set; } public static string ExportFileUndefied { get; private set; } public static string ExportDirUndefied { get; private set; } @@ -131,6 +153,7 @@ static AppPhrases() public static string FillKPGridError { get; private set; } // Словарь ScadaAdmin.FrmImport + public static string AllTablesItem { get; private set; } public static string ArchiveItem { get; private set; } // Словарь ScadaAdmin.FrmInCnlProps @@ -193,6 +216,10 @@ static AppPhrases() public static string DeleteRowsConfirm { get; private set; } public static string ClearTableConfirm { get; private set; } + // Словарь ScadaAdmin.ServersSettings + public static string LoadServersSettingsError { get; private set; } + public static string SaveServersSettingsError { get; private set; } + // Словарь ScadaAdmin.Tables public static string UpdateDataError { get; private set; } public static string FillSchemaError { get; private set; } @@ -208,20 +235,60 @@ static AppPhrases() public static string GetInCnlNumsError { get; private set; } public static string GetCtrlCnlNumsError { get; private set; } + // Словарь ScadaAdmin.Remote + public static string ChooseConfigDir { get; private set; } + public static string ConfigDirRequired { get; private set; } + public static string ConfigArcRequired { get; private set; } + + // Словарь ScadaAdmin.Remote.CtrlServerConn + public static string DeleteConnConfirm { get; private set; } + + // Словарь ScadaAdmin.Remote.FrmConnSettings + public static string EmptyFieldsNotAllowed { get; private set; } + public static string ConnNameDuplicated { get; private set; } + public static string IncorrectSecretKey { get; private set; } + + // Словарь ScadaAdmin.Remote.FrmServerStatus + public static string UndefinedSvcStatus { get; private set; } + public static string NormalSvcStatus { get; private set; } + public static string StoppedSvcStatus { get; private set; } + public static string ErrorSvcStatus { get; private set; } + private static void SetToDefault() { BaseSDFFileNotFound = "Файл базы конфигурации в формате SDF {0} не найден."; RefreshRequired = "\r\nОбновите открытые таблицы, чтобы отобразить изменения."; + DownloadTitle = "{0} Скачивание конфигурации"; + ConnectionName = "Соединение : {0}"; + SessionCreated = "Создана сессия {0}"; + UnableCreateSession = "Не удалось создать сессию"; + LoggedOn = "Вход в систему выполнен"; + UnableLogin = "Не удалось войти в систему - {0}"; + ConnectAgentError = "Ошибка при соединении с Агентом"; + DownloadDataEmpty = "Отсутствуют данные для скачивания"; + DownloadSuccessful = "Скачивание завершено успешно за {0} с."; + DownloadError = "Ошибка при скачивании конфигурации"; + UploadTitle = "{0} Передача конфигурации"; + NoConfigInSrc = "Конфигурация отсутствует в заданном источнике."; + ConfigUploaded = "Конфигурация передана"; + ServerRestarted = "Служба Сервера перезапущена"; + UnableRestartServer = "Не удалось перезапустить службу Сервера"; + CommRestarted = "Служба Коммуникатора перезапущена"; + UnableRestartComm = "Не удалось перезапустить службу Коммуникатора"; + UploadSuccessful = "Передача завершена успешно за {0} с.\r\n" + + "Проверьте работоспособность удалённого сервера."; + UploadError = "Ошибка при передаче конфигурации"; + ChooseBaseTableFile = "Выберите файл таблицы базы конфигурации"; - ChooseBaseArchiveFile = "Выберите файл архива базы конфигурации"; - BaseTableFileFilter = "Таблицы базы конфигурации|*.dat|Все файлы|*.*"; - BaseArchiveFileFilter = "Архив базы конфигурации|*.zip|Все файлы|*.*"; - ImportFileUndefied = "Импортируемый файл не определён."; + ChooseArchiveFile = "Выберите файл архива конфигурации"; + BaseTableFileFilter = "Таблицы базы конфигурации (*.dat)|*.dat|Все файлы (*.*)|*.*"; + ArchiveFileFilter = "Архив конфигурации (*.zip)|*.zip|Все файлы (*.*)|*.*"; ImportFileNotExist = "Импортируемый файл не существует."; + ImportDirNotExist = "Импортируемая директория не существует."; ImportTitle = "Импорт базы конфигурации"; ImportTableTitle = "Импорт таблицы базы конфигурации \"{0}\""; - ImportSource = "Исходный файл : "; + ImportSource = "Исходный файл или директория : "; LoadTableError = "Ошибка при загрузке импортируемой таблицы"; SrcTableColumns = "Поля исходной таблицы"; DestTableColumns = "Поля таблицы, в которую производится импорт"; @@ -236,6 +303,8 @@ private static void SetToDefault() ImportTableResult = "Результат импорта таблицы"; ImportTableErrors = "Ошибки импорта таблицы"; ImportTableError = "Ошибка при импорте таблицы базы конфигурации"; + ImportAllTablesError = "Ошибка при импорте всех таблиц базы конфигурации"; + ImportArchiveError = "Ошибка при импорте базы конфигурации из архива"; ExportFileUndefied = "Файл экспорта не определён."; ExportDirUndefied = "Директория экспорта не определена."; ExportDirNotExists = "Директория экспорта не существует."; @@ -298,6 +367,7 @@ private static void SetToDefault() FillKPFilterError = "Ошибка при заполнении фильтра КП"; FillKPGridError = "Ошибка при заполнении таблицы выбора КП"; + AllTablesItem = "Все таблицы"; ArchiveItem = "Таблицы из архива"; ShowInCnlPropsError = "Ошибка при отображении свойств входного канала"; @@ -354,6 +424,9 @@ private static void SetToDefault() DeleteRowsConfirm = "Вы уверены, что хотите удалить строки?"; ClearTableConfirm = "Вы уверены, что хотите очистить таблицу?"; + LoadServersSettingsError = "Ошибка при загрузке настроек взаимодействия с удалёнными серверами"; + SaveServersSettingsError = "Ошибка при сохранении настроек взаимодействия с удалёнными серверами"; + UpdateDataError = "Ошибка при сохранении изменений таблицы в БД"; FillSchemaError = "Ошибка при получении схемы данных таблицы"; DataRequired = "Столбец \"{0}\" не может содержать пустых значений."; @@ -367,6 +440,21 @@ private static void SetToDefault() GetCtrlCnlNameError = "Ошибка при получении наименования канала управления"; GetInCnlNumsError = "Ошибка при получении номеров входных каналов"; GetCtrlCnlNumsError = "Ошибка при получении номеров каналов управления"; + + ChooseConfigDir = "Выберите директорию конфигурации"; + ConfigDirRequired = "Укажите директорию конфигурации."; + ConfigArcRequired = "Укажите имя файла архива конфигурации."; + + DeleteConnConfirm = "Вы уверены, что хотите удалить подключение?"; + + EmptyFieldsNotAllowed = "Пустые значения полей не допускаются."; + ConnNameDuplicated = "Соединение с таким наименованием уже существует."; + IncorrectSecretKey = "Некорректный секретный ключ."; + + UndefinedSvcStatus = "Не определён"; + NormalSvcStatus = "Норма"; + StoppedSvcStatus = "Остановлен"; + ErrorSvcStatus = "Ошибка"; } public static void Init() @@ -378,14 +466,37 @@ public static void Init() RefreshRequired = dict.GetPhrase("RefreshRequired", RefreshRequired); } + if (Localization.Dictionaries.TryGetValue("ScadaAdmin.DownloadUpload", out dict)) + { + DownloadTitle = dict.GetPhrase("DownloadTitle", DownloadTitle); + ConnectionName = dict.GetPhrase("ConnectionName", ConnectionName); + SessionCreated = dict.GetPhrase("SessionCreated", SessionCreated); + UnableCreateSession = dict.GetPhrase("UnableCreateSession", UnableCreateSession); + LoggedOn = dict.GetPhrase("LoggedOn", LoggedOn); + UnableLogin = dict.GetPhrase("UnableLogin", UnableLogin); + ConnectAgentError = dict.GetPhrase("ConnectAgentError", ConnectAgentError); + DownloadDataEmpty = dict.GetPhrase("DownloadDataEmpty", DownloadDataEmpty); + DownloadSuccessful = dict.GetPhrase("DownloadSuccessful", DownloadSuccessful); + DownloadError = dict.GetPhrase("DownloadError", DownloadError); + UploadTitle = dict.GetPhrase("UploadTitle", UploadTitle); + NoConfigInSrc = dict.GetPhrase("NoConfigInSrc", NoConfigInSrc); + ConfigUploaded = dict.GetPhrase("ConfigUploaded", ConfigUploaded); + ServerRestarted = dict.GetPhrase("ServerRestarted", ServerRestarted); + UnableRestartServer = dict.GetPhrase("UnableRestartServer", UnableRestartServer); + CommRestarted = dict.GetPhrase("CommRestarted", CommRestarted); + UnableRestartComm = dict.GetPhrase("UnableRestartComm", UnableRestartComm); + UploadSuccessful = dict.GetPhrase("UploadSuccessful", UploadSuccessful); + UploadError = dict.GetPhrase("UploadError", UploadError); + } + if (Localization.Dictionaries.TryGetValue("ScadaAdmin.ImportExport", out dict)) { ChooseBaseTableFile = dict.GetPhrase("ChooseBaseTableFile", ChooseBaseTableFile); - ChooseBaseArchiveFile = dict.GetPhrase("ChooseBaseArchiveFile", ChooseBaseArchiveFile); + ChooseArchiveFile = dict.GetPhrase("ChooseArchiveFile", ChooseArchiveFile); BaseTableFileFilter = dict.GetPhrase("BaseTableFileFilter", BaseTableFileFilter); - BaseArchiveFileFilter = dict.GetPhrase("BaseArchiveFileFilter", BaseArchiveFileFilter); - ImportFileUndefied = dict.GetPhrase("ImportFileUndefied", ImportFileUndefied); + ArchiveFileFilter = dict.GetPhrase("ArchiveFileFilter", ArchiveFileFilter); ImportFileNotExist = dict.GetPhrase("ImportFileNotExist", ImportFileNotExist); + ImportDirNotExist = dict.GetPhrase("ImportDirNotExist", ImportDirNotExist); ImportTitle = dict.GetPhrase("ImportTitle", ImportTitle); ImportTableTitle = dict.GetPhrase("ImportTableTitle", ImportTableTitle); ImportSource = dict.GetPhrase("ImportSource", ImportSource); @@ -402,6 +513,8 @@ public static void Init() ImportTableResult = dict.GetPhrase("ImportTableResult", ImportTableResult); ImportTableErrors = dict.GetPhrase("ImportTableErrors", ImportTableErrors); ImportTableError = dict.GetPhrase("ImportError", ImportTableError); + ImportAllTablesError = dict.GetPhrase("ImportAllTablesError", ImportAllTablesError); + ImportArchiveError = dict.GetPhrase("ImportArchiveError", ImportArchiveError); ExportFileUndefied = dict.GetPhrase("ExportFileUndefied", ExportFileUndefied); ExportDirUndefied = dict.GetPhrase("ExportDirUndefied", ExportDirUndefied); ExportDirNotExists = dict.GetPhrase("ExportDirNotExists", ExportDirNotExists); @@ -474,7 +587,10 @@ public static void Init() } if (Localization.Dictionaries.TryGetValue("ScadaAdmin.FrmImport", out dict)) + { + AllTablesItem = dict.GetPhrase("AllTablesItem", AllTablesItem); ArchiveItem = dict.GetPhrase("ArchiveItem", ArchiveItem); + } if (Localization.Dictionaries.TryGetValue("ScadaAdmin.FrmInCnlProps", out dict)) { @@ -493,7 +609,9 @@ public static void Init() } if (Localization.Dictionaries.TryGetValue("ScadaAdmin.FrmLanguage", out dict)) + { IncorrectLanguage = dict.GetPhrase("IncorrectLanguage", IncorrectLanguage); + } if (Localization.Dictionaries.TryGetValue("ScadaAdmin.FrmMain", out dict)) { @@ -546,6 +664,12 @@ public static void Init() ClearTableConfirm = dict.GetPhrase("ClearTableConfirm", ClearTableConfirm); } + if (Localization.Dictionaries.TryGetValue("ScadaAdmin.ServersSettings", out dict)) + { + LoadServersSettingsError = dict.GetPhrase("LoadServersSettingsError", LoadServersSettingsError); + SaveServersSettingsError = dict.GetPhrase("SaveServersSettingsError", SaveServersSettingsError); + } + if (Localization.Dictionaries.TryGetValue("ScadaAdmin.Tables", out dict)) { UpdateDataError = dict.GetPhrase("UpdateDataError", UpdateDataError); @@ -562,6 +686,33 @@ public static void Init() GetInCnlNumsError = dict.GetPhrase("GetInCnlNumsError", GetInCnlNumsError); GetCtrlCnlNumsError = dict.GetPhrase("GetCtrlCnlNumsError", GetCtrlCnlNumsError); } + + if (Localization.Dictionaries.TryGetValue("ScadaAdmin.Remote", out dict)) + { + ChooseConfigDir = dict.GetPhrase("ChooseConfigDir", ChooseConfigDir); + ConfigDirRequired = dict.GetPhrase("ConfigDirRequired", ConfigDirRequired); + ConfigArcRequired = dict.GetPhrase("ConfigArcRequired", ConfigArcRequired); + } + + if (Localization.Dictionaries.TryGetValue("ScadaAdmin.Remote.CtrlServerConn", out dict)) + { + DeleteConnConfirm = dict.GetPhrase("DeleteConnConfirm", DeleteConnConfirm); + } + + if (Localization.Dictionaries.TryGetValue("ScadaAdmin.Remote.FrmConnSettings", out dict)) + { + EmptyFieldsNotAllowed = dict.GetPhrase("EmptyFieldsNotAllowed", EmptyFieldsNotAllowed); + ConnNameDuplicated = dict.GetPhrase("ConnNameDuplicated", ConnNameDuplicated); + IncorrectSecretKey = dict.GetPhrase("IncorrectSecretKey", IncorrectSecretKey); + } + + if (Localization.Dictionaries.TryGetValue("ScadaAdmin.Remote.FrmServerStatus", out dict)) + { + UndefinedSvcStatus = dict.GetPhrase("UndefinedSvcStatus", UndefinedSvcStatus); + NormalSvcStatus = dict.GetPhrase("NormalSvcStatus", NormalSvcStatus); + StoppedSvcStatus = dict.GetPhrase("StoppedSvcStatus", StoppedSvcStatus); + ErrorSvcStatus = dict.GetPhrase("ErrorSvcStatus", ErrorSvcStatus); + } } } } diff --git a/ScadaAdmin/ScadaAdmin/AppCode/AppUtils.cs b/ScadaAdmin/ScadaAdmin/AppCode/AppUtils.cs index 305560c7a..7232183fe 100644 --- a/ScadaAdmin/ScadaAdmin/AppCode/AppUtils.cs +++ b/ScadaAdmin/ScadaAdmin/AppCode/AppUtils.cs @@ -1,5 +1,5 @@ /* - * Copyright 2016 Mikhail Shiryaev + * Copyright 2018 Mikhail Shiryaev * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -20,11 +20,12 @@ * * Author : Mikhail Shiryaev * Created : 2010 - * Modified : 2016 + * Modified : 2018 */ using Scada; using Scada.UI; +using System.IO; using Utils; namespace ScadaAdmin @@ -97,5 +98,15 @@ public static bool ValidateStr(string val, int maxLen, out string errMsg) return false; } } + + + /// + /// Вывести в файл заголовок с подчёркиванием + /// + public static void WriteTitle(StreamWriter writer, string title) + { + writer.WriteLine(title); + writer.WriteLine(new string('-', title.Length)); + } } } diff --git a/ScadaAdmin/ScadaAdmin/AppCode/DownloadUpload.cs b/ScadaAdmin/ScadaAdmin/AppCode/DownloadUpload.cs new file mode 100644 index 000000000..718bde63c --- /dev/null +++ b/ScadaAdmin/ScadaAdmin/AppCode/DownloadUpload.cs @@ -0,0 +1,437 @@ +/* + * Copyright 2018 Mikhail Shiryaev + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * + * Product : Rapid SCADA + * Module : SCADA-Administrator + * Summary : Downloading and uploading configuration + * + * Author : Mikhail Shiryaev + * Created : 2018 + * Modified : 2018 + */ + +using Ionic.Zip; +using Scada; +using ScadaAdmin.AgentSvcRef; +using System; +using System.Collections.Generic; +using System.IO; +using System.ServiceModel; +using System.Text; + +namespace ScadaAdmin +{ + /// + /// Downloading and uploading configuration + /// Скачивание и передача конфигурации + /// + internal static class DownloadUpload + { + /// + /// Исключаемые пути файлов, специфичные для экземпляра системы + /// + private static readonly RelPath[] ExcludedPaths; + + + /// + /// Статический конструктор + /// + static DownloadUpload() + { + ExcludedPaths = new RelPath[] + { + new RelPath() { ConfigPart = ConfigParts.Communicator, AppFolder = AppFolder.Config, Path = "*_Reg.xml" }, + new RelPath() { ConfigPart = ConfigParts.Communicator, AppFolder = AppFolder.Config, Path = "CompCode.txt" }, + new RelPath() { ConfigPart = ConfigParts.Server, AppFolder = AppFolder.Config, Path = "*_Reg.xml" }, + new RelPath() { ConfigPart = ConfigParts.Server, AppFolder = AppFolder.Config, Path = "CompCode.txt" }, + new RelPath() { ConfigPart = ConfigParts.Webstation, AppFolder = AppFolder.Config, Path = "*_Reg.xml" }, + new RelPath() { ConfigPart = ConfigParts.Webstation, AppFolder = AppFolder.Storage, Path = "" }, + }; + } + + + /// + /// Создать вектор инициализации на освнове ид. сессии + /// + private static byte[] CreateIV(long sessionID) + { + byte[] iv = new byte[ScadaUtils.IVSize]; + byte[] sessBuf = BitConverter.GetBytes(sessionID); + int sessBufLen = sessBuf.Length; + + for (int i = 0; i < ScadaUtils.IVSize; i++) + { + iv[i] = sessBuf[i % sessBufLen]; + } + + return iv; + } + + /// + /// Сформировать адрес для подключения к Агенту + /// + private static EndpointAddress GetEpAddress(string host, int port) + { + return new EndpointAddress( + string.Format("http://{0}:{1}/ScadaAgent/ScadaAgentSvc/", host, port)); + } + + /// + /// Соединиться с Агентом + /// + private static void Connect(ServersSettings.ConnectionSettings connectionSettings, + StreamWriter writer, out AgentSvcClient client, out long sessionID) + { + // настройка соединения + client = new AgentSvcClient(); + client.Endpoint.Address = GetEpAddress(connectionSettings.Host, connectionSettings.Port); + + // создание сессии + if (client.CreateSession(out sessionID)) + writer?.WriteLine(AppPhrases.SessionCreated, sessionID); + else + throw new ScadaException(AppPhrases.UnableCreateSession); + + // вход в систему + string encryptedPassword = ScadaUtils.Encrypt(connectionSettings.Password, + connectionSettings.SecretKey, CreateIV(sessionID)); + + if (client.Login(out string errMsg, sessionID, connectionSettings.Username, + encryptedPassword, connectionSettings.ScadaInstance)) + writer?.WriteLine(AppPhrases.LoggedOn); + else + throw new ScadaException(string.Format(AppPhrases.UnableLogin, errMsg)); + } + + /// + /// Упаковать конфигурацию во временный файл + /// + private static void PackConfig(string srcDir, List selectedFiles, + out string outFileName, out ConfigParts configParts) + { + srcDir = ScadaUtils.NormalDir(srcDir); + int srcDirLen = srcDir.Length; + outFileName = srcDir + "upload-config_" + + DateTime.Now.ToString("yyyy-MM-dd_HH-mm-ss") + ".zip"; + configParts = ConfigParts.None; + + using (ZipFile zipFile = new ZipFile(outFileName)) + { + foreach (string relPath in selectedFiles) + { + string path = srcDir + relPath; + configParts = configParts | GetConfigPart(relPath); + + if (Directory.Exists(path)) // путь является директорией + { + string[] filesInDir = Directory.GetFiles(path, "*", SearchOption.AllDirectories); + foreach (string fileName in filesInDir) + { + if (Path.GetExtension(fileName) != ".bak") + { + string dirInArc = Path.GetDirectoryName(fileName.Substring(srcDirLen)) + .Replace('\\', '/'); + zipFile.AddFile(fileName, dirInArc); + } + } + } + else if (File.Exists(path)) + { + string dirInArc = Path.GetDirectoryName(relPath).Replace('\\', '/'); + zipFile.AddFile(path, dirInArc); + } + } + + zipFile.Save(); + } + } + + /// + /// Получить часть конфигурации, которая соответствует пути + /// + private static ConfigParts GetConfigPart(string relPath) + { + if (relPath.StartsWith("BaseDAT", StringComparison.Ordinal)) + return ConfigParts.Base; + else if (relPath.StartsWith("Interface", StringComparison.Ordinal)) + return ConfigParts.Interface; + else if (relPath.StartsWith("ScadaComm", StringComparison.Ordinal)) + return ConfigParts.Communicator; + else if (relPath.StartsWith("ScadaServer", StringComparison.Ordinal)) + return ConfigParts.Server; + else if (relPath.StartsWith("ScadaWeb", StringComparison.Ordinal)) + return ConfigParts.Webstation; + else + return ConfigParts.None; + } + + /// + /// Получить части конфигурации, которые содержатся в архиве + /// + private static ConfigParts GetConfigParts(string arcFileName) + { + ConfigParts configParts = ConfigParts.None; + + using (ZipFile zipFile = new ZipFile(arcFileName)) + { + foreach (ZipEntry zipEntry in zipFile.Entries) + { + configParts = configParts | GetConfigPart(zipEntry.FileName); + } + } + + return configParts; + } + + + /// + /// Скачать конфигурацию + /// + public static bool DownloadConfig(ServersSettings.ServerSettings serverSettings, + string logFileName, out bool logCreated, out string msg) + { + if (serverSettings == null) + throw new ArgumentNullException("serverSettings"); + if (logFileName == null) + throw new ArgumentNullException("logFileName"); + + logCreated = false; + StreamWriter writer = null; + AgentSvcClient client = null; + + try + { + DateTime t0 = DateTime.UtcNow; + writer = new StreamWriter(logFileName, false, Encoding.UTF8); + logCreated = true; + + AppUtils.WriteTitle(writer, + string.Format(AppPhrases.DownloadTitle, DateTime.Now.ToString("G", Localization.Culture))); + writer.WriteLine(AppPhrases.ConnectionName, serverSettings.Connection.Name); + writer.WriteLine(); + + // соединение с Агентом + Connect(serverSettings.Connection, writer, out client, out long sessionID); + + // скачивание конфигурации + ServersSettings.DownloadSettings downloadSettings = serverSettings.Download; + ConfigOptions configOptions = new ConfigOptions() { ConfigParts = ConfigParts.All }; + + if (!downloadSettings.IncludeSpecificFiles) + configOptions.ExcludedPaths = ExcludedPaths; + + Stream downloadStream = client.DownloadConfig(sessionID, configOptions); + + if (downloadStream == null) + throw new ScadaException(AppPhrases.DownloadDataEmpty); + + if (downloadSettings.SaveToDir) + { + // сохранение в директорию + string destDir = downloadSettings.DestDir; + Directory.CreateDirectory(destDir); + string tempFileName = destDir + "download-config_" + + DateTime.Now.ToString("yyyy-MM-dd_HH-mm-ss") + ".zip"; + + try + { + // сохранение во временный файл, т.к. распаковка из MemoryStream не работает + using (FileStream destStream = File.Create(tempFileName)) + { + downloadStream.CopyTo(destStream); + } + + // распаковка + using (ZipFile zipFile = ZipFile.Read(tempFileName)) + { + foreach (ZipEntry zipEntry in zipFile) + { + zipEntry.Extract(destDir, ExtractExistingFileAction.OverwriteSilently); + } + } + } + finally + { + try { File.Delete(tempFileName); } + catch { } + } + } + else + { + // сохранение в файл + string destFile = downloadSettings.DestFile; + Directory.CreateDirectory(Path.GetDirectoryName(destFile)); + + using (FileStream destStream = File.Create(destFile)) + { + downloadStream.CopyTo(destStream); + } + } + + downloadStream.Close(); + msg = string.Format(AppPhrases.DownloadSuccessful, (int)(DateTime.UtcNow - t0).TotalSeconds); + writer.WriteLine(msg); + return true; + } + catch (Exception ex) + { + msg = AppPhrases.DownloadError + ":\r\n" + ex.Message; + + try { writer?.WriteLine(msg); } + catch { } + + return false; + } + finally + { + try { writer?.Close(); } + catch { } + + try { client?.Close(); } + catch { } + } + } + + /// + /// Передать конфигурацию + /// + public static bool UploadConfig(ServersSettings.ServerSettings serverSettings, + string logFileName, out bool logCreated, out string msg) + { + if (serverSettings == null) + throw new ArgumentNullException("serverSettings"); + if (logFileName == null) + throw new ArgumentNullException("logFileName"); + + logCreated = false; + StreamWriter writer = null; + AgentSvcClient client = null; + + try + { + DateTime t0 = DateTime.UtcNow; + + writer = new StreamWriter(logFileName, false, Encoding.UTF8); + logCreated = true; + + AppUtils.WriteTitle(writer, + string.Format(AppPhrases.UploadTitle, DateTime.Now.ToString("G", Localization.Culture))); + writer.WriteLine(AppPhrases.ConnectionName, serverSettings.Connection.Name); + writer.WriteLine(); + + // соединение с Агентом + Connect(serverSettings.Connection, writer, out client, out long sessionID); + + // подготовка конфигурации для передачи + ServersSettings.UploadSettings uploadSettings = serverSettings.Upload; + ConfigOptions configOptions = new ConfigOptions(); + ConfigParts configParts; + string outFileName; + bool deleteOutFile; + + if (uploadSettings.GetFromDir) + { + PackConfig(uploadSettings.SrcDir, uploadSettings.SelectedFiles, + out outFileName, out configParts); + configOptions.ConfigParts = configParts; + deleteOutFile = true; + } + else + { + outFileName = uploadSettings.SrcFile; + configOptions.ConfigParts = configParts = GetConfigParts(outFileName); + deleteOutFile = false; + } + + if (configOptions.ConfigParts == ConfigParts.None) + throw new ScadaException(AppPhrases.NoConfigInSrc); + + if (!uploadSettings.ClearSpecificFiles) + configOptions.ExcludedPaths = ExcludedPaths; + + // передача конфигурации + using (Stream outStream = File.Open(outFileName, FileMode.Open, FileAccess.Read, FileShare.Read)) + { + client.UploadConfig(configOptions, sessionID, outStream); + writer.WriteLine(AppPhrases.ConfigUploaded); + } + + // удаление временного файла + if (deleteOutFile) + File.Delete(outFileName); + + // перезапуск служб на удалённом сервере + if (configParts.HasFlag(ConfigParts.Base) || configParts.HasFlag(ConfigParts.Server)) + { + if (client.ControlService(sessionID, ServiceApp.Server, ServiceCommand.Restart)) + writer.WriteLine(AppPhrases.ServerRestarted); + else + writer.WriteLine(AppPhrases.UnableRestartServer); + } + + if (configParts.HasFlag(ConfigParts.Base) || configParts.HasFlag(ConfigParts.Communicator)) + { + if (client.ControlService(sessionID, ServiceApp.Communicator, ServiceCommand.Restart)) + writer.WriteLine(AppPhrases.CommRestarted); + else + writer.WriteLine(AppPhrases.UnableRestartComm); + } + + msg = string.Format(AppPhrases.UploadSuccessful, (int)(DateTime.UtcNow - t0).TotalSeconds); + writer.WriteLine(msg); + return true; + } + catch (Exception ex) + { + msg = AppPhrases.UploadError + ":\r\n" + ex.Message; + + try { writer?.WriteLine(msg); } + catch { } + + return false; + } + finally + { + try { writer?.Close(); } + catch { } + + try { client?.Close(); } + catch { } + } + } + + /// + /// Соединиться с Агентом + /// + public static bool Connect(ServersSettings.ConnectionSettings connectionSettings, + out AgentSvcClient client, out long sessionID, out string errMsg) + { + try + { + Connect(connectionSettings, null, out client, out sessionID); + errMsg = ""; + return true; + } + catch (Exception ex) + { + client = null; + sessionID = 0; + errMsg = AppPhrases.ConnectAgentError + ":\r\n" + ex.Message; + return false; + } + } + } +} diff --git a/ScadaAdmin/ScadaAdmin/AppCode/ImportExport.cs b/ScadaAdmin/ScadaAdmin/AppCode/ImportExport.cs index 392e3cbca..a10887312 100644 --- a/ScadaAdmin/ScadaAdmin/AppCode/ImportExport.cs +++ b/ScadaAdmin/ScadaAdmin/AppCode/ImportExport.cs @@ -48,21 +48,12 @@ internal static class ImportExport private const int ZipDelay = 200; - /// - /// Вывести в журнал заголовок с подчёркиванием - /// - private static void WriteTitle(StreamWriter writer, string title) - { - writer.WriteLine(title); - writer.WriteLine(new string('-', title.Length)); - } - /// /// Вывести в журнал столбцы таблицы /// private static void WriteColumns(StreamWriter writer, DataTable dataTable, string subTitle) { - WriteTitle(writer, subTitle); + AppUtils.WriteTitle(writer, subTitle); if (dataTable.Columns.Count > 0) { foreach (DataColumn column in dataTable.Columns) @@ -103,7 +94,7 @@ private static void ImportTable(DataTable srcTable, Tables.TableInfo destTableIn if (writer != null) { writer.WriteLine(); - WriteTitle(writer, string.Format(AppPhrases.ImportTableTitle, + AppUtils.WriteTitle(writer, string.Format(AppPhrases.ImportTableTitle, destTableInfo.Name + " (" + destTableInfo.Header + ")")); writer.WriteLine(); WriteColumns(writer, srcTable, AppPhrases.SrcTableColumns); @@ -118,7 +109,8 @@ private static void ImportTable(DataTable srcTable, Tables.TableInfo destTableIn if (tryToUpdate) { - int newID = (int)srcRow[idColName] + shiftID; + object curID = srcRow[idColName]; + object newID = curID is int ? (int)curID + shiftID : curID; int rowInd = destTable.DefaultView.Find(newID); // таблица отсортирована по ключу if (rowInd >= 0) destRow = destTable.DefaultView[rowInd].Row; @@ -170,13 +162,13 @@ private static void ImportTable(DataTable srcTable, Tables.TableInfo destTableIn // вывод результата и ошибок в журнал импорта if (writer != null) { - WriteTitle(writer, AppPhrases.ImportTableResult); + AppUtils.WriteTitle(writer, AppPhrases.ImportTableResult); writer.WriteLine(msg); if (errRowCnt > 0) { writer.WriteLine(); - WriteTitle(writer, AppPhrases.ImportTableErrors); + AppUtils.WriteTitle(writer, AppPhrases.ImportTableErrors); foreach (DataRow row in errRows) { @@ -196,29 +188,30 @@ public static bool ImportTable(string srcFileName, Tables.TableInfo destTableInf int minID, int maxID, int newMinID, string logFileName, out bool logCreated, out string msg) { // проверка аргументов метода - if (string.IsNullOrWhiteSpace(srcFileName)) - throw new ArgumentException(AppPhrases.ImportFileUndefied); - - if (!File.Exists(srcFileName)) - throw new FileNotFoundException(AppPhrases.ImportFileNotExist); + if (srcFileName == null) + throw new ArgumentNullException("srcFileName"); if (destTableInfo == null) throw new ArgumentNullException("destTableInfo"); + if (logFileName == null) + throw new ArgumentNullException("logFileName"); + logCreated = false; StreamWriter writer = null; try { // создание журнала импорта и вывод параметров импорта - if (!string.IsNullOrEmpty(logFileName)) - { - writer = new StreamWriter(logFileName, false, Encoding.UTF8); - logCreated = true; + writer = new StreamWriter(logFileName, false, Encoding.UTF8); + logCreated = true; + AppUtils.WriteTitle(writer, DateTime.Now.ToString("G", Localization.Culture) + " " + + AppPhrases.ImportTitle); + writer.WriteLine(AppPhrases.ImportSource + srcFileName); - WriteTitle(writer, DateTime.Now.ToString("G", Localization.Culture) + " " + AppPhrases.ImportTitle); - writer.WriteLine(AppPhrases.ImportSource + srcFileName); - } + // проверка существования импортируемого файла + if (!File.Exists(srcFileName)) + throw new FileNotFoundException(AppPhrases.ImportFileNotExist); // загрузка импортируемой таблицы в формате DAT BaseAdapter baseAdapter = new BaseAdapter(); @@ -265,42 +258,144 @@ public static bool ImportTable(string srcFileName, Tables.TableInfo destTableInf } /// - /// Импортировать архив базы конфигурации (патч) + /// Импортировать все таблицы базы конфигурации из заданной директории /// - public static bool ImportArchive(string srcFileName, List destTableInfoList, + public static bool ImportAllTables(string srcDir, List destTableInfoList, string logFileName, out bool logCreated, out string msg) { // проверка аргументов метода - if (string.IsNullOrWhiteSpace(srcFileName)) - throw new ArgumentException(AppPhrases.ImportFileUndefied); - - if (!File.Exists(srcFileName)) - throw new FileNotFoundException(AppPhrases.ImportFileNotExist); + if (srcDir == null) + throw new ArgumentNullException("srcDir"); if (destTableInfoList == null) throw new ArgumentNullException("destTableInfoList"); + if (logFileName == null) + throw new ArgumentNullException("logFileName"); + logCreated = false; StreamWriter writer = null; try { // создание журнала импорта и вывод параметров импорта - if (!string.IsNullOrEmpty(logFileName)) + writer = new StreamWriter(logFileName, false, Encoding.UTF8); + logCreated = true; + AppUtils.WriteTitle(writer, DateTime.Now.ToString("G", Localization.Culture) + " " + + AppPhrases.ImportTitle); + writer.WriteLine(AppPhrases.ImportSource + srcDir); + + // проверка существования импортируемой директории + if (!Directory.Exists(srcDir)) + throw new DirectoryNotFoundException(AppPhrases.ImportDirNotExist); + + // импорт таблиц, файлы которых существуют в заданной директории + int totalUpdRowCnt = 0; + int totalErrRowCnt = 0; + int updRowCnt; + int errRowCnt; + srcDir = ScadaUtils.NormalDir(srcDir); + + foreach (Tables.TableInfo destTableInfo in destTableInfoList) { - writer = new StreamWriter(logFileName, false, Encoding.UTF8); - logCreated = true; + string srcFileName = srcDir + destTableInfo.FileName; + + if (File.Exists(srcFileName)) + { + // загрузка импортируемой таблицы в формате DAT + BaseAdapter baseAdapter = new BaseAdapter(); + DataTable srcTable = new DataTable(); + baseAdapter.FileName = srcFileName; - WriteTitle(writer, DateTime.Now.ToString("G", Localization.Culture) + " " + AppPhrases.ImportTitle); - writer.WriteLine(AppPhrases.ImportSource + srcFileName); + try + { + baseAdapter.Fill(srcTable, true); + } + catch (Exception ex) + { + throw new Exception(AppPhrases.LoadTableError + ":\r\n" + ex.Message); + } + + // импорт таблицы + string s; + ImportTable(srcTable, destTableInfo, 0, writer, out updRowCnt, out errRowCnt, out s); + totalUpdRowCnt += updRowCnt; + totalErrRowCnt += errRowCnt; + } } + msg = totalErrRowCnt == 0 ? string.Format(AppPhrases.ImportCompleted, totalUpdRowCnt) : + string.Format(AppPhrases.ImportCompletedWithErr, totalUpdRowCnt, totalErrRowCnt); + + // вывод результата в журнал импорта + writer.WriteLine(); + AppUtils.WriteTitle(writer, AppPhrases.ImportResult); + writer.WriteLine(msg); + + if (totalUpdRowCnt > 0) + msg += AppPhrases.RefreshRequired; + return totalErrRowCnt == 0; + } + catch (Exception ex) + { + msg = AppPhrases.ImportAllTablesError + ":\r\n" + ex.Message; + try { if (logCreated) writer.WriteLine(msg); } + catch { } + return false; + } + finally + { + try { writer.Close(); } + catch { } + } + } + + /// + /// Импортировать архив базы конфигурации (патч) + /// + public static bool ImportArchive(string srcFileName, List destTableInfoList, + string logFileName, out bool logCreated, out string msg) + { + // проверка аргументов метода + if (srcFileName == null) + throw new ArgumentNullException("srcFileName"); + + if (destTableInfoList == null) + throw new ArgumentNullException("destTableInfoList"); + + if (logFileName == null) + throw new ArgumentNullException("logFileName"); + + logCreated = false; + StreamWriter writer = null; + + try + { + // создание журнала импорта и вывод параметров импорта + writer = new StreamWriter(logFileName, false, Encoding.UTF8); + logCreated = true; + AppUtils.WriteTitle(writer, DateTime.Now.ToString("G", Localization.Culture) + " " + + AppPhrases.ImportTitle); + writer.WriteLine(AppPhrases.ImportSource + srcFileName); + + // проверка существования импортируемого файла + if (!File.Exists(srcFileName)) + throw new FileNotFoundException(AppPhrases.ImportFileNotExist); + using (ZipFile zipFile = ZipFile.Read(srcFileName)) { // получение словаря всех файлов архива с именами в нижнем регистре Dictionary zipEntries = new Dictionary(zipFile.Count); foreach (ZipEntry zipEntry in zipFile) - zipEntries.Add(zipEntry.FileName.ToLowerInvariant(), zipEntry); + { + string fileName = zipEntry.FileName.ToLowerInvariant(); + if (fileName.StartsWith("basedat/", StringComparison.Ordinal) || + fileName.StartsWith("basedat\\", StringComparison.Ordinal)) + { + fileName = fileName.Substring("basedat/".Length); + zipEntries.Add(fileName, zipEntry); + } + } // импорт таблиц из тех, которые содержатся в архиве int totalUpdRowCnt = 0; @@ -346,12 +441,9 @@ public static bool ImportArchive(string srcFileName, List dest string.Format(AppPhrases.ImportCompletedWithErr, totalUpdRowCnt, totalErrRowCnt); // вывод результата в журнал импорта - if (logCreated) - { - writer.WriteLine(); - WriteTitle(writer, AppPhrases.ImportResult); - writer.WriteLine(msg); - } + writer.WriteLine(); + AppUtils.WriteTitle(writer, AppPhrases.ImportResult); + writer.WriteLine(msg); if (totalUpdRowCnt > 0) msg += AppPhrases.RefreshRequired; diff --git a/ScadaAdmin/ScadaAdmin/AppCode/ServersSettings.cs b/ScadaAdmin/ScadaAdmin/AppCode/ServersSettings.cs new file mode 100644 index 000000000..e2404fcb6 --- /dev/null +++ b/ScadaAdmin/ScadaAdmin/AppCode/ServersSettings.cs @@ -0,0 +1,485 @@ +/* + * Copyright 2018 Mikhail Shiryaev + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * + * Product : Rapid SCADA + * Module : SCADA-Administrator + * Summary : Settings of interaction with remote servers + * + * Author : Mikhail Shiryaev + * Created : 2018 + * Modified : 2018 + */ + +using Scada; +using System; +using System.Collections.Generic; +using System.IO; +using System.Xml; + +namespace ScadaAdmin +{ + /// + /// Settings of interaction with remote servers + /// Настройки взаимодействия с удалёнными серверами + /// + public class ServersSettings + { + /// + /// Директория конфигурации по умолчанию + /// + private const string DefConfigDir = @"C:\SCADA\"; + /// + /// Архив конфигурации по умолчанию + /// + private const string DefConfigArc = @"C:\SCADA\config.zip"; + + /// + /// Remote server connection settings + /// Настройки подключения к удалённому серверу + /// + public class ConnectionSettings + { + /// + /// Конструктор + /// + public ConnectionSettings() + { + SetToDefault(); + } + + /// + /// Получить или установить наименование + /// + public string Name { get; set; } + /// + /// Получить или установить имя компьютера или IP-адрес + /// + public string Host { get; set; } + /// + /// Получить или установить TCP-порт + /// + public int Port { get; set; } + /// + /// Получить или установить имя пользователя + /// + public string Username { get; set; } + /// + /// Получить или установить пароль пользователя + /// + public string Password { get; set; } + /// + /// Получить или установить наименования экземпляра системы + /// + public string ScadaInstance { get; set; } + /// + /// Получить или установить секретный ключ + /// + public byte[] SecretKey { get; set; } + + /// + /// Установить настройки по умолчанию + /// + private void SetToDefault() + { + Name = ""; + Host = ""; + Port = 10002; + Username = "admin"; + Password = ""; + ScadaInstance = "Default"; + SecretKey = new byte[0]; + } + /// + /// Загрузить настройки из XML-узла + /// + public void LoadFromXml(XmlNode xmlNode) + { + if (xmlNode == null) + throw new ArgumentNullException("xmlNode"); + + Name = xmlNode.GetChildAsString("Name"); + Host = xmlNode.GetChildAsString("Host"); + Port = xmlNode.GetChildAsInt("Port", 10002); + Username = xmlNode.GetChildAsString("Username", "admin"); + Password = xmlNode.GetChildAsString("Password"); + ScadaInstance = xmlNode.GetChildAsString("ScadaInstance"); + SecretKey = ScadaUtils.HexToBytes(xmlNode.GetChildAsString("SecretKey")); + } + /// + /// Сохранить настройки в XML-узле + /// + public void SaveToXml(XmlElement xmlElem) + { + if (xmlElem == null) + throw new ArgumentNullException("xmlElem"); + + xmlElem.AppendElem("Name", Name); + xmlElem.AppendElem("Host", Host); + xmlElem.AppendElem("Port", Port); + xmlElem.AppendElem("Username", Username); + xmlElem.AppendElem("Password", Password); + xmlElem.AppendElem("ScadaInstance", ScadaInstance); + xmlElem.AppendElem("SecretKey", ScadaUtils.BytesToHex(SecretKey)); + } + } + + /// + /// Settings of downloading configuration + /// Настройки скачивания конфигурации + /// + public class DownloadSettings + { + /// + /// Конструктор + /// + public DownloadSettings() + { + SetToDefault(); + } + + /// + /// Получить или установить признак сохранения в директорию + /// + public bool SaveToDir { get; set; } + /// + /// Получить или установить директорию для сохранения конфигурации + /// + public string DestDir { get; set; } + /// + /// Получить или установить имя файла архива для сохранения конфигурации + /// + public string DestFile { get; set; } + /// + /// Получить или установить признак скачивания файлов, специфичных для экземпляра системы + /// + public bool IncludeSpecificFiles { get; set; } + /// + /// Получить или установить признак запуска импорта базы конфигурации после скачивания + /// + public bool ImportBase { get; set; } + + /// + /// Установить настройки по умолчанию + /// + private void SetToDefault() + { + SaveToDir = true; + DestDir = DefConfigDir; + DestFile = DefConfigArc; + IncludeSpecificFiles = true; + ImportBase = true; + } + /// + /// Загрузить настройки из XML-узла + /// + public void LoadFromXml(XmlNode xmlNode) + { + if (xmlNode == null) + throw new ArgumentNullException("xmlNode"); + + SaveToDir = xmlNode.GetChildAsBool("SaveToDir", true); + DestDir = ScadaUtils.NormalDir(xmlNode.GetChildAsString("DestDir", DefConfigDir)); + DestFile = xmlNode.GetChildAsString("DestFile", DefConfigArc); + IncludeSpecificFiles = xmlNode.GetChildAsBool("IncludeSpecificFiles", true); + ImportBase = xmlNode.GetChildAsBool("ImportBase", true); + } + /// + /// Сохранить настройки в XML-узле + /// + public void SaveToXml(XmlElement xmlElem) + { + if (xmlElem == null) + throw new ArgumentNullException("xmlElem"); + + xmlElem.AppendElem("SaveToDir", SaveToDir); + xmlElem.AppendElem("DestDir", DestDir); + xmlElem.AppendElem("DestFile", DestFile); + xmlElem.AppendElem("IncludeSpecificFiles", IncludeSpecificFiles); + xmlElem.AppendElem("ImportBase", ImportBase); + } + } + + /// + /// Settings of uploading configuration + /// Настройки передачи конфигурации + /// + public class UploadSettings + { + /// + /// Конструктор + /// + public UploadSettings() + { + SelectedFiles = new List(); + SetToDefault(); + } + + /// + /// Получить или установить признак передачи из директории + /// + public bool GetFromDir { get; set; } + /// + /// Получить или установить директорию конфигурации + /// + public string SrcDir { get; set; } + /// + /// Получить выбранные для передачи файлы конфигурации + /// + public List SelectedFiles { get; private set; } + /// + /// Получить или установить имя файла архива для передачи + /// + public string SrcFile { get; set; } + /// + /// Получить или установить признак очистки файлов, специфичных для экземпляра системы + /// + public bool ClearSpecificFiles { get; set; } + + /// + /// Установить настройки по умолчанию + /// + private void SetToDefault() + { + GetFromDir = true; + SrcDir = DefConfigDir; + SelectedFiles.Clear(); + SrcFile = DefConfigArc; + ClearSpecificFiles = true; + } + /// + /// Загрузить настройки из XML-узла + /// + public void LoadFromXml(XmlNode xmlNode) + { + if (xmlNode == null) + throw new ArgumentNullException("xmlNode"); + + GetFromDir = xmlNode.GetChildAsBool("GetFromDir", true); + SrcDir = ScadaUtils.NormalDir(xmlNode.GetChildAsString("SrcDir", DefConfigDir)); + + SelectedFiles.Clear(); + XmlNode selectedFilesNode = xmlNode.SelectSingleNode("SelectedFiles"); + if (selectedFilesNode != null) + { + XmlNodeList pathNodeList = selectedFilesNode.SelectNodes("Path"); + foreach (XmlNode pathNode in pathNodeList) + { + SelectedFiles.Add(pathNode.InnerText); + } + } + + SrcFile = xmlNode.GetChildAsString("SrcFile", DefConfigArc); + ClearSpecificFiles = xmlNode.GetChildAsBool("ClearSpecificFiles", true); + } + /// + /// Сохранить настройки в XML-узле + /// + public void SaveToXml(XmlElement xmlElem) + { + if (xmlElem == null) + throw new ArgumentNullException("xmlElem"); + + xmlElem.AppendElem("GetFromDir", GetFromDir); + xmlElem.AppendElem("SrcDir", SrcDir); + + XmlElement selectedFilesElem = xmlElem.AppendElem("SelectedFiles"); + foreach (string path in SelectedFiles) + { + selectedFilesElem.AppendElem("Path", path); + } + + xmlElem.AppendElem("SrcFile", SrcFile); + xmlElem.AppendElem("ClearSpecificFiles", ClearSpecificFiles); + } + } + + /// + /// Settings of interaction with a remote server + /// Настройки взаимодействия с удалённым сервером + /// + public class ServerSettings + { + /// + /// Конструктор + /// + public ServerSettings() + { + Connection = new ConnectionSettings(); + Download = new DownloadSettings(); + Upload = new UploadSettings(); + } + + /// + /// Получить настройки подключения к серверу + /// + public ConnectionSettings Connection { get; private set; } + /// + /// Получить настройки скачивания конфигурации + /// + public DownloadSettings Download { get; private set; } + /// + /// Получить настройки передачи конфигурации + /// + public UploadSettings Upload { get; private set; } + + /// + /// Загрузить настройки из XML-узла + /// + public void LoadFromXml(XmlNode xmlNode) + { + if (xmlNode == null) + throw new ArgumentNullException("xmlNode"); + + XmlNode connectionNode = xmlNode.SelectSingleNode("Connection"); + if (connectionNode != null) + Connection.LoadFromXml(connectionNode); + + XmlNode downloadNode = xmlNode.SelectSingleNode("Download"); + if (downloadNode != null) + Download.LoadFromXml(downloadNode); + + XmlNode uploadNode = xmlNode.SelectSingleNode("Upload"); + if (uploadNode != null) + Upload.LoadFromXml(uploadNode); + } + /// + /// Сохранить настройки в XML-узле + /// + public void SaveToXml(XmlElement xmlElem) + { + if (xmlElem == null) + throw new ArgumentNullException("xmlElem"); + + Connection.SaveToXml(xmlElem.AppendElem("Connection")); + Download.SaveToXml(xmlElem.AppendElem("Download")); + Upload.SaveToXml(xmlElem.AppendElem("Upload")); + } + /// + /// Получить строковое представление объекта + /// + public override string ToString() + { + return Connection.Name; + } + } + + + /// + /// Имя файла настроек по умолчанию + /// + public const string DefFileName = "RemoteServers.xml"; + + + /// + /// Конструктор + /// + public ServersSettings() + { + Servers = new SortedList(); + } + + + /// + /// Получить список настроек взаимодействия с серверами, ключ - наименование подключения + /// + public SortedList Servers { get; private set; } + + + /// + /// Загрузить настройки из файла + /// + public bool Load(string fileName, out string errMsg) + { + // установка значений по умолчанию + Servers.Clear(); + + try + { + if (!File.Exists(fileName)) + throw new FileNotFoundException(string.Format(CommonPhrases.NamedFileNotFound, fileName)); + + XmlDocument xmlDoc = new XmlDocument(); + xmlDoc.Load(fileName); + + XmlNodeList remoteServerNodeList = xmlDoc.DocumentElement.SelectNodes("RemoteServer"); + foreach (XmlNode remoteServerNode in remoteServerNodeList) + { + ServerSettings serverSettings = new ServerSettings(); + serverSettings.LoadFromXml(remoteServerNode); + Servers[serverSettings.Connection.Name] = serverSettings; + } + + errMsg = ""; + return true; + } + catch (Exception ex) + { + errMsg = AppPhrases.LoadServersSettingsError + ":" + Environment.NewLine + ex.Message; + return false; + } + } + + /// + /// Сохранить настройки в файле + /// + public bool Save(string fileName, out string errMsg) + { + try + { + XmlDocument xmlDoc = new XmlDocument(); + + XmlDeclaration xmlDecl = xmlDoc.CreateXmlDeclaration("1.0", "utf-8", null); + xmlDoc.AppendChild(xmlDecl); + + XmlElement rootElem = xmlDoc.CreateElement("RemoteServers"); + xmlDoc.AppendChild(rootElem); + + foreach (ServerSettings serverSettings in Servers.Values) + { + serverSettings.SaveToXml(rootElem.AppendElem("RemoteServer")); + } + + string bakName = fileName + ".bak"; + File.Copy(fileName, bakName, true); + xmlDoc.Save(fileName); + + errMsg = ""; + return true; + } + catch (Exception ex) + { + errMsg = AppPhrases.SaveServersSettingsError + ":" + Environment.NewLine + ex.Message; + return false; + } + } + + /// + /// Получить наименования существующих подключений + /// + public HashSet GetExistingNames(string exceptName = null) + { + HashSet existingNames = new HashSet(); + + foreach (ServerSettings serverSettings in Servers.Values) + { + if (!string.Equals(serverSettings.Connection.Name, exceptName, StringComparison.Ordinal)) + existingNames.Add(serverSettings.Connection.Name); + } + + return existingNames; + } + } +} diff --git a/ScadaAdmin/ScadaAdmin/AppCode/Settings.cs b/ScadaAdmin/ScadaAdmin/AppCode/Settings.cs index 18cf8e529..fa809facc 100644 --- a/ScadaAdmin/ScadaAdmin/AppCode/Settings.cs +++ b/ScadaAdmin/ScadaAdmin/AppCode/Settings.cs @@ -1,5 +1,5 @@ /* - * Copyright 2016 Mikhail Shiryaev + * Copyright 2018 Mikhail Shiryaev * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -20,7 +20,7 @@ * * Author : Mikhail Shiryaev * Created : 2010 - * Modified : 2016 + * Modified : 2018 */ using System; @@ -125,6 +125,10 @@ public FormState() /// Получить или установить ширину дерева проводника /// public int ExplorerWidth { get; set; } + /// + /// Получить или установить наименование соединения с удалённым сервером + /// + public string ServerConn { get; set; } /// /// Установить состояние главной формы по умолчанию @@ -138,6 +142,7 @@ public void SetToDefault() Height = 0; Maximized = false; ExplorerWidth = 0; + ServerConn = ""; } } @@ -182,7 +187,7 @@ public bool LoadAppSettings(out string errMsg) AppSett.SetToDefault(); // загрузка из файла - string fileName = AppData.ExeDir + AppSettingsFileName; + string fileName = AppData.AppDirs.ConfigDir + AppSettingsFileName; try { @@ -258,7 +263,7 @@ public bool SaveAppSettings(out string errMsg) "Автоматически резервировать базу конфигурации", "Automatically backup the configuration database"); // сохранение в файле - xmlDoc.Save(AppData.ExeDir + AppSettingsFileName); + xmlDoc.Save(AppData.AppDirs.ConfigDir + AppSettingsFileName); errMsg = ""; return true; } @@ -279,7 +284,7 @@ public void LoadFormState() FormSt.SetToDefault(); // загрузка из файла - string fileName = AppData.ExeDir + FormStateFileName; + string fileName = AppData.AppDirs.ConfigDir + FormStateFileName; if (File.Exists(fileName)) { @@ -310,6 +315,8 @@ public void LoadFormState() FormSt.Maximized = bool.Parse(val); else if (nameL == "explorerwidth") FormSt.ExplorerWidth = int.Parse(val); + else if (nameL == "serverconn") + FormSt.ServerConn = val; } catch { @@ -351,9 +358,10 @@ public bool SaveFormState(out string errMsg) rootElem.AppendParamElem("Height", FormSt.Height); rootElem.AppendParamElem("Maximized", FormSt.Maximized); rootElem.AppendParamElem("ExplorerWidth", FormSt.ExplorerWidth); + rootElem.AppendParamElem("ServerConn", FormSt.ServerConn); // сохранение в файле - xmlDoc.Save(AppData.ExeDir + FormStateFileName); + xmlDoc.Save(AppData.AppDirs.ConfigDir + FormStateFileName); errMsg = ""; return true; } diff --git a/ScadaAdmin/ScadaAdmin/AppCode/Tables.cs b/ScadaAdmin/ScadaAdmin/AppCode/Tables.cs index 678f6b4be..d516b81bb 100644 --- a/ScadaAdmin/ScadaAdmin/AppCode/Tables.cs +++ b/ScadaAdmin/ScadaAdmin/AppCode/Tables.cs @@ -48,12 +48,14 @@ public class TableInfo /// /// Конструктор /// - public TableInfo(string name, string header, GetTableDelegate getTable, string idColName) + public TableInfo(string name, string header, GetTableDelegate getTable, string idColName, + bool hasIntID = true) { Name = name; Header = header; GetTable = getTable; IDColName = idColName; + HasIntID = !string.IsNullOrEmpty(idColName) && hasIntID; } /// @@ -82,6 +84,10 @@ public string FileName /// Получить наименование столбца идентификатора, если он числовой и определяется одним столбцом /// public string IDColName { get; private set; } + /// + /// Таблица имеет целочисленный идентификатор + /// + public bool HasIntID { get; private set; } /// /// Получить строковое представление объекта @@ -135,7 +141,7 @@ static Tables() TableInfoList.Add(new TableInfo("Unit", CommonPhrases.UnitTable, GetUnitTable, "UnitID")); TableInfoList.Add(new TableInfo("CmdVal", CommonPhrases.CmdValTable, GetCmdValTable, "CmdValID")); TableInfoList.Add(new TableInfo("Format", CommonPhrases.FormatTable, GetFormatTable, "FormatID")); - TableInfoList.Add(new TableInfo("Formula", CommonPhrases.FormulaTable, GetFormulaTable, "")); + TableInfoList.Add(new TableInfo("Formula", CommonPhrases.FormulaTable, GetFormulaTable, "Name", false)); } @@ -745,8 +751,7 @@ public static void FillTableSchema(DataTable dataTable) { if (dataTable != null) { - string tableName = dataTable.TableName == "User" ? "[User]" : dataTable.TableName; - string sql = "select * from " + tableName; + string sql = "select * from [" + dataTable.TableName + "]"; SqlCeDataAdapter adapter = new SqlCeDataAdapter(sql, AppData.Conn); adapter.ContinueUpdateOnError = true; adapter.FillSchema(dataTable, SchemaType.Source); diff --git a/ScadaAdmin/ScadaAdmin/Config/RemoteServers.xml b/ScadaAdmin/ScadaAdmin/Config/RemoteServers.xml new file mode 100644 index 000000000..ea12ef034 --- /dev/null +++ b/ScadaAdmin/ScadaAdmin/Config/RemoteServers.xml @@ -0,0 +1,28 @@ + + + + + Test + localhost + 10002 + admin + 12345 + Default + 5ABF5A7FD01752A2F1DFD21370B96EA462B0AE5C66A64F8901C9E1E2A06E40F1 + + + true + C:\SCADA3\ + C:\SCADA\config.zip + true + true + + + true + C:\SCADA\ + + C:\SCADA\config.zip + true + + + \ No newline at end of file diff --git a/ScadaAdmin/ScadaAdmin/Config/ScadaAdminConfig.xml b/ScadaAdmin/ScadaAdmin/Config/ScadaAdminConfig.xml new file mode 100644 index 000000000..53cb7c5ad --- /dev/null +++ b/ScadaAdmin/ScadaAdmin/Config/ScadaAdminConfig.xml @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/ScadaAdmin/ScadaAdmin/Connected Services/AgentSvcRef/AgentSvc.wsdl b/ScadaAdmin/ScadaAdmin/Connected Services/AgentSvcRef/AgentSvc.wsdl new file mode 100644 index 000000000..cee4e852c --- /dev/null +++ b/ScadaAdmin/ScadaAdmin/Connected Services/AgentSvcRef/AgentSvc.wsdl @@ -0,0 +1,216 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/ScadaAdmin/ScadaAdmin/Connected Services/AgentSvcRef/Reference.cs b/ScadaAdmin/ScadaAdmin/Connected Services/AgentSvcRef/Reference.cs new file mode 100644 index 000000000..269e3df39 --- /dev/null +++ b/ScadaAdmin/ScadaAdmin/Connected Services/AgentSvcRef/Reference.cs @@ -0,0 +1,387 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// Runtime Version:4.0.30319.42000 +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +namespace ScadaAdmin.AgentSvcRef { + using System.Runtime.Serialization; + using System; + + + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Runtime.Serialization", "4.0.0.0")] + [System.Runtime.Serialization.DataContractAttribute(Name="ServiceApp", Namespace="http://schemas.datacontract.org/2004/07/Scada.Agent")] + public enum ServiceApp : int { + + [System.Runtime.Serialization.EnumMemberAttribute()] + Server = 0, + + [System.Runtime.Serialization.EnumMemberAttribute()] + Communicator = 1, + } + + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Runtime.Serialization", "4.0.0.0")] + [System.Runtime.Serialization.DataContractAttribute(Name="ServiceCommand", Namespace="http://schemas.datacontract.org/2004/07/Scada.Agent")] + public enum ServiceCommand : int { + + [System.Runtime.Serialization.EnumMemberAttribute()] + Start = 0, + + [System.Runtime.Serialization.EnumMemberAttribute()] + Stop = 1, + + [System.Runtime.Serialization.EnumMemberAttribute()] + Restart = 2, + } + + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Runtime.Serialization", "4.0.0.0")] + [System.Runtime.Serialization.DataContractAttribute(Name="ServiceStatus", Namespace="http://schemas.datacontract.org/2004/07/Scada.Agent")] + public enum ServiceStatus : int { + + [System.Runtime.Serialization.EnumMemberAttribute()] + Undefined = 0, + + [System.Runtime.Serialization.EnumMemberAttribute()] + Normal = 1, + + [System.Runtime.Serialization.EnumMemberAttribute()] + Stopped = 2, + + [System.Runtime.Serialization.EnumMemberAttribute()] + Error = 3, + } + + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Runtime.Serialization", "4.0.0.0")] + [System.FlagsAttribute()] + [System.Runtime.Serialization.DataContractAttribute(Name="ConfigParts", Namespace="http://schemas.datacontract.org/2004/07/Scada.Agent")] + public enum ConfigParts : int { + + [System.Runtime.Serialization.EnumMemberAttribute()] + None = 0, + + [System.Runtime.Serialization.EnumMemberAttribute()] + Base = 1, + + [System.Runtime.Serialization.EnumMemberAttribute()] + Interface = 2, + + [System.Runtime.Serialization.EnumMemberAttribute()] + Server = 4, + + [System.Runtime.Serialization.EnumMemberAttribute()] + Communicator = 8, + + [System.Runtime.Serialization.EnumMemberAttribute()] + Webstation = 16, + + [System.Runtime.Serialization.EnumMemberAttribute()] + All = 31, + } + + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Runtime.Serialization", "4.0.0.0")] + [System.Runtime.Serialization.DataContractAttribute(Name="ConfigOptions", Namespace="http://schemas.datacontract.org/2004/07/Scada.Agent")] + [System.SerializableAttribute()] + public partial class ConfigOptions : object, System.Runtime.Serialization.IExtensibleDataObject, System.ComponentModel.INotifyPropertyChanged { + + [System.NonSerializedAttribute()] + private System.Runtime.Serialization.ExtensionDataObject extensionDataField; + + [System.Runtime.Serialization.OptionalFieldAttribute()] + private ScadaAdmin.AgentSvcRef.ConfigParts ConfigPartsField; + + [System.Runtime.Serialization.OptionalFieldAttribute()] + private ScadaAdmin.AgentSvcRef.RelPath[] ExcludedPathsField; + + [global::System.ComponentModel.BrowsableAttribute(false)] + public System.Runtime.Serialization.ExtensionDataObject ExtensionData { + get { + return this.extensionDataField; + } + set { + this.extensionDataField = value; + } + } + + [System.Runtime.Serialization.DataMemberAttribute()] + public ScadaAdmin.AgentSvcRef.ConfigParts ConfigParts { + get { + return this.ConfigPartsField; + } + set { + if ((this.ConfigPartsField.Equals(value) != true)) { + this.ConfigPartsField = value; + this.RaisePropertyChanged("ConfigParts"); + } + } + } + + [System.Runtime.Serialization.DataMemberAttribute()] + public ScadaAdmin.AgentSvcRef.RelPath[] ExcludedPaths { + get { + return this.ExcludedPathsField; + } + set { + if ((object.ReferenceEquals(this.ExcludedPathsField, value) != true)) { + this.ExcludedPathsField = value; + this.RaisePropertyChanged("ExcludedPaths"); + } + } + } + + public event System.ComponentModel.PropertyChangedEventHandler PropertyChanged; + + protected void RaisePropertyChanged(string propertyName) { + System.ComponentModel.PropertyChangedEventHandler propertyChanged = this.PropertyChanged; + if ((propertyChanged != null)) { + propertyChanged(this, new System.ComponentModel.PropertyChangedEventArgs(propertyName)); + } + } + } + + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Runtime.Serialization", "4.0.0.0")] + [System.Runtime.Serialization.DataContractAttribute(Name="RelPath", Namespace="http://schemas.datacontract.org/2004/07/Scada.Agent")] + [System.SerializableAttribute()] + public partial class RelPath : object, System.Runtime.Serialization.IExtensibleDataObject, System.ComponentModel.INotifyPropertyChanged { + + [System.NonSerializedAttribute()] + private System.Runtime.Serialization.ExtensionDataObject extensionDataField; + + [System.Runtime.Serialization.OptionalFieldAttribute()] + private ScadaAdmin.AgentSvcRef.AppFolder AppFolderField; + + [System.Runtime.Serialization.OptionalFieldAttribute()] + private ScadaAdmin.AgentSvcRef.ConfigParts ConfigPartField; + + [System.Runtime.Serialization.OptionalFieldAttribute()] + private string PathField; + + [global::System.ComponentModel.BrowsableAttribute(false)] + public System.Runtime.Serialization.ExtensionDataObject ExtensionData { + get { + return this.extensionDataField; + } + set { + this.extensionDataField = value; + } + } + + [System.Runtime.Serialization.DataMemberAttribute()] + public ScadaAdmin.AgentSvcRef.AppFolder AppFolder { + get { + return this.AppFolderField; + } + set { + if ((this.AppFolderField.Equals(value) != true)) { + this.AppFolderField = value; + this.RaisePropertyChanged("AppFolder"); + } + } + } + + [System.Runtime.Serialization.DataMemberAttribute()] + public ScadaAdmin.AgentSvcRef.ConfigParts ConfigPart { + get { + return this.ConfigPartField; + } + set { + if ((this.ConfigPartField.Equals(value) != true)) { + this.ConfigPartField = value; + this.RaisePropertyChanged("ConfigPart"); + } + } + } + + [System.Runtime.Serialization.DataMemberAttribute()] + public string Path { + get { + return this.PathField; + } + set { + if ((object.ReferenceEquals(this.PathField, value) != true)) { + this.PathField = value; + this.RaisePropertyChanged("Path"); + } + } + } + + public event System.ComponentModel.PropertyChangedEventHandler PropertyChanged; + + protected void RaisePropertyChanged(string propertyName) { + System.ComponentModel.PropertyChangedEventHandler propertyChanged = this.PropertyChanged; + if ((propertyChanged != null)) { + propertyChanged(this, new System.ComponentModel.PropertyChangedEventArgs(propertyName)); + } + } + } + + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Runtime.Serialization", "4.0.0.0")] + [System.Runtime.Serialization.DataContractAttribute(Name="AppFolder", Namespace="http://schemas.datacontract.org/2004/07/Scada.Agent")] + public enum AppFolder : int { + + [System.Runtime.Serialization.EnumMemberAttribute()] + Root = 0, + + [System.Runtime.Serialization.EnumMemberAttribute()] + Config = 1, + + [System.Runtime.Serialization.EnumMemberAttribute()] + Log = 2, + + [System.Runtime.Serialization.EnumMemberAttribute()] + Storage = 3, + } + + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.ServiceModel", "4.0.0.0")] + [System.ServiceModel.ServiceContractAttribute(ConfigurationName="AgentSvcRef.AgentSvc")] + public interface AgentSvc { + + [System.ServiceModel.OperationContractAttribute(Action="http://tempuri.org/AgentSvc/CreateSession", ReplyAction="http://tempuri.org/AgentSvc/CreateSessionResponse")] + bool CreateSession(out long sessionID); + + [System.ServiceModel.OperationContractAttribute(Action="http://tempuri.org/AgentSvc/Login", ReplyAction="http://tempuri.org/AgentSvc/LoginResponse")] + bool Login(out string errMsg, long sessionID, string username, string encryptedPassword, string scadaInstanceName); + + [System.ServiceModel.OperationContractAttribute(Action="http://tempuri.org/AgentSvc/ControlService", ReplyAction="http://tempuri.org/AgentSvc/ControlServiceResponse")] + bool ControlService(long sessionID, ScadaAdmin.AgentSvcRef.ServiceApp serviceApp, ScadaAdmin.AgentSvcRef.ServiceCommand command); + + [System.ServiceModel.OperationContractAttribute(Action="http://tempuri.org/AgentSvc/GetServiceStatus", ReplyAction="http://tempuri.org/AgentSvc/GetServiceStatusResponse")] + bool GetServiceStatus(out ScadaAdmin.AgentSvcRef.ServiceStatus status, long sessionID, ScadaAdmin.AgentSvcRef.ServiceApp serviceApp); + + [System.ServiceModel.OperationContractAttribute(Action="http://tempuri.org/AgentSvc/GetAvailableConfig", ReplyAction="http://tempuri.org/AgentSvc/GetAvailableConfigResponse")] + bool GetAvailableConfig(out ScadaAdmin.AgentSvcRef.ConfigParts configParts, long sessionID); + + [System.ServiceModel.OperationContractAttribute(Action="http://tempuri.org/AgentSvc/DownloadConfig", ReplyAction="http://tempuri.org/AgentSvc/DownloadConfigResponse")] + System.IO.Stream DownloadConfig(long sessionID, ScadaAdmin.AgentSvcRef.ConfigOptions configOptions); + + // CODEGEN: Generating message contract since the operation UploadConfig is neither RPC nor document wrapped. + [System.ServiceModel.OperationContractAttribute(Action="http://tempuri.org/AgentSvc/UploadConfig", ReplyAction="http://tempuri.org/AgentSvc/UploadConfigResponse")] + ScadaAdmin.AgentSvcRef.UploadConfigResponse UploadConfig(ScadaAdmin.AgentSvcRef.ConfigUploadMessage request); + + [System.ServiceModel.OperationContractAttribute(Action="http://tempuri.org/AgentSvc/Browse", ReplyAction="http://tempuri.org/AgentSvc/BrowseResponse")] + bool Browse(out string[] directories, out string[] files, long sessionID, ScadaAdmin.AgentSvcRef.RelPath relPath); + + [System.ServiceModel.OperationContractAttribute(Action="http://tempuri.org/AgentSvc/DownloadFile", ReplyAction="http://tempuri.org/AgentSvc/DownloadFileResponse")] + System.IO.Stream DownloadFile(long sessionID, ScadaAdmin.AgentSvcRef.RelPath relPath); + + [System.ServiceModel.OperationContractAttribute(Action="http://tempuri.org/AgentSvc/DownloadFileRest", ReplyAction="http://tempuri.org/AgentSvc/DownloadFileRestResponse")] + System.IO.Stream DownloadFileRest(long sessionID, ScadaAdmin.AgentSvcRef.RelPath relPath, long position); + } + + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.ServiceModel", "4.0.0.0")] + [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Advanced)] + [System.ServiceModel.MessageContractAttribute(WrapperName="ConfigUploadMessage", WrapperNamespace="http://tempuri.org/", IsWrapped=true)] + public partial class ConfigUploadMessage { + + [System.ServiceModel.MessageHeaderAttribute(Namespace="http://tempuri.org/")] + public ScadaAdmin.AgentSvcRef.ConfigOptions ConfigOptions; + + [System.ServiceModel.MessageHeaderAttribute(Namespace="http://tempuri.org/")] + public long SessionID; + + [System.ServiceModel.MessageBodyMemberAttribute(Namespace="http://tempuri.org/", Order=0)] + public System.IO.Stream Stream; + + public ConfigUploadMessage() { + } + + public ConfigUploadMessage(ScadaAdmin.AgentSvcRef.ConfigOptions ConfigOptions, long SessionID, System.IO.Stream Stream) { + this.ConfigOptions = ConfigOptions; + this.SessionID = SessionID; + this.Stream = Stream; + } + } + + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.ServiceModel", "4.0.0.0")] + [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Advanced)] + [System.ServiceModel.MessageContractAttribute(IsWrapped=false)] + public partial class UploadConfigResponse { + + public UploadConfigResponse() { + } + } + + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.ServiceModel", "4.0.0.0")] + public interface AgentSvcChannel : ScadaAdmin.AgentSvcRef.AgentSvc, System.ServiceModel.IClientChannel { + } + + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.ServiceModel", "4.0.0.0")] + public partial class AgentSvcClient : System.ServiceModel.ClientBase, ScadaAdmin.AgentSvcRef.AgentSvc { + + public AgentSvcClient() { + } + + public AgentSvcClient(string endpointConfigurationName) : + base(endpointConfigurationName) { + } + + public AgentSvcClient(string endpointConfigurationName, string remoteAddress) : + base(endpointConfigurationName, remoteAddress) { + } + + public AgentSvcClient(string endpointConfigurationName, System.ServiceModel.EndpointAddress remoteAddress) : + base(endpointConfigurationName, remoteAddress) { + } + + public AgentSvcClient(System.ServiceModel.Channels.Binding binding, System.ServiceModel.EndpointAddress remoteAddress) : + base(binding, remoteAddress) { + } + + public bool CreateSession(out long sessionID) { + return base.Channel.CreateSession(out sessionID); + } + + public bool Login(out string errMsg, long sessionID, string username, string encryptedPassword, string scadaInstanceName) { + return base.Channel.Login(out errMsg, sessionID, username, encryptedPassword, scadaInstanceName); + } + + public bool ControlService(long sessionID, ScadaAdmin.AgentSvcRef.ServiceApp serviceApp, ScadaAdmin.AgentSvcRef.ServiceCommand command) { + return base.Channel.ControlService(sessionID, serviceApp, command); + } + + public bool GetServiceStatus(out ScadaAdmin.AgentSvcRef.ServiceStatus status, long sessionID, ScadaAdmin.AgentSvcRef.ServiceApp serviceApp) { + return base.Channel.GetServiceStatus(out status, sessionID, serviceApp); + } + + public bool GetAvailableConfig(out ScadaAdmin.AgentSvcRef.ConfigParts configParts, long sessionID) { + return base.Channel.GetAvailableConfig(out configParts, sessionID); + } + + public System.IO.Stream DownloadConfig(long sessionID, ScadaAdmin.AgentSvcRef.ConfigOptions configOptions) { + return base.Channel.DownloadConfig(sessionID, configOptions); + } + + [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Advanced)] + ScadaAdmin.AgentSvcRef.UploadConfigResponse ScadaAdmin.AgentSvcRef.AgentSvc.UploadConfig(ScadaAdmin.AgentSvcRef.ConfigUploadMessage request) { + return base.Channel.UploadConfig(request); + } + + public void UploadConfig(ScadaAdmin.AgentSvcRef.ConfigOptions ConfigOptions, long SessionID, System.IO.Stream Stream) { + ScadaAdmin.AgentSvcRef.ConfigUploadMessage inValue = new ScadaAdmin.AgentSvcRef.ConfigUploadMessage(); + inValue.ConfigOptions = ConfigOptions; + inValue.SessionID = SessionID; + inValue.Stream = Stream; + ScadaAdmin.AgentSvcRef.UploadConfigResponse retVal = ((ScadaAdmin.AgentSvcRef.AgentSvc)(this)).UploadConfig(inValue); + } + + public bool Browse(out string[] directories, out string[] files, long sessionID, ScadaAdmin.AgentSvcRef.RelPath relPath) { + return base.Channel.Browse(out directories, out files, sessionID, relPath); + } + + public System.IO.Stream DownloadFile(long sessionID, ScadaAdmin.AgentSvcRef.RelPath relPath) { + return base.Channel.DownloadFile(sessionID, relPath); + } + + public System.IO.Stream DownloadFileRest(long sessionID, ScadaAdmin.AgentSvcRef.RelPath relPath, long position) { + return base.Channel.DownloadFileRest(sessionID, relPath, position); + } + } +} diff --git a/ScadaAdmin/ScadaAdmin/Connected Services/AgentSvcRef/Reference.svcmap b/ScadaAdmin/ScadaAdmin/Connected Services/AgentSvcRef/Reference.svcmap new file mode 100644 index 000000000..35ec80ed6 --- /dev/null +++ b/ScadaAdmin/ScadaAdmin/Connected Services/AgentSvcRef/Reference.svcmap @@ -0,0 +1,36 @@ + + + + false + true + + false + false + false + + + true + Auto + true + true + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/ScadaAdmin/ScadaAdmin/Connected Services/AgentSvcRef/ScadaAdmin.AgentSvcRef.ConfigParts.datasource b/ScadaAdmin/ScadaAdmin/Connected Services/AgentSvcRef/ScadaAdmin.AgentSvcRef.ConfigParts.datasource new file mode 100644 index 000000000..d0dc511ef --- /dev/null +++ b/ScadaAdmin/ScadaAdmin/Connected Services/AgentSvcRef/ScadaAdmin.AgentSvcRef.ConfigParts.datasource @@ -0,0 +1,10 @@ + + + + ScadaAdmin.AgentSvcRef.ConfigParts, Connected Services.AgentSvcRef.Reference.cs.dll, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null + \ No newline at end of file diff --git a/ScadaAdmin/ScadaAdmin/Connected Services/AgentSvcRef/ScadaAdmin.AgentSvcRef.ServiceStatus.datasource b/ScadaAdmin/ScadaAdmin/Connected Services/AgentSvcRef/ScadaAdmin.AgentSvcRef.ServiceStatus.datasource new file mode 100644 index 000000000..27519ae88 --- /dev/null +++ b/ScadaAdmin/ScadaAdmin/Connected Services/AgentSvcRef/ScadaAdmin.AgentSvcRef.ServiceStatus.datasource @@ -0,0 +1,10 @@ + + + + ScadaAdmin.AgentSvcRef.ServiceStatus, Connected Services.AgentSvcRef.Reference.cs.dll, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null + \ No newline at end of file diff --git a/ScadaAgent/ScadaAgent/ScadaAgentCtrl/Connected Services/ServiceReference1/configuration.svcinfo b/ScadaAdmin/ScadaAdmin/Connected Services/AgentSvcRef/configuration.svcinfo similarity index 63% rename from ScadaAgent/ScadaAgent/ScadaAgentCtrl/Connected Services/ServiceReference1/configuration.svcinfo rename to ScadaAdmin/ScadaAdmin/Connected Services/AgentSvcRef/configuration.svcinfo index 47aeac9b9..38bb543c7 100644 --- a/ScadaAgent/ScadaAgent/ScadaAgentCtrl/Connected Services/ServiceReference1/configuration.svcinfo +++ b/ScadaAdmin/ScadaAdmin/Connected Services/AgentSvcRef/configuration.svcinfo @@ -5,6 +5,6 @@ - + \ No newline at end of file diff --git a/ScadaAgent/ScadaAgent/ScadaAgentCtrl/Connected Services/ServiceReference1/configuration91.svcinfo b/ScadaAdmin/ScadaAdmin/Connected Services/AgentSvcRef/configuration91.svcinfo similarity index 98% rename from ScadaAgent/ScadaAgent/ScadaAgentCtrl/Connected Services/ServiceReference1/configuration91.svcinfo rename to ScadaAdmin/ScadaAdmin/Connected Services/AgentSvcRef/configuration91.svcinfo index aebb32cab..8031434d2 100644 --- a/ScadaAgent/ScadaAgent/ScadaAgentCtrl/Connected Services/ServiceReference1/configuration91.svcinfo +++ b/ScadaAdmin/ScadaAdmin/Connected Services/AgentSvcRef/configuration91.svcinfo @@ -1,5 +1,5 @@ - + @@ -112,7 +112,7 @@ - + http://localhost:10002/ScadaAgent/ScadaAgentSvc/ @@ -127,7 +127,7 @@ BasicHttpBinding_AgentSvc - ServiceReference1.AgentSvc + AgentSvcRef.AgentSvc System.ServiceModel.Configuration.AddressHeaderCollectionElement diff --git a/ScadaAgent/ScadaAgent/ScadaAgentCtrl/Connected Services/ServiceReference1/item.disco b/ScadaAdmin/ScadaAdmin/Connected Services/AgentSvcRef/item.disco similarity index 100% rename from ScadaAgent/ScadaAgent/ScadaAgentCtrl/Connected Services/ServiceReference1/item.disco rename to ScadaAdmin/ScadaAdmin/Connected Services/AgentSvcRef/item.disco diff --git a/ScadaAdmin/ScadaAdmin/Connected Services/AgentSvcRef/item.xsd b/ScadaAdmin/ScadaAdmin/Connected Services/AgentSvcRef/item.xsd new file mode 100644 index 000000000..04a74a45c --- /dev/null +++ b/ScadaAdmin/ScadaAdmin/Connected Services/AgentSvcRef/item.xsd @@ -0,0 +1,9 @@ + + + + + + + + + \ No newline at end of file diff --git a/ScadaAdmin/ScadaAdmin/Connected Services/AgentSvcRef/item1.xsd b/ScadaAdmin/ScadaAdmin/Connected Services/AgentSvcRef/item1.xsd new file mode 100644 index 000000000..e13908491 --- /dev/null +++ b/ScadaAdmin/ScadaAdmin/Connected Services/AgentSvcRef/item1.xsd @@ -0,0 +1,116 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + + + + + + + 1 + + + + + + + 2 + + + + + + + 4 + + + + + + + 8 + + + + + + + 16 + + + + + + + 31 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/ScadaAdmin/ScadaAdmin/Connected Services/AgentSvcRef/item2.xsd b/ScadaAdmin/ScadaAdmin/Connected Services/AgentSvcRef/item2.xsd new file mode 100644 index 000000000..9c6da3168 --- /dev/null +++ b/ScadaAdmin/ScadaAdmin/Connected Services/AgentSvcRef/item2.xsd @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/ScadaAdmin/ScadaAdmin/Connected Services/AgentSvcRef/item3.xsd b/ScadaAdmin/ScadaAdmin/Connected Services/AgentSvcRef/item3.xsd new file mode 100644 index 000000000..f5e7fda8c --- /dev/null +++ b/ScadaAdmin/ScadaAdmin/Connected Services/AgentSvcRef/item3.xsd @@ -0,0 +1,156 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/ScadaAgent/ScadaAgent/ScadaAgentCtrl/Connected Services/ServiceReference1/item1.xsd b/ScadaAdmin/ScadaAdmin/Connected Services/AgentSvcRef/item4.xsd similarity index 100% rename from ScadaAgent/ScadaAgent/ScadaAgentCtrl/Connected Services/ServiceReference1/item1.xsd rename to ScadaAdmin/ScadaAdmin/Connected Services/AgentSvcRef/item4.xsd diff --git a/ScadaAdmin/ScadaAdmin/FrmAbout.cs b/ScadaAdmin/ScadaAdmin/FrmAbout.cs index 85a2cbcac..a21366b91 100644 --- a/ScadaAdmin/ScadaAdmin/FrmAbout.cs +++ b/ScadaAdmin/ScadaAdmin/FrmAbout.cs @@ -1,5 +1,5 @@ /* - * Copyright 2017 Mikhail Shiryaev + * Copyright 2018 Mikhail Shiryaev * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -20,7 +20,7 @@ * * Author : Mikhail Shiryaev * Created : 2010 - * Modified : 2017 + * Modified : 2018 */ using Scada; @@ -37,7 +37,7 @@ namespace ScadaAdmin /// public partial class FrmAbout : Form { - private const string Version = "5.0.0.2"; // версия приложения + private const string Version = "5.1.0.0"; // версия приложения private static FrmAbout frmAbout = null; // экземпляр формы о программе private bool inited; // форма инициализирована @@ -99,7 +99,7 @@ private void Init() // загрузка изображения и гиперссылки из файлов, если они существуют bool imgLoaded; string errMsg; - if (ScadaUiUtils.LoadAboutForm(AppData.ExeDir, this, activePictureBox, lblWebsite, + if (ScadaUiUtils.LoadAboutForm(AppData.AppDirs.ExeDir, this, activePictureBox, lblWebsite, out imgLoaded, out linkUrl, out errMsg)) { if (imgLoaded) diff --git a/ScadaAdmin/ScadaAdmin/FrmAbout.resx b/ScadaAdmin/ScadaAdmin/FrmAbout.resx index ec4228b71..fac45ea49 100644 --- a/ScadaAdmin/ScadaAdmin/FrmAbout.resx +++ b/ScadaAdmin/ScadaAdmin/FrmAbout.resx @@ -331,67 +331,64 @@ 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 @@ -401,8 +398,11 @@ 75GxXlO7/wDtG4svyWAHvkbFeU7v/wC0biy/JYAe+RsV5Tu//tG4svyWAHvkbFeU7v8A+0biy/JYAe+R sV5Tu/8A7RuLL8lgB75GxXlO7/8AtG4svyWAHvkbFeU7v/7RuLL8lgB75GxXlO7/APtG4svyWAHvkbFe U7v/AO0biy/JYAe+RsV5Tu//ALRuLL8lgB75GxXlO7/+0biy/JYAe+RsV5Tu/wD7RuLL8lgB75GxXlO7 - /wDtG4svyWAHvkbFeU7v/wC0biy/JYAiDk12vnlx8bfIM3ljjK3fYSQu6QbXoyo+nY/uNw41WWnKkDP4 - iedjlKMXkGej2NN9uFs9xw7jR0dWVby2G+0oTNGK48F4f//Z + /wDtG4svyWAHvkbFeU7v/wC0biy/JYAe+RsV5Tu//tG4svyWAHvkbFeU7v8A+0biy/JYAe+RsV5Tu/8A + 7RuLL8lgB75GxXlO7/8AtG4svyWAHvkbFeU7v/7RuLL8lgB75GxXlO7/APtG4svyWAHvkbFeU7v/AO0b + iy/JYAe+RsV5Tu//ALRuLL8lgB75GxXlO7/+0biy/JYAe+RsV5Tu/wD7RuLL8lgB75GxXlO7/wDtG4sv + yWAHvkbFeU7v/wC0biy/JYAiDk12vnlx8bfIM3ljjK3fYSQu6QbXoyo+nY/uNw41WWnKkDP4iedjlKMX + kGej2NN9uFs9xw7jR0dWVby2G+0oTNGK48F4f//Z @@ -411,7 +411,7 @@ AQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAgICAgICAgICAgIDAwMDAwMDAwMD/9sAQwEBAQEBAQECAQEC AgIBAgIDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMD/8AAEQgA 3gGoAwERAAIRAQMRAf/EABwAAQEBAQEBAQEBAAAAAAAAAAAICQcGBQoEA//EAEcQAAAFBAEABQsBBQYF - AgcAAAAEBQYHAQIDCAkSExQWWREVF5cYeJi4GTnZ1yEi1lgKIyQlNTe3MUFRNDYyUkJicjNTcyb/xAAb + AgcAAAAEBQYHAQIDCAkSExQYWREVFheXeJi4GTnZ1yEi1lgKIyQlNTe3MUFRNDYyUkJicjNTcyb/xAAb AQEAAwEBAQEAAAAAAAAAAAAABAYHBQMCAf/EAEARAQABAgQCBQgIBQMFAQAAAAABEQIhAwQFMRJBUdEi FaEyshOTVDUGYXGBkVJzFHTwscFCYnLSM+HCIyQlFv/aAAwDAQACEQMRAD8AvbQPQPRJ5aJaVO936Val Op2OrUrXByOh0OTXCHVxxORxLkOs1TW15eW1NmmlJYWlhSNZTBo0Yy5M5jPkuyZLrr7q1rrm27bt2Zt2 @@ -476,210 +476,210 @@ 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 \ No newline at end of file diff --git a/ScadaAdmin/ScadaAdmin/FrmCnlMap.cs b/ScadaAdmin/ScadaAdmin/FrmCnlMap.cs index c74103c82..cd37beb33 100644 --- a/ScadaAdmin/ScadaAdmin/FrmCnlMap.cs +++ b/ScadaAdmin/ScadaAdmin/FrmCnlMap.cs @@ -1,5 +1,5 @@ /* - * Copyright 2016 Mikhail Shiryaev + * Copyright 2018 Mikhail Shiryaev * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -20,7 +20,7 @@ * * Author : Mikhail Shiryaev * Created : 2012 - * Modified : 2016 + * Modified : 2018 */ using Scada; @@ -137,7 +137,7 @@ private void btnCreate_Click(object sender, EventArgs e) StreamWriter writer = null; bool mapCreated = false; - string mapFileName = AppData.ExeDir + "ScadaAdminCnlMap.txt"; + string mapFileName = AppData.AppDirs.LogDir + "ScadaAdminCnlMap.txt"; try { diff --git a/ScadaAdmin/ScadaAdmin/FrmCreateCnls.cs b/ScadaAdmin/ScadaAdmin/FrmCreateCnls.cs index e86eb785d..6a88eb910 100644 --- a/ScadaAdmin/ScadaAdmin/FrmCreateCnls.cs +++ b/ScadaAdmin/ScadaAdmin/FrmCreateCnls.cs @@ -1,5 +1,5 @@ /* - * Copyright 2016 Mikhail Shiryaev + * Copyright 2018 Mikhail Shiryaev * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -20,7 +20,7 @@ * * Author : Mikhail Shiryaev * Created : 2010 - * Modified : 2016 + * Modified : 2018 */ using Scada; @@ -356,7 +356,7 @@ private void btnCalc_Click(object sender, EventArgs e) private void btnCreate_Click(object sender, EventArgs e) { // создание каналов - string logFileName = AppData.ExeDir + "ScadaAdminCreateCnls.txt"; + string logFileName = AppData.AppDirs.LogDir + "ScadaAdminCreateCnls.txt"; bool logCreated; string msg; diff --git a/ScadaAdmin/ScadaAdmin/FrmImport.Designer.cs b/ScadaAdmin/ScadaAdmin/FrmImport.Designer.cs index a17d59384..6b8ee85dc 100644 --- a/ScadaAdmin/ScadaAdmin/FrmImport.Designer.cs +++ b/ScadaAdmin/ScadaAdmin/FrmImport.Designer.cs @@ -47,7 +47,8 @@ private void InitializeComponent() this.lblFinalID = new System.Windows.Forms.Label(); this.lblStartID = new System.Windows.Forms.Label(); this.openFileDialog = new System.Windows.Forms.OpenFileDialog(); - this.chkImportLog = new System.Windows.Forms.CheckBox(); + this.lblDirectory = new System.Windows.Forms.Label(); + this.folderBrowserDialog = new System.Windows.Forms.FolderBrowserDialog(); this.gbIDs.SuspendLayout(); ((System.ComponentModel.ISupportInitialize)(this.numNewStartID)).BeginInit(); ((System.ComponentModel.ISupportInitialize)(this.numFinalID)).BeginInit(); @@ -56,7 +57,7 @@ private void InitializeComponent() // // btnImport // - this.btnImport.Location = new System.Drawing.Point(152, 188); + this.btnImport.Location = new System.Drawing.Point(152, 162); this.btnImport.Name = "btnImport"; this.btnImport.Size = new System.Drawing.Size(75, 23); this.btnImport.TabIndex = 7; @@ -67,7 +68,7 @@ private void InitializeComponent() // btnClose // this.btnClose.DialogResult = System.Windows.Forms.DialogResult.Cancel; - this.btnClose.Location = new System.Drawing.Point(233, 188); + this.btnClose.Location = new System.Drawing.Point(233, 162); this.btnClose.Name = "btnClose"; this.btnClose.Size = new System.Drawing.Size(75, 23); this.btnClose.TabIndex = 8; @@ -242,17 +243,14 @@ private void InitializeComponent() this.openFileDialog.Filter = "Таблицы базы конфигурации|*.dat|Все файлы|*.*"; this.openFileDialog.Title = "Выберите файл таблицы базы конфигурации"; // - // chkImportLog + // lblDirectory // - this.chkImportLog.AutoSize = true; - this.chkImportLog.Checked = true; - this.chkImportLog.CheckState = System.Windows.Forms.CheckState.Checked; - this.chkImportLog.Location = new System.Drawing.Point(25, 164); - this.chkImportLog.Name = "chkImportLog"; - this.chkImportLog.Size = new System.Drawing.Size(169, 17); - this.chkImportLog.TabIndex = 6; - this.chkImportLog.Text = "Записать в журнал импорта"; - this.chkImportLog.UseVisualStyleBackColor = true; + this.lblDirectory.AutoSize = true; + this.lblDirectory.Location = new System.Drawing.Point(51, 49); + this.lblDirectory.Name = "lblDirectory"; + this.lblDirectory.Size = new System.Drawing.Size(69, 13); + this.lblDirectory.TabIndex = 9; + this.lblDirectory.Text = "Директория"; // // FrmImport // @@ -260,8 +258,8 @@ private void InitializeComponent() this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; this.CancelButton = this.btnClose; - this.ClientSize = new System.Drawing.Size(320, 223); - this.Controls.Add(this.chkImportLog); + this.ClientSize = new System.Drawing.Size(320, 197); + this.Controls.Add(this.lblDirectory); this.Controls.Add(this.gbIDs); this.Controls.Add(this.btnImport); this.Controls.Add(this.btnClose); @@ -308,6 +306,7 @@ private void InitializeComponent() private System.Windows.Forms.CheckBox chkNewStartID; private System.Windows.Forms.CheckBox chkFinalID; private System.Windows.Forms.OpenFileDialog openFileDialog; - private System.Windows.Forms.CheckBox chkImportLog; + private System.Windows.Forms.Label lblDirectory; + private System.Windows.Forms.FolderBrowserDialog folderBrowserDialog; } } \ No newline at end of file diff --git a/ScadaAdmin/ScadaAdmin/FrmImport.cs b/ScadaAdmin/ScadaAdmin/FrmImport.cs index 5369211c0..ea902c99b 100644 --- a/ScadaAdmin/ScadaAdmin/FrmImport.cs +++ b/ScadaAdmin/ScadaAdmin/FrmImport.cs @@ -1,5 +1,5 @@ /* - * Copyright 2016 Mikhail Shiryaev + * Copyright 2018 Mikhail Shiryaev * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -20,7 +20,7 @@ * * Author : Mikhail Shiryaev * Created : 2010 - * Modified : 2016 + * Modified : 2018 */ using Scada; @@ -39,9 +39,32 @@ namespace ScadaAdmin public partial class FrmImport : Form { /// - /// Имя файла архива базы конфигурации + /// Элемент выпадающего списка для иморта всех таблиц /// - public const string BaseDATArcFileName = "BaseDAT.zip"; + private class ImportAllTablesItem + { + public override string ToString() + { + return AppPhrases.AllTablesItem; + } + } + + /// + /// Элемент выпадающего списка для иморта из архива + /// + private class ImportArchiveItem + { + public override string ToString() + { + return AppPhrases.ArchiveItem; + } + } + + /// + /// Выбранный элемент при открытии формы + /// + public enum SelectedItem { Table, AllTables, Archive }; + /// /// Конструктор @@ -50,20 +73,32 @@ public FrmImport() { InitializeComponent(); + DefaultSelection = SelectedItem.Table; DefaultTableName = ""; - DefaultDirectory = ""; + DefaultArcFileName = ""; + DefaultBaseDATDir = ""; } + /// + /// Выбранный элемент по умолчанию + /// + public SelectedItem DefaultSelection { get; set; } + /// /// Получить или установить имя таблицы, выбранной по умолчанию /// public string DefaultTableName { get; set; } + /// + /// Получить или установить имя файла архива конфигурации по умолчанию + /// + public string DefaultArcFileName { get; set; } + /// /// Получить или установить директорию по умолчанию /// - public string DefaultDirectory { get; set; } + public string DefaultBaseDATDir { get; set; } private void FrmImport_Load(object sender, EventArgs e) @@ -71,62 +106,109 @@ private void FrmImport_Load(object sender, EventArgs e) // перевод формы Translator.TranslateForm(this, "ScadaAdmin.FrmImport"); + // настройка элементов управления + lblDirectory.Left = lblFileName.Left; + + // определение имени файла архива по умолчанию + if (string.IsNullOrEmpty(DefaultArcFileName) && !string.IsNullOrEmpty(DefaultBaseDATDir)) + DefaultArcFileName = Path.GetFullPath(DefaultBaseDATDir + @"..\config.zip"); + // заполнение выпадающего списка таблиц - int selInd = 0; + int tableInd = 0; foreach (Tables.TableInfo tableInfo in Tables.TableInfoList) { int ind = cbTable.Items.Add(tableInfo); if (tableInfo.Name == DefaultTableName) - selInd = ind; + tableInd = ind; } - cbTable.Items.Add(AppPhrases.ArchiveItem); + int allTablesInd = cbTable.Items.Add(new ImportAllTablesItem()); + int archiveInd = cbTable.Items.Add(new ImportArchiveItem()); - if (cbTable.Items.Count > 0) - cbTable.SelectedIndex = selInd; + // выбор элемента списка + switch (DefaultSelection) + { + case SelectedItem.AllTables: + cbTable.SelectedIndex = allTablesInd; + break; + case SelectedItem.Archive: + cbTable.SelectedIndex = archiveInd; + break; + default: // SelectedItem.Table + cbTable.SelectedIndex = tableInd; + break; + } } private void cbTable_SelectedIndexChanged(object sender, EventArgs e) { // установка имени файла таблицы - Tables.TableInfo tableInfo = cbTable.SelectedItem as Tables.TableInfo; + object selItem = cbTable.SelectedItem; - if (tableInfo == null) + if (selItem is ImportAllTablesItem) { - txtFileName.Text = DefaultDirectory + BaseDATArcFileName; + lblFileName.Visible = false; + lblDirectory.Visible = true; + txtFileName.Text = DefaultBaseDATDir; gbIDs.Enabled = false; } - else + else if (selItem is ImportArchiveItem) + { + lblFileName.Visible = true; + lblDirectory.Visible = false; + txtFileName.Text = DefaultArcFileName; + gbIDs.Enabled = false; + } + else if (selItem is Tables.TableInfo tableInfo) { - txtFileName.Text = DefaultDirectory + tableInfo.FileName; - gbIDs.Enabled = tableInfo.IDColName != ""; + lblFileName.Visible = true; + lblDirectory.Visible = false; + txtFileName.Text = DefaultBaseDATDir + tableInfo.FileName; + gbIDs.Enabled = tableInfo.HasIntID; } } private void btnBrowse_Click(object sender, EventArgs e) { - // настройка диалога открытия файла - string fileName = txtFileName.Text.Trim(); - if (fileName.EndsWith("zip", StringComparison.OrdinalIgnoreCase)) + if (lblFileName.Visible) { - openFileDialog.Title = AppPhrases.ChooseBaseArchiveFile; - openFileDialog.Filter = AppPhrases.BaseArchiveFileFilter; + // выбор импортируемого файла + if (cbTable.SelectedItem is ImportArchiveItem) + { + openFileDialog.Title = AppPhrases.ChooseArchiveFile; + openFileDialog.Filter = AppPhrases.ArchiveFileFilter; + } + else + { + openFileDialog.Title = AppPhrases.ChooseBaseTableFile; + openFileDialog.Filter = AppPhrases.BaseTableFileFilter; + } + + string fileName = txtFileName.Text.Trim(); + openFileDialog.FileName = fileName; + + if (fileName != "") + openFileDialog.InitialDirectory = Path.GetDirectoryName(fileName); + + if (openFileDialog.ShowDialog() == DialogResult.OK) + txtFileName.Text = openFileDialog.FileName; + + txtFileName.Focus(); + txtFileName.DeselectAll(); } else { - openFileDialog.Title = AppPhrases.ChooseBaseTableFile; - openFileDialog.Filter = AppPhrases.BaseTableFileFilter; - } + // выбор директории + folderBrowserDialog.SelectedPath = txtFileName.Text.Trim(); + folderBrowserDialog.Description = CommonPhrases.ChooseBaseDATDir; + + if (folderBrowserDialog.ShowDialog() == DialogResult.OK) + txtFileName.Text = ScadaUtils.NormalDir(folderBrowserDialog.SelectedPath); - // выбор файла таблицы - openFileDialog.FileName = fileName; - if (fileName != "") - openFileDialog.InitialDirectory = Path.GetDirectoryName(fileName); - if (openFileDialog.ShowDialog() == DialogResult.OK) - txtFileName.Text = openFileDialog.FileName; - txtFileName.Focus(); - txtFileName.DeselectAll(); + txtFileName.Focus(); + txtFileName.DeselectAll(); + } } private void chkStartID_CheckedChanged(object sender, EventArgs e) @@ -147,16 +229,21 @@ private void chkNewStartID_CheckedChanged(object sender, EventArgs e) private void btnImport_Click(object sender, EventArgs e) { // импорт выбранной таблицы из формата DAT - Tables.TableInfo tableInfo = cbTable.SelectedItem as Tables.TableInfo; - if (AppData.Connected) { - string logFileName = chkImportLog.Checked ? AppData.ExeDir + "ScadaAdminImport.txt" : ""; + object selItem = cbTable.SelectedItem; + string logFileName = AppData.AppDirs.LogDir + "ScadaAdminImport.txt"; bool importOK; bool logCreated; string msg; - if (tableInfo == null) + if (selItem is ImportAllTablesItem) + { + // импорт всех таблиц из директории + importOK = ImportExport.ImportAllTables(txtFileName.Text, Tables.TableInfoList, + logFileName, out logCreated, out msg); + } + else if (selItem is ImportArchiveItem) { // импорт архива importOK = ImportExport.ImportArchive(txtFileName.Text, Tables.TableInfoList, @@ -165,22 +252,27 @@ private void btnImport_Click(object sender, EventArgs e) else { // импорт таблицы - int minID = gbIDs.Enabled && chkStartID.Checked ? Convert.ToInt32(numStartID.Value) : 1; + Tables.TableInfo tableInfo = (Tables.TableInfo)selItem; + int minID = gbIDs.Enabled && chkStartID.Checked ? Convert.ToInt32(numStartID.Value) : 0; int maxID = gbIDs.Enabled && chkFinalID.Checked ? Convert.ToInt32(numFinalID.Value) : int.MaxValue; int newMinID = gbIDs.Enabled && chkNewStartID.Checked ? Convert.ToInt32(numNewStartID.Value) : 0; importOK = ImportExport.ImportTable(txtFileName.Text, tableInfo, minID, maxID, newMinID, logFileName, out logCreated, out msg); } - // отображение сообщения о результате импорта + // отображение сообщения о результате if (importOK) + { ScadaUiUtils.ShowInfo(msg); + } else + { AppUtils.ProcError(msg); - // отображение журанала в блокноте - if (logCreated) - Process.Start(logFileName); + // отображение журнала в блокноте + if (logCreated) + Process.Start(logFileName); + } } } } diff --git a/ScadaAdmin/ScadaAdmin/FrmImport.resx b/ScadaAdmin/ScadaAdmin/FrmImport.resx index 724c152b0..545dc9e09 100644 --- a/ScadaAdmin/ScadaAdmin/FrmImport.resx +++ b/ScadaAdmin/ScadaAdmin/FrmImport.resx @@ -136,4 +136,7 @@ 17, 17 + + 150, 17 + \ No newline at end of file diff --git a/ScadaAdmin/ScadaAdmin/FrmMain.Designer.cs b/ScadaAdmin/ScadaAdmin/FrmMain.Designer.cs index 2a0dcb6d2..d252bc3de 100644 --- a/ScadaAdmin/ScadaAdmin/FrmMain.Designer.cs +++ b/ScadaAdmin/ScadaAdmin/FrmMain.Designer.cs @@ -100,6 +100,10 @@ private void InitializeComponent() this.miExplorerRefresh = new System.Windows.Forms.ToolStripMenuItem(); this.contextInCnls = new System.Windows.Forms.ContextMenuStrip(this.components); this.miInCnlProps = new System.Windows.Forms.ToolStripMenuItem(); + this.miRemote = new System.Windows.Forms.ToolStripMenuItem(); + this.miRemoteDownload = new System.Windows.Forms.ToolStripMenuItem(); + this.miRemoteUpload = new System.Windows.Forms.ToolStripMenuItem(); + this.miRemoteStatus = new System.Windows.Forms.ToolStripMenuItem(); this.menuMain.SuspendLayout(); this.toolMain.SuspendLayout(); this.statusMain.SuspendLayout(); @@ -116,6 +120,7 @@ private void InitializeComponent() this.miEdit, this.miView, this.miService, + this.miRemote, this.miSettings, this.miWindow, this.miHelp}); @@ -364,14 +369,14 @@ private void InitializeComponent() // this.miSettingsParams.Image = ((System.Drawing.Image)(resources.GetObject("miSettingsParams.Image"))); this.miSettingsParams.Name = "miSettingsParams"; - this.miSettingsParams.Size = new System.Drawing.Size(147, 22); + this.miSettingsParams.Size = new System.Drawing.Size(180, 22); this.miSettingsParams.Text = "Параметры..."; this.miSettingsParams.Click += new System.EventHandler(this.miSettingsParams_Click); // // miSettingsLanguage // this.miSettingsLanguage.Name = "miSettingsLanguage"; - this.miSettingsLanguage.Size = new System.Drawing.Size(147, 22); + this.miSettingsLanguage.Size = new System.Drawing.Size(180, 22); this.miSettingsLanguage.Text = "Язык..."; this.miSettingsLanguage.Click += new System.EventHandler(this.miSettingsLanguage_Click); // @@ -740,6 +745,37 @@ private void InitializeComponent() this.miInCnlProps.Text = "Свойства канала"; this.miInCnlProps.Click += new System.EventHandler(this.miInCnlProps_Click); // + // miRemote + // + this.miRemote.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] { + this.miRemoteDownload, + this.miRemoteUpload, + this.miRemoteStatus}); + this.miRemote.Name = "miRemote"; + this.miRemote.Size = new System.Drawing.Size(122, 20); + this.miRemote.Text = "&Удаленный сервер"; + // + // miRemoteDownload + // + this.miRemoteDownload.Name = "miRemoteDownload"; + this.miRemoteDownload.Size = new System.Drawing.Size(221, 22); + this.miRemoteDownload.Text = "Скачать конфигурацию..."; + this.miRemoteDownload.Click += new System.EventHandler(this.miRemoteDownload_Click); + // + // miRemoteUpload + // + this.miRemoteUpload.Name = "miRemoteUpload"; + this.miRemoteUpload.Size = new System.Drawing.Size(221, 22); + this.miRemoteUpload.Text = "Передать конфигурацию..."; + this.miRemoteUpload.Click += new System.EventHandler(this.miRemoteUpload_Click); + // + // miRemoteStatus + // + this.miRemoteStatus.Name = "miRemoteStatus"; + this.miRemoteStatus.Size = new System.Drawing.Size(221, 22); + this.miRemoteStatus.Text = "Статус сервера..."; + this.miRemoteStatus.Click += new System.EventHandler(this.miRemoteStatus_Click); + // // FrmMain // this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); @@ -848,6 +884,10 @@ private void InitializeComponent() private System.Windows.Forms.ToolStripButton btnRestartComm; private System.Windows.Forms.ToolStripSeparator sepFifth; private System.Windows.Forms.ToolStripMenuItem miSettingsLanguage; + private System.Windows.Forms.ToolStripMenuItem miRemote; + private System.Windows.Forms.ToolStripMenuItem miRemoteDownload; + private System.Windows.Forms.ToolStripMenuItem miRemoteUpload; + private System.Windows.Forms.ToolStripMenuItem miRemoteStatus; } } diff --git a/ScadaAdmin/ScadaAdmin/FrmMain.cs b/ScadaAdmin/ScadaAdmin/FrmMain.cs index 1b9c04f94..ca66da019 100644 --- a/ScadaAdmin/ScadaAdmin/FrmMain.cs +++ b/ScadaAdmin/ScadaAdmin/FrmMain.cs @@ -1,5 +1,5 @@ /* - * Copyright 2017 Mikhail Shiryaev + * Copyright 2018 Mikhail Shiryaev * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -20,11 +20,12 @@ * * Author : Mikhail Shiryaev * Created : 2010 - * Modified : 2017 + * Modified : 2018 */ using Scada; using Scada.UI; +using ScadaAdmin.Remote; using System; using System.Collections.Generic; using System.Data; @@ -116,6 +117,7 @@ public FrmMain() allNodes = new List(); preventDblClick = false; + settings = AppData.Settings; frmReplace = null; } @@ -393,7 +395,7 @@ private bool Connect(bool expandTree) // соединение с БД if (connectNeeded) { - AppData.Connect(settings.AppSett.BaseSDFFile); + AppData.Connect(); nodDB.ImageKey = nodDB.SelectedImageKey = "db.gif"; nodSystem.Expand(); @@ -552,6 +554,8 @@ private void SetItemsEnabledOnConnect() miServiceCreateCnls.Enabled = connected; miServiceCloneCnls.Enabled = connected; miServiceCnlsMap.Enabled = connected; + miRemoteDownload.Enabled = connected; + miRemoteUpload.Enabled = connected; } /// @@ -587,15 +591,12 @@ private void PrepareCloseAll(bool showError) private void FrmMain_Load(object sender, EventArgs e) { // локализация приложения - string langDir = AppData.ExeDir + "Lang\\"; - string errMsg; - - if (Localization.LoadDictionaries(langDir, "ScadaData", out errMsg)) + if (Localization.LoadDictionaries(AppData.AppDirs.LangDir, "ScadaData", out string errMsg)) CommonPhrases.Init(); else ScadaUiUtils.ShowError(errMsg); - if (Localization.LoadDictionaries(langDir, "ScadaAdmin", out errMsg)) + if (Localization.LoadDictionaries(AppData.AppDirs.LangDir, "ScadaAdmin", out errMsg)) { Translator.TranslateForm(this, "ScadaAdmin.FrmMain", null, contextExpolorer, contextInCnls); AppPhrases.Init(); @@ -619,7 +620,6 @@ private void FrmMain_Load(object sender, EventArgs e) SetItemsEnabledOnWindowAction(); // загрузка состояния формы - settings = new Settings(); settings.LoadFormState(); if (settings.FormSt.IsEmpty) { @@ -797,13 +797,13 @@ private void miDbPassToServer_Click(object sender, EventArgs e) if (AppData.Connected) { // резервное копирование файла базы конфигурации - string msg; - if (settings.AppSett.AutoBackupBase && - !ImportExport.BackupSDF(settings.AppSett.BaseSDFFile, settings.AppSett.BackupDir, out msg)) + Settings.AppSettings appSettings = settings.AppSett; + if (appSettings.AutoBackupBase && + !ImportExport.BackupSDF(appSettings.BaseSDFFile, appSettings.BackupDir, out string msg)) AppUtils.ProcError(msg); // конвертирование базы конфигурации в формат DAT - if (ImportExport.PassBase(Tables.TableInfoList, settings.AppSett.BaseDATDir, out msg)) + if (ImportExport.PassBase(Tables.TableInfoList, appSettings.BaseDATDir, out msg)) ScadaUiUtils.ShowInfo(msg); else AppUtils.ProcError(msg); @@ -852,9 +852,11 @@ private void miDbImport_Click(object sender, EventArgs e) // создание и отоборажение формы импорта таблицы FrmImport frmImport = new FrmImport(); FrmTable frmTable = winControl.ActiveForm as FrmTable; + if (frmTable != null && frmTable.Table != null) frmImport.DefaultTableName = frmTable.Table.TableName; - frmImport.DefaultDirectory = settings.AppSett.BaseDATDir; + + frmImport.DefaultBaseDATDir = settings.AppSett.BaseDATDir; frmImport.ShowDialog(); } @@ -1027,6 +1029,27 @@ private void miServiceRestart_Click(object sender, EventArgs e) } } + private void miRemoteDownload_Click(object sender, EventArgs e) + { + // открытие формы скачивания конфигурации + FrmDownloadConfig frmDownloadConfig = new FrmDownloadConfig(); + frmDownloadConfig.ShowDialog(); + } + + private void miRemoteUpload_Click(object sender, EventArgs e) + { + // открытие формы передачи конфигурации + FrmUploadConfig frmUploadConfig = new FrmUploadConfig(); + frmUploadConfig.ShowDialog(); + } + + private void miRemoteStatus_Click(object sender, EventArgs e) + { + // открытие формы статуса сервера + FrmServerStatus frmServerStatus = new FrmServerStatus(); + frmServerStatus.ShowDialog(); + } + private void miWindowCloseActive_Click(object sender, EventArgs e) { FrmTable frmTable = winControl.ActiveForm as FrmTable; diff --git a/ScadaAdmin/ScadaAdmin/FrmMain.resx b/ScadaAdmin/ScadaAdmin/FrmMain.resx index f7549a9c6..3606e77d4 100644 --- a/ScadaAdmin/ScadaAdmin/FrmMain.resx +++ b/ScadaAdmin/ScadaAdmin/FrmMain.resx @@ -400,7 +400,7 @@ AAEAAAD/////AQAAAAAAAAAMAgAAAFdTeXN0ZW0uV2luZG93cy5Gb3JtcywgVmVyc2lvbj00LjAuMC4w LCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODkFAQAAACZTeXN0 ZW0uV2luZG93cy5Gb3Jtcy5JbWFnZUxpc3RTdHJlYW1lcgEAAAAERGF0YQcCAgAAAAkDAAAADwMAAAAY - DwAAAk1TRnQBSQFMAgEBBwEAAdgBAwHYAQMBEAEAARABAAT/AQkBAAj/AUIBTQE2AQQGAAE2AQQCAAEo + DwAAAk1TRnQBSQFMAgEBBwEAAeABAwHgAQMBEAEAARABAAT/AQkBAAj/AUIBTQE2AQQGAAE2AQQCAAEo AwABQAMAASADAAEBAQABCAYAAQgYAAGAAgABgAMAAoABAAGAAwABgAEAAYABAAKAAgADwAEAAcAB3AHA AQAB8AHKAaYBAAEzBQABMwEAATMBAAEzAQACMwIAAxYBAAMcAQADIgEAAykBAANVAQADTQEAA0IBAAM5 AQABgAF8Af8BAAJQAf8BAAGTAQAB1gEAAf8B7AHMAQABxgHWAe8BAAHWAucBAAGQAakBrQIAAf8BMwMA diff --git a/ScadaAdmin/ScadaAdmin/Lang/ScadaAdmin.en-GB.xml b/ScadaAdmin/ScadaAdmin/Lang/ScadaAdmin.en-GB.xml index 69e9b5a3e..566683197 100644 --- a/ScadaAdmin/ScadaAdmin/Lang/ScadaAdmin.en-GB.xml +++ b/ScadaAdmin/ScadaAdmin/Lang/ScadaAdmin.en-GB.xml @@ -4,16 +4,37 @@ The configuration database file in SDF format {0} not found. Update the open tables to display the changes. + + {0} Download Configuration + Connection : {0} + Session {0} created + Unable to create session + Logged on + Unable to login - {0} + Error connecting to Agent + No data to download + Download completed successfully in {0} sec. + Error downloading configuration + {0} Upload Configuration + Configuration is missing in the specified source. + Configuration uploaded + The Server service restarted + Unable to restart the Server service + The Communicator service restarted + Unable to restart the Communicator service + Upload completed successfully in {0} sec. Check the remote server. + Error uploading configuration + Choose a configuration database table file - Choose a configuration database archive file - Configuration Database Tables|*.dat|All Files|*.* - Configuration Database Archive|*.zip|All Files|*.* - Import file is undefined. + Choose a configuration archive file + Configuration Database Tables (*.dat)|*.dat|All Files (*.*)|*.* + Configuration Archive (*.zip)|*.zip|All Files (*.*)|*.* Import file does not exist. + Import directory does not exist. Import Configuration Database Import Configuration Database Table "{0}" - Source file : + Source file or directory : Error loading imported table Columns of the Source Table Columns of the Destination Table @@ -26,7 +47,9 @@ Import Result Import Table Result Import Table Errors - Error import the configuration database table + Error import the configuration database table + Error import all tables of the configuration database + Error import the configuration database from archive Export file is undefined. Export directory is undefined. Export directory does not exist. @@ -155,13 +178,14 @@ Import from File Table File + Directory Identifiers Start Final New start - Write to import log Import Close + All tables Tables from archive @@ -239,6 +263,10 @@ Channel Map... Restart SCADA-Server Restart SCADA-Communicator + &Remote Server + Download Configuration... + Upload Configuration... + Server Status... &Settings Parameters... Language... @@ -347,6 +375,10 @@ Are you sure you want to delete the rows? Are you sure you want to clear the table? + + Error loading settings of interaction with remote servers + Error saving settings of interaction with remote servers + Error saving the table changes to the database Error getting the data table schema @@ -495,4 +527,67 @@ Role Description + + Choose a configuration directory + Configuration directory is required. + File name of a configuration archive is required. + + + Connection to server + Create + Edit + Remove + Are you sure you want to delete the connection? + + + Connection Settings + Name + Server + Port + Username + Password + System instance + Secret key + Generate secret key + Empty field values are not allowed. + A connection with this name already exists. + Incorrect secret key. + + + Download Configuration + Download options + Save to directory: + Save to archive: + Including server specific files such as registration keys + Import the configuration database to SDF format after downloading + Download + Close + + + Server Status + Actions + Connect + Disconnect + Status + Server service + Restart + Communicator service + Restart + Update time + Close + Undefined + Normal + Stopped + Error + + + Upload Configuration + Upload options + Configuration directory: + Files to upload + Configuration archive file: + Clear server specific files such as registration keys + Upload + Close + diff --git a/ScadaAdmin/ScadaAdmin/Properties/AssemblyInfo.cs b/ScadaAdmin/ScadaAdmin/Properties/AssemblyInfo.cs index 8642062b7..56a0a2c59 100644 --- a/ScadaAdmin/ScadaAdmin/Properties/AssemblyInfo.cs +++ b/ScadaAdmin/ScadaAdmin/Properties/AssemblyInfo.cs @@ -9,7 +9,7 @@ [assembly: AssemblyConfiguration("")] [assembly: AssemblyCompany("")] [assembly: AssemblyProduct("Rapid SCADA")] -[assembly: AssemblyCopyright("Copyright © 2010-2017")] +[assembly: AssemblyCopyright("Copyright © 2010-2018")] [assembly: AssemblyTrademark("")] [assembly: AssemblyCulture("")] diff --git a/ScadaAdmin/ScadaAdmin/Remote/CtrlServerConn.Designer.cs b/ScadaAdmin/ScadaAdmin/Remote/CtrlServerConn.Designer.cs new file mode 100644 index 000000000..d48122186 --- /dev/null +++ b/ScadaAdmin/ScadaAdmin/Remote/CtrlServerConn.Designer.cs @@ -0,0 +1,113 @@ +namespace ScadaAdmin.Remote +{ + partial class CtrlServerConn + { + /// + /// Required designer variable. + /// + private System.ComponentModel.IContainer components = null; + + /// + /// Clean up any resources being used. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region Component Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + this.gbConnection = new System.Windows.Forms.GroupBox(); + this.btnRemoveConn = new System.Windows.Forms.Button(); + this.btnEditConn = new System.Windows.Forms.Button(); + this.btnCreateConn = new System.Windows.Forms.Button(); + this.cbConnection = new System.Windows.Forms.ComboBox(); + this.gbConnection.SuspendLayout(); + this.SuspendLayout(); + // + // gbConnection + // + this.gbConnection.Controls.Add(this.btnRemoveConn); + this.gbConnection.Controls.Add(this.btnEditConn); + this.gbConnection.Controls.Add(this.btnCreateConn); + this.gbConnection.Controls.Add(this.cbConnection); + this.gbConnection.Location = new System.Drawing.Point(0, 0); + this.gbConnection.Name = "gbConnection"; + this.gbConnection.Padding = new System.Windows.Forms.Padding(10, 3, 10, 10); + this.gbConnection.Size = new System.Drawing.Size(469, 55); + this.gbConnection.TabIndex = 1; + this.gbConnection.TabStop = false; + this.gbConnection.Text = "Подключение к серверу"; + // + // btnRemoveConn + // + this.btnRemoveConn.Location = new System.Drawing.Point(381, 19); + this.btnRemoveConn.Name = "btnRemoveConn"; + this.btnRemoveConn.Size = new System.Drawing.Size(75, 23); + this.btnRemoveConn.TabIndex = 3; + this.btnRemoveConn.Text = "Удалить"; + this.btnRemoveConn.UseVisualStyleBackColor = true; + this.btnRemoveConn.Click += new System.EventHandler(this.btnRemoveConn_Click); + // + // btnEditConn + // + this.btnEditConn.Location = new System.Drawing.Point(300, 19); + this.btnEditConn.Name = "btnEditConn"; + this.btnEditConn.Size = new System.Drawing.Size(75, 23); + this.btnEditConn.TabIndex = 2; + this.btnEditConn.Text = "Настроить"; + this.btnEditConn.UseVisualStyleBackColor = true; + this.btnEditConn.Click += new System.EventHandler(this.btnEditConn_Click); + // + // btnCreateConn + // + this.btnCreateConn.Location = new System.Drawing.Point(219, 19); + this.btnCreateConn.Name = "btnCreateConn"; + this.btnCreateConn.Size = new System.Drawing.Size(75, 23); + this.btnCreateConn.TabIndex = 1; + this.btnCreateConn.Text = "Создать"; + this.btnCreateConn.UseVisualStyleBackColor = true; + this.btnCreateConn.Click += new System.EventHandler(this.btnCreateConn_Click); + // + // cbConnection + // + this.cbConnection.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList; + this.cbConnection.FormattingEnabled = true; + this.cbConnection.Location = new System.Drawing.Point(13, 20); + this.cbConnection.Name = "cbConnection"; + this.cbConnection.Size = new System.Drawing.Size(200, 21); + this.cbConnection.TabIndex = 0; + this.cbConnection.SelectedIndexChanged += new System.EventHandler(this.cbConnection_SelectedIndexChanged); + // + // CtrlServerConn + // + this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.Controls.Add(this.gbConnection); + this.Name = "CtrlServerConn"; + this.Size = new System.Drawing.Size(469, 55); + this.gbConnection.ResumeLayout(false); + this.ResumeLayout(false); + + } + + #endregion + + private System.Windows.Forms.GroupBox gbConnection; + private System.Windows.Forms.Button btnRemoveConn; + private System.Windows.Forms.Button btnEditConn; + private System.Windows.Forms.Button btnCreateConn; + private System.Windows.Forms.ComboBox cbConnection; + } +} diff --git a/ScadaAdmin/ScadaAdmin/Remote/CtrlServerConn.cs b/ScadaAdmin/ScadaAdmin/Remote/CtrlServerConn.cs new file mode 100644 index 000000000..d1fa8336b --- /dev/null +++ b/ScadaAdmin/ScadaAdmin/Remote/CtrlServerConn.cs @@ -0,0 +1,236 @@ +/* + * Copyright 2018 Mikhail Shiryaev + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * + * Product : Rapid SCADA + * Module : SCADA-Administrator + * Summary : Control for selecting a connection to a remote server + * + * Author : Mikhail Shiryaev + * Created : 2018 + * Modified : 2018 + */ + +using Scada; +using System; +using System.ComponentModel; +using System.Windows.Forms; + +namespace ScadaAdmin.Remote +{ + /// + /// Control for selecting a connection to a remote server + /// Элемент управления для выбора подключения к удалённому серверу + /// + public partial class CtrlServerConn : UserControl + { + private ServersSettings serversSettings; // настройки взаимодействия с удалёнными серверами + + + /// + /// Конструктор + /// + public CtrlServerConn() + { + InitializeComponent(); + serversSettings = null; + } + + + /// + /// Получить или установить настройки взаимодействия с удалёнными серверами + /// + public ServersSettings ServersSettings + { + get + { + return serversSettings; + } + set + { + serversSettings = value; + FillConnList(); + } + } + + /// + /// Получить выбранные настройки + /// + public ServersSettings.ServerSettings SelectedSettings + { + get + { + return cbConnection.SelectedItem as ServersSettings.ServerSettings; + } + } + + + /// + /// Заполнить список подключений + /// + private void FillConnList() + { + try + { + cbConnection.BeginUpdate(); + cbConnection.Items.Clear(); + int selInd = 0; + + if (serversSettings != null) + { + string defConnName = AppData.Settings.FormSt.ServerConn; + + foreach (ServersSettings.ServerSettings serverSettings in serversSettings.Servers.Values) + { + int ind = cbConnection.Items.Add(serverSettings); + if (string.Equals(serverSettings.Connection.Name, defConnName)) + selInd = ind; + } + } + + if (cbConnection.Items.Count > 0) + cbConnection.SelectedIndex = selInd; + } + finally + { + cbConnection.EndUpdate(); + } + } + + /// + /// Добавить настройки сервера в общие настройки и выпадающий список + /// + private void AddToLists(ServersSettings.ServerSettings serverSettings) + { + // добавление в общие настройки + string connName = serverSettings.Connection.Name; + serversSettings.Servers.Add(connName, serverSettings); + + // добавление в выпадающий список + int ind = serversSettings.Servers.IndexOfKey(connName); + if (ind >= 0) + { + cbConnection.Items.Insert(ind, serverSettings); + cbConnection.SelectedIndex = ind; + } + } + + /// + /// Сохранить настройки взаимодействия с удалёнными серверами + /// + private void SaveServersSettings() + { + if (!serversSettings.Save(AppData.AppDirs.ConfigDir + ServersSettings.DefFileName, out string errMsg)) + AppUtils.ProcError(errMsg); + } + + /// + /// Вызвать событие SelectedSettingsChanged + /// + private void OnSelectedSettingsChanged() + { + SelectedSettingsChanged?.Invoke(this, EventArgs.Empty); + } + + + /// + /// Событие возникающее при изменении выбранного соединения + /// + [Category("Property Changed")] + public event EventHandler SelectedSettingsChanged; + + + private void cbConnection_SelectedIndexChanged(object sender, EventArgs e) + { + btnCreateConn.Enabled = serversSettings != null; + btnEditConn.Enabled = btnRemoveConn.Enabled = SelectedSettings != null; + OnSelectedSettingsChanged(); + } + + private void btnCreateConn_Click(object sender, EventArgs e) + { + // создание новых настроек + ServersSettings.ServerSettings serverSettings = new ServersSettings.ServerSettings(); + FrmConnSettings frmConnSettings = new FrmConnSettings() + { + ConnectionSettings = serverSettings.Connection, + ExistingNames = ServersSettings.GetExistingNames() + }; + + if (frmConnSettings.ShowDialog() == DialogResult.OK) + { + AddToLists(serverSettings); + SaveServersSettings(); + } + } + + private void btnEditConn_Click(object sender, EventArgs e) + { + // редактирование настроек + ServersSettings.ServerSettings serverSettings = SelectedSettings; + string oldName = serverSettings.Connection.Name; + + FrmConnSettings frmConnSettings = new FrmConnSettings() + { + ConnectionSettings = serverSettings.Connection, + ExistingNames = ServersSettings.GetExistingNames(oldName) + }; + + if (frmConnSettings.ShowDialog() == DialogResult.OK) + { + // обновление наименования, если оно изменилось + if (!string.Equals(oldName, serverSettings.Connection.Name, StringComparison.Ordinal)) + { + serversSettings.Servers.Remove(oldName); + cbConnection.BeginUpdate(); + cbConnection.Items.RemoveAt(cbConnection.SelectedIndex); + AddToLists(serverSettings); + cbConnection.EndUpdate(); + } + + // сохранение настроек + SaveServersSettings(); + } + } + + private void btnRemoveConn_Click(object sender, EventArgs e) + { + // удаление настроек + if (MessageBox.Show(AppPhrases.DeleteConnConfirm, CommonPhrases.QuestionCaption, + MessageBoxButtons.YesNoCancel, MessageBoxIcon.Question) == DialogResult.Yes) + { + // удаление из общих настроек + ServersSettings.ServerSettings serverSettings = SelectedSettings; + serversSettings.Servers.Remove(serverSettings.Connection.Name); + + // удаление из выпадающего списка + cbConnection.BeginUpdate(); + int selInd = cbConnection.SelectedIndex; + cbConnection.Items.RemoveAt(selInd); + + if (cbConnection.Items.Count > 0) + { + cbConnection.SelectedIndex = selInd >= cbConnection.Items.Count ? + cbConnection.Items.Count - 1 : selInd; + } + + cbConnection.EndUpdate(); + + // сохранение настроек + SaveServersSettings(); + } + } + } +} diff --git a/ScadaAgent/ScadaAgent/ScadaAgentCtrl/FrmMain.resx b/ScadaAdmin/ScadaAdmin/Remote/CtrlServerConn.resx similarity index 100% rename from ScadaAgent/ScadaAgent/ScadaAgentCtrl/FrmMain.resx rename to ScadaAdmin/ScadaAdmin/Remote/CtrlServerConn.resx diff --git a/ScadaAdmin/ScadaAdmin/Remote/FrmConnSettings.Designer.cs b/ScadaAdmin/ScadaAdmin/Remote/FrmConnSettings.Designer.cs new file mode 100644 index 000000000..7cd12e3f1 --- /dev/null +++ b/ScadaAdmin/ScadaAdmin/Remote/FrmConnSettings.Designer.cs @@ -0,0 +1,269 @@ +namespace ScadaAdmin.Remote +{ + partial class FrmConnSettings + { + /// + /// Required designer variable. + /// + private System.ComponentModel.IContainer components = null; + + /// + /// Clean up any resources being used. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region Windows Form Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + this.components = new System.ComponentModel.Container(); + System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(FrmConnSettings)); + this.lblName = new System.Windows.Forms.Label(); + this.txtName = new System.Windows.Forms.TextBox(); + this.txtHost = new System.Windows.Forms.TextBox(); + this.lblHost = new System.Windows.Forms.Label(); + this.numPort = new System.Windows.Forms.NumericUpDown(); + this.lblPort = new System.Windows.Forms.Label(); + this.txtUsername = new System.Windows.Forms.TextBox(); + this.lblUsername = new System.Windows.Forms.Label(); + this.txtPassword = new System.Windows.Forms.TextBox(); + this.lblPassword = new System.Windows.Forms.Label(); + this.txtScadaInstance = new System.Windows.Forms.TextBox(); + this.lblScadaInstance = new System.Windows.Forms.Label(); + this.txtSecretKey = new System.Windows.Forms.TextBox(); + this.lblSecretKey = new System.Windows.Forms.Label(); + this.btnGenSecretKey = new System.Windows.Forms.Button(); + this.btnOK = new System.Windows.Forms.Button(); + this.btnCancel = new System.Windows.Forms.Button(); + this.toolTip = new System.Windows.Forms.ToolTip(this.components); + ((System.ComponentModel.ISupportInitialize)(this.numPort)).BeginInit(); + this.SuspendLayout(); + // + // lblName + // + this.lblName.AutoSize = true; + this.lblName.Location = new System.Drawing.Point(9, 9); + this.lblName.Name = "lblName"; + this.lblName.Size = new System.Drawing.Size(83, 13); + this.lblName.TabIndex = 0; + this.lblName.Text = "Наименование"; + // + // txtName + // + this.txtName.Location = new System.Drawing.Point(12, 25); + this.txtName.Name = "txtName"; + this.txtName.Size = new System.Drawing.Size(250, 20); + this.txtName.TabIndex = 1; + // + // txtHost + // + this.txtHost.Location = new System.Drawing.Point(12, 64); + this.txtHost.Name = "txtHost"; + this.txtHost.Size = new System.Drawing.Size(169, 20); + this.txtHost.TabIndex = 3; + // + // lblHost + // + this.lblHost.AutoSize = true; + this.lblHost.Location = new System.Drawing.Point(9, 48); + this.lblHost.Name = "lblHost"; + this.lblHost.Size = new System.Drawing.Size(44, 13); + this.lblHost.TabIndex = 2; + this.lblHost.Text = "Сервер"; + // + // numPort + // + this.numPort.Location = new System.Drawing.Point(187, 64); + this.numPort.Maximum = new decimal(new int[] { + 65535, + 0, + 0, + 0}); + this.numPort.Name = "numPort"; + this.numPort.Size = new System.Drawing.Size(75, 20); + this.numPort.TabIndex = 5; + this.numPort.Value = new decimal(new int[] { + 10002, + 0, + 0, + 0}); + // + // lblPort + // + this.lblPort.AutoSize = true; + this.lblPort.Location = new System.Drawing.Point(184, 48); + this.lblPort.Name = "lblPort"; + this.lblPort.Size = new System.Drawing.Size(32, 13); + this.lblPort.TabIndex = 4; + this.lblPort.Text = "Порт"; + // + // txtUsername + // + this.txtUsername.Location = new System.Drawing.Point(12, 103); + this.txtUsername.Name = "txtUsername"; + this.txtUsername.Size = new System.Drawing.Size(250, 20); + this.txtUsername.TabIndex = 7; + // + // lblUsername + // + this.lblUsername.AutoSize = true; + this.lblUsername.Location = new System.Drawing.Point(9, 87); + this.lblUsername.Name = "lblUsername"; + this.lblUsername.Size = new System.Drawing.Size(80, 13); + this.lblUsername.TabIndex = 6; + this.lblUsername.Text = "Пользователь"; + // + // txtPassword + // + this.txtPassword.Location = new System.Drawing.Point(12, 142); + this.txtPassword.Name = "txtPassword"; + this.txtPassword.Size = new System.Drawing.Size(250, 20); + this.txtPassword.TabIndex = 9; + this.txtPassword.UseSystemPasswordChar = true; + // + // lblPassword + // + this.lblPassword.AutoSize = true; + this.lblPassword.Location = new System.Drawing.Point(9, 126); + this.lblPassword.Name = "lblPassword"; + this.lblPassword.Size = new System.Drawing.Size(45, 13); + this.lblPassword.TabIndex = 8; + this.lblPassword.Text = "Пароль"; + // + // txtScadaInstance + // + this.txtScadaInstance.Location = new System.Drawing.Point(12, 181); + this.txtScadaInstance.Name = "txtScadaInstance"; + this.txtScadaInstance.Size = new System.Drawing.Size(250, 20); + this.txtScadaInstance.TabIndex = 11; + // + // lblScadaInstance + // + this.lblScadaInstance.AutoSize = true; + this.lblScadaInstance.Location = new System.Drawing.Point(9, 165); + this.lblScadaInstance.Name = "lblScadaInstance"; + this.lblScadaInstance.Size = new System.Drawing.Size(112, 13); + this.lblScadaInstance.TabIndex = 10; + this.lblScadaInstance.Text = "Экземпляр системы"; + // + // txtSecretKey + // + this.txtSecretKey.Location = new System.Drawing.Point(12, 230); + this.txtSecretKey.Multiline = true; + this.txtSecretKey.Name = "txtSecretKey"; + this.txtSecretKey.Size = new System.Drawing.Size(250, 40); + this.txtSecretKey.TabIndex = 14; + // + // lblSecretKey + // + this.lblSecretKey.AutoSize = true; + this.lblSecretKey.Location = new System.Drawing.Point(9, 214); + this.lblSecretKey.Name = "lblSecretKey"; + this.lblSecretKey.Size = new System.Drawing.Size(91, 13); + this.lblSecretKey.TabIndex = 12; + this.lblSecretKey.Text = "Секретный ключ"; + // + // btnGenSecretKey + // + this.btnGenSecretKey.FlatStyle = System.Windows.Forms.FlatStyle.Popup; + this.btnGenSecretKey.Image = ((System.Drawing.Image)(resources.GetObject("btnGenSecretKey.Image"))); + this.btnGenSecretKey.Location = new System.Drawing.Point(242, 207); + this.btnGenSecretKey.Name = "btnGenSecretKey"; + this.btnGenSecretKey.Size = new System.Drawing.Size(20, 20); + this.btnGenSecretKey.TabIndex = 13; + this.toolTip.SetToolTip(this.btnGenSecretKey, "Генерировать секретный ключ"); + this.btnGenSecretKey.UseVisualStyleBackColor = true; + this.btnGenSecretKey.Click += new System.EventHandler(this.btnGenSecretKey_Click); + // + // btnOK + // + this.btnOK.Location = new System.Drawing.Point(106, 276); + this.btnOK.Name = "btnOK"; + this.btnOK.Size = new System.Drawing.Size(75, 23); + this.btnOK.TabIndex = 15; + this.btnOK.Text = "OK"; + this.btnOK.UseVisualStyleBackColor = true; + this.btnOK.Click += new System.EventHandler(this.btnOK_Click); + // + // btnCancel + // + this.btnCancel.DialogResult = System.Windows.Forms.DialogResult.Cancel; + this.btnCancel.Location = new System.Drawing.Point(187, 276); + this.btnCancel.Name = "btnCancel"; + this.btnCancel.Size = new System.Drawing.Size(75, 23); + this.btnCancel.TabIndex = 16; + this.btnCancel.Text = "Отмена"; + this.btnCancel.UseVisualStyleBackColor = true; + // + // FrmConnSettings + // + this.AcceptButton = this.btnOK; + this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.CancelButton = this.btnCancel; + this.ClientSize = new System.Drawing.Size(274, 311); + this.Controls.Add(this.btnCancel); + this.Controls.Add(this.btnOK); + this.Controls.Add(this.btnGenSecretKey); + this.Controls.Add(this.txtSecretKey); + this.Controls.Add(this.lblSecretKey); + this.Controls.Add(this.txtScadaInstance); + this.Controls.Add(this.lblScadaInstance); + this.Controls.Add(this.lblPassword); + this.Controls.Add(this.txtPassword); + this.Controls.Add(this.txtUsername); + this.Controls.Add(this.lblUsername); + this.Controls.Add(this.lblPort); + this.Controls.Add(this.numPort); + this.Controls.Add(this.txtHost); + this.Controls.Add(this.lblHost); + this.Controls.Add(this.txtName); + this.Controls.Add(this.lblName); + this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedDialog; + this.MaximizeBox = false; + this.MinimizeBox = false; + this.Name = "FrmConnSettings"; + this.ShowInTaskbar = false; + this.StartPosition = System.Windows.Forms.FormStartPosition.CenterScreen; + this.Text = "Настройки соединения"; + this.Load += new System.EventHandler(this.FrmConnSettings_Load); + ((System.ComponentModel.ISupportInitialize)(this.numPort)).EndInit(); + this.ResumeLayout(false); + this.PerformLayout(); + + } + + #endregion + + private System.Windows.Forms.Label lblName; + private System.Windows.Forms.TextBox txtName; + private System.Windows.Forms.TextBox txtHost; + private System.Windows.Forms.Label lblHost; + private System.Windows.Forms.NumericUpDown numPort; + private System.Windows.Forms.Label lblPort; + private System.Windows.Forms.TextBox txtUsername; + private System.Windows.Forms.Label lblUsername; + private System.Windows.Forms.TextBox txtPassword; + private System.Windows.Forms.Label lblPassword; + private System.Windows.Forms.TextBox txtScadaInstance; + private System.Windows.Forms.Label lblScadaInstance; + private System.Windows.Forms.TextBox txtSecretKey; + private System.Windows.Forms.Label lblSecretKey; + private System.Windows.Forms.Button btnGenSecretKey; + private System.Windows.Forms.Button btnOK; + private System.Windows.Forms.Button btnCancel; + private System.Windows.Forms.ToolTip toolTip; + } +} \ No newline at end of file diff --git a/ScadaAdmin/ScadaAdmin/Remote/FrmConnSettings.cs b/ScadaAdmin/ScadaAdmin/Remote/FrmConnSettings.cs new file mode 100644 index 000000000..4838a8ea8 --- /dev/null +++ b/ScadaAdmin/ScadaAdmin/Remote/FrmConnSettings.cs @@ -0,0 +1,151 @@ +/* + * Copyright 2018 Mikhail Shiryaev + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * + * Product : Rapid SCADA + * Module : SCADA-Administrator + * Summary : Remote server connection settings form + * + * Author : Mikhail Shiryaev + * Created : 2018 + * Modified : 2018 + */ + +using Scada; +using Scada.UI; +using System; +using System.Collections.Generic; +using System.Windows.Forms; + +namespace ScadaAdmin.Remote +{ + /// + /// Remote server connection settings form + /// Форма настроек подключения к удалённому серверу + /// + public partial class FrmConnSettings : Form + { + /// + /// Конструктор + /// + public FrmConnSettings() + { + InitializeComponent(); + } + + + /// + /// Получить или установить редактируемые настройки подключения + /// + public ServersSettings.ConnectionSettings ConnectionSettings { get; set; } + + /// + /// Получить или установить существующие наименования настроек + /// + public HashSet ExistingNames { get; set; } + + + /// + /// Установить элементы управления в соответствии с настройками + /// + private void SettingsToControls() + { + if (ConnectionSettings != null) + { + txtName.Text = ConnectionSettings.Name; + txtHost.Text = ConnectionSettings.Host; + numPort.SetValue(ConnectionSettings.Port); + txtUsername.Text = ConnectionSettings.Username; + txtPassword.Text = ConnectionSettings.Password; + txtScadaInstance.Text = ConnectionSettings.ScadaInstance; + txtSecretKey.Text = ScadaUtils.BytesToHex(ConnectionSettings.SecretKey); + } + } + + /// + /// Установить настройки в соответствии с элементами управления + /// + private void ControlsToSettings() + { + if (ConnectionSettings != null) + { + ConnectionSettings.Name = txtName.Text.Trim(); + ConnectionSettings.Host = txtHost.Text.Trim(); + ConnectionSettings.Port = (int)numPort.Value; + ConnectionSettings.Username = txtUsername.Text.Trim(); + ConnectionSettings.Password = txtPassword.Text; + ConnectionSettings.ScadaInstance = txtScadaInstance.Text.Trim(); + ConnectionSettings.SecretKey = ScadaUtils.HexToBytes(txtSecretKey.Text.Trim()); + } + } + + /// + /// Проверить значения элементов управления + /// + private bool ValidateControls() + { + if (string.IsNullOrWhiteSpace(txtName.Text) || + string.IsNullOrWhiteSpace(txtHost.Text) || + string.IsNullOrWhiteSpace(txtUsername.Text) || + string.IsNullOrWhiteSpace(txtPassword.Text) || + string.IsNullOrWhiteSpace(txtScadaInstance.Text) || + string.IsNullOrWhiteSpace(txtSecretKey.Text)) + { + ScadaUiUtils.ShowError(AppPhrases.EmptyFieldsNotAllowed); + return false; + } + + if (ExistingNames.Contains(txtName.Text.Trim())) + { + ScadaUiUtils.ShowError(AppPhrases.ConnNameDuplicated); + return false; + } + + if (!ScadaUtils.HexToBytes(txtSecretKey.Text.Trim(), out byte[] bytes)) + { + ScadaUiUtils.ShowError(AppPhrases.IncorrectSecretKey); + return false; + } + + return true; + } + + + private void FrmConnSettings_Load(object sender, EventArgs e) + { + // перевод формы + Translator.TranslateForm(this, "ScadaAdmin.Remote.FrmConnSettings", toolTip); + + // отображение настроек + SettingsToControls(); + } + + private void btnGenSecretKey_Click(object sender, EventArgs e) + { + // генерация секретного ключа + txtSecretKey.Text = ScadaUtils.BytesToHex(ScadaUtils.GetRandomBytes(ScadaUtils.SecretKeySize)); + txtSecretKey.Focus(); + } + + private void btnOK_Click(object sender, EventArgs e) + { + if (ValidateControls()) + { + ControlsToSettings(); + DialogResult = DialogResult.OK; + } + } + } +} diff --git a/ScadaAdmin/ScadaAdmin/Remote/FrmConnSettings.resx b/ScadaAdmin/ScadaAdmin/Remote/FrmConnSettings.resx new file mode 100644 index 000000000..1758942e8 --- /dev/null +++ b/ScadaAdmin/ScadaAdmin/Remote/FrmConnSettings.resx @@ -0,0 +1,135 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + + + iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABGdBTUEAALGPC/xhBQAAAAlwSFlzAAAL + EwAACxMBAJqcGAAAAAd0SU1FB+IFDRAyEEEzoOEAAAEpSURBVDhPYxh8IMxe1ODUtsz/m+cE/Z/VYPl/ + Qr7q/74syf/BNsI6UCX4wcoJ7v//f53///+vdf8/PJ8EpDf+//qy63+GF8t/qBL8YFKpwf//39f9f/+4 + /X91ot7/j097////se5/vBMrcQZ0Zij///mm/f//z7P//3/f/P//t0X/753N/e+gxUacAZEOYqrV0TL/ + /7+uARrQ9f/ppYT/zsa8/x31eJKgSgiDaEcRj+4suf//Xpb/tzPgfm2tw+MKlSIedGfL/f//PO//zZ3W + X0wUWc5AhYkHNXHi//8/CP/vZczxx8mAxxoqTDwoDBT6//9x7N9989Q/KosyP4AKEw8SHbn+vT6g9d1U + me2+sSp3EFSYeBDpIOroa8j+1kKDxxMqNDwBAwMAUEuGdf4YP7YAAAAASUVORK5CYII= + + + + 17, 17 + + \ No newline at end of file diff --git a/ScadaAdmin/ScadaAdmin/Remote/FrmDownloadConfig.Designer.cs b/ScadaAdmin/ScadaAdmin/Remote/FrmDownloadConfig.Designer.cs new file mode 100644 index 000000000..bfcfc40a2 --- /dev/null +++ b/ScadaAdmin/ScadaAdmin/Remote/FrmDownloadConfig.Designer.cs @@ -0,0 +1,230 @@ +namespace ScadaAdmin.Remote +{ + partial class FrmDownloadConfig + { + /// + /// Required designer variable. + /// + private System.ComponentModel.IContainer components = null; + + /// + /// Clean up any resources being used. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region Windows Form Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(FrmDownloadConfig)); + this.rbSaveToDir = new System.Windows.Forms.RadioButton(); + this.txtDestDir = new System.Windows.Forms.TextBox(); + this.btnBrowseDestDir = new System.Windows.Forms.Button(); + this.rbSaveToArc = new System.Windows.Forms.RadioButton(); + this.btnSelectDestFile = new System.Windows.Forms.Button(); + this.txtDestFile = new System.Windows.Forms.TextBox(); + this.btnDownload = new System.Windows.Forms.Button(); + this.btnClose = new System.Windows.Forms.Button(); + this.gbOptions = new System.Windows.Forms.GroupBox(); + this.chkIncludeSpecificFiles = new System.Windows.Forms.CheckBox(); + this.chkImportBase = new System.Windows.Forms.CheckBox(); + this.openFileDialog = new System.Windows.Forms.OpenFileDialog(); + this.folderBrowserDialog = new System.Windows.Forms.FolderBrowserDialog(); + this.ctrlServerConn = new ScadaAdmin.Remote.CtrlServerConn(); + this.gbOptions.SuspendLayout(); + this.SuspendLayout(); + // + // rbSaveToDir + // + this.rbSaveToDir.AutoSize = true; + this.rbSaveToDir.Location = new System.Drawing.Point(13, 19); + this.rbSaveToDir.Name = "rbSaveToDir"; + this.rbSaveToDir.Size = new System.Drawing.Size(154, 17); + this.rbSaveToDir.TabIndex = 0; + this.rbSaveToDir.Text = "Сохранить в директорию:"; + this.rbSaveToDir.UseVisualStyleBackColor = true; + this.rbSaveToDir.CheckedChanged += new System.EventHandler(this.rbSave_CheckedChanged); + // + // txtDestDir + // + this.txtDestDir.Location = new System.Drawing.Point(13, 43); + this.txtDestDir.Name = "txtDestDir"; + this.txtDestDir.Size = new System.Drawing.Size(417, 20); + this.txtDestDir.TabIndex = 1; + this.txtDestDir.Text = "C:\\SCADA\\"; + this.txtDestDir.TextChanged += new System.EventHandler(this.downloadControl_Changed); + // + // btnBrowseDestDir + // + this.btnBrowseDestDir.FlatStyle = System.Windows.Forms.FlatStyle.Popup; + this.btnBrowseDestDir.Image = ((System.Drawing.Image)(resources.GetObject("btnBrowseDestDir.Image"))); + this.btnBrowseDestDir.Location = new System.Drawing.Point(436, 43); + this.btnBrowseDestDir.Name = "btnBrowseDestDir"; + this.btnBrowseDestDir.Size = new System.Drawing.Size(20, 20); + this.btnBrowseDestDir.TabIndex = 2; + this.btnBrowseDestDir.UseVisualStyleBackColor = true; + this.btnBrowseDestDir.Click += new System.EventHandler(this.btnBrowseDestDir_Click); + // + // rbSaveToArc + // + this.rbSaveToArc.AutoSize = true; + this.rbSaveToArc.Location = new System.Drawing.Point(13, 69); + this.rbSaveToArc.Name = "rbSaveToArc"; + this.rbSaveToArc.Size = new System.Drawing.Size(122, 17); + this.rbSaveToArc.TabIndex = 3; + this.rbSaveToArc.Text = "Сохранить в архив:"; + this.rbSaveToArc.UseVisualStyleBackColor = true; + this.rbSaveToArc.CheckedChanged += new System.EventHandler(this.rbSave_CheckedChanged); + // + // btnSelectDestFile + // + this.btnSelectDestFile.FlatStyle = System.Windows.Forms.FlatStyle.Popup; + this.btnSelectDestFile.Image = ((System.Drawing.Image)(resources.GetObject("btnSelectDestFile.Image"))); + this.btnSelectDestFile.Location = new System.Drawing.Point(436, 92); + this.btnSelectDestFile.Name = "btnSelectDestFile"; + this.btnSelectDestFile.Size = new System.Drawing.Size(20, 20); + this.btnSelectDestFile.TabIndex = 5; + this.btnSelectDestFile.UseVisualStyleBackColor = true; + this.btnSelectDestFile.Click += new System.EventHandler(this.btnSelectDestFile_Click); + // + // txtDestFile + // + this.txtDestFile.Location = new System.Drawing.Point(13, 92); + this.txtDestFile.Name = "txtDestFile"; + this.txtDestFile.Size = new System.Drawing.Size(417, 20); + this.txtDestFile.TabIndex = 4; + this.txtDestFile.TextChanged += new System.EventHandler(this.downloadControl_Changed); + // + // btnDownload + // + this.btnDownload.Location = new System.Drawing.Point(325, 255); + this.btnDownload.Name = "btnDownload"; + this.btnDownload.Size = new System.Drawing.Size(75, 23); + this.btnDownload.TabIndex = 2; + this.btnDownload.Text = "Скачать"; + this.btnDownload.UseVisualStyleBackColor = true; + this.btnDownload.Click += new System.EventHandler(this.btnDownload_Click); + // + // btnClose + // + this.btnClose.DialogResult = System.Windows.Forms.DialogResult.Cancel; + this.btnClose.Location = new System.Drawing.Point(406, 255); + this.btnClose.Name = "btnClose"; + this.btnClose.Size = new System.Drawing.Size(75, 23); + this.btnClose.TabIndex = 3; + this.btnClose.Text = "Закрыть"; + this.btnClose.UseVisualStyleBackColor = true; + // + // gbOptions + // + this.gbOptions.Controls.Add(this.chkIncludeSpecificFiles); + this.gbOptions.Controls.Add(this.chkImportBase); + this.gbOptions.Controls.Add(this.rbSaveToDir); + this.gbOptions.Controls.Add(this.txtDestDir); + this.gbOptions.Controls.Add(this.btnBrowseDestDir); + this.gbOptions.Controls.Add(this.btnSelectDestFile); + this.gbOptions.Controls.Add(this.rbSaveToArc); + this.gbOptions.Controls.Add(this.txtDestFile); + this.gbOptions.Location = new System.Drawing.Point(12, 73); + this.gbOptions.Name = "gbOptions"; + this.gbOptions.Padding = new System.Windows.Forms.Padding(10, 3, 10, 10); + this.gbOptions.Size = new System.Drawing.Size(469, 176); + this.gbOptions.TabIndex = 1; + this.gbOptions.TabStop = false; + this.gbOptions.Text = "Параметры скачивания"; + // + // chkIncludeSpecificFiles + // + this.chkIncludeSpecificFiles.AutoSize = true; + this.chkIncludeSpecificFiles.Location = new System.Drawing.Point(13, 123); + this.chkIncludeSpecificFiles.Name = "chkIncludeSpecificFiles"; + this.chkIncludeSpecificFiles.Size = new System.Drawing.Size(441, 17); + this.chkIncludeSpecificFiles.TabIndex = 6; + this.chkIncludeSpecificFiles.Text = "Включая файлы специфичные для сервера, в том числе, регистрационные ключи"; + this.chkIncludeSpecificFiles.UseVisualStyleBackColor = true; + this.chkIncludeSpecificFiles.CheckedChanged += new System.EventHandler(this.downloadControl_Changed); + // + // chkImportBase + // + this.chkImportBase.AutoSize = true; + this.chkImportBase.Location = new System.Drawing.Point(13, 146); + this.chkImportBase.Name = "chkImportBase"; + this.chkImportBase.Size = new System.Drawing.Size(339, 17); + this.chkImportBase.TabIndex = 7; + this.chkImportBase.Text = "Импорт базы конфигурации в формат SDF после скачивания"; + this.chkImportBase.UseVisualStyleBackColor = true; + this.chkImportBase.CheckedChanged += new System.EventHandler(this.downloadControl_Changed); + // + // openFileDialog + // + this.openFileDialog.CheckFileExists = false; + this.openFileDialog.DefaultExt = "*.zip"; + this.openFileDialog.Filter = "Архивы конфигурации (*.zip)|*.zip|Все файлы (*.*)|*.*"; + this.openFileDialog.Title = "Выберите файл архива конфигурации"; + // + // folderBrowserDialog + // + this.folderBrowserDialog.Description = "Выберите директорию конфигурации"; + // + // ctrlServerConn + // + this.ctrlServerConn.Location = new System.Drawing.Point(12, 12); + this.ctrlServerConn.Name = "ctrlServerConn"; + this.ctrlServerConn.ServersSettings = null; + this.ctrlServerConn.Size = new System.Drawing.Size(469, 55); + this.ctrlServerConn.TabIndex = 0; + this.ctrlServerConn.SelectedSettingsChanged += new System.EventHandler(this.ctrlServerConn_SelectedSettingsChanged); + // + // FrmDownloadConfig + // + this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.CancelButton = this.btnClose; + this.ClientSize = new System.Drawing.Size(493, 290); + this.Controls.Add(this.ctrlServerConn); + this.Controls.Add(this.gbOptions); + this.Controls.Add(this.btnClose); + this.Controls.Add(this.btnDownload); + this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedDialog; + this.MaximizeBox = false; + this.MinimizeBox = false; + this.Name = "FrmDownloadConfig"; + this.ShowInTaskbar = false; + this.StartPosition = System.Windows.Forms.FormStartPosition.CenterParent; + this.Text = "Скачивание конфигурации"; + this.Load += new System.EventHandler(this.FrmDownloadConfig_Load); + this.gbOptions.ResumeLayout(false); + this.gbOptions.PerformLayout(); + this.ResumeLayout(false); + + } + + #endregion + private System.Windows.Forms.RadioButton rbSaveToDir; + private System.Windows.Forms.TextBox txtDestDir; + private System.Windows.Forms.Button btnBrowseDestDir; + private System.Windows.Forms.RadioButton rbSaveToArc; + private System.Windows.Forms.Button btnSelectDestFile; + private System.Windows.Forms.TextBox txtDestFile; + private System.Windows.Forms.Button btnDownload; + private System.Windows.Forms.Button btnClose; + private System.Windows.Forms.GroupBox gbOptions; + private CtrlServerConn ctrlServerConn; + private System.Windows.Forms.OpenFileDialog openFileDialog; + private System.Windows.Forms.FolderBrowserDialog folderBrowserDialog; + private System.Windows.Forms.CheckBox chkImportBase; + private System.Windows.Forms.CheckBox chkIncludeSpecificFiles; + } +} \ No newline at end of file diff --git a/ScadaAdmin/ScadaAdmin/Remote/FrmDownloadConfig.cs b/ScadaAdmin/ScadaAdmin/Remote/FrmDownloadConfig.cs new file mode 100644 index 000000000..b375b11d7 --- /dev/null +++ b/ScadaAdmin/ScadaAdmin/Remote/FrmDownloadConfig.cs @@ -0,0 +1,263 @@ +/* + * Copyright 2018 Mikhail Shiryaev + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * + * Product : Rapid SCADA + * Module : SCADA-Administrator + * Summary : Download configuration form + * + * Author : Mikhail Shiryaev + * Created : 2018 + * Modified : 2018 + */ + +using Scada; +using Scada.UI; +using System; +using System.Diagnostics; +using System.IO; +using System.Windows.Forms; + +namespace ScadaAdmin.Remote +{ + /// + /// Download configuration form + /// Форма скачивания конфигурации + /// + public partial class FrmDownloadConfig : Form + { + private ServersSettings serversSettings; // настройки взаимодействия с удалёнными серверами + private bool downloadSettingsModified; // последние выбранные настройки скачивания были изменены + + + /// + /// Конструктор + /// + public FrmDownloadConfig() + { + InitializeComponent(); + serversSettings = new ServersSettings(); + downloadSettingsModified = false; + } + + + /// + /// Отобразить настройки скачивания конфигурации + /// + private void ShowDownloadSettings(ServersSettings.DownloadSettings downloadSettings) + { + if (downloadSettings == null) + { + gbOptions.Enabled = false; + rbSaveToDir.Checked = true; + txtDestDir.Text = txtDestFile.Text = ""; + chkIncludeSpecificFiles.Checked = false; + chkImportBase.Checked = false; + btnDownload.Enabled = false; + } + else + { + gbOptions.Enabled = true; + txtDestDir.Text = downloadSettings.DestDir; + txtDestFile.Text = downloadSettings.DestFile; + chkIncludeSpecificFiles.Checked = downloadSettings.IncludeSpecificFiles; + chkImportBase.Checked = downloadSettings.ImportBase; + btnDownload.Enabled = true; + + if (downloadSettings.SaveToDir) + rbSaveToDir.Checked = true; + else + rbSaveToArc.Checked = true; + } + } + + /// + /// Проверить настройки скачивания конфигурации + /// + private bool ValidateDownloadSettings() + { + if (rbSaveToDir.Checked) + { + if (string.IsNullOrWhiteSpace(txtDestDir.Text)) + { + ScadaUiUtils.ShowError(AppPhrases.ConfigDirRequired); + return false; + } + } + else if (string.IsNullOrWhiteSpace(txtDestFile.Text)) + { + ScadaUiUtils.ShowError(AppPhrases.ConfigArcRequired); + return false; + } + + return true; + } + + /// + /// Применить настройки скачивания конфигурации + /// + private void ApplyDownloadSettings(ServersSettings.DownloadSettings downloadSettings) + { + downloadSettings.SaveToDir = rbSaveToDir.Checked; + downloadSettings.DestDir = txtDestDir.Text; + downloadSettings.DestFile = txtDestFile.Text; + downloadSettings.IncludeSpecificFiles = chkIncludeSpecificFiles.Checked; + downloadSettings.ImportBase = chkImportBase.Checked; + } + + /// + /// Сохранить настройки взаимодействия с удалёнными серверами + /// + private void SaveServersSettings() + { + if (!serversSettings.Save(AppData.AppDirs.ConfigDir + ServersSettings.DefFileName, out string errMsg)) + AppUtils.ProcError(errMsg); + } + + /// + /// Скачать конфигурацию + /// + private void DownloadConfig(ServersSettings.ServerSettings serverSettings) + { + // скачивание + Cursor = Cursors.WaitCursor; + string logFileName = AppData.AppDirs.LogDir + "ScadaAdminDownload.txt"; + bool downloadOK = DownloadUpload.DownloadConfig(serverSettings, + logFileName, out bool logCreated, out string msg); + Cursor = Cursors.Default; + + // отображение сообщения о результате + if (downloadOK) + { + ScadaUiUtils.ShowInfo(msg); + + // запуск импорта + ServersSettings.DownloadSettings downloadSettings = serverSettings.Download; + if (downloadSettings.ImportBase) + { + FrmImport frmImport = new FrmImport(); + if (downloadSettings.SaveToDir) + { + frmImport.DefaultSelection = FrmImport.SelectedItem.AllTables; + frmImport.DefaultBaseDATDir = Path.Combine(downloadSettings.DestDir, "BaseDAT"); + } + else + { + frmImport.DefaultSelection = FrmImport.SelectedItem.Archive; + frmImport.DefaultArcFileName = downloadSettings.DestFile; + frmImport.DefaultBaseDATDir = AppData.Settings.AppSett.BaseDATDir; + } + frmImport.ShowDialog(); + } + } + else + { + AppUtils.ProcError(msg); + + // отображение журнала в блокноте + if (logCreated) + Process.Start(logFileName); + } + } + + + private void FrmDownloadConfig_Load(object sender, EventArgs e) + { + // перевод формы + Translator.TranslateForm(this, "ScadaAdmin.Remote.CtrlServerConn"); + Translator.TranslateForm(this, "ScadaAdmin.Remote.FrmDownloadConfig"); + openFileDialog.Title = AppPhrases.ChooseArchiveFile; + openFileDialog.Filter = AppPhrases.ArchiveFileFilter; + folderBrowserDialog.Description = AppPhrases.ChooseConfigDir; + + // загрузка настроек + if (!serversSettings.Load(AppData.AppDirs.ConfigDir + ServersSettings.DefFileName, out string errMsg)) + AppUtils.ProcError(errMsg); + + // отображение настроек + ctrlServerConn.ServersSettings = serversSettings; + } + + private void ctrlServerConn_SelectedSettingsChanged(object sender, EventArgs e) + { + ShowDownloadSettings(ctrlServerConn.SelectedSettings?.Download); + downloadSettingsModified = false; + } + + private void rbSave_CheckedChanged(object sender, EventArgs e) + { + if (((RadioButton)sender).Checked) // чтобы исключить двойное срабатывание + { + bool saveToDir = rbSaveToDir.Checked; + txtDestDir.Enabled = saveToDir; + btnBrowseDestDir.Enabled = saveToDir; + txtDestFile.Enabled = !saveToDir; + btnSelectDestFile.Enabled = !saveToDir; + downloadSettingsModified = true; + } + } + + private void downloadControl_Changed(object sender, EventArgs e) + { + downloadSettingsModified = true; + } + + private void btnBrowseDestDir_Click(object sender, EventArgs e) + { + // выбор директории для сохранения конфигурации + folderBrowserDialog.SelectedPath = txtDestDir.Text.Trim(); + + if (folderBrowserDialog.ShowDialog() == DialogResult.OK) + txtDestDir.Text = ScadaUtils.NormalDir(folderBrowserDialog.SelectedPath); + + txtDestDir.Focus(); + txtDestDir.DeselectAll(); + } + + private void btnSelectDestFile_Click(object sender, EventArgs e) + { + // выбор файла архива для сохранения конфигурации + string fileName = txtDestFile.Text.Trim(); + openFileDialog.FileName = fileName; + + if (fileName != "") + openFileDialog.InitialDirectory = Path.GetDirectoryName(fileName); + + if (openFileDialog.ShowDialog() == DialogResult.OK) + txtDestFile.Text = openFileDialog.FileName; + + txtDestFile.Focus(); + txtDestFile.DeselectAll(); + } + + private void btnDownload_Click(object sender, EventArgs e) + { + // проверка настроек и скачивание конфигурации + ServersSettings.ServerSettings serverSettings = ctrlServerConn.SelectedSettings; + + if (serverSettings != null && ValidateDownloadSettings()) + { + if (downloadSettingsModified) + { + ApplyDownloadSettings(serverSettings.Download); + SaveServersSettings(); + } + + AppData.Settings.FormSt.ServerConn = serverSettings.Connection.Name; + DownloadConfig(serverSettings); + } + } + } +} diff --git a/ScadaAdmin/ScadaAdmin/Remote/FrmDownloadConfig.resx b/ScadaAdmin/ScadaAdmin/Remote/FrmDownloadConfig.resx new file mode 100644 index 000000000..51627ba7d --- /dev/null +++ b/ScadaAdmin/ScadaAdmin/Remote/FrmDownloadConfig.resx @@ -0,0 +1,157 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + + + R0lGODlhEAAQAIZ/AP/ghPvrn/fwq/nuprSYWZOId//YdP7omP3omLmsi//YcZWKerCmjODFfZiOfZ2R + fJmOep+Vg//OXP/PX6GVf6igi/3egf/QX7OmiP/TaOPg2emoKf/cfv/Wa7eqintuV2FWRP/de7ecXP/N + VP/TZdSyave+RvW8QdGpVod5YPbqoKuhifzFS6Sbj/bup/PmmpWLeVtLIvCzNzUuJYBnI9fPvcXDvvHc + iR4ZFPK2O+WgJM7Cie/XgcKnZo+AZu6wNJyRgFxLItfRwLWYWaOZhqqhjbCnjqOahpqQfuzSef/RYv7d + gKqfg62ki6aagXRnUfLhktSME//LVc2FEJGGdvrBSfe7Qf7JUbGojf/NWODe2kM6Lt7EgP/fgb6jYm9i + Tp+UghYSDvvUcVJIOaWciJeMeoFpJcaraf/ijPzHTtO+ftrSoPrETLqfX+ysMW1pXquijufl4a6kiuuq + LikiG9uiLv/aese6jBgTDqGVeq+jhvW5P6eeiaykj//UZ////yH/C05FVFNDQVBFMi4wAwEBAAAh+QQB + AAB/ACwAAAAAEAAQAAAIwgD/CBxIsKDBgwQ19Fm4sAbCP33WCBAwIEARIQjhuKAYAIEYPkTAIClTYGAF + FRUP2PHDsmVJgWReBDiQIIEHDHqYOKHwAAKMAkegIOBixAKAowC6hDDQAUWLCDfQYLljoOWFESys1HkS + BwiPBgyWZPCjJEsaEzncmMnzx0GSJjsUkJBwpcqeHxumxNDyZ4EaORwmSGFzQsYcHVFovBFYYEWJMz28 + tBExhIDlIDYEUvGR4sMXEGO2zKCDIwyeh6hTFwwIADs= + + + + + R0lGODlhEAAQAIZ/AP/ghPvrn/fwq/nuprSYWZOId//YdP7omP3omLmsi//YcZWKerCmjODFfZiOfZ2R + fJmOep+Vg//OXP/PX6GVf6igi/3egf/QX7OmiP/TaOPg2emoKf/cfv/Wa7eqintuV2FWRP/de7ecXP/N + VP/TZdSyave+RvW8QdGpVod5YPbqoKuhifzFS6Sbj/bup/PmmpWLeVtLIvCzNzUuJYBnI9fPvcXDvvHc + iR4ZFPK2O+WgJM7Cie/XgcKnZo+AZu6wNJyRgFxLItfRwLWYWaOZhqqhjbCnjqOahpqQfuzSef/RYv7d + gKqfg62ki6aagXRnUfLhktSME//LVc2FEJGGdvrBSfe7Qf7JUbGojf/NWODe2kM6Lt7EgP/fgb6jYm9i + Tp+UghYSDvvUcVJIOaWciJeMeoFpJcaraf/ijPzHTtO+ftrSoPrETLqfX+ysMW1pXquijufl4a6kiuuq + LikiG9uiLv/aese6jBgTDqGVeq+jhvW5P6eeiaykj//UZ////yH/C05FVFNDQVBFMi4wAwEBAAAh+QQB + AAB/ACwAAAAAEAAQAAAIwgD/CBxIsKDBgwQ19Fm4sAbCP33WCBAwIEARIQjhuKAYAIEYPkTAIClTYGAF + FRUP2PHDsmVJgWReBDiQIIEHDHqYOKHwAAKMAkegIOBixAKAowC6hDDQAUWLCDfQYLljoOWFESys1HkS + BwiPBgyWZPCjJEsaEzncmMnzx0GSJjsUkJBwpcqeHxumxNDyZ4EaORwmSGFzQsYcHVFovBFYYEWJMz28 + tBExhIDlIDYEUvGR4sMXEGO2zKCDIwyeh6hTFwwIADs= + + + + 180, 17 + + + 17, 17 + + \ No newline at end of file diff --git a/ScadaAdmin/ScadaAdmin/Remote/FrmServerStatus.Designer.cs b/ScadaAdmin/ScadaAdmin/Remote/FrmServerStatus.Designer.cs new file mode 100644 index 000000000..dcb76a5fe --- /dev/null +++ b/ScadaAdmin/ScadaAdmin/Remote/FrmServerStatus.Designer.cs @@ -0,0 +1,240 @@ +namespace ScadaAdmin.Remote +{ + partial class FrmServerStatus + { + /// + /// Required designer variable. + /// + private System.ComponentModel.IContainer components = null; + + /// + /// Clean up any resources being used. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region Windows Form Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + this.components = new System.ComponentModel.Container(); + this.ctrlServerConn = new ScadaAdmin.Remote.CtrlServerConn(); + this.gbAction = new System.Windows.Forms.GroupBox(); + this.btnDisconnect = new System.Windows.Forms.Button(); + this.btnConnect = new System.Windows.Forms.Button(); + this.gbStatus = new System.Windows.Forms.GroupBox(); + this.txtUpdateTime = new System.Windows.Forms.TextBox(); + this.lblUpdateTime = new System.Windows.Forms.Label(); + this.btnRestartComm = new System.Windows.Forms.Button(); + this.txtCommStatus = new System.Windows.Forms.TextBox(); + this.lblCommStatus = new System.Windows.Forms.Label(); + this.btnRestartServer = new System.Windows.Forms.Button(); + this.txtServerStatus = new System.Windows.Forms.TextBox(); + this.lblServerStatus = new System.Windows.Forms.Label(); + this.btnClose = new System.Windows.Forms.Button(); + this.timer = new System.Windows.Forms.Timer(this.components); + this.gbAction.SuspendLayout(); + this.gbStatus.SuspendLayout(); + this.SuspendLayout(); + // + // ctrlServerConn + // + this.ctrlServerConn.Location = new System.Drawing.Point(12, 12); + this.ctrlServerConn.Name = "ctrlServerConn"; + this.ctrlServerConn.ServersSettings = null; + this.ctrlServerConn.Size = new System.Drawing.Size(469, 55); + this.ctrlServerConn.TabIndex = 1; + this.ctrlServerConn.SelectedSettingsChanged += new System.EventHandler(this.ctrlServerConn_SelectedSettingsChanged); + // + // gbAction + // + this.gbAction.Controls.Add(this.btnDisconnect); + this.gbAction.Controls.Add(this.btnConnect); + this.gbAction.Location = new System.Drawing.Point(12, 73); + this.gbAction.Name = "gbAction"; + this.gbAction.Padding = new System.Windows.Forms.Padding(10, 3, 10, 10); + this.gbAction.Size = new System.Drawing.Size(469, 55); + this.gbAction.TabIndex = 2; + this.gbAction.TabStop = false; + this.gbAction.Text = "Действия"; + // + // btnDisconnect + // + this.btnDisconnect.Location = new System.Drawing.Point(119, 19); + this.btnDisconnect.Name = "btnDisconnect"; + this.btnDisconnect.Size = new System.Drawing.Size(100, 23); + this.btnDisconnect.TabIndex = 1; + this.btnDisconnect.Text = "Разъединиться"; + this.btnDisconnect.UseVisualStyleBackColor = true; + this.btnDisconnect.Click += new System.EventHandler(this.btnDisconnect_Click); + // + // btnConnect + // + this.btnConnect.Location = new System.Drawing.Point(13, 19); + this.btnConnect.Name = "btnConnect"; + this.btnConnect.Size = new System.Drawing.Size(100, 23); + this.btnConnect.TabIndex = 0; + this.btnConnect.Text = "Соединиться"; + this.btnConnect.UseVisualStyleBackColor = true; + this.btnConnect.Click += new System.EventHandler(this.btnConnect_Click); + // + // gbStatus + // + this.gbStatus.Controls.Add(this.txtUpdateTime); + this.gbStatus.Controls.Add(this.lblUpdateTime); + this.gbStatus.Controls.Add(this.btnRestartComm); + this.gbStatus.Controls.Add(this.txtCommStatus); + this.gbStatus.Controls.Add(this.lblCommStatus); + this.gbStatus.Controls.Add(this.btnRestartServer); + this.gbStatus.Controls.Add(this.txtServerStatus); + this.gbStatus.Controls.Add(this.lblServerStatus); + this.gbStatus.Location = new System.Drawing.Point(12, 134); + this.gbStatus.Name = "gbStatus"; + this.gbStatus.Padding = new System.Windows.Forms.Padding(10, 3, 10, 10); + this.gbStatus.Size = new System.Drawing.Size(469, 111); + this.gbStatus.TabIndex = 3; + this.gbStatus.TabStop = false; + this.gbStatus.Text = "Статус"; + // + // txtUpdateTime + // + this.txtUpdateTime.Location = new System.Drawing.Point(150, 78); + this.txtUpdateTime.Name = "txtUpdateTime"; + this.txtUpdateTime.ReadOnly = true; + this.txtUpdateTime.Size = new System.Drawing.Size(200, 20); + this.txtUpdateTime.TabIndex = 7; + // + // lblUpdateTime + // + this.lblUpdateTime.AutoSize = true; + this.lblUpdateTime.Location = new System.Drawing.Point(13, 82); + this.lblUpdateTime.Name = "lblUpdateTime"; + this.lblUpdateTime.Size = new System.Drawing.Size(103, 13); + this.lblUpdateTime.TabIndex = 6; + this.lblUpdateTime.Text = "Время обновления"; + // + // btnRestartComm + // + this.btnRestartComm.Location = new System.Drawing.Point(356, 48); + this.btnRestartComm.Name = "btnRestartComm"; + this.btnRestartComm.Size = new System.Drawing.Size(100, 23); + this.btnRestartComm.TabIndex = 5; + this.btnRestartComm.Text = "Перезапустить"; + this.btnRestartComm.UseVisualStyleBackColor = true; + this.btnRestartComm.Click += new System.EventHandler(this.btnRestartComm_Click); + // + // txtCommStatus + // + this.txtCommStatus.Location = new System.Drawing.Point(150, 49); + this.txtCommStatus.Name = "txtCommStatus"; + this.txtCommStatus.ReadOnly = true; + this.txtCommStatus.Size = new System.Drawing.Size(200, 20); + this.txtCommStatus.TabIndex = 4; + // + // lblCommStatus + // + this.lblCommStatus.AutoSize = true; + this.lblCommStatus.Location = new System.Drawing.Point(13, 53); + this.lblCommStatus.Name = "lblCommStatus"; + this.lblCommStatus.Size = new System.Drawing.Size(129, 13); + this.lblCommStatus.TabIndex = 3; + this.lblCommStatus.Text = "Служба Коммуникатора"; + // + // btnRestartServer + // + this.btnRestartServer.Location = new System.Drawing.Point(356, 19); + this.btnRestartServer.Name = "btnRestartServer"; + this.btnRestartServer.Size = new System.Drawing.Size(100, 23); + this.btnRestartServer.TabIndex = 2; + this.btnRestartServer.Text = "Перезапустить"; + this.btnRestartServer.UseVisualStyleBackColor = true; + this.btnRestartServer.Click += new System.EventHandler(this.btnRestartServer_Click); + // + // txtServerStatus + // + this.txtServerStatus.Location = new System.Drawing.Point(150, 20); + this.txtServerStatus.Name = "txtServerStatus"; + this.txtServerStatus.ReadOnly = true; + this.txtServerStatus.Size = new System.Drawing.Size(200, 20); + this.txtServerStatus.TabIndex = 1; + // + // lblServerStatus + // + this.lblServerStatus.AutoSize = true; + this.lblServerStatus.Location = new System.Drawing.Point(13, 24); + this.lblServerStatus.Name = "lblServerStatus"; + this.lblServerStatus.Size = new System.Drawing.Size(91, 13); + this.lblServerStatus.TabIndex = 0; + this.lblServerStatus.Text = "Служба Сервера"; + // + // btnClose + // + this.btnClose.DialogResult = System.Windows.Forms.DialogResult.Cancel; + this.btnClose.Location = new System.Drawing.Point(406, 251); + this.btnClose.Name = "btnClose"; + this.btnClose.Size = new System.Drawing.Size(75, 23); + this.btnClose.TabIndex = 4; + this.btnClose.Text = "Закрыть"; + this.btnClose.UseVisualStyleBackColor = true; + // + // timer + // + this.timer.Interval = 1000; + this.timer.Tick += new System.EventHandler(this.timer_Tick); + // + // FrmServerStatus + // + this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.CancelButton = this.btnClose; + this.ClientSize = new System.Drawing.Size(493, 286); + this.Controls.Add(this.btnClose); + this.Controls.Add(this.gbStatus); + this.Controls.Add(this.gbAction); + this.Controls.Add(this.ctrlServerConn); + this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedDialog; + this.MaximizeBox = false; + this.MinimizeBox = false; + this.Name = "FrmServerStatus"; + this.ShowInTaskbar = false; + this.StartPosition = System.Windows.Forms.FormStartPosition.CenterParent; + this.Text = "Статус сервера"; + this.FormClosed += new System.Windows.Forms.FormClosedEventHandler(this.FrmServerStatus_FormClosed); + this.Load += new System.EventHandler(this.FrmServerStatus_Load); + this.gbAction.ResumeLayout(false); + this.gbStatus.ResumeLayout(false); + this.gbStatus.PerformLayout(); + this.ResumeLayout(false); + + } + + #endregion + + private CtrlServerConn ctrlServerConn; + private System.Windows.Forms.GroupBox gbAction; + private System.Windows.Forms.Button btnConnect; + private System.Windows.Forms.Button btnDisconnect; + private System.Windows.Forms.GroupBox gbStatus; + private System.Windows.Forms.Label lblServerStatus; + private System.Windows.Forms.TextBox txtServerStatus; + private System.Windows.Forms.Button btnRestartServer; + private System.Windows.Forms.Button btnRestartComm; + private System.Windows.Forms.TextBox txtCommStatus; + private System.Windows.Forms.Label lblCommStatus; + private System.Windows.Forms.TextBox txtUpdateTime; + private System.Windows.Forms.Label lblUpdateTime; + private System.Windows.Forms.Button btnClose; + private System.Windows.Forms.Timer timer; + } +} \ No newline at end of file diff --git a/ScadaAdmin/ScadaAdmin/Remote/FrmServerStatus.cs b/ScadaAdmin/ScadaAdmin/Remote/FrmServerStatus.cs new file mode 100644 index 000000000..9c61fb72c --- /dev/null +++ b/ScadaAdmin/ScadaAdmin/Remote/FrmServerStatus.cs @@ -0,0 +1,201 @@ +/* + * Copyright 2018 Mikhail Shiryaev + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * + * Product : Rapid SCADA + * Module : SCADA-Administrator + * Summary : Form for checking status of a remote server + * + * Author : Mikhail Shiryaev + * Created : 2018 + * Modified : 2018 + */ + +using Scada; +using Scada.UI; +using ScadaAdmin.AgentSvcRef; +using System; +using System.Windows.Forms; + +namespace ScadaAdmin.Remote +{ + /// + /// Form for checking status of a remote server + /// Форма для проверки статуса удалённого сервера + /// + public partial class FrmServerStatus : Form + { + private ServersSettings serversSettings; // настройки взаимодействия с удалёнными серверами + private AgentSvcClient client; // клиент для взаимодействия с сервером + private long sessionID; // ид. сессии взаимодействия с сервером + + + /// + /// Конструктор + /// + public FrmServerStatus() + { + InitializeComponent(); + serversSettings = new ServersSettings(); + client = null; + sessionID = 0; + } + + + /// + /// Разъединиться с удалённым сервером + /// + private void Disconnect() + { + timer.Stop(); + client = null; + btnConnect.Enabled = true; + btnDisconnect.Enabled = false; + gbStatus.Enabled = false; + txtServerStatus.Text = txtCommStatus.Text = txtUpdateTime.Text = ""; + } + + /// + /// Получить строковое представление статуса службы + /// + private string StatusToString(ServiceStatus status) + { + switch (status) + { + case ServiceStatus.Normal: + return AppPhrases.NormalSvcStatus; + case ServiceStatus.Stopped: + return AppPhrases.StoppedSvcStatus; + case ServiceStatus.Error: + return AppPhrases.ErrorSvcStatus; + default: // ServiceStatus.Undefined + return AppPhrases.UndefinedSvcStatus; + } + } + + + private void FrmServerStatus_Load(object sender, EventArgs e) + { + // перевод формы + Translator.TranslateForm(this, "ScadaAdmin.Remote.CtrlServerConn"); + Translator.TranslateForm(this, "ScadaAdmin.Remote.FrmServerStatus"); + + // загрузка настроек + if (!serversSettings.Load(AppData.AppDirs.ConfigDir + ServersSettings.DefFileName, out string errMsg)) + AppUtils.ProcError(errMsg); + + // отображение настроек + ctrlServerConn.ServersSettings = serversSettings; + } + + private void FrmServerStatus_FormClosed(object sender, FormClosedEventArgs e) + { + timer.Stop(); + } + + private void ctrlServerConn_SelectedSettingsChanged(object sender, EventArgs e) + { + Disconnect(); + } + + private void btnConnect_Click(object sender, EventArgs e) + { + // соединение с удалённым сервером + if (!timer.Enabled) + { + btnConnect.Enabled = false; + btnDisconnect.Enabled = true; + gbStatus.Enabled = true; + AppData.Settings.FormSt.ServerConn = ctrlServerConn.SelectedSettings.Connection.Name; + timer.Start(); + } + } + + private void btnDisconnect_Click(object sender, EventArgs e) + { + // разъединение с удалённым сервером + Disconnect(); + } + + private void btnRestartServer_Click(object sender, EventArgs e) + { + // перезапуск службы Сервера на удалённом сервере + if (client != null) + { + if (client.ControlService(sessionID, ServiceApp.Server, ServiceCommand.Restart)) + ScadaUiUtils.ShowInfo(AppPhrases.ServerRestarted); + else + ScadaUiUtils.ShowError(AppPhrases.UnableRestartServer); + } + } + + private void btnRestartComm_Click(object sender, EventArgs e) + { + // перезапуск службы Коммуникатора на удалённом сервере + if (client != null) + { + if (client.ControlService(sessionID, ServiceApp.Communicator, ServiceCommand.Restart)) + ScadaUiUtils.ShowInfo(AppPhrases.CommRestarted); + else + ScadaUiUtils.ShowError(AppPhrases.UnableRestartComm); + } + } + + private void timer_Tick(object sender, EventArgs e) + { + timer.Stop(); + + // соединение + if (client == null) + { + if (!DownloadUpload.Connect(ctrlServerConn.SelectedSettings.Connection, + out client, out sessionID, out string errMsg)) + { + Disconnect(); + ScadaUiUtils.ShowError(errMsg); + } + } + + // запрос данных + if (client != null) + { + ServiceStatus status; + + try + { + txtServerStatus.Text = client.GetServiceStatus(out status, sessionID, ServiceApp.Server) ? + StatusToString(status) : "---"; + } + catch (Exception ex) + { + txtServerStatus.Text = ex.Message; + } + + try + { + txtCommStatus.Text = client.GetServiceStatus(out status, sessionID, ServiceApp.Communicator) ? + StatusToString(status) : "---"; + } + catch (Exception ex) + { + txtCommStatus.Text = ex.Message; + } + + txtUpdateTime.Text = DateTime.Now.ToLocalizedString(); + timer.Start(); + } + } + } +} diff --git a/ScadaAdmin/ScadaAdmin/Remote/FrmServerStatus.resx b/ScadaAdmin/ScadaAdmin/Remote/FrmServerStatus.resx new file mode 100644 index 000000000..e22c5ac68 --- /dev/null +++ b/ScadaAdmin/ScadaAdmin/Remote/FrmServerStatus.resx @@ -0,0 +1,123 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + 17, 17 + + \ No newline at end of file diff --git a/ScadaAdmin/ScadaAdmin/Remote/FrmUploadConfig.Designer.cs b/ScadaAdmin/ScadaAdmin/Remote/FrmUploadConfig.Designer.cs new file mode 100644 index 000000000..015d511f2 --- /dev/null +++ b/ScadaAdmin/ScadaAdmin/Remote/FrmUploadConfig.Designer.cs @@ -0,0 +1,267 @@ +namespace ScadaAdmin.Remote +{ + partial class FrmUploadConfig + { + /// + /// Required designer variable. + /// + private System.ComponentModel.IContainer components = null; + + /// + /// Clean up any resources being used. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region Windows Form Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + this.components = new System.ComponentModel.Container(); + System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(FrmUploadConfig)); + System.Windows.Forms.TreeNode treeNode1 = new System.Windows.Forms.TreeNode("BaseDAT\\"); + System.Windows.Forms.TreeNode treeNode2 = new System.Windows.Forms.TreeNode("C:\\SCADA\\", new System.Windows.Forms.TreeNode[] { + treeNode1}); + this.gbOptions = new System.Windows.Forms.GroupBox(); + this.chkClearSpecificFiles = new System.Windows.Forms.CheckBox(); + this.btnSelectSrcFile = new System.Windows.Forms.Button(); + this.txtSrcFile = new System.Windows.Forms.TextBox(); + this.rbGetFromArc = new System.Windows.Forms.RadioButton(); + this.rbGetFromDir = new System.Windows.Forms.RadioButton(); + this.tvFiles = new System.Windows.Forms.TreeView(); + this.lblFiles = new System.Windows.Forms.Label(); + this.txtSrcDir = new System.Windows.Forms.TextBox(); + this.btnBrowseSrcDir = new System.Windows.Forms.Button(); + this.btnClose = new System.Windows.Forms.Button(); + this.btnUpload = new System.Windows.Forms.Button(); + this.folderBrowserDialog = new System.Windows.Forms.FolderBrowserDialog(); + this.openFileDialog = new System.Windows.Forms.OpenFileDialog(); + this.ilTree = new System.Windows.Forms.ImageList(this.components); + this.ctrlServerConn = new ScadaAdmin.Remote.CtrlServerConn(); + this.gbOptions.SuspendLayout(); + this.SuspendLayout(); + // + // gbOptions + // + this.gbOptions.Controls.Add(this.chkClearSpecificFiles); + this.gbOptions.Controls.Add(this.btnSelectSrcFile); + this.gbOptions.Controls.Add(this.txtSrcFile); + this.gbOptions.Controls.Add(this.rbGetFromArc); + this.gbOptions.Controls.Add(this.rbGetFromDir); + this.gbOptions.Controls.Add(this.tvFiles); + this.gbOptions.Controls.Add(this.lblFiles); + this.gbOptions.Controls.Add(this.txtSrcDir); + this.gbOptions.Controls.Add(this.btnBrowseSrcDir); + this.gbOptions.Location = new System.Drawing.Point(12, 73); + this.gbOptions.Name = "gbOptions"; + this.gbOptions.Padding = new System.Windows.Forms.Padding(10, 3, 10, 10); + this.gbOptions.Size = new System.Drawing.Size(469, 408); + this.gbOptions.TabIndex = 1; + this.gbOptions.TabStop = false; + this.gbOptions.Text = "Параметры передачи"; + // + // chkClearSpecificFiles + // + this.chkClearSpecificFiles.AutoSize = true; + this.chkClearSpecificFiles.Location = new System.Drawing.Point(13, 378); + this.chkClearSpecificFiles.Name = "chkClearSpecificFiles"; + this.chkClearSpecificFiles.Size = new System.Drawing.Size(444, 17); + this.chkClearSpecificFiles.TabIndex = 8; + this.chkClearSpecificFiles.Text = "Очистить файлы специфичные для сервера, в том числе, регистрационные ключи"; + this.chkClearSpecificFiles.UseVisualStyleBackColor = true; + this.chkClearSpecificFiles.CheckedChanged += new System.EventHandler(this.uploadControl_Changed); + // + // btnSelectSrcFile + // + this.btnSelectSrcFile.FlatStyle = System.Windows.Forms.FlatStyle.Popup; + this.btnSelectSrcFile.Image = ((System.Drawing.Image)(resources.GetObject("btnSelectSrcFile.Image"))); + this.btnSelectSrcFile.Location = new System.Drawing.Point(436, 347); + this.btnSelectSrcFile.Name = "btnSelectSrcFile"; + this.btnSelectSrcFile.Size = new System.Drawing.Size(20, 20); + this.btnSelectSrcFile.TabIndex = 7; + this.btnSelectSrcFile.UseVisualStyleBackColor = true; + this.btnSelectSrcFile.Click += new System.EventHandler(this.btnSelectSrcFile_Click); + // + // txtSrcFile + // + this.txtSrcFile.Location = new System.Drawing.Point(13, 347); + this.txtSrcFile.Name = "txtSrcFile"; + this.txtSrcFile.Size = new System.Drawing.Size(417, 20); + this.txtSrcFile.TabIndex = 6; + this.txtSrcFile.TextChanged += new System.EventHandler(this.uploadControl_Changed); + // + // rbGetFromArc + // + this.rbGetFromArc.AutoSize = true; + this.rbGetFromArc.Location = new System.Drawing.Point(13, 324); + this.rbGetFromArc.Name = "rbGetFromArc"; + this.rbGetFromArc.Size = new System.Drawing.Size(170, 17); + this.rbGetFromArc.TabIndex = 5; + this.rbGetFromArc.Text = "Файл архива конфигурации:"; + this.rbGetFromArc.UseVisualStyleBackColor = true; + this.rbGetFromArc.CheckedChanged += new System.EventHandler(this.rbGet_CheckedChanged); + // + // rbGetFromDir + // + this.rbGetFromDir.AutoSize = true; + this.rbGetFromDir.Location = new System.Drawing.Point(13, 19); + this.rbGetFromDir.Name = "rbGetFromDir"; + this.rbGetFromDir.Size = new System.Drawing.Size(165, 17); + this.rbGetFromDir.TabIndex = 0; + this.rbGetFromDir.Text = "Директория конфигурации:"; + this.rbGetFromDir.UseVisualStyleBackColor = true; + this.rbGetFromDir.CheckedChanged += new System.EventHandler(this.rbGet_CheckedChanged); + // + // tvFiles + // + this.tvFiles.CheckBoxes = true; + this.tvFiles.ImageIndex = 0; + this.tvFiles.ImageList = this.ilTree; + this.tvFiles.Location = new System.Drawing.Point(13, 81); + this.tvFiles.Name = "tvFiles"; + treeNode1.Name = "Node1"; + treeNode1.Text = "BaseDAT\\"; + treeNode2.Name = "Node0"; + treeNode2.Text = "C:\\SCADA\\"; + this.tvFiles.Nodes.AddRange(new System.Windows.Forms.TreeNode[] { + treeNode2}); + this.tvFiles.SelectedImageIndex = 0; + this.tvFiles.Size = new System.Drawing.Size(443, 237); + this.tvFiles.TabIndex = 4; + this.tvFiles.AfterCheck += new System.Windows.Forms.TreeViewEventHandler(this.tvFiles_AfterCheck); + this.tvFiles.BeforeCollapse += new System.Windows.Forms.TreeViewCancelEventHandler(this.tvFiles_BeforeCollapse); + this.tvFiles.BeforeExpand += new System.Windows.Forms.TreeViewCancelEventHandler(this.tvFiles_BeforeExpand); + // + // lblFiles + // + this.lblFiles.AutoSize = true; + this.lblFiles.Location = new System.Drawing.Point(10, 65); + this.lblFiles.Name = "lblFiles"; + this.lblFiles.Size = new System.Drawing.Size(115, 13); + this.lblFiles.TabIndex = 3; + this.lblFiles.Text = "Файлы для передачи"; + // + // txtSrcDir + // + this.txtSrcDir.Location = new System.Drawing.Point(13, 42); + this.txtSrcDir.Name = "txtSrcDir"; + this.txtSrcDir.ReadOnly = true; + this.txtSrcDir.Size = new System.Drawing.Size(417, 20); + this.txtSrcDir.TabIndex = 1; + this.txtSrcDir.Text = "C:\\SCADA\\"; + this.txtSrcDir.TextChanged += new System.EventHandler(this.uploadControl_Changed); + // + // btnBrowseSrcDir + // + this.btnBrowseSrcDir.FlatStyle = System.Windows.Forms.FlatStyle.Popup; + this.btnBrowseSrcDir.Image = ((System.Drawing.Image)(resources.GetObject("btnBrowseSrcDir.Image"))); + this.btnBrowseSrcDir.Location = new System.Drawing.Point(436, 42); + this.btnBrowseSrcDir.Name = "btnBrowseSrcDir"; + this.btnBrowseSrcDir.Size = new System.Drawing.Size(20, 20); + this.btnBrowseSrcDir.TabIndex = 2; + this.btnBrowseSrcDir.UseVisualStyleBackColor = true; + this.btnBrowseSrcDir.Click += new System.EventHandler(this.btnBrowseSrcDir_Click); + // + // btnClose + // + this.btnClose.DialogResult = System.Windows.Forms.DialogResult.Cancel; + this.btnClose.Location = new System.Drawing.Point(406, 487); + this.btnClose.Name = "btnClose"; + this.btnClose.Size = new System.Drawing.Size(75, 23); + this.btnClose.TabIndex = 3; + this.btnClose.Text = "Закрыть"; + this.btnClose.UseVisualStyleBackColor = true; + // + // btnUpload + // + this.btnUpload.Location = new System.Drawing.Point(325, 487); + this.btnUpload.Name = "btnUpload"; + this.btnUpload.Size = new System.Drawing.Size(75, 23); + this.btnUpload.TabIndex = 2; + this.btnUpload.Text = "Передать"; + this.btnUpload.UseVisualStyleBackColor = true; + this.btnUpload.Click += new System.EventHandler(this.btnUpload_Click); + // + // folderBrowserDialog + // + this.folderBrowserDialog.Description = "Выберите директорию конфигурации"; + // + // openFileDialog + // + this.openFileDialog.CheckFileExists = false; + this.openFileDialog.DefaultExt = "*.zip"; + this.openFileDialog.Filter = "Архивы конфигурации (*.zip)|*.zip|Все файлы (*.*)|*.*"; + this.openFileDialog.Title = "Выберите файл архива конфигурации"; + // + // ilTree + // + this.ilTree.ImageStream = ((System.Windows.Forms.ImageListStreamer)(resources.GetObject("ilTree.ImageStream"))); + this.ilTree.TransparentColor = System.Drawing.Color.Transparent; + this.ilTree.Images.SetKeyName(0, "folder_closed2.png"); + this.ilTree.Images.SetKeyName(1, "folder_open2.png"); + this.ilTree.Images.SetKeyName(2, "file.png"); + // + // ctrlServerConn + // + this.ctrlServerConn.Location = new System.Drawing.Point(12, 12); + this.ctrlServerConn.Name = "ctrlServerConn"; + this.ctrlServerConn.ServersSettings = null; + this.ctrlServerConn.Size = new System.Drawing.Size(469, 55); + this.ctrlServerConn.TabIndex = 0; + this.ctrlServerConn.SelectedSettingsChanged += new System.EventHandler(this.ctrlServerConn_SelectedSettingsChanged); + // + // FrmUploadConfig + // + this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.CancelButton = this.btnClose; + this.ClientSize = new System.Drawing.Size(493, 522); + this.Controls.Add(this.btnClose); + this.Controls.Add(this.btnUpload); + this.Controls.Add(this.gbOptions); + this.Controls.Add(this.ctrlServerConn); + this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedDialog; + this.MaximizeBox = false; + this.MinimizeBox = false; + this.Name = "FrmUploadConfig"; + this.ShowInTaskbar = false; + this.StartPosition = System.Windows.Forms.FormStartPosition.CenterParent; + this.Text = "Передача конфигурации"; + this.Load += new System.EventHandler(this.FrmUploadConfig_Load); + this.gbOptions.ResumeLayout(false); + this.gbOptions.PerformLayout(); + this.ResumeLayout(false); + + } + + #endregion + + private CtrlServerConn ctrlServerConn; + private System.Windows.Forms.GroupBox gbOptions; + private System.Windows.Forms.Button btnClose; + private System.Windows.Forms.Button btnUpload; + private System.Windows.Forms.TextBox txtSrcDir; + private System.Windows.Forms.Button btnBrowseSrcDir; + private System.Windows.Forms.Label lblFiles; + private System.Windows.Forms.TreeView tvFiles; + private System.Windows.Forms.FolderBrowserDialog folderBrowserDialog; + private System.Windows.Forms.RadioButton rbGetFromDir; + private System.Windows.Forms.RadioButton rbGetFromArc; + private System.Windows.Forms.Button btnSelectSrcFile; + private System.Windows.Forms.TextBox txtSrcFile; + private System.Windows.Forms.CheckBox chkClearSpecificFiles; + private System.Windows.Forms.OpenFileDialog openFileDialog; + private System.Windows.Forms.ImageList ilTree; + } +} \ No newline at end of file diff --git a/ScadaAdmin/ScadaAdmin/Remote/FrmUploadConfig.cs b/ScadaAdmin/ScadaAdmin/Remote/FrmUploadConfig.cs new file mode 100644 index 000000000..7a65fae41 --- /dev/null +++ b/ScadaAdmin/ScadaAdmin/Remote/FrmUploadConfig.cs @@ -0,0 +1,475 @@ +/* + * Copyright 2018 Mikhail Shiryaev + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * + * Product : Rapid SCADA + * Module : SCADA-Administrator + * Summary : Upload configuration form + * + * Author : Mikhail Shiryaev + * Created : 2018 + * Modified : 2018 + */ + +using Scada; +using Scada.UI; +using ScadaAdmin.AgentSvcRef; +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.IO; +using System.Windows.Forms; + +namespace ScadaAdmin.Remote +{ + /// + /// Upload configuration form + /// Форма передачи конфигурации + /// + public partial class FrmUploadConfig : Form + { + /// + /// Информация узла дерева + /// + private class NodeInfo + { + /// + /// Получить или установить путь относительно директории конфигурации + /// + public string Path { get; set; } + /// + /// Получить или установить признак, что узел соответствует директории + /// + public bool IsDirectory { get; set; } + } + + // Ключи пиктограмм узлов дерева + private const string FolderClosedImageKey = "folder_closed2.png"; + private const string FolderOpenImageKey = "folder_open2.png"; + private const string FileImageKey = "file.png"; + + private ServersSettings serversSettings; // настройки взаимодействия с удалёнными серверами + private bool uploadSettingsModified; // последние выбранные настройки передачи были изменены + private TreeNode rootNode; // корневой узел дерева + + + /// + /// Конструктор + /// + public FrmUploadConfig() + { + InitializeComponent(); + + serversSettings = new ServersSettings(); + uploadSettingsModified = false; + rootNode = null; + } + + + /// + /// Отобразить настройки передачи конфигурации + /// + private void ShowUploadSettings(ServersSettings.UploadSettings uploadSettings) + { + if (uploadSettings == null) + { + gbOptions.Enabled = false; + rbGetFromDir.Checked = true; + txtSrcDir.Text = txtSrcFile.Text = ""; + tvFiles.Nodes.Clear(); + chkClearSpecificFiles.Checked = false; + btnUpload.Enabled = false; + } + else + { + gbOptions.Enabled = true; + txtSrcDir.Text = uploadSettings.SrcDir; + FillTreeView(uploadSettings.SrcDir, uploadSettings.SelectedFiles); + txtSrcFile.Text = uploadSettings.SrcFile; + chkClearSpecificFiles.Checked = uploadSettings.ClearSpecificFiles; + btnUpload.Enabled = true; + + if (uploadSettings.GetFromDir) + rbGetFromDir.Checked = true; + else + rbGetFromArc.Checked = true; + } + } + + /// + /// Заполнить дерево выбранных файлов + /// + private void FillTreeView(string srcDir, List selectedFiles) + { + try + { + tvFiles.BeginUpdate(); + tvFiles.Nodes.Clear(); + + srcDir = ScadaUtils.NormalDir(srcDir); + int srcDirLen = srcDir.Length; + rootNode = tvFiles.Nodes.Add(srcDir.TrimEnd('\\')); + + // добавление узла базы конфигурации + HashSet selFiles = new HashSet(selectedFiles); + AddDirToTreeView(rootNode, srcDir + "BaseDAT\\", srcDirLen, selFiles); + + // добавление узла интерфейса + AddDirToTreeView(rootNode, srcDir + "Interface\\", srcDirLen, selFiles); + + // добавление узла Коммуникатора + string commDir = srcDir + "ScadaComm\\"; + if (Directory.Exists(commDir)) + { + TreeNode commNode = rootNode.Nodes.Add("ScadaComm"); + AddDirToTreeView(commNode, commDir + "Config\\", srcDirLen, selFiles); + } + + // добавление узла Сервера + string serverDir = srcDir + "ScadaServer\\"; + if (Directory.Exists(serverDir)) + { + TreeNode serverNode = rootNode.Nodes.Add("ScadaServer"); + AddDirToTreeView(serverNode, serverDir + "Config\\", srcDirLen, selFiles); + } + + // добавление узла Вебстанции + string webDir = srcDir + "ScadaWeb\\"; + if (Directory.Exists(webDir)) + { + TreeNode serverNode = rootNode.Nodes.Add("ScadaWeb"); + AddDirToTreeView(serverNode, webDir + "config\\", srcDirLen, selFiles); + AddDirToTreeView(serverNode, webDir + "storage\\", srcDirLen, selFiles); + } + + rootNode.Expand(); + } + finally + { + tvFiles.EndUpdate(); + } + } + + /// + /// Добавить директорию в дерево + /// + private void AddDirToTreeView(TreeNode parentNode, string dir, int rootDirLen, HashSet selFiles) + { + AddDirToTreeView(parentNode, new DirectoryInfo(dir), rootDirLen, selFiles); + } + + /// + /// Добавить директорию в дерево + /// + private void AddDirToTreeView(TreeNode parentNode, DirectoryInfo dirInfo, + int rootDirLen, HashSet selFiles) + { + if (dirInfo.Exists) + { + TreeNode dirNode = parentNode.Nodes.Add(dirInfo.Name); + dirNode.ImageKey = dirNode.SelectedImageKey = FolderClosedImageKey; + string dirNodePath = ScadaUtils.NormalDir(dirInfo.FullName.Substring(rootDirLen)); + dirNode.Tag = new NodeInfo() { Path = dirNodePath, IsDirectory = true }; + + // добавление поддиректорий + DirectoryInfo[] subdirInfoArr = dirInfo.GetDirectories("*", SearchOption.TopDirectoryOnly); + + foreach (DirectoryInfo subdirInfo in subdirInfoArr) + { + AddDirToTreeView(dirNode, subdirInfo, rootDirLen, selFiles); + } + + // добавление файлов + FileInfo[] fileInfoArr = dirInfo.GetFiles("*", SearchOption.TopDirectoryOnly); + + foreach (FileInfo fileInfo in fileInfoArr) + { + if (fileInfo.Extension != ".bak") + { + TreeNode fileNode = dirNode.Nodes.Add(fileInfo.Name); + fileNode.ImageKey = fileNode.SelectedImageKey = FileImageKey; + string fileNodePath = fileInfo.FullName.Substring(rootDirLen); + fileNode.Tag = new NodeInfo() { Path = fileNodePath, IsDirectory = false }; + + if (selFiles.Contains(fileNodePath)) + fileNode.Checked = true; + } + } + + // выбор узла и его дочерних узлов после того, как они добавлены в дерево + if (selFiles.Contains(dirNodePath)) + { + dirNode.Checked = true; + CheckAllChildNodes(dirNode, true); + } + } + } + + /// + /// Установить или снять выбор дочерних узлов дерева + /// + private void CheckAllChildNodes(TreeNode treeNode, bool nodeChecked) + { + foreach (TreeNode node in treeNode.Nodes) + { + node.Checked = nodeChecked; + CheckAllChildNodes(node, nodeChecked); + } + } + + /// + /// Проверить настройки передачи конфигурации + /// + private bool ValidateUploadSettings() + { + if (rbGetFromDir.Checked) + { + if (string.IsNullOrWhiteSpace(txtSrcDir.Text)) + { + ScadaUiUtils.ShowError(AppPhrases.ConfigDirRequired); + return false; + } + } + else if (string.IsNullOrWhiteSpace(txtSrcFile.Text)) + { + ScadaUiUtils.ShowError(AppPhrases.ConfigArcRequired); + return false; + } + + return true; + } + + /// + /// Применить настройки передачи конфигурации + /// + private void ApplyUploadSettings(ServersSettings.UploadSettings uploadSettings) + { + uploadSettings.GetFromDir = rbGetFromDir.Checked; + uploadSettings.SrcDir = txtSrcDir.Text; + uploadSettings.SrcFile = txtSrcFile.Text; + uploadSettings.ClearSpecificFiles = chkClearSpecificFiles.Checked; + + uploadSettings.SelectedFiles.Clear(); + TraverseNodes(rootNode); + + // Получить выбранные файлы на основе выбранных узлов дерева + void TraverseNodes(TreeNode node) + { + if (node.Tag is NodeInfo nodeInfo && node.Checked) + { + uploadSettings.SelectedFiles.Add(nodeInfo.Path); + } + else + { + foreach (TreeNode childNode in node.Nodes) + { + TraverseNodes(childNode); + } + } + } + } + + /// + /// Сохранить настройки взаимодействия с удалёнными серверами + /// + private void SaveServersSettings() + { + if (!serversSettings.Save(AppData.AppDirs.ConfigDir + ServersSettings.DefFileName, out string errMsg)) + AppUtils.ProcError(errMsg); + } + + /// + /// Конвертировать базу конфигурации в формат DAT, если необходимо + /// + private void ConvertBaseToDAT(string srcDir) + { + Settings.AppSettings appSettings = AppData.Settings.AppSett; + string workBaseDATDir = ScadaUtils.NormalDir(appSettings.BaseDATDir); + string srcBaseDATDir = Path.Combine(srcDir, "BaseDAT\\"); + + if (string.Equals(workBaseDATDir, srcBaseDATDir, StringComparison.OrdinalIgnoreCase)) + { + // резервное копирование + if (appSettings.AutoBackupBase && + !ImportExport.BackupSDF(appSettings.BaseSDFFile, appSettings.BackupDir, out string msg)) + AppUtils.ProcError(msg); + + // конвертирование + if (!ImportExport.PassBase(Tables.TableInfoList, workBaseDATDir, out msg)) + AppUtils.ProcError(msg); + } + } + + /// + /// Передать конфигурацию + /// + private void UploadConfig(ServersSettings.ServerSettings serverSettings) + { + // передача + Cursor = Cursors.WaitCursor; + string logFileName = AppData.AppDirs.LogDir + "ScadaAdminUpload.txt"; + bool uploadOK = DownloadUpload.UploadConfig(serverSettings, + logFileName, out bool logCreated, out string msg); + Cursor = Cursors.Default; + + // отображение сообщения о результате + if (uploadOK) + { + ScadaUiUtils.ShowInfo(msg); + } + else + { + AppUtils.ProcError(msg); + + // отображение журнала в блокноте + if (logCreated) + Process.Start(logFileName); + } + } + + + private void FrmUploadConfig_Load(object sender, EventArgs e) + { + // перевод формы + Translator.TranslateForm(this, "ScadaAdmin.Remote.CtrlServerConn"); + Translator.TranslateForm(this, "ScadaAdmin.Remote.FrmUploadConfig"); + openFileDialog.Title = AppPhrases.ChooseArchiveFile; + openFileDialog.Filter = AppPhrases.ArchiveFileFilter; + folderBrowserDialog.Description = AppPhrases.ChooseConfigDir; + + // загрузка настроек + if (!serversSettings.Load(AppData.AppDirs.ConfigDir + ServersSettings.DefFileName, out string errMsg)) + AppUtils.ProcError(errMsg); + + // отображение настроек + ctrlServerConn.ServersSettings = serversSettings; + } + + private void ctrlServerConn_SelectedSettingsChanged(object sender, EventArgs e) + { + ShowUploadSettings(ctrlServerConn.SelectedSettings?.Upload); + uploadSettingsModified = false; + } + + private void rbGet_CheckedChanged(object sender, EventArgs e) + { + if (((RadioButton)sender).Checked) // чтобы исключить двойное срабатывание + { + bool getFromDir = rbGetFromDir.Checked; + txtSrcDir.Enabled = getFromDir; + btnBrowseSrcDir.Enabled = getFromDir; + tvFiles.Enabled = getFromDir; + txtSrcFile.Enabled = !getFromDir; + btnSelectSrcFile.Enabled = !getFromDir; + uploadSettingsModified = true; + } + } + + private void uploadControl_Changed(object sender, EventArgs e) + { + uploadSettingsModified = true; + } + + private void tvFiles_AfterCheck(object sender, TreeViewEventArgs e) + { + if (e.Action != TreeViewAction.Unknown) + { + // установка или снятие выбора для дочерних узлов + TreeNode node = e.Node; + CheckAllChildNodes(node, node.Checked); + + // снятие выбора родительских узлов + if (!node.Checked) + { + while (node.Parent != null) + { + node = node.Parent; + node.Checked = false; + } + } + } + + uploadSettingsModified = true; + } + + private void tvFiles_BeforeCollapse(object sender, TreeViewCancelEventArgs e) + { + // установка пиктограммы узла дерева + TreeNode node = e.Node; + if (node == rootNode || node.Tag is NodeInfo nodeInfo && nodeInfo.IsDirectory) + node.ImageKey = node.SelectedImageKey = FolderClosedImageKey; + } + + private void tvFiles_BeforeExpand(object sender, TreeViewCancelEventArgs e) + { + // установка пиктограммы узла дерева + TreeNode node = e.Node; + if (node == rootNode || node.Tag is NodeInfo nodeInfo && nodeInfo.IsDirectory) + node.ImageKey = node.SelectedImageKey = FolderOpenImageKey; + } + + private void btnBrowseSrcDir_Click(object sender, EventArgs e) + { + // выбор директории конфигурации + folderBrowserDialog.SelectedPath = txtSrcDir.Text.Trim(); + + if (folderBrowserDialog.ShowDialog() == DialogResult.OK) + { + txtSrcDir.Text = ScadaUtils.NormalDir(folderBrowserDialog.SelectedPath); + FillTreeView(txtSrcDir.Text, ctrlServerConn.SelectedSettings.Upload.SelectedFiles); + } + + txtSrcDir.Focus(); + txtSrcDir.DeselectAll(); + } + + private void btnSelectSrcFile_Click(object sender, EventArgs e) + { + // выбор файла архива конфигурации + string fileName = txtSrcFile.Text.Trim(); + openFileDialog.FileName = fileName; + + if (fileName != "") + openFileDialog.InitialDirectory = Path.GetDirectoryName(fileName); + + if (openFileDialog.ShowDialog() == DialogResult.OK) + txtSrcFile.Text = openFileDialog.FileName; + + txtSrcFile.Focus(); + txtSrcFile.DeselectAll(); + } + + private void btnUpload_Click(object sender, EventArgs e) + { + // проверка настроек и передача конфигурации + ServersSettings.ServerSettings serverSettings = ctrlServerConn.SelectedSettings; + + if (serverSettings != null && ValidateUploadSettings()) + { + if (uploadSettingsModified) + { + ApplyUploadSettings(serverSettings.Upload); + SaveServersSettings(); + } + + if (serverSettings.Upload.GetFromDir) + ConvertBaseToDAT(serverSettings.Upload.SrcDir); + + AppData.Settings.FormSt.ServerConn = serverSettings.Connection.Name; + UploadConfig(serverSettings); + } + } + } +} diff --git a/ScadaAdmin/ScadaAdmin/Remote/FrmUploadConfig.resx b/ScadaAdmin/ScadaAdmin/Remote/FrmUploadConfig.resx new file mode 100644 index 000000000..7fcbd03d8 --- /dev/null +++ b/ScadaAdmin/ScadaAdmin/Remote/FrmUploadConfig.resx @@ -0,0 +1,211 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + + + R0lGODlhEAAQAIZ/AP/ghPvrn/fwq/nuprSYWZOId//YdP7omP3omLmsi//YcZWKerCmjODFfZiOfZ2R + fJmOep+Vg//OXP/PX6GVf6igi/3egf/QX7OmiP/TaOPg2emoKf/cfv/Wa7eqintuV2FWRP/de7ecXP/N + VP/TZdSyave+RvW8QdGpVod5YPbqoKuhifzFS6Sbj/bup/PmmpWLeVtLIvCzNzUuJYBnI9fPvcXDvvHc + iR4ZFPK2O+WgJM7Cie/XgcKnZo+AZu6wNJyRgFxLItfRwLWYWaOZhqqhjbCnjqOahpqQfuzSef/RYv7d + gKqfg62ki6aagXRnUfLhktSME//LVc2FEJGGdvrBSfe7Qf7JUbGojf/NWODe2kM6Lt7EgP/fgb6jYm9i + Tp+UghYSDvvUcVJIOaWciJeMeoFpJcaraf/ijPzHTtO+ftrSoPrETLqfX+ysMW1pXquijufl4a6kiuuq + LikiG9uiLv/aese6jBgTDqGVeq+jhvW5P6eeiaykj//UZ////yH/C05FVFNDQVBFMi4wAwEBAAAh+QQB + AAB/ACwAAAAAEAAQAAAIwgD/CBxIsKDBgwQ19Fm4sAbCP33WCBAwIEARIQjhuKAYAIEYPkTAIClTYGAF + FRUP2PHDsmVJgWReBDiQIIEHDHqYOKHwAAKMAkegIOBixAKAowC6hDDQAUWLCDfQYLljoOWFESys1HkS + BwiPBgyWZPCjJEsaEzncmMnzx0GSJjsUkJBwpcqeHxumxNDyZ4EaORwmSGFzQsYcHVFovBFYYEWJMz28 + tBExhIDlIDYEUvGR4sMXEGO2zKCDIwyeh6hTFwwIADs= + + + + 313, 17 + + + + AAEAAAD/////AQAAAAAAAAAMAgAAAFdTeXN0ZW0uV2luZG93cy5Gb3JtcywgVmVyc2lvbj00LjAuMC4w + LCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODkFAQAAACZTeXN0 + ZW0uV2luZG93cy5Gb3Jtcy5JbWFnZUxpc3RTdHJlYW1lcgEAAAAERGF0YQcCAgAAAAkDAAAADwMAAACC + CQAAAk1TRnQBSQFMAgEBAwEAAUgBAAFIAQABEAEAARABAAT/AQkBAAj/AUIBTQE2AQQGAAE2AQQCAAEo + AwABQAMAARADAAEBAQABCAYAAQQYAAGAAgABgAMAAoABAAGAAwABgAEAAYABAAKAAgADwAEAAcAB3AHA + AQAB8AHKAaYBAAEzBQABMwEAATMBAAEzAQACMwIAAxYBAAMcAQADIgEAAykBAANVAQADTQEAA0IBAAM5 + AQABgAF8Af8BAAJQAf8BAAGTAQAB1gEAAf8B7AHMAQABxgHWAe8BAAHWAucBAAGQAakBrQIAAf8BMwMA + AWYDAAGZAwABzAIAATMDAAIzAgABMwFmAgABMwGZAgABMwHMAgABMwH/AgABZgMAAWYBMwIAAmYCAAFm + AZkCAAFmAcwCAAFmAf8CAAGZAwABmQEzAgABmQFmAgACmQIAAZkBzAIAAZkB/wIAAcwDAAHMATMCAAHM + AWYCAAHMAZkCAALMAgABzAH/AgAB/wFmAgAB/wGZAgAB/wHMAQABMwH/AgAB/wEAATMBAAEzAQABZgEA + ATMBAAGZAQABMwEAAcwBAAEzAQAB/wEAAf8BMwIAAzMBAAIzAWYBAAIzAZkBAAIzAcwBAAIzAf8BAAEz + AWYCAAEzAWYBMwEAATMCZgEAATMBZgGZAQABMwFmAcwBAAEzAWYB/wEAATMBmQIAATMBmQEzAQABMwGZ + AWYBAAEzApkBAAEzAZkBzAEAATMBmQH/AQABMwHMAgABMwHMATMBAAEzAcwBZgEAATMBzAGZAQABMwLM + AQABMwHMAf8BAAEzAf8BMwEAATMB/wFmAQABMwH/AZkBAAEzAf8BzAEAATMC/wEAAWYDAAFmAQABMwEA + AWYBAAFmAQABZgEAAZkBAAFmAQABzAEAAWYBAAH/AQABZgEzAgABZgIzAQABZgEzAWYBAAFmATMBmQEA + AWYBMwHMAQABZgEzAf8BAAJmAgACZgEzAQADZgEAAmYBmQEAAmYBzAEAAWYBmQIAAWYBmQEzAQABZgGZ + AWYBAAFmApkBAAFmAZkBzAEAAWYBmQH/AQABZgHMAgABZgHMATMBAAFmAcwBmQEAAWYCzAEAAWYBzAH/ + AQABZgH/AgABZgH/ATMBAAFmAf8BmQEAAWYB/wHMAQABzAEAAf8BAAH/AQABzAEAApkCAAGZATMBmQEA + AZkBAAGZAQABmQEAAcwBAAGZAwABmQIzAQABmQEAAWYBAAGZATMBzAEAAZkBAAH/AQABmQFmAgABmQFm + ATMBAAGZATMBZgEAAZkBZgGZAQABmQFmAcwBAAGZATMB/wEAApkBMwEAApkBZgEAA5kBAAKZAcwBAAKZ + Af8BAAGZAcwCAAGZAcwBMwEAAWYBzAFmAQABmQHMAZkBAAGZAswBAAGZAcwB/wEAAZkB/wIAAZkB/wEz + AQABmQHMAWYBAAGZAf8BmQEAAZkB/wHMAQABmQL/AQABzAMAAZkBAAEzAQABzAEAAWYBAAHMAQABmQEA + AcwBAAHMAQABmQEzAgABzAIzAQABzAEzAWYBAAHMATMBmQEAAcwBMwHMAQABzAEzAf8BAAHMAWYCAAHM + AWYBMwEAAZkCZgEAAcwBZgGZAQABzAFmAcwBAAGZAWYB/wEAAcwBmQIAAcwBmQEzAQABzAGZAWYBAAHM + ApkBAAHMAZkBzAEAAcwBmQH/AQACzAIAAswBMwEAAswBZgEAAswBmQEAA8wBAALMAf8BAAHMAf8CAAHM + Af8BMwEAAZkB/wFmAQABzAH/AZkBAAHMAf8BzAEAAcwC/wEAAcwBAAEzAQAB/wEAAWYBAAH/AQABmQEA + AcwBMwIAAf8CMwEAAf8BMwFmAQAB/wEzAZkBAAH/ATMBzAEAAf8BMwH/AQAB/wFmAgAB/wFmATMBAAHM + AmYBAAH/AWYBmQEAAf8BZgHMAQABzAFmAf8BAAH/AZkCAAH/AZkBMwEAAf8BmQFmAQAB/wKZAQAB/wGZ + AcwBAAH/AZkB/wEAAf8BzAIAAf8BzAEzAQAB/wHMAWYBAAH/AcwBmQEAAf8CzAEAAf8BzAH/AQAC/wEz + AQABzAH/AWYBAAL/AZkBAAL/AcwBAAJmAf8BAAFmAf8BZgEAAWYC/wEAAf8CZgEAAf8BZgH/AQAC/wFm + AQABIQEAAaUBAANfAQADdwEAA4YBAAOWAQADywEAA7IBAAPXAQAD3QEAA+MBAAPqAQAD8QEAA/gBAAHw + AfsB/wEAAaQCoAEAA4ADAAH/AgAB/wMAAv8BAAH/AwAB/wEAAf8BAAL/AgAD/2MAAfcKZjUAAfcC9ALz + BBkB3QFmFQAB7APrAm0B6gISARMCFAQAAuwC6wFtAeoBEgETARQBFQERAQcEAAH3A/QBGQLzAxkBZhUA + AXMJUgFLARQEAAHsARwBeQVSAVECSwFEBAAB9wT0A/MCGQFmFQAB7AF5AXoDWQE4AzIBSwEUBAAB7AF5 + ARwBmgN6AlkBUwFSAUoBBwMAAfcB9QX0ARkB8wEZAWYVAAFzAZoCegNZATgCMgFRARMEAAHsAXoCHAR6 + A1kBUQFEAwABtQP1BPQC8wFmFQAB7QKaAnoDWQE4ATIBUQETBAAB7AGaAXkBHAd6AVkBUQEHAgAB7wL/ + AvUE9AEZAWYVAAEcAaACmgJ6BFkBUgESBAABHAGaAaABmQEcB3oBdAFzAgABtQP/AvUE9AFmFQABHAPD + A6ADWQFSARIEAAEcA6AEHAFzBewCAAG7BP8D9QL0AWYVAAYcAXkDoAFSARIEAAEcBaAFegHsBAABuwb/ + AvUB9AFmFQABHAOaAnoG7AQAARwEoAF6BuwEAAG7Bv8B9wNmFQABHAEaBMMBHAkAARwBmgSgARwJAAG7 + Bv8BtQHuAWYBBxUAAbwFHAG8CQABvAUcAbwJAAEJBv8BtQFmAQc2AAUJAbsBBwG7AfFVAAFCAU0BPgcA + AT4DAAEoAwABQAMAARADAAEBAQABAQUAAYAXAAP/AQAG/wIABP8BwAEHAgAE/wHAAQcCAAHAAQMBwAED + AcABBwIAAcABAwHAAQMBwAEHAgABwAEDAcABAQHAAQcCAAHAAQMBwAEBAcABBwIAAcABAwHAAQABwAEH + AgABwAEDAcABAAHAAQcCAAHAAQMBwAEAAcABBwIAAcABAwHAAQMBwAEHAgABwAEDAcABAwHAAQcCAAHA + AX8BwAF/AcABBwIAAcABfwHAAX8BwAEPAgAE/wHAAR8CAAb/AgAL + + + + + R0lGODlhEAAQAIZ/AP/ghPvrn/fwq/nuprSYWZOId//YdP7omP3omLmsi//YcZWKerCmjODFfZiOfZ2R + fJmOep+Vg//OXP/PX6GVf6igi/3egf/QX7OmiP/TaOPg2emoKf/cfv/Wa7eqintuV2FWRP/de7ecXP/N + VP/TZdSyave+RvW8QdGpVod5YPbqoKuhifzFS6Sbj/bup/PmmpWLeVtLIvCzNzUuJYBnI9fPvcXDvvHc + iR4ZFPK2O+WgJM7Cie/XgcKnZo+AZu6wNJyRgFxLItfRwLWYWaOZhqqhjbCnjqOahpqQfuzSef/RYv7d + gKqfg62ki6aagXRnUfLhktSME//LVc2FEJGGdvrBSfe7Qf7JUbGojf/NWODe2kM6Lt7EgP/fgb6jYm9i + Tp+UghYSDvvUcVJIOaWciJeMeoFpJcaraf/ijPzHTtO+ftrSoPrETLqfX+ysMW1pXquijufl4a6kiuuq + LikiG9uiLv/aese6jBgTDqGVeq+jhvW5P6eeiaykj//UZ////yH/C05FVFNDQVBFMi4wAwEBAAAh+QQB + AAB/ACwAAAAAEAAQAAAIwgD/CBxIsKDBgwQ19Fm4sAbCP33WCBAwIEARIQjhuKAYAIEYPkTAIClTYGAF + FRUP2PHDsmVJgWReBDiQIIEHDHqYOKHwAAKMAkegIOBixAKAowC6hDDQAUWLCDfQYLljoOWFESys1HkS + BwiPBgyWZPCjJEsaEzncmMnzx0GSJjsUkJBwpcqeHxumxNDyZ4EaORwmSGFzQsYcHVFovBFYYEWJMz28 + tBExhIDlIDYEUvGR4sMXEGO2zKCDIwyeh6hTFwwIADs= + + + + 17, 17 + + + 180, 17 + + + 52 + + \ No newline at end of file diff --git a/ScadaAdmin/ScadaAdmin/ScadaAdmin.csproj b/ScadaAdmin/ScadaAdmin/ScadaAdmin.csproj index fb785955b..499f3d47c 100644 --- a/ScadaAdmin/ScadaAdmin/ScadaAdmin.csproj +++ b/ScadaAdmin/ScadaAdmin/ScadaAdmin.csproj @@ -65,7 +65,7 @@ False - ..\..\Log\bin\Release\Log.dll + ..\..\Log\Log\bin\Release\Log.dll ..\..\ScadaComm\ScadaCommCommon\bin\Release\ScadaCommCommon.dll @@ -83,6 +83,8 @@ + + @@ -93,9 +95,17 @@ + + + + + True + True + Reference.svcmap + Form @@ -183,6 +193,36 @@ + + UserControl + + + CtrlServerConn.cs + + + Form + + + FrmConnSettings.cs + + + Form + + + FrmDownloadConfig.cs + + + Form + + + FrmServerStatus.cs + + + Form + + + FrmUploadConfig.cs + FrmAbout.cs @@ -235,8 +275,45 @@ Resources.resx True + + CtrlServerConn.cs + + + FrmConnSettings.cs + + + FrmDownloadConfig.cs + + + FrmServerStatus.cs + + + FrmUploadConfig.cs + + + + Designer + + + Designer + + + Designer + + + Designer + + + Designer + + + Reference.svcmap + + + Reference.svcmap + SettingsSingleFileGenerator Settings.Designer.cs @@ -258,6 +335,19 @@ Lang\ScadaData.ru-RU.xml PreserveNewest + + + + + WCF Proxy Generator + Reference.cs + + + PreserveNewest + + + PreserveNewest + Designer @@ -268,7 +358,12 @@ Designer - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + 148, 17 + + + 17, 17 + + + False + + \ No newline at end of file diff --git a/ScadaAgent/ScadaAgent/ScadaAgentService/Properties/AssemblyInfo.cs b/ScadaAgent/ScadaAgentSvc/Properties/AssemblyInfo.cs similarity index 78% rename from ScadaAgent/ScadaAgent/ScadaAgentService/Properties/AssemblyInfo.cs rename to ScadaAgent/ScadaAgentSvc/Properties/AssemblyInfo.cs index 4622c3ea7..71343ab09 100644 --- a/ScadaAgent/ScadaAgent/ScadaAgentService/Properties/AssemblyInfo.cs +++ b/ScadaAgent/ScadaAgentSvc/Properties/AssemblyInfo.cs @@ -1,16 +1,16 @@ -using System.Reflection; -using System.Runtime.CompilerServices; +using Scada.Agent; +using System.Reflection; using System.Runtime.InteropServices; // General Information about an assembly is controlled through the following // set of attributes. Change these attribute values to modify the information // associated with an assembly. -[assembly: AssemblyTitle("ScadaAgentService")] +[assembly: AssemblyTitle("Agent Service for Windows")] [assembly: AssemblyDescription("")] [assembly: AssemblyConfiguration("")] [assembly: AssemblyCompany("")] -[assembly: AssemblyProduct("ScadaAgentService")] -[assembly: AssemblyCopyright("Copyright © 2018")] +[assembly: AssemblyProduct("Rapid SCADA")] +[assembly: AssemblyCopyright("Copyright © 2018")] [assembly: AssemblyTrademark("")] [assembly: AssemblyCulture("")] @@ -32,5 +32,5 @@ // You can specify all the values or you can default the Build and Revision Numbers // by using the '*' as shown below: // [assembly: AssemblyVersion("1.0.*")] -[assembly: AssemblyVersion("1.0.0.0")] -[assembly: AssemblyFileVersion("1.0.0.0")] +[assembly: AssemblyVersion(AgentUtils.AppVersion)] +[assembly: AssemblyFileVersion(AgentUtils.AppVersion)] diff --git a/ScadaAgent/ScadaAgentSvc/ScadaAgentSvc.csproj b/ScadaAgent/ScadaAgentSvc/ScadaAgentSvc.csproj new file mode 100644 index 000000000..898c5b4f0 --- /dev/null +++ b/ScadaAgent/ScadaAgentSvc/ScadaAgentSvc.csproj @@ -0,0 +1,102 @@ + + + + + Debug + AnyCPU + {593318B1-3CB4-441B-B273-E3F37DF070B5} + WinExe + Scada.Agent.Svc + ScadaAgentSvc + v4.6.1 + 512 + true + + + AnyCPU + true + full + false + bin\Debug\ + DEBUG;TRACE + prompt + 4 + + + AnyCPU + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + + + + False + ..\..\Log\Log.Std\bin\Release\netstandard2.0\Log.Std.dll + + + False + ..\..\ScadaData\ScadaData.Std\bin\Release\netstandard2.0\ScadaData.Std.dll + + + + + + + + + Component + + + ProjectInstaller.cs + + + Component + + + SvcMain.cs + + + + + + + + PreserveNewest + + + PreserveNewest + + + + + {5163526D-91E4-414D-97FE-090E1E7FDA6B} + ScadaAgentCore + + + {c377283b-858b-4efc-a560-e90ff2f26b03} + ScadaAgentNet + + + + + ProjectInstaller.cs + + + + + Lang\ScadaData.en-GB.xml + PreserveNewest + + + Lang\ScadaData.ru-RU.xml + PreserveNewest + + + PreserveNewest + + + + \ No newline at end of file diff --git a/ScadaAgent/ScadaAgent/ScadaAgentService/Service1.Designer.cs b/ScadaAgent/ScadaAgentSvc/SvcMain.Designer.cs similarity index 94% rename from ScadaAgent/ScadaAgent/ScadaAgentService/Service1.Designer.cs rename to ScadaAgent/ScadaAgentSvc/SvcMain.Designer.cs index c2fd74d0b..a0bf3e3ab 100644 --- a/ScadaAgent/ScadaAgent/ScadaAgentService/Service1.Designer.cs +++ b/ScadaAgent/ScadaAgentSvc/SvcMain.Designer.cs @@ -1,6 +1,6 @@ -namespace ScadaAgentService +namespace Scada.Agent.Svc { - partial class Service1 + partial class SvcMain { /// /// Required designer variable. diff --git a/ScadaAgent/ScadaAgentSvc/SvcMain.cs b/ScadaAgent/ScadaAgentSvc/SvcMain.cs new file mode 100644 index 000000000..cd788d361 --- /dev/null +++ b/ScadaAgent/ScadaAgentSvc/SvcMain.cs @@ -0,0 +1,60 @@ +/* + * Copyright 2018 Mikhail Shiryaev + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * + * Product : Rapid SCADA + * Module : Agent Service + * Summary : ScadaAgentSvc service implementation + * + * Author : Mikhail Shiryaev + * Created : 2018 + * Modified : 2018 + */ + +using Scada.Agent.Net; +using System.ServiceProcess; + +namespace Scada.Agent.Svc +{ + /// + /// ScadaAgentSvc service implementation + /// Реализация службы ScadaAgentSvc + /// + public partial class SvcMain : ServiceBase + { + AgentManager agentManager; + + public SvcMain() + { + InitializeComponent(); + agentManager = new AgentManager(); + } + + protected override void OnStart(string[] args) + { + agentManager.StartAgent(); + } + + protected override void OnStop() + { + agentManager.StopAgent(); + } + + protected override void OnShutdown() + { + agentManager.StopAgent(); + } + } +} diff --git a/ScadaAgent/ScadaAgentSvc/svc_install.bat b/ScadaAgent/ScadaAgentSvc/svc_install.bat new file mode 100644 index 000000000..efae5ba90 --- /dev/null +++ b/ScadaAgent/ScadaAgentSvc/svc_install.bat @@ -0,0 +1,2 @@ +cd /d "%~dp0" +C:\Windows\Microsoft.NET\Framework\v4.0.30319\InstallUtil.exe ScadaAgentSvc.exe diff --git a/ScadaAgent/ScadaAgentSvc/svc_uninstall.bat b/ScadaAgent/ScadaAgentSvc/svc_uninstall.bat new file mode 100644 index 000000000..224054c40 --- /dev/null +++ b/ScadaAgent/ScadaAgentSvc/svc_uninstall.bat @@ -0,0 +1,2 @@ +cd /d "%~dp0" +C:\Windows\Microsoft.NET\Framework\v4.0.30319\InstallUtil.exe /u ScadaAgentSvc.exe diff --git a/ScadaAgent/ScadaAgentTest/App.config b/ScadaAgent/ScadaAgentTest/App.config new file mode 100644 index 000000000..70e82ccb5 --- /dev/null +++ b/ScadaAgent/ScadaAgentTest/App.config @@ -0,0 +1,18 @@ + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/ScadaAgent/ScadaAgentTest/Connected Services/AgentSvcRef/AgentSvc.wsdl b/ScadaAgent/ScadaAgentTest/Connected Services/AgentSvcRef/AgentSvc.wsdl new file mode 100644 index 000000000..cee4e852c --- /dev/null +++ b/ScadaAgent/ScadaAgentTest/Connected Services/AgentSvcRef/AgentSvc.wsdl @@ -0,0 +1,216 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/ScadaAgent/ScadaAgentTest/Connected Services/AgentSvcRef/Reference.cs b/ScadaAgent/ScadaAgentTest/Connected Services/AgentSvcRef/Reference.cs new file mode 100644 index 000000000..1c5ad0b7e --- /dev/null +++ b/ScadaAgent/ScadaAgentTest/Connected Services/AgentSvcRef/Reference.cs @@ -0,0 +1,492 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// Runtime Version:4.0.30319.42000 +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +namespace Scada.Agent.Test.AgentSvcRef { + + + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.ServiceModel", "4.0.0.0")] + [System.ServiceModel.ServiceContractAttribute(ConfigurationName="AgentSvcRef.AgentSvc")] + public interface AgentSvc { + + [System.ServiceModel.OperationContractAttribute(Action="http://tempuri.org/AgentSvc/CreateSession", ReplyAction="http://tempuri.org/AgentSvc/CreateSessionResponse")] + Scada.Agent.Test.AgentSvcRef.CreateSessionResponse CreateSession(Scada.Agent.Test.AgentSvcRef.CreateSessionRequest request); + + // CODEGEN: Generating message contract since the operation has multiple return values. + [System.ServiceModel.OperationContractAttribute(Action="http://tempuri.org/AgentSvc/CreateSession", ReplyAction="http://tempuri.org/AgentSvc/CreateSessionResponse")] + System.Threading.Tasks.Task CreateSessionAsync(Scada.Agent.Test.AgentSvcRef.CreateSessionRequest request); + + [System.ServiceModel.OperationContractAttribute(Action="http://tempuri.org/AgentSvc/Login", ReplyAction="http://tempuri.org/AgentSvc/LoginResponse")] + Scada.Agent.Test.AgentSvcRef.LoginResponse Login(Scada.Agent.Test.AgentSvcRef.LoginRequest request); + + // CODEGEN: Generating message contract since the operation has multiple return values. + [System.ServiceModel.OperationContractAttribute(Action="http://tempuri.org/AgentSvc/Login", ReplyAction="http://tempuri.org/AgentSvc/LoginResponse")] + System.Threading.Tasks.Task LoginAsync(Scada.Agent.Test.AgentSvcRef.LoginRequest request); + + [System.ServiceModel.OperationContractAttribute(Action="http://tempuri.org/AgentSvc/ControlService", ReplyAction="http://tempuri.org/AgentSvc/ControlServiceResponse")] + bool ControlService(long sessionID, Scada.Agent.ServiceApp serviceApp, Scada.Agent.ServiceCommand command); + + [System.ServiceModel.OperationContractAttribute(Action="http://tempuri.org/AgentSvc/ControlService", ReplyAction="http://tempuri.org/AgentSvc/ControlServiceResponse")] + System.Threading.Tasks.Task ControlServiceAsync(long sessionID, Scada.Agent.ServiceApp serviceApp, Scada.Agent.ServiceCommand command); + + [System.ServiceModel.OperationContractAttribute(Action="http://tempuri.org/AgentSvc/GetServiceStatus", ReplyAction="http://tempuri.org/AgentSvc/GetServiceStatusResponse")] + Scada.Agent.Test.AgentSvcRef.GetServiceStatusResponse GetServiceStatus(Scada.Agent.Test.AgentSvcRef.GetServiceStatusRequest request); + + // CODEGEN: Generating message contract since the operation has multiple return values. + [System.ServiceModel.OperationContractAttribute(Action="http://tempuri.org/AgentSvc/GetServiceStatus", ReplyAction="http://tempuri.org/AgentSvc/GetServiceStatusResponse")] + System.Threading.Tasks.Task GetServiceStatusAsync(Scada.Agent.Test.AgentSvcRef.GetServiceStatusRequest request); + + [System.ServiceModel.OperationContractAttribute(Action="http://tempuri.org/AgentSvc/GetAvailableConfig", ReplyAction="http://tempuri.org/AgentSvc/GetAvailableConfigResponse")] + Scada.Agent.Test.AgentSvcRef.GetAvailableConfigResponse GetAvailableConfig(Scada.Agent.Test.AgentSvcRef.GetAvailableConfigRequest request); + + // CODEGEN: Generating message contract since the operation has multiple return values. + [System.ServiceModel.OperationContractAttribute(Action="http://tempuri.org/AgentSvc/GetAvailableConfig", ReplyAction="http://tempuri.org/AgentSvc/GetAvailableConfigResponse")] + System.Threading.Tasks.Task GetAvailableConfigAsync(Scada.Agent.Test.AgentSvcRef.GetAvailableConfigRequest request); + + [System.ServiceModel.OperationContractAttribute(Action="http://tempuri.org/AgentSvc/DownloadConfig", ReplyAction="http://tempuri.org/AgentSvc/DownloadConfigResponse")] + System.IO.Stream DownloadConfig(long sessionID, Scada.Agent.ConfigOptions configOptions); + + [System.ServiceModel.OperationContractAttribute(Action="http://tempuri.org/AgentSvc/DownloadConfig", ReplyAction="http://tempuri.org/AgentSvc/DownloadConfigResponse")] + System.Threading.Tasks.Task DownloadConfigAsync(long sessionID, Scada.Agent.ConfigOptions configOptions); + + // CODEGEN: Generating message contract since the operation UploadConfig is neither RPC nor document wrapped. + [System.ServiceModel.OperationContractAttribute(Action="http://tempuri.org/AgentSvc/UploadConfig", ReplyAction="http://tempuri.org/AgentSvc/UploadConfigResponse")] + Scada.Agent.Test.AgentSvcRef.UploadConfigResponse UploadConfig(Scada.Agent.Test.AgentSvcRef.ConfigUploadMessage request); + + [System.ServiceModel.OperationContractAttribute(Action="http://tempuri.org/AgentSvc/UploadConfig", ReplyAction="http://tempuri.org/AgentSvc/UploadConfigResponse")] + System.Threading.Tasks.Task UploadConfigAsync(Scada.Agent.Test.AgentSvcRef.ConfigUploadMessage request); + + [System.ServiceModel.OperationContractAttribute(Action="http://tempuri.org/AgentSvc/Browse", ReplyAction="http://tempuri.org/AgentSvc/BrowseResponse")] + Scada.Agent.Test.AgentSvcRef.BrowseResponse Browse(Scada.Agent.Test.AgentSvcRef.BrowseRequest request); + + // CODEGEN: Generating message contract since the operation has multiple return values. + [System.ServiceModel.OperationContractAttribute(Action="http://tempuri.org/AgentSvc/Browse", ReplyAction="http://tempuri.org/AgentSvc/BrowseResponse")] + System.Threading.Tasks.Task BrowseAsync(Scada.Agent.Test.AgentSvcRef.BrowseRequest request); + + [System.ServiceModel.OperationContractAttribute(Action="http://tempuri.org/AgentSvc/DownloadFile", ReplyAction="http://tempuri.org/AgentSvc/DownloadFileResponse")] + System.IO.Stream DownloadFile(long sessionID, Scada.Agent.RelPath relPath); + + [System.ServiceModel.OperationContractAttribute(Action="http://tempuri.org/AgentSvc/DownloadFile", ReplyAction="http://tempuri.org/AgentSvc/DownloadFileResponse")] + System.Threading.Tasks.Task DownloadFileAsync(long sessionID, Scada.Agent.RelPath relPath); + + [System.ServiceModel.OperationContractAttribute(Action="http://tempuri.org/AgentSvc/DownloadFileRest", ReplyAction="http://tempuri.org/AgentSvc/DownloadFileRestResponse")] + System.IO.Stream DownloadFileRest(long sessionID, Scada.Agent.RelPath relPath, long position); + + [System.ServiceModel.OperationContractAttribute(Action="http://tempuri.org/AgentSvc/DownloadFileRest", ReplyAction="http://tempuri.org/AgentSvc/DownloadFileRestResponse")] + System.Threading.Tasks.Task DownloadFileRestAsync(long sessionID, Scada.Agent.RelPath relPath, long position); + } + + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.ServiceModel", "4.0.0.0")] + [System.ServiceModel.MessageContractAttribute(WrapperName="CreateSession", WrapperNamespace="http://tempuri.org/", IsWrapped=true)] + public partial class CreateSessionRequest { + + public CreateSessionRequest() { + } + } + + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.ServiceModel", "4.0.0.0")] + [System.ServiceModel.MessageContractAttribute(WrapperName="CreateSessionResponse", WrapperNamespace="http://tempuri.org/", IsWrapped=true)] + public partial class CreateSessionResponse { + + [System.ServiceModel.MessageBodyMemberAttribute(Namespace="http://tempuri.org/", Order=0)] + public bool CreateSessionResult; + + [System.ServiceModel.MessageBodyMemberAttribute(Namespace="http://tempuri.org/", Order=1)] + public long sessionID; + + public CreateSessionResponse() { + } + + public CreateSessionResponse(bool CreateSessionResult, long sessionID) { + this.CreateSessionResult = CreateSessionResult; + this.sessionID = sessionID; + } + } + + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.ServiceModel", "4.0.0.0")] + [System.ServiceModel.MessageContractAttribute(WrapperName="Login", WrapperNamespace="http://tempuri.org/", IsWrapped=true)] + public partial class LoginRequest { + + [System.ServiceModel.MessageBodyMemberAttribute(Namespace="http://tempuri.org/", Order=0)] + public long sessionID; + + [System.ServiceModel.MessageBodyMemberAttribute(Namespace="http://tempuri.org/", Order=1)] + public string username; + + [System.ServiceModel.MessageBodyMemberAttribute(Namespace="http://tempuri.org/", Order=2)] + public string encryptedPassword; + + [System.ServiceModel.MessageBodyMemberAttribute(Namespace="http://tempuri.org/", Order=3)] + public string scadaInstanceName; + + public LoginRequest() { + } + + public LoginRequest(long sessionID, string username, string encryptedPassword, string scadaInstanceName) { + this.sessionID = sessionID; + this.username = username; + this.encryptedPassword = encryptedPassword; + this.scadaInstanceName = scadaInstanceName; + } + } + + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.ServiceModel", "4.0.0.0")] + [System.ServiceModel.MessageContractAttribute(WrapperName="LoginResponse", WrapperNamespace="http://tempuri.org/", IsWrapped=true)] + public partial class LoginResponse { + + [System.ServiceModel.MessageBodyMemberAttribute(Namespace="http://tempuri.org/", Order=0)] + public bool LoginResult; + + [System.ServiceModel.MessageBodyMemberAttribute(Namespace="http://tempuri.org/", Order=1)] + public string errMsg; + + public LoginResponse() { + } + + public LoginResponse(bool LoginResult, string errMsg) { + this.LoginResult = LoginResult; + this.errMsg = errMsg; + } + } + + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.ServiceModel", "4.0.0.0")] + [System.ServiceModel.MessageContractAttribute(WrapperName="GetServiceStatus", WrapperNamespace="http://tempuri.org/", IsWrapped=true)] + public partial class GetServiceStatusRequest { + + [System.ServiceModel.MessageBodyMemberAttribute(Namespace="http://tempuri.org/", Order=0)] + public long sessionID; + + [System.ServiceModel.MessageBodyMemberAttribute(Namespace="http://tempuri.org/", Order=1)] + public Scada.Agent.ServiceApp serviceApp; + + public GetServiceStatusRequest() { + } + + public GetServiceStatusRequest(long sessionID, Scada.Agent.ServiceApp serviceApp) { + this.sessionID = sessionID; + this.serviceApp = serviceApp; + } + } + + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.ServiceModel", "4.0.0.0")] + [System.ServiceModel.MessageContractAttribute(WrapperName="GetServiceStatusResponse", WrapperNamespace="http://tempuri.org/", IsWrapped=true)] + public partial class GetServiceStatusResponse { + + [System.ServiceModel.MessageBodyMemberAttribute(Namespace="http://tempuri.org/", Order=0)] + public bool GetServiceStatusResult; + + [System.ServiceModel.MessageBodyMemberAttribute(Namespace="http://tempuri.org/", Order=1)] + public Scada.Agent.ServiceStatus status; + + public GetServiceStatusResponse() { + } + + public GetServiceStatusResponse(bool GetServiceStatusResult, Scada.Agent.ServiceStatus status) { + this.GetServiceStatusResult = GetServiceStatusResult; + this.status = status; + } + } + + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.ServiceModel", "4.0.0.0")] + [System.ServiceModel.MessageContractAttribute(WrapperName="GetAvailableConfig", WrapperNamespace="http://tempuri.org/", IsWrapped=true)] + public partial class GetAvailableConfigRequest { + + [System.ServiceModel.MessageBodyMemberAttribute(Namespace="http://tempuri.org/", Order=0)] + public long sessionID; + + public GetAvailableConfigRequest() { + } + + public GetAvailableConfigRequest(long sessionID) { + this.sessionID = sessionID; + } + } + + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.ServiceModel", "4.0.0.0")] + [System.ServiceModel.MessageContractAttribute(WrapperName="GetAvailableConfigResponse", WrapperNamespace="http://tempuri.org/", IsWrapped=true)] + public partial class GetAvailableConfigResponse { + + [System.ServiceModel.MessageBodyMemberAttribute(Namespace="http://tempuri.org/", Order=0)] + public bool GetAvailableConfigResult; + + [System.ServiceModel.MessageBodyMemberAttribute(Namespace="http://tempuri.org/", Order=1)] + public Scada.Agent.ConfigParts configParts; + + public GetAvailableConfigResponse() { + } + + public GetAvailableConfigResponse(bool GetAvailableConfigResult, Scada.Agent.ConfigParts configParts) { + this.GetAvailableConfigResult = GetAvailableConfigResult; + this.configParts = configParts; + } + } + + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.ServiceModel", "4.0.0.0")] + [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Advanced)] + [System.ServiceModel.MessageContractAttribute(WrapperName="ConfigUploadMessage", WrapperNamespace="http://tempuri.org/", IsWrapped=true)] + public partial class ConfigUploadMessage { + + [System.ServiceModel.MessageHeaderAttribute(Namespace="http://tempuri.org/")] + public Scada.Agent.ConfigOptions ConfigOptions; + + [System.ServiceModel.MessageHeaderAttribute(Namespace="http://tempuri.org/")] + public long SessionID; + + [System.ServiceModel.MessageBodyMemberAttribute(Namespace="http://tempuri.org/", Order=0)] + public System.IO.Stream Stream; + + public ConfigUploadMessage() { + } + + public ConfigUploadMessage(Scada.Agent.ConfigOptions ConfigOptions, long SessionID, System.IO.Stream Stream) { + this.ConfigOptions = ConfigOptions; + this.SessionID = SessionID; + this.Stream = Stream; + } + } + + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.ServiceModel", "4.0.0.0")] + [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Advanced)] + [System.ServiceModel.MessageContractAttribute(IsWrapped=false)] + public partial class UploadConfigResponse { + + public UploadConfigResponse() { + } + } + + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.ServiceModel", "4.0.0.0")] + [System.ServiceModel.MessageContractAttribute(WrapperName="Browse", WrapperNamespace="http://tempuri.org/", IsWrapped=true)] + public partial class BrowseRequest { + + [System.ServiceModel.MessageBodyMemberAttribute(Namespace="http://tempuri.org/", Order=0)] + public long sessionID; + + [System.ServiceModel.MessageBodyMemberAttribute(Namespace="http://tempuri.org/", Order=1)] + public Scada.Agent.RelPath relPath; + + public BrowseRequest() { + } + + public BrowseRequest(long sessionID, Scada.Agent.RelPath relPath) { + this.sessionID = sessionID; + this.relPath = relPath; + } + } + + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.ServiceModel", "4.0.0.0")] + [System.ServiceModel.MessageContractAttribute(WrapperName="BrowseResponse", WrapperNamespace="http://tempuri.org/", IsWrapped=true)] + public partial class BrowseResponse { + + [System.ServiceModel.MessageBodyMemberAttribute(Namespace="http://tempuri.org/", Order=0)] + public bool BrowseResult; + + [System.ServiceModel.MessageBodyMemberAttribute(Namespace="http://tempuri.org/", Order=1)] + public string[] directories; + + [System.ServiceModel.MessageBodyMemberAttribute(Namespace="http://tempuri.org/", Order=2)] + public string[] files; + + public BrowseResponse() { + } + + public BrowseResponse(bool BrowseResult, string[] directories, string[] files) { + this.BrowseResult = BrowseResult; + this.directories = directories; + this.files = files; + } + } + + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.ServiceModel", "4.0.0.0")] + public interface AgentSvcChannel : Scada.Agent.Test.AgentSvcRef.AgentSvc, System.ServiceModel.IClientChannel { + } + + [System.Diagnostics.DebuggerStepThroughAttribute()] + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.ServiceModel", "4.0.0.0")] + public partial class AgentSvcClient : System.ServiceModel.ClientBase, Scada.Agent.Test.AgentSvcRef.AgentSvc { + + public AgentSvcClient() { + } + + public AgentSvcClient(string endpointConfigurationName) : + base(endpointConfigurationName) { + } + + public AgentSvcClient(string endpointConfigurationName, string remoteAddress) : + base(endpointConfigurationName, remoteAddress) { + } + + public AgentSvcClient(string endpointConfigurationName, System.ServiceModel.EndpointAddress remoteAddress) : + base(endpointConfigurationName, remoteAddress) { + } + + public AgentSvcClient(System.ServiceModel.Channels.Binding binding, System.ServiceModel.EndpointAddress remoteAddress) : + base(binding, remoteAddress) { + } + + [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Advanced)] + Scada.Agent.Test.AgentSvcRef.CreateSessionResponse Scada.Agent.Test.AgentSvcRef.AgentSvc.CreateSession(Scada.Agent.Test.AgentSvcRef.CreateSessionRequest request) { + return base.Channel.CreateSession(request); + } + + public bool CreateSession(out long sessionID) { + Scada.Agent.Test.AgentSvcRef.CreateSessionRequest inValue = new Scada.Agent.Test.AgentSvcRef.CreateSessionRequest(); + Scada.Agent.Test.AgentSvcRef.CreateSessionResponse retVal = ((Scada.Agent.Test.AgentSvcRef.AgentSvc)(this)).CreateSession(inValue); + sessionID = retVal.sessionID; + return retVal.CreateSessionResult; + } + + public System.Threading.Tasks.Task CreateSessionAsync(Scada.Agent.Test.AgentSvcRef.CreateSessionRequest request) { + return base.Channel.CreateSessionAsync(request); + } + + [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Advanced)] + Scada.Agent.Test.AgentSvcRef.LoginResponse Scada.Agent.Test.AgentSvcRef.AgentSvc.Login(Scada.Agent.Test.AgentSvcRef.LoginRequest request) { + return base.Channel.Login(request); + } + + public bool Login(long sessionID, string username, string encryptedPassword, string scadaInstanceName, out string errMsg) { + Scada.Agent.Test.AgentSvcRef.LoginRequest inValue = new Scada.Agent.Test.AgentSvcRef.LoginRequest(); + inValue.sessionID = sessionID; + inValue.username = username; + inValue.encryptedPassword = encryptedPassword; + inValue.scadaInstanceName = scadaInstanceName; + Scada.Agent.Test.AgentSvcRef.LoginResponse retVal = ((Scada.Agent.Test.AgentSvcRef.AgentSvc)(this)).Login(inValue); + errMsg = retVal.errMsg; + return retVal.LoginResult; + } + + public System.Threading.Tasks.Task LoginAsync(Scada.Agent.Test.AgentSvcRef.LoginRequest request) { + return base.Channel.LoginAsync(request); + } + + public bool ControlService(long sessionID, Scada.Agent.ServiceApp serviceApp, Scada.Agent.ServiceCommand command) { + return base.Channel.ControlService(sessionID, serviceApp, command); + } + + public System.Threading.Tasks.Task ControlServiceAsync(long sessionID, Scada.Agent.ServiceApp serviceApp, Scada.Agent.ServiceCommand command) { + return base.Channel.ControlServiceAsync(sessionID, serviceApp, command); + } + + [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Advanced)] + Scada.Agent.Test.AgentSvcRef.GetServiceStatusResponse Scada.Agent.Test.AgentSvcRef.AgentSvc.GetServiceStatus(Scada.Agent.Test.AgentSvcRef.GetServiceStatusRequest request) { + return base.Channel.GetServiceStatus(request); + } + + public bool GetServiceStatus(long sessionID, Scada.Agent.ServiceApp serviceApp, out Scada.Agent.ServiceStatus status) { + Scada.Agent.Test.AgentSvcRef.GetServiceStatusRequest inValue = new Scada.Agent.Test.AgentSvcRef.GetServiceStatusRequest(); + inValue.sessionID = sessionID; + inValue.serviceApp = serviceApp; + Scada.Agent.Test.AgentSvcRef.GetServiceStatusResponse retVal = ((Scada.Agent.Test.AgentSvcRef.AgentSvc)(this)).GetServiceStatus(inValue); + status = retVal.status; + return retVal.GetServiceStatusResult; + } + + public System.Threading.Tasks.Task GetServiceStatusAsync(Scada.Agent.Test.AgentSvcRef.GetServiceStatusRequest request) { + return base.Channel.GetServiceStatusAsync(request); + } + + [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Advanced)] + Scada.Agent.Test.AgentSvcRef.GetAvailableConfigResponse Scada.Agent.Test.AgentSvcRef.AgentSvc.GetAvailableConfig(Scada.Agent.Test.AgentSvcRef.GetAvailableConfigRequest request) { + return base.Channel.GetAvailableConfig(request); + } + + public bool GetAvailableConfig(long sessionID, out Scada.Agent.ConfigParts configParts) { + Scada.Agent.Test.AgentSvcRef.GetAvailableConfigRequest inValue = new Scada.Agent.Test.AgentSvcRef.GetAvailableConfigRequest(); + inValue.sessionID = sessionID; + Scada.Agent.Test.AgentSvcRef.GetAvailableConfigResponse retVal = ((Scada.Agent.Test.AgentSvcRef.AgentSvc)(this)).GetAvailableConfig(inValue); + configParts = retVal.configParts; + return retVal.GetAvailableConfigResult; + } + + public System.Threading.Tasks.Task GetAvailableConfigAsync(Scada.Agent.Test.AgentSvcRef.GetAvailableConfigRequest request) { + return base.Channel.GetAvailableConfigAsync(request); + } + + public System.IO.Stream DownloadConfig(long sessionID, Scada.Agent.ConfigOptions configOptions) { + return base.Channel.DownloadConfig(sessionID, configOptions); + } + + public System.Threading.Tasks.Task DownloadConfigAsync(long sessionID, Scada.Agent.ConfigOptions configOptions) { + return base.Channel.DownloadConfigAsync(sessionID, configOptions); + } + + [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Advanced)] + Scada.Agent.Test.AgentSvcRef.UploadConfigResponse Scada.Agent.Test.AgentSvcRef.AgentSvc.UploadConfig(Scada.Agent.Test.AgentSvcRef.ConfigUploadMessage request) { + return base.Channel.UploadConfig(request); + } + + public void UploadConfig(Scada.Agent.ConfigOptions ConfigOptions, long SessionID, System.IO.Stream Stream) { + Scada.Agent.Test.AgentSvcRef.ConfigUploadMessage inValue = new Scada.Agent.Test.AgentSvcRef.ConfigUploadMessage(); + inValue.ConfigOptions = ConfigOptions; + inValue.SessionID = SessionID; + inValue.Stream = Stream; + Scada.Agent.Test.AgentSvcRef.UploadConfigResponse retVal = ((Scada.Agent.Test.AgentSvcRef.AgentSvc)(this)).UploadConfig(inValue); + } + + [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Advanced)] + System.Threading.Tasks.Task Scada.Agent.Test.AgentSvcRef.AgentSvc.UploadConfigAsync(Scada.Agent.Test.AgentSvcRef.ConfigUploadMessage request) { + return base.Channel.UploadConfigAsync(request); + } + + public System.Threading.Tasks.Task UploadConfigAsync(Scada.Agent.ConfigOptions ConfigOptions, long SessionID, System.IO.Stream Stream) { + Scada.Agent.Test.AgentSvcRef.ConfigUploadMessage inValue = new Scada.Agent.Test.AgentSvcRef.ConfigUploadMessage(); + inValue.ConfigOptions = ConfigOptions; + inValue.SessionID = SessionID; + inValue.Stream = Stream; + return ((Scada.Agent.Test.AgentSvcRef.AgentSvc)(this)).UploadConfigAsync(inValue); + } + + [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Advanced)] + Scada.Agent.Test.AgentSvcRef.BrowseResponse Scada.Agent.Test.AgentSvcRef.AgentSvc.Browse(Scada.Agent.Test.AgentSvcRef.BrowseRequest request) { + return base.Channel.Browse(request); + } + + public bool Browse(long sessionID, Scada.Agent.RelPath relPath, out string[] directories, out string[] files) { + Scada.Agent.Test.AgentSvcRef.BrowseRequest inValue = new Scada.Agent.Test.AgentSvcRef.BrowseRequest(); + inValue.sessionID = sessionID; + inValue.relPath = relPath; + Scada.Agent.Test.AgentSvcRef.BrowseResponse retVal = ((Scada.Agent.Test.AgentSvcRef.AgentSvc)(this)).Browse(inValue); + directories = retVal.directories; + files = retVal.files; + return retVal.BrowseResult; + } + + public System.Threading.Tasks.Task BrowseAsync(Scada.Agent.Test.AgentSvcRef.BrowseRequest request) { + return base.Channel.BrowseAsync(request); + } + + public System.IO.Stream DownloadFile(long sessionID, Scada.Agent.RelPath relPath) { + return base.Channel.DownloadFile(sessionID, relPath); + } + + public System.Threading.Tasks.Task DownloadFileAsync(long sessionID, Scada.Agent.RelPath relPath) { + return base.Channel.DownloadFileAsync(sessionID, relPath); + } + + public System.IO.Stream DownloadFileRest(long sessionID, Scada.Agent.RelPath relPath, long position) { + return base.Channel.DownloadFileRest(sessionID, relPath, position); + } + + public System.Threading.Tasks.Task DownloadFileRestAsync(long sessionID, Scada.Agent.RelPath relPath, long position) { + return base.Channel.DownloadFileRestAsync(sessionID, relPath, position); + } + } +} diff --git a/ScadaAgent/ScadaAgent/ScadaAgentCtrl/Connected Services/ServiceReference1/Reference.svcmap b/ScadaAgent/ScadaAgentTest/Connected Services/AgentSvcRef/Reference.svcmap similarity index 63% rename from ScadaAgent/ScadaAgent/ScadaAgentCtrl/Connected Services/ServiceReference1/Reference.svcmap rename to ScadaAgent/ScadaAgentTest/Connected Services/AgentSvcRef/Reference.svcmap index 04424c815..27dce9b1d 100644 --- a/ScadaAgent/ScadaAgent/ScadaAgentCtrl/Connected Services/ServiceReference1/Reference.svcmap +++ b/ScadaAgent/ScadaAgentTest/Connected Services/AgentSvcRef/Reference.svcmap @@ -1,5 +1,5 @@ - + false true @@ -22,10 +22,13 @@ - - - - + + + + + + + diff --git a/ScadaAgent/ScadaAgentTest/Connected Services/AgentSvcRef/Scada.Agent.Test.AgentSvcRef.BrowseResponse.datasource b/ScadaAgent/ScadaAgentTest/Connected Services/AgentSvcRef/Scada.Agent.Test.AgentSvcRef.BrowseResponse.datasource new file mode 100644 index 000000000..0b62e42ed --- /dev/null +++ b/ScadaAgent/ScadaAgentTest/Connected Services/AgentSvcRef/Scada.Agent.Test.AgentSvcRef.BrowseResponse.datasource @@ -0,0 +1,10 @@ + + + + Scada.Agent.Test.AgentSvcRef.BrowseResponse + \ No newline at end of file diff --git a/ScadaAgent/ScadaAgentTest/Connected Services/AgentSvcRef/Scada.Agent.Test.AgentSvcRef.CreateSessionResponse.datasource b/ScadaAgent/ScadaAgentTest/Connected Services/AgentSvcRef/Scada.Agent.Test.AgentSvcRef.CreateSessionResponse.datasource new file mode 100644 index 000000000..afebfb821 --- /dev/null +++ b/ScadaAgent/ScadaAgentTest/Connected Services/AgentSvcRef/Scada.Agent.Test.AgentSvcRef.CreateSessionResponse.datasource @@ -0,0 +1,10 @@ + + + + Scada.Agent.Test.AgentSvcRef.CreateSessionResponse + \ No newline at end of file diff --git a/ScadaAgent/ScadaAgentTest/Connected Services/AgentSvcRef/Scada.Agent.Test.AgentSvcRef.GetAvailableConfigResponse.datasource b/ScadaAgent/ScadaAgentTest/Connected Services/AgentSvcRef/Scada.Agent.Test.AgentSvcRef.GetAvailableConfigResponse.datasource new file mode 100644 index 000000000..477ee8f06 --- /dev/null +++ b/ScadaAgent/ScadaAgentTest/Connected Services/AgentSvcRef/Scada.Agent.Test.AgentSvcRef.GetAvailableConfigResponse.datasource @@ -0,0 +1,10 @@ + + + + Scada.Agent.Test.AgentSvcRef.GetAvailableConfigResponse + \ No newline at end of file diff --git a/ScadaAgent/ScadaAgentTest/Connected Services/AgentSvcRef/Scada.Agent.Test.AgentSvcRef.GetServiceStatusResponse.datasource b/ScadaAgent/ScadaAgentTest/Connected Services/AgentSvcRef/Scada.Agent.Test.AgentSvcRef.GetServiceStatusResponse.datasource new file mode 100644 index 000000000..1c7b71986 --- /dev/null +++ b/ScadaAgent/ScadaAgentTest/Connected Services/AgentSvcRef/Scada.Agent.Test.AgentSvcRef.GetServiceStatusResponse.datasource @@ -0,0 +1,10 @@ + + + + Scada.Agent.Test.AgentSvcRef.GetServiceStatusResponse + \ No newline at end of file diff --git a/ScadaAgent/ScadaAgentTest/Connected Services/AgentSvcRef/Scada.Agent.Test.AgentSvcRef.LoginResponse.datasource b/ScadaAgent/ScadaAgentTest/Connected Services/AgentSvcRef/Scada.Agent.Test.AgentSvcRef.LoginResponse.datasource new file mode 100644 index 000000000..bf22d3b92 --- /dev/null +++ b/ScadaAgent/ScadaAgentTest/Connected Services/AgentSvcRef/Scada.Agent.Test.AgentSvcRef.LoginResponse.datasource @@ -0,0 +1,10 @@ + + + + Scada.Agent.Test.AgentSvcRef.LoginResponse + \ No newline at end of file diff --git a/ScadaAgent/ScadaAgentTest/Connected Services/AgentSvcRef/Scada.Agent.Test.AgentSvcRef.UploadConfigResponse.datasource b/ScadaAgent/ScadaAgentTest/Connected Services/AgentSvcRef/Scada.Agent.Test.AgentSvcRef.UploadConfigResponse.datasource new file mode 100644 index 000000000..759deeea0 --- /dev/null +++ b/ScadaAgent/ScadaAgentTest/Connected Services/AgentSvcRef/Scada.Agent.Test.AgentSvcRef.UploadConfigResponse.datasource @@ -0,0 +1,10 @@ + + + + Scada.Agent.Test.AgentSvcRef.UploadConfigResponse + \ No newline at end of file diff --git a/ScadaAgent/ScadaAgentTest/Connected Services/AgentSvcRef/configuration.svcinfo b/ScadaAgent/ScadaAgentTest/Connected Services/AgentSvcRef/configuration.svcinfo new file mode 100644 index 000000000..38bb543c7 --- /dev/null +++ b/ScadaAgent/ScadaAgentTest/Connected Services/AgentSvcRef/configuration.svcinfo @@ -0,0 +1,10 @@ + + + + + + + + + + \ No newline at end of file diff --git a/ScadaAgent/ScadaAgentTest/Connected Services/AgentSvcRef/configuration91.svcinfo b/ScadaAgent/ScadaAgentTest/Connected Services/AgentSvcRef/configuration91.svcinfo new file mode 100644 index 000000000..8031434d2 --- /dev/null +++ b/ScadaAgent/ScadaAgentTest/Connected Services/AgentSvcRef/configuration91.svcinfo @@ -0,0 +1,201 @@ + + + + + + + BasicHttpBinding_AgentSvc + + + + + + + + + + + + + + + + + + + + + StrongWildcard + + + + + + 65536 + + + + + + + + + System.ServiceModel.Configuration.XmlDictionaryReaderQuotasElement + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + System.Text.UTF8Encoding + + + Buffered + + + + + + Text + + + System.ServiceModel.Configuration.BasicHttpSecurityElement + + + None + + + System.ServiceModel.Configuration.HttpTransportSecurityElement + + + None + + + None + + + System.Security.Authentication.ExtendedProtection.Configuration.ExtendedProtectionPolicyElement + + + Never + + + TransportSelected + + + (Collection) + + + + + + System.ServiceModel.Configuration.BasicHttpMessageSecurityElement + + + UserName + + + Default + + + + + + + + + http://localhost:10002/ScadaAgent/ScadaAgentSvc/ + + + + + + basicHttpBinding + + + BasicHttpBinding_AgentSvc + + + AgentSvcRef.AgentSvc + + + System.ServiceModel.Configuration.AddressHeaderCollectionElement + + + <Header /> + + + System.ServiceModel.Configuration.IdentityElement + + + System.ServiceModel.Configuration.UserPrincipalNameElement + + + + + + System.ServiceModel.Configuration.ServicePrincipalNameElement + + + + + + System.ServiceModel.Configuration.DnsElement + + + + + + System.ServiceModel.Configuration.RsaElement + + + + + + System.ServiceModel.Configuration.CertificateElement + + + + + + System.ServiceModel.Configuration.CertificateReferenceElement + + + My + + + LocalMachine + + + FindBySubjectDistinguishedName + + + + + + False + + + BasicHttpBinding_AgentSvc + + + + + + + + + + + \ No newline at end of file diff --git a/ScadaAgent/ScadaAgentTest/Connected Services/AgentSvcRef/item.disco b/ScadaAgent/ScadaAgentTest/Connected Services/AgentSvcRef/item.disco new file mode 100644 index 000000000..c6b1d8ffa --- /dev/null +++ b/ScadaAgent/ScadaAgentTest/Connected Services/AgentSvcRef/item.disco @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/ScadaAgent/ScadaAgentTest/Connected Services/AgentSvcRef/item.xsd b/ScadaAgent/ScadaAgentTest/Connected Services/AgentSvcRef/item.xsd new file mode 100644 index 000000000..04a74a45c --- /dev/null +++ b/ScadaAgent/ScadaAgentTest/Connected Services/AgentSvcRef/item.xsd @@ -0,0 +1,9 @@ + + + + + + + + + \ No newline at end of file diff --git a/ScadaAgent/ScadaAgentTest/Connected Services/AgentSvcRef/item1.xsd b/ScadaAgent/ScadaAgentTest/Connected Services/AgentSvcRef/item1.xsd new file mode 100644 index 000000000..e13908491 --- /dev/null +++ b/ScadaAgent/ScadaAgentTest/Connected Services/AgentSvcRef/item1.xsd @@ -0,0 +1,116 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + + + + + + + 1 + + + + + + + 2 + + + + + + + 4 + + + + + + + 8 + + + + + + + 16 + + + + + + + 31 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/ScadaAgent/ScadaAgentTest/Connected Services/AgentSvcRef/item2.xsd b/ScadaAgent/ScadaAgentTest/Connected Services/AgentSvcRef/item2.xsd new file mode 100644 index 000000000..9c6da3168 --- /dev/null +++ b/ScadaAgent/ScadaAgentTest/Connected Services/AgentSvcRef/item2.xsd @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/ScadaAgent/ScadaAgentTest/Connected Services/AgentSvcRef/item3.xsd b/ScadaAgent/ScadaAgentTest/Connected Services/AgentSvcRef/item3.xsd new file mode 100644 index 000000000..f5e7fda8c --- /dev/null +++ b/ScadaAgent/ScadaAgentTest/Connected Services/AgentSvcRef/item3.xsd @@ -0,0 +1,156 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/ScadaAgent/ScadaAgentTest/Connected Services/AgentSvcRef/item4.xsd b/ScadaAgent/ScadaAgentTest/Connected Services/AgentSvcRef/item4.xsd new file mode 100644 index 000000000..d58e7f39c --- /dev/null +++ b/ScadaAgent/ScadaAgentTest/Connected Services/AgentSvcRef/item4.xsd @@ -0,0 +1,42 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/ScadaAgent/ScadaAgentTest/FrmMain.Designer.cs b/ScadaAgent/ScadaAgentTest/FrmMain.Designer.cs new file mode 100644 index 000000000..286481f92 --- /dev/null +++ b/ScadaAgent/ScadaAgentTest/FrmMain.Designer.cs @@ -0,0 +1,90 @@ +namespace Scada.Agent.Test +{ + partial class FrmMain + { + /// + /// Required designer variable. + /// + private System.ComponentModel.IContainer components = null; + + /// + /// Clean up any resources being used. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region Windows Form Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + this.btnCreateSession = new System.Windows.Forms.Button(); + this.btnDownload = new System.Windows.Forms.Button(); + this.btnUpload = new System.Windows.Forms.Button(); + this.SuspendLayout(); + // + // btnCreateSession + // + this.btnCreateSession.Location = new System.Drawing.Point(12, 12); + this.btnCreateSession.Name = "btnCreateSession"; + this.btnCreateSession.Size = new System.Drawing.Size(100, 23); + this.btnCreateSession.TabIndex = 0; + this.btnCreateSession.Text = "Create Session"; + this.btnCreateSession.UseVisualStyleBackColor = true; + this.btnCreateSession.Click += new System.EventHandler(this.btnCreateSession_Click); + // + // btnDownload + // + this.btnDownload.Location = new System.Drawing.Point(12, 41); + this.btnDownload.Name = "btnDownload"; + this.btnDownload.Size = new System.Drawing.Size(100, 23); + this.btnDownload.TabIndex = 1; + this.btnDownload.Text = "Download"; + this.btnDownload.UseVisualStyleBackColor = true; + this.btnDownload.Click += new System.EventHandler(this.btnDownload_Click); + // + // btnUpload + // + this.btnUpload.Location = new System.Drawing.Point(12, 70); + this.btnUpload.Name = "btnUpload"; + this.btnUpload.Size = new System.Drawing.Size(100, 23); + this.btnUpload.TabIndex = 2; + this.btnUpload.Text = "Upload"; + this.btnUpload.UseVisualStyleBackColor = true; + this.btnUpload.Click += new System.EventHandler(this.btnUpload_Click); + // + // FrmMain + // + this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.ClientSize = new System.Drawing.Size(284, 311); + this.Controls.Add(this.btnUpload); + this.Controls.Add(this.btnDownload); + this.Controls.Add(this.btnCreateSession); + this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedSingle; + this.MaximizeBox = false; + this.Name = "FrmMain"; + this.StartPosition = System.Windows.Forms.FormStartPosition.CenterScreen; + this.Text = "Agent Test"; + this.ResumeLayout(false); + + } + + #endregion + + private System.Windows.Forms.Button btnCreateSession; + private System.Windows.Forms.Button btnDownload; + private System.Windows.Forms.Button btnUpload; + } +} + diff --git a/ScadaAgent/ScadaAgentTest/FrmMain.cs b/ScadaAgent/ScadaAgentTest/FrmMain.cs new file mode 100644 index 000000000..d06a12a2a --- /dev/null +++ b/ScadaAgent/ScadaAgentTest/FrmMain.cs @@ -0,0 +1,134 @@ +/* + * Copyright 2018 Mikhail Shiryaev + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * + * Product : Rapid SCADA + * Module : ScadaAgentTest + * Summary : Simple application for testing Agent + * + * Author : Mikhail Shiryaev + * Created : 2018 + * Modified : 2018 + */ + +using Scada.Agent.Test.AgentSvcRef; +using System; +using System.IO; +using System.Windows.Forms; + +namespace Scada.Agent.Test +{ + /// + /// Simple application for testing Agent + /// Простое приложение для тестирования Агента + /// + public partial class FrmMain : Form + { + private const string SecretKey = "5ABF5A7FD01752A2F1DFD21370B96EA462B0AE5C66A64F8901C9E1E2A06E40F1"; + private const string DefConfigArc = @"C:\SCADA\config.zip"; + + private long sessionID = 0; + + + public FrmMain() + { + InitializeComponent(); + } + + + private void btnCreateSession_Click(object sender, EventArgs e) + { + AgentSvcClient client = new AgentSvcClient(); + + try + { + if (client.CreateSession(out sessionID)) + { + MessageBox.Show("Session created: " + sessionID); + + string encPwd = CryptoUtils.EncryptPassword("12345", sessionID, ScadaUtils.HexToBytes(SecretKey)); + + if (client.Login(sessionID, "admin", encPwd, "Default", out string errMsg)) + MessageBox.Show("Logged on."); + else + MessageBox.Show(errMsg); + } + else + { + MessageBox.Show("Unable to create session."); + } + } + finally + { + client.Close(); + } + } + + private void btnDownload_Click(object sender, EventArgs e) + { + AgentSvcClient client = new AgentSvcClient(); + + try + { + Stream stream = client.DownloadConfig(sessionID, new ConfigOptions()); + + if (stream == null) + { + MessageBox.Show("Download stream is null."); + } + else + { + DateTime t0 = DateTime.UtcNow; + byte[] buf = new byte[1024]; + + using (FileStream fileStream = + File.Open(DefConfigArc, FileMode.Create, FileAccess.Write, FileShare.Read)) + { + stream.CopyTo(fileStream); + } + + stream.Close(); + MessageBox.Show("Done in " + (int)(DateTime.UtcNow - t0).TotalMilliseconds + " ms"); + } + } + finally + { + client.Close(); + } + } + + private void btnUpload_Click(object sender, EventArgs e) + { + AgentSvcClient client = new AgentSvcClient(); + + try + { + DateTime t0 = DateTime.UtcNow; + + using (FileStream fileStream = + File.Open(DefConfigArc, FileMode.Open, FileAccess.Read, FileShare.Read)) + { + client.UploadConfig(new ConfigOptions(), sessionID, fileStream); + } + + MessageBox.Show("Done in " + (int)(DateTime.UtcNow - t0).TotalMilliseconds + " ms"); + } + finally + { + client.Close(); + } + } + } +} diff --git a/ScadaAgent/ScadaAgentTest/FrmMain.resx b/ScadaAgent/ScadaAgentTest/FrmMain.resx new file mode 100644 index 000000000..1af7de150 --- /dev/null +++ b/ScadaAgent/ScadaAgentTest/FrmMain.resx @@ -0,0 +1,120 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + \ No newline at end of file diff --git a/ScadaAgent/ScadaAgent/ScadaAgentCtrl/Program.cs b/ScadaAgent/ScadaAgentTest/Program.cs similarity index 93% rename from ScadaAgent/ScadaAgent/ScadaAgentCtrl/Program.cs rename to ScadaAgent/ScadaAgentTest/Program.cs index 89aa955a4..f104b38fc 100644 --- a/ScadaAgent/ScadaAgent/ScadaAgentCtrl/Program.cs +++ b/ScadaAgent/ScadaAgentTest/Program.cs @@ -1,7 +1,7 @@ using System; using System.Windows.Forms; -namespace Scada.Agent.Ctrl +namespace Scada.Agent.Test { static class Program { diff --git a/ScadaAgent/ScadaAgent/ScadaAgentCtrl/Properties/AssemblyInfo.cs b/ScadaAgent/ScadaAgentTest/Properties/AssemblyInfo.cs similarity index 75% rename from ScadaAgent/ScadaAgent/ScadaAgentCtrl/Properties/AssemblyInfo.cs rename to ScadaAgent/ScadaAgentTest/Properties/AssemblyInfo.cs index 2c7eab398..e233dfa8e 100644 --- a/ScadaAgent/ScadaAgent/ScadaAgentCtrl/Properties/AssemblyInfo.cs +++ b/ScadaAgent/ScadaAgentTest/Properties/AssemblyInfo.cs @@ -1,16 +1,16 @@ -using System.Reflection; -using System.Runtime.CompilerServices; +using Scada.Agent; +using System.Reflection; using System.Runtime.InteropServices; // General Information about an assembly is controlled through the following // set of attributes. Change these attribute values to modify the information // associated with an assembly. -[assembly: AssemblyTitle("ScadaAgentCtrl")] +[assembly: AssemblyTitle("ScadaAgentTest")] [assembly: AssemblyDescription("")] [assembly: AssemblyConfiguration("")] [assembly: AssemblyCompany("")] -[assembly: AssemblyProduct("ScadaAgentCtrl")] -[assembly: AssemblyCopyright("Copyright © 2018")] +[assembly: AssemblyProduct("Rapid SCADA")] +[assembly: AssemblyCopyright("Copyright © 2018")] [assembly: AssemblyTrademark("")] [assembly: AssemblyCulture("")] @@ -20,7 +20,7 @@ [assembly: ComVisible(false)] // The following GUID is for the ID of the typelib if this project is exposed to COM -[assembly: Guid("67aee6a7-0f2e-4273-8253-231e6bf3c943")] +[assembly: Guid("c5b4f9fa-e4ae-418e-9ce8-8cb92c9cbfb8")] // Version information for an assembly consists of the following four values: // @@ -32,5 +32,5 @@ // You can specify all the values or you can default the Build and Revision Numbers // by using the '*' as shown below: // [assembly: AssemblyVersion("1.0.*")] -[assembly: AssemblyVersion("1.0.0.0")] -[assembly: AssemblyFileVersion("1.0.0.0")] +[assembly: AssemblyVersion(AgentUtils.AppVersion)] +[assembly: AssemblyFileVersion(AgentUtils.AppVersion)] diff --git a/ScadaAgent/ScadaAgent/ScadaAgentCtrl/Properties/Resources.Designer.cs b/ScadaAgent/ScadaAgentTest/Properties/Resources.Designer.cs similarity index 94% rename from ScadaAgent/ScadaAgent/ScadaAgentCtrl/Properties/Resources.Designer.cs rename to ScadaAgent/ScadaAgentTest/Properties/Resources.Designer.cs index 95e08f008..629ee0126 100644 --- a/ScadaAgent/ScadaAgent/ScadaAgentCtrl/Properties/Resources.Designer.cs +++ b/ScadaAgent/ScadaAgentTest/Properties/Resources.Designer.cs @@ -8,7 +8,7 @@ // //------------------------------------------------------------------------------ -namespace Scada.Agent.Ctrl.Properties { +namespace Scada.Agent.Test.Properties { using System; @@ -39,7 +39,7 @@ internal Resources() { internal static global::System.Resources.ResourceManager ResourceManager { get { if (object.ReferenceEquals(resourceMan, null)) { - global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("Scada.Agent.Ctrl.Properties.Resources", typeof(Resources).Assembly); + global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("Scada.Agent.Test.Properties.Resources", typeof(Resources).Assembly); resourceMan = temp; } return resourceMan; diff --git a/ScadaAgent/ScadaAgent/ScadaAgentCtrl/Properties/Resources.resx b/ScadaAgent/ScadaAgentTest/Properties/Resources.resx similarity index 100% rename from ScadaAgent/ScadaAgent/ScadaAgentCtrl/Properties/Resources.resx rename to ScadaAgent/ScadaAgentTest/Properties/Resources.resx diff --git a/ScadaAgent/ScadaAgent/ScadaAgentCtrl/Properties/Settings.Designer.cs b/ScadaAgent/ScadaAgentTest/Properties/Settings.Designer.cs similarity index 94% rename from ScadaAgent/ScadaAgent/ScadaAgentCtrl/Properties/Settings.Designer.cs rename to ScadaAgent/ScadaAgentTest/Properties/Settings.Designer.cs index 620cff267..f8ad98ccf 100644 --- a/ScadaAgent/ScadaAgent/ScadaAgentCtrl/Properties/Settings.Designer.cs +++ b/ScadaAgent/ScadaAgentTest/Properties/Settings.Designer.cs @@ -8,11 +8,11 @@ // //------------------------------------------------------------------------------ -namespace Scada.Agent.Ctrl.Properties { +namespace Scada.Agent.Test.Properties { [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] - [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "15.6.0.0")] + [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "15.7.0.0")] internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase { private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings()))); diff --git a/ScadaAgent/ScadaAgent/ScadaAgentCtrl/Properties/Settings.settings b/ScadaAgent/ScadaAgentTest/Properties/Settings.settings similarity index 100% rename from ScadaAgent/ScadaAgent/ScadaAgentCtrl/Properties/Settings.settings rename to ScadaAgent/ScadaAgentTest/Properties/Settings.settings diff --git a/ScadaAgent/ScadaAgent/ScadaAgentCtrl/ScadaAgentCtrl.csproj b/ScadaAgent/ScadaAgentTest/ScadaAgentTest.csproj similarity index 57% rename from ScadaAgent/ScadaAgent/ScadaAgentCtrl/ScadaAgentCtrl.csproj rename to ScadaAgent/ScadaAgentTest/ScadaAgentTest.csproj index a611faa34..1af8f433f 100644 --- a/ScadaAgent/ScadaAgent/ScadaAgentCtrl/ScadaAgentCtrl.csproj +++ b/ScadaAgent/ScadaAgentTest/ScadaAgentTest.csproj @@ -4,10 +4,10 @@ Debug AnyCPU - {67AEE6A7-0F2E-4273-8253-231E6BF3C943} + {C5B4F9FA-E4AE-418E-9CE8-8CB92C9CBFB8} WinExe - Scada.Agent.Ctrl - ScadaAgentCtrl + Scada.Agent.Test + ScadaAgentTest v4.6.1 512 true @@ -32,16 +32,24 @@ 4 + + ..\..\Log\Log.Std\bin\Release\netstandard2.0\Log.Std.dll + + + ..\..\ScadaData\ScadaData.Std\bin\Release\netstandard2.0\ScadaData.Std.dll + - - + + + + - + True True Reference.svcmap @@ -67,13 +75,40 @@ Resources.resx True - - + + + Designer + + Designer - + Designer + + Designer + + + Designer + + + Reference.svcmap + + + Reference.svcmap + + + Reference.svcmap + + + Reference.svcmap + + + Reference.svcmap + + + Reference.svcmap + SettingsSingleFileGenerator Settings.Designer.cs @@ -87,23 +122,29 @@ + + + {5163526d-91e4-414d-97fe-090e1e7fda6b} + ScadaAgentCore + + - + - + - + - + - + WCF Proxy Generator Reference.cs diff --git a/ScadaComm/OpenKPs/AddressBook/AddressBook.csproj b/ScadaComm/OpenKPs/AddressBook/AddressBook.csproj index 24d714a29..d19544f38 100644 --- a/ScadaComm/OpenKPs/AddressBook/AddressBook.csproj +++ b/ScadaComm/OpenKPs/AddressBook/AddressBook.csproj @@ -34,7 +34,7 @@ False - ..\..\..\Log\bin\Release\Log.dll + ..\..\..\Log\Log\bin\Release\Log.dll False diff --git a/ScadaComm/OpenKPs/KpEmail/KpEmail.csproj b/ScadaComm/OpenKPs/KpEmail/KpEmail.csproj index ff9fe237e..71a9903f1 100644 --- a/ScadaComm/OpenKPs/KpEmail/KpEmail.csproj +++ b/ScadaComm/OpenKPs/KpEmail/KpEmail.csproj @@ -31,8 +31,9 @@ 4 - - ..\..\..\Log\bin\Release\Log.dll + + False + ..\..\..\Log\Log\bin\Release\Log.dll ..\..\ScadaCommCommon\bin\Release\ScadaCommCommon.dll diff --git a/ScadaComm/OpenKPs/KpHttpNotif/KpHttpNotif.csproj b/ScadaComm/OpenKPs/KpHttpNotif/KpHttpNotif.csproj index 94c3ea92c..a677fe0bd 100644 --- a/ScadaComm/OpenKPs/KpHttpNotif/KpHttpNotif.csproj +++ b/ScadaComm/OpenKPs/KpHttpNotif/KpHttpNotif.csproj @@ -30,8 +30,9 @@ 4 - - ..\..\..\Log\bin\Release\Log.dll + + False + ..\..\..\Log\Log\bin\Release\Log.dll ..\..\ScadaCommCommon\bin\Release\ScadaCommCommon.dll diff --git a/ScadaComm/OpenKPs/KpModbus/KpModbus.csproj b/ScadaComm/OpenKPs/KpModbus/KpModbus.csproj index 55b59b71c..c25a48513 100644 --- a/ScadaComm/OpenKPs/KpModbus/KpModbus.csproj +++ b/ScadaComm/OpenKPs/KpModbus/KpModbus.csproj @@ -34,7 +34,7 @@ False - ..\..\..\Log\bin\Release\Log.dll + ..\..\..\Log\Log\bin\Release\Log.dll ..\..\ScadaCommCommon\bin\Release\ScadaCommCommon.dll diff --git a/ScadaComm/OpenKPs/KpSms/KpSms.csproj b/ScadaComm/OpenKPs/KpSms/KpSms.csproj index 4c47f3c94..f6b4d3dc6 100644 --- a/ScadaComm/OpenKPs/KpSms/KpSms.csproj +++ b/ScadaComm/OpenKPs/KpSms/KpSms.csproj @@ -38,7 +38,7 @@ False - ..\..\..\Log\bin\Release\Log.dll + ..\..\..\Log\Log\bin\Release\Log.dll ..\..\ScadaCommCommon\bin\Release\ScadaCommCommon.dll diff --git a/ScadaComm/OpenKPs/KpSnmp/KpSnmp.csproj b/ScadaComm/OpenKPs/KpSnmp/KpSnmp.csproj index 745e5f2bb..217553a66 100644 --- a/ScadaComm/OpenKPs/KpSnmp/KpSnmp.csproj +++ b/ScadaComm/OpenKPs/KpSnmp/KpSnmp.csproj @@ -30,8 +30,9 @@ 4 - - ..\..\..\Log\bin\Release\Log.dll + + False + ..\..\..\Log\Log\bin\Release\Log.dll ..\..\ScadaCommCommon\bin\Release\ScadaCommCommon.dll diff --git a/ScadaComm/OpenKPs/KpTest/KpTest.csproj b/ScadaComm/OpenKPs/KpTest/KpTest.csproj index 0a6d8a2fc..7b2803dac 100644 --- a/ScadaComm/OpenKPs/KpTest/KpTest.csproj +++ b/ScadaComm/OpenKPs/KpTest/KpTest.csproj @@ -36,8 +36,9 @@ 4 - - ..\..\..\Log\bin\Release\Log.dll + + False + ..\..\..\Log\Log\bin\Release\Log.dll ..\..\ScadaCommCommon\bin\Release\ScadaCommCommon.dll diff --git a/ScadaComm/ScadaCommCommon/Channels/SerialConnection.cs b/ScadaComm/ScadaCommCommon/Channels/SerialConnection.cs index 0e9ac54e8..d71167f48 100644 --- a/ScadaComm/ScadaCommCommon/Channels/SerialConnection.cs +++ b/ScadaComm/ScadaCommCommon/Channels/SerialConnection.cs @@ -167,7 +167,7 @@ public override int Read(byte[] buffer, int offset, int maxCount, int timeout, C int curInd = offset; SerialPort.ReadTimeout = 0; - while (readCnt <= maxCount && !stopReceived && startDT <= nowDT && nowDT <= stopDT) + while (readCnt < maxCount && !stopReceived && startDT <= nowDT && nowDT <= stopDT) { bool readOk; try { readOk = SerialPort.Read(buffer, curInd, 1) > 0; } diff --git a/ScadaComm/ScadaCommCommon/CommUtils.cs b/ScadaComm/ScadaCommCommon/CommUtils.cs index 865228fc5..9a66fd0d2 100644 --- a/ScadaComm/ScadaCommCommon/CommUtils.cs +++ b/ScadaComm/ScadaCommCommon/CommUtils.cs @@ -1,5 +1,5 @@ /* - * Copyright 2017 Mikhail Shiryaev + * Copyright 2018 Mikhail Shiryaev * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -20,7 +20,7 @@ * * Author : Mikhail Shiryaev * Created : 2015 - * Modified : 2017 + * Modified : 2018 */ using Scada.Data.Configuration; @@ -58,7 +58,7 @@ public enum ProtocolLogFormats /// /// Версия Коммуникатора /// - public const string AppVersion = "5.1.0.2"; + public const string AppVersion = "5.1.0.3"; /// /// Формат даты и времени для вывода в журнал линии связи diff --git a/ScadaComm/ScadaCommCommon/Properties/AssemblyInfo.cs b/ScadaComm/ScadaCommCommon/Properties/AssemblyInfo.cs index 4958905b3..5ff05e896 100644 --- a/ScadaComm/ScadaCommCommon/Properties/AssemblyInfo.cs +++ b/ScadaComm/ScadaCommCommon/Properties/AssemblyInfo.cs @@ -10,7 +10,7 @@ [assembly: AssemblyConfiguration("")] [assembly: AssemblyCompany("")] [assembly: AssemblyProduct("Rapid SCADA")] -[assembly: AssemblyCopyright("Copyright © 2015-2016")] +[assembly: AssemblyCopyright("Copyright © 2015-2018")] [assembly: AssemblyTrademark("")] [assembly: AssemblyCulture("")] diff --git a/ScadaComm/ScadaCommCommon/ScadaCommCommon.csproj b/ScadaComm/ScadaCommCommon/ScadaCommCommon.csproj index 79d47b249..5d9b48b61 100644 --- a/ScadaComm/ScadaCommCommon/ScadaCommCommon.csproj +++ b/ScadaComm/ScadaCommCommon/ScadaCommCommon.csproj @@ -33,7 +33,7 @@ False - ..\..\Log\bin\Release\Log.dll + ..\..\Log\Log\bin\Release\Log.dll ..\..\ScadaData\ScadaData\bin\Release\ScadaData.dll diff --git a/ScadaComm/ScadaCommCtrl/FrmAbout.resx b/ScadaComm/ScadaCommCtrl/FrmAbout.resx index 5ddd4b666..b5da92898 100644 --- a/ScadaComm/ScadaCommCtrl/FrmAbout.resx +++ b/ScadaComm/ScadaCommCtrl/FrmAbout.resx @@ -760,238 +760,237 @@ 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 - 85ranFwGI//Z + +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 @@ -1634,236 +1633,236 @@ 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 - zaULQd6Xf3qy2d24tTDXXu5TNPV9VkHbV1NJrKfluDpmYTQzQyOKO2le3eD3EuAbRrXOBAowlop2nFjC - WtLqA1rSOJc57QaUFBjiRXloeQVIBNMQtDkFob+ppmxnMzGcr1/Zjf23HP1UnNhzOW1qqd8olH3b5iZx - VPIBdnkkgal5e6Wozm5uXy0W+oG30luXR0mk1PVPc2Vz1zRVv42JmkwqOqnwmdVMOni3nRd4zuzFutI3 - iG9sP7XZDiTQmoaRV2AAwbANdQOod4OqcscKYY09OQ2nPqHkn7vfmc5bqv5SLT1zS0gmtOWEu9YXmZrC - +lKVhII600ycWt7jWlO6bqCzNNSubxcivdGXejL3SJ9V8G8iqNg6OeW9UiIeT91UBVTiZXV5BKJHAnec - 1zQ2hrjN3lfpaUwzrvbKYrkcb2kA5Ag1/rd2nLnjlSnmXfndsWG7w/l/sLazl2uDcCQSSiuXaQcrtqHc - 0v3QFsLrVTXUktJRs/obmIp3lwjeV+4VjZTR3LHU8pk1FvLNVVc6BnF2pfEIqZVbU3FofSR3Dhu57SWU - ysBLnlx7JIAqat3t4Grs98No32d05qUTZGtDScBTPmzpSmGVK451C0C+Nqeabmcufcmua+5Rbu0/WvL3 - d21M45XJkqv+VX7nas5beXPvD+UrmduHSluZrI+Y6OupVPM5zyUvypSSfS95cemKFomj3kpk1LqjJEuH - qOrKw+jlhiY1rZGlr2newdUOdG5oJ7NA1hcQd0uJqXUODW/Oa9xJLTUHDKlAQeXM020Ay5ScXW5Zr1wH - ItaCSjlMn98b3SzvV5Lz+SO2VNT7ltVcGwlLVP3ptY8+c+fRFX3dvBb62Esu7TPLjVU1t5NlUjU85h4i - pZ9ES+BmMdTURGTwRZcRfGnHvA2LuO7r2qOIjDMgCabwDsQMBUgHBdLHd2OzV2/XZh2q7TnTD6C+i9ob - ZVzOOYy+/Mtd+R/BZi/MJy/ctVKRsylE7iqF5dKIi3U4q+unkNL5hVUto6vuaS9T2NnE5Mmm7t1PbdUn - bNzPJZLajkMwg4dGWVohbBEaj2nHlcchsqGtwFRg4voSCCitYSS52eQ6Pon0AVxXgSacl/MrMec2/V4K - ln9fVRylXD5+bAXdmnKZI5py/SKT3B+6vlm7vmVWX5v5fXkfSxvJD/0c+aLl8jIqqLfvKzpX5nkVMuZl - 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 \ No newline at end of file diff --git a/ScadaComm/ScadaCommCtrl/Properties/AssemblyInfo.cs b/ScadaComm/ScadaCommCtrl/Properties/AssemblyInfo.cs index abc535d59..8cb7e0207 100644 --- a/ScadaComm/ScadaCommCtrl/Properties/AssemblyInfo.cs +++ b/ScadaComm/ScadaCommCtrl/Properties/AssemblyInfo.cs @@ -10,7 +10,7 @@ [assembly: AssemblyConfiguration("")] [assembly: AssemblyCompany("")] [assembly: AssemblyProduct("Rapid SCADA")] -[assembly: AssemblyCopyright("Copyright © 2008-2016")] +[assembly: AssemblyCopyright("Copyright © 2008-2018")] [assembly: AssemblyTrademark("")] [assembly: AssemblyCulture("")] diff --git a/ScadaComm/ScadaCommCtrl/ScadaCommCtrl.csproj b/ScadaComm/ScadaCommCtrl/ScadaCommCtrl.csproj index 4d362b076..18d59e0f2 100644 --- a/ScadaComm/ScadaCommCtrl/ScadaCommCtrl.csproj +++ b/ScadaComm/ScadaCommCtrl/ScadaCommCtrl.csproj @@ -58,7 +58,7 @@ False - ..\..\Log\bin\Release\Log.dll + ..\..\Log\Log\bin\Release\Log.dll ..\ScadaCommCommon\bin\Release\ScadaCommCommon.dll diff --git a/ScadaComm/ScadaCommMono/Properties/AssemblyInfo.cs b/ScadaComm/ScadaCommMono/Properties/AssemblyInfo.cs index 2b0c04c70..2a30f40de 100644 --- a/ScadaComm/ScadaCommMono/Properties/AssemblyInfo.cs +++ b/ScadaComm/ScadaCommMono/Properties/AssemblyInfo.cs @@ -10,7 +10,7 @@ [assembly: AssemblyConfiguration("")] [assembly: AssemblyCompany("")] [assembly: AssemblyProduct("Rapid SCADA")] -[assembly: AssemblyCopyright("Copyright © 2015-2016")] +[assembly: AssemblyCopyright("Copyright © 2015-2018")] [assembly: AssemblyTrademark("")] [assembly: AssemblyCulture("")] diff --git a/ScadaComm/ScadaCommMono/ScadaCommMono.csproj b/ScadaComm/ScadaCommMono/ScadaCommMono.csproj index 65a6350b3..5ad55854e 100644 --- a/ScadaComm/ScadaCommMono/ScadaCommMono.csproj +++ b/ScadaComm/ScadaCommMono/ScadaCommMono.csproj @@ -32,8 +32,9 @@ 4 - - ..\..\Log\bin\Release\Log.dll + + False + ..\..\Log\Log\bin\Release\Log.dll ..\..\ScadaData\ScadaData\bin\Release\ScadaData.dll diff --git a/ScadaComm/ScadaCommSvc/Manager.cs b/ScadaComm/ScadaCommSvc/Manager.cs index 03c9354ae..5f23d526f 100644 --- a/ScadaComm/ScadaCommSvc/Manager.cs +++ b/ScadaComm/ScadaCommSvc/Manager.cs @@ -1,5 +1,5 @@ /* - * Copyright 2017 Mikhail Shiryaev + * Copyright 2018 Mikhail Shiryaev * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -20,7 +20,7 @@ * * Author : Mikhail Shiryaev * Created : 2006 - * Modified : 2017 + * Modified : 2018 */ using Scada.Data.Models; @@ -43,9 +43,43 @@ namespace Scada.Comm.Svc internal sealed class Manager { /// - /// Имя файла конфигурации + /// Наименования состояний работы /// - private const string ConfigFileName = "ScadaCommSvcConfig.xml"; + private static class WorkStateNames + { + /// + /// Статический конструктор + /// + static WorkStateNames() + { + if (Localization.UseRussian) + { + Normal = "норма"; + Stopped = "остановлен"; + Error = "ошибка"; + } + else + { + Normal = "normal"; + Stopped = "stopped"; + Error = "error"; + } + } + + /// + /// Норма + /// + public static readonly string Normal; + /// + /// Остановлен + /// + public static readonly string Stopped; + /// + /// Ошибка + /// + public static readonly string Error; + } + /// /// Имя основного Log-файла программы /// @@ -70,6 +104,7 @@ internal sealed class Manager private string infoFileName; // полное имя файла информации private Thread startThread; // поток повторения попыток запуска private DateTime startDT; // дата и время запуска работы + private string workState; // состояние работы private bool linesStarted; // потоки линий связи запущены private string[] lineCaptions; // обозначения линий связи private object lineCmdLock; // объект для синхронизации выполнения команд над линиями связи @@ -87,6 +122,7 @@ public Manager() infoFileName = ""; startThread = null; startDT = DateTime.MinValue; + workState = ""; linesStarted = false; lineCaptions = null; lineCmdLock = new object(); @@ -290,7 +326,7 @@ private void WriteInfo() StringBuilder sbInfo = new StringBuilder(); TimeSpan workSpan = DateTime.Now - startDT; - string workStr = workSpan.Days > 0 ? workSpan.ToString(@"d\.hh\:mm\:ss") : + string workDur = workSpan.Days > 0 ? workSpan.ToString(@"d\.hh\:mm\:ss") : workSpan.ToString(@"hh\:mm\:ss"); if (Localization.UseRussian) @@ -299,7 +335,8 @@ private void WriteInfo() .AppendLine("SCADA-Коммуникатор") .AppendLine("------------------") .Append("Запуск : ").AppendLine(startDT.ToLocalizedString()) - .Append("Время работы : ").AppendLine(workStr) + .Append("Время работы : ").AppendLine(workDur) + .Append("Состояние : ").AppendLine(workState) .Append("Версия : ").AppendLine(CommUtils.AppVersion) .Append("SCADA-Сервер : ").AppendLine(Settings.Params.ServerUse ? (ServerComm == null ? "не инициализирован" : ServerComm.CommStateDescr) : @@ -314,7 +351,8 @@ private void WriteInfo() .AppendLine("SCADA-Communicator") .AppendLine("------------------") .Append("Started : ").AppendLine(startDT.ToLocalizedString()) - .Append("Execution time : ").AppendLine(workStr) + .Append("Execution time : ").AppendLine(workDur) + .Append("State : ").AppendLine(workState) .Append("Version : ").AppendLine(CommUtils.AppVersion) .Append("SCADA-Server : ").AppendLine(Settings.Params.ServerUse ? (ServerComm == null ? "not initialized" : ServerComm.CommStateDescr) : @@ -402,6 +440,7 @@ private bool StartOperation() } else { + workState = WorkStateNames.Error; WriteInfo(); return false; } @@ -506,14 +545,20 @@ private bool StartThreads() commandReader.StartThread(); } - // запуск потока записи информации о работе приложения if (linesStarted) { + // запуск потока записи информации о работе приложения infoThread = new Thread(new ThreadStart(WriteInfoExecute)); infoThread.Start(); - } - return linesStarted; + workState = WorkStateNames.Normal; + return true; + } + else + { + workState = WorkStateNames.Error; + return false; + } } catch (Exception ex) { @@ -599,6 +644,7 @@ private void StopThreads() Thread.Sleep(ScadaUtils.ThreadDelay); // запись информации о работе программы + workState = WorkStateNames.Stopped; WriteInfo(); } catch (Exception ex) @@ -628,7 +674,7 @@ public void StartCommLine(int lineNum) // загрузка линии связи из файла кофигурации string errMsg; Settings.CommLine commLineSett; - if (Settings.LoadCommLine(AppDirs.ConfigDir + ConfigFileName, lineNum, + if (Settings.LoadCommLine(AppDirs.ConfigDir + Settings.DefFileName, lineNum, out commLineSett, out errMsg)) { if (commLineSett == null) @@ -843,9 +889,11 @@ public void StartService() // запуск работы if (!StartOperation()) - AppLog.WriteAction(Localization.UseRussian ? + { + AppLog.WriteAction(Localization.UseRussian ? "Нормальная работа программы невозможна." : "Normal program execution is impossible.", Log.ActTypes.Error); + } } else { diff --git a/ScadaComm/ScadaCommSvc/Properties/AssemblyInfo.cs b/ScadaComm/ScadaCommSvc/Properties/AssemblyInfo.cs index 81571d64c..f099fa262 100644 --- a/ScadaComm/ScadaCommSvc/Properties/AssemblyInfo.cs +++ b/ScadaComm/ScadaCommSvc/Properties/AssemblyInfo.cs @@ -10,7 +10,7 @@ [assembly: AssemblyConfiguration("")] [assembly: AssemblyCompany("")] [assembly: AssemblyProduct("Rapid SCADA")] -[assembly: AssemblyCopyright("Copyright © 2006-2016")] +[assembly: AssemblyCopyright("Copyright © 2006-2018")] [assembly: AssemblyTrademark("")] [assembly: AssemblyCulture("")] diff --git a/ScadaComm/ScadaCommSvc/ScadaCommSvc.csproj b/ScadaComm/ScadaCommSvc/ScadaCommSvc.csproj index d98272bf5..eeac5dd13 100644 --- a/ScadaComm/ScadaCommSvc/ScadaCommSvc.csproj +++ b/ScadaComm/ScadaCommSvc/ScadaCommSvc.csproj @@ -53,7 +53,7 @@ False - ..\..\Log\bin\Release\Log.dll + ..\..\Log\Log\bin\Release\Log.dll False diff --git a/ScadaData/ScadaData.Std/ScadaData.Std.csproj b/ScadaData/ScadaData.Std/ScadaData.Std.csproj new file mode 100644 index 000000000..8bb6a5ebc --- /dev/null +++ b/ScadaData/ScadaData.Std/ScadaData.Std.csproj @@ -0,0 +1,64 @@ + + + + netstandard2.0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ..\..\Log\Log.Std\bin\Release\netstandard2.0\Log.Std.dll + + + + diff --git a/ScadaData/ScadaData.sln b/ScadaData/ScadaData.sln index ad9d9441a..dbad85f73 100644 --- a/ScadaData/ScadaData.sln +++ b/ScadaData/ScadaData.sln @@ -1,6 +1,6 @@ Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio 14 -VisualStudioVersion = 14.0.25420.1 +# Visual Studio 15 +VisualStudioVersion = 15.0.27428.2005 MinimumVisualStudioVersion = 10.0.40219.1 Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ScadaData", "ScadaData\ScadaData.csproj", "{C5DC293F-13CA-435F-A7DB-4BA91639C292}" EndProject @@ -10,6 +10,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ScadaData.Svc", "ScadaData. EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ScadaData.Dao", "ScadaData.Dao\ScadaData.Dao.csproj", "{1DDE26A2-1E24-4680-A635-2760B37CAFDB}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ScadaData.Std", "ScadaData.Std\ScadaData.Std.csproj", "{3C69A20A-6810-445E-AE86-E98AB91C42F4}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -32,8 +34,15 @@ Global {1DDE26A2-1E24-4680-A635-2760B37CAFDB}.Debug|Any CPU.Build.0 = Debug|Any CPU {1DDE26A2-1E24-4680-A635-2760B37CAFDB}.Release|Any CPU.ActiveCfg = Release|Any CPU {1DDE26A2-1E24-4680-A635-2760B37CAFDB}.Release|Any CPU.Build.0 = Release|Any CPU + {3C69A20A-6810-445E-AE86-E98AB91C42F4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {3C69A20A-6810-445E-AE86-E98AB91C42F4}.Debug|Any CPU.Build.0 = Debug|Any CPU + {3C69A20A-6810-445E-AE86-E98AB91C42F4}.Release|Any CPU.ActiveCfg = Release|Any CPU + {3C69A20A-6810-445E-AE86-E98AB91C42F4}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {ED6A68FA-3866-482A-846C-1C0CED33847A} + EndGlobalSection EndGlobal diff --git a/ScadaData/ScadaData/CommonPhrases.cs b/ScadaData/ScadaData/CommonPhrases.cs index bc05dabf9..0165004e8 100644 --- a/ScadaData/ScadaData/CommonPhrases.cs +++ b/ScadaData/ScadaData/CommonPhrases.cs @@ -64,6 +64,7 @@ static CommonPhrases() public static string DateTimeRequired { get; private set; } public static string LineLengthLimit { get; private set; } public static string NotNumber { get; private set; } + public static string NotHexadecimal { get; private set; } public static string LoadImageError { get; private set; } public static string LoadHyperlinkError { get; private set; } public static string IncorrectFileFormat { get; private set; } @@ -136,6 +137,7 @@ private static void SetToDefault() DateTimeRequired = Localization.Dict.GetEmptyPhrase("DateTimeRequired"); LineLengthLimit = Localization.Dict.GetEmptyPhrase("LineLengthLimit"); NotNumber = Localization.Dict.GetEmptyPhrase("NotNumber"); + NotHexadecimal = Localization.Dict.GetEmptyPhrase("NotHexadecimal"); LoadImageError = Localization.Dict.GetEmptyPhrase("LoadImageError"); LoadHyperlinkError = Localization.Dict.GetEmptyPhrase("LoadHyperlinkError"); IncorrectFileFormat = Localization.Dict.GetEmptyPhrase("IncorrectFileFormat"); @@ -212,6 +214,7 @@ public static void Init() DateTimeRequired = dict.GetPhrase("DateTimeRequired", DateTimeRequired); LineLengthLimit = dict.GetPhrase("LineLengthLimit", LineLengthLimit); NotNumber = dict.GetPhrase("NotNumber", NotNumber); + NotHexadecimal = dict.GetPhrase("NotHexadecimal", NotHexadecimal); LoadImageError = dict.GetPhrase("LoadImageError", LoadImageError); LoadHyperlinkError = dict.GetPhrase("LoadHyperlinkError", LoadHyperlinkError); NoData = dict.GetPhrase("NoData", NoData); diff --git a/ScadaData/ScadaData/Lang/ScadaData.en-GB.xml b/ScadaData/ScadaData/Lang/ScadaData.en-GB.xml index 55afea2c9..c67154112 100644 --- a/ScadaData/ScadaData/Lang/ScadaData.en-GB.xml +++ b/ScadaData/ScadaData/Lang/ScadaData.en-GB.xml @@ -27,6 +27,7 @@ Date and time are required. The string length must be {0} symbols or less. "{0}" is not a number. + String is not hexadecimal. Error loading image from file: {0} Error loading hyperlink from file: {0} Incorrect file format. diff --git a/ScadaData/ScadaData/Lang/ScadaData.ru-RU.xml b/ScadaData/ScadaData/Lang/ScadaData.ru-RU.xml index 3393ccd89..c09427ac7 100644 --- a/ScadaData/ScadaData/Lang/ScadaData.ru-RU.xml +++ b/ScadaData/ScadaData/Lang/ScadaData.ru-RU.xml @@ -27,6 +27,7 @@ Требуется дата и время. Длина строки должна быть не более {0} символов. "{0}" не является числом. + Строка не является 16-ричной записью. Ошибка при загрузке изображения из файла: {0} Ошибка при загрузке гиперссылки из файла: {0} Некорректный формат файла. diff --git a/ScadaData/ScadaData/Localization.cs b/ScadaData/ScadaData/Localization.cs index 0333a64b3..8f687e505 100644 --- a/ScadaData/ScadaData/Localization.cs +++ b/ScadaData/ScadaData/Localization.cs @@ -1,5 +1,5 @@ /* - * Copyright 2017 Mikhail Shiryaev + * Copyright 2018 Mikhail Shiryaev * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -20,10 +20,9 @@ * * Author : Mikhail Shiryaev * Created : 2014 - * Modified : 2017 + * Modified : 2018 */ -using Microsoft.Win32; using System; using System.Collections.Generic; using System.Globalization; @@ -166,11 +165,17 @@ private static string ReadCulture() { try { - using (RegistryKey key = RegistryKey.OpenBaseKey(RegistryHive.LocalMachine, RegistryView.Registry64) +#if NETSTANDARD2_0 + return ""; +#else + using (Microsoft.Win32.RegistryKey key = + Microsoft.Win32.RegistryKey.OpenBaseKey(Microsoft.Win32.RegistryHive.LocalMachine, + Microsoft.Win32.RegistryView.Registry64) .OpenSubKey("Software\\SCADA", false)) { return key.GetValue("Culture").ToString(); } +#endif } catch { @@ -224,9 +229,15 @@ public static bool WriteCulture(string cultureName, out string errMsg) { try { - using (RegistryKey key = RegistryKey.OpenBaseKey(RegistryHive.LocalMachine, RegistryView.Registry64). +#if !NETSTANDARD2_0 + using (Microsoft.Win32.RegistryKey key = + Microsoft.Win32.RegistryKey.OpenBaseKey(Microsoft.Win32.RegistryHive.LocalMachine, + Microsoft.Win32.RegistryView.Registry64). CreateSubKey("Software\\SCADA")) + { key.SetValue("Culture", cultureName); + } +#endif errMsg = ""; return true; } diff --git a/ScadaData/ScadaData/ScadaData.csproj b/ScadaData/ScadaData/ScadaData.csproj index c25fad589..4e7668afa 100644 --- a/ScadaData/ScadaData/ScadaData.csproj +++ b/ScadaData/ScadaData/ScadaData.csproj @@ -39,8 +39,9 @@ bin\Release\ScadaData.XML - - ..\..\Log\bin\Release\Log.dll + + False + ..\..\Log\Log\bin\Release\Log.dll @@ -83,6 +84,7 @@ + diff --git a/ScadaData/ScadaData/ScadaUtils.Crypto.cs b/ScadaData/ScadaData/ScadaUtils.Crypto.cs new file mode 100644 index 000000000..398852434 --- /dev/null +++ b/ScadaData/ScadaData/ScadaUtils.Crypto.cs @@ -0,0 +1,170 @@ +/* + * Copyright 2018 Mikhail Shiryaev + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * + * Product : Rapid SCADA + * Module : ScadaData + * Summary : The class contains utility methods for the whole system. Cryptographic utilities + * + * Author : Mikhail Shiryaev + * Created : 2018 + * Modified : 2018 + */ + +using System; +using System.Collections.Generic; +using System.IO; +using System.Security.Cryptography; +using System.Text; + +namespace Scada +{ + partial class ScadaUtils + { + /// + /// Генератор криптографически защищённых случайных чисел + /// + private static readonly RNGCryptoServiceProvider Rng = new RNGCryptoServiceProvider(); + + /// + /// Размер секретного ключа, байт + /// + public const int SecretKeySize = 32; + /// + /// Размер вектора инициализации, байт + /// + public const int IVSize = 16; + + + /// + /// Считать все данные из потока + /// + private static byte[] ReadToEnd(Stream inputStream) + { + using (MemoryStream memStream = new MemoryStream()) + { + inputStream.CopyTo(memStream); + return memStream.ToArray(); + } + } + + + /// + /// Получить случайное 64-битное целое + /// + public static long GetRandomLong() + { + byte[] randomArr = new byte[8]; + Rng.GetBytes(randomArr); + return BitConverter.ToInt64(randomArr, 0); + } + + /// + /// Получить случайный массив байт + /// + public static byte[] GetRandomBytes(int count) + { + byte[] randomArr = new byte[count]; + Rng.GetBytes(randomArr); + return randomArr; + } + + /// + /// Вычислить хеш-функцию MD5 по массиву байт + /// + public static string ComputeHash(byte[] bytes) + { + return BytesToHex(MD5.Create().ComputeHash(bytes)); + } + + /// + /// Вычислить хеш-функцию MD5 по строке + /// + public static string ComputeHash(string s) + { + return ComputeHash(Encoding.UTF8.GetBytes(s)); + } + + /// + /// Зашифровать строку + /// + public static string Encrypt(string s, byte[] secretKey, byte[] iv) + { + return BytesToHex(EncryptBytes(Encoding.UTF8.GetBytes(s), secretKey, iv)); + } + + /// + /// Зашифровать массив байт + /// + public static byte[] EncryptBytes(byte[] bytes, byte[] secretKey, byte[] iv) + { + RijndaelManaged alg = null; + + try + { + alg = new RijndaelManaged() { Key = secretKey, IV = iv }; + + using (MemoryStream memStream = new MemoryStream()) + { + using (CryptoStream cryptoStream = + new CryptoStream(memStream, alg.CreateEncryptor(secretKey, iv), CryptoStreamMode.Write)) + { + cryptoStream.Write(bytes, 0, bytes.Length); + } + + return memStream.ToArray(); + } + } + finally + { + alg?.Clear(); + } + } + + /// + /// Дешифровать строку + /// + public static string Decrypt(string s, byte[] secretKey, byte[] iv) + { + return Encoding.UTF8.GetString(DecryptBytes(HexToBytes(s), secretKey, iv)); + } + + /// + /// Дешифровать массив байт + /// + public static byte[] DecryptBytes(byte[] bytes, byte[] secretKey, byte[] iv) + { + RijndaelManaged alg = null; + + try + { + alg = new RijndaelManaged() { Key = secretKey, IV = iv }; + + using (MemoryStream memStream = new MemoryStream(bytes)) + { + using (CryptoStream cryptoStream = + new CryptoStream(memStream, alg.CreateDecryptor(secretKey, iv), CryptoStreamMode.Read)) + { + return ReadToEnd(cryptoStream); + } + } + } + finally + { + alg?.Clear(); + } + } + } +} diff --git a/ScadaData/ScadaData/ScadaUtils.cs b/ScadaData/ScadaData/ScadaUtils.cs index 5020813d7..ad06c9964 100644 --- a/ScadaData/ScadaData/ScadaUtils.cs +++ b/ScadaData/ScadaData/ScadaUtils.cs @@ -26,11 +26,8 @@ using System; using System.Globalization; using System.IO; -using System.Runtime.Serialization; using System.Runtime.Serialization.Formatters.Binary; -using System.Security.Cryptography; using System.Text; -using System.Web; namespace Scada { @@ -43,7 +40,16 @@ public static partial class ScadaUtils /// /// Версия данной библиотеки /// - internal const string LibVersion = "5.1.0.0"; + internal const string LibVersion = "5.1.1.0"; + /// + /// Формат вещественных чисел с разделителем точкой + /// + private static readonly NumberFormatInfo NfiDot; + /// + /// Формат вещественных чисел с разделителем запятой + /// + private static readonly NumberFormatInfo NfiComma; + /// /// Задержка потока для экономии ресурсов, мс /// @@ -54,15 +60,15 @@ public static partial class ScadaUtils /// Совпадает с началом отсчёта времени в OLE Automation и Delphi public static readonly DateTime ScadaEpoch = new DateTime(1899, 12, 30, 0, 0, 0, DateTimeKind.Utc); - private static NumberFormatInfo nfi; // формат вещественных чисел - /// /// Конструктор /// static ScadaUtils() { - nfi = (NumberFormatInfo)CultureInfo.CurrentCulture.NumberFormat.Clone(); + NfiDot = (NumberFormatInfo)CultureInfo.InvariantCulture.NumberFormat.Clone(); + NfiComma = (NumberFormatInfo)CultureInfo.InvariantCulture.NumberFormat.Clone(); + NfiComma.NumberDecimalSeparator = ","; } @@ -230,11 +236,7 @@ public static double StrToDoubleExc(string s) /// Метод работает с разделителями целой части '.' и ',' public static double ParseDouble(string s) { - lock (nfi) - { - nfi.NumberDecimalSeparator = s.Contains(".") ? "." : ","; - return double.Parse(s, nfi); - } + return double.Parse(s, s.Contains(".") ? NfiDot : NfiComma); } /// @@ -243,11 +245,7 @@ public static double ParseDouble(string s) /// Метод работает с разделителями целой части '.' и ',' public static bool TryParseDouble(string s, out double result) { - lock (nfi) - { - nfi.NumberDecimalSeparator = s.Contains(".") ? "." : ","; - return double.TryParse(s, NumberStyles.Float, nfi, out result); - } + return double.TryParse(s, NumberStyles.Float, s.Contains(".") ? NfiDot : NfiComma, out result); } /// @@ -311,21 +309,16 @@ public static bool HexToBytes(string s, out byte[] bytes, bool skipWhiteSpace = } /// - /// Вычислить хеш-функцию MD5 по массиву байт + /// Преобразовать строку 16-ричных чисел в массив байт /// - public static string ComputeHash(byte[] bytes) + public static byte[] HexToBytes(string s, bool skipWhiteSpace = false) { - return BytesToHex(MD5.Create().ComputeHash(bytes)); + if (HexToBytes(s, out byte[] bytes, skipWhiteSpace)) + return bytes; + else + throw new FormatException(CommonPhrases.NotHexadecimal); } - /// - /// Вычислить хеш-функцию MD5 по строке - /// - public static string ComputeHash(string s) - { - return ComputeHash(Encoding.UTF8.GetBytes(s)); - } - /// /// Глубокое (полное) клонирование объекта /// diff --git a/ScadaDoc/ScadaDoc/ScadaDoc.csproj b/ScadaDoc/ScadaDoc/ScadaDoc.csproj index adcc7784e..8fa98119c 100644 --- a/ScadaDoc/ScadaDoc/ScadaDoc.csproj +++ b/ScadaDoc/ScadaDoc/ScadaDoc.csproj @@ -22,6 +22,7 @@ + true @@ -111,6 +112,7 @@ + @@ -118,6 +120,19 @@ + + + + + + + + + + + + + @@ -226,6 +241,7 @@ + @@ -258,6 +274,13 @@ + + + + + + + diff --git a/ScadaDoc/ScadaDoc/content/en/software-overview/roadmap.html b/ScadaDoc/ScadaDoc/content/en/software-overview/roadmap.html new file mode 100644 index 000000000..11734729b --- /dev/null +++ b/ScadaDoc/ScadaDoc/content/en/software-overview/roadmap.html @@ -0,0 +1,100 @@ + + + + Roadmap - Rapid SCADA Documentation + + + + + + +

Roadmap

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Main Features
Unified development environment of Rapid SCADA projectsIn development
The Agent application for interacting with remote serversIn development
Schemes
Binding any properties of scheme components to input channelsNot included in plan
Displaying popups by a linkPlanned in 2018
New scheme componentsCommunity help is appreciated
New images for schemesCommunity help is appreciated
Communicator Drivers
IEC-61850 DriverCommunity help is appreciated
BACnet DriverCommunity help is appreciated
Any new driversCommunity help is appreciated
Server Modules
Module for automatic generation of reports on a scheduleNot included in plan
Voice ModuleCommunity help is appreciated
Any new modulesCommunity help is appreciated
Webstation Plugins
Update Chart Pro Plugin according to feedback from usersNot included in plan
Improvement of Dashboard PluginNot included in plan
Development of a plugin for downloading and uploading archivesNot included in plan
Any new pluginsCommunity help is appreciated
+ + \ No newline at end of file diff --git a/ScadaDoc/ScadaDoc/content/en/use-cases/remote-server-management-files/server_connection_en.png b/ScadaDoc/ScadaDoc/content/en/use-cases/remote-server-management-files/server_connection_en.png new file mode 100644 index 000000000..55d33a86f Binary files /dev/null and b/ScadaDoc/ScadaDoc/content/en/use-cases/remote-server-management-files/server_connection_en.png differ diff --git a/ScadaDoc/ScadaDoc/content/en/use-cases/remote-server-management-files/server_download1_en.png b/ScadaDoc/ScadaDoc/content/en/use-cases/remote-server-management-files/server_download1_en.png new file mode 100644 index 000000000..13c930ef1 Binary files /dev/null and b/ScadaDoc/ScadaDoc/content/en/use-cases/remote-server-management-files/server_download1_en.png differ diff --git a/ScadaDoc/ScadaDoc/content/en/use-cases/remote-server-management-files/server_download2_en.png b/ScadaDoc/ScadaDoc/content/en/use-cases/remote-server-management-files/server_download2_en.png new file mode 100644 index 000000000..edad9b164 Binary files /dev/null and b/ScadaDoc/ScadaDoc/content/en/use-cases/remote-server-management-files/server_download2_en.png differ diff --git a/ScadaDoc/ScadaDoc/content/en/use-cases/remote-server-management-files/server_status_en.png b/ScadaDoc/ScadaDoc/content/en/use-cases/remote-server-management-files/server_status_en.png new file mode 100644 index 000000000..0993f25fa Binary files /dev/null and b/ScadaDoc/ScadaDoc/content/en/use-cases/remote-server-management-files/server_status_en.png differ diff --git a/ScadaDoc/ScadaDoc/content/en/use-cases/remote-server-management-files/server_upload1_en.png b/ScadaDoc/ScadaDoc/content/en/use-cases/remote-server-management-files/server_upload1_en.png new file mode 100644 index 000000000..739fc36b3 Binary files /dev/null and b/ScadaDoc/ScadaDoc/content/en/use-cases/remote-server-management-files/server_upload1_en.png differ diff --git a/ScadaDoc/ScadaDoc/content/en/use-cases/remote-server-management-files/server_upload2_en.png b/ScadaDoc/ScadaDoc/content/en/use-cases/remote-server-management-files/server_upload2_en.png new file mode 100644 index 000000000..da67b70b4 Binary files /dev/null and b/ScadaDoc/ScadaDoc/content/en/use-cases/remote-server-management-files/server_upload2_en.png differ diff --git a/ScadaDoc/ScadaDoc/content/en/use-cases/remote-server-management.html b/ScadaDoc/ScadaDoc/content/en/use-cases/remote-server-management.html new file mode 100644 index 000000000..ad55a9a1a --- /dev/null +++ b/ScadaDoc/ScadaDoc/content/en/use-cases/remote-server-management.html @@ -0,0 +1,73 @@ + + + + Managing Remote Server using Agent - Rapid SCADA Documentation + + + + + + +

Managing Remote Server using Agent

+ +

The Agent service is installed on a remote server and provides the exchange of configurations between the server and a workstation of an engineer who is working on a SCADA system project.

+ +

Installation

+ +

Agent works on Windows and Linux operating systems. Agent does not have a user interface and it works as a Windows service or as a Linux daemon. The step-by-step installation manual of Agent is in the distributive package.

+ +

To interact with Agent, the Administrator application 5.1.0.0 or higher is needed. Administrator is installed as a part of Rapid SCADA.

+ +

Use Cases

+ +

Initial condition: there is a remote server with installed Rapid SCADA and Agent, as well as an engineer's workstation which is used for the manipulations described in the article.

+ +

Edit Existing Configuration

+ +

It is recommended to store Rapid SCADA configurations (projects) on a file server that is backed up, or use a version control system such as Git. To upload a configuration to a production server, edit the configuration on a workstation and use the Administrator application for transfer.

+ +

It is possible that a configuration of Rapid SCADA is stored only on a remote server. In this case, in order to edit the configuration, you have to download it to the workstation first. Before this, open the configuration database file in SDF format using Administrator. The configuration will be imported into this SDF database for editing. Then click the menu item Remote Server > Download configuration... to open the form shown in the figure below.

+ +

+ Download Configuration
+

+ +

In the case of subsequent editing of the configuration, you have to set the download parameters exactly as shown in the figure. After the successful download, the form for importing the configuration from the DAT format to the SDF format will open. The cause is that a working copy of the configuration on the server is stored in the specialized DAT format, while the SDF format is used for editing. After successful import, edit the Rapid SCADA configuration database and settings of the all applications on the workstation.

+ +

Before the first using of the download and upload feature, create a connection to the server as shown in the following figure. The user name and password are verified by the Agent according to the configuration database deployed on the remote server. The specified user must have the Administrator role. The System instance and Secret key fields must match the corresponding Agent settings.

+ +

+ Connection Settings
+

+ +

After the configuration editing is completed, upload it back to the remote server. To do this, choose the menu item Remote Server > Upload configuration... The following form appears:

+ +

+ Upload Configuration
+

+ +

First, tick the root node of the tree to select all the configuration files for uploading, and then expand each node in the tree to check the selected files and exclude redundant files if they are present. After successful uploading the configuration, the Agent restarts the Server and Communicator services on the remote server to apply the changes. Test the server is up after the configuration is uploaded.

+ +

Copy Configuration from One Server to Another

+ +

This scenario is possible if there are test and production servers or main and standby servers. Consider the transfer of the configuration from the server 1 to the server 2.

+ +

Open the downloading dialog and set the download options as shown in the figure. The difference is that the configuration is saved into the archive, the server-specific files are not downloaded, and the configuration database import is not executed. After the download is complete, it is a good idea to open the saved archive file and check the configuration files it contains.

+ +

+ Download Configuration
+

+ +

Then, open the upload dialog and create a connection to the server 2. Select the previously saved configuration archive file as the source and untick the checkbox of clearing server-specific files. After uploading the configuration, verify that the server 2 works well.

+ +

+ Upload Configuration
+

+ +

Check the server status with help of the form which is called from the menu Remote Server > Server Status... Select the connection to the server and click the Connect button. In case of the error status of the Server or Communicator service, connect to the file system of the remote server and analyze the Rapid SCADA application logs. In addition, this form allows to remotely restart the the Server and Communicator services.

+ +

+ Server Status
+

+ + \ No newline at end of file diff --git a/ScadaDoc/ScadaDoc/content/en/version-history/administrator-history.html b/ScadaDoc/ScadaDoc/content/en/version-history/administrator-history.html new file mode 100644 index 000000000..b717b5d72 --- /dev/null +++ b/ScadaDoc/ScadaDoc/content/en/version-history/administrator-history.html @@ -0,0 +1,16 @@ + + + + Administrator History - Rapid SCADA Documentation + + + + + + +

Administrator History

+ +
5.1.0.0 (May 23, 2018)
+- Interaction with Agent for downloading and uploading configurations
+ + diff --git a/ScadaDoc/ScadaDoc/content/en/version-history/communicator-history.html b/ScadaDoc/ScadaDoc/content/en/version-history/communicator-history.html new file mode 100644 index 000000000..096e2152e --- /dev/null +++ b/ScadaDoc/ScadaDoc/content/en/version-history/communicator-history.html @@ -0,0 +1,17 @@ + + + + Communicator History - Rapid SCADA Documentation + + + + + + +

Communicator History

+ +
5.1.0.3 (May 23, 2018)
+- The status of the service is displayed in the status file
+- Fixed a bug in reading from the serial port with a stop condition
+ + diff --git a/ScadaDoc/ScadaDoc/content/en/version-history/index.html b/ScadaDoc/ScadaDoc/content/en/version-history/index.html new file mode 100644 index 000000000..c1c45b862 --- /dev/null +++ b/ScadaDoc/ScadaDoc/content/en/version-history/index.html @@ -0,0 +1,17 @@ + + + + Rapid SCADA Documentation + + + + + + + + + diff --git a/ScadaDoc/ScadaDoc/content/en/version-history/scada-history.html b/ScadaDoc/ScadaDoc/content/en/version-history/scada-history.html index 6057781a9..551d84889 100644 --- a/ScadaDoc/ScadaDoc/content/en/version-history/scada-history.html +++ b/ScadaDoc/ScadaDoc/content/en/version-history/scada-history.html @@ -9,5 +9,23 @@

Rapid SCADA History

+
Rapid SCADA 5.5.2 (May 23, 2018)
+  Server 5.1.0.3
+  Communicator 5.1.0.3
+  Webstation 5.0.6.0
+  Administrator 5.1.0.0
+  Table Editor 5.0.1.0
+  Scheme Editor 5.2.1.1
+
+Rapid SCADA 5.5.1 (March 16, 2018)
+  Server 5.1.0.3
+  Communicator 5.1.0.2
+    Modbus Driver 5.1.0.2
+    OPC Driver 5.0.2.0
+  Webstation 5.0.5.0
+    Basic Scheme Components 5.0.0.0
+  Administrator 5.0.0.2
+  Table Editor 5.0.1.0
+  Scheme Editor 5.2.1.0
diff --git a/ScadaDoc/ScadaDoc/content/en/version-history/scheme-editor-history.html b/ScadaDoc/ScadaDoc/content/en/version-history/scheme-editor-history.html new file mode 100644 index 000000000..13a4f09f0 --- /dev/null +++ b/ScadaDoc/ScadaDoc/content/en/version-history/scheme-editor-history.html @@ -0,0 +1,21 @@ + + + + Scheme Editor History - Rapid SCADA Documentation + + + + + + +

Scheme Editor History

+ +
5.2.1.1 (May 23, 2018)
+- Working with properties, the Delete button does not delete the component
+- Fixed a bug in the method which determines using the editor
+
+5.2.1.0 (March 16, 2018)
+- The main menu is added
+- Option to choose a browser
+ + diff --git a/ScadaDoc/ScadaDoc/content/en/version-history/server-history.html b/ScadaDoc/ScadaDoc/content/en/version-history/server-history.html new file mode 100644 index 000000000..968054dda --- /dev/null +++ b/ScadaDoc/ScadaDoc/content/en/version-history/server-history.html @@ -0,0 +1,16 @@ + + + + Server History - Rapid SCADA Documentation + + + + + + +

Server History

+ +
5.1.0.3 (March 16, 2018)
+- Localization of the file filter for modules is fixed
+ + diff --git a/ScadaDoc/ScadaDoc/content/en/version-history/webstation-history.html b/ScadaDoc/ScadaDoc/content/en/version-history/webstation-history.html new file mode 100644 index 000000000..25cf4e525 --- /dev/null +++ b/ScadaDoc/ScadaDoc/content/en/version-history/webstation-history.html @@ -0,0 +1,22 @@ + + + + Webstation History - Rapid SCADA Documentation + + + + + + +

Webstation History

+ +
5.0.6.0 (May 23, 2018)
+- Changed the base class for plugin specification
+
+5.0.5.0 (March 16, 2018)
+- Fixed a bug of jumping value formatting
+- Fixed a bug of formatting values after changing the culture
+- Queue for sending Ajax requests
+- Protect sensitive files from accessing through a browser
+ + diff --git a/ScadaDoc/ScadaDoc/content/ru/modules/mod-auto-control.html b/ScadaDoc/ScadaDoc/content/ru/modules/mod-auto-control.html index d0ee05293..fe02e4f6f 100644 --- a/ScadaDoc/ScadaDoc/content/ru/modules/mod-auto-control.html +++ b/ScadaDoc/ScadaDoc/content/ru/modules/mod-auto-control.html @@ -10,7 +10,7 @@

Модуль автоматического управления

Обзор

-

Модуль автоматического управления позволяет в автоматическом режиме отправлять команды при выполнении определённых условий. Без регистрации модуль работает в демонстрационном режиме с ограничением времени полнофункциональной работы 10 минут после перезапуска.Модуль подключается к программе SCADA-Сервер. Настройка модуля выполняется с помощью удобной формы, показанной на следующем рисунке.

+

Модуль автоматического управления позволяет в автоматическом режиме отправлять команды при выполнении определённых условий. Без регистрации модуль работает в демонстрационном режиме с ограничением времени полнофункциональной работы 10 минут после перезапуска. Модуль подключается к программе SCADA-Сервер. Настройка модуля выполняется с помощью удобной формы, показанной на следующем рисунке.

Форма конфигурации модуля

diff --git a/ScadaDoc/ScadaDoc/content/ru/software-overview/roadmap.html b/ScadaDoc/ScadaDoc/content/ru/software-overview/roadmap.html new file mode 100644 index 000000000..da530a83a --- /dev/null +++ b/ScadaDoc/ScadaDoc/content/ru/software-overview/roadmap.html @@ -0,0 +1,100 @@ + + + + Дорожная карта - Документация Rapid SCADA + + + + + + +

Дорожная карта

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Основная функциональность
Единая среда разработки проектов Rapid SCADAВ разработке
Приложение Агент для взаимодействия с удалёнными серверамиВ разработке
Мнемосхемы
Привязка произвольных свойств компонентов схем к входным каналамНе включено в план
Вызов всплывающих окон по ссылкеПланируется в 2018
Новые компоненты схемПриветствуется помощь сообщества
Новые изображения для схемПриветствуется помощь сообщества
Драйверы Коммуникатора
Драйвер IEC-61850Приветствуется помощь сообщества
Драйвер BACnetПриветствуется помощь сообщества
Любые новые драйверыПриветствуется помощь сообщества
Модули Сервера
Модуль автоматической генерации отчётов по расписаниюНе включено в план
Голосовой модульПриветствуется помощь сообщества
Любые новые модулиПриветствуется помощь сообщества
Плагины Вебстанции
Обновление плагина Графики Про согласно пожеланиям пользователейНе включено в план
Развитие плагина ДэшбордыНе включено в план
Разработка плагина выгрузки и загрузки архивовНе включено в план
Любые новые плагиныПриветствуется помощь сообщества
+ + \ No newline at end of file diff --git a/ScadaDoc/ScadaDoc/content/ru/use-cases/remote-server-management-files/server_connection_ru.png b/ScadaDoc/ScadaDoc/content/ru/use-cases/remote-server-management-files/server_connection_ru.png new file mode 100644 index 000000000..61bdbad49 Binary files /dev/null and b/ScadaDoc/ScadaDoc/content/ru/use-cases/remote-server-management-files/server_connection_ru.png differ diff --git a/ScadaDoc/ScadaDoc/content/ru/use-cases/remote-server-management-files/server_download1_ru.png b/ScadaDoc/ScadaDoc/content/ru/use-cases/remote-server-management-files/server_download1_ru.png new file mode 100644 index 000000000..68cf31291 Binary files /dev/null and b/ScadaDoc/ScadaDoc/content/ru/use-cases/remote-server-management-files/server_download1_ru.png differ diff --git a/ScadaDoc/ScadaDoc/content/ru/use-cases/remote-server-management-files/server_download2_ru.png b/ScadaDoc/ScadaDoc/content/ru/use-cases/remote-server-management-files/server_download2_ru.png new file mode 100644 index 000000000..cfd33fe86 Binary files /dev/null and b/ScadaDoc/ScadaDoc/content/ru/use-cases/remote-server-management-files/server_download2_ru.png differ diff --git a/ScadaDoc/ScadaDoc/content/ru/use-cases/remote-server-management-files/server_status_ru.png b/ScadaDoc/ScadaDoc/content/ru/use-cases/remote-server-management-files/server_status_ru.png new file mode 100644 index 000000000..de3d124df Binary files /dev/null and b/ScadaDoc/ScadaDoc/content/ru/use-cases/remote-server-management-files/server_status_ru.png differ diff --git a/ScadaDoc/ScadaDoc/content/ru/use-cases/remote-server-management-files/server_upload1_ru.png b/ScadaDoc/ScadaDoc/content/ru/use-cases/remote-server-management-files/server_upload1_ru.png new file mode 100644 index 000000000..7e7a30bbf Binary files /dev/null and b/ScadaDoc/ScadaDoc/content/ru/use-cases/remote-server-management-files/server_upload1_ru.png differ diff --git a/ScadaDoc/ScadaDoc/content/ru/use-cases/remote-server-management-files/server_upload2_ru.png b/ScadaDoc/ScadaDoc/content/ru/use-cases/remote-server-management-files/server_upload2_ru.png new file mode 100644 index 000000000..600bbb626 Binary files /dev/null and b/ScadaDoc/ScadaDoc/content/ru/use-cases/remote-server-management-files/server_upload2_ru.png differ diff --git a/ScadaDoc/ScadaDoc/content/ru/use-cases/remote-server-management.html b/ScadaDoc/ScadaDoc/content/ru/use-cases/remote-server-management.html new file mode 100644 index 000000000..4240678cf --- /dev/null +++ b/ScadaDoc/ScadaDoc/content/ru/use-cases/remote-server-management.html @@ -0,0 +1,73 @@ + + + + Управление удалённым сервером с помощью Агента - Документация Rapid SCADA + + + + + + +

Управление удалённым сервером с помощью Агента

+ +

Служба Агент устанавливается на удалённый сервер и обеспечивает обмен конфигурациями между сервером и рабочей станцией инженера, на которой выполняется работа над проектом SCADA-системы.

+ +

Установка

+ +

Агент работает на операционных системах Windows и Linux. Агент не имеет пользовательского интерфейса и работает как служба Windows или как демон на Linux. Пошаговая инструкия по установке Агента находится в архиве его дистрибутива.

+ +

Для взаимодейтвия с Агентом необходима программа Администратор версии не ниже 5.1.0.0. Администратор устанавливается в составе Rapid SCADA.

+ +

Сценарии использования

+ +

Исходные данные: имеется удалённый сервер с установленной Rapid SCADA и Агентом, а также отдельная рабочая станция инженера, с которой осуществляются описанные в статье действия.

+ +

Редактирование существующей конфигурации

+ +

Рекомендуется хранить конфигурации (проекты) Rapid SCADA на отдельном файловом сервере, который резервируется, либо использовать систему контроля версий типа Git. Чтобы передать необходимую для работы конфигурацию на производственный сервер, отредактируйте её на рабочей станции и используйте приложение Администратор для передачи.

+ +

Возможна ситуация, когда конфигурация Rapid SCADA хранится только на удалённом сервере. В этом случае, чтобы отредактировать конфигурацию, необходимо сначала её скачать на рабочую станцию. Предварительно откройте в Администраторе файл базы конфигурации в формате SDF, в который будет импортирована конфигурация для редактирования. После этого выберите пункт меню Удалённый сервер > Скачать конфигурацию..., откроется форма, показанная на рисунке ниже.

+ +

+ Скачивание конфигурации
+

+ +

Для сценария с последующим редактированием конфигурации необходимо выбрать параметры скачивания именно так, как показано на рисунке. После успешного скачивания откроется форма импорта конфигурации из формата DAT в формат SDF. Дело в том, что рабочая копия конфигурации на сервере хранится в специализированном формате DAT, а для редактирования используется формат SDF. После успешного выполнения импорта редактируйте базу конфигурации Rapid SCADA и конфигурацию всех приложений на рабочей станции.

+ +

При первом использовании функционала скачивания и передачи конфигурации необходимо создать подключение к серверу, как показано на следующем рисунке. Проверка имени и пароля пользователя выполняется Агентом по базе конфигурации, работающей на удалённом сервере. Указанный пользователь должен иметь роль Администратор. Поля Экземпляр системы и Серетный ключ должны совпадать с соответствующими параметрами настройки Агента.

+ +

+ Настройки соединения
+

+ +

После того, как необходимое редактирование конфигурации завершено, передайте её обратно на удалённый сервер. Для этого выберите пункт меню Удалённый сервер > Передать конфигурацию..., откроется следующая форма:

+ +

+ Передача конфигурации
+

+ +

Сначала отметьте корневой узел дерева, чтобы выбрать все файлы конфигурации для передачи, а затем раскройте каждый узел дерева, чтобы проверить и исключить из выбора посторонние файлы, если они присутствуют. После успешной передачи конфигурации Агент перезапустит службы Сервера и Коммуникатора на удалённом сервере, чтобы изменения вступили в силу. Обязательно проверьте работоспособность сервера после передачи конфигурации.

+ +

Копирование конфигурации с одного сервера на другой

+ +

Данный сценарий возможен в ситауации, когда существует тестовый и производственный сервера или основной и резервный сервера. Рассмотрим перенос конфигурации с сервера 1 на сервер 2.

+ +

Откройте диалог скачивания конфигурации и выберите параметры скачивания, как показано на рисунке. Отличия заключаются в том, что конфигурация сохраняется в архив, специфичные для сервера файлы не скачиваются, и импорт базы конфигурации не вызывается. После завершения скачивания можно открыть сохранённый файл архива и проверить, какие файлы конфигурации в него вошли.

+ +

+ Скачивание конфигурации
+

+ +

Затем вызовите диалог передачи конфигурации и создайте подключение к серверу 2. Выберите в качестве источника сохранённый ранее архив конфигурации и снимите галочку очистки специфичных файлов сервера. После передачи конфигурации проверьте работоспособность сервера 2.

+ +

+ Передача конфигурации
+

+ +

Проверить состояние сервера поможет соответствующая форма, которая вызывается из меню Удалённый сервер > Статус сервера... На форме необходимо выбрать подключение к серверу и нажать кнопку Соединиться. В случае, если состояние службы Сервера или Коммуникатора - ошибка, необходимо подключиться к файловой системе удалённого сервера и проанализировать журналы работы приложений Rapid SCADA. Кроме того, данная форма позволяет удалённо перезапустить службы Сервера и Коммуникатора.

+ +

+ Статус сервера
+

+ + \ No newline at end of file diff --git a/ScadaDoc/ScadaDoc/content/ru/version-history/administrator-history.html b/ScadaDoc/ScadaDoc/content/ru/version-history/administrator-history.html index 3bee1f9b1..1d51ec20c 100644 --- a/ScadaDoc/ScadaDoc/content/ru/version-history/administrator-history.html +++ b/ScadaDoc/ScadaDoc/content/ru/version-history/administrator-history.html @@ -10,7 +10,10 @@

История приложения Администратор

-
5.0.0.2 (25.09.2017)
+    
5.1.0.0 (23.05.2018)
+- Взаимодействие с Агентом для скачивания и передачи конфигурации
+
+5.0.0.2 (25.09.2017)
 - Размер поля Исходный код в таблице Формулы увеличен до 4000 символов
 - Определение длины поля при редактировании исходного кода формул
 - Изменён алгоритм архивирования базы конфигурации
diff --git a/ScadaDoc/ScadaDoc/content/ru/version-history/communicator-history.html b/ScadaDoc/ScadaDoc/content/ru/version-history/communicator-history.html
index 421f6ec2e..73f74dc9e 100644
--- a/ScadaDoc/ScadaDoc/content/ru/version-history/communicator-history.html
+++ b/ScadaDoc/ScadaDoc/content/ru/version-history/communicator-history.html
@@ -10,7 +10,11 @@
 
     

История приложения Коммуникатор

-
5.1.0.2 (21.12.2017)
+    
5.1.0.3 (23.05.2018)
+- В файл состояния выводится состояние работы службы
+- Исправлена ошибка считывания из последовательного порта с условием остановки
+
+5.1.0.2 (21.12.2017)
 - Исправлена ошибка при разрыве соединения в канале связи UDP
 
 5.1.0.1 (18.10.2017)
diff --git a/ScadaDoc/ScadaDoc/content/ru/version-history/scada-history.html b/ScadaDoc/ScadaDoc/content/ru/version-history/scada-history.html
index f76a9aa16..d4a230d27 100644
--- a/ScadaDoc/ScadaDoc/content/ru/version-history/scada-history.html
+++ b/ScadaDoc/ScadaDoc/content/ru/version-history/scada-history.html
@@ -10,7 +10,15 @@
 
     

История Rapid SCADA

-
Rapid SCADA 5.5.1 (16.03.2018)
+    
Rapid SCADA 5.5.2 (23.05.2018)
+  Сервер 5.1.0.3
+  Коммуникатор 5.1.0.3
+  Вебстанция 5.0.6.0
+  Администратор 5.1.0.0
+  Редактор таблиц 5.0.1.0
+  Редактор схем 5.2.1.1
+
+Rapid SCADA 5.5.1 (16.03.2018)
   Сервер 5.1.0.3
   Коммуникатор 5.1.0.2
     Драйвер Modbus 5.1.0.2
diff --git a/ScadaDoc/ScadaDoc/content/ru/version-history/scheme-editor-history.html b/ScadaDoc/ScadaDoc/content/ru/version-history/scheme-editor-history.html
index 7749fe8ea..eec313974 100644
--- a/ScadaDoc/ScadaDoc/content/ru/version-history/scheme-editor-history.html
+++ b/ScadaDoc/ScadaDoc/content/ru/version-history/scheme-editor-history.html
@@ -10,7 +10,11 @@
 
     

История приложения Редактор схем

-
5.2.1.0 (16.03.2018)
+    
5.2.1.1 (23.05.2018)
+- При работе со свойствами кнопка Delete не удаляет компонент
+- Исправлена ошибка в методе определения запуска редактора
+
+5.2.1.0 (16.03.2018)
 - Добавлено главное меню
 - Опция выбора браузера
 
diff --git a/ScadaDoc/ScadaDoc/content/ru/version-history/webstation-history.html b/ScadaDoc/ScadaDoc/content/ru/version-history/webstation-history.html
index 2b9cfb629..b516b5374 100644
--- a/ScadaDoc/ScadaDoc/content/ru/version-history/webstation-history.html
+++ b/ScadaDoc/ScadaDoc/content/ru/version-history/webstation-history.html
@@ -10,7 +10,10 @@
 
     

История приложения Вебстанция

-
5.0.5.0 (16.03.2018)
+    
5.0.6.0 (23.05.2018)
+- Изменён родительский класс спецификации плагина
+
+5.0.5.0 (16.03.2018)
 - Исправлена ошибка сбоев форматирования значений
 - Исправлена ошибка форматирования значений после смены культуры
 - Очередь для отправки Ajax-запросов
diff --git a/ScadaDoc/ScadaDoc/content/ru/version-history/webstation-plugins-history.html b/ScadaDoc/ScadaDoc/content/ru/version-history/webstation-plugins-history.html
index 718fcfb9c..9b5eb4172 100644
--- a/ScadaDoc/ScadaDoc/content/ru/version-history/webstation-plugins-history.html
+++ b/ScadaDoc/ScadaDoc/content/ru/version-history/webstation-plugins-history.html
@@ -15,7 +15,10 @@ 

Графики

- Рефакторинг

Графики Про

-
PlgChartPro 5.0.2.0 (21.12.2017)
+    
PlgChartPro 5.0.2.1 (23.05.2018)
+- Сборка в связи с изменениями в базовых библиотеках
+
+PlgChartPro 5.0.2.0 (21.12.2017)
 - Регистрационная форма перенесена в меню Регистрация
 
 PlgChartPro 5.0.1.1 (25.09.2017)
@@ -46,7 +49,10 @@ 

Конфигуратор

- Исправлена ошибка получения списка плагинов на Linux

Дэшборды

-
PlgDashboard 5.0.1.1 (16.03.2018)
+    
PlgDashboard 5.0.1.2 (22.05.2018)
+- Сборка в связи с изменениями в базовых библиотеках
+
+PlgDashboard 5.0.1.1 (16.03.2018)
 - Обновление в связи с изменениями в базовых библиотеках
 
 PlgDashboard 5.0.1.0 (21.12.2017)
@@ -64,7 +70,10 @@ 

Дэшборды

- Первоначальная разработка плагина

Гибкий отчёт

-
PlgElasticReport 5.0.2.0 (21.12.2017)
+    
PlgElasticReport 5.0.2.1 (23.05.2018)
+- Сборка в связи с изменениями в базовых библиотеках
+
+PlgElasticReport 5.0.2.0 (21.12.2017)
 - Регистрационная форма перенесена в меню Регистрация
 
 PlgElasticReport 5.0.1.2 (25.09.2017)
@@ -88,7 +97,10 @@ 

Магазин

- Первоначальная разработка плагина

Таблицы

-
PlgTable 5.0.2.0 (16.03.2018)
+    
PlgTable 5.0.2.1 (В разработке)
+- Скрытые элементы табличных представлений не выводятся в отчёт
+
+PlgTable 5.0.2.0 (16.03.2018)
 - Использование очереди для отправки Ajax-запросов
 - Сокращено на 1 секунду время закрытия диалога отправки команды
 
@@ -109,7 +121,10 @@ 

Таблицы

- Возможность отправки бинарных команд с выбором значений из списка

Схемы

-
PlgScheme 5.2.1.0 (16.03.2018)
+    
PlgScheme 5.2.1.1 (В разработке)
+- Изменения относятся к Редактору схем
+
+PlgScheme 5.2.1.0 (16.03.2018)
 - Добавлено свойство ширины рамки для написей и рисунков
 - Возможность отправки команд сразу
 - Использование очереди для отправки Ajax-запросов
diff --git a/ScadaDoc/ScadaDoc/js/contents-en.js b/ScadaDoc/ScadaDoc/js/contents-en.js
index 804053588..4c65ac7d1 100644
--- a/ScadaDoc/ScadaDoc/js/contents-en.js
+++ b/ScadaDoc/ScadaDoc/js/contents-en.js
@@ -11,6 +11,7 @@ function addContents(context) {
     addArticle(context, "software-overview/applications/administrator-application.html", "Administrator Application", 2);
     addArticle(context, "software-overview/applications/table-editor-application.html", "Table Editor Application", 2);
     addArticle(context, "software-overview/applications/scheme-editor-application.html", "Scheme Editor Application", 2);
+    addArticle(context, "software-overview/roadmap.html", "Roadmap", 1);
 
     addArticle(context, "installation-and-run/", "Installation and Run");
     addArticle(context, "installation-and-run/system-requirements.html", "System Requirements", 1);
@@ -41,7 +42,13 @@ function addContents(context) {
     addArticle(context, "use-cases/", "Use Cases");
     addArticle(context, "use-cases/modbus-protocol.html", "Connecting Devices Using Modbus Protocol", 1);
     addArticle(context, "use-cases/opc-standard.html", "Connecting Devices Using OPC Standard", 1);
+    addArticle(context, "use-cases/remote-server-management.html", "Managing Remote Server using Agent", 1);
 
-    /*addArticle(context, "", "Version History");
-    addArticle(context, "version-history/scada-history.html", "History of Rapid SCADA", 1);*/
+    addArticle(context, "version-history/", "Version History");
+    addArticle(context, "version-history/scada-history.html", "History of Rapid SCADA", 1);
+    addArticle(context, "version-history/server-history.html", "Server History", 1);
+    addArticle(context, "version-history/communicator-history.html", "Communicator History", 1);
+    addArticle(context, "version-history/administrator-history.html", "Administrator History", 1);
+    addArticle(context, "version-history/webstation-history.html", "Webstation History", 1);
+    addArticle(context, "version-history/scheme-editor-history.html", "Scheme Editor History", 1);
 }
diff --git a/ScadaDoc/ScadaDoc/js/contents-ru.js b/ScadaDoc/ScadaDoc/js/contents-ru.js
index c1a5f9da8..a4e87bdbe 100644
--- a/ScadaDoc/ScadaDoc/js/contents-ru.js
+++ b/ScadaDoc/ScadaDoc/js/contents-ru.js
@@ -11,6 +11,7 @@ function addContents(context) {
     addArticle(context, "software-overview/applications/administrator-application.html", "Приложение Администратор", 2);
     addArticle(context, "software-overview/applications/table-editor-application.html", "Приложение Редактор таблиц", 2);
     addArticle(context, "software-overview/applications/scheme-editor-application.html", "Приложение Редактор схем", 2);
+    addArticle(context, "software-overview/roadmap.html", "Дорожная карта", 1);
 
     addArticle(context, "installation-and-run/", "Установка и запуск");
     addArticle(context, "installation-and-run/system-requirements.html", "Системные требования", 1);
@@ -41,6 +42,7 @@ function addContents(context) {
     addArticle(context, "use-cases/", "Сценарии использования");
     addArticle(context, "use-cases/modbus-protocol.html", "Подключение устройств по протоколу Modbus", 1);
     addArticle(context, "use-cases/opc-standard.html", "Подключение устройств с использованием стандарта OPC", 1);
+    addArticle(context, "use-cases/remote-server-management.html", "Управление удалённым сервером с помощью Агента", 1);
 
     addArticle(context, "version-history/", "История версий");
     addArticle(context, "version-history/scada-history.html", "История Rapid SCADA", 1);
diff --git a/ScadaServer/OpenModules/ModDBExport/ModDBExport.csproj b/ScadaServer/OpenModules/ModDBExport/ModDBExport.csproj
index e288f7c39..6d12958ea 100644
--- a/ScadaServer/OpenModules/ModDBExport/ModDBExport.csproj
+++ b/ScadaServer/OpenModules/ModDBExport/ModDBExport.csproj
@@ -32,7 +32,7 @@
   
     
       False
-      ..\..\..\Log\bin\Release\Log.dll
+      ..\..\..\Log\Log\bin\Release\Log.dll
     
     
       ..\..\..\..\dll\PostgreSQL\Mono.Security.dll
diff --git a/ScadaServer/OpenModules/ModTest/ModTest.csproj b/ScadaServer/OpenModules/ModTest/ModTest.csproj
index f83de6ab7..2ce645256 100644
--- a/ScadaServer/OpenModules/ModTest/ModTest.csproj
+++ b/ScadaServer/OpenModules/ModTest/ModTest.csproj
@@ -33,7 +33,7 @@
   
     
       False
-      ..\..\..\Log\bin\Release\Log.dll
+      ..\..\..\Log\Log\bin\Release\Log.dll
     
     
       False
diff --git a/ScadaServer/ScadaServerCommon/ScadaServerCommon.csproj b/ScadaServer/ScadaServerCommon/ScadaServerCommon.csproj
index a885f75c7..e47c0c4d5 100644
--- a/ScadaServer/ScadaServerCommon/ScadaServerCommon.csproj
+++ b/ScadaServer/ScadaServerCommon/ScadaServerCommon.csproj
@@ -32,8 +32,9 @@
     bin\Release\ScadaServerCommon.XML
   
   
-    
-      ..\..\Log\bin\Release\Log.dll
+    
+      False
+      ..\..\Log\Log\bin\Release\Log.dll
     
     
       ..\..\ScadaData\ScadaData\bin\Release\ScadaData.dll
diff --git a/ScadaServer/ScadaServerCtrl/ScadaServerCtrl.csproj b/ScadaServer/ScadaServerCtrl/ScadaServerCtrl.csproj
index af6f86e25..d0bad3344 100644
--- a/ScadaServer/ScadaServerCtrl/ScadaServerCtrl.csproj
+++ b/ScadaServer/ScadaServerCtrl/ScadaServerCtrl.csproj
@@ -69,7 +69,7 @@
     prompt
     false
     false
-    C:\Program Files (x86)\Microsoft Visual Studio 14.0\Team Tools\Static Analysis Tools\Rule Sets\ManagedMinimumRules.ruleset
+    MinimumRecommendedRules.ruleset
   
   
     app.manifest
@@ -80,7 +80,7 @@
   
     
       False
-      ..\..\Log\bin\Release\Log.dll
+      ..\..\Log\Log\bin\Release\Log.dll
     
     
       False
diff --git a/ScadaServer/ScadaServerMono/ScadaServerMono.csproj b/ScadaServer/ScadaServerMono/ScadaServerMono.csproj
index 49d29af24..b19038c0f 100644
--- a/ScadaServer/ScadaServerMono/ScadaServerMono.csproj
+++ b/ScadaServer/ScadaServerMono/ScadaServerMono.csproj
@@ -32,8 +32,9 @@
     4
   
   
-    
-      ..\..\Log\bin\Release\Log.dll
+    
+      False
+      ..\..\Log\Log\bin\Release\Log.dll
     
     
       ..\..\ScadaData\ScadaData\bin\Release\ScadaData.dll
diff --git a/ScadaServer/ScadaServerSvc/ScadaServerSvc.csproj b/ScadaServer/ScadaServerSvc/ScadaServerSvc.csproj
index 39c8530d1..bbbf347e8 100644
--- a/ScadaServer/ScadaServerSvc/ScadaServerSvc.csproj
+++ b/ScadaServer/ScadaServerSvc/ScadaServerSvc.csproj
@@ -50,8 +50,9 @@
     4
   
   
-    
-      ..\..\Log\bin\Release\Log.dll
+    
+      False
+      ..\..\Log\Log\bin\Release\Log.dll
     
     
       False
diff --git a/ScadaWeb/OpenPlugins/PlgChart/PlgChart.csproj b/ScadaWeb/OpenPlugins/PlgChart/PlgChart.csproj
index efd0e609b..b5c044f3e 100644
--- a/ScadaWeb/OpenPlugins/PlgChart/PlgChart.csproj
+++ b/ScadaWeb/OpenPlugins/PlgChart/PlgChart.csproj
@@ -22,6 +22,7 @@
     
     
     
+    
   
   
     true
@@ -41,8 +42,9 @@
     4
   
   
-    
-      ..\..\..\Log\bin\Release\Log.dll
+    
+      False
+      ..\..\..\Log\Log\bin\Release\Log.dll
     
     
       False
diff --git a/ScadaWeb/OpenPlugins/PlgChartCommon/PlgChartCommon.csproj b/ScadaWeb/OpenPlugins/PlgChartCommon/PlgChartCommon.csproj
index 715162078..9e2a25052 100644
--- a/ScadaWeb/OpenPlugins/PlgChartCommon/PlgChartCommon.csproj
+++ b/ScadaWeb/OpenPlugins/PlgChartCommon/PlgChartCommon.csproj
@@ -31,8 +31,9 @@
     bin\Release\PlgChartCommon.XML
   
   
-    
-      ..\..\..\Log\bin\Release\Log.dll
+    
+      False
+      ..\..\..\Log\Log\bin\Release\Log.dll
     
     
       ..\..\..\ScadaData\ScadaData\bin\Release\ScadaData.dll
diff --git a/ScadaWeb/OpenPlugins/PlgConfig/PlgConfig.csproj b/ScadaWeb/OpenPlugins/PlgConfig/PlgConfig.csproj
index b8ce44603..f06a5df48 100644
--- a/ScadaWeb/OpenPlugins/PlgConfig/PlgConfig.csproj
+++ b/ScadaWeb/OpenPlugins/PlgConfig/PlgConfig.csproj
@@ -22,6 +22,7 @@
     
     
     
+    
   
   
     true
@@ -41,8 +42,9 @@
     4
   
   
-    
-      ..\..\..\Log\bin\Release\Log.dll
+    
+      False
+      ..\..\..\Log\Log\bin\Release\Log.dll
     
     
     
diff --git a/ScadaWeb/OpenPlugins/PlgMonitor/PlgMonitor.csproj b/ScadaWeb/OpenPlugins/PlgMonitor/PlgMonitor.csproj
index 4e0ef3779..0c8ad825f 100644
--- a/ScadaWeb/OpenPlugins/PlgMonitor/PlgMonitor.csproj
+++ b/ScadaWeb/OpenPlugins/PlgMonitor/PlgMonitor.csproj
@@ -20,6 +20,7 @@
     
     
     
+    
   
   
     true
@@ -39,8 +40,9 @@
     4
   
   
-    
-      ..\..\..\Log\bin\Release\Log.dll
+    
+      False
+      ..\..\..\Log\Log\bin\Release\Log.dll
     
     
       ..\..\..\ScadaData\ScadaData\bin\Release\ScadaData.dll
diff --git a/ScadaWeb/OpenPlugins/PlgTable/AppCode/Table/HourDataRepBuilder.cs b/ScadaWeb/OpenPlugins/PlgTable/AppCode/Table/HourDataRepBuilder.cs
index 5703ccd7d..b9d013fc1 100644
--- a/ScadaWeb/OpenPlugins/PlgTable/AppCode/Table/HourDataRepBuilder.cs
+++ b/ScadaWeb/OpenPlugins/PlgTable/AppCode/Table/HourDataRepBuilder.cs
@@ -20,7 +20,7 @@
  * 
  * Author   : Mikhail Shiryaev
  * Created  : 2016
- * Modified : 2016
+ * Modified : 2018
  */
 
 using Scada.Client;
@@ -203,10 +203,13 @@ protected override void FinalXmlDocProc()
             for (int i = 0, cnt = tableView.Items.Count; i < cnt; i++)
             {
                 viewItem = tableView.Items[i];
-                cnlProps = viewItem.CnlNum > 0 ? dataAccess.GetCnlProps(viewItem.CnlNum) : null;
-                Row newRow = itemRowTemplate.Clone();
-                ExcelProc(newRow);
-                table.AppendRow(newRow);
+                if (!viewItem.Hidden)
+                {
+                    cnlProps = viewItem.CnlNum > 0 ? dataAccess.GetCnlProps(viewItem.CnlNum) : null;
+                    Row newRow = itemRowTemplate.Clone();
+                    ExcelProc(newRow);
+                    table.AppendRow(newRow);
+                }
             }
         }
 
diff --git a/ScadaWeb/OpenPlugins/PlgTable/PlgTable.csproj b/ScadaWeb/OpenPlugins/PlgTable/PlgTable.csproj
index 8e111d888..8b3c89153 100644
--- a/ScadaWeb/OpenPlugins/PlgTable/PlgTable.csproj
+++ b/ScadaWeb/OpenPlugins/PlgTable/PlgTable.csproj
@@ -20,6 +20,7 @@
     
     
     
+    
   
   
     true
@@ -39,8 +40,9 @@
     4
   
   
-    
-      ..\..\..\Log\bin\Release\Log.dll
+    
+      False
+      ..\..\..\Log\Log\bin\Release\Log.dll
     
     
       ..\..\..\Report\RepBuilder\bin\Release\RepBuilder.dll
diff --git a/ScadaWeb/OpenPlugins/PlgTableCommon/PlgTableCommon.csproj b/ScadaWeb/OpenPlugins/PlgTableCommon/PlgTableCommon.csproj
index 0f4a370c2..81541d878 100644
--- a/ScadaWeb/OpenPlugins/PlgTableCommon/PlgTableCommon.csproj
+++ b/ScadaWeb/OpenPlugins/PlgTableCommon/PlgTableCommon.csproj
@@ -31,8 +31,9 @@
     bin\Release\PlgTableCommon.XML
   
   
-    
-      ..\..\..\Log\bin\Release\Log.dll
+    
+      False
+      ..\..\..\Log\Log\bin\Release\Log.dll
     
     
       ..\..\..\ScadaData\ScadaData\bin\Release\ScadaData.dll
diff --git a/ScadaWeb/OpenPlugins/PlgTableCommon/TableUtils.cs b/ScadaWeb/OpenPlugins/PlgTableCommon/TableUtils.cs
index cfce67d4e..d22b99261 100644
--- a/ScadaWeb/OpenPlugins/PlgTableCommon/TableUtils.cs
+++ b/ScadaWeb/OpenPlugins/PlgTableCommon/TableUtils.cs
@@ -34,6 +34,6 @@ public static class TableUtils
         /// 
         /// Версия таблиц
         /// 
-        public const string TableVersion = "5.0.2.0";
+        public const string TableVersion = "5.0.2.1";
     }
 }
diff --git a/ScadaWeb/OpenPlugins/PlgWebPage/PlgWebPage.csproj b/ScadaWeb/OpenPlugins/PlgWebPage/PlgWebPage.csproj
index cde2641c6..1ade04e25 100644
--- a/ScadaWeb/OpenPlugins/PlgWebPage/PlgWebPage.csproj
+++ b/ScadaWeb/OpenPlugins/PlgWebPage/PlgWebPage.csproj
@@ -20,6 +20,7 @@
     
     
     
+    
   
   
     true
@@ -39,8 +40,9 @@
     4
   
   
-    
-      ..\..\..\Log\bin\Release\Log.dll
+    
+      False
+      ..\..\..\Log\Log\bin\Release\Log.dll
     
     
       ..\..\..\ScadaData\ScadaData\bin\Release\ScadaData.dll
diff --git a/ScadaWeb/ScadaScheme/PlgSchBasicComp/AppCode/PlgSchBasicCompSpec.cs b/ScadaWeb/ScadaScheme/PlgSchBasicComp/AppCode/PlgSchBasicCompSpec.cs
index 96c2f7343..bac7520a0 100644
--- a/ScadaWeb/ScadaScheme/PlgSchBasicComp/AppCode/PlgSchBasicCompSpec.cs
+++ b/ScadaWeb/ScadaScheme/PlgSchBasicComp/AppCode/PlgSchBasicCompSpec.cs
@@ -51,7 +51,7 @@ public override string Name
             {
                 return Localization.UseRussian ?
                     "Основные компоненты схем" :
-                    "Basic scheme components";
+                    "Basic Scheme Components";
             }
         }
 
diff --git a/ScadaWeb/ScadaScheme/PlgSchBasicComp/PlgSchBasicComp.csproj b/ScadaWeb/ScadaScheme/PlgSchBasicComp/PlgSchBasicComp.csproj
index 1f4ffd5fa..0eefc2dee 100644
--- a/ScadaWeb/ScadaScheme/PlgSchBasicComp/PlgSchBasicComp.csproj
+++ b/ScadaWeb/ScadaScheme/PlgSchBasicComp/PlgSchBasicComp.csproj
@@ -22,6 +22,7 @@
     
     
     
+    
   
   
     true
@@ -41,8 +42,9 @@
     4
   
   
-    
-      ..\..\..\Log\bin\Release\Log.dll
+    
+      False
+      ..\..\..\Log\Log\bin\Release\Log.dll
     
     
       ..\..\..\ScadaData\ScadaData\bin\Release\ScadaData.dll
diff --git a/ScadaWeb/ScadaScheme/PlgScheme/AppCode/PlgSchemeSpec.cs b/ScadaWeb/ScadaScheme/PlgScheme/AppCode/PlgSchemeSpec.cs
index 840759d4b..3012de2f1 100644
--- a/ScadaWeb/ScadaScheme/PlgScheme/AppCode/PlgSchemeSpec.cs
+++ b/ScadaWeb/ScadaScheme/PlgScheme/AppCode/PlgSchemeSpec.cs
@@ -1,5 +1,5 @@
 /*
- * Copyright 2016 Mikhail Shiryaev
+ * Copyright 2018 Mikhail Shiryaev
  * 
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -20,7 +20,7 @@
  * 
  * Author   : Mikhail Shiryaev
  * Created  : 2016
- * Modified : 2016
+ * Modified : 2018
  */
 
 using Scada.Scheme;
@@ -112,7 +112,7 @@ public override void Init()
 
             // инициализация менеджера компонентов
             CompManager compManager = CompManager.GetInstance();
-            compManager.Init(AppData.GetAppData().AppDirs.BinDir, Log);
+            compManager.Init(AppData.GetAppData().AppDirs, Log);
         }
 
         /// 
diff --git a/ScadaWeb/ScadaScheme/PlgScheme/PlgScheme.csproj b/ScadaWeb/ScadaScheme/PlgScheme/PlgScheme.csproj
index 2c5876914..7aa2dfca0 100644
--- a/ScadaWeb/ScadaScheme/PlgScheme/PlgScheme.csproj
+++ b/ScadaWeb/ScadaScheme/PlgScheme/PlgScheme.csproj
@@ -23,6 +23,7 @@
     
     
     True
+    
   
   
     true
@@ -44,7 +45,7 @@
   
     
       False
-      ..\..\..\Log\bin\Release\Log.dll
+      ..\..\..\Log\Log\bin\Release\Log.dll
     
     
       False
diff --git a/ScadaWeb/ScadaScheme/ScadaSchemeCommon/CompManager.cs b/ScadaWeb/ScadaScheme/ScadaSchemeCommon/CompManager.cs
index b3fac217e..5fdccb8d4 100644
--- a/ScadaWeb/ScadaScheme/ScadaSchemeCommon/CompManager.cs
+++ b/ScadaWeb/ScadaScheme/ScadaSchemeCommon/CompManager.cs
@@ -1,5 +1,5 @@
 /*
- * Copyright 2017 Mikhail Shiryaev
+ * Copyright 2018 Mikhail Shiryaev
  * 
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -20,11 +20,12 @@
  * 
  * Author   : Mikhail Shiryaev
  * Created  : 2017
- * Modified : 2017
+ * Modified : 2018
  */
 
 using Scada.Scheme.Model;
 using Scada.Scheme.Model.PropertyGrid;
+using Scada.Web;
 using Scada.Web.Plugins;
 using System;
 using System.Collections.Generic;
@@ -53,8 +54,8 @@ public sealed class CompManager
         /// 
         private static readonly CompManager instance;
 
-        private string binDir; // директория исполняемых файлов
-        private ILog log;      // журнал приложения
+        private AppDirs appDirs; // директории веб-приложения
+        private ILog log;        // журнал приложения
         private List allSpecs;                    // все спецификации библиотек
         private Dictionary factsByPrefix; // фабрики компонентов, ключ - XML-префикс
         private Dictionary specsByType;   // спецификации библиотек, ключ - имя типа компонента
@@ -81,7 +82,7 @@ static CompManager()
         /// 
private CompManager() { - binDir = ""; + appDirs = null; log = new LogStub(); allSpecs = new List(); factsByPrefix = new Dictionary(); @@ -156,15 +157,10 @@ private bool TypeIsStrandard(Type compType) /// /// Инициализировать менеджер компонентов /// - public void Init(string binDir, Log log) + public void Init(AppDirs appDirs, ILog log) { - if (string.IsNullOrEmpty(binDir)) - throw new ArgumentException("Directory must not be empty.", "binDir"); - if (log == null) - throw new ArgumentNullException("log"); - - this.binDir = binDir; - this.log = log; + this.appDirs = appDirs ?? throw new ArgumentNullException("appDirs"); + this.log = log ?? throw new ArgumentNullException("log"); } /// @@ -180,7 +176,7 @@ public void LoadCompFromFiles() ClearDicts(); AttrTranslator attrTranslator = new AttrTranslator(); - DirectoryInfo dirInfo = new DirectoryInfo(binDir); + DirectoryInfo dirInfo = new DirectoryInfo(appDirs.BinDir); FileInfo[] fileInfoArr = dirInfo.GetFiles(CompLibMask, SearchOption.TopDirectoryOnly); foreach (FileInfo fileInfo in fileInfoArr) @@ -195,6 +191,8 @@ public void LoadCompFromFiles() } else if (pluginSpec is ISchemeComp) { + pluginSpec.AppDirs = appDirs; + pluginSpec.Log = log; pluginSpec.Init(); if (AddComponents((ISchemeComp)pluginSpec, attrTranslator)) diff --git a/ScadaWeb/ScadaScheme/ScadaSchemeCommon/ScadaSchemeCommon.csproj b/ScadaWeb/ScadaScheme/ScadaSchemeCommon/ScadaSchemeCommon.csproj index a91d5ee0b..98c1b3456 100644 --- a/ScadaWeb/ScadaScheme/ScadaSchemeCommon/ScadaSchemeCommon.csproj +++ b/ScadaWeb/ScadaScheme/ScadaSchemeCommon/ScadaSchemeCommon.csproj @@ -33,7 +33,7 @@ False - ..\..\..\Log\bin\Release\Log.dll + ..\..\..\Log\Log\bin\Release\Log.dll ..\..\..\ScadaData\ScadaData\bin\Release\ScadaData.dll diff --git a/ScadaWeb/ScadaScheme/ScadaSchemeCommon/SchemeUtils.cs b/ScadaWeb/ScadaScheme/ScadaSchemeCommon/SchemeUtils.cs index 271d43aaa..21a8a0aa6 100644 --- a/ScadaWeb/ScadaScheme/ScadaSchemeCommon/SchemeUtils.cs +++ b/ScadaWeb/ScadaScheme/ScadaSchemeCommon/SchemeUtils.cs @@ -36,7 +36,7 @@ public static class SchemeUtils /// /// Версия схем /// - public const string SchemeVersion = "5.2.1.0"; + public const string SchemeVersion = "5.2.1.1"; /// /// Цвет, устанавливаемый в зависимости от статуса входного канала /// @@ -48,8 +48,9 @@ public static class SchemeUtils public static bool EditorMode { get - { - return Assembly.GetEntryAssembly().GetName().Name == "ScadaSchemeEditor"; + { + Assembly asm = Assembly.GetEntryAssembly(); + return asm != null && asm.GetName().Name == "ScadaSchemeEditor"; } } diff --git a/ScadaWeb/ScadaScheme/ScadaSchemeEditor/AppCode/AppData.cs b/ScadaWeb/ScadaScheme/ScadaSchemeEditor/AppCode/AppData.cs index 58ad83a1a..dc25cd760 100644 --- a/ScadaWeb/ScadaScheme/ScadaSchemeEditor/AppCode/AppData.cs +++ b/ScadaWeb/ScadaScheme/ScadaSchemeEditor/AppCode/AppData.cs @@ -1,5 +1,5 @@ /* - * Copyright 2017 Mikhail Shiryaev + * Copyright 2018 Mikhail Shiryaev * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -20,7 +20,7 @@ * * Author : Mikhail Shiryaev * Created : 2017 - * Modified : 2017 + * Modified : 2018 */ using Scada.Client; @@ -202,7 +202,7 @@ public void LoadComponents() Web.AppDirs webAppDirs = new Web.AppDirs(); webAppDirs.Init(AppDirs.WebDir); - CompManager.Init(webAppDirs.BinDir, Log); + CompManager.Init(webAppDirs, Log); CompManager.LoadCompFromFiles(); } diff --git a/ScadaWeb/ScadaScheme/ScadaSchemeEditor/FrmMain.Designer.cs b/ScadaWeb/ScadaScheme/ScadaSchemeEditor/FrmMain.Designer.cs index e971c614d..2196ac34f 100644 --- a/ScadaWeb/ScadaScheme/ScadaSchemeEditor/FrmMain.Designer.cs +++ b/ScadaWeb/ScadaScheme/ScadaSchemeEditor/FrmMain.Designer.cs @@ -497,7 +497,7 @@ private void InitializeComponent() this.miEditCut.Image = ((System.Drawing.Image)(resources.GetObject("miEditCut.Image"))); this.miEditCut.Name = "miEditCut"; this.miEditCut.ShortcutKeys = ((System.Windows.Forms.Keys)((System.Windows.Forms.Keys.Control | System.Windows.Forms.Keys.X))); - this.miEditCut.Size = new System.Drawing.Size(144, 22); + this.miEditCut.Size = new System.Drawing.Size(180, 22); this.miEditCut.Text = "Cut"; this.miEditCut.Click += new System.EventHandler(this.miEditCut_Click); // @@ -506,7 +506,7 @@ private void InitializeComponent() this.miEditCopy.Image = ((System.Drawing.Image)(resources.GetObject("miEditCopy.Image"))); this.miEditCopy.Name = "miEditCopy"; this.miEditCopy.ShortcutKeys = ((System.Windows.Forms.Keys)((System.Windows.Forms.Keys.Control | System.Windows.Forms.Keys.C))); - this.miEditCopy.Size = new System.Drawing.Size(144, 22); + this.miEditCopy.Size = new System.Drawing.Size(180, 22); this.miEditCopy.Text = "Copy"; this.miEditCopy.Click += new System.EventHandler(this.miEditCopy_Click); // @@ -515,21 +515,21 @@ private void InitializeComponent() this.miEditPaste.Image = ((System.Drawing.Image)(resources.GetObject("miEditPaste.Image"))); this.miEditPaste.Name = "miEditPaste"; this.miEditPaste.ShortcutKeys = ((System.Windows.Forms.Keys)((System.Windows.Forms.Keys.Control | System.Windows.Forms.Keys.V))); - this.miEditPaste.Size = new System.Drawing.Size(144, 22); + this.miEditPaste.Size = new System.Drawing.Size(180, 22); this.miEditPaste.Text = "Paste"; this.miEditPaste.Click += new System.EventHandler(this.miEditPaste_Click); // // miEditSep1 // this.miEditSep1.Name = "miEditSep1"; - this.miEditSep1.Size = new System.Drawing.Size(141, 6); + this.miEditSep1.Size = new System.Drawing.Size(177, 6); // // miEditUndo // this.miEditUndo.Image = ((System.Drawing.Image)(resources.GetObject("miEditUndo.Image"))); this.miEditUndo.Name = "miEditUndo"; this.miEditUndo.ShortcutKeys = ((System.Windows.Forms.Keys)((System.Windows.Forms.Keys.Control | System.Windows.Forms.Keys.Z))); - this.miEditUndo.Size = new System.Drawing.Size(144, 22); + this.miEditUndo.Size = new System.Drawing.Size(180, 22); this.miEditUndo.Text = "Undo"; this.miEditUndo.Click += new System.EventHandler(this.miEditUndo_Click); // @@ -538,20 +538,20 @@ private void InitializeComponent() this.miEditRedo.Image = ((System.Drawing.Image)(resources.GetObject("miEditRedo.Image"))); this.miEditRedo.Name = "miEditRedo"; this.miEditRedo.ShortcutKeys = ((System.Windows.Forms.Keys)((System.Windows.Forms.Keys.Control | System.Windows.Forms.Keys.Y))); - this.miEditRedo.Size = new System.Drawing.Size(144, 22); + this.miEditRedo.Size = new System.Drawing.Size(180, 22); this.miEditRedo.Text = "Redo"; this.miEditRedo.Click += new System.EventHandler(this.miEditRedo_Click); // // miEditSep2 // this.miEditSep2.Name = "miEditSep2"; - this.miEditSep2.Size = new System.Drawing.Size(141, 6); + this.miEditSep2.Size = new System.Drawing.Size(177, 6); // // miEditPointer // this.miEditPointer.Image = ((System.Drawing.Image)(resources.GetObject("miEditPointer.Image"))); this.miEditPointer.Name = "miEditPointer"; - this.miEditPointer.Size = new System.Drawing.Size(144, 22); + this.miEditPointer.Size = new System.Drawing.Size(180, 22); this.miEditPointer.Text = "Pointer"; this.miEditPointer.Click += new System.EventHandler(this.miEditPointer_Click); // @@ -559,8 +559,7 @@ private void InitializeComponent() // this.miEditDelete.Image = ((System.Drawing.Image)(resources.GetObject("miEditDelete.Image"))); this.miEditDelete.Name = "miEditDelete"; - this.miEditDelete.ShortcutKeys = System.Windows.Forms.Keys.Delete; - this.miEditDelete.Size = new System.Drawing.Size(144, 22); + this.miEditDelete.Size = new System.Drawing.Size(180, 22); this.miEditDelete.Text = "Delete"; this.miEditDelete.Click += new System.EventHandler(this.miEditDelete_Click); // @@ -576,7 +575,7 @@ private void InitializeComponent() // this.miToolsOptions.Image = ((System.Drawing.Image)(resources.GetObject("miToolsOptions.Image"))); this.miToolsOptions.Name = "miToolsOptions"; - this.miToolsOptions.Size = new System.Drawing.Size(125, 22); + this.miToolsOptions.Size = new System.Drawing.Size(180, 22); this.miToolsOptions.Text = "Options..."; this.miToolsOptions.Click += new System.EventHandler(this.miToolsOptions_Click); // diff --git a/ScadaWeb/ScadaScheme/ScadaSchemeEditor/FrmMain.cs b/ScadaWeb/ScadaScheme/ScadaSchemeEditor/FrmMain.cs index 8483eb139..e45ee89bf 100644 --- a/ScadaWeb/ScadaScheme/ScadaSchemeEditor/FrmMain.cs +++ b/ScadaWeb/ScadaScheme/ScadaSchemeEditor/FrmMain.cs @@ -728,16 +728,10 @@ private void FrmMain_Resize(object sender, EventArgs e) private void FrmMain_KeyDown(object sender, KeyEventArgs e) { - // реализация горячих клавиш, которые не обрабатываются автоматически главным меню - if (ActiveControl == propertyGrid) + // реализация горячих клавиш, которые не заданы для элементов главного меню + if (ActiveControl != propertyGrid && e.KeyCode == Keys.Escape) { - if (e.KeyCode == Keys.Delete) - e.Handled = true; - } - else - { - if (e.KeyCode == Keys.Escape) - miEditPointer_Click(null, null); + miEditPointer_Click(null, null); } } diff --git a/ScadaWeb/ScadaScheme/ScadaSchemeEditor/FrmMain.resx b/ScadaWeb/ScadaScheme/ScadaSchemeEditor/FrmMain.resx index b1add4de1..c0d641af2 100644 --- a/ScadaWeb/ScadaScheme/ScadaSchemeEditor/FrmMain.resx +++ b/ScadaWeb/ScadaScheme/ScadaSchemeEditor/FrmMain.resx @@ -204,14 +204,14 @@ iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8 YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAHMSURBVDhPYyAG/P//nwXKJAxWbNjXPXvpuidQLsO/f//0 - b958+q66ddIGqBB+MHnOapP6+vp/VS0zJEH8r9+/t7b3zfiXnFMZA1ZADKifvfLX5DmrFgOdzv/oxZuX - afk1/8T5+RWh0oTBso27PnVNnvLz+OmLDQePnfttb+/+V0iIUxoqTRjMX7ltM8gbvVMX7i8H0j5+0a+g - UsSBzokLHEuAGpPz6v7Z27v+dfMOWgWVIh4k5NW/C0so/G+QVv/HL741AipMGES1v9WNaH+92b75wU/v + b958+q66ddIGqBB+MHnOapP6+vp/VS0zJEH8r9+/t7b1Tv+XnFMZA1ZADKifvfLX5DmrFgOdzv/oxZuX + afk1/8T5+RWh0oTBso27PnVNnvLz+OmLDQePnfttb+/2V0iIUxoqTRjMX7ltM8gbvVMX7i8H0j5+0a+g + UsSBzokLHEuAGpPz6v7Z27v8dfMOWgWVIh4k5NW/C0so/K+fVv/HL741AipMGES1v9WNaH+92b75wU/v khNrfeLP/vbLP//du/T0fJesXV5QZdhBRPsrw8iud5/9G85/twyc9sXUr+uuW96+N/7VV/+7Zu/8bxUz fwJUKXYQ2vpsQ1jb0/+OaRv+mwbV/zAJ6t3iXbLpl1fJFQmn9I0JJj71v6BKsQOf+ke/gpvuG9qnbDGQ BCq2COkV8qm++sur6ryBWcS0bHmH+N9QpdiBT/29X/4lVwzsklYngQwAiXkWHT9rl7Tqv6ZN8n8ZeaUv YIW4gHflxXP2Sav/Gwd0/Vc3CnsMFGK2T1kdqWqS8E7dPPy9sV9bBkQlDuCUsTnCKGTSY1WT2HcGXlV5 - UGFaAgYGAEqKyTZ3WJd2AAAAAElFTkSuQmCC + UGFaAgYGADjeyTBarefvAAAAAElFTkSuQmCC @@ -250,13 +250,13 @@ iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8 YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAHnSURBVDhPY6ApmLTlW8zEjV93zNz98dGyA1+OrNj/Zcqy I1+loNL4Qe+GrzvqN1z5073u6/PGFR8f1y/+cmfuzo+Pl+36+gmrId2rXv1fcvKLAYjdtfbLsv7593+n - 9Lx64xJ/4rdW6vY/+gnrv9uX3f04c+vXN6v2f7kJ1gQDK4/942xc8vL/vP1fr9Yv/9pQv+nqn7j6Y/9c - C47/t8vY9MskdtVx+/ytD7Xi2/6Edbz8ufjA5/tQrQhQPPP5/6xZn/8XzvnyP7Lr3Qsrpy1/zaIX/zCJ + 9Lx64xJ/4rdW6vY/+gnrv9uX3f04c+vXN6v2f7kJ1gQDK4/942xc8vL/vP1fr9Yv/9pQv+nKn7j6o/9c + C47/t8vY9MskdtVx+/ytD7XiW/+Edbz8ufjA5/tQrQhQPPP5/6xZn/8XzvnyP7Lr3Qsrxy1/zaIX/zCJ XpkPkvet36FiGLzghWv59ff1S7/sAWtCBkl9z/57N735H937+X/ZnDf/NbwmrTaKWuEIlWZgCA1llo8/ - 9Nu17M7r+pVfDkFFESCo+el/s+L7/z2bXoFdktjz6H/twreWUGkGY+M0VjuP/X/d6p59a1rxeQtUGAGc - Kh7/dyi69t8q8/h/k/ht/w2j1v7X8Jn6HyrNYJK4Rsk2c8E/+5ZTf/OnPSqFCuMGoICFMsFA3Xuyu1bZ - lT9p9ef+1a/6zwYVJh5YpOy7GFJ//l9Y3dlcqBBxILHvg5J93vkYf6Bmt8or3xgY/jNCpYgDHpVPnH3q - n/6yz9r/0zhyhRdUmHgQ0fM50rnkaqNB4kpRqNCgAgwMAPK/85lL2oFiAAAAAElFTkSuQmCC + 9Nu17M7r+pVfDkFFESCo+el/s+L7/z2bXoFdktjz6H/twreWUGkGY+M0Vjv3/X/d6p59a1rxeQtUGAGc + Kh7/dyi69t8q8/h/k/ht/w2j1v7X8Jn6HyrNYJK4Rsk2c/4/+5aTf/OnPSqFCuMGoICFMsFA3Xuyu1bZ + lT9p9Wf/1a/6zwYVJh5YpOy7GFJ/7l9Y3dlcqBBxILHvg5J93vkYf6Bmt8or3xgY/jNCpYgDHpVPnH3q + n/6yz9r/0zhyhRdUmHgQ0fM50rnkaqNB4kpRqNCgAgwMAN1984+XEVaTAAAAAElFTkSuQmCC @@ -265,12 +265,12 @@ YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAHPSURBVDhPY6AaWHbkq9SK/V+mLDvw5cjM3R8f9az/klK4 8h8nVBo/AGletuvrp7k7Pz6uX/zlTuOKj49bV325UzL/y+fKhV9Socpwg1X7v9ycufXrG/fyB+/1E9Z/ 10rZ9sc+d//XlMnvXhTO+fKiYO7nMJC6JSe/GDgUXfsP1oQMFh/4fD+s4+VP+ej5v13y1t80jl5zzDR2 - zRf5+Pm/nSZf+ps++f2zrLmfI+ft/3rVOvP4/5XH0LxWv/TLHtfy6+9VPXpu+dbvUAGJmUSvzFeLXPpV + zRf5+Pm/HSdf/Js++f2zrLmfI+ft/3rVOvP4/5XH0LxWv/TLHtfy6+9VPXpu+dbvUAGJmUSvzFeLXPpV 0mf2L/+W98+BLvmfNevzf5P4rZguqF/55ZBT8b1XKp59hxlCQ5mhwgxGUSscNbwmrS6b8+Z/dO/n/95N - b/7rhS7GNKBpxect9kUvvqp4T7hpbJzGChVmmLz1s+6UrV/BNns2vfpvVnz/v4bPVEwD8qc9KrVvPf1X - 0mfNL3HXYm6oMAMowKyAfjaJ3/ZfL2QJWLOqWxcWL6z6z5ZWf+6fVtmVP+rek92hwmCAEWC4QFjd2dyQ - +vP/LFL2XYQKkQr+M3pXXntp33L+r33e+ZjEvg9KUAnigYrHYj6vypunAlo/ffWofOIMFSYdeDe+Co3o - +RwJ5Q5qwMAAAP6q6T5lxW8NAAAAAElFTkSuQmCC + b/7rhS7GNKBpxect9kUvvqp4T7hpbJzGChVmmLz1s+6UrV/BNns2vfpvVnz/v4bPVEwD8qc9KrVvPfVX + 0mfNL3HXYm6oMAMowKyAfjaJ3/ZfL2QJWLOqWxcWL6z6z5ZWf/afVtmVP+rek92hwmCAEWC4QFjd2dyQ + +nP/LFL2XYQKkQr+M3pXXntp33Lur33e+ZjEvg9KUAnigYrHYj6vypunAlo/ffWofOIMFSYdeDe+Co3o + +RwJ5Q5qwMAAAPJ06Tid5phHAAAAAElFTkSuQmCC @@ -289,15 +289,15 @@ iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8 - YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAH3SURBVDhPrZNNTBNBFMdHUMIW2I9ZWmgCLlQkWqWx3Zlu - 1cTykXDg42AaD1449ADxYjx758TJcPBiPHIxkXAxJpJ4NzEo0pjQxMYYTbwZWjiwu+8x0w6HUgkk+kv2 - MO/99+2b/3tL/gvIjVuha21C1p5EQtpU+HzgA9IOrrUEi7NYWZjygdP7MqbSTWCeXERmJITmsQo1gsBo - MeT0DRSncbeYDMT56ckimHc6ZYeVhUk/ZOYLFW4Amd44ZGmuXqTAEB7exZBbG5Dq66rncwNamB/eqBQc - X2hWMBntrr94EkySDvH1J5Vpx5eFhHgNPDMliq2qoqvoWoaS/x1h4gXw6PUgQ7fklX7OxQ9rM6mqMPm1 - 7ETJzgZde1y2DPNj6GfoN8jpVKXOBj1jKOB0u8wpHKRNrKZ19F1rV6VPR+4ApE3Hd41SOdkf/LrRswnc - ZtLc3zd1BG4+kldU8laQR/sDL7ZVmxjC0kik/K6vfVxOQj4ho88/OZq/ndCYkjcj5xzmYq+qt7tqHwe1 - vQ+XtYJKqR2g+o/RSLmU6Hy7bpHBFkMha84eeDH8nNDwy3Bk/XgHjmlcLzryfuDS/s5VLdu08nL+YsbL - 3691484V7Svw3tEmgUJu55+U/hKYzVvyYhszIbOeCaPuwR275zSz6v+DG4+o479CyBF/3tFH9OOHfwAA + YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAH3SURBVDhPrZNPTBNBFMYHEcMW2D+ztNAEXKhItGhjuzPd + KglFTDiIHkzjwQuHHjRejGfvnDgRDl6MRy8mEi7GRBLvJAREGmNJbAyBxJuxlYO7+x4z7XAotcFEf8ke + 5r1v37753lvyX0BuXAtdaw2y9gwSckaF/w68TzrBtR7BwzmszN/ygdN7MqbSTWCenEVmJITmiQo1gsBo + MeT0LRRn8UsxGYjzs5NFMO90yw4r8zN+yMwXKtwAMv1xyNJcvUiBITyYxJBbq5Aa6Knnc0NamB9drRQc + X2gWMRntrb94EkySc+LrTyuzji8LCfEr8MyUKLasii6jaxlK/meEiR3g0ctBhm7KK+3fif+u3U5Vhclv + ZCdKdjro2tOyZbh7Ff0M/Qo5narU6aBnjAScbpc5hcO0idW0jr5rlVW6PXIHIG06vmuUysnB4GCibw24 + zaS536/oCNx8LK+o5K0gjw4GXmyzdnMES2OR3fcDndNyEvIJGX2+5Wj+dkJjSt6MnHOYi72uXu+pbQxr + P9fPawWVUjtA9b3xyG4p0f1uxSLDLYZC1pw79GL4MaHhp9HIyvEOHNO4XnTsw1DXr52LWrZp5eX8xYwX + vl3qxZ0L2mfg/eNNAoXczh8p/SUwm7fkxTZmQmYtCaOm4Ibd186s+v/gxiPq+K8QcgR5CdFE2NbC7AAA AABJRU5ErkJggg== @@ -312,7 +312,7 @@ AAEAAAD/////AQAAAAAAAAAMAgAAAFdTeXN0ZW0uV2luZG93cy5Gb3JtcywgVmVyc2lvbj00LjAuMC4w LCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODkFAQAAACZTeXN0 ZW0uV2luZG93cy5Gb3Jtcy5JbWFnZUxpc3RTdHJlYW1lcgEAAAAERGF0YQcCAgAAAAkDAAAADwMAAACs - EgAAAk1TRnQBSQFMAgEBBgEAAZABAAGQAQABEAEAARABAAT/ASEBAAj/AUIBTQE2BwABNgMAASgDAAFA + EgAAAk1TRnQBSQFMAgEBBgEAAZgBAAGYAQABEAEAARABAAT/ASEBAAj/AUIBTQE2BwABNgMAASgDAAFA AwABIAMAAQEBAAEgBgABIP8AGwADBAEGAw0EEgEYAxIBGAMSARgDEgEYAxIBGAMSARgDEgEYAxIBGAMS ARgDDQESAwQBBiAAAwQBBgFzAVkBRQH/AWgBTgE6Af8BOwE4ATYBV5wAAw0BEgMjATYDKwFJAysBSQMr AUkDKwFJAysBSQMrAUkDKwFJAysBSQMrAUkDIwE2Aw0BEiAAAWMBWwFUAZYBgQFnAVMB/wHKAbIBpAH/ diff --git a/ScadaWeb/ScadaScheme/ScadaSchemeEditor/ScadaSchemeEditor.csproj b/ScadaWeb/ScadaScheme/ScadaSchemeEditor/ScadaSchemeEditor.csproj index 6e95acb40..3f5e26aca 100644 --- a/ScadaWeb/ScadaScheme/ScadaSchemeEditor/ScadaSchemeEditor.csproj +++ b/ScadaWeb/ScadaScheme/ScadaSchemeEditor/ScadaSchemeEditor.csproj @@ -55,8 +55,9 @@ app.manifest - - ..\..\..\Log\bin\Release\Log.dll + + False + ..\..\..\Log\Log\bin\Release\Log.dll ..\..\..\ScadaData\ScadaData\bin\Release\ScadaData.dll diff --git a/ScadaWeb/ScadaTableEditor/ScadaTableEditor.csproj b/ScadaWeb/ScadaTableEditor/ScadaTableEditor.csproj index 1c00dc0ef..05265d513 100644 --- a/ScadaWeb/ScadaTableEditor/ScadaTableEditor.csproj +++ b/ScadaWeb/ScadaTableEditor/ScadaTableEditor.csproj @@ -44,10 +44,6 @@ full AnyCPU prompt - true - true - false - ..\..\..\..\Program Files (x86)\Microsoft Visual Studio 14.0\Team Tools\Static Analysis Tools\Rule Sets\MinimumRecommendedRules.ruleset bin\Release\ @@ -56,9 +52,6 @@ pdbonly AnyCPU prompt - true - true - C:\Program Files (x86)\Microsoft Visual Studio 14.0\Team Tools\Static Analysis Tools\Rule Sets\ManagedMinimumRules.ruleset app.manifest diff --git a/ScadaWeb/ScadaWebCommon5/DictUpdater.cs b/ScadaWeb/ScadaWebCommon5/DictUpdater.cs index 8308ee1d2..5213bd97d 100644 --- a/ScadaWeb/ScadaWebCommon5/DictUpdater.cs +++ b/ScadaWeb/ScadaWebCommon5/DictUpdater.cs @@ -1,5 +1,5 @@ /* - * Copyright 2016 Mikhail Shiryaev + * Copyright 2018 Mikhail Shiryaev * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -20,7 +20,7 @@ * * Author : Mikhail Shiryaev * Created : 2016 - * Modified : 2016 + * Modified : 2018 */ using System; @@ -49,7 +49,7 @@ public class DictUpdater /// /// Журнал /// - protected readonly Log log; + protected readonly ILog log; /// /// Первое обновление настроек /// @@ -66,7 +66,7 @@ protected DictUpdater() /// /// Конструктор /// - public DictUpdater(string directory, string fileNamePrefix, Action initPhrasesAction, Log log = null) + public DictUpdater(string directory, string fileNamePrefix, Action initPhrasesAction, ILog log = null) { if (directory == null) throw new ArgumentNullException("directory"); diff --git a/ScadaWeb/ScadaWebCommon5/Plugins/PluginSpec.cs b/ScadaWeb/ScadaWebCommon5/Plugins/PluginSpec.cs index 5ca428a35..eb24681c9 100644 --- a/ScadaWeb/ScadaWebCommon5/Plugins/PluginSpec.cs +++ b/ScadaWeb/ScadaWebCommon5/Plugins/PluginSpec.cs @@ -1,5 +1,5 @@ /* - * Copyright 2016 Mikhail Shiryaev + * Copyright 2018 Mikhail Shiryaev * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -20,7 +20,7 @@ * * Author : Mikhail Shiryaev * Created : 2016 - * Modified : 2016 + * Modified : 2018 */ using Scada.Web.Shell; @@ -39,7 +39,7 @@ namespace Scada.Web.Plugins public abstract class PluginSpec { private AppDirs appDirs; // директории веб-приложения - private Log log; // журнал + private ILog log; // журнал /// @@ -48,7 +48,7 @@ public abstract class PluginSpec public PluginSpec() { appDirs = new AppDirs(); - log = null; + log = new LogStub(); } @@ -122,16 +122,14 @@ public AppDirs AppDirs } set { - if (value == null) - throw new ArgumentNullException("value"); - appDirs = value; + appDirs = value ?? throw new ArgumentNullException("value"); } } /// /// Получить или установить журнал /// - public Log Log + public ILog Log { get { @@ -139,9 +137,7 @@ public Log Log } set { - if (value == null) - throw new ArgumentNullException("value"); - log = value; + log = value ?? throw new ArgumentNullException("value"); } } diff --git a/ScadaWeb/ScadaWebCommon5/ScadaWebCommon5.csproj b/ScadaWeb/ScadaWebCommon5/ScadaWebCommon5.csproj index cbc219f28..e89c14c1a 100644 --- a/ScadaWeb/ScadaWebCommon5/ScadaWebCommon5.csproj +++ b/ScadaWeb/ScadaWebCommon5/ScadaWebCommon5.csproj @@ -31,8 +31,9 @@ bin\Release\ScadaWebCommon5.xml - - ..\..\Log\bin\Release\Log.dll + + False + ..\..\Log\Log\bin\Release\Log.dll ..\..\ScadaData\ScadaData\bin\Release\ScadaData.dll diff --git a/ScadaWeb/ScadaWebCommon5/UserMonitor.cs b/ScadaWeb/ScadaWebCommon5/UserMonitor.cs index 5307b9204..1daa3dce4 100644 --- a/ScadaWeb/ScadaWebCommon5/UserMonitor.cs +++ b/ScadaWeb/ScadaWebCommon5/UserMonitor.cs @@ -321,7 +321,7 @@ public UserShot[] GetActiveUsers() { lock (userDataDict) { - UserShot[] userShotArr = new UserData[userDataDict.Count]; + UserShot[] userShotArr = new UserShot[userDataDict.Count]; int i = 0; foreach (UserData userData in userDataDict.Values) diff --git a/ScadaWeb/ScadaWebCommon5/WebUtils.cs b/ScadaWeb/ScadaWebCommon5/WebUtils.cs index 2a47f1914..4a544b330 100644 --- a/ScadaWeb/ScadaWebCommon5/WebUtils.cs +++ b/ScadaWeb/ScadaWebCommon5/WebUtils.cs @@ -40,7 +40,7 @@ public static partial class WebUtils /// /// Версия веб-приложения /// - public const string AppVersion = "5.0.5.0"; + public const string AppVersion = "5.0.6.0"; /// /// Шиблон для вставки стилей на веб-страницу /// diff --git a/ScadaWeb/ScadaWebShell5/ScadaWebShell5.csproj b/ScadaWeb/ScadaWebShell5/ScadaWebShell5.csproj index c49f7f1e0..37508f23f 100644 --- a/ScadaWeb/ScadaWebShell5/ScadaWebShell5.csproj +++ b/ScadaWeb/ScadaWebShell5/ScadaWebShell5.csproj @@ -23,6 +23,7 @@ True + true @@ -44,7 +45,7 @@ False - ..\..\Log\bin\Release\Log.dll + ..\..\Log\Log\bin\Release\Log.dll False