From 48310357f31476a1d408c7060213ef654f3146db Mon Sep 17 00:00:00 2001 From: Edward Date: Tue, 25 Feb 2020 18:20:32 +0800 Subject: [PATCH 01/19] Add Glib & VideoConver & Batch refine project arch --- .gitignore | 48 +- Build/Config/gb28181.xml | 21 - CHANGELOG.md | 13 +- .../Common.GLib.WinControls.csproj | 11 + .../GLib.Controls.Form/AXDataGridView.cs | 136 + .../GLib.Controls.Web/BulletedList.cs | 13 + .../GLib.Controls.Web/Button.cs | 8 + .../GLib.Controls.Web/CheckBox.cs | 8 + .../GLib.Controls.Web/CheckBoxList.cs | 13 + .../GLib.Controls.Web/ControlsConfig.cs | 9 + .../GLib.Controls.Web/DropDownList.cs | 13 + .../GLib.Controls.Web/GridView.cs | 8 + .../GLib.Controls.Web/HiddenField.cs | 8 + .../GLib.Controls.Web/HyperLink.cs | 8 + .../GLib.Controls.Web/Image.cs | 8 + .../GLib.Controls.Web/ImageButton.cs | 8 + .../GLib.Controls.Web/ImageMap.cs | 8 + .../GLib.Controls.Web/Label.cs | 8 + .../GLib.Controls.Web/LinkButton.cs | 8 + .../GLib.Controls.Web/ListBox.cs | 13 + .../GLib.Controls.Web/ListView.cs | 8 + .../GLib.Controls.Web/Literal.cs | 8 + .../GLib.Controls.Web/Panel.cs | 8 + .../GLib.Controls.Web/PlaceHolder.cs | 8 + .../GLib.Controls.Web/RadioButton.cs | 8 + .../GLib.Controls.Web/RadioButtonList.cs | 13 + .../GLib.Controls.Web/TextBox.cs | 8 + Common.GLib.WinControls/GLib/DebugEx.cs | 131 + Common.GLib.WinControls/RegistryHelper.cs | 81 + Common.GLib.WinControls/Watchdog.cs | 236 ++ Common.GLib/AXLib.Utility/Action.cs | 22 + Common.GLib/AXLib.Utility/Callback.cs | 22 + Common.GLib/AXLib.Utility/IAction.cs | 7 + Common.GLib/AXLib.Utility/ICallback.cs | 7 + Common.GLib/Common.GLib.csproj | 22 + Common.GLib/GLib.AXLib.Utility/ALog.cs | 109 + Common.GLib/GLib.AXLib.Utility/Loop.cs | 53 + Common.GLib/GLib.AXLib.Utility/ObjectPool.cs | 154 + .../GLib.AXLib.Utility/RuntimeExceptionEx.cs | 62 + Common.GLib/GLib.AXLib.Utility/ThreadEx.cs | 554 ++++ Common.GLib/GLib.AXLib.Utility/WaitResult.cs | 68 + Common.GLib/GLib.Assist/XmlHelper.cs | 178 ++ Common.GLib/GLib.Assist/XmlRange.cs | 9 + Common.GLib/GLib.Data.Core/DataBaseType.cs | 10 + Common.GLib/GLib.Data.Core/IRepository.cs | 66 + Common.GLib/GLib.Data.Core/ISqlCreator.cs | 30 + Common.GLib/GLib.Data.Core/Repository.cs | 594 ++++ Common.GLib/GLib.Data.Core/SqLiteCreator.cs | 419 +++ Common.GLib/GLib.Data.Core/SqlCreator.cs | 419 +++ .../GLib.Data.Core/SqlCreatorFactory.cs | 17 + Common.GLib/GLib.Data.Core/SqlHelper.cs | 259 ++ Common.GLib/GLib.Data.Entity/DBParam.cs | 49 + .../GLib.Data.Entity/EntityAttribute.cs | 36 + Common.GLib/GLib.Data.Entity/EntityHelper.cs | 170 ++ Common.GLib/GLib.Data.Entity/EntityInfo.cs | 103 + .../GLib.Data.Entity/EntityTypeCache.cs | 54 + Common.GLib/GLib.Data.Entity/ILogicEntity.cs | 26 + Common.GLib/GLib.Data/DBT_SqlHelper.cs | 254 ++ Common.GLib/GLib.Data/PageList.cs | 32 + Common.GLib/GLib.Extension/ComHelper.cs | 669 +++++ Common.GLib/GLib.Extension/FunctionEx.cs | 1136 +++++++ Common.GLib/GLib.Extension/ReflectionEx.cs | 174 ++ Common.GLib/GLib.Extension/Singleton.cs | 27 + Common.GLib/GLib.Extension/StringEx.cs | 263 ++ Common.GLib/GLib.Extension/TypeEx.cs | 57 + Common.GLib/GLib.GeneralModel/AQueue.cs | 75 + Common.GLib/GLib.GeneralModel/EventArgsEx.cs | 18 + Common.GLib/GLib.GeneralModel/KeyValue.cs | 43 + Common.GLib/GLib.GeneralModel/KeyValueList.cs | 44 + Common.GLib/GLib.GeneralModel/ListEx.cs | 16 + Common.GLib/GLib.GeneralModel/TreeNode.cs | 101 + Common.GLib/GLib.GeneralModel/TreeRoot.cs | 63 + Common.GLib/GLib.IO/BitStream.cs | 2615 +++++++++++++++++ Common.GLib/GLib.IO/BitStream.resx | 59 + Common.GLib/GLib.IO/BitStreamReader.cs | 110 + Common.GLib/GLib.IO/BufferStream.cs | 146 + Common.GLib/GLib.IO/IOStream.cs | 6 + Common.GLib/GLib.Linq/DynamicQueryable.cs | 30 + Common.GLib/GLib.Linq/FilterExpression.cs | 20 + .../GLib.Linq/IFilterExpressionContainer.cs | 17 + Common.GLib/GLib.Logging/Log.cs | 184 ++ Common.GLib/GLib.Logging/LogMessage.cs | 71 + Common.GLib/GLib.Logging/LogType.cs | 10 + Common.GLib/GLib.Logging/MessageType.cs | 11 + .../AnsycSocket4ByteLengthDespatcher.cs | 163 + Common.GLib/GLib.Net/AnsycSocketDespatcher.cs | 232 ++ Common.GLib/GLib.Net/ByteObjSocket.cs | 21 + Common.GLib/GLib.Net/IByteObj.cs | 9 + Common.GLib/GLib.Net/SocketEx.cs | 132 + Common.GLib/GLib.Net/TCPService.cs | 111 + Common.GLib/GLib.Net/TimeOutSocket.cs | 59 + .../GLib.Serializer/SerializerHelper.cs | 105 + .../GLib.Utilities.IO/DirectoryHelper.cs | 43 + Common.GLib/GLib.Utilities.IO/ExcelHelper.cs | 37 + Common.GLib/GLib.Utilities.IO/FileHelper.cs | 58 + Common.GLib/GLib.Utilities.IO/FileType.cs | 9 + .../GLib.Utilities.IO/FileTypeHelper.cs | 21 + Common.GLib/GLib.Utilities.IO/TxtHelper.cs | 47 + .../GLib.Utilities.Security/DecryptHelper.cs | 37 + .../GLib.Utilities.Security/EncryptHelper.cs | 56 + Common.GLib/GLib.Utilities/Computer.cs | 207 ++ Common.GLib/GLib.Utilities/EmailSender.cs | 282 ++ Common.GLib/GLib.Utilities/ExportFormat.cs | 9 + Common.GLib/GLib.Utilities/ExportHelper.cs | 206 ++ Common.GLib/GLib.Utilities/HtmlTag.cs | 176 ++ Common.GLib/GLib.Utilities/IPHelper.cs | 53 + Common.GLib/GLib.Utilities/IniFile.cs | 214 ++ Common.GLib/GLib.Utilities/JsonSerializer.cs | 20 + Common.GLib/GLib.Utilities/SendState.cs | 10 + Common.GLib/GLib.Utilities/StringHelper.cs | 48 + Common.GLib/GLib.Web/HttpCache.cs | 114 + Common.GLib/GLib.Web/HttpSession.cs | 76 + Common.GLib/GLib.Web/Warn.cs | 42 + Common.GLib/GLib.Web/WarnDescription.cs | 46 + Common.GLib/GLib/AuxiliaryFieldAttribute.cs | 9 + Common.GLib/GLib/DebugEx.cs | 119 + Common.GLib/GLib/DescriptionAttribute.cs | 133 + Common.GLib/GLib/DescriptionObjectType.cs | 11 + Common.GLib/GLib/MyTask.cs | 48 + Common.GLib/MSQueue.cs | 126 + .../MyGather.BLL.UserControls/HttpClient.cs | 145 + Common.GLib/Properties/AssemblyInfo.cs | 20 + Common.GLib/RegexUtils.cs | 93 + Common.GLib/RegistryHelper.cs | 80 + Common.GLib/Watchdog.cs | 236 ++ .../SIP.App/SIPUserAgents/JingleUserAgent.cs | 97 + .../Servers.Cores/IMediaService.cs | 8 +- .../SIPMessage/SIPMessageCore.cs | 20 + .../SIPMonitor/SIPMonitorCore.cs | 39 +- GB28181.SIPSorcery/Sys/Config/SIPSqlite.cs | 84 + .../Sys/WrapperImpersonationContext.cs | 144 + GB28181.Solution.sln | 56 +- .../Base/_DebugEx.cs | 2 +- .../Media/AAC_ADTS.cs | 2 +- .../Media/AVCodecCfg.cs | 2 +- .../Media/MediaFrame.cs | 4 +- .../Media/PATPMT.cs | 2 +- .../Media/PES.cs | 4 +- .../Media/StreamFileHelper.cs | 4 +- .../Media/TS/PSAnalyze.cs | 6 +- .../Media/TS/Rtsp/NetSDK.cs | 2 +- .../Media/TS/Rtsp/StreamDataCallBack.cs | 2 +- .../TS/TSStreamInput/GB28181TSStreamInput.cs | 6 +- .../Media/TS/TSStreamInput/TSStreamInput.cs | 6 +- .../Media/TS/mp4parser/AspectRatio.cs | 0 .../Media/TS/mp4parser/BTree.cs | 0 .../Media/TS/mp4parser/BitstreamReader.cs | 0 .../Media/TS/mp4parser/BitstreamWriter.cs | 0 .../Media/TS/mp4parser/CAVLCReader.cs | 0 .../Media/TS/mp4parser/CAVLCWriter.cs | 0 .../Media/TS/mp4parser/CharCache.cs | 0 .../Media/TS/mp4parser/ChromaFormat.cs | 0 .../Media/TS/mp4parser/HRDParameters.cs | 0 .../Media/TS/mp4parser/PictureParameterSet.cs | 0 .../Media/TS/mp4parser/ScalingList.cs | 0 .../Media/TS/mp4parser/ScalingMatrix.cs | 0 .../Media/TS/mp4parser/SeqParameterSet.cs | 0 .../Media/TS/mp4parser/SliceHeader.cs | 0 .../Media/TS/mp4parser/VUIParameters.cs | 0 .../Media/TSPacket.cs | 4 +- .../Media/TSProgramManage.cs | 4 +- SS.MediaNetEngine/SS.MediaNetEngine.csproj | 18 + SS.VideoConver/Properties/AssemblyInfo.cs | 20 + SS.VideoConver/QuickAudioEncodingCommands.cs | 10 + SS.VideoConver/SS.VideoConver.csproj | 11 + SS.VideoConver/StarEye.VideoConver.sln | 25 + SS.VideoConver/VideoEncoder/EncodedVideo.cs | 29 + SS.VideoConver/VideoEncoder/Encoder.cs | 211 ++ .../QuickVideoEncodingCommands.cs | 91 + SS.VideoConver/VideoEncoder/VideoFile.cs | 106 + SS.VideoConver/VideoThumbnail/Program.cs | 133 + .../videoconver/ShellPathNameConvert.cs | 33 + .../Test.GB28181.Service.csproj | 1 + Test.GB28181.Service/TestVideoThubnail.cs | 140 + Win.GB28181.Client/Form1.Designer.cs | 578 ++-- Win.GB28181.Client/Form1.cs | 272 +- .../Message/SIPMessageDaemon.cs | 28 +- Win.GB28181.Client/Message/SIPMessagetate.cs | 12 +- Win.GB28181.Client/Player/Codec/AVCodecCfg.cs | 22 +- .../Player/Codec/CameraEncoder.cs | 60 +- Win.GB28181.Client/Player/Codec/FFImp.cs | 4 +- Win.GB28181.Client/Player/Codec/FaacImp.cs | 2 +- Win.GB28181.Client/Player/Codec/FaadImp.cs | 2 +- Win.GB28181.Client/Player/Codec/MicEncoder.cs | 8 +- Win.GB28181.Client/Player/Codec/Speex.cs | 2 +- .../Player/Codec/StreamFileHelper.cs | 4 +- Win.GB28181.Client/Player/Codec/SwsScale.cs | 2 +- Win.GB28181.Client/Player/Codec/x264.cs | 12 +- .../Player/Controls/PlayerControl.Designer.cs | 2 +- .../Player/Controls/PlayerControl.cs | 8 +- .../Player/DShow/BaseFilterEx.cs | 2 +- .../Player/DShow/DShowHelper.cs | 2 +- Win.GB28181.Client/Player/DShow/FilterGrap.cs | 2 +- .../Player/DShow/IDSMutualFilter.cs | 2 +- .../Player/DShow/IffdshowBase.cs | 2 +- Win.GB28181.Client/Player/DShow/PinEx.cs | 2 +- .../Player/DShow/SampleGrabberCB.cs | 2 +- .../Player/Media/AudioPlayer.cs | 10 +- .../Player/Media/MediaCapturer.cs | 10 +- .../Player/Media/MediaPlayer.cs | 8 +- .../Player/Media/MediaSteamConverter.cs | 4 +- Win.GB28181.Client/Player/Media/SDLPlay.cs | 2 +- .../Player/Media/VideoPlayer.cs | 6 +- .../Player/Media/Wave/WavInDevice.cs | 2 +- .../Player/Media/Wave/WavOutDevice.cs | 2 +- .../Player/Media/Wave/WaveIn.cs | 4 +- .../Player/Media/Wave/WaveOut.cs | 4 +- .../Player/Media/Wave/native/MMSYSERR.cs | 2 +- .../Player/Media/Wave/native/WAVEFORMATEX.cs | 2 +- .../Player/Media/Wave/native/WAVEHDR.cs | 2 +- .../Player/Media/Wave/native/WAVEOUTCAPS.cs | 2 +- .../Player/Media/Wave/native/WavConstants.cs | 2 +- .../Player/Media/Wave/native/WavFormat.cs | 2 +- .../Player/Media/Wave/native/WavMethods.cs | 2 +- Win.GB28181.Client/Player/Media/YUVDraw.cs | 2 +- .../Player/Mixer/Audio/AAC_ADTS.cs | 2 +- .../Player/Mixer/Audio/AacDec.cs | 8 +- .../Player/Mixer/Audio/AacEnc.cs | 4 +- .../Player/Mixer/Audio/ByteArrayExtensions.cs | 2 +- .../Player/Mixer/Audio/DecoderBase.cs | 37 +- .../Player/Mixer/Audio/EncorderBase.cs | 2 +- .../Player/Mixer/Audio/Mixer.cs | 2 +- .../Player/Mixer/MediaCanvas.cs | 12 +- .../Player/Mixer/Video/Canvas.cs | 2 +- .../Player/Mixer/Video/CanvasStyle.cs | 2 +- .../Player/Mixer/Video/GraphicsBase.cs | 2 +- .../Player/Mixer/Video/ImageCanvas.cs | 2 +- .../Player/Mixer/Video/MarqueeCanvas.cs | 2 +- .../Player/Mixer/Video/StringCanvas.cs | 2 +- .../Player/Mixer/Video/TimeCanvas.cs | 2 +- .../Player/Mixer/Video/VideoCanvas.cs | 10 +- Win.GB28181.Client/Win.GB28181.Client.csproj | 33 +- Win.GB28181.Libs/GLib.dll | Bin 192000 -> 0 bytes Win.MeidaNetEngine/Win.MediaNetEngine.csproj | 19 - 234 files changed, 16182 insertions(+), 701 deletions(-) delete mode 100644 Build/Config/gb28181.xml create mode 100644 Common.GLib.WinControls/Common.GLib.WinControls.csproj create mode 100644 Common.GLib.WinControls/GLib.Controls.Form/AXDataGridView.cs create mode 100644 Common.GLib.WinControls/GLib.Controls.Web/BulletedList.cs create mode 100644 Common.GLib.WinControls/GLib.Controls.Web/Button.cs create mode 100644 Common.GLib.WinControls/GLib.Controls.Web/CheckBox.cs create mode 100644 Common.GLib.WinControls/GLib.Controls.Web/CheckBoxList.cs create mode 100644 Common.GLib.WinControls/GLib.Controls.Web/ControlsConfig.cs create mode 100644 Common.GLib.WinControls/GLib.Controls.Web/DropDownList.cs create mode 100644 Common.GLib.WinControls/GLib.Controls.Web/GridView.cs create mode 100644 Common.GLib.WinControls/GLib.Controls.Web/HiddenField.cs create mode 100644 Common.GLib.WinControls/GLib.Controls.Web/HyperLink.cs create mode 100644 Common.GLib.WinControls/GLib.Controls.Web/Image.cs create mode 100644 Common.GLib.WinControls/GLib.Controls.Web/ImageButton.cs create mode 100644 Common.GLib.WinControls/GLib.Controls.Web/ImageMap.cs create mode 100644 Common.GLib.WinControls/GLib.Controls.Web/Label.cs create mode 100644 Common.GLib.WinControls/GLib.Controls.Web/LinkButton.cs create mode 100644 Common.GLib.WinControls/GLib.Controls.Web/ListBox.cs create mode 100644 Common.GLib.WinControls/GLib.Controls.Web/ListView.cs create mode 100644 Common.GLib.WinControls/GLib.Controls.Web/Literal.cs create mode 100644 Common.GLib.WinControls/GLib.Controls.Web/Panel.cs create mode 100644 Common.GLib.WinControls/GLib.Controls.Web/PlaceHolder.cs create mode 100644 Common.GLib.WinControls/GLib.Controls.Web/RadioButton.cs create mode 100644 Common.GLib.WinControls/GLib.Controls.Web/RadioButtonList.cs create mode 100644 Common.GLib.WinControls/GLib.Controls.Web/TextBox.cs create mode 100644 Common.GLib.WinControls/GLib/DebugEx.cs create mode 100644 Common.GLib.WinControls/RegistryHelper.cs create mode 100644 Common.GLib.WinControls/Watchdog.cs create mode 100644 Common.GLib/AXLib.Utility/Action.cs create mode 100644 Common.GLib/AXLib.Utility/Callback.cs create mode 100644 Common.GLib/AXLib.Utility/IAction.cs create mode 100644 Common.GLib/AXLib.Utility/ICallback.cs create mode 100644 Common.GLib/Common.GLib.csproj create mode 100644 Common.GLib/GLib.AXLib.Utility/ALog.cs create mode 100644 Common.GLib/GLib.AXLib.Utility/Loop.cs create mode 100644 Common.GLib/GLib.AXLib.Utility/ObjectPool.cs create mode 100644 Common.GLib/GLib.AXLib.Utility/RuntimeExceptionEx.cs create mode 100644 Common.GLib/GLib.AXLib.Utility/ThreadEx.cs create mode 100644 Common.GLib/GLib.AXLib.Utility/WaitResult.cs create mode 100644 Common.GLib/GLib.Assist/XmlHelper.cs create mode 100644 Common.GLib/GLib.Assist/XmlRange.cs create mode 100644 Common.GLib/GLib.Data.Core/DataBaseType.cs create mode 100644 Common.GLib/GLib.Data.Core/IRepository.cs create mode 100644 Common.GLib/GLib.Data.Core/ISqlCreator.cs create mode 100644 Common.GLib/GLib.Data.Core/Repository.cs create mode 100644 Common.GLib/GLib.Data.Core/SqLiteCreator.cs create mode 100644 Common.GLib/GLib.Data.Core/SqlCreator.cs create mode 100644 Common.GLib/GLib.Data.Core/SqlCreatorFactory.cs create mode 100644 Common.GLib/GLib.Data.Core/SqlHelper.cs create mode 100644 Common.GLib/GLib.Data.Entity/DBParam.cs create mode 100644 Common.GLib/GLib.Data.Entity/EntityAttribute.cs create mode 100644 Common.GLib/GLib.Data.Entity/EntityHelper.cs create mode 100644 Common.GLib/GLib.Data.Entity/EntityInfo.cs create mode 100644 Common.GLib/GLib.Data.Entity/EntityTypeCache.cs create mode 100644 Common.GLib/GLib.Data.Entity/ILogicEntity.cs create mode 100644 Common.GLib/GLib.Data/DBT_SqlHelper.cs create mode 100644 Common.GLib/GLib.Data/PageList.cs create mode 100644 Common.GLib/GLib.Extension/ComHelper.cs create mode 100644 Common.GLib/GLib.Extension/FunctionEx.cs create mode 100644 Common.GLib/GLib.Extension/ReflectionEx.cs create mode 100644 Common.GLib/GLib.Extension/Singleton.cs create mode 100644 Common.GLib/GLib.Extension/StringEx.cs create mode 100644 Common.GLib/GLib.Extension/TypeEx.cs create mode 100644 Common.GLib/GLib.GeneralModel/AQueue.cs create mode 100644 Common.GLib/GLib.GeneralModel/EventArgsEx.cs create mode 100644 Common.GLib/GLib.GeneralModel/KeyValue.cs create mode 100644 Common.GLib/GLib.GeneralModel/KeyValueList.cs create mode 100644 Common.GLib/GLib.GeneralModel/ListEx.cs create mode 100644 Common.GLib/GLib.GeneralModel/TreeNode.cs create mode 100644 Common.GLib/GLib.GeneralModel/TreeRoot.cs create mode 100644 Common.GLib/GLib.IO/BitStream.cs create mode 100644 Common.GLib/GLib.IO/BitStream.resx create mode 100644 Common.GLib/GLib.IO/BitStreamReader.cs create mode 100644 Common.GLib/GLib.IO/BufferStream.cs create mode 100644 Common.GLib/GLib.IO/IOStream.cs create mode 100644 Common.GLib/GLib.Linq/DynamicQueryable.cs create mode 100644 Common.GLib/GLib.Linq/FilterExpression.cs create mode 100644 Common.GLib/GLib.Linq/IFilterExpressionContainer.cs create mode 100644 Common.GLib/GLib.Logging/Log.cs create mode 100644 Common.GLib/GLib.Logging/LogMessage.cs create mode 100644 Common.GLib/GLib.Logging/LogType.cs create mode 100644 Common.GLib/GLib.Logging/MessageType.cs create mode 100644 Common.GLib/GLib.Net/AnsycSocket4ByteLengthDespatcher.cs create mode 100644 Common.GLib/GLib.Net/AnsycSocketDespatcher.cs create mode 100644 Common.GLib/GLib.Net/ByteObjSocket.cs create mode 100644 Common.GLib/GLib.Net/IByteObj.cs create mode 100644 Common.GLib/GLib.Net/SocketEx.cs create mode 100644 Common.GLib/GLib.Net/TCPService.cs create mode 100644 Common.GLib/GLib.Net/TimeOutSocket.cs create mode 100644 Common.GLib/GLib.Serializer/SerializerHelper.cs create mode 100644 Common.GLib/GLib.Utilities.IO/DirectoryHelper.cs create mode 100644 Common.GLib/GLib.Utilities.IO/ExcelHelper.cs create mode 100644 Common.GLib/GLib.Utilities.IO/FileHelper.cs create mode 100644 Common.GLib/GLib.Utilities.IO/FileType.cs create mode 100644 Common.GLib/GLib.Utilities.IO/FileTypeHelper.cs create mode 100644 Common.GLib/GLib.Utilities.IO/TxtHelper.cs create mode 100644 Common.GLib/GLib.Utilities.Security/DecryptHelper.cs create mode 100644 Common.GLib/GLib.Utilities.Security/EncryptHelper.cs create mode 100644 Common.GLib/GLib.Utilities/Computer.cs create mode 100644 Common.GLib/GLib.Utilities/EmailSender.cs create mode 100644 Common.GLib/GLib.Utilities/ExportFormat.cs create mode 100644 Common.GLib/GLib.Utilities/ExportHelper.cs create mode 100644 Common.GLib/GLib.Utilities/HtmlTag.cs create mode 100644 Common.GLib/GLib.Utilities/IPHelper.cs create mode 100644 Common.GLib/GLib.Utilities/IniFile.cs create mode 100644 Common.GLib/GLib.Utilities/JsonSerializer.cs create mode 100644 Common.GLib/GLib.Utilities/SendState.cs create mode 100644 Common.GLib/GLib.Utilities/StringHelper.cs create mode 100644 Common.GLib/GLib.Web/HttpCache.cs create mode 100644 Common.GLib/GLib.Web/HttpSession.cs create mode 100644 Common.GLib/GLib.Web/Warn.cs create mode 100644 Common.GLib/GLib.Web/WarnDescription.cs create mode 100644 Common.GLib/GLib/AuxiliaryFieldAttribute.cs create mode 100644 Common.GLib/GLib/DebugEx.cs create mode 100644 Common.GLib/GLib/DescriptionAttribute.cs create mode 100644 Common.GLib/GLib/DescriptionObjectType.cs create mode 100644 Common.GLib/GLib/MyTask.cs create mode 100644 Common.GLib/MSQueue.cs create mode 100644 Common.GLib/MyGather.BLL.UserControls/HttpClient.cs create mode 100644 Common.GLib/Properties/AssemblyInfo.cs create mode 100644 Common.GLib/RegexUtils.cs create mode 100644 Common.GLib/RegistryHelper.cs create mode 100644 Common.GLib/Watchdog.cs create mode 100644 GB28181.SIPSorcery/SIP.App/SIPUserAgents/JingleUserAgent.cs create mode 100644 GB28181.SIPSorcery/Sys/Config/SIPSqlite.cs create mode 100644 GB28181.SIPSorcery/Sys/WrapperImpersonationContext.cs rename {Win.MeidaNetEngine => SS.MediaNetEngine}/Base/_DebugEx.cs (96%) rename {Win.MeidaNetEngine => SS.MediaNetEngine}/Media/AAC_ADTS.cs (99%) rename {Win.MeidaNetEngine => SS.MediaNetEngine}/Media/AVCodecCfg.cs (99%) rename {Win.MeidaNetEngine => SS.MediaNetEngine}/Media/MediaFrame.cs (99%) rename {Win.MeidaNetEngine => SS.MediaNetEngine}/Media/PATPMT.cs (99%) rename {Win.MeidaNetEngine => SS.MediaNetEngine}/Media/PES.cs (99%) rename {Win.MeidaNetEngine => SS.MediaNetEngine}/Media/StreamFileHelper.cs (98%) rename {Win.MeidaNetEngine => SS.MediaNetEngine}/Media/TS/PSAnalyze.cs (99%) rename {Win.MeidaNetEngine => SS.MediaNetEngine}/Media/TS/Rtsp/NetSDK.cs (95%) rename {Win.MeidaNetEngine => SS.MediaNetEngine}/Media/TS/Rtsp/StreamDataCallBack.cs (85%) rename {Win.MeidaNetEngine => SS.MediaNetEngine}/Media/TS/TSStreamInput/GB28181TSStreamInput.cs (96%) rename {Win.MeidaNetEngine => SS.MediaNetEngine}/Media/TS/TSStreamInput/TSStreamInput.cs (99%) rename {Win.MeidaNetEngine => SS.MediaNetEngine}/Media/TS/mp4parser/AspectRatio.cs (100%) rename {Win.MeidaNetEngine => SS.MediaNetEngine}/Media/TS/mp4parser/BTree.cs (100%) rename {Win.MeidaNetEngine => SS.MediaNetEngine}/Media/TS/mp4parser/BitstreamReader.cs (100%) rename {Win.MeidaNetEngine => SS.MediaNetEngine}/Media/TS/mp4parser/BitstreamWriter.cs (100%) rename {Win.MeidaNetEngine => SS.MediaNetEngine}/Media/TS/mp4parser/CAVLCReader.cs (100%) rename {Win.MeidaNetEngine => SS.MediaNetEngine}/Media/TS/mp4parser/CAVLCWriter.cs (100%) rename {Win.MeidaNetEngine => SS.MediaNetEngine}/Media/TS/mp4parser/CharCache.cs (100%) rename {Win.MeidaNetEngine => SS.MediaNetEngine}/Media/TS/mp4parser/ChromaFormat.cs (100%) rename {Win.MeidaNetEngine => SS.MediaNetEngine}/Media/TS/mp4parser/HRDParameters.cs (100%) rename {Win.MeidaNetEngine => SS.MediaNetEngine}/Media/TS/mp4parser/PictureParameterSet.cs (100%) rename {Win.MeidaNetEngine => SS.MediaNetEngine}/Media/TS/mp4parser/ScalingList.cs (100%) rename {Win.MeidaNetEngine => SS.MediaNetEngine}/Media/TS/mp4parser/ScalingMatrix.cs (100%) rename {Win.MeidaNetEngine => SS.MediaNetEngine}/Media/TS/mp4parser/SeqParameterSet.cs (100%) rename {Win.MeidaNetEngine => SS.MediaNetEngine}/Media/TS/mp4parser/SliceHeader.cs (100%) rename {Win.MeidaNetEngine => SS.MediaNetEngine}/Media/TS/mp4parser/VUIParameters.cs (100%) rename {Win.MeidaNetEngine => SS.MediaNetEngine}/Media/TSPacket.cs (99%) rename {Win.MeidaNetEngine => SS.MediaNetEngine}/Media/TSProgramManage.cs (99%) create mode 100644 SS.MediaNetEngine/SS.MediaNetEngine.csproj create mode 100644 SS.VideoConver/Properties/AssemblyInfo.cs create mode 100644 SS.VideoConver/QuickAudioEncodingCommands.cs create mode 100644 SS.VideoConver/SS.VideoConver.csproj create mode 100644 SS.VideoConver/StarEye.VideoConver.sln create mode 100644 SS.VideoConver/VideoEncoder/EncodedVideo.cs create mode 100644 SS.VideoConver/VideoEncoder/Encoder.cs create mode 100644 SS.VideoConver/VideoEncoder/QuickVideoEncodingCommands.cs create mode 100644 SS.VideoConver/VideoEncoder/VideoFile.cs create mode 100644 SS.VideoConver/VideoThumbnail/Program.cs create mode 100644 SS.VideoConver/videoconver/ShellPathNameConvert.cs create mode 100644 Test.GB28181.Service/TestVideoThubnail.cs delete mode 100644 Win.GB28181.Libs/GLib.dll delete mode 100644 Win.MeidaNetEngine/Win.MediaNetEngine.csproj diff --git a/.gitignore b/.gitignore index 90d5964..4c1ea26 100644 --- a/.gitignore +++ b/.gitignore @@ -151,48 +151,10 @@ $RECYCLE.BIN/ .DS_Store .vs *.cache -/Build/netcoreapp2.1/GB28181.Service.dll -/Build/netcoreapp2.1/GB28181.Service.dll -/Build/netcoreapp2.1/SIPSorcery.28181.dll -/Build/netcoreapp2.1/SIPSorcery.28181.dll -/Build/netcoreapp2.1/SIPSorcery.28181.pdb -/GB28181.Service/obj/Debug/netcoreapp2.1/GB28181.Service.csprojAssemblyReference.cache -/GrpcAgent/bin/Debug/netcoreapp2.1/SIPSorcery.28181.dll -/GrpcAgent/bin/Debug/netcoreapp2.1/SIPSorcery.28181.pdb -/GrpcAgent/obj/Debug/netcoreapp2.1/GrpcAgent.csprojAssemblyReference.cache -/SIPSorcery.28181/bin/Debug/netcoreapp2.1/SIPSorcery.28181.dll -/SIPSorcery.28181/bin/Debug/netcoreapp2.1/SIPSorcery.28181.pdb -/SIPSorcery.28181/obj/Debug/netcoreapp2.1/SIPSorcery.28181.dll -/SIPSorcery.28181/obj/Debug/netcoreapp2.1/SIPSorcery.28181.pdb -/Test.GB28181.Service/bin/Debug/netcoreapp2.1/SIPSorcery.28181.dll -/Test.GB28181.Service/bin/Debug/netcoreapp2.1/SIPSorcery.28181.pdb -/Test.GB28181.Service/obj/Debug/netcoreapp2.1/Test.GB28181.Service.csprojAssemblyReference.cache -/Build/netcoreapp2.1/GB28181.Service.dll -/Build/netcoreapp2.1/GB28181.Service.pdb -/GB28181.Service/obj/Debug/netcoreapp2.1/GB28181.Service.dll -/GB28181.Service/obj/Debug/netcoreapp2.1/GB28181.Service.pdb -/Logger4Net/obj/Debug/netcoreapp2.1/Logger4Net.csproj.FileListAbsolute.txt -/Logger4Net/obj/Debug/netcoreapp2.1/Logger4Net.csprojAssemblyReference.cache -/NATS.Client/obj/Debug/netcoreapp2.1/NATS.Client.csproj.FileListAbsolute.txt -/NATS.Client/obj/Debug/netcoreapp2.1/NATS.Client.csprojAssemblyReference.cache -/Proto.Grpc/obj/Debug/netcoreapp2.1/GrpcProtocol.csproj.FileListAbsolute.txt -/Proto.Grpc/obj/Debug/netcoreapp2.1/GrpcProtocol.csprojAssemblyReference.cache -/SIPSorcery.28181/obj/Debug/netcoreapp2.1/SIPSorcery.28181.csprojAssemblyReference.cache -/Test.GB28181.Service/bin/Debug/netcoreapp2.1/GB28181.Service.dll -/Test.GB28181.Service/bin/Debug/netcoreapp2.1/GB28181.Service.pdb -/Build/netcoreapp2.1/GB28181.Service.dll -/Build/netcoreapp2.1/GB28181.Service.pdb -/GB28181.Service/obj/Debug/netcoreapp2.1/GB28181.Service.dll -/GB28181.Service/obj/Debug/netcoreapp2.1/GB28181.Service.pdb -/Logger4Net/obj/Debug/netcoreapp2.1/Logger4Net.csproj.FileListAbsolute.txt -/Logger4Net/obj/Debug/netcoreapp2.1/Logger4Net.csprojAssemblyReference.cache -/NATS.Client/obj/Debug/netcoreapp2.1/NATS.Client.csproj.FileListAbsolute.txt -/NATS.Client/obj/Debug/netcoreapp2.1/NATS.Client.csprojAssemblyReference.cache -/Proto.Grpc/obj/Debug/netcoreapp2.1/GrpcProtocol.csproj.FileListAbsolute.txt -/Proto.Grpc/obj/Debug/netcoreapp2.1/GrpcProtocol.csprojAssemblyReference.cache -/SIPSorcery.28181/obj/Debug/netcoreapp2.1/SIPSorcery.28181.csprojAssemblyReference.cache -/Test.GB28181.Service/bin/Debug/netcoreapp2.1/GB28181.Service.dll -/Test.GB28181.Service/bin/Debug/netcoreapp2.1/GB28181.Service.pdb -/SIPSorcery.28181/obj/Debug/netcoreapp2.1/SIPSorcery.28181.csproj.FileListAbsolute.txt obj/ bin/ +/.vs/ +/packages +packages.config +obj/ +*.orig diff --git a/Build/Config/gb28181.xml b/Build/Config/gb28181.xml deleted file mode 100644 index e5f699b..0000000 --- a/Build/Config/gb28181.xml +++ /dev/null @@ -1,21 +0,0 @@ - - - -10 - 下级平台 - GB-2011 - 34010000002000000001 - 192.168.1.21 - 5060 - 0 - false - admin - 34010000001360000001 - Udp - Udp - passive - GB2312 - true - 5060 - 3 - - \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md index 34f2fc0..211467c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,12 +1,3 @@ -## release v6.0.0.1 -* realtime video and playback video successfully finished +# Important Change -## release v6.0.0.1 -* Registered device to DMS -* Get GBserver config info from devicemanagementservice -* Real video request and play -* Keepalive of real video request - -## release v6.0.0.0 - -* add md log file +## a lot of change ,as a basic codes \ No newline at end of file diff --git a/Common.GLib.WinControls/Common.GLib.WinControls.csproj b/Common.GLib.WinControls/Common.GLib.WinControls.csproj new file mode 100644 index 0000000..0b89b8f --- /dev/null +++ b/Common.GLib.WinControls/Common.GLib.WinControls.csproj @@ -0,0 +1,11 @@ + + + + Library + netcoreapp3.1 + Common.GLib.WinControls + Common.GLib.WinControls + true + + + diff --git a/Common.GLib.WinControls/GLib.Controls.Form/AXDataGridView.cs b/Common.GLib.WinControls/GLib.Controls.Form/AXDataGridView.cs new file mode 100644 index 0000000..3a0259f --- /dev/null +++ b/Common.GLib.WinControls/GLib.Controls.Form/AXDataGridView.cs @@ -0,0 +1,136 @@ +using System; +using System.ComponentModel; +using System.Drawing; +using System.Windows.Forms; + +namespace GLib.Controls.Form +{ + public class AXDataGridView : DataGridView + { + private int _index = 0; + + private bool _isScorll = true; + + private int _move = 30; + + private IContainer components = null; + + private Timer timer1; + + [Browsable(true)] + [DefaultValue(true)] + public new bool ReadOnly + { + get + { + return base.ReadOnly; + } + set + { + base.ReadOnly = value; + } + } + + public AXDataGridView() + { + InitializeComponent(); + Init(); + } + + private void Init() + { + base.AllowUserToAddRows = false; + base.AllowUserToDeleteRows = false; + base.BorderStyle = BorderStyle.None; + base.BackgroundColor = SystemColors.Window; + base.ColumnHeadersHeightSizeMode = DataGridViewColumnHeadersHeightSizeMode.DisableResizing; + base.EnableHeadersVisualStyles = false; + base.RowHeadersVisible = false; + base.RowTemplate.Height = 20; + base.SelectionMode = DataGridViewSelectionMode.FullRowSelect; + base.AutoGenerateColumns = false; + base.AllowUserToResizeRows = false; + SetStyle(ControlStyles.AllPaintingInWmPaint | ControlStyles.DoubleBuffer | ControlStyles.OptimizedDoubleBuffer, value: true); + UpdateStyles(); + } + + private void AXDataGridView_MouseWheel(object sender, MouseEventArgs e) + { + _move = 0; + } + + private void AXDataGridView_RowsAdded(object sender, DataGridViewRowsAddedEventArgs e) + { + if (_isScorll && base.FirstDisplayedScrollingRowIndex != -1) + { + _index++; + base.FirstDisplayedScrollingRowIndex = ((base.Rows.Count > 0) ? (base.Rows.Count - 1) : 0); + } + } + + private void AXDataGridView_RowsRemoved(object sender, DataGridViewRowsRemovedEventArgs e) + { + _index--; + if (_isScorll && base.FirstDisplayedScrollingRowIndex != -1) + { + base.FirstDisplayedScrollingRowIndex = base.Rows.Count - 2; + } + } + + private void AXDataGridView_Scroll(object sender, ScrollEventArgs e) + { + if (_index > e.NewValue) + { + _move = 0; + _isScorll = false; + } + else + { + _isScorll = true; + } + if (_isScorll) + { + _index = e.NewValue; + } + } + + private void AXDataGridView_MouseClick(object sender, MouseEventArgs e) + { + _isScorll = false; + } + + private void AXDataGridView_MouseMove(object sender, MouseEventArgs e) + { + _move = 0; + } + + private void timer1_Tick(object sender, EventArgs e) + { + } + + protected override void Dispose(bool disposing) + { + if (disposing && components != null) + { + timer1.Enabled = false; + timer1.Dispose(); + components.Dispose(); + } + base.Dispose(disposing); + } + + private void InitializeComponent() + { + components = new System.ComponentModel.Container(); + timer1 = new System.Windows.Forms.Timer(components); + ((System.ComponentModel.ISupportInitialize)this).BeginInit(); + SuspendLayout(); + timer1.Enabled = true; + timer1.Interval = 1000; + timer1.Tick += new System.EventHandler(timer1_Tick); + base.RowTemplate.Height = 23; + ((System.ComponentModel.ISupportInitialize)this).EndInit(); + ResumeLayout(false); + } + } +} diff --git a/Common.GLib.WinControls/GLib.Controls.Web/BulletedList.cs b/Common.GLib.WinControls/GLib.Controls.Web/BulletedList.cs new file mode 100644 index 0000000..fe4798f --- /dev/null +++ b/Common.GLib.WinControls/GLib.Controls.Web/BulletedList.cs @@ -0,0 +1,13 @@ +//using System.Web.UI.WebControls; + +namespace GLib.Controls.Web +{ + //public class BulletedList : System.Web.UI.WebControls.BulletedList + //{ + // public BulletedList() + // { + // DataValueField = ControlsConfig.Controls_DataValueField; + // DataTextField = ControlsConfig.Controls_DataTextField; + // } + //} +} diff --git a/Common.GLib.WinControls/GLib.Controls.Web/Button.cs b/Common.GLib.WinControls/GLib.Controls.Web/Button.cs new file mode 100644 index 0000000..2395a44 --- /dev/null +++ b/Common.GLib.WinControls/GLib.Controls.Web/Button.cs @@ -0,0 +1,8 @@ +//using System.Web.UI.WebControls; + +//namespace GLib.Controls.Web +//{ +// public class Button : System.Web.UI.WebControls.Button +// { +// } +//} diff --git a/Common.GLib.WinControls/GLib.Controls.Web/CheckBox.cs b/Common.GLib.WinControls/GLib.Controls.Web/CheckBox.cs new file mode 100644 index 0000000..8f36f81 --- /dev/null +++ b/Common.GLib.WinControls/GLib.Controls.Web/CheckBox.cs @@ -0,0 +1,8 @@ +//using System.Web.UI.WebControls; + +//namespace GLib.Controls.Web +//{ +// public class CheckBox : System.Web.UI.WebControls.CheckBox +// { +// } +//} diff --git a/Common.GLib.WinControls/GLib.Controls.Web/CheckBoxList.cs b/Common.GLib.WinControls/GLib.Controls.Web/CheckBoxList.cs new file mode 100644 index 0000000..be793b8 --- /dev/null +++ b/Common.GLib.WinControls/GLib.Controls.Web/CheckBoxList.cs @@ -0,0 +1,13 @@ +//using System.Web.UI.WebControls; + +//namespace GLib.Controls.Web +//{ +// public class CheckBoxList : System.Web.UI.WebControls.CheckBoxList +// { +// public CheckBoxList() +// { +// DataValueField = ControlsConfig.Controls_DataValueField; +// DataTextField = ControlsConfig.Controls_DataTextField; +// } +// } +//} diff --git a/Common.GLib.WinControls/GLib.Controls.Web/ControlsConfig.cs b/Common.GLib.WinControls/GLib.Controls.Web/ControlsConfig.cs new file mode 100644 index 0000000..9443603 --- /dev/null +++ b/Common.GLib.WinControls/GLib.Controls.Web/ControlsConfig.cs @@ -0,0 +1,9 @@ +namespace GLib.Controls.Web +{ + internal class ControlsConfig + { + public static string Controls_DataValueField => "Key"; + + public static string Controls_DataTextField => "Value"; + } +} diff --git a/Common.GLib.WinControls/GLib.Controls.Web/DropDownList.cs b/Common.GLib.WinControls/GLib.Controls.Web/DropDownList.cs new file mode 100644 index 0000000..ade7f33 --- /dev/null +++ b/Common.GLib.WinControls/GLib.Controls.Web/DropDownList.cs @@ -0,0 +1,13 @@ +//using System.Web.UI.WebControls; + +//namespace GLib.Controls.Web +//{ +// public class DropDownList : System.Web.UI.WebControls.DropDownList +// { +// public DropDownList() +// { +// DataValueField = ControlsConfig.Controls_DataValueField; +// DataTextField = ControlsConfig.Controls_DataTextField; +// } +// } +//} diff --git a/Common.GLib.WinControls/GLib.Controls.Web/GridView.cs b/Common.GLib.WinControls/GLib.Controls.Web/GridView.cs new file mode 100644 index 0000000..4dd4297 --- /dev/null +++ b/Common.GLib.WinControls/GLib.Controls.Web/GridView.cs @@ -0,0 +1,8 @@ +//using System.Web.UI.WebControls; + +//namespace GLib.Controls.Web +//{ +// public class GridView : System.Web.UI.WebControls.GridView +// { +// } +//} diff --git a/Common.GLib.WinControls/GLib.Controls.Web/HiddenField.cs b/Common.GLib.WinControls/GLib.Controls.Web/HiddenField.cs new file mode 100644 index 0000000..9745e50 --- /dev/null +++ b/Common.GLib.WinControls/GLib.Controls.Web/HiddenField.cs @@ -0,0 +1,8 @@ +//using System.Web.UI.WebControls; + +namespace GLib.Controls.Web +{ + //public class HiddenField : System.Web.UI.WebControls.HiddenField + //{ + //} +} diff --git a/Common.GLib.WinControls/GLib.Controls.Web/HyperLink.cs b/Common.GLib.WinControls/GLib.Controls.Web/HyperLink.cs new file mode 100644 index 0000000..d5f1a6d --- /dev/null +++ b/Common.GLib.WinControls/GLib.Controls.Web/HyperLink.cs @@ -0,0 +1,8 @@ +//using System.Web.UI.WebControls; + +//namespace GLib.Controls.Web +//{ +// public class HyperLink : System.Web.UI.WebControls.HyperLink +// { +// } +//} diff --git a/Common.GLib.WinControls/GLib.Controls.Web/Image.cs b/Common.GLib.WinControls/GLib.Controls.Web/Image.cs new file mode 100644 index 0000000..c5dc76b --- /dev/null +++ b/Common.GLib.WinControls/GLib.Controls.Web/Image.cs @@ -0,0 +1,8 @@ +//using System.Web.UI.WebControls; + +//namespace GLib.Controls.Web +//{ +// public class Image : System.Web.UI.WebControls.Image +// { +// } +//} diff --git a/Common.GLib.WinControls/GLib.Controls.Web/ImageButton.cs b/Common.GLib.WinControls/GLib.Controls.Web/ImageButton.cs new file mode 100644 index 0000000..bf9ec45 --- /dev/null +++ b/Common.GLib.WinControls/GLib.Controls.Web/ImageButton.cs @@ -0,0 +1,8 @@ +//using System.Web.UI.WebControls; + +namespace GLib.Controls.Web +{ + //public class ImageButton : System.Web.UI.WebControls.ImageButton + //{ + //} +} diff --git a/Common.GLib.WinControls/GLib.Controls.Web/ImageMap.cs b/Common.GLib.WinControls/GLib.Controls.Web/ImageMap.cs new file mode 100644 index 0000000..0c89a3b --- /dev/null +++ b/Common.GLib.WinControls/GLib.Controls.Web/ImageMap.cs @@ -0,0 +1,8 @@ +//using System.Web.UI.WebControls; + +//namespace GLib.Controls.Web +//{ +// public class ImageMap : System.Web.UI.WebControls.ImageMap +// { +// } +//} diff --git a/Common.GLib.WinControls/GLib.Controls.Web/Label.cs b/Common.GLib.WinControls/GLib.Controls.Web/Label.cs new file mode 100644 index 0000000..55a45c3 --- /dev/null +++ b/Common.GLib.WinControls/GLib.Controls.Web/Label.cs @@ -0,0 +1,8 @@ +//using System.Web.UI.WebControls; + +//namespace GLib.Controls.Web +//{ +// public class Label : System.Web.UI.WebControls.Label +// { +// } +//} diff --git a/Common.GLib.WinControls/GLib.Controls.Web/LinkButton.cs b/Common.GLib.WinControls/GLib.Controls.Web/LinkButton.cs new file mode 100644 index 0000000..ac0a81b --- /dev/null +++ b/Common.GLib.WinControls/GLib.Controls.Web/LinkButton.cs @@ -0,0 +1,8 @@ +//using System.Web.UI.WebControls; + +//namespace GLib.Controls.Web +//{ +// public class LinkButton : System.Web.UI.WebControls.LinkButton +// { +// } +//} diff --git a/Common.GLib.WinControls/GLib.Controls.Web/ListBox.cs b/Common.GLib.WinControls/GLib.Controls.Web/ListBox.cs new file mode 100644 index 0000000..667b455 --- /dev/null +++ b/Common.GLib.WinControls/GLib.Controls.Web/ListBox.cs @@ -0,0 +1,13 @@ +//using System.Web.UI.WebControls; + +//namespace GLib.Controls.Web +//{ +// public class ListBox : System.Web.UI.WebControls.ListBox +// { +// public ListBox() +// { +// DataValueField = ControlsConfig.Controls_DataValueField; +// DataTextField = ControlsConfig.Controls_DataTextField; +// } +// } +//} diff --git a/Common.GLib.WinControls/GLib.Controls.Web/ListView.cs b/Common.GLib.WinControls/GLib.Controls.Web/ListView.cs new file mode 100644 index 0000000..e2cf276 --- /dev/null +++ b/Common.GLib.WinControls/GLib.Controls.Web/ListView.cs @@ -0,0 +1,8 @@ +//using System.Web.UI.WebControls; + +//namespace GLib.Controls.Web +//{ +// public class ListView : System.Web.UI.WebControls.ListView +// { +// } +//} diff --git a/Common.GLib.WinControls/GLib.Controls.Web/Literal.cs b/Common.GLib.WinControls/GLib.Controls.Web/Literal.cs new file mode 100644 index 0000000..af74d54 --- /dev/null +++ b/Common.GLib.WinControls/GLib.Controls.Web/Literal.cs @@ -0,0 +1,8 @@ +//using System.Web.UI.WebControls; + +//namespace GLib.Controls.Web +//{ +// public class Literal : System.Web.UI.WebControls.Literal +// { +// } +//} diff --git a/Common.GLib.WinControls/GLib.Controls.Web/Panel.cs b/Common.GLib.WinControls/GLib.Controls.Web/Panel.cs new file mode 100644 index 0000000..bc77e50 --- /dev/null +++ b/Common.GLib.WinControls/GLib.Controls.Web/Panel.cs @@ -0,0 +1,8 @@ +//using System.Web.UI.WebControls; + +//namespace GLib.Controls.Web +//{ +// public class Panel : System.Web.UI.WebControls.Panel +// { +// } +//} diff --git a/Common.GLib.WinControls/GLib.Controls.Web/PlaceHolder.cs b/Common.GLib.WinControls/GLib.Controls.Web/PlaceHolder.cs new file mode 100644 index 0000000..97515f6 --- /dev/null +++ b/Common.GLib.WinControls/GLib.Controls.Web/PlaceHolder.cs @@ -0,0 +1,8 @@ +//using System.Web.UI.WebControls; + +//namespace GLib.Controls.Web +//{ +// public class PlaceHolder : System.Web.UI.WebControls.PlaceHolder +// { +// } +//} diff --git a/Common.GLib.WinControls/GLib.Controls.Web/RadioButton.cs b/Common.GLib.WinControls/GLib.Controls.Web/RadioButton.cs new file mode 100644 index 0000000..baf418e --- /dev/null +++ b/Common.GLib.WinControls/GLib.Controls.Web/RadioButton.cs @@ -0,0 +1,8 @@ +//using System.Web.UI.WebControls; + +//namespace GLib.Controls.Web +//{ +// public class RadioButton : System.Web.UI.WebControls.RadioButton +// { +// } +//} diff --git a/Common.GLib.WinControls/GLib.Controls.Web/RadioButtonList.cs b/Common.GLib.WinControls/GLib.Controls.Web/RadioButtonList.cs new file mode 100644 index 0000000..f661398 --- /dev/null +++ b/Common.GLib.WinControls/GLib.Controls.Web/RadioButtonList.cs @@ -0,0 +1,13 @@ +//using System.Web.UI.WebControls; + +//namespace GLib.Controls.Web +//{ +// public class RadioButtonList : System.Web.UI.WebControls.RadioButtonList +// { +// public RadioButtonList() +// { +// DataValueField = ControlsConfig.Controls_DataValueField; +// DataTextField = ControlsConfig.Controls_DataTextField; +// } +// } +//} diff --git a/Common.GLib.WinControls/GLib.Controls.Web/TextBox.cs b/Common.GLib.WinControls/GLib.Controls.Web/TextBox.cs new file mode 100644 index 0000000..84a193c --- /dev/null +++ b/Common.GLib.WinControls/GLib.Controls.Web/TextBox.cs @@ -0,0 +1,8 @@ +//using System.Web.UI.WebControls; + +//namespace GLib.Controls.Web +//{ +// public class TextBox : System.Web.UI.WebControls.TextBox +// { +// } +//} diff --git a/Common.GLib.WinControls/GLib/DebugEx.cs b/Common.GLib.WinControls/GLib/DebugEx.cs new file mode 100644 index 0000000..02df780 --- /dev/null +++ b/Common.GLib.WinControls/GLib/DebugEx.cs @@ -0,0 +1,131 @@ +using System; +using System.IO; +using System.Reflection; +using System.Text; +using System.Threading; +using System.Windows.Forms; + +namespace GLib +{ + public static class DebugEx + { + private static string _appName = ""; + + private static Action _unhandledExceptionCallBack = null; + + private static bool _alertExceptionMsg = false; + + public static string LogPath = Application.StartupPath + "\\log\\"; + + public static string Version = Assembly.GetExecutingAssembly().GetName().Version.ToString(); + + public static event Action EvtTrace; + + public static void Trace(string flag, string msg) + { + string text = $"{flag}___{msg}"; + Console.WriteLine(text); + if (EvtTrace != null) + { + EvtTrace(text); + } + } + + public static void RegisterUnHandldException() + { + RegisterUnHandldException(Application.ProductName, null, alertExceptionMsg: true); + } + + public static void RegisterUnHandldException(string appName, Action unhandledExceptionCallBack, bool alertExceptionMsg = false) + { + _appName = appName; + _alertExceptionMsg = alertExceptionMsg; + _unhandledExceptionCallBack = unhandledExceptionCallBack; + Application.ThreadException += Application_ThreadException; + AppDomain.CurrentDomain.UnhandledException += CurrentDomain_UnhandledException; + } + + private static void CurrentDomain_UnhandledException(object sender, UnhandledExceptionEventArgs e) + { + OnFatalException(e.ExceptionObject as Exception); + if (e.IsTerminating && _unhandledExceptionCallBack != null) + { + _unhandledExceptionCallBack(e); + } + } + + private static void Application_ThreadException(object sender, ThreadExceptionEventArgs e) + { + OnFatalException(e.Exception); + } + + public static void OnFatalException(Exception ex, bool isEnd = false) + { + StringBuilder stringBuilder = new StringBuilder(); + string text = ""; + string version = Version; + text = $"{_appName} {version} {DateTime.Now}"; + if (isEnd) + { + text = string.Format("=================致命错误==================\r\n{0} {1}", _appName, ""); + } + stringBuilder.AppendLine(text); + stringBuilder.AppendLine(GetErrorString(ex)); + WriteLog(stringBuilder.ToString()); + string text2 = $"{text}出现一个未处理的异常\r\n请将程序安装目录下的日志反馈给软件提供商。\r\n详细信息:{ex.Message + ex.StackTrace}\r\n发生时间:{DateTime.Now}"; + if (!_alertExceptionMsg) + { + } + } + + public static string GetLog(Exception ex, bool isEnd = false) + { + StringBuilder stringBuilder = new StringBuilder(); + string text = ""; + string arg = Assembly.GetExecutingAssembly().GetName().Version.ToString(); + text = $"{_appName} {arg} {DateTime.Now}"; + if (isEnd) + { + text = string.Format("=================致命错误==================\r\n{0} {1}", _appName, ""); + } + stringBuilder.AppendLine(text); + stringBuilder.AppendLine(GetErrorString(ex)); + return stringBuilder.ToString(); + } + + public static void WriteLog(string msg) + { + string text = LogPath.ToSystemPath(); + if (!Directory.Exists(text)) + { + Directory.CreateDirectory(text); + } + string path = string.Format("{0}\\Log_{1}.txt", text, DateTime.Now.ToString("yyyy-MM-dd")).ToSystemPath(); + File.AppendAllText(path, msg + "\r\n", Encoding.UTF8); + } + + private static string GetErrorString(Exception ex, string pleft = "") + { + StringBuilder stringBuilder = new StringBuilder(); + stringBuilder.AppendLine(pleft + ex.Message); + stringBuilder.AppendLine(pleft + ex.GetType().Name); + stringBuilder.AppendLine(pleft + ex.StackTrace); + if (ex.InnerException != null) + { + stringBuilder.AppendLine("---------------------------------------------->"); + stringBuilder.AppendLine(GetErrorString(ex.InnerException, pleft + " ")); + } + return stringBuilder.ToString(); + } + + public static string ToSystemPath(this string path) + { + if (Environment.OSVersion.Platform == PlatformID.Unix) + { + return path.Replace("\\", "/"); + } + return path.Replace("/", "\\"); + } + } + +} diff --git a/Common.GLib.WinControls/RegistryHelper.cs b/Common.GLib.WinControls/RegistryHelper.cs new file mode 100644 index 0000000..54aa27b --- /dev/null +++ b/Common.GLib.WinControls/RegistryHelper.cs @@ -0,0 +1,81 @@ +using Microsoft.Win32; +using System; +using System.Diagnostics; +using System.Windows.Forms; + +public class RegistryHelper +{ + public static bool ConfigAutoStart(bool isAutoStart, string[] args) + { + try + { + string processName = Process.GetCurrentProcess().ProcessName; + RegistryKey registryKey = null; + using (registryKey = OpenKeyForWrite("SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Run")) + { + if (registryKey == null) + { + return false; + } + string text = $"\"{Application.ExecutablePath}\""; + for (int i = 0; i < args.Length; i++) + { + text = ((i != 2) ? (text + " " + args[i]) : (text + " " + $"\"{args[i]}\"")); + } + if (isAutoStart) + { + registryKey.SetValue(processName, text); + } + else + { + registryKey.DeleteValue(processName, throwOnMissingValue: false); + } + registryKey.Close(); + return true; + } + } + catch (Exception) + { + return false; + } + } + + public static RegistryKey OpenKeyForWrite(string subKey) + { + return OpenKeyForWrite(Registry.LocalMachine, subKey); + } + + public static RegistryKey OpenKeyForWrite(RegistryKey key, string subKey) + { + RegistryKey registryKey = null; + registryKey = key.OpenSubKey(subKey, writable: true); + if (registryKey == null) + { + registryKey = key.CreateSubKey(subKey); + } + return registryKey; + } + + public static void WriteAutoLoginWindowRegistryKey(bool isAutoLogin, string defaultUserName, string defaultPassword) + { + try + { + RegistryKey registryKey = Registry.LocalMachine.OpenSubKey("SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Winlogon", writable: true); + if (isAutoLogin) + { + registryKey.SetValue("AutoAdminLogon", "1"); + registryKey.SetValue("DefaultUserName", defaultUserName); + registryKey.SetValue("DefaultPassword", defaultPassword); + } + else + { + registryKey.SetValue("AutoAdminLogon", "0"); + registryKey.SetValue("DefaultPassword", string.Empty); + } + registryKey.Close(); + } + catch (Exception) + { + } + } +} diff --git a/Common.GLib.WinControls/Watchdog.cs b/Common.GLib.WinControls/Watchdog.cs new file mode 100644 index 0000000..b0a9479 --- /dev/null +++ b/Common.GLib.WinControls/Watchdog.cs @@ -0,0 +1,236 @@ +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.IO; +using System.Linq; +using System.Runtime.InteropServices; +using System.Text; +using System.Threading; +using System.Windows.Forms; + +public static class Watchdog +{ + private static void Application_ThreadException(object sender, ThreadExceptionEventArgs e) + { + OnFatalException(e.Exception); + } + + private static int CheckActive(string appName) + { + int num = 0; + Process[] processes = Process.GetProcesses(); + foreach (Process process in processes) + { + if (process.ProcessName == appName) + { + num++; + } + } + return num; + } + + private static void CurrentDomain_UnhandledException(object sender, UnhandledExceptionEventArgs e) + { + OnFatalException(e.ExceptionObject as Exception); + } + + [DllImport("user32.dll", CharSet = CharSet.Unicode)] + public static extern IntPtr FindWindow(string lpClassName, string lpWindowName); + + [DllImport("User32.dll", CharSet = CharSet.Unicode)] + public static extern IntPtr FindWindowEx(IntPtr hwndParent, IntPtr hwndChildAfter, string strClassName, string strWindowName); + + [DllImport("user32.dll")] + private static extern int GetWindowThreadProcessId(IntPtr hWnd, out int ProcessId); + + private static void HideConsoleWindow() + { + Console.Title = Application.ProductName; + IntPtr intPtr = FindWindow("ConsoleWindowClass", Application.ProductName); + if (intPtr != IntPtr.Zero) + { + ShowWindow(intPtr, 0u); + } + } + + private static void KillDApp(string appName) + { + List list = Enumerable.ToList(Enumerable.Select(new string[6] + { + "WerFault.exe", + "dwwin.exe", + "dw20.exe", + "WerFault", + "dwwin", + "dw20" + }, (string p) => p.ToUpper())); + Process[] processes = Process.GetProcesses(); + Process[] array = processes; + foreach (Process process in array) + { + try + { + if (list.Contains(process.ProcessName.ToUpper().Replace(" *32", ""))) + { + Log($"异常进程:{process.ProcessName}"); + process.Kill(); + } + } + catch (Exception) + { + } + } + try + { + IntPtr intPtr = FindWindowEx(IntPtr.Zero, IntPtr.Zero, null, $"{appName}.exe - 应用程序错误"); + if (intPtr != IntPtr.Zero) + { + int ProcessId = 0; + GetWindowThreadProcessId(intPtr, out ProcessId); + if (ProcessId != 0) + { + Process.GetProcessById(ProcessId).Kill(); + Log($"异常窗口 {appName}.exe - 应用程序错误"); + } + } + intPtr = FindWindowEx(IntPtr.Zero, IntPtr.Zero, null, "Microsoft Visual C++ Runtime Library"); + if (intPtr != IntPtr.Zero) + { + int ProcessId2 = 0; + GetWindowThreadProcessId(intPtr, out ProcessId2); + if (ProcessId2 != 0) + { + Process.GetProcessById(ProcessId2).Kill(); + Log($"异常窗口 {appName}.exe - Microsoft Visual C++ Runtime Library"); + } + } + } + catch (Exception) + { + } + } + + private static void KillOtherDog() + { + Process currentProcess = Process.GetCurrentProcess(); + Process[] processes = Process.GetProcesses(); + foreach (Process process in processes) + { + if (process.ProcessName.ToUpper() == currentProcess.ProcessName.ToUpper()) + { + try + { + if (currentProcess.Id != process.Id) + { + process.Kill(); + } + } + catch (Exception) + { + } + } + } + } + + private static void Log(string msg) + { + msg = $"{DateTime.Now} {msg}"; + Console.WriteLine(msg); + string text = Application.StartupPath + "\\Watchdog"; + if (!Directory.Exists(text)) + { + Directory.CreateDirectory(text); + } + File.AppendAllText(string.Format("{0}\\{1}.txt", text, DateTime.Now.ToString("yyyy_MM")), msg + "\r\n"); + } + + private static void Main(string[] args) + { + try + { + RegisterUnHandldException(); + HideConsoleWindow(); + string text = args[0]; + string text2 = args[1]; + string text3 = args[2]; + int num = int.Parse(args[3]); + string text4 = args[4]; + string text5 = args[5]; + string text6 = (args.Length > 6) ? args[6] : null; + string text7 = (args.Length > 7) ? args[7] : null; + Console.WriteLine(string.Format("{0} {1} {2} {3} {4} {5} {6}", text, text2, text3, num, text4, text5, text6, text7)); + if (!(text == "0")) + { + RegistryHelper.ConfigAutoStart(text4 == "1", args); + KillOtherDog(); + DateTime now = DateTime.Now; + while (true) + { + bool flag = true; + KillDApp(text2); + if (CheckActive(text2) > 0) + { + now = DateTime.Now; + } + if (now.AddSeconds(num) < DateTime.Now) + { + StartApp(text2, text3); + now = DateTime.Now; + } + Thread.Sleep(1000); + } + } + RegistryHelper.ConfigAutoStart(isAutoStart: false, args); + KillOtherDog(); + } + catch (Exception ex) + { + Console.WriteLine(ex.ToString()); + Console.Read(); + } + } + + private static void OnFatalException(Exception ex) + { + StringBuilder stringBuilder = new StringBuilder(); + string value = string.Format("{0} {1}", "Watchdog", ""); + stringBuilder.AppendLine(value); + stringBuilder.AppendLine(ex.Message); + stringBuilder.AppendLine(ex.GetType().Name); + stringBuilder.AppendLine(ex.StackTrace); + Log(stringBuilder.ToString()); + } + + private static void RegisterUnHandldException() + { + Application.ThreadException += Application_ThreadException; + AppDomain.CurrentDomain.UnhandledException += CurrentDomain_UnhandledException; + } + + [DllImport("user32.dll")] + public static extern bool ShowWindow(IntPtr hWnd, uint nCmdShow); + + private static void StartApp(string appName, string exe) + { + try + { + int num = CheckActive(appName); + Log($"尝试启动 {appName} 路径:{exe}"); + Directory.SetCurrentDirectory(new FileInfo(exe).Directory.ToString()); + Process.Start(exe); + if (CheckActive(appName) > num) + { + Log($"启动成功 {appName} 路径:{exe}"); + } + else + { + Log($"启动失败 {appName} 路径:{exe}"); + } + Thread.Sleep(3000); + } + catch (Exception arg) + { + Log($"启动异常 {appName} 路径:{exe} \r\n异常信息 {arg}"); + } + } +} diff --git a/Common.GLib/AXLib.Utility/Action.cs b/Common.GLib/AXLib.Utility/Action.cs new file mode 100644 index 0000000..dcf7b14 --- /dev/null +++ b/Common.GLib/AXLib.Utility/Action.cs @@ -0,0 +1,22 @@ +using System; + +namespace AXLib.Utility +{ + public class Action : IAction + { + private System.Action _action = null; + + public Action(System.Action action) + { + _action = action; + } + + public void invoke(T t) + { + if (_action != null) + { + _action(t); + } + } + } +} diff --git a/Common.GLib/AXLib.Utility/Callback.cs b/Common.GLib/AXLib.Utility/Callback.cs new file mode 100644 index 0000000..ed764c7 --- /dev/null +++ b/Common.GLib/AXLib.Utility/Callback.cs @@ -0,0 +1,22 @@ +using System; + +namespace AXLib.Utility +{ + public class Callback : ICallback + { + private Action _action = null; + + public Callback(Action action) + { + _action = action; + } + + public void invoke() + { + if (_action != null) + { + _action(); + } + } + } +} diff --git a/Common.GLib/AXLib.Utility/IAction.cs b/Common.GLib/AXLib.Utility/IAction.cs new file mode 100644 index 0000000..7762efa --- /dev/null +++ b/Common.GLib/AXLib.Utility/IAction.cs @@ -0,0 +1,7 @@ +namespace AXLib.Utility +{ + public interface IAction + { + void invoke(T t); + } +} diff --git a/Common.GLib/AXLib.Utility/ICallback.cs b/Common.GLib/AXLib.Utility/ICallback.cs new file mode 100644 index 0000000..d036c8a --- /dev/null +++ b/Common.GLib/AXLib.Utility/ICallback.cs @@ -0,0 +1,7 @@ +namespace AXLib.Utility +{ + public interface ICallback + { + void invoke(); + } +} diff --git a/Common.GLib/Common.GLib.csproj b/Common.GLib/Common.GLib.csproj new file mode 100644 index 0000000..7882e1c --- /dev/null +++ b/Common.GLib/Common.GLib.csproj @@ -0,0 +1,22 @@ + + + Library + 8.0 + false + GLib + Common.GLib + netstandard2.0 + true + + + + TRACE;DEBUG;NETCOREAPP3_1 + + + + + + + + + \ No newline at end of file diff --git a/Common.GLib/GLib.AXLib.Utility/ALog.cs b/Common.GLib/GLib.AXLib.Utility/ALog.cs new file mode 100644 index 0000000..453c94a --- /dev/null +++ b/Common.GLib/GLib.AXLib.Utility/ALog.cs @@ -0,0 +1,109 @@ +using System; + +namespace GLib.AXLib.Utility +{ + public class ALog + { + public bool Enabled; + + public bool EnabledT; + + public bool EnabledI; + + public bool EnabledD; + + public bool EnabledE; + + public string Tag; + + private ALog(string tag) + { + Tag = tag; + Enabled = (EnabledT = (EnabledI = (EnabledD = (EnabledE = true)))); + } + + public static ALog Create(string tag) + { + return new ALog(tag); + } + + public static ALog Create(Type type) + { + return new ALog(type.Name); + } + + private void Print(string str) + { + Console.WriteLine(str); + } + + private void Print(Exception e) + { + Console.WriteLine(e.ToString()); + } + + public void I(string format, params string[] args) + { + if (Enabled && EnabledI) + { + Print(string.Format(format, args)); + } + } + + public void I(Exception e) + { + if (Enabled && EnabledI) + { + Print(e); + } + } + + public void T(string format, params string[] args) + { + if (Enabled && EnabledT) + { + Print(string.Format(format, args)); + } + } + + public void T(Exception e) + { + if (Enabled && EnabledT) + { + Print(e); + } + } + + public void D(string format, params string[] args) + { + if (Enabled && EnabledD) + { + Print(string.Format(format, args)); + } + } + + public void D(Exception e) + { + if (Enabled && EnabledD) + { + Print(e); + } + } + + public void E(string format, params string[] args) + { + if (Enabled && EnabledE) + { + Print(string.Format(format, args)); + } + } + + public void E(Exception e) + { + if (Enabled && EnabledE) + { + Print(e); + } + } + } +} diff --git a/Common.GLib/GLib.AXLib.Utility/Loop.cs b/Common.GLib/GLib.AXLib.Utility/Loop.cs new file mode 100644 index 0000000..39f0040 --- /dev/null +++ b/Common.GLib/GLib.AXLib.Utility/Loop.cs @@ -0,0 +1,53 @@ +using System; + +namespace GLib.AXLib.Utility +{ + public class Loop + { + private int _interval = 0; + + private Action _callback = null; + + private Action _error = null; + + private bool _isRuning = false; + + public Guid Key + { + get; + private set; + } + + public int Interval => _interval; + + public Loop(int interval, Action callback) + : this(interval, callback, null) + { + } + + public Loop(int interval, Action callback, Action error) + { + _interval = interval; + _callback = callback; + _error = error; + } + + public void Start() + { + if (!_isRuning) + { + _isRuning = true; + Key = ThreadEx.NewTimer(_interval, _callback, _error); + } + } + + public void Stop() + { + if (_isRuning) + { + _isRuning = false; + ThreadEx.FreeTimer(Key); + } + } + } +} diff --git a/Common.GLib/GLib.AXLib.Utility/ObjectPool.cs b/Common.GLib/GLib.AXLib.Utility/ObjectPool.cs new file mode 100644 index 0000000..fc9f877 --- /dev/null +++ b/Common.GLib/GLib.AXLib.Utility/ObjectPool.cs @@ -0,0 +1,154 @@ +using GLib.GeneralModel; +using System; +using System.Collections.Generic; + +namespace GLib.AXLib.Utility +{ + public class ObjectPool + { + public class Item + { + private int _refCount = 0; + + private object _lockObj = new object(); + + private ObjectPool _control = null; + + public T Object + { + get; + private set; + } + + public Item(ObjectPool control, T @object) + { + Object = @object; + _control = control; + } + + public void AddRef() + { + lock (_lockObj) + { + _refCount++; + if (_refCount > 1) + { + throw new Exception(); + } + } + } + + public void DelRef() + { + lock (_lockObj) + { + _refCount--; + if (_refCount < 0) + { + throw new Exception(); + } + if (_refCount == 0) + { + _control.ReleaseItem(this); + } + } + } + } + + private int _min = 0; + + private int _max = 0; + + private int _count = 0; + + private AQueue _qIdle = new AQueue(); + + private List _listUsed = new List(); + + private Func _getObjectItemCallback = null; + + public ObjectPool(int count, Func getObjectItemCallback) + : this(count, count, getObjectItemCallback) + { + } + + public ObjectPool(int min, int max, Func getObjectItemCallback) + { + _min = min; + _max = max; + _getObjectItemCallback = getObjectItemCallback; + Init(); + } + + public ObjectPool(T[] arr) + { + _min = arr.Length; + _max = arr.Length; + lock (_qIdle) + { + foreach (T @object in arr) + { + Item item = new Item(this, @object); + _qIdle.Enqueue(item); + _count++; + } + } + } + + private void Init() + { + for (int i = 0; i < _min; i++) + { + AddItem(); + } + } + + private void AddItem() + { + lock (_qIdle) + { + Item item = new Item(this, _getObjectItemCallback()); + _qIdle.Enqueue(item); + _count++; + } + } + + public Item AllowItem() + { + lock (_qIdle) + { + if (_qIdle.Count > 0) + { + Item item = _qIdle.Dequeue(); + item.AddRef(); + lock (_listUsed) + { + if (!_listUsed.Contains(item)) + { + _listUsed.Add(item); + } + } + return item; + } + if (_count < _max) + { + AddItem(); + return AllowItem(); + } + return null; + } + } + + public void ReleaseItem(Item item) + { + lock (_qIdle) + { + lock (_listUsed) + { + _listUsed.Remove(item); + } + _qIdle.Enqueue(item); + } + } + } +} diff --git a/Common.GLib/GLib.AXLib.Utility/RuntimeExceptionEx.cs b/Common.GLib/GLib.AXLib.Utility/RuntimeExceptionEx.cs new file mode 100644 index 0000000..dd05e44 --- /dev/null +++ b/Common.GLib/GLib.AXLib.Utility/RuntimeExceptionEx.cs @@ -0,0 +1,62 @@ +using System; + +namespace GLib.AXLib.Utility +{ + public class RuntimeExceptionEx : Exception + { + private bool _setMsged = false; + + public new string Message = null; + + public bool CanCancel = false; + + public string StackTraceString = ""; + + public RuntimeExceptionEx(string msg) + : base(msg) + { + SetStackTraceString(); + } + + public RuntimeExceptionEx(Exception e) + : base(e.Message, e) + { + SetStackTraceString(); + } + + public RuntimeExceptionEx(string msg, Exception e) + : base(msg, e) + { + } + + private void SetStackTraceString() + { + StackTraceString = ToString(); + } + + public static string GetStackTraceString(Exception e) + { + return GetStackTraceString(e, ""); + } + + public static string GetStackTraceString(Exception e, string span) + { + return e?.ToString(); + } + + public static void PrintException(Exception e) + { + Console.WriteLine("PrintException", GetStackTraceString(e)); + } + + public static RuntimeExceptionEx Create(Exception e) + { + return new RuntimeExceptionEx(e); + } + + public static RuntimeExceptionEx Create(string msg) + { + return new RuntimeExceptionEx(msg); + } + } +} diff --git a/Common.GLib/GLib.AXLib.Utility/ThreadEx.cs b/Common.GLib/GLib.AXLib.Utility/ThreadEx.cs new file mode 100644 index 0000000..e5595ae --- /dev/null +++ b/Common.GLib/GLib.AXLib.Utility/ThreadEx.cs @@ -0,0 +1,554 @@ +using GLib.GeneralModel; +using System; +using System.Collections.Generic; +using System.Threading; + +namespace GLib.AXLib.Utility +{ + public class ThreadEx + { + private class TimerExecuter + { + private bool _isworking = false; + + private Semaphore _semaphore = new Semaphore(0, 1); + + private TimerInfo _timerInfo; + + private Thread _loopThread = null; + + private Action _completed; + + private bool _rerun = false; + + private object _syncObj = new object(); + + public bool IsRuning + { + get; + private set; + } + + public long CompleteTime + { + get; + private set; + } + + public Thread Thread => _loopThread; + + public TimerExecuter(Action completed) + { + _completed = completed; + } + + public void Run(TimerInfo info) + { + if (!_isworking) + { + throw new Exception("status error"); + } + if (IsRuning) + { + throw new Exception("status error"); + } + _timerInfo = info; + _timerInfo.TimerThread = this; + if (!_DEBUG) + { + _semaphore.Release(1); + } + } + + public void ReRun(TimerInfo info) + { + if (!_isworking) + { + throw new Exception("status error"); + } + if (IsRuning) + { + throw new Exception("status error"); + } + _rerun = true; + _timerInfo = info; + _timerInfo.TimerThread = this; + } + + public void Start() + { + if (!_isworking) + { + _isworking = true; + _loopThread = ThreadCall(Loop); + } + } + + public void Stop() + { + if (_isworking) + { + _isworking = false; + ThreadStop(_loopThread); + } + } + + public void Reset() + { + if (_isworking) + { + _loopThread.Abort(); + _loopThread.Join(10); + _semaphore.Close(); + _semaphore = new Semaphore(0, 1); + if (_timerInfo != null && _timerInfo.TimerThread != null) + { + _timerInfo.TimerThread = null; + } + _timerInfo = null; + IsRuning = false; + _loopThread = ThreadCall(Loop); + ThreadReset(this); + } + } + + private void Loop() + { + Loop(null); + } + + private void Loop(object obj) + { + while (_isworking) + { + if (_DEBUG) + { + if (_timerInfo == null) + { + Thread.Sleep(5); + continue; + } + } + else if (!_rerun) + { + _semaphore.WaitOne(); + } + _rerun = false; + IsRuning = true; + Call(); + IsRuning = false; + OnCompleted(); + CompleteTime = TickCount; + } + } + + private void Call() + { + TimerInfo timerInfo = _timerInfo; + object syncObject = default(object); + try + { + bool lockTaken = false; + try + { + Monitor.Enter(syncObject = timerInfo.SyncObject, ref lockTaken); + timerInfo.IsRuning = true; + timerInfo.IsReady = false; + } + finally + { + if (lockTaken) + { + Monitor.Exit(syncObject); + } + } + timerInfo.LastBeginTime = TickCount; + timerInfo.Callback(); + timerInfo.LastEndTime = TickCount; + _timerInfo = null; + } + catch (Exception ex) + { + if (!(timerInfo?.IsFree ?? true)) + { + timerInfo.IsError = true; + timerInfo.Error = ex; + timerInfo.LastEndTime = TickCount; + OnError(ex); + } + _timerInfo = null; + } + finally + { + if (!(timerInfo?.IsFree ?? true)) + { + bool lockTaken2 = false; + try + { + Monitor.Enter(syncObject = timerInfo.SyncObject, ref lockTaken2); + timerInfo.IsRuning = false; + timerInfo.TimerThread = null; + } + finally + { + if (lockTaken2) + { + Monitor.Exit(syncObject); + } + } + } + } + } + + private void OnCompleted() + { + _completed(this); + } + + private void OnError(Exception e) + { + if (_timerInfo.ErrorHandle != null) + { + _timerInfo.ErrorHandle.BeginInvoke(e, null, null); + } + FreeTimer(_timerInfo.Key); + } + } + + private class TimerInfo + { + public Guid Key; + + public long LastBeginTime; + + public long LastEndTime; + + public string Name; + + public Action Callback; + + public int Interval; + + public bool IsReady; + + public bool IsRuning; + + public bool IsError; + + public bool IsFree; + + public Exception Error; + + public Action ErrorHandle; + + public object SyncObject = new object(); + + public TimerExecuter TimerThread; + } + + private static bool _DEBUG = false; + + private static int _maxThread = 400; + + private static bool _runing = false; + + private static Dictionary _dicTimers = new Dictionary(); + + private static AQueue _queueTimers = new AQueue(); + + private static AQueue _queueIdleThreads = new AQueue(); + + private static AQueue _queueCompleteThreads = new AQueue(); + + private static List _timerThreads = new List(); + + private static long _lastSystemTick = 0L; + + private static long _TickStart = 0L; + + private static long _TickCount = 0L; + + public static long TickCount + { + get + { + if (_TickCount == 0) + { + _TickCount = DateTime.Now.Ticks / 10000; + } + if (_lastSystemTick == Environment.TickCount) + { + return _TickCount; + } + _lastSystemTick = Environment.TickCount; + _TickCount = DateTime.Now.Ticks / 10000 - _TickStart; + return _TickCount; + } + } + + public static Thread Call(Action action, string name) + { + Thread thread = new Thread(action.Invoke); + if (name != null) + { + thread.Name = name; + } + thread.Start(); + return thread; + } + + public static Thread ThreadCall(Action action) + { + return ThreadCall(action, null); + } + + public static Thread ThreadCall(Action action, string name) + { + return Call(action, name); + } + + public static Loop LoopCall(int interval, Action callback, Action error) + { + Loop loop = new Loop(interval, callback, error); + loop.Start(); + return loop; + } + + public static void PoolCall(Action handle, object value = null) + { + ThreadPool.QueueUserWorkItem(handle.Invoke, value); + } + + public static void ThreadStop(Thread thread) + { + Stop(thread); + } + + public static void ThreadStop(Thread thread, object lockObj, int time) + { + bool flag = false; + try + { + flag = Monitor.TryEnter(lockObj, time); + } + finally + { + if (flag) + { + Monitor.Exit(lockObj); + } + } + Stop(thread); + } + + public static void LoopStop(Loop loop) + { + loop.Stop(); + } + + public static void Stop(Thread thread) + { + try + { + thread.Abort(); + } + catch + { + } + } + + public static void Sleep(int ms = 10) + { + Thread.Sleep(ms); + } + + public static Guid NewTimer(int interval, Action callback, Action errorHandle) + { + return NewTimer(interval, callback, null, errorHandle); + } + + public static Guid NewTimer(int interval, Action callback, string name, Action errorHandle) + { + TimerInfo timerInfo = new TimerInfo(); + timerInfo.Interval = interval; + timerInfo.Key = Guid.NewGuid(); + timerInfo.Callback = callback; + timerInfo.ErrorHandle = errorHandle; + timerInfo.IsError = false; + timerInfo.IsReady = false; + timerInfo.IsRuning = false; + timerInfo.Name = name; + TimerInfo timerInfo2 = timerInfo; + NewTimer(timerInfo2); + return timerInfo2.Key; + } + + private static void NewTimer(TimerInfo info) + { + lock (_dicTimers) + { + _dicTimers[info.Key] = info; + if (!_runing) + { + _runing = true; + ThreadCall(Thread1); + ThreadCall(Thread2); + } + } + } + + public static void FreeTimer(Guid key, bool _stopThread = false) + { + TimerInfo timerInfo = null; + lock (_dicTimers) + { + if (_dicTimers.ContainsKey(key)) + { + timerInfo = _dicTimers[key]; + timerInfo.IsFree = true; + _dicTimers.Remove(key); + } + } + if (timerInfo != null && _stopThread) + { + lock (timerInfo.SyncObject) + { + if (timerInfo.TimerThread != null) + { + timerInfo.TimerThread.Reset(); + } + } + } + } + + private static void Thread1() + { + while (true) + { + bool flag = true; + long tickCount = TickCount; + lock (_dicTimers) + { + foreach (TimerInfo value in _dicTimers.Values) + { + lock (value.SyncObject) + { + if (!value.IsReady && !value.IsRuning && tickCount - value.LastEndTime > value.Interval) + { + value.IsReady = true; + _queueTimers.Enqueue(value); + } + } + } + } + long tickCount2 = TickCount; + if (tickCount2 - tickCount < 5) + { + Thread.Sleep(5); + } + } + } + + private static void Thread2() + { + int num = 200; + while (true) + { + bool flag = true; + long tickCount = TickCount; + while (_queueTimers.Count > 0) + { + TimerInfo timerInfo = null; + lock (_queueTimers) + { + if (_queueTimers.Count > 0) + { + TimerInfo timerInfo2 = _queueTimers.Dequeue(); + if (timerInfo2 != null && _dicTimers.ContainsKey(timerInfo2.Key)) + { + timerInfo = timerInfo2; + } + } + } + if (timerInfo == null) + { + continue; + } + TimerExecuter timerExecuter = null; + while (true) + { + flag = true; + timerExecuter = GetIdleThread(); + if (timerExecuter != null) + { + break; + } + Thread.Sleep(1); + } + if (timerInfo == null) + { + throw new Exception("item null"); + } + timerExecuter.Run(timerInfo); + } + long tickCount2 = TickCount; + if (tickCount2 - tickCount < 5) + { + Thread.Sleep(5); + } + } + } + + private static void ThreadCompleted(TimerExecuter executer) + { + _ = _DEBUG; + bool flag = 1 == 0; + lock (_queueCompleteThreads) + { + _queueCompleteThreads.Enqueue(executer); + } + } + + private static void ThreadReset(TimerExecuter executer) + { + lock (_queueCompleteThreads) + { + if (!_queueCompleteThreads.Contains(executer)) + { + _queueCompleteThreads.Enqueue(executer); + } + } + } + + private static TimerExecuter GetIdleThread() + { + if (_queueIdleThreads.Count > 0) + { + return _queueIdleThreads.Dequeue(); + } + while (_queueCompleteThreads.Count > 0) + { + TimerExecuter timerExecuter = _queueCompleteThreads.Peek(); + timerExecuter = _queueCompleteThreads.Dequeue(); + _queueIdleThreads.Enqueue(timerExecuter); + } + if (_queueIdleThreads.Count > 0) + { + return _queueIdleThreads.Dequeue(); + } + if (_timerThreads.Count <= _maxThread) + { + return CreateThread(); + } + return null; + } + + private static TimerExecuter CreateThread() + { + TimerExecuter timerExecuter = new TimerExecuter(ThreadCompleted); + _timerThreads.Add(timerExecuter); + timerExecuter.Start(); + return timerExecuter; + } + } +} diff --git a/Common.GLib/GLib.AXLib.Utility/WaitResult.cs b/Common.GLib/GLib.AXLib.Utility/WaitResult.cs new file mode 100644 index 0000000..be4c442 --- /dev/null +++ b/Common.GLib/GLib.AXLib.Utility/WaitResult.cs @@ -0,0 +1,68 @@ +using System; +using System.Threading; + +namespace GLib.AXLib.Utility +{ + public class WaitResult + { + private bool _isFinish = false; + + private Thread _waitThread = null; + + private object _lockObject = new object(); + + private Semaphore _sp = new Semaphore(0, 1); + + public T Result; + + public void Wait() + { + _waitThread = Thread.CurrentThread; + try + { + lock (_lockObject) + { + _sp.WaitOne(); + } + } + catch (Exception ex) + { + throw ex; + } + } + + public void Wait(long timeout) + { + _waitThread = Thread.CurrentThread; + try + { + lock (_lockObject) + { + _sp.WaitOne((int)timeout); + } + } + catch (Exception ex) + { + throw ex; + } + } + + public void Finish(T result) + { + Result = result; + _isFinish = true; + if (_waitThread != null) + { + lock (_lockObject) + { + _sp.Release(); + } + } + } + + public bool GetIsFinish() + { + return _isFinish; + } + } +} diff --git a/Common.GLib/GLib.Assist/XmlHelper.cs b/Common.GLib/GLib.Assist/XmlHelper.cs new file mode 100644 index 0000000..664ecd2 --- /dev/null +++ b/Common.GLib/GLib.Assist/XmlHelper.cs @@ -0,0 +1,178 @@ +using System; +using System.Collections.Generic; +using System.Xml; +using System.Xml.Linq; +using System.Xml.XPath; + +namespace GLib.Assist +{ + public static class XmlHelper + { + public static string GetXPath(string xeName, string xeAttribute, string xeValue, XmlRange range) + { + string result = null; + switch (range) + { + case XmlRange.All: + result = ((xeAttribute == null || xeValue == null || !(xeAttribute.Trim() != "") || !(xeValue.Trim() != "")) ? ("//" + xeName) : $"//{xeName}[@{xeAttribute}=\"{xeValue}\"]"); + break; + case XmlRange.Root: + result = ((xeAttribute == null || xeValue == null || !(xeAttribute.Trim() != "") || !(xeValue.Trim() != "")) ? ("/" + xeName) : $"/{xeName}[@{xeAttribute}=\"{xeValue}\"]"); + break; + case XmlRange.ThisNode: + result = ((xeAttribute == null || xeValue == null || !(xeAttribute.Trim() != "") || !(xeValue.Trim() != "")) ? (xeName ?? "") : $"{xeName}[@{xeAttribute}=\"{xeValue}\"]"); + break; + } + return result; + } + + public static XmlElement GetFirstXmlElement(string strXML, string xPath) + { + bool flag = false; + XmlDocument xmlDocument = new XmlDocument(); + try + { + xmlDocument.LoadXml(strXML); + flag = true; + } + catch (Exception) + { + throw new ArgumentException("Xml字符串格式错误", "strXML"); + } + if (flag) + { + return GetFirstXmlElement(xmlDocument, xPath); + } + return null; + } + + public static XmlElement GetFirstXmlElement(XmlElement xElement, string name, XmlRange range) + { + XmlDocument xmlDocument = new XmlDocument(); + xmlDocument.LoadXml(xElement.OuterXml); + return GetFirstXmlElement(xmlDocument, name, range); + } + + public static XmlElement GetFirstXmlElement(XmlElement xElement, string xPath) + { + XmlDocument xmlDocument = new XmlDocument(); + xmlDocument.LoadXml(xElement.OuterXml); + return GetFirstXmlElement(xmlDocument, xPath); + } + + public static XmlElement GetFirstXmlElement(XmlDocument xDoc, string name, XmlRange range) + { + string xPath = GetXPath(name, null, null, range); + return GetFirstXmlElement(xDoc, xPath); + } + + public static XmlElement GetFirstXmlElement(XmlDocument xDoc, string xPath) + { + XmlNode xmlNode = xDoc.DocumentElement.SelectSingleNode(xPath); + return (XmlElement)xmlNode; + } + + public static XmlElement GetFirstXmlElement(XmlDocument xDoc, string name, string attribute, string value, XmlRange range) + { + string xPath = GetXPath(name, attribute, value, range); + return GetFirstXmlElement(xDoc, xPath); + } + + public static XmlElement GetFirstXmlElement(XmlDocument xDoc, string name, string attribute, string value) + { + string xPath = GetXPath(name, attribute, value, XmlRange.ThisNode); + return GetFirstXmlElement(xDoc, xPath); + } + + public static XmlNodeList GetXmlNodeList(XmlDocument xDoc, string name, XmlRange range) + { + string xPath = GetXPath(name, null, null, range); + return GetXmlNodeList(xDoc, xPath); + } + + public static XmlNodeList GetXmlNodeList(XmlDocument xDoc, string name, string attribute, string value) + { + string xPath = GetXPath(name, attribute, value, XmlRange.ThisNode); + return GetXmlNodeList(xDoc, xPath); + } + + public static XmlNodeList GetXmlNodeList(XmlDocument xDoc, string name, string attribute, string value, XmlRange range) + { + string xPath = GetXPath(name, attribute, value, range); + return GetXmlNodeList(xDoc, xPath); + } + + public static XmlNodeList GetXmlNodeList(XmlDocument xDoc, string xPath) + { + return xDoc.DocumentElement.SelectNodes(xPath); + } + + public static XElement GetFirstXElement(XElement xElement, string name, XmlRange range) + { + string xPath = GetXPath(name, null, null, range); + return GetFirstXElement(xElement, xPath); + } + + public static XElement GetFirstXElement(XElement xElement, string xPath) + { + return xElement.XPathSelectElement(xPath); + } + + public static XElement GetFirstXElement(XElement xElement, string name, string attribute, string value, XmlRange range) + { + string xPath = GetXPath(name, null, null, range); + return GetFirstXElement(xElement, xPath); + } + + public static IEnumerable GetXElement(XElement xElement, string name, XmlRange range) + { + string xPath = GetXPath(name, null, null, range); + return GetXElement(xElement, xPath); + } + + public static IEnumerable GetXElement(XElement xElement, string xPath) + { + return xElement.XPathSelectElements(xPath); + } + + public static IEnumerable GetXElement(XElement xElement, string name, string attribute, string value, XmlRange range) + { + string xPath = GetXPath(name, null, null, range); + return GetXElement(xElement, xPath); + } + + public static XElement GetFirstXElement(XDocument xDoc, string name, XmlRange range) + { + string xPath = GetXPath(name, null, null, range); + return xDoc.Root.XPathSelectElement(xPath); + } + + public static XElement GetFirstXElement(XDocument xDoc, string xPath) + { + return xDoc.Root.XPathSelectElement(xPath); + } + + public static XElement GetFirstXElement(XDocument xDoc, string name, string attribute, string value, XmlRange range) + { + string xPath = GetXPath(name, null, null, range); + return xDoc.Root.XPathSelectElement(xPath); + } + + public static IEnumerable GetXElement(XDocument xDoc, string name, XmlRange range) + { + string xPath = GetXPath(name, null, null, range); + return xDoc.Root.XPathSelectElements(xPath); + } + + public static IEnumerable GetXElement(XDocument xDoc, string xPath) + { + return xDoc.Root.XPathSelectElements(xPath); + } + + public static IEnumerable GetXElement(XDocument xDoc, string name, string attribute, string value, XmlRange range) + { + string xPath = GetXPath(name, null, null, range); + return xDoc.Root.XPathSelectElements(xPath); + } + } +} diff --git a/Common.GLib/GLib.Assist/XmlRange.cs b/Common.GLib/GLib.Assist/XmlRange.cs new file mode 100644 index 0000000..1062670 --- /dev/null +++ b/Common.GLib/GLib.Assist/XmlRange.cs @@ -0,0 +1,9 @@ +namespace GLib.Assist +{ + public enum XmlRange + { + All = 0, + Root = 1, + ThisNode = 2 + } +} diff --git a/Common.GLib/GLib.Data.Core/DataBaseType.cs b/Common.GLib/GLib.Data.Core/DataBaseType.cs new file mode 100644 index 0000000..d655b15 --- /dev/null +++ b/Common.GLib/GLib.Data.Core/DataBaseType.cs @@ -0,0 +1,10 @@ +namespace GLib.Data.Core +{ + public enum DataBaseType + { + SqlServer = 1, + Access = 2, + MySql = 3, + Oracle = 4 + } +} diff --git a/Common.GLib/GLib.Data.Core/IRepository.cs b/Common.GLib/GLib.Data.Core/IRepository.cs new file mode 100644 index 0000000..7908401 --- /dev/null +++ b/Common.GLib/GLib.Data.Core/IRepository.cs @@ -0,0 +1,66 @@ +using GLib.Data.Entity; +using System; + +namespace GLib.Data.Core +{ + public interface IRepository : IDisposable + { + bool Exists(TL model); + + bool Exists(int id); + + bool Exists(long id); + + bool Exists(string selector); + + bool Exists(string selector, params DBParam[] values); + + int Sum(string selector, string column); + + int Sum(string selector, string column, params DBParam[] values); + + int InsertModel(TL model); + + int[] InsertModelList(TL[] modelList); + + TL GetModel(int id); + + TL GetModel(long id); + + TL GetModel(TL model); + + TL GetModel(string selector, params DBParam[] values); + + TL GetModel(string selector, string colList, params DBParam[] values); + + TL[] GetModelList(); + + TL[] GetModelList(TL model); + + TL[] GetModelList(string selector, params DBParam[] values); + + TL[] GetModelList(string selector, string ordering, params DBParam[] values); + + TL[] GetModelList(string selector, string ordering, string colList, params DBParam[] values); + + TL[] GetModelList(string selector, string ordering, string colList, int pageIndex, int pageSize, params DBParam[] values); + + int GetModelListCount(string selector, params DBParam[] values); + + bool UpdateModel(TL model); + + bool UpdateModel(TL model, string colList); + + bool UpdateModel(TL model, string selector, params DBParam[] values); + + bool UpdateModel(TL model, string colList, string selector, params DBParam[] values); + + bool DeleteModel(int id); + + bool DeleteModel(long id); + + bool DeleteModel(TL model); + + bool Delete(string selector, params DBParam[] values); + } +} diff --git a/Common.GLib/GLib.Data.Core/ISqlCreator.cs b/Common.GLib/GLib.Data.Core/ISqlCreator.cs new file mode 100644 index 0000000..edac4d4 --- /dev/null +++ b/Common.GLib/GLib.Data.Core/ISqlCreator.cs @@ -0,0 +1,30 @@ +using GLib.Data.Entity; +using System; + +namespace GLib.Data.Core +{ + public interface ISqlCreator : IDisposable where TL : ILogicEntity, new() + { + string CreateMaxSql(string selector, string col); + + string CreateCountSql(string selector, string col); + + string CreateSumSql(string selector, string col); + + string CreateInsertSql(TL model, out DBParam[] outparam); + + string CreateUpdateSql(TL model, string colList, string selector, out DBParam[] outparam, params DBParam[] values); + + string CreateDeleteSql(TL model, out DBParam[] outparam); + + string CreateDeleteSql(string selector); + + string CreateModelSql(TL model, out DBParam[] outparam); + + string CreateModelSql(string selector, string colList); + + string CreatePageSql(TL model, out DBParam[] outparam); + + string CreatePageSql(string selector, int pageIndex, int pageSize, string ordering, string colList, params DBParam[] values); + } +} diff --git a/Common.GLib/GLib.Data.Core/Repository.cs b/Common.GLib/GLib.Data.Core/Repository.cs new file mode 100644 index 0000000..49342e2 --- /dev/null +++ b/Common.GLib/GLib.Data.Core/Repository.cs @@ -0,0 +1,594 @@ +using GLib.Data.Entity; +using GLib.Logging; +using System; +using System.Collections.Generic; +using System.Data; +using System.Reflection; + +namespace GLib.Data.Core +{ + public class Repository : IRepository, IDisposable where TL : ILogicEntity, new() + { + private ISqlCreator creator = null; + + private string _dbname = ""; + + private string _PrimaryKey = ""; + + private TL _model = default(TL); + + private int _PageSize = 100; + + private TL Model + { + get + { + if (_model == null) + { + _model = new TL(); + } + return _model; + } + } + + public string DbName + { + get + { + if (string.IsNullOrEmpty(_dbname)) + { + if (Model == null) + { + throw new ArgumentNullException("model is null!"); + } + _dbname = Model.DbName; + } + return _dbname; + } + set + { + _dbname = value; + } + } + + public string PrimaryKey + { + get + { + if (_PrimaryKey == "") + { + if (Model == null) + { + throw new ArgumentNullException("model is null !"); + } + _PrimaryKey = Model.PrimaryKey; + } + return _PrimaryKey; + } + set + { + _PrimaryKey = value; + } + } + + public int MaxID + { + get + { + string strCommand = creator.CreateMaxSql(string.Empty, PrimaryKey); + object obj = SqlHelper.ExecuteScalar(DbName, strCommand, CommandType.Text, null); + if (obj == null) + { + return 0; + } + if (obj.ToString().Trim() == "") + { + return 0; + } + return int.Parse(obj.ToString()); + } + } + + public int PageSize + { + get + { + return _PageSize; + } + set + { + _PageSize = value; + } + } + + public Repository() + { + creator = SqlCreatorFactory.GetSqlCreator(); + } + + protected Repository(string dbName) + : this() + { + _dbname = dbName; + creator = SqlCreatorFactory.GetSqlCreator(); + } + + public virtual bool Exists(TL model) + { + throw new ArgumentNullException("Exists is not implement!"); + } + + public virtual bool Exists(int id) + { + return Exists($"{PrimaryKey}=@0", new DBParam + { + ParamName = PrimaryKey, + ParamDbType = DbType.Int32, + ParamValue = id + }); + } + + public virtual bool Exists(long id) + { + return Exists($"{PrimaryKey}=@0", new DBParam + { + ParamName = PrimaryKey, + ParamDbType = DbType.Int64, + ParamValue = id + }); + } + + public virtual bool Exists(string selector) + { + return Exists(selector, (DBParam[])null); + } + + public virtual bool Exists(string selector, params DBParam[] values) + { + string strCommand = creator.CreateCountSql(selector, string.Empty); + object obj = SqlHelper.ExecuteScalar(DbName, strCommand, CommandType.Text, values); + if (object.Equals(obj, null) || object.Equals(obj, DBNull.Value)) + { + return false; + } + if (Convert.ToInt32(obj) == 0) + { + return false; + } + return true; + } + + public virtual int Sum(string selector, string column) + { + return Sum(selector, column, (DBParam[])null); + } + + public virtual int Sum(string selector, string column, params DBParam[] values) + { + string strCommand = creator.CreateSumSql(selector, column); + object obj = SqlHelper.ExecuteScalar(DbName, strCommand, CommandType.Text, values); + if (object.Equals(obj, null) || object.Equals(obj, DBNull.Value)) + { + return 0; + } + return Convert.ToInt32(obj); + } + + public virtual int InsertModel(TL model) + { + _model = model; + try + { + DBParam[] outparam = null; + string strCommand = creator.CreateInsertSql(model, out outparam); + if (model.IsAutoID) + { + object obj = SqlHelper.ExecuteScalar(DbName, strCommand, CommandType.Text, outparam); + if (SqlHelper.GetDBType() == DataBaseType.Access) + { + return MaxID; + } + if (obj == null || obj == DBNull.Value) + { + return 0; + } + return Convert.ToInt32(obj); + } + return SqlHelper.ExecuteNonQuery(DbName, strCommand, CommandType.Text, outparam); + } + catch (Exception ex) + { + Log log = new Log(); + log.Write(new LogMessage + { + Content = "GLib.Data.Core.Repository. InsertModel(TL model):\r\n " + ex.Message, + Type = MessageType.Error + }); + return 0; + } + } + + public virtual int[] InsertModelList(TL[] modelList) + { + List list = new List(); + foreach (TL model in modelList) + { + int item; + if ((item = InsertModel(model)) > 0) + { + list.Add(item); + } + } + return list.ToArray(); + } + + public virtual TL GetModel(int id) + { + return GetModel($"{PrimaryKey}={id}", string.Empty, (DBParam[])null); + } + + public virtual TL GetModel(long id) + { + return GetModel($"{PrimaryKey}={id}", string.Empty, (DBParam[])null); + } + + public virtual TL GetModel(TL model) + { + try + { + DBParam[] outparam = null; + string strCommand = creator.CreateModelSql(model, out outparam); + model = default(TL); + using (IDataReader dataReader = SqlHelper.ExecuteDataReader(DbName, strCommand, CommandType.Text, outparam)) + { + if (dataReader.Read()) + { + model = GetModel(dataReader); + } + dataReader.Close(); + } + return model; + } + catch (Exception ex) + { + Log log = new Log(); + log.Write(new LogMessage + { + Content = "GLib.Data.Core.Repository. GetModel(String selector, String colList, params DBParam[] values):\r\n " + ex.Message, + Type = MessageType.Error + }); + return default(TL); + } + } + + public virtual TL GetModel(string selector, params DBParam[] values) + { + return GetModel(selector, string.Empty, values); + } + + public virtual TL GetModel(string selector, string colList, params DBParam[] values) + { + try + { + string strCommand = creator.CreateModelSql(selector, colList); + TL result = default(TL); + using (IDataReader dataReader = SqlHelper.ExecuteDataReader(DbName, strCommand, CommandType.Text, values)) + { + if (dataReader.Read()) + { + result = GetModel(dataReader); + } + dataReader.Close(); + } + return result; + } + catch (Exception ex) + { + Log log = new Log(); + log.Write(new LogMessage + { + Content = "GLib.Data.Core.Repository. GetModel(String selector, String colList, params DBParam[] values):\r\n " + ex.Message, + Type = MessageType.Error + }); + return default(TL); + } + } + + public virtual TL GetModel(IDataReader dr) + { + TL val = new TL(); + PropertyInfo[] properties = EntityTypeCache.GetEntityInfo(typeof(TL)).Properties; + PropertyInfo[] array = properties; + foreach (PropertyInfo propertyInfo in array) + { + object[] customAttributes = propertyInfo.GetCustomAttributes(typeof(EntityAttribute), inherit: true); + EntityAttribute entityAttribute = null; + if (customAttributes.Length > 0) + { + entityAttribute = (EntityAttribute)customAttributes[0]; + } + if (entityAttribute != null && entityAttribute.CustomMember) + { + continue; + } + int ordinal; + try + { + ordinal = dr.GetOrdinal(propertyInfo.Name); + } + catch (IndexOutOfRangeException) + { + continue; + } + object value; + if (dr.IsDBNull(ordinal) && EntityHelper.GetDbType(propertyInfo.PropertyType) == DbType.String) + { + value = string.Empty; + } + else + { + if (dr.IsDBNull(ordinal)) + { + continue; + } + value = dr.GetValue(ordinal); + } + propertyInfo.SetValue(val, value, null); + } + return val; + } + + public virtual TL[] GetModelList() + { + return GetModelList(string.Empty, string.Empty, string.Empty, 0, PageSize, (DBParam[])null); + } + + public virtual TL[] GetModelList(TL model) + { + try + { + DBParam[] outparam = null; + string strCommand = creator.CreatePageSql(model, out outparam); + TL[] array = null; + using (IDataReader dr = SqlHelper.ExecuteDataReader(DbName, strCommand, CommandType.Text, outparam)) + { + array = GetModelList(dr); + } + if (array == null) + { + array = new TL[0]; + } + return array; + } + catch (Exception ex) + { + Log log = new Log(); + log.Write(new LogMessage + { + Content = "GLib.Data.Core.Repository.GetModelList(TL model)" + ex.Message, + Type = MessageType.Error + }); + return null; + } + } + + public virtual TL[] GetModelList(string selector, params DBParam[] values) + { + return GetModelList(selector, string.Empty, values); + } + + public virtual TL[] GetModelList(string selector, string ordering, params DBParam[] values) + { + return GetModelList(selector, ordering, string.Empty, values); + } + + public virtual TL[] GetModelList(string selector, string ordering, string colList, params DBParam[] values) + { + return GetModelList(selector, ordering, colList, 0, PageSize, values); + } + + public virtual TL[] GetModelList(string selector, string ordering, string colList, int pageIndex, int pageSize, params DBParam[] values) + { + if (pageIndex <= 0) + { + pageIndex = 1; + } + if (pageSize <= 0) + { + pageSize = PageSize; + } + try + { + string strCommand = creator.CreatePageSql(selector, pageIndex, pageSize, ordering, colList, values); + TL[] array = null; + using (IDataReader dr = SqlHelper.ExecuteDataReader(DbName, strCommand, CommandType.Text, values)) + { + array = GetModelList(dr); + } + if (array == null) + { + array = new TL[0]; + } + return array; + } + catch (Exception ex) + { + Log log = new Log(); + log.Write(new LogMessage + { + Content = "GLib.Data.Core.Repository. GetModelList(String selector, String ordering, String colList, Int32 pageIndex, Int32 pageSize, params DBParam[] values):\r\n " + ex.Message, + Type = MessageType.Error + }); + return null; + } + } + + public virtual PageList GetPageList(string selector, string ordering, string colList, int pageIndex, int pageSize, params DBParam[] values) + { + if (pageIndex <= 0) + { + pageIndex = 1; + } + if (pageSize <= 0) + { + pageSize = PageSize; + } + PageList pageList = new PageList(pageIndex, pageSize, 0); + string str = creator.CreatePageSql(selector, pageIndex, pageSize, ordering, colList, values); + string str2 = creator.CreateCountSql(selector, string.Empty); + try + { + List list = new List(); + using (IDataReader dataReader = SqlHelper.ExecuteDataReader(DbName, str + " " + str2, CommandType.Text, values)) + { + while (dataReader.Read()) + { + list.Add(GetModel(dataReader)); + } + if (!dataReader.IsClosed) + { + dataReader.Close(); + } + } + pageList.TotalCount = GetModelListCount(selector, values); + pageList.AddRange(list); + return pageList; + } + catch (Exception ex) + { + Log log = new Log(); + log.Write(new LogMessage + { + Content = "GLib.Data.Core.Repository.GetPageList(String selector, String ordering, String colList, int pageIndex, int pageSize, params DBParam[] values):\r\n " + ex.Message, + Type = MessageType.Error + }); + return pageList; + } + } + + public virtual TL[] GetModelList(IDataReader dr) + { + List list = new List(); + if (dr != null) + { + while (dr.Read()) + { + list.Add(GetModel(dr)); + } + dr?.Close(); + } + return list.ToArray(); + } + + public virtual int GetModelListCount(string selector, params DBParam[] values) + { + int num = 0; + try + { + string strCommand = creator.CreateCountSql(selector, string.Empty); + return int.Parse(SqlHelper.ExecuteScalar(DbName, strCommand, CommandType.Text, values).ToString()); + } + catch (Exception ex) + { + Log log = new Log(); + log.Write(new LogMessage + { + Content = "GLib.Data.Core.Repository. GetModelListCount(String selector, params DBParam[] values):\r\n " + ex.Message, + Type = MessageType.Error + }); + return 0; + } + } + + public virtual bool UpdateModel(TL model) + { + return UpdateModel(model, string.Empty, string.Empty, (DBParam[])null); + } + + public virtual bool UpdateModel(TL model, string colList) + { + return UpdateModel(model, colList, string.Empty, (DBParam[])null); + } + + public virtual bool UpdateModel(TL model, string selector, params DBParam[] values) + { + return UpdateModel(model, string.Empty, selector, values); + } + + public virtual bool UpdateModel(TL model, string colList, string selector, params DBParam[] values) + { + _model = model; + try + { + DBParam[] outparam = null; + string strCommand = creator.CreateUpdateSql(model, colList, selector, out outparam, values); + return SqlHelper.ExecuteNonQuery(DbName, strCommand, CommandType.Text, outparam) > 0; + } + catch (Exception ex) + { + Log log = new Log(); + log.Write(new LogMessage + { + Content = "GLib.Data.Core.Repository. UpdateModel(TL model, string colList, string selector, params DBParam[] values):\r\n " + ex.Message, + Type = MessageType.Error + }); + return false; + } + } + + public virtual bool DeleteModel(int id) + { + return Delete($"{PrimaryKey}={id}", (DBParam[])null); + } + + public virtual bool DeleteModel(long id) + { + return Delete($"{PrimaryKey}={id}", (DBParam[])null); + } + + public virtual bool DeleteModel(TL model) + { + _model = model; + try + { + DBParam[] outparam = null; + string strCommand = creator.CreateDeleteSql(model, out outparam); + return SqlHelper.ExecuteNonQuery(DbName, strCommand, CommandType.Text, outparam) > 0; + } + catch (Exception ex) + { + Log log = new Log(); + log.Write(new LogMessage + { + Content = "GLib.Data.Core.Repository.Delete(TL model):\r\n " + ex.Message, + Type = MessageType.Error + }); + return false; + } + } + + public virtual bool Delete(string selector, params DBParam[] values) + { + try + { + string strCommand = creator.CreateDeleteSql(selector); + return SqlHelper.ExecuteNonQuery(DbName, strCommand, CommandType.Text, values) > 0; + } + catch (Exception ex) + { + Log log = new Log(); + log.Write(new LogMessage + { + Content = "GLib.Data.Core.Repository.Delete(String selector, params DBParam[] values):\r\n " + ex.Message, + Type = MessageType.Error + }); + return false; + } + } + + public void Dispose() + { + GC.SuppressFinalize(true); + } + } +} diff --git a/Common.GLib/GLib.Data.Core/SqLiteCreator.cs b/Common.GLib/GLib.Data.Core/SqLiteCreator.cs new file mode 100644 index 0000000..d3f8188 --- /dev/null +++ b/Common.GLib/GLib.Data.Core/SqLiteCreator.cs @@ -0,0 +1,419 @@ +using GLib.Data.Entity; +using System; +using System.Collections.Generic; +using System.Reflection; +using System.Text; + +namespace GLib.Data.Core +{ + public class SqLiteCreator : ISqlCreator, IDisposable where TL : ILogicEntity, new() + { + private string _PrimaryKey = ""; + + private string _TableName = ""; + + private TL _model = default(TL); + + private int _PageSize = 100; + + private TL Model + { + get + { + if (_model == null) + { + _model = new TL(); + } + return _model; + } + } + + public string PrimaryKey + { + get + { + if (_PrimaryKey == "") + { + if (Model == null) + { + throw new ArgumentNullException("model is null !"); + } + _PrimaryKey = Model.PrimaryKey; + } + return _PrimaryKey; + } + set + { + _PrimaryKey = value; + } + } + + public virtual string TableName + { + get + { + if (_TableName == "") + { + bool flag = false; + PropertyInfo[] properties = EntityTypeCache.GetEntityInfo(typeof(TL)).Properties; + for (int i = 0; i < properties.Length; i++) + { + if (properties[i].Name.Trim().ToLower() == "TableName".ToLower()) + { + object value = properties[i].GetValue(Model, null); + if (value != null && !string.IsNullOrEmpty(value.ToString())) + { + _TableName = value.ToString(); + flag = true; + break; + } + } + } + if (!flag) + { + _TableName = "[" + typeof(TL).Name + "]"; + } + } + return _TableName; + } + set + { + _TableName = value; + } + } + + public int PageSize + { + get + { + return _PageSize; + } + set + { + _PageSize = value; + } + } + + public string CreateMaxSql(string selector, string col) + { + col = (string.IsNullOrEmpty(col) ? PrimaryKey : col); + StringBuilder stringBuilder = new StringBuilder(); + stringBuilder.Append($"select max({GetSQLFildList(col)}) from {TableName}"); + if (!string.IsNullOrEmpty(selector)) + { + stringBuilder.Append(" where " + selector); + } + return stringBuilder.ToString(); + } + + public string CreateCountSql(string selector, string col) + { + col = (string.IsNullOrEmpty(col) ? "1" : col); + StringBuilder stringBuilder = new StringBuilder(); + stringBuilder.Append($"select count({col}) as TotalCount from {TableName} "); + if (!string.IsNullOrEmpty(selector)) + { + stringBuilder.Append(" where " + selector); + } + return stringBuilder.ToString(); + } + + public string CreateSumSql(string selector, string col) + { + StringBuilder stringBuilder = new StringBuilder(); + stringBuilder.Append($"select sum({GetSQLFildList(col)}) from {TableName} "); + if (!string.IsNullOrEmpty(selector)) + { + stringBuilder.Append(" where " + selector); + } + return stringBuilder.ToString(); + } + + public string CreateInsertSql(TL model, out DBParam[] outparam) + { + StringBuilder stringBuilder = new StringBuilder(); + StringBuilder stringBuilder2 = new StringBuilder(); + stringBuilder.Append($"insert into {TableName}("); + PropertyInfo[] properties = EntityTypeCache.GetEntityInfo(typeof(TL)).Properties; + List list = new List(); + for (int i = 0; i < properties.Length; i++) + { + object[] customAttributes = properties[i].GetCustomAttributes(typeof(EntityAttribute), inherit: true); + EntityAttribute entityAttribute = null; + if (customAttributes.Length > 0) + { + entityAttribute = (EntityAttribute)customAttributes[0]; + } + if (!model.IsAutoID || !(model.PrimaryKey == properties[i].Name) || entityAttribute == null || !entityAttribute.IsDbGenerated) + { + if (properties[i].Name == PrimaryKey && entityAttribute != null && !entityAttribute.IsDbGenerated) + { + stringBuilder.Append("[" + properties[i].Name + "],"); + stringBuilder2.Append("@" + properties[i].Name + ","); + list.Add(new DBParam + { + ParamName = properties[i].Name, + ParamDbType = EntityHelper.GetDbType(properties[i].PropertyType), + ParamValue = EntityHelper.GetTypeDefaultValue(properties[i].GetValue(model, null), EntityHelper.GetDbType(properties[i].PropertyType)) + }); + } + else if (properties[i].Name != PrimaryKey && (entityAttribute == null || (!entityAttribute.IsDbGenerated && !entityAttribute.CustomMember))) + { + stringBuilder.Append("[" + properties[i].Name + "],"); + stringBuilder2.Append("@" + properties[i].Name + ","); + list.Add(new DBParam + { + ParamName = properties[i].Name, + ParamDbType = EntityHelper.GetDbType(properties[i].PropertyType), + ParamValue = EntityHelper.GetTypeDefaultValue(properties[i].GetValue(model, null), EntityHelper.GetDbType(properties[i].PropertyType)) + }); + } + } + } + stringBuilder = stringBuilder.Replace(",", ")", stringBuilder.Length - 1, 1); + stringBuilder2 = stringBuilder2.Replace(",", ")", stringBuilder2.Length - 1, 1); + stringBuilder.Append(" values ("); + stringBuilder.Append(stringBuilder2.ToString() + ";"); + if (model.IsAutoID) + { + stringBuilder.Append($" select ident_current('{TableName}') "); + } + outparam = list.ToArray(); + return stringBuilder.ToString(); + } + + public string CreateUpdateSql(TL model, string colList, string selector, out DBParam[] outparam, params DBParam[] values) + { + StringBuilder stringBuilder = new StringBuilder(); + stringBuilder.Append("update " + TableName + " set "); + PropertyInfo[] properties = EntityTypeCache.GetEntityInfo(typeof(TL)).Properties; + PropertyInfo propertyInfo = null; + List list = new List(); + for (int i = 0; i < properties.Length; i++) + { + object[] customAttributes = properties[i].GetCustomAttributes(typeof(EntityAttribute), inherit: true); + EntityAttribute entityAttribute = null; + if (customAttributes.Length > 0) + { + entityAttribute = (EntityAttribute)customAttributes[0]; + } + if (properties[i].Name == PrimaryKey) + { + propertyInfo = properties[i]; + } + else if (properties[i].Name != PrimaryKey && !(entityAttribute?.CustomMember ?? false) && (string.IsNullOrEmpty(colList) || colList.IndexOf(properties[i].Name.Trim()) >= 0) && !EntityHelper.IsTypeMinValue(properties[i].GetValue(model, null), EntityHelper.GetDbType(properties[i].PropertyType))) + { + stringBuilder.Append("[" + properties[i].Name + "]=@" + properties[i].Name + ","); + list.Add(new DBParam + { + ParamDbType = EntityHelper.GetDbType(properties[i].PropertyType), + ParamName = properties[i].Name, + ParamValue = properties[i].GetValue(model, null) + }); + } + } + stringBuilder = stringBuilder.Replace(",", " ", stringBuilder.Length - 1, 1); + if (!string.IsNullOrEmpty(selector)) + { + stringBuilder.Append(" where 1=1 and " + selector); + if (values != null) + { + for (int i = 0; i < values.Length; i++) + { + list.Insert(i, values[i]); + } + } + } + else + { + stringBuilder.Append(" where [" + PrimaryKey + "]=@" + PrimaryKey); + list.Add(new DBParam + { + ParamDbType = EntityHelper.GetDbType(propertyInfo.PropertyType), + ParamName = propertyInfo.Name, + ParamValue = propertyInfo.GetValue(model, null) + }); + } + outparam = list.ToArray(); + return stringBuilder.ToString(); + } + + public string CreateDeleteSql(TL model, out DBParam[] outparam) + { + StringBuilder stringBuilder = new StringBuilder(); + PropertyInfo[] properties = EntityTypeCache.GetEntityInfo(typeof(TL)).Properties; + PropertyInfo propertyInfo = null; + List list = new List(); + for (int i = 0; i < properties.Length; i++) + { + object[] customAttributes = properties[i].GetCustomAttributes(typeof(EntityAttribute), inherit: true); + EntityAttribute entityAttribute = null; + if (customAttributes.Length > 0) + { + entityAttribute = (EntityAttribute)customAttributes[0]; + } + if (properties[i].Name == PrimaryKey) + { + propertyInfo = properties[i]; + } + } + stringBuilder.Append(" " + PrimaryKey + "=@" + PrimaryKey); + list.Add(new DBParam + { + ParamDbType = EntityHelper.GetDbType(propertyInfo.PropertyType), + ParamName = propertyInfo.Name, + ParamValue = propertyInfo.GetValue(model, null) + }); + outparam = list.ToArray(); + return CreateDeleteSql(stringBuilder.ToString()); + } + + public string CreateDeleteSql(string selector) + { + StringBuilder stringBuilder = new StringBuilder(); + stringBuilder.Append("delete from " + TableName); + if (!string.IsNullOrEmpty(selector)) + { + stringBuilder.Append(" where " + selector); + } + return stringBuilder.ToString(); + } + + public string CreateModelSql(TL model, out DBParam[] outparam) + { + PropertyInfo[] properties = EntityTypeCache.GetEntityInfo(typeof(TL)).Properties; + List list = new List(); + for (int i = 0; i < properties.Length; i++) + { + if (properties[i].Name == PrimaryKey) + { + list.Add(new DBParam + { + ParamName = properties[i].Name, + ParamDbType = EntityHelper.GetDbType(properties[i].PropertyType), + ParamValue = properties[i].GetValue(model, null) + }); + break; + } + } + outparam = list.ToArray(); + return CreateModelSql(string.Format("{0}=@{0}", PrimaryKey), string.Empty); + } + + public string CreateModelSql(string selector, string colList) + { + StringBuilder stringBuilder = new StringBuilder(); + if (string.IsNullOrEmpty(colList)) + { + stringBuilder.Append(string.Format("select top 1 {0} from {1}", "*", TableName)); + } + else + { + stringBuilder.Append(string.Format("select top 1 {0} from {1}", colList.Replace("new", ""), TableName)); + } + if (!string.IsNullOrEmpty(selector)) + { + stringBuilder.Append(" where " + selector); + } + return stringBuilder.ToString(); + } + + public string CreatePageSql(TL model, out DBParam[] outparam) + { + PropertyInfo[] properties = EntityTypeCache.GetEntityInfo(typeof(TL)).Properties; + List list = new List(); + for (int i = 0; i < properties.Length; i++) + { + if (properties[i].Name == PrimaryKey) + { + list.Add(new DBParam + { + ParamName = properties[i].Name, + ParamDbType = EntityHelper.GetDbType(properties[i].PropertyType), + ParamValue = properties[i].GetValue(model, null) + }); + break; + } + } + outparam = list.ToArray(); + return CreatePageSql(string.Format("{0}=@{0}", PrimaryKey), 0, PageSize, string.Empty, string.Empty, outparam); + } + + public string CreatePageSql(string selector, int pageIndex, int pageSize, string ordering, string colList, params DBParam[] values) + { + pageIndex = ((pageIndex <= 0) ? 1 : pageIndex); + if (pageSize == 0) + { + pageSize = PageSize; + } + string text = ""; + if (string.IsNullOrEmpty(colList) || colList == "*") + { + PropertyInfo[] properties = EntityTypeCache.GetEntityInfo(typeof(TL)).Properties; + PropertyInfo[] array = properties; + foreach (PropertyInfo propertyInfo in array) + { + object[] customAttributes = propertyInfo.GetCustomAttributes(typeof(EntityAttribute), inherit: true); + EntityAttribute entityAttribute = null; + if (customAttributes.Length > 0) + { + entityAttribute = (EntityAttribute)customAttributes[0]; + } + if (!(entityAttribute?.CustomMember ?? false)) + { + text = text + "[" + propertyInfo.Name + "],"; + } + } + text = text.Substring(0, text.Length - 1); + } + else + { + text = GetSQLFildList(colList); + } + StringBuilder stringBuilder = new StringBuilder(); + string arg; + if (string.IsNullOrEmpty(ordering)) + { + arg = ((!string.IsNullOrEmpty(PrimaryKey)) ? $" order by {PrimaryKey} desc" : string.Format(" order by {0} desc", "newid()")); + } + else + { + ordering = ordering.Replace("descending", "desc").Replace("ascending", "asc"); + arg = $" order by {ordering}"; + } + if (string.IsNullOrEmpty(selector)) + { + stringBuilder.Append($"select {text} from {TableName} "); + stringBuilder.Append($" {arg} limit {(pageIndex - 1) * pageSize},{pageSize};"); + } + else + { + stringBuilder.Append($"select {text} from {TableName} "); + stringBuilder.Append($" where {SqlHelper.ParseSelector(selector, values)}"); + stringBuilder.Append($" {arg} limit {(pageIndex - 1) * pageSize},{pageSize};"); + } + return stringBuilder.ToString(); + } + + public void Dispose() + { + GC.SuppressFinalize(this); + } + + private string GetSQLFildList(string fldList) + { + if (string.IsNullOrEmpty(fldList)) + { + return "*"; + } + if (fldList.Trim() == "*") + { + return "*"; + } + fldList = "[" + fldList + "]"; + fldList = fldList.Replace(',', ','); + fldList = fldList.Replace(",", "],["); + return fldList; + } + } +} diff --git a/Common.GLib/GLib.Data.Core/SqlCreator.cs b/Common.GLib/GLib.Data.Core/SqlCreator.cs new file mode 100644 index 0000000..ca0a76e --- /dev/null +++ b/Common.GLib/GLib.Data.Core/SqlCreator.cs @@ -0,0 +1,419 @@ +using GLib.Data.Entity; +using System; +using System.Collections.Generic; +using System.Reflection; +using System.Text; + +namespace GLib.Data.Core +{ + public class SqlCreator : ISqlCreator, IDisposable where TL : ILogicEntity, new() + { + private string _PrimaryKey = ""; + + private string _TableName = ""; + + private TL _model = default(TL); + + private int _PageSize = 100; + + private TL Model + { + get + { + if (_model == null) + { + _model = new TL(); + } + return _model; + } + } + + public string PrimaryKey + { + get + { + if (_PrimaryKey == "") + { + if (Model == null) + { + throw new ArgumentNullException("model is null !"); + } + _PrimaryKey = Model.PrimaryKey; + } + return _PrimaryKey; + } + set + { + _PrimaryKey = value; + } + } + + public virtual string TableName + { + get + { + if (_TableName == "") + { + bool flag = false; + PropertyInfo[] properties = EntityTypeCache.GetEntityInfo(typeof(TL)).Properties; + for (int i = 0; i < properties.Length; i++) + { + if (properties[i].Name.Trim().ToLower() == "TableName".ToLower()) + { + object value = properties[i].GetValue(Model, null); + if (value != null && !string.IsNullOrEmpty(value.ToString())) + { + _TableName = value.ToString(); + flag = true; + break; + } + } + } + if (!flag) + { + _TableName = "[" + typeof(TL).Name + "]"; + } + } + return _TableName; + } + set + { + _TableName = value; + } + } + + public int PageSize + { + get + { + return _PageSize; + } + set + { + _PageSize = value; + } + } + + public string CreateMaxSql(string selector, string col) + { + col = (string.IsNullOrEmpty(col) ? PrimaryKey : col); + StringBuilder stringBuilder = new StringBuilder(); + stringBuilder.Append($"select max({GetSQLFildList(col)}) from {TableName}"); + if (!string.IsNullOrEmpty(selector)) + { + stringBuilder.Append(" where " + selector); + } + return stringBuilder.ToString(); + } + + public string CreateCountSql(string selector, string col) + { + col = (string.IsNullOrEmpty(col) ? "1" : col); + StringBuilder stringBuilder = new StringBuilder(); + stringBuilder.Append($"select count({col}) as TotalCount from {TableName} "); + if (!string.IsNullOrEmpty(selector)) + { + stringBuilder.Append(" where " + selector); + } + return stringBuilder.ToString(); + } + + public string CreateSumSql(string selector, string col) + { + StringBuilder stringBuilder = new StringBuilder(); + stringBuilder.Append($"select sum({GetSQLFildList(col)}) from {TableName} "); + if (!string.IsNullOrEmpty(selector)) + { + stringBuilder.Append(" where " + selector); + } + return stringBuilder.ToString(); + } + + public string CreateInsertSql(TL model, out DBParam[] outparam) + { + StringBuilder stringBuilder = new StringBuilder(); + StringBuilder stringBuilder2 = new StringBuilder(); + stringBuilder.Append($"insert into {TableName}("); + PropertyInfo[] properties = EntityTypeCache.GetEntityInfo(typeof(TL)).Properties; + List list = new List(); + for (int i = 0; i < properties.Length; i++) + { + object[] customAttributes = properties[i].GetCustomAttributes(typeof(EntityAttribute), inherit: true); + EntityAttribute entityAttribute = null; + if (customAttributes.Length > 0) + { + entityAttribute = (EntityAttribute)customAttributes[0]; + } + if (!model.IsAutoID || !(model.PrimaryKey == properties[i].Name) || entityAttribute == null || !entityAttribute.IsDbGenerated) + { + if (properties[i].Name == PrimaryKey && entityAttribute != null && !entityAttribute.IsDbGenerated) + { + stringBuilder.Append("[" + properties[i].Name + "],"); + stringBuilder2.Append("@" + properties[i].Name + ","); + list.Add(new DBParam + { + ParamName = properties[i].Name, + ParamDbType = EntityHelper.GetDbType(properties[i].PropertyType), + ParamValue = EntityHelper.GetTypeDefaultValue(properties[i].GetValue(model, null), EntityHelper.GetDbType(properties[i].PropertyType)) + }); + } + else if (properties[i].Name != PrimaryKey && (entityAttribute == null || (!entityAttribute.IsDbGenerated && !entityAttribute.CustomMember))) + { + stringBuilder.Append("[" + properties[i].Name + "],"); + stringBuilder2.Append("@" + properties[i].Name + ","); + list.Add(new DBParam + { + ParamName = properties[i].Name, + ParamDbType = EntityHelper.GetDbType(properties[i].PropertyType), + ParamValue = EntityHelper.GetTypeDefaultValue(properties[i].GetValue(model, null), EntityHelper.GetDbType(properties[i].PropertyType)) + }); + } + } + } + stringBuilder = stringBuilder.Replace(",", ")", stringBuilder.Length - 1, 1); + stringBuilder2 = stringBuilder2.Replace(",", ")", stringBuilder2.Length - 1, 1); + stringBuilder.Append(" values ("); + stringBuilder.Append(stringBuilder2.ToString() + ";"); + if (model.IsAutoID) + { + stringBuilder.Append($" select ident_current('{TableName}') "); + } + outparam = list.ToArray(); + return stringBuilder.ToString(); + } + + public string CreateUpdateSql(TL model, string colList, string selector, out DBParam[] outparam, params DBParam[] values) + { + StringBuilder stringBuilder = new StringBuilder(); + stringBuilder.Append("update " + TableName + " set "); + PropertyInfo[] properties = EntityTypeCache.GetEntityInfo(typeof(TL)).Properties; + PropertyInfo propertyInfo = null; + List list = new List(); + for (int i = 0; i < properties.Length; i++) + { + object[] customAttributes = properties[i].GetCustomAttributes(typeof(EntityAttribute), inherit: true); + EntityAttribute entityAttribute = null; + if (customAttributes.Length > 0) + { + entityAttribute = (EntityAttribute)customAttributes[0]; + } + if (properties[i].Name == PrimaryKey) + { + propertyInfo = properties[i]; + } + else if (properties[i].Name != PrimaryKey && !(entityAttribute?.CustomMember ?? false) && (string.IsNullOrEmpty(colList) || colList.IndexOf(properties[i].Name.Trim()) >= 0) && !EntityHelper.IsTypeMinValue(properties[i].GetValue(model, null), EntityHelper.GetDbType(properties[i].PropertyType))) + { + stringBuilder.Append("[" + properties[i].Name + "]=@" + properties[i].Name + ","); + list.Add(new DBParam + { + ParamDbType = EntityHelper.GetDbType(properties[i].PropertyType), + ParamName = properties[i].Name, + ParamValue = properties[i].GetValue(model, null) + }); + } + } + stringBuilder = stringBuilder.Replace(",", " ", stringBuilder.Length - 1, 1); + if (!string.IsNullOrEmpty(selector)) + { + stringBuilder.Append(" where 1=1 and " + selector); + if (values != null) + { + for (int i = 0; i < values.Length; i++) + { + list.Insert(i, values[i]); + } + } + } + else + { + stringBuilder.Append(" where [" + PrimaryKey + "]=@" + PrimaryKey); + list.Add(new DBParam + { + ParamDbType = EntityHelper.GetDbType(propertyInfo.PropertyType), + ParamName = propertyInfo.Name, + ParamValue = propertyInfo.GetValue(model, null) + }); + } + outparam = list.ToArray(); + return stringBuilder.ToString(); + } + + public string CreateDeleteSql(TL model, out DBParam[] outparam) + { + StringBuilder stringBuilder = new StringBuilder(); + PropertyInfo[] properties = EntityTypeCache.GetEntityInfo(typeof(TL)).Properties; + PropertyInfo propertyInfo = null; + List list = new List(); + for (int i = 0; i < properties.Length; i++) + { + object[] customAttributes = properties[i].GetCustomAttributes(typeof(EntityAttribute), inherit: true); + EntityAttribute entityAttribute = null; + if (customAttributes.Length > 0) + { + entityAttribute = (EntityAttribute)customAttributes[0]; + } + if (properties[i].Name == PrimaryKey) + { + propertyInfo = properties[i]; + } + } + stringBuilder.Append(" " + PrimaryKey + "=@" + PrimaryKey); + list.Add(new DBParam + { + ParamDbType = EntityHelper.GetDbType(propertyInfo.PropertyType), + ParamName = propertyInfo.Name, + ParamValue = propertyInfo.GetValue(model, null) + }); + outparam = list.ToArray(); + return CreateDeleteSql(stringBuilder.ToString()); + } + + public string CreateDeleteSql(string selector) + { + StringBuilder stringBuilder = new StringBuilder(); + stringBuilder.Append("delete from " + TableName); + if (!string.IsNullOrEmpty(selector)) + { + stringBuilder.Append(" where " + selector); + } + return stringBuilder.ToString(); + } + + public string CreateModelSql(TL model, out DBParam[] outparam) + { + PropertyInfo[] properties = EntityTypeCache.GetEntityInfo(typeof(TL)).Properties; + List list = new List(); + for (int i = 0; i < properties.Length; i++) + { + if (properties[i].Name == PrimaryKey) + { + list.Add(new DBParam + { + ParamName = properties[i].Name, + ParamDbType = EntityHelper.GetDbType(properties[i].PropertyType), + ParamValue = properties[i].GetValue(model, null) + }); + break; + } + } + outparam = list.ToArray(); + return CreateModelSql(string.Format("{0}=@{0}", PrimaryKey), string.Empty); + } + + public string CreateModelSql(string selector, string colList) + { + StringBuilder stringBuilder = new StringBuilder(); + if (string.IsNullOrEmpty(colList)) + { + stringBuilder.Append(string.Format("select top 1 {0} from {1}", "*", TableName)); + } + else + { + stringBuilder.Append(string.Format("select top 1 {0} from {1}", colList.Replace("new", ""), TableName)); + } + if (!string.IsNullOrEmpty(selector)) + { + stringBuilder.Append(" where " + selector); + } + return stringBuilder.ToString(); + } + + public string CreatePageSql(TL model, out DBParam[] outparam) + { + PropertyInfo[] properties = EntityTypeCache.GetEntityInfo(typeof(TL)).Properties; + List list = new List(); + for (int i = 0; i < properties.Length; i++) + { + if (properties[i].Name == PrimaryKey) + { + list.Add(new DBParam + { + ParamName = properties[i].Name, + ParamDbType = EntityHelper.GetDbType(properties[i].PropertyType), + ParamValue = properties[i].GetValue(model, null) + }); + break; + } + } + outparam = list.ToArray(); + return CreatePageSql(string.Format("{0}=@{0}", PrimaryKey), 0, PageSize, string.Empty, string.Empty, outparam); + } + + public string CreatePageSql(string selector, int pageIndex, int pageSize, string ordering, string colList, params DBParam[] values) + { + pageIndex = ((pageIndex <= 0) ? 1 : pageIndex); + if (pageSize == 0) + { + pageSize = PageSize; + } + string text = ""; + if (string.IsNullOrEmpty(colList) || colList == "*") + { + PropertyInfo[] properties = EntityTypeCache.GetEntityInfo(typeof(TL)).Properties; + PropertyInfo[] array = properties; + foreach (PropertyInfo propertyInfo in array) + { + object[] customAttributes = propertyInfo.GetCustomAttributes(typeof(EntityAttribute), inherit: true); + EntityAttribute entityAttribute = null; + if (customAttributes.Length > 0) + { + entityAttribute = (EntityAttribute)customAttributes[0]; + } + if (!(entityAttribute?.CustomMember ?? false)) + { + text = text + "[" + propertyInfo.Name + "],"; + } + } + text = text.Substring(0, text.Length - 1); + } + else + { + text = GetSQLFildList(colList); + } + StringBuilder stringBuilder = new StringBuilder(); + string text2; + if (string.IsNullOrEmpty(ordering)) + { + text2 = ((!string.IsNullOrEmpty(PrimaryKey)) ? $" order by {PrimaryKey} desc" : string.Format(" order by {0} desc", "newid()")); + } + else + { + ordering = ordering.Replace("descending", "desc").Replace("ascending", "asc"); + text2 = $" order by {ordering}"; + } + if (string.IsNullOrEmpty(selector)) + { + stringBuilder.Append($"select {text} from(select {text}, row_number() over({text2}) as row from {TableName}"); + stringBuilder.Append($") a where row between {(pageIndex - 1) * pageSize + 1} and {pageIndex * pageSize}"); + } + else + { + stringBuilder.Append($"select {text} from(select {text}, row_number() over({text2}) as row from {TableName}"); + stringBuilder.Append($" where {SqlHelper.ParseSelector(selector, values)}"); + stringBuilder.Append($") a where row between {(pageIndex - 1) * pageSize + 1} and {pageIndex * pageSize}"); + } + return stringBuilder.ToString(); + } + + public void Dispose() + { + GC.SuppressFinalize(this); + } + + private string GetSQLFildList(string fldList) + { + if (string.IsNullOrEmpty(fldList)) + { + return "*"; + } + if (fldList.Trim() == "*") + { + return "*"; + } + fldList = "[" + fldList + "]"; + fldList = fldList.Replace(',', ','); + fldList = fldList.Replace(",", "],["); + return fldList; + } + } +} diff --git a/Common.GLib/GLib.Data.Core/SqlCreatorFactory.cs b/Common.GLib/GLib.Data.Core/SqlCreatorFactory.cs new file mode 100644 index 0000000..5b6b89e --- /dev/null +++ b/Common.GLib/GLib.Data.Core/SqlCreatorFactory.cs @@ -0,0 +1,17 @@ +using GLib.Data.Entity; + +namespace GLib.Data.Core +{ + public class SqlCreatorFactory + { + public static ISqlCreator GetSqlCreator() where TL : ILogicEntity, new() + { + DataBaseType dBType = SqlHelper.GetDBType(); + if (dBType == DataBaseType.SqlServer) + { + return new SqlCreator(); + } + return new SqlCreator(); + } + } +} diff --git a/Common.GLib/GLib.Data.Core/SqlHelper.cs b/Common.GLib/GLib.Data.Core/SqlHelper.cs new file mode 100644 index 0000000..016e65f --- /dev/null +++ b/Common.GLib/GLib.Data.Core/SqlHelper.cs @@ -0,0 +1,259 @@ +using GLib.Data.Entity; +using GLib.Logging; +using MySql.Data.MySqlClient; +using System; +using System.Configuration; +using System.Data; +using System.Data.Common; +using System.Data.OleDb; +using System.Data.OracleClient; +using System.Data.SqlClient; + +namespace GLib.Data.Core +{ + public class SqlHelper + { + public static string GetConnectionString(string dbName) + { + if (string.IsNullOrEmpty(dbName)) + { + throw new ArgumentNullException("ConnectionString is null"); + } + return ConfigurationManager.ConnectionStrings[dbName].ConnectionString; + } + + public static DataBaseType GetDBType() + { + switch (ConfigurationManager.AppSettings["DBType"]) + { + case "SqlServer": + return DataBaseType.SqlServer; + case "Access": + return DataBaseType.Access; + case "MySql": + return DataBaseType.MySql; + case "Oracle": + return DataBaseType.Oracle; + default: + return DataBaseType.SqlServer; + } + } + + public static DbProviderFactory GetDBFactory(DataBaseType dbType) + { + switch (dbType) + { + case DataBaseType.SqlServer: + return SqlClientFactory.Instance; + case DataBaseType.Access: + return OleDbFactory.Instance; + case DataBaseType.MySql: + return (DbProviderFactory)(object)MySqlClientFactory.Instance; + //case DataBaseType.Oracle: + // return OracleClientFactory.Instance; + default: + return SqlClientFactory.Instance; + } + } + + public static string ParseSelector(string selector, params DBParam[] values) + { + string text = selector; + if (values != null) + { + for (int i = 0; i < values.Length; i++) + { + if (string.IsNullOrEmpty(values[i].ParamName)) + { + text = text.Replace($"@{i}", $"@param{i}"); + values[i].ParamName = $"param{i}"; + } + else + { + text = text.Replace($"@{i}", "@" + values[i].ParamName); + } + } + } + return text.Replace("==", " = ").Replace("&&", " and ").Replace("||", " or "); + } + + public static DbCommand GetCommand(string dbName, string strCommand) + { + return GetCommand(dbName, strCommand, 30); + } + + public static DbCommand GetCommand(string dbName, string strCommand, int timeOut) + { + DbProviderFactory dBFactory = GetDBFactory(GetDBType()); + DbCommand dbCommand = dBFactory.CreateCommand(); + string text = GetConnectionString(dbName); + if (GetDBType() == DataBaseType.MySql) + { + strCommand = strCommand.Replace("[", "").Replace("]", ""); + } + if (GetDBType() == DataBaseType.Access) + { + text = text.Replace("@Path", AppDomain.CurrentDomain.BaseDirectory); + } + dbCommand.CommandText = strCommand; + DbConnection dbConnection = dBFactory.CreateConnection(); + dbConnection.ConnectionString = text; + dbConnection.Open(); + dbCommand.Connection = dbConnection; + dbCommand.CommandTimeout = timeOut; + return dbCommand; + } + + public static IDataReader ExecuteDataReader(string dbName, string strCommand, CommandType commandType, DBParam[] listParam) + { + return ExecuteDataReader(dbName, strCommand, commandType, listParam, 30); + } + + public static IDataReader ExecuteDataReader(string dbName, string strCommand, CommandType commandType, DBParam[] listParam, int timeOut) + { + strCommand = ParseSelector(strCommand, listParam); + DbCommand command = GetCommand(dbName, strCommand, timeOut); + command.CommandType = commandType; + if (listParam != null) + { + DbParameterCollection parameters = command.Parameters; + foreach (DBParam dBParam in listParam) + { + DbParameter dbParameter = command.CreateParameter(); + dbParameter.ParameterName = dBParam.ParamName; + dbParameter.DbType = dBParam.ParamDbType; + dbParameter.Value = dBParam.ParamValue; + if (!parameters.Contains(dbParameter)) + { + parameters.Add(dbParameter); + } + } + } + try + { + IDataReader result = command.ExecuteReader(CommandBehavior.CloseConnection); + command.Parameters.Clear(); + return result; + } + catch (Exception ex) + { + if (command.Connection.State == ConnectionState.Open) + { + command.Connection.Close(); + command.Connection.Dispose(); + } + Log log = new Log(); + log.Write(new LogMessage + { + Content = "GLib.Data.Core.SqlHelper.ExecuteDataReader:\r\n" + ex.Message, + Type = MessageType.Error + }); + return null; + } + } + + public static int ExecuteNonQuery(string dbName, string strCommand, CommandType commandType, DBParam[] listParam) + { + strCommand = ParseSelector(strCommand, listParam); + int result = -1; + using (DbCommand dbCommand = GetCommand(dbName, strCommand)) + { + dbCommand.CommandType = commandType; + if (listParam != null) + { + DbParameterCollection parameters = dbCommand.Parameters; + foreach (DBParam dBParam in listParam) + { + DbParameter dbParameter = dbCommand.CreateParameter(); + dbParameter.ParameterName = dBParam.ParamName; + dbParameter.DbType = dBParam.ParamDbType; + dbParameter.Value = dBParam.ParamValue; + if (!parameters.Contains(dbParameter)) + { + parameters.Add(dbParameter); + } + } + } + result = dbCommand.ExecuteNonQuery(); + dbCommand.Connection.Close(); + dbCommand.Dispose(); + } + return result; + } + + public static object ExecuteScalar(string dbName, string strCommand, CommandType commandType, DBParam[] listParam) + { + strCommand = ParseSelector(strCommand, listParam); + object result = null; + using (DbCommand dbCommand = GetCommand(dbName, strCommand)) + { + dbCommand.CommandType = commandType; + if (listParam != null) + { + DbParameterCollection parameters = dbCommand.Parameters; + foreach (DBParam dBParam in listParam) + { + DbParameter dbParameter = dbCommand.CreateParameter(); + dbParameter.ParameterName = dBParam.ParamName; + dbParameter.DbType = dBParam.ParamDbType; + dbParameter.Value = dBParam.ParamValue; + if (!parameters.Contains(dbParameter)) + { + parameters.Add(dbParameter); + } + } + } + result = dbCommand.ExecuteScalar(); + dbCommand.Connection.Close(); + dbCommand.Dispose(); + } + return result; + } + + public static DataTable ExecuteTable(string dbName, string strCommand, CommandType commandType, DBParam[] listParam) + { + string text = GetConnectionString(dbName); + if (GetDBType() == DataBaseType.MySql) + { + strCommand = strCommand.Replace("[", "").Replace("]", ""); + } + if (GetDBType() == DataBaseType.Access) + { + text = text.Replace("@Path", AppDomain.CurrentDomain.BaseDirectory); + } + DataTable dataTable = new DataTable(); + DbProviderFactory dBFactory = GetDBFactory(GetDBType()); + using (DbCommand dbCommand = dBFactory.CreateCommand()) + { + DbConnection dbConnection = dBFactory.CreateConnection(); + dbConnection.ConnectionString = text; + dbConnection.Open(); + dbCommand.Connection = dbConnection; + dbCommand.CommandTimeout = 30; + dbCommand.CommandType = commandType; + dbCommand.CommandText = ParseSelector(strCommand, listParam); + if (listParam != null) + { + DbParameterCollection parameters = dbCommand.Parameters; + foreach (DBParam dBParam in listParam) + { + DbParameter dbParameter = dbCommand.CreateParameter(); + dbParameter.ParameterName = dBParam.ParamName; + dbParameter.DbType = dBParam.ParamDbType; + dbParameter.Value = dBParam.ParamValue; + if (!parameters.Contains(dbParameter)) + { + parameters.Add(dbParameter); + } + } + } + DbDataAdapter dbDataAdapter = dBFactory.CreateDataAdapter(); + dbDataAdapter.SelectCommand = dbCommand; + dbDataAdapter.Fill(dataTable); + dbCommand.Connection.Close(); + dbCommand.Dispose(); + } + return dataTable; + } + } +} diff --git a/Common.GLib/GLib.Data.Entity/DBParam.cs b/Common.GLib/GLib.Data.Entity/DBParam.cs new file mode 100644 index 0000000..2f205ca --- /dev/null +++ b/Common.GLib/GLib.Data.Entity/DBParam.cs @@ -0,0 +1,49 @@ +using System.Data; + +namespace GLib.Data.Entity +{ + public class DBParam + { + private string _ParamName = ""; + + private DbType _ParamDbType = DbType.String; + + private object _ParamValue = null; + + public string ParamName + { + get + { + return _ParamName; + } + set + { + _ParamName = value; + } + } + + public DbType ParamDbType + { + get + { + return _ParamDbType; + } + set + { + _ParamDbType = value; + } + } + + public object ParamValue + { + get + { + return _ParamValue; + } + set + { + _ParamValue = value; + } + } + } +} diff --git a/Common.GLib/GLib.Data.Entity/EntityAttribute.cs b/Common.GLib/GLib.Data.Entity/EntityAttribute.cs new file mode 100644 index 0000000..0d8b855 --- /dev/null +++ b/Common.GLib/GLib.Data.Entity/EntityAttribute.cs @@ -0,0 +1,36 @@ +using System; + +namespace GLib.Data.Entity +{ + [AttributeUsage(AttributeTargets.All, AllowMultiple = true, Inherited = true)] + public class EntityAttribute : Attribute + { + private bool _customMember; + + private bool _IsDbGenerated; + + public bool CustomMember + { + get + { + return _customMember; + } + set + { + _customMember = value; + } + } + + public bool IsDbGenerated + { + get + { + return _IsDbGenerated; + } + set + { + _IsDbGenerated = value; + } + } + } +} diff --git a/Common.GLib/GLib.Data.Entity/EntityHelper.cs b/Common.GLib/GLib.Data.Entity/EntityHelper.cs new file mode 100644 index 0000000..5d74b8f --- /dev/null +++ b/Common.GLib/GLib.Data.Entity/EntityHelper.cs @@ -0,0 +1,170 @@ +using System; +using System.Data; + +namespace GLib.Data.Entity +{ + public static class EntityHelper + { + public static DbType GetDbType(Type sysType) + { + DbType result = DbType.String; + switch (sysType.Name) + { + case "String": + result = DbType.String; + break; + case "Byte": + result = DbType.Byte; + break; + case "Byte[]": + result = DbType.Binary; + break; + case "Int16": + result = DbType.Int16; + break; + case "Int32": + result = DbType.Int32; + break; + case "Int64": + result = DbType.Int64; + break; + case "DateTime": + result = DbType.DateTime; + break; + case "Decimal": + result = DbType.Decimal; + break; + case "Double": + result = DbType.Double; + break; + case "Single": + result = DbType.Single; + break; + case "Boolean": + result = DbType.Boolean; + break; + case "Guid": + result = DbType.Guid; + break; + } + return result; + } + + public static bool IsTypeMinValue(object obValue, DbType dbType) + { + bool result = false; + switch (dbType) + { + case DbType.String: + if (obValue == null) + { + result = true; + } + break; + case DbType.Int16: + if (Convert.ToInt16(obValue) == short.MinValue) + { + result = true; + } + break; + case DbType.Int32: + if (Convert.ToInt32(obValue) == int.MinValue) + { + result = true; + } + break; + case DbType.Int64: + if (Convert.ToInt64(obValue) == long.MinValue) + { + result = true; + } + break; + case DbType.Decimal: + if (Convert.ToDecimal(obValue) == decimal.MinValue) + { + result = true; + } + break; + case DbType.Double: + if (Convert.ToDouble(obValue) == double.MinValue) + { + result = true; + } + break; + case DbType.Single: + if (Convert.ToSingle(obValue) == float.MinValue) + { + result = true; + } + break; + case DbType.DateTime: + if (Convert.ToDateTime(obValue) == new DateTime(1900, 1, 1)) + { + result = true; + } + break; + } + return result; + } + + public static object GetTypeDefaultValue(object obValue, DbType dbType) + { + object result = obValue; + switch (dbType) + { + case DbType.String: + if (obValue == null || Convert.ToString(obValue) == string.Empty) + { + result = string.Empty; + } + break; + case DbType.Int16: + if (Convert.ToInt16(obValue) == short.MinValue) + { + result = 0; + } + break; + case DbType.Int32: + if (Convert.ToInt32(obValue) == int.MinValue) + { + result = 0; + } + break; + case DbType.Int64: + if (Convert.ToInt64(obValue) == long.MinValue) + { + result = 0; + } + break; + case DbType.Byte: + if (Convert.ToByte(obValue) == 0) + { + result = 0; + } + break; + case DbType.Decimal: + if (Convert.ToDecimal(obValue) == decimal.MinValue) + { + result = 0; + } + break; + case DbType.Double: + if (Convert.ToDouble(obValue) == double.MinValue) + { + result = 0; + } + break; + case DbType.Single: + if (Convert.ToSingle(obValue) == float.MinValue) + { + result = 0; + } + break; + default: + result = obValue; + break; + } + return result; + } + } +} diff --git a/Common.GLib/GLib.Data.Entity/EntityInfo.cs b/Common.GLib/GLib.Data.Entity/EntityInfo.cs new file mode 100644 index 0000000..30b309d --- /dev/null +++ b/Common.GLib/GLib.Data.Entity/EntityInfo.cs @@ -0,0 +1,103 @@ +using System.Collections.Generic; +using System.Reflection; + +namespace GLib.Data.Entity +{ + public class EntityInfo + { + private EntityAttribute[] columns; + + private IDictionary dicColumns = new Dictionary(); + + private FieldInfo[] fields; + + private IDictionary dicFields = new Dictionary(); + + private PropertyInfo[] properties; + + private IDictionary dicProperties = new Dictionary(); + + public EntityAttribute[] Columns + { + get + { + return columns; + } + set + { + columns = value; + } + } + + public FieldInfo[] Fields + { + get + { + return fields; + } + set + { + fields = value; + } + } + + public PropertyInfo[] Properties + { + get + { + return properties; + } + set + { + properties = value; + } + } + + public IDictionary DicColumns + { + get + { + return dicColumns; + } + set + { + dicColumns = value; + } + } + + public IDictionary DicFields + { + get + { + return dicFields; + } + set + { + dicFields = value; + } + } + + public IDictionary DicProperties + { + get + { + return dicProperties; + } + set + { + dicProperties = value; + } + } + + public EntityInfo() + { + } + + public EntityInfo(EntityAttribute[] columns, FieldInfo[] fields, PropertyInfo[] properties) + { + this.columns = columns; + this.fields = fields; + this.properties = properties; + } + } +} diff --git a/Common.GLib/GLib.Data.Entity/EntityTypeCache.cs b/Common.GLib/GLib.Data.Entity/EntityTypeCache.cs new file mode 100644 index 0000000..ba21cdc --- /dev/null +++ b/Common.GLib/GLib.Data.Entity/EntityTypeCache.cs @@ -0,0 +1,54 @@ +using System; +using System.Collections.Generic; +using System.Reflection; + +namespace GLib.Data.Entity +{ + public static class EntityTypeCache + { + private static IDictionary cache; + + static EntityTypeCache() + { + cache = null; + cache = new Dictionary(); + } + + public static void InsertEntityInfo(Type type, EntityInfo entityInfo) + { + if (!cache.ContainsKey(type)) + { + cache.Add(type, entityInfo); + } + } + + public static void InsertEntityInfo(ILogicEntity entity, EntityInfo entityInfo) + { + Type type = entity.GetType(); + InsertEntityInfo(type, entityInfo); + } + + public static EntityInfo GetEntityInfo(Type type) + { + if (cache.ContainsKey(type)) + { + return cache[type]; + } + EntityInfo entityInfo = new EntityInfo(null, null, type.GetProperties(BindingFlags.DeclaredOnly | BindingFlags.Instance | BindingFlags.Public)); + InsertEntityInfo(type, entityInfo); + return entityInfo; + } + + public static EntityInfo GetEntityInfo(ILogicEntity entity) + { + Type type = entity.GetType(); + return GetEntityInfo(type); + } + + public static EntityInfo GetEntityInfo() where T : ILogicEntity + { + Type typeFromHandle = typeof(T); + return GetEntityInfo(typeFromHandle); + } + } +} diff --git a/Common.GLib/GLib.Data.Entity/ILogicEntity.cs b/Common.GLib/GLib.Data.Entity/ILogicEntity.cs new file mode 100644 index 0000000..bfdec8f --- /dev/null +++ b/Common.GLib/GLib.Data.Entity/ILogicEntity.cs @@ -0,0 +1,26 @@ +namespace GLib.Data.Entity +{ + public interface ILogicEntity + { + [Entity(CustomMember = true)] + string PrimaryKey + { + get; + set; + } + + [Entity(CustomMember = true)] + bool IsAutoID + { + get; + set; + } + + [Entity(CustomMember = true)] + string DbName + { + get; + set; + } + } +} diff --git a/Common.GLib/GLib.Data/DBT_SqlHelper.cs b/Common.GLib/GLib.Data/DBT_SqlHelper.cs new file mode 100644 index 0000000..18cb7e3 --- /dev/null +++ b/Common.GLib/GLib.Data/DBT_SqlHelper.cs @@ -0,0 +1,254 @@ +using System; +using System.Configuration; +using System.Data; +using System.Data.SqlClient; +using System.IO; +using System.Text; + +namespace GLib.Data +{ + public abstract class DBT_SqlHelper + { + public static string connectionString = string.Concat(ConfigurationSettings.AppSettings["con"]); + + public static int ExecteNonQuery(string connectionString, CommandType cmdType, string cmdText, params SqlParameter[] commandParameters) + { + SqlCommand sqlCommand = new SqlCommand(); + using (SqlConnection conn = new SqlConnection(connectionString)) + { + PrepareCommand(sqlCommand, conn, null, cmdType, cmdText, commandParameters); + int result = sqlCommand.ExecuteNonQuery(); + sqlCommand.Parameters.Clear(); + return result; + } + } + + public static int ExecteNonQueryProducts(string cmdText, params SqlParameter[] commandParameters) + { + return ExecteNonQuery(connectionString, CommandType.StoredProcedure, cmdText, commandParameters); + } + + public static int ExecteNonQueryText(string cmdText, params SqlParameter[] commandParameters) + { + return ExecteNonQuery(connectionString, CommandType.Text, cmdText, commandParameters); + } + + private static void PrepareCommand(SqlCommand cmd, SqlConnection conn, SqlTransaction trans, CommandType cmdType, string cmdText, SqlParameter[] cmdParms) + { + if (conn.State != ConnectionState.Open) + { + conn.Open(); + } + cmd.Connection = conn; + cmd.CommandText = cmdText; + if (trans != null) + { + cmd.Transaction = trans; + } + cmd.CommandType = cmdType; + if (cmdParms != null) + { + foreach (SqlParameter value in cmdParms) + { + cmd.Parameters.Add(value); + } + } + } + + public static void CreateDatabase(string dbName, string dbFileName, string dbSize, string dbMaxSize, string dbFileGrowth, string logName, string logFileName, string logSize, string logMaxSize, string logFileGrowth, bool isDeletedb) + { + StringBuilder stringBuilder = new StringBuilder(); + stringBuilder.Append("USE master "); + stringBuilder.Append(" GO"); + if (isDeletedb) + { + stringBuilder.Append("IF EXISTS(SELECT * FROM sysdatabases WHERE name ='@dbName')begin DROP DATABASE @dbName end"); + } + stringBuilder.Append("CREATE DATABASE @dbName ON PRIMARY ("); + stringBuilder.Append("NAME='@ dbName_data',"); + stringBuilder.Append("FILENAME='@dbFileName', "); + stringBuilder.Append("SIZE=@dbSize, "); + stringBuilder.Append("MAXSIZE= @dbMaxSize,"); + stringBuilder.Append("FILEGROWTH=@dbFileGrowth)"); + stringBuilder.Append("LOG ON ("); + stringBuilder.Append("NAME='@logName_log',"); + stringBuilder.Append("FILENAME='@logFileName',"); + stringBuilder.Append("SIZE=@logSize,"); + stringBuilder.Append("MAXSIZE=@logMaxSize,"); + stringBuilder.Append("FILEGROWTH=@logFileGrowth ) GO"); + SqlParameter[] array = new SqlParameter[10] + { + new SqlParameter("@dbName", dbName), + new SqlParameter("@dbFileName", dbFileName), + new SqlParameter("@dbSize", dbSize), + new SqlParameter("@dbMaxSize", dbMaxSize), + new SqlParameter("@dbFileGrowth", dbFileGrowth), + new SqlParameter("@logName", logName), + new SqlParameter("@logFileName", logFileName), + new SqlParameter("@logSize", logSize), + new SqlParameter("@logMaxSize", logMaxSize), + new SqlParameter("@logFileGrowth", logFileGrowth) + }; + ExecteNonQueryText(stringBuilder.ToString().Trim(), (SqlParameter[])null); + } + + public static void DropDatabase(string dbName) + { + StringBuilder stringBuilder = new StringBuilder(); + stringBuilder.AppendLine("USE master "); + stringBuilder.AppendLine("DROP DATABASE " + dbName); + SqlParameter[] array = new SqlParameter[1] + { + new SqlParameter("@dbName", dbName) + }; + ExecteNonQueryText(stringBuilder.ToString().Trim()); + } + + public static void BackupDatabase(string dbName, string dbFileName) + { + StringBuilder stringBuilder = new StringBuilder(); + stringBuilder.Append("USE master "); + stringBuilder.Append(" GO "); + stringBuilder.Append("BACKUP DATABASE @dbName TO DISK ='@dbFileName'"); + SqlParameter[] commandParameters = new SqlParameter[2] + { + new SqlParameter("@dbName", dbName), + new SqlParameter("@dbFileName", dbFileName) + }; + ExecteNonQueryText(stringBuilder.ToString().Trim(), commandParameters); + } + + public static void RestoreDatabase(string dbName, string dbFileName) + { + StringBuilder stringBuilder = new StringBuilder(); + stringBuilder.Append("USE master "); + stringBuilder.Append(" GO "); + stringBuilder.Append("restore database @dbName from disk='@dbFileName' WITH REPLACE,RECOVERY"); + SqlParameter[] array = new SqlParameter[2] + { + new SqlParameter("@dbName", dbName), + new SqlParameter("@dbFileName", dbFileName) + }; + ExecteNonQueryText(stringBuilder.ToString().Trim(), (SqlParameter[])null); + } + + public static void OnlineDatabase(string newDbName, string dbFileName, string logFileName) + { + StringBuilder stringBuilder = new StringBuilder(); + stringBuilder.Append("USE master "); + stringBuilder.Append(" GO "); + stringBuilder.Append("EXEC sp_attach_db @ newDbName,'@dbFileName','@logFileName'"); + SqlParameter[] commandParameters = new SqlParameter[2] + { + new SqlParameter("@dbFileName", dbFileName), + new SqlParameter("@logFileName", logFileName) + }; + ExecteNonQueryText(stringBuilder.ToString().Trim(), commandParameters); + } + + public static void OfflineDatabase(string dbName) + { + StringBuilder stringBuilder = new StringBuilder(); + stringBuilder.Append("USE master "); + stringBuilder.Append(" GO "); + stringBuilder.Append(" exec sp_detach_db '@dbName' "); + SqlParameter[] array = new SqlParameter[1] + { + new SqlParameter("@dbName", dbName) + }; + ExecteNonQueryText(stringBuilder.ToString().Trim(), (SqlParameter[])null); + } + + public static void ResetPassword(string newPassword, string userName) + { + StringBuilder stringBuilder = new StringBuilder(); + stringBuilder.Append("USE master "); + stringBuilder.Append(" GO "); + stringBuilder.Append("EXEC sp_password null,'@newPassword','@userName'"); + SqlParameter[] array = new SqlParameter[2] + { + new SqlParameter("@newPassword", newPassword), + new SqlParameter("@userName", userName) + }; + ExecteNonQueryText(stringBuilder.ToString().Trim(), (SqlParameter[])null); + } + + public static void CreateDbUser(string dbName, string userName, string passWord) + { + StringBuilder stringBuilder = new StringBuilder(); + stringBuilder.Append("USE " + dbName); + stringBuilder.Append(" GO "); + stringBuilder.Append("EXEC sp_addlogin N'@userName','@passWord'"); + stringBuilder.Append("EXEC sp_grantdbaccess N'@userName'"); + SqlParameter[] array = new SqlParameter[3] + { + new SqlParameter("@dbName", userName), + new SqlParameter("@userName", userName), + new SqlParameter("@passWord", passWord) + }; + ExecteNonQueryText(stringBuilder.ToString().Trim(), (SqlParameter[])null); + } + + public static void AddRoleToDbUser(string dbName, string userName) + { + StringBuilder stringBuilder = new StringBuilder(); + stringBuilder.Append("USE " + dbName); + stringBuilder.Append("GO "); + stringBuilder.Append("EXEC sp_addrolemember N'@dbName', N'@userName'"); + SqlParameter[] array = new SqlParameter[2] + { + new SqlParameter("@dbName", userName), + new SqlParameter("@userName", userName) + }; + ExecteNonQueryText(stringBuilder.ToString().Trim(), (SqlParameter[])null); + } + + public static void ExecuteSQLFile(string sqlFileName) + { + SqlConnection sqlConnection = null; + try + { + sqlConnection = new SqlConnection(connectionString); + SqlCommand sqlCommand = sqlConnection.CreateCommand(); + sqlConnection.Open(); + using (FileStream fileStream = new FileStream(sqlFileName, FileMode.Open, FileAccess.ReadWrite)) + { + StreamReader streamReader = new StreamReader(fileStream, Encoding.Default); + StringBuilder stringBuilder = new StringBuilder(); + string text = ""; + while ((text = streamReader.ReadLine()) != null) + { + if (text.Trim().ToUpper() != "GO") + { + stringBuilder.AppendLine(text); + } + else + { + sqlCommand.CommandText = stringBuilder.ToString(); + sqlCommand.ExecuteNonQuery(); + stringBuilder.Remove(0, stringBuilder.Length); + } + } + fileStream.Dispose(); + } + } + catch (Exception ex) + { + Console.WriteLine(ex.Message); + } + finally + { + if (sqlConnection != null && sqlConnection.State != 0) + { + sqlConnection.Close(); + } + } + } + + public static void Test() + { + connectionString = "server=.;uid=sa;password=123456;database=master"; + DropDatabase("db"); + } + } +} diff --git a/Common.GLib/GLib.Data/PageList.cs b/Common.GLib/GLib.Data/PageList.cs new file mode 100644 index 0000000..e4b20db --- /dev/null +++ b/Common.GLib/GLib.Data/PageList.cs @@ -0,0 +1,32 @@ +using System.Collections.Generic; + +namespace GLib.Data +{ + public class PageList : List + { + public int PageIndex + { + get; + set; + } + + public int PageSize + { + get; + set; + } + + public int TotalCount + { + get; + set; + } + + public PageList(int pageIndex, int pageSize, int totalCount) + { + PageIndex = pageIndex; + PageSize = pageSize; + TotalCount = totalCount; + } + } +} diff --git a/Common.GLib/GLib.Extension/ComHelper.cs b/Common.GLib/GLib.Extension/ComHelper.cs new file mode 100644 index 0000000..e43be24 --- /dev/null +++ b/Common.GLib/GLib.Extension/ComHelper.cs @@ -0,0 +1,669 @@ +using System; +using System.Data; +using System.IO; +using System.Net; +using System.Security.Cryptography; +using System.Text; +using System.Text.RegularExpressions; +//using System.Web.Caching; +//using System.Web.UI; +//using System.Web.UI.WebControls; + +namespace GLib.Extension +{ + public class ComHelper + { + private static byte[] Keys = new byte[8] + { + 16, + 48, + 80, + 115, + 151, + 171, + 205, + 239 + }; + + public static string AddSucces => "添加成功"; + + public static string AddSame => "已经存在!"; + + public static string AddError => "添加出错,请重试!"; + + public static string DeleteSucces => "删除成功"; + + public static string DeleteSame => "已经存在!"; + + public static string DeleteError => "删除出错,请重试!"; + + public static string UpdateSucces => "修改成功"; + + public static string UpdateSame => "已经存在!"; + + public static string UpdateError => "修改出错,请重试!"; + + public static string StrConvert(string strInput) + { + if (strInput != null && strInput != "") + { + string[,] array = new string[13, 2] + { + { + "'", + "’" + }, + { + "%20", + " " + }, + { + "%24", + " " + }, + { + "%27", + " " + }, + { + "%3a", + " " + }, + { + "%3b", + " " + }, + { + "%3c", + " " + }, + { + ";", + ";" + }, + { + ":", + ":" + }, + { + "%", + "%" + }, + { + "--", + "--" + }, + { + "*", + "*" + }, + { + "\\", + "、、" + } + }; + for (int i = 0; i < array.Length / 2; i++) + { + strInput = strInput.Replace(array[i, 0], array[i, 1]); + } + } + return strInput; + } + + public static string EncryptDES(string encryptString, string encryptKey) + { + try + { + byte[] bytes = Encoding.UTF8.GetBytes(encryptKey.Substring(0, 8)); + byte[] keys = Keys; + byte[] bytes2 = Encoding.UTF8.GetBytes(encryptString); + DESCryptoServiceProvider dESCryptoServiceProvider = new DESCryptoServiceProvider(); + MemoryStream memoryStream = new MemoryStream(); + CryptoStream cryptoStream = new CryptoStream(memoryStream, dESCryptoServiceProvider.CreateEncryptor(bytes, keys), CryptoStreamMode.Write); + cryptoStream.Write(bytes2, 0, bytes2.Length); + cryptoStream.FlushFinalBlock(); + return Convert.ToBase64String(memoryStream.ToArray()); + } + catch + { + return encryptString; + } + } + + public static string DecryptDES(string decryptString, string decryptKey) + { + try + { + byte[] bytes = Encoding.UTF8.GetBytes(decryptKey); + byte[] keys = Keys; + byte[] array = Convert.FromBase64String(decryptString); + DESCryptoServiceProvider dESCryptoServiceProvider = new DESCryptoServiceProvider(); + MemoryStream memoryStream = new MemoryStream(); + CryptoStream cryptoStream = new CryptoStream(memoryStream, dESCryptoServiceProvider.CreateDecryptor(bytes, keys), CryptoStreamMode.Write); + cryptoStream.Write(array, 0, array.Length); + cryptoStream.FlushFinalBlock(); + return Encoding.UTF8.GetString(memoryStream.ToArray()); + } + catch + { + return decryptString; + } + } + +/* + public static void RunScript(Page p, string sScript) + { + ClientScriptManager clientScript = p.ClientScript; + string script = ""; + clientScript.RegisterStartupScript(p.GetType(), "alertMessage", script); + } + + public static void Alert(Page p, string message) + { + ClientScriptManager clientScript = p.ClientScript; + string script = ""; + clientScript.RegisterClientScriptBlock(p.GetType(), "alertMessage", script); + } + + public static void Alert(Page p, string message, string derectPage) + { + ClientScriptManager clientScript = p.ClientScript; + string script = ""; + clientScript.RegisterClientScriptBlock(p.GetType(), "alertMessage", script); + } + + public static void Confirm(Page p, string message, string derectPage) + { + ClientScriptManager clientScript = p.ClientScript; + string script = ""; + clientScript.RegisterClientScriptBlock(p.GetType(), "alertMessage", script); + } + + public static void Confirm(string message, string url) + { + ClientScriptManager clientScript = ((Page)HttpContext.Current.Handler).ClientScript; + string script = ""; + clientScript.RegisterClientScriptBlock(((Page)HttpContext.Current.Handler).GetType(), "alertMessage", script); + } + + public static void Go(string url) + { + ClientScriptManager clientScript = ((Page)HttpContext.Current.Handler).ClientScript; + string script = ""; + clientScript.RegisterClientScriptBlock(((Page)HttpContext.Current.Handler).GetType(), "go", script); + } + + public static void GoParent(string url) + { + ClientScriptManager clientScript = ((Page)HttpContext.Current.Handler).ClientScript; + string script = ""; + clientScript.RegisterClientScriptBlock(((Page)HttpContext.Current.Handler).GetType(), "go", script); + } + + public static void GoParent(Page p, string url) + { + ClientScriptManager clientScript = p.ClientScript; + string script = ""; + clientScript.RegisterClientScriptBlock(p.GetType(), "go", script); + } + + public static void Back(Page p, int nFlag) + { + ClientScriptManager clientScript = p.ClientScript; + string script = ""; + clientScript.RegisterClientScriptBlock(p.GetType(), "back", script); + } +*/ + public static bool HasData(DataSet ds) + { + bool result = false; + if (ds != null) + { + int count = ds.Tables.Count; + if (count > 0) + { + int count2 = ds.Tables[0].Rows.Count; + if (count2 > 0) + { + result = true; + } + } + } + return result; + } + + /* + public static List GetCheckedAllControls(string checkedBoxId, GridView gv) + { + List list = new List(); + for (int i = 0; i < gv.Rows.Count; i++) + { + CheckBox checkBox = (CheckBox)gv.Rows[i].FindControl(checkedBoxId); + if (checkBox != null && checkBox.Checked) + { + list.Add(checkBox); + } + } + return list; + } + + public static List GetGetCheckedAllControlsAll(string checkedBoxId, Repeater gv) + { + List list = new List(); + for (int i = 0; i < gv.Items.Count; i++) + { + CheckBox checkBox = (CheckBox)gv.Items[i].FindControl(checkedBoxId); + if (checkBox != null) + { + list.Add(checkBox); + } + } + return list; + } + + public static List GetCheckedAllControls(string checkedBoxId, Repeater gv) + { + List list = new List(); + for (int i = 0; i < gv.Items.Count; i++) + { + CheckBox checkBox = (CheckBox)gv.Items[i].FindControl(checkedBoxId); + if (checkBox != null && checkBox.Checked) + { + list.Add(checkBox); + } + } + return list; + } + + public static void GetTreeViewCheckNodeAllList(TreeView treeview, List getList) + { + foreach (TreeNode node in treeview.Nodes) + { + getList.Add(node); + if (node.ChildNodes.Count > 0) + { + GetTreeViewNodeAll(node, getList); + } + } + } + + private static void GetTreeViewNodeAll(TreeNode ParentNode, List getList) + { + foreach (TreeNode childNode in ParentNode.ChildNodes) + { + getList.Add(childNode); + if (childNode.ChildNodes.Count > 0) + { + GetTreeViewNodeAll(childNode, getList); + } + } + } + + public static void GetTreeViewCheckNodeList(TreeView treeview, List getList) + { + foreach (TreeNode node in treeview.Nodes) + { + if (node.Checked) + { + getList.Add(node); + } + if (node.ChildNodes.Count > 0) + { + GetTreeViewNode(node, getList); + } + } + } + + private static void GetTreeViewNode(TreeNode ParentNode, List getList) + { + foreach (TreeNode childNode in ParentNode.ChildNodes) + { + if (childNode.Checked) + { + getList.Add(childNode); + } + if (childNode.ChildNodes.Count > 0) + { + GetTreeViewNode(childNode, getList); + } + } + } + + public static void UpdateMessage(ObjectDataSourceStatusEventArgs e, Label lblMessage) + { + if (e.Exception != null) + { + e.ExceptionHandled = true; + return; + } + int num = (int)e.ReturnValue; + if (num > 0) + { + lblMessage.Text = "编辑成功!"; + } + else if (num == 0) + { + lblMessage.Text = "请重试!"; + } + } + + public static void UpdateAlertMessage(ObjectDataSourceStatusEventArgs e, Page page) + { + if (e.Exception != null) + { + e.ExceptionHandled = true; + return; + } + int num = (int)e.ReturnValue; + if (num > 0) + { + Alert(page, "编辑成功!"); + } + else if (num == 0) + { + Alert(page, "请重试!"); + } + } + + public static void DeleteMessage(ObjectDataSourceStatusEventArgs e, Label lblMessage) + { + if (e.Exception != null) + { + e.ExceptionHandled = true; + return; + } + int num = (int)e.ReturnValue; + if (num > 0) + { + lblMessage.Text = "删除成功!"; + } + else if (num == 0) + { + lblMessage.Text = "请重试!"; + } + } + + public static List GetListControl(ListControl control) + { + List list = new List(); + for (int i = 0; i < control.Items.Count; i++) + { + if (control.Items[i].Selected) + { + list.Add(control.Items[i]); + } + } + return list; + } + + public static DataSet GetXMLDataSet(string key, string xml) + { + object obj = HttpContext.Current.Cache[key]; + if (obj == null) + { + DataSet dataSet = new DataSet(); + dataSet.ReadXml(xml); + HttpContext.Current.Cache.Insert(key, dataSet, new CacheDependency(xml)); + return dataSet; + } + return (DataSet)obj; + } + + */ + public static string Post(string Web, string postData) + { + string text = ""; + postData = postData.Replace(" ", "%20"); + try + { + HttpWebRequest httpWebRequest = (HttpWebRequest)WebRequest.Create(Web); + Stream stream = new MemoryStream(); + StreamWriter streamWriter = new StreamWriter(stream, Encoding.Default); + streamWriter.Write(postData); + streamWriter.Flush(); + long length = stream.Length; + streamWriter.Close(); + httpWebRequest.ContentType = "application/x-www-form-urlencoded"; + httpWebRequest.ContentLength = length; + httpWebRequest.Method = "POST"; + Stream requestStream = httpWebRequest.GetRequestStream(); + streamWriter = new StreamWriter(requestStream, Encoding.Default); + streamWriter.Write(postData); + streamWriter.Close(); + HttpWebResponse httpWebResponse = (HttpWebResponse)httpWebRequest.GetResponse(); + Stream responseStream = httpWebResponse.GetResponseStream(); + Encoding @default = Encoding.Default; + StreamReader streamReader = new StreamReader(responseStream, @default); + text = streamReader.ReadToEnd(); + streamReader.Close(); + httpWebResponse.Close(); + return text; + } + catch (Exception ex) + { + throw ex; + } + } + + private static string UrlEncode(string url, Encoding enc) + { + byte[] bytes = enc.GetBytes(url); + StringBuilder stringBuilder = new StringBuilder(); + for (int i = 0; i < bytes.Length; i++) + { + if (bytes[i] < 128) + { + stringBuilder.Append((char)bytes[i]); + continue; + } + stringBuilder.Append("%" + bytes[i++].ToString("x").PadLeft(2, '0')); + stringBuilder.Append("%" + bytes[i].ToString("x").PadLeft(2, '0')); + } + return stringBuilder.ToString(); + } + + public static string Get(string url, Encoding enc) + { + string requestUriString = UrlEncode(url, enc); + HttpWebRequest httpWebRequest = (HttpWebRequest)WebRequest.Create(requestUriString); + HttpWebResponse httpWebResponse = (HttpWebResponse)httpWebRequest.GetResponse(); + Stream responseStream = httpWebResponse.GetResponseStream(); + StreamReader streamReader = new StreamReader(responseStream, enc); + string result = streamReader.ReadToEnd(); + streamReader.Close(); + httpWebResponse.Close(); + return result; + } + + public static string Get(string url) + { + Encoding encoding = Encoding.GetEncoding("gb2312"); + return Get(UrlEncode(url, encoding), encoding); + } +/* + public static string RenderUserControl(string UserControlName) + { + StringBuilder stringBuilder = new StringBuilder(); + StringWriter writer = new StringWriter(stringBuilder); + HtmlTextWriter writer2 = new HtmlTextWriter(writer); + UserControl userControl = new UserControl(); + Control control = userControl.LoadControl(UserControlName); + control.RenderControl(writer2); + return stringBuilder.ToString(); + } + + public static void SetListControl(ListControl control, object oItemValue, int flag) + { + string b = string.Concat(oItemValue); + if (flag >= 0) + { + for (int i = 0; i < control.Items.Count; i++) + { + if (control.Items[i].Value == b) + { + control.Items[i].Selected = true; + } + else + { + control.Items[i].Selected = false; + } + } + return; + } + for (int i = 0; i < control.Items.Count; i++) + { + if (control.Items[i].Text == b) + { + control.Items[i].Selected = true; + } + else + { + control.Items[i].Selected = false; + } + } + } + + public static void SetListControlFuzz(ListControl control, object oItemValue) + { + string text = $"\uff3e{string.Concat(oItemValue)}\uff3e"; + int num = 0; + while (true) + { + if (num < control.Items.Count) + { + if ($"\uff3e{control.Items[num].Value}\uff3e".IndexOf(text.ToString()) == 0) + { + break; + } + control.Items[num].Selected = false; + num++; + continue; + } + return; + } + control.Items[num].Selected = true; + } +*/ + public static bool IsInt(string str) + { + Regex regex = new Regex("^[-]?\\d+$"); + return regex.IsMatch(str); + } + + public static bool IsNumeric(string str) + { + str.Trim(); + Regex regex = new Regex("^[-]?\\d+[.]?\\d*$"); + return regex.IsMatch(str); + } + + public static bool IsDateTime(string strValue) + { + if (null == strValue) + { + return false; + } + strValue = strValue.Trim(); + string pattern = "[1-2]{1}[0-9]{3}((-|\\/){1}(([0]?[1-9]{1})|(1[0-2]{1}))((-|\\/){1}((([0]?[1-9]{1})|([1-2]{1}[0-9]{1})|(3[0-1]{1})))( (([0-1]{1}[0-9]{1})|2[0-3]{1}):([0-5]{1}[0-9]{1}):([0-5]{1}[0-9]{1})(\\.[0-9]{3})?)?)?)?$"; + if (Regex.IsMatch(strValue, pattern)) + { + int num = -1; + int num2 = -1; + int num3 = -1; + if (-1 != (num = strValue.IndexOf("-"))) + { + num2 = strValue.IndexOf("-", num + 1); + num3 = strValue.IndexOf(":"); + } + else + { + num = strValue.IndexOf("/"); + num2 = strValue.IndexOf("/", num + 1); + num3 = strValue.IndexOf(":"); + } + if (-1 == num2) + { + return true; + } + if (-1 == num3) + { + num3 = strValue.Length + 3; + } + int num4 = Convert.ToInt32(strValue.Substring(0, num)); + int num5 = Convert.ToInt32(strValue.Substring(num + 1, num2 - num - 1)); + int num6 = Convert.ToInt32(strValue.Substring(num2 + 1, num3 - num2 - 4)); + if ((num5 < 8 && 1 == num5 % 2) || (num5 > 8 && 0 == num5 % 2)) + { + if (num6 < 32) + { + return true; + } + } + else if (num5 != 2) + { + if (num6 < 31) + { + return true; + } + } + else if (num4 % 400 == 0 || (num4 % 4 == 0 && 0 < num4 % 100)) + { + if (num6 < 30) + { + return true; + } + } + else if (num6 < 29) + { + return true; + } + } + return false; + } + + public static string DisplayBoolean(int boolFlag) + { + string result = string.Empty; + switch (boolFlag) + { + case 0: + result = "是"; + break; + case 1: + result = "否"; + break; + } + return result; + } + + public static string GetExtendName(string fileName) + { + string text = ""; + int num = fileName.LastIndexOf('.') + 1; + text = fileName.Substring(num, fileName.Length - num); + return text.ToLower(); + } +/* + public static void DownloadFileByFilePath(Page WebForm, string FileNameWhenUserDownload, string FilePath) + { + WebForm.Response.ContentType = "application/x-zip-compressed"; + WebForm.Response.AddHeader("Content-Disposition", "attachment;filename=" + FileNameWhenUserDownload); + WebForm.Response.TransmitFile(FilePath); + } + + public static string GetClientIP() + { + string text = HttpContext.Current.Request.ServerVariables["HTTP_X_FORWARDED_FOR"]; + if (text == null || text == string.Empty) + { + text = HttpContext.Current.Request.ServerVariables["REMOTE_ADDR"]; + } + if (text == null || text == string.Empty) + { + text = HttpContext.Current.Request.UserHostAddress; + } + return text; + } +*/ + } +} diff --git a/Common.GLib/GLib.Extension/FunctionEx.cs b/Common.GLib/GLib.Extension/FunctionEx.cs new file mode 100644 index 0000000..56e067e --- /dev/null +++ b/Common.GLib/GLib.Extension/FunctionEx.cs @@ -0,0 +1,1136 @@ +using System; +using System.Collections.Generic; +using System.Runtime.InteropServices; + +namespace GLib.Extension +{ + public static class FunctionEx + { + private static byte[] ArrayCRCHigh = new byte[256] + { + 0, + 193, + 129, + 64, + 1, + 192, + 128, + 65, + 1, + 192, + 128, + 65, + 0, + 193, + 129, + 64, + 1, + 192, + 128, + 65, + 0, + 193, + 129, + 64, + 0, + 193, + 129, + 64, + 1, + 192, + 128, + 65, + 1, + 192, + 128, + 65, + 0, + 193, + 129, + 64, + 0, + 193, + 129, + 64, + 1, + 192, + 128, + 65, + 0, + 193, + 129, + 64, + 1, + 192, + 128, + 65, + 1, + 192, + 128, + 65, + 0, + 193, + 129, + 64, + 1, + 192, + 128, + 65, + 0, + 193, + 129, + 64, + 0, + 193, + 129, + 64, + 1, + 192, + 128, + 65, + 0, + 193, + 129, + 64, + 1, + 192, + 128, + 65, + 1, + 192, + 128, + 65, + 0, + 193, + 129, + 64, + 0, + 193, + 129, + 64, + 1, + 192, + 128, + 65, + 1, + 192, + 128, + 65, + 0, + 193, + 129, + 64, + 1, + 192, + 128, + 65, + 0, + 193, + 129, + 64, + 0, + 193, + 129, + 64, + 1, + 192, + 128, + 65, + 1, + 192, + 128, + 65, + 0, + 193, + 129, + 64, + 0, + 193, + 129, + 64, + 1, + 192, + 128, + 65, + 0, + 193, + 129, + 64, + 1, + 192, + 128, + 65, + 1, + 192, + 128, + 65, + 0, + 193, + 129, + 64, + 0, + 193, + 129, + 64, + 1, + 192, + 128, + 65, + 1, + 192, + 128, + 65, + 0, + 193, + 129, + 64, + 1, + 192, + 128, + 65, + 0, + 193, + 129, + 64, + 0, + 193, + 129, + 64, + 1, + 192, + 128, + 65, + 0, + 193, + 129, + 64, + 1, + 192, + 128, + 65, + 1, + 192, + 128, + 65, + 0, + 193, + 129, + 64, + 1, + 192, + 128, + 65, + 0, + 193, + 129, + 64, + 0, + 193, + 129, + 64, + 1, + 192, + 128, + 65, + 1, + 192, + 128, + 65, + 0, + 193, + 129, + 64, + 0, + 193, + 129, + 64, + 1, + 192, + 128, + 65, + 0, + 193, + 129, + 64, + 1, + 192, + 128, + 65, + 1, + 192, + 128, + 65, + 0, + 193, + 129, + 64 + }; + + private static byte[] checkCRCLow = new byte[256] + { + 0, + 192, + 193, + 1, + 195, + 3, + 2, + 194, + 198, + 6, + 7, + 199, + 5, + 197, + 196, + 4, + 204, + 12, + 13, + 205, + 15, + 207, + 206, + 14, + 10, + 202, + 203, + 11, + 201, + 9, + 8, + 200, + 216, + 24, + 25, + 217, + 27, + 219, + 218, + 26, + 30, + 222, + 223, + 31, + 221, + 29, + 28, + 220, + 20, + 212, + 213, + 21, + 215, + 23, + 22, + 214, + 210, + 18, + 19, + 211, + 17, + 209, + 208, + 16, + 240, + 48, + 49, + 241, + 51, + 243, + 242, + 50, + 54, + 246, + 247, + 55, + 245, + 53, + 52, + 244, + 60, + 252, + 253, + 61, + 255, + 63, + 62, + 254, + 250, + 58, + 59, + 251, + 57, + 249, + 248, + 56, + 40, + 232, + 233, + 41, + 235, + 43, + 42, + 234, + 238, + 46, + 47, + 239, + 45, + 237, + 236, + 44, + 228, + 36, + 37, + 229, + 39, + 231, + 230, + 38, + 34, + 226, + 227, + 35, + 225, + 33, + 32, + 224, + 160, + 96, + 97, + 161, + 99, + 163, + 162, + 98, + 102, + 166, + 167, + 103, + 165, + 101, + 100, + 164, + 108, + 172, + 173, + 109, + 175, + 111, + 110, + 174, + 170, + 106, + 107, + 171, + 105, + 169, + 168, + 104, + 120, + 184, + 185, + 121, + 187, + 123, + 122, + 186, + 190, + 126, + 127, + 191, + 125, + 189, + 188, + 124, + 180, + 116, + 117, + 181, + 119, + 183, + 182, + 118, + 114, + 178, + 179, + 115, + 177, + 113, + 112, + 176, + 80, + 144, + 145, + 81, + 147, + 83, + 82, + 146, + 150, + 86, + 87, + 151, + 85, + 149, + 148, + 84, + 156, + 92, + 93, + 157, + 95, + 159, + 158, + 94, + 90, + 154, + 155, + 91, + 153, + 89, + 88, + 152, + 136, + 72, + 73, + 137, + 75, + 139, + 138, + 74, + 78, + 142, + 143, + 79, + 141, + 77, + 76, + 140, + 68, + 132, + 133, + 69, + 135, + 71, + 70, + 134, + 130, + 66, + 67, + 131, + 65, + 129, + 128, + 64 + }; + + public static string EmptyString(this string value) + { + return value.EmptyString(null); + } + + public static string EmptyString(this string value, string def) + { + if (value != null) + { + if (value.Trim() == "") + { + return def; + } + return value; + } + return def; + } + + public static decimal EmptyDecimal(this string value, decimal def = 0m) + { + if (value.EmptyString() == null) + { + return def; + } + return value.Convert(); + } + + public static int? EmptyInt(this string value) + { + if (value.EmptyString() == null) + { + return null; + } + return value.Convert(); + } + + public static int EmptyInt(this string value, int def = 0) + { + if (value.EmptyString() == null) + { + return def; + } + return value.Convert(); + } + + public static long? EmptyLong(this string value) + { + if (value.EmptyString() == null) + { + return null; + } + return value.Convert(); + } + + public static long EmptyLong(this string value, long def = 0L) + { + if (value.EmptyString() == null) + { + return def; + } + return value.Convert(); + } + + public static string EmptyString(this int? value, string def = "") + { + return value.HasValue ? string.Concat(value) : def; + } + + public static string EmptyString(this decimal? value, string def = "") + { + if (value.HasValue) + { + if (value.Value == 0m) + { + return "0"; + } + return value.Value.ToString("G0"); + } + return def; + } + + public static string EmptyString(this long? value, string def = "") + { + return value.HasValue ? string.Concat(value) : def; + } + + public static string EmptyString(this DateTime? value, string def = "") + { + return value.HasValue ? value.ToDateTime() : def; + } + + public static string EmptyString(this object value, string def = "") + { + if (value != null && (value is decimal || value is decimal)) + { + if (value is decimal?) + { + return ((decimal?)value).EmptyString(); + } + return EmptyString((decimal)value); + } + return string.Concat(value).EmptyString(def); + } + + public static DateTime? EmptyDateTime(this string value) + { + if (value.EmptyString() == null) + { + return null; + } + return value.Convert(); + } + + public static DateTime EmptyDateTime(this string value, DateTime def) + { + if (value.EmptyString() == null) + { + return def; + } + return value.Convert(); + } + + public static T NullType(T? value) where T : struct + { + return NullType(value, default(T)); + } + + public static T NullType(T? value, T def) where T : struct + { + if (value.HasValue) + { + return value.Value; + } + return def; + } + + public static int NullInt(this int? value) + { + return NullType(value, 0); + } + + public static int NullInt(this int? value, int def) + { + return NullType(value, def); + } + + public static int NullInt(this object value, int def = 0) + { + if (value is int) + { + return (int)value; + } + if (value is int?) + { + if (((int?)value).HasValue) + { + return ((int?)value).Value; + } + return def; + } + if (value is string) + { + return ((string)value).EmptyInt(def); + } + return def; + } + + public static decimal NullDecimal(this decimal? value) + { + return NullType(value, 0m); + } + + public static decimal NullDecimal(this decimal? value, decimal def) + { + return NullType(value, def); + } + + public static decimal NullDecimal(this object value, long def = 0L) + { + if (value is decimal) + { + return (decimal)value; + } + if (value is decimal?) + { + if (((decimal?)value).HasValue) + { + return ((decimal?)value).Value; + } + return def; + } + if (value is string) + { + return ((string)value).EmptyDecimal(def); + } + return def; + } + + public static long NullLong(this long? value) + { + return NullType(value, 0L); + } + + public static long NullLong(this long? value, long def) + { + return NullType(value, def); + } + + public static long NullLong(this object value, long def = 0L) + { + if (value is long) + { + return (long)value; + } + if (value is long?) + { + if (((long?)value).HasValue) + { + return ((long?)value).Value; + } + return def; + } + if (value is string) + { + return ((string)value).EmptyLong(def); + } + return def; + } + + public static bool NullBool(this bool? value) + { + return value.NullBool(def: false); + } + + public static bool NullBool(this bool? value, bool def = false) + { + if (value.HasValue) + { + return value.Value; + } + return def; + } + + public static bool NullBool(this object value, bool def = false) + { + if (value is bool) + { + return (bool)value; + } + if (value is bool?) + { + if (((bool?)value).HasValue) + { + return ((bool?)value).Value; + } + return def; + } + return def; + } + + public static T Convert(this object value) + { + return value.Convert(showError: true); + } + + public static T Convert(this object value, bool showError) + { + Exception ex = null; + T outValue = default(T); + if (!value.Convert(out outValue, out ex) && showError) + { + throw ex; + } + return outValue; + } + + public static bool Convert(this object value, out T outValue) + { + Exception ex = null; + return value.Convert(out outValue, out ex); + } + + public static T Convert(this object value, string message) + { + T val = default(T); + try + { + return value.Convert(); + } + catch + { + throw new ArgumentException(message); + } + } + + private static bool Convert(this object value, out T outValue, out Exception ex) + { + bool result = false; + ex = null; + try + { + Type typeFromHandle = typeof(T); + if (value is T) + { + outValue = (T)value; + } + else if (typeFromHandle.IsEnum) + { + outValue = (T)Enum.Parse(typeof(T), value.ToString(), ignoreCase: true); + } + else + { + outValue = (T)System.Convert.ChangeType(value, typeof(T)); + } + result = true; + } + catch (Exception ex2) + { + Exception ex3 = ex = ex2; + outValue = default(T); + } + return result; + } + + public static T Convert(this string value) + { + return ((object)value).Convert(); + } + + public static T[] Convert(this Array Collection) + { + List list = new List(); + foreach (object item in Collection) + { + list.Add(item.Convert()); + } + return list.ToArray(); + } + + public static T Convert(this IEnumerable items) where T : ICollection, new() + { + T result = new T(); + foreach (U item in items) + { + result.Add(item); + } + return result; + } + + public static T BytesToStruct(byte[] bytes, int startIndex, int length) + { + if (bytes == null) + { + return default(T); + } + if (bytes.Length <= 0) + { + return default(T); + } + IntPtr intPtr = Marshal.AllocHGlobal(length); + try + { + Marshal.Copy(bytes, startIndex, intPtr, length); + return (T)Marshal.PtrToStructure(intPtr, typeof(T)); + } + catch (Exception ex) + { + throw new Exception("Error in BytesToStruct ! " + ex.Message); + } + finally + { + Marshal.FreeHGlobal(intPtr); + } + } + + public static T BytesToStruct(byte[] bytes) + { + return BytesToStruct(bytes, 0, bytes.Length); + } + + public static byte[] StructToBytes(object structObj, int size) + { + IntPtr intPtr = Marshal.AllocHGlobal(size); + try + { + Marshal.StructureToPtr(structObj, intPtr, fDeleteOld: false); + byte[] array = new byte[size]; + Marshal.Copy(intPtr, array, 0, size); + return array; + } + catch (Exception ex) + { + throw new Exception("Error in StructToBytes ! " + ex.Message); + } + finally + { + Marshal.FreeHGlobal(intPtr); + } + } + + public static byte[] StructToBytes(object structObj) + { + int size = Marshal.SizeOf(structObj); + return StructToBytes(structObj, size); + } + + public static IntPtr StructToIntPtr(object structObj) + { + byte[] buff = StructToBytes(structObj); + return BytesToIntPtr(buff); + } + + public static T IntPtrToStruct(IntPtr intptr) + { + int index = 0; + int length = Marshal.SizeOf(typeof(T)); + return IntPtrToStruct(intptr, index, length); + } + + public static T IntPtrToStruct(IntPtr intptr, int index, int length) + { + byte[] array = new byte[length]; + Marshal.Copy(intptr, array, index, length); + return BytesToStruct(array, 0, array.Length); + } + + public static IntPtr BytesToIntPtr(byte[] buff) + { + IntPtr intPtr = Marshal.AllocHGlobal(buff.Length); + Marshal.Copy(buff, 0, intPtr, buff.Length); + return intPtr; + } + + public static byte[] IntPtrToBytes(IntPtr intptr, int index, int length) + { + byte[] array = new byte[length]; + Marshal.Copy(intptr, array, index, length); + return array; + } + + public static void IntPtrSetValue(IntPtr intptr, object structObj) + { + IntPtrSetValue(intptr, StructToBytes(structObj)); + } + + public static void IntPtrSetValue(IntPtr intptr, byte[] bytes) + { + Marshal.Copy(bytes, 0, intptr, bytes.Length); + } + + public static long GetHashNum(this Guid guid) + { + return guid.ToString().Replace("-", "").GetHashNum(); + } + + public static long GetHashNum(this string szStr) + { + long num = 5381L; + foreach (int num2 in szStr) + { + num = (((num << 5) + num) ^ num2); + } + return num; + } + + public static long GenerateUniqueCode() + { + return Guid.NewGuid().ToString().Replace("-", "") + .GetHashNum(); + } + + public static string ToDateTime(this DateTime? time) + { + return (!time.HasValue) ? "" : time.Value.ToString("yyyy-MM-dd"); + } + + public static string ToDisplayTime(this DateTime? time) + { + return (!time.HasValue) ? "" : time.Value.ToString("yyyy年MM月dd日"); + } + + public static string ToDisplayTime(this DateTime time) + { + return time.ToString("yyyy年MM月dd日"); + } + + public static string ToDateTime(this DateTime time) + { + return time.ToString("yyyy-MM-dd"); + } + + public static string ToDecimalString(this decimal? d) + { + string result = ""; + if (d.HasValue) + { + result = d.ToString(); + } + return result; + } + + public static string ToIntString(this int? n) + { + string result = ""; + if (n.HasValue) + { + result = n.ToString(); + } + return result; + } + + public static string ToSString(this string ss) + { + string result = ""; + if (!string.IsNullOrEmpty(ss)) + { + result = ss; + } + return result; + } + + public static string ToDateTime(this object time) + { + if (time is DateTime) + { + return ((DateTime)time).ToString("yyyy-MM-dd"); + } + if (time is DateTime? && ((DateTime?)time).HasValue) + { + return ((DateTime?)time).Value.ToString("yyyy-MM-dd"); + } + return null; + } + + public static bool IsNotNull(this string s) + { + return !string.IsNullOrEmpty(s); + } + + public static bool IsNullOrEmpty(this string s) + { + return string.IsNullOrEmpty(s); + } + + public static byte[] ToByteArray(short[] src) + { + int num = src.Length * 2; + IntPtr intPtr = Marshal.AllocHGlobal(num); + Marshal.Copy(src, 0, intPtr, src.Length); + byte[] array = new byte[num]; + Marshal.Copy(intPtr, array, 0, num); + Marshal.FreeHGlobal(intPtr); + return array; + } + + public static byte[] ToByteArray(int[] src) + { + int num = src.Length * 4; + IntPtr intPtr = Marshal.AllocHGlobal(num); + Marshal.Copy(src, 0, intPtr, src.Length); + byte[] array = new byte[num]; + Marshal.Copy(intPtr, array, 0, num); + Marshal.FreeHGlobal(intPtr); + return array; + } + + public static short[] ToShortArray(byte[] src) + { + int num = (src.Length % 2 == 0) ? (src.Length / 2) : (src.Length / 2 + 1); + IntPtr intPtr = Marshal.AllocHGlobal(src.Length); + Marshal.Copy(src, 0, intPtr, src.Length); + short[] array = new short[num]; + Marshal.Copy(intPtr, array, 0, array.Length); + Marshal.FreeHGlobal(intPtr); + return array; + } + + public static int[] ToIntArray(byte[] src) + { + int num = (src.Length % 4 == 0) ? (src.Length / 4) : (src.Length / 4 + 1); + IntPtr intPtr = Marshal.AllocHGlobal(src.Length); + Marshal.Copy(src, 0, intPtr, src.Length); + int[] array = new int[num]; + Marshal.Copy(intPtr, array, 0, array.Length); + Marshal.FreeHGlobal(intPtr); + return array; + } + + public static short CRC16(this byte[] data) + { + return CRC16(data, data.Length); + } + + public static short CRC16(byte[] data, int arrayLength) + { + byte b = byte.MaxValue; + byte b2 = byte.MaxValue; + int num = 0; + while (arrayLength-- > 0) + { + byte b3 = (byte)(b ^ data[num++]); + b = (byte)(b2 ^ ArrayCRCHigh[b3]); + b2 = checkCRCLow[b3]; + } + return (short)((b << 8) | b2); + } + } +} diff --git a/Common.GLib/GLib.Extension/ReflectionEx.cs b/Common.GLib/GLib.Extension/ReflectionEx.cs new file mode 100644 index 0000000..4808867 --- /dev/null +++ b/Common.GLib/GLib.Extension/ReflectionEx.cs @@ -0,0 +1,174 @@ +using System; +using System.Linq; +using System.Reflection; + +namespace GLib.Extension +{ + public static class ReflectionEx + { + public static void EvaluationByFields(object o1, object o2) + { + EvaluationByFields(o1, o2, null); + } + + public static void EvaluationByFields(object o1, object o2, Type attType) + { + if (o1 == null || o2 == null) + { + throw new Exception(); + } + Type type = o1.GetType(); + Type type2 = o2.GetType(); + FieldInfo[] array = type.GetFields(); + if (attType != null) + { + array = type.GetAttributeFields(attType).ToArray(); + } + FieldInfo[] array2 = type2.GetFields(); + if (attType != null) + { + array2 = type2.GetAttributeFields(attType).ToArray(); + } + FieldInfo[] array3 = array; + foreach (FieldInfo f1 in array3) + { + FieldInfo[] source = array2; + Func predicate = (FieldInfo p) => p.Name == f1.Name; + FieldInfo fieldInfo = source.FirstOrDefault(predicate); + if (fieldInfo != null) + { + f1.SetValue(o1, fieldInfo.GetValue(o2)); + } + } + } + + public static void RefSetFieldsByFields(object dts, object src) + { + RefSetFieldsByFields(dts, src, null); + } + + public static void RefSetFieldsByFields(object dts, object src, Type attType) + { + if (dts == null || src == null) + { + throw new Exception(); + } + Type type = dts.GetType(); + Type type2 = src.GetType(); + FieldInfo[] array = type.GetFields(); + if (attType != null) + { + array = type.GetAttributeFields(attType).ToArray(); + } + FieldInfo[] array2 = type2.GetFields(); + if (attType != null) + { + array2 = type2.GetAttributeFields(attType).ToArray(); + } + FieldInfo[] array3 = array; + foreach (FieldInfo f1 in array3) + { + FieldInfo[] source = array2; + Func predicate = (FieldInfo p) => p.Name == f1.Name; + FieldInfo fieldInfo = source.FirstOrDefault(predicate); + if (fieldInfo != null) + { + f1.SetValue(dts, fieldInfo.GetValue(src)); + } + } + } + + public static void RefSetPropertiesByProperties(object o1, object o2, Type attType) + { + if (o1 == null || o2 == null) + { + throw new Exception(); + } + Type type = o1.GetType(); + Type type2 = o2.GetType(); + PropertyInfo[] array = type.GetProperties(); + if (attType != null) + { + array = type.GetAttributeProperties(attType).ToArray(); + } + PropertyInfo[] array2 = type2.GetProperties(); + if (attType != null) + { + array2 = type2.GetAttributeProperties(attType).ToArray(); + } + PropertyInfo[] array3 = array; + foreach (PropertyInfo f1 in array3) + { + PropertyInfo[] source = array2; + Func predicate = (PropertyInfo p) => p.Name == f1.Name; + PropertyInfo propertyInfo = source.FirstOrDefault(predicate); + if (propertyInfo != null) + { + f1.SetValue(o1, propertyInfo.GetValue(o2, null), null); + } + } + } + + public static void RefSetFieldsByProperties(object o1, object o2, Type attType) + { + if (o1 == null || o2 == null) + { + throw new Exception(); + } + Type type = o1.GetType(); + Type type2 = o2.GetType(); + FieldInfo[] array = type.GetFields(); + if (attType != null) + { + array = type.GetAttributeFields(attType).ToArray(); + } + PropertyInfo[] array2 = type2.GetProperties(); + if (attType != null) + { + array2 = type2.GetAttributeProperties(attType).ToArray(); + } + FieldInfo[] array3 = array; + foreach (FieldInfo f1 in array3) + { + PropertyInfo[] source = array2; + Func predicate = (PropertyInfo p) => p.Name == f1.Name; + PropertyInfo propertyInfo = source.FirstOrDefault(predicate); + if (propertyInfo != null) + { + f1.SetValue(o1, propertyInfo.GetValue(o2, null)); + } + } + } + + public static void RefSetPropertiesByFields(object o1, object o2, Type attType) + { + if (o1 == null || o2 == null) + { + throw new Exception(); + } + Type type = o1.GetType(); + Type type2 = o2.GetType(); + PropertyInfo[] array = type.GetProperties(); + if (attType != null) + { + array = type.GetAttributeProperties(attType).ToArray(); + } + FieldInfo[] array2 = type2.GetFields(); + if (attType != null) + { + array2 = type.GetAttributeFields(attType).ToArray(); + } + PropertyInfo[] array3 = array; + foreach (PropertyInfo f1 in array3) + { + FieldInfo[] source = array2; + Func predicate = (FieldInfo p) => p.Name == f1.Name; + FieldInfo fieldInfo = source.FirstOrDefault(predicate); + if (fieldInfo != null) + { + f1.SetValue(o1, fieldInfo.GetValue(o2), null); + } + } + } + } +} diff --git a/Common.GLib/GLib.Extension/Singleton.cs b/Common.GLib/GLib.Extension/Singleton.cs new file mode 100644 index 0000000..b548343 --- /dev/null +++ b/Common.GLib/GLib.Extension/Singleton.cs @@ -0,0 +1,27 @@ +namespace GLib.Extension +{ + public class Singleton where T : new() + { + private static T instance__ = default(T); + + private static object syncRoot__ = new object(); + + public static T Instance + { + get + { + if (instance__ == null) + { + lock (syncRoot__) + { + if (instance__ == null) + { + instance__ = new T(); + } + } + } + return instance__; + } + } + } +} diff --git a/Common.GLib/GLib.Extension/StringEx.cs b/Common.GLib/GLib.Extension/StringEx.cs new file mode 100644 index 0000000..828abd7 --- /dev/null +++ b/Common.GLib/GLib.Extension/StringEx.cs @@ -0,0 +1,263 @@ +using Newtonsoft.Json; +using Newtonsoft.Json.Converters; +using System; +using System.Collections; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace GLib.Extension +{ + public static class StringEx + { + public static string _Format(this string str, string format) + { + return string.Format(format, str); + } + + public static string CutString(this string inputString, int len) + { + ASCIIEncoding aSCIIEncoding = new ASCIIEncoding(); + int num = 0; + string text = ""; + byte[] bytes = aSCIIEncoding.GetBytes(inputString); + for (int i = 0; i < bytes.Length; i++) + { + num = ((bytes[i] != 63) ? (num + 1) : (num + 2)); + try + { + text += inputString.Substring(i, 1); + } + catch + { + break; + } + if (num > len) + { + break; + } + } + byte[] bytes2 = Encoding.Default.GetBytes(inputString); + if (bytes2.Length > len) + { + text += "..."; + } + return text; + } + + public static string CutString(this object inputString, int len) + { + return string.Concat(inputString).CutString(len); + } + + public static string ConstituteString(this IEnumerable items, string splitKey) + { + string text = ""; + foreach (object item in items) + { + if (item != null) + { + text = string.Concat(text, (text == "") ? "" : splitKey, string.Concat(item)); + } + } + return text; + } + + public static string ConstituteString(this IEnumerable items) + { + return items.ConstituteString(","); + } + + public static bool EqIgnoreCase(this string source, string value) + { + if (source == value) + { + return true; + } + return source?.Equals(value, StringComparison.OrdinalIgnoreCase) ?? false; + } + + public static T[] Split(this string source, string splitKey = ",") + { + if (string.IsNullOrEmpty(source)) + { + return new T[0]; + } + return Enumerable.ToArray(Enumerable.Select(source.Split(new string[1] + { + splitKey + }, StringSplitOptions.RemoveEmptyEntries), (string p) => p.Convert())); + } + + public static string UrlFilter(this string url, string filter) + { + return new Uri(url).UrlFilter(filter); + } + + public static string UrlFilter(this Uri url, string filter) + { + string text = ""; + string[] array = url.Query.Replace("?", "").Split("&"); + string[] array2 = array; + foreach (string text2 in array2) + { + string[] array3 = text2.Split("="); + string source = ""; + string text3 = ""; + if (array3.Length > 0) + { + source = array3[0]; + } + if (array3.Length > 1) + { + text3 = array3[1]; + } + if (!source.EqIgnoreCase(filter)) + { + text = text + ((text == "") ? "" : "&") + text2; + } + } + if (text == "") + { + text = "1=1"; + } + string result = url.AbsoluteUri + "?" + text; + if (url.Query != "") + { + result = url.AbsoluteUri.Replace(url.Query, "") + "?" + text; + } + return result; + } + + public static string To16Str(this byte b) + { + return Convert.ToString(b, 16).PadLeft(2, '0'); + } + + public static byte To16Byte(this string s) + { + return Convert.ToByte(s, 16); + } + + public static string To16Strs(this byte[] bs) + { + return bs.To16Strs(0, bs.Length); + } + + public static string To16Strs(this byte[] bs, int offset, int len) + { + StringBuilder stringBuilder = new StringBuilder(); + foreach (byte item in Enumerable.Take(Enumerable.Skip(bs, offset), len)) + { + stringBuilder.Append(item.To16Str() + " "); + } + return stringBuilder.ToString(); + } + + public static byte[] To16Bytes(this string s) + { + List list = new List(); + string[] array = s.Split(new string[1] + { + " " + }, StringSplitOptions.RemoveEmptyEntries); + string[] array2 = array; + foreach (string s2 in array2) + { + list.Add(s2.To16Byte()); + } + return list.ToArray(); + } + + public static string ToSystemPath(this string path) + { + if (Environment.OSVersion.Platform == PlatformID.Unix) + { + return path.Replace("\\", "/"); + } + return path.Replace("/", "\\"); + } + + public static string JsonConvert(this object o) + { + IsoDateTimeConverter isoDateTimeConverter = new IsoDateTimeConverter(); + isoDateTimeConverter.DateTimeFormat = "yyyy-MM-dd HH:mm:ss.fff"; + return Newtonsoft.Json.JsonConvert.SerializeObject(o, Formatting.Indented, isoDateTimeConverter); + } + + public static string JsonConvert(this object o, bool isIndented) + { + return Newtonsoft.Json.JsonConvert.SerializeObject(o, isIndented ? Formatting.Indented : Formatting.None); + } + + public static T JsonConvert(this string str) + { + return Newtonsoft.Json.JsonConvert.DeserializeObject(str); + } + + public static object JsonConvert(this string str, Type type) + { + return Newtonsoft.Json.JsonConvert.DeserializeObject(str, type); + } + + public static T JsonConvert(this string str, T obj) + { + return Newtonsoft.Json.JsonConvert.DeserializeAnonymousType(str, obj); + } + + public static string StringToBase64String(this string value) + { + byte[] bytes = new UnicodeEncoding().GetBytes(value); + int num = (int)Math.Ceiling((double)bytes.Length / 3.0) * 4; + char[] array = new char[num]; + Convert.ToBase64CharArray(bytes, 0, bytes.Length, array, 0); + return new string(array); + } + + public static string Base64StringToString(this string base64) + { + char[] array = base64.ToCharArray(); + byte[] bytes = Convert.FromBase64CharArray(array, 0, array.Length); + return new UnicodeEncoding().GetString(bytes); + } + + public static string ToBase64(this byte[] binBuffer) + { + return binBuffer.ToBase64(0, binBuffer.Length); + } + + public static string ToBase64(this byte[] binBuffer, int offset, int count) + { + int num = (int)Math.Ceiling((double)count / 3.0) * 4; + char[] array = new char[num]; + Convert.ToBase64CharArray(binBuffer, offset, count, array, 0); + return new string(array); + } + + public static byte[] Base64ToBytes(this string base64) + { + char[] array = base64.ToCharArray(); + return Convert.FromBase64CharArray(array, 0, array.Length); + } + + public static byte[] ToUTF8Bytes(this string value) + { + return Encoding.UTF8.GetBytes(value); + } + + public static string ToUTF8String(this byte[] bytes) + { + return Encoding.UTF8.GetString(bytes); + } + + public static string ToUTF8String(this byte[] bytes, int offset, int count) + { + return Encoding.UTF8.GetString(bytes, offset, count); + } + + public static string EmptyString(string str1, string str2) + { + return str1.EmptyString(str2); + } + } +} diff --git a/Common.GLib/GLib.Extension/TypeEx.cs b/Common.GLib/GLib.Extension/TypeEx.cs new file mode 100644 index 0000000..b8096f8 --- /dev/null +++ b/Common.GLib/GLib.Extension/TypeEx.cs @@ -0,0 +1,57 @@ +using System; +using System.Collections.Generic; +using System.Reflection; + +namespace GLib.Extension +{ + public static class TypeEx + { + public static List GetAttributeProperties(this Type type, Type attType) + { + PropertyInfo[] properties = type.GetProperties(); + List list = new List(); + PropertyInfo[] array = properties; + foreach (PropertyInfo propertyInfo in array) + { + object[] customAttributes = propertyInfo.GetCustomAttributes(attType, inherit: true); + if (customAttributes.Length > 0) + { + list.Add(propertyInfo); + } + } + return list; + } + + public static List GetAttributeFields(this Type type, Type attType) + { + FieldInfo[] fields = type.GetFields(); + List list = new List(); + FieldInfo[] array = fields; + foreach (FieldInfo fieldInfo in array) + { + object[] customAttributes = fieldInfo.GetCustomAttributes(attType, inherit: true); + if (customAttributes.Length > 0) + { + list.Add(fieldInfo); + } + } + return list; + } + + public static List GetAttributeMembers(this Type type, Type attType) + { + MemberInfo[] members = type.GetMembers(); + List list = new List(); + MemberInfo[] array = members; + foreach (MemberInfo memberInfo in array) + { + object[] customAttributes = memberInfo.GetCustomAttributes(attType, inherit: true); + if (customAttributes.Length > 0) + { + list.Add(memberInfo); + } + } + return list; + } + } +} diff --git a/Common.GLib/GLib.GeneralModel/AQueue.cs b/Common.GLib/GLib.GeneralModel/AQueue.cs new file mode 100644 index 0000000..6eb61a1 --- /dev/null +++ b/Common.GLib/GLib.GeneralModel/AQueue.cs @@ -0,0 +1,75 @@ +using System.Collections.Generic; + +namespace GLib.GeneralModel +{ + public class AQueue : Queue + { + private object _lock = new object(); + + public new int Count + { + get + { + lock (_lock) + { + return base.Count; + } + } + } + + public AQueue() + { + } + + public AQueue(IEnumerable collection) + : base(collection) + { + } + + public AQueue(int capacity) + : base(capacity) + { + } + + public new T Dequeue() + { + lock (_lock) + { + return base.Dequeue(); + } + } + + public new void Enqueue(T item) + { + lock (_lock) + { + base.Enqueue(item); + } + } + + public new T Peek() + { + lock (_lock) + { + if (base.Count == 0) + { + return default(T); + } + return base.Peek(); + } + } + + public new T[] ToArray() + { + lock (_lock) + { + return base.ToArray(); + } + } + + public object GetLock() + { + return _lock; + } + } +} diff --git a/Common.GLib/GLib.GeneralModel/EventArgsEx.cs b/Common.GLib/GLib.GeneralModel/EventArgsEx.cs new file mode 100644 index 0000000..9972a57 --- /dev/null +++ b/Common.GLib/GLib.GeneralModel/EventArgsEx.cs @@ -0,0 +1,18 @@ +using System; + +namespace GLib.GeneralModel +{ + public class EventArgsEx : EventArgs + { + public T Arg + { + get; + private set; + } + + public EventArgsEx(T arg) + { + Arg = arg; + } + } +} diff --git a/Common.GLib/GLib.GeneralModel/KeyValue.cs b/Common.GLib/GLib.GeneralModel/KeyValue.cs new file mode 100644 index 0000000..faa87fc --- /dev/null +++ b/Common.GLib/GLib.GeneralModel/KeyValue.cs @@ -0,0 +1,43 @@ +using System; + +namespace GLib.GeneralModel +{ + [Serializable] + public class KeyValue + { + public TKey Key + { + get; + set; + } + + public UValue Value + { + get; + set; + } + + public KeyValue() + { + } + + public KeyValue(TKey key, UValue value) + { + Key = key; + Value = value; + } + + public override string ToString() + { + if (Value != null) + { + return Value.ToString(); + } + if (Key != null) + { + return Key.ToString(); + } + return base.ToString(); + } + } +} diff --git a/Common.GLib/GLib.GeneralModel/KeyValueList.cs b/Common.GLib/GLib.GeneralModel/KeyValueList.cs new file mode 100644 index 0000000..ba7b6da --- /dev/null +++ b/Common.GLib/GLib.GeneralModel/KeyValueList.cs @@ -0,0 +1,44 @@ +using System; +using System.Collections.Generic; +using System.Linq; + +namespace GLib.GeneralModel +{ + [Serializable] + public class KeyValueList : List> + { + public UValue this[TKey key] + { + get + { + KeyValue keyValue = Enumerable.FirstOrDefault(this, (KeyValue p) => p.Key.Equals(key)); + if (keyValue != null) + { + return keyValue.Value; + } + return default(UValue); + } + set + { + KeyValue keyValue = Enumerable.FirstOrDefault(this, (KeyValue p) => p.Key.Equals(key)); + if (keyValue != null) + { + keyValue.Value = value; + } + else + { + Add(new KeyValue(key, value)); + } + } + } + + public KeyValueList() + { + } + + public KeyValueList(IEnumerable> collection) + : base(collection) + { + } + } +} diff --git a/Common.GLib/GLib.GeneralModel/ListEx.cs b/Common.GLib/GLib.GeneralModel/ListEx.cs new file mode 100644 index 0000000..0638c93 --- /dev/null +++ b/Common.GLib/GLib.GeneralModel/ListEx.cs @@ -0,0 +1,16 @@ +using System.Collections.Generic; + +namespace GLib.GeneralModel +{ + public class ListEx : List + { + public ListEx() + { + } + + public ListEx(IEnumerable collection) + : base(collection) + { + } + } +} diff --git a/Common.GLib/GLib.GeneralModel/TreeNode.cs b/Common.GLib/GLib.GeneralModel/TreeNode.cs new file mode 100644 index 0000000..24837e9 --- /dev/null +++ b/Common.GLib/GLib.GeneralModel/TreeNode.cs @@ -0,0 +1,101 @@ +using System; +using System.Collections.Generic; +using System.Linq; + +namespace GLib.GeneralModel +{ + public class TreeNode + { + public TKey Key + { + get; + set; + } + + public UValue Value + { + get; + set; + } + + public TKey ParentKey + { + get; + set; + } + + public TreeNode Parent + { + get; + set; + } + + public List> Childs + { + get; + set; + } + + public virtual TreeNode this[TKey key] => GetValue(key); + + public TreeNode(TKey key, UValue value, TKey parentKey) + { + Key = key; + Value = value; + ParentKey = parentKey; + Childs = new List>(); + } + + public TreeNode(List> list) + { + Init(list, default(TKey)); + } + + public TreeNode(List> list, TKey rootKey) + { + Init(list, rootKey); + } + + protected void Init(List> list, TKey rootKey) + { + TreeNode treeNode = Enumerable.FirstOrDefault(list, (TreeNode p) => p.Key.Equals(rootKey)); + if (treeNode == null) + { + throw new ApplicationException("parent no find"); + } + Key = treeNode.Key; + Value = treeNode.Value; + ParentKey = treeNode.ParentKey; + IEnumerable> enumerable = Enumerable.Where(list, (TreeNode p) => p.ParentKey.Equals(rootKey)); + Childs = new List>(); + foreach (TreeNode item2 in enumerable) + { + TreeNode treeNode2 = new TreeNode(list, item2.Key); + treeNode2.Parent = this; + TreeNode item = treeNode2; + Childs.Add(item); + } + } + + public virtual TreeNode GetValue(TKey key) + { + TreeNode treeNode = null; + if (Key.Equals(key)) + { + treeNode = this; + } + else + { + foreach (TreeNode child in Childs) + { + treeNode = child.GetValue(key); + if (treeNode != null) + { + break; + } + } + } + return treeNode; + } + } +} diff --git a/Common.GLib/GLib.GeneralModel/TreeRoot.cs b/Common.GLib/GLib.GeneralModel/TreeRoot.cs new file mode 100644 index 0000000..a3ce2d2 --- /dev/null +++ b/Common.GLib/GLib.GeneralModel/TreeRoot.cs @@ -0,0 +1,63 @@ +using System.Collections.Generic; +using System.Linq; + +namespace GLib.GeneralModel +{ + public class TreeRoot : TreeNode + { + public List> SourceList + { + get; + set; + } + + public override TreeNode this[TKey key] => GetValue(key); + + public TreeRoot(TKey defKey, UValue value, List> list) + : base(default(TKey), default(UValue), default(TKey)) + { + init(defKey, value, list); + } + + public TreeRoot(List> list) + : base(default(TKey), default(UValue), default(TKey)) + { + init(default(TKey), default(UValue), list); + } + + private void init(TKey defKey, UValue value, List> list) + { + SourceList = list; + IEnumerable> enumerable = Enumerable.Where(list, (TreeNode p) => p.ParentKey.Equals(defKey)); + base.Childs = new List>(); + foreach (TreeNode item2 in enumerable) + { + TreeNode treeNode = new TreeNode(list, item2.Key); + treeNode.Parent = this; + TreeNode item = treeNode; + base.Childs.Add(item); + } + } + + public override TreeNode GetValue(TKey key) + { + TreeNode treeNode = null; + if (base.Key != null && base.Key.Equals(key)) + { + treeNode = this; + } + else + { + foreach (TreeNode child in base.Childs) + { + treeNode = child.GetValue(key); + if (treeNode != null) + { + break; + } + } + } + return treeNode; + } + } +} diff --git a/Common.GLib/GLib.IO/BitStream.cs b/Common.GLib/GLib.IO/BitStream.cs new file mode 100644 index 0000000..69ab31b --- /dev/null +++ b/Common.GLib/GLib.IO/BitStream.cs @@ -0,0 +1,2615 @@ +using System; +using System.Globalization; +using System.IO; +using System.Net.Sockets; +using System.Resources; +using System.Security.Cryptography; +using System.Text; + +namespace GLib.IO +{ + public class BitStream : Stream + { + private sealed class BitStreamResources + { + private static ResourceManager _resman; + + private static object _oResManLock; + + private static bool _blnLoadingResource; + + private static void InitialiseResourceManager() + { + if (_resman == null) + { + lock (typeof(BitStreamResources)) + { + if (_resman == null) + { + _oResManLock = new object(); + _resman = new ResourceManager("BKSystem.IO.BitStream", typeof(BitStream).Assembly); + } + } + } + } + + public static string GetString(string name) + { + if (_resman == null) + { + InitialiseResourceManager(); + } + string @string; + lock (_oResManLock) + { + if (_blnLoadingResource) + { + return "The resource manager was unable to load the resource: " + name; + } + _blnLoadingResource = true; + @string = _resman.GetString(name, null); + _blnLoadingResource = false; + } + return @string; + } + } + + private const int SizeOfByte = 8; + + private const int SizeOfChar = 128; + + private const int SizeOfUInt16 = 16; + + private const int SizeOfUInt32 = 32; + + private const int SizeOfSingle = 32; + + private const int SizeOfUInt64 = 64; + + private const int SizeOfDouble = 64; + + private const uint BitBuffer_SizeOfElement = 32u; + + private const int BitBuffer_SizeOfElement_Shift = 5; + + private const uint BitBuffer_SizeOfElement_Mod = 31u; + + private static uint[] BitMaskHelperLUT = new uint[33] + { + 0u, + 1u, + 3u, + 7u, + 15u, + 31u, + 63u, + 127u, + 255u, + 511u, + 1023u, + 2047u, + 4095u, + 8191u, + 16383u, + 32767u, + 65535u, + 131071u, + 262143u, + 524287u, + 1048575u, + 2097151u, + 4194303u, + 8388607u, + 16777215u, + 33554431u, + 67108863u, + 134217727u, + 268435455u, + 536870911u, + 1073741823u, + 2147483647u, + 4294967295u + }; + + private bool _blnIsOpen = true; + + private uint[] _auiBitBuffer; + + private uint _uiBitBuffer_Length; + + private uint _uiBitBuffer_Index; + + private uint _uiBitBuffer_BitIndex; + + private static IFormatProvider _ifp = CultureInfo.InvariantCulture; + + public override long Length + { + get + { + if (!_blnIsOpen) + { + throw new ObjectDisposedException(BitStreamResources.GetString("ObjectDisposed_BitStreamClosed")); + } + return _uiBitBuffer_Length; + } + } + + public virtual long Length8 + { + get + { + if (!_blnIsOpen) + { + throw new ObjectDisposedException(BitStreamResources.GetString("ObjectDisposed_BitStreamClosed")); + } + return (_uiBitBuffer_Length >> 3) + (((_uiBitBuffer_Length & 7) != 0) ? 1 : 0); + } + } + + public virtual long Length16 + { + get + { + if (!_blnIsOpen) + { + throw new ObjectDisposedException(BitStreamResources.GetString("ObjectDisposed_BitStreamClosed")); + } + return (_uiBitBuffer_Length >> 4) + (((_uiBitBuffer_Length & 0xF) != 0) ? 1 : 0); + } + } + + public virtual long Length32 + { + get + { + if (!_blnIsOpen) + { + throw new ObjectDisposedException(BitStreamResources.GetString("ObjectDisposed_BitStreamClosed")); + } + return (_uiBitBuffer_Length >> 5) + (((_uiBitBuffer_Length & 0x1F) != 0) ? 1 : 0); + } + } + + public virtual long Length64 + { + get + { + if (!_blnIsOpen) + { + throw new ObjectDisposedException(BitStreamResources.GetString("ObjectDisposed_BitStreamClosed")); + } + return (_uiBitBuffer_Length >> 6) + (((_uiBitBuffer_Length & 0x3F) != 0) ? 1 : 0); + } + } + + public virtual long Capacity + { + get + { + if (!_blnIsOpen) + { + throw new ObjectDisposedException(BitStreamResources.GetString("ObjectDisposed_BitStreamClosed")); + } + return (long)_auiBitBuffer.Length << 5; + } + } + + public override long Position + { + get + { + if (!_blnIsOpen) + { + throw new ObjectDisposedException(BitStreamResources.GetString("ObjectDisposed_BitStreamClosed")); + } + uint num = (_uiBitBuffer_Index << 5) + _uiBitBuffer_BitIndex; + return num; + } + set + { + if (!_blnIsOpen) + { + throw new ObjectDisposedException(BitStreamResources.GetString("ObjectDisposed_BitStreamClosed")); + } + if (value < 0) + { + throw new ArgumentOutOfRangeException("value", BitStreamResources.GetString("ArgumentOutOfRange_NegativePosition")); + } + uint num = (uint)value; + if (_uiBitBuffer_Length < num + 1) + { + throw new ArgumentOutOfRangeException("value", BitStreamResources.GetString("ArgumentOutOfRange_InvalidPosition")); + } + _uiBitBuffer_Index = num >> 5; + if ((num & 0x1F) != 0) + { + _uiBitBuffer_BitIndex = (num & 0x1F); + } + else + { + _uiBitBuffer_BitIndex = 0u; + } + } + } + + public override bool CanRead => _blnIsOpen; + + public override bool CanSeek => false; + + public override bool CanWrite => _blnIsOpen; + + public static bool CanSetLength => false; + + public static bool CanFlush => false; + + public BitStream() + { + _auiBitBuffer = new uint[1]; + } + + public BitStream(long capacity) + { + if (capacity <= 0) + { + throw new ArgumentOutOfRangeException(BitStreamResources.GetString("ArgumentOutOfRange_NegativeOrZeroCapacity")); + } + _auiBitBuffer = new uint[(capacity >> 5) + (((capacity & 0x1F) > 0) ? 1 : 0)]; + } + + public BitStream(byte[] bits) + : this() + { + if (bits == null) + { + throw new ArgumentNullException("bits", BitStreamResources.GetString("ArgumentNull_BitBuffer")); + } + Write(bits, 0, bits.Length); + } + + public BitStream(Stream bits) + : this() + { + if (bits == null) + { + throw new ArgumentNullException("bits", BitStreamResources.GetString("ArgumentNull_BitBuffer")); + } + byte[] buffer = new byte[bits.Length]; + long position = bits.Position; + bits.Position = 0L; + bits.Read(buffer, 0, (int)bits.Length); + bits.Position = position; + Write(buffer, 0, (int)bits.Length); + } + + private void Write(ref uint bits, ref uint bitIndex, ref uint count) + { + uint num = (_uiBitBuffer_Index << 5) + _uiBitBuffer_BitIndex; + uint num2 = _uiBitBuffer_Length >> 5; + uint num3 = bitIndex + count; + int num4 = (int)bitIndex; + uint num5 = BitMaskHelperLUT[count] << num4; + bits &= num5; + uint num6 = 32 - _uiBitBuffer_BitIndex; + num4 = (int)(num6 - num3); + uint num7 = 0u; + num7 = ((num4 >= 0) ? (bits << num4) : (bits >> Math.Abs(num4))); + if (_uiBitBuffer_Length >= num + 1) + { + int num8 = (int)(num6 - count); + uint num9 = 0u; + num9 = (uint)((num8 >= 0) ? (-1 ^ (int)(BitMaskHelperLUT[count] << num8)) : (-1 ^ (int)(BitMaskHelperLUT[count] >> Math.Abs(num8)))); + _auiBitBuffer[_uiBitBuffer_Index] &= num9; + if (num2 == _uiBitBuffer_Index) + { + uint num10 = 0u; + num10 = ((num6 < count) ? (num + num6) : (num + count)); + if (num10 > _uiBitBuffer_Length) + { + uint bits2 = num10 - _uiBitBuffer_Length; + UpdateLengthForWrite(bits2); + } + } + } + else if (num6 >= count) + { + UpdateLengthForWrite(count); + } + else + { + UpdateLengthForWrite(num6); + } + _auiBitBuffer[_uiBitBuffer_Index] |= num7; + if (num6 >= count) + { + UpdateIndicesForWrite(count); + return; + } + UpdateIndicesForWrite(num6); + uint count2 = count - num6; + uint bitIndex2 = bitIndex; + Write(ref bits, ref bitIndex2, ref count2); + } + + public virtual void Write(bool bit) + { + if (!_blnIsOpen) + { + throw new ObjectDisposedException(BitStreamResources.GetString("ObjectDisposed_BitStreamClosed")); + } + uint bits = bit ? 1u : 0u; + uint bitIndex = 0u; + uint count = 1u; + Write(ref bits, ref bitIndex, ref count); + } + + public virtual void Write(bool[] bits) + { + if (!_blnIsOpen) + { + throw new ObjectDisposedException(BitStreamResources.GetString("ObjectDisposed_BitStreamClosed")); + } + if (bits == null) + { + throw new ArgumentNullException("bits", BitStreamResources.GetString("ArgumentNull_BitBuffer")); + } + Write(bits, 0, bits.Length); + } + + public virtual void Write(bool[] bits, int offset, int count) + { + if (!_blnIsOpen) + { + throw new ObjectDisposedException(BitStreamResources.GetString("ObjectDisposed_BitStreamClosed")); + } + if (bits == null) + { + throw new ArgumentNullException("bits", BitStreamResources.GetString("ArgumentNull_BitBuffer")); + } + if (offset < 0) + { + throw new ArgumentOutOfRangeException("offset", BitStreamResources.GetString("ArgumentOutOfRange_NegativeParameter")); + } + if (count < 0) + { + throw new ArgumentOutOfRangeException("count", BitStreamResources.GetString("ArgumentOutOfRange_NegativeParameter")); + } + if (count > bits.Length - offset) + { + throw new ArgumentException(BitStreamResources.GetString("Argument_InvalidCountOrOffset")); + } + int num = offset + count; + for (int i = offset; i < num; i++) + { + Write(bits[i]); + } + } + + public virtual void Write(byte bits) + { + Write(bits, 0, 8); + } + + public virtual void Write(byte bits, int bitIndex, int count) + { + if (!_blnIsOpen) + { + throw new ObjectDisposedException(BitStreamResources.GetString("ObjectDisposed_BitStreamClosed")); + } + if (bitIndex < 0) + { + throw new ArgumentOutOfRangeException("bitIndex", BitStreamResources.GetString("ArgumentOutOfRange_NegativeParameter")); + } + if (count < 0) + { + throw new ArgumentOutOfRangeException("count", BitStreamResources.GetString("ArgumentOutOfRange_NegativeParameter")); + } + if (count > 8 - bitIndex) + { + throw new ArgumentException(BitStreamResources.GetString("Argument_InvalidCountOrBitIndex_Byte")); + } + uint bits2 = bits; + uint bitIndex2 = (uint)bitIndex; + uint count2 = (uint)count; + Write(ref bits2, ref bitIndex2, ref count2); + } + + public virtual void Write(byte[] bits) + { + if (!_blnIsOpen) + { + throw new ObjectDisposedException(BitStreamResources.GetString("ObjectDisposed_BitStreamClosed")); + } + if (bits == null) + { + throw new ArgumentNullException("bits", BitStreamResources.GetString("ArgumentNull_BitBuffer")); + } + Write(bits, 0, bits.Length); + } + + public override void Write(byte[] bits, int offset, int count) + { + if (!_blnIsOpen) + { + throw new ObjectDisposedException(BitStreamResources.GetString("ObjectDisposed_BitStreamClosed")); + } + if (bits == null) + { + throw new ArgumentNullException("bits", BitStreamResources.GetString("ArgumentNull_BitBuffer")); + } + if (offset < 0) + { + throw new ArgumentOutOfRangeException("offset", BitStreamResources.GetString("ArgumentOutOfRange_NegativeParameter")); + } + if (count < 0) + { + throw new ArgumentOutOfRangeException("count", BitStreamResources.GetString("ArgumentOutOfRange_NegativeParameter")); + } + if (count > bits.Length - offset) + { + throw new ArgumentException(BitStreamResources.GetString("Argument_InvalidCountOrOffset")); + } + int num = offset + count; + for (int i = offset; i < num; i++) + { + Write(bits[i]); + } + } + + [CLSCompliant(false)] + public virtual void Write(sbyte bits) + { + Write(bits, 0, 8); + } + + [CLSCompliant(false)] + public virtual void Write(sbyte bits, int bitIndex, int count) + { + byte bits2 = (byte)bits; + Write(bits2, bitIndex, count); + } + + [CLSCompliant(false)] + public virtual void Write(sbyte[] bits) + { + if (!_blnIsOpen) + { + throw new ObjectDisposedException(BitStreamResources.GetString("ObjectDisposed_BitStreamClosed")); + } + if (bits == null) + { + throw new ArgumentNullException("bits", BitStreamResources.GetString("ArgumentNull_BitBuffer")); + } + Write(bits, 0, bits.Length); + } + + [CLSCompliant(false)] + public virtual void Write(sbyte[] bits, int offset, int count) + { + if (!_blnIsOpen) + { + throw new ObjectDisposedException(BitStreamResources.GetString("ObjectDisposed_BitStreamClosed")); + } + if (bits == null) + { + throw new ArgumentNullException("bits", BitStreamResources.GetString("ArgumentNull_BitBuffer")); + } + if (offset < 0) + { + throw new ArgumentOutOfRangeException("offset", BitStreamResources.GetString("ArgumentOutOfRange_NegativeParameter")); + } + if (count < 0) + { + throw new ArgumentOutOfRangeException("count", BitStreamResources.GetString("ArgumentOutOfRange_NegativeParameter")); + } + if (count > bits.Length - offset) + { + throw new ArgumentException(BitStreamResources.GetString("Argument_InvalidCountOrOffset")); + } + byte[] array = new byte[count]; + Buffer.BlockCopy(bits, offset, array, 0, count); + Write(array, 0, count); + } + + public override void WriteByte(byte value) + { + Write(value); + } + + [CLSCompliant(false)] + public virtual void Write(char bits) + { + Write(bits, 0, 128); + } + + [CLSCompliant(false)] + public virtual void Write(char bits, int bitIndex, int count) + { + if (!_blnIsOpen) + { + throw new ObjectDisposedException(BitStreamResources.GetString("ObjectDisposed_BitStreamClosed")); + } + if (bitIndex < 0) + { + throw new ArgumentOutOfRangeException("bitIndex", BitStreamResources.GetString("ArgumentOutOfRange_NegativeParameter")); + } + if (count < 0) + { + throw new ArgumentOutOfRangeException("count", BitStreamResources.GetString("ArgumentOutOfRange_NegativeParameter")); + } + if (count > 128 - bitIndex) + { + throw new ArgumentException(BitStreamResources.GetString("Argument_InvalidCountOrBitIndex_Char")); + } + uint bits2 = bits; + uint bitIndex2 = (uint)bitIndex; + uint count2 = (uint)count; + Write(ref bits2, ref bitIndex2, ref count2); + } + + [CLSCompliant(false)] + public virtual void Write(char[] bits) + { + if (!_blnIsOpen) + { + throw new ObjectDisposedException(BitStreamResources.GetString("ObjectDisposed_BitStreamClosed")); + } + if (bits == null) + { + throw new ArgumentNullException("bits", BitStreamResources.GetString("ArgumentNull_BitBuffer")); + } + Write(bits, 0, bits.Length); + } + + [CLSCompliant(false)] + public virtual void Write(char[] bits, int offset, int count) + { + if (!_blnIsOpen) + { + throw new ObjectDisposedException(BitStreamResources.GetString("ObjectDisposed_BitStreamClosed")); + } + if (bits == null) + { + throw new ArgumentNullException("bits", BitStreamResources.GetString("ArgumentNull_BitBuffer")); + } + if (offset < 0) + { + throw new ArgumentOutOfRangeException("offset", BitStreamResources.GetString("ArgumentOutOfRange_NegativeParameter")); + } + if (count < 0) + { + throw new ArgumentOutOfRangeException("count", BitStreamResources.GetString("ArgumentOutOfRange_NegativeParameter")); + } + if (count > bits.Length - offset) + { + throw new ArgumentException(BitStreamResources.GetString("Argument_InvalidCountOrOffset")); + } + int num = offset + count; + for (int i = offset; i < num; i++) + { + Write(bits[i]); + } + } + + [CLSCompliant(false)] + public virtual void Write(ushort bits) + { + Write(bits, 0, 16); + } + + [CLSCompliant(false)] + public virtual void Write(ushort bits, int bitIndex, int count) + { + if (!_blnIsOpen) + { + throw new ObjectDisposedException(BitStreamResources.GetString("ObjectDisposed_BitStreamClosed")); + } + if (bitIndex < 0) + { + throw new ArgumentOutOfRangeException("bitIndex", BitStreamResources.GetString("ArgumentOutOfRange_NegativeParameter")); + } + if (count < 0) + { + throw new ArgumentOutOfRangeException("count", BitStreamResources.GetString("ArgumentOutOfRange_NegativeParameter")); + } + if (count > 16 - bitIndex) + { + throw new ArgumentException(BitStreamResources.GetString("Argument_InvalidCountOrBitIndex_UInt16")); + } + uint bits2 = bits; + uint bitIndex2 = (uint)bitIndex; + uint count2 = (uint)count; + Write(ref bits2, ref bitIndex2, ref count2); + } + + [CLSCompliant(false)] + public virtual void Write(ushort[] bits) + { + if (!_blnIsOpen) + { + throw new ObjectDisposedException(BitStreamResources.GetString("ObjectDisposed_BitStreamClosed")); + } + if (bits == null) + { + throw new ArgumentNullException("bits", BitStreamResources.GetString("ArgumentNull_BitBuffer")); + } + Write(bits, 0, bits.Length); + } + + [CLSCompliant(false)] + public virtual void Write(ushort[] bits, int offset, int count) + { + if (!_blnIsOpen) + { + throw new ObjectDisposedException(BitStreamResources.GetString("ObjectDisposed_BitStreamClosed")); + } + if (bits == null) + { + throw new ArgumentNullException("bits", BitStreamResources.GetString("ArgumentNull_BitBuffer")); + } + if (offset < 0) + { + throw new ArgumentOutOfRangeException("offset", BitStreamResources.GetString("ArgumentOutOfRange_NegativeParameter")); + } + if (count < 0) + { + throw new ArgumentOutOfRangeException("count", BitStreamResources.GetString("ArgumentOutOfRange_NegativeParameter")); + } + if (count > bits.Length - offset) + { + throw new ArgumentException(BitStreamResources.GetString("Argument_InvalidCountOrOffset")); + } + int num = offset + count; + for (int i = offset; i < num; i++) + { + Write(bits[i]); + } + } + + public virtual void Write(short bits) + { + Write(bits, 0, 16); + } + + public virtual void Write(short bits, int bitIndex, int count) + { + ushort bits2 = (ushort)bits; + Write(bits2, bitIndex, count); + } + + public virtual void Write(short[] bits) + { + if (!_blnIsOpen) + { + throw new ObjectDisposedException(BitStreamResources.GetString("ObjectDisposed_BitStreamClosed")); + } + if (bits == null) + { + throw new ArgumentNullException("bits", BitStreamResources.GetString("ArgumentNull_BitBuffer")); + } + Write(bits, 0, bits.Length); + } + + public virtual void Write(short[] bits, int offset, int count) + { + if (!_blnIsOpen) + { + throw new ObjectDisposedException(BitStreamResources.GetString("ObjectDisposed_BitStreamClosed")); + } + if (bits == null) + { + throw new ArgumentNullException("bits", BitStreamResources.GetString("ArgumentNull_BitBuffer")); + } + if (offset < 0) + { + throw new ArgumentOutOfRangeException("offset", BitStreamResources.GetString("ArgumentOutOfRange_NegativeParameter")); + } + if (count < 0) + { + throw new ArgumentOutOfRangeException("count", BitStreamResources.GetString("ArgumentOutOfRange_NegativeParameter")); + } + if (count > bits.Length - offset) + { + throw new ArgumentException(BitStreamResources.GetString("Argument_InvalidCountOrOffset")); + } + ushort[] array = new ushort[count]; + Buffer.BlockCopy(bits, offset << 1, array, 0, count << 1); + Write(array, 0, count); + } + + [CLSCompliant(false)] + public virtual void Write(uint bits) + { + Write(bits, 0, 32); + } + + [CLSCompliant(false)] + public virtual void Write(uint bits, int bitIndex, int count) + { + if (!_blnIsOpen) + { + throw new ObjectDisposedException(BitStreamResources.GetString("ObjectDisposed_BitStreamClosed")); + } + if (bitIndex < 0) + { + throw new ArgumentOutOfRangeException("bitIndex", BitStreamResources.GetString("ArgumentOutOfRange_NegativeParameter")); + } + if (count < 0) + { + throw new ArgumentOutOfRangeException("count", BitStreamResources.GetString("ArgumentOutOfRange_NegativeParameter")); + } + if (count > 32 - bitIndex) + { + throw new ArgumentException(BitStreamResources.GetString("Argument_InvalidCountOrBitIndex_UInt32")); + } + uint bitIndex2 = (uint)bitIndex; + uint count2 = (uint)count; + Write(ref bits, ref bitIndex2, ref count2); + } + + [CLSCompliant(false)] + public virtual void Write(uint[] bits) + { + if (!_blnIsOpen) + { + throw new ObjectDisposedException(BitStreamResources.GetString("ObjectDisposed_BitStreamClosed")); + } + if (bits == null) + { + throw new ArgumentNullException("bits", BitStreamResources.GetString("ArgumentNull_BitBuffer")); + } + Write(bits, 0, bits.Length); + } + + [CLSCompliant(false)] + public virtual void Write(uint[] bits, int offset, int count) + { + if (!_blnIsOpen) + { + throw new ObjectDisposedException(BitStreamResources.GetString("ObjectDisposed_BitStreamClosed")); + } + if (bits == null) + { + throw new ArgumentNullException("bits", BitStreamResources.GetString("ArgumentNull_BitBuffer")); + } + if (offset < 0) + { + throw new ArgumentOutOfRangeException("offset", BitStreamResources.GetString("ArgumentOutOfRange_NegativeParameter")); + } + if (count < 0) + { + throw new ArgumentOutOfRangeException("count", BitStreamResources.GetString("ArgumentOutOfRange_NegativeParameter")); + } + if (count > bits.Length - offset) + { + throw new ArgumentException(BitStreamResources.GetString("Argument_InvalidCountOrOffset")); + } + int num = offset + count; + for (int i = offset; i < num; i++) + { + Write(bits[i]); + } + } + + public virtual void Write(int bits) + { + Write(bits, 0, 32); + } + + public virtual void Write(int bits, int bitIndex, int count) + { + Write((uint)bits, bitIndex, count); + } + + public virtual void Write(int[] bits) + { + if (!_blnIsOpen) + { + throw new ObjectDisposedException(BitStreamResources.GetString("ObjectDisposed_BitStreamClosed")); + } + if (bits == null) + { + throw new ArgumentNullException("bits", BitStreamResources.GetString("ArgumentNull_BitBuffer")); + } + Write(bits, 0, bits.Length); + } + + public virtual void Write(int[] bits, int offset, int count) + { + if (!_blnIsOpen) + { + throw new ObjectDisposedException(BitStreamResources.GetString("ObjectDisposed_BitStreamClosed")); + } + if (bits == null) + { + throw new ArgumentNullException("bits", BitStreamResources.GetString("ArgumentNull_BitBuffer")); + } + if (offset < 0) + { + throw new ArgumentOutOfRangeException("offset", BitStreamResources.GetString("ArgumentOutOfRange_NegativeParameter")); + } + if (count < 0) + { + throw new ArgumentOutOfRangeException("count", BitStreamResources.GetString("ArgumentOutOfRange_NegativeParameter")); + } + if (count > bits.Length - offset) + { + throw new ArgumentException(BitStreamResources.GetString("Argument_InvalidCountOrOffset")); + } + uint[] array = new uint[count]; + Buffer.BlockCopy(bits, offset << 2, array, 0, count << 2); + Write(array, 0, count); + } + + public virtual void Write(float bits) + { + Write(bits, 0, 32); + } + + public virtual void Write(float bits, int bitIndex, int count) + { + byte[] bytes = BitConverter.GetBytes(bits); + uint bits2 = (uint)(bytes[0] | (bytes[1] << 8) | (bytes[2] << 16) | (bytes[3] << 24)); + Write(bits2, bitIndex, count); + } + + public virtual void Write(float[] bits) + { + if (!_blnIsOpen) + { + throw new ObjectDisposedException(BitStreamResources.GetString("ObjectDisposed_BitStreamClosed")); + } + if (bits == null) + { + throw new ArgumentNullException("bits", BitStreamResources.GetString("ArgumentNull_BitBuffer")); + } + Write(bits, 0, bits.Length); + } + + public virtual void Write(float[] bits, int offset, int count) + { + if (!_blnIsOpen) + { + throw new ObjectDisposedException(BitStreamResources.GetString("ObjectDisposed_BitStreamClosed")); + } + if (bits == null) + { + throw new ArgumentNullException("bits", BitStreamResources.GetString("ArgumentNull_BitBuffer")); + } + if (offset < 0) + { + throw new ArgumentOutOfRangeException("offset", BitStreamResources.GetString("ArgumentOutOfRange_NegativeParameter")); + } + if (count < 0) + { + throw new ArgumentOutOfRangeException("count", BitStreamResources.GetString("ArgumentOutOfRange_NegativeParameter")); + } + if (count > bits.Length - offset) + { + throw new ArgumentException(BitStreamResources.GetString("Argument_InvalidCountOrOffset")); + } + int num = offset + count; + for (int i = offset; i < num; i++) + { + Write(bits[i]); + } + } + + [CLSCompliant(false)] + public virtual void Write(ulong bits) + { + Write(bits, 0, 64); + } + + [CLSCompliant(false)] + public virtual void Write(ulong bits, int bitIndex, int count) + { + if (!_blnIsOpen) + { + throw new ObjectDisposedException(BitStreamResources.GetString("ObjectDisposed_BitStreamClosed")); + } + if (bitIndex < 0) + { + throw new ArgumentOutOfRangeException("bitIndex", BitStreamResources.GetString("ArgumentOutOfRange_NegativeParameter")); + } + if (count < 0) + { + throw new ArgumentOutOfRangeException("count", BitStreamResources.GetString("ArgumentOutOfRange_NegativeParameter")); + } + if (count > 64 - bitIndex) + { + throw new ArgumentException(BitStreamResources.GetString("Argument_InvalidCountOrBitIndex_UInt64")); + } + int num = (bitIndex >> 5 < 1) ? bitIndex : (-1); + int num2 = (bitIndex + count <= 32) ? (-1) : ((num < 0) ? (bitIndex - 32) : 0); + int num3 = (num > -1) ? ((num + count > 32) ? (32 - num) : count) : 0; + int num4 = (num2 > -1) ? ((num3 == 0) ? count : (count - num3)) : 0; + if (num3 > 0) + { + uint bits2 = (uint)bits; + uint bitIndex2 = (uint)num; + uint count2 = (uint)num3; + Write(ref bits2, ref bitIndex2, ref count2); + } + if (num4 > 0) + { + uint bits3 = (uint)(bits >> 32); + uint bitIndex3 = (uint)num2; + uint count3 = (uint)num4; + Write(ref bits3, ref bitIndex3, ref count3); + } + } + + [CLSCompliant(false)] + public virtual void Write(ulong[] bits) + { + if (!_blnIsOpen) + { + throw new ObjectDisposedException(BitStreamResources.GetString("ObjectDisposed_BitStreamClosed")); + } + if (bits == null) + { + throw new ArgumentNullException("bits", BitStreamResources.GetString("ArgumentNull_BitBuffer")); + } + Write(bits, 0, bits.Length); + } + + [CLSCompliant(false)] + public virtual void Write(ulong[] bits, int offset, int count) + { + if (!_blnIsOpen) + { + throw new ObjectDisposedException(BitStreamResources.GetString("ObjectDisposed_BitStreamClosed")); + } + if (bits == null) + { + throw new ArgumentNullException("bits", BitStreamResources.GetString("ArgumentNull_BitBuffer")); + } + if (offset < 0) + { + throw new ArgumentOutOfRangeException("offset", BitStreamResources.GetString("ArgumentOutOfRange_NegativeParameter")); + } + if (count < 0) + { + throw new ArgumentOutOfRangeException("count", BitStreamResources.GetString("ArgumentOutOfRange_NegativeParameter")); + } + if (count > bits.Length - offset) + { + throw new ArgumentException(BitStreamResources.GetString("Argument_InvalidCountOrOffset")); + } + int num = offset + count; + for (int i = offset; i < num; i++) + { + Write(bits[i]); + } + } + + public virtual void Write(long bits) + { + Write(bits, 0, 64); + } + + public virtual void Write(long bits, int bitIndex, int count) + { + Write((ulong)bits, bitIndex, count); + } + + public virtual void Write(long[] bits) + { + if (!_blnIsOpen) + { + throw new ObjectDisposedException(BitStreamResources.GetString("ObjectDisposed_BitStreamClosed")); + } + if (bits == null) + { + throw new ArgumentNullException("bits", BitStreamResources.GetString("ArgumentNull_BitBuffer")); + } + Write(bits, 0, bits.Length); + } + + public virtual void Write(long[] bits, int offset, int count) + { + if (!_blnIsOpen) + { + throw new ObjectDisposedException(BitStreamResources.GetString("ObjectDisposed_BitStreamClosed")); + } + if (bits == null) + { + throw new ArgumentNullException("bits", BitStreamResources.GetString("ArgumentNull_BitBuffer")); + } + if (offset < 0) + { + throw new ArgumentOutOfRangeException("offset", BitStreamResources.GetString("ArgumentOutOfRange_NegativeParameter")); + } + if (count < 0) + { + throw new ArgumentOutOfRangeException("count", BitStreamResources.GetString("ArgumentOutOfRange_NegativeParameter")); + } + if (count > bits.Length - offset) + { + throw new ArgumentException(BitStreamResources.GetString("Argument_InvalidCountOrOffset")); + } + ulong[] array = new ulong[count]; + Buffer.BlockCopy(bits, offset << 4, array, 0, count << 4); + Write(array, 0, count); + } + + public virtual void Write(double bits) + { + Write(bits, 0, 64); + } + + public virtual void Write(double bits, int bitIndex, int count) + { + byte[] bytes = BitConverter.GetBytes(bits); + ulong bits2 = bytes[0] | ((ulong)bytes[1] << 8) | ((ulong)bytes[2] << 16) | ((ulong)bytes[3] << 24) | ((ulong)bytes[4] << 32) | ((ulong)bytes[5] << 40) | ((ulong)bytes[6] << 48) | ((ulong)bytes[7] << 56); + Write(bits2, bitIndex, count); + } + + public virtual void Write(double[] bits) + { + if (!_blnIsOpen) + { + throw new ObjectDisposedException(BitStreamResources.GetString("ObjectDisposed_BitStreamClosed")); + } + if (bits == null) + { + throw new ArgumentNullException("bits", BitStreamResources.GetString("ArgumentNull_BitBuffer")); + } + Write(bits, 0, bits.Length); + } + + public virtual void Write(double[] bits, int offset, int count) + { + if (!_blnIsOpen) + { + throw new ObjectDisposedException(BitStreamResources.GetString("ObjectDisposed_BitStreamClosed")); + } + if (bits == null) + { + throw new ArgumentNullException("bits", BitStreamResources.GetString("ArgumentNull_BitBuffer")); + } + if (offset < 0) + { + throw new ArgumentOutOfRangeException("offset", BitStreamResources.GetString("ArgumentOutOfRange_NegativeParameter")); + } + if (count < 0) + { + throw new ArgumentOutOfRangeException("count", BitStreamResources.GetString("ArgumentOutOfRange_NegativeParameter")); + } + if (count > bits.Length - offset) + { + throw new ArgumentException(BitStreamResources.GetString("Argument_InvalidCountOrOffset")); + } + int num = offset + count; + for (int i = offset; i < num; i++) + { + Write(bits[i]); + } + } + + public virtual void WriteTo(Stream bits) + { + if (!_blnIsOpen) + { + throw new ObjectDisposedException(BitStreamResources.GetString("ObjectDisposed_BitStreamClosed")); + } + if (bits == null) + { + throw new ArgumentNullException("bits", BitStreamResources.GetString("ArgumentNull_Stream")); + } + byte[] array = ToByteArray(); + bits.Write(array, 0, array.Length); + } + + private uint Read(ref uint bits, ref uint bitIndex, ref uint count) + { + uint num = (_uiBitBuffer_Index << 5) + _uiBitBuffer_BitIndex; + uint num2 = count; + if (_uiBitBuffer_Length < num + num2) + { + num2 = _uiBitBuffer_Length - num; + } + uint num3 = _auiBitBuffer[_uiBitBuffer_Index]; + int num4 = (int)(32 - (_uiBitBuffer_BitIndex + num2)); + if (num4 < 0) + { + num4 = Math.Abs(num4); + uint num5 = BitMaskHelperLUT[num2] >> num4; + num3 &= num5; + num3 <<= num4; + uint count2 = (uint)num4; + uint bitIndex2 = 0u; + uint bits2 = 0u; + UpdateIndicesForRead(num2 - count2); + Read(ref bits2, ref bitIndex2, ref count2); + num3 |= bits2; + } + else + { + uint num5 = BitMaskHelperLUT[num2] << num4; + num3 &= num5; + num3 >>= num4; + UpdateIndicesForRead(num2); + } + bits = num3 << (int)bitIndex; + return num2; + } + + public virtual int Read(out bool bit) + { + if (!_blnIsOpen) + { + throw new ObjectDisposedException(BitStreamResources.GetString("ObjectDisposed_BitStreamClosed")); + } + uint bitIndex = 0u; + uint count = 1u; + uint bits = 0u; + uint result = Read(ref bits, ref bitIndex, ref count); + bit = Convert.ToBoolean(bits); + return (int)result; + } + + public virtual int Read(bool[] bits) + { + if (!_blnIsOpen) + { + throw new ObjectDisposedException(BitStreamResources.GetString("ObjectDisposed_BitStreamClosed")); + } + if (bits == null) + { + throw new ArgumentNullException("bits", BitStreamResources.GetString("ArgumentNull_BitBuffer")); + } + return Read(bits, 0, bits.Length); + } + + public virtual int Read(bool[] bits, int offset, int count) + { + if (!_blnIsOpen) + { + throw new ObjectDisposedException(BitStreamResources.GetString("ObjectDisposed_BitStreamClosed")); + } + if (bits == null) + { + throw new ArgumentNullException("bits", BitStreamResources.GetString("ArgumentNull_BitBuffer")); + } + if (offset < 0) + { + throw new ArgumentOutOfRangeException("offset", BitStreamResources.GetString("ArgumentOutOfRange_NegativeParameter")); + } + if (count < 0) + { + throw new ArgumentOutOfRangeException("count", BitStreamResources.GetString("ArgumentOutOfRange_NegativeParameter")); + } + if (count > bits.Length - offset) + { + throw new ArgumentException(BitStreamResources.GetString("Argument_InvalidCountOrOffset")); + } + int num = offset + count; + int num2 = 0; + for (int i = offset; i < num; i++) + { + num2 += Read(out bits[i]); + } + return num2; + } + + public virtual int Read(out byte bits) + { + return Read(out bits, 0, 8); + } + + public virtual int Read(out byte bits, int bitIndex, int count) + { + if (!_blnIsOpen) + { + throw new ObjectDisposedException(BitStreamResources.GetString("ObjectDisposed_BitStreamClosed")); + } + if (bitIndex < 0) + { + throw new ArgumentOutOfRangeException("bitIndex", BitStreamResources.GetString("ArgumentOutOfRange_NegativeParameter")); + } + if (count < 0) + { + throw new ArgumentOutOfRangeException("count", BitStreamResources.GetString("ArgumentOutOfRange_NegativeParameter")); + } + if (count > 8 - bitIndex) + { + throw new ArgumentException(BitStreamResources.GetString("Argument_InvalidCountOrBitIndex_Byte")); + } + uint bitIndex2 = (uint)bitIndex; + uint count2 = (uint)count; + uint bits2 = 0u; + uint result = Read(ref bits2, ref bitIndex2, ref count2); + bits = (byte)bits2; + return (int)result; + } + + public virtual int Read(byte[] bits) + { + if (!_blnIsOpen) + { + throw new ObjectDisposedException(BitStreamResources.GetString("ObjectDisposed_BitStreamClosed")); + } + if (bits == null) + { + throw new ArgumentNullException("bits", BitStreamResources.GetString("ArgumentNull_BitBuffer")); + } + return Read(bits, 0, bits.Length); + } + + public override int Read(byte[] bits, int offset, int count) + { + if (!_blnIsOpen) + { + throw new ObjectDisposedException(BitStreamResources.GetString("ObjectDisposed_BitStreamClosed")); + } + if (bits == null) + { + throw new ArgumentNullException("bits", BitStreamResources.GetString("ArgumentNull_BitBuffer")); + } + if (offset < 0) + { + throw new ArgumentOutOfRangeException("offset", BitStreamResources.GetString("ArgumentOutOfRange_NegativeParameter")); + } + if (count < 0) + { + throw new ArgumentOutOfRangeException("count", BitStreamResources.GetString("ArgumentOutOfRange_NegativeParameter")); + } + if (count > bits.Length - offset) + { + throw new ArgumentException(BitStreamResources.GetString("Argument_InvalidCountOrOffset")); + } + int num = offset + count; + int num2 = 0; + for (int i = offset; i < num; i++) + { + num2 += Read(out bits[i]); + } + return num2; + } + + [CLSCompliant(false)] + public virtual int Read(out sbyte bits) + { + return Read(out bits, 0, 8); + } + + [CLSCompliant(false)] + public virtual int Read(out sbyte bits, int bitIndex, int count) + { + byte bits2 = 0; + int result = Read(out bits2, bitIndex, count); + bits = (sbyte)bits2; + return result; + } + + [CLSCompliant(false)] + public virtual int Read(sbyte[] bits) + { + if (!_blnIsOpen) + { + throw new ObjectDisposedException(BitStreamResources.GetString("ObjectDisposed_BitStreamClosed")); + } + if (bits == null) + { + throw new ArgumentNullException("bits", BitStreamResources.GetString("ArgumentNull_BitBuffer")); + } + return Read(bits, 0, bits.Length); + } + + [CLSCompliant(false)] + public virtual int Read(sbyte[] bits, int offset, int count) + { + if (!_blnIsOpen) + { + throw new ObjectDisposedException(BitStreamResources.GetString("ObjectDisposed_BitStreamClosed")); + } + if (bits == null) + { + throw new ArgumentNullException("bits", BitStreamResources.GetString("ArgumentNull_BitBuffer")); + } + if (offset < 0) + { + throw new ArgumentOutOfRangeException("offset", BitStreamResources.GetString("ArgumentOutOfRange_NegativeParameter")); + } + if (count < 0) + { + throw new ArgumentOutOfRangeException("count", BitStreamResources.GetString("ArgumentOutOfRange_NegativeParameter")); + } + if (count > bits.Length - offset) + { + throw new ArgumentException(BitStreamResources.GetString("Argument_InvalidCountOrOffset")); + } + int num = offset + count; + int num2 = 0; + for (int i = offset; i < num; i++) + { + num2 += Read(out bits[i]); + } + return num2; + } + + public override int ReadByte() + { + if (Read(out byte bits) == 0) + { + return -1; + } + return bits; + } + + public virtual byte[] ToByteArray() + { + long position = Position; + Position = 0L; + byte[] array = new byte[Length8]; + Read(array, 0, (int)Length8); + if (Position != position) + { + Position = position; + } + return array; + } + + public virtual int Read(out char bits) + { + return Read(out bits, 0, 128); + } + + public virtual int Read(out char bits, int bitIndex, int count) + { + if (!_blnIsOpen) + { + throw new ObjectDisposedException(BitStreamResources.GetString("ObjectDisposed_BitStreamClosed")); + } + if (bitIndex < 0) + { + throw new ArgumentOutOfRangeException("bitIndex", BitStreamResources.GetString("ArgumentOutOfRange_NegativeParameter")); + } + if (count < 0) + { + throw new ArgumentOutOfRangeException("count", BitStreamResources.GetString("ArgumentOutOfRange_NegativeParameter")); + } + if (count > 128 - bitIndex) + { + throw new ArgumentException(BitStreamResources.GetString("Argument_InvalidCountOrBitIndex_Char")); + } + uint bitIndex2 = (uint)bitIndex; + uint count2 = (uint)count; + uint bits2 = 0u; + uint result = Read(ref bits2, ref bitIndex2, ref count2); + bits = (char)bits2; + return (int)result; + } + + public virtual int Read(char[] bits) + { + if (!_blnIsOpen) + { + throw new ObjectDisposedException(BitStreamResources.GetString("ObjectDisposed_BitStreamClosed")); + } + if (bits == null) + { + throw new ArgumentNullException("bits", BitStreamResources.GetString("ArgumentNull_BitBuffer")); + } + return Read(bits, 0, bits.Length); + } + + public virtual int Read(char[] bits, int offset, int count) + { + if (!_blnIsOpen) + { + throw new ObjectDisposedException(BitStreamResources.GetString("ObjectDisposed_BitStreamClosed")); + } + if (bits == null) + { + throw new ArgumentNullException("bits", BitStreamResources.GetString("ArgumentNull_BitBuffer")); + } + if (offset < 0) + { + throw new ArgumentOutOfRangeException("offset", BitStreamResources.GetString("ArgumentOutOfRange_NegativeParameter")); + } + if (count < 0) + { + throw new ArgumentOutOfRangeException("count", BitStreamResources.GetString("ArgumentOutOfRange_NegativeParameter")); + } + if (count > bits.Length - offset) + { + throw new ArgumentException(BitStreamResources.GetString("Argument_InvalidCountOrOffset")); + } + int num = offset + count; + int num2 = 0; + for (int i = offset; i < num; i++) + { + num2 += Read(out bits[i]); + } + return num2; + } + + [CLSCompliant(false)] + public virtual int Read(out ushort bits) + { + return Read(out bits, 0, 16); + } + + [CLSCompliant(false)] + public virtual int Read(out ushort bits, int bitIndex, int count) + { + if (!_blnIsOpen) + { + throw new ObjectDisposedException(BitStreamResources.GetString("ObjectDisposed_BitStreamClosed")); + } + if (bitIndex < 0) + { + throw new ArgumentOutOfRangeException("bitIndex", BitStreamResources.GetString("ArgumentOutOfRange_NegativeParameter")); + } + if (count < 0) + { + throw new ArgumentOutOfRangeException("count", BitStreamResources.GetString("ArgumentOutOfRange_NegativeParameter")); + } + if (count > 16 - bitIndex) + { + throw new ArgumentException(BitStreamResources.GetString("Argument_InvalidCountOrBitIndex_UInt16")); + } + uint bitIndex2 = (uint)bitIndex; + uint count2 = (uint)count; + uint bits2 = 0u; + uint result = Read(ref bits2, ref bitIndex2, ref count2); + bits = (ushort)bits2; + return (int)result; + } + + [CLSCompliant(false)] + public virtual int Read(ushort[] bits) + { + if (!_blnIsOpen) + { + throw new ObjectDisposedException(BitStreamResources.GetString("ObjectDisposed_BitStreamClosed")); + } + if (bits == null) + { + throw new ArgumentNullException("bits", BitStreamResources.GetString("ArgumentNull_BitBuffer")); + } + return Read(bits, 0, bits.Length); + } + + [CLSCompliant(false)] + public virtual int Read(ushort[] bits, int offset, int count) + { + if (!_blnIsOpen) + { + throw new ObjectDisposedException(BitStreamResources.GetString("ObjectDisposed_BitStreamClosed")); + } + if (bits == null) + { + throw new ArgumentNullException("bits", BitStreamResources.GetString("ArgumentNull_BitBuffer")); + } + if (offset < 0) + { + throw new ArgumentOutOfRangeException("offset", BitStreamResources.GetString("ArgumentOutOfRange_NegativeParameter")); + } + if (count < 0) + { + throw new ArgumentOutOfRangeException("count", BitStreamResources.GetString("ArgumentOutOfRange_NegativeParameter")); + } + if (count > bits.Length - offset) + { + throw new ArgumentException(BitStreamResources.GetString("Argument_InvalidCountOrOffset")); + } + int num = offset + count; + int num2 = 0; + for (int i = offset; i < num; i++) + { + num2 += Read(out bits[i]); + } + return num2; + } + + public virtual int Read(out short bits) + { + return Read(out bits, 0, 16); + } + + public virtual int Read(out short bits, int bitIndex, int count) + { + ushort bits2 = 0; + int result = Read(out bits2, bitIndex, count); + bits = (short)bits2; + return result; + } + + public virtual int Read(short[] bits) + { + if (!_blnIsOpen) + { + throw new ObjectDisposedException(BitStreamResources.GetString("ObjectDisposed_BitStreamClosed")); + } + if (bits == null) + { + throw new ArgumentNullException("bits", BitStreamResources.GetString("ArgumentNull_BitBuffer")); + } + return Read(bits, 0, bits.Length); + } + + public virtual int Read(short[] bits, int offset, int count) + { + if (!_blnIsOpen) + { + throw new ObjectDisposedException(BitStreamResources.GetString("ObjectDisposed_BitStreamClosed")); + } + if (bits == null) + { + throw new ArgumentNullException("bits", BitStreamResources.GetString("ArgumentNull_BitBuffer")); + } + if (offset < 0) + { + throw new ArgumentOutOfRangeException("offset", BitStreamResources.GetString("ArgumentOutOfRange_NegativeParameter")); + } + if (count < 0) + { + throw new ArgumentOutOfRangeException("count", BitStreamResources.GetString("ArgumentOutOfRange_NegativeParameter")); + } + if (count > bits.Length - offset) + { + throw new ArgumentException(BitStreamResources.GetString("Argument_InvalidCountOrOffset")); + } + int num = offset + count; + int num2 = 0; + for (int i = offset; i < num; i++) + { + num2 += Read(out bits[i]); + } + return num2; + } + + [CLSCompliant(false)] + public virtual int Read(out uint bits) + { + return Read(out bits, 0, 32); + } + + [CLSCompliant(false)] + public virtual int Read(out uint bits, int bitIndex, int count) + { + if (!_blnIsOpen) + { + throw new ObjectDisposedException(BitStreamResources.GetString("ObjectDisposed_BitStreamClosed")); + } + if (bitIndex < 0) + { + throw new ArgumentOutOfRangeException("bitIndex", BitStreamResources.GetString("ArgumentOutOfRange_NegativeParameter")); + } + if (count < 0) + { + throw new ArgumentOutOfRangeException("count", BitStreamResources.GetString("ArgumentOutOfRange_NegativeParameter")); + } + if (count > 32 - bitIndex) + { + throw new ArgumentException(BitStreamResources.GetString("Argument_InvalidCountOrBitIndex_UInt32")); + } + uint bitIndex2 = (uint)bitIndex; + uint count2 = (uint)count; + uint bits2 = 0u; + uint result = Read(ref bits2, ref bitIndex2, ref count2); + bits = bits2; + return (int)result; + } + + [CLSCompliant(false)] + public virtual int Read(uint[] bits) + { + if (!_blnIsOpen) + { + throw new ObjectDisposedException(BitStreamResources.GetString("ObjectDisposed_BitStreamClosed")); + } + if (bits == null) + { + throw new ArgumentNullException("bits", BitStreamResources.GetString("ArgumentNull_BitBuffer")); + } + return Read(bits, 0, bits.Length); + } + + [CLSCompliant(false)] + public virtual int Read(uint[] bits, int offset, int count) + { + if (!_blnIsOpen) + { + throw new ObjectDisposedException(BitStreamResources.GetString("ObjectDisposed_BitStreamClosed")); + } + if (bits == null) + { + throw new ArgumentNullException("bits", BitStreamResources.GetString("ArgumentNull_BitBuffer")); + } + if (offset < 0) + { + throw new ArgumentOutOfRangeException("offset", BitStreamResources.GetString("ArgumentOutOfRange_NegativeParameter")); + } + if (count < 0) + { + throw new ArgumentOutOfRangeException("count", BitStreamResources.GetString("ArgumentOutOfRange_NegativeParameter")); + } + if (count > bits.Length - offset) + { + throw new ArgumentException(BitStreamResources.GetString("Argument_InvalidCountOrOffset")); + } + int num = offset + count; + int num2 = 0; + for (int i = offset; i < num; i++) + { + num2 += Read(out bits[i]); + } + return num2; + } + + public virtual int Read(out int bits) + { + return Read(out bits, 0, 32); + } + + public virtual int Read(out int bits, int bitIndex, int count) + { + uint bits2 = 0u; + int result = Read(out bits2, bitIndex, count); + bits = (int)bits2; + return result; + } + + public virtual int Read(int[] bits) + { + if (!_blnIsOpen) + { + throw new ObjectDisposedException(BitStreamResources.GetString("ObjectDisposed_BitStreamClosed")); + } + if (bits == null) + { + throw new ArgumentNullException("bits", BitStreamResources.GetString("ArgumentNull_BitBuffer")); + } + return Read(bits, 0, bits.Length); + } + + public virtual int Read(int[] bits, int offset, int count) + { + if (!_blnIsOpen) + { + throw new ObjectDisposedException(BitStreamResources.GetString("ObjectDisposed_BitStreamClosed")); + } + if (bits == null) + { + throw new ArgumentNullException("bits", BitStreamResources.GetString("ArgumentNull_BitBuffer")); + } + if (offset < 0) + { + throw new ArgumentOutOfRangeException("offset", BitStreamResources.GetString("ArgumentOutOfRange_NegativeParameter")); + } + if (count < 0) + { + throw new ArgumentOutOfRangeException("count", BitStreamResources.GetString("ArgumentOutOfRange_NegativeParameter")); + } + if (count > bits.Length - offset) + { + throw new ArgumentException(BitStreamResources.GetString("Argument_InvalidCountOrOffset")); + } + int num = offset + count; + int num2 = 0; + for (int i = offset; i < num; i++) + { + num2 += Read(out bits[i]); + } + return num2; + } + + public virtual int Read(out float bits) + { + return Read(out bits, 0, 32); + } + + public virtual int Read(out float bits, int bitIndex, int count) + { + int bits2 = 0; + int result = Read(out bits2, bitIndex, count); + bits = BitConverter.ToSingle(BitConverter.GetBytes(bits2), 0); + return result; + } + + public virtual int Read(float[] bits) + { + if (!_blnIsOpen) + { + throw new ObjectDisposedException(BitStreamResources.GetString("ObjectDisposed_BitStreamClosed")); + } + if (bits == null) + { + throw new ArgumentNullException("bits", BitStreamResources.GetString("ArgumentNull_BitBuffer")); + } + return Read(bits, 0, bits.Length); + } + + public virtual int Read(float[] bits, int offset, int count) + { + if (!_blnIsOpen) + { + throw new ObjectDisposedException(BitStreamResources.GetString("ObjectDisposed_BitStreamClosed")); + } + if (bits == null) + { + throw new ArgumentNullException("bits", BitStreamResources.GetString("ArgumentNull_BitBuffer")); + } + if (offset < 0) + { + throw new ArgumentOutOfRangeException("offset", BitStreamResources.GetString("ArgumentOutOfRange_NegativeParameter")); + } + if (count < 0) + { + throw new ArgumentOutOfRangeException("count", BitStreamResources.GetString("ArgumentOutOfRange_NegativeParameter")); + } + if (count > bits.Length - offset) + { + throw new ArgumentException(BitStreamResources.GetString("Argument_InvalidCountOrOffset")); + } + int num = offset + count; + int num2 = 0; + for (int i = offset; i < num; i++) + { + num2 += Read(out bits[i]); + } + return num2; + } + + [CLSCompliant(false)] + public virtual int Read(out ulong bits) + { + return Read(out bits, 0, 64); + } + + [CLSCompliant(false)] + public virtual int Read(out ulong bits, int bitIndex, int count) + { + if (!_blnIsOpen) + { + throw new ObjectDisposedException(BitStreamResources.GetString("ObjectDisposed_BitStreamClosed")); + } + if (bitIndex < 0) + { + throw new ArgumentOutOfRangeException("bitIndex", BitStreamResources.GetString("ArgumentOutOfRange_NegativeParameter")); + } + if (count < 0) + { + throw new ArgumentOutOfRangeException("count", BitStreamResources.GetString("ArgumentOutOfRange_NegativeParameter")); + } + if (count > 64 - bitIndex) + { + throw new ArgumentException(BitStreamResources.GetString("Argument_InvalidCountOrBitIndex_UInt64")); + } + int num = (bitIndex >> 5 < 1) ? bitIndex : (-1); + int num2 = (bitIndex + count <= 32) ? (-1) : ((num < 0) ? (bitIndex - 32) : 0); + int num3 = (num > -1) ? ((num + count > 32) ? (32 - num) : count) : 0; + int num4 = (num2 > -1) ? ((num3 == 0) ? count : (count - num3)) : 0; + uint num5 = 0u; + uint bits2 = 0u; + uint bits3 = 0u; + if (num3 > 0) + { + uint bitIndex2 = (uint)num; + uint count2 = (uint)num3; + num5 = Read(ref bits2, ref bitIndex2, ref count2); + } + if (num4 > 0) + { + uint bitIndex3 = (uint)num2; + uint count3 = (uint)num4; + num5 += Read(ref bits3, ref bitIndex3, ref count3); + } + bits = (((ulong)bits3 << 32) | bits2); + return (int)num5; + } + + [CLSCompliant(false)] + public virtual int Read(ulong[] bits) + { + if (!_blnIsOpen) + { + throw new ObjectDisposedException(BitStreamResources.GetString("ObjectDisposed_BitStreamClosed")); + } + if (bits == null) + { + throw new ArgumentNullException("bits", BitStreamResources.GetString("ArgumentNull_BitBuffer")); + } + return Read(bits, 0, bits.Length); + } + + [CLSCompliant(false)] + public virtual int Read(ulong[] bits, int offset, int count) + { + if (!_blnIsOpen) + { + throw new ObjectDisposedException(BitStreamResources.GetString("ObjectDisposed_BitStreamClosed")); + } + if (bits == null) + { + throw new ArgumentNullException("bits", BitStreamResources.GetString("ArgumentNull_BitBuffer")); + } + if (offset < 0) + { + throw new ArgumentOutOfRangeException("offset", BitStreamResources.GetString("ArgumentOutOfRange_NegativeParameter")); + } + if (count < 0) + { + throw new ArgumentOutOfRangeException("count", BitStreamResources.GetString("ArgumentOutOfRange_NegativeParameter")); + } + if (count > bits.Length - offset) + { + throw new ArgumentException(BitStreamResources.GetString("Argument_InvalidCountOrOffset")); + } + int num = offset + count; + int num2 = 0; + for (int i = offset; i < num; i++) + { + num2 += Read(out bits[i]); + } + return num2; + } + + public virtual int Read(out long bits) + { + return Read(out bits, 0, 64); + } + + public virtual int Read(out long bits, int bitIndex, int count) + { + ulong bits2 = 0uL; + int result = Read(out bits2, bitIndex, count); + bits = (long)bits2; + return result; + } + + public virtual int Read(long[] bits) + { + if (!_blnIsOpen) + { + throw new ObjectDisposedException(BitStreamResources.GetString("ObjectDisposed_BitStreamClosed")); + } + if (bits == null) + { + throw new ArgumentNullException("bits", BitStreamResources.GetString("ArgumentNull_BitBuffer")); + } + return Read(bits, 0, bits.Length); + } + + public virtual int Read(long[] bits, int offset, int count) + { + if (!_blnIsOpen) + { + throw new ObjectDisposedException(BitStreamResources.GetString("ObjectDisposed_BitStreamClosed")); + } + if (bits == null) + { + throw new ArgumentNullException("bits", BitStreamResources.GetString("ArgumentNull_BitBuffer")); + } + if (offset < 0) + { + throw new ArgumentOutOfRangeException("offset", BitStreamResources.GetString("ArgumentOutOfRange_NegativeParameter")); + } + if (count < 0) + { + throw new ArgumentOutOfRangeException("count", BitStreamResources.GetString("ArgumentOutOfRange_NegativeParameter")); + } + if (count > bits.Length - offset) + { + throw new ArgumentException(BitStreamResources.GetString("Argument_InvalidCountOrOffset")); + } + int num = offset + count; + int num2 = 0; + for (int i = offset; i < num; i++) + { + num2 += Read(out bits[i]); + } + return num2; + } + + public virtual int Read(out double bits) + { + return Read(out bits, 0, 64); + } + + public virtual int Read(out double bits, int bitIndex, int count) + { + ulong bits2 = 0uL; + int result = Read(out bits2, bitIndex, count); + bits = BitConverter.ToDouble(BitConverter.GetBytes(bits2), 0); + return result; + } + + public virtual int Read(double[] bits) + { + if (!_blnIsOpen) + { + throw new ObjectDisposedException(BitStreamResources.GetString("ObjectDisposed_BitStreamClosed")); + } + if (bits == null) + { + throw new ArgumentNullException("bits", BitStreamResources.GetString("ArgumentNull_BitBuffer")); + } + return Read(bits, 0, bits.Length); + } + + public virtual int Read(double[] bits, int offset, int count) + { + if (!_blnIsOpen) + { + throw new ObjectDisposedException(BitStreamResources.GetString("ObjectDisposed_BitStreamClosed")); + } + if (bits == null) + { + throw new ArgumentNullException("bits", BitStreamResources.GetString("ArgumentNull_BitBuffer")); + } + if (offset < 0) + { + throw new ArgumentOutOfRangeException("offset", BitStreamResources.GetString("ArgumentOutOfRange_NegativeParameter")); + } + if (count < 0) + { + throw new ArgumentOutOfRangeException("count", BitStreamResources.GetString("ArgumentOutOfRange_NegativeParameter")); + } + if (count > bits.Length - offset) + { + throw new ArgumentException(BitStreamResources.GetString("Argument_InvalidCountOrOffset")); + } + int num = offset + count; + int num2 = 0; + for (int i = offset; i < num; i++) + { + num2 += Read(out bits[i]); + } + return num2; + } + + public virtual BitStream And(BitStream bits) + { + if (!_blnIsOpen) + { + throw new ObjectDisposedException(BitStreamResources.GetString("ObjectDisposed_BitStreamClosed")); + } + if (bits == null) + { + throw new ArgumentNullException("bits", BitStreamResources.GetString("ArgumentNull_BitStream")); + } + if (bits.Length != _uiBitBuffer_Length) + { + throw new ArgumentException(BitStreamResources.GetString("Argument_DifferentBitStreamLengths")); + } + BitStream bitStream = new BitStream(_uiBitBuffer_Length); + uint num = _uiBitBuffer_Length >> 5; + uint num2 = 0u; + for (num2 = 0u; num2 < num; num2++) + { + bitStream._auiBitBuffer[num2] = (_auiBitBuffer[num2] & bits._auiBitBuffer[num2]); + } + if ((_uiBitBuffer_Length & 0x1F) != 0) + { + uint num3 = (uint)(-1 << (int)(32 - (_uiBitBuffer_Length & 0x1F))); + bitStream._auiBitBuffer[num2] = (_auiBitBuffer[num2] & bits._auiBitBuffer[num2] & num3); + } + return bitStream; + } + + public virtual BitStream Or(BitStream bits) + { + if (!_blnIsOpen) + { + throw new ObjectDisposedException(BitStreamResources.GetString("ObjectDisposed_BitStreamClosed")); + } + if (bits == null) + { + throw new ArgumentNullException("bits", BitStreamResources.GetString("ArgumentNull_BitStream")); + } + if (bits.Length != _uiBitBuffer_Length) + { + throw new ArgumentException(BitStreamResources.GetString("Argument_DifferentBitStreamLengths")); + } + BitStream bitStream = new BitStream(_uiBitBuffer_Length); + uint num = _uiBitBuffer_Length >> 5; + uint num2 = 0u; + for (num2 = 0u; num2 < num; num2++) + { + bitStream._auiBitBuffer[num2] = (_auiBitBuffer[num2] | bits._auiBitBuffer[num2]); + } + if ((_uiBitBuffer_Length & 0x1F) != 0) + { + uint num3 = (uint)(-1 << (int)(32 - (_uiBitBuffer_Length & 0x1F))); + bitStream._auiBitBuffer[num2] = (_auiBitBuffer[num2] | (bits._auiBitBuffer[num2] & num3)); + } + return bitStream; + } + + public virtual BitStream Xor(BitStream bits) + { + if (!_blnIsOpen) + { + throw new ObjectDisposedException(BitStreamResources.GetString("ObjectDisposed_BitStreamClosed")); + } + if (bits == null) + { + throw new ArgumentNullException("bits", BitStreamResources.GetString("ArgumentNull_BitStream")); + } + if (bits.Length != _uiBitBuffer_Length) + { + throw new ArgumentException(BitStreamResources.GetString("Argument_DifferentBitStreamLengths")); + } + BitStream bitStream = new BitStream(_uiBitBuffer_Length); + uint num = _uiBitBuffer_Length >> 5; + uint num2 = 0u; + for (num2 = 0u; num2 < num; num2++) + { + bitStream._auiBitBuffer[num2] = (_auiBitBuffer[num2] ^ bits._auiBitBuffer[num2]); + } + if ((_uiBitBuffer_Length & 0x1F) != 0) + { + uint num3 = (uint)(-1 << (int)(32 - (_uiBitBuffer_Length & 0x1F))); + bitStream._auiBitBuffer[num2] = (_auiBitBuffer[num2] ^ (bits._auiBitBuffer[num2] & num3)); + } + return bitStream; + } + + public virtual BitStream Not() + { + if (!_blnIsOpen) + { + throw new ObjectDisposedException(BitStreamResources.GetString("ObjectDisposed_BitStreamClosed")); + } + BitStream bitStream = new BitStream(_uiBitBuffer_Length); + uint num = _uiBitBuffer_Length >> 5; + uint num2 = 0u; + for (num2 = 0u; num2 < num; num2++) + { + bitStream._auiBitBuffer[num2] = ~_auiBitBuffer[num2]; + } + if ((_uiBitBuffer_Length & 0x1F) != 0) + { + uint num3 = (uint)(-1 << (int)(32 - (_uiBitBuffer_Length & 0x1F))); + bitStream._auiBitBuffer[num2] = (~_auiBitBuffer[num2] & num3); + } + return bitStream; + } + + public virtual BitStream ShiftLeft(long count) + { + if (!_blnIsOpen) + { + throw new ObjectDisposedException(BitStreamResources.GetString("ObjectDisposed_BitStreamClosed")); + } + BitStream bitStream = Copy(); + uint num = (uint)count; + uint num2 = (uint)bitStream.Length; + if (num >= num2) + { + bitStream.Position = 0L; + for (uint num3 = 0u; num3 < num2; num3++) + { + bitStream.Write(bit: false); + } + } + else + { + bool bit = false; + for (uint num3 = 0u; num3 < num2 - num; num3++) + { + bitStream.Position = num + num3; + bitStream.Read(out bit); + bitStream.Position = num3; + bitStream.Write(bit); + } + for (uint num3 = num2 - num; num3 < num2; num3++) + { + bitStream.Write(bit: false); + } + } + bitStream.Position = 0L; + return bitStream; + } + + public virtual BitStream ShiftRight(long count) + { + if (!_blnIsOpen) + { + throw new ObjectDisposedException(BitStreamResources.GetString("ObjectDisposed_BitStreamClosed")); + } + BitStream bitStream = Copy(); + uint num = (uint)count; + uint num2 = (uint)bitStream.Length; + if (num >= num2) + { + bitStream.Position = 0L; + for (uint num3 = 0u; num3 < num2; num3++) + { + bitStream.Write(bit: false); + } + } + else + { + bool bit = false; + for (uint num3 = 0u; num3 < num2 - num; num3++) + { + bitStream.Position = num3; + bitStream.Read(out bit); + bitStream.Position = num3 + num; + bitStream.Write(bit); + } + bitStream.Position = 0L; + for (uint num3 = 0u; num3 < num; num3++) + { + bitStream.Write(bit: false); + } + } + bitStream.Position = 0L; + return bitStream; + } + + public override string ToString() + { + uint num = _uiBitBuffer_Length >> 5; + uint num2 = 0u; + int num3 = 0; + uint num4 = 1u; + StringBuilder stringBuilder = new StringBuilder((int)_uiBitBuffer_Length); + for (num2 = 0u; num2 < num; num2++) + { + stringBuilder.Append("[" + num2.ToString(_ifp) + "]:{"); + for (num3 = 31; num3 >= 0; num3--) + { + uint num5 = num4 << num3; + if ((_auiBitBuffer[num2] & num5) == num5) + { + stringBuilder.Append('1'); + } + else + { + stringBuilder.Append('0'); + } + } + stringBuilder.Append("}\r\n"); + } + if ((_uiBitBuffer_Length & 0x1F) != 0) + { + stringBuilder.Append("[" + num2.ToString(_ifp) + "]:{"); + int num6 = (int)(32 - (_uiBitBuffer_Length & 0x1F)); + for (num3 = 31; num3 >= num6; num3--) + { + uint num5 = num4 << num3; + if ((_auiBitBuffer[num2] & num5) == num5) + { + stringBuilder.Append('1'); + } + else + { + stringBuilder.Append('0'); + } + } + for (num3 = num6 - 1; num3 >= 0; num3--) + { + stringBuilder.Append('.'); + } + stringBuilder.Append("}\r\n"); + } + return stringBuilder.ToString(); + } + + public static string ToString(bool bit) + { + return "Boolean{" + (bit ? 1 : 0) + "}"; + } + + public static string ToString(byte bits) + { + StringBuilder stringBuilder = new StringBuilder(8); + uint num = 1u; + stringBuilder.Append("Byte{"); + for (int num2 = 7; num2 >= 0; num2--) + { + uint num3 = num << num2; + if ((bits & num3) == num3) + { + stringBuilder.Append('1'); + } + else + { + stringBuilder.Append('0'); + } + } + stringBuilder.Append("}"); + return stringBuilder.ToString(); + } + + [CLSCompliant(false)] + public static string ToString(sbyte bits) + { + byte b = (byte)bits; + StringBuilder stringBuilder = new StringBuilder(8); + uint num = 1u; + stringBuilder.Append("SByte{"); + for (int num2 = 7; num2 >= 0; num2--) + { + uint num3 = num << num2; + if ((b & num3) == num3) + { + stringBuilder.Append('1'); + } + else + { + stringBuilder.Append('0'); + } + } + stringBuilder.Append("}"); + return stringBuilder.ToString(); + } + + public static string ToString(char bits) + { + StringBuilder stringBuilder = new StringBuilder(16); + uint num = 1u; + stringBuilder.Append("Char{"); + for (int num2 = 15; num2 >= 0; num2--) + { + uint num3 = num << num2; + if ((bits & num3) == num3) + { + stringBuilder.Append('1'); + } + else + { + stringBuilder.Append('0'); + } + } + stringBuilder.Append("}"); + return stringBuilder.ToString(); + } + + [CLSCompliant(false)] + public static string ToString(ushort bits) + { + short num = (short)bits; + StringBuilder stringBuilder = new StringBuilder(16); + uint num2 = 1u; + stringBuilder.Append("UInt16{"); + for (int num3 = 15; num3 >= 0; num3--) + { + uint num4 = num2 << num3; + if ((num & num4) == num4) + { + stringBuilder.Append('1'); + } + else + { + stringBuilder.Append('0'); + } + } + stringBuilder.Append("}"); + return stringBuilder.ToString(); + } + + public static string ToString(short bits) + { + StringBuilder stringBuilder = new StringBuilder(16); + uint num = 1u; + stringBuilder.Append("Int16{"); + for (int num2 = 15; num2 >= 0; num2--) + { + uint num3 = num << num2; + if ((bits & num3) == num3) + { + stringBuilder.Append('1'); + } + else + { + stringBuilder.Append('0'); + } + } + stringBuilder.Append("}"); + return stringBuilder.ToString(); + } + + [CLSCompliant(false)] + public static string ToString(uint bits) + { + StringBuilder stringBuilder = new StringBuilder(32); + uint num = 1u; + stringBuilder.Append("UInt32{"); + for (int num2 = 31; num2 >= 0; num2--) + { + uint num3 = num << num2; + if ((bits & num3) == num3) + { + stringBuilder.Append('1'); + } + else + { + stringBuilder.Append('0'); + } + } + stringBuilder.Append("}"); + return stringBuilder.ToString(); + } + + public static string ToString(int bits) + { + StringBuilder stringBuilder = new StringBuilder(32); + uint num = 1u; + stringBuilder.Append("Int32{"); + for (int num2 = 31; num2 >= 0; num2--) + { + uint num3 = num << num2; + if ((bits & (int)num3) == (int)num3) + { + stringBuilder.Append('1'); + } + else + { + stringBuilder.Append('0'); + } + } + stringBuilder.Append("}"); + return stringBuilder.ToString(); + } + + [CLSCompliant(false)] + public static string ToString(ulong bits) + { + StringBuilder stringBuilder = new StringBuilder(64); + ulong num = 1uL; + stringBuilder.Append("UInt64{"); + for (int num2 = 63; num2 >= 0; num2--) + { + ulong num3 = num << num2; + if ((bits & num3) == num3) + { + stringBuilder.Append('1'); + } + else + { + stringBuilder.Append('0'); + } + } + stringBuilder.Append("}"); + return stringBuilder.ToString(); + } + + public static string ToString(long bits) + { + StringBuilder stringBuilder = new StringBuilder(64); + ulong num = 1uL; + stringBuilder.Append("Int64{"); + for (int num2 = 63; num2 >= 0; num2--) + { + ulong num3 = num << num2; + if ((bits & (long)num3) == (long)num3) + { + stringBuilder.Append('1'); + } + else + { + stringBuilder.Append('0'); + } + } + stringBuilder.Append("}"); + return stringBuilder.ToString(); + } + + public static string ToString(float bits) + { + byte[] bytes = BitConverter.GetBytes(bits); + uint num = (uint)(bytes[0] | (bytes[1] << 8) | (bytes[2] << 16) | (bytes[3] << 24)); + StringBuilder stringBuilder = new StringBuilder(32); + uint num2 = 1u; + stringBuilder.Append("Single{"); + for (int num3 = 31; num3 >= 0; num3--) + { + uint num4 = num2 << num3; + if ((num & num4) == num4) + { + stringBuilder.Append('1'); + } + else + { + stringBuilder.Append('0'); + } + } + stringBuilder.Append("}"); + return stringBuilder.ToString(); + } + + public static string ToString(double bits) + { + byte[] bytes = BitConverter.GetBytes(bits); + ulong num = bytes[0] | ((ulong)bytes[1] << 8) | ((ulong)bytes[2] << 16) | ((ulong)bytes[3] << 24) | ((ulong)bytes[4] << 32) | ((ulong)bytes[5] << 40) | ((ulong)bytes[6] << 48) | ((ulong)bytes[7] << 56); + StringBuilder stringBuilder = new StringBuilder(64); + ulong num2 = 1uL; + stringBuilder.Append("Double{"); + for (int num3 = 63; num3 >= 0; num3--) + { + ulong num4 = num2 << num3; + if ((num & num4) == num4) + { + stringBuilder.Append('1'); + } + else + { + stringBuilder.Append('0'); + } + } + stringBuilder.Append("}"); + return stringBuilder.ToString(); + } + + private void UpdateLengthForWrite(uint bits) + { + _uiBitBuffer_Length += bits; + } + + private void UpdateIndicesForWrite(uint bits) + { + _uiBitBuffer_BitIndex += bits; + if (_uiBitBuffer_BitIndex == 32) + { + _uiBitBuffer_Index++; + _uiBitBuffer_BitIndex = 0u; + if (_auiBitBuffer.Length == _uiBitBuffer_Length >> 5) + { + _auiBitBuffer = ReDimPreserve(_auiBitBuffer, (uint)(_auiBitBuffer.Length << 1)); + } + } + else if (_uiBitBuffer_BitIndex > 32) + { + throw new InvalidOperationException(BitStreamResources.GetString("InvalidOperation_BitIndexGreaterThan32")); + } + } + + private void UpdateIndicesForRead(uint bits) + { + _uiBitBuffer_BitIndex += bits; + if (_uiBitBuffer_BitIndex == 32) + { + _uiBitBuffer_Index++; + _uiBitBuffer_BitIndex = 0u; + } + else if (_uiBitBuffer_BitIndex > 32) + { + throw new InvalidOperationException(BitStreamResources.GetString("InvalidOperation_BitIndexGreaterThan32")); + } + } + + private static uint[] ReDimPreserve(uint[] buffer, uint newLength) + { + uint[] array = new uint[newLength]; + uint num = (uint)buffer.Length; + if (num < newLength) + { + Buffer.BlockCopy(buffer, 0, array, 0, (int)(num << 2)); + } + else + { + Buffer.BlockCopy(buffer, 0, array, 0, (int)(newLength << 2)); + } + buffer = null; + return array; + } + + public override void Close() + { + _blnIsOpen = false; + _uiBitBuffer_Index = 0u; + _uiBitBuffer_BitIndex = 0u; + } + + [CLSCompliant(false)] + public virtual uint[] GetBuffer() + { + return _auiBitBuffer; + } + + public virtual BitStream Copy() + { + BitStream bitStream = new BitStream(Length); + Buffer.BlockCopy(_auiBitBuffer, 0, bitStream._auiBitBuffer, 0, bitStream._auiBitBuffer.Length << 2); + bitStream._uiBitBuffer_Length = _uiBitBuffer_Length; + return bitStream; + } + + public override IAsyncResult BeginRead(byte[] buffer, int offset, int count, AsyncCallback callback, object state) + { + throw new NotSupportedException(BitStreamResources.GetString("NotSupported_AsyncOps")); + } + + public override IAsyncResult BeginWrite(byte[] buffer, int offset, int count, AsyncCallback callback, object state) + { + throw new NotSupportedException(BitStreamResources.GetString("NotSupported_AsyncOps")); + } + + public override int EndRead(IAsyncResult asyncResult) + { + throw new NotSupportedException(BitStreamResources.GetString("NotSupported_AsyncOps")); + } + + public override void EndWrite(IAsyncResult asyncResult) + { + throw new NotSupportedException(BitStreamResources.GetString("NotSupported_AsyncOps")); + } + + public override long Seek(long offset, SeekOrigin origin) + { + throw new NotSupportedException(BitStreamResources.GetString("NotSupported_Seek")); + } + + public override void SetLength(long value) + { + throw new NotSupportedException(BitStreamResources.GetString("NotSupported_SetLength")); + } + + public override void Flush() + { + throw new NotSupportedException(BitStreamResources.GetString("NotSupported_Flush")); + } + + public static implicit operator BitStream(MemoryStream bits) + { + if (bits == null) + { + throw new ArgumentNullException("bits", BitStreamResources.GetString("ArgumentNull_MemoryStream")); + } + return new BitStream(bits); + } + + public static implicit operator MemoryStream(BitStream bits) + { + if (bits == null) + { + throw new ArgumentNullException("bits", BitStreamResources.GetString("ArgumentNull_BitStream")); + } + return new MemoryStream(bits.ToByteArray()); + } + + public static implicit operator BitStream(FileStream bits) + { + if (bits == null) + { + throw new ArgumentNullException("bits", BitStreamResources.GetString("ArgumentNull_FileStream")); + } + return new BitStream(bits); + } + + public static implicit operator BitStream(BufferedStream bits) + { + if (bits == null) + { + throw new ArgumentNullException("bits", BitStreamResources.GetString("ArgumentNull_BufferedStream")); + } + return new BitStream(bits); + } + + public static implicit operator BufferedStream(BitStream bits) + { + if (bits == null) + { + throw new ArgumentNullException("bits", BitStreamResources.GetString("ArgumentNull_BitStream")); + } + return new BufferedStream((MemoryStream)bits); + } + + public static implicit operator BitStream(NetworkStream bits) + { + if (bits == null) + { + throw new ArgumentNullException("bits", BitStreamResources.GetString("ArgumentNull_NetworkStream")); + } + return new BitStream(bits); + } + + public static implicit operator BitStream(CryptoStream bits) + { + if (bits == null) + { + throw new ArgumentNullException("bits", BitStreamResources.GetString("ArgumentNull_CryptoStream")); + } + return new BitStream(bits); + } + } +} diff --git a/Common.GLib/GLib.IO/BitStream.resx b/Common.GLib/GLib.IO/BitStream.resx new file mode 100644 index 0000000..5e7aedb --- /dev/null +++ b/Common.GLib/GLib.IO/BitStream.resx @@ -0,0 +1,59 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +text/microsoft-resx1.3System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089Position must be greater than or equal to zero. + count + offset were out of bounds for the BitStream or count is greater than the number of elements from bitIndex to the end of the BitStream. + The BitStream cannot be null. + The BufferedStream cannot be null. + Capacity must be greater than zero. + count + bitIndex exceeds the length of the 128-bit value. + Parameter must be greater than or equal to zero. + The CryptoStream cannot be null. + The internal bit buffer's bit index cannot be greater than 32. + Cannot SetLength of a BitStream. + The NetworkStream cannot be null. + Asynchronous operations are not supported by the BitStream class. + Cannot Seek on a BitStream. Use Position property instead. + The inherited ReadByte method is not supported by the BitStream class. Use one of the overloaded Read methods instead. + Position must be less than or equal to the Bit Stream Length - 1. + count + bitIndex exceeds the length of the 16-bit value. + count + bitIndex exceeds the length of the 8-bit value. + The inherited WriteByte method is not supported by the BitStream class. Use one of the overloaded Write methods instead. + The FileStream cannot be null. + count + offset were out of bounds for the array or count is greater than the number of elements from offset to the end of the array. + The Stream cannot be null. + count + bitIndex exceeds the length of the 64-bit value. + count + bitIndex exceeds the length of the 32-bit value. + count + bitIndex exceeds the length of the 16-bit value. + The MemoryStream cannot be null. + Cannot Flush a BitStream. + Cannot access a closed BitStream. + BitStream lengths must be the same. + The bit buffer cannot be null. + \ No newline at end of file diff --git a/Common.GLib/GLib.IO/BitStreamReader.cs b/Common.GLib/GLib.IO/BitStreamReader.cs new file mode 100644 index 0000000..cefd4eb --- /dev/null +++ b/Common.GLib/GLib.IO/BitStreamReader.cs @@ -0,0 +1,110 @@ +using System; +using System.Collections; +using System.Collections.Generic; +using System.IO; + +namespace GLib.IO +{ + public class BitStreamReader + { + private Stream _stream = null; + + private BinaryReader _reader = null; + + private int byte_point = -1; + + private BitArray bit_arr = null; + + public BitStreamReader(byte[] bytes) + : this(new MemoryStream(bytes)) + { + } + + public BitStreamReader(Stream stream) + { + _stream = stream; + _reader = new BinaryReader(_stream); + } + + public bool ReadBit() + { + if (byte_point == -1 || bit_arr == null) + { + bit_arr = new BitArray(new byte[1] + { + _reader.ReadByte() + }); + byte_point = 7; + } + bool result = bit_arr.Get(byte_point); + byte_point--; + return result; + } + + public byte[] ReadBit(int len) + { + int num = 0; + int num2 = len / 8 + ((len % 8 != 0) ? 1 : 0); + List list = new List(); + for (int i = 0; i < num2; i++) + { + byte b = 0; + int num3 = (len - num >= 8) ? 7 : (len - num - 1); + for (int num4 = num3; num4 >= 0; num4--) + { + b = ((!ReadBit()) ? ((byte)(b << ((num4 > 0) ? 1 : 0))) : ((byte)((1 | b) << ((num4 > 0) ? 1 : 0)))); + num++; + if (num == len) + { + break; + } + } + list.Add(b); + if (num == len) + { + break; + } + } + return list.ToArray(); + } + + public void Skip(int len) + { + ReadBit(len); + } + + public byte ReadByte(int len) + { + byte[] array = ReadBit(len); + return array[0]; + } + + public short ReadShort(int len) + { + byte[] array = ReadBit(len); + if (array.Length < 2) + { + List list = new List(); + list.AddRange(new byte[2 - array.Length]); + list.AddRange(array); + array = list.ToArray(); + } + Array.Reverse(array); + return BitConverter.ToInt16(array, 0); + } + + public int ReadInt(int len) + { + byte[] array = ReadBit(len); + if (array.Length < 4) + { + List list = new List(); + list.AddRange(new byte[4 - array.Length]); + list.AddRange(array); + array = list.ToArray(); + } + Array.Reverse(array); + return BitConverter.ToInt32(array, 0); + } + } +} diff --git a/Common.GLib/GLib.IO/BufferStream.cs b/Common.GLib/GLib.IO/BufferStream.cs new file mode 100644 index 0000000..602f19e --- /dev/null +++ b/Common.GLib/GLib.IO/BufferStream.cs @@ -0,0 +1,146 @@ +using GLib.GeneralModel; +using System; +using System.IO; +using System.Threading; + +namespace GLib.IO +{ + public class BufferStream : Stream + { + private AQueue _queueMS = new AQueue(); + + private MemoryStream _curMS = null; + + private object _lock = new object(); + + public int _size = 0; + + public override long Length => _size; + + public virtual int Size => (int)Length; + + public override long Position + { + get + { + return 0L; + } + set + { + throw new NotImplementedException(); + } + } + + public override bool CanRead => true; + + public override bool CanSeek => false; + + public override bool CanWrite => true; + + public void Write(byte[] bs) + { + Write(bs, 0, bs.Length); + } + + public override void Write(byte[] bs, int index, int count) + { + lock (_lock) + { + _Write(bs, index, count); + } + } + + public byte[] Read(int len) + { + lock (_lock) + { + return _Read(len); + } + } + + public override int Read(byte[] buf, int offset, int len) + { + byte[] array = Read(len); + Array.Copy(array, 0, buf, offset, len); + return array.Length; + } + + private void _Write(byte[] bs, int index, int count) + { + MemoryStream memoryStream = new MemoryStream(bs, index, count); + memoryStream.Position = 0L; + lock (_queueMS.GetLock()) + { + _queueMS.Enqueue(memoryStream); + _size += count; + } + } + + private byte[] _Read(int len) + { + while (_size < len) + { + Thread.Sleep(10); + bool flag = true; + } + int size = _size; + byte[] array = new byte[len]; + int num = 0; + lock (_queueMS.GetLock()) + { + while (num < len) + { + if (_curMS == null) + { + _curMS = _queueMS.Dequeue(); + } + num += _curMS.Read(array, num, len - num); + if (_curMS.Length == _curMS.Position) + { + _curMS = null; + } + } + if (num != len) + { + throw new Exception(); + } + _size -= len; + } + return array; + } + + public override void Flush() + { + } + + public override void SetLength(long value) + { + throw new NotImplementedException(); + } + + public override long Seek(long offset, SeekOrigin origin) + { + throw new NotImplementedException(); + } + + public byte[] ToArray() + { + byte[] array = new byte[_size]; + Read(array, 0, array.Length); + return array; + } + + public override void Close() + { + base.Close(); + if (_curMS != null) + { + _queueMS.Clear(); + } + if (_curMS != null) + { + _curMS.Close(); + } + } + } +} diff --git a/Common.GLib/GLib.IO/IOStream.cs b/Common.GLib/GLib.IO/IOStream.cs new file mode 100644 index 0000000..03e7d78 --- /dev/null +++ b/Common.GLib/GLib.IO/IOStream.cs @@ -0,0 +1,6 @@ +namespace GLib.IO +{ + public class IOStream : BufferStream + { + } +} diff --git a/Common.GLib/GLib.Linq/DynamicQueryable.cs b/Common.GLib/GLib.Linq/DynamicQueryable.cs new file mode 100644 index 0000000..9fce18e --- /dev/null +++ b/Common.GLib/GLib.Linq/DynamicQueryable.cs @@ -0,0 +1,30 @@ +using System.Collections.Generic; +using System.Linq; + +namespace GLib.Linq +{ + public static class DynamicQueryable + { + public static IQueryable Where(this IQueryable source, IFilterExpressionContainer container) + { + //IList expressions = container.GetExpressions(); + //foreach (FilterExpression item in expressions) + //{ + // //source = DynamicQueryable.Where(source, item.Predicate, item.Values); + //} + source = Where(source, container); + + return source; + } + + public static IQueryable OrderBy(this IQueryable source, string ordering) + { + if (!string.IsNullOrEmpty(ordering)) + { + // return DynamicQueryable.OrderBy(source, ordering, new object[0]); + OrderBy(source, ordering); + } + return source; + } + } +} diff --git a/Common.GLib/GLib.Linq/FilterExpression.cs b/Common.GLib/GLib.Linq/FilterExpression.cs new file mode 100644 index 0000000..540027d --- /dev/null +++ b/Common.GLib/GLib.Linq/FilterExpression.cs @@ -0,0 +1,20 @@ +using System; + +namespace GLib.Linq +{ + [Serializable] + public class FilterExpression + { + public string Predicate + { + get; + set; + } + + public object[] Values + { + get; + set; + } + } +} diff --git a/Common.GLib/GLib.Linq/IFilterExpressionContainer.cs b/Common.GLib/GLib.Linq/IFilterExpressionContainer.cs new file mode 100644 index 0000000..32a0318 --- /dev/null +++ b/Common.GLib/GLib.Linq/IFilterExpressionContainer.cs @@ -0,0 +1,17 @@ +using System.Collections.Generic; + +namespace GLib.Linq +{ + public interface IFilterExpressionContainer + { + IList GetExpressions(); + + void AddFilterExpression(string predicate, params object[] values); + + void RemoveFilterExpression(string predicate, params object[] values); + + void RemoveAllFilterExpression(string predicate); + + void RemoveAllFilterExpression(); + } +} diff --git a/Common.GLib/GLib.Logging/Log.cs b/Common.GLib/GLib.Logging/Log.cs new file mode 100644 index 0000000..2624493 --- /dev/null +++ b/Common.GLib/GLib.Logging/Log.cs @@ -0,0 +1,184 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Text; +using System.Threading; + +namespace GLib.Logging +{ + public class Log : IDisposable + { + private static Queue logMessages; + + private static string path; + + private static bool state; + + private static LogType logtype; + + private static DateTime time; + + private static StreamWriter writer; + + public Log() + : this(AppDomain.CurrentDomain.BaseDirectory, LogType.Daily) + { + } + + public Log(LogType t) + : this(AppDomain.CurrentDomain.BaseDirectory, t) + { + } + + public Log(string filepath, LogType t) + { + if (logMessages == null) + { + state = true; + path = filepath; + logtype = t; + FileOpen(); + logMessages = new Queue(); + Thread thread = new Thread(Work); + thread.Start(); + } + } + + private void Work() + { + while (true) + { + bool flag = true; + if (logMessages.Count > 0) + { + LogMessage logMessage = null; + lock (logMessages) + { + logMessage = logMessages.Dequeue(); + } + if (logMessage != null) + { + WriteLogMessage(logMessage); + } + } + else if (state) + { + Thread.Sleep(1); + } + else + { + FileClose(); + } + } + } + + private void WriteLogMessage(LogMessage message) + { + try + { + if (writer == null) + { + FileOpen(); + } + else + { + if (DateTime.Now >= time) + { + FileClose(); + FileOpen(); + } + writer.Write(message.Time); + writer.Write("\t"); + writer.Write(message.Type); + writer.Write("\t\r\n"); + writer.Write(message.Content); + writer.Write("\r\n\r\n"); + writer.Flush(); + } + } + catch (Exception ex) + { + Console.WriteLine(ex.Message); + } + FileClose(); + } + + private string GetFileName() + { + DateTime now = DateTime.Now; + string format = ""; + switch (logtype) + { + case LogType.Daily: + time = new DateTime(now.Year, now.Month, now.Day); + time = time.AddDays(1.0); + format = "yyyyMMdd'.log'"; + break; + case LogType.Weekly: + time = new DateTime(now.Year, now.Month, now.Day); + time = time.AddDays(7.0); + format = "yyyyMMdd'.log'"; + break; + case LogType.Monthly: + time = new DateTime(now.Year, now.Month, 1); + time = time.AddMonths(1); + format = "yyyyMM'.log'"; + break; + case LogType.Annually: + time = new DateTime(now.Year, 1, 1); + time = time.AddYears(1); + format = "yyyy'.log'"; + break; + } + return now.ToString(format); + } + + public void Write(LogMessage message) + { + if (logMessages != null) + { + lock (logMessages) + { + logMessages.Enqueue(message); + } + } + } + + public void Write(string text, MessageType type) + { + Write(new LogMessage(text, type)); + } + + public void Write(DateTime now, string text, MessageType type) + { + Write(new LogMessage(now, text, type)); + } + + public void Write(Exception e, MessageType type) + { + Write(new LogMessage(e.Message, type)); + } + + private void FileOpen() + { + writer = new StreamWriter(path + GetFileName(), append: true, Encoding.Default); + } + + private void FileClose() + { + if (writer != null) + { + writer.Flush(); + writer.Close(); + writer.Dispose(); + writer = null; + } + } + + public void Dispose() + { + state = false; + GC.SuppressFinalize(this); + } + } +} diff --git a/Common.GLib/GLib.Logging/LogMessage.cs b/Common.GLib/GLib.Logging/LogMessage.cs new file mode 100644 index 0000000..b24817f --- /dev/null +++ b/Common.GLib/GLib.Logging/LogMessage.cs @@ -0,0 +1,71 @@ +using System; + +namespace GLib.Logging +{ + public class LogMessage + { + private DateTime _time; + + private string _content; + + private MessageType _type; + + public DateTime Time + { + get + { + return _time; + } + set + { + _time = value; + } + } + + public string Content + { + get + { + return _content; + } + set + { + _content = value; + } + } + + public MessageType Type + { + get + { + return _type; + } + set + { + _type = value; + } + } + + public LogMessage() + : this("", MessageType.Unkown) + { + } + + public LogMessage(string content, MessageType type) + : this(DateTime.Now, content, type) + { + } + + public LogMessage(DateTime time, string content, MessageType type) + { + _time = time; + _content = content; + _type = type; + } + + public override string ToString() + { + return _time.ToString() + "\t" + _content + "\t"; + } + } +} diff --git a/Common.GLib/GLib.Logging/LogType.cs b/Common.GLib/GLib.Logging/LogType.cs new file mode 100644 index 0000000..7bcf7c2 --- /dev/null +++ b/Common.GLib/GLib.Logging/LogType.cs @@ -0,0 +1,10 @@ +namespace GLib.Logging +{ + public enum LogType + { + Daily = 0, + Weekly = 1, + Monthly = 2, + Annually = 3 + } +} diff --git a/Common.GLib/GLib.Logging/MessageType.cs b/Common.GLib/GLib.Logging/MessageType.cs new file mode 100644 index 0000000..74fbecd --- /dev/null +++ b/Common.GLib/GLib.Logging/MessageType.cs @@ -0,0 +1,11 @@ +namespace GLib.Logging +{ + public enum MessageType + { + Unkown = 0, + Common = 1, + Warning = 2, + Error = 3, + Success = 4 + } +} diff --git a/Common.GLib/GLib.Net/AnsycSocket4ByteLengthDespatcher.cs b/Common.GLib/GLib.Net/AnsycSocket4ByteLengthDespatcher.cs new file mode 100644 index 0000000..5c67d4a --- /dev/null +++ b/Common.GLib/GLib.Net/AnsycSocket4ByteLengthDespatcher.cs @@ -0,0 +1,163 @@ +using System; +using System.Net.Sockets; + +namespace GLib.Net +{ + public class AnsycSocket4ByteLengthDespatcher + { + private AnsycSocketDespatcher _despatcher = null; + + private bool _isBeging = false; + + private bool _needTSLen = true; + + private bool _needTSData = true; + + private int _needTSDataLen = 0; + + private byte[] _bsLen = new byte[4]; + + private byte[] _bsData = null; + + private object _lock = new object(); + + private Action _DisoconnectHandle; + + private Action _Completed; + + private bool _isReceiveMode = false; + + private bool _isDisposed = false; + + public AnsycSocket4ByteLengthDespatcher(Socket socket, bool isReceiveMode, Action disoconnectHandle, Action _completed) + { + _isReceiveMode = isReceiveMode; + _DisoconnectHandle = disoconnectHandle; + _Completed = _completed; + _despatcher = new AnsycSocketDespatcher(socket, isReceiveMode, _despatcher_Disoconnect, _despatcher_Completed); + } + + public void BeginSend(byte[] buffer) + { + if (!_isDisposed && !_isBeging) + { + _needTSLen = true; + _needTSData = true; + _bsLen = BitConverter.GetBytes(buffer.Length); + _bsData = buffer; + _despatcher.Begin(_bsLen); + } + } + + public void EndSend() + { + if (_isBeging) + { + _isBeging = false; + _needTSLen = true; + _needTSData = true; + _bsData = null; + _despatcher.End(); + } + } + + public void BeginReceive() + { + if (!_isDisposed && !_isBeging) + { + _needTSLen = true; + _needTSData = true; + _bsData = null; + _despatcher.Begin(_bsLen); + } + } + + public void EndReceive() + { + if (_isBeging) + { + _isBeging = false; + _needTSLen = true; + _needTSData = true; + _bsData = null; + _despatcher.End(); + } + } + + private void OnCompleted(byte[] bytes) + { + if (!_isDisposed) + { + _isBeging = false; + if (_Completed != null) + { + _Completed(_bsData); + } + } + } + + private void _despatcher_Disoconnect() + { + if (_DisoconnectHandle != null) + { + _DisoconnectHandle(); + } + } + + private void _despatcher_Completed(AnsycSocketDespatcher.DespatcheStateModel model) + { + if (_isDisposed) + { + return; + } + if (!_isReceiveMode) + { + if (_needTSLen) + { + _needTSLen = false; + } + if (_needTSData) + { + _needTSData = false; + _despatcher.Begin(_bsData); + } + else + { + OnCompleted(model.Buffer); + } + return; + } + if (_needTSLen) + { + _needTSLen = false; + _needTSDataLen = BitConverter.ToInt32(model.Buffer, 0); + _bsData = new byte[_needTSDataLen]; + } + if (_needTSData) + { + _needTSData = false; + _despatcher.Begin(_bsData); + if (_bsData.Length != _needTSDataLen) + { + throw new Exception(); + } + } + else + { + OnCompleted(model.Buffer); + } + } + + private void Log(string msg) + { + } + + public void Dispose() + { + _isDisposed = false; + _despatcher.Dispose(); + _DisoconnectHandle = null; + _Completed = null; + } + } +} diff --git a/Common.GLib/GLib.Net/AnsycSocketDespatcher.cs b/Common.GLib/GLib.Net/AnsycSocketDespatcher.cs new file mode 100644 index 0000000..8ba0a2d --- /dev/null +++ b/Common.GLib/GLib.Net/AnsycSocketDespatcher.cs @@ -0,0 +1,232 @@ +using GLib.GeneralModel; +using System; +using System.Net.Sockets; + +namespace GLib.Net +{ + public class AnsycSocketDespatcher : IDisposable + { + public class DespatcheStateModel + { + public byte[] Buffer; + + public int Offset; + + public int Size; + + public bool IsCompleted; + } + + private bool _isBeging = false; + + private object _lockObj = new object(); + + private IAsyncResult _lasyAsyncResult = null; + + private Socket _socket = null; + + private bool _CompletedHandle_Invokeing = false; + + private AQueue _queueCompletedHandleInvoke = null; + + private Action _DisoconnectHandle; + + private Action _CompletedHandle; + + private bool _isDisposed = false; + + public bool IsReceiveMode + { + get; + private set; + } + + public AnsycSocketDespatcher(Socket socket, bool isReceiveMode, Action disoconnectHandle, Action completedHandle) + { + _socket = socket; + IsReceiveMode = isReceiveMode; + _DisoconnectHandle = disoconnectHandle; + _CompletedHandle = completedHandle; + } + + public void Begin(byte[] buffer) + { + Begin(buffer, 0, buffer.Length); + } + + public void Begin(byte[] buffer, int offset, int size) + { + DespatcheStateModel despatcheStateModel = new DespatcheStateModel(); + despatcheStateModel.Size = size; + despatcheStateModel.Buffer = buffer; + despatcheStateModel.Offset = offset; + despatcheStateModel.IsCompleted = false; + DespatcheStateModel so = despatcheStateModel; + Begin(so); + } + + public void Begin(DespatcheStateModel so) + { + if (!_isDisposed && !_isBeging) + { + _isBeging = true; + try + { + lock (_lockObj) + { + if (IsReceiveMode) + { + _lasyAsyncResult = _socket.BeginReceive(so.Buffer, so.Offset, so.Size, SocketFlags.None, ReadCallback, so); + } + else + { + _lasyAsyncResult = _socket.BeginSend(so.Buffer, so.Offset, so.Size, SocketFlags.None, ReadCallback, so); + } + } + } + catch (Exception e) + { + OnDisoconnect(e); + } + } + } + + public void End() + { + if (!_isDisposed && _isBeging) + { + _isBeging = false; + try + { + if (IsReceiveMode) + { + if (_lasyAsyncResult != null && !_lasyAsyncResult.IsCompleted) + { + _socket.EndReceive(_lasyAsyncResult); + } + } + else if (_lasyAsyncResult != null && !_lasyAsyncResult.IsCompleted) + { + _socket.EndSend(_lasyAsyncResult); + } + } + catch (Exception e) + { + if (!_isDisposed) + { + OnDisoconnect(e); + } + } + _lasyAsyncResult = null; + } + } + + private void Completed(DespatcheStateModel model) + { + if (!_isDisposed) + { + _isBeging = false; + _lasyAsyncResult = null; + lock (_lockObj) + { + if (_queueCompletedHandleInvoke == null) + { + _queueCompletedHandleInvoke = new AQueue(); + } + _queueCompletedHandleInvoke.Enqueue(model); + if (!_CompletedHandle_Invokeing) + { + model = _queueCompletedHandleInvoke.Dequeue(); + _CompletedHandle_Invokeing = true; + _CompletedHandle.BeginInvoke(model, _CompletedHandle_AsyncCallback, null); + } + } + } + } + + private void _CompletedHandle_AsyncCallback(IAsyncResult ar) + { + if (!_isDisposed) + { + lock (_lockObj) + { + _CompletedHandle.EndInvoke(ar); + if (_queueCompletedHandleInvoke.Count > 0) + { + DespatcheStateModel obj = _queueCompletedHandleInvoke.Dequeue(); + _CompletedHandle.BeginInvoke(obj, _CompletedHandle_AsyncCallback, null); + } + else + { + _CompletedHandle_Invokeing = false; + } + } + } + } + + private void ReadCallback(IAsyncResult ar) + { + if (!_isDisposed) + { + DespatcheStateModel despatcheStateModel = null; + despatcheStateModel = (DespatcheStateModel)ar.AsyncState; + try + { + int num = _socket.EndReceive(ar); + despatcheStateModel.Offset += num; + despatcheStateModel.Size -= num; + if (num == 0) + { + _ = _socket.Connected; + bool flag = 1 == 0; + if (_DisoconnectHandle != null) + { + _DisoconnectHandle.BeginInvoke(null, null); + } + } + else if (despatcheStateModel.Size == 0) + { + despatcheStateModel.IsCompleted = true; + Completed(despatcheStateModel); + } + else if (IsReceiveMode) + { + _lasyAsyncResult = _socket.BeginReceive(despatcheStateModel.Buffer, despatcheStateModel.Offset, despatcheStateModel.Size, SocketFlags.None, ReadCallback, despatcheStateModel); + } + else + { + _lasyAsyncResult = _socket.BeginSend(despatcheStateModel.Buffer, despatcheStateModel.Offset, despatcheStateModel.Size, SocketFlags.None, ReadCallback, despatcheStateModel); + } + } + catch (Exception e) + { + OnDisoconnect(e); + } + } + } + + protected void OnDisoconnect(Exception e) + { + if (!_isDisposed && _DisoconnectHandle != null) + { + _DisoconnectHandle.BeginInvoke(null, null); + } + } + + protected void OnDisoconnect() + { + if (!_isDisposed && _DisoconnectHandle != null) + { + _DisoconnectHandle.BeginInvoke(null, null); + } + } + + public void Dispose() + { + _isDisposed = true; + End(); + _DisoconnectHandle = null; + _CompletedHandle = null; + } + } +} diff --git a/Common.GLib/GLib.Net/ByteObjSocket.cs b/Common.GLib/GLib.Net/ByteObjSocket.cs new file mode 100644 index 0000000..64a75d6 --- /dev/null +++ b/Common.GLib/GLib.Net/ByteObjSocket.cs @@ -0,0 +1,21 @@ +namespace GLib.Net +{ + public class ByteObjSocket : SocketEx where T : IByteObj, new() + { + public virtual T ReadObj() + { + int len = ReadInt32(); + byte[] bytes = ReadBytes(len); + T result = new T(); + result.SetBytes(bytes); + return result; + } + + public virtual void Write(T t) + { + byte[] bytes = t.GetBytes(); + Write(bytes.Length); + Write(bytes); + } + } +} diff --git a/Common.GLib/GLib.Net/IByteObj.cs b/Common.GLib/GLib.Net/IByteObj.cs new file mode 100644 index 0000000..67e5988 --- /dev/null +++ b/Common.GLib/GLib.Net/IByteObj.cs @@ -0,0 +1,9 @@ +namespace GLib.Net +{ + public interface IByteObj + { + byte[] GetBytes(); + + void SetBytes(byte[] buf); + } +} diff --git a/Common.GLib/GLib.Net/SocketEx.cs b/Common.GLib/GLib.Net/SocketEx.cs new file mode 100644 index 0000000..938f299 --- /dev/null +++ b/Common.GLib/GLib.Net/SocketEx.cs @@ -0,0 +1,132 @@ +using System.IO; +using System.Net.Sockets; + +namespace GLib.Net +{ + public class SocketEx : Socket + { + private NetworkStream __ns = null; + + private BinaryReader __br = null; + + private BinaryWriter __bw = null; + + private NetworkStream _ns + { + get + { + if (__ns == null) + { + __ns = new NetworkStream(this); + } + return __ns; + } + } + + private BinaryReader _br + { + get + { + if (__br == null) + { + __br = new BinaryReader(_ns); + } + return __br; + } + } + + private BinaryWriter _bw + { + get + { + if (__bw == null) + { + __bw = new BinaryWriter(_ns); + } + return __bw; + } + } + + public SocketEx() + : this(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp) + { + } + + public SocketEx(AddressFamily addressFamily, SocketType socketType, ProtocolType protocolType) + : base(addressFamily, socketType, protocolType) + { + } + + public virtual byte[] ReadBytes(int len) + { + return _br.ReadBytes(len); + } + + public virtual byte ReadByte() + { + return _br.ReadByte(); + } + + public virtual short ReadInt16() + { + return _br.ReadInt16(); + } + + public virtual int ReadInt32() + { + return _br.ReadInt32(); + } + + public virtual long ReadInt64() + { + return _br.ReadInt64(); + } + + public virtual void Write(byte[] buffer, int index, int count) + { + _bw.Write(buffer, index, count); + } + + public virtual void Write(byte[] buffer) + { + _bw.Write(buffer); + } + + public virtual void Write(byte value) + { + _bw.Write(value); + } + + public virtual void Write(short value) + { + _bw.Write(value); + } + + public virtual void Write(int value) + { + _bw.Write(value); + } + + public virtual void Write(long value) + { + _bw.Write(value); + } + + protected override void Dispose(bool disposing) + { + if (__bw != null) + { + __bw.Close(); + } + if (__br != null) + { + __br.Close(); + } + if (__ns != null) + { + __ns.Close(); + } + base.Dispose(disposing); + } + } +} diff --git a/Common.GLib/GLib.Net/TCPService.cs b/Common.GLib/GLib.Net/TCPService.cs new file mode 100644 index 0000000..04f01ba --- /dev/null +++ b/Common.GLib/GLib.Net/TCPService.cs @@ -0,0 +1,111 @@ +using GLib.GeneralModel; +using System; +using System.Net; +using System.Net.Sockets; +using System.Threading; + +namespace GLib.Net +{ + public class TCPService + { + private int _maxConnect = 256; + + private int _port = -1; + + private Socket _sock = null; + + private bool _working = false; + + private Thread _thread = null; + + public int Port => _port; + + public event EventHandler> Accepted; + + public TCPService(int port, int macConnect = 256) + { + _port = port; + _maxConnect = macConnect; + } + + public void Start() + { + lock (this) + { + if (!_working) + { + _working = true; + _thread = new Thread(AcceptThread); + _thread.Start(); + } + } + } + + public void Stop() + { + lock (this) + { + if (_working) + { + _working = false; + if (_thread != null) + { + _thread.Abort(); + _thread.Join(1000); + } + _thread = null; + try + { + if (_sock != null) + { + _sock.Close(); + _sock.Dispose(); + } + } + catch (Exception) + { + } + } + } + } + + private void AcceptThread() + { + _sock = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); + _sock.Bind(new IPEndPoint(IPAddress.Any, _port)); + _sock.Listen(_maxConnect); + while (true) + { + Socket state = _sock.Accept(); + ThreadPool.QueueUserWorkItem(OnAccept, state); + } + } + + private void OnAccept(object obj) + { + Socket socket = (Socket)obj; + try + { + if (this.Accepted != null) + { + this.Accepted(this, new EventArgsEx(socket)); + } + } + catch (Exception value) + { + try + { + if (socket != null) + { + socket.Close(); + socket.Dispose(); + } + } + catch + { + } + Console.WriteLine(value); + } + } + } +} diff --git a/Common.GLib/GLib.Net/TimeOutSocket.cs b/Common.GLib/GLib.Net/TimeOutSocket.cs new file mode 100644 index 0000000..82446a6 --- /dev/null +++ b/Common.GLib/GLib.Net/TimeOutSocket.cs @@ -0,0 +1,59 @@ +using System; +using System.Net; +using System.Net.Sockets; +using System.Threading; + +namespace GLib.Net +{ + public static class TimeOutSocket + { + private static bool IsConnectionSuccessful = false; + + private static Exception socketexception; + + private static ManualResetEvent TimeoutObject = new ManualResetEvent(initialState: false); + + public static void Connect(Socket sock, string ip, int port, int timeoutMSec) + { + Connect(sock, new IPEndPoint(IPAddress.Parse(ip), port), timeoutMSec); + } + + public static void Connect(Socket sock, IPEndPoint remoteEndPoint, int timeoutMSec) + { + sock.BeginConnect(remoteEndPoint, CallBackMethod, sock); + if (TimeoutObject.WaitOne(timeoutMSec, exitContext: false)) + { + if (IsConnectionSuccessful) + { + return; + } + throw socketexception; + } + sock.Close(); + throw new TimeoutException("TimeOut Exception"); + } + + private static void CallBackMethod(IAsyncResult asyncresult) + { + try + { + IsConnectionSuccessful = false; + Socket socket = asyncresult.AsyncState as Socket; + if (socket != null) + { + socket.EndConnect(asyncresult); + IsConnectionSuccessful = true; + } + } + catch (Exception ex) + { + IsConnectionSuccessful = false; + socketexception = ex; + } + finally + { + TimeoutObject.Set(); + } + } + } +} diff --git a/Common.GLib/GLib.Serializer/SerializerHelper.cs b/Common.GLib/GLib.Serializer/SerializerHelper.cs new file mode 100644 index 0000000..f126d95 --- /dev/null +++ b/Common.GLib/GLib.Serializer/SerializerHelper.cs @@ -0,0 +1,105 @@ +using System; +using System.IO; +using System.Text; + +namespace GLib.Serializer +{ + public class SerializerHelper + { + public static string StringSerializer(object value) + { + string text = ""; + try + { + // NetDataContractSerializer netDataContractSerializer = new NetDataContractSerializer(); + MemoryStream memoryStream = new MemoryStream(); + // netDataContractSerializer.WriteObject(memoryStream, value); + byte[] array = memoryStream.ToArray(); + return Encoding.UTF8.GetString(array, 0, array.Length); + } + catch (Exception ex) + { + throw ex; + } + } + + public static object StringDeserialize(string value) + { + object obj = null; + try + { + // NetDataContractSerializer netDataContractSerializer = new NetDataContractSerializer(); + byte[] bytes = Encoding.UTF8.GetBytes(value); + MemoryStream memoryStream = new MemoryStream(bytes); + memoryStream.Seek(0L, SeekOrigin.Begin); + // return netDataContractSerializer.ReadObject(memoryStream); + return null; + } + catch (Exception ex) + { + throw ex; + } + } + + public static Stream StreamSerializer(object value) + { + Stream stream = null; + try + { + //NetDataContractSerializer netDataContractSerializer = new NetDataContractSerializer(); + MemoryStream memoryStream = new MemoryStream(); + // netDataContractSerializer.WriteObject(memoryStream, value); + stream = memoryStream; + stream.Seek(0L, SeekOrigin.Begin); + } + catch (Exception ex) + { + throw ex; + } + return stream; + } + + public static object StreamDeserialize(Stream value) + { + object obj = null; + if (!value.CanSeek) + { + value = GetNewStream(value); + } + try + { + //NetDataContractSerializer netDataContractSerializer = new NetDataContractSerializer(); + value.Seek(0L, SeekOrigin.Begin); + // return netDataContractSerializer.ReadObject(value); + return obj; + } + catch (Exception ex) + { + throw ex; + } + } + + public static T StreamDeserialize(Stream stream) + { + object obj = StreamDeserialize(stream); + if (obj is T) + { + return (T)obj; + } + return default(T); + } + + private static Stream GetNewStream(Stream value) + { + Stream stream = new MemoryStream(); + byte[] buffer = new byte[4096]; + int num = 0; + while ((num = value.Read(buffer, 0, 4096)) > 0) + { + stream.Write(buffer, 0, num); + } + stream.Seek(0L, SeekOrigin.Begin); + return stream; + } + } +} diff --git a/Common.GLib/GLib.Utilities.IO/DirectoryHelper.cs b/Common.GLib/GLib.Utilities.IO/DirectoryHelper.cs new file mode 100644 index 0000000..4039662 --- /dev/null +++ b/Common.GLib/GLib.Utilities.IO/DirectoryHelper.cs @@ -0,0 +1,43 @@ +using System; +using System.IO; + +namespace GLib.Utilities.IO +{ + public class DirectoryHelper + { + public static string CreateMultiFolder(params string[] names) + { + string text = null; + if (names.Length > 0) + { + text = names[0]; + if (!Directory.Exists(text)) + { + Directory.CreateDirectory(text); + } + } + if (text != null) + { + for (int i = 1; i < names.Length; i++) + { + text = text + "\\" + names[i]; + if (!Directory.Exists(text)) + { + Directory.CreateDirectory(text); + } + } + return text + "\\"; + } + return null; + } + + public static string CreateMultiFolder(string path) + { + string[] names = path.Replace("\\\\", "\\").Split(new string[1] + { + "\\" + }, StringSplitOptions.RemoveEmptyEntries); + return CreateMultiFolder(names); + } + } +} diff --git a/Common.GLib/GLib.Utilities.IO/ExcelHelper.cs b/Common.GLib/GLib.Utilities.IO/ExcelHelper.cs new file mode 100644 index 0000000..a94b434 --- /dev/null +++ b/Common.GLib/GLib.Utilities.IO/ExcelHelper.cs @@ -0,0 +1,37 @@ +using System.Data; +using System.Data.OleDb; + +namespace GLib.Utilities.IO +{ + public class ExcelHelper + { + public static DataTable ReadExcel(string fileName, string Sheet) + { + DataSet dataSet = new DataSet(); + string connectionString = "Provider=Microsoft.Jet.Oledb.4.0;Data Source=" + fileName + ";Extended Properties=Excel 8.0"; + OleDbConnection oleDbConnection = new OleDbConnection(connectionString); + try + { + oleDbConnection.Open(); + DataTable oleDbSchemaTable = oleDbConnection.GetOleDbSchemaTable(OleDbSchemaGuid.Tables, null); + string[] array = new string[oleDbSchemaTable.Rows.Count]; + int num = 0; + foreach (DataRow row in oleDbSchemaTable.Rows) + { + array[num] = row[2].ToString(); + num++; + } + for (int i = 0; i < array.Length; i++) + { + OleDbDataAdapter oleDbDataAdapter = new OleDbDataAdapter("SELECT * FROM [" + array[i] + "]", oleDbConnection); + oleDbDataAdapter.Fill(dataSet, "TEMPTABLE"); + } + } + catch + { + } + oleDbConnection.Close(); + return dataSet.Tables["TEMPTABLE"]; + } + } +} diff --git a/Common.GLib/GLib.Utilities.IO/FileHelper.cs b/Common.GLib/GLib.Utilities.IO/FileHelper.cs new file mode 100644 index 0000000..9e9418d --- /dev/null +++ b/Common.GLib/GLib.Utilities.IO/FileHelper.cs @@ -0,0 +1,58 @@ +using System; +using System.IO; +using System.Text; + +namespace GLib.Utilities.IO +{ + public static class FileHelper + { + public static string CreateFileName() + { + Random random = new Random(); + return DateTime.Now.ToString("yyyyMMddHHmmss") + random.Next(1000, 9999); + } + + public static void WriteFile(string content) + { + WriteFile(string.Empty, string.Empty, content); + } + + public static void WriteFile(string fileName, string content) + { + WriteFile(string.Empty, fileName, content); + } + + public static void WriteFile(string path, string fileName, string content) + { + if (path == string.Empty) + { + path = AppDomain.CurrentDomain.BaseDirectory; + } + if (fileName == string.Empty) + { + fileName = CreateFileName() + ".log"; + } + if (!Directory.Exists(path)) + { + Directory.CreateDirectory(path); + } + path += fileName; + try + { + if (!File.Exists(path)) + { + FileStream fileStream = File.Create(path); + fileStream.Close(); + } + StreamWriter streamWriter = new StreamWriter(path, append: true, Encoding.Default); + streamWriter.Write(content); + streamWriter.Write("\r\n"); + streamWriter.Close(); + streamWriter.Dispose(); + } + catch (Exception) + { + } + } + } +} diff --git a/Common.GLib/GLib.Utilities.IO/FileType.cs b/Common.GLib/GLib.Utilities.IO/FileType.cs new file mode 100644 index 0000000..65c81e3 --- /dev/null +++ b/Common.GLib/GLib.Utilities.IO/FileType.cs @@ -0,0 +1,9 @@ +namespace GLib.Utilities.IO +{ + public enum FileType : short + { + Excel = 10, + Text = 20, + UnKnow = 0 + } +} diff --git a/Common.GLib/GLib.Utilities.IO/FileTypeHelper.cs b/Common.GLib/GLib.Utilities.IO/FileTypeHelper.cs new file mode 100644 index 0000000..57be2af --- /dev/null +++ b/Common.GLib/GLib.Utilities.IO/FileTypeHelper.cs @@ -0,0 +1,21 @@ +using System.IO; + +namespace GLib.Utilities.IO +{ + public class FileTypeHelper + { + public static FileType GetFileType(string filename) + { + filename = filename.ToLower(); + switch (Path.GetExtension(filename)) + { + case ".txt": + return FileType.Text; + case ".xls": + return FileType.Excel; + default: + return FileType.UnKnow; + } + } + } +} diff --git a/Common.GLib/GLib.Utilities.IO/TxtHelper.cs b/Common.GLib/GLib.Utilities.IO/TxtHelper.cs new file mode 100644 index 0000000..04f77b5 --- /dev/null +++ b/Common.GLib/GLib.Utilities.IO/TxtHelper.cs @@ -0,0 +1,47 @@ +using System; +using System.Data; +using System.IO; +using System.Text; + +namespace GLib.Utilities.IO +{ + public class TxtHelper + { + public static DataTable ReadFile(string filename, string[] split) + { + try + { + StreamReader streamReader = new StreamReader(filename, Encoding.Default); + DataTable dataTable = new DataTable(); + int num = 0; + string text; + while ((text = streamReader.ReadLine()) != null) + { + string[] array = text.Split(split, StringSplitOptions.RemoveEmptyEntries); + if (num == 0) + { + for (int i = 0; i < array.Length; i++) + { + dataTable.Columns.Add(array[i]); + } + } + else + { + DataRow dataRow = dataTable.NewRow(); + for (int i = 0; i < array.Length; i++) + { + dataRow[i] = array[i]; + } + dataTable.Rows.Add(dataRow); + } + num++; + } + return dataTable; + } + catch (Exception) + { + } + return null; + } + } +} diff --git a/Common.GLib/GLib.Utilities.Security/DecryptHelper.cs b/Common.GLib/GLib.Utilities.Security/DecryptHelper.cs new file mode 100644 index 0000000..fa7bea2 --- /dev/null +++ b/Common.GLib/GLib.Utilities.Security/DecryptHelper.cs @@ -0,0 +1,37 @@ +using System; +using System.IO; +using System.Security.Cryptography; +using System.Text; + +namespace GLib.Utilities.Security +{ + public sealed class DecryptHelper + { + public static string DES(string source, string key) + { + DESCryptoServiceProvider dESCryptoServiceProvider = new DESCryptoServiceProvider(); + byte[] array = new byte[source.Length / 2]; + for (int i = 0; i < source.Length / 2; i++) + { + int num = Convert.ToInt32(source.Substring(i * 2, 2), 16); + array[i] = (byte)num; + } + dESCryptoServiceProvider.Key = Encoding.ASCII.GetBytes(key); + dESCryptoServiceProvider.IV = Encoding.ASCII.GetBytes(key); + MemoryStream memoryStream = new MemoryStream(); + CryptoStream cryptoStream = new CryptoStream(memoryStream, dESCryptoServiceProvider.CreateDecryptor(), CryptoStreamMode.Write); + cryptoStream.Write(array, 0, array.Length); + cryptoStream.FlushFinalBlock(); + return Encoding.Default.GetString(memoryStream.ToArray()); + } + + public static string Base64(string source) + { + if (!string.IsNullOrEmpty(source)) + { + return Encoding.ASCII.GetString(Convert.FromBase64String(source)); + } + return string.Empty; + } + } +} diff --git a/Common.GLib/GLib.Utilities.Security/EncryptHelper.cs b/Common.GLib/GLib.Utilities.Security/EncryptHelper.cs new file mode 100644 index 0000000..245dda8 --- /dev/null +++ b/Common.GLib/GLib.Utilities.Security/EncryptHelper.cs @@ -0,0 +1,56 @@ +using System; +using System.IO; +using System.Security.Cryptography; +using System.Text; + +namespace GLib.Utilities.Security +{ + public sealed class EncryptHelper + { + public static string MD5(string source) + { + return GetMD5(source + "WEN@#!&*&*(~)_W#@!!@!^WEN!"); + } + + private static string GetMD5(string source) + { + MD5CryptoServiceProvider mD5CryptoServiceProvider = new MD5CryptoServiceProvider(); + mD5CryptoServiceProvider.ComputeHash(Encoding.ASCII.GetBytes(source)); + StringBuilder stringBuilder = new StringBuilder(); + byte[] hash = mD5CryptoServiceProvider.Hash; + foreach (byte b in hash) + { + stringBuilder.AppendFormat("{0:X2}", b); + } + return stringBuilder.ToString(); + } + + public static string DES(string source, string key) + { + DESCryptoServiceProvider dESCryptoServiceProvider = new DESCryptoServiceProvider(); + byte[] bytes = Encoding.Default.GetBytes(source); + dESCryptoServiceProvider.Key = Encoding.ASCII.GetBytes(key); + dESCryptoServiceProvider.IV = Encoding.ASCII.GetBytes(key); + MemoryStream memoryStream = new MemoryStream(); + CryptoStream cryptoStream = new CryptoStream(memoryStream, dESCryptoServiceProvider.CreateEncryptor(), CryptoStreamMode.Write); + cryptoStream.Write(bytes, 0, bytes.Length); + cryptoStream.FlushFinalBlock(); + StringBuilder stringBuilder = new StringBuilder(); + byte[] array = memoryStream.ToArray(); + foreach (byte b in array) + { + stringBuilder.AppendFormat("{0:X2}", b); + } + return stringBuilder.ToString(); + } + + public static string Base64(string source) + { + if (!string.IsNullOrEmpty(source)) + { + return Convert.ToBase64String(Encoding.Default.GetBytes(source)); + } + return string.Empty; + } + } +} diff --git a/Common.GLib/GLib.Utilities/Computer.cs b/Common.GLib/GLib.Utilities/Computer.cs new file mode 100644 index 0000000..8a55d6d --- /dev/null +++ b/Common.GLib/GLib.Utilities/Computer.cs @@ -0,0 +1,207 @@ +using System; +using System.Management; + +namespace GLib.Utilities +{ + public class Computer + { + public string CpuID; + + public string MacAddress; + + public string DiskID; + + public string LoginUserName; + + public string ComputerName; + + public string SystemType; + + public string TotalPhysicalMemory; + + private static Computer _instance; + + public static Computer Instance() + { + if (_instance == null) + { + _instance = new Computer(); + } + return _instance; + } + + public Computer() + { + CpuID = GetCpuID(); + MacAddress = GetMacAddress(); + DiskID = GetDiskID(); + LoginUserName = GetUserName(); + SystemType = GetSystemType(); + TotalPhysicalMemory = GetTotalPhysicalMemory(); + ComputerName = GetComputerName(); + } + + private string GetCpuID() + { + try + { + string result = ""; + ManagementClass managementClass = new ManagementClass("Win32_Processor"); + ManagementObjectCollection instances = managementClass.GetInstances(); + foreach (ManagementObject item in instances) + { + result = item.Properties["ProcessorId"].Value.ToString(); + } + instances = null; + managementClass = null; + return result; + } + catch + { + return "unknow"; + } + finally + { + } + } + + private string GetMacAddress() + { + try + { + string result = ""; + ManagementClass managementClass = new ManagementClass("Win32_NetworkAdapterConfiguration"); + ManagementObjectCollection instances = managementClass.GetInstances(); + foreach (ManagementObject item in instances) + { + if ((bool)item["IPEnabled"]) + { + result = item["MacAddress"].ToString(); + break; + } + } + instances = null; + managementClass = null; + return result; + } + catch + { + return "unknow"; + } + finally + { + } + } + + private string GetDiskID() + { + try + { + string result = ""; + ManagementClass managementClass = new ManagementClass("Win32_DiskDrive"); + ManagementObjectCollection instances = managementClass.GetInstances(); + foreach (ManagementObject item in instances) + { + result = item.Properties["Model"].ToString(); + } + instances = null; + managementClass = null; + return result; + } + catch + { + return "unknow"; + } + finally + { + } + } + + private string GetUserName() + { + try + { + string result = ""; + ManagementClass managementClass = new ManagementClass("Win32_ComputerSystem"); + ManagementObjectCollection instances = managementClass.GetInstances(); + foreach (ManagementObject item in instances) + { + result = item["UserName"].ToString(); + } + instances = null; + managementClass = null; + return result; + } + catch + { + return "unknow"; + } + finally + { + } + } + + private string GetSystemType() + { + try + { + string result = ""; + ManagementClass managementClass = new ManagementClass("Win32_ComputerSystem"); + ManagementObjectCollection instances = managementClass.GetInstances(); + foreach (ManagementObject item in instances) + { + result = item["SystemType"].ToString(); + } + instances = null; + managementClass = null; + return result; + } + catch + { + return "unknow"; + } + finally + { + } + } + + private string GetTotalPhysicalMemory() + { + try + { + string result = ""; + ManagementClass managementClass = new ManagementClass("Win32_ComputerSystem"); + ManagementObjectCollection instances = managementClass.GetInstances(); + foreach (ManagementObject item in instances) + { + result = item["TotalPhysicalMemory"].ToString(); + } + instances = null; + managementClass = null; + return result; + } + catch + { + return "unknow"; + } + finally + { + } + } + + private string GetComputerName() + { + try + { + return Environment.GetEnvironmentVariable("ComputerName"); + } + catch + { + return "unknow"; + } + finally + { + } + } + } +} diff --git a/Common.GLib/GLib.Utilities/EmailSender.cs b/Common.GLib/GLib.Utilities/EmailSender.cs new file mode 100644 index 0000000..4760ac9 --- /dev/null +++ b/Common.GLib/GLib.Utilities/EmailSender.cs @@ -0,0 +1,282 @@ +using System; +using System.Collections.Generic; +using System.Collections.Specialized; +using System.ComponentModel; +using System.Net; +using System.Net.Mail; +using System.Text; + +namespace GLib.Utilities +{ + public class EmailSender + { + private IList mailAttachmentList = new List(); + + private string message = ""; + + private SendState sendState = SendState.Sending; + + private StringCollection bcc = new StringCollection(); + + private StringCollection cc = new StringCollection(); + + private StringCollection to = new StringCollection(); + + public string Server + { + get; + set; + } + + public int ServerPort + { + get; + set; + } + + public string UserName + { + get; + set; + } + + public string Password + { + get; + set; + } + + public string From + { + get; + set; + } + + public string FromName + { + get; + set; + } + + public string Body + { + get; + set; + } + + public Encoding BodyEncoding + { + get; + set; + } + + public bool IsBodyHtml + { + get; + set; + } + + public MailPriority Priority + { + get; + set; + } + + public string ReplyTo + { + get; + set; + } + + public StringCollection Bcc => bcc; + + public StringCollection CC => cc; + + public MailAddress Sender + { + get; + set; + } + + public string Subject + { + get; + set; + } + + public Encoding SubjectEncoding + { + get; + set; + } + + public StringCollection To => to; + + public IList MailAttachmentList => mailAttachmentList; + + public char Delimiter + { + get; + set; + } + + public string Message => message; + + public SendState SendState => sendState; + + public EmailSender() + { + IsBodyHtml = true; + Priority = MailPriority.High; + BodyEncoding = Encoding.UTF8; + SubjectEncoding = Encoding.UTF8; + ServerPort = 25; + Delimiter = '='; + } + + public virtual bool Send() + { + if (string.IsNullOrEmpty(From)) + { + sendState = SendState.Error; + message = "没有发件人!"; + return false; + } + if (string.IsNullOrEmpty(Subject)) + { + sendState = SendState.Error; + message = "没有邮件标题!"; + return false; + } + if (string.IsNullOrEmpty(Body)) + { + sendState = SendState.Error; + message = "没有邮件正文!"; + return false; + } + if (To.Count < 1) + { + sendState = SendState.Error; + message = "没有收件人!"; + return false; + } + if (string.IsNullOrEmpty(Server)) + { + sendState = SendState.Error; + message = "没有设置邮件服务器地址!"; + return false; + } + if (string.IsNullOrEmpty(Password)) + { + sendState = SendState.Error; + message = "没有设置邮件服务器账号密码!"; + return false; + } + if (string.IsNullOrEmpty(UserName)) + { + UserName = From; + } + MailMessage mailMessage = new MailMessage(); + mailMessage.From = new MailAddress(From, FromName); + mailMessage.Subject = Subject.Trim(); + mailMessage.SubjectEncoding = SubjectEncoding; + mailMessage.Body = Body.Trim(); + mailMessage.BodyEncoding = BodyEncoding; + mailMessage.IsBodyHtml = IsBodyHtml; + foreach (string mailAttachment in mailAttachmentList) + { + mailMessage.Attachments.Add(new Attachment(mailAttachment)); + } + StringEnumerator enumerator2 = To.GetEnumerator(); + try + { + while (enumerator2.MoveNext()) + { + string current2 = enumerator2.Current; + string[] array = current2.Split(Delimiter); + MailAddress mailAddress = null; + mailAddress = ((array.Length <= 1) ? new MailAddress(array[0].Trim()) : new MailAddress(array[0].Trim(), array[1].Trim())); + mailMessage.To.Add(mailAddress); + } + } + finally + { + (enumerator2 as IDisposable)?.Dispose(); + } + if (Bcc.Count > 0) + { + enumerator2 = Bcc.GetEnumerator(); + try + { + while (enumerator2.MoveNext()) + { + string current3 = enumerator2.Current; + string[] array2 = current3.Split(Delimiter); + MailAddress mailAddress = null; + mailAddress = ((array2.Length <= 1) ? new MailAddress(array2[0].Trim()) : new MailAddress(array2[0].Trim(), array2[1].Trim())); + mailMessage.Bcc.Add(mailAddress); + } + } + finally + { + (enumerator2 as IDisposable)?.Dispose(); + } + } + if (CC.Count > 0) + { + enumerator2 = CC.GetEnumerator(); + try + { + while (enumerator2.MoveNext()) + { + string current3 = enumerator2.Current; + string[] array3 = current3.Split(Delimiter); + MailAddress mailAddress = null; + mailAddress = ((array3.Length <= 1) ? new MailAddress(array3[0].Trim()) : new MailAddress(array3[0].Trim(), array3[1].Trim())); + mailMessage.CC.Add(mailAddress); + } + } + finally + { + (enumerator2 as IDisposable)?.Dispose(); + } + } + try + { + SmtpClient smtpClient = new SmtpClient(Server, ServerPort); + smtpClient.Credentials = new NetworkCredential(UserName, Password); + smtpClient.SendCompleted += SendCompletedCallback; + string subject = Subject; + smtpClient.Send(mailMessage); + } + catch (Exception ex) + { + sendState = SendState.Error; + message = ex.Message; + return false; + } + mailMessage.Dispose(); + return true; + } + + private void SendCompletedCallback(object sender, AsyncCompletedEventArgs e) + { + string arg = (string)e.UserState; + if (e.Cancelled) + { + sendState = SendState.Canceled; + message = $"[{arg}] 发送取消"; + } + if (e.Error != null) + { + sendState = SendState.Error; + message = $"[{arg}] {e.Error.ToString()}"; + } + else + { + sendState = SendState.Succeed; + message = "发送成功"; + } + } + } +} diff --git a/Common.GLib/GLib.Utilities/ExportFormat.cs b/Common.GLib/GLib.Utilities/ExportFormat.cs new file mode 100644 index 0000000..79cb227 --- /dev/null +++ b/Common.GLib/GLib.Utilities/ExportFormat.cs @@ -0,0 +1,9 @@ +namespace GLib.Utilities +{ + public enum ExportFormat + { + CSV = 0, + DOC = 1, + TXT = 2 + } +} diff --git a/Common.GLib/GLib.Utilities/ExportHelper.cs b/Common.GLib/GLib.Utilities/ExportHelper.cs new file mode 100644 index 0000000..4183fbd --- /dev/null +++ b/Common.GLib/GLib.Utilities/ExportHelper.cs @@ -0,0 +1,206 @@ +using System.Collections.Generic; +using System.Data; +using System.IO; +using System.Text; +using System.Web; +using System.Xml; +using System.Xml.Xsl; + +namespace GLib.Utilities +{ + public class ExportHelper + { + public static void Export(DataTable dt, ExportFormat exportFormat, string fileName, Encoding encoding) + { + DataSet dataSet = new DataSet("Export"); + DataTable dataTable = dt.Copy(); + dataTable.TableName = "Values"; + dataSet.Tables.Add(dataTable); + string[] array = new string[dataTable.Columns.Count]; + string[] array2 = new string[dataTable.Columns.Count]; + for (int i = 0; i < dataTable.Columns.Count; i++) + { + array[i] = dataTable.Columns[i].ColumnName; + array2[i] = ReplaceSpecialChars(dataTable.Columns[i].ColumnName); + } + Export(dataSet, array, array2, exportFormat, fileName, encoding, null); + } + + public static void Export(DataTable dt, int[] columnIndexList, ExportFormat exportFormat, string fileName, Encoding encoding) + { + DataSet dataSet = new DataSet("Export"); + DataTable dataTable = dt.Copy(); + dataTable.TableName = "Values"; + dataSet.Tables.Add(dataTable); + string[] array = new string[columnIndexList.Length]; + string[] array2 = new string[columnIndexList.Length]; + for (int i = 0; i < columnIndexList.Length; i++) + { + array[i] = dataTable.Columns[columnIndexList[i]].ColumnName; + array2[i] = ReplaceSpecialChars(dataTable.Columns[columnIndexList[i]].ColumnName); + } + Export(dataSet, array, array2, exportFormat, fileName, encoding, null); + } + + public static void Export(DataTable dt, string[] columnNameList, ExportFormat exportFormat, string fileName, Encoding encoding) + { + List list = new List(); + DataColumnCollection columns = dt.Columns; + foreach (string columnName in columnNameList) + { + list.Add(GetColumnIndexByColumnName(columns, columnName)); + } + Export(dt, list.ToArray(), exportFormat, fileName, encoding); + } + + public static void Export(DataTable dt, int[] columnIndexList, string[] headers, ExportFormat exportFormat, string fileName, Encoding encoding) + { + DataSet dataSet = new DataSet("Export"); + DataTable dataTable = dt.Copy(); + dataTable.TableName = "Values"; + dataSet.Tables.Add(dataTable); + string[] array = new string[columnIndexList.Length]; + for (int i = 0; i < columnIndexList.Length; i++) + { + array[i] = ReplaceSpecialChars(dataTable.Columns[columnIndexList[i]].ColumnName); + } + Export(dataSet, headers, array, exportFormat, fileName, encoding, null); + } + + public static void Export(DataTable dt, int[] columnIndexList, string[] headers, ExportFormat exportFormat, string fileName, Encoding encoding, Dictionary function) + { + DataSet dataSet = new DataSet("Export"); + DataTable dataTable = dt.Copy(); + dataTable.TableName = "Values"; + dataSet.Tables.Add(dataTable); + string[] array = new string[columnIndexList.Length]; + for (int i = 0; i < columnIndexList.Length; i++) + { + array[i] = ReplaceSpecialChars(dataTable.Columns[columnIndexList[i]].ColumnName); + } + Export(dataSet, headers, array, exportFormat, fileName, encoding, function); + } + + public static void Export(DataTable dt, string[] columnNameList, string[] headers, ExportFormat exportFormat, string fileName, Encoding encoding) + { + List list = new List(); + DataColumnCollection columns = dt.Columns; + foreach (string columnName in columnNameList) + { + list.Add(GetColumnIndexByColumnName(columns, columnName)); + } + Export(dt, list.ToArray(), headers, exportFormat, fileName, encoding); + } + + public static void Export(DataTable dt, string[] columnNameList, string[] headers, ExportFormat exportFormat, string fileName, Encoding encoding, Dictionary function) + { + List list = new List(); + DataColumnCollection columns = dt.Columns; + foreach (string columnName in columnNameList) + { + list.Add(GetColumnIndexByColumnName(columns, columnName)); + } + Export(dt, list.ToArray(), headers, exportFormat, fileName, encoding, function); + } + + private static void Export(DataSet ds, string[] headers, string[] fields, ExportFormat exportFormat, string fileName, Encoding encoding, Dictionary function) + { + //HttpContext.Current.Response.Clear(); + //HttpContext.Current.Response.Buffer = true; + //HttpContext.Current.Response.ContentType = $"text/{exportFormat.ToString().ToLower()}"; + //HttpContext.Current.Response.AddHeader("content-disposition", $"attachment;filename={fileName}.{exportFormat.ToString().ToLower()}"); + //HttpContext.Current.Response.ContentEncoding = encoding; + MemoryStream memoryStream = new MemoryStream(); + XmlTextWriter xmlTextWriter = new XmlTextWriter(memoryStream, encoding); + CreateStylesheet(xmlTextWriter, headers, fields, exportFormat, function); + xmlTextWriter.Flush(); + memoryStream.Seek(0L, SeekOrigin.Begin); + //XmlDataDocument input = new XmlDataDocument(ds); + XslCompiledTransform xslCompiledTransform = new XslCompiledTransform(); + xslCompiledTransform.Load(new XmlTextReader(memoryStream)); + StringWriter stringWriter = new StringWriter(); + //xslCompiledTransform.Transform(input, null, stringWriter); + // HttpContext.Current.Response.Write(stringWriter.ToString()); + stringWriter.Close(); + xmlTextWriter.Close(); + memoryStream.Close(); + // HttpContext.Current.Response.End(); + } + + private static void CreateStylesheet(XmlTextWriter writer, string[] headers, string[] fields, ExportFormat exportFormat, Dictionary function) + { + string ns = "http://www.w3.org/1999/XSL/Transform"; + writer.Formatting = Formatting.Indented; + writer.WriteStartDocument(); + writer.WriteStartElement("xsl", "stylesheet", ns); + writer.WriteAttributeString("version", "1.0"); + writer.WriteStartElement("xsl:output"); + writer.WriteAttributeString("method", "text"); + writer.WriteAttributeString("version", "4.0"); + writer.WriteEndElement(); + writer.WriteStartElement("xsl:template"); + writer.WriteAttributeString("match", "/"); + for (int i = 0; i < headers.Length; i++) + { + writer.WriteString("\""); + writer.WriteStartElement("xsl:value-of"); + writer.WriteAttributeString("select", "'" + headers[i] + "'"); + writer.WriteEndElement(); + writer.WriteString("\""); + if (i != fields.Length - 1) + { + writer.WriteString((exportFormat == ExportFormat.CSV) ? "," : "\t"); + } + } + writer.WriteStartElement("xsl:for-each"); + writer.WriteAttributeString("select", "Export/Values"); + writer.WriteString("\r\n"); + for (int i = 0; i < fields.Length; i++) + { + writer.WriteString("\""); + writer.WriteStartElement("xsl:value-of"); + if (function != null && function.ContainsKey(fields[i])) + { + string value = ""; + function.TryGetValue(fields[i], out value); + writer.WriteAttributeString("select", value); + } + else + { + writer.WriteAttributeString("select", fields[i]); + } + writer.WriteEndElement(); + writer.WriteString("\""); + if (i != fields.Length - 1) + { + writer.WriteString((exportFormat == ExportFormat.CSV) ? "," : "\t"); + } + } + writer.WriteEndElement(); + writer.WriteEndElement(); + writer.WriteEndElement(); + } + + public static string ReplaceSpecialChars(string input) + { + input = input.Replace(" ", "_x0020_").Replace("%", "_x0025_").Replace("#", "_x0023_") + .Replace("&", "_x0026_") + .Replace("/", "_x002F_"); + return input; + } + + public static int GetColumnIndexByColumnName(DataColumnCollection dcc, string columnName) + { + int result = -1; + for (int i = 0; i < dcc.Count; i++) + { + if (dcc[i].ColumnName.ToLower() == columnName.ToLower()) + { + result = i; + break; + } + } + return result; + } + } +} diff --git a/Common.GLib/GLib.Utilities/HtmlTag.cs b/Common.GLib/GLib.Utilities/HtmlTag.cs new file mode 100644 index 0000000..54306f2 --- /dev/null +++ b/Common.GLib/GLib.Utilities/HtmlTag.cs @@ -0,0 +1,176 @@ +using System.Collections; +using System.Collections.Generic; +using System.IO; +using System.Net; +using System.Text; +using System.Text.RegularExpressions; + +namespace GLib.Utilities +{ + public class HtmlTag + { + private string m_Name; + + private string m_BeginTag; + + private string m_InnerHTML; + + private Hashtable m_Attributes = new Hashtable(); + + private static Regex attrReg = new Regex("([a-zA-Z1-9_-]+)\\s*=\\s*(\\x27|\\x22)([^\\x27\\x22]*)(\\x27|\\x22)", RegexOptions.IgnoreCase); + + public string TagName => m_Name; + + public string InnerHTML => m_InnerHTML; + + private HtmlTag(string name, string beginTag, string innerHTML) + { + m_Name = name; + m_BeginTag = beginTag; + m_InnerHTML = innerHTML; + MatchCollection matchCollection = attrReg.Matches(beginTag); + foreach (Match item in matchCollection) + { + m_Attributes[item.Groups[1].Value.ToUpper()] = item.Groups[3].Value; + } + } + + public List FindTag(string name) + { + return FindTag(m_InnerHTML, name, $"<{name}(\\s[^<>]*|)>"); + } + + public List FindTag(string name, string format) + { + return FindTag(m_InnerHTML, name, format); + } + + public List FindTagByAttr(string tagName, string attrName, string attrValue) + { + return FindTagByAttr(m_InnerHTML, tagName, attrName, attrValue); + } + + public List FindNoEndTag(string name) + { + return FindNoEndTag(m_InnerHTML, name, $"<{name}(\\s[^<>]*|)>"); + } + + public List FindNoEndTag(string name, string format) + { + return FindNoEndTag(m_InnerHTML, name, format); + } + + public List FindNoEndTagByAttr(string tagName, string attrName, string attrValue) + { + return FindNoEndTagByAttr(m_InnerHTML, tagName, attrName, attrValue); + } + + public string GetAttribute(string name) + { + return m_Attributes[name.ToUpper()] as string; + } + + public static string GetHtml(string url) + { + try + { + HttpWebRequest httpWebRequest = WebRequest.Create(url) as HttpWebRequest; + httpWebRequest.Timeout = 30000; + HttpWebResponse httpWebResponse = httpWebRequest.GetResponse() as HttpWebResponse; + Stream responseStream = httpWebResponse.GetResponseStream(); + MemoryStream memoryStream = new MemoryStream(); + byte[] buffer = new byte[4096]; + int num = 0; + while ((num = responseStream.Read(buffer, 0, 4096)) > 0) + { + memoryStream.Write(buffer, 0, num); + } + return Encoding.GetEncoding(httpWebResponse.CharacterSet).GetString(memoryStream.GetBuffer()); + } + catch + { + return string.Empty; + } + } + + public static List FindTagByAttr(string html, string tagName, string attrName, string attrValue) + { + string format = $"<{tagName}\\s[^<>]*{attrName}\\s*=\\s*(\\x27|\\x22){attrValue}(\\x27|\\x22)[^<>]*>"; + return FindTag(html, tagName, format); + } + + public static List FindTag(string html, string name, string format) + { + Regex regex = new Regex(format, RegexOptions.IgnoreCase); + Regex regex2 = new Regex($"<(\\/|)({name})(\\s[^<>]*|)>", RegexOptions.IgnoreCase); + List list = new List(); + int startat = 0; + while (true) + { + bool flag = true; + Match match = regex.Match(html, startat); + if (!match.Success) + { + break; + } + startat = match.Index + match.Length; + Match match2 = null; + int num = 1; + do + { + flag = true; + match2 = regex2.Match(html, startat); + if (!match2.Success) + { + match2 = null; + break; + } + startat = match2.Index + match2.Length; + num = ((!(match2.Groups[1].Value == "/")) ? (num + 1) : (num - 1)); + } + while (num != 0); + if (match2 != null) + { + HtmlTag item = new HtmlTag(name, match.Value, html.Substring(match.Index + match.Length, match2.Index - match.Index - match.Length)); + list.Add(item); + continue; + } + break; + } + return list; + } + + public static List FindNoEndTagByAttr(string html, string tagName, string attrName, string attrValue) + { + string format = $"<{tagName}\\s[^<>]*{attrName}\\s*=\\s*(\\x27|\\x22){attrValue}(\\x27|\\x22)[^<>]*>"; + return FindNoEndTag(html, tagName, format); + } + + public static List FindNoEndTag(string html, string name, string format) + { + Regex regex = new Regex(format, RegexOptions.IgnoreCase); + Regex regex2 = new Regex($"<({name})(\\s[^<>]*|)(\\/)+>", RegexOptions.IgnoreCase); + List list = new List(); + int startat = 0; + while (true) + { + bool flag = true; + Match match = regex.Match(html, startat); + if (match.Success) + { + startat = match.Index + match.Length; + Match match2 = match; + if (match2 != null) + { + HtmlTag item = new HtmlTag(name, match.Value, string.Empty); + list.Add(item); + continue; + } + break; + } + break; + } + return list; + } + } +} diff --git a/Common.GLib/GLib.Utilities/IPHelper.cs b/Common.GLib/GLib.Utilities/IPHelper.cs new file mode 100644 index 0000000..73ef1f7 --- /dev/null +++ b/Common.GLib/GLib.Utilities/IPHelper.cs @@ -0,0 +1,53 @@ +using System.Management; +using System.Web; + +namespace GLib.Utilities +{ + public class IPHelper + { + public static string GetServerIPAddress() + { + string result = ""; + ManagementClass managementClass = new ManagementClass("Win32_NetworkAdapterConfiguration"); + ManagementObjectCollection instances = managementClass.GetInstances(); + foreach (ManagementObject item in instances) + { + if ((bool)item["IPEnabled"]) + { + string[] array = (string[])item["IPAddress"]; + if (array.Length > 0) + { + result = array[0]; + } + } + } + return result; + } + + public static string GetServerMACAddress() + { + string text = ""; + ManagementClass managementClass = new ManagementClass("Win32_NetworkAdapterConfiguration"); + ManagementObjectCollection instances = managementClass.GetInstances(); + foreach (ManagementObject item in instances) + { + if ((bool)item["IPEnabled"]) + { + text += item["MACAddress"].ToString(); + } + } + return text; + } + + public static string GetIPAddress() + { + //string text = (HttpContext.Current.Request.ServerVariables["HTTP_X_FORWARDED_FOR"] != null && HttpContext.Current.Request.ServerVariables["HTTP_X_FORWARDED_FOR"] != string.Empty) ? HttpContext.Current.Request.ServerVariables["HTTP_X_FORWARDED_FOR"] : HttpContext.Current.Request.ServerVariables["REMOTE_ADDR"]; + //if (string.IsNullOrEmpty(text)) + //{ + // text = HttpContext.Current.Request.UserHostAddress; + //} + //return text; + return string.Empty; + } + } +} diff --git a/Common.GLib/GLib.Utilities/IniFile.cs b/Common.GLib/GLib.Utilities/IniFile.cs new file mode 100644 index 0000000..dfdf9c7 --- /dev/null +++ b/Common.GLib/GLib.Utilities/IniFile.cs @@ -0,0 +1,214 @@ +using System; +using System.Collections.Specialized; +using System.IO; +using System.Runtime.InteropServices; +using System.Text; + +namespace GLib.Utilities +{ + public class IniFile + { + public string FileName; + + [DllImport("kernel32")] + private static extern bool WritePrivateProfileString(string section, string key, string val, string filePath); + + [DllImport("kernel32")] + private static extern int GetPrivateProfileString(string section, string key, string def, byte[] retVal, int size, string filePath); + + public IniFile(string IniFileName, bool ForceCreate) + { + FileInfo fileInfo = new FileInfo(IniFileName); + if (!fileInfo.Exists) + { + if (!ForceCreate) + { + throw new ApplicationException("Ini文件不存在"); + } + fileInfo.Directory.Create(); + fileInfo.Create(); + } + FileName = fileInfo.FullName; + } + + public void WriteString(string Section, string Ident, string Value) + { + if (!WritePrivateProfileString(Section, Ident, Value, FileName)) + { + throw new ApplicationException("写Ini文件出错"); + } + } + + public string ReadString(string Section, string Ident, string Default) + { + byte[] array = new byte[65535]; + int privateProfileString = GetPrivateProfileString(Section, Ident, Default, array, array.GetUpperBound(0), FileName); + string @string = Encoding.GetEncoding(0).GetString(array); + @string = @string.Substring(0, privateProfileString); + return @string.Trim(); + } + + public int ReadInteger(string Section, string Ident, int Default) + { + string value = ReadString(Section, Ident, Default.ToString()); + try + { + return Convert.ToInt32(value); + } + catch (Exception) + { + return Default; + } + } + + public void WriteInteger(string Section, string Ident, int Value) + { + WriteString(Section, Ident, Value.ToString()); + } + + public bool ReadBool(string Section, string Ident, bool Default) + { + try + { + return Convert.ToBoolean(ReadString(Section, Ident, Default.ToString())); + } + catch (Exception) + { + return Default; + } + } + + public void WriteBool(string Section, string Ident, bool Value) + { + WriteString(Section, Ident, Value.ToString()); + } + + public void WriteDateTime(string Section, string Ident, DateTime Value) + { + WriteString(Section, Ident, Value.ToString()); + } + + public DateTime ReadDateTime(string Section, string Ident, DateTime Default) + { + try + { + return Convert.ToDateTime(ReadString(Section, Ident, Default.ToString())); + } + catch (Exception) + { + return Default; + } + } + + public void WriteDouble(string Section, string Ident, double Value) + { + WriteString(Section, Ident, Value.ToString()); + } + + public double ReadFloat(string Section, string Ident, double Default) + { + try + { + return Convert.ToDouble(ReadString(Section, Ident, Default.ToString())); + } + catch (Exception) + { + return Default; + } + } + + public StringCollection ReadSection(string Section) + { + byte[] array = new byte[16384]; + StringCollection stringCollection = new StringCollection(); + int privateProfileString = GetPrivateProfileString(Section, null, null, array, array.GetUpperBound(0), FileName); + GetStringsFromBuffer(array, privateProfileString, stringCollection); + return stringCollection; + } + + private void GetStringsFromBuffer(byte[] Buffer, int bufLen, StringCollection Strings) + { + Strings.Clear(); + if (bufLen == 0) + { + return; + } + int num = 0; + for (int i = 0; i < bufLen; i++) + { + if (Buffer[i] == 0 && i - num > 0) + { + string @string = Encoding.GetEncoding(0).GetString(Buffer, num, i - num); + Strings.Add(@string); + num = i + 1; + } + } + } + + public StringCollection ReadSections() + { + StringCollection stringCollection = new StringCollection(); + byte[] array = new byte[65535]; + int num = 0; + num = GetPrivateProfileString(null, null, null, array, array.GetUpperBound(0), FileName); + GetStringsFromBuffer(array, num, stringCollection); + return stringCollection; + } + + public NameValueCollection ReadSectionValues(string Section) + { + NameValueCollection nameValueCollection = new NameValueCollection(); + StringCollection stringCollection = ReadSection(Section); + nameValueCollection.Clear(); + StringEnumerator enumerator = stringCollection.GetEnumerator(); + try + { + while (enumerator.MoveNext()) + { + string current = enumerator.Current; + nameValueCollection.Add(current, ReadString(Section, current, "")); + } + } + finally + { + (enumerator as IDisposable)?.Dispose(); + } + return nameValueCollection; + } + + public void EraseSection(string Section) + { + if (!WritePrivateProfileString(Section, null, null, FileName)) + { + throw new ApplicationException("无法清除Ini文件中的Section"); + } + } + + public void DeleteKey(string Section, string Ident) + { + WritePrivateProfileString(Section, Ident, null, FileName); + } + + public void UpdateFile() + { + WritePrivateProfileString(null, null, null, FileName); + } + + public bool SectionExists(string Section) + { + StringCollection stringCollection = ReadSections(); + return stringCollection.IndexOf(Section) > -1; + } + + public bool ValueExists(string Section, string Ident) + { + StringCollection stringCollection = ReadSection(Section); + return stringCollection.IndexOf(Ident) > -1; + } + + ~IniFile() + { + UpdateFile(); + } + } +} diff --git a/Common.GLib/GLib.Utilities/JsonSerializer.cs b/Common.GLib/GLib.Utilities/JsonSerializer.cs new file mode 100644 index 0000000..ea243ea --- /dev/null +++ b/Common.GLib/GLib.Utilities/JsonSerializer.cs @@ -0,0 +1,20 @@ +using System; +using System.IO; +using System.Runtime.Serialization.Json; +using System.Text; + +namespace GLib.Utilities +{ + public class JsonSerializer + { + public static T ParseFromJson(string szJson) + { + T val = Activator.CreateInstance(); + using (MemoryStream stream = new MemoryStream(Encoding.UTF8.GetBytes(szJson))) + { + DataContractJsonSerializer dataContractJsonSerializer = new DataContractJsonSerializer(val.GetType()); + return (T)dataContractJsonSerializer.ReadObject(stream); + } + } + } +} diff --git a/Common.GLib/GLib.Utilities/SendState.cs b/Common.GLib/GLib.Utilities/SendState.cs new file mode 100644 index 0000000..2b8a0ee --- /dev/null +++ b/Common.GLib/GLib.Utilities/SendState.cs @@ -0,0 +1,10 @@ +namespace GLib.Utilities +{ + public enum SendState + { + Canceled = 0, + Succeed = 1, + Error = 2, + Sending = 3 + } +} diff --git a/Common.GLib/GLib.Utilities/StringHelper.cs b/Common.GLib/GLib.Utilities/StringHelper.cs new file mode 100644 index 0000000..340e2e6 --- /dev/null +++ b/Common.GLib/GLib.Utilities/StringHelper.cs @@ -0,0 +1,48 @@ +using GLib.Data.Entity; +using System; +using System.Collections.Generic; +using System.Data; +using System.Text; + +namespace GLib.Utilities +{ + public class StringHelper + { + public static string GetOrSelector(string col, string strid, out IList outlist) + { + string[] array = strid.Split(new char[1] + { + ',' + }, StringSplitOptions.RemoveEmptyEntries); + StringBuilder stringBuilder = new StringBuilder(); + outlist = new List(); + for (int i = 0; i < array.Length; i++) + { + if (i == 0) + { + stringBuilder.Append(" " + col + "=@" + i); + } + else + { + stringBuilder.Append(" or " + col + "=@" + i); + } + outlist.Add(new DBParam + { + ParamDbType = DbType.Int32, + ParamValue = int.Parse(array[i]) + }); + } + return stringBuilder.ToString(); + } + + public static string FormatSqlString(string strInput) + { + return strInput.Replace("'", "''"); + } + + public static string FormatDataTime(DateTime dt) + { + return dt.ToString("yyyy-MM-dd HH:mm"); + } + } +} diff --git a/Common.GLib/GLib.Web/HttpCache.cs b/Common.GLib/GLib.Web/HttpCache.cs new file mode 100644 index 0000000..9f208f8 --- /dev/null +++ b/Common.GLib/GLib.Web/HttpCache.cs @@ -0,0 +1,114 @@ +using System; +using System.Collections.Generic; +using System.Web; +//using System.Web.Caching; + +namespace GLib.Web +{ + + class Cache + { + + } + + + public class HttpCache + { + //protected static Cache _cache = null; + + private static void InitCache() + { + try + { +// _cache = HttpRuntime.Cache; + } + catch (Exception ex) + { + throw ex; + } + } + + public static bool SetCache(string cacheKey, object value) + { + //if (_cache == null) + //{ + // InitCache(); + //} + bool flag = false; + try + { + // _cache[cacheKey] = value; + return true; + } + catch (Exception ex) + { + throw ex; + } + } + + public static bool SetCache(string cacheKey, object value, int hours) + { + TimeSpan span = new TimeSpan(hours, 0, 0); + return SetCache(cacheKey, value, span); + } + + public static bool SetCache(string cacheKey, object value, TimeSpan span) + { + //if (_cache == null) + //{ + // InitCache(); + //} + bool flag = false; + try + { + // _cache.Insert(cacheKey, value, null, DateTime.MaxValue, span); + return true; + } + catch (Exception ex) + { + throw ex; + } + } + + public static object GetCache(string cacheKey) + { + //if (_cache == null) + //{ + // return null; + //} + object obj = null; + try + { + // obj = _cache[cacheKey]; + } + catch (Exception ex) + { + throw ex; + } + return obj; + } + + public static T GetCache(string cacheKey) where T : new() + { + //if (_cache == null) + //{ + // return default(T); + //} + T val = default(T); + try + { + //// object obj = _cache[cacheKey]; + // if (!(obj is T)) + // { + // throw new Exception("未能将对象强制转换"); + // } + // val = (T)obj; + } + catch (Exception ex) + { + throw ex; + } + return val; + } + } +} diff --git a/Common.GLib/GLib.Web/HttpSession.cs b/Common.GLib/GLib.Web/HttpSession.cs new file mode 100644 index 0000000..a96a4fe --- /dev/null +++ b/Common.GLib/GLib.Web/HttpSession.cs @@ -0,0 +1,76 @@ +using System; +using System.Web; + +namespace GLib.Web +{ + public class HttpSession + { + public static bool SetSession(string sessionKey, object value) + { + bool result = false; + //if (HttpContext.Current != null && HttpContext.Current.Session != null) + //{ + // try + // { + // HttpContext.Current.Session[sessionKey] = value; + // result = true; + // } + // catch (Exception ex) + // { + // throw ex; + // } + //} + return result; + } + + public static object GetSession(string sessionKey) + { + object result = null; + //if (HttpContext.Current != null && HttpContext.Current.Session != null) + //{ + // try + // { + // result = HttpContext.Current.Session[sessionKey]; + // } + // catch (Exception ex) + // { + // throw ex; + // } + //} + return result; + } + + public static T GetSession(string sessionKey) + { + T result = default(T); + object session = GetSession(sessionKey); + if (session != null) + { + if (session is T) + { + return (T)session; + } + throw new Exception($"对象不能强制转换为\"{typeof(T).ToString()}\"类型"); + } + return result; + } + + public static void ClearSession() + { + //if (HttpContext.Current != null && HttpContext.Current.Session != null) + //{ + // HttpContext.Current.Session.Clear(); + //} + } + + public static string GetSessionId() + { + //if (HttpContext.Current != null && HttpContext.Current.Session != null) + //{ + // return HttpContext.Current.Session.SessionID; + //} + //throw new Exception("Session未实例化"); + return string.Empty; + } + } +} diff --git a/Common.GLib/GLib.Web/Warn.cs b/Common.GLib/GLib.Web/Warn.cs new file mode 100644 index 0000000..81c7a6e --- /dev/null +++ b/Common.GLib/GLib.Web/Warn.cs @@ -0,0 +1,42 @@ +using System; + +namespace GLib.Web +{ + public abstract class Warn : Exception + { + public virtual Warn InnerWarn + { + get; + protected set; + } + + public virtual WarnDescription Description + { + get; + protected set; + } + + public Warn(WarnDescription wd) + : base(wd.Description) + { + Description = wd; + } + + public Warn(WarnDescription wd, Warn inner) + { + InnerWarn = inner; + Description = wd; + } + + public void Execute() + { + if (InnerWarn != null) + { + InnerWarn.Execute(); + } + DoExecute(); + } + + protected abstract void DoExecute(); + } +} diff --git a/Common.GLib/GLib.Web/WarnDescription.cs b/Common.GLib/GLib.Web/WarnDescription.cs new file mode 100644 index 0000000..dfaebf3 --- /dev/null +++ b/Common.GLib/GLib.Web/WarnDescription.cs @@ -0,0 +1,46 @@ +using System; + +namespace GLib.Web +{ + public class WarnDescription + { + public string Title + { + get; + set; + } + + public string Description + { + get; + set; + } + + public int HelpCode + { + get; + set; + } + + public virtual Exception Original + { + get; + set; + } + + protected WarnDescription() + { + } + + public WarnDescription(string description) + { + Description = description; + } + + public WarnDescription(Exception exc) + { + Description = exc.Message; + Original = exc; + } + } +} diff --git a/Common.GLib/GLib/AuxiliaryFieldAttribute.cs b/Common.GLib/GLib/AuxiliaryFieldAttribute.cs new file mode 100644 index 0000000..0492257 --- /dev/null +++ b/Common.GLib/GLib/AuxiliaryFieldAttribute.cs @@ -0,0 +1,9 @@ +using System; + +namespace GLib +{ + [AttributeUsage(AttributeTargets.Enum | AttributeTargets.Field)] + public class AuxiliaryFieldAttribute : Attribute + { + } +} diff --git a/Common.GLib/GLib/DebugEx.cs b/Common.GLib/GLib/DebugEx.cs new file mode 100644 index 0000000..4824a63 --- /dev/null +++ b/Common.GLib/GLib/DebugEx.cs @@ -0,0 +1,119 @@ +using System; +using System.Reflection; +using System.Text; +using System.Threading; + +namespace GLib +{ + public class DebugEx + { + private static string _appName = ""; + + private static Action _unhandledExceptionCallBack = null; + + private static bool _alertExceptionMsg = false; + + //public static string LogPath = Application.StartupPath + "\\log\\"; + + public static string Version = Assembly.GetExecutingAssembly().GetName().Version.ToString(); + + public static event Action EvtTrace; + + public static void Trace(string flag, string msg) + { + string text = $"{flag}___{msg}"; + Console.WriteLine(text); + if (EvtTrace != null) + { + EvtTrace(text); + } + } + + public static void RegisterUnHandldException() + { + //RegisterUnHandldException(Application.ProductName, null, alertExceptionMsg: true); + } + + public static void RegisterUnHandldException(string appName, Action unhandledExceptionCallBack, bool alertExceptionMsg = false) + { + _appName = appName; + _alertExceptionMsg = alertExceptionMsg; + _unhandledExceptionCallBack = unhandledExceptionCallBack; + // Application.ThreadException += Application_ThreadException; + AppDomain.CurrentDomain.UnhandledException += CurrentDomain_UnhandledException; + } + + private static void CurrentDomain_UnhandledException(object sender, UnhandledExceptionEventArgs e) + { + OnFatalException(e.ExceptionObject as Exception); + if (e.IsTerminating && _unhandledExceptionCallBack != null) + { + _unhandledExceptionCallBack(e); + } + } + + private static void Application_ThreadException(object sender, ThreadExceptionEventArgs e) + { + OnFatalException(e.Exception); + } + + public static void OnFatalException(Exception ex, bool isEnd = false) + { + StringBuilder stringBuilder = new StringBuilder(); + string text = ""; + string version = Version; + text = $"{_appName} {version} {DateTime.Now}"; + if (isEnd) + { + text = string.Format("=================致命错误==================\r\n{0} {1}", _appName, ""); + } + stringBuilder.AppendLine(text); + stringBuilder.AppendLine(GetErrorString(ex)); + WriteLog(stringBuilder.ToString()); + string text2 = $"{text}出现一个未处理的异常\r\n请将程序安装目录下的日志反馈给软件提供商。\r\n详细信息:{ex.Message + ex.StackTrace}\r\n发生时间:{DateTime.Now}"; + if (!_alertExceptionMsg) + { + } + } + + public static string GetLog(Exception ex, bool isEnd = false) + { + StringBuilder stringBuilder = new StringBuilder(); + string text = ""; + string arg = Assembly.GetExecutingAssembly().GetName().Version.ToString(); + text = $"{_appName} {arg} {DateTime.Now}"; + if (isEnd) + { + text = string.Format("=================致命错误==================\r\n{0} {1}", _appName, ""); + } + stringBuilder.AppendLine(text); + stringBuilder.AppendLine(GetErrorString(ex)); + return stringBuilder.ToString(); + } + + public static void WriteLog(string msg) + { + //// string text = LogPath.ToSystemPath(); + // if (!Directory.Exists(text)) + // { + // Directory.CreateDirectory(text); + // } + // string path = string.Format("{0}\\Log_{1}.txt", text, DateTime.Now.ToString("yyyy-MM-dd")).ToSystemPath(); + // File.AppendAllText(path, msg + "\r\n", Encoding.UTF8); + } + + private static string GetErrorString(Exception ex, string pleft = "") + { + StringBuilder stringBuilder = new StringBuilder(); + stringBuilder.AppendLine(pleft + ex.Message); + stringBuilder.AppendLine(pleft + ex.GetType().Name); + stringBuilder.AppendLine(pleft + ex.StackTrace); + if (ex.InnerException != null) + { + stringBuilder.AppendLine("---------------------------------------------->"); + stringBuilder.AppendLine(GetErrorString(ex.InnerException, pleft + " ")); + } + return stringBuilder.ToString(); + } + } +} diff --git a/Common.GLib/GLib/DescriptionAttribute.cs b/Common.GLib/GLib/DescriptionAttribute.cs new file mode 100644 index 0000000..a1c5c54 --- /dev/null +++ b/Common.GLib/GLib/DescriptionAttribute.cs @@ -0,0 +1,133 @@ +using System; +using System.Collections.Generic; +using System.Reflection; + +namespace GLib +{ + [AttributeUsage(AttributeTargets.All)] + public class DescriptionAttribute : Attribute + { + public string Description + { + get; + set; + } + + public string Name + { + get; + set; + } + + public object DefaultValue + { + get; + set; + } + + public static DescriptionAttribute GetDescription(object value) + { + return GetDescription(value.GetType(), DescriptionObjectType.Type, null, inherit: false); + } + + public static DescriptionAttribute GetDescription(Type attributeType) + { + return GetDescription(attributeType, DescriptionObjectType.Type, null, inherit: false); + } + + public static DescriptionAttribute GetDescription(Type attributeType, bool inherit) + { + return GetDescription(attributeType, DescriptionObjectType.Type, null, inherit); + } + + public static DescriptionAttribute GetDescription(Type attributeType, DescriptionObjectType objectType, string name) + { + return GetDescription(attributeType, objectType, name, inherit: false); + } + + public static DescriptionAttribute GetDescription(Type attributeType, DescriptionObjectType objectType, string name, bool inherit) + { + MemberInfo memberInfo = null; + object[] array = null; + Type typeFromHandle = typeof(DescriptionAttribute); + switch (objectType) + { + case DescriptionObjectType.Event: + memberInfo = attributeType.GetEvent(name); + break; + case DescriptionObjectType.Field: + memberInfo = attributeType.GetField(name); + break; + case DescriptionObjectType.Method: + memberInfo = attributeType.GetMethod(name); + break; + case DescriptionObjectType.Property: + memberInfo = attributeType.GetProperty(name); + break; + } + array = ((DescriptionObjectType.Type != objectType) ? memberInfo.GetCustomAttributes(typeFromHandle, inherit) : attributeType.GetCustomAttributes(typeFromHandle, inherit)); + if (array != null && array.Length > 0) + { + return (DescriptionAttribute)array[0]; + } + return null; + } + + public static DescriptionAttribute GetEnumDescription(object value) + { + Type type = value.GetType(); + if (!type.IsEnum) + { + throw new ArgumentNullException("参数类型必须为枚举类型"); + } + string[] array = value.ToString().Split(','); + IList list = new List(); + string[] array2 = array; + foreach (string text in array2) + { + if (!(text.Trim() != "")) + { + continue; + } + FieldInfo field = type.GetField(text.Trim()); + if (field != null && field.GetCustomAttributes(typeof(AuxiliaryFieldAttribute), inherit: true).Length == 0) + { + object[] customAttributes = field.GetCustomAttributes(typeof(DescriptionAttribute), inherit: true); + if (customAttributes.Length > 0) + { + list.Add((DescriptionAttribute)customAttributes[0]); + } + } + } + if (list.Count > 1) + { + DescriptionAttribute descriptionAttribute = new DescriptionAttribute(); + int num = 0; + foreach (DescriptionAttribute item in list) + { + if (num == 0) + { + descriptionAttribute = item; + } + else + { + DescriptionAttribute descriptionAttribute2 = descriptionAttribute; + descriptionAttribute2.Name = descriptionAttribute2.Name + "," + item.Name; + } + num++; + } + return descriptionAttribute; + } + if (list.Count > 0) + { + return list[0]; + } + return null; + } + + public override string ToString() + { + return Name; + } + } +} diff --git a/Common.GLib/GLib/DescriptionObjectType.cs b/Common.GLib/GLib/DescriptionObjectType.cs new file mode 100644 index 0000000..7be48eb --- /dev/null +++ b/Common.GLib/GLib/DescriptionObjectType.cs @@ -0,0 +1,11 @@ +namespace GLib +{ + public enum DescriptionObjectType + { + Event = 1, + Method = 2, + Field = 4, + Property = 8, + Type = 0x10 + } +} diff --git a/Common.GLib/GLib/MyTask.cs b/Common.GLib/GLib/MyTask.cs new file mode 100644 index 0000000..aaf1e39 --- /dev/null +++ b/Common.GLib/GLib/MyTask.cs @@ -0,0 +1,48 @@ +using System; +using System.Threading; + +namespace GLib +{ + public static class MyTask + { + private static ApartmentState ApartmentState = ApartmentState.MTA; + + public static TResult CallTask(this Func fun, TArg arg) + { + TResult result = default(TResult); + Thread thread = new Thread(((Action)delegate + { + result = fun(arg); + }).Invoke); + thread.IsBackground = true; + thread.Priority = ThreadPriority.Lowest; + thread.SetApartmentState(ApartmentState); + thread.Start(); + thread.Join(); + return result; + } + + public static void CallTask(this Action act, TArg arg) + { + Thread thread = new Thread(((Action)delegate + { + act(arg); + }).Invoke); + thread.IsBackground = true; + thread.Priority = ThreadPriority.Lowest; + thread.SetApartmentState(ApartmentState); + thread.Start(); + thread.Join(); + } + + public static void CallTask(this Action act) + { + Thread thread = new Thread(act.Invoke); + thread.IsBackground = true; + thread.Priority = ThreadPriority.Lowest; + thread.SetApartmentState(ApartmentState); + thread.Start(); + thread.Join(); + } + } +} diff --git a/Common.GLib/MSQueue.cs b/Common.GLib/MSQueue.cs new file mode 100644 index 0000000..89e9237 --- /dev/null +++ b/Common.GLib/MSQueue.cs @@ -0,0 +1,126 @@ +using System.Threading; + +public class MSQueue +{ + private class node_t + { + public T value; + + public pointer_t next; + } + + private struct pointer_t + { + public long count; + + public node_t ptr; + + public pointer_t(pointer_t p) + { + ptr = p.ptr; + count = p.count; + } + + public pointer_t(node_t node, long c) + { + ptr = node; + count = c; + } + } + + private pointer_t Head; + + private pointer_t Tail; + + public int Count; + + public MSQueue() + { + node_t ptr = new node_t(); + Head.ptr = (Tail.ptr = ptr); + Count = 0; + } + + private bool CAS(ref pointer_t destination, pointer_t compared, pointer_t exchange) + { + if (compared.ptr == Interlocked.CompareExchange(ref destination.ptr, exchange.ptr, compared.ptr)) + { + Interlocked.Exchange(ref destination.count, exchange.count); + return true; + } + return false; + } + + public bool deque(ref T t) + { + bool flag = true; + while (flag) + { + pointer_t head = Head; + pointer_t tail = Tail; + pointer_t next = head.ptr.next; + if (head.count != Head.count || head.ptr != Head.ptr) + { + continue; + } + if (head.ptr == tail.ptr) + { + if (null == next.ptr) + { + return false; + } + CAS(ref Tail, tail, new pointer_t(next.ptr, tail.count + 1)); + } + else + { + t = next.ptr.value; + if (CAS(ref Head, head, new pointer_t(next.ptr, head.count + 1))) + { + flag = false; + } + } + } + Interlocked.Decrement(ref Count); + return true; + } + + public void enqueue(T t) + { + node_t node_t = new node_t(); + node_t.value = t; + bool flag = true; + while (flag) + { + pointer_t tail = Tail; + pointer_t next = tail.ptr.next; + if (tail.count != Tail.count || tail.ptr != Tail.ptr) + { + continue; + } + if (null == next.ptr) + { + if (CAS(ref tail.ptr.next, next, new pointer_t(node_t, next.count + 1))) + { + Interlocked.Increment(ref Count); + flag = false; + } + } + else + { + CAS(ref Tail, tail, new pointer_t(next.ptr, tail.count + 1)); + } + } + } + + public T Dequeue() + { + T t = default(T); + deque(ref t); + return t; + } + + public void Enqueue(T item) + { + enqueue(item); + } +} diff --git a/Common.GLib/MyGather.BLL.UserControls/HttpClient.cs b/Common.GLib/MyGather.BLL.UserControls/HttpClient.cs new file mode 100644 index 0000000..c0d4ae8 --- /dev/null +++ b/Common.GLib/MyGather.BLL.UserControls/HttpClient.cs @@ -0,0 +1,145 @@ +using System; +using System.Drawing; +using System.IO; +using System.Net; +using System.Text; +using System.Web; + +namespace MyGather.BLL.UserControls +{ + public class HttpClient : WebClient + { + private CookieContainer cookieContainer; + + public CookieContainer Cookies + { + get + { + return cookieContainer; + } + set + { + cookieContainer = value; + } + } + + public static HttpClient Create() + { + return new HttpClient(); + } + + public static HttpClient Create(CookieContainer cookieContainer) + { + return new HttpClient(cookieContainer); + } + + public HttpClient() + { + cookieContainer = new CookieContainer(); + } + + public HttpClient(CookieContainer cookies) + { + cookieContainer = cookies; + } + + protected override WebRequest GetWebRequest(Uri address) + { + WebRequest webRequest = base.GetWebRequest(address); + if (webRequest is HttpWebRequest) + { + HttpWebRequest httpWebRequest = webRequest as HttpWebRequest; + httpWebRequest.CookieContainer = cookieContainer; + } + return webRequest; + } + + public string PostData(string uriString, string postString, string postStringEncoding, string dataEncoding, out string msg) + { + try + { + byte[] bytes = Encoding.GetEncoding(postStringEncoding).GetBytes(postString); + base.Headers.Add("Content-Type", "application/x-www-form-urlencoded"); + byte[] bytes2 = UploadData(uriString, "POST", bytes); + string @string = Encoding.GetEncoding(dataEncoding).GetString(bytes2); + msg = string.Empty; + return @string; + } + catch (WebException ex) + { + msg = ex.Message; + return string.Empty; + } + } + + public string PostData(string uriString, string postString, out string msg) + { + return PostData(uriString, postString, "gb2312", "gb2312", out msg); + } + + public string GetSrc(string uriString, string dataEncoding, out string msg) + { + try + { + byte[] bytes = DownloadData(uriString); + string @string = Encoding.GetEncoding(dataEncoding).GetString(bytes); + @string = @string.Replace("\t", ""); + @string = @string.Replace("\r", ""); + @string = @string.Replace("\n", ""); + msg = string.Empty; + return @string; + } + catch (WebException ex) + { + msg = ex.Message; + return string.Empty; + } + } + + public string GetSrc(string uriString, out string msg) + { + return GetSrc(uriString, "gb2312", out msg); + } + + public Stream GetSteam(string uriString, string dataEncoding, out string msg) + { + try + { + byte[] array = DownloadData(uriString); + MemoryStream memoryStream = new MemoryStream(array); + Image image = new Bitmap(memoryStream); + string @string = Encoding.GetEncoding(dataEncoding).GetString(array); + @string = @string.Replace("\t", ""); + @string = @string.Replace("\r", ""); + @string = @string.Replace("\n", ""); + msg = string.Empty; + return memoryStream; + } + catch (WebException ex) + { + msg = ex.Message; + return null; + } + } + + public bool GetFile(string urlString, string fileName, out string msg) + { + try + { + DownloadFile(urlString, fileName); + msg = string.Empty; + return true; + } + catch (WebException ex) + { + msg = ex.Message; + return false; + } + } + + public string UrlEncode(string url) + { + return HttpUtility.UrlEncode(url); + } + } +} diff --git a/Common.GLib/Properties/AssemblyInfo.cs b/Common.GLib/Properties/AssemblyInfo.cs new file mode 100644 index 0000000..fd24936 --- /dev/null +++ b/Common.GLib/Properties/AssemblyInfo.cs @@ -0,0 +1,20 @@ +using System.Diagnostics; +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Versioning; + +[assembly: AssemblyFileVersion("1.0.0.0")] +[assembly: Guid("078f0b5e-24dd-4c6b-b186-d9f5e2644d9e")] +[assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)] +[assembly: CompilationRelaxations(8)] +[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] +[assembly: AssemblyTitle("GLib")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("GLib")] +[assembly: AssemblyCopyright("Copyright © 2010")] +[assembly: AssemblyTrademark("")] +[assembly: ComVisible(false)] +[assembly: AssemblyVersion("1.0.0.0")] diff --git a/Common.GLib/RegexUtils.cs b/Common.GLib/RegexUtils.cs new file mode 100644 index 0000000..32e399c --- /dev/null +++ b/Common.GLib/RegexUtils.cs @@ -0,0 +1,93 @@ +using System.Text.RegularExpressions; + +public class RegexUtils +{ + public class Pattern + { + public static bool matches(string regex, string str) + { + Regex regex2 = new Regex(regex); + int count = regex2.Matches(str).Count; + return count > 0; + } + } + + public static bool checkEmail(string email) + { + string regex = "\\w+@\\w+\\.[a-z]+(\\.[a-z]+)?"; + string regex2 = "\\w+\\.[a-z]+(\\.[a-z]+)?@\\w+\\.[a-z]+(\\.[a-z]+)?"; + return Pattern.matches(regex, email) || Pattern.matches(regex2, email); + } + + public static bool checkIdCard(string idCard) + { + string regex = "[1-9]\\d{13,16}[a-zA-Z0-9]{1}"; + return Pattern.matches(regex, idCard); + } + + public static bool checkMobile(string mobile) + { + string regex = "(\\+\\d+)?1[3458]\\d{9}$"; + return Pattern.matches(regex, mobile); + } + + public static bool checkPhone(string phone) + { + string regex = "(\\+\\d+)?(\\d{3,4}\\-?)?\\d{7,8}$"; + return Pattern.matches(regex, phone); + } + + public static bool checkDigit(string digit) + { + string regex = "\\-?[1-9]\\d+"; + return Pattern.matches(regex, digit); + } + + public static bool checkDecimals(string decimals) + { + string regex = "\\-?[1-9]\\d+(\\.\\d+)?"; + return Pattern.matches(regex, decimals); + } + + public static bool checkBlankSpace(string blankSpace) + { + string regex = "\\s+"; + return Pattern.matches(regex, blankSpace); + } + + public static bool checkChinese(string chinese) + { + string regex = "^[一-龥]+$"; + return Pattern.matches(regex, chinese); + } + + public static bool checkBirthday(string birthday) + { + string regex = "[1-9]{4}([-./])\\d{1,2}\\1\\d{1,2}"; + return Pattern.matches(regex, birthday); + } + + public static bool checkURL(string url) + { + string regex = "(https?://(w{3}\\.)?)?\\w+\\.\\w+(\\.[a-zA-Z]+)*(:\\d{1,5})?(/\\w*)*(\\??(.+=.*)?(&.+=.*)?)?"; + return Pattern.matches(regex, url); + } + + public static bool checkPostcode(string postcode) + { + string regex = "[1-9]\\d{5}"; + return Pattern.matches(regex, postcode); + } + + public static bool checkIpAddress(string ipAddress) + { + string regex = "[1-9](\\d{1,2})?\\.(0|([1-9](\\d{1,2})?))\\.(0|([1-9](\\d{1,2})?))\\.(0|([1-9](\\d{1,2})?))"; + return Pattern.matches(regex, ipAddress); + } + + public static bool checkAccount(string account) + { + string regex = "[a-zA-Z0-9]{4,15}"; + return Pattern.matches(regex, account); + } +} diff --git a/Common.GLib/RegistryHelper.cs b/Common.GLib/RegistryHelper.cs new file mode 100644 index 0000000..b524f5c --- /dev/null +++ b/Common.GLib/RegistryHelper.cs @@ -0,0 +1,80 @@ +using Microsoft.Win32; +using System; +using System.Diagnostics; + +public class RegistryHelper +{ + public static bool ConfigAutoStart(bool isAutoStart, string[] args) + { + try + { + string processName = Process.GetCurrentProcess().ProcessName; + RegistryKey registryKey = null; + using (registryKey = OpenKeyForWrite("SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Run")) + { + if (registryKey == null) + { + return false; + } + string text = ""; // $"\"{Application.ExecutablePath}\""; + for (int i = 0; i < args.Length; i++) + { + text = ((i != 2) ? (text + " " + args[i]) : (text + " " + $"\"{args[i]}\"")); + } + if (isAutoStart) + { + registryKey.SetValue(processName, text); + } + else + { + registryKey.DeleteValue(processName, throwOnMissingValue: false); + } + registryKey.Close(); + return true; + } + } + catch (Exception) + { + return false; + } + } + + public static RegistryKey OpenKeyForWrite(string subKey) + { + return OpenKeyForWrite(Registry.LocalMachine, subKey); + } + + public static RegistryKey OpenKeyForWrite(RegistryKey key, string subKey) + { + RegistryKey registryKey = null; + registryKey = key.OpenSubKey(subKey, writable: true); + if (registryKey == null) + { + registryKey = key.CreateSubKey(subKey); + } + return registryKey; + } + + public static void WriteAutoLoginWindowRegistryKey(bool isAutoLogin, string defaultUserName, string defaultPassword) + { + try + { + RegistryKey registryKey = Registry.LocalMachine.OpenSubKey("SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Winlogon", writable: true); + if (isAutoLogin) + { + registryKey.SetValue("AutoAdminLogon", "1"); + registryKey.SetValue("DefaultUserName", defaultUserName); + registryKey.SetValue("DefaultPassword", defaultPassword); + } + else + { + registryKey.SetValue("AutoAdminLogon", "0"); + registryKey.SetValue("DefaultPassword", string.Empty); + } + registryKey.Close(); + } + catch (Exception) + { + } + } +} diff --git a/Common.GLib/Watchdog.cs b/Common.GLib/Watchdog.cs new file mode 100644 index 0000000..900eb97 --- /dev/null +++ b/Common.GLib/Watchdog.cs @@ -0,0 +1,236 @@ +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.IO; +using System.Linq; +using System.Runtime.InteropServices; +using System.Text; +using System.Threading; +//using System.Windows.Forms; + +public static class Watchdog +{ + private static void Application_ThreadException(object sender, ThreadExceptionEventArgs e) + { + OnFatalException(e.Exception); + } + + private static int CheckActive(string appName) + { + int num = 0; + Process[] processes = Process.GetProcesses(); + foreach (Process process in processes) + { + if (process.ProcessName == appName) + { + num++; + } + } + return num; + } + + private static void CurrentDomain_UnhandledException(object sender, UnhandledExceptionEventArgs e) + { + OnFatalException(e.ExceptionObject as Exception); + } + + [DllImport("user32.dll", CharSet = CharSet.Unicode)] + public static extern IntPtr FindWindow(string lpClassName, string lpWindowName); + + [DllImport("User32.dll", CharSet = CharSet.Unicode)] + public static extern IntPtr FindWindowEx(IntPtr hwndParent, IntPtr hwndChildAfter, string strClassName, string strWindowName); + + [DllImport("user32.dll")] + private static extern int GetWindowThreadProcessId(IntPtr hWnd, out int ProcessId); + + private static void HideConsoleWindow() + { + //Console.Title = Application.ProductName; + //IntPtr intPtr = FindWindow("ConsoleWindowClass", Application.ProductName); + //if (intPtr != IntPtr.Zero) + //{ + // ShowWindow(intPtr, 0u); + //} + } + + private static void KillDApp(string appName) + { + List list = Enumerable.ToList(Enumerable.Select(new string[6] + { + "WerFault.exe", + "dwwin.exe", + "dw20.exe", + "WerFault", + "dwwin", + "dw20" + }, (string p) => p.ToUpper())); + Process[] processes = Process.GetProcesses(); + Process[] array = processes; + foreach (Process process in array) + { + try + { + if (list.Contains(process.ProcessName.ToUpper().Replace(" *32", ""))) + { + Log($"异常进程:{process.ProcessName}"); + process.Kill(); + } + } + catch (Exception) + { + } + } + try + { + IntPtr intPtr = FindWindowEx(IntPtr.Zero, IntPtr.Zero, null, $"{appName}.exe - 应用程序错误"); + if (intPtr != IntPtr.Zero) + { + int ProcessId = 0; + GetWindowThreadProcessId(intPtr, out ProcessId); + if (ProcessId != 0) + { + Process.GetProcessById(ProcessId).Kill(); + Log($"异常窗口 {appName}.exe - 应用程序错误"); + } + } + intPtr = FindWindowEx(IntPtr.Zero, IntPtr.Zero, null, "Microsoft Visual C++ Runtime Library"); + if (intPtr != IntPtr.Zero) + { + int ProcessId2 = 0; + GetWindowThreadProcessId(intPtr, out ProcessId2); + if (ProcessId2 != 0) + { + Process.GetProcessById(ProcessId2).Kill(); + Log($"异常窗口 {appName}.exe - Microsoft Visual C++ Runtime Library"); + } + } + } + catch (Exception) + { + } + } + + private static void KillOtherDog() + { + Process currentProcess = Process.GetCurrentProcess(); + Process[] processes = Process.GetProcesses(); + foreach (Process process in processes) + { + if (process.ProcessName.ToUpper() == currentProcess.ProcessName.ToUpper()) + { + try + { + if (currentProcess.Id != process.Id) + { + process.Kill(); + } + } + catch (Exception) + { + } + } + } + } + + private static void Log(string msg) + { + //msg = $"{DateTime.Now} {msg}"; + //Console.WriteLine(msg); + //string text = Application.StartupPath + "\\Watchdog"; + //if (!Directory.Exists(text)) + //{ + // Directory.CreateDirectory(text); + //} + //File.AppendAllText(string.Format("{0}\\{1}.txt", text, DateTime.Now.ToString("yyyy_MM")), msg + "\r\n"); + } + + private static void Main(string[] args) + { + try + { + RegisterUnHandldException(); + HideConsoleWindow(); + string text = args[0]; + string text2 = args[1]; + string text3 = args[2]; + int num = int.Parse(args[3]); + string text4 = args[4]; + string text5 = args[5]; + string text6 = (args.Length > 6) ? args[6] : null; + string text7 = (args.Length > 7) ? args[7] : null; + Console.WriteLine(string.Format("{0} {1} {2} {3} {4} {5} {6}", text, text2, text3, num, text4, text5, text6, text7)); + if (!(text == "0")) + { + RegistryHelper.ConfigAutoStart(text4 == "1", args); + KillOtherDog(); + DateTime now = DateTime.Now; + while (true) + { + bool flag = true; + KillDApp(text2); + if (CheckActive(text2) > 0) + { + now = DateTime.Now; + } + if (now.AddSeconds(num) < DateTime.Now) + { + StartApp(text2, text3); + now = DateTime.Now; + } + Thread.Sleep(1000); + } + } + RegistryHelper.ConfigAutoStart(isAutoStart: false, args); + KillOtherDog(); + } + catch (Exception ex) + { + Console.WriteLine(ex.ToString()); + Console.Read(); + } + } + + private static void OnFatalException(Exception ex) + { + StringBuilder stringBuilder = new StringBuilder(); + string value = string.Format("{0} {1}", "Watchdog", ""); + stringBuilder.AppendLine(value); + stringBuilder.AppendLine(ex.Message); + stringBuilder.AppendLine(ex.GetType().Name); + stringBuilder.AppendLine(ex.StackTrace); + Log(stringBuilder.ToString()); + } + + private static void RegisterUnHandldException() + { + //Application.ThreadException += Application_ThreadException; + AppDomain.CurrentDomain.UnhandledException += CurrentDomain_UnhandledException; + } + + [DllImport("user32.dll")] + public static extern bool ShowWindow(IntPtr hWnd, uint nCmdShow); + + private static void StartApp(string appName, string exe) + { + try + { + int num = CheckActive(appName); + Log($"尝试启动 {appName} 路径:{exe}"); + Directory.SetCurrentDirectory(new FileInfo(exe).Directory.ToString()); + Process.Start(exe); + if (CheckActive(appName) > num) + { + Log($"启动成功 {appName} 路径:{exe}"); + } + else + { + Log($"启动失败 {appName} 路径:{exe}"); + } + Thread.Sleep(3000); + } + catch (Exception arg) + { + Log($"启动异常 {appName} 路径:{exe} \r\n异常信息 {arg}"); + } + } +} diff --git a/GB28181.SIPSorcery/SIP.App/SIPUserAgents/JingleUserAgent.cs b/GB28181.SIPSorcery/SIP.App/SIPUserAgents/JingleUserAgent.cs new file mode 100644 index 0000000..a190513 --- /dev/null +++ b/GB28181.SIPSorcery/SIP.App/SIPUserAgents/JingleUserAgent.cs @@ -0,0 +1,97 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Net; +using System.Text; +using System.Threading; +using GB28181.SIPSorcery.Net; +using GB28181.SIPSorcery.Sys; + +namespace GB28181.SIPSorcery.SIP.App +{ + public class JingleUserAgent : ISIPClientUserAgent + { + private static string m_CRLF = SDP.CRLF; + + private SIPMonitorLogDelegate Log_External; + + // private XMPPClient m_xmppClient; + + public string Owner { get; private set; } + public string AdminMemberId { get; private set; } + public UACInviteTransaction ServerTransaction { get; private set; } + public SIPDialogue SIPDialogue { get; private set; } + public SIPCallDescriptor CallDescriptor { get; private set; } + public bool IsUACAnswered { get; private set; } + + public event SIPCallResponseDelegate CallTrying; + public event SIPCallResponseDelegate CallRinging; + public event SIPCallResponseDelegate CallAnswered; + public event SIPCallFailedDelegate CallFailed; + + public JingleUserAgent( + string owner, + string adminMemberId, + SIPMonitorLogDelegate logDelegate) + { + Owner = owner; + AdminMemberId = adminMemberId; + Log_External = logDelegate; + + // If external logging is not required assign an empty handler to stop null reference exceptions. + if (Log_External == null) + { + Log_External = (e) => { }; + } + } + + public void Call(SIPCallDescriptor sipCallDescriptor) + { + //CallDescriptor = sipCallDescriptor; + //m_xmppClient = new XMPPClient("talk.google.com", 5222, "google.com", null, null); + //m_xmppClient.IsBound += IsBound; + //m_xmppClient.Answered += Answered; + + //IPEndPoint sdpEndPoint = SDP.GetSDPRTPEndPoint(CallDescriptor.Content); + //if (IPSocket.IsPrivateAddress(sdpEndPoint.Address.ToString())) + //{ + // bool wasSDPMangled; + // CallDescriptor.Content = SIPPacketMangler.MangleSDP(CallDescriptor.Content, CallDescriptor.MangleIPAddress.ToString(), out wasSDPMangled); + //} + + //ThreadPool.QueueUserWorkItem(delegate { m_xmppClient.Connect(); }); + } + + private void IsBound() + { + Console.WriteLine("XMPP client IsBound"); + // m_xmppClient.PlaceCall(SIPURI.ParseSIPURI(CallDescriptor.To).User + "@voice.google.com", SDP.ParseSDPDescription(CallDescriptor.Content)); + } + + private void Answered(SDP sdp) + { + Console.WriteLine("XMPP client call answered."); + + IsUACAnswered = true; + + SIPResponse okResponse = new SIPResponse(SIPResponseStatusCodesEnum.Ok, "Ok", new SIPEndPoint(new IPEndPoint(IPAddress.Loopback, 0))); + okResponse.Header.ContentType = SDP.SDP_MIME_CONTENTTYPE; + okResponse.Body = sdp.ToString(); + + SIPDialogue = new SIPDialogue(null, null, null, null, -1, null, null, null, Guid.NewGuid(), Owner, AdminMemberId, null, sdp.ToString()); + SIPDialogue.CallDurationLimit = CallDescriptor.CallDurationLimit; + + CallAnswered(this, okResponse); + } + + public void Cancel() + { + throw new NotImplementedException(); + } + + public void Update(CRMHeaders crmHeaders) + { + throw new NotImplementedException(); + } + } +} diff --git a/GB28181.SIPSorcery/Servers.Cores/IMediaService.cs b/GB28181.SIPSorcery/Servers.Cores/IMediaService.cs index f642f9b..c7c620e 100644 --- a/GB28181.SIPSorcery/Servers.Cores/IMediaService.cs +++ b/GB28181.SIPSorcery/Servers.Cores/IMediaService.cs @@ -6,6 +6,12 @@ namespace GB28181.SIPSorcery.Servers { public interface IMediaAction { + + /// + /// 实时视频请求 + /// + void RealVideoReq(); + /// /// 实时视频请求 /// @@ -31,7 +37,7 @@ namespace GB28181.SIPSorcery.Servers /// /// 视频流回调完成 /// - // event Action OnStreamReady; + event Action OnStreamReady; #region 录像点播 diff --git a/GB28181.SIPSorcery/Servers.Cores/SIPMessage/SIPMessageCore.cs b/GB28181.SIPSorcery/Servers.Cores/SIPMessage/SIPMessageCore.cs index d5b1908..8980b8f 100644 --- a/GB28181.SIPSorcery/Servers.Cores/SIPMessage/SIPMessageCore.cs +++ b/GB28181.SIPSorcery/Servers.Cores/SIPMessage/SIPMessageCore.cs @@ -24,6 +24,24 @@ using System.Threading.Tasks; namespace GB28181.SIPSorcery.Servers.SIPMessage { + public struct MonitorKey + { + /// + /// 设备编码 + /// + public string DeviceID { get; set; } + + /// + /// 命令类型 + /// + public CommandType CmdType { get; set; } + + public override string ToString() + { + return this.DeviceID; + } + } + /// /// sip消息核心处理 /// @@ -258,6 +276,8 @@ namespace GB28181.SIPSorcery.Servers.SIPMessage } } + + public void PtzControl(PTZCommand ptzcmd, int dwSpeed, string deviceId) { try diff --git a/GB28181.SIPSorcery/Servers.Cores/SIPMonitor/SIPMonitorCore.cs b/GB28181.SIPSorcery/Servers.Cores/SIPMonitor/SIPMonitorCore.cs index e3c492b..e0a0f3e 100644 --- a/GB28181.SIPSorcery/Servers.Cores/SIPMonitor/SIPMonitorCore.cs +++ b/GB28181.SIPSorcery/Servers.Cores/SIPMonitor/SIPMonitorCore.cs @@ -56,7 +56,7 @@ namespace GB28181.SIPSorcery.Servers.SIPMonitor /// /// 视频流回调 /// - // public event Action OnStreamReady; + public event Action OnStreamReady; #endregion #region 初始化监控 @@ -71,6 +71,43 @@ namespace GB28181.SIPSorcery.Servers.SIPMonitor #endregion #region 实时视频 + + /// + /// 实时视频请求 + /// + /// 设备编码 + public void RealVideoReq() + { + //_mediaPort = _msgCore.SetMediaPort(); + //string localIp = _msgCore.LocalEP.Address.ToString(); + //string fromTag = CallProperties.CreateNewTag(); + //int cSeq = CallProperties.CreateNewCSeq(); + //string callId = CallProperties.CreateNewCallId(); + + //SIPURI remoteUri = new SIPURI(_deviceId, _remoteEP.ToHost(), ""); + //SIPURI localUri = new SIPURI(_msgCore.LocalSIPId, _msgCore.LocalEP.ToHost(), ""); + //SIPFromHeader from = new SIPFromHeader(null, localUri, fromTag); + //SIPToHeader to = new SIPToHeader(null, remoteUri, null); + //SIPRequest realReq = _msgCore.Transport.GetRequest(SIPMethodsEnum.INVITE, remoteUri); + //SIPContactHeader contactHeader = new SIPContactHeader(null, localUri); + //realReq.Header.Contact.Clear(); + //realReq.Header.Contact.Add(contactHeader); + + //realReq.Header.Allow = null; + //realReq.Header.From = from; + //realReq.Header.To = to; + //realReq.Header.UserAgent = SIPConstants.SIP_USERAGENT_STRING; + //realReq.Header.CSeq = cSeq; + //realReq.Header.CallId = callId; + //realReq.Header.Subject = SetSubject(); + //realReq.Header.ContentType = "application/sdp"; + + //realReq.Body = SetMediaReq(localIp, _mediaPort); + //_msgCore.SendReliableRequest(_remoteEP, realReq); + //_reqSession = realReq; + } + + /// /// 实时视频请求 /// diff --git a/GB28181.SIPSorcery/Sys/Config/SIPSqlite.cs b/GB28181.SIPSorcery/Sys/Config/SIPSqlite.cs new file mode 100644 index 0000000..8fda920 --- /dev/null +++ b/GB28181.SIPSorcery/Sys/Config/SIPSqlite.cs @@ -0,0 +1,84 @@ +using GB28181.SIPSorcery.Persistence; +using GB28181.SIPSorcery.SIP.App; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace GB28181.SIPSorcery.Sys.Config +{ + public class SIPSqlite + { + private static readonly string m_storageTypeKey = SIPSorceryConfiguration.PERSISTENCE_STORAGETYPE_KEY; + private static readonly string m_connStrKey = SIPSorceryConfiguration.PERSISTENCE_STORAGECONNSTR_KEY; + private static readonly string m_XMLFilename = "gb28181.xml"; + + private static StorageTypes m_storageType; + private static string m_connStr; + + private static SIPSqlite _instance; + + private List _accounts; + + public List Accounts + { + get { return _accounts; } + set { _accounts = value; } + } + private SIPAssetPersistor _sipAccount; + + public SIPAssetPersistor SipAccount + { + get { return _sipAccount; } + } + + public static SIPSqlite Instance + { + get + { + if (_instance == null) + { + _instance = new SIPSqlite(); + } + return _instance; + } + } + + static SIPSqlite() + { + string path = AppDomain.CurrentDomain.BaseDirectory + "Config\\"; + m_storageType = (AppState.GetConfigSetting(m_storageTypeKey) != null) ? StorageTypesConverter.GetStorageType(AppState.GetConfigSetting(m_storageTypeKey)) : StorageTypes.Unknown; + m_connStr = AppState.GetConfigSetting(m_connStrKey); + if (m_storageType == StorageTypes.SQLite) + { + m_connStr = string.Format(m_connStr, path); + + } + if (m_storageType == StorageTypes.Unknown || m_connStr.IsNullOrBlank()) + { + throw new ApplicationException("The SIP Registrar cannot start with no persistence settings."); + } + } + + public void Read() + { + SIPAssetPersistor account = SIPAssetPersistorFactory.CreateSIPAssetPersistor(m_storageType, m_connStr, m_XMLFilename); + _sipAccount = account; + _accounts = account.Get(); + } + + public void Save(SIPAccount account) + { + if (_accounts.Any(d => d.SIPUsername == account.SIPUsername || d.SIPDomain == account.SIPDomain)) + { + SipAccount.Update(account); + } + else + { + SipAccount.Add(account); + _accounts.Add(account); + } + } + } +} diff --git a/GB28181.SIPSorcery/Sys/WrapperImpersonationContext.cs b/GB28181.SIPSorcery/Sys/WrapperImpersonationContext.cs new file mode 100644 index 0000000..327c82f --- /dev/null +++ b/GB28181.SIPSorcery/Sys/WrapperImpersonationContext.cs @@ -0,0 +1,144 @@ +// ============================================================================ +// FileName: WrapperImpersonationContext.cs +// +// Description: +// Creates a Windows impersonation context for a specified set of login credentials. +// +// Author(s): +// Aaron Clauson +// +// History: +// 18 Jul 2010 Aaron Clauson Created from http://www.vanotegem.nl/PermaLink,guid,36633846-2eca-40fe-9957-2859d8a244dc.aspx. +// +// License: +// Public domain. +// ============================================================================ + +using System; +using System.ComponentModel; +using System.Runtime.InteropServices; +using System.Security.Permissions; +using System.Security.Principal; + +#if UNITTEST +using NUnit.Framework; +#endif + +public class WrapperImpersonationContext +{ + [DllImport("advapi32.dll", SetLastError = true, CharSet = CharSet.Unicode)] + public static extern bool LogonUser(String lpszUsername, String lpszDomain, + String lpszPassword, int dwLogonType, int dwLogonProvider, ref IntPtr phToken); + + [DllImport("kernel32.dll", CharSet = CharSet.Auto)] + public extern static bool CloseHandle(IntPtr handle); + + private const int LOGON32_PROVIDER_DEFAULT = 0; + private const int LOGON32_LOGON_INTERACTIVE = 2; + + private string m_Domain; + private string m_Password; + private string m_Username; + private IntPtr m_Token; + + // private WindowsImpersonationContext m_Context = null; + + protected bool IsInContext { get; } + //{ + // get { return m_Context != null; } + //} + + public WrapperImpersonationContext(string domain, string username, string password) + { + m_Domain = domain; + m_Username = username; + m_Password = password; + } + + [PermissionSetAttribute(SecurityAction.Demand, Name = "FullTrust")] + public void Enter() + { + if (this.IsInContext) return; + m_Token = new IntPtr(0); + try + { + m_Token = IntPtr.Zero; + bool logonSuccessfull = LogonUser( + m_Username, + m_Domain, + m_Password, + LOGON32_LOGON_INTERACTIVE, + LOGON32_PROVIDER_DEFAULT, + ref m_Token); + if (logonSuccessfull == false) + { + int error = Marshal.GetLastWin32Error(); + throw new Win32Exception(error); + } + WindowsIdentity identity = new WindowsIdentity(m_Token); + // m_Context = identity.Impersonate(); + } + catch + { + throw; + } + } + + [PermissionSetAttribute(SecurityAction.Demand, Name = "FullTrust")] + public void Leave() + { + if (this.IsInContext == false) return; + // m_Context.Undo(); + + if (m_Token != IntPtr.Zero) CloseHandle(m_Token); + // m_Context = null; + } + + #region Unit testing. + + #if UNITTEST + + [TestFixture] + public class WrapperImpersonationContextUnitTest + { + [TestFixtureSetUp] + public void Init() { } + + [TestFixtureTearDown] + public void Dispose() { } + + [Test] + public void SampleTest() + { + Console.WriteLine(System.Reflection.MethodBase.GetCurrentMethod().Name); + } + + [Test] + public void EnterContextUnitTest() + { + Console.WriteLine(System.Reflection.MethodBase.GetCurrentMethod().Name); + + Console.WriteLine("identity=" + WindowsIdentity.GetCurrent().Name + "."); + using (StreamReader sr = new StreamReader(@"c:\temp\impersonationtest.txt")) + { + Console.WriteLine(sr.ReadToEnd()); + } + + WrapperImpersonationContext context = new WrapperImpersonationContext(null, "sipsorcery-appsvr", "password"); + context.Enter(); + Console.WriteLine("identity=" + WindowsIdentity.GetCurrent().Name + "."); + + using (StreamReader sr = new StreamReader(@"c:\temp\impersonationtest.txt")) + { + Console.WriteLine(sr.ReadToEnd()); + } + + context.Leave(); + Console.WriteLine("identity=" + WindowsIdentity.GetCurrent().Name + "."); + } + } + + #endif + + #endregion +} \ No newline at end of file diff --git a/GB28181.Solution.sln b/GB28181.Solution.sln index 2d40847..c04c85c 100644 --- a/GB28181.Solution.sln +++ b/GB28181.Solution.sln @@ -9,12 +9,18 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Test.GB28181.Service", "Tes EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Win.GB28181.Client", "Win.GB28181.Client\Win.GB28181.Client.csproj", "{3E2F1C35-7354-4F55-ABA4-44CBCE2E18B5}" EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Win.MediaNetEngine", "Win.MeidaNetEngine\Win.MediaNetEngine.csproj", "{8332828E-DA9A-4813-9569-9DBA95DF8FF8}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SS.MediaNetEngine", "SS.MediaNetEngine\SS.MediaNetEngine.csproj", "{8332828E-DA9A-4813-9569-9DBA95DF8FF8}" EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "GB28181.SIPSorcery", "GB28181.SIPSorcery\GB28181.SIPSorcery.csproj", "{42050B07-B393-4292-A89F-7ECE14989E0F}" EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "GB28181.Server", "GB28181.Server\GB28181.Server.csproj", "{A10D6BA9-C42F-4B3A-BBFB-D820FB1597EF}" EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Common.GLib", "Common.GLib\Common.GLib.csproj", "{E377051D-1FF6-4F36-BA54-33F5BBF11154}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SS.VideoConver", "SS.VideoConver\SS.VideoConver.csproj", "{D6783F96-45F9-488C-8507-9DB2BF0012E2}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Common.GLib.WinControls", "Common.GLib.WinControls\Common.GLib.WinControls.csproj", "{C8399060-DEA1-4222-A863-E6F9940D23B0}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -123,6 +129,54 @@ Global {A10D6BA9-C42F-4B3A-BBFB-D820FB1597EF}.Release|x64.Build.0 = Release|Any CPU {A10D6BA9-C42F-4B3A-BBFB-D820FB1597EF}.Release|x86.ActiveCfg = Release|Any CPU {A10D6BA9-C42F-4B3A-BBFB-D820FB1597EF}.Release|x86.Build.0 = Release|Any CPU + {E377051D-1FF6-4F36-BA54-33F5BBF11154}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {E377051D-1FF6-4F36-BA54-33F5BBF11154}.Debug|Any CPU.Build.0 = Debug|Any CPU + {E377051D-1FF6-4F36-BA54-33F5BBF11154}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU + {E377051D-1FF6-4F36-BA54-33F5BBF11154}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU + {E377051D-1FF6-4F36-BA54-33F5BBF11154}.Debug|x64.ActiveCfg = Debug|Any CPU + {E377051D-1FF6-4F36-BA54-33F5BBF11154}.Debug|x64.Build.0 = Debug|Any CPU + {E377051D-1FF6-4F36-BA54-33F5BBF11154}.Debug|x86.ActiveCfg = Debug|Any CPU + {E377051D-1FF6-4F36-BA54-33F5BBF11154}.Debug|x86.Build.0 = Debug|Any CPU + {E377051D-1FF6-4F36-BA54-33F5BBF11154}.Release|Any CPU.ActiveCfg = Release|Any CPU + {E377051D-1FF6-4F36-BA54-33F5BBF11154}.Release|Any CPU.Build.0 = Release|Any CPU + {E377051D-1FF6-4F36-BA54-33F5BBF11154}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU + {E377051D-1FF6-4F36-BA54-33F5BBF11154}.Release|Mixed Platforms.Build.0 = Release|Any CPU + {E377051D-1FF6-4F36-BA54-33F5BBF11154}.Release|x64.ActiveCfg = Release|Any CPU + {E377051D-1FF6-4F36-BA54-33F5BBF11154}.Release|x64.Build.0 = Release|Any CPU + {E377051D-1FF6-4F36-BA54-33F5BBF11154}.Release|x86.ActiveCfg = Release|Any CPU + {E377051D-1FF6-4F36-BA54-33F5BBF11154}.Release|x86.Build.0 = Release|Any CPU + {D6783F96-45F9-488C-8507-9DB2BF0012E2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {D6783F96-45F9-488C-8507-9DB2BF0012E2}.Debug|Any CPU.Build.0 = Debug|Any CPU + {D6783F96-45F9-488C-8507-9DB2BF0012E2}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU + {D6783F96-45F9-488C-8507-9DB2BF0012E2}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU + {D6783F96-45F9-488C-8507-9DB2BF0012E2}.Debug|x64.ActiveCfg = Debug|Any CPU + {D6783F96-45F9-488C-8507-9DB2BF0012E2}.Debug|x64.Build.0 = Debug|Any CPU + {D6783F96-45F9-488C-8507-9DB2BF0012E2}.Debug|x86.ActiveCfg = Debug|Any CPU + {D6783F96-45F9-488C-8507-9DB2BF0012E2}.Debug|x86.Build.0 = Debug|Any CPU + {D6783F96-45F9-488C-8507-9DB2BF0012E2}.Release|Any CPU.ActiveCfg = Release|Any CPU + {D6783F96-45F9-488C-8507-9DB2BF0012E2}.Release|Any CPU.Build.0 = Release|Any CPU + {D6783F96-45F9-488C-8507-9DB2BF0012E2}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU + {D6783F96-45F9-488C-8507-9DB2BF0012E2}.Release|Mixed Platforms.Build.0 = Release|Any CPU + {D6783F96-45F9-488C-8507-9DB2BF0012E2}.Release|x64.ActiveCfg = Release|Any CPU + {D6783F96-45F9-488C-8507-9DB2BF0012E2}.Release|x64.Build.0 = Release|Any CPU + {D6783F96-45F9-488C-8507-9DB2BF0012E2}.Release|x86.ActiveCfg = Release|Any CPU + {D6783F96-45F9-488C-8507-9DB2BF0012E2}.Release|x86.Build.0 = Release|Any CPU + {C8399060-DEA1-4222-A863-E6F9940D23B0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {C8399060-DEA1-4222-A863-E6F9940D23B0}.Debug|Any CPU.Build.0 = Debug|Any CPU + {C8399060-DEA1-4222-A863-E6F9940D23B0}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU + {C8399060-DEA1-4222-A863-E6F9940D23B0}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU + {C8399060-DEA1-4222-A863-E6F9940D23B0}.Debug|x64.ActiveCfg = Debug|Any CPU + {C8399060-DEA1-4222-A863-E6F9940D23B0}.Debug|x64.Build.0 = Debug|Any CPU + {C8399060-DEA1-4222-A863-E6F9940D23B0}.Debug|x86.ActiveCfg = Debug|Any CPU + {C8399060-DEA1-4222-A863-E6F9940D23B0}.Debug|x86.Build.0 = Debug|Any CPU + {C8399060-DEA1-4222-A863-E6F9940D23B0}.Release|Any CPU.ActiveCfg = Release|Any CPU + {C8399060-DEA1-4222-A863-E6F9940D23B0}.Release|Any CPU.Build.0 = Release|Any CPU + {C8399060-DEA1-4222-A863-E6F9940D23B0}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU + {C8399060-DEA1-4222-A863-E6F9940D23B0}.Release|Mixed Platforms.Build.0 = Release|Any CPU + {C8399060-DEA1-4222-A863-E6F9940D23B0}.Release|x64.ActiveCfg = Release|Any CPU + {C8399060-DEA1-4222-A863-E6F9940D23B0}.Release|x64.Build.0 = Release|Any CPU + {C8399060-DEA1-4222-A863-E6F9940D23B0}.Release|x86.ActiveCfg = Release|Any CPU + {C8399060-DEA1-4222-A863-E6F9940D23B0}.Release|x86.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/Win.MeidaNetEngine/Base/_DebugEx.cs b/SS.MediaNetEngine/Base/_DebugEx.cs similarity index 96% rename from Win.MeidaNetEngine/Base/_DebugEx.cs rename to SS.MediaNetEngine/Base/_DebugEx.cs index 008cebc..1292649 100644 --- a/Win.MeidaNetEngine/Base/_DebugEx.cs +++ b/SS.MediaNetEngine/Base/_DebugEx.cs @@ -1,6 +1,6 @@ using System; using System.Linq; -namespace Win.Comm +namespace SS.Comm { public class _DebugEx { diff --git a/Win.MeidaNetEngine/Media/AAC_ADTS.cs b/SS.MediaNetEngine/Media/AAC_ADTS.cs similarity index 99% rename from Win.MeidaNetEngine/Media/AAC_ADTS.cs rename to SS.MediaNetEngine/Media/AAC_ADTS.cs index ed50d88..82965f8 100644 --- a/Win.MeidaNetEngine/Media/AAC_ADTS.cs +++ b/SS.MediaNetEngine/Media/AAC_ADTS.cs @@ -3,7 +3,7 @@ using System; using System.Collections.Generic; using System.IO; -namespace Win.MediaServer.Media +namespace SS.MediaServer.Media { public class AAC_ADTS { diff --git a/Win.MeidaNetEngine/Media/AVCodecCfg.cs b/SS.MediaNetEngine/Media/AVCodecCfg.cs similarity index 99% rename from Win.MeidaNetEngine/Media/AVCodecCfg.cs rename to SS.MediaNetEngine/Media/AVCodecCfg.cs index 631ca6e..1b7cba2 100644 --- a/Win.MeidaNetEngine/Media/AVCodecCfg.cs +++ b/SS.MediaNetEngine/Media/AVCodecCfg.cs @@ -3,7 +3,7 @@ using System.Collections.Generic; using System.IO; using System.Text; -namespace Win.Media.Codec +namespace SS.Media.Codec { //编码配置基类 diff --git a/Win.MeidaNetEngine/Media/MediaFrame.cs b/SS.MediaNetEngine/Media/MediaFrame.cs similarity index 99% rename from Win.MeidaNetEngine/Media/MediaFrame.cs rename to SS.MediaNetEngine/Media/MediaFrame.cs index 2dd71b2..5369059 100644 --- a/Win.MeidaNetEngine/Media/MediaFrame.cs +++ b/SS.MediaNetEngine/Media/MediaFrame.cs @@ -1,10 +1,10 @@ using GLib.Extension; using GLib.Net; -using Win.Media.Codec; +using SS.Media.Codec; using System; using System.IO; using System.Text; -namespace Win.Media +namespace SS.Media { public enum AVCode { diff --git a/Win.MeidaNetEngine/Media/PATPMT.cs b/SS.MediaNetEngine/Media/PATPMT.cs similarity index 99% rename from Win.MeidaNetEngine/Media/PATPMT.cs rename to SS.MediaNetEngine/Media/PATPMT.cs index cd08f45..5598fa3 100644 --- a/Win.MeidaNetEngine/Media/PATPMT.cs +++ b/SS.MediaNetEngine/Media/PATPMT.cs @@ -5,7 +5,7 @@ using System.Linq; using System.Text; -namespace Win.MediaServer.Media.TS +namespace SS.MediaServer.Media.TS { #region PAT diff --git a/Win.MeidaNetEngine/Media/PES.cs b/SS.MediaNetEngine/Media/PES.cs similarity index 99% rename from Win.MeidaNetEngine/Media/PES.cs rename to SS.MediaNetEngine/Media/PES.cs index 7dffd4b..3a9f948 100644 --- a/Win.MeidaNetEngine/Media/PES.cs +++ b/SS.MediaNetEngine/Media/PES.cs @@ -1,12 +1,12 @@ using GLib.IO; using GLib.Net; -using Win.Media; +using SS.Media; using System; using System.Collections.Generic; using System.IO; using System.Net; -namespace Win.MediaServer.Media.TS +namespace SS.MediaServer.Media.TS { //http://www.360doc.com/content/13/0512/11/532901_284774233.shtml diff --git a/Win.MeidaNetEngine/Media/StreamFileHelper.cs b/SS.MediaNetEngine/Media/StreamFileHelper.cs similarity index 98% rename from Win.MeidaNetEngine/Media/StreamFileHelper.cs rename to SS.MediaNetEngine/Media/StreamFileHelper.cs index 0fd26e2..f60766a 100644 --- a/Win.MeidaNetEngine/Media/StreamFileHelper.cs +++ b/SS.MediaNetEngine/Media/StreamFileHelper.cs @@ -1,10 +1,10 @@ -using Win.Media; +using SS.Media; using System; using System.Collections.Generic; using System.IO; using System.Linq; -namespace Win.MediaServer.Media +namespace SS.MediaServer.Media { public class ReadFile { public static List GetBuffByFile1(string file) { diff --git a/Win.MeidaNetEngine/Media/TS/PSAnalyze.cs b/SS.MediaNetEngine/Media/TS/PSAnalyze.cs similarity index 99% rename from Win.MeidaNetEngine/Media/TS/PSAnalyze.cs rename to SS.MediaNetEngine/Media/TS/PSAnalyze.cs index 6446e34..9c13486 100644 --- a/Win.MeidaNetEngine/Media/TS/PSAnalyze.cs +++ b/SS.MediaNetEngine/Media/TS/PSAnalyze.cs @@ -2,7 +2,7 @@ using GLib.GeneralModel; using GLib.IO; using GLib.Net; -using Win.Media; +using SS.Media; using System; using System.Collections.Generic; using System.IO; @@ -10,7 +10,7 @@ using System.Linq; using System.Net; using System.Threading; -namespace Win.MediaServer.Media.TS +namespace SS.MediaServer.Media.TS { public class HikPSAnalyze : PSAnalyze { @@ -151,7 +151,7 @@ namespace Win.MediaServer.Media.TS } catch (Exception) { - //if (_isWorking && Win.Base.AppConfig._D) + //if (_isWorking && SS.Base.AppConfig._D) //{ // //GLib.DebugEx.WriteLog(e); // throw; diff --git a/Win.MeidaNetEngine/Media/TS/Rtsp/NetSDK.cs b/SS.MediaNetEngine/Media/TS/Rtsp/NetSDK.cs similarity index 95% rename from Win.MeidaNetEngine/Media/TS/Rtsp/NetSDK.cs rename to SS.MediaNetEngine/Media/TS/Rtsp/NetSDK.cs index 2b791c0..357ad14 100644 --- a/Win.MeidaNetEngine/Media/TS/Rtsp/NetSDK.cs +++ b/SS.MediaNetEngine/Media/TS/Rtsp/NetSDK.cs @@ -1,4 +1,4 @@ -namespace Win.MediaServer.Media.TS.Rtsp +namespace SS.MediaServer.Media.TS.Rtsp { using System; using System.Runtime.InteropServices; diff --git a/Win.MeidaNetEngine/Media/TS/Rtsp/StreamDataCallBack.cs b/SS.MediaNetEngine/Media/TS/Rtsp/StreamDataCallBack.cs similarity index 85% rename from Win.MeidaNetEngine/Media/TS/Rtsp/StreamDataCallBack.cs rename to SS.MediaNetEngine/Media/TS/Rtsp/StreamDataCallBack.cs index ada1642..4b9acd1 100644 --- a/Win.MeidaNetEngine/Media/TS/Rtsp/StreamDataCallBack.cs +++ b/SS.MediaNetEngine/Media/TS/Rtsp/StreamDataCallBack.cs @@ -1,4 +1,4 @@ -namespace Win.MediaServer.Media.TS.Rtsp +namespace SS.MediaServer.Media.TS.Rtsp { using System; diff --git a/Win.MeidaNetEngine/Media/TS/TSStreamInput/GB28181TSStreamInput.cs b/SS.MediaNetEngine/Media/TS/TSStreamInput/GB28181TSStreamInput.cs similarity index 96% rename from Win.MeidaNetEngine/Media/TS/TSStreamInput/GB28181TSStreamInput.cs rename to SS.MediaNetEngine/Media/TS/TSStreamInput/GB28181TSStreamInput.cs index b344aaf..ec8c4f9 100644 --- a/Win.MeidaNetEngine/Media/TS/TSStreamInput/GB28181TSStreamInput.cs +++ b/SS.MediaNetEngine/Media/TS/TSStreamInput/GB28181TSStreamInput.cs @@ -1,13 +1,13 @@ using GLib.AXLib.Utility; -using Win.Media; -using Win.MediaServer.Media.TS; +using SS.Media; +using SS.MediaServer.Media.TS; using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; -namespace Win.MeidaNetEngine.Media.TS +namespace SS.MeidaNetEngine.Media.TS { public class GB28181TSStreamInput : TSStreamInput { diff --git a/Win.MeidaNetEngine/Media/TS/TSStreamInput/TSStreamInput.cs b/SS.MediaNetEngine/Media/TS/TSStreamInput/TSStreamInput.cs similarity index 99% rename from Win.MeidaNetEngine/Media/TS/TSStreamInput/TSStreamInput.cs rename to SS.MediaNetEngine/Media/TS/TSStreamInput/TSStreamInput.cs index 0fb16c8..e4b8151 100644 --- a/Win.MeidaNetEngine/Media/TS/TSStreamInput/TSStreamInput.cs +++ b/SS.MediaNetEngine/Media/TS/TSStreamInput/TSStreamInput.cs @@ -1,15 +1,15 @@ using GLib.AXLib.Utility; using GLib.GeneralModel; using GLib.IO; -using Win.Comm; -using Win.Media; +using SS.Comm; +using SS.Media; using System; using System.IO; using System.Linq; using System.Threading; using System.Xml.Serialization; -namespace Win.MediaServer.Media.TS +namespace SS.MediaServer.Media.TS { public class WSIPTVChannelInfo diff --git a/Win.MeidaNetEngine/Media/TS/mp4parser/AspectRatio.cs b/SS.MediaNetEngine/Media/TS/mp4parser/AspectRatio.cs similarity index 100% rename from Win.MeidaNetEngine/Media/TS/mp4parser/AspectRatio.cs rename to SS.MediaNetEngine/Media/TS/mp4parser/AspectRatio.cs diff --git a/Win.MeidaNetEngine/Media/TS/mp4parser/BTree.cs b/SS.MediaNetEngine/Media/TS/mp4parser/BTree.cs similarity index 100% rename from Win.MeidaNetEngine/Media/TS/mp4parser/BTree.cs rename to SS.MediaNetEngine/Media/TS/mp4parser/BTree.cs diff --git a/Win.MeidaNetEngine/Media/TS/mp4parser/BitstreamReader.cs b/SS.MediaNetEngine/Media/TS/mp4parser/BitstreamReader.cs similarity index 100% rename from Win.MeidaNetEngine/Media/TS/mp4parser/BitstreamReader.cs rename to SS.MediaNetEngine/Media/TS/mp4parser/BitstreamReader.cs diff --git a/Win.MeidaNetEngine/Media/TS/mp4parser/BitstreamWriter.cs b/SS.MediaNetEngine/Media/TS/mp4parser/BitstreamWriter.cs similarity index 100% rename from Win.MeidaNetEngine/Media/TS/mp4parser/BitstreamWriter.cs rename to SS.MediaNetEngine/Media/TS/mp4parser/BitstreamWriter.cs diff --git a/Win.MeidaNetEngine/Media/TS/mp4parser/CAVLCReader.cs b/SS.MediaNetEngine/Media/TS/mp4parser/CAVLCReader.cs similarity index 100% rename from Win.MeidaNetEngine/Media/TS/mp4parser/CAVLCReader.cs rename to SS.MediaNetEngine/Media/TS/mp4parser/CAVLCReader.cs diff --git a/Win.MeidaNetEngine/Media/TS/mp4parser/CAVLCWriter.cs b/SS.MediaNetEngine/Media/TS/mp4parser/CAVLCWriter.cs similarity index 100% rename from Win.MeidaNetEngine/Media/TS/mp4parser/CAVLCWriter.cs rename to SS.MediaNetEngine/Media/TS/mp4parser/CAVLCWriter.cs diff --git a/Win.MeidaNetEngine/Media/TS/mp4parser/CharCache.cs b/SS.MediaNetEngine/Media/TS/mp4parser/CharCache.cs similarity index 100% rename from Win.MeidaNetEngine/Media/TS/mp4parser/CharCache.cs rename to SS.MediaNetEngine/Media/TS/mp4parser/CharCache.cs diff --git a/Win.MeidaNetEngine/Media/TS/mp4parser/ChromaFormat.cs b/SS.MediaNetEngine/Media/TS/mp4parser/ChromaFormat.cs similarity index 100% rename from Win.MeidaNetEngine/Media/TS/mp4parser/ChromaFormat.cs rename to SS.MediaNetEngine/Media/TS/mp4parser/ChromaFormat.cs diff --git a/Win.MeidaNetEngine/Media/TS/mp4parser/HRDParameters.cs b/SS.MediaNetEngine/Media/TS/mp4parser/HRDParameters.cs similarity index 100% rename from Win.MeidaNetEngine/Media/TS/mp4parser/HRDParameters.cs rename to SS.MediaNetEngine/Media/TS/mp4parser/HRDParameters.cs diff --git a/Win.MeidaNetEngine/Media/TS/mp4parser/PictureParameterSet.cs b/SS.MediaNetEngine/Media/TS/mp4parser/PictureParameterSet.cs similarity index 100% rename from Win.MeidaNetEngine/Media/TS/mp4parser/PictureParameterSet.cs rename to SS.MediaNetEngine/Media/TS/mp4parser/PictureParameterSet.cs diff --git a/Win.MeidaNetEngine/Media/TS/mp4parser/ScalingList.cs b/SS.MediaNetEngine/Media/TS/mp4parser/ScalingList.cs similarity index 100% rename from Win.MeidaNetEngine/Media/TS/mp4parser/ScalingList.cs rename to SS.MediaNetEngine/Media/TS/mp4parser/ScalingList.cs diff --git a/Win.MeidaNetEngine/Media/TS/mp4parser/ScalingMatrix.cs b/SS.MediaNetEngine/Media/TS/mp4parser/ScalingMatrix.cs similarity index 100% rename from Win.MeidaNetEngine/Media/TS/mp4parser/ScalingMatrix.cs rename to SS.MediaNetEngine/Media/TS/mp4parser/ScalingMatrix.cs diff --git a/Win.MeidaNetEngine/Media/TS/mp4parser/SeqParameterSet.cs b/SS.MediaNetEngine/Media/TS/mp4parser/SeqParameterSet.cs similarity index 100% rename from Win.MeidaNetEngine/Media/TS/mp4parser/SeqParameterSet.cs rename to SS.MediaNetEngine/Media/TS/mp4parser/SeqParameterSet.cs diff --git a/Win.MeidaNetEngine/Media/TS/mp4parser/SliceHeader.cs b/SS.MediaNetEngine/Media/TS/mp4parser/SliceHeader.cs similarity index 100% rename from Win.MeidaNetEngine/Media/TS/mp4parser/SliceHeader.cs rename to SS.MediaNetEngine/Media/TS/mp4parser/SliceHeader.cs diff --git a/Win.MeidaNetEngine/Media/TS/mp4parser/VUIParameters.cs b/SS.MediaNetEngine/Media/TS/mp4parser/VUIParameters.cs similarity index 100% rename from Win.MeidaNetEngine/Media/TS/mp4parser/VUIParameters.cs rename to SS.MediaNetEngine/Media/TS/mp4parser/VUIParameters.cs diff --git a/Win.MeidaNetEngine/Media/TSPacket.cs b/SS.MediaNetEngine/Media/TSPacket.cs similarity index 99% rename from Win.MeidaNetEngine/Media/TSPacket.cs rename to SS.MediaNetEngine/Media/TSPacket.cs index a095916..7258b3c 100644 --- a/Win.MeidaNetEngine/Media/TSPacket.cs +++ b/SS.MediaNetEngine/Media/TSPacket.cs @@ -1,11 +1,11 @@ using GLib.IO; -using Win.Media; +using SS.Media; using System; using System.IO; using System.Text; -namespace Win.MediaServer.Media.TS +namespace SS.MediaServer.Media.TS { //http://www.360doc.com/content/13/0512/11/532901_284774233.shtml diff --git a/Win.MeidaNetEngine/Media/TSProgramManage.cs b/SS.MediaNetEngine/Media/TSProgramManage.cs similarity index 99% rename from Win.MeidaNetEngine/Media/TSProgramManage.cs rename to SS.MediaNetEngine/Media/TSProgramManage.cs index e4d2935..283a880 100644 --- a/Win.MeidaNetEngine/Media/TSProgramManage.cs +++ b/SS.MediaNetEngine/Media/TSProgramManage.cs @@ -2,9 +2,9 @@ using System.Collections.Generic; using System.IO; using System.Linq; -using Win.Media; +using SS.Media; -namespace Win.MediaServer.Media.TS +namespace SS.MediaServer.Media.TS { //http://www.360doc.com/content/13/0512/11/532901_284774233.shtml diff --git a/SS.MediaNetEngine/SS.MediaNetEngine.csproj b/SS.MediaNetEngine/SS.MediaNetEngine.csproj new file mode 100644 index 0000000..7b4b191 --- /dev/null +++ b/SS.MediaNetEngine/SS.MediaNetEngine.csproj @@ -0,0 +1,18 @@ + + + Library + netstandard2.0 + 8.0 + false + SS.MediaNetEngine + SS.MediaNetEngine + true + + + TRACE;DEBUG;NETCOREAPP3_1 + + + + + + \ No newline at end of file diff --git a/SS.VideoConver/Properties/AssemblyInfo.cs b/SS.VideoConver/Properties/AssemblyInfo.cs new file mode 100644 index 0000000..1d2aa92 --- /dev/null +++ b/SS.VideoConver/Properties/AssemblyInfo.cs @@ -0,0 +1,20 @@ +using System.Diagnostics; +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Versioning; + +[assembly: ComVisible(false)] +[assembly: AssemblyFileVersion("1.0.0.0")] +[assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)] +[assembly: AssemblyTrademark("")] +[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] +[assembly: AssemblyCopyright("Copyright © 2012")] +[assembly: Guid("e8d0c7d8-16f2-4e43-95d6-ae6f9c7629f8")] +[assembly: CompilationRelaxations(8)] +[assembly: AssemblyTitle("StarEye.VideoConver")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyProduct("StarEye.VideoConver")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyVersion("1.0.0.0")] diff --git a/SS.VideoConver/QuickAudioEncodingCommands.cs b/SS.VideoConver/QuickAudioEncodingCommands.cs new file mode 100644 index 0000000..add0be4 --- /dev/null +++ b/SS.VideoConver/QuickAudioEncodingCommands.cs @@ -0,0 +1,10 @@ +public class QuickAudioEncodingCommands +{ + public static string MP3128Kbps = "-y -ab 128k -ar 44100"; + + public static string MP396Kbps = "-y -ab 96k -ar 44100"; + + public static string MP364Kbps = "-y -ab 64k -ar 44100"; + + public static string MP332Kbps = "-y -ab 32k -ar 44100"; +} diff --git a/SS.VideoConver/SS.VideoConver.csproj b/SS.VideoConver/SS.VideoConver.csproj new file mode 100644 index 0000000..c758d09 --- /dev/null +++ b/SS.VideoConver/SS.VideoConver.csproj @@ -0,0 +1,11 @@ + + + netstandard2.0 + false + SS.VideoConver + SS.VideoConver + + + TRACE;DEBUG;NETCOREAPP3_1 + + diff --git a/SS.VideoConver/StarEye.VideoConver.sln b/SS.VideoConver/StarEye.VideoConver.sln new file mode 100644 index 0000000..3dbe32f --- /dev/null +++ b/SS.VideoConver/StarEye.VideoConver.sln @@ -0,0 +1,25 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 16 +VisualStudioVersion = 16.0.29806.167 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "StarEye.VideoConver", "StarEye.VideoConver.csproj", "{D6783F96-45F9-488C-8507-9DB2BF0012E2}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|x86 = Debug|x86 + Release|x86 = Release|x86 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {D6783F96-45F9-488C-8507-9DB2BF0012E2}.Debug|x86.ActiveCfg = Debug|x86 + {D6783F96-45F9-488C-8507-9DB2BF0012E2}.Debug|x86.Build.0 = Debug|x86 + {D6783F96-45F9-488C-8507-9DB2BF0012E2}.Release|x86.ActiveCfg = Release|x86 + {D6783F96-45F9-488C-8507-9DB2BF0012E2}.Release|x86.Build.0 = Release|x86 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {F24FB382-B4DD-476E-AEA0-2605E8F0E016} + EndGlobalSection +EndGlobal diff --git a/SS.VideoConver/VideoEncoder/EncodedVideo.cs b/SS.VideoConver/VideoEncoder/EncodedVideo.cs new file mode 100644 index 0000000..50fc3d3 --- /dev/null +++ b/SS.VideoConver/VideoEncoder/EncodedVideo.cs @@ -0,0 +1,29 @@ +namespace VideoEncoder +{ + public class EncodedVideo + { + public string EncodedVideoPath + { + get; + set; + } + + public string ThumbnailPath + { + get; + set; + } + + public string EncodingLog + { + get; + set; + } + + public bool Success + { + get; + set; + } + } +} diff --git a/SS.VideoConver/VideoEncoder/Encoder.cs b/SS.VideoConver/VideoEncoder/Encoder.cs new file mode 100644 index 0000000..ac014b5 --- /dev/null +++ b/SS.VideoConver/VideoEncoder/Encoder.cs @@ -0,0 +1,211 @@ +using System; +using System.Diagnostics; +using System.IO; +using System.Text.RegularExpressions; + +namespace VideoEncoder +{ + public class Encoder + { + public string FFmpegPath + { + get; + set; + } + + private string Params + { + get; + set; + } + + public EncodedVideo EncodeVideo(VideoFile input, string encodingCommand, string outputFile, bool getVideoThumbnail) + { + EncodedVideo encodedVideo = new EncodedVideo(); + Params = $"-i {input.File} {encodingCommand} {outputFile}"; + string text2 = encodedVideo.EncodingLog = RunProcess(Params); + encodedVideo.EncodedVideoPath = outputFile; + if (File.Exists(outputFile)) + { + encodedVideo.Success = true; + if (getVideoThumbnail) + { + string text3 = outputFile + "_thumb.jpg"; + if (GetVideoThumbnail(input, text3)) + { + encodedVideo.ThumbnailPath = text3; + } + } + } + else + { + encodedVideo.Success = false; + } + return encodedVideo; + } + + public bool GetVideoThumbnail(VideoFile input, string saveThumbnailTo) + { + if (!input.infoGathered) + { + GetVideoInfo(input); + } + int num = (int)Math.Round(TimeSpan.FromTicks(input.Duration.Ticks / 3).TotalSeconds, 0); + string parameters = $"-i {input.File} {saveThumbnailTo} -vcodec mjpeg -ss {num} -vframes 1 -an -f rawvideo"; + string text = RunProcess(parameters); + if (File.Exists(saveThumbnailTo)) + { + return true; + } + parameters = $"-i {input.File} {saveThumbnailTo} -vcodec mjpeg -ss {1} -vframes 1 -an -f rawvideo"; + text = RunProcess(parameters); + if (File.Exists(saveThumbnailTo)) + { + return true; + } + return false; + } + + public void GetVideoInfo(VideoFile input) + { + string parameters = $"-i {input.File}"; + string text2 = input.RawInfo = RunProcess(parameters); + input.Duration = ExtractDuration(input.RawInfo); + input.BitRate = ExtractBitrate(input.RawInfo); + input.RawAudioFormat = ExtractRawAudioFormat(input.RawInfo); + input.AudioFormat = ExtractAudioFormat(input.RawAudioFormat); + input.RawVideoFormat = ExtractRawVideoFormat(input.RawInfo); + input.VideoFormat = ExtractVideoFormat(input.RawVideoFormat); + input.Width = ExtractVideoWidth(input.RawInfo); + input.Height = ExtractVideoHeight(input.RawInfo); + input.infoGathered = true; + } + + private string RunProcess(string Parameters) + { + ProcessStartInfo processStartInfo = new ProcessStartInfo(FFmpegPath, Parameters); + processStartInfo.UseShellExecute = false; + processStartInfo.CreateNoWindow = true; + processStartInfo.RedirectStandardOutput = true; + processStartInfo.RedirectStandardError = true; + string result = null; + StreamReader streamReader = null; + try + { + Process process = Process.Start(processStartInfo); + process.WaitForExit(); + streamReader = process.StandardError; + result = streamReader.ReadToEnd(); + process.Close(); + } + catch (Exception) + { + result = string.Empty; + } + finally + { + if (streamReader != null) + { + streamReader.Close(); + streamReader.Dispose(); + } + } + return result; + } + + private TimeSpan ExtractDuration(string rawInfo) + { + TimeSpan result = new TimeSpan(0L); + Regex regex = new Regex("[D|d]uration:.((\\d|:|\\.)*)", RegexOptions.Compiled); + Match match = regex.Match(rawInfo); + if (match.Success) + { + string value = match.Groups[1].Value; + string[] array = value.Split(':', '.'); + if (array.Length == 4) + { + result = new TimeSpan(0, Convert.ToInt16(array[0]), Convert.ToInt16(array[1]), Convert.ToInt16(array[2]), Convert.ToInt16(array[3])); + } + } + return result; + } + + private double ExtractBitrate(string rawInfo) + { + Regex regex = new Regex("[B|b]itrate:.((\\d|:)*)", RegexOptions.Compiled); + Match match = regex.Match(rawInfo); + double result = 0.0; + if (match.Success) + { + double.TryParse(match.Groups[1].Value, out result); + } + return result; + } + + private string ExtractRawAudioFormat(string rawInfo) + { + string text = string.Empty; + Regex regex = new Regex("[A|a]udio:.*", RegexOptions.Compiled); + Match match = regex.Match(rawInfo); + if (match.Success) + { + text = match.Value; + } + return text.Replace("Audio: ", ""); + } + + private string ExtractAudioFormat(string rawAudioFormat) + { + string[] array = rawAudioFormat.Split(new string[1] + { + ", " + }, StringSplitOptions.None); + return array[0].Replace("Audio: ", ""); + } + + private string ExtractRawVideoFormat(string rawInfo) + { + string text = string.Empty; + Regex regex = new Regex("[V|v]ideo:.*", RegexOptions.Compiled); + Match match = regex.Match(rawInfo); + if (match.Success) + { + text = match.Value; + } + return text.Replace("Video: ", ""); + } + + private string ExtractVideoFormat(string rawVideoFormat) + { + string[] array = rawVideoFormat.Split(new string[1] + { + ", " + }, StringSplitOptions.None); + return array[0].Replace("Video: ", ""); + } + + private int ExtractVideoWidth(string rawInfo) + { + int result = 0; + Regex regex = new Regex("(\\d{2,4})x(\\d{2,4})", RegexOptions.Compiled); + Match match = regex.Match(rawInfo); + if (match.Success) + { + int.TryParse(match.Groups[1].Value, out result); + } + return result; + } + + private int ExtractVideoHeight(string rawInfo) + { + int result = 0; + Regex regex = new Regex("(\\d{2,4})x(\\d{2,4})", RegexOptions.Compiled); + Match match = regex.Match(rawInfo); + if (match.Success) + { + int.TryParse(match.Groups[2].Value, out result); + } + return result; + } + } +} diff --git a/SS.VideoConver/VideoEncoder/QuickVideoEncodingCommands.cs b/SS.VideoConver/VideoEncoder/QuickVideoEncodingCommands.cs new file mode 100644 index 0000000..78351ee --- /dev/null +++ b/SS.VideoConver/VideoEncoder/QuickVideoEncodingCommands.cs @@ -0,0 +1,91 @@ +namespace VideoEncoder +{ + public class QuickVideoEncodingCommands + { + private static string LQVideoBitrate = "256k"; + + private static string MQVideoBitrate = "512k"; + + private static string HQVideoBitrate = "756k"; + + private static string VHQVideoBitrate = "1024k"; + + private static string LQAudioBitrate = "32k"; + + private static string MQAudioBitrate = "64k"; + + private static string HQAudioBitrate = "96k"; + + private static string VHQAudioBitrate = "128k"; + + private static string LQAudioSamplingFrequency = "22050"; + + private static string MQAudioSamplingFrequency = "44100"; + + private static string HQAudioSamplingFrequency = "44100"; + + private static string SQCIF = "sqcif"; + + private static string QCIF = "qcif"; + + private static string QVGA = "qvga"; + + private static string CIF = "cif"; + + private static string VGA = "vga"; + + private static string SVGA = "svga"; + + private static string N43 = "480x360"; + + public static string FLVLowQualityQCIF = $"-y -b {LQVideoBitrate} -ab {LQAudioBitrate} -ar {LQAudioSamplingFrequency} -s {QVGA} -f flv"; + + public static string FLVMediumQualityCIF = $"-y -b {MQVideoBitrate} -ab {MQAudioBitrate} -ar {MQAudioSamplingFrequency} -s {CIF} -f flv"; + + public static string FLVHighQualityVGA = $"-y -b {HQVideoBitrate} -ab {HQAudioBitrate} -ar {HQAudioSamplingFrequency} -s {VGA} -f flv"; + + public static string FLVVeryHighQualitySVGA = $"-y -b {VHQVideoBitrate} -ab {VHQAudioBitrate} -ar {HQAudioSamplingFrequency} -s {SVGA} -f flv"; + + public static string FLVLowQualityKeepOriginalSize = string.Format("-y -b {0} -ab {1} -ar {2} -f flv", LQVideoBitrate, LQAudioBitrate, LQAudioSamplingFrequency, QVGA); + + public static string FLVMediumQualityKeepOriginalSize = string.Format("-y -b {0} -ab {1} -ar {2} -f flv", MQVideoBitrate, MQAudioBitrate, MQAudioSamplingFrequency, CIF); + + public static string FLVHighQualityKeepOriginalSize = string.Format("-y -b {0} -ab {1} -ar {2} -f flv", HQVideoBitrate, HQAudioBitrate, HQAudioSamplingFrequency, VGA); + + public static string FLVVeryHighQualityKeepOriginalSize = string.Format("-y -b {0} -ab {1} -ar {2} -f flv", VHQVideoBitrate, VHQAudioBitrate, HQAudioSamplingFrequency, SVGA); + + public static string THREEGPLowQualitySQCIF = $"-y -acodec aac -ac 1 -b {LQVideoBitrate} -ab {LQAudioBitrate} -ar {LQAudioSamplingFrequency} -s {SQCIF} -f 3gp"; + + public static string THREEGPMediumQualityQCIF = $"-y -acodec aac -b {MQVideoBitrate} -ab {MQAudioBitrate} -ar {MQAudioSamplingFrequency} -s {QCIF} -f 3gp"; + + public static string THREEGPHighQualityCIF = $"-y -acodec aac -b {VHQVideoBitrate} -ab {VHQAudioBitrate} -ar {HQAudioSamplingFrequency} -s {CIF} -f 3gp"; + + public static string MP4LowQualityKeepOriginalSize = string.Format("-y -b {0} -ab {1} -ar {2} -f mp4", LQVideoBitrate, LQAudioBitrate, LQAudioSamplingFrequency, QVGA); + + public static string MP4MediumQualityKeepOriginalSize = string.Format("-y -b {0} -ab {1} -ar {2} -f mp4", MQVideoBitrate, MQAudioBitrate, MQAudioSamplingFrequency, CIF); + + public static string MP4HighQualityKeepOriginalSize = string.Format("-y -b {0} -ab {1} -ar {2} -f mp4", HQVideoBitrate, HQAudioBitrate, HQAudioSamplingFrequency, VGA); + + public static string MP4LowQualityQVGA = $"-y -b {LQVideoBitrate} -ab {LQAudioBitrate} -ar {LQAudioSamplingFrequency} -s {QVGA} -f mp4"; + + public static string MP4MediumQualityCIF = $"-y -b {MQVideoBitrate} -ab {MQAudioBitrate} -ar {MQAudioSamplingFrequency} -s {CIF} -f mp4"; + + public static string MP4HighQualityVGA = $"-y -b {HQVideoBitrate} -ab {HQAudioBitrate} -ar {HQAudioSamplingFrequency} -s {VGA} -f mp4"; + + public static string WMVLowQualityQVGA = $"-y -vcodec wmv2 -acodec wmav2 -b {LQVideoBitrate} -ab {LQAudioBitrate} -ar {LQAudioSamplingFrequency} -s {QVGA}"; + + public static string WMVMediumQualityCIF = $"-y -vcodec wmv2 -acodec wmav2 -b {MQVideoBitrate} -ab {MQAudioBitrate} -ar {MQAudioSamplingFrequency} -s {CIF}"; + + public static string WMVHighQualityVGA = $"-y -vcodec wmv2 -acodec wmav2 -b {HQVideoBitrate} -ab {HQAudioBitrate} -ar {HQAudioSamplingFrequency} -s {VGA}"; + + public static string WMVVeryHighQualitySVGA = $"-y -vcodec wmv2 -acodec wmav2 -b {VHQVideoBitrate} -ab {VHQAudioBitrate} -ar {HQAudioSamplingFrequency} -s {SVGA}"; + + public static string WMVLowQualityKeepOriginalSize = string.Format("-y -vcodec wmv2 -acodec wmav2 -b {0} -ab {1} -ar {2}", LQVideoBitrate, LQAudioBitrate, LQAudioSamplingFrequency, QVGA); + + public static string WMVMediumQualityKeepOriginalSize = string.Format("-y -vcodec wmv2 -acodec wmav2 -b {0} -ab {1} -ar {2}", MQVideoBitrate, MQAudioBitrate, MQAudioSamplingFrequency, CIF); + + public static string WMVHighQualityKeepOriginalSize = string.Format("-y -vcodec wmv2 -acodec wmav2 -b {0} -ab {1} -ar {2}", HQVideoBitrate, HQAudioBitrate, HQAudioSamplingFrequency, VGA); + + public static string WMVVeryHighQualityKeepOriginalSize = string.Format("-y -vcodec wmv2 -acodec wmav2 -b {0} -ab {1} -ar {2}", VHQVideoBitrate, VHQAudioBitrate, HQAudioSamplingFrequency, SVGA); + } +} diff --git a/SS.VideoConver/VideoEncoder/VideoFile.cs b/SS.VideoConver/VideoEncoder/VideoFile.cs new file mode 100644 index 0000000..b17d4dd --- /dev/null +++ b/SS.VideoConver/VideoEncoder/VideoFile.cs @@ -0,0 +1,106 @@ +using System; +using System.IO; + +namespace VideoEncoder +{ + public class VideoFile + { + private string _File; + + public string File + { + get + { + return _File; + } + set + { + _File = value; + } + } + + public TimeSpan Duration + { + get; + set; + } + + public double BitRate + { + get; + set; + } + + public string RawAudioFormat + { + get; + set; + } + + public string AudioFormat + { + get; + set; + } + + public string RawVideoFormat + { + get; + set; + } + + public string VideoFormat + { + get; + set; + } + + public int Height + { + get; + set; + } + + public int Width + { + get; + set; + } + + public string RawInfo + { + get; + set; + } + + public bool infoGathered + { + get; + set; + } + + public VideoFile(string path) + { + _File = path; + Initialize(); + } + + private void Initialize() + { + infoGathered = false; + if (string.IsNullOrEmpty(_File)) + { + throw new Exception("Video file Path not set or empty."); + } + if (!System.IO.File.Exists(_File)) + { + throw new Exception("The video file " + _File + " does not exist."); + } + } + + public override string ToString() + { + return $"w*h:{Width}*{Height}, time:{Duration}, format:{VideoFormat}, raw:{RawVideoFormat}, "; + } + } +} diff --git a/SS.VideoConver/VideoThumbnail/Program.cs b/SS.VideoConver/VideoThumbnail/Program.cs new file mode 100644 index 0000000..da6c06e --- /dev/null +++ b/SS.VideoConver/VideoThumbnail/Program.cs @@ -0,0 +1,133 @@ +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.IO; +using System.Text; +using System.Threading; +using System.Threading.Tasks; +using videoconver; +using VideoEncoder; + +namespace VideoThumbnail +{ + public class Thumbnail + { + private const string Thumbnails_cmd_format = " -y -i {0} -f image2 -ss {1}.001 -s 240x180 {2}"; + + private const string ffmpeg_param_format = " -y -i {0} {1}"; + + private static string ffmpeg = "ffmpeg.exe"; + + private static List ProcessList = new List(); + + public static event Action OnProcessData; + + public static event Action Trace; + + + public static void CreateThumbnails(string iFile, string oFile) + { + VideoFile videoInfo = GetVideoInfo(iFile); + CreateThumbnails(iFile, oFile, (int)videoInfo.Duration.TotalSeconds / 2); + } + + public static void CreateThumbnails(string iFile, string oFile, int time) + { + VideoFile videoInfo = GetVideoInfo(iFile); + oFile = ShellPathNameConvert.ToShortPathName(Path.GetDirectoryName(oFile)) + "\\" + Path.GetFileName(oFile); + iFile = ShellPathNameConvert.ToShortPathName(iFile); + var num = videoInfo.Duration.TotalSeconds / 2.0; + if (num > 8.0) + { + num = 8.0; + } + var arguments = string.Format(" -y -i {0} -f image2 -ss {2}.001 -s 240x180 {1}", iFile, oFile, time); + var p = CreateProcess(ffmpeg, arguments); + RunProcess(p); + } + + public static void RunProcess(Process p) + { + DateTime dt = DateTime.Now; + try + { + ProcessList.Add(p); + p.Start(); + p.BeginOutputReadLine(); + p.BeginErrorReadLine(); + DataReceivedEventHandler value = delegate(object sender, DataReceivedEventArgs e) + { + dt = DateTime.Now; + OnProcessData?.Invoke(e.Data); + }; + p.ErrorDataReceived += value; + p.OutputDataReceived += value; + Task task = new Task(delegate + { + p.WaitForExit(); + }); + task.Start(); + do + { + Thread.Sleep(100); + } + while (dt.AddMinutes(1.0) > DateTime.Now && !task.IsCompleted && !task.IsFaulted && !task.IsCanceled); + p.ErrorDataReceived -= value; + p.OutputDataReceived -= value; + p.CancelOutputRead(); + p.CancelErrorRead(); + if (!p.HasExited) + { + p.Kill(); + } + p.Close(); + p.Dispose(); + ProcessList.Remove(p); + } + catch + { + p.Dispose(); + throw; + } + } + + public static VideoFile GetVideoInfo(string iFile) + { + VideoEncoder.Encoder encoder = new VideoEncoder.Encoder(); + encoder.FFmpegPath = ffmpeg; + VideoFile videoFile = new VideoFile(iFile); + encoder.GetVideoInfo(videoFile); + TimeSpan duration = videoFile.Duration; + StringBuilder stringBuilder = new StringBuilder(); + string arg = $"{(int)duration.TotalHours:00}:{duration.Minutes:00}:{duration.Seconds:00}"; + stringBuilder.AppendFormat("时间长度:{0}\n", arg); + stringBuilder.AppendFormat("高度:{0}\n", videoFile.Height); + stringBuilder.AppendFormat("宽度:{0}\n", videoFile.Width); + stringBuilder.AppendFormat("数据格式:{0}\n", videoFile.VideoFormat); + stringBuilder.AppendFormat("比特率:{0}\n", videoFile.BitRate); + stringBuilder.AppendFormat("文件路径:{0}\n", videoFile.File); + return videoFile; + } + + public static Process CreateProcess(string exe, string arguments) + { + string text = $"{exe} {arguments}"; + Process process = new Process(); + process.StartInfo.WindowStyle = ProcessWindowStyle.Normal; + process.StartInfo.FileName = exe; + process.StartInfo.Arguments = arguments; + process.StartInfo.UseShellExecute = false; + process.StartInfo.RedirectStandardError = true; + process.StartInfo.RedirectStandardOutput = true; + process.StartInfo.CreateNoWindow = true; + return process; + } + + public static void MP42TS(string mp4, string ts) + { + string arguments = $" -y -i {mp4} -codec copy -bsf h264_mp4toannexb {ts}"; + Process p = CreateProcess(ffmpeg, arguments); + RunProcess(p); + } + } +} diff --git a/SS.VideoConver/videoconver/ShellPathNameConvert.cs b/SS.VideoConver/videoconver/ShellPathNameConvert.cs new file mode 100644 index 0000000..6f3ef29 --- /dev/null +++ b/SS.VideoConver/videoconver/ShellPathNameConvert.cs @@ -0,0 +1,33 @@ +using System.Runtime.InteropServices; +using System.Text; + +namespace videoconver +{ + public class ShellPathNameConvert + { + [DllImport("kernel32.dll", CharSet = CharSet.Unicode)] + private static extern uint GetLongPathName(string shortname, StringBuilder longnamebuff, uint buffersize); + + [DllImport("kernel32.dll", CharSet = CharSet.Auto)] + private static extern int GetShortPathName([MarshalAs(UnmanagedType.LPWStr)] string path, [MarshalAs(UnmanagedType.LPWStr)] StringBuilder shortPath, int shortPathLength); + + public static string ToLongPathName(string shortName) + { + StringBuilder stringBuilder = new StringBuilder(256); + uint capacity = (uint)stringBuilder.Capacity; + GetLongPathName(shortName, stringBuilder, capacity); + return stringBuilder.ToString(); + } + + public static string ToShortPathName(string longName) + { + StringBuilder stringBuilder = new StringBuilder(256); + int capacity = stringBuilder.Capacity; + if (GetShortPathName(longName, stringBuilder, capacity) == 0) + { + return longName; + } + return stringBuilder.ToString(); + } + } +} diff --git a/Test.GB28181.Service/Test.GB28181.Service.csproj b/Test.GB28181.Service/Test.GB28181.Service.csproj index eb53ae5..9061b5a 100644 --- a/Test.GB28181.Service/Test.GB28181.Service.csproj +++ b/Test.GB28181.Service/Test.GB28181.Service.csproj @@ -20,6 +20,7 @@ + diff --git a/Test.GB28181.Service/TestVideoThubnail.cs b/Test.GB28181.Service/TestVideoThubnail.cs new file mode 100644 index 0000000..8c1143a --- /dev/null +++ b/Test.GB28181.Service/TestVideoThubnail.cs @@ -0,0 +1,140 @@ +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.IO; +using System.Text; +using System.Threading; +using System.Threading.Tasks; +using videoconver; +using VideoEncoder; +using Xunit; + +namespace Test.VideoThumbnail +{ + public class TestVideoThubnail + { + private const string Thumbnails_cmd_format = " -y -i {0} -f image2 -ss {1}.001 -s 240x180 {2}"; + + private const string ffmpeg_param_format = " -y -i {0} {1}"; + + private static string ffmpeg = "ffmpeg.exe"; + + private static List ProcessList = new List(); + + public static event Action OnProcessData; + + public static event Action Trace; + + [Fact] + public void Test() + { + VideoFile videoInfo = GetVideoInfo("record\\tmp4.mp4"); + CreateThumbnails("record\\tmp4.mp4", "record\\abc.jpg"); + } + + static void CreateThumbnails(string iFile, string oFile) + { + VideoFile videoInfo = GetVideoInfo(iFile); + CreateThumbnails(iFile, oFile, (int)videoInfo.Duration.TotalSeconds / 2); + } + + static void CreateThumbnails(string iFile, string oFile, int time) + { + VideoFile videoInfo = GetVideoInfo(iFile); + oFile = ShellPathNameConvert.ToShortPathName(Path.GetDirectoryName(oFile)) + "\\" + Path.GetFileName(oFile); + iFile = ShellPathNameConvert.ToShortPathName(iFile); + double num = videoInfo.Duration.TotalSeconds / 2.0; + if (num > 8.0) + { + num = 8.0; + } + string arguments = string.Format(" -y -i {0} -f image2 -ss {2}.001 -s 240x180 {1}", iFile, oFile, time); + Process p = CreateProcess(ffmpeg, arguments); + RunProcess(p); + } + + static void RunProcess(Process p) + { + DateTime dt = DateTime.Now; + try + { + ProcessList.Add(p); + p.Start(); + p.BeginOutputReadLine(); + p.BeginErrorReadLine(); + DataReceivedEventHandler value = delegate (object sender, DataReceivedEventArgs e) + { + dt = DateTime.Now; + OnProcessData?.Invoke(e.Data); + }; + p.ErrorDataReceived += value; + p.OutputDataReceived += value; + Task task = new Task(delegate + { + p.WaitForExit(); + }); + task.Start(); + do + { + Thread.Sleep(100); + } + while (dt.AddMinutes(1.0) > DateTime.Now && !task.IsCompleted && !task.IsFaulted && !task.IsCanceled); + p.ErrorDataReceived -= value; + p.OutputDataReceived -= value; + p.CancelOutputRead(); + p.CancelErrorRead(); + if (!p.HasExited) + { + p.Kill(); + } + p.Close(); + p.Dispose(); + ProcessList.Remove(p); + } + catch + { + p.Dispose(); + throw; + } + } + + static VideoFile GetVideoInfo(string iFile) + { + VideoEncoder.Encoder encoder = new VideoEncoder.Encoder(); + encoder.FFmpegPath = ffmpeg; + VideoFile videoFile = new VideoFile(iFile); + encoder.GetVideoInfo(videoFile); + TimeSpan duration = videoFile.Duration; + StringBuilder stringBuilder = new StringBuilder(); + string arg = $"{(int)duration.TotalHours:00}:{duration.Minutes:00}:{duration.Seconds:00}"; + stringBuilder.AppendFormat("时间长度:{0}\n", arg); + stringBuilder.AppendFormat("高度:{0}\n", videoFile.Height); + stringBuilder.AppendFormat("宽度:{0}\n", videoFile.Width); + stringBuilder.AppendFormat("数据格式:{0}\n", videoFile.VideoFormat); + stringBuilder.AppendFormat("比特率:{0}\n", videoFile.BitRate); + stringBuilder.AppendFormat("文件路径:{0}\n", videoFile.File); + return videoFile; + } + + static Process CreateProcess(string exe, string arguments) + { + string text = $"{exe} {arguments}"; + Process process = new Process(); + process.StartInfo.WindowStyle = ProcessWindowStyle.Normal; + process.StartInfo.FileName = exe; + process.StartInfo.Arguments = arguments; + process.StartInfo.UseShellExecute = false; + process.StartInfo.RedirectStandardError = true; + process.StartInfo.RedirectStandardOutput = true; + process.StartInfo.CreateNoWindow = true; + return process; + } + + public static void MP42TS(string mp4, string ts) + { + string arguments = $" -y -i {mp4} -codec copy -bsf h264_mp4toannexb {ts}"; + Process p = CreateProcess(ffmpeg, arguments); + RunProcess(p); + } + } +} diff --git a/Win.GB28181.Client/Form1.Designer.cs b/Win.GB28181.Client/Form1.Designer.cs index 5bff8eb..215e0f2 100644 --- a/Win.GB28181.Client/Form1.Designer.cs +++ b/Win.GB28181.Client/Form1.Designer.cs @@ -165,19 +165,21 @@ // // btnStart // - this.btnStart.Location = new System.Drawing.Point(6, 7); + this.btnStart.Location = new System.Drawing.Point(8, 9); + this.btnStart.Margin = new System.Windows.Forms.Padding(4, 4, 4, 4); this.btnStart.Name = "btnStart"; - this.btnStart.Size = new System.Drawing.Size(75, 23); + this.btnStart.Size = new System.Drawing.Size(100, 29); this.btnStart.TabIndex = 0; this.btnStart.Text = "启动"; this.btnStart.UseVisualStyleBackColor = true; - this.btnStart.Click += new System.EventHandler(this.BtnStart_Click); + this.btnStart.Click += new System.EventHandler(this.btnStart_Click); // // btnStop // - this.btnStop.Location = new System.Drawing.Point(93, 7); + this.btnStop.Location = new System.Drawing.Point(124, 9); + this.btnStop.Margin = new System.Windows.Forms.Padding(4, 4, 4, 4); this.btnStop.Name = "btnStop"; - this.btnStop.Size = new System.Drawing.Size(75, 23); + this.btnStop.Size = new System.Drawing.Size(100, 29); this.btnStop.TabIndex = 1; this.btnStop.Text = "停止"; this.btnStop.UseVisualStyleBackColor = true; @@ -187,17 +189,19 @@ // this.lblStatus.AutoSize = true; this.lblStatus.ForeColor = System.Drawing.Color.Red; - this.lblStatus.Location = new System.Drawing.Point(179, 13); + this.lblStatus.Location = new System.Drawing.Point(239, 16); + this.lblStatus.Margin = new System.Windows.Forms.Padding(4, 0, 4, 0); this.lblStatus.Name = "lblStatus"; - this.lblStatus.Size = new System.Drawing.Size(77, 12); + this.lblStatus.Size = new System.Drawing.Size(97, 15); this.lblStatus.TabIndex = 2; this.lblStatus.Text = "等待中。。。"; // // btnCatalogSearch // - this.btnCatalogSearch.Location = new System.Drawing.Point(709, 54); + this.btnCatalogSearch.Location = new System.Drawing.Point(945, 68); + this.btnCatalogSearch.Margin = new System.Windows.Forms.Padding(4, 4, 4, 4); this.btnCatalogSearch.Name = "btnCatalogSearch"; - this.btnCatalogSearch.Size = new System.Drawing.Size(75, 23); + this.btnCatalogSearch.Size = new System.Drawing.Size(100, 29); this.btnCatalogSearch.TabIndex = 3; this.btnCatalogSearch.Text = "目录查询"; this.btnCatalogSearch.UseVisualStyleBackColor = true; @@ -205,9 +209,10 @@ // // btnReal // - this.btnReal.Location = new System.Drawing.Point(6, 18); + this.btnReal.Location = new System.Drawing.Point(8, 22); + this.btnReal.Margin = new System.Windows.Forms.Padding(4, 4, 4, 4); this.btnReal.Name = "btnReal"; - this.btnReal.Size = new System.Drawing.Size(75, 23); + this.btnReal.Size = new System.Drawing.Size(100, 29); this.btnReal.TabIndex = 8; this.btnReal.Text = "直播视频"; this.btnReal.UseVisualStyleBackColor = true; @@ -215,9 +220,10 @@ // // btnBye // - this.btnBye.Location = new System.Drawing.Point(6, 47); + this.btnBye.Location = new System.Drawing.Point(8, 59); + this.btnBye.Margin = new System.Windows.Forms.Padding(4, 4, 4, 4); this.btnBye.Name = "btnBye"; - this.btnBye.Size = new System.Drawing.Size(75, 23); + this.btnBye.Size = new System.Drawing.Size(100, 29); this.btnBye.TabIndex = 10; this.btnBye.Text = "终止直播"; this.btnBye.UseVisualStyleBackColor = true; @@ -231,10 +237,11 @@ this.devState}); this.lvDev.FullRowSelect = true; this.lvDev.HideSelection = false; - this.lvDev.Location = new System.Drawing.Point(348, 54); + this.lvDev.Location = new System.Drawing.Point(464, 68); + this.lvDev.Margin = new System.Windows.Forms.Padding(4, 4, 4, 4); this.lvDev.MultiSelect = false; this.lvDev.Name = "lvDev"; - this.lvDev.Size = new System.Drawing.Size(355, 203); + this.lvDev.Size = new System.Drawing.Size(472, 253); this.lvDev.TabIndex = 11; this.lvDev.UseCompatibleStateImageBehavior = false; this.lvDev.View = System.Windows.Forms.View.Details; @@ -254,65 +261,72 @@ // // btnRecord // - this.btnRecord.Location = new System.Drawing.Point(12, 145); + this.btnRecord.Location = new System.Drawing.Point(16, 181); + this.btnRecord.Margin = new System.Windows.Forms.Padding(4, 4, 4, 4); this.btnRecord.Name = "btnRecord"; - this.btnRecord.Size = new System.Drawing.Size(68, 23); + this.btnRecord.Size = new System.Drawing.Size(91, 29); this.btnRecord.TabIndex = 12; this.btnRecord.Text = "录像点播"; this.btnRecord.UseVisualStyleBackColor = true; - this.btnRecord.Click += new System.EventHandler(this.BtnRecord_Click); + this.btnRecord.Click += new System.EventHandler(this.btnRecord_Click); // // btnStopRecord // - this.btnStopRecord.Location = new System.Drawing.Point(95, 145); + this.btnStopRecord.Location = new System.Drawing.Point(127, 181); + this.btnStopRecord.Margin = new System.Windows.Forms.Padding(4, 4, 4, 4); this.btnStopRecord.Name = "btnStopRecord"; - this.btnStopRecord.Size = new System.Drawing.Size(68, 23); + this.btnStopRecord.Size = new System.Drawing.Size(91, 29); this.btnStopRecord.TabIndex = 13; this.btnStopRecord.Text = "终止点播"; this.btnStopRecord.UseVisualStyleBackColor = true; - this.btnStopRecord.Click += new System.EventHandler(this.BtnStopRecord_Click); + this.btnStopRecord.Click += new System.EventHandler(this.btnStopRecord_Click); // // txtStartTime // - this.txtStartTime.Location = new System.Drawing.Point(69, 6); + this.txtStartTime.Location = new System.Drawing.Point(92, 8); + this.txtStartTime.Margin = new System.Windows.Forms.Padding(4, 4, 4, 4); this.txtStartTime.Name = "txtStartTime"; - this.txtStartTime.Size = new System.Drawing.Size(125, 21); + this.txtStartTime.Size = new System.Drawing.Size(165, 25); this.txtStartTime.TabIndex = 14; // // txtStopTime // - this.txtStopTime.Location = new System.Drawing.Point(69, 33); + this.txtStopTime.Location = new System.Drawing.Point(92, 41); + this.txtStopTime.Margin = new System.Windows.Forms.Padding(4, 4, 4, 4); this.txtStopTime.Name = "txtStopTime"; - this.txtStopTime.Size = new System.Drawing.Size(125, 21); + this.txtStopTime.Size = new System.Drawing.Size(165, 25); this.txtStopTime.TabIndex = 15; // // label2 // this.label2.AutoSize = true; - this.label2.Location = new System.Drawing.Point(493, 63); + this.label2.Location = new System.Drawing.Point(657, 79); + this.label2.Margin = new System.Windows.Forms.Padding(4, 0, 4, 0); this.label2.Name = "label2"; - this.label2.Size = new System.Drawing.Size(53, 12); + this.label2.Size = new System.Drawing.Size(67, 15); this.label2.TabIndex = 16; this.label2.Text = "开始时间"; // // label3 // this.label3.AutoSize = true; - this.label3.Location = new System.Drawing.Point(493, 97); + this.label3.Location = new System.Drawing.Point(657, 121); + this.label3.Margin = new System.Windows.Forms.Padding(4, 0, 4, 0); this.label3.Name = "label3"; - this.label3.Size = new System.Drawing.Size(53, 12); + this.label3.Size = new System.Drawing.Size(67, 15); this.label3.TabIndex = 17; this.label3.Text = "结束时间"; // // btnRecordGet // - this.btnRecordGet.Location = new System.Drawing.Point(200, 31); + this.btnRecordGet.Location = new System.Drawing.Point(267, 39); + this.btnRecordGet.Margin = new System.Windows.Forms.Padding(4, 4, 4, 4); this.btnRecordGet.Name = "btnRecordGet"; - this.btnRecordGet.Size = new System.Drawing.Size(68, 23); + this.btnRecordGet.Size = new System.Drawing.Size(91, 29); this.btnRecordGet.TabIndex = 18; this.btnRecordGet.Text = "录像查询"; this.btnRecordGet.UseVisualStyleBackColor = true; - this.btnRecordGet.Click += new System.EventHandler(this.BtnRecordGet_Click); + this.btnRecordGet.Click += new System.EventHandler(this.btnRecordGet_Click); // // lvRecord // @@ -321,10 +335,12 @@ this.columnHeader3, this.columnHeader4}); this.lvRecord.FullRowSelect = true; - this.lvRecord.Location = new System.Drawing.Point(6, 174); + this.lvRecord.HideSelection = false; + this.lvRecord.Location = new System.Drawing.Point(8, 218); + this.lvRecord.Margin = new System.Windows.Forms.Padding(4, 4, 4, 4); this.lvRecord.MultiSelect = false; this.lvRecord.Name = "lvRecord"; - this.lvRecord.Size = new System.Drawing.Size(319, 88); + this.lvRecord.Size = new System.Drawing.Size(424, 109); this.lvRecord.TabIndex = 19; this.lvRecord.UseCompatibleStateImageBehavior = false; this.lvRecord.View = System.Windows.Forms.View.Details; @@ -346,9 +362,10 @@ // // btnCatalogSubscribe // - this.btnCatalogSubscribe.Location = new System.Drawing.Point(709, 90); + this.btnCatalogSubscribe.Location = new System.Drawing.Point(945, 112); + this.btnCatalogSubscribe.Margin = new System.Windows.Forms.Padding(4, 4, 4, 4); this.btnCatalogSubscribe.Name = "btnCatalogSubscribe"; - this.btnCatalogSubscribe.Size = new System.Drawing.Size(75, 23); + this.btnCatalogSubscribe.Size = new System.Drawing.Size(100, 29); this.btnCatalogSubscribe.TabIndex = 26; this.btnCatalogSubscribe.Text = "目录订阅"; this.btnCatalogSubscribe.UseVisualStyleBackColor = true; @@ -356,9 +373,10 @@ // // btnEventSubscribe // - this.btnEventSubscribe.Location = new System.Drawing.Point(709, 126); + this.btnEventSubscribe.Location = new System.Drawing.Point(945, 158); + this.btnEventSubscribe.Margin = new System.Windows.Forms.Padding(4, 4, 4, 4); this.btnEventSubscribe.Name = "btnEventSubscribe"; - this.btnEventSubscribe.Size = new System.Drawing.Size(75, 23); + this.btnEventSubscribe.Size = new System.Drawing.Size(100, 29); this.btnEventSubscribe.TabIndex = 27; this.btnEventSubscribe.Text = "事件订阅"; this.btnEventSubscribe.UseVisualStyleBackColor = true; @@ -366,19 +384,21 @@ // // btnStateSearch // - this.btnStateSearch.Location = new System.Drawing.Point(12, 14); + this.btnStateSearch.Location = new System.Drawing.Point(16, 18); + this.btnStateSearch.Margin = new System.Windows.Forms.Padding(4, 4, 4, 4); this.btnStateSearch.Name = "btnStateSearch"; - this.btnStateSearch.Size = new System.Drawing.Size(75, 23); + this.btnStateSearch.Size = new System.Drawing.Size(100, 29); this.btnStateSearch.TabIndex = 28; this.btnStateSearch.Text = "状态查询"; this.btnStateSearch.UseVisualStyleBackColor = true; - this.btnStateSearch.Click += new System.EventHandler(this.BtnStateSearch_Click); + this.btnStateSearch.Click += new System.EventHandler(this.btnStateSearch_Click); // // btnSetGuard // - this.btnSetGuard.Location = new System.Drawing.Point(709, 162); + this.btnSetGuard.Location = new System.Drawing.Point(945, 202); + this.btnSetGuard.Margin = new System.Windows.Forms.Padding(4, 4, 4, 4); this.btnSetGuard.Name = "btnSetGuard"; - this.btnSetGuard.Size = new System.Drawing.Size(75, 23); + this.btnSetGuard.Size = new System.Drawing.Size(100, 29); this.btnSetGuard.TabIndex = 29; this.btnSetGuard.Text = "布防"; this.btnSetGuard.UseVisualStyleBackColor = true; @@ -386,9 +406,10 @@ // // btResetGuard // - this.btResetGuard.Location = new System.Drawing.Point(709, 198); + this.btResetGuard.Location = new System.Drawing.Point(945, 248); + this.btResetGuard.Margin = new System.Windows.Forms.Padding(4, 4, 4, 4); this.btResetGuard.Name = "btResetGuard"; - this.btResetGuard.Size = new System.Drawing.Size(75, 23); + this.btResetGuard.Size = new System.Drawing.Size(100, 29); this.btResetGuard.TabIndex = 31; this.btResetGuard.Text = "撤防"; this.btResetGuard.UseVisualStyleBackColor = true; @@ -396,9 +417,10 @@ // // btnDevSearch // - this.btnDevSearch.Location = new System.Drawing.Point(12, 74); + this.btnDevSearch.Location = new System.Drawing.Point(16, 92); + this.btnDevSearch.Margin = new System.Windows.Forms.Padding(4, 4, 4, 4); this.btnDevSearch.Name = "btnDevSearch"; - this.btnDevSearch.Size = new System.Drawing.Size(93, 23); + this.btnDevSearch.Size = new System.Drawing.Size(124, 29); this.btnDevSearch.TabIndex = 32; this.btnDevSearch.Text = "设备信息查询"; this.btnDevSearch.UseVisualStyleBackColor = true; @@ -406,9 +428,10 @@ // // brnRenboot // - this.brnRenboot.Location = new System.Drawing.Point(12, 44); + this.brnRenboot.Location = new System.Drawing.Point(16, 55); + this.brnRenboot.Margin = new System.Windows.Forms.Padding(4, 4, 4, 4); this.brnRenboot.Name = "brnRenboot"; - this.brnRenboot.Size = new System.Drawing.Size(75, 23); + this.brnRenboot.Size = new System.Drawing.Size(100, 29); this.brnRenboot.TabIndex = 33; this.brnRenboot.Text = "设备重启"; this.brnRenboot.UseVisualStyleBackColor = true; @@ -416,9 +439,10 @@ // // btnAlarmReset // - this.btnAlarmReset.Location = new System.Drawing.Point(709, 234); + this.btnAlarmReset.Location = new System.Drawing.Point(945, 292); + this.btnAlarmReset.Margin = new System.Windows.Forms.Padding(4, 4, 4, 4); this.btnAlarmReset.Name = "btnAlarmReset"; - this.btnAlarmReset.Size = new System.Drawing.Size(75, 23); + this.btnAlarmReset.Size = new System.Drawing.Size(100, 29); this.btnAlarmReset.TabIndex = 34; this.btnAlarmReset.Text = "报警复位"; this.btnAlarmReset.UseVisualStyleBackColor = true; @@ -427,9 +451,10 @@ // label4 // this.label4.AutoSize = true; - this.label4.Location = new System.Drawing.Point(9, 21); + this.label4.Location = new System.Drawing.Point(12, 26); + this.label4.Margin = new System.Windows.Forms.Padding(4, 0, 4, 0); this.label4.Name = "label4"; - this.label4.Size = new System.Drawing.Size(53, 12); + this.label4.Size = new System.Drawing.Size(67, 15); this.label4.TabIndex = 51; this.label4.Text = "云台速度"; // @@ -437,7 +462,7 @@ // this.txtLengthY.Location = new System.Drawing.Point(260, 73); this.txtLengthY.Name = "txtLengthY"; - this.txtLengthY.Size = new System.Drawing.Size(43, 21); + this.txtLengthY.Size = new System.Drawing.Size(43, 25); this.txtLengthY.TabIndex = 37; // // label11 @@ -453,7 +478,7 @@ // this.txtLengthX.Location = new System.Drawing.Point(260, 46); this.txtLengthX.Name = "txtLengthX"; - this.txtLengthX.Size = new System.Drawing.Size(43, 21); + this.txtLengthX.Size = new System.Drawing.Size(43, 25); this.txtLengthX.TabIndex = 35; // // label10 @@ -469,7 +494,7 @@ // this.txtMidPointY.Location = new System.Drawing.Point(263, 19); this.txtMidPointY.Name = "txtMidPointY"; - this.txtMidPointY.Size = new System.Drawing.Size(40, 21); + this.txtMidPointY.Size = new System.Drawing.Size(40, 25); this.txtMidPointY.TabIndex = 33; // // label9 @@ -485,7 +510,7 @@ // this.txtMidPointX.Location = new System.Drawing.Point(117, 72); this.txtMidPointX.Name = "txtMidPointX"; - this.txtMidPointX.Size = new System.Drawing.Size(43, 21); + this.txtMidPointX.Size = new System.Drawing.Size(43, 25); this.txtMidPointX.TabIndex = 31; // // label8 @@ -501,7 +526,7 @@ // this.txtWidth.Location = new System.Drawing.Point(117, 46); this.txtWidth.Name = "txtWidth"; - this.txtWidth.Size = new System.Drawing.Size(43, 21); + this.txtWidth.Size = new System.Drawing.Size(43, 25); this.txtWidth.TabIndex = 29; // // label7 @@ -517,7 +542,7 @@ // this.txtLength.Location = new System.Drawing.Point(117, 19); this.txtLength.Name = "txtLength"; - this.txtLength.Size = new System.Drawing.Size(43, 21); + this.txtLength.Size = new System.Drawing.Size(43, 25); this.txtLength.TabIndex = 27; // // label6 @@ -537,9 +562,10 @@ this.cataName}); this.lvCata.FullRowSelect = true; this.lvCata.HideSelection = false; - this.lvCata.Location = new System.Drawing.Point(332, 328); + this.lvCata.Location = new System.Drawing.Point(443, 410); + this.lvCata.Margin = new System.Windows.Forms.Padding(4, 4, 4, 4); this.lvCata.Name = "lvCata"; - this.lvCata.Size = new System.Drawing.Size(11, 156); + this.lvCata.Size = new System.Drawing.Size(602, 194); this.lvCata.TabIndex = 36; this.lvCata.UseCompatibleStateImageBehavior = false; this.lvCata.View = System.Windows.Forms.View.Details; @@ -562,18 +588,20 @@ // lblKeepalive // this.lblKeepalive.AutoSize = true; - this.lblKeepalive.Location = new System.Drawing.Point(475, 13); + this.lblKeepalive.Location = new System.Drawing.Point(633, 16); + this.lblKeepalive.Margin = new System.Windows.Forms.Padding(4, 0, 4, 0); this.lblKeepalive.Name = "lblKeepalive"; - this.lblKeepalive.Size = new System.Drawing.Size(89, 12); + this.lblKeepalive.Size = new System.Drawing.Size(112, 15); this.lblKeepalive.TabIndex = 38; this.lblKeepalive.Text = "等待心跳。。。"; // // chbSave // this.chbSave.AutoSize = true; - this.chbSave.Location = new System.Drawing.Point(495, 35); + this.chbSave.Location = new System.Drawing.Point(660, 44); + this.chbSave.Margin = new System.Windows.Forms.Padding(4, 4, 4, 4); this.chbSave.Name = "chbSave"; - this.chbSave.Size = new System.Drawing.Size(48, 16); + this.chbSave.Size = new System.Drawing.Size(59, 19); this.chbSave.TabIndex = 39; this.chbSave.Text = "存储"; this.chbSave.UseVisualStyleBackColor = true; @@ -581,26 +609,29 @@ // lblExport // this.lblExport.AutoSize = true; - this.lblExport.Location = new System.Drawing.Point(607, 365); + this.lblExport.Location = new System.Drawing.Point(809, 456); + this.lblExport.Margin = new System.Windows.Forms.Padding(4, 0, 4, 0); this.lblExport.Name = "lblExport"; - this.lblExport.Size = new System.Drawing.Size(0, 12); + this.lblExport.Size = new System.Drawing.Size(0, 15); this.lblExport.TabIndex = 41; // // btnStopRd // - this.btnStopRd.Location = new System.Drawing.Point(95, 116); + this.btnStopRd.Location = new System.Drawing.Point(127, 145); + this.btnStopRd.Margin = new System.Windows.Forms.Padding(4, 4, 4, 4); this.btnStopRd.Name = "btnStopRd"; - this.btnStopRd.Size = new System.Drawing.Size(68, 22); + this.btnStopRd.Size = new System.Drawing.Size(91, 28); this.btnStopRd.TabIndex = 2; this.btnStopRd.Text = "停止录像"; this.btnStopRd.UseVisualStyleBackColor = true; - this.btnStopRd.Click += new System.EventHandler(this.BtnStopRd_Click); + this.btnStopRd.Click += new System.EventHandler(this.btnStopRd_Click); // // btnStartRecord // - this.btnStartRecord.Location = new System.Drawing.Point(12, 116); + this.btnStartRecord.Location = new System.Drawing.Point(16, 145); + this.btnStartRecord.Margin = new System.Windows.Forms.Padding(4, 4, 4, 4); this.btnStartRecord.Name = "btnStartRecord"; - this.btnStartRecord.Size = new System.Drawing.Size(68, 22); + this.btnStartRecord.Size = new System.Drawing.Size(91, 28); this.btnStartRecord.TabIndex = 0; this.btnStartRecord.Text = "开始录像"; this.btnStartRecord.UseVisualStyleBackColor = true; @@ -609,74 +640,82 @@ // label5 // this.label5.AutoSize = true; - this.label5.Location = new System.Drawing.Point(10, 92); + this.label5.Location = new System.Drawing.Point(13, 115); + this.label5.Margin = new System.Windows.Forms.Padding(4, 0, 4, 0); this.label5.Name = "label5"; - this.label5.Size = new System.Drawing.Size(59, 12); + this.label5.Size = new System.Drawing.Size(75, 15); this.label5.TabIndex = 29; this.label5.Text = "拖动播放:"; // // txtDragDrop // - this.txtDragDrop.Location = new System.Drawing.Point(69, 89); + this.txtDragDrop.Location = new System.Drawing.Point(92, 111); + this.txtDragDrop.Margin = new System.Windows.Forms.Padding(4, 4, 4, 4); this.txtDragDrop.Name = "txtDragDrop"; - this.txtDragDrop.Size = new System.Drawing.Size(125, 21); + this.txtDragDrop.Size = new System.Drawing.Size(165, 25); this.txtDragDrop.TabIndex = 28; // // button17 // - this.button17.Location = new System.Drawing.Point(200, 88); + this.button17.Location = new System.Drawing.Point(267, 110); + this.button17.Margin = new System.Windows.Forms.Padding(4, 4, 4, 4); this.button17.Name = "button17"; - this.button17.Size = new System.Drawing.Size(68, 23); + this.button17.Size = new System.Drawing.Size(91, 29); this.button17.TabIndex = 27; this.button17.Text = "播放"; this.button17.UseVisualStyleBackColor = true; - this.button17.Click += new System.EventHandler(this.Button17_Click); + this.button17.Click += new System.EventHandler(this.button17_Click); // // label1 // this.label1.AutoSize = true; - this.label1.Location = new System.Drawing.Point(10, 63); + this.label1.Location = new System.Drawing.Point(13, 79); + this.label1.Margin = new System.Windows.Forms.Padding(4, 0, 4, 0); this.label1.Name = "label1"; - this.label1.Size = new System.Drawing.Size(59, 12); + this.label1.Size = new System.Drawing.Size(75, 15); this.label1.TabIndex = 26; this.label1.Text = "播放倍数:"; // // txtScale // - this.txtScale.Location = new System.Drawing.Point(69, 60); + this.txtScale.Location = new System.Drawing.Point(92, 75); + this.txtScale.Margin = new System.Windows.Forms.Padding(4, 4, 4, 4); this.txtScale.Name = "txtScale"; - this.txtScale.Size = new System.Drawing.Size(125, 21); + this.txtScale.Size = new System.Drawing.Size(165, 25); this.txtScale.TabIndex = 26; // // btnSdu // - this.btnSdu.Location = new System.Drawing.Point(200, 59); + this.btnSdu.Location = new System.Drawing.Point(267, 74); + this.btnSdu.Margin = new System.Windows.Forms.Padding(4, 4, 4, 4); this.btnSdu.Name = "btnSdu"; - this.btnSdu.Size = new System.Drawing.Size(68, 23); + this.btnSdu.Size = new System.Drawing.Size(91, 29); this.btnSdu.TabIndex = 19; this.btnSdu.Text = "设置"; this.btnSdu.UseVisualStyleBackColor = true; - this.btnSdu.Click += new System.EventHandler(this.BtnSdu_Click); + this.btnSdu.Click += new System.EventHandler(this.btnSdu_Click); // // btnPlay // - this.btnPlay.Location = new System.Drawing.Point(178, 145); + this.btnPlay.Location = new System.Drawing.Point(237, 181); + this.btnPlay.Margin = new System.Windows.Forms.Padding(4, 4, 4, 4); this.btnPlay.Name = "btnPlay"; - this.btnPlay.Size = new System.Drawing.Size(68, 23); + this.btnPlay.Size = new System.Drawing.Size(91, 29); this.btnPlay.TabIndex = 15; this.btnPlay.Text = "播放继续"; this.btnPlay.UseVisualStyleBackColor = true; - this.btnPlay.Click += new System.EventHandler(this.BtnPlay_Click); + this.btnPlay.Click += new System.EventHandler(this.btnPlay_Click); // // btnPause // - this.btnPause.Location = new System.Drawing.Point(178, 116); + this.btnPause.Location = new System.Drawing.Point(237, 145); + this.btnPause.Margin = new System.Windows.Forms.Padding(4, 4, 4, 4); this.btnPause.Name = "btnPause"; - this.btnPause.Size = new System.Drawing.Size(68, 23); + this.btnPause.Size = new System.Drawing.Size(91, 29); this.btnPause.TabIndex = 14; this.btnPause.Text = "播放暂停"; this.btnPause.UseVisualStyleBackColor = true; - this.btnPause.Click += new System.EventHandler(this.BtnPause_Click); + this.btnPause.Click += new System.EventHandler(this.btnPause_Click); // // tabControl1 // @@ -686,20 +725,22 @@ this.tabControl1.Controls.Add(this.tbOther); this.tabControl1.Controls.Add(this.tabNew); this.tabControl1.Controls.Add(this.tabPage1); - this.tabControl1.Location = new System.Drawing.Point(6, 32); + this.tabControl1.Location = new System.Drawing.Point(8, 40); + this.tabControl1.Margin = new System.Windows.Forms.Padding(4, 4, 4, 4); this.tabControl1.Name = "tabControl1"; this.tabControl1.SelectedIndex = 0; - this.tabControl1.Size = new System.Drawing.Size(340, 294); + this.tabControl1.Size = new System.Drawing.Size(453, 368); this.tabControl1.TabIndex = 47; // // tbReal // this.tbReal.Controls.Add(this.btnReal); this.tbReal.Controls.Add(this.btnBye); - this.tbReal.Location = new System.Drawing.Point(4, 22); + this.tbReal.Location = new System.Drawing.Point(4, 25); + this.tbReal.Margin = new System.Windows.Forms.Padding(4, 4, 4, 4); this.tbReal.Name = "tbReal"; - this.tbReal.Padding = new System.Windows.Forms.Padding(3); - this.tbReal.Size = new System.Drawing.Size(332, 268); + this.tbReal.Padding = new System.Windows.Forms.Padding(4, 4, 4, 4); + this.tbReal.Size = new System.Drawing.Size(445, 339); this.tbReal.TabIndex = 0; this.tbReal.Text = "实时"; this.tbReal.UseVisualStyleBackColor = true; @@ -729,10 +770,11 @@ this.tbRecord.Controls.Add(this.txtStartTime); this.tbRecord.Controls.Add(this.label2); this.tbRecord.Controls.Add(this.label3); - this.tbRecord.Location = new System.Drawing.Point(4, 22); + this.tbRecord.Location = new System.Drawing.Point(4, 25); + this.tbRecord.Margin = new System.Windows.Forms.Padding(4, 4, 4, 4); this.tbRecord.Name = "tbRecord"; - this.tbRecord.Padding = new System.Windows.Forms.Padding(3); - this.tbRecord.Size = new System.Drawing.Size(332, 268); + this.tbRecord.Padding = new System.Windows.Forms.Padding(4, 4, 4, 4); + this.tbRecord.Size = new System.Drawing.Size(445, 339); this.tbRecord.TabIndex = 1; this.tbRecord.Text = "录像"; this.tbRecord.UseVisualStyleBackColor = true; @@ -741,16 +783,18 @@ // this.cbxRecordType.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList; this.cbxRecordType.FormattingEnabled = true; - this.cbxRecordType.Location = new System.Drawing.Point(200, 6); + this.cbxRecordType.Location = new System.Drawing.Point(267, 8); + this.cbxRecordType.Margin = new System.Windows.Forms.Padding(4, 4, 4, 4); this.cbxRecordType.Name = "cbxRecordType"; - this.cbxRecordType.Size = new System.Drawing.Size(68, 20); + this.cbxRecordType.Size = new System.Drawing.Size(89, 23); this.cbxRecordType.TabIndex = 50; // // btnRecordDownload // - this.btnRecordDownload.Location = new System.Drawing.Point(250, 116); + this.btnRecordDownload.Location = new System.Drawing.Point(333, 145); + this.btnRecordDownload.Margin = new System.Windows.Forms.Padding(4, 4, 4, 4); this.btnRecordDownload.Name = "btnRecordDownload"; - this.btnRecordDownload.Size = new System.Drawing.Size(75, 23); + this.btnRecordDownload.Size = new System.Drawing.Size(100, 29); this.btnRecordDownload.TabIndex = 49; this.btnRecordDownload.Text = "录像下载"; this.btnRecordDownload.UseVisualStyleBackColor = true; @@ -759,18 +803,20 @@ // label13 // this.label13.AutoSize = true; - this.label13.Location = new System.Drawing.Point(10, 38); + this.label13.Location = new System.Drawing.Point(13, 48); + this.label13.Margin = new System.Windows.Forms.Padding(4, 0, 4, 0); this.label13.Name = "label13"; - this.label13.Size = new System.Drawing.Size(53, 12); + this.label13.Size = new System.Drawing.Size(67, 15); this.label13.TabIndex = 48; this.label13.Text = "结束时间"; // // label12 // this.label12.AutoSize = true; - this.label12.Location = new System.Drawing.Point(10, 11); + this.label12.Location = new System.Drawing.Point(13, 14); + this.label12.Margin = new System.Windows.Forms.Padding(4, 0, 4, 0); this.label12.Name = "label12"; - this.label12.Size = new System.Drawing.Size(53, 12); + this.label12.Size = new System.Drawing.Size(67, 15); this.label12.TabIndex = 40; this.label12.Text = "开始时间"; // @@ -802,9 +848,10 @@ this.tbPTZ.Controls.Add(this.btnRight); this.tbPTZ.Controls.Add(this.btnSetPreset); this.tbPTZ.Controls.Add(this.btnLeft); - this.tbPTZ.Location = new System.Drawing.Point(4, 22); + this.tbPTZ.Location = new System.Drawing.Point(4, 25); + this.tbPTZ.Margin = new System.Windows.Forms.Padding(4, 4, 4, 4); this.tbPTZ.Name = "tbPTZ"; - this.tbPTZ.Size = new System.Drawing.Size(332, 268); + this.tbPTZ.Size = new System.Drawing.Size(445, 339); this.tbPTZ.TabIndex = 2; this.tbPTZ.Text = "云台"; this.tbPTZ.UseVisualStyleBackColor = true; @@ -813,16 +860,18 @@ // this.cbxPreset.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList; this.cbxPreset.FormattingEnabled = true; - this.cbxPreset.Location = new System.Drawing.Point(243, 18); + this.cbxPreset.Location = new System.Drawing.Point(324, 22); + this.cbxPreset.Margin = new System.Windows.Forms.Padding(4, 4, 4, 4); this.cbxPreset.Name = "cbxPreset"; - this.cbxPreset.Size = new System.Drawing.Size(86, 20); + this.cbxPreset.Size = new System.Drawing.Size(113, 23); this.cbxPreset.TabIndex = 73; // // btnPositionClose // - this.btnPositionClose.Location = new System.Drawing.Point(199, 219); + this.btnPositionClose.Location = new System.Drawing.Point(265, 274); + this.btnPositionClose.Margin = new System.Windows.Forms.Padding(4, 4, 4, 4); this.btnPositionClose.Name = "btnPositionClose"; - this.btnPositionClose.Size = new System.Drawing.Size(75, 23); + this.btnPositionClose.Size = new System.Drawing.Size(100, 29); this.btnPositionClose.TabIndex = 72; this.btnPositionClose.Text = "看守位关"; this.btnPositionClose.UseVisualStyleBackColor = true; @@ -830,9 +879,10 @@ // // btnPositionOpen // - this.btnPositionOpen.Location = new System.Drawing.Point(199, 190); + this.btnPositionOpen.Location = new System.Drawing.Point(265, 238); + this.btnPositionOpen.Margin = new System.Windows.Forms.Padding(4, 4, 4, 4); this.btnPositionOpen.Name = "btnPositionOpen"; - this.btnPositionOpen.Size = new System.Drawing.Size(75, 23); + this.btnPositionOpen.Size = new System.Drawing.Size(100, 29); this.btnPositionOpen.TabIndex = 71; this.btnPositionOpen.Text = "看守位开"; this.btnPositionOpen.UseVisualStyleBackColor = true; @@ -840,9 +890,10 @@ // // btnZoomOut // - this.btnZoomOut.Location = new System.Drawing.Point(199, 161); + this.btnZoomOut.Location = new System.Drawing.Point(265, 201); + this.btnZoomOut.Margin = new System.Windows.Forms.Padding(4, 4, 4, 4); this.btnZoomOut.Name = "btnZoomOut"; - this.btnZoomOut.Size = new System.Drawing.Size(75, 23); + this.btnZoomOut.Size = new System.Drawing.Size(100, 29); this.btnZoomOut.TabIndex = 70; this.btnZoomOut.Text = "拉框缩小"; this.btnZoomOut.UseVisualStyleBackColor = true; @@ -850,9 +901,10 @@ // // btnZoomIn // - this.btnZoomIn.Location = new System.Drawing.Point(199, 132); + this.btnZoomIn.Location = new System.Drawing.Point(265, 165); + this.btnZoomIn.Margin = new System.Windows.Forms.Padding(4, 4, 4, 4); this.btnZoomIn.Name = "btnZoomIn"; - this.btnZoomIn.Size = new System.Drawing.Size(75, 23); + this.btnZoomIn.Size = new System.Drawing.Size(100, 29); this.btnZoomIn.TabIndex = 69; this.btnZoomIn.Text = "拉框放大"; this.btnZoomIn.UseVisualStyleBackColor = true; @@ -861,9 +913,10 @@ // btnPTZStop // this.btnPTZStop.ForeColor = System.Drawing.Color.Red; - this.btnPTZStop.Location = new System.Drawing.Point(75, 103); + this.btnPTZStop.Location = new System.Drawing.Point(100, 129); + this.btnPTZStop.Margin = new System.Windows.Forms.Padding(4, 4, 4, 4); this.btnPTZStop.Name = "btnPTZStop"; - this.btnPTZStop.Size = new System.Drawing.Size(37, 36); + this.btnPTZStop.Size = new System.Drawing.Size(49, 45); this.btnPTZStop.TabIndex = 63; this.btnPTZStop.Text = "█"; this.btnPTZStop.UseVisualStyleBackColor = true; @@ -871,9 +924,10 @@ // // btnFocus2 // - this.btnFocus2.Location = new System.Drawing.Point(66, 234); + this.btnFocus2.Location = new System.Drawing.Point(88, 292); + this.btnFocus2.Margin = new System.Windows.Forms.Padding(4, 4, 4, 4); this.btnFocus2.Name = "btnFocus2"; - this.btnFocus2.Size = new System.Drawing.Size(55, 23); + this.btnFocus2.Size = new System.Drawing.Size(73, 29); this.btnFocus2.TabIndex = 61; this.btnFocus2.Text = "聚焦-"; this.btnFocus2.UseVisualStyleBackColor = true; @@ -881,9 +935,10 @@ // // btnZoom2 // - this.btnZoom2.Location = new System.Drawing.Point(4, 234); + this.btnZoom2.Location = new System.Drawing.Point(5, 292); + this.btnZoom2.Margin = new System.Windows.Forms.Padding(4, 4, 4, 4); this.btnZoom2.Name = "btnZoom2"; - this.btnZoom2.Size = new System.Drawing.Size(55, 23); + this.btnZoom2.Size = new System.Drawing.Size(73, 29); this.btnZoom2.TabIndex = 60; this.btnZoom2.Text = "变倍-"; this.btnZoom2.UseVisualStyleBackColor = true; @@ -891,9 +946,10 @@ // // btnIris2 // - this.btnIris2.Location = new System.Drawing.Point(128, 234); + this.btnIris2.Location = new System.Drawing.Point(171, 292); + this.btnIris2.Margin = new System.Windows.Forms.Padding(4, 4, 4, 4); this.btnIris2.Name = "btnIris2"; - this.btnIris2.Size = new System.Drawing.Size(55, 23); + this.btnIris2.Size = new System.Drawing.Size(73, 29); this.btnIris2.TabIndex = 59; this.btnIris2.Text = "光圈关"; this.btnIris2.UseVisualStyleBackColor = true; @@ -901,9 +957,10 @@ // // btnIris1 // - this.btnIris1.Location = new System.Drawing.Point(128, 205); + this.btnIris1.Location = new System.Drawing.Point(171, 256); + this.btnIris1.Margin = new System.Windows.Forms.Padding(4, 4, 4, 4); this.btnIris1.Name = "btnIris1"; - this.btnIris1.Size = new System.Drawing.Size(55, 23); + this.btnIris1.Size = new System.Drawing.Size(73, 29); this.btnIris1.TabIndex = 58; this.btnIris1.Text = "光圈开"; this.btnIris1.UseVisualStyleBackColor = true; @@ -911,30 +968,33 @@ // // btnFocus1 // - this.btnFocus1.Location = new System.Drawing.Point(66, 205); + this.btnFocus1.Location = new System.Drawing.Point(88, 256); + this.btnFocus1.Margin = new System.Windows.Forms.Padding(4, 4, 4, 4); this.btnFocus1.Name = "btnFocus1"; - this.btnFocus1.Size = new System.Drawing.Size(55, 23); + this.btnFocus1.Size = new System.Drawing.Size(73, 29); this.btnFocus1.TabIndex = 57; this.btnFocus1.Text = "聚焦+"; this.btnFocus1.UseVisualStyleBackColor = true; - this.btnFocus1.Click += new System.EventHandler(this.BtnFocus1_Click); + this.btnFocus1.Click += new System.EventHandler(this.btnFocus1_Click); // // btnZoom1 // - this.btnZoom1.Location = new System.Drawing.Point(4, 205); + this.btnZoom1.Location = new System.Drawing.Point(5, 256); + this.btnZoom1.Margin = new System.Windows.Forms.Padding(4, 4, 4, 4); this.btnZoom1.Name = "btnZoom1"; - this.btnZoom1.Size = new System.Drawing.Size(55, 23); + this.btnZoom1.Size = new System.Drawing.Size(73, 29); this.btnZoom1.TabIndex = 62; this.btnZoom1.Text = "变倍+"; this.btnZoom1.UseVisualStyleBackColor = true; - this.btnZoom1.Click += new System.EventHandler(this.BtnZoom1_Click); + this.btnZoom1.Click += new System.EventHandler(this.btnZoom1_Click); // // btnRightDown // - this.btnRightDown.Font = new System.Drawing.Font("宋体", 11.25F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(134))); - this.btnRightDown.Location = new System.Drawing.Point(137, 156); + this.btnRightDown.Font = new System.Drawing.Font("SimSun", 11.25F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(134))); + this.btnRightDown.Location = new System.Drawing.Point(183, 195); + this.btnRightDown.Margin = new System.Windows.Forms.Padding(4, 4, 4, 4); this.btnRightDown.Name = "btnRightDown"; - this.btnRightDown.Size = new System.Drawing.Size(37, 36); + this.btnRightDown.Size = new System.Drawing.Size(49, 45); this.btnRightDown.TabIndex = 56; this.btnRightDown.Text = "↘"; this.btnRightDown.UseVisualStyleBackColor = true; @@ -942,10 +1002,11 @@ // // btnLeftDown // - this.btnLeftDown.Font = new System.Drawing.Font("宋体", 11.25F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(134))); - this.btnLeftDown.Location = new System.Drawing.Point(13, 156); + this.btnLeftDown.Font = new System.Drawing.Font("SimSun", 11.25F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(134))); + this.btnLeftDown.Location = new System.Drawing.Point(17, 195); + this.btnLeftDown.Margin = new System.Windows.Forms.Padding(4, 4, 4, 4); this.btnLeftDown.Name = "btnLeftDown"; - this.btnLeftDown.Size = new System.Drawing.Size(37, 36); + this.btnLeftDown.Size = new System.Drawing.Size(49, 45); this.btnLeftDown.TabIndex = 55; this.btnLeftDown.Text = "↙"; this.btnLeftDown.UseVisualStyleBackColor = true; @@ -953,10 +1014,11 @@ // // btnRightUP // - this.btnRightUP.Font = new System.Drawing.Font("宋体", 11.25F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(134))); - this.btnRightUP.Location = new System.Drawing.Point(137, 50); + this.btnRightUP.Font = new System.Drawing.Font("SimSun", 11.25F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(134))); + this.btnRightUP.Location = new System.Drawing.Point(183, 62); + this.btnRightUP.Margin = new System.Windows.Forms.Padding(4, 4, 4, 4); this.btnRightUP.Name = "btnRightUP"; - this.btnRightUP.Size = new System.Drawing.Size(37, 36); + this.btnRightUP.Size = new System.Drawing.Size(49, 45); this.btnRightUP.TabIndex = 54; this.btnRightUP.Text = "↗"; this.btnRightUP.UseVisualStyleBackColor = true; @@ -964,9 +1026,10 @@ // // btnRemovePreset // - this.btnRemovePreset.Location = new System.Drawing.Point(199, 103); + this.btnRemovePreset.Location = new System.Drawing.Point(265, 129); + this.btnRemovePreset.Margin = new System.Windows.Forms.Padding(4, 4, 4, 4); this.btnRemovePreset.Name = "btnRemovePreset"; - this.btnRemovePreset.Size = new System.Drawing.Size(75, 23); + this.btnRemovePreset.Size = new System.Drawing.Size(100, 29); this.btnRemovePreset.TabIndex = 67; this.btnRemovePreset.Text = "删除预置位"; this.btnRemovePreset.UseVisualStyleBackColor = true; @@ -974,10 +1037,11 @@ // // btnLeftUP // - this.btnLeftUP.Font = new System.Drawing.Font("宋体", 11.25F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(134))); - this.btnLeftUP.Location = new System.Drawing.Point(13, 50); + this.btnLeftUP.Font = new System.Drawing.Font("SimSun", 11.25F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(134))); + this.btnLeftUP.Location = new System.Drawing.Point(17, 62); + this.btnLeftUP.Margin = new System.Windows.Forms.Padding(4, 4, 4, 4); this.btnLeftUP.Name = "btnLeftUP"; - this.btnLeftUP.Size = new System.Drawing.Size(37, 36); + this.btnLeftUP.Size = new System.Drawing.Size(49, 45); this.btnLeftUP.TabIndex = 53; this.btnLeftUP.Text = "↖"; this.btnLeftUP.UseVisualStyleBackColor = true; @@ -990,7 +1054,8 @@ 0, 0, 0}); - this.numberSpeed.Location = new System.Drawing.Point(69, 16); + this.numberSpeed.Location = new System.Drawing.Point(92, 20); + this.numberSpeed.Margin = new System.Windows.Forms.Padding(4, 4, 4, 4); this.numberSpeed.Maximum = new decimal(new int[] { 255, 0, @@ -1002,7 +1067,7 @@ 0, 0}); this.numberSpeed.Name = "numberSpeed"; - this.numberSpeed.Size = new System.Drawing.Size(93, 21); + this.numberSpeed.Size = new System.Drawing.Size(124, 25); this.numberSpeed.TabIndex = 52; this.numberSpeed.Value = new decimal(new int[] { 10, @@ -1012,10 +1077,11 @@ // // btnDown // - this.btnDown.Font = new System.Drawing.Font("宋体", 11.25F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(134))); - this.btnDown.Location = new System.Drawing.Point(75, 156); + this.btnDown.Font = new System.Drawing.Font("SimSun", 11.25F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(134))); + this.btnDown.Location = new System.Drawing.Point(100, 195); + this.btnDown.Margin = new System.Windows.Forms.Padding(4, 4, 4, 4); this.btnDown.Name = "btnDown"; - this.btnDown.Size = new System.Drawing.Size(37, 36); + this.btnDown.Size = new System.Drawing.Size(49, 45); this.btnDown.TabIndex = 50; this.btnDown.Text = "↓"; this.btnDown.UseVisualStyleBackColor = true; @@ -1023,9 +1089,10 @@ // // btnGetPreset // - this.btnGetPreset.Location = new System.Drawing.Point(199, 74); + this.btnGetPreset.Location = new System.Drawing.Point(265, 92); + this.btnGetPreset.Margin = new System.Windows.Forms.Padding(4, 4, 4, 4); this.btnGetPreset.Name = "btnGetPreset"; - this.btnGetPreset.Size = new System.Drawing.Size(75, 23); + this.btnGetPreset.Size = new System.Drawing.Size(100, 29); this.btnGetPreset.TabIndex = 66; this.btnGetPreset.Text = "调用预置位"; this.btnGetPreset.UseVisualStyleBackColor = true; @@ -1033,10 +1100,11 @@ // // btnUP // - this.btnUP.Font = new System.Drawing.Font("宋体", 11.25F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(134))); - this.btnUP.Location = new System.Drawing.Point(75, 50); + this.btnUP.Font = new System.Drawing.Font("SimSun", 11.25F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(134))); + this.btnUP.Location = new System.Drawing.Point(100, 62); + this.btnUP.Margin = new System.Windows.Forms.Padding(4, 4, 4, 4); this.btnUP.Name = "btnUP"; - this.btnUP.Size = new System.Drawing.Size(37, 36); + this.btnUP.Size = new System.Drawing.Size(49, 45); this.btnUP.TabIndex = 47; this.btnUP.Text = "↑"; this.btnUP.UseVisualStyleBackColor = true; @@ -1044,9 +1112,10 @@ // // btnSearchPreset // - this.btnSearchPreset.Location = new System.Drawing.Point(199, 45); + this.btnSearchPreset.Location = new System.Drawing.Point(265, 56); + this.btnSearchPreset.Margin = new System.Windows.Forms.Padding(4, 4, 4, 4); this.btnSearchPreset.Name = "btnSearchPreset"; - this.btnSearchPreset.Size = new System.Drawing.Size(75, 23); + this.btnSearchPreset.Size = new System.Drawing.Size(100, 29); this.btnSearchPreset.TabIndex = 65; this.btnSearchPreset.Text = "预置位查询"; this.btnSearchPreset.UseVisualStyleBackColor = true; @@ -1054,10 +1123,11 @@ // // btnRight // - this.btnRight.Font = new System.Drawing.Font("宋体", 11.25F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(134))); - this.btnRight.Location = new System.Drawing.Point(137, 103); + this.btnRight.Font = new System.Drawing.Font("SimSun", 11.25F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(134))); + this.btnRight.Location = new System.Drawing.Point(183, 129); + this.btnRight.Margin = new System.Windows.Forms.Padding(4, 4, 4, 4); this.btnRight.Name = "btnRight"; - this.btnRight.Size = new System.Drawing.Size(37, 36); + this.btnRight.Size = new System.Drawing.Size(49, 45); this.btnRight.TabIndex = 49; this.btnRight.Text = "→"; this.btnRight.UseVisualStyleBackColor = true; @@ -1065,9 +1135,10 @@ // // btnSetPreset // - this.btnSetPreset.Location = new System.Drawing.Point(165, 16); + this.btnSetPreset.Location = new System.Drawing.Point(220, 20); + this.btnSetPreset.Margin = new System.Windows.Forms.Padding(4, 4, 4, 4); this.btnSetPreset.Name = "btnSetPreset"; - this.btnSetPreset.Size = new System.Drawing.Size(75, 23); + this.btnSetPreset.Size = new System.Drawing.Size(100, 29); this.btnSetPreset.TabIndex = 64; this.btnSetPreset.Text = "预置位设置"; this.btnSetPreset.UseVisualStyleBackColor = true; @@ -1075,10 +1146,11 @@ // // btnLeft // - this.btnLeft.Font = new System.Drawing.Font("宋体", 11.25F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(134))); - this.btnLeft.Location = new System.Drawing.Point(13, 103); + this.btnLeft.Font = new System.Drawing.Font("SimSun", 11.25F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(134))); + this.btnLeft.Location = new System.Drawing.Point(17, 129); + this.btnLeft.Margin = new System.Windows.Forms.Padding(4, 4, 4, 4); this.btnLeft.Name = "btnLeft"; - this.btnLeft.Size = new System.Drawing.Size(37, 36); + this.btnLeft.Size = new System.Drawing.Size(49, 45); this.btnLeft.TabIndex = 48; this.btnLeft.Text = "←"; this.btnLeft.UseVisualStyleBackColor = true; @@ -1095,18 +1167,20 @@ this.tbOther.Controls.Add(this.btnDevSearch); this.tbOther.Controls.Add(this.txtMsg); this.tbOther.Controls.Add(this.brnRenboot); - this.tbOther.Location = new System.Drawing.Point(4, 22); + this.tbOther.Location = new System.Drawing.Point(4, 25); + this.tbOther.Margin = new System.Windows.Forms.Padding(4, 4, 4, 4); this.tbOther.Name = "tbOther"; - this.tbOther.Size = new System.Drawing.Size(332, 268); + this.tbOther.Size = new System.Drawing.Size(445, 339); this.tbOther.TabIndex = 3; this.tbOther.Text = "其他"; this.tbOther.UseVisualStyleBackColor = true; // // btnKeyFrame // - this.btnKeyFrame.Location = new System.Drawing.Point(156, 44); + this.btnKeyFrame.Location = new System.Drawing.Point(208, 55); + this.btnKeyFrame.Margin = new System.Windows.Forms.Padding(4, 4, 4, 4); this.btnKeyFrame.Name = "btnKeyFrame"; - this.btnKeyFrame.Size = new System.Drawing.Size(75, 23); + this.btnKeyFrame.Size = new System.Drawing.Size(100, 29); this.btnKeyFrame.TabIndex = 51; this.btnKeyFrame.Text = "关键帧"; this.btnKeyFrame.UseVisualStyleBackColor = true; @@ -1114,9 +1188,10 @@ // // button1 // - this.button1.Location = new System.Drawing.Point(156, 14); + this.button1.Location = new System.Drawing.Point(208, 18); + this.button1.Margin = new System.Windows.Forms.Padding(4, 4, 4, 4); this.button1.Name = "button1"; - this.button1.Size = new System.Drawing.Size(75, 23); + this.button1.Size = new System.Drawing.Size(100, 29); this.button1.TabIndex = 50; this.button1.Text = "Test"; this.button1.UseVisualStyleBackColor = true; @@ -1125,9 +1200,10 @@ // label14 // this.label14.AutoSize = true; - this.label14.Location = new System.Drawing.Point(11, 112); + this.label14.Location = new System.Drawing.Point(15, 140); + this.label14.Margin = new System.Windows.Forms.Padding(4, 0, 4, 0); this.label14.Name = "label14"; - this.label14.Size = new System.Drawing.Size(53, 12); + this.label14.Size = new System.Drawing.Size(67, 15); this.label14.TabIndex = 49; this.label14.Text = "配置参数"; // @@ -1135,28 +1211,31 @@ // this.cbxConfig.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList; this.cbxConfig.FormattingEnabled = true; - this.cbxConfig.Location = new System.Drawing.Point(71, 108); + this.cbxConfig.Location = new System.Drawing.Point(95, 135); + this.cbxConfig.Margin = new System.Windows.Forms.Padding(4, 4, 4, 4); this.cbxConfig.Name = "cbxConfig"; - this.cbxConfig.Size = new System.Drawing.Size(121, 20); + this.cbxConfig.Size = new System.Drawing.Size(160, 23); this.cbxConfig.TabIndex = 48; // // btnConfigQuery // - this.btnConfigQuery.Location = new System.Drawing.Point(201, 106); + this.btnConfigQuery.Location = new System.Drawing.Point(268, 132); + this.btnConfigQuery.Margin = new System.Windows.Forms.Padding(4, 4, 4, 4); this.btnConfigQuery.Name = "btnConfigQuery"; - this.btnConfigQuery.Size = new System.Drawing.Size(98, 23); + this.btnConfigQuery.Size = new System.Drawing.Size(131, 29); this.btnConfigQuery.TabIndex = 47; this.btnConfigQuery.Text = "设备配置查询"; this.btnConfigQuery.UseVisualStyleBackColor = true; - this.btnConfigQuery.Click += new System.EventHandler(this.BtnConfigQuery_Click); + this.btnConfigQuery.Click += new System.EventHandler(this.btnConfigQuery_Click); // // txtMsg // - this.txtMsg.Location = new System.Drawing.Point(12, 136); + this.txtMsg.Location = new System.Drawing.Point(16, 170); + this.txtMsg.Margin = new System.Windows.Forms.Padding(4, 4, 4, 4); this.txtMsg.Multiline = true; this.txtMsg.Name = "txtMsg"; this.txtMsg.ScrollBars = System.Windows.Forms.ScrollBars.Vertical; - this.txtMsg.Size = new System.Drawing.Size(306, 93); + this.txtMsg.Size = new System.Drawing.Size(407, 115); this.txtMsg.TabIndex = 46; // // tabNew @@ -1168,19 +1247,21 @@ this.tabNew.Controls.Add(this.label22); this.tabNew.Controls.Add(this.btnSubPositionInfo); this.tabNew.Controls.Add(this.btnAudioNotify); - this.tabNew.Location = new System.Drawing.Point(4, 22); + this.tabNew.Location = new System.Drawing.Point(4, 25); + this.tabNew.Margin = new System.Windows.Forms.Padding(4, 4, 4, 4); this.tabNew.Name = "tabNew"; - this.tabNew.Padding = new System.Windows.Forms.Padding(3); - this.tabNew.Size = new System.Drawing.Size(332, 268); + this.tabNew.Padding = new System.Windows.Forms.Padding(4, 4, 4, 4); + this.tabNew.Size = new System.Drawing.Size(445, 339); this.tabNew.TabIndex = 4; this.tabNew.Text = "新加12/23"; this.tabNew.UseVisualStyleBackColor = true; // // button2 // - this.button2.Location = new System.Drawing.Point(20, 144); + this.button2.Location = new System.Drawing.Point(27, 180); + this.button2.Margin = new System.Windows.Forms.Padding(4, 4, 4, 4); this.button2.Name = "button2"; - this.button2.Size = new System.Drawing.Size(119, 23); + this.button2.Size = new System.Drawing.Size(159, 29); this.button2.TabIndex = 7; this.button2.Text = "目录订阅取消订阅"; this.button2.UseVisualStyleBackColor = true; @@ -1188,33 +1269,36 @@ // // btnSubscribeCancel // - this.btnSubscribeCancel.Location = new System.Drawing.Point(171, 71); + this.btnSubscribeCancel.Location = new System.Drawing.Point(228, 89); + this.btnSubscribeCancel.Margin = new System.Windows.Forms.Padding(4, 4, 4, 4); this.btnSubscribeCancel.Name = "btnSubscribeCancel"; - this.btnSubscribeCancel.Size = new System.Drawing.Size(119, 23); + this.btnSubscribeCancel.Size = new System.Drawing.Size(159, 29); this.btnSubscribeCancel.TabIndex = 5; this.btnSubscribeCancel.Text = "移动位置取消订阅"; this.btnSubscribeCancel.UseVisualStyleBackColor = true; - this.btnSubscribeCancel.Click += new System.EventHandler(this.BtnSubscribeCancel_Click); + this.btnSubscribeCancel.Click += new System.EventHandler(this.btnSubscribeCancel_Click); // // label23 // this.label23.AutoSize = true; - this.label23.Location = new System.Drawing.Point(181, 114); + this.label23.Location = new System.Drawing.Point(241, 142); + this.label23.Margin = new System.Windows.Forms.Padding(4, 0, 4, 0); this.label23.Name = "label23"; - this.label23.Size = new System.Drawing.Size(47, 12); + this.label23.Size = new System.Drawing.Size(60, 15); this.label23.TabIndex = 4; this.label23.Text = "单位/秒"; // // numInterval // - this.numInterval.Location = new System.Drawing.Point(101, 109); + this.numInterval.Location = new System.Drawing.Point(135, 136); + this.numInterval.Margin = new System.Windows.Forms.Padding(4, 4, 4, 4); this.numInterval.Minimum = new decimal(new int[] { 5, 0, 0, 0}); this.numInterval.Name = "numInterval"; - this.numInterval.Size = new System.Drawing.Size(74, 21); + this.numInterval.Size = new System.Drawing.Size(99, 25); this.numInterval.TabIndex = 3; this.numInterval.Value = new decimal(new int[] { 5, @@ -1225,27 +1309,30 @@ // label22 // this.label22.AutoSize = true; - this.label22.Location = new System.Drawing.Point(18, 113); + this.label22.Location = new System.Drawing.Point(24, 141); + this.label22.Margin = new System.Windows.Forms.Padding(4, 0, 4, 0); this.label22.Name = "label22"; - this.label22.Size = new System.Drawing.Size(77, 12); + this.label22.Size = new System.Drawing.Size(97, 15); this.label22.TabIndex = 2; this.label22.Text = "上报时间间隔"; // // btnSubPositionInfo // - this.btnSubPositionInfo.Location = new System.Drawing.Point(20, 71); + this.btnSubPositionInfo.Location = new System.Drawing.Point(27, 89); + this.btnSubPositionInfo.Margin = new System.Windows.Forms.Padding(4, 4, 4, 4); this.btnSubPositionInfo.Name = "btnSubPositionInfo"; - this.btnSubPositionInfo.Size = new System.Drawing.Size(138, 23); + this.btnSubPositionInfo.Size = new System.Drawing.Size(184, 29); this.btnSubPositionInfo.TabIndex = 1; this.btnSubPositionInfo.Text = "移动位置数据订阅"; this.btnSubPositionInfo.UseVisualStyleBackColor = true; - this.btnSubPositionInfo.Click += new System.EventHandler(this.BtnSubPositionInfo_Click); + this.btnSubPositionInfo.Click += new System.EventHandler(this.btnSubPositionInfo_Click); // // btnAudioNotify // - this.btnAudioNotify.Location = new System.Drawing.Point(20, 22); + this.btnAudioNotify.Location = new System.Drawing.Point(27, 28); + this.btnAudioNotify.Margin = new System.Windows.Forms.Padding(4, 4, 4, 4); this.btnAudioNotify.Name = "btnAudioNotify"; - this.btnAudioNotify.Size = new System.Drawing.Size(138, 23); + this.btnAudioNotify.Size = new System.Drawing.Size(184, 29); this.btnAudioNotify.TabIndex = 0; this.btnAudioNotify.Text = "语音广播通知"; this.btnAudioNotify.UseVisualStyleBackColor = true; @@ -1265,10 +1352,11 @@ this.tabPage1.Controls.Add(this.label15); this.tabPage1.Controls.Add(this.txtDevName); this.tabPage1.Controls.Add(this.btnDevConfig); - this.tabPage1.Location = new System.Drawing.Point(4, 22); + this.tabPage1.Location = new System.Drawing.Point(4, 25); + this.tabPage1.Margin = new System.Windows.Forms.Padding(4, 4, 4, 4); this.tabPage1.Name = "tabPage1"; - this.tabPage1.Padding = new System.Windows.Forms.Padding(3); - this.tabPage1.Size = new System.Drawing.Size(332, 268); + this.tabPage1.Padding = new System.Windows.Forms.Padding(4, 4, 4, 4); + this.tabPage1.Size = new System.Drawing.Size(445, 339); this.tabPage1.TabIndex = 5; this.tabPage1.Text = "设备配置"; this.tabPage1.UseVisualStyleBackColor = true; @@ -1276,42 +1364,47 @@ // label21 // this.label21.AutoSize = true; - this.label21.Location = new System.Drawing.Point(174, 76); + this.label21.Location = new System.Drawing.Point(232, 95); + this.label21.Margin = new System.Windows.Forms.Padding(4, 0, 4, 0); this.label21.Name = "label21"; - this.label21.Size = new System.Drawing.Size(47, 12); + this.label21.Size = new System.Drawing.Size(60, 15); this.label21.TabIndex = 11; this.label21.Text = "单位/秒"; // // label20 // this.label20.AutoSize = true; - this.label20.Location = new System.Drawing.Point(174, 106); + this.label20.Location = new System.Drawing.Point(232, 132); + this.label20.Margin = new System.Windows.Forms.Padding(4, 0, 4, 0); this.label20.Name = "label20"; - this.label20.Size = new System.Drawing.Size(47, 12); + this.label20.Size = new System.Drawing.Size(60, 15); this.label20.TabIndex = 10; this.label20.Text = "单位/秒"; // // label19 // this.label19.AutoSize = true; - this.label19.Location = new System.Drawing.Point(174, 49); + this.label19.Location = new System.Drawing.Point(232, 61); + this.label19.Margin = new System.Windows.Forms.Padding(4, 0, 4, 0); this.label19.Name = "label19"; - this.label19.Size = new System.Drawing.Size(47, 12); + this.label19.Size = new System.Drawing.Size(60, 15); this.label19.TabIndex = 9; this.label19.Text = "单位/秒"; // // label18 // this.label18.AutoSize = true; - this.label18.Location = new System.Drawing.Point(4, 105); + this.label18.Location = new System.Drawing.Point(5, 131); + this.label18.Margin = new System.Windows.Forms.Padding(4, 0, 4, 0); this.label18.Name = "label18"; - this.label18.Size = new System.Drawing.Size(77, 12); + this.label18.Size = new System.Drawing.Size(97, 15); this.label18.TabIndex = 8; this.label18.Text = "心跳超时次数"; // // numIntervalTotal // - this.numIntervalTotal.Location = new System.Drawing.Point(83, 101); + this.numIntervalTotal.Location = new System.Drawing.Point(111, 126); + this.numIntervalTotal.Margin = new System.Windows.Forms.Padding(4, 4, 4, 4); this.numIntervalTotal.Maximum = new decimal(new int[] { 10, 0, @@ -1323,7 +1416,7 @@ 0, 0}); this.numIntervalTotal.Name = "numIntervalTotal"; - this.numIntervalTotal.Size = new System.Drawing.Size(85, 21); + this.numIntervalTotal.Size = new System.Drawing.Size(113, 25); this.numIntervalTotal.TabIndex = 7; this.numIntervalTotal.Value = new decimal(new int[] { 3, @@ -1334,22 +1427,24 @@ // label17 // this.label17.AutoSize = true; - this.label17.Location = new System.Drawing.Point(4, 77); + this.label17.Location = new System.Drawing.Point(5, 96); + this.label17.Margin = new System.Windows.Forms.Padding(4, 0, 4, 0); this.label17.Name = "label17"; - this.label17.Size = new System.Drawing.Size(77, 12); + this.label17.Size = new System.Drawing.Size(97, 15); this.label17.TabIndex = 6; this.label17.Text = "心跳间隔时间"; // // numIntervalTime // - this.numIntervalTime.Location = new System.Drawing.Point(83, 72); + this.numIntervalTime.Location = new System.Drawing.Point(111, 90); + this.numIntervalTime.Margin = new System.Windows.Forms.Padding(4, 4, 4, 4); this.numIntervalTime.Minimum = new decimal(new int[] { 5, 0, 0, 0}); this.numIntervalTime.Name = "numIntervalTime"; - this.numIntervalTime.Size = new System.Drawing.Size(85, 21); + this.numIntervalTime.Size = new System.Drawing.Size(113, 25); this.numIntervalTime.TabIndex = 5; this.numIntervalTime.Value = new decimal(new int[] { 30, @@ -1360,22 +1455,24 @@ // label16 // this.label16.AutoSize = true; - this.label16.Location = new System.Drawing.Point(4, 49); + this.label16.Location = new System.Drawing.Point(5, 61); + this.label16.Margin = new System.Windows.Forms.Padding(4, 0, 4, 0); this.label16.Name = "label16"; - this.label16.Size = new System.Drawing.Size(77, 12); + this.label16.Size = new System.Drawing.Size(97, 15); this.label16.TabIndex = 4; this.label16.Text = "注册过期时间"; // // numIntervalTimeOut // - this.numIntervalTimeOut.Location = new System.Drawing.Point(83, 44); + this.numIntervalTimeOut.Location = new System.Drawing.Point(111, 55); + this.numIntervalTimeOut.Margin = new System.Windows.Forms.Padding(4, 4, 4, 4); this.numIntervalTimeOut.Maximum = new decimal(new int[] { 8000, 0, 0, 0}); this.numIntervalTimeOut.Name = "numIntervalTimeOut"; - this.numIntervalTimeOut.Size = new System.Drawing.Size(85, 21); + this.numIntervalTimeOut.Size = new System.Drawing.Size(113, 25); this.numIntervalTimeOut.TabIndex = 3; this.numIntervalTimeOut.Value = new decimal(new int[] { 3600, @@ -1386,25 +1483,28 @@ // label15 // this.label15.AutoSize = true; - this.label15.Location = new System.Drawing.Point(28, 21); + this.label15.Location = new System.Drawing.Point(37, 26); + this.label15.Margin = new System.Windows.Forms.Padding(4, 0, 4, 0); this.label15.Name = "label15"; - this.label15.Size = new System.Drawing.Size(53, 12); + this.label15.Size = new System.Drawing.Size(67, 15); this.label15.TabIndex = 2; this.label15.Text = "设备名称"; // // txtDevName // - this.txtDevName.Location = new System.Drawing.Point(83, 17); + this.txtDevName.Location = new System.Drawing.Point(111, 21); + this.txtDevName.Margin = new System.Windows.Forms.Padding(4, 4, 4, 4); this.txtDevName.Name = "txtDevName"; - this.txtDevName.Size = new System.Drawing.Size(131, 21); + this.txtDevName.Size = new System.Drawing.Size(173, 25); this.txtDevName.TabIndex = 1; this.txtDevName.Text = "测试"; // // btnDevConfig // - this.btnDevConfig.Location = new System.Drawing.Point(83, 144); + this.btnDevConfig.Location = new System.Drawing.Point(111, 180); + this.btnDevConfig.Margin = new System.Windows.Forms.Padding(4, 4, 4, 4); this.btnDevConfig.Name = "btnDevConfig"; - this.btnDevConfig.Size = new System.Drawing.Size(75, 23); + this.btnDevConfig.Size = new System.Drawing.Size(100, 29); this.btnDevConfig.TabIndex = 0; this.btnDevConfig.Text = "设备配置"; this.btnDevConfig.UseVisualStyleBackColor = true; @@ -1412,15 +1512,16 @@ // // tvCalatog // - this.tvCalatog.Location = new System.Drawing.Point(6, 328); + this.tvCalatog.Location = new System.Drawing.Point(8, 410); + this.tvCalatog.Margin = new System.Windows.Forms.Padding(4, 4, 4, 4); this.tvCalatog.Name = "tvCalatog"; - this.tvCalatog.Size = new System.Drawing.Size(320, 156); + this.tvCalatog.Size = new System.Drawing.Size(425, 194); this.tvCalatog.TabIndex = 49; this.tvCalatog.AfterSelect += new System.Windows.Forms.TreeViewEventHandler(this.tvCalatog_AfterSelect); // // Form1 // - this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 12F); + this.AutoScaleDimensions = new System.Drawing.SizeF(8F, 15F); this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; this.ClientSize = new System.Drawing.Size(1055, 614); this.Controls.Add(this.tvCalatog); @@ -1438,9 +1539,10 @@ this.Controls.Add(this.lblStatus); this.Controls.Add(this.btnStop); this.Controls.Add(this.btnStart); - this.Name = "Form1"; + this.Margin = new System.Windows.Forms.Padding(4, 4, 4, 4); + this.Name = "Win.GB28181.Client(Alpha) - This is a Test Tool"; this.StartPosition = System.Windows.Forms.FormStartPosition.CenterScreen; - this.Text = "Form1"; + this.Text = "Win.GB28181.Client(Alpha) - This is a Test Tool"; this.tabControl1.ResumeLayout(false); this.tbReal.ResumeLayout(false); this.tbRecord.ResumeLayout(false); @@ -1463,7 +1565,7 @@ } - + #endregion @@ -1588,7 +1690,7 @@ private System.Windows.Forms.Button btnKeyFrame; private System.Windows.Forms.TreeView tvCalatog; private System.Windows.Forms.Button button2; - private Win.ClientBase.PlayerControl playerWin; + private SS.ClientBase.PlayerControl playerWin; } } diff --git a/Win.GB28181.Client/Form1.cs b/Win.GB28181.Client/Form1.cs index 36a555e..08b5c5c 100644 --- a/Win.GB28181.Client/Form1.cs +++ b/Win.GB28181.Client/Form1.cs @@ -1,5 +1,4 @@ -using GB28181.Logger4Net; -using GB28181.SIPSorcery.Net; +using GB28181.SIPSorcery.Net; using GB28181.SIPSorcery.Servers; using GB28181.SIPSorcery.Servers.SIPMessage; using GB28181.SIPSorcery.Servers.SIPMonitor; @@ -8,20 +7,18 @@ using GB28181.SIPSorcery.Sys; using GB28181.SIPSorcery.Sys.Config; using GB28181.SIPSorcery.Sys.Model; using GB28181.SIPSorcery.Sys.XML; +using GB28181.Logger4Net; +using SS.Media; +using SS.MediaServer.Media.TS; using System; using System.Collections.Generic; -using System.ComponentModel; using System.Drawing; using System.IO; using System.Linq; -using System.Reflection; using System.Text; -using System.Text.RegularExpressions; using System.Threading; using System.Windows.Forms; using Win.GB28181.Client.Player.Analyzer; -using Win.Media; -using Win.MediaServer.Media.TS; namespace Win.GB28181.Client { @@ -35,8 +32,8 @@ namespace Win.GB28181.Client private string _dir = AppDomain.CurrentDomain.BaseDirectory + "Config"; private DateTime _keepaliveTime; private Thread _keepaliveThread; - private readonly Queue _keepQueue = new Queue(); - //private int _count = 0; + private Queue _keepQueue = new Queue(); + private int _count = 0; private SIPMessageCore _messageCore; #endregion @@ -44,7 +41,7 @@ namespace Win.GB28181.Client /// /// 选择的设备键 /// - private string DevKey + private MonitorKey DevKey { get { @@ -53,13 +50,12 @@ namespace Win.GB28181.Client { devItem = item; } - // MonitorKey key = new MonitorKey() - // { - // DeviceID = devItem.ImageKey, - // CmdType = CommandType.Play - // }; - // return key; - return devItem.ImageKey; + var key = new MonitorKey() + { + DeviceID = devItem.ImageKey, + CmdType = CommandType.Play + }; + return key; } } #endregion @@ -93,7 +89,6 @@ namespace Win.GB28181.Client public Form1() { InitializeComponent(); - Initialize(); } private void Initialize() @@ -103,50 +98,42 @@ namespace Win.GB28181.Client txtStopTime.Text = DateTime.Now.ToString("yyyy-MM-dd 9:00:00"); //txtDragDrop.Text = DateTime.Now.ToString("yyyy-MM-dd 14:00:00"); - var configType = new Dictionary - { - { "BasicParam", "基本参数配置" }, - { "VideoParamOpt", "视频参数范围" }, - { "SVACEncodeConfig", "SVAC编码配置" }, - { "SVACDecodeConfig", "SVAC解码配置" } - }; - BindingSource bs = new BindingSource - { - DataSource = configType - }; + Dictionary configType = new Dictionary(); + configType.Add("BasicParam", "基本参数配置"); + configType.Add("VideoParamOpt", "视频参数范围"); + configType.Add("SVACEncodeConfig", "SVAC编码配置"); + configType.Add("SVACDecodeConfig", "SVAC解码配置"); + BindingSource bs = new BindingSource(); + bs.DataSource = configType; cbxConfig.DataSource = bs; cbxConfig.DisplayMember = "Value"; cbxConfig.ValueMember = "Key"; - Dictionary recordType = new Dictionary - { - { "time", "time" }, - { "alarm", "alarm" }, - { "manual", "manual" }, - { "all", "all" } - }; - BindingSource bsRecord = new BindingSource - { - DataSource = recordType - }; + Dictionary recordType = new Dictionary(); + recordType.Add("time", "time"); + recordType.Add("alarm", "alarm"); + recordType.Add("manual", "manual"); + recordType.Add("all", "all"); + BindingSource bsRecord = new BindingSource(); + bsRecord.DataSource = recordType; cbxRecordType.DataSource = bsRecord; cbxRecordType.DisplayMember = "Value"; cbxRecordType.ValueMember = "Key"; - SipAccountStorage.Instance.Read(); - IList cameras = new List(); - var account = SipAccountStorage.Instance.Accounts.First(); - if (account == null) - { - logger.Error("Account Config NULL,SIP not started"); - return; - } + //SIPSqlite.Instance.Read(); + // var cameras = new List(); + // var account = SIPSqlite.Instance.Accounts.First(); + //if (account == null) + //{ + // logger.Error("Account Config NULL,SIP not started"); + // return; + //} _keepaliveTime = DateTime.Now; _cataThread = new Thread(new ThreadStart(HandleCata)); _keepaliveThread = new Thread(new ThreadStart(HandleKeepalive)); - // _messageCore = new SIPMessageCore(cameras, account); + // _messageCore = new SIPMessageCore(cameras, account); } #endregion @@ -159,16 +146,14 @@ namespace Win.GB28181.Client #endregion #region 开始/停止服务 - private void BtnStart_Click(object sender, System.EventArgs e) + private void btnStart_Click(object sender, System.EventArgs e) { - //_tn = new TreeNode(); //tvCalatog.Nodes.Add(_tn); //_bg = new TreeNode(); //_tn.Nodes.Add(_bg); //tvCalatog.Nodes.Add(_tn); - txtStartTime.Text = DateTime.Now.ToString("yyyy-MM-dd 8:00:00"); _keepaliveTime = DateTime.Now; playerWin.Start(); Initialize(); @@ -181,6 +166,7 @@ namespace Win.GB28181.Client _messageCore.OnCatalogReceived += m_msgCore_OnCatalogReceived; _messageCore.OnNotifyCatalogReceived += MessageCore_OnNotifyCatalogReceived; _messageCore.OnAlarmReceived += MessageCore_OnAlarmReceived; + _messageCore.OnRecordInfoReceived += MessageCore_OnRecordInfoReceived; _messageCore.OnKeepaliveReceived += MessageCore_OnKeepaliveReceived; _messageCore.OnDeviceStatusReceived += DeviceStatusReceived; @@ -303,13 +289,12 @@ namespace Win.GB28181.Client Invoke(new Action(() => { MessageBox.Show(msg); - // var key = new MonitorKey() - // { - // CmdType = CommandType.Play, - // DeviceID = alarm.DeviceID - // }; - var key = alarm.DeviceID; - _messageCore.NodeMonitorService[key].AlarmResponse(alarm); + var key = new MonitorKey() + { + CmdType = CommandType.Play, + DeviceID = alarm.DeviceID + }; + _messageCore.NodeMonitorService[key.ToString()].AlarmResponse(alarm); //txtMsg.Text = msg; })); } @@ -463,22 +448,22 @@ namespace Win.GB28181.Client #region 其他接口 //系统设备配置查询 - private void BtnConfigQuery_Click(object sender, EventArgs e) + private void btnConfigQuery_Click(object sender, EventArgs e) { string configType = cbxConfig.SelectedValue.ToString(); - _messageCore.NodeMonitorService[DevKey].DeviceConfigQuery(configType); + _messageCore.NodeMonitorService[DevKey.ToString()].DeviceConfigQuery(configType); } //设备状态查询 - private void BtnStateSearch_Click(object sender, EventArgs e) + private void btnStateSearch_Click(object sender, EventArgs e) { - _messageCore.NodeMonitorService[DevKey].DeviceStateQuery(); + _messageCore.NodeMonitorService[DevKey.ToString()].DeviceStateQuery(); } //设备详细信息查询 private void btnDevSearch_Click(object sender, EventArgs e) { - _messageCore.NodeMonitorService[DevKey].DeviceInfoQuery(); + _messageCore.NodeMonitorService[DevKey.ToString()].DeviceInfoQuery(); } //设备信息查询回调函数 @@ -509,7 +494,7 @@ namespace Win.GB28181.Client //设备重启 private void brnRenboot_Click(object sender, EventArgs e) { - _messageCore.NodeMonitorService[DevKey].DeviceReboot(); + _messageCore.NodeMonitorService[DevKey.ToString()].DeviceReboot(); } //设备配置 @@ -523,10 +508,12 @@ namespace Win.GB28181.Client int expiration = (int)numIntervalTimeOut.Value; int heartBeatInterval = (int)numIntervalTime.Value; int heartBeatToal = (int)numIntervalTotal.Value; - _messageCore.NodeMonitorService[DevKey].DeviceConfig(name, expiration, heartBeatInterval, heartBeatToal); + _messageCore.NodeMonitorService[DevKey.ToString()].DeviceConfig(name, expiration, heartBeatInterval, heartBeatToal); } - public static byte[] ConvertUnicodeToUTF8(string message) + public byte[] ConvertUnicodeToUTF8(string message) { + System.Text.Encoding utf8, gb2312; + utf8 = System.Text.Encoding.GetEncoding("utf-8"); byte[] array = Encoding.Default.GetBytes(message); byte[] s4 = System.Text.Encoding.Convert(System.Text.Encoding.GetEncoding("gb2312"), System.Text.Encoding.UTF8, array); return s4; @@ -543,25 +530,25 @@ namespace Win.GB28181.Client //事件订阅 private void btnEventSubscribe_Click(object sender, EventArgs e) { - _messageCore.NodeMonitorService[DevKey].DeviceEventSubscribe(); + _messageCore.NodeMonitorService[DevKey.ToString()].DeviceEventSubscribe(); } //布防 private void btnSetGuard_Click(object sender, EventArgs e) { - _messageCore.NodeMonitorService[DevKey].DeviceControlSetGuard(); + _messageCore.NodeMonitorService[DevKey.ToString()].DeviceControlSetGuard(); } //撤防 private void btResetGuard_Click(object sender, EventArgs e) { - _messageCore.NodeMonitorService[DevKey].DeviceControlResetGuard(); + _messageCore.NodeMonitorService[DevKey.ToString()].DeviceControlResetGuard(); } //报警复位 private void btnAlarmReset_Click(object sender, EventArgs e) { - _messageCore.NodeMonitorService[DevKey].DeviceControlResetAlarm(); + _messageCore.NodeMonitorService[DevKey.ToString()].DeviceControlResetAlarm(); } #endregion @@ -569,7 +556,7 @@ namespace Win.GB28181.Client //目录订阅 private void btnCatalogSubscribe_Click(object sender, EventArgs e) { - _messageCore.NodeMonitorService[DevKey].DeviceCatalogSubscribe(true); + _messageCore.NodeMonitorService[DevKey.ToString()].DeviceCatalogSubscribe(true); } //目录查询 @@ -589,24 +576,20 @@ namespace Win.GB28181.Client private void BtnReal_Click(object sender, EventArgs e) { _analyzer = new StreamAnalyzer(); -// _messageCore.NodeMonitorService[DevKey].RealVideoReq(); - // _messageCore.NodeMonitorService[DevKey].OnStreamReady += Form1_OnStreamReady; + _messageCore.NodeMonitorService[DevKey.ToString()].RealVideoReq(); + _messageCore.NodeMonitorService[DevKey.ToString()].OnStreamReady += Form1_OnStreamReady; } //停止实时视频 private void BtnBye_Click(object sender, EventArgs e) { - // _messageCore.NodeMonitorService[DevKey].OnStreamReady -= Form1_OnStreamReady; - _messageCore.NodeMonitorService[DevKey].ByeVideoReq(); + _messageCore.NodeMonitorService[DevKey.ToString()].OnStreamReady -= Form1_OnStreamReady; + _messageCore.NodeMonitorService[DevKey.ToString()].ByeVideoReq(); } FileStream m_fs; void Form1_OnStreamReady(RTPFrame rtpFrame) { - if (rtpFrame == null) - { - throw new ArgumentNullException(nameof(rtpFrame)); - } //byte[] buffer = rtpFrame.GetFramePayload(); //if (this.m_fs == null) //{ @@ -655,96 +638,95 @@ namespace Win.GB28181.Client } //录像播放(点播) - private void BtnRecord_Click(object sender, EventArgs e) + private void btnRecord_Click(object sender, EventArgs e) { _analyzer = new StreamAnalyzer(); var key = DevKey; - // key.CmdType = CommandType.Playback; + key.CmdType = CommandType.Playback; DateTime startTime = DateTime.Parse(txtStartTime.Text.Trim()); DateTime stopTime = DateTime.Parse(txtStopTime.Text.Trim()); - _messageCore.NodeMonitorService[key].BackVideoReq(startTime, stopTime); - // _messageCore.NodeMonitorService[key].OnStreamReady += Form1_OnStreamReady; + _messageCore.NodeMonitorService[key.ToString()].BackVideoReq(startTime, stopTime); + // _messageCore.NodeMonitorService[key.ToString()].OnStreamReady += Form1_OnStreamReady; } //终止点播(停止) - private void BtnStopRecord_Click(object sender, EventArgs e) + private void btnStopRecord_Click(object sender, EventArgs e) { var key = DevKey; - // key.CmdType = CommandType.Playback; - _messageCore.NodeMonitorService[key].ByeVideoReq(); - // _messageCore.NodeMonitorService[key].OnStreamReady -= Form1_OnStreamReady; + key.CmdType = CommandType.Playback; + _messageCore.NodeMonitorService[key.ToString()].ByeVideoReq(); + _messageCore.NodeMonitorService[key.ToString()].OnStreamReady -= Form1_OnStreamReady; } //暂停播放 - private void BtnPause_Click(object sender, EventArgs e) + private void btnPause_Click(object sender, EventArgs e) { var key = DevKey; -// key.CmdType = CommandType.Playback; - _messageCore.NodeMonitorService[key].BackVideoPauseControlReq(); + key.CmdType = CommandType.Playback; + _messageCore.NodeMonitorService[key.ToString()].BackVideoPauseControlReq(); } //继续播放 - private void BtnPlay_Click(object sender, EventArgs e) + private void btnPlay_Click(object sender, EventArgs e) { var key = DevKey; -// key.CmdType = CommandType.Playback; - _messageCore.NodeMonitorService[key].BackVideoContinuePlayingControlReq(); + key.CmdType = CommandType.Playback; + _messageCore.NodeMonitorService[key.ToString()].BackVideoContinuePlayingControlReq(); } //播放倍数设置 - private void BtnSdu_Click(object sender, EventArgs e) + private void btnSdu_Click(object sender, EventArgs e) { var key = DevKey; - // key.CmdType = CommandType.Playback; + key.CmdType = CommandType.Playback; string range = txtScale.Text.Trim(); - _messageCore.NodeMonitorService[key].BackVideoPlaySpeedControlReq(range); + _messageCore.NodeMonitorService[key.ToString()].BackVideoPlaySpeedControlReq(range); } //拖动播放 - private void Button17_Click(object sender, EventArgs e) + private void button17_Click(object sender, EventArgs e) { var key = DevKey; - // key.CmdType = CommandType.Playback; + key.CmdType = CommandType.Playback; int time = int.Parse(txtDragDrop.Text.Trim()); - _messageCore.NodeMonitorService[key].BackVideoPlayPositionControlReq(time); + _messageCore.NodeMonitorService[key.ToString()].BackVideoPlayPositionControlReq(time); } //录像文件查询 - private void BtnRecordGet_Click(object sender, EventArgs e) + private void btnRecordGet_Click(object sender, EventArgs e) { _recordSN = 1; lvRecord.Items.Clear(); DateTime startTime = DateTime.Parse(txtStartTime.Text.Trim()); DateTime stopTime = DateTime.Parse(txtStopTime.Text.Trim()); - var key = DevKey; - // key.CmdType = CommandType.Playback; + //key.CmdType = CommandType.Playback; string type = cbxRecordType.SelectedValue.ToString(); - _messageCore.NodeMonitorService[key].RecordFileQuery(startTime, stopTime, type); + _messageCore.NodeMonitorService[DevKey.ToString()].RecordFileQuery(startTime, stopTime, type); } //录像文件下载 private void btnRecordDownload_Click(object sender, EventArgs e) { var key = DevKey; - // key.CmdType = CommandType.Playback; + key.CmdType = CommandType.Playback; DateTime startTime = DateTime.Parse(txtStartTime.Text.Trim()); DateTime stopTime = DateTime.Parse(txtStopTime.Text.Trim()); - _messageCore.NodeMonitorService[key].VideoDownloadReq(startTime, stopTime); - // _messageCore.NodeMonitorService[key].OnStreamReady += Form1_OnStreamReady; + _messageCore.NodeMonitorService[key.ToString()].VideoDownloadReq(startTime, stopTime); + _messageCore.NodeMonitorService[key.ToString()].OnStreamReady += Form1_OnStreamReady; } //开始手动录像 private void btnStartRecord_Click(object sender, EventArgs e) { - _messageCore.NodeMonitorService[DevKey].DeviceControlRecord(true); + _messageCore.NodeMonitorService[DevKey.ToString()].DeviceControlRecord(true); } //停止手动录像 - private void BtnStopRd_Click(object sender, EventArgs e) + private void btnStopRd_Click(object sender, EventArgs e) { - _messageCore.NodeMonitorService[DevKey].DeviceControlRecord(false); + _messageCore.NodeMonitorService[DevKey.ToString()].DeviceControlRecord(false); } #endregion @@ -753,55 +735,55 @@ namespace Win.GB28181.Client //上 private void btnUP_Click(object sender, EventArgs e) { - _messageCore.NodeMonitorService[DevKey].PtzContrl(PTZCommand.Up, int.Parse(numberSpeed.Value.ToString())); + _messageCore.NodeMonitorService[DevKey.ToString()].PtzContrl(PTZCommand.Up, int.Parse(numberSpeed.Value.ToString())); } //下 private void btnDown_Click(object sender, EventArgs e) { - _messageCore.NodeMonitorService[DevKey].PtzContrl(PTZCommand.Down, int.Parse(numberSpeed.Value.ToString())); + _messageCore.NodeMonitorService[DevKey.ToString()].PtzContrl(PTZCommand.Down, int.Parse(numberSpeed.Value.ToString())); } //左 private void btnLeft_Click(object sender, EventArgs e) { - _messageCore.NodeMonitorService[DevKey].PtzContrl(PTZCommand.Left, int.Parse(numberSpeed.Value.ToString())); + _messageCore.NodeMonitorService[DevKey.ToString()].PtzContrl(PTZCommand.Left, int.Parse(numberSpeed.Value.ToString())); } //右 private void btnRight_Click(object sender, EventArgs e) { - _messageCore.NodeMonitorService[DevKey].PtzContrl(PTZCommand.Right, int.Parse(numberSpeed.Value.ToString())); + _messageCore.NodeMonitorService[DevKey.ToString()].PtzContrl(PTZCommand.Right, int.Parse(numberSpeed.Value.ToString())); } //左上 private void btnLeftUP_Click(object sender, EventArgs e) { - _messageCore.NodeMonitorService[DevKey].PtzContrl(PTZCommand.UpLeft, int.Parse(numberSpeed.Value.ToString())); + _messageCore.NodeMonitorService[DevKey.ToString()].PtzContrl(PTZCommand.UpLeft, int.Parse(numberSpeed.Value.ToString())); } //右上 private void btnRightUP_Click(object sender, EventArgs e) { - _messageCore.NodeMonitorService[DevKey].PtzContrl(PTZCommand.UpRight, int.Parse(numberSpeed.Value.ToString())); + _messageCore.NodeMonitorService[DevKey.ToString()].PtzContrl(PTZCommand.UpRight, int.Parse(numberSpeed.Value.ToString())); } //左下 private void btnLeftDown_Click(object sender, EventArgs e) { - _messageCore.NodeMonitorService[DevKey].PtzContrl(PTZCommand.DownLeft, int.Parse(numberSpeed.Value.ToString())); + _messageCore.NodeMonitorService[DevKey.ToString()].PtzContrl(PTZCommand.DownLeft, int.Parse(numberSpeed.Value.ToString())); } //右下 private void btnRightDown_Click(object sender, EventArgs e) { - _messageCore.NodeMonitorService[DevKey].PtzContrl(PTZCommand.DownRight, int.Parse(numberSpeed.Value.ToString())); + _messageCore.NodeMonitorService[DevKey.ToString()].PtzContrl(PTZCommand.DownRight, int.Parse(numberSpeed.Value.ToString())); } //停止 private void btnPTZStop_Click(object sender, EventArgs e) { - _messageCore.NodeMonitorService[DevKey].PtzContrl(PTZCommand.Stop, int.Parse(numberSpeed.Value.ToString())); + _messageCore.NodeMonitorService[DevKey.ToString()].PtzContrl(PTZCommand.Stop, int.Parse(numberSpeed.Value.ToString())); } #endregion @@ -809,14 +791,14 @@ namespace Win.GB28181.Client //设置预置位 private void btnSetPreset_Click(object sender, EventArgs e) { - _messageCore.NodeMonitorService[DevKey].PtzContrl(PTZCommand.SetPreset, int.Parse(numberSpeed.Value.ToString())); + _messageCore.NodeMonitorService[DevKey.ToString()].PtzContrl(PTZCommand.SetPreset, int.Parse(numberSpeed.Value.ToString())); } //查询预置位 private void btnSearchPreset_Click(object sender, EventArgs e) { cbxPreset.Items.Clear(); - _messageCore.NodeMonitorService[DevKey].DevicePresetQuery(); + _messageCore.NodeMonitorService[DevKey.ToString()].DevicePresetQuery(); } //private Dictionary presetList = new Dictionary(); @@ -854,7 +836,7 @@ namespace Win.GB28181.Client /// 调用预置位 private void btnGetPreset_Click(object sender, EventArgs e) { - _messageCore.NodeMonitorService[DevKey].PtzContrl(PTZCommand.GetPreset, int.Parse(numberSpeed.Value.ToString())); + _messageCore.NodeMonitorService[DevKey.ToString()].PtzContrl(PTZCommand.GetPreset, int.Parse(numberSpeed.Value.ToString())); } //删除预置位 @@ -862,7 +844,7 @@ namespace Win.GB28181.Client { if (cbxPreset.SelectedItem != null) { - _messageCore.NodeMonitorService[DevKey].PtzContrl(PTZCommand.RemovePreset, int.Parse(cbxPreset.SelectedItem.ToString())); + _messageCore.NodeMonitorService[DevKey.ToString()].PtzContrl(PTZCommand.RemovePreset, int.Parse(cbxPreset.SelectedItem.ToString())); cbxPreset.Items.Remove(cbxPreset.SelectedItem); //presetList.Remove(cbxPreset.SelectedText.ToString()); //reloadPreset(); @@ -873,39 +855,39 @@ namespace Win.GB28181.Client #region 变倍/聚焦/光圈 //变倍+ - private void BtnZoom1_Click(object sender, EventArgs e) + private void btnZoom1_Click(object sender, EventArgs e) { - _messageCore.NodeMonitorService[DevKey].PtzContrl(PTZCommand.Zoom1, int.Parse(numberSpeed.Value.ToString())); + _messageCore.NodeMonitorService[DevKey.ToString()].PtzContrl(PTZCommand.Zoom1, int.Parse(numberSpeed.Value.ToString())); } //变倍- private void btnZoom2_Click(object sender, EventArgs e) { - _messageCore.NodeMonitorService[DevKey].PtzContrl(PTZCommand.Zoom2, int.Parse(numberSpeed.Value.ToString())); + _messageCore.NodeMonitorService[DevKey.ToString()].PtzContrl(PTZCommand.Zoom2, int.Parse(numberSpeed.Value.ToString())); } //聚焦+ - private void BtnFocus1_Click(object sender, EventArgs e) + private void btnFocus1_Click(object sender, EventArgs e) { - _messageCore.NodeMonitorService[DevKey].PtzContrl(PTZCommand.Focus1, int.Parse(numberSpeed.Value.ToString())); + _messageCore.NodeMonitorService[DevKey.ToString()].PtzContrl(PTZCommand.Focus1, int.Parse(numberSpeed.Value.ToString())); } //聚焦- private void btnFocus2_Click(object sender, EventArgs e) { - _messageCore.NodeMonitorService[DevKey].PtzContrl(PTZCommand.Focus2, int.Parse(numberSpeed.Value.ToString())); + _messageCore.NodeMonitorService[DevKey.ToString()].PtzContrl(PTZCommand.Focus2, int.Parse(numberSpeed.Value.ToString())); } //光圈开 private void btnIris1_Click(object sender, EventArgs e) { - _messageCore.NodeMonitorService[DevKey].PtzContrl(PTZCommand.Iris1, int.Parse(numberSpeed.Value.ToString())); + _messageCore.NodeMonitorService[DevKey.ToString()].PtzContrl(PTZCommand.Iris1, int.Parse(numberSpeed.Value.ToString())); } //光圈关 private void btnIris2_Click(object sender, EventArgs e) { - _messageCore.NodeMonitorService[DevKey].PtzContrl(PTZCommand.Iris2, int.Parse(numberSpeed.Value.ToString())); + _messageCore.NodeMonitorService[DevKey.ToString()].PtzContrl(PTZCommand.Iris2, int.Parse(numberSpeed.Value.ToString())); } #endregion @@ -934,14 +916,14 @@ namespace Win.GB28181.Client private void btnZoomIn_Click(object sender, EventArgs e) { var zoom = DragZoomValue(); - _messageCore.NodeMonitorService[DevKey].DragZoomContrl(zoom, true); + _messageCore.NodeMonitorService[DevKey.ToString()].DragZoomContrl(zoom, true); } //拉框缩小 private void btnZoomOut_Click(object sender, EventArgs e) { var zoom = DragZoomValue(); - _messageCore.NodeMonitorService[DevKey].DragZoomContrl(zoom, false); + _messageCore.NodeMonitorService[DevKey.ToString()].DragZoomContrl(zoom, false); } #endregion @@ -949,13 +931,13 @@ namespace Win.GB28181.Client //看守位开 private void btnPositionOpen_Click(object sender, EventArgs e) { - _messageCore.NodeMonitorService[DevKey].HomePositionControl(true); + _messageCore.NodeMonitorService[DevKey.ToString()].HomePositionControl(true); } //看守位关 private void btnPositionClose_Click(object sender, EventArgs e) { - _messageCore.NodeMonitorService[DevKey].HomePositionControl(false); + _messageCore.NodeMonitorService[DevKey.ToString()].HomePositionControl(false); } #endregion #endregion @@ -1082,7 +1064,7 @@ namespace Win.GB28181.Client }; playerWin.Play(frame); } - catch (Exception) + catch (Exception ex) { } } @@ -1108,8 +1090,8 @@ namespace Win.GB28181.Client //header.GetBytes(); //packet.Header = header; //packet.Payload = buffer; - - // string viaStr = via.ToString(); + + // string viaStr = via.ToString(); Console.WriteLine(""); @@ -1224,22 +1206,22 @@ a=rtpmap:97 MPEG4/90000"; /// private void BtnAudioNotify_Click(object sender, EventArgs e) { - _messageCore.NodeMonitorService[DevKey].AudioPublishNotify(); + _messageCore.NodeMonitorService[DevKey.ToString()].AudioPublishNotify(); } - private void BtnSubPositionInfo_Click(object sender, EventArgs e) + private void btnSubPositionInfo_Click(object sender, EventArgs e) { int interval = (int)numInterval.Value; - _messageCore.NodeMonitorService[DevKey].MobilePositionQueryRequest(interval, true); + _messageCore.NodeMonitorService[DevKey.ToString()].MobilePositionQueryRequest(interval, true); } #endregion - private void BtnSubscribeCancel_Click(object sender, EventArgs e) + private void btnSubscribeCancel_Click(object sender, EventArgs e) { int interval = (int)numInterval.Value; - _messageCore.NodeMonitorService[DevKey].MobilePositionQueryRequest(interval, false); + _messageCore.NodeMonitorService[DevKey.ToString()].MobilePositionQueryRequest(interval, false); } #region 移动设备位置数据订阅/通知 @@ -1272,7 +1254,7 @@ a=rtpmap:97 MPEG4/90000"; /// private void btnKeyFrame_Click(object sender, EventArgs e) { - _messageCore.NodeMonitorService[DevKey].MakeKeyFrameRequest(); + _messageCore.NodeMonitorService[DevKey.ToString()].MakeKeyFrameRequest(); } private void tvCalatog_AfterSelect(object sender, TreeViewEventArgs e) @@ -1293,7 +1275,7 @@ a=rtpmap:97 MPEG4/90000"; private void button2_Click_1(object sender, EventArgs e) { - _messageCore.NodeMonitorService[DevKey].DeviceCatalogSubscribe(false); + _messageCore.NodeMonitorService[DevKey.ToString()].DeviceCatalogSubscribe(false); } } diff --git a/Win.GB28181.Client/Message/SIPMessageDaemon.cs b/Win.GB28181.Client/Message/SIPMessageDaemon.cs index cc8578f..96950a3 100644 --- a/Win.GB28181.Client/Message/SIPMessageDaemon.cs +++ b/Win.GB28181.Client/Message/SIPMessageDaemon.cs @@ -34,24 +34,18 @@ // POSSIBILITY OF SUCH DAMAGE. // ============================================================================ -using System; -using System.Collections.Generic; -using System.IO; -using System.Linq; -using System.Net; -using System.Net.Sockets; -using System.Text; -using System.Xml; -using GB28181.SIPSorcery.Persistence; +using GB28181.Logger4Net; +using GB28181.SIPSorcery.Servers; +using GB28181.SIPSorcery.Servers.SIPMessage; using GB28181.SIPSorcery.SIP; using GB28181.SIPSorcery.SIP.App; -using GB28181.SIPSorcery.Servers; using GB28181.SIPSorcery.Sys; -using GB28181.Logger4Net; -using GB28181.SIPSorcery.Servers.SIPMessage; using GB28181.SIPSorcery.Sys.Config; +using System; +using System.Collections.Generic; +using System.Linq; -namespace Win.GB28181.Client.Message +namespace Gb28181_Client.Message { public class SIPMessageDaemon { @@ -59,7 +53,7 @@ namespace Win.GB28181.Client.Message private SIPTransport m_sipTransport; - private SIPAssetGetDelegate GetSIPAccount_External; + // private SIPAssetGetDelegate GetSIPAccount_External; private SIPAuthenticateRequestDelegate SIPAuthenticateRequest_External; private Dictionary _platformList; private SIPAccount _account; @@ -86,14 +80,12 @@ namespace Win.GB28181.Client.Message m_sipTransport = new SIPTransport(SIPDNSManager.ResolveSIPService, new SIPTransactionEngine(), false); m_sipTransport.PerformanceMonitorPrefix = SIPSorceryPerformanceMonitor.REGISTRAR_PREFIX; SIPAccount account = SipAccountStorage.Instance.Accounts.FirstOrDefault(); - var sipChannels = SIPTransportConfig.ParseSIPChannelsNode(account.LocalIP, account.LocalPort); m_sipTransport.AddSIPChannel(sipChannels); + MessageCore = new SIPMessageCore(m_sipTransport, SIPConstants.SIP_SERVER_STRING); - - MessageCore.Initialize(SIPAuthenticateRequest_External, _platformList,_account); - + MessageCore.Initialize(SIPAuthenticateRequest_External, _platformList, _account); GB28181Catalog.Instance.MessageCore = MessageCore; m_sipTransport.SIPTransportRequestReceived += MessageCore.AddMessageRequest; m_sipTransport.SIPTransportResponseReceived += MessageCore.AddMessageResponse; diff --git a/Win.GB28181.Client/Message/SIPMessagetate.cs b/Win.GB28181.Client/Message/SIPMessagetate.cs index 298226b..bb8ddee 100644 --- a/Win.GB28181.Client/Message/SIPMessagetate.cs +++ b/Win.GB28181.Client/Message/SIPMessagetate.cs @@ -34,17 +34,11 @@ // POSSIBILITY OF SUCH DAMAGE. // ============================================================================ +using GB28181.Logger4Net; using System; -using System.Collections.Generic; -using System.Linq; -using System.Net; -using System.Text; using System.Xml; -using GB28181.Logger4Net; -using GB28181.SIPSorcery.Sys; -using System.Configuration; -namespace Win.GB28181.Client.Message +namespace Gb28181_Client.Message { /// /// Retrieves application conifguration settings from App.Config. @@ -78,7 +72,7 @@ namespace Win.GB28181.Client.Message try { - // GB28181.Logger4Net.Config.XmlConfigurator.Configure(); + // log4net.Config.XmlConfigurator.Configure(); logger = LogManager.GetLogger(LOGGER_NAME); } catch (Exception logExcp) diff --git a/Win.GB28181.Client/Player/Codec/AVCodecCfg.cs b/Win.GB28181.Client/Player/Codec/AVCodecCfg.cs index ab9dc5c..0532533 100644 --- a/Win.GB28181.Client/Player/Codec/AVCodecCfg.cs +++ b/Win.GB28181.Client/Player/Codec/AVCodecCfg.cs @@ -3,10 +3,10 @@ using System.Collections.Generic; using System.Linq; using System.Text; using System.Runtime.InteropServices; -using Win.Media; +using SS.Media; using System.IO; -namespace Win.ClientBase.Codec +namespace SS.ClientBase.Codec { /// /// 音视频编码参数设置 @@ -80,7 +80,7 @@ namespace Win.ClientBase.Codec // encodeName = name; // encoder = GetGeneralEncoder(name); // } - + // // 获取通用编码代号 // public static int GetGeneralEncoder(String name) { @@ -96,14 +96,12 @@ namespace Win.ClientBase.Codec //} - public class VideoEncodeCfg : Win.Media.Codec.VideoEncodeCfg - { - + public class VideoEncodeCfg : SS.Media.Codec.VideoEncodeCfg { + public IYUVDraw Draw; + - - public static VideoEncodeCfg GetDefaule(IYUVDraw _Draw = null) - { + public static VideoEncodeCfg GetDefaule(IYUVDraw _Draw = null) { VideoEncodeCfg encCfg = new VideoEncodeCfg(); encCfg.SetEncoder("H264"); @@ -120,8 +118,7 @@ namespace Win.ClientBase.Codec - public class AudioEncodeCfg : Win.Media.Codec.AudioEncodeCfg - { + public class AudioEncodeCfg : SS.Media.Codec.AudioEncodeCfg { public int micId = 0; public int frequency = 8000;// 采样 public int format = 16;// 位元 @@ -132,8 +129,7 @@ namespace Win.ClientBase.Codec - public static AudioEncodeCfg GetDefault() - { + public static AudioEncodeCfg GetDefault() { AudioEncodeCfg r = new AudioEncodeCfg(); r.SetEncoder("AAC_"); r.frequency = 32000; diff --git a/Win.GB28181.Client/Player/Codec/CameraEncoder.cs b/Win.GB28181.Client/Player/Codec/CameraEncoder.cs index 382aad5..b025a31 100644 --- a/Win.GB28181.Client/Player/Codec/CameraEncoder.cs +++ b/Win.GB28181.Client/Player/Codec/CameraEncoder.cs @@ -2,10 +2,10 @@ using GLib.AXLib.Utility; using GLib.Extension; using GLib.GeneralModel; -using Win.ClientBase.Mixer.Video; -using Win.Comm; -using Win.Media; -using Win.WPFClient.DShow; +using SS.ClientBase.Mixer.Video; +using SS.Comm; +using SS.Media; +using SS.WPFClient.DShow; using System; using System.Collections.Generic; using System.Drawing; @@ -14,7 +14,7 @@ using System.Drawing.Imaging; using System.Runtime.InteropServices; using System.Threading; -namespace Win.ClientBase.Codec +namespace SS.ClientBase.Codec { public class CameraCapturer : IDisposable { @@ -29,12 +29,12 @@ namespace Win.ClientBase.Codec private bool _isworking = false; private bool _isDisoseing = false; private bool _isDisosed = false; - private readonly int _camera; - private readonly int _width; - private readonly int _height; + private int _camera; + private int _width; + private int _height; private FFScale _ffscale = null; - private readonly Action _callBack = null; + private Action _callBack = null; public CameraCapturer() { } @@ -173,7 +173,8 @@ namespace Win.ClientBase.Codec buf = _ffscale.Convert(buf); - _callBack?.Invoke(buf); + if (_callBack != null) + _callBack(buf); } public void Dispose() @@ -219,10 +220,10 @@ namespace Win.ClientBase.Codec public class CameraAForge : CameraCapturer { - private readonly AForge.Video.DirectShow.VideoCaptureDevice videoDevice; - private readonly AForge.Video.DirectShow.FilterInfoCollection videoDevices; - private readonly FFScale _ffscale = null; - private readonly Action _callBack = null; + private AForge.Video.DirectShow.VideoCaptureDevice videoDevice; + private AForge.Video.DirectShow.FilterInfoCollection videoDevices; + private FFScale _ffscale = null; + private Action _callBack = null; public CameraAForge(int camera, int width, int height, Action callBack) { _callBack = callBack; @@ -261,7 +262,8 @@ namespace Win.ClientBase.Codec byte[] buffer = FunctionEx.IntPtrToBytes(e.Buffer, 0, e.Len); buffer = _ffscale.Convert(buffer); - _callBack?.Invoke(buffer); + if (_callBack != null) + _callBack(buffer); } @@ -690,7 +692,7 @@ namespace Win.ClientBase.Codec } public class CameraEncoder : IDisposable { - public static int CameraCapturerMode = System.Configuration.ConfigurationManager.AppSettings["CameraCapturerMode"] == "1" ? 1 : 0; + public static int CameraCapturerMode = System.Configuration.ConfigurationSettings.AppSettings["CameraCapturerMode"] == "1" ? 1 : 0; protected bool _isworking = false; protected CameraCapturer _capturer = null; protected X264Native _x264; @@ -811,7 +813,7 @@ namespace Win.ClientBase.Codec if (mf.nIsKeyFrame == 1) { - var sps_pps = Win.ClientBase.Media.MediaSteamConverter.GetSPS_PPS(enc); + var sps_pps = SS.ClientBase.Media.MediaSteamConverter.GetSPS_PPS(enc); mf.nSPSLen = (short)sps_pps[0].Length; mf.nPPSLen = (short)sps_pps[1].Length; } @@ -823,7 +825,8 @@ namespace Win.ClientBase.Codec { _needClearVideoTransportBuffer = false; var frame = CreateClearVideoTransportBufferMediaFrame(mf); - _callBack?.Invoke(frame); + if (_callBack != null) + _callBack(frame); } if (_isFirstKeyFrame) @@ -838,23 +841,24 @@ namespace Win.ClientBase.Codec _callBack(frame); } - _callBack?.Invoke(mf); + if (_callBack != null) + _callBack(mf); } - catch (Exception) + catch (Exception e) { if (_isworking) throw; } } - protected static MediaFrame CreateClearVideoTransportBufferMediaFrame(MediaFrame mf) + protected MediaFrame CreateClearVideoTransportBufferMediaFrame(MediaFrame mf) { var frame = MediaFrame.CreateCommandMediaFrame(false, MediaFrameCommandType.ClearVideoTransportBuffer); return frame; } - protected static MediaFrame CreateResetCodecMediaFrame(MediaFrame mf) + protected MediaFrame CreateResetCodecMediaFrame(MediaFrame mf) { var infoMediaFrame = new MediaFrame() { @@ -868,7 +872,7 @@ namespace Win.ClientBase.Codec nPPSLen = mf.nPPSLen, nSPSLen = mf.nSPSLen, nTimetick = mf.nTimetick, - Data = Array.Empty(), + Data = new byte[0], nSize = 0, }; @@ -881,7 +885,7 @@ namespace Win.ClientBase.Codec _draw.Draw(yuv); } - protected virtual void Dispose(bool all) + public void Dispose() { try { @@ -892,18 +896,12 @@ namespace Win.ClientBase.Codec _x264.Release(); _draw.Release(); } - catch (Exception) + catch (Exception e) { throw; } } - public void Dispose() - { - Dispose(true); - GC.SuppressFinalize(this); - } - } diff --git a/Win.GB28181.Client/Player/Codec/FFImp.cs b/Win.GB28181.Client/Player/Codec/FFImp.cs index d96b499..1447ec0 100644 --- a/Win.GB28181.Client/Player/Codec/FFImp.cs +++ b/Win.GB28181.Client/Player/Codec/FFImp.cs @@ -5,11 +5,11 @@ using System.Linq; using System.Text; using System.Runtime.InteropServices; using GLib.Extension; -//using Win.Base; +//using SS.Base; using System.Threading; -namespace Win.ClientBase.Codec { +namespace SS.ClientBase.Codec { public partial class FFImp { diff --git a/Win.GB28181.Client/Player/Codec/FaacImp.cs b/Win.GB28181.Client/Player/Codec/FaacImp.cs index 988ddb4..7f500d0 100644 --- a/Win.GB28181.Client/Player/Codec/FaacImp.cs +++ b/Win.GB28181.Client/Player/Codec/FaacImp.cs @@ -7,7 +7,7 @@ using GLib.Extension; using System.IO; using System.Threading; -namespace Win.ClientBase.Codec { +namespace SS.ClientBase.Codec { public class FaacImp : IDisposable { private IntPtr _handle = IntPtr.Zero; private int _channel = 0; diff --git a/Win.GB28181.Client/Player/Codec/FaadImp.cs b/Win.GB28181.Client/Player/Codec/FaadImp.cs index 7fc144b..2e2b6d3 100644 --- a/Win.GB28181.Client/Player/Codec/FaadImp.cs +++ b/Win.GB28181.Client/Player/Codec/FaadImp.cs @@ -6,7 +6,7 @@ using System.Text; using GLib.Extension; using System.IO; -namespace Win.ClientBase.Codec { +namespace SS.ClientBase.Codec { public class FaadImp : IDisposable { private IntPtr _handle = IntPtr.Zero; private Boolean _inited = false; diff --git a/Win.GB28181.Client/Player/Codec/MicEncoder.cs b/Win.GB28181.Client/Player/Codec/MicEncoder.cs index 413afcd..bf6e1f7 100644 --- a/Win.GB28181.Client/Player/Codec/MicEncoder.cs +++ b/Win.GB28181.Client/Player/Codec/MicEncoder.cs @@ -11,11 +11,11 @@ using System.Runtime.InteropServices; using System.Threading; using System.IO; -using Win.Media; -using Win.Media.Wave.Wave; +using SS.Media; +using SS.Media.Wave.Wave; -namespace Win.ClientBase.Codec +namespace SS.ClientBase.Codec { @@ -151,7 +151,7 @@ namespace Win.ClientBase.Codec if (buf.Length == 0) return; //生成媒体帧 - var mf = new Win.Media.MediaFrame() + var mf = new SS.Media.MediaFrame() { nFrequency = _frequency, nSamples = (short)_audioCfg.samples, diff --git a/Win.GB28181.Client/Player/Codec/Speex.cs b/Win.GB28181.Client/Player/Codec/Speex.cs index 3b335b0..10ecda1 100644 --- a/Win.GB28181.Client/Player/Codec/Speex.cs +++ b/Win.GB28181.Client/Player/Codec/Speex.cs @@ -7,7 +7,7 @@ using GLib.Extension; using System.Threading; -namespace Win.ClientBase.Codec +namespace SS.ClientBase.Codec { /// /// SPEEX编码器 diff --git a/Win.GB28181.Client/Player/Codec/StreamFileHelper.cs b/Win.GB28181.Client/Player/Codec/StreamFileHelper.cs index 2ab698c..6440c63 100644 --- a/Win.GB28181.Client/Player/Codec/StreamFileHelper.cs +++ b/Win.GB28181.Client/Player/Codec/StreamFileHelper.cs @@ -3,9 +3,9 @@ //using System.IO; //using System.Linq; //using System.Text; -//using Win.MediaNetEngine; +//using SS.Media; -//namespace Win.ClientBase.Codec { +//namespace SS.ClientBase.Codec { // public class ReadFile { // public static List GetBuffByFile1(string file) { // var q = GetBuffByFile(file); diff --git a/Win.GB28181.Client/Player/Codec/SwsScale.cs b/Win.GB28181.Client/Player/Codec/SwsScale.cs index 78fb002..ed67b74 100644 --- a/Win.GB28181.Client/Player/Codec/SwsScale.cs +++ b/Win.GB28181.Client/Player/Codec/SwsScale.cs @@ -6,7 +6,7 @@ using System.Runtime.InteropServices; using GLib.Extension; -namespace Win.ClientBase.Codec { +namespace SS.ClientBase.Codec { public class FFScale { private int _handle = -1; diff --git a/Win.GB28181.Client/Player/Codec/x264.cs b/Win.GB28181.Client/Player/Codec/x264.cs index 022095b..512ac59 100644 --- a/Win.GB28181.Client/Player/Codec/x264.cs +++ b/Win.GB28181.Client/Player/Codec/x264.cs @@ -1,12 +1,14 @@ using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; using System.Runtime.InteropServices; +using System.Linq; using GLib.Extension; using System.IO; -using Win.Media; -namespace Win.ClientBase.Codec -{ - public partial class X264Native { +namespace SS.ClientBase.Codec { + public partial class X264Native { private static BinaryWriter w = null; public static void Test() { int width = 320, height = 240; @@ -16,7 +18,7 @@ namespace Win.ClientBase.Codec x264.Init(); var ls = MediaServer.Media.ReadFile.GetBuffByFile1(@"D:\video_monitor\v2v_super_exchange\branch\branch_V3.16.0.0(dongtaifuyong)\bin\Debug\1237.yuv"); - AVCodecCfg cf = AVCodecCfg.CreateVideo(width, height, (int)AVCode.CODEC_ID_H264, 100000); + AVCodecCfg cf = AVCodecCfg.CreateVideo(width, height, (int)SS.Media.AVCode.CODEC_ID_H264, 100000); FFImp ffimp = new FFImp(cf, true); //FFScale ffscale = new FFScale(width, height, 26, 12, width, height, 12, 12); FFScale ffscale = new FFScale(width, height, 0, 12,width,height, 3, 24); diff --git a/Win.GB28181.Client/Player/Controls/PlayerControl.Designer.cs b/Win.GB28181.Client/Player/Controls/PlayerControl.Designer.cs index 22a62ef..ca3f196 100644 --- a/Win.GB28181.Client/Player/Controls/PlayerControl.Designer.cs +++ b/Win.GB28181.Client/Player/Controls/PlayerControl.Designer.cs @@ -1,4 +1,4 @@ -namespace Win.ClientBase +namespace SS.ClientBase { partial class PlayerControl { diff --git a/Win.GB28181.Client/Player/Controls/PlayerControl.cs b/Win.GB28181.Client/Player/Controls/PlayerControl.cs index 1fc2711..27d02aa 100644 --- a/Win.GB28181.Client/Player/Controls/PlayerControl.cs +++ b/Win.GB28181.Client/Player/Controls/PlayerControl.cs @@ -7,11 +7,11 @@ using System.Linq; using System.Text; using System.Threading.Tasks; using System.Windows.Forms; -using Win.ClientBase.Codec; -using Win.ClientBase.Media; -using Win.Media; +using SS.ClientBase.Codec; +using SS.ClientBase.Media; +using SS.Media; -namespace Win.ClientBase +namespace SS.ClientBase { public partial class PlayerControl : UserControl { diff --git a/Win.GB28181.Client/Player/DShow/BaseFilterEx.cs b/Win.GB28181.Client/Player/DShow/BaseFilterEx.cs index e34f9ff..e86ae6e 100644 --- a/Win.GB28181.Client/Player/DShow/BaseFilterEx.cs +++ b/Win.GB28181.Client/Player/DShow/BaseFilterEx.cs @@ -5,7 +5,7 @@ using System.Text; using DirectShowLib; using System.Runtime.InteropServices; -namespace Win.WPFClient.DShow +namespace SS.WPFClient.DShow { /// /// DShow过滤器扩展 diff --git a/Win.GB28181.Client/Player/DShow/DShowHelper.cs b/Win.GB28181.Client/Player/DShow/DShowHelper.cs index 7b9bd0b..3dbee07 100644 --- a/Win.GB28181.Client/Player/DShow/DShowHelper.cs +++ b/Win.GB28181.Client/Player/DShow/DShowHelper.cs @@ -9,7 +9,7 @@ using GLib.Extension; using GLib; using System.Drawing; -namespace Win.WPFClient.DShow +namespace SS.WPFClient.DShow { public class DShowHelper { diff --git a/Win.GB28181.Client/Player/DShow/FilterGrap.cs b/Win.GB28181.Client/Player/DShow/FilterGrap.cs index 30304e2..2351afe 100644 --- a/Win.GB28181.Client/Player/DShow/FilterGrap.cs +++ b/Win.GB28181.Client/Player/DShow/FilterGrap.cs @@ -7,7 +7,7 @@ using DirectShowLib; using System.Runtime.InteropServices; using GLib.Extension; using System.Diagnostics; -namespace Win.WPFClient.DShow +namespace SS.WPFClient.DShow { /// /// 过滤器--图表基类 diff --git a/Win.GB28181.Client/Player/DShow/IDSMutualFilter.cs b/Win.GB28181.Client/Player/DShow/IDSMutualFilter.cs index 86f2853..1adb86f 100644 --- a/Win.GB28181.Client/Player/DShow/IDSMutualFilter.cs +++ b/Win.GB28181.Client/Player/DShow/IDSMutualFilter.cs @@ -8,7 +8,7 @@ using DirectShowLib; using GLib.Extension; using System.Diagnostics; -namespace Win.WPFClient.DShow +namespace SS.WPFClient.DShow { [UnmanagedFunctionPointer(CallingConvention.Cdecl)] public delegate long JSSourceFilter_FillBufferCallBack(ref IntPtr pData); diff --git a/Win.GB28181.Client/Player/DShow/IffdshowBase.cs b/Win.GB28181.Client/Player/DShow/IffdshowBase.cs index 0f4ebf6..86a1888 100644 --- a/Win.GB28181.Client/Player/DShow/IffdshowBase.cs +++ b/Win.GB28181.Client/Player/DShow/IffdshowBase.cs @@ -5,7 +5,7 @@ using System.Text; using System.Runtime.InteropServices; using System.Security; -namespace Win.WPFClient.DShow +namespace SS.WPFClient.DShow { #region [Guid("FC5BCCF4-FD62-45ee-B022-3840EAEA77B2"), SuppressUnmanagedCodeSecurity, diff --git a/Win.GB28181.Client/Player/DShow/PinEx.cs b/Win.GB28181.Client/Player/DShow/PinEx.cs index e9c4478..d62d57b 100644 --- a/Win.GB28181.Client/Player/DShow/PinEx.cs +++ b/Win.GB28181.Client/Player/DShow/PinEx.cs @@ -6,7 +6,7 @@ using DirectShowLib; using System.Runtime.InteropServices; using System.Diagnostics; using GLib.GeneralModel; -namespace Win.WPFClient.DShow +namespace SS.WPFClient.DShow { public class PinConnectEventArg : EventArgs { diff --git a/Win.GB28181.Client/Player/DShow/SampleGrabberCB.cs b/Win.GB28181.Client/Player/DShow/SampleGrabberCB.cs index fd3abcf..de26630 100644 --- a/Win.GB28181.Client/Player/DShow/SampleGrabberCB.cs +++ b/Win.GB28181.Client/Player/DShow/SampleGrabberCB.cs @@ -5,7 +5,7 @@ using System.Text; using System.Runtime.InteropServices; using DirectShowLib; -namespace Win.WPFClient.DShow +namespace SS.WPFClient.DShow { //directshow 数据回调 [System.Security.SuppressUnmanagedCodeSecurity] diff --git a/Win.GB28181.Client/Player/Media/AudioPlayer.cs b/Win.GB28181.Client/Player/Media/AudioPlayer.cs index d4f4f0f..6c131c0 100644 --- a/Win.GB28181.Client/Player/Media/AudioPlayer.cs +++ b/Win.GB28181.Client/Player/Media/AudioPlayer.cs @@ -14,13 +14,13 @@ using System.Threading; using System.Runtime.InteropServices; using System.Drawing; using System.IO; -using Win.Media; -using Win.Media.Wave.Wave; -using Win.ClientBase.Codec; +using SS.Media; +using SS.Media.Wave.Wave; +using SS.ClientBase.Codec; using GLib.AXLib.Utility; -using Win.MediaServer.Media; +using SS.MediaServer.Media; -namespace Win.ClientBase.Media +namespace SS.ClientBase.Media { /// /// 音频播放器 diff --git a/Win.GB28181.Client/Player/Media/MediaCapturer.cs b/Win.GB28181.Client/Player/Media/MediaCapturer.cs index e8fe3a3..8d84fad 100644 --- a/Win.GB28181.Client/Player/Media/MediaCapturer.cs +++ b/Win.GB28181.Client/Player/Media/MediaCapturer.cs @@ -15,13 +15,13 @@ using System.Threading; using System.IO; -using Win.Comm; -using Win.Media; -using Win.ClientBase.Codec; -using Win.MediaServer.Media.TS; +using SS.Comm; +using SS.Media; +using SS.ClientBase.Codec; +using SS.MediaServer.Media.TS; -namespace Win.ClientBase.Media +namespace SS.ClientBase.Media { public class MediaCapturer : IDisposable diff --git a/Win.GB28181.Client/Player/Media/MediaPlayer.cs b/Win.GB28181.Client/Player/Media/MediaPlayer.cs index ff6214c..e4fbe1e 100644 --- a/Win.GB28181.Client/Player/Media/MediaPlayer.cs +++ b/Win.GB28181.Client/Player/Media/MediaPlayer.cs @@ -6,11 +6,11 @@ using System.Threading; using System.Windows.Forms; using GLib.AXLib.Utility; using GLib.GeneralModel; -using Win.ClientBase.Codec; -using Win.ClientBase.Media; -using Win.Media; +using SS.ClientBase.Codec; +using SS.ClientBase.Media; +using SS.Media; -namespace Win.ClientBase.Media { +namespace SS.ClientBase.Media { public class MediaPlayer : IDisposable { private WaveAudioPlayer _ap; diff --git a/Win.GB28181.Client/Player/Media/MediaSteamConverter.cs b/Win.GB28181.Client/Player/Media/MediaSteamConverter.cs index 5a2b2fd..ecb7b3f 100644 --- a/Win.GB28181.Client/Player/Media/MediaSteamConverter.cs +++ b/Win.GB28181.Client/Player/Media/MediaSteamConverter.cs @@ -5,11 +5,11 @@ using BoxMatrix.Media; using GLib.AXLib.Utility; using GLib.Extension; -using Win.Media; +using SS.Media; using System; using System.IO; -namespace Win.ClientBase.Media +namespace SS.ClientBase.Media { diff --git a/Win.GB28181.Client/Player/Media/SDLPlay.cs b/Win.GB28181.Client/Player/Media/SDLPlay.cs index 447ee77..e916e4d 100644 --- a/Win.GB28181.Client/Player/Media/SDLPlay.cs +++ b/Win.GB28181.Client/Player/Media/SDLPlay.cs @@ -8,7 +8,7 @@ using GLib.Extension; using Tao.Sdl; -namespace Win.ClientBase.Media +namespace SS.ClientBase.Media { public class SDLPlay { diff --git a/Win.GB28181.Client/Player/Media/VideoPlayer.cs b/Win.GB28181.Client/Player/Media/VideoPlayer.cs index 7ecd494..2b5f4c1 100644 --- a/Win.GB28181.Client/Player/Media/VideoPlayer.cs +++ b/Win.GB28181.Client/Player/Media/VideoPlayer.cs @@ -3,13 +3,13 @@ using System.Collections.Generic; using System.Linq; using System.Text; using System.Windows.Forms; -using Win.Media; -using Win.ClientBase.Codec; +using SS.Media; +using SS.ClientBase.Codec; using System.Threading; using GLib.AXLib.Utility; using GLib.GeneralModel; -namespace Win.ClientBase.Media { +namespace SS.ClientBase.Media { public class VideoPlayer : IDisposable { private IYUVDraw _yuvDraw = null; private FFImp _ffimp = null; diff --git a/Win.GB28181.Client/Player/Media/Wave/WavInDevice.cs b/Win.GB28181.Client/Player/Media/Wave/WavInDevice.cs index 7048f76..10518d7 100644 --- a/Win.GB28181.Client/Player/Media/Wave/WavInDevice.cs +++ b/Win.GB28181.Client/Player/Media/Wave/WavInDevice.cs @@ -2,7 +2,7 @@ using System; using System.Collections.Generic; using System.Text; -namespace Win.Media.Wave.Wave +namespace SS.Media.Wave.Wave { /// /// This class represents wav input device. diff --git a/Win.GB28181.Client/Player/Media/Wave/WavOutDevice.cs b/Win.GB28181.Client/Player/Media/Wave/WavOutDevice.cs index a1b2b1e..9a6e16e 100644 --- a/Win.GB28181.Client/Player/Media/Wave/WavOutDevice.cs +++ b/Win.GB28181.Client/Player/Media/Wave/WavOutDevice.cs @@ -2,7 +2,7 @@ using System; using System.Collections.Generic; using System.Text; -namespace Win.Media.Wave.Wave +namespace SS.Media.Wave.Wave { /// /// This class represents wav output device. diff --git a/Win.GB28181.Client/Player/Media/Wave/WaveIn.cs b/Win.GB28181.Client/Player/Media/Wave/WaveIn.cs index a473708..759834b 100644 --- a/Win.GB28181.Client/Player/Media/Wave/WaveIn.cs +++ b/Win.GB28181.Client/Player/Media/Wave/WaveIn.cs @@ -4,9 +4,9 @@ using System.Text; using System.Threading; using System.Runtime.InteropServices; -using Win.Media.Wave.Wave.Native; +using SS.Media.Wave.Wave.Native; -namespace Win.Media.Wave.Wave { +namespace SS.Media.Wave.Wave { #region Delegates Implementation /// diff --git a/Win.GB28181.Client/Player/Media/Wave/WaveOut.cs b/Win.GB28181.Client/Player/Media/Wave/WaveOut.cs index d78934a..5862c23 100644 --- a/Win.GB28181.Client/Player/Media/Wave/WaveOut.cs +++ b/Win.GB28181.Client/Player/Media/Wave/WaveOut.cs @@ -5,9 +5,9 @@ using System.Text; using System.Threading; using System.Runtime.InteropServices; -using Win.Media.Wave.Wave.Native; +using SS.Media.Wave.Wave.Native; -namespace Win.Media.Wave.Wave +namespace SS.Media.Wave.Wave { /// /// This class implements streaming wav data player. diff --git a/Win.GB28181.Client/Player/Media/Wave/native/MMSYSERR.cs b/Win.GB28181.Client/Player/Media/Wave/native/MMSYSERR.cs index bfde803..d522d58 100644 --- a/Win.GB28181.Client/Player/Media/Wave/native/MMSYSERR.cs +++ b/Win.GB28181.Client/Player/Media/Wave/native/MMSYSERR.cs @@ -2,7 +2,7 @@ using System; using System.Collections.Generic; using System.Text; -namespace Win.Media.Wave.Wave.Native +namespace SS.Media.Wave.Wave.Native { /// /// This class holds MMSYSERR errors. diff --git a/Win.GB28181.Client/Player/Media/Wave/native/WAVEFORMATEX.cs b/Win.GB28181.Client/Player/Media/Wave/native/WAVEFORMATEX.cs index 9f4b844..6de3b9b 100644 --- a/Win.GB28181.Client/Player/Media/Wave/native/WAVEFORMATEX.cs +++ b/Win.GB28181.Client/Player/Media/Wave/native/WAVEFORMATEX.cs @@ -3,7 +3,7 @@ using System.Collections.Generic; using System.Text; using System.Runtime.InteropServices; -namespace Win.Media.Wave.Wave.Native +namespace SS.Media.Wave.Wave.Native { // Why this must be class ? otherwise in win XP won't work. diff --git a/Win.GB28181.Client/Player/Media/Wave/native/WAVEHDR.cs b/Win.GB28181.Client/Player/Media/Wave/native/WAVEHDR.cs index b13087a..5bb3b20 100644 --- a/Win.GB28181.Client/Player/Media/Wave/native/WAVEHDR.cs +++ b/Win.GB28181.Client/Player/Media/Wave/native/WAVEHDR.cs @@ -3,7 +3,7 @@ using System.Collections.Generic; using System.Text; using System.Runtime.InteropServices; -namespace Win.Media.Wave.Wave.Native +namespace SS.Media.Wave.Wave.Native { /// /// This class represents WAVEHDR structure. diff --git a/Win.GB28181.Client/Player/Media/Wave/native/WAVEOUTCAPS.cs b/Win.GB28181.Client/Player/Media/Wave/native/WAVEOUTCAPS.cs index 00e281a..59b55fb 100644 --- a/Win.GB28181.Client/Player/Media/Wave/native/WAVEOUTCAPS.cs +++ b/Win.GB28181.Client/Player/Media/Wave/native/WAVEOUTCAPS.cs @@ -3,7 +3,7 @@ using System.Collections.Generic; using System.Text; using System.Runtime.InteropServices; -namespace Win.Media.Wave.Wave.Native +namespace SS.Media.Wave.Wave.Native { /// /// This class represents WAVEOUTCAPS structure. diff --git a/Win.GB28181.Client/Player/Media/Wave/native/WavConstants.cs b/Win.GB28181.Client/Player/Media/Wave/native/WavConstants.cs index a4d9664..ca19e85 100644 --- a/Win.GB28181.Client/Player/Media/Wave/native/WavConstants.cs +++ b/Win.GB28181.Client/Player/Media/Wave/native/WavConstants.cs @@ -2,7 +2,7 @@ using System; using System.Collections.Generic; using System.Text; -namespace Win.Media.Wave.Wave.Native +namespace SS.Media.Wave.Wave.Native { /// /// This class provides most used wav constants. diff --git a/Win.GB28181.Client/Player/Media/Wave/native/WavFormat.cs b/Win.GB28181.Client/Player/Media/Wave/native/WavFormat.cs index 7385ca5..b3f64c8 100644 --- a/Win.GB28181.Client/Player/Media/Wave/native/WavFormat.cs +++ b/Win.GB28181.Client/Player/Media/Wave/native/WavFormat.cs @@ -2,7 +2,7 @@ using System; using System.Collections.Generic; using System.Text; -namespace Win.Media.Wave.Wave.Native +namespace SS.Media.Wave.Wave.Native { /// /// This class holds most known wav compression formats. diff --git a/Win.GB28181.Client/Player/Media/Wave/native/WavMethods.cs b/Win.GB28181.Client/Player/Media/Wave/native/WavMethods.cs index e8fa6c3..89c8685 100644 --- a/Win.GB28181.Client/Player/Media/Wave/native/WavMethods.cs +++ b/Win.GB28181.Client/Player/Media/Wave/native/WavMethods.cs @@ -3,7 +3,7 @@ using System.Collections.Generic; using System.Text; using System.Runtime.InteropServices; -namespace Win.Media.Wave.Wave.Native +namespace SS.Media.Wave.Wave.Native { /// /// The waveOutProc function is the callback function used with the waveform-audio output device. diff --git a/Win.GB28181.Client/Player/Media/YUVDraw.cs b/Win.GB28181.Client/Player/Media/YUVDraw.cs index de62eb2..00f5e1f 100644 --- a/Win.GB28181.Client/Player/Media/YUVDraw.cs +++ b/Win.GB28181.Client/Player/Media/YUVDraw.cs @@ -10,7 +10,7 @@ using System.Drawing; using System.Drawing.Imaging; using System.Threading; -namespace Win.ClientBase.Codec { +namespace SS.ClientBase.Codec { public interface IYUVDraw { void Start(); diff --git a/Win.GB28181.Client/Player/Mixer/Audio/AAC_ADTS.cs b/Win.GB28181.Client/Player/Mixer/Audio/AAC_ADTS.cs index 9d70d46..14e955b 100644 --- a/Win.GB28181.Client/Player/Mixer/Audio/AAC_ADTS.cs +++ b/Win.GB28181.Client/Player/Mixer/Audio/AAC_ADTS.cs @@ -3,7 +3,7 @@ using System; using System.Collections.Generic; using System.IO; -namespace Win.ClientBase.Mixer.Audio +namespace SS.ClientBase.Mixer.Audio { public class AAC_ADTS { diff --git a/Win.GB28181.Client/Player/Mixer/Audio/AacDec.cs b/Win.GB28181.Client/Player/Mixer/Audio/AacDec.cs index e98ce88..fab4e83 100644 --- a/Win.GB28181.Client/Player/Mixer/Audio/AacDec.cs +++ b/Win.GB28181.Client/Player/Mixer/Audio/AacDec.cs @@ -1,6 +1,6 @@ -using Win.ClientBase.Codec; -using Win.Media; -using Win.MediaServer.Media; +using SS.ClientBase.Codec; +using SS.Media; +using SS.MediaServer.Media; using System; using System.Collections.Generic; using System.IO; @@ -8,7 +8,7 @@ using System.Linq; using System.Text; using System.Threading.Tasks; -namespace Win.ClientBase.Mixer.Audio +namespace SS.ClientBase.Mixer.Audio { internal class AacDec : DecoderLine { diff --git a/Win.GB28181.Client/Player/Mixer/Audio/AacEnc.cs b/Win.GB28181.Client/Player/Mixer/Audio/AacEnc.cs index bbe05db..1b42060 100644 --- a/Win.GB28181.Client/Player/Mixer/Audio/AacEnc.cs +++ b/Win.GB28181.Client/Player/Mixer/Audio/AacEnc.cs @@ -1,11 +1,11 @@ -using Win.ClientBase.Codec; +using SS.ClientBase.Codec; using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; -namespace Win.ClientBase.Mixer.Audio +namespace SS.ClientBase.Mixer.Audio { public class AacEnc : IDisposable diff --git a/Win.GB28181.Client/Player/Mixer/Audio/ByteArrayExtensions.cs b/Win.GB28181.Client/Player/Mixer/Audio/ByteArrayExtensions.cs index dc202ef..712eeb2 100644 --- a/Win.GB28181.Client/Player/Mixer/Audio/ByteArrayExtensions.cs +++ b/Win.GB28181.Client/Player/Mixer/Audio/ByteArrayExtensions.cs @@ -4,7 +4,7 @@ using System.Globalization; using System.Linq; using System.Net; using System.Text; -namespace Win.ClientBase.Mixer.Audio +namespace SS.ClientBase.Mixer.Audio { /// /// Extension methods for byte[]. diff --git a/Win.GB28181.Client/Player/Mixer/Audio/DecoderBase.cs b/Win.GB28181.Client/Player/Mixer/Audio/DecoderBase.cs index f59b181..2026b92 100644 --- a/Win.GB28181.Client/Player/Mixer/Audio/DecoderBase.cs +++ b/Win.GB28181.Client/Player/Mixer/Audio/DecoderBase.cs @@ -1,21 +1,46 @@ using System; using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; -namespace Win.ClientBase.Mixer.Audio +namespace SS.ClientBase.Mixer.Audio { internal abstract class DecoderLine { - private byte[] _Buffer = Array.Empty(); + + public int ID; + /// + /// + /// + public int AudioType; + private byte[] _Buffer = new byte[0]; public byte[] Buffer { get { return _Buffer; } - set => _Buffer = value ?? Array.Empty(); + set + { + if (value == null) + _Buffer = new byte[0]; + else + _Buffer = value; + } } - public Queue QueueBuffer { get; set; } = new Queue(); + public Queue QueueBuffer + { + get + { + return queueBuffer; + } + + set + { + queueBuffer = value; + } + } - public int AudioType { get; set; } - public int ID { get; set; } + private Queue queueBuffer = new Queue(); public abstract void Dec(byte[] src); diff --git a/Win.GB28181.Client/Player/Mixer/Audio/EncorderBase.cs b/Win.GB28181.Client/Player/Mixer/Audio/EncorderBase.cs index a37018d..64156dc 100644 --- a/Win.GB28181.Client/Player/Mixer/Audio/EncorderBase.cs +++ b/Win.GB28181.Client/Player/Mixer/Audio/EncorderBase.cs @@ -4,7 +4,7 @@ using System.Linq; using System.Text; using System.Threading.Tasks; -namespace Win.ClientBase.Mixer.Audio +namespace SS.ClientBase.Mixer.Audio { public class EncorderBase { diff --git a/Win.GB28181.Client/Player/Mixer/Audio/Mixer.cs b/Win.GB28181.Client/Player/Mixer/Audio/Mixer.cs index 02a2536..16e3890 100644 --- a/Win.GB28181.Client/Player/Mixer/Audio/Mixer.cs +++ b/Win.GB28181.Client/Player/Mixer/Audio/Mixer.cs @@ -4,7 +4,7 @@ using System.Linq; using System.Text; using System.Threading; using System.Threading.Tasks; -namespace Win.ClientBase.Mixer.Audio +namespace SS.ClientBase.Mixer.Audio { public partial class MixerAudio:IDisposable { diff --git a/Win.GB28181.Client/Player/Mixer/MediaCanvas.cs b/Win.GB28181.Client/Player/Mixer/MediaCanvas.cs index 5dce9e2..39493df 100644 --- a/Win.GB28181.Client/Player/Mixer/MediaCanvas.cs +++ b/Win.GB28181.Client/Player/Mixer/MediaCanvas.cs @@ -3,17 +3,17 @@ using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; -using Win.ClientBase.Mixer.Video; +using SS.ClientBase.Mixer.Video; using System.Drawing; using System.Collections; using System.Windows.Forms; using System.Runtime.InteropServices; using System.Threading; -using Win.ClientBase.Codec; +using SS.ClientBase.Codec; using System.Drawing.Imaging; -using Win.ClientBase.Media; +using SS.ClientBase.Media; -namespace Win.ClientBase.Mixer +namespace SS.ClientBase.Mixer { public sealed class MediaMixerCanvas { @@ -368,7 +368,7 @@ namespace Win.ClientBase.Mixer if (count < 0 || count > MAXVIDEO_NUM) return; - Image image = Image.FromFile(@"D:\Mixer\SlWClient\Win.WPFClient\Images\bg_module_call.png"); + Image image = Image.FromFile(@"D:\Mixer\SlWClient\SS.WPFClient\Images\bg_module_call.png"); mapRects.Clear(); CreateRect(count); System.Drawing.Font logFont = new System.Drawing.Font("宋体", 22.5F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(134))); @@ -424,7 +424,7 @@ namespace Win.ClientBase.Mixer item.StreamID = StreamID; } } - public void Play(Win.Media.MediaFrame frame) + public void Play(SS.Media.MediaFrame frame) { //if(frame.StreamID) monitor[0].Play(frame); diff --git a/Win.GB28181.Client/Player/Mixer/Video/Canvas.cs b/Win.GB28181.Client/Player/Mixer/Video/Canvas.cs index c2744a6..36523cb 100644 --- a/Win.GB28181.Client/Player/Mixer/Video/Canvas.cs +++ b/Win.GB28181.Client/Player/Mixer/Video/Canvas.cs @@ -2,7 +2,7 @@ using System.Collections.Generic; using System.Drawing; -namespace Win.ClientBase.Mixer.Video +namespace SS.ClientBase.Mixer.Video { public class Canvas : IDisposable { diff --git a/Win.GB28181.Client/Player/Mixer/Video/CanvasStyle.cs b/Win.GB28181.Client/Player/Mixer/Video/CanvasStyle.cs index 8209ca8..1e06db0 100644 --- a/Win.GB28181.Client/Player/Mixer/Video/CanvasStyle.cs +++ b/Win.GB28181.Client/Player/Mixer/Video/CanvasStyle.cs @@ -1,4 +1,4 @@ -namespace Win.ClientBase.Mixer.Video +namespace SS.ClientBase.Mixer.Video { public enum CanvasStyle : byte { diff --git a/Win.GB28181.Client/Player/Mixer/Video/GraphicsBase.cs b/Win.GB28181.Client/Player/Mixer/Video/GraphicsBase.cs index 1c677f7..95eed98 100644 --- a/Win.GB28181.Client/Player/Mixer/Video/GraphicsBase.cs +++ b/Win.GB28181.Client/Player/Mixer/Video/GraphicsBase.cs @@ -2,7 +2,7 @@ using System.Drawing; using System.Drawing.Drawing2D; -namespace Win.ClientBase.Mixer.Video +namespace SS.ClientBase.Mixer.Video { public abstract class GraphicsBase : IDisposable { diff --git a/Win.GB28181.Client/Player/Mixer/Video/ImageCanvas.cs b/Win.GB28181.Client/Player/Mixer/Video/ImageCanvas.cs index 7e3d9b0..74bf21d 100644 --- a/Win.GB28181.Client/Player/Mixer/Video/ImageCanvas.cs +++ b/Win.GB28181.Client/Player/Mixer/Video/ImageCanvas.cs @@ -1,7 +1,7 @@ using System.Drawing; using System.Drawing.Drawing2D; -namespace Win.ClientBase.Mixer.Video +namespace SS.ClientBase.Mixer.Video { public class ImageCanvas : Canvas { diff --git a/Win.GB28181.Client/Player/Mixer/Video/MarqueeCanvas.cs b/Win.GB28181.Client/Player/Mixer/Video/MarqueeCanvas.cs index 60b7b81..4a3c16f 100644 --- a/Win.GB28181.Client/Player/Mixer/Video/MarqueeCanvas.cs +++ b/Win.GB28181.Client/Player/Mixer/Video/MarqueeCanvas.cs @@ -1,7 +1,7 @@ using System; using System.Drawing; -namespace Win.ClientBase.Mixer.Video +namespace SS.ClientBase.Mixer.Video { public class MarqueeCanvas : StringCanvas { diff --git a/Win.GB28181.Client/Player/Mixer/Video/StringCanvas.cs b/Win.GB28181.Client/Player/Mixer/Video/StringCanvas.cs index 78736a4..c91c0c9 100644 --- a/Win.GB28181.Client/Player/Mixer/Video/StringCanvas.cs +++ b/Win.GB28181.Client/Player/Mixer/Video/StringCanvas.cs @@ -1,6 +1,6 @@ using System.Drawing; -namespace Win.ClientBase.Mixer.Video +namespace SS.ClientBase.Mixer.Video { public class StringCanvas : Canvas { diff --git a/Win.GB28181.Client/Player/Mixer/Video/TimeCanvas.cs b/Win.GB28181.Client/Player/Mixer/Video/TimeCanvas.cs index b0fde61..9f82bfd 100644 --- a/Win.GB28181.Client/Player/Mixer/Video/TimeCanvas.cs +++ b/Win.GB28181.Client/Player/Mixer/Video/TimeCanvas.cs @@ -1,7 +1,7 @@ using System; using System.Drawing; -namespace Win.ClientBase.Mixer.Video +namespace SS.ClientBase.Mixer.Video { public class TimeCanvas : StringCanvas { diff --git a/Win.GB28181.Client/Player/Mixer/Video/VideoCanvas.cs b/Win.GB28181.Client/Player/Mixer/Video/VideoCanvas.cs index 100dd55..0cc8486 100644 --- a/Win.GB28181.Client/Player/Mixer/Video/VideoCanvas.cs +++ b/Win.GB28181.Client/Player/Mixer/Video/VideoCanvas.cs @@ -1,14 +1,14 @@ -using Win.ClientBase.Codec; -using System.Drawing; +using SS.ClientBase.Codec; using System; -using System.Runtime.InteropServices; +using System.Drawing; using System.Drawing.Imaging; +using System.Runtime.InteropServices; -namespace Win.ClientBase.Mixer.Video +namespace SS.ClientBase.Mixer.Video { public class VideoCanvas : Canvas, IYUVDraw { - public System.Drawing.Bitmap Background; + public Bitmap Background; public int srcWidth; diff --git a/Win.GB28181.Client/Win.GB28181.Client.csproj b/Win.GB28181.Client/Win.GB28181.Client.csproj index 99414cf..e5643f5 100644 --- a/Win.GB28181.Client/Win.GB28181.Client.csproj +++ b/Win.GB28181.Client/Win.GB28181.Client.csproj @@ -2,19 +2,16 @@ Debug AnyCPU - {3E2F1C35-7354-4F55-ABA4-44CBCE2E18B5} WinExe - netcoreapp3.1 + netcoreapp3.1 true false - Properties Win.GB28181.Client Win.GB28181.Client - 512 true - x86 + AnyCPU @@ -23,14 +20,13 @@ - - + - - + + @@ -48,27 +44,8 @@ ..\Win.GB28181.Libs\DirectShowLib-2005.dll - - ..\Win.GB28181.Libs\GLib.dll - - - ..\Win.GB28181.Libs\StarEye.VideoConver.dll - ..\Win.GB28181.Libs\Tao.Sdl.dll - - - True - True - Settings.settings - - - - - SettingsSingleFileGenerator - Settings.Designer.cs - - \ No newline at end of file diff --git a/Win.GB28181.Libs/GLib.dll b/Win.GB28181.Libs/GLib.dll deleted file mode 100644 index 2cec2d41e551d08cd248ee9a1e23c7e8e3910671..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 192000 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 - - {8332828E-DA9A-4813-9569-9DBA95DF8FF8} - Library - Properties - Win.MediaNetEngine - Win.MediaNetEngine - netcoreapp3.1 - true - - - - - - - ..\Win.GB28181.Libs\GLib.dll - - - \ No newline at end of file -- Gitee From b64d6372c793ad66a72012271c232d896ca3d3e5 Mon Sep 17 00:00:00 2001 From: Edward Date: Tue, 25 Feb 2020 18:42:53 +0800 Subject: [PATCH 02/19] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 0bbe1ed..e978663 100644 --- a/README.md +++ b/README.md @@ -71,7 +71,7 @@ BSD v2 ## 讨论、成为共同作者、近距离贡献 -微信扫描二维码,添加好友,进入微信讨论群(注明:GB28181=公司+姓名): +微信扫描二维码,添加好友,进入微信讨论群(注明:GB28181+公司+姓名): ![qrcode](./docs/crazybber.jpg) -- Gitee From 913decca9f099f2dc3179b2ad0bd5db45f84cd75 Mon Sep 17 00:00:00 2001 From: Edward Date: Tue, 25 Feb 2020 18:45:30 +0800 Subject: [PATCH 03/19] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index e978663..8ea37b4 100644 --- a/README.md +++ b/README.md @@ -32,7 +32,7 @@ running on aspnetcore 3.1+ + [x] 设计与系统配置服务(或数据服务)交互的GRPC接口 + [x] 精简服务模块,调整代码结构关系 + [ ] 为配置接口和流媒体服务接口提供mock数据,使得服务可以独立运行 - + [ ] 以GRPC方式对接流媒体服务[EasydarwinGo](https://www.github.com/gb28181/easydawingo) + + [ ] 以GRPC方式对接流媒体服务[monibuca](https://github.com/langhuihui/monibuca) + [ ] 以GRPC方式从系统配置服务(或者数据服务)中获取GB信令服务的配置信息,包括名称、ID、端口、协议等 + [ ] 使服务注册组件变成可配置的,(当前是consul,并且k8s环境中也不需要) + [x] 将GRPC服务的实现改为apsnetcore3.1+的内置实现方式. -- Gitee From 4e3d83d6cb4662f8ff9eabf8af736fca996380bd Mon Sep 17 00:00:00 2001 From: Edward Date: Fri, 28 Feb 2020 18:03:44 +0800 Subject: [PATCH 04/19] Update README.md --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 8ea37b4..487250b 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # GB28181 Standard -+ 当前版本以GB2014为基础逐渐增加GB2016的国标要求,最新国标是:【[GB28181-2016](docs/GBT%2028181-2016%20公共安全视频监控联网系统信息传输、交换、控制技术要求-目录版.pdf)】 ++ 最新国标是:【[GB28181-2016](docs/GBT%2028181-2016%20公共安全视频监控联网系统信息传输、交换、控制技术要求-目录版.pdf)】 + 项目结构、代码结仍存在不少问题,待完善,因为时间问题,也是希望大家能一起完善 + 希望每一个对本项目感兴趣的朋友,都能成为本项目的共同作者或者贡献者 @@ -32,7 +32,7 @@ running on aspnetcore 3.1+ + [x] 设计与系统配置服务(或数据服务)交互的GRPC接口 + [x] 精简服务模块,调整代码结构关系 + [ ] 为配置接口和流媒体服务接口提供mock数据,使得服务可以独立运行 - + [ ] 以GRPC方式对接流媒体服务[monibuca](https://github.com/langhuihui/monibuca) + + [ ] 以GRPC方式对接流媒体服务【[monibuca](https://github.com/langhuihui/monibuca)】 + [ ] 以GRPC方式从系统配置服务(或者数据服务)中获取GB信令服务的配置信息,包括名称、ID、端口、协议等 + [ ] 使服务注册组件变成可配置的,(当前是consul,并且k8s环境中也不需要) + [x] 将GRPC服务的实现改为apsnetcore3.1+的内置实现方式. -- Gitee From e3f9ea7eca16a25ffbb069733cdc427e85772f70 Mon Sep 17 00:00:00 2001 From: Edward Date: Tue, 3 Mar 2020 15:48:08 +0800 Subject: [PATCH 05/19] add Microsoft.CodeAnalysis.FxCopAnalyzers --- GB28181.SIPSorcery/GB28181.SIPSorcery.csproj | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/GB28181.SIPSorcery/GB28181.SIPSorcery.csproj b/GB28181.SIPSorcery/GB28181.SIPSorcery.csproj index 079ebb5..d2a267f 100644 --- a/GB28181.SIPSorcery/GB28181.SIPSorcery.csproj +++ b/GB28181.SIPSorcery/GB28181.SIPSorcery.csproj @@ -20,6 +20,10 @@ + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + -- Gitee From 0363d5babe820b51d3c21cfa4df536a9d6aa1336 Mon Sep 17 00:00:00 2001 From: Edward Date: Tue, 3 Mar 2020 15:48:27 +0800 Subject: [PATCH 06/19] fix missing files for sql --- .gitignore | 1 - .../Persistence/SIPAssetPersistorFactory.cs | 3 +- .../Persistence/SQL/SQLAssetPersistor.cs | 608 ++++++++++++++++++ .../Persistence/SQL/SQLExpressionVisitor.cs | 226 +++++++ .../Persistence/SQL/SQLObjectReader.cs | 88 +++ .../Persistence/SQL/SQLQueryProvider.cs | 426 ++++++++++++ 6 files changed, 1350 insertions(+), 2 deletions(-) create mode 100644 GB28181.SIPSorcery/Persistence/SQL/SQLAssetPersistor.cs create mode 100644 GB28181.SIPSorcery/Persistence/SQL/SQLExpressionVisitor.cs create mode 100644 GB28181.SIPSorcery/Persistence/SQL/SQLObjectReader.cs create mode 100644 GB28181.SIPSorcery/Persistence/SQL/SQLQueryProvider.cs diff --git a/.gitignore b/.gitignore index 4c1ea26..268fe78 100644 --- a/.gitignore +++ b/.gitignore @@ -108,7 +108,6 @@ csx AppPackages/ # Others -sql/ *.Cache ClientBin/ [Ss]tyle[Cc]op.* diff --git a/GB28181.SIPSorcery/Persistence/SIPAssetPersistorFactory.cs b/GB28181.SIPSorcery/Persistence/SIPAssetPersistorFactory.cs index e31a335..b655681 100644 --- a/GB28181.SIPSorcery/Persistence/SIPAssetPersistorFactory.cs +++ b/GB28181.SIPSorcery/Persistence/SIPAssetPersistorFactory.cs @@ -41,10 +41,11 @@ using GB28181.SIPSorcery.SIP.App; using GB28181.SIPSorcery.Sys; using GB28181.Logger4Net; using GB28181.SIPSorcery.Persistence.XML; +using SIPSorcery.GB28181.Persistence; namespace GB28181.SIPSorcery.Persistence { - public class SIPAssetPersistorFactory where T : class, ISIPAsset, new() + public static class SIPAssetPersistorFactory where T : class, ISIPAsset, new() { private static ILog logger = AppState.logger; diff --git a/GB28181.SIPSorcery/Persistence/SQL/SQLAssetPersistor.cs b/GB28181.SIPSorcery/Persistence/SQL/SQLAssetPersistor.cs new file mode 100644 index 0000000..f7d21d5 --- /dev/null +++ b/GB28181.SIPSorcery/Persistence/SQL/SQLAssetPersistor.cs @@ -0,0 +1,608 @@ +// ============================================================================ +// FileName: SQLAssetPersistor.cs +// +// Description: +// An asset persistor for Amazon's SimpleDB data store. +// +// Author(s): +// Aaron Clauson +// +// History: +// 24 Oct 2009 Aaron Clauson Created. +// +// License: +// This software is licensed under the BSD License http://www.opensource.org/licenses/bsd-license.php +// +// Copyright (c) 2009 Aaron Clauson (aaron@sipsorcery.com), SIP Sorcery PTY LTD, Hobart, Australia (www.sipsorcery.com) +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without modification, are permitted provided that +// the following conditions are met: +// +// Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. +// Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following +// disclaimer in the documentation and/or other materials provided with the distribution. Neither the name of SIP Sorcery PTY LTD +// nor the names of its contributors may be used to endorse or promote products derived from this software without specific +// prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, +// BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +// IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, +// OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, +// OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +// POSSIBILITY OF SUCH DAMAGE. +// ============================================================================ + +using GB28181.Logger4Net; +using GB28181.SIPSorcery.Persistence; +using GB28181.SIPSorcery.SIP.App; +using GB28181.SIPSorcery.Sys; +using System; +using System.Collections.Generic; +using System.Data; +using System.Data.Common; +using System.Linq; +using System.Linq.Expressions; +using System.Text; + +namespace SIPSorcery.GB28181.Persistence +{ + public class SQLAssetPersistor : SIPAssetPersistor where T : class, ISIPAsset, new() + { + public override event SIPAssetDelegate Added; + public override event SIPAssetDelegate Updated; + public override event SIPAssetDelegate Deleted; + public override event SIPAssetsModifiedDelegate Modified; + private static ILog logger = AppState.logger; + protected DbProviderFactory m_dbProviderFactory; + protected string m_dbConnectionStr; + protected ObjectMapper m_objectMapper; + public SQLAssetPersistor(DbProviderFactory factory, string dbConnStr) + { + m_dbProviderFactory = factory; + m_dbConnectionStr = dbConnStr; + m_objectMapper = new ObjectMapper(); + } + + public override List Add(List assets) + { + using (IDbConnection connection = m_dbProviderFactory.CreateConnection()) + { + connection.ConnectionString = m_dbConnectionStr; + connection.Open(); + using (IDbTransaction trans = connection.BeginTransaction()) + { + try + { + IDbCommand insertCommand = connection.CreateCommand(); + insertCommand.Transaction = trans; + foreach (var asset in assets) + { + + + var insertQuery = new StringBuilder("insert into " + m_objectMapper.TableName + " ("); + var parametersStr = new StringBuilder("("); + List dbParameters = new List(); + + int paramNumber = 1; + Dictionary allPropertyValues = m_objectMapper.GetAllValues(asset); + foreach (KeyValuePair propertyValue in allPropertyValues) + { + DbParameter dbParameter = base.GetParameter(m_dbProviderFactory, propertyValue.Key, propertyValue.Value, paramNumber.ToString()); + insertCommand.Parameters.Add(dbParameter); + + insertQuery.Append(propertyValue.Key + ","); + parametersStr.Append("?" + paramNumber + ","); + paramNumber++; + } + + string insertCommandText = insertQuery.ToString().TrimEnd(',') + ") values " + parametersStr.ToString().TrimEnd(',') + ")"; + + //logger.Debug("SQLAssetPersistor insert SQL: " + insertCommandText + "."); + + insertCommand.CommandText = insertCommandText; + insertCommand.ExecuteNonQuery(); + Added?.Invoke(asset); + } + trans.Commit(); + + } + catch (Exception excp) + { + trans.Rollback(); + logger.Error("Exception SQLAssetPersistor Add (for " + typeof(T).Name + "). " + excp.Message); + throw; + } + } + return assets; + } + } + + public override T Add(T asset) + { + using (IDbConnection connection = m_dbProviderFactory.CreateConnection()) + { + connection.ConnectionString = m_dbConnectionStr; + connection.Open(); + using (IDbTransaction trans = connection.BeginTransaction()) + { + try + { + + IDbCommand insertCommand = connection.CreateCommand(); + insertCommand.Transaction = trans; + StringBuilder insertQuery = new StringBuilder("insert into " + m_objectMapper.TableName + " ("); + StringBuilder parametersStr = new StringBuilder("("); + List dbParameters = new List(); + + int paramNumber = 1; + Dictionary allPropertyValues = m_objectMapper.GetAllValues(asset); + foreach (KeyValuePair propertyValue in allPropertyValues) + { + DbParameter dbParameter = base.GetParameter(m_dbProviderFactory, propertyValue.Key, propertyValue.Value, paramNumber.ToString()); + insertCommand.Parameters.Add(dbParameter); + + insertQuery.Append(propertyValue.Key + ","); + parametersStr.Append("?" + paramNumber + ","); + paramNumber++; + } + + string insertCommandText = insertQuery.ToString().TrimEnd(',') + ") values " + parametersStr.ToString().TrimEnd(',') + ")"; + + //logger.Debug("SQLAssetPersistor insert SQL: " + insertCommandText + "."); + + insertCommand.CommandText = insertCommandText; + insertCommand.ExecuteNonQuery(); + trans.Commit(); + if (Added != null) + { + Added(asset); + } + } + catch (Exception excp) + { + trans.Rollback(); + logger.Error("Exception SQLAssetPersistor Add (for " + typeof(T).Name + "). " + excp.Message); + throw; + } + } + return asset; + } + return null; + } + + public override T Update(T asset) + { + try + { + using (var connection = m_dbProviderFactory.CreateConnection()) + { + connection.ConnectionString = m_dbConnectionStr; + connection.Open(); + + IDbCommand insertCommand = connection.CreateCommand(); + + IDbCommand updateCommand = connection.CreateCommand(); + + StringBuilder updateQuery = new StringBuilder("update " + m_objectMapper.TableName + " set "); + List dbParameters = new List(); + + int paramNumber = 1; + Dictionary allPropertyValues = m_objectMapper.GetAllValues(asset); + foreach (KeyValuePair propertyValue in allPropertyValues) + { + // if (!propertyValue.Key.IsPrimaryKey) + { + DbParameter dbParameter = base.GetParameter(m_dbProviderFactory, propertyValue.Key, propertyValue.Value, paramNumber.ToString()); + updateCommand.Parameters.Add(dbParameter); + + updateQuery.Append(propertyValue.Key + "= ?" + paramNumber + ","); + paramNumber++; + } + } + + string updateCommandText = updateQuery.ToString().TrimEnd(',') + " where id = '" + asset.Id + "'"; + + //logger.Debug("SQLAssetPersistor update SQL: " + updateCommandText + "."); + + updateCommand.CommandText = updateCommandText; + updateCommand.ExecuteNonQuery(); + + if (Updated != null) + { + Updated(asset); + } + + return asset; + } + } + catch (Exception excp) + { + logger.Error("Exception SQLAssetPersistor Update (for " + typeof(T).Name + "). " + excp.Message); + throw; + } + // return null; + } + + public override void UpdateProperty(Guid id, string propertyName, object value) + { + try + { + using (IDbConnection connection = m_dbProviderFactory.CreateConnection()) + { + connection.ConnectionString = m_dbConnectionStr; + connection.Open(); + + IDbCommand updateCommand = connection.CreateCommand(); + + MetaDataMember member = m_objectMapper.GetMember(propertyName); + string parameterName = "1"; + DbParameter dbParameter = base.GetParameter(m_dbProviderFactory, member, value, parameterName); + updateCommand.Parameters.Add(dbParameter); + + updateCommand.CommandText = "update " + m_objectMapper.TableName + " set " + propertyName + " = ?" + parameterName + " where id = '" + id + "'"; + updateCommand.ExecuteNonQuery(); + } + } + catch (Exception excp) + { + logger.Error("Exception SQLAssetPersistor UpdateProperty (for " + typeof(T).Name + "). " + excp.Message); + throw; + } + } + + public override void IncrementProperty(Guid id, string propertyName) + { + base.Increment(id, propertyName); + } + + public override void DecrementProperty(Guid id, string propertyName) + { + base.Decrement(id, propertyName); + } + + public override void Delete() + { + + using (IDbConnection connection = m_dbProviderFactory.CreateConnection()) + { + connection.ConnectionString = m_dbConnectionStr; + connection.Open(); + using (IDbTransaction trans = connection.BeginTransaction()) + { + try + { + + + IDbCommand deleteCommand = connection.CreateCommand(); + deleteCommand.Transaction = trans; + deleteCommand.CommandText = "delete from " + m_objectMapper.TableName; + deleteCommand.ExecuteNonQuery(); + trans.Commit(); + } + catch (Exception excp) + { + trans.Rollback(); + logger.Error("Exception SQLAssetPersistor Delete (for " + typeof(T).Name + "). " + excp.Message); + throw; + } + } + } + + } + + public override void Delete(T asset) + { + using (IDbConnection connection = m_dbProviderFactory.CreateConnection()) + { + connection.ConnectionString = m_dbConnectionStr; + connection.Open(); + using (IDbTransaction trans = connection.BeginTransaction()) + { + try + { + + + IDbCommand deleteCommand = connection.CreateCommand(); + deleteCommand.Transaction = trans; + deleteCommand.CommandText = "delete from " + m_objectMapper.TableName + " where id = '" + asset.Id + "'"; + deleteCommand.ExecuteNonQuery(); + trans.Commit(); + // Deleted?.(asset); + + } + catch (Exception excp) + { + trans.Rollback(); + logger.Error("Exception SQLAssetPersistor Delete (for " + typeof(T).Name + "). " + excp.Message); + throw; + } + } + } + + } + + public override void Delete(Expression> where) + { + + SQLQueryProvider sqlQueryProvider = new SQLQueryProvider(m_dbProviderFactory, m_dbConnectionStr, m_objectMapper.TableName, m_objectMapper.SetValue); + string whereStr = sqlQueryProvider.GetQueryText(where); + + using (IDbConnection connection = m_dbProviderFactory.CreateConnection()) + { + connection.ConnectionString = m_dbConnectionStr; + connection.Open(); + using (IDbTransaction trans = connection.BeginTransaction()) + { + try + { + + IDbCommand deleteCommand = connection.CreateCommand(); + deleteCommand.Transaction = trans; + deleteCommand.CommandText = "delete from " + m_objectMapper.TableName + " where " + whereStr; + deleteCommand.ExecuteNonQuery(); + trans.Commit(); + } + catch (Exception excp) + { + trans.Rollback(); + logger.Error("Exception SQLAssetPersistor Delete (for " + typeof(T).Name + "). " + excp.Message); + throw; + } + } + } + + } + + public override T Get(Guid id) + { + try + { + using (IDbConnection connection = m_dbProviderFactory.CreateConnection()) + { + connection.ConnectionString = m_dbConnectionStr; + connection.Open(); + + IDbCommand command = connection.CreateCommand(); + command.CommandText = "select * from " + m_objectMapper.TableName + " where id = '" + id + "'"; + IDbDataAdapter adapter = m_dbProviderFactory.CreateDataAdapter(); + adapter.SelectCommand = command; + var resultSet = new DataSet(); + adapter.Fill(resultSet); + + if (resultSet != null && resultSet.Tables[0].Rows.Count == 1) + { + T instance = new T(); + instance.Load(resultSet.Tables[0].Rows[0]); + return instance; + } + else if (resultSet != null && resultSet.Tables[0].Rows.Count > 1) + { + throw new ApplicationException("Multiple rows were returned for Get with id=" + id + "."); + } + else + { + return null; + } + } + } + catch (Exception excp) + { + logger.Error("Exception SQLAssetPersistor Get (id) (for " + typeof(T).Name + "). " + excp.Message); + throw; + } + } + + public override object GetProperty(Guid id, string propertyName) + { + try + { + using (IDbConnection connection = m_dbProviderFactory.CreateConnection()) + { + connection.ConnectionString = m_dbConnectionStr; + connection.Open(); + + IDbCommand command = connection.CreateCommand(); + command.CommandText = "select " + propertyName + " from " + m_objectMapper.TableName + " where id = '" + id + "'"; + + return command.ExecuteScalar(); + } + } + catch (Exception excp) + { + logger.Error("Exception SQLAssetPersistor GetProperty (for " + typeof(T).Name + "). " + excp.Message); + throw; + } + } + + public override int Count(Expression> whereClause) + { + try + { + SQLQueryProvider sqlQueryProvider = new SQLQueryProvider(m_dbProviderFactory, m_dbConnectionStr, m_objectMapper.TableName, m_objectMapper.SetValue); + Query assets = new Query(sqlQueryProvider); + if (whereClause != null) + { + return assets.Where(whereClause).Count(); + } + else + { + return assets.Count(); + } + } + catch (Exception excp) + { + logger.Error("Exception SQLAssetPersistor Count (for " + typeof(T).Name + "). " + excp.Message); + throw; + } + } + + public override T Get(Expression> whereClause) + { + try + { + SQLQueryProvider sqlQueryProvider = new SQLQueryProvider(m_dbProviderFactory, m_dbConnectionStr, m_objectMapper.TableName, m_objectMapper.SetValue); + Query assets = new Query(sqlQueryProvider); + IQueryable getList = null; + if (whereClause != null) + { + getList = from asset in assets.Where(whereClause) select asset; + } + else + { + getList = from asset in assets select asset; + } + return getList.FirstOrDefault(); + } + catch (Exception excp) + { + string whereClauseStr = (whereClause != null) ? whereClause.ToString() + ". " : null; + logger.Error("Exception SQLAssetPersistor Get (where) (for " + typeof(T).Name + "). " + whereClauseStr + excp); + throw; + } + } + + public override List Get(Expression> whereClause, string orderByField, int offset, int count) + { + try + { + SQLQueryProvider sqlQueryProvider = new SQLQueryProvider(m_dbProviderFactory, m_dbConnectionStr, m_objectMapper.TableName, m_objectMapper.SetValue); + Query assetList = new Query(sqlQueryProvider); + //IQueryable getList = from asset in assetList.Where(whereClause) orderby orderByField select asset; + IQueryable getList = null; + if (whereClause != null) + { + getList = from asset in assetList.Where(whereClause) select asset; + } + else + { + getList = from asset in assetList select asset; + } + + if (!orderByField.IsNullOrBlank()) + { + sqlQueryProvider.OrderBy = orderByField; + } + + if (offset != 0) + { + sqlQueryProvider.Offset = offset; + } + + if (count != Int32.MaxValue) + { + sqlQueryProvider.Count = count; + } + + return getList.ToList() ?? new List(); + } + catch (Exception excp) + { + string whereClauseStr = (whereClause != null) ? whereClause.ToString() + ". " : null; + logger.Error("Exception SQLAssetPersistor Get (list) (for " + typeof(T).Name + "). " + whereClauseStr + excp.Message); + throw; + } + } + + public override List Get() + { + try + { + SQLQueryProvider sqlQueryProvider = new SQLQueryProvider(m_dbProviderFactory, m_dbConnectionStr, m_objectMapper.TableName, m_objectMapper.SetValue); + Query assetList = new Query(sqlQueryProvider); + //IQueryable getList = from asset in assetList.Where(whereClause) orderby orderByField select asset; + IQueryable getList = null; + getList = from asset in assetList select asset; + + + return getList.ToList() ?? new List(); + } + catch (Exception excp) + { + logger.Error("Exception SQLAssetPersistor Get (list) (for " + excp.Message); + throw; + } + } + } + + #region Unit testing. + +#if UNITTEST + + [TestFixture] + public class SQLAssetPersistorUnitTest { + + // [Table(Name="table")] + private class MockSIPAsset : ISIPAsset { + + private Guid m_id; + public Guid Id { + get { return m_id; } + set { m_id = value; } + } + + public DataTable GetTable() { + throw new NotImplementedException(); + } + + public void Load(DataRow row) { + throw new NotImplementedException(); + } + + public Dictionary Load(System.Xml.XmlDocument dom) { + throw new NotImplementedException(); + } + + public string ToXML() { + throw new NotImplementedException(); + } + + public string ToXMLNoParent() { + throw new NotImplementedException(); + } + + public string GetXMLElementName() { + throw new NotImplementedException(); + } + + public string GetXMLDocumentElementName() { + throw new NotImplementedException(); + } + } + + [TestFixtureSetUp] + public void Init() { } + + [TestFixtureTearDown] + public void Dispose() { } + + [Test] + public void SampleTest() { + Console.WriteLine(System.Reflection.MethodBase.GetCurrentMethod().Name); + } + + /*[Test] + public void BuildSingleParameterSelectQueryUnitTest() { + Console.WriteLine(System.Reflection.MethodBase.GetCurrentMethod().Name); + SimpleDBAssetPersistor persistor = new SimpleDBAssetPersistor(null, null); + string selectQuery = persistor.BuildSelectQuery("select * from table where inserted < ?1", new SqlParameter("1", DateTime.Now)); + Console.WriteLine(selectQuery); + } + + [Test] + public void BuildMultipleParameterSelectQueryUnitTest() { + Console.WriteLine(System.Reflection.MethodBase.GetCurrentMethod().Name); + SimpleDBAssetPersistor persistor = new SimpleDBAssetPersistor(null, null); + SqlParameter[] parameters = new SqlParameter[2]; + parameters[0] = new SqlParameter("1", DateTime.Now); + parameters[1] = new SqlParameter("2", "test"); + string selectQuery = persistor.BuildSelectQuery("select * from table where inserted < ?1 and name = ?2", parameters); + Console.WriteLine(selectQuery); + }*/ + } + +#endif + + #endregion +} diff --git a/GB28181.SIPSorcery/Persistence/SQL/SQLExpressionVisitor.cs b/GB28181.SIPSorcery/Persistence/SQL/SQLExpressionVisitor.cs new file mode 100644 index 0000000..b516fac --- /dev/null +++ b/GB28181.SIPSorcery/Persistence/SQL/SQLExpressionVisitor.cs @@ -0,0 +1,226 @@ +using System; +using System.Linq; +using System.Linq.Expressions; +using System.Text; + +namespace GB28181.SIPSorcery.Persistence +{ + + internal class SQLExpressionVisitor : ExpressionVisitor { + + private StringBuilder sb; + private bool m_isLeaf; + private bool m_whereAdded; + + internal SQLExpressionVisitor() { } + + internal string Translate(Expression expression) { + this.sb = new StringBuilder(); + this.Visit(expression); + string query = this.sb.ToString().Trim(); + return query; + } + + private static Expression StripQuotes(Expression e) { + while (e.NodeType == ExpressionType.Quote) { + e = ((UnaryExpression)e).Operand; + } + return e; + } + + protected override Expression VisitMethodCall(MethodCallExpression m) { + if (m.Method.DeclaringType == typeof(Queryable) && + (m.Method.Name == "Where" || m.Method.Name == "Select" || m.Method.Name == "Count" || + m.Method.Name == "FirstOrDefault")) { + + if (m_isLeaf) { + if (m.Method.Name == "Where" && !m_whereAdded) { + sb.Append(" where "); + m_whereAdded = true; + } + + this.Visit(m.Arguments[0]); + LambdaExpression lambda = (LambdaExpression)StripQuotes(m.Arguments[1]); + this.Visit(lambda.Body); + return m; + } + else { + if (m.Method.Name == "Select") { + m_isLeaf = true; + sb.Append("select * from {0}"); + this.Visit(m.Arguments[0]); + LambdaExpression lambda = (LambdaExpression)StripQuotes(m.Arguments[1]); + this.Visit(lambda.Body); + return m; + } + else if (m.Method.Name == "Where") { + m_isLeaf = true; + m_whereAdded = true; + sb.Append("select * from {0} where "); + this.Visit(m.Arguments[0]); + LambdaExpression lambda = (LambdaExpression)StripQuotes(m.Arguments[1]); + this.Visit(lambda.Body); + return m; + } + else if (m.Method.Name == "Count") { + m_isLeaf = true; + sb.Append("select count(*) from {0}"); + this.Visit(m.Arguments[0]); + return m; + } + else if (m.Method.Name == "FirstOrDefault") { + m_isLeaf = true; + sb.Append("select * from {0}"); + this.Visit(m.Arguments[0]); + sb.Append(" limit 1"); + return m; + } + } + } + + throw new NotSupportedException(string.Format("The method '{0}' is not supported by SQL.", m.Method.Name)); + } + + protected override Expression VisitUnary(UnaryExpression u) { + switch (u.NodeType) { + case ExpressionType.Not: + sb.Append("not ("); + this.Visit(u.Operand); + sb.Append(")"); + break; + default: + throw new NotSupportedException(string.Format("The unary operator '{0}' is not supported by SQL.", u.NodeType)); + } + return u; + } + + protected override Expression VisitBinary(BinaryExpression b) { + this.Visit(b.Left); + switch (b.NodeType) { + case ExpressionType.And | ExpressionType.AndAlso: + sb.Append(" and "); + break; + case ExpressionType.Or: + sb.Append(" or "); + break; + case ExpressionType.Equal: + sb.Append(" = "); + break; + case ExpressionType.NotEqual: + sb.Append(" != "); + break; + case ExpressionType.LessThan: + sb.Append(" < "); + break; + case ExpressionType.LessThanOrEqual: + sb.Append(" <= "); + break; + case ExpressionType.GreaterThan: + sb.Append(" > "); + break; + case ExpressionType.GreaterThanOrEqual: + sb.Append(" >= "); + break; + default: + throw new NotSupportedException(string.Format("The binary operator '{0}' is not supported by SQL.", b.NodeType)); + } + + this.Visit(b.Right); + return b; + } + + protected override Expression VisitConstant(ConstantExpression c) { + IQueryable q = c.Value as IQueryable; + if (q != null) { + //throw new ApplicationException("Nested expressions not supported."); + } + else if (c.Value == null) { + sb.Append("null"); + } + else { + if (c.Value.GetType() == typeof(Guid)) { + sb.Append("'"); + sb.Append(c.Value); + sb.Append("'"); + } + else { + switch (Type.GetTypeCode(c.Value.GetType())) { + case TypeCode.DateTime: + sb.Append("'"); + sb.Append(((DateTime)c.Value).ToString("o")); + sb.Append("'"); + break; + case TypeCode.Object: + if (c.Value is DateTimeOffset) + { + sb.Append("'"); + sb.Append(((DateTimeOffset)c.Value).ToString("o")); + sb.Append("'"); + } + else + { + throw new NotSupportedException(string.Format("The constant for '{0}' is not supported by SQL.", c.Value)); + } + break; + default: + sb.Append("'"); + sb.Append(c.Value.ToString().Replace("'", "''")); + sb.Append("'"); + break; + } + } + } + return c; + } + + protected override Expression VisitMemberAccess(MemberExpression m) { + if (m.Expression != null && m.Expression.NodeType == ExpressionType.Parameter) { + if (GetMemberType(m) == typeof(Boolean)) { + sb.Append(m.Member.Name.ToLower() + " = '1'"); + } + else { + sb.Append(m.Member.Name.ToLower()); + } + return m; + } + throw new NotSupportedException(string.Format("The member '{0}' is not supported by SQL.", m.Member.Name)); + } + + private string GetTableName(MethodCallExpression m) { + IQueryable q = ((ConstantExpression)m.Arguments[0]).Value as IQueryable; + return GetTableName(q.ElementType); + } + + private string GetTableName(Type tableType) { + //AttributeMappingSource mappingSource = new AttributeMappingSource(); + //MetaModel mapping = mappingSource.GetModel(tableType); + //MetaTable table = mapping.GetTable(tableType); + //return table.TableName; + return null; + } + + private bool IsPrimaryKey(MemberExpression m) { + //AttributeMappingSource mappingSource = new AttributeMappingSource(); + //MetaModel mapping = mappingSource.GetModel(m.Member.DeclaringType); + //MetaTable table = mapping.GetTable(m.Member.DeclaringType); + //foreach (MetaDataMember dataMember in table.RowType.PersistentDataMembers) { + // if (dataMember.Name == m.Member.Name) { + // return dataMember.IsPrimaryKey; + // } + //} + return false; + } + + private Type GetMemberType(MemberExpression m) { + //AttributeMappingSource mappingSource = new AttributeMappingSource(); + //MetaModel mapping = mappingSource.GetModel(m.Member.DeclaringType); + //MetaTable table = mapping.GetTable(m.Member.DeclaringType); + //foreach (MetaDataMember dataMember in table.RowType.PersistentDataMembers) { + // if (dataMember.Name == m.Member.Name) { + // return dataMember.Type; + // } + //} + return null; + } + } +} diff --git a/GB28181.SIPSorcery/Persistence/SQL/SQLObjectReader.cs b/GB28181.SIPSorcery/Persistence/SQL/SQLObjectReader.cs new file mode 100644 index 0000000..d23f1c1 --- /dev/null +++ b/GB28181.SIPSorcery/Persistence/SQL/SQLObjectReader.cs @@ -0,0 +1,88 @@ +using System; +using System.Collections; +using System.Collections.Generic; +using System.Data; +using GB28181.SIPSorcery.SIP.App; +using GB28181.SIPSorcery.Sys; +using GB28181.Logger4Net; + +namespace GB28181.SIPSorcery.Persistence { + + public class SQLObjectReader : IEnumerable, IEnumerable where T : class, ISIPAsset, new() + { + + private static ILog logger = AppState.logger; + + Enumerator enumerator; + private DataSet m_selectResult; + private SetterDelegate m_setter; + + public SQLObjectReader(DataSet selectResult) { + m_selectResult = selectResult; + } + + public SQLObjectReader(DataSet selectResult, SetterDelegate setter) { + m_selectResult = selectResult; + m_setter = setter; + this.enumerator = new Enumerator(selectResult, setter); + } + + public IEnumerator GetEnumerator() { + Enumerator e = this.enumerator; + + if (e == null) + { + throw new InvalidOperationException("Cannot enumerate more than once"); + } + this.enumerator = null; + return e; + } + + IEnumerator IEnumerable.GetEnumerator() { + return this.GetEnumerator(); + } + + public T First() { + T instance = new T(); + instance.Load(m_selectResult.Tables[0].Rows[0]); + return instance; + } + + class Enumerator : IEnumerator, IEnumerator, IDisposable { + + private DataSet m_selectResult; + private SetterDelegate m_setter; + int m_selectIndex; + T current; + + internal Enumerator(DataSet selectResult, SetterDelegate setter) { + m_selectResult = selectResult; + m_setter = setter; + } + + public T Current { + get { return this.current; } + } + + object IEnumerator.Current { + get { return this.current; } + } + + public bool MoveNext() { + + if (m_selectIndex < m_selectResult.Tables[0].Rows.Count) { + T instance = new T(); + instance.Load(m_selectResult.Tables[0].Rows[m_selectIndex]); + this.current = instance; + m_selectIndex++; + return true; + } + return false; + } + + public void Reset() { } + + public void Dispose() { } + } + } +} diff --git a/GB28181.SIPSorcery/Persistence/SQL/SQLQueryProvider.cs b/GB28181.SIPSorcery/Persistence/SQL/SQLQueryProvider.cs new file mode 100644 index 0000000..1d6373c --- /dev/null +++ b/GB28181.SIPSorcery/Persistence/SQL/SQLQueryProvider.cs @@ -0,0 +1,426 @@ +using System; +using System.Collections; +using System.Data; +using System.Data.Common; +using System.Linq.Expressions; +using System.Reflection; +using System.Transactions; +using GB28181.SIPSorcery.SIP.App; +using GB28181.SIPSorcery.Sys; +using GB28181.Logger4Net; + +namespace GB28181.SIPSorcery.Persistence { + + public class SQLQueryProvider : QueryProvider { + + private static ILog logger = AppState.logger; + + private DbProviderFactory m_dbFactory; + private string m_dbConnStr; + private string m_tableName; + private SetterDelegate m_setter; + + public string OrderBy; + public int Offset; + public int Count = Int32.MaxValue; + + public SQLQueryProvider(DbProviderFactory dbFactory, string dbConnStr, string tableName, SetterDelegate setter) { + + m_dbFactory = dbFactory; + m_dbConnStr = dbConnStr; + m_tableName = tableName; + m_setter = setter; + } + + public override string GetQueryText(Expression expression) { + return this.Translate(expression); + } + + public override object Execute(Expression expression) { + + try { + Type elementType = TypeSystem.GetElementType(expression.Type); + string methodName = ((MethodCallExpression)expression).Method.Name; + bool isIQueryable = (expression.Type.FullName.StartsWith("System.Linq.IQueryable") || expression.Type.FullName.StartsWith("System.Linq.IOrderedQueryable")); + string queryString = String.Format(this.Translate(expression), m_tableName); + + if (m_tableName == "sipaccounts") + { + Console.WriteLine(); + } + if (!OrderBy.IsNullOrBlank()) { + queryString += " order by " + OrderBy; + } + + if (Count != Int32.MaxValue) { + queryString += " limit " + Count; + } + + if (Offset != 0) { + queryString += " offset " + Offset; + } + + //logger.Debug(queryString); + + if (!queryString.IsNullOrBlank()) { + + using(TransactionScope transactionScope = new TransactionScope(TransactionScopeOption.Suppress)) + { + using (IDbConnection connection = m_dbFactory.CreateConnection()) { + connection.ConnectionString = m_dbConnStr; + connection.Open(); + + if (elementType == typeof(Int32)) + { + // This is a count. + IDbCommand command = connection.CreateCommand(); + command.CommandText = queryString; + return Convert.ToInt32(command.ExecuteScalar()); + } + else + { + //logger.Debug("SimpleDB select: " + queryString + "."); + IDbCommand command = connection.CreateCommand(); + command.CommandText = queryString; + IDbDataAdapter adapter = m_dbFactory.CreateDataAdapter(); + adapter.SelectCommand = command; + DataSet resultSet = new DataSet(); + adapter.Fill(resultSet); + + if (resultSet != null && resultSet.Tables[0] != null) + { + + object result = Activator.CreateInstance( + typeof(SQLObjectReader<>).MakeGenericType(elementType), + BindingFlags.Instance | BindingFlags.Public, null, + new object[] { resultSet, m_setter }, + null); + + if (isIQueryable) + { + return result; + } + else + { + IEnumerator enumerator = ((IEnumerable)result).GetEnumerator(); + if (enumerator.MoveNext()) + { + return enumerator.Current; + } + else + { + return null; + } + } + } + } + } + throw new ApplicationException("No results for SQL query."); + } + } + else { + throw new ApplicationException("The expression translation by the SQLQueryProvider resulted in an empty select string."); + } + } + catch (Exception excp) { + logger.Error("Exception SQLQueryProvider Execute. " + expression.ToString() + ". " + excp.Message); + throw; + } + } + + private string Translate(Expression expression) { + //Stopwatch timer = new Stopwatch(); + //timer.Start(); + expression = Evaluator.PartialEval(expression); + string translation = new SQLExpressionVisitor().Translate(expression); + //timer.Stop(); + //logger.Debug("SQL query took " + timer.ElapsedMilliseconds + "ms: " + translation + "."); + return translation; + } + + #region Unit testing. + + #if UNITTEST + + [TestFixture] + public class SQLQueryProviderUnitTest { + + // [Table(Name = "table")] + private class MockSIPAsset : ISIPAsset { + + private Guid m_id; + [Column(Storage = "m_id", Name = "id", DbType = "character varying(36)", IsPrimaryKey = true, CanBeNull = false)] + public Guid Id { + get { return m_id; } + set { m_id = value; } + } + + private string m_username; + public string Username { + get { return m_username; } + set { m_username = value; } + } + + private string m_adminId; + public string AdminId { + get { return m_adminId; } + set { m_adminId = value; } + } + + private bool m_expired; + // [Column(Name = "expired", DbType = "boolean", CanBeNull = false)] + public bool Expired { + get { return m_expired; } + set { m_expired = value; } + } + + private DateTime m_inserted; + public DateTime Inserted { + get { return m_inserted; } + set { m_inserted = value; } + } + + public DataTable GetTable() { + throw new NotImplementedException(); + } + + public void Load(DataRow row) { + throw new NotImplementedException(); + } + + public Dictionary Load(System.Xml.XmlDocument dom) { + throw new NotImplementedException(); + } + + public string ToXML() { + throw new NotImplementedException(); + } + + public string ToXMLNoParent() { + throw new NotImplementedException(); + } + + public string GetXMLElementName() { + throw new NotImplementedException(); + } + + public string GetXMLDocumentElementName() { + throw new NotImplementedException(); + } + } + + [TestFixtureSetUp] + public void Init() { + Logger4Net.Config.BasicConfigurator.Configure(); + } + + [TestFixtureTearDown] + public void Dispose() { } + + [Test] + public void SampleTest() { + Console.WriteLine(System.Reflection.MethodBase.GetCurrentMethod().Name); + } + + /// + /// Check that the query text is generated correctly for a select based on an object's id. + /// + [Test] + public void SimpleSelectOnIdTest() { + Console.WriteLine(System.Reflection.MethodBase.GetCurrentMethod().Name); + + SQLQueryProvider queryProvider = new SQLQueryProvider(null, null, null, null); + Guid id = Guid.NewGuid(); + Expression> whereClause = (asset) => asset.Id == id; + string querytext = queryProvider.GetQueryText(whereClause); + Console.WriteLine("Query: " + querytext); + + Assert.IsTrue(querytext == "id = '" + id + "'", "The query text was incorrect."); + } + + /// + /// Check that the query text is generated correctly for a select containing a DateTime. + /// + [Test] + public void SimpleSelectOnDateTest() { + Console.WriteLine(System.Reflection.MethodBase.GetCurrentMethod().Name); + + SQLQueryProvider queryProvider = new SQLQueryProvider(null, null, null, null); + DateTime checkDate = DateTime.Now; + Expression> whereClause = (asset) => asset.Inserted >= checkDate; + string querytext = queryProvider.GetQueryText(whereClause); + Console.WriteLine("Query: " + querytext); + + Assert.IsTrue(querytext == "inserted >= '" + checkDate.ToString("o") + "'", "The query text was incorrect."); + } + + /// + /// Check that the query text is generated correctly for a select containing an "and" operator. + /// + [Test] + public void SelectWithAndOperatorTest() { + Console.WriteLine(System.Reflection.MethodBase.GetCurrentMethod().Name); + + SQLQueryProvider queryProvider = new SQLQueryProvider(null, null, null, null); + Expression> whereClause = (asset) => asset.AdminId == "1234" && asset.Username == "abcd"; + string querytext = queryProvider.GetQueryText(whereClause); + Console.WriteLine("Query: " + querytext); + + Assert.IsTrue(querytext == "adminid = '1234' and username = 'abcd'", "The query text was incorrect."); + } + + /// + /// Check that the query text is generated correctly when the select contains a locally scoped variable. + /// + [Test] + public void SelectWithLocallyScopedVariableOperatorTest() { + + Console.WriteLine(System.Reflection.MethodBase.GetCurrentMethod().Name); + + SQLQueryProvider queryProvider = new SQLQueryProvider(null, null, null, null); + string username = "efgh"; + Expression> whereClause = (asset) => asset.Username == username; + string querytext = queryProvider.GetQueryText(whereClause); + Console.WriteLine("Query: " + querytext); + + Assert.IsTrue(querytext == "username = '" + username + "'", "The query text was incorrect."); + } + + /// + /// Check that the query text is generated correctly when the select contains a locally scoped embedded variable. + /// + [Test] + public void SelectWithLocallyScopedEmbeddedVariableOperatorTest() { + + Console.WriteLine(System.Reflection.MethodBase.GetCurrentMethod().Name); + + SimpleDBQueryProvider queryProvider = new SimpleDBQueryProvider(null, null, null); + Expression> whereClause = (asset) => asset.Inserted < DateTime.UtcNow; + string querytext = queryProvider.GetQueryText(whereClause); + Console.WriteLine("Query: " + querytext); + + Assert.IsTrue(Regex.Match(querytext, @"inserted < '\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}\.\d{7}Z'").Success, "The query text was incorrect."); + } + + /// + /// Check that the query text is generated correctly when the select contains a boolean not operator + /// + [Test] + public void SelectWithNotOperatorTest() { + Console.WriteLine(System.Reflection.MethodBase.GetCurrentMethod().Name); + + SQLQueryProvider queryProvider = new SQLQueryProvider(null, null, null, null); + Expression> whereClause = (asset) => !asset.Expired; + string querytext = queryProvider.GetQueryText(whereClause); + Console.WriteLine("Query: " + querytext + "."); + + Assert.IsTrue(querytext == "not (expired = '1')", "The query text was incorrect."); + } + + /// + /// Check that the query text is generated correctly when the select contains a boolean not operator. + /// + [Test] + public void SelectWithBooleanTest() { + Console.WriteLine(System.Reflection.MethodBase.GetCurrentMethod().Name); + + SQLQueryProvider queryProvider = new SQLQueryProvider(null, null, null, null); + Expression> whereClause = (asset) => asset.Expired; + string querytext = queryProvider.GetQueryText(whereClause); + Console.WriteLine("Query: " + querytext + "."); + + Assert.IsTrue(querytext == "expired = '1'", "The query text was incorrect."); + } + + /// + /// Check that the query text is generated correctly when the select contains a boolean not operator + /// and an And clause. + /// + [Test] + public void SelectWithNotCombinedWithAndOperatorTest() { + Console.WriteLine(System.Reflection.MethodBase.GetCurrentMethod().Name); + + SQLQueryProvider queryProvider = new SQLQueryProvider(null, null, null, null); + DateTime checkDate = DateTime.Now; + Expression> whereClause = (asset) => !asset.Expired && asset.Inserted >= checkDate; + string querytext = queryProvider.GetQueryText(whereClause); + Console.WriteLine("Query: " + querytext + "."); + + Assert.IsTrue(querytext == "not (expired = '1') and inserted >= '" + checkDate.ToString("o") + "'", "The query text was incorrect."); + } + + /// + /// Check that the query text is generated correctly when the select contains a member variable. + /// + [Test] + public void SelectWithMemberVariableOperatorTest() { + Console.WriteLine(System.Reflection.MethodBase.GetCurrentMethod().Name); + + SQLQueryProvider queryProvider = new SQLQueryProvider(null, null, null, null); + var myObj = new { Name = "xyz" }; + Expression> whereClause = (asset) => asset.Username == myObj.Name; + string querytext = queryProvider.GetQueryText(whereClause); + Console.WriteLine("Query: " + querytext); + + Assert.IsTrue(querytext == "username = '" + myObj.Name + "'", "The query text was incorrect."); + } + + /// + /// Check that the query text is generated correctly when the select contains a member variable. + /// + [Test] + public void SelectWithNotEqualMemberVariableOperatorTest() { + Console.WriteLine(System.Reflection.MethodBase.GetCurrentMethod().Name); + + SQLQueryProvider queryProvider = new SQLQueryProvider(null, null, null, null); + var myObj = new { Name = "xyz" }; + Expression> whereClause = (asset) => asset.Username != myObj.Name; + string querytext = queryProvider.GetQueryText(whereClause); + Console.WriteLine("Query: " + querytext); + + Assert.IsTrue(querytext == "username != '" + myObj.Name + "'", "The query text was incorrect."); + } + + /// + /// Check that the query text is generated correctly when the select contains a member variable + /// combined with an And clause. + /// + [Test] + public void SelectWithMemberVariableCombinedWithAndClauseOperatorTest() { + Console.WriteLine(System.Reflection.MethodBase.GetCurrentMethod().Name); + + SQLQueryProvider queryProvider = new SQLQueryProvider(null, null, null, null); + var myObj = new { Name = "xyz" }; + DateTime checkDate = DateTime.Now; + Expression> whereClause = (asset) => asset.Username == myObj.Name && !asset.Expired && asset.Inserted >= checkDate; + string querytext = queryProvider.GetQueryText(whereClause); + Console.WriteLine("Query: " + querytext); + + Assert.IsTrue(querytext == "username = '" + myObj.Name + "' and not (expired = '1') and inserted >= '" + checkDate.ToString("o") + "'", "The query text was incorrect."); + } + + /// + /// Check that the query text is generated correctly when the select expression includes an orderby clause. + /// + [Test] + public void OrderedSelectTest() { + + Console.WriteLine(System.Reflection.MethodBase.GetCurrentMethod().Name); + + SQLQueryProvider queryProvider = new SQLQueryProvider(null, null, null, null); + Query assetList = new Query(queryProvider); + + DateTime checkDate = DateTime.Now; + var dummyResult = from asset in assetList orderby asset.Inserted select asset; + string querytext = queryProvider.GetQueryText(dummyResult.Expression); + Console.WriteLine("Query: " + querytext); + + //Assert.IsTrue(querytext == "username = '" + myObj.Name + "' and not (expired = '1') and inserted >= '" + checkDate.ToString("o") + "'", "The query text was incorrect."); + } + } + + #endif + + #endregion + } +} -- Gitee From 667ffac8a19da7f03965a2bceb65fb6a98072c39 Mon Sep 17 00:00:00 2001 From: Edward Date: Thu, 5 Mar 2020 21:07:08 +0800 Subject: [PATCH 07/19] add video format instruction --- docs/Video/Format/Video-Data-Package-Format.png | Bin 0 -> 82757 bytes docs/Video/Format/Video-Data-Package-RFC.png | Bin 0 -> 4667 bytes 2 files changed, 0 insertions(+), 0 deletions(-) create mode 100644 docs/Video/Format/Video-Data-Package-Format.png create mode 100644 docs/Video/Format/Video-Data-Package-RFC.png diff --git a/docs/Video/Format/Video-Data-Package-Format.png b/docs/Video/Format/Video-Data-Package-Format.png new file mode 100644 index 0000000000000000000000000000000000000000..644da4c4cf1db3eac2d3b7b2202849d6181f1b08 GIT binary patch literal 82757 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

G-qr@2v^zJ?Z9G1%FV2lsj#3KOnNM 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 CK68@* literal 0 HcmV?d00001 -- Gitee From 29f689d8a6a359e8b0d413084cfd59ab24811736 Mon Sep 17 00:00:00 2001 From: Edward Date: Thu, 5 Mar 2020 21:07:34 +0800 Subject: [PATCH 08/19] add video session flow --- docs/Video/Flow/Video-Session-Cascade.png | Bin 0 -> 28905 bytes docs/Video/Flow/Video-Session-Flow.png | Bin 0 -> 27425 bytes 2 files changed, 0 insertions(+), 0 deletions(-) create mode 100644 docs/Video/Flow/Video-Session-Cascade.png create mode 100644 docs/Video/Flow/Video-Session-Flow.png diff --git a/docs/Video/Flow/Video-Session-Cascade.png b/docs/Video/Flow/Video-Session-Cascade.png new file mode 100644 index 0000000000000000000000000000000000000000..70a27fae77ad36e839e9642fc4c5ceacd80d9bfa GIT binary patch literal 28905 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

G$v|bPeWZl7IN4WZ6WXmx;}4mqMtN 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 Date: Thu, 5 Mar 2020 21:48:03 +0800 Subject: [PATCH 09/19] move DI to Startup --- GB28181.Server/Main/MainProcess.cs | 68 +++++++++++------------------- GB28181.Server/Program.cs | 7 ++- GB28181.Server/Startup.cs | 29 +++++++++++++ 3 files changed, 57 insertions(+), 47 deletions(-) diff --git a/GB28181.Server/Main/MainProcess.cs b/GB28181.Server/Main/MainProcess.cs index 80cdcd7..f7d0563 100644 --- a/GB28181.Server/Main/MainProcess.cs +++ b/GB28181.Server/Main/MainProcess.cs @@ -1,19 +1,8 @@ using GB28181.Logger4Net; -using GB28181.Server.Message; -using GB28181.Service; -using GB28181.Service.Protos.DeviceCatalog; -using GB28181.Service.Protos.DeviceFeature; -using GB28181.Service.Protos.Ptz; -using GB28181.Service.Protos.Video; -using GB28181.Service.Protos.VideoRecord; using GB28181.SIPSorcery.Servers; using GB28181.SIPSorcery.Servers.SIPMessage; -using GB28181.SIPSorcery.Servers.SIPMonitor; -using GB28181.SIPSorcery.SIP; using GB28181.SIPSorcery.Sys; -using GB28181.SIPSorcery.Sys.Cache; using GB28181.SIPSorcery.Sys.Config; -using GB28181.SIPSorcery.Sys.Model; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; using System; @@ -40,8 +29,20 @@ namespace GB28181.Server.Main private readonly CancellationTokenSource _deviceStatusReportToken = new CancellationTokenSource(); // private Queue _keepAliveQueue = new Queue(); - private readonly IServiceCollection servicesContainer = new ServiceCollection(); + //private readonly IServiceCollection servicesContainer = new ServiceCollection(); + // private ServiceProvider _serviceProvider = null; + private ISipMessageCore _mainSipService; + private MessageHub messageCenter; + private ISIPRegistrarCore registry; + + public MainProcess(ISipMessageCore sipMessageCore, MessageHub messageHub, ISIPRegistrarCore sipRegistrarCore, IServiceCollection services) + { + _mainSipService = sipMessageCore; + messageCenter = messageHub; + registry = sipRegistrarCore; + _serviceProvider = services.BuildServiceProvider(); + } public void Stop() { @@ -60,48 +61,28 @@ namespace GB28181.Server.Main //InitServer SipAccountStorage.RPCGBServerConfigReceived += SipAccountStorage_RPCGBServerConfigReceived; - //Config Service & and run - ConfigServices(config); + ////Config Service & and run + //ConfigServices(config); //Start the sip main service Task.Factory.StartNew(() => Processing(), _processingServiceToken.Token); } - private void ConfigServices(IConfigurationRoot config) - { - //we should initialize resource here then use them. - servicesContainer.AddSingleton() - .AddSingleton(config) // add configuration - .AddSingleton() - .AddSingleton() - .AddSingleton() - .AddSingleton() - .AddSingleton() - .AddSingleton() - .AddScoped() - .AddTransient() - .AddSingleton() - .AddSingleton() - .AddTransient() - .AddSingleton() - .AddSingleton, DeviceObjectCache>() - .AddScoped() - .AddScoped() - .AddScoped() - .AddScoped() - .AddScoped() - .AddSingleton(servicesContainer); // add itself - _serviceProvider = servicesContainer.BuildServiceProvider(); - } + //private void ConfigServices(IConfigurationRoot config) + //{ + // //we should initialize resource here then use them. + // servicesContainer.AddSingleton(servicesContainer); // add itself + // _serviceProvider = servicesContainer.BuildServiceProvider(); + //} private void Processing() { // _keepaliveTime = DateTime.Now; try { - var _mainSipService = _serviceProvider.GetRequiredService(); + // var _mainSipService = _serviceProvider.GetRequiredService(); //Get meassage Handler - var messageCenter = _serviceProvider.GetRequiredService(); + // var messageCenter = _serviceProvider.GetRequiredService(); // start the Listening SipService in main Service Task.Run(() => { @@ -122,7 +103,7 @@ namespace GB28181.Server.Main }); // run the register service - var registry = _serviceProvider.GetRequiredService(); + // var registry = _serviceProvider.GetRequiredService(); Task.Factory.StartNew(() => registry.ProcessRegisterRequest(), _registryServiceToken.Token); @@ -132,6 +113,7 @@ namespace GB28181.Server.Main catch (Exception exMsg) { logger.Error(exMsg.Message); + throw exMsg; } } diff --git a/GB28181.Server/Program.cs b/GB28181.Server/Program.cs index c382d4a..414feec 100644 --- a/GB28181.Server/Program.cs +++ b/GB28181.Server/Program.cs @@ -1,11 +1,10 @@ using Microsoft.AspNetCore.Hosting; -using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Configuration; using Microsoft.Extensions.Hosting; -using System; -using System.Threading.Tasks; using Microsoft.Extensions.Logging; -using Microsoft.Extensions.Configuration; +using System; using System.IO; +using System.Threading.Tasks; namespace GB28181.Service { diff --git a/GB28181.Server/Startup.cs b/GB28181.Server/Startup.cs index 85fd1f0..e379f97 100644 --- a/GB28181.Server/Startup.cs +++ b/GB28181.Server/Startup.cs @@ -10,6 +10,15 @@ using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Hosting; using Microsoft.Extensions.Configuration; using GB28181.Server.Main; +using GB28181.SIPSorcery.Sys.Config; +using GB28181.Server.Message; +using GB28181.SIPSorcery.Servers; +using GB28181.SIPSorcery.Servers.SIPMonitor; +using GB28181.SIPSorcery.Servers.SIPMessage; +using GB28181.SIPSorcery.SIP; +using GB28181.SIPSorcery.Sys.Cache; +using GB28181.SIPSorcery.Sys.Model; +using GB28181.Logger4Net; namespace GB28181.Service { @@ -32,6 +41,26 @@ namespace GB28181.Service services.AddSingleton(); services.AddHostedService(); services.AddGrpc(); + services.AddSingleton() + .AddSingleton() + .AddSingleton() + .AddSingleton() + .AddSingleton() + .AddSingleton() + .AddSingleton() + .AddScoped() + .AddTransient() + .AddSingleton() + .AddSingleton() + .AddTransient() + .AddSingleton() + .AddSingleton, DeviceObjectCache>() + .AddScoped() + .AddScoped() + .AddScoped() + .AddScoped() + .AddScoped(); + } // This method gets called by the runtime. Use this method to configure the HTTP request pipeline. -- Gitee From 3e182987af932b084fc84f3170e29ea958f23d4e Mon Sep 17 00:00:00 2001 From: Edward Date: Tue, 10 Mar 2020 00:15:04 +0800 Subject: [PATCH 10/19] Update README.md --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index 487250b..dbab86d 100644 --- a/README.md +++ b/README.md @@ -1,8 +1,10 @@ # GB28181 Standard ++ GB28181开源的目标是:通过代码复用,适当降低工作难度和减少业务代码的重复性,并非替代你的开发工作或者让你几乎不用开发工作。 + 最新国标是:【[GB28181-2016](docs/GBT%2028181-2016%20公共安全视频监控联网系统信息传输、交换、控制技术要求-目录版.pdf)】 + 项目结构、代码结仍存在不少问题,待完善,因为时间问题,也是希望大家能一起完善 + 希望每一个对本项目感兴趣的朋友,都能成为本项目的共同作者或者贡献者 ++ 注意:**代码一直在更新,GB28181系列项目,并不是生产就绪的,往往须要根据自己的项目和产品架构,做适当的调整和适配!!** ## 运行环境(environment) -- Gitee From da9490e77c731ea0536faf455202096bd73ebfe2 Mon Sep 17 00:00:00 2001 From: Edward Date: Tue, 10 Mar 2020 00:16:06 +0800 Subject: [PATCH 11/19] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index dbab86d..3600292 100644 --- a/README.md +++ b/README.md @@ -52,7 +52,7 @@ running on aspnetcore 3.1+ + [x] 注册到服务的设备信息缓存 + [ ] 注册到服务的平台信息缓存,待进一步测试 -+ Streaming Media(流媒体,以EasydarwinGo为基础) ++ Streaming Media(流媒体,以【[monibuca](https://github.com/langhuihui/monibuca)】为基础) + [ ] 实现SIP信令服务与流媒体服务交互的GRPC接口。 + [ ] 实现完整的实时视频播放功能, Video Live Play + [ ] 实现完整的历史视频搜索功能,History Video Record Search -- Gitee From 51f7afb9e2e11fd064e8360b2327f34754fd8bba Mon Sep 17 00:00:00 2001 From: Edward Date: Sat, 21 Mar 2020 13:26:29 +0800 Subject: [PATCH 12/19] Update README.md --- README.md | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 3600292..b8f52f4 100644 --- a/README.md +++ b/README.md @@ -29,7 +29,7 @@ running on aspnetcore 3.1+ 打勾的是已完成的,没打勾的是正在做的,需要大家一起完成的。 -+ Architecture架构 ++ Architecture & framework + [x] 设计与流媒体服务交互的GRPC接口 + [x] 设计与系统配置服务(或数据服务)交互的GRPC接口 + [x] 精简服务模块,调整代码结构关系 @@ -53,7 +53,8 @@ running on aspnetcore 3.1+ + [ ] 注册到服务的平台信息缓存,待进一步测试 + Streaming Media(流媒体,以【[monibuca](https://github.com/langhuihui/monibuca)】为基础) - + [ ] 实现SIP信令服务与流媒体服务交互的GRPC接口。 + + [x] 定义SIP信令服务与流媒体服务交互的RTSP接口 + + [x] 定义SIP信令服务与流媒体服务交互的GRPC接口 + [ ] 实现完整的实时视频播放功能, Video Live Play + [ ] 实现完整的历史视频搜索功能,History Video Record Search + [ ] 实现完整的历史视频播放功能, History Video PlayBack -- Gitee From 8dd2aa3179837a3987b06d1b7eff99dbe5d6beff Mon Sep 17 00:00:00 2001 From: Edward Date: Sat, 21 Mar 2020 13:26:49 +0800 Subject: [PATCH 13/19] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index b8f52f4..b52497b 100644 --- a/README.md +++ b/README.md @@ -54,7 +54,7 @@ running on aspnetcore 3.1+ + Streaming Media(流媒体,以【[monibuca](https://github.com/langhuihui/monibuca)】为基础) + [x] 定义SIP信令服务与流媒体服务交互的RTSP接口 - + [x] 定义SIP信令服务与流媒体服务交互的GRPC接口 + + [ ] 定义SIP信令服务与流媒体服务交互的GRPC接口 + [ ] 实现完整的实时视频播放功能, Video Live Play + [ ] 实现完整的历史视频搜索功能,History Video Record Search + [ ] 实现完整的历史视频播放功能, History Video PlayBack -- Gitee From 34c050bee09fb5fb1fd811f4b349da96da0f82c0 Mon Sep 17 00:00:00 2001 From: YIHONG LIN <121553122@qq.com> Date: Wed, 1 Apr 2020 17:39:23 +0800 Subject: [PATCH 14/19] =?UTF-8?q?=E4=BF=AE=E5=A4=8Dservice=E5=90=AF?= =?UTF-8?q?=E5=8A=A8=E9=97=AE=E9=A2=98=EF=BC=8C=E5=92=8Cgb2312=E6=8A=A5?= =?UTF-8?q?=E9=94=99=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- GB28181.SIPSorcery/SIP.Core/SIP/SIPTransport.cs | 1 + GB28181.Server/Main/MainProcess.cs | 4 ++-- GB28181.Server/appsettings.json | 4 ++-- 3 files changed, 5 insertions(+), 4 deletions(-) diff --git a/GB28181.SIPSorcery/SIP.Core/SIP/SIPTransport.cs b/GB28181.SIPSorcery/SIP.Core/SIP/SIPTransport.cs index 0a6b7c4..87795ed 100644 --- a/GB28181.SIPSorcery/SIP.Core/SIP/SIPTransport.cs +++ b/GB28181.SIPSorcery/SIP.Core/SIP/SIPTransport.cs @@ -1268,6 +1268,7 @@ namespace GB28181.SIPSorcery.SIP else { //rawSIPMessage = Encoding.Default.GetString(buffer, 0, buffer.Length); + Encoding.RegisterProvider(CodePagesEncodingProvider.Instance);//ע,ʹGB2312쳣System.Text.Encoding.CodePagesʹ rawSIPMessage = Encoding.GetEncoding("GB2312").GetString(buffer, 0, buffer.Length); if (!rawSIPMessage.StartsWith("REGISTER") && !rawSIPMessage.StartsWith("MESSAGE")) { diff --git a/GB28181.Server/Main/MainProcess.cs b/GB28181.Server/Main/MainProcess.cs index f7d0563..7b423f2 100644 --- a/GB28181.Server/Main/MainProcess.cs +++ b/GB28181.Server/Main/MainProcess.cs @@ -36,12 +36,12 @@ namespace GB28181.Server.Main private MessageHub messageCenter; private ISIPRegistrarCore registry; - public MainProcess(ISipMessageCore sipMessageCore, MessageHub messageHub, ISIPRegistrarCore sipRegistrarCore, IServiceCollection services) + public MainProcess(ISipMessageCore sipMessageCore, MessageHub messageHub, ISIPRegistrarCore sipRegistrarCore) { _mainSipService = sipMessageCore; messageCenter = messageHub; registry = sipRegistrarCore; - _serviceProvider = services.BuildServiceProvider(); + // _serviceProvider = services.BuildServiceProvider();//, IServiceCollection services } public void Stop() diff --git a/GB28181.Server/appsettings.json b/GB28181.Server/appsettings.json index 5d859fd..52d8e0c 100644 --- a/GB28181.Server/appsettings.json +++ b/GB28181.Server/appsettings.json @@ -5,7 +5,7 @@ "Name": "ϼƽ̨", "GbVersion": "GB-2016", "LocalID": "42010000002100000002", - "LocalIP": "10.78.115.182", + "LocalIP": "127.0.0.1", "LocalPort": "5061", "RemotePort": "5060", "Authentication": "false", @@ -21,7 +21,7 @@ "ServiceType": "Device" } }, - "urls": "https://localhost:8080;http://*:80", + "urls": "https://localhost:8080;http://*:82", "Logging": { "LogLevel": { "Default": "Information", -- Gitee From 3a0979f9a8cba5994e79991d8c8b7b462d259fee Mon Sep 17 00:00:00 2001 From: YIHONG LIN <121553122@qq.com> Date: Fri, 10 Apr 2020 17:01:57 +0800 Subject: [PATCH 15/19] --- --- .../Servers.Cores/SIPMessage/SIPMessageCore.cs | 11 ++++++++--- GB28181.Server/Config/gb28181.xml | 2 +- GB28181.Server/Main/MainProcess.cs | 4 ++-- GB28181.Server/Main/MessageHub.cs | 1 + GB28181.Server/appsettings.json | 4 ++-- Win.GB28181.Client/Form1.cs | 17 +++++++++++++++-- 6 files changed, 29 insertions(+), 10 deletions(-) diff --git a/GB28181.SIPSorcery/Servers.Cores/SIPMessage/SIPMessageCore.cs b/GB28181.SIPSorcery/Servers.Cores/SIPMessage/SIPMessageCore.cs index 8980b8f..de18e94 100644 --- a/GB28181.SIPSorcery/Servers.Cores/SIPMessage/SIPMessageCore.cs +++ b/GB28181.SIPSorcery/Servers.Cores/SIPMessage/SIPMessageCore.cs @@ -166,13 +166,13 @@ namespace GB28181.SIPSorcery.Servers.SIPMessage // MessageCore = new SIPMessageCore(m_sipTransport, SIPConstants.SIP_SERVER_STRING); public SIPMessageCore(ISIPTransport sipTransport, string sipServerAgentStr) { + _registrarCore = new SIPRegistrarCore(); _transport = sipTransport; _sipServerAgent = sipServerAgentStr; // Configure the SIP transport layer. _transport.SIPTransportRequestReceived += AddMessageRequest; _transport.SIPTransportResponseReceived += AddMessageResponse; - - _cameraCache.OnItemAdded += _cameraCache_OnItemAdded; + //_cameraCache.OnItemAdded += _cameraCache_OnItemAdded; } @@ -227,7 +227,12 @@ namespace GB28181.SIPSorcery.Servers.SIPMessage public void Start() { _serviceState = ServiceStatus.Wait; - LocalEP = SIPEndPoint.ParseSIPEndPoint(_LocalSipAccount.MsgProtocol + ":" + _LocalSipAccount.LocalIP.ToString() + ":" + _LocalSipAccount.LocalPort); + _LocalSipAccount = new SIPAccount(); + _LocalSipAccount.MsgProtocol = ProtocolType.Udp; + _LocalSipAccount.LocalIP = IPAddress.Parse("192.168.197.108") ; + // _LocalSipAccount.LocalPort = ushort.Parse("5061"); + + LocalEP = SIPEndPoint.ParseSIPEndPoint(_LocalSipAccount.MsgProtocol + ":" + _LocalSipAccount.LocalIP.ToString() + ":5061"); LocalSIPId = _LocalSipAccount.LocalID; try diff --git a/GB28181.Server/Config/gb28181.xml b/GB28181.Server/Config/gb28181.xml index 68fb26b..d4fa5ea 100644 --- a/GB28181.Server/Config/gb28181.xml +++ b/GB28181.Server/Config/gb28181.xml @@ -4,7 +4,7 @@ 上级平台 GB-2016 42010000002100000002 - 10.78.115.182 + 127.0.0.1 5061 5060 false diff --git a/GB28181.Server/Main/MainProcess.cs b/GB28181.Server/Main/MainProcess.cs index 7b423f2..383b304 100644 --- a/GB28181.Server/Main/MainProcess.cs +++ b/GB28181.Server/Main/MainProcess.cs @@ -107,8 +107,8 @@ namespace GB28181.Server.Main Task.Factory.StartNew(() => registry.ProcessRegisterRequest(), _registryServiceToken.Token); - //Device Status Report - Task.Factory.StartNew(() => messageCenter.DeviceStatusReport(), _deviceStatusReportToken.Token); + //Device Status Report 设备状态 + //Task.Factory.StartNew(() => messageCenter.DeviceStatusReport(), _deviceStatusReportToken.Token); } catch (Exception exMsg) { diff --git a/GB28181.Server/Main/MessageHub.cs b/GB28181.Server/Main/MessageHub.cs index 07d5cb8..4a19472 100644 --- a/GB28181.Server/Main/MessageHub.cs +++ b/GB28181.Server/Main/MessageHub.cs @@ -462,6 +462,7 @@ namespace GB28181.Server.Main /// private bool IsDeviceExisted(string deviceid) { + //return true; bool tf = false; //var options = new List { new ChannelOption(ChannelOptions.MaxMessageLength, int.MaxValue) }; // Channel channel = new Channel(EnvironmentVariables.DeviceManagementServiceAddress ?? "devicemanagementservice:8080", ChannelCredentials.Insecure); diff --git a/GB28181.Server/appsettings.json b/GB28181.Server/appsettings.json index 52d8e0c..0f4946f 100644 --- a/GB28181.Server/appsettings.json +++ b/GB28181.Server/appsettings.json @@ -4,7 +4,7 @@ "ID": "10", "Name": "ϼƽ̨", "GbVersion": "GB-2016", - "LocalID": "42010000002100000002", + "LocalID": "34020000002000000001", "LocalIP": "127.0.0.1", "LocalPort": "5061", "RemotePort": "5060", @@ -21,7 +21,7 @@ "ServiceType": "Device" } }, - "urls": "https://localhost:8080;http://*:82", + "urls": "https://localhost:8082;http://*:82", "Logging": { "LogLevel": { "Default": "Information", diff --git a/Win.GB28181.Client/Form1.cs b/Win.GB28181.Client/Form1.cs index 08b5c5c..58fcaa3 100644 --- a/Win.GB28181.Client/Form1.cs +++ b/Win.GB28181.Client/Form1.cs @@ -19,6 +19,7 @@ using System.Text; using System.Threading; using System.Windows.Forms; using Win.GB28181.Client.Player.Analyzer; +using GB28181.SIPSorcery.SIP.App; namespace Win.GB28181.Client { @@ -133,7 +134,18 @@ namespace Win.GB28181.Client _keepaliveTime = DateTime.Now; _cataThread = new Thread(new ThreadStart(HandleCata)); _keepaliveThread = new Thread(new ThreadStart(HandleKeepalive)); - // _messageCore = new SIPMessageCore(cameras, account); + + + SIPTransport m_sipTransport; + + m_sipTransport = new SIPTransport(SIPDNSManager.ResolveSIPService, new SIPTransactionEngine(), false); + m_sipTransport.PerformanceMonitorPrefix = SIPSorceryPerformanceMonitor.REGISTRAR_PREFIX; + SIPAccount account = SipAccountStorage.Instance.Accounts.FirstOrDefault(); + var sipChannels = SIPTransportConfig.ParseSIPChannelsNode(account.LocalIP, account.LocalPort); + m_sipTransport.AddSIPChannel(sipChannels); + + + _messageCore = new SIPMessageCore(m_sipTransport, SIPConstants.SIP_SERVER_STRING); } #endregion @@ -155,12 +167,13 @@ namespace Win.GB28181.Client //tvCalatog.Nodes.Add(_tn); _keepaliveTime = DateTime.Now; + playerWin = new SS.ClientBase.PlayerControl(); playerWin.Start(); Initialize(); _cataThread.Start(); _keepaliveThread.Start(); - + // _messageCore = new SIPMessageCore(); _messageCore.Start(); _messageCore.OnServiceChanged += SIPServiceChangeHandle; _messageCore.OnCatalogReceived += m_msgCore_OnCatalogReceived; -- Gitee From f5bed1cdfe2f30b25a2db995c688a84339b1c8cc Mon Sep 17 00:00:00 2001 From: YIHONG LIN <121553122@qq.com> Date: Fri, 10 Apr 2020 18:16:11 +0800 Subject: [PATCH 16/19] =?UTF-8?q?=E8=B0=83=E8=AF=95=E5=B7=A5=E5=85=B7?= =?UTF-8?q?=E5=90=AF=E5=8A=A8=E9=97=AE=E9=A2=98=E9=83=A8=E5=88=86=E4=BF=AE?= =?UTF-8?q?=E5=A4=8D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Servers.Cores/SIPMessage/SIPMessageCore.cs | 15 +++++++++------ Test.GB28181.Service/TestMainProcess.cs | 6 +++--- Win.GB28181.Client/Program.cs | 4 +++- 3 files changed, 15 insertions(+), 10 deletions(-) diff --git a/GB28181.SIPSorcery/Servers.Cores/SIPMessage/SIPMessageCore.cs b/GB28181.SIPSorcery/Servers.Cores/SIPMessage/SIPMessageCore.cs index de18e94..37ebf9c 100644 --- a/GB28181.SIPSorcery/Servers.Cores/SIPMessage/SIPMessageCore.cs +++ b/GB28181.SIPSorcery/Servers.Cores/SIPMessage/SIPMessageCore.cs @@ -166,7 +166,7 @@ namespace GB28181.SIPSorcery.Servers.SIPMessage // MessageCore = new SIPMessageCore(m_sipTransport, SIPConstants.SIP_SERVER_STRING); public SIPMessageCore(ISIPTransport sipTransport, string sipServerAgentStr) { - _registrarCore = new SIPRegistrarCore(); + // _registrarCore = new SIPRegistrarCore(); _transport = sipTransport; _sipServerAgent = sipServerAgentStr; // Configure the SIP transport layer. @@ -227,12 +227,15 @@ namespace GB28181.SIPSorcery.Servers.SIPMessage public void Start() { _serviceState = ServiceStatus.Wait; - _LocalSipAccount = new SIPAccount(); - _LocalSipAccount.MsgProtocol = ProtocolType.Udp; - _LocalSipAccount.LocalIP = IPAddress.Parse("192.168.197.108") ; - // _LocalSipAccount.LocalPort = ushort.Parse("5061"); - LocalEP = SIPEndPoint.ParseSIPEndPoint(_LocalSipAccount.MsgProtocol + ":" + _LocalSipAccount.LocalIP.ToString() + ":5061"); + if (_LocalSipAccount == null) + { + _LocalSipAccount = new SIPAccount(); + _LocalSipAccount.MsgProtocol = ProtocolType.Udp; + _LocalSipAccount.LocalIP = IPAddress.Parse("127.0.0.1"); + _LocalSipAccount.LocalPort = ushort.Parse("5061"); + } + LocalEP = SIPEndPoint.ParseSIPEndPoint(_LocalSipAccount.MsgProtocol + ":" + _LocalSipAccount.LocalIP.ToString() + ":" + _LocalSipAccount.LocalPort); LocalSIPId = _LocalSipAccount.LocalID; try diff --git a/Test.GB28181.Service/TestMainProcess.cs b/Test.GB28181.Service/TestMainProcess.cs index 781e9eb..a351700 100644 --- a/Test.GB28181.Service/TestMainProcess.cs +++ b/Test.GB28181.Service/TestMainProcess.cs @@ -19,10 +19,10 @@ namespace Test.GB28181.Service //SipAccountStorage sas = new SipAccountStorage(); ////ISipAccountStorageMock.Setup(accouts=> accouts.Accounts.Add(new GB28181.SIPSorcery.SIP.App.SIPAccount { })) ; //var IMemoCacheMock = new Mock>(); - var obj = new MainProcess(); - obj.Run(); + //var obj = new MainProcess(); + //obj.Run(); - Assert.NotNull(obj); + //Assert.NotNull(obj); } } } diff --git a/Win.GB28181.Client/Program.cs b/Win.GB28181.Client/Program.cs index 52822a9..d4a5519 100644 --- a/Win.GB28181.Client/Program.cs +++ b/Win.GB28181.Client/Program.cs @@ -1,4 +1,5 @@ -using System; +using GB28181.SIPSorcery.Servers; +using System; using System.Windows.Forms; namespace Win.GB28181.Client @@ -11,6 +12,7 @@ namespace Win.GB28181.Client [STAThread] static void Main() { + // ISIPRegistrarCore aa = new SIPRegistrarCore(); Application.EnableVisualStyles(); Application.SetCompatibleTextRenderingDefault(false); Application.Run(new Form1()); -- Gitee From 41a0eb22e53946a30afc42a58eb117564683ec3b Mon Sep 17 00:00:00 2001 From: lin <121553122@qq.com> Date: Sun, 19 Apr 2020 16:26:08 +0800 Subject: [PATCH 17/19] =?UTF-8?q?Client=E6=B5=8B=E8=AF=95=E5=B7=A5?= =?UTF-8?q?=E5=85=B7=E4=BC=98=E5=8C=96=EF=BC=8C=E5=A4=A7=E9=83=A8=E5=88=86?= =?UTF-8?q?=E5=8A=9F=E8=83=BD=E5=8F=AF=E4=BD=BF=E7=94=A8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../SIP.Core/SIP/SIPConstants.cs | 2 +- .../SIP.Core/SIP/SIPResponse.cs | 12 +-- .../SIPMessage/SIPMessageCore.cs | 15 ++- .../SIPMonitor/SIPMonitorCore.cs | 14 +-- .../Sys/EnvironmentVariables.cs | 2 +- GB28181.Server/Config/gb28181.xml | 4 +- GB28181.Server/Main/Initialize.cs | 4 +- GB28181.Server/Main/MessageHub.cs | 2 +- GB28181.Server/Main/MockProcess.cs | 2 +- .../Protos/AsClient/system_config.proto | 2 +- GB28181.Server/Services/DeviceManageImpl.cs | 2 +- GB28181.Server/Services/SSMediaSessionImpl.cs | 16 +-- GB28181.Server/appsettings.json | 2 +- Test.GB28181.Service/Config/gb28181.xml | 4 +- Win.GB28181.Client/Config/gb28181.bak.xml | 21 ++++ Win.GB28181.Client/Config/gb28181.xml | 23 +++++ Win.GB28181.Client/Form1.cs | 97 ++++++++++++++++--- Win.GB28181.Client/Program.cs | 12 ++- Win.GB28181.Client/Win.GB28181.Client.csproj | 2 + 19 files changed, 181 insertions(+), 57 deletions(-) create mode 100644 Win.GB28181.Client/Config/gb28181.bak.xml create mode 100644 Win.GB28181.Client/Config/gb28181.xml diff --git a/GB28181.SIPSorcery/SIP.Core/SIP/SIPConstants.cs b/GB28181.SIPSorcery/SIP.Core/SIP/SIPConstants.cs index e126eee..ff38403 100644 --- a/GB28181.SIPSorcery/SIP.Core/SIP/SIPConstants.cs +++ b/GB28181.SIPSorcery/SIP.Core/SIP/SIPConstants.cs @@ -66,7 +66,7 @@ namespace GB28181.SIPSorcery.SIP public const int DEFAULT_MAX_FORWARDS = 70; public const int DEFAULT_REGISTEREXPIRY_SECONDS = 600; public const int DEFAULT_SIP_PORT = 5060; - public const int DEFAULT_SIP_TLS_PORT = 5061; + public const int DEFAULT_SIP_TLS_PORT = 5060; public const int MAX_SIP_PORT = 65535; public const string NAT_SENDKEEPALIVES_VALUE = "y"; diff --git a/GB28181.SIPSorcery/SIP.Core/SIP/SIPResponse.cs b/GB28181.SIPSorcery/SIP.Core/SIP/SIPResponse.cs index cbd98e3..83f719f 100644 --- a/GB28181.SIPSorcery/SIP.Core/SIP/SIPResponse.cs +++ b/GB28181.SIPSorcery/SIP.Core/SIP/SIPResponse.cs @@ -413,15 +413,15 @@ namespace GB28181.SIPSorcery.SIP "SIP/2.0 200 OK" + m_CRLF + "From: Blue Face;tag=as5fd53de7" + m_CRLF + "To: sip:xxx@127.0.0.1;tag=MTHf2-ol1Yn0" + m_CRLF + - "Call-ID: 3e7df9d805ac596f3f091510164115e2@212.159.110.30:5061" + m_CRLF + + "Call-ID: 3e7df9d805ac596f3f091510164115e2@212.159.110.30:5060" + m_CRLF + "CSeq: 102 INVITE" + m_CRLF + "Via: SIP/2.0/UDP 213.168.225.133:5060;branch=z9hG4bKG+WGOVwLyT6vOW9s" + m_CRLF + - "Via: SIP/2.0/UDP 213.168.225.133:5061;branch=z9hG4bK09db9c73" + m_CRLF + - "Contact: +3535xxx" + m_CRLF + + "Via: SIP/2.0/UDP 213.168.225.133:5060;branch=z9hG4bK09db9c73" + m_CRLF + + "Contact: +3535xxx" + m_CRLF + "User-Agent: MSC/VC510 Build-Date Nov 7 2005" + m_CRLF + "Allow: INVITE,BYE,CANCEL,OPTIONS,PRACK,NOTIFY,UPDATE,REFER" + m_CRLF + "Supported: timer,replaces" + m_CRLF + - "Record-Route: ," + m_CRLF + + "Record-Route: ," + m_CRLF + "Content-Type: application/sdp" + m_CRLF + "Content-Length: 182" + m_CRLF + m_CRLF + @@ -532,9 +532,9 @@ namespace GB28181.SIPSorcery.SIP string sipMsg = "SIP/2.0 200 OK" + m_CRLF + - "Via: SIP/2.0/UDP 194.213.29.100:5060;branch=z9hG4bK5feb18267ce40fb05969b4ba843681dbfc9ffcff, SIP/2.0/UDP 194.213.29.54:5061;branch=z9hG4bK52b6a8b7" + m_CRLF + + "Via: SIP/2.0/UDP 194.213.29.100:5060;branch=z9hG4bK5feb18267ce40fb05969b4ba843681dbfc9ffcff, SIP/2.0/UDP 194.213.29.54:5060;branch=z9hG4bK52b6a8b7" + m_CRLF + "Record-Route: " + m_CRLF + - "From: Unknown ;tag=as58cbdbd1" + m_CRLF + + "From: Unknown ;tag=as58cbdbd1" + m_CRLF + "To: ;tag=1144090013" + m_CRLF + "Call-ID: 40741a72794b85ed197e1e020bf42bb9@194.213.29.54" + m_CRLF + "CSeq: 102 INVITE" + m_CRLF + diff --git a/GB28181.SIPSorcery/Servers.Cores/SIPMessage/SIPMessageCore.cs b/GB28181.SIPSorcery/Servers.Cores/SIPMessage/SIPMessageCore.cs index 37ebf9c..f6aa93f 100644 --- a/GB28181.SIPSorcery/Servers.Cores/SIPMessage/SIPMessageCore.cs +++ b/GB28181.SIPSorcery/Servers.Cores/SIPMessage/SIPMessageCore.cs @@ -166,7 +166,7 @@ namespace GB28181.SIPSorcery.Servers.SIPMessage // MessageCore = new SIPMessageCore(m_sipTransport, SIPConstants.SIP_SERVER_STRING); public SIPMessageCore(ISIPTransport sipTransport, string sipServerAgentStr) { - // _registrarCore = new SIPRegistrarCore(); + // _registrarCore = new SIPRegistrarCore(); _transport = sipTransport; _sipServerAgent = sipServerAgentStr; // Configure the SIP transport layer. @@ -233,7 +233,7 @@ namespace GB28181.SIPSorcery.Servers.SIPMessage _LocalSipAccount = new SIPAccount(); _LocalSipAccount.MsgProtocol = ProtocolType.Udp; _LocalSipAccount.LocalIP = IPAddress.Parse("127.0.0.1"); - _LocalSipAccount.LocalPort = ushort.Parse("5061"); + _LocalSipAccount.LocalPort = ushort.Parse("5060"); } LocalEP = SIPEndPoint.ParseSIPEndPoint(_LocalSipAccount.MsgProtocol + ":" + _LocalSipAccount.LocalIP.ToString() + ":" + _LocalSipAccount.LocalPort); LocalSIPId = _LocalSipAccount.LocalID; @@ -665,8 +665,15 @@ namespace GB28181.SIPSorcery.Servers.SIPMessage { _serviceState = ServiceStatus.Complete; - try { OnServiceChanged.Invoke(msg, state); } - catch { } + if (OnServiceChanged == null) + { + // OnServiceChanged+= MessageHub.OnServiceChanged; + } + else + { + try { OnServiceChanged.Invoke(msg, state); } + catch { } + } //OnServiceChanged?.GetInvocationList().ToList().ForEach((item) => //{ // var handler = item as Action; diff --git a/GB28181.SIPSorcery/Servers.Cores/SIPMonitor/SIPMonitorCore.cs b/GB28181.SIPSorcery/Servers.Cores/SIPMonitor/SIPMonitorCore.cs index e0a0f3e..0503e5d 100644 --- a/GB28181.SIPSorcery/Servers.Cores/SIPMonitor/SIPMonitorCore.cs +++ b/GB28181.SIPSorcery/Servers.Cores/SIPMonitor/SIPMonitorCore.cs @@ -23,7 +23,6 @@ namespace GB28181.SIPSorcery.Servers.SIPMonitor #region 私有字段 private static ILog logger = AppState.logger; private AutoResetEvent _autoResetEventForRpc = new AutoResetEvent(false); - //concurent requet/reply private ConcurrentDictionary _syncRequestContext = new ConcurrentDictionary(); private ConcurrentQueue> _syncResponseContext = new ConcurrentQueue>(); @@ -38,7 +37,6 @@ namespace GB28181.SIPSorcery.Servers.SIPMonitor // RTP wil be established from other place // private Channel _channel; public string DeviceId { get; set; } - private SIPRequest _reqSession; private int[] _mediaPort; // private SIPContactHeader _contact; @@ -47,18 +45,14 @@ namespace GB28181.SIPSorcery.Servers.SIPMonitor private int _recordTotal = -1; // private DevStatus _Status; private SIPAccount _sipAccount; - private ISIPTransport _sipTransport; - #endregion - #region 事件回调 ///

/// 视频流回调 /// public event Action OnStreamReady; #endregion - #region 初始化监控 //public SIPMonitorCore(ISipMessageCore sipMsgCoreService, ISIPTransport sipTransport, ISipAccountStorage sipAccountStorage) public SIPMonitorCore(ISipMessageCore sipMessageCore, ISIPTransport sipTransport, ISipAccountStorage sipAccountStorage) @@ -78,8 +72,8 @@ namespace GB28181.SIPSorcery.Servers.SIPMonitor /// 设备编码 public void RealVideoReq() { - //_mediaPort = _msgCore.SetMediaPort(); - //string localIp = _msgCore.LocalEP.Address.ToString(); + //_mediaPort = _sipMsgCoreService.SetMediaPort(); + //string localIp = _sipMsgCoreService.LocalEP.Address.ToString(); //string fromTag = CallProperties.CreateNewTag(); //int cSeq = CallProperties.CreateNewCSeq(); //string callId = CallProperties.CreateNewCallId(); @@ -88,7 +82,7 @@ namespace GB28181.SIPSorcery.Servers.SIPMonitor //SIPURI localUri = new SIPURI(_msgCore.LocalSIPId, _msgCore.LocalEP.ToHost(), ""); //SIPFromHeader from = new SIPFromHeader(null, localUri, fromTag); //SIPToHeader to = new SIPToHeader(null, remoteUri, null); - //SIPRequest realReq = _msgCore.Transport.GetRequest(SIPMethodsEnum.INVITE, remoteUri); + //SIPRequest realReq = _sipMsgCoreService.Transport.GetRequest(SIPMethodsEnum.INVITE, remoteUri); //SIPContactHeader contactHeader = new SIPContactHeader(null, localUri); //realReq.Header.Contact.Clear(); //realReq.Header.Contact.Add(contactHeader); @@ -103,7 +97,7 @@ namespace GB28181.SIPSorcery.Servers.SIPMonitor //realReq.Header.ContentType = "application/sdp"; //realReq.Body = SetMediaReq(localIp, _mediaPort); - //_msgCore.SendReliableRequest(_remoteEP, realReq); + //_sipMsgCoreService.SendReliableRequest(_remoteEP, realReq); //_reqSession = realReq; } diff --git a/GB28181.SIPSorcery/Sys/EnvironmentVariables.cs b/GB28181.SIPSorcery/Sys/EnvironmentVariables.cs index 534439b..32b2a59 100644 --- a/GB28181.SIPSorcery/Sys/EnvironmentVariables.cs +++ b/GB28181.SIPSorcery/Sys/EnvironmentVariables.cs @@ -54,7 +54,7 @@ namespace GB28181.SIPSorcery.Sys } public static int GbServiceLocalPort //obsolete { - get { return 5061; } + get { return 5060; } } } } diff --git a/GB28181.Server/Config/gb28181.xml b/GB28181.Server/Config/gb28181.xml index d4fa5ea..d6d6738 100644 --- a/GB28181.Server/Config/gb28181.xml +++ b/GB28181.Server/Config/gb28181.xml @@ -3,9 +3,9 @@ 10 上级平台 GB-2016 - 42010000002100000002 + 34020000002000000001 127.0.0.1 - 5061 + 5060 5060 false admin diff --git a/GB28181.Server/Main/Initialize.cs b/GB28181.Server/Main/Initialize.cs index 3b45ac4..8a046d1 100644 --- a/GB28181.Server/Main/Initialize.cs +++ b/GB28181.Server/Main/Initialize.cs @@ -28,9 +28,9 @@ namespace GB28181.Server.Main obj.Id = Guid.NewGuid(); //obj.Owner = item.Name; obj.GbVersion = string.IsNullOrEmpty(item.GbVersion) ? "GB-2016" : item.GbVersion; - obj.LocalID = string.IsNullOrEmpty(item.LocalID) ? "42010000002100000002" : item.LocalID; + obj.LocalID = string.IsNullOrEmpty(item.LocalID) ? "34020000002000000001" : item.LocalID; obj.LocalIP = HostsEnv.GetRawIP(); - obj.LocalPort = string.IsNullOrEmpty(item.LocalPort) ? Convert.ToUInt16(5061) : Convert.ToUInt16(item.LocalPort); + obj.LocalPort = string.IsNullOrEmpty(item.LocalPort) ? Convert.ToUInt16(5060) : Convert.ToUInt16(item.LocalPort); obj.RemotePort = string.IsNullOrEmpty(item.RemotePort) ? Convert.ToUInt16(5060) : Convert.ToUInt16(item.RemotePort); obj.Authentication = string.IsNullOrEmpty(item.Authentication) ? false : bool.Parse(item.Authentication); obj.SIPUsername = string.IsNullOrEmpty(item.SIPUsername) ? "admin" : item.SIPUsername; diff --git a/GB28181.Server/Main/MessageHub.cs b/GB28181.Server/Main/MessageHub.cs index 4a19472..77ae7fe 100644 --- a/GB28181.Server/Main/MessageHub.cs +++ b/GB28181.Server/Main/MessageHub.cs @@ -396,7 +396,7 @@ namespace GB28181.Server.Main _device.Name = gbname; _device.LoginUser.Add(new LoginUser() { LoginName = _SIPAccount.SIPUsername ?? "admin", LoginPwd = _SIPAccount.SIPPassword ?? "123456" });//same to GB config service _device.Port = Convert.ToUInt32(sipTransaction.TransactionRequest.RemoteSIPEndPoint.Port);//5060 - _device.GBID = sipTransaction.TransactionRequestFrom.URI.User;//42010000001180000184 + _device.GBID = sipTransaction.TransactionRequestFrom.URI.User;//78978201001320000015 _device.PtzType = 0; _device.ProtocolType = 0; _device.ShapeType = ShapeType.Dome; diff --git a/GB28181.Server/Main/MockProcess.cs b/GB28181.Server/Main/MockProcess.cs index 3b2530f..71b590e 100644 --- a/GB28181.Server/Main/MockProcess.cs +++ b/GB28181.Server/Main/MockProcess.cs @@ -53,7 +53,7 @@ namespace GB28181.Server.Main case ConsoleKey.I: { var mockCaller = _serviceProvider.GetService(); - //mockCaller.MakeVideoRequest("42010000001180000184", new int[] { 5060 }, EnvironmentVariables.LocalIp); + //mockCaller.MakeVideoRequest("78978201001320000015", new int[] { 5060 }, EnvironmentVariables.LocalIp); } break; case ConsoleKey.E: diff --git a/GB28181.Server/Protos/AsClient/system_config.proto b/GB28181.Server/Protos/AsClient/system_config.proto index 2837aa6..8e7adef 100644 --- a/GB28181.Server/Protos/AsClient/system_config.proto +++ b/GB28181.Server/Protos/AsClient/system_config.proto @@ -44,7 +44,7 @@ message GBPlatformConfig{ string GbVersion = 3;//版本,例如:GB-2018 string LocalID = 4;//SIP服务器编号*,例如:42010000002100000002 string LocalIP = 5;//SIP服务器IP*,例如:10.78.115.182 - string LocalPort = 6;//SIP服务器端口号*,例如:5061 + string LocalPort = 6;//SIP服务器端口号*,例如:5060 string RemotePort = 7;//Device本地端口*,例如:5060 string Authentication = 8;//授权,例如:false string SIPUsername = 9;//帐号*,例如:admin diff --git a/GB28181.Server/Services/DeviceManageImpl.cs b/GB28181.Server/Services/DeviceManageImpl.cs index e05781a..53f113d 100644 --- a/GB28181.Server/Services/DeviceManageImpl.cs +++ b/GB28181.Server/Services/DeviceManageImpl.cs @@ -29,7 +29,7 @@ namespace GB28181.Service.Protos.AsClient.DeviceManagement _device.Name = "gb" + _device.IP; _device.LoginUser.Add(new LoginUser() { LoginName = sIPAccount.SIPUsername ?? "admin", LoginPwd = sIPAccount.SIPPassword ?? "123456" }); _device.Port = Convert.ToUInt32(sipTransaction.TransactionRequest.RemoteSIPEndPoint.Port);//5060 - _device.GBID = sipTransaction.TransactionRequestFrom.URI.User;//42010000001180000184 + _device.GBID = sipTransaction.TransactionRequestFrom.URI.User;//78978201001320000015 _device.PtzType = 0; _device.ProtocolType = 0; _device.ShapeType = ShapeType.Dome; diff --git a/GB28181.Server/Services/SSMediaSessionImpl.cs b/GB28181.Server/Services/SSMediaSessionImpl.cs index 0ad9217..6e5402c 100644 --- a/GB28181.Server/Services/SSMediaSessionImpl.cs +++ b/GB28181.Server/Services/SSMediaSessionImpl.cs @@ -174,13 +174,13 @@ namespace GB28181.Service.Protos.Video switch (request.BusinessType) { case BusinessType.BtLiveplay: - tf = _sipServiceDirector.Stop(string.IsNullOrEmpty(request.Gbid) ? "42010000001180000184" : request.Gbid, request.Hdr.Sessionid); + tf = _sipServiceDirector.Stop(string.IsNullOrEmpty(request.Gbid) ? "78978201001320000015" : request.Gbid, request.Hdr.Sessionid); break; case BusinessType.BtPlayback: - tf = _sipServiceDirector.BackVideoStopPlayingControlReq(string.IsNullOrEmpty(request.Gbid) ? "42010000001180000184" : request.Gbid, request.Hdr.Sessionid); + tf = _sipServiceDirector.BackVideoStopPlayingControlReq(string.IsNullOrEmpty(request.Gbid) ? "78978201001320000015" : request.Gbid, request.Hdr.Sessionid); break; default: - tf = _sipServiceDirector.Stop(string.IsNullOrEmpty(request.Gbid) ? "42010000001180000184" : request.Gbid, request.Hdr.Sessionid); + tf = _sipServiceDirector.Stop(string.IsNullOrEmpty(request.Gbid) ? "78978201001320000015" : request.Gbid, request.Hdr.Sessionid); break; } msg = tf ? "Stop Successful!" : "Stop Failed!"; @@ -227,19 +227,19 @@ namespace GB28181.Service.Protos.Video switch (request.PlaybackType) { case PlaybackControlType.Moveto: - tf = _sipServiceDirector.BackVideoPlayPositionControlReq(string.IsNullOrEmpty(request.Gbid) ? "42010000001180000184" : request.Gbid, request.Hdr.Sessionid, request.StartTime); + tf = _sipServiceDirector.BackVideoPlayPositionControlReq(string.IsNullOrEmpty(request.Gbid) ? "78978201001320000015" : request.Gbid, request.Hdr.Sessionid, request.StartTime); break; case PlaybackControlType.Pause: - tf = _sipServiceDirector.BackVideoPauseControlReq(string.IsNullOrEmpty(request.Gbid) ? "42010000001180000184" : request.Gbid, request.Hdr.Sessionid); + tf = _sipServiceDirector.BackVideoPauseControlReq(string.IsNullOrEmpty(request.Gbid) ? "78978201001320000015" : request.Gbid, request.Hdr.Sessionid); break; case PlaybackControlType.Resume: - tf = _sipServiceDirector.BackVideoContinuePlayingControlReq(string.IsNullOrEmpty(request.Gbid) ? "42010000001180000184" : request.Gbid, request.Hdr.Sessionid); + tf = _sipServiceDirector.BackVideoContinuePlayingControlReq(string.IsNullOrEmpty(request.Gbid) ? "78978201001320000015" : request.Gbid, request.Hdr.Sessionid); break; case PlaybackControlType.Scale: - tf = _sipServiceDirector.BackVideoPlaySpeedControlReq(string.IsNullOrEmpty(request.Gbid) ? "42010000001180000184" : request.Gbid, request.Hdr.Sessionid, request.Scale); + tf = _sipServiceDirector.BackVideoPlaySpeedControlReq(string.IsNullOrEmpty(request.Gbid) ? "78978201001320000015" : request.Gbid, request.Hdr.Sessionid, request.Scale); break; default: - tf = _sipServiceDirector.Stop(string.IsNullOrEmpty(request.Gbid) ? "42010000001180000184" : request.Gbid, request.Hdr.Sessionid); + tf = _sipServiceDirector.Stop(string.IsNullOrEmpty(request.Gbid) ? "78978201001320000015" : request.Gbid, request.Hdr.Sessionid); break; } msg = tf ? "PlaybackControl Successful!" : "PlaybackControl Failed!"; diff --git a/GB28181.Server/appsettings.json b/GB28181.Server/appsettings.json index 0f4946f..3455b61 100644 --- a/GB28181.Server/appsettings.json +++ b/GB28181.Server/appsettings.json @@ -6,7 +6,7 @@ "GbVersion": "GB-2016", "LocalID": "34020000002000000001", "LocalIP": "127.0.0.1", - "LocalPort": "5061", + "LocalPort": "5060", "RemotePort": "5060", "Authentication": "false", "SIPUsername": "admin", diff --git a/Test.GB28181.Service/Config/gb28181.xml b/Test.GB28181.Service/Config/gb28181.xml index 468cd2c..8082bbf 100644 --- a/Test.GB28181.Service/Config/gb28181.xml +++ b/Test.GB28181.Service/Config/gb28181.xml @@ -3,9 +3,9 @@ 10 上级平台 GB-2016 - 42010000002100000002 + 34020000002000000001 10.77.38.86 - 5061 + 5060 5060 false admin diff --git a/Win.GB28181.Client/Config/gb28181.bak.xml b/Win.GB28181.Client/Config/gb28181.bak.xml new file mode 100644 index 0000000..a296d25 --- /dev/null +++ b/Win.GB28181.Client/Config/gb28181.bak.xml @@ -0,0 +1,21 @@ + + + 10 + 上级平台 + GB-2016 + 34010000002000000001 + 10.77.38.86 + 7777 + 5060 + false + admin + 12345678 + UDP + UDP + passive + GB2312 + true + 5000 + 3 + + \ No newline at end of file diff --git a/Win.GB28181.Client/Config/gb28181.xml b/Win.GB28181.Client/Config/gb28181.xml new file mode 100644 index 0000000..d6d6738 --- /dev/null +++ b/Win.GB28181.Client/Config/gb28181.xml @@ -0,0 +1,23 @@ + + + 10 + 上级平台 + GB-2016 + 34020000002000000001 + 127.0.0.1 + 5060 + 5060 + false + admin + 123456 + UDP + UDP + passive + GB2312 + true + 5000 + 3 + + + + \ No newline at end of file diff --git a/Win.GB28181.Client/Form1.cs b/Win.GB28181.Client/Form1.cs index 58fcaa3..cf59151 100644 --- a/Win.GB28181.Client/Form1.cs +++ b/Win.GB28181.Client/Form1.cs @@ -20,6 +20,12 @@ using System.Threading; using System.Windows.Forms; using Win.GB28181.Client.Player.Analyzer; using GB28181.SIPSorcery.SIP.App; +using Autofac; +using GB28181.Server.Message; +using GB28181.Service; +using GB28181.Server.Main; +using GB28181.SIPSorcery.Sys.Cache; +using System.Threading.Tasks; namespace Win.GB28181.Client { @@ -87,13 +93,65 @@ namespace Win.GB28181.Client #endregion #region 初始化服务 + //在类中定义变量 + private IContainer container; + private readonly CancellationTokenSource _registryServiceToken = new CancellationTokenSource(); public Form1() { + + //构造函数中添加如下代码 + var builder = new ContainerBuilder(); + //.AddSingleton() + // .AddSingleton() + // .AddSingleton() + // .AddSingleton() + // .AddSingleton() + // .AddSingleton() + // .AddScoped() + // .AddTransient() + // .AddSingleton() + // .AddSingleton() + // .AddTransient() + // .AddSingleton() + // .AddSingleton, DeviceObjectCache>() + // .AddScoped() + // .AddScoped() + // .AddScoped() + // .AddScoped() + // .AddScoped(); + + + //builder.RegisterType(); + //builder.RegisterType(); + //builder.RegisterType(); + //builder.RegisterType(); + //builder.RegisterType(); + + //builder.RegisterAssemblyTypes(typeof(ISIPServiceDirector).Assembly).AsImplementedInterfaces(); + //builder.RegisterAssemblyTypes(typeof(ISIPMonitorCore).Assembly).AsImplementedInterfaces(); + //builder.RegisterAssemblyTypes(typeof(ISipMessageCore).Assembly).AsImplementedInterfaces(); + //builder.RegisterType().Named("SIPMessageCore"); + + //builder.RegisterAssemblyTypes(typeof(ISIPTransport).Assembly).AsImplementedInterfaces(); + //builder.RegisterAssemblyTypes(typeof(ISIPTransactionEngine).Assembly).AsImplementedInterfaces(); + //builder.RegisterAssemblyTypes(typeof(ISIPRegistrarCore).Assembly).AsImplementedInterfaces(); + //builder.RegisterAssemblyTypes(typeof(IMemoCache).Assembly).AsImplementedInterfaces(); + + + //builder.RegisterInstance(this).As
(); + //container = builder.Build(); + + + + InitializeComponent(); } - + private ISIPRegistrarCore registry; private void Initialize() { + + + _devList = new List(); txtStartTime.Text = DateTime.Now.ToString("yyyy-MM-dd 8:00:00"); txtStopTime.Text = DateTime.Now.ToString("yyyy-MM-dd 9:00:00"); @@ -124,8 +182,8 @@ namespace Win.GB28181.Client cbxRecordType.ValueMember = "Key"; //SIPSqlite.Instance.Read(); - // var cameras = new List(); - // var account = SIPSqlite.Instance.Accounts.First(); + // var cameras = new List(); + // var account = SIPSqlite.Instance.Accounts.First(); //if (account == null) //{ // logger.Error("Account Config NULL,SIP not started"); @@ -135,17 +193,28 @@ namespace Win.GB28181.Client _cataThread = new Thread(new ThreadStart(HandleCata)); _keepaliveThread = new Thread(new ThreadStart(HandleKeepalive)); - - SIPTransport m_sipTransport; - m_sipTransport = new SIPTransport(SIPDNSManager.ResolveSIPService, new SIPTransactionEngine(), false); + SIPTransport m_sipTransport; + + m_sipTransport = new SIPTransport(SIPDNSManager.ResolveSIPService, new SIPTransactionEngine(), false); m_sipTransport.PerformanceMonitorPrefix = SIPSorceryPerformanceMonitor.REGISTRAR_PREFIX; SIPAccount account = SipAccountStorage.Instance.Accounts.FirstOrDefault(); var sipChannels = SIPTransportConfig.ParseSIPChannelsNode(account.LocalIP, account.LocalPort); m_sipTransport.AddSIPChannel(sipChannels); - _messageCore = new SIPMessageCore(m_sipTransport, SIPConstants.SIP_SERVER_STRING); + + SipAccountStorage sipAccountStorage = new SipAccountStorage(); + IMemoCache aa = new DeviceObjectCache(); + SIPRegistrarCore sipRegistrarCore = new SIPRegistrarCore(m_sipTransport, sipAccountStorage, aa, true, true); + + // _messageCore = new SIPMessageCore(m_sipTransport, SIPConstants.SIP_SERVER_STRING); + _messageCore = new SIPMessageCore(sipRegistrarCore, m_sipTransport, sipAccountStorage, aa); + + Task.Factory.StartNew(() => sipRegistrarCore.ProcessRegisterRequest(), _registryServiceToken.Token); + + // sipRegistrarCore.ProcessRegisterRequest(); + } #endregion @@ -173,7 +242,7 @@ namespace Win.GB28181.Client _cataThread.Start(); _keepaliveThread.Start(); - // _messageCore = new SIPMessageCore(); + // _messageCore = new SIPMessageCore(); _messageCore.Start(); _messageCore.OnServiceChanged += SIPServiceChangeHandle; _messageCore.OnCatalogReceived += m_msgCore_OnCatalogReceived; @@ -588,15 +657,16 @@ namespace Win.GB28181.Client //开始实时视频 private void BtnReal_Click(object sender, EventArgs e) { + int[] mediaPort = { 1000,2000 }; _analyzer = new StreamAnalyzer(); - _messageCore.NodeMonitorService[DevKey.ToString()].RealVideoReq(); + _messageCore.NodeMonitorService[DevKey.ToString()].RealVideoReq(mediaPort, "127.0.0.1", true); _messageCore.NodeMonitorService[DevKey.ToString()].OnStreamReady += Form1_OnStreamReady; } //停止实时视频 private void BtnBye_Click(object sender, EventArgs e) { - _messageCore.NodeMonitorService[DevKey.ToString()].OnStreamReady -= Form1_OnStreamReady; + _messageCore.NodeMonitorService[DevKey.ToString()].OnStreamReady -= Form1_OnStreamReady; _messageCore.NodeMonitorService[DevKey.ToString()].ByeVideoReq(); } @@ -660,7 +730,7 @@ namespace Win.GB28181.Client DateTime startTime = DateTime.Parse(txtStartTime.Text.Trim()); DateTime stopTime = DateTime.Parse(txtStopTime.Text.Trim()); _messageCore.NodeMonitorService[key.ToString()].BackVideoReq(startTime, stopTime); - // _messageCore.NodeMonitorService[key.ToString()].OnStreamReady += Form1_OnStreamReady; + // _messageCore.NodeMonitorService[key.ToString()].OnStreamReady += Form1_OnStreamReady; } //终止点播(停止) @@ -1103,8 +1173,8 @@ namespace Win.GB28181.Client //header.GetBytes(); //packet.Header = header; //packet.Payload = buffer; - - // string viaStr = via.ToString(); + + // string viaStr = via.ToString(); Console.WriteLine(""); @@ -1308,3 +1378,4 @@ a=rtpmap:97 MPEG4/90000"; public KeepAlive Heart { get; set; } } } + diff --git a/Win.GB28181.Client/Program.cs b/Win.GB28181.Client/Program.cs index d4a5519..ada2213 100644 --- a/Win.GB28181.Client/Program.cs +++ b/Win.GB28181.Client/Program.cs @@ -1,18 +1,24 @@ -using GB28181.SIPSorcery.Servers; +using Autofac; +using GB28181.SIPSorcery.Servers; +using GB28181.SIPSorcery.Servers.SIPMessage; using System; +using System.Reflection; using System.Windows.Forms; namespace Win.GB28181.Client { static class Program - { + { /// /// 应用程序的主入口点。 /// [STAThread] static void Main() { - // ISIPRegistrarCore aa = new SIPRegistrarCore(); + + + + // ISIPRegistrarCore aa = new SIPRegistrarCore(); Application.EnableVisualStyles(); Application.SetCompatibleTextRenderingDefault(false); Application.Run(new Form1()); diff --git a/Win.GB28181.Client/Win.GB28181.Client.csproj b/Win.GB28181.Client/Win.GB28181.Client.csproj index e5643f5..c8c3ec7 100644 --- a/Win.GB28181.Client/Win.GB28181.Client.csproj +++ b/Win.GB28181.Client/Win.GB28181.Client.csproj @@ -20,10 +20,12 @@ + + -- Gitee From fe6c927638c00b4a6be2e652ada0b08ef90e10ae Mon Sep 17 00:00:00 2001 From: lin <121553122@qq.com> Date: Sun, 19 Apr 2020 20:35:40 +0800 Subject: [PATCH 18/19] =?UTF-8?q?=E6=B5=8B=E8=AF=95=E5=B7=A5=E5=85=B7?= =?UTF-8?q?=E4=BF=AE=E5=A4=8D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- CallStack1.dgml | 689 ++++++++++++++++++++++++++++++++++++ Win.GB28181.Client/Form1.cs | 9 +- 2 files changed, 692 insertions(+), 6 deletions(-) create mode 100644 CallStack1.dgml diff --git a/CallStack1.dgml b/CallStack1.dgml new file mode 100644 index 0000000..e67b14d --- /dev/null +++ b/CallStack1.dgml @@ -0,0 +1,689 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Win.GB28181.Client/Form1.cs b/Win.GB28181.Client/Form1.cs index cf59151..210b4cb 100644 --- a/Win.GB28181.Client/Form1.cs +++ b/Win.GB28181.Client/Form1.cs @@ -202,14 +202,11 @@ namespace Win.GB28181.Client var sipChannels = SIPTransportConfig.ParseSIPChannelsNode(account.LocalIP, account.LocalPort); m_sipTransport.AddSIPChannel(sipChannels); - - SipAccountStorage sipAccountStorage = new SipAccountStorage(); - IMemoCache aa = new DeviceObjectCache(); - SIPRegistrarCore sipRegistrarCore = new SIPRegistrarCore(m_sipTransport, sipAccountStorage, aa, true, true); - + IMemoCache memocache = new DeviceObjectCache(); + SIPRegistrarCore sipRegistrarCore = new SIPRegistrarCore(m_sipTransport, sipAccountStorage, memocache, true, true); // _messageCore = new SIPMessageCore(m_sipTransport, SIPConstants.SIP_SERVER_STRING); - _messageCore = new SIPMessageCore(sipRegistrarCore, m_sipTransport, sipAccountStorage, aa); + _messageCore = new SIPMessageCore(sipRegistrarCore, m_sipTransport, sipAccountStorage, memocache); Task.Factory.StartNew(() => sipRegistrarCore.ProcessRegisterRequest(), _registryServiceToken.Token); -- Gitee From 1fe185a2fbd419da9aaeeeee7adcae2077d58905 Mon Sep 17 00:00:00 2001 From: lin <121553122@qq.com> Date: Mon, 20 Apr 2020 00:44:40 +0800 Subject: [PATCH 19/19] =?UTF-8?q?=E6=B5=8B=E8=AF=95=E7=9B=B4=E6=92=AD?= =?UTF-8?q?=E6=8E=A8=E6=B5=81=E8=B0=83=E8=AF=95=E6=AD=A3=E5=B8=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- CallStack1.dgml | 6 +++--- Win.GB28181.Client/Form1.cs | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/CallStack1.dgml b/CallStack1.dgml index e67b14d..7654bf8 100644 --- a/CallStack1.dgml +++ b/CallStack1.dgml @@ -101,7 +101,7 @@ - + @@ -125,7 +125,7 @@ - + @@ -193,7 +193,7 @@ - + diff --git a/Win.GB28181.Client/Form1.cs b/Win.GB28181.Client/Form1.cs index 210b4cb..e71d988 100644 --- a/Win.GB28181.Client/Form1.cs +++ b/Win.GB28181.Client/Form1.cs @@ -656,7 +656,7 @@ namespace Win.GB28181.Client { int[] mediaPort = { 1000,2000 }; _analyzer = new StreamAnalyzer(); - _messageCore.NodeMonitorService[DevKey.ToString()].RealVideoReq(mediaPort, "127.0.0.1", true); + _messageCore.NodeMonitorService[DevKey.ToString()].RealVideoReq(mediaPort, "192.168.197.33", true); _messageCore.NodeMonitorService[DevKey.ToString()].OnStreamReady += Form1_OnStreamReady; } -- Gitee