├── CH340BConfigure ├── CH340BConfigure.ico ├── output │ └── CH340BConfigure.exe ├── App.config ├── Properties │ ├── Settings.settings │ ├── Settings.Designer.cs │ ├── AssemblyInfo.cs │ ├── Resources.Designer.cs │ └── Resources.resx ├── CH340BConfigure.sln ├── CH340BConfigurationData.cs ├── Program.cs ├── CH340BConfigure.csproj ├── UiForm.Designer.cs ├── UiForm.cs ├── NativeAccess.cs ├── UiForm.resx └── CH340BDeviceAccess.cs ├── README.md ├── LICENSE ├── .github └── workflows │ └── dotnet-desktop.yml └── .gitignore /CH340BConfigure/CH340BConfigure.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/senthilnathant/tools-ch340b-configuration/HEAD/CH340BConfigure/CH340BConfigure.ico -------------------------------------------------------------------------------- /CH340BConfigure/output/CH340BConfigure.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/senthilnathant/tools-ch340b-configuration/HEAD/CH340BConfigure/output/CH340BConfigure.exe -------------------------------------------------------------------------------- /CH340BConfigure/App.config: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /CH340BConfigure/Properties/Settings.settings: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # tools-ch340b-configuration 2 | 3 | This CH340B Configuration Utility is a .Net Framework WinForms Application - a configuration utility built especially for WCH (WinChipHead) USB-UART Bridge chip - CH340B. The CH340B is a USB to UART Bridge that can be used to provide the Virtual Serial Port interface through USB. 4 | 5 | With this application you can read and update the configuration data of CH340B. 6 | 7 | The configuration data such as Vendor ID, Product ID, Product Name, Serial Number can be read / modified and written to the CH340B chip. This application requires .Net Framework 4.7.2 or above. 8 | 9 | The source code can be compiled on Microsoft Visual Studio 2019 or above with C# .Net Framework 4.7.2 or above. 10 | 11 | This is a free and open source software provided under MIT License. 12 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2021 SENTHILNATHAN THANGAVEL, INDEPENDENT DEVELOPER 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /CH340BConfigure/Properties/Settings.Designer.cs: -------------------------------------------------------------------------------- 1 | //------------------------------------------------------------------------------ 2 | // 3 | // This code was generated by a tool. 4 | // Runtime Version:4.0.30319.42000 5 | // 6 | // Changes to this file may cause incorrect behavior and will be lost if 7 | // the code is regenerated. 8 | // 9 | //------------------------------------------------------------------------------ 10 | 11 | 12 | namespace CH340BConfigure.Properties 13 | { 14 | [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] 15 | [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "11.0.0.0")] 16 | internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase 17 | { 18 | 19 | private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings()))); 20 | 21 | public static Settings Default 22 | { 23 | get 24 | { 25 | return defaultInstance; 26 | } 27 | } 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /CH340BConfigure/CH340BConfigure.sln: -------------------------------------------------------------------------------- 1 | 2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio Version 16 4 | VisualStudioVersion = 16.0.31911.196 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CH340BConfigure", "CH340BConfigure.csproj", "{4CA137FF-16E2-44CA-A27C-81672E1067B1}" 7 | EndProject 8 | Global 9 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 10 | Debug|Any CPU = Debug|Any CPU 11 | Release|Any CPU = Release|Any CPU 12 | EndGlobalSection 13 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 14 | {4CA137FF-16E2-44CA-A27C-81672E1067B1}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 15 | {4CA137FF-16E2-44CA-A27C-81672E1067B1}.Debug|Any CPU.Build.0 = Debug|Any CPU 16 | {4CA137FF-16E2-44CA-A27C-81672E1067B1}.Release|Any CPU.ActiveCfg = Release|Any CPU 17 | {4CA137FF-16E2-44CA-A27C-81672E1067B1}.Release|Any CPU.Build.0 = Release|Any CPU 18 | EndGlobalSection 19 | GlobalSection(SolutionProperties) = preSolution 20 | HideSolutionNode = FALSE 21 | EndGlobalSection 22 | GlobalSection(ExtensibilityGlobals) = postSolution 23 | SolutionGuid = {D6A6FB74-9ADA-4EEB-AFDF-8987C55BC35B} 24 | EndGlobalSection 25 | EndGlobal 26 | -------------------------------------------------------------------------------- /CH340BConfigure/CH340BConfigurationData.cs: -------------------------------------------------------------------------------- 1 | // ********************************************************************************************************* 2 | // 3 | // Project : WCH CH340B Configuration Utility 4 | // FileName : CH340BConfigurationData.cs 5 | // Author : SENTHILNATHAN THANGAVEL, INDEPENDENT DEVELOPER 6 | // Co-Author(s) : 7 | // Created : ‎02 January, ‎2022 8 | // 9 | // ********************************************************************************************************* 10 | // 11 | // Module Description 12 | // 13 | // This class declares the Configuration data such as VID, PID, Product String and Serial number of CH340B 14 | // ********************************************************************************************************* 15 | // 16 | // History 17 | // 18 | // Date Version Author Changes 19 | // 20 | // ‎02 January, ‎2022 1.0.0 SENTHILNATHAN THANGAVEL Initial version 21 | // 22 | // ********************************************************************************************************* 23 | namespace CH340BConfigure 24 | { 25 | public class CH340BConfigurationData 26 | { 27 | public ushort ushVID; 28 | public ushort ushPID; 29 | public string szProductString; 30 | public string szSerialNumber; 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /CH340BConfigure/Program.cs: -------------------------------------------------------------------------------- 1 | // ********************************************************************************************************* 2 | // 3 | // Project : WCH CH340B Configuration Utility 4 | // FileName : Program.cs 5 | // Author : SENTHILNATHAN THANGAVEL, INDEPENDENT DEVELOPER 6 | // Co-Author(s) : 7 | // Created : ‎20 December, ‎2021 8 | // 9 | // ********************************************************************************************************* 10 | // 11 | // Module Description 12 | // 13 | // IDE generated code - main entry point of the application 14 | // ********************************************************************************************************* 15 | // 16 | // History 17 | // 18 | // Date Version Author Changes 19 | // 20 | // 20 December, ‎2021 1.0.0 SENTHILNATHAN THANGAVEL Initial version 21 | // 22 | // ********************************************************************************************************* 23 | using System; 24 | using System.Windows.Forms; 25 | 26 | namespace CH340BConfigure 27 | { 28 | static class Program 29 | { 30 | /// 31 | /// The main entry point for the application. 32 | /// 33 | [STAThread] 34 | static void Main() 35 | { 36 | Application.EnableVisualStyles(); 37 | Application.SetCompatibleTextRenderingDefault(false); 38 | Application.Run(new UiForm()); 39 | } 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /CH340BConfigure/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.CompilerServices; 3 | using System.Runtime.InteropServices; 4 | 5 | // General Information about an assembly is controlled through the following 6 | // set of attributes. Change these attribute values to modify the information 7 | // associated with an assembly. 8 | [assembly: AssemblyTitle("CH340B Configuration Utility")] 9 | [assembly: AssemblyDescription("CH340B Configuration Utility")] 10 | [assembly: AssemblyConfiguration("")] 11 | [assembly: AssemblyCompany("SENTHILNATHAN THANGAVEL, INDEPENDENT DEVELOPER")] 12 | [assembly: AssemblyProduct("CH340B Configuration Utility")] 13 | [assembly: AssemblyCopyright("Copyright © 2021, SENTHILNATHAN THANGAVEL, INDEPENDENT DEVELOPER")] 14 | [assembly: AssemblyTrademark("SENTHILNATHAN THANGAVEL, INDEPENDENT DEVELOPER")] 15 | [assembly: AssemblyCulture("")] 16 | 17 | // Setting ComVisible to false makes the types in this assembly not visible 18 | // to COM components. If you need to access a type in this assembly from 19 | // COM, set the ComVisible attribute to true on that type. 20 | [assembly: ComVisible(false)] 21 | 22 | // The following GUID is for the ID of the typelib if this project is exposed to COM 23 | [assembly: Guid("4ca137ff-16e2-44ca-a27c-81672e1067b1")] 24 | 25 | // Version information for an assembly consists of the following four values: 26 | // 27 | // Major Version 28 | // Minor Version 29 | // Build Number 30 | // Revision 31 | // 32 | // You can specify all the values or you can default the Build and Revision Numbers 33 | // by using the '*' as shown below: 34 | // [assembly: AssemblyVersion("1.0.*")] 35 | [assembly: AssemblyVersion("0.1.0.0")] 36 | [assembly: AssemblyFileVersion("0.1.0.0")] 37 | -------------------------------------------------------------------------------- /CH340BConfigure/Properties/Resources.Designer.cs: -------------------------------------------------------------------------------- 1 | //------------------------------------------------------------------------------ 2 | // 3 | // This code was generated by a tool. 4 | // Runtime Version:4.0.30319.42000 5 | // 6 | // Changes to this file may cause incorrect behavior and will be lost if 7 | // the code is regenerated. 8 | // 9 | //------------------------------------------------------------------------------ 10 | 11 | 12 | namespace CH340BConfigure.Properties 13 | { 14 | /// 15 | /// A strongly-typed resource class, for looking up localized strings, etc. 16 | /// 17 | // This class was auto-generated by the StronglyTypedResourceBuilder 18 | // class via a tool like ResGen or Visual Studio. 19 | // To add or remove a member, edit your .ResX file then rerun ResGen 20 | // with the /str option, or rebuild your VS project. 21 | [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")] 22 | [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] 23 | [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] 24 | internal class Resources 25 | { 26 | 27 | private static global::System.Resources.ResourceManager resourceMan; 28 | 29 | private static global::System.Globalization.CultureInfo resourceCulture; 30 | 31 | [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] 32 | internal Resources() 33 | { 34 | } 35 | 36 | /// 37 | /// Returns the cached ResourceManager instance used by this class. 38 | /// 39 | [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] 40 | internal static global::System.Resources.ResourceManager ResourceManager 41 | { 42 | get 43 | { 44 | if ((resourceMan == null)) 45 | { 46 | global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("CH340BConfigure.Properties.Resources", typeof(Resources).Assembly); 47 | resourceMan = temp; 48 | } 49 | return resourceMan; 50 | } 51 | } 52 | 53 | /// 54 | /// Overrides the current thread's CurrentUICulture property for all 55 | /// resource lookups using this strongly typed resource class. 56 | /// 57 | [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] 58 | internal static global::System.Globalization.CultureInfo Culture 59 | { 60 | get 61 | { 62 | return resourceCulture; 63 | } 64 | set 65 | { 66 | resourceCulture = value; 67 | } 68 | } 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /CH340BConfigure/CH340BConfigure.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Debug 6 | AnyCPU 7 | {4CA137FF-16E2-44CA-A27C-81672E1067B1} 8 | WinExe 9 | CH340BConfigure 10 | CH340BConfigure 11 | v4.7.2 12 | 512 13 | true 14 | true 15 | 16 | 17 | AnyCPU 18 | true 19 | full 20 | false 21 | bin\Debug\ 22 | DEBUG;TRACE 23 | prompt 24 | 4 25 | 26 | 27 | AnyCPU 28 | pdbonly 29 | true 30 | bin\Release\ 31 | TRACE 32 | prompt 33 | 4 34 | 35 | 36 | CH340BConfigure.ico 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | Form 56 | 57 | 58 | UiForm.cs 59 | 60 | 61 | 62 | 63 | 64 | UiForm.cs 65 | 66 | 67 | ResXFileCodeGenerator 68 | Resources.Designer.cs 69 | Designer 70 | 71 | 72 | True 73 | Resources.resx 74 | 75 | 76 | SettingsSingleFileGenerator 77 | Settings.Designer.cs 78 | 79 | 80 | True 81 | Settings.settings 82 | True 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | -------------------------------------------------------------------------------- /.github/workflows/dotnet-desktop.yml: -------------------------------------------------------------------------------- 1 | # This workflow uses actions that are not certified by GitHub. 2 | # They are provided by a third-party and are governed by 3 | # separate terms of service, privacy policy, and support 4 | # documentation. 5 | 6 | # This workflow will build, test, sign and package a WPF or Windows Forms desktop application 7 | # built on .NET Core. 8 | # To learn how to migrate your existing application to .NET Core, 9 | # refer to https://docs.microsoft.com/en-us/dotnet/desktop-wpf/migration/convert-project-from-net-framework 10 | # 11 | # To configure this workflow: 12 | # 13 | # 1. Configure environment variables 14 | # GitHub sets default environment variables for every workflow run. 15 | # Replace the variables relative to your project in the "env" section below. 16 | # 17 | # 2. Signing 18 | # Generate a signing certificate in the Windows Application 19 | # Packaging Project or add an existing signing certificate to the project. 20 | # Next, use PowerShell to encode the .pfx file using Base64 encoding 21 | # by running the following Powershell script to generate the output string: 22 | # 23 | # $pfx_cert = Get-Content '.\SigningCertificate.pfx' -Encoding Byte 24 | # [System.Convert]::ToBase64String($pfx_cert) | Out-File 'SigningCertificate_Encoded.txt' 25 | # 26 | # Open the output file, SigningCertificate_Encoded.txt, and copy the 27 | # string inside. Then, add the string to the repo as a GitHub secret 28 | # and name it "Base64_Encoded_Pfx." 29 | # For more information on how to configure your signing certificate for 30 | # this workflow, refer to https://github.com/microsoft/github-actions-for-desktop-apps#signing 31 | # 32 | # Finally, add the signing certificate password to the repo as a secret and name it "Pfx_Key". 33 | # See "Build the Windows Application Packaging project" below to see how the secret is used. 34 | # 35 | # For more information on GitHub Actions, refer to https://github.com/features/actions 36 | # For a complete CI/CD sample to get started with GitHub Action workflows for Desktop Applications, 37 | # refer to https://github.com/microsoft/github-actions-for-desktop-apps 38 | 39 | name: .NET Core Desktop 40 | 41 | on: 42 | push: 43 | branches: [ "main" ] 44 | pull_request: 45 | branches: [ "main" ] 46 | 47 | jobs: 48 | 49 | build: 50 | 51 | strategy: 52 | matrix: 53 | configuration: [Debug, Release] 54 | 55 | runs-on: windows-latest # For a list of available runner types, refer to 56 | # https://help.github.com/en/actions/reference/workflow-syntax-for-github-actions#jobsjob_idruns-on 57 | 58 | env: 59 | Solution_Name: your-solution-name # Replace with your solution name, i.e. MyWpfApp.sln. 60 | Test_Project_Path: your-test-project-path # Replace with the path to your test project, i.e. MyWpfApp.Tests\MyWpfApp.Tests.csproj. 61 | Wap_Project_Directory: your-wap-project-directory-name # Replace with the Wap project directory relative to the solution, i.e. MyWpfApp.Package. 62 | Wap_Project_Path: your-wap-project-path # Replace with the path to your Wap project, i.e. MyWpf.App.Package\MyWpfApp.Package.wapproj. 63 | 64 | steps: 65 | - name: Checkout 66 | uses: actions/checkout@v3 67 | with: 68 | fetch-depth: 0 69 | 70 | # Install the .NET Core workload 71 | - name: Install .NET Core 72 | uses: actions/setup-dotnet@v3 73 | with: 74 | dotnet-version: 6.0.x 75 | 76 | # Add MSBuild to the PATH: https://github.com/microsoft/setup-msbuild 77 | - name: Setup MSBuild.exe 78 | uses: microsoft/setup-msbuild@v1.0.2 79 | 80 | # Execute all unit tests in the solution 81 | - name: Execute unit tests 82 | run: dotnet test 83 | 84 | # Restore the application to populate the obj folder with RuntimeIdentifiers 85 | - name: Restore the application 86 | run: msbuild $env:Solution_Name /t:Restore /p:Configuration=$env:Configuration 87 | env: 88 | Configuration: ${{ matrix.configuration }} 89 | 90 | # Decode the base 64 encoded pfx and save the Signing_Certificate 91 | - name: Decode the pfx 92 | run: | 93 | $pfx_cert_byte = [System.Convert]::FromBase64String("${{ secrets.Base64_Encoded_Pfx }}") 94 | $certificatePath = Join-Path -Path $env:Wap_Project_Directory -ChildPath GitHubActionsWorkflow.pfx 95 | [IO.File]::WriteAllBytes("$certificatePath", $pfx_cert_byte) 96 | 97 | # Create the app package by building and packaging the Windows Application Packaging project 98 | - name: Create the app package 99 | run: msbuild $env:Wap_Project_Path /p:Configuration=$env:Configuration /p:UapAppxPackageBuildMode=$env:Appx_Package_Build_Mode /p:AppxBundle=$env:Appx_Bundle /p:PackageCertificateKeyFile=GitHubActionsWorkflow.pfx /p:PackageCertificatePassword=${{ secrets.Pfx_Key }} 100 | env: 101 | Appx_Bundle: Always 102 | Appx_Bundle_Platforms: x86|x64 103 | Appx_Package_Build_Mode: StoreUpload 104 | Configuration: ${{ matrix.configuration }} 105 | 106 | # Remove the pfx 107 | - name: Remove the pfx 108 | run: Remove-Item -path $env:Wap_Project_Directory\GitHubActionsWorkflow.pfx 109 | 110 | # Upload the MSIX package: https://github.com/marketplace/actions/upload-a-build-artifact 111 | - name: Upload build artifacts 112 | uses: actions/upload-artifact@v3 113 | with: 114 | name: MSIX Package 115 | path: ${{ env.Wap_Project_Directory }}\AppPackages 116 | -------------------------------------------------------------------------------- /CH340BConfigure/Properties/Resources.resx: -------------------------------------------------------------------------------- 1 | 2 | 3 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | text/microsoft-resx 107 | 108 | 109 | 2.0 110 | 111 | 112 | System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 113 | 114 | 115 | System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 116 | 117 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | ## Ignore Visual Studio temporary files, build results, and 2 | ## files generated by popular Visual Studio add-ons. 3 | ## 4 | ## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore 5 | 6 | # User-specific files 7 | *.rsuser 8 | *.suo 9 | *.user 10 | *.userosscache 11 | *.sln.docstates 12 | 13 | # User-specific files (MonoDevelop/Xamarin Studio) 14 | *.userprefs 15 | 16 | # Mono auto generated files 17 | mono_crash.* 18 | 19 | # Build results 20 | [Dd]ebug/ 21 | [Dd]ebugPublic/ 22 | [Rr]elease/ 23 | [Rr]eleases/ 24 | x64/ 25 | x86/ 26 | [Aa][Rr][Mm]/ 27 | [Aa][Rr][Mm]64/ 28 | bld/ 29 | [Bb]in/ 30 | [Oo]bj/ 31 | [Ll]og/ 32 | [Ll]ogs/ 33 | 34 | # Visual Studio 2015/2017 cache/options directory 35 | .vs/ 36 | # Uncomment if you have tasks that create the project's static files in wwwroot 37 | #wwwroot/ 38 | 39 | # Visual Studio 2017 auto generated files 40 | Generated\ Files/ 41 | 42 | # MSTest test Results 43 | [Tt]est[Rr]esult*/ 44 | [Bb]uild[Ll]og.* 45 | 46 | # NUnit 47 | *.VisualState.xml 48 | TestResult.xml 49 | nunit-*.xml 50 | 51 | # Build Results of an ATL Project 52 | [Dd]ebugPS/ 53 | [Rr]eleasePS/ 54 | dlldata.c 55 | 56 | # Benchmark Results 57 | BenchmarkDotNet.Artifacts/ 58 | 59 | # .NET Core 60 | project.lock.json 61 | project.fragment.lock.json 62 | artifacts/ 63 | 64 | # StyleCop 65 | StyleCopReport.xml 66 | 67 | # Files built by Visual Studio 68 | *_i.c 69 | *_p.c 70 | *_h.h 71 | *.ilk 72 | *.meta 73 | *.obj 74 | *.iobj 75 | *.pch 76 | *.pdb 77 | *.ipdb 78 | *.pgc 79 | *.pgd 80 | *.rsp 81 | *.sbr 82 | *.tlb 83 | *.tli 84 | *.tlh 85 | *.tmp 86 | *.tmp_proj 87 | *_wpftmp.csproj 88 | *.log 89 | *.vspscc 90 | *.vssscc 91 | .builds 92 | *.pidb 93 | *.svclog 94 | *.scc 95 | 96 | # Chutzpah Test files 97 | _Chutzpah* 98 | 99 | # Visual C++ cache files 100 | ipch/ 101 | *.aps 102 | *.ncb 103 | *.opendb 104 | *.opensdf 105 | *.sdf 106 | *.cachefile 107 | *.VC.db 108 | *.VC.VC.opendb 109 | 110 | # Visual Studio profiler 111 | *.psess 112 | *.vsp 113 | *.vspx 114 | *.sap 115 | 116 | # Visual Studio Trace Files 117 | *.e2e 118 | 119 | # TFS 2012 Local Workspace 120 | $tf/ 121 | 122 | # Guidance Automation Toolkit 123 | *.gpState 124 | 125 | # ReSharper is a .NET coding add-in 126 | _ReSharper*/ 127 | *.[Rr]e[Ss]harper 128 | *.DotSettings.user 129 | 130 | # TeamCity is a build add-in 131 | _TeamCity* 132 | 133 | # DotCover is a Code Coverage Tool 134 | *.dotCover 135 | 136 | # AxoCover is a Code Coverage Tool 137 | .axoCover/* 138 | !.axoCover/settings.json 139 | 140 | # Visual Studio code coverage results 141 | *.coverage 142 | *.coveragexml 143 | 144 | # NCrunch 145 | _NCrunch_* 146 | .*crunch*.local.xml 147 | nCrunchTemp_* 148 | 149 | # MightyMoose 150 | *.mm.* 151 | AutoTest.Net/ 152 | 153 | # Web workbench (sass) 154 | .sass-cache/ 155 | 156 | # Installshield output folder 157 | [Ee]xpress/ 158 | 159 | # DocProject is a documentation generator add-in 160 | DocProject/buildhelp/ 161 | DocProject/Help/*.HxT 162 | DocProject/Help/*.HxC 163 | DocProject/Help/*.hhc 164 | DocProject/Help/*.hhk 165 | DocProject/Help/*.hhp 166 | DocProject/Help/Html2 167 | DocProject/Help/html 168 | 169 | # Click-Once directory 170 | publish/ 171 | 172 | # Publish Web Output 173 | *.[Pp]ublish.xml 174 | *.azurePubxml 175 | # Note: Comment the next line if you want to checkin your web deploy settings, 176 | # but database connection strings (with potential passwords) will be unencrypted 177 | *.pubxml 178 | *.publishproj 179 | 180 | # Microsoft Azure Web App publish settings. Comment the next line if you want to 181 | # checkin your Azure Web App publish settings, but sensitive information contained 182 | # in these scripts will be unencrypted 183 | PublishScripts/ 184 | 185 | # NuGet Packages 186 | *.nupkg 187 | # NuGet Symbol Packages 188 | *.snupkg 189 | # The packages folder can be ignored because of Package Restore 190 | **/[Pp]ackages/* 191 | # except build/, which is used as an MSBuild target. 192 | !**/[Pp]ackages/build/ 193 | # Uncomment if necessary however generally it will be regenerated when needed 194 | #!**/[Pp]ackages/repositories.config 195 | # NuGet v3's project.json files produces more ignorable files 196 | *.nuget.props 197 | *.nuget.targets 198 | 199 | # Microsoft Azure Build Output 200 | csx/ 201 | *.build.csdef 202 | 203 | # Microsoft Azure Emulator 204 | ecf/ 205 | rcf/ 206 | 207 | # Windows Store app package directories and files 208 | AppPackages/ 209 | BundleArtifacts/ 210 | Package.StoreAssociation.xml 211 | _pkginfo.txt 212 | *.appx 213 | *.appxbundle 214 | *.appxupload 215 | 216 | # Visual Studio cache files 217 | # files ending in .cache can be ignored 218 | *.[Cc]ache 219 | # but keep track of directories ending in .cache 220 | !?*.[Cc]ache/ 221 | 222 | # Others 223 | ClientBin/ 224 | ~$* 225 | *~ 226 | *.dbmdl 227 | *.dbproj.schemaview 228 | *.jfm 229 | *.pfx 230 | *.publishsettings 231 | orleans.codegen.cs 232 | 233 | # Including strong name files can present a security risk 234 | # (https://github.com/github/gitignore/pull/2483#issue-259490424) 235 | #*.snk 236 | 237 | # Since there are multiple workflows, uncomment next line to ignore bower_components 238 | # (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) 239 | #bower_components/ 240 | 241 | # RIA/Silverlight projects 242 | Generated_Code/ 243 | 244 | # Backup & report files from converting an old project file 245 | # to a newer Visual Studio version. Backup files are not needed, 246 | # because we have git ;-) 247 | _UpgradeReport_Files/ 248 | Backup*/ 249 | UpgradeLog*.XML 250 | UpgradeLog*.htm 251 | ServiceFabricBackup/ 252 | *.rptproj.bak 253 | 254 | # SQL Server files 255 | *.mdf 256 | *.ldf 257 | *.ndf 258 | 259 | # Business Intelligence projects 260 | *.rdl.data 261 | *.bim.layout 262 | *.bim_*.settings 263 | *.rptproj.rsuser 264 | *- [Bb]ackup.rdl 265 | *- [Bb]ackup ([0-9]).rdl 266 | *- [Bb]ackup ([0-9][0-9]).rdl 267 | 268 | # Microsoft Fakes 269 | FakesAssemblies/ 270 | 271 | # GhostDoc plugin setting file 272 | *.GhostDoc.xml 273 | 274 | # Node.js Tools for Visual Studio 275 | .ntvs_analysis.dat 276 | node_modules/ 277 | 278 | # Visual Studio 6 build log 279 | *.plg 280 | 281 | # Visual Studio 6 workspace options file 282 | *.opt 283 | 284 | # Visual Studio 6 auto-generated workspace file (contains which files were open etc.) 285 | *.vbw 286 | 287 | # Visual Studio LightSwitch build output 288 | **/*.HTMLClient/GeneratedArtifacts 289 | **/*.DesktopClient/GeneratedArtifacts 290 | **/*.DesktopClient/ModelManifest.xml 291 | **/*.Server/GeneratedArtifacts 292 | **/*.Server/ModelManifest.xml 293 | _Pvt_Extensions 294 | 295 | # Paket dependency manager 296 | .paket/paket.exe 297 | paket-files/ 298 | 299 | # FAKE - F# Make 300 | .fake/ 301 | 302 | # CodeRush personal settings 303 | .cr/personal 304 | 305 | # Python Tools for Visual Studio (PTVS) 306 | __pycache__/ 307 | *.pyc 308 | 309 | # Cake - Uncomment if you are using it 310 | # tools/** 311 | # !tools/packages.config 312 | 313 | # Tabs Studio 314 | *.tss 315 | 316 | # Telerik's JustMock configuration file 317 | *.jmconfig 318 | 319 | # BizTalk build output 320 | *.btp.cs 321 | *.btm.cs 322 | *.odx.cs 323 | *.xsd.cs 324 | 325 | # OpenCover UI analysis results 326 | OpenCover/ 327 | 328 | # Azure Stream Analytics local run output 329 | ASALocalRun/ 330 | 331 | # MSBuild Binary and Structured Log 332 | *.binlog 333 | 334 | # NVidia Nsight GPU debugger configuration file 335 | *.nvuser 336 | 337 | # MFractors (Xamarin productivity tool) working folder 338 | .mfractor/ 339 | 340 | # Local History for Visual Studio 341 | .localhistory/ 342 | 343 | # BeatPulse healthcheck temp database 344 | healthchecksdb 345 | 346 | # Backup folder for Package Reference Convert tool in Visual Studio 2017 347 | MigrationBackup/ 348 | 349 | # Ionide (cross platform F# VS Code tools) working folder 350 | .ionide/ 351 | -------------------------------------------------------------------------------- /CH340BConfigure/UiForm.Designer.cs: -------------------------------------------------------------------------------- 1 | 2 | namespace CH340BConfigure 3 | { 4 | partial class UiForm 5 | { 6 | /// 7 | /// Required designer variable. 8 | /// 9 | private System.ComponentModel.IContainer components = null; 10 | 11 | /// 12 | /// Clean up any resources being used. 13 | /// 14 | /// true if managed resources should be disposed; otherwise, false. 15 | protected override void Dispose(bool disposing) 16 | { 17 | if (disposing && (components != null)) 18 | { 19 | components.Dispose(); 20 | } 21 | base.Dispose(disposing); 22 | } 23 | 24 | #region Windows Form Designer generated code 25 | 26 | /// 27 | /// Required method for Designer support - do not modify 28 | /// the contents of this method with the code editor. 29 | /// 30 | private void InitializeComponent() 31 | { 32 | System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(UiForm)); 33 | this.groupBox2 = new System.Windows.Forms.GroupBox(); 34 | this.buttonUpdateDevList = new System.Windows.Forms.Button(); 35 | this.comboBoxDeviceList = new System.Windows.Forms.ComboBox(); 36 | this.groupBoxConfigControls = new System.Windows.Forms.GroupBox(); 37 | this.labelStatus = new System.Windows.Forms.Label(); 38 | this.buttonWrite = new System.Windows.Forms.Button(); 39 | this.buttonRead = new System.Windows.Forms.Button(); 40 | this.textBoxSerialNumber = new System.Windows.Forms.TextBox(); 41 | this.label3 = new System.Windows.Forms.Label(); 42 | this.textBoxProductString = new System.Windows.Forms.TextBox(); 43 | this.label4 = new System.Windows.Forms.Label(); 44 | this.textBoxPid = new System.Windows.Forms.TextBox(); 45 | this.label2 = new System.Windows.Forms.Label(); 46 | this.textBoxVid = new System.Windows.Forms.TextBox(); 47 | this.label1 = new System.Windows.Forms.Label(); 48 | this.groupBox2.SuspendLayout(); 49 | this.groupBoxConfigControls.SuspendLayout(); 50 | this.SuspendLayout(); 51 | // 52 | // groupBox2 53 | // 54 | this.groupBox2.Controls.Add(this.buttonUpdateDevList); 55 | this.groupBox2.Controls.Add(this.comboBoxDeviceList); 56 | this.groupBox2.Location = new System.Drawing.Point(12, 12); 57 | this.groupBox2.Name = "groupBox2"; 58 | this.groupBox2.Size = new System.Drawing.Size(367, 55); 59 | this.groupBox2.TabIndex = 22; 60 | this.groupBox2.TabStop = false; 61 | this.groupBox2.Text = "CH340B Devices"; 62 | // 63 | // buttonUpdateDevList 64 | // 65 | this.buttonUpdateDevList.Location = new System.Drawing.Point(270, 19); 66 | this.buttonUpdateDevList.Name = "buttonUpdateDevList"; 67 | this.buttonUpdateDevList.Size = new System.Drawing.Size(85, 23); 68 | this.buttonUpdateDevList.TabIndex = 1; 69 | this.buttonUpdateDevList.Text = "Update"; 70 | this.buttonUpdateDevList.UseVisualStyleBackColor = true; 71 | this.buttonUpdateDevList.Click += new System.EventHandler(this.buttonUpdateDevList_Click); 72 | // 73 | // comboBoxDeviceList 74 | // 75 | this.comboBoxDeviceList.AllowDrop = true; 76 | this.comboBoxDeviceList.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList; 77 | this.comboBoxDeviceList.FormattingEnabled = true; 78 | this.comboBoxDeviceList.Location = new System.Drawing.Point(12, 20); 79 | this.comboBoxDeviceList.Name = "comboBoxDeviceList"; 80 | this.comboBoxDeviceList.Size = new System.Drawing.Size(249, 21); 81 | this.comboBoxDeviceList.TabIndex = 0; 82 | this.comboBoxDeviceList.SelectedIndexChanged += new System.EventHandler(this.comboBoxDeviceList_SelectedIndexChanged); 83 | // 84 | // groupBoxConfigControls 85 | // 86 | this.groupBoxConfigControls.Controls.Add(this.labelStatus); 87 | this.groupBoxConfigControls.Controls.Add(this.buttonWrite); 88 | this.groupBoxConfigControls.Controls.Add(this.buttonRead); 89 | this.groupBoxConfigControls.Controls.Add(this.textBoxSerialNumber); 90 | this.groupBoxConfigControls.Controls.Add(this.label3); 91 | this.groupBoxConfigControls.Controls.Add(this.textBoxProductString); 92 | this.groupBoxConfigControls.Controls.Add(this.label4); 93 | this.groupBoxConfigControls.Controls.Add(this.textBoxPid); 94 | this.groupBoxConfigControls.Controls.Add(this.label2); 95 | this.groupBoxConfigControls.Controls.Add(this.textBoxVid); 96 | this.groupBoxConfigControls.Controls.Add(this.label1); 97 | this.groupBoxConfigControls.Location = new System.Drawing.Point(12, 76); 98 | this.groupBoxConfigControls.Name = "groupBoxConfigControls"; 99 | this.groupBoxConfigControls.Size = new System.Drawing.Size(367, 203); 100 | this.groupBoxConfigControls.TabIndex = 23; 101 | this.groupBoxConfigControls.TabStop = false; 102 | this.groupBoxConfigControls.Text = "Configure CH340B"; 103 | // 104 | // labelStatus 105 | // 106 | this.labelStatus.AutoSize = true; 107 | this.labelStatus.Location = new System.Drawing.Point(9, 170); 108 | this.labelStatus.Name = "labelStatus"; 109 | this.labelStatus.Size = new System.Drawing.Size(40, 13); 110 | this.labelStatus.TabIndex = 10; 111 | this.labelStatus.Text = "Status:"; 112 | // 113 | // buttonWrite 114 | // 115 | this.buttonWrite.Location = new System.Drawing.Point(270, 165); 116 | this.buttonWrite.Name = "buttonWrite"; 117 | this.buttonWrite.Size = new System.Drawing.Size(85, 23); 118 | this.buttonWrite.TabIndex = 9; 119 | this.buttonWrite.Text = "Write"; 120 | this.buttonWrite.UseVisualStyleBackColor = true; 121 | this.buttonWrite.Click += new System.EventHandler(this.buttonWrite_Click); 122 | // 123 | // buttonRead 124 | // 125 | this.buttonRead.Location = new System.Drawing.Point(176, 165); 126 | this.buttonRead.Name = "buttonRead"; 127 | this.buttonRead.Size = new System.Drawing.Size(85, 23); 128 | this.buttonRead.TabIndex = 8; 129 | this.buttonRead.Text = "Read"; 130 | this.buttonRead.UseVisualStyleBackColor = true; 131 | this.buttonRead.Click += new System.EventHandler(this.buttonRead_Click); 132 | // 133 | // textBoxSerialNumber 134 | // 135 | this.textBoxSerialNumber.Location = new System.Drawing.Point(139, 130); 136 | this.textBoxSerialNumber.MaxLength = 8; 137 | this.textBoxSerialNumber.Name = "textBoxSerialNumber"; 138 | this.textBoxSerialNumber.Size = new System.Drawing.Size(216, 20); 139 | this.textBoxSerialNumber.TabIndex = 7; 140 | // 141 | // label3 142 | // 143 | this.label3.AutoSize = true; 144 | this.label3.Location = new System.Drawing.Point(9, 133); 145 | this.label3.Name = "label3"; 146 | this.label3.Size = new System.Drawing.Size(117, 13); 147 | this.label3.TabIndex = 6; 148 | this.label3.Text = "Serial Number (8 chars)"; 149 | // 150 | // textBoxProductString 151 | // 152 | this.textBoxProductString.Location = new System.Drawing.Point(139, 95); 153 | this.textBoxProductString.MaxLength = 18; 154 | this.textBoxProductString.Name = "textBoxProductString"; 155 | this.textBoxProductString.Size = new System.Drawing.Size(216, 20); 156 | this.textBoxProductString.TabIndex = 5; 157 | // 158 | // label4 159 | // 160 | this.label4.AutoSize = true; 161 | this.label4.Location = new System.Drawing.Point(9, 98); 162 | this.label4.Name = "label4"; 163 | this.label4.Size = new System.Drawing.Size(124, 13); 164 | this.label4.TabIndex = 4; 165 | this.label4.Text = "Product String (18 chars)"; 166 | // 167 | // textBoxPid 168 | // 169 | this.textBoxPid.Location = new System.Drawing.Point(139, 60); 170 | this.textBoxPid.Name = "textBoxPid"; 171 | this.textBoxPid.Size = new System.Drawing.Size(216, 20); 172 | this.textBoxPid.TabIndex = 3; 173 | // 174 | // label2 175 | // 176 | this.label2.AutoSize = true; 177 | this.label2.Location = new System.Drawing.Point(9, 63); 178 | this.label2.Name = "label2"; 179 | this.label2.Size = new System.Drawing.Size(99, 13); 180 | this.label2.TabIndex = 2; 181 | this.label2.Text = "Product ID (PID) 0x"; 182 | // 183 | // textBoxVid 184 | // 185 | this.textBoxVid.Location = new System.Drawing.Point(139, 25); 186 | this.textBoxVid.Name = "textBoxVid"; 187 | this.textBoxVid.Size = new System.Drawing.Size(216, 20); 188 | this.textBoxVid.TabIndex = 1; 189 | // 190 | // label1 191 | // 192 | this.label1.AutoSize = true; 193 | this.label1.Location = new System.Drawing.Point(9, 28); 194 | this.label1.Name = "label1"; 195 | this.label1.Size = new System.Drawing.Size(96, 13); 196 | this.label1.TabIndex = 0; 197 | this.label1.Text = "Vendor ID (VID) 0x"; 198 | // 199 | // Form1 200 | // 201 | this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); 202 | this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; 203 | this.ClientSize = new System.Drawing.Size(392, 291); 204 | this.Controls.Add(this.groupBoxConfigControls); 205 | this.Controls.Add(this.groupBox2); 206 | this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedSingle; 207 | this.Icon = ((System.Drawing.Icon)(resources.GetObject("$this.Icon"))); 208 | this.MaximizeBox = false; 209 | this.Name = "Form1"; 210 | this.SizeGripStyle = System.Windows.Forms.SizeGripStyle.Hide; 211 | this.StartPosition = System.Windows.Forms.FormStartPosition.CenterScreen; 212 | this.Text = "CH340B Configuration Utility"; 213 | this.groupBox2.ResumeLayout(false); 214 | this.groupBoxConfigControls.ResumeLayout(false); 215 | this.groupBoxConfigControls.PerformLayout(); 216 | this.ResumeLayout(false); 217 | 218 | } 219 | 220 | #endregion 221 | 222 | private System.Windows.Forms.GroupBox groupBox2; 223 | private System.Windows.Forms.Button buttonUpdateDevList; 224 | private System.Windows.Forms.ComboBox comboBoxDeviceList; 225 | private System.Windows.Forms.GroupBox groupBoxConfigControls; 226 | private System.Windows.Forms.TextBox textBoxVid; 227 | private System.Windows.Forms.Label label1; 228 | private System.Windows.Forms.Button buttonWrite; 229 | private System.Windows.Forms.Button buttonRead; 230 | private System.Windows.Forms.TextBox textBoxSerialNumber; 231 | private System.Windows.Forms.Label label3; 232 | private System.Windows.Forms.TextBox textBoxProductString; 233 | private System.Windows.Forms.Label label4; 234 | private System.Windows.Forms.TextBox textBoxPid; 235 | private System.Windows.Forms.Label label2; 236 | private System.Windows.Forms.Label labelStatus; 237 | } 238 | } 239 | 240 | -------------------------------------------------------------------------------- /CH340BConfigure/UiForm.cs: -------------------------------------------------------------------------------- 1 | // ********************************************************************************************************* 2 | // 3 | // Project : WCH CH340B Configuration Utility 4 | // FileName : UiForm.cs 5 | // Author : SENTHILNATHAN THANGAVEL, INDEPENDENT DEVELOPER 6 | // Co-Author(s) : 7 | // Created : ‎20 December, ‎2021 8 | // 9 | // ********************************************************************************************************* 10 | // 11 | // Module Description 12 | // 13 | // This is the main user interface form which is displayed when the 14 | // executble is run. This has the ui button controls and event handlers, input / output text box controls. 15 | // This module will detect the CH340B devices connected to the PC and list the detected devices on its ui 16 | // combo box control. Based on the Read/Write function selected this module would send the Read / Write 17 | // request to the selected device in the device list. 18 | // ********************************************************************************************************* 19 | // 20 | // History 21 | // 22 | // Date Version Author Changes 23 | // 24 | // 20 December, ‎2021 1.0.0 SENTHILNATHAN THANGAVEL Initial version 25 | // 02 January, ‎2022 1.0.1 SENTHILNATHAN THANGAVEL Code restructured to provide good modularity 26 | // 27 | // ********************************************************************************************************* 28 | using System; 29 | using System.Text; 30 | using System.Windows.Forms; 31 | 32 | namespace CH340BConfigure 33 | { 34 | public partial class UiForm : Form 35 | { 36 | // Number of CH340B devices connected to the PC 37 | private int nNumberOfDevices = 0; 38 | // Device index tracking when a new device is selected in the device list combo box 39 | private int nSelectedDeviceIndex = 0; 40 | // CH340BDeviceAccess object - this will have the device information, device detection function, 41 | // configuration data read/write functions 42 | private CH340BDeviceAccess oCH340BDeviceAccess = new CH340BDeviceAccess(); 43 | 44 | public UiForm() 45 | { 46 | // IDE generated 47 | InitializeComponent(); 48 | // This closing handler does nothing now 49 | this.FormClosing += Form1_FormClosing; 50 | // Call the SearchAndListCh340BDevices - i.e look for devices and list them 51 | buttonUpdateDevList_Click(null, null); 52 | } 53 | 54 | private void Form1_FormClosing(object sender, FormClosingEventArgs e) 55 | { 56 | 57 | } 58 | 59 | /* 60 | * Function Name: buttonUpdateDevList_Click 61 | * Description: UpdateDevList button click event handler 62 | */ 63 | private void buttonUpdateDevList_Click(object sender, EventArgs e) 64 | { 65 | // Init the ui contorls state 66 | buttonUpdateDevList.Enabled = false; 67 | groupBoxConfigControls.Enabled = false; 68 | // Look for the CH340B devices and list them on the device list combo box 69 | SearchAndListCh340BDevices(); 70 | buttonUpdateDevList.Enabled = true; 71 | if (nNumberOfDevices > 0) 72 | { 73 | groupBoxConfigControls.Enabled = true; 74 | } 75 | else 76 | { 77 | groupBoxConfigControls.Enabled = false; 78 | } 79 | labelStatus.Text = ""; 80 | } 81 | 82 | /* 83 | * Function Name: SearchAndListCh340BDevices 84 | * Description: This function detects the CH340B devices and list them on the combo boxes 85 | */ 86 | private void SearchAndListCh340BDevices() 87 | { 88 | // If there is already a list of devices, free the list of device and resources allocated 89 | comboBoxDeviceList.Items.Clear(); 90 | // Look for the CH340B devices connected to the System 91 | nNumberOfDevices = oCH340BDeviceAccess.FindDevices(); 92 | if (nNumberOfDevices > 0) 93 | { 94 | // Add the CH340B devices detected to the combobox 95 | for (int i = 0; i < nNumberOfDevices; i++) 96 | { 97 | comboBoxDeviceList.Items.Insert(i, oCH340BDeviceAccess.aoDevInfo[i].szDeviceName); 98 | } 99 | comboBoxDeviceList.SelectedIndex = 0; 100 | nSelectedDeviceIndex = 0; 101 | } 102 | } 103 | 104 | /* 105 | * Function Name: comboBoxDeviceList_SelectedIndexChanged 106 | * Description: This function is the Combobox Device List index changed handler 107 | */ 108 | private void comboBoxDeviceList_SelectedIndexChanged(object sender, EventArgs e) 109 | { 110 | // Store the selected index to the device index variable 111 | nSelectedDeviceIndex = comboBoxDeviceList.SelectedIndex; 112 | } 113 | 114 | /* 115 | * Function Name: buttonRead_Click 116 | * Description: This function is buttonRead click event handler 117 | */ 118 | private void buttonRead_Click(object sender, EventArgs e) 119 | { 120 | bool bResult = false; 121 | buttonRead.Enabled = false; 122 | textBoxVid.Text = ""; 123 | textBoxPid.Text = ""; 124 | textBoxProductString.Text = ""; 125 | textBoxSerialNumber.Text = ""; 126 | 127 | buttonRead.Enabled = false; 128 | 129 | try 130 | { 131 | labelStatus.Text = ""; 132 | CH340BConfigurationData oCH340BConfigurationData = new CH340BConfigurationData(); 133 | bResult = oCH340BDeviceAccess.ReadConfigurationData(nSelectedDeviceIndex, ref oCH340BConfigurationData); 134 | // Display the configuration data to the UI 135 | if (bResult) 136 | { 137 | textBoxVid.Text = oCH340BConfigurationData.ushVID.ToString("X4"); 138 | textBoxPid.Text = oCH340BConfigurationData.ushPID.ToString("X4"); 139 | textBoxProductString.Text = oCH340BConfigurationData.szProductString; 140 | textBoxSerialNumber.Text = oCH340BConfigurationData.szSerialNumber; 141 | // Update the Read status 142 | labelStatus.Text = "Status: Read Success"; 143 | } 144 | else 145 | { 146 | // Update the Read status 147 | labelStatus.Text = "Status: Read Failed"; 148 | } 149 | } 150 | catch (Exception ex) 151 | { 152 | MessageBox.Show("Exception occurred: " + ex.Message, "CH340B Configuration Utlity", MessageBoxButtons.OK, 153 | MessageBoxIcon.Exclamation, MessageBoxDefaultButton.Button1); 154 | } 155 | 156 | buttonRead.Enabled = true; 157 | } 158 | 159 | /* 160 | * Function Name: buttonWrite_Click 161 | * Description: This function is buttonWrite click event handler 162 | */ 163 | private void buttonWrite_Click(object sender, EventArgs e) 164 | { 165 | ushort ushVID = 0x0000; 166 | ushort ushPID = 0x0000; 167 | string szProductString = ""; 168 | string szSerialNumber = ""; 169 | bool bResult = false; 170 | labelStatus.Text = ""; 171 | buttonWrite.Enabled = false; 172 | 173 | do 174 | { 175 | // Validate VID 176 | try 177 | { 178 | string szVID = textBoxVid.Text; 179 | ushVID = Convert.ToUInt16(szVID, 16); 180 | } 181 | catch (Exception) 182 | { 183 | MessageBox.Show("Enter valid value for Vendor ID in hex.", "CH340B Configuration Utlity", MessageBoxButtons.OK, 184 | MessageBoxIcon.Exclamation, MessageBoxDefaultButton.Button1); 185 | break; 186 | } 187 | 188 | // Validate PID 189 | try 190 | { 191 | string szPID = textBoxPid.Text; 192 | ushPID = Convert.ToUInt16(szPID, 16); 193 | } 194 | catch (Exception) 195 | { 196 | MessageBox.Show("Enter valid value for Product ID in hex.", "CH340B Configuration Utlity", MessageBoxButtons.OK, 197 | MessageBoxIcon.Exclamation, MessageBoxDefaultButton.Button1); 198 | break; 199 | } 200 | 201 | // Validate Product string 202 | try 203 | { 204 | szProductString = textBoxProductString.Text; 205 | if (string.IsNullOrEmpty(szProductString)) 206 | { 207 | MessageBox.Show("Enter valid string value for Product String.", "CH340B Configuration Utlity", MessageBoxButtons.OK, 208 | MessageBoxIcon.Exclamation, MessageBoxDefaultButton.Button1); 209 | break; 210 | } 211 | } 212 | catch (Exception) 213 | { 214 | MessageBox.Show("Enter valid string value for Product String.", "CH340B Configuration Utlity", MessageBoxButtons.OK, 215 | MessageBoxIcon.Exclamation, MessageBoxDefaultButton.Button1); 216 | break; 217 | } 218 | 219 | // Validate Serial Number 220 | try 221 | { 222 | szSerialNumber = textBoxSerialNumber.Text; 223 | if (string.IsNullOrEmpty(szSerialNumber) == false) 224 | { 225 | byte[] abySerialNumber = Encoding.ASCII.GetBytes(szSerialNumber); 226 | 227 | for (int i = 0; i < abySerialNumber.Length; i++) 228 | { 229 | if ((abySerialNumber[i] >= 0x30 && abySerialNumber[i] <= 0x39) || (abySerialNumber[i] >= 0x41 && abySerialNumber[i] <= 0x5A) || 230 | (abySerialNumber[i] >= 0x61 && abySerialNumber[i] <= 0x7A)) 231 | { 232 | // Valid serial number string 233 | } 234 | else 235 | { 236 | MessageBox.Show("Enter valid string value for Serial Number.", "CH340B Configuration Utlity", MessageBoxButtons.OK, 237 | MessageBoxIcon.Exclamation, MessageBoxDefaultButton.Button1); 238 | break; 239 | } 240 | } 241 | } 242 | } 243 | catch (Exception) 244 | { 245 | MessageBox.Show("Enter valid string value for Product String.", "CH340B Configuration Utlity", MessageBoxButtons.OK, 246 | MessageBoxIcon.Exclamation, MessageBoxDefaultButton.Button1); 247 | break; 248 | } 249 | 250 | // Write the configuration data to CH340B 251 | CH340BConfigurationData oCH340BConfigurationData = new CH340BConfigurationData(); 252 | oCH340BConfigurationData.ushVID = ushVID; 253 | oCH340BConfigurationData.ushPID = ushPID; 254 | oCH340BConfigurationData.szProductString = szProductString; 255 | oCH340BConfigurationData.szSerialNumber = szSerialNumber; 256 | bResult = oCH340BDeviceAccess.WriteConfigurationData(nSelectedDeviceIndex, oCH340BConfigurationData); 257 | 258 | // Update the Write status 259 | if (bResult) 260 | { 261 | labelStatus.Text = "Status: Write Success"; 262 | } 263 | else 264 | { 265 | labelStatus.Text = "Status: Write Failed"; 266 | } 267 | } while (false); 268 | 269 | buttonWrite.Enabled = true; 270 | } 271 | } 272 | } 273 | -------------------------------------------------------------------------------- /CH340BConfigure/NativeAccess.cs: -------------------------------------------------------------------------------- 1 | // ********************************************************************************************************* 2 | // 3 | // Project : WCH CH340B Configuration Utility 4 | // FileName : NativeAccess.cs 5 | // Author : SENTHILNATHAN THANGAVEL, INDEPENDENT DEVELOPER 6 | // Co-Author(s) : 7 | // Created : ‎02 January, ‎2022 8 | // 9 | // ********************************************************************************************************* 10 | // 11 | // Module Description 12 | // 13 | // This module has classes that contain managed version of Win32 native structs, constants, native methods 14 | // Here C# .Net Framework's Platform Invoke (P/Invoke) interoperability service is used to call the 15 | // native unmanaged Win32 APIs. 16 | // ********************************************************************************************************* 17 | // 18 | // History 19 | // 20 | // Date Version Author Changes 21 | // 22 | // ‎02 January, ‎2022 1.0.0 SENTHILNATHAN THANGAVEL Initial version 23 | // 24 | // ********************************************************************************************************* 25 | using System; 26 | using System.Runtime.InteropServices; 27 | 28 | namespace CH340BConfigure 29 | { 30 | public class NativeAccess 31 | { 32 | internal class NativeStructs 33 | { 34 | [StructLayout(LayoutKind.Sequential)] 35 | internal class SP_DEVINFO_DATA 36 | { 37 | public Int32 cbSize; 38 | public Guid ClassGuid; 39 | public Int32 DevInst; 40 | public IntPtr Reserved; 41 | } 42 | 43 | [StructLayout(LayoutKind.Sequential)] 44 | internal class SP_DEVICE_INTERFACE_DETAIL_DATA 45 | { 46 | public Int32 cbSize; 47 | 48 | [MarshalAs(UnmanagedType.ByValArray, SizeConst = 260)] 49 | public byte[] DevicePath; 50 | } 51 | 52 | [StructLayout(LayoutKind.Sequential)] 53 | internal class SP_DEVICE_INTERFACE_DATA 54 | { 55 | public Int32 cbSize; 56 | public System.Guid InterfaceClassGuid; 57 | public Int32 Flags; 58 | public UIntPtr Reserved; 59 | } 60 | 61 | [StructLayout(LayoutKind.Sequential, Pack = 8)] 62 | internal class OVERLAPPED 63 | { 64 | public IntPtr InternalLow; 65 | public IntPtr InternalHigh; 66 | public long Offset; 67 | public IntPtr hEvent; 68 | } 69 | 70 | [StructLayout(LayoutKind.Sequential, Pack = 8)] 71 | internal class SERIAL_COMMPROP 72 | { 73 | public UInt16 PacketLength; 74 | public UInt16 PacketVersion; 75 | public UInt32 ServiceMask; 76 | public UInt32 Reserved1; 77 | public UInt32 MaxTxQueue; 78 | public UInt32 MaxRxQueue; 79 | public UInt32 MaxBaud; 80 | public UInt32 ProvSubType; 81 | public UInt32 ProvCapabilities; 82 | public UInt32 SettableParams; 83 | public UInt32 SettableBaud; 84 | public UInt16 SettableData; 85 | public UInt16 SettableStopParity; 86 | public UInt32 CurrentTxQueue; 87 | public UInt32 CurrentRxQueue; 88 | public UInt32 ProvSpec1; 89 | public UInt32 ProvSpec2; 90 | public IntPtr ProvChar; 91 | } 92 | 93 | [StructLayout(LayoutKind.Sequential, Pack = 8)] 94 | internal class SERIAL_QUEUE_SIZE 95 | { 96 | public UInt32 InSize; 97 | public UInt32 OutSize; 98 | } 99 | 100 | [StructLayout(LayoutKind.Sequential, Pack = 8)] 101 | internal class SERIAL_TIMEOUTS 102 | { 103 | public UInt32 ReadIntervalTimeout; 104 | public UInt32 ReadTotalTimeoutMultiplier; 105 | public UInt32 ReadTotalTimeoutConstant; 106 | public UInt32 WriteTotalTimeoutMultiplier; 107 | public UInt32 WriteTotalTimeoutConstant; 108 | } 109 | 110 | [StructLayout(LayoutKind.Sequential, Pack = 8)] 111 | internal class SERIAL_BAUD_RATE 112 | { 113 | public UInt32 BaudRate; 114 | } 115 | 116 | [StructLayout(LayoutKind.Sequential, Pack = 8)] 117 | internal class SERIAL_LINE_CONTROL 118 | { 119 | public Byte StopBits; 120 | public Byte Parity; 121 | public Byte WordLength; 122 | } 123 | 124 | [StructLayout(LayoutKind.Sequential, Pack = 8)] 125 | internal class SERIAL_CHARS 126 | { 127 | public Byte EofChar; 128 | public Byte ErrorChar; 129 | public Byte BreakChar; 130 | public Byte EventChar; 131 | public Byte XonChar; 132 | public Byte XoffChar; 133 | } 134 | 135 | [StructLayout(LayoutKind.Sequential, Pack = 8)] 136 | internal class SERIAL_HANDFLOW 137 | { 138 | public UInt32 ControlHandShake; 139 | public UInt32 FlowReplace; 140 | public Int32 XonLimit; 141 | public Int32 XoffLimit; 142 | } 143 | } 144 | 145 | internal class Constants 146 | { 147 | // Define constants 148 | // internal const uint INVALID_HANDLE_VALUE = 0xFFFFFFFF; 149 | internal static readonly IntPtr INVALID_HANDLE_VALUE = new IntPtr(-1); 150 | 151 | internal const uint ERROR_INVALID_HANDLE = 0x00000006; 152 | internal const uint ERROR_INSUFFICIENT_BUFFER = 122; 153 | 154 | internal const uint GENERIC_READ = 0x80000000; 155 | internal const uint GENERIC_WRITE = 0x40000000; 156 | internal const uint FILE_SHARE_READ = 0x00000001; 157 | internal const uint FILE_SHARE_WRITE = 0x00000002; 158 | 159 | internal const uint FILE_FLAG_OVERLAPPED = 0x40000000; 160 | internal const uint OPEN_EXISTING = 0x00000003; 161 | 162 | internal const uint NO_ERROR = 0x00000000; 163 | internal const uint STATUS_SUCCESS = 0x00000000; 164 | 165 | internal const uint DIGCF_DEFAULT = 0x00000001; 166 | internal const uint DIGCF_PRESENT = 0x00000002; 167 | internal const uint DIGCF_ALLCLASSES = 0x00000004; 168 | internal const uint DIGCF_PROFILE = 0x00000008; 169 | internal const uint DIGCF_DEVICEINTERFACE = 0x00000010; 170 | 171 | internal const UInt32 ERROR_IO_PENDING = 997; 172 | internal const UInt32 INFINITE = 0xFFFFFFFF; 173 | internal const UInt32 WAIT_ABANDONED = 0x00000080; 174 | internal const UInt32 WAIT_OBJECT_0 = 0x00000000; 175 | internal const UInt32 WAIT_TIMEOUT = 0x00000102; 176 | 177 | internal const UInt32 IOCTL_SERIAL_GET_PROPERTIES = 0x1b0074; 178 | internal const UInt32 IOCTL_SERIAL_SET_QUEUE_SIZE = 0x1b0008; 179 | internal const UInt32 IOCTL_SERIAL_GET_TIMEOUTS = 0x1b0020; 180 | internal const UInt32 IOCTL_SERIAL_SET_TIMEOUTS = 0x1b001c; 181 | internal const UInt32 IOCTL_SERIAL_PURGE = 0x1b004c; 182 | internal const UInt32 IOCTL_SERIAL_GET_BAUD_RATE = 0x1b0050; 183 | internal const UInt32 IOCTL_SERIAL_GET_LINE_CONTROL = 0x1b0054; 184 | internal const UInt32 IOCTL_SERIAL_GET_CHARS = 0x1b0058; 185 | internal const UInt32 IOCTL_SERIAL_GET_HANDFLOW = 0x1b0060; 186 | internal const UInt32 IOCTL_SERIAL_SET_BAUD_RATE = 0x1b0004; 187 | internal const UInt32 IOCTL_SERIAL_SET_RTS = 0x1b0030; 188 | internal const UInt32 IOCTL_SERIAL_SET_DTR = 0x1b0024; 189 | internal const UInt32 IOCTL_SERIAL_SET_LINE_CONTROL = 0x1b000c; 190 | internal const UInt32 IOCTL_SERIAL_SET_CHARS = 0x1b005c; 191 | internal const UInt32 IOCTL_SERIAL_SET_HANDFLOW = 0x1b0064; 192 | 193 | internal enum SPDRP 194 | { 195 | SPDRP_DEVICEDESC = 0, 196 | SPDRP_HARDWAREID = 0x1, 197 | SPDRP_COMPATIBLEIDS = 0x2, 198 | SPDRP_UNUSED0 = 0x3, 199 | SPDRP_SERVICE = 0x4, 200 | SPDRP_UNUSED1 = 0x5, 201 | SPDRP_UNUSED2 = 0x6, 202 | SPDRP_CLASS = 0x7, 203 | SPDRP_CLASSGUID = 0x8, 204 | SPDRP_DRIVER = 0x9, 205 | SPDRP_CONFIGFLAGS = 0xa, 206 | SPDRP_MFG = 0xb, 207 | SPDRP_FRIENDLYNAME = 0xc, 208 | SPDRP_LOCATION_INFORMATION = 0xd, 209 | SPDRP_PHYSICAL_DEVICE_OBJECT_NAME = 0xe, 210 | SPDRP_CAPABILITIES = 0xf, 211 | SPDRP_UI_NUMBER = 0x10, 212 | SPDRP_UPPERFILTERS = 0x11, 213 | SPDRP_LOWERFILTERS = 0x12, 214 | SPDRP_BUSTYPEGUID = 0x13, 215 | SPDRP_LEGACYBUSTYPE = 0x14, 216 | SPDRP_BUSNUMBER = 0x15, 217 | SPDRP_ENUMERATOR_NAME = 0x16, 218 | SPDRP_SECURITY = 0x17, 219 | SPDRP_SECURITY_SDS = 0x18, 220 | SPDRP_DEVTYPE = 0x19, 221 | SPDRP_EXCLUSIVE = 0x1a, 222 | SPDRP_CHARACTERISTICS = 0x1b, 223 | SPDRP_ADDRESS = 0x1c, 224 | SPDRP_UI_NUMBER_DESC_FORMAT = 0x1e, 225 | SPDRP_MAXIMUM_PROPERTY = 0x1f 226 | 227 | } 228 | } 229 | 230 | internal class NativeMethods 231 | { 232 | [DllImport("hid.dll", CharSet = CharSet.Unicode, SetLastError = true)] 233 | internal static extern void HidD_GetHidGuid(ref System.Guid HidGuid); 234 | 235 | [DllImport("hid.dll", CharSet = CharSet.Unicode, SetLastError = true)] 236 | internal static extern Boolean HidD_SetOutputReport(IntPtr HidDeviceObject, Byte[] lpReportBuffer, 237 | Int32 ReportBufferLength); 238 | 239 | [DllImport("hid.dll", CharSet = CharSet.Unicode, SetLastError = true)] 240 | internal static extern Boolean HidD_SetFeature(IntPtr HidDeviceObject, Byte[] lpReportBuffer, 241 | Int32 ReportBufferLength); 242 | 243 | [DllImport("hid.dll", CharSet = CharSet.Unicode, SetLastError = true)] 244 | internal static extern Boolean HidD_GetFeature(IntPtr HidDeviceObject, [Out] byte[] lpBuffer, Int32 ReportBufferLength); 245 | 246 | [DllImport("setupapi.dll", CharSet = CharSet.Unicode, SetLastError = true)] 247 | internal static extern IntPtr SetupDiGetClassDevs(ref System.Guid ClassGuid, 248 | IntPtr Enumerator, IntPtr hwndParent, UInt32 Flags); 249 | 250 | [DllImport("setupapi.dll", CharSet = CharSet.Unicode, SetLastError = true)] 251 | public static extern bool SetupDiDestroyDeviceInfoList(IntPtr DeviceInfoSet); 252 | 253 | [DllImport("setupapi.dll", SetLastError = true, CharSet = CharSet.Unicode)] 254 | internal static extern Boolean SetupDiEnumDeviceInfo(IntPtr hDevInfo, 255 | uint uintDeviceID, IntPtr psDeviceInfoData); 256 | 257 | [DllImport("setupapi.dll", SetLastError = true, CharSet = CharSet.Unicode)] 258 | internal static extern Boolean SetupDiGetDeviceRegistryProperty(IntPtr DeviceInfoSet, 259 | IntPtr psDeviceInfoData, uint Property, ref uint PropertyRegDataType, IntPtr pchBuffer, 260 | uint uintBufferSize, ref uint untBufferSize); 261 | 262 | [DllImport("setupapi.dll", SetLastError = true, CharSet = CharSet.Unicode)] 263 | internal static extern Boolean SetupDiEnumDeviceInterfaces(IntPtr DeviceInfoSet, 264 | IntPtr DeviceInfoData, ref System.Guid InterfaceClassGuid, 265 | uint MemberIndex, IntPtr psDeviceInterfaceData); 266 | 267 | [DllImport("setupapi.dll", SetLastError = true, CharSet = CharSet.Unicode)] 268 | internal static extern Boolean SetupDiGetDeviceInterfaceDetail(IntPtr hDevInfo, 269 | IntPtr pspDeviceInterfaceData, 270 | IntPtr DeviceInterfaceDetailData, Int32 DeviceInterfaceDetailDataSize, ref Int32 RequiredSize, 271 | IntPtr DeviceInfoData); 272 | 273 | [DllImport("kernel32.dll", SetLastError = true, CharSet = CharSet.Unicode)] 274 | internal static extern uint GetLastError(); 275 | 276 | [DllImport("kernel32.dll", CharSet = CharSet.Unicode, SetLastError = true)] 277 | internal static extern IntPtr CreateFile(String lpFileName, UInt32 dwDesiredAccess, 278 | UInt32 dwShareMode, IntPtr lpSecurityAttributes, UInt32 dwCreationDisposition, 279 | UInt32 dwFlagsAndAttributes, IntPtr hTemplateFile); 280 | 281 | [DllImport("kernel32.dll", CharSet = CharSet.Unicode, SetLastError = true)] 282 | internal static extern Boolean CloseHandle(IntPtr pHandle); 283 | 284 | [DllImport("kernel32.dll", CharSet = CharSet.Unicode, SetLastError = true)] 285 | internal static extern Boolean WriteFile(IntPtr pHandle, Byte[] lpReportBuffer, 286 | uint unReportBufferSize, ref UInt32 lpBytesReturned, IntPtr lpOverlapped); 287 | 288 | [DllImport("kernel32.dll", SetLastError = true)] 289 | internal static extern bool ReadFile(IntPtr hFile, [Out] byte[] lpBuffer, uint nNumberOfBytesToRead, ref uint lpNumberOfBytesRead, IntPtr lpOverlapped); 290 | 291 | [DllImport("hid.dll", SetLastError = true)] 292 | internal static extern Boolean HidD_GetInputReport(IntPtr hFileHandle, byte[] reportBuffer, uint reportBufferLength); 293 | 294 | [DllImport("kernel32.dll")] 295 | internal static extern IntPtr CreateEvent(IntPtr lpEventAttributes, bool bManualReset, bool bInitialState, string lpName); 296 | 297 | [DllImport("kernel32.dll", SetLastError = true)] 298 | internal static extern UInt32 WaitForSingleObject(IntPtr hHandle, UInt32 dwMilliseconds); 299 | 300 | [DllImport("kernel32.dll")] 301 | internal static extern bool ResetEvent(IntPtr hEvent); 302 | 303 | [DllImport("kernel32.dll")] 304 | [return: MarshalAs(UnmanagedType.Bool)] 305 | internal static extern bool CancelIo(IntPtr hFile); 306 | 307 | [DllImport("kernel32.dll")] 308 | internal static extern bool SetEvent(IntPtr hEvent); 309 | 310 | 311 | [DllImport("Kernel32.dll", SetLastError = true, CharSet = CharSet.Auto)] 312 | internal static extern bool DeviceIoControl(IntPtr hDevice, uint ioControlCode, 313 | [MarshalAs(UnmanagedType.LPArray)][In] byte[] inBuffer, int ninBufferSize, 314 | [MarshalAs(UnmanagedType.LPArray)][Out] byte[] outBuffer, int noutBufferSize, 315 | out uint bytesReturned, [In] IntPtr overlapped); 316 | 317 | [DllImport("Kernel32.dll", SetLastError = true, CharSet = CharSet.Auto)] 318 | internal static extern bool DeviceIoControl(IntPtr hDevice, uint ioControlCode, IntPtr inBuffer, int ninBufferSize, 319 | IntPtr outBuffer, int noutBufferSize, out uint bytesReturned, [In] IntPtr overlapped); 320 | 321 | [DllImport("Kernel32.dll", SetLastError = true, CharSet = CharSet.Auto)] 322 | internal static extern bool DeviceIoControl(IntPtr hDevice, uint ioControlCode, byte[] inBuffer, int ninBufferSize, 323 | IntPtr outBuffer, int noutBufferSize, out uint bytesReturned, [In] IntPtr overlapped); 324 | 325 | [DllImport("Kernel32.dll", SetLastError = true, CharSet = CharSet.Auto)] 326 | internal static extern bool DeviceIoControl(IntPtr hDevice, uint ioControlCode, IntPtr inBuffer, int ninBufferSize, 327 | byte[] outBuffer, int noutBufferSize, out uint bytesReturned, [In] IntPtr overlapped); 328 | 329 | } 330 | } 331 | } 332 | -------------------------------------------------------------------------------- /CH340BConfigure/UiForm.resx: -------------------------------------------------------------------------------- 1 | 2 | 3 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | text/microsoft-resx 110 | 111 | 112 | 2.0 113 | 114 | 115 | System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 116 | 117 | 118 | System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 119 | 120 | 121 | 122 | 123 | AAABAAYAEBAQAAAAAAAoAQAAZgAAABAQAAAAAAAAaAUAAI4BAAAgIBAAAAAAAOgCAAD2BgAAICAAAAAA 124 | AACoCAAA3gkAADAwAAAAAAAAqA4AAIYSAAAwMBAAAAAAAGgGAAAuIQAAKAAAABAAAAAgAAAAAQAEAAAA 125 | AADAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgAAAgAAAAICAAAAAAIAAAICAAIAAgACAgIAAwMDAAAD/ 126 | AAD/AAAA//8AAAAA/wAA//8A/wD/AP///wAAAAAHcAAAAAeAAP+NkAAAB4B3j4mIAAAHgHiICbsAAAeA 127 | eIsAiAAAB/B7i9+IAAAH8Ie73/iIgAfwiH3YB3eAB3CId3d3d4B/94h4iIiIcAd3eHIiIi9wAAf/ciIi 128 | L3AAAHdyIiIvcAAAAHKiIi9wAAAAcqqqr3AAAAB/////cIwfAACADwAAgAcAAIAHAACABwAAgAEAAIAA 129 | AACAAAAAgAAAAAAAAACAAAAA4AAAAPAAAAD8AAAA/AAAAPwAAAAoAAAAEAAAACAAAAABAAgAAAAAAEAB 130 | AAAAAAAAAAAAAAAAAAAAAAAAAAAAAIAAAAAAgAAAgIAAAAAAgACAAIAAAICAAMDAwADA3MAApsrwAAQE 131 | BAAICAgADAwMABEREQAWFhYAHBwcACIiIgApKSkAVVVVAE1NTQBCQkIAOTk5AP98gAD/UFAA1gCTAMzs 132 | /wDv1sYA5+fWAK2pkAAzAAAAZgAAAJkAAADMAAAAADMAADMzAABmMwAAmTMAAMwzAAD/MwAAAGYAADNm 133 | AABmZgAAmWYAAMxmAAD/ZgAAAJkAADOZAABmmQAAmZkAAMyZAAD/mQAAAMwAADPMAABmzAAAmcwAAMzM 134 | AAD/zAAAZv8AAJn/AADM/wAAAAAzADMAMwBmADMAmQAzAMwAMwD/ADMAADMzADMzMwBmMzMAmTMzAMwz 135 | MwD/MzMAAGYzADNmMwBmZjMAmWYzAMxmMwD/ZjMAAJkzADOZMwBmmTMAmZkzAMyZMwD/mTMAAMwzADPM 136 | MwBmzDMAmcwzAMzMMwD/zDMAM/8zAGb/MwCZ/zMAzP8zAP//MwAAAGYAMwBmAGYAZgCZAGYAzABmAP8A 137 | ZgAAM2YAMzNmAGYzZgCZM2YAzDNmAP8zZgAAZmYAM2ZmAGZmZgCZZmYAzGZmAACZZgAzmWYAZplmAJmZ 138 | ZgDMmWYA/5lmAADMZgAzzGYAmcxmAMzMZgD/zGYAAP9mADP/ZgCZ/2YAzP9mAP8AzADMAP8AAJmZAJkz 139 | mQCZAJkAzACZAAAAmQAzM5kAZgCZAMwzmQD/AJkAAGaZADNmmQBmM5kAmWaZAMxmmQD/M5kAM5mZAGaZ 140 | mQCZmZkAzJmZAP+ZmQAAzJkAM8yZAGbMZgCZzJkAzMyZAP/MmQAA/5kAM/+ZAGbMmQCZ/5kAzP+ZAP// 141 | mQAAAMwAMwCZAGYAzACZAMwAzADMAAAzmQAzM8wAZjPMAJkzzADMM8wA/zPMAABmzAAzZswAZmaZAJlm 142 | zADMZswA/2aZAACZzAAzmcwAZpnMAJmZzADMmcwA/5nMAADMzAAzzMwAZszMAJnMzADMzMwA/8zMAAD/ 143 | zAAz/8wAZv+ZAJn/zADM/8wA///MADMAzABmAP8AmQD/AAAzzAAzM/8AZjP/AJkz/wDMM/8A/zP/AABm 144 | /wAzZv8AZmbMAJlm/wDMZv8A/2bMAACZ/wAzmf8AZpn/AJmZ/wDMmf8A/5n/AADM/wAzzP8AZsz/AJnM 145 | /wDMzP8A/8z/ADP//wBm/8wAmf//AMz//wD/ZmYAZv9mAP//ZgBmZv8A/2b/AGb//wClACEAX19fAHd3 146 | dwCGhoYAlpaWAMvLywCysrIA19fXAN3d3QDj4+MA6urqAPHx8QD4+PgA//vwAKCgpACAgIAA/wAAAAD/ 147 | AAD//wAAAAD/AP8A/wAA//8A////AAAAAAAAAAAAAAAAAAAAAAAA7AcAAOz//wf++gAAAAAAAOwHAOwH 148 | B/8H+gcHAAAAAADsBwDsBwcHAPr7+wAAAAAA7AcA7AcH+wAABwcAAAAAAOz/AOz7B/v+/wcHAAAAAADs 149 | /wAH7Pv7/v//AAcHBwAA7P8ABwcAAAAAAOzs7AcAAOzsAAcH7Ozs7Ozs7OwHAOz//+wHB+wHBwcHBwcH 150 | 7AAA7Ozs7Afsb3pSMU1M/+wAAAAA7P//7G/lelIxTf/sAAAAAADs7Oxv5eV6UjH/7AAAAAAAAADsb3rl 151 | 5XpS/+wAAAAAAAAA7G9MTExMTP/sAAAAAAAAAOzw8PDw8PDw7ACMHwAAgA8AAIAHAACABwAAgAcAAIAB 152 | AACAAAAAgAAAAIAAAAAAAAAAgAAAAOAAAADwAAAA/AAAAPwAAAD8AAAAKAAAACAAAABAAAAAAQAEAAAA 153 | AACAAgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgAAAgAAAAICAAAAAAIAAAICAAIAAgACAgIAAwMDAAAD/ 154 | AAD/AAAA//8AAAAA/wAA//8A/wD/AP///wAAAAAAAAAAB3cAAAAAAAAAAAAAAAAAB3iN3ZAAAAAAAAB4 155 | +PAAAH+PiN2ZkAAAAAAAf4+AcAeH+P3ZmYgAAAAAAHj48IcHeH+I2ZiIAAAAAAB/j4B4d4eH+NmIi7AA 156 | AAAAePjwh3h4eHAJi7uwAAAAAH+PgHh3h4cAALu4gAAAAAB4+PCHeIi7AAB4eHAAAAAAf4+AeHi7ibAH 157 | h4eAAAAAAH//8Id7uJu9/3h4cAAAAAB///B4d4m7vfj3hwAAAAAAf//wh4ebu92Pj3gIiIgAAH//8IiI 158 | e73diPjwAACIcAB///CIiAd93YiAB3d3iHAAf//wiIgP93d3f/////9wAHd3cIiIB3d3d3d3d3d4cAB3 159 | d3CIiAAAAAAAAAAAAIAH///3CIgHiIiIiIiIiIcAd3d3d3CIB/////////+HAAAAB3d3CAfyIiIiIiIv 160 | hwAAAAB3d3AH8riDMzqqL4cAAAAAB///B/L7iDMzqi+HAAAAAAB3d3Dyv7iDMzovhwAAAAAAAAAH8vv7 161 | iDMzL4cAAAAAAAAAB/K/v7iDMy+HAAAAAAAAAAfyi/v7iDMvhwAAAAAAAAAH8oi/v7iDL4cAAAAAAAAA 162 | B/KIi/v7iC+HAAAAAAAAAAfyIiIiIiIvhwAAAAAAAAAH/////////4cAAAAAAAAAAHd3d3d3d3d3AP/+ 163 | B//A+AH/wHAA/8AgAH/AAAB/wAAAP8AAAD/AAGA/wABgP8AAAD/AAAA/wAAAA8AAAAHAAAAAwAAAAMAA 164 | AADAAAAAwAAAAIAAAAEAAAAB+AAAAfwAAAH+AAAB/wAAAf/4AAH/+AAB//gAAf/4AAH/+AAB//gAAf/4 165 | AAH//AADKAAAACAAAABAAAAAAQAIAAAAAACABAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAAAAAAIAAAICA 166 | AAAAAIAAgACAAACAgADAwMAAwNzAAKbK8AAEBAQACAgIAAwMDAAREREAFhYWABwcHAAiIiIAKSkpAFVV 167 | VQBNTU0AQkJCADk5OQD/fIAA/1BQANYAkwDM7P8A79bGAOfn1gCtqZAAMwAAAGYAAACZAAAAzAAAAAAz 168 | AAAzMwAAZjMAAJkzAADMMwAA/zMAAABmAAAzZgAAZmYAAJlmAADMZgAA/2YAAACZAAAzmQAAZpkAAJmZ 169 | AADMmQAA/5kAAADMAAAzzAAAZswAAJnMAADMzAAA/8wAAGb/AACZ/wAAzP8AAAAAMwAzADMAZgAzAJkA 170 | MwDMADMA/wAzAAAzMwAzMzMAZjMzAJkzMwDMMzMA/zMzAABmMwAzZjMAZmYzAJlmMwDMZjMA/2YzAACZ 171 | MwAzmTMAZpkzAJmZMwDMmTMA/5kzAADMMwAzzDMAZswzAJnMMwDMzDMA/8wzADP/MwBm/zMAmf8zAMz/ 172 | MwD//zMAAABmADMAZgBmAGYAmQBmAMwAZgD/AGYAADNmADMzZgBmM2YAmTNmAMwzZgD/M2YAAGZmADNm 173 | ZgBmZmYAmWZmAMxmZgAAmWYAM5lmAGaZZgCZmWYAzJlmAP+ZZgAAzGYAM8xmAJnMZgDMzGYA/8xmAAD/ 174 | ZgAz/2YAmf9mAMz/ZgD/AMwAzAD/AACZmQCZM5kAmQCZAMwAmQAAAJkAMzOZAGYAmQDMM5kA/wCZAABm 175 | mQAzZpkAZjOZAJlmmQDMZpkA/zOZADOZmQBmmZkAmZmZAMyZmQD/mZkAAMyZADPMmQBmzGYAmcyZAMzM 176 | mQD/zJkAAP+ZADP/mQBmzJkAmf+ZAMz/mQD//5kAAADMADMAmQBmAMwAmQDMAMwAzAAAM5kAMzPMAGYz 177 | zACZM8wAzDPMAP8zzAAAZswAM2bMAGZmmQCZZswAzGbMAP9mmQAAmcwAM5nMAGaZzACZmcwAzJnMAP+Z 178 | zAAAzMwAM8zMAGbMzACZzMwAzMzMAP/MzAAA/8wAM//MAGb/mQCZ/8wAzP/MAP//zAAzAMwAZgD/AJkA 179 | /wAAM8wAMzP/AGYz/wCZM/8AzDP/AP8z/wAAZv8AM2b/AGZmzACZZv8AzGb/AP9mzAAAmf8AM5n/AGaZ 180 | /wCZmf8AzJn/AP+Z/wAAzP8AM8z/AGbM/wCZzP8AzMz/AP/M/wAz//8AZv/MAJn//wDM//8A/2ZmAGb/ 181 | ZgD//2YAZmb/AP9m/wBm//8ApQAhAF9fXwB3d3cAhoaGAJaWlgDLy8sAsrKyANfX1wDd3d0A4+PjAOrq 182 | 6gDx8fEA+Pj4AP/78ACgoKQAgICAAP8AAAAA/wAA//8AAAAA/wD/AP8AAP//AP///wAAAAAAAAAAAAAA 183 | AAAAAADq6upDQ0MAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADq6ru74cJYMUNDAAAAAAAAAAAAAADsvP+8 184 | /wAAAAAA6gcHu7vhwlgxMJ9DAAAAAAAAAAAAAOz/vP+8AOwAAOrvBwcHu+FYMTCfn59DAAAAAAAAAAAA 185 | 7Lz/vP8A9+wA6+/vBwe74TEwn5/y8kMAAAAAAAAAAADs/7z/vADs9+rv7+/vB7u7MJ/y8vLy8kMAAAAA 186 | AAAAAOy8/7z/APfs6rzv7+/vBwAA8vLy7+/vQwAAAAAAAAAA7P+8/7wA7PfqvLy87+8AAAAA7Ozs7+9D 187 | AAAAAAAAAADsvP+8/wD37OqSkpKSkgAAAADw8Ozs7EMAAAAAAAAAAOz/vP+8AOz36vLyn59YWAAA7/f/ 188 | 8O/vQwAAAAAAAAAA7P////8A9+zq8p9YWFJzc7rv9wf/8PBDAAAAAAAAAADs/////wDs9+zqWFhSc3jh 189 | uu/v9wf/QwAAAAAAAAAAAOz/////APfs9+pYUlJz4eG6uu/39wdDBwcHBwcAAAAA7P////8A9/f39+pS 190 | c3jhurq67+/3QwAAAAAH7+wAAADs/////wD39/f3AOvreOG6urrvQ0Ps7Ozs7AcH7AAAAOz/////APf3 191 | 9/cA///t7e3t6+v////////////sAAAA7Ozs7OwA9/f39wDs7Ozs7Ozs7Ozs7Ozs7Ozs7+wAAADq6urq 192 | 6gD39/f3AAAAAAAAAAAAAAAAAAAAAAAA7wsA7P//////6gD39/cA7AcHBwcHBwcHBwcHBwcHB+wAAOzs 193 | 7Ozs7Ozq6gD39wDs//////////////////8H7AAAAAAAAADs6urq6gD3AOz/AQEBAQEBAQEBAQEB/wfs 194 | AAAAAAAAAADs6urq6gAA7P8B+3p6MTExMU1NTQH/B+wAAAAAAAAAAADs/////wDs/wHDXnp6MTExMU1N 195 | Af8H7AAAAAAAAAAAAADs7Ozs7AD/AV7DXnp6MTExMU0B/wfsAAAAAAAAAAAAAAAAAAAA7P8Bw17DXnp6 196 | MTExMQH/B+wAAAAAAAAAAAAAAAAAAADs/wFew17DXnp6MTExAf8H7AAAAAAAAAAAAAAAAAAAAOz/AXpe 197 | w17DXnp6MTEB/wfsAAAAAAAAAAAAAAAAAAAA7P8Benpew17DXnp6MQH/B+wAAAAAAAAAAAAAAAAAAADs 198 | /wF6enpew17D+3p6Af8H7AAAAAAAAAAAAAAAAAAAAOz/AQEBAQEBAQEBAQEB/wfsAAAAAAAAAAAAAAAA 199 | AAAA7P//////////////////B+wAAAAAAAAAAAAAAAAAAAAA6+vr6+vr6+vr6+vr6+vr6wAA//4H/8D4 200 | Af/AcAD/wCAAf8AAAH/AAAA/wAAAP8AAYD/AAGA/wAAAP8AAAD/AAAADwAAAAcAAAADAAAAAwAAAAMAA 201 | AADAAAAAgAAAAQAAAAH4AAAB/AAAAf4AAAH/AAAB//gAAf/4AAH/+AAB//gAAf/4AAH/+AAB//gAAf/8 202 | AAMoAAAAMAAAAGAAAAABAAgAAAAAAIAKAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIAAAAAAgAAAgIAAAAAA 203 | gACAAIAAAICAAMDAwADA3MAApsrwAAQEBAAICAgADAwMABEREQAWFhYAHBwcACIiIgApKSkAVVVVAE1N 204 | TQBCQkIAOTk5AP98gAD/UFAA1gCTAMzs/wDv1sYA5+fWAK2pkAAzAAAAZgAAAJkAAADMAAAAADMAADMz 205 | AABmMwAAmTMAAMwzAAD/MwAAAGYAADNmAABmZgAAmWYAAMxmAAD/ZgAAAJkAADOZAABmmQAAmZkAAMyZ 206 | AAD/mQAAAMwAADPMAABmzAAAmcwAAMzMAAD/zAAAZv8AAJn/AADM/wAAAAAzADMAMwBmADMAmQAzAMwA 207 | MwD/ADMAADMzADMzMwBmMzMAmTMzAMwzMwD/MzMAAGYzADNmMwBmZjMAmWYzAMxmMwD/ZjMAAJkzADOZ 208 | MwBmmTMAmZkzAMyZMwD/mTMAAMwzADPMMwBmzDMAmcwzAMzMMwD/zDMAM/8zAGb/MwCZ/zMAzP8zAP// 209 | MwAAAGYAMwBmAGYAZgCZAGYAzABmAP8AZgAAM2YAMzNmAGYzZgCZM2YAzDNmAP8zZgAAZmYAM2ZmAGZm 210 | ZgCZZmYAzGZmAACZZgAzmWYAZplmAJmZZgDMmWYA/5lmAADMZgAzzGYAmcxmAMzMZgD/zGYAAP9mADP/ 211 | ZgCZ/2YAzP9mAP8AzADMAP8AAJmZAJkzmQCZAJkAzACZAAAAmQAzM5kAZgCZAMwzmQD/AJkAAGaZADNm 212 | mQBmM5kAmWaZAMxmmQD/M5kAM5mZAGaZmQCZmZkAzJmZAP+ZmQAAzJkAM8yZAGbMZgCZzJkAzMyZAP/M 213 | mQAA/5kAM/+ZAGbMmQCZ/5kAzP+ZAP//mQAAAMwAMwCZAGYAzACZAMwAzADMAAAzmQAzM8wAZjPMAJkz 214 | zADMM8wA/zPMAABmzAAzZswAZmaZAJlmzADMZswA/2aZAACZzAAzmcwAZpnMAJmZzADMmcwA/5nMAADM 215 | zAAzzMwAZszMAJnMzADMzMwA/8zMAAD/zAAz/8wAZv+ZAJn/zADM/8wA///MADMAzABmAP8AmQD/AAAz 216 | zAAzM/8AZjP/AJkz/wDMM/8A/zP/AABm/wAzZv8AZmbMAJlm/wDMZv8A/2bMAACZ/wAzmf8AZpn/AJmZ 217 | /wDMmf8A/5n/AADM/wAzzP8AZsz/AJnM/wDMzP8A/8z/ADP//wBm/8wAmf//AMz//wD/ZmYAZv9mAP// 218 | ZgBmZv8A/2b/AGb//wClACEAX19fAHd3dwCGhoYAlpaWAMvLywCysrIA19fXAN3d3QDj4+MA6urqAPHx 219 | 8QD4+PgA//vwAKCgpACAgIAA/wAAAAD/AAD//wAAAAD/AP8A/wAA//8A////AAAAAAAAAAAAAAAAAAAA 220 | AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAB7wZ 221 | 4cEZ4rsAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAO8HBwcJCcHh4cGZeQAAAAAA 222 | AAAAAAAAAAAAAAAAAOvw8PDw8PAAAAAAAAAAAAD3BwcHBwcI4cHh4QiYeFIxAAAAAAAAAAAAAAAAAAAA 223 | AOvw8PDw8PAA7QAAAAAAAO3t9wcHBwcI4cHh4ZiYV1JYeQAAAAAAAAAAAAAAAAAAAOvw8PDw8PAA7e0A 224 | AAAA9/ft7e8HBwcHGcHhwZh4UlJ5eXgAAAAAAAAAAAAAAAAAAOvw8PDw8PAA7e3tAAAAB+/3ku3vBwcI 225 | CcHhwZh4Unl5n58AAAAAAAAAAAAAAAAAAOvw8PDw8PAA7e3t7QDwvAfv95Lt77y84cHhwXhSWHmfn8LC 226 | AAAAAAAAAAAAAAAAAOvw8PDw8PAA7e3t7QD08LwH7+/3ku+84cHBUlJSeZ/CwsLCAAAAAAAAAAAAAAAA 227 | AOvw8PDw8PAA7e3tAPT/9PHwvAfv9+/vwcHBUlifn8LCG8IbCAAAAAAAAAAAAAAAAOvw8PDw8PAA7e3t 228 | APX19fLx8LwHB/fvAAAAc3kbG/EbG/Ly/wAAAAAAAAAAAAAAAOvw8PDw8PAA7e3tAPfvBwcHBwcH7+8A 229 | AAAAALy8vLy8vLy88AAAAAAAAAAAAAAAAOvw8PDw8PAA7e3tAJKS9/f39+8HBwcAAAAAAO2Skvf39/f3 230 | 7wAAAAAAAAAAAAAAAOvw8PDw8PAA7e3tAPfv7+/v7wifwngAAAAAAAcHkpKSkpKS9wAAAAAAAAAAAAAA 231 | AOvw8PDw8PAA7e3tAAe88PDwwp94UpidAAAAku+8B++SkpL3kgAAAAAAAAAAAAAAAOvw8PDw8PAA7e3t 232 | AAfywsLCn3lSeJjBu8G77+/v8PC8B/f3kgAAAAAAAAAAAAAAAOvx8fHx8fEA7+3t7QDCwp+fV1JSV8Hh 233 | wcG77/fvvPH0//KSAAAAAAAAAAAAAAAAAOvy8vLy8vIA7e/t7QCfn59YUlJXeMHh3MG77/fvB7zx9f// 234 | AAAAAAAAAAAAAAAAAOv09PT09PQA7+3v7e0AeFhYUlJ4mMHh4cG7u+/37wfw8v8ABwcHBwcHBwcAAAAA 235 | AOv19fX19fUA7+/t7+0AWFhSUnh4mMHhwcG7u+/v9++89PAABwcHBwcHBwfsAAAAAOv///////8A7+/v 236 | 7e/tAFJSUniYmMHh4cG7urvv7+8HBwAHBwcHBwcHBwfsAAAAAOv///////8A7+/v7+3v7QBSeHiYweHh 237 | 4cG7u7vv7+/3AAcHBwcHBwcHBwfsAAAAAOv///////8A7+/v7+/t7+0AAJiYweEJCcG7uru79wAABwcA 238 | AAAAAAAAB+/sAAAAAOv///////8A7+/v7+/v7e8A/wAAu+EZwcHhu5EAAAcHBwfs7Ozs7OzsBwfsAAAA 239 | AOv///////8A7+/v7+/v7+0A////AAAAAAAAAAD////////////////////sAAAAAOv///////8A7+/v 240 | 7+/v7+8A6+zs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7O/sAAAAAOvr6+vr6+sA7+/v7+/v7+8AAAAAAAAA 241 | AAAAAAAAAAAAAAAAAAAAAAAAAADvCwAAABISEhISEhIA7+/v7+/v7+8A7AcHBwcHBwcHBwcHBwcHBwcH 242 | BwcHBwcHB+wAAAAA6/////////8SAO/v7+/v7+8A7P/19fX19fX19fX19fX19fX19fX19fX1B+wAAADr 243 | //////////8SEgDv7+/v7+8A7P////X19fX19fX19fX19fX19fX19f/1B+wAAOvr6+vr6+vr6+sSEhIA 244 | 7+/v7+8A7P//AQEBAQEBAQEBAQEBAQEBAQEBAf/1B+wAAAAAAAAAAADrEhISEhISAO/v7+8A7P//AXp6 245 | Xnp6ejExMTExMU1NTU1NAf/1B+wAAAAAAAAAAAAA6xISEhISEgDv7+8A7P//AcN6el56enoxMTExMTFN 246 | TU1NAf/1B+wAAAAAAAAAAAAAAOsSEhISEhIA7+8A7P//AV7Denpeenp6MTExMTExTU1NAfX1B+wAAAAA 247 | AAAAAAAAAADrEhISEhISAO8A7P//AcNew3p6Xnp6ejExMTExMU1NAfX1B+wAAAAAAAAAAAAAAAAA6xIS 248 | EhISEgAA7P//AV7DXsN6el56enoxMTExMTFNAfX1B+wAAAAAAAAAAAAAAAAAAOv///////8A7P//AV5e 249 | w17Denpeenp6MTExMTExAfX1B+wAAAAAAAAAAAAAAAAAAADr6+vr6+vrAP//AV5eXsNew3p6Xnp6ejEx 250 | MTExAfX1B+wAAAAAAAAAAAAAAAAAAAAAAAAAAAAA7P//AXpeXl7DXsN6el56enoxMTExAfX1B+wAAAAA 251 | AAAAAAAAAAAAAAAAAAAAAAAA7P//AXp6Xl5ew17Denpeenp6MTExAfX1B+wAAAAAAAAAAAAAAAAAAAAA 252 | AAAAAAAA7P//AXp6el5eXsNew3p6Xnp6ejExAfX1B+wAAAAAAAAAAAAAAAAAAAAAAAAAAAAA7P//AXp6 253 | enpeXl7DXsN6el56enoxAfX1B+wAAAAAAAAAAAAAAAAAAAAAAAAAAAAA7P//AXp6enp6Xl5ew17Denpe 254 | enp6AfX1B+wAAAAAAAAAAAAAAAAAAAAAAAAAAAAA7P//AXp6enp6el5eXsNew3p6Xnp6AfX1B+wAAAAA 255 | AAAAAAAAAAAAAAAAAAAAAAAA7P//AQEBAQEBAQEBAQEBAQEBAQEBAfX1B+wAAAAAAAAAAAAAAAAAAAAA 256 | AAAAAAAA7P////////////////////////////X1B+wAAAAAAAAAAAAAAAAAAAAAAAAAAAAA7P////// 257 | ///////////////////////17+wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAOvr6+vr6+vr6+vr6+vr6+vr 258 | 6+vr6+vr6wAAAP///gH//wAA///4AH//AADgH+AAH/8AAOAPwAAP/wAA4AeAAAf/AADgAwAAA/8AAOAB 259 | AAAD/wAA4AAAAAH/AADgAAAAAf8AAOAAAAAA/wAA4AAAAAD/AADgAAA4AP8AAOAAADgA/wAA4AAAOAD/ 260 | AADgAAAAAP8AAOAAAAAA/wAA4AAAAAH/AADgAAAAAAMAAOAAAAAAAQAA4AAAAAAAAADgAAAAAAAAAOAA 261 | AAAAAAAA4AAAAAAAAADgAAAAAAAAAOAAAAAAAAAA4AAAAAAAAADgAAAAAAAAAOAAAAAAAQAAwAAAAAAB 262 | AACAAAAAAAEAAAAAAAAAAQAA/gAAAAABAAD/AAAAAAEAAP+AAAAAAQAA/8AAAAABAAD/4AAAAAEAAP/w 263 | AAAAAQAA//gAAAABAAD///AAAAEAAP//8AAAAQAA///wAAABAAD///AAAAEAAP//8AAAAQAA///wAAAB 264 | AAD///AAAAEAAP//8AAAAQAA///wAAABAAD///gAAAcAACgAAAAwAAAAYAAAAAEABAAAAAAAAAYAAAAA 265 | AAAAAAAAAAAAAAAAAAAAAAAAAIAAAIAAAACAgAAAAACAAACAgACAAIAAgICAAMDAwAAA/wAA/wAAAP// 266 | AAAAAP8AAP//AP8A/wD///8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFj43fkAAA 267 | AAAAAAAAAAAAAAAAAAAAAAiFWI3YmIAAAAAAAAAAAAeIiIgAAAAACHiIWI3YmHMwAAAAAAAAAAeIiIgH 268 | AAAAd4eIVY3ZmDO4AAAAAAAAAAeIiIgHcAAHd3h4Vf3ZhzOJkAAAAAAAAAeIiIgHdwAHd3eHhV3ZhziZ 269 | gAAAAAAAAAeIiIgHd3CId3d4dV3Yc7mYjwAAAAAAAAeIiIgHd3D4+Hd3h13TM5mI+AAAAAAAAAeIiIgH 270 | dw//j4h3eF2TuZ+Pj4AAAAAAAAeIiIgHdw//+PiHdwAHj/j///AAAAAAAAeIiIgHdwiIiIiIcAAAiIiI 271 | iIAAAAAAAAeIiIgHdwd3d3d3gAAAd3iIiIAAAAAAAAeIiIgHdwiIiIiYcAAAiHd3d4AAAAAAAAeIiIgH 272 | dwiIiJl7gwAHiIh3d3AAAAAAAAf4+PgHdwj4iZizPZWHePiId3AAAAAAAAePj48Id3CJmbsz3ZWIeI// 273 | 9wAAAAAAAAf///8Hh3CZm7M33ZWId4+P/wAAAAAAAAf///8IeHcHuzN92ZWIh3j/8IiIiIgAAAf///8I 274 | h4cLszd9mVWIiHePgIiIiIhwAAf///8IiHhwMzfdmVVYiHeICIiIiIhwAAf///8IiIeHA3fdmVVYiIdw 275 | iIiIiIhwAAf///8IiIh4cA3ZlVVYiIAIgAAAAIhwAAf///8IiIiHgPAJlVVYcAiIh3d3d4hwAAf///8I 276 | iIiIcP/wAAAAD/////////9wAAf///8IiIiIgHd3d3d3d3d3d3d3d3hwAAd3d3cIiIiIgAAAAAAAAAAA 277 | AAAAAACAAAd3d3cIiIiIgHiIiIiIiIiIiIiIiIcAAH////9wiIiIgH///////////////4cAB/////93 278 | CIiIgH///////////////4cAd3d3d3d3cIiIgH/yIiIiIiIiIiIi/4cAAAAAB3d3dwiIgH/yqqqqqqqq 279 | qqqi/4cAAAAAAHd3d3CIgH/yqqqqqqqqIiKi/4cAAAAAAAd3d3cIgH/yqqqqqqqqqqKi/4cAAAAAAAB3 280 | d3dwgH/yqqqqqqqqqqKi/4cAAAAAAAAHd3d3AH/yqqqqqqqqqqKi/4cAAAAAAAAAf///8H/yqqqqqqqq 281 | qqqi/4cAAAAAAAAAB3d3dw/yqqqqqqqqqqqi/4cAAAAAAAAAAAAAAH/yqqqqqqqqqqqi/4cAAAAAAAAA 282 | AAAAAH/yqqqqqqqqqqqi/4cAAAAAAAAAAAAAAH/yqqqqqqqqqqqi/4cAAAAAAAAAAAAAAH/yqvqqqqqq 283 | qqqi/4cAAAAAAAAAAAAAAH/yqqqqqqqqqqqi/4cAAAAAAAAAAAAAAH/yqqqqqqqqqqqi/4cAAAAAAAAA 284 | AAAAAH/yIiIiIiIiIiIi/4cAAAAAAAAAAAAAAH///////////////4cAAAAAAAAAAAAAAH////////// 285 | /////4cAAAAAAAAAAAAAAAd3d3d3d3d3d3d3d3AA///+Af//AAD///gAf/8AAOAf4AAf/wAA4A/AAA// 286 | AADgB4AAB/8AAOADAAAD/wAA4AEAAAP/AADgAAAAAf8AAOAAAAAB/wAA4AAAAAD/AADgAAAAAP8AAOAA 287 | ADgA/wAA4AAAOAD/AADgAAA4AP8AAOAAAAAA/wAA4AAAAAD/AADgAAAAAf8AAOAAAAAAAwAA4AAAAAAB 288 | AADgAAAAAAAAAOAAAAAAAAAA4AAAAAAAAADgAAAAAAAAAOAAAAAAAAAA4AAAAAAAAADgAAAAAAAAAOAA 289 | AAAAAAAA4AAAAAABAADAAAAAAAEAAIAAAAAAAQAAAAAAAAABAAD+AAAAAAEAAP8AAAAAAQAA/4AAAAAB 290 | AAD/wAAAAAEAAP/gAAAAAQAA//AAAAABAAD/+AAAAAEAAP//8AAAAQAA///wAAABAAD///AAAAEAAP// 291 | 8AAAAQAA///wAAABAAD///AAAAEAAP//8AAAAQAA///wAAABAAD///AAAAEAAP//+AAABwAA 292 | 293 | 294 | -------------------------------------------------------------------------------- /CH340BConfigure/CH340BDeviceAccess.cs: -------------------------------------------------------------------------------- 1 | // ********************************************************************************************************* 2 | // 3 | // Project : WCH CH340B Configuration Utility 4 | // FileName : CH340BDeviceAccess.cs 5 | // Author : SENTHILNATHAN THANGAVEL, INDEPENDENT DEVELOPER 6 | // Co-Author(s) : 7 | // Created : ‎02 January, ‎2022 8 | // 9 | // ********************************************************************************************************* 10 | // 11 | // Module Description 12 | // 13 | // This module has methods that will detect CH340B devices connected to PC USB port, read configuration data 14 | // from the selected CH340B device, write configuration data to the selected CH340B device. 15 | // ********************************************************************************************************* 16 | // 17 | // History 18 | // 19 | // Date Version Author Changes 20 | // 21 | // ‎02 January, ‎2022 1.0.0 SENTHILNATHAN THANGAVEL Initial version 22 | // 23 | // ********************************************************************************************************* 24 | using System; 25 | using System.Runtime.InteropServices; 26 | using System.Text; 27 | using System.Windows.Forms; 28 | using static CH340BConfigure.NativeAccess; 29 | 30 | namespace CH340BConfigure 31 | { 32 | public class CH340BDeviceAccess 33 | { 34 | // Device Info object array that has device's user friendly name, actual COM port name 35 | // This application supports multiple CH340B devices connected to the same PC's USB ports - 36 | // up to 10 number of devices 37 | internal DeviceInfo[] aoDevInfo = DeviceInfo.NewInitArray(10); 38 | 39 | // Allocate separate buffers for Read and Write functions 40 | private Byte[] abyReadData = new byte[1024]; 41 | private Byte[] abyWriteData = new byte[1024]; 42 | // Allocate a byte array buffer for using in the DeviceIoControl calls 43 | private Byte[] abyInputBuffer = null; 44 | private uint unBytesReturned = 0; 45 | // Device Handle 46 | private IntPtr pHandle = IntPtr.Zero; 47 | private IntPtr pspDeviceInterfaceData = IntPtr.Zero; 48 | private IntPtr pspDeviceInterfaceDetailData = IntPtr.Zero; 49 | 50 | internal class DeviceInfo 51 | { 52 | [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 260)] 53 | public string szComportName; 54 | 55 | [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 260)] 56 | public string szComportNameForHandle; 57 | 58 | [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 260)] 59 | public string szDeviceName; 60 | 61 | public int nDeviceIndex; 62 | 63 | // Array of Device Info objects 64 | static internal DeviceInfo[] NewInitArray(ulong num) 65 | { 66 | DeviceInfo[] aoDeviceInfo = new DeviceInfo[num]; 67 | for (ulong i = 0; i < num; i++) 68 | { 69 | aoDeviceInfo[i] = new DeviceInfo(); 70 | } 71 | return aoDeviceInfo; 72 | } 73 | } 74 | 75 | internal int FindDevices() 76 | { 77 | bool bResult = true; 78 | int nNumberOfDevices = 0; 79 | try 80 | { 81 | bResult = GetDevices(ref aoDevInfo, ref nNumberOfDevices); 82 | } 83 | catch (Exception ex) 84 | { 85 | MessageBox.Show("Exception occurred: " + ex.Message, "CH340B Configuration Utlity", MessageBoxButtons.OK, 86 | MessageBoxIcon.Exclamation, MessageBoxDefaultButton.Button1); 87 | } 88 | return nNumberOfDevices; 89 | } 90 | 91 | /* 92 | * Function Name: GetDevices 93 | * Description: This function looks for the CH340B devices connected to the PC USB port and 94 | * get the device friendly name, COM port name, which will be used in further device opening to perform Read / Write 95 | * functions with the device. 96 | * Arguments: 97 | * DeviceInfo[] - DeviceInfo object array - it will have the device info object for each device detected in the system 98 | * nTotalDevices - Integer value that represents the number of devices detected in the system 99 | * Return: boolean value - true if the function call is successsful, false if any error occurred 100 | * The code doesn't report error as of now. It checks for error using GetLastError, but not reporting to the caller. 101 | */ 102 | private bool GetDevices(ref DeviceInfo[] aoDevInfo, ref int nTotalDevices) 103 | { 104 | bool bStatus = true; 105 | uint uintError = Constants.NO_ERROR; 106 | IntPtr hDevInfo = IntPtr.Zero; 107 | IntPtr hDevice = IntPtr.Zero; 108 | uint uintDeviceID = 0; 109 | uint uintDataT = 0; 110 | uint uintBufferSize = 0; 111 | // COM Port Interface Class GUID 112 | Guid sGuid = new Guid("86E0D1E0-8089-11D0-9CE4-08003E301F73"); 113 | IntPtr psDeviceInfoData = IntPtr.Zero; 114 | NativeStructs.SP_DEVINFO_DATA sDeviceInfoData = new NativeStructs.SP_DEVINFO_DATA(); 115 | IntPtr pPropertyBuffer = IntPtr.Zero; 116 | do 117 | { 118 | uintError = NativeAccess.Constants.NO_ERROR; 119 | nTotalDevices = 0; 120 | // Create a HDEVINFO with all the present devices of the COM Port Interface Class GUID Supplied. 121 | hDevInfo = NativeMethods.SetupDiGetClassDevs(ref sGuid, IntPtr.Zero, IntPtr.Zero, 122 | Constants.DIGCF_DEVICEINTERFACE | Constants.DIGCF_PRESENT); 123 | // Validate the hDevInfo handle 124 | if (Constants.INVALID_HANDLE_VALUE == hDevInfo) 125 | { 126 | uintError = Constants.ERROR_INVALID_HANDLE; // (Long Pointer Value - 1) 127 | bStatus = false; 128 | break; 129 | } 130 | // Enumerate through all devices in the set 131 | sDeviceInfoData.cbSize = Marshal.SizeOf(sDeviceInfoData); 132 | // Initialize pointer for sDeviceInfoData 133 | psDeviceInfoData = Marshal.AllocHGlobal(Marshal.SizeOf(sDeviceInfoData)); 134 | Marshal.StructureToPtr(sDeviceInfoData, psDeviceInfoData, true); 135 | for (uintDeviceID = 0; NativeMethods.SetupDiEnumDeviceInfo(hDevInfo, uintDeviceID, psDeviceInfoData); 136 | uintDeviceID++) 137 | { 138 | sDeviceInfoData = (NativeStructs.SP_DEVINFO_DATA)Marshal.PtrToStructure(psDeviceInfoData, 139 | typeof(NativeStructs.SP_DEVINFO_DATA)); 140 | // Get the device friendly name from the registry 141 | while (!NativeMethods.SetupDiGetDeviceRegistryProperty(hDevInfo, psDeviceInfoData, 142 | (uint)Constants.SPDRP.SPDRP_FRIENDLYNAME, ref uintDataT, pPropertyBuffer, uintBufferSize, ref uintBufferSize)) 143 | { 144 | // Check for error 145 | uintError = (uint)Marshal.GetLastWin32Error(); 146 | if (Constants.ERROR_INSUFFICIENT_BUFFER == uintError) 147 | { 148 | // If the error is insufficient buffer, then allocate the buffer for number of bytes specified by uintBufferSize 149 | pPropertyBuffer = Marshal.AllocHGlobal((int)uintBufferSize); 150 | } 151 | else 152 | { 153 | // If the error is not ERROR_INSUFFICIENT_BUFFER, quit the loop 154 | bStatus = false; 155 | break; 156 | } 157 | } 158 | IntPtr pDeviceName = new IntPtr(pPropertyBuffer.ToInt64()); 159 | String szDeviceName = Marshal.PtrToStringAuto(pDeviceName); 160 | String szDevicePathName = System.String.Empty; 161 | String szComportName = ""; 162 | try 163 | { 164 | szComportName = szDeviceName.Split(new char[] { '(', ')' })[1]; 165 | } 166 | catch (Exception ex) 167 | { 168 | MessageBox.Show("Exception occurred: " + ex.Message, "CH340B Configuration Utlity", MessageBoxButtons.OK, 169 | MessageBoxIcon.Exclamation, MessageBoxDefaultButton.Button1); 170 | } 171 | if (string.IsNullOrEmpty(szComportName) == false) 172 | { 173 | // Form the COM Port name like this "\\\\.\\COMn" 174 | string szComportNameForHandle = "\\\\.\\" + szComportName; 175 | // Check if the device detected is really CH340B or other Virtual / Real COM Port devices 176 | bool bDeviceIsCh340B = CheckIfDeviceIsCh340B(szComportNameForHandle); 177 | if (bDeviceIsCh340B) 178 | { 179 | // If this is really CH340B then, store its friendly name, COM Port name 180 | // to the device info object 181 | aoDevInfo[nTotalDevices].szComportName = szComportName; 182 | aoDevInfo[nTotalDevices].szComportNameForHandle = szComportNameForHandle; 183 | aoDevInfo[nTotalDevices].szDeviceName = szDeviceName; 184 | aoDevInfo[nTotalDevices].nDeviceIndex = nTotalDevices; 185 | nTotalDevices++; 186 | } 187 | } 188 | } 189 | 190 | } while (false); 191 | // Free the memory allocated from unmanaged memory used 192 | if (psDeviceInfoData != IntPtr.Zero) 193 | { 194 | Marshal.FreeHGlobal(psDeviceInfoData); 195 | psDeviceInfoData = IntPtr.Zero; 196 | } 197 | if (pPropertyBuffer != IntPtr.Zero) 198 | { 199 | Marshal.FreeHGlobal(pPropertyBuffer); 200 | pPropertyBuffer = IntPtr.Zero; 201 | } 202 | // Destroy the device information list 203 | if (hDevInfo != IntPtr.Zero) 204 | { 205 | NativeMethods.SetupDiDestroyDeviceInfoList(hDevInfo); 206 | } 207 | return bStatus; 208 | } 209 | 210 | /* 211 | * Function Name: CheckIfDeviceIsCh340B 212 | * Description: This function checks whether the detected device is a CH340B or other COM port devices 213 | * Arguments: 214 | * IntPtr - pHandle - Managed Pointer variable that represents the device handle 215 | * Return: boolean value - true if the device detected is a CH340B or else false 216 | */ 217 | private bool CheckIfDeviceIsCh340B(string szComportName) 218 | { 219 | bool bResult = false; 220 | bool bDeviceIsCh340B = false; 221 | try 222 | { 223 | // Open the device using the COM Port Name in the format "\\\\.\\COMn" 224 | pHandle = NativeMethods.CreateFile(szComportName, Constants.GENERIC_READ | Constants.GENERIC_WRITE, 225 | Constants.FILE_SHARE_READ | Constants.FILE_SHARE_WRITE, IntPtr.Zero, Constants.OPEN_EXISTING, 0, IntPtr.Zero); 226 | if (pHandle != IntPtr.Zero && pHandle != Constants.INVALID_HANDLE_VALUE) 227 | { 228 | // Initialize the vendor interface 229 | bResult = InitializeCh340BVendorInterface(pHandle); 230 | if (bResult == true) 231 | { 232 | // Get Serial Properties 233 | NativeStructs.SERIAL_COMMPROP sSerialCompProp = new NativeStructs.SERIAL_COMMPROP(); 234 | IntPtr psSerialCompProp = Marshal.AllocHGlobal(Marshal.SizeOf(sSerialCompProp)); 235 | Marshal.StructureToPtr(sSerialCompProp, psSerialCompProp, false); 236 | bResult = NativeMethods.DeviceIoControl(pHandle, Constants.IOCTL_SERIAL_GET_PROPERTIES, IntPtr.Zero, 0, psSerialCompProp, 237 | Marshal.SizeOf(sSerialCompProp), out unBytesReturned, IntPtr.Zero); 238 | Marshal.PtrToStructure(psSerialCompProp, sSerialCompProp); 239 | Marshal.FreeHGlobal(psSerialCompProp); 240 | 241 | // The magic value 0x43485523 is returned in the unsigned integer ProvSpec2 of Serial Comm Prop structure by the CH340B driver 242 | if (sSerialCompProp.ProvSpec2 == 0x43485523) 243 | { 244 | // Device is CH340B 245 | bDeviceIsCh340B = true; 246 | } 247 | } 248 | } 249 | } 250 | catch (Exception ex) 251 | { 252 | MessageBox.Show("Exception occurred: " + ex.Message, "CH340B Configuration Utlity", MessageBoxButtons.OK, 253 | MessageBoxIcon.Exclamation, MessageBoxDefaultButton.Button1); 254 | } 255 | // Close the device handle 256 | if (pHandle != IntPtr.Zero && pHandle != Constants.INVALID_HANDLE_VALUE) 257 | { 258 | NativeMethods.CloseHandle(pHandle); 259 | } 260 | return bDeviceIsCh340B; 261 | } 262 | 263 | /* 264 | * Function Name: InitializeCh340BVendorInterface 265 | * Description: This function initializes the Vendor Interface of the CH340B driver 266 | * Arguments: 267 | * IntPtr - pHandle - Manged Pointer variable that represents the device handle 268 | * Return: boolean value - true if the device detected is a CH340B or else false 269 | */ 270 | private bool InitializeCh340BVendorInterface(IntPtr pHandle) 271 | { 272 | bool bResult = false; 273 | 274 | try 275 | { 276 | // Validate the device hanlde 277 | if (pHandle != IntPtr.Zero && pHandle != Constants.INVALID_HANDLE_VALUE) 278 | { 279 | // CH340B uses a vendor supplied driver on Microsoft Windows, that is its not fully complaint with 280 | // Microsoft's USB CDC driver, so the Microsoft USB CDC driver is not loaded and it requires 281 | // the vendor - chip manufacturer (WCH) supplied driver. 282 | // First the device must be informed to send the Vendor request command through Control Endpoint 283 | // The following sequence of commands are issued to the CH340B's Kernel mode driver and make the CH340B driver 284 | // to issue a vendor request through Control Endpoint to the CH340B. 285 | 286 | // Get Serial Properties 287 | NativeStructs.SERIAL_COMMPROP sSerialCompProp = new NativeStructs.SERIAL_COMMPROP(); 288 | IntPtr psSerialCompProp = Marshal.AllocHGlobal(Marshal.SizeOf(sSerialCompProp)); 289 | Marshal.StructureToPtr(sSerialCompProp, psSerialCompProp, false); 290 | bResult = NativeMethods.DeviceIoControl(pHandle, Constants.IOCTL_SERIAL_GET_PROPERTIES, IntPtr.Zero, 0, psSerialCompProp, 291 | Marshal.SizeOf(sSerialCompProp), out unBytesReturned, IntPtr.Zero); 292 | Marshal.PtrToStructure(psSerialCompProp, sSerialCompProp); 293 | Marshal.FreeHGlobal(psSerialCompProp); 294 | 295 | // Set Serial Queue size 296 | NativeStructs.SERIAL_QUEUE_SIZE sSerialQueueSize = new NativeStructs.SERIAL_QUEUE_SIZE(); 297 | sSerialQueueSize.InSize = 0x00002000; 298 | sSerialQueueSize.OutSize = 0x00002000; 299 | IntPtr psSerialQueueSize = Marshal.AllocHGlobal(Marshal.SizeOf(sSerialQueueSize)); 300 | Marshal.StructureToPtr(sSerialQueueSize, psSerialQueueSize, false); 301 | bResult = NativeMethods.DeviceIoControl(pHandle, Constants.IOCTL_SERIAL_SET_QUEUE_SIZE, psSerialQueueSize, 302 | Marshal.SizeOf(sSerialQueueSize), IntPtr.Zero, 0, out unBytesReturned, IntPtr.Zero); 303 | Marshal.FreeHGlobal(psSerialQueueSize); 304 | 305 | // Get Serial TimeOuts 306 | NativeStructs.SERIAL_TIMEOUTS sSerialTimeOuts = new NativeStructs.SERIAL_TIMEOUTS(); 307 | IntPtr psSerialTimeOuts = Marshal.AllocHGlobal(Marshal.SizeOf(sSerialTimeOuts)); 308 | Marshal.StructureToPtr(sSerialTimeOuts, psSerialTimeOuts, false); 309 | bResult = NativeMethods.DeviceIoControl(pHandle, Constants.IOCTL_SERIAL_GET_TIMEOUTS, IntPtr.Zero, 0, psSerialTimeOuts, 310 | Marshal.SizeOf(sSerialTimeOuts), out unBytesReturned, IntPtr.Zero); 311 | Marshal.PtrToStructure(psSerialTimeOuts, sSerialTimeOuts); 312 | Marshal.FreeHGlobal(psSerialTimeOuts); 313 | 314 | // Set Serial Timeouts 315 | sSerialTimeOuts = new NativeStructs.SERIAL_TIMEOUTS(); 316 | sSerialTimeOuts.ReadIntervalTimeout = 0x00000000; 317 | sSerialTimeOuts.ReadTotalTimeoutMultiplier = 0x00000064; 318 | sSerialTimeOuts.ReadTotalTimeoutConstant = 0x000003E8; 319 | sSerialTimeOuts.WriteTotalTimeoutMultiplier = 0x00000032; 320 | sSerialTimeOuts.WriteTotalTimeoutConstant = 0x000001F4; 321 | psSerialTimeOuts = Marshal.AllocHGlobal(Marshal.SizeOf(sSerialTimeOuts)); 322 | Marshal.StructureToPtr(sSerialTimeOuts, psSerialTimeOuts, false); 323 | bResult = NativeMethods.DeviceIoControl(pHandle, Constants.IOCTL_SERIAL_SET_TIMEOUTS, psSerialTimeOuts, 324 | Marshal.SizeOf(sSerialTimeOuts), IntPtr.Zero, 0, out unBytesReturned, IntPtr.Zero); 325 | Marshal.FreeHGlobal(psSerialTimeOuts); 326 | 327 | // Issue Serial Purge 328 | abyInputBuffer = new byte[4]; 329 | abyInputBuffer[0] = 0x0F; 330 | bResult = NativeMethods.DeviceIoControl(pHandle, Constants.IOCTL_SERIAL_PURGE, abyInputBuffer, abyInputBuffer.Length, 331 | IntPtr.Zero, 0, out unBytesReturned, IntPtr.Zero); 332 | 333 | // Get Serial Baudrate 334 | NativeStructs.SERIAL_BAUD_RATE sSerialBaudRate = new NativeStructs.SERIAL_BAUD_RATE(); 335 | IntPtr psSerialBaudRate = Marshal.AllocHGlobal(Marshal.SizeOf(sSerialBaudRate)); 336 | Marshal.StructureToPtr(sSerialBaudRate, psSerialBaudRate, false); 337 | bResult = NativeMethods.DeviceIoControl(pHandle, Constants.IOCTL_SERIAL_GET_BAUD_RATE, IntPtr.Zero, 0, psSerialBaudRate, 338 | Marshal.SizeOf(sSerialBaudRate), out unBytesReturned, IntPtr.Zero); 339 | Marshal.PtrToStructure(psSerialBaudRate, sSerialBaudRate); 340 | Marshal.FreeHGlobal(psSerialBaudRate); 341 | 342 | // Get Serial Line control 343 | NativeStructs.SERIAL_LINE_CONTROL sSerialLineControl = new NativeStructs.SERIAL_LINE_CONTROL(); 344 | IntPtr psSerialLineControl = Marshal.AllocHGlobal(Marshal.SizeOf(sSerialLineControl)); 345 | Marshal.StructureToPtr(sSerialLineControl, psSerialLineControl, false); 346 | bResult = NativeMethods.DeviceIoControl(pHandle, Constants.IOCTL_SERIAL_GET_LINE_CONTROL, IntPtr.Zero, 0, psSerialLineControl, 347 | Marshal.SizeOf(sSerialLineControl), out unBytesReturned, IntPtr.Zero); 348 | Marshal.PtrToStructure(psSerialLineControl, sSerialLineControl); 349 | Marshal.FreeHGlobal(psSerialLineControl); 350 | 351 | // Get Serial CHARS 352 | NativeStructs.SERIAL_CHARS sSerialChars = new NativeStructs.SERIAL_CHARS(); 353 | IntPtr psSerialChars = Marshal.AllocHGlobal(Marshal.SizeOf(sSerialChars)); 354 | Marshal.StructureToPtr(sSerialChars, psSerialChars, false); 355 | bResult = NativeMethods.DeviceIoControl(pHandle, Constants.IOCTL_SERIAL_GET_CHARS, IntPtr.Zero, 0, psSerialChars, 356 | Marshal.SizeOf(sSerialChars), out unBytesReturned, IntPtr.Zero); 357 | Marshal.PtrToStructure(psSerialChars, sSerialChars); 358 | Marshal.FreeHGlobal(psSerialChars); 359 | 360 | // Get Serial Handflow 361 | NativeStructs.SERIAL_HANDFLOW sSerialHandFlow = new NativeStructs.SERIAL_HANDFLOW(); 362 | IntPtr psSerialHandFlow = Marshal.AllocHGlobal(Marshal.SizeOf(sSerialHandFlow)); 363 | Marshal.StructureToPtr(sSerialHandFlow, psSerialHandFlow, false); 364 | bResult = NativeMethods.DeviceIoControl(pHandle, Constants.IOCTL_SERIAL_GET_HANDFLOW, IntPtr.Zero, 0, psSerialHandFlow, 365 | Marshal.SizeOf(sSerialHandFlow), out unBytesReturned, IntPtr.Zero); 366 | Marshal.PtrToStructure(psSerialHandFlow, sSerialHandFlow); 367 | Marshal.FreeHGlobal(psSerialHandFlow); 368 | 369 | // Get Serial Baudrate 370 | sSerialBaudRate = new NativeStructs.SERIAL_BAUD_RATE(); 371 | psSerialBaudRate = Marshal.AllocHGlobal(Marshal.SizeOf(sSerialBaudRate)); 372 | Marshal.StructureToPtr(sSerialBaudRate, psSerialBaudRate, false); 373 | bResult = NativeMethods.DeviceIoControl(pHandle, Constants.IOCTL_SERIAL_GET_BAUD_RATE, IntPtr.Zero, 0, psSerialBaudRate, 374 | Marshal.SizeOf(sSerialBaudRate), out unBytesReturned, IntPtr.Zero); 375 | Marshal.PtrToStructure(psSerialBaudRate, sSerialBaudRate); 376 | Marshal.FreeHGlobal(psSerialBaudRate); 377 | 378 | // Get Serial Line control 379 | sSerialLineControl = new NativeStructs.SERIAL_LINE_CONTROL(); 380 | psSerialLineControl = Marshal.AllocHGlobal(Marshal.SizeOf(sSerialLineControl)); 381 | Marshal.StructureToPtr(sSerialLineControl, psSerialLineControl, false); 382 | bResult = NativeMethods.DeviceIoControl(pHandle, Constants.IOCTL_SERIAL_GET_LINE_CONTROL, IntPtr.Zero, 0, psSerialLineControl, 383 | Marshal.SizeOf(sSerialLineControl), out unBytesReturned, IntPtr.Zero); 384 | Marshal.PtrToStructure(psSerialLineControl, sSerialLineControl); 385 | Marshal.FreeHGlobal(psSerialLineControl); 386 | 387 | // Get Serial CHARS 388 | sSerialChars = new NativeStructs.SERIAL_CHARS(); 389 | psSerialChars = Marshal.AllocHGlobal(Marshal.SizeOf(sSerialChars)); 390 | Marshal.StructureToPtr(sSerialChars, psSerialChars, false); 391 | bResult = NativeMethods.DeviceIoControl(pHandle, Constants.IOCTL_SERIAL_GET_CHARS, IntPtr.Zero, 0, psSerialChars, 392 | Marshal.SizeOf(sSerialChars), out unBytesReturned, IntPtr.Zero); 393 | Marshal.PtrToStructure(psSerialChars, sSerialChars); 394 | Marshal.FreeHGlobal(psSerialChars); 395 | 396 | // Get Serial Handflow 397 | sSerialHandFlow = new NativeStructs.SERIAL_HANDFLOW(); 398 | psSerialHandFlow = Marshal.AllocHGlobal(Marshal.SizeOf(sSerialHandFlow)); 399 | Marshal.StructureToPtr(sSerialHandFlow, psSerialHandFlow, false); 400 | bResult = NativeMethods.DeviceIoControl(pHandle, Constants.IOCTL_SERIAL_GET_HANDFLOW, IntPtr.Zero, 0, psSerialHandFlow, 401 | Marshal.SizeOf(sSerialHandFlow), out unBytesReturned, IntPtr.Zero); 402 | Marshal.PtrToStructure(psSerialHandFlow, sSerialHandFlow); 403 | Marshal.FreeHGlobal(psSerialHandFlow); 404 | 405 | // Set Serial BaudRate 406 | sSerialBaudRate = new NativeStructs.SERIAL_BAUD_RATE(); 407 | sSerialBaudRate.BaudRate = 300; 408 | psSerialBaudRate = Marshal.AllocHGlobal(Marshal.SizeOf(sSerialBaudRate)); 409 | Marshal.StructureToPtr(sSerialBaudRate, psSerialBaudRate, false); 410 | bResult = NativeMethods.DeviceIoControl(pHandle, Constants.IOCTL_SERIAL_SET_BAUD_RATE, psSerialBaudRate, 411 | Marshal.SizeOf(sSerialBaudRate), IntPtr.Zero, 0, out unBytesReturned, IntPtr.Zero); 412 | Marshal.FreeHGlobal(psSerialBaudRate); 413 | 414 | // Set Serial RTS 415 | bResult = NativeMethods.DeviceIoControl(pHandle, Constants.IOCTL_SERIAL_SET_RTS, IntPtr.Zero, 0, 416 | IntPtr.Zero, 0, out unBytesReturned, IntPtr.Zero); 417 | 418 | // Set Serial DTR 419 | bResult = NativeMethods.DeviceIoControl(pHandle, Constants.IOCTL_SERIAL_SET_DTR, IntPtr.Zero, 0, 420 | IntPtr.Zero, 0, out unBytesReturned, IntPtr.Zero); 421 | 422 | // Set Serial Line control 423 | sSerialLineControl = new NativeStructs.SERIAL_LINE_CONTROL(); 424 | sSerialLineControl.StopBits = 0x00; 425 | sSerialLineControl.Parity = 0x00; 426 | sSerialLineControl.WordLength = 0x08; 427 | psSerialLineControl = Marshal.AllocHGlobal(Marshal.SizeOf(sSerialLineControl)); 428 | Marshal.StructureToPtr(sSerialLineControl, psSerialLineControl, false); 429 | bResult = NativeMethods.DeviceIoControl(pHandle, Constants.IOCTL_SERIAL_SET_LINE_CONTROL, 430 | psSerialLineControl, Marshal.SizeOf(sSerialLineControl), IntPtr.Zero, 0, out unBytesReturned, IntPtr.Zero); 431 | Marshal.FreeHGlobal(psSerialLineControl); 432 | 433 | // Set Serial CHARS 434 | sSerialChars = new NativeStructs.SERIAL_CHARS(); 435 | sSerialChars.EofChar = 0x00; 436 | sSerialChars.ErrorChar = 0x00; 437 | sSerialChars.BreakChar = 0x00; 438 | sSerialChars.EventChar = 0x00; 439 | sSerialChars.XonChar = 0x11; 440 | sSerialChars.XoffChar = 0x13; 441 | psSerialChars = Marshal.AllocHGlobal(Marshal.SizeOf(sSerialChars)); 442 | Marshal.StructureToPtr(sSerialChars, psSerialChars, false); 443 | bResult = NativeMethods.DeviceIoControl(pHandle, Constants.IOCTL_SERIAL_SET_CHARS, psSerialChars, 444 | Marshal.SizeOf(sSerialChars), IntPtr.Zero, 0, out unBytesReturned, IntPtr.Zero); 445 | Marshal.FreeHGlobal(psSerialChars); 446 | 447 | // Set Serial Handflow 448 | sSerialHandFlow = new NativeStructs.SERIAL_HANDFLOW(); 449 | sSerialHandFlow.ControlHandShake = 0x00000001; 450 | sSerialHandFlow.FlowReplace = 0x00000040; 451 | sSerialHandFlow.XonLimit = 0x000086C0; 452 | sSerialHandFlow.XoffLimit = 0x000021B0; 453 | psSerialHandFlow = Marshal.AllocHGlobal(Marshal.SizeOf(sSerialHandFlow)); 454 | Marshal.StructureToPtr(sSerialHandFlow, psSerialHandFlow, false); 455 | bResult = NativeMethods.DeviceIoControl(pHandle, Constants.IOCTL_SERIAL_SET_HANDFLOW, psSerialHandFlow, 456 | Marshal.SizeOf(sSerialHandFlow), IntPtr.Zero, 0, out unBytesReturned, IntPtr.Zero); 457 | Marshal.FreeHGlobal(psSerialHandFlow); 458 | } 459 | } 460 | catch (Exception ex) 461 | { 462 | MessageBox.Show("Exception occurred: " + ex.Message, "CH340B Configuration Utlity", MessageBoxButtons.OK, 463 | MessageBoxIcon.Exclamation, MessageBoxDefaultButton.Button1); 464 | } 465 | 466 | return bResult; 467 | } 468 | 469 | /* 470 | * Function Name: ReadConfigurationData 471 | * Description: This function reads the configuration data from CH340B's EEPROM and returns the data to the caller 472 | * Arguments: 473 | * int nSelectedDeviceIndex - index of the selected device - this denotes the index in the device list if 474 | * there are multiple devices found. If there is only one device, then its value would be 0 475 | * ref CH340BConfigurationData oCH340BConfigurationData - reference of the object of type CH340BConfigurationData 476 | * on returning this function, this oCH340BConfigurationData will have the actual configuration data read from the 477 | * chip. 478 | * Return: boolean value - true if the read function finishes successfully, else false 479 | */ 480 | internal bool ReadConfigurationData(int nSelectedDeviceIndex, ref CH340BConfigurationData oCH340BConfigurationData) 481 | { 482 | bool bResult = false; 483 | 484 | try 485 | { 486 | // Open the device handle 487 | pHandle = NativeMethods.CreateFile(aoDevInfo[nSelectedDeviceIndex].szComportNameForHandle, Constants.GENERIC_READ | Constants.GENERIC_WRITE, 488 | Constants.FILE_SHARE_READ | Constants.FILE_SHARE_WRITE, IntPtr.Zero, Constants.OPEN_EXISTING, 0, IntPtr.Zero); 489 | if (pHandle == IntPtr.Zero || pHandle == Constants.INVALID_HANDLE_VALUE) 490 | { 491 | MessageBox.Show("Can't open device for reading configuration data.", "CH340B Configuration Utlity", MessageBoxButtons.OK, 492 | MessageBoxIcon.Exclamation, MessageBoxDefaultButton.Button1); 493 | return bResult; 494 | } 495 | // Initialize the vendor interface of the CH340B driver 496 | InitializeCh340BVendorInterface(pHandle); 497 | // Read USB Vendor ID 498 | // Read the E2PROM location 0x04 and 0x05 499 | ushort ushVID = 0x0000; 500 | ushort ushVIDLSB = 0x0000; 501 | ushort ushVIDMSB = 0x0000; 502 | abyWriteData = new byte[4] { 0x40, 0xA1, 0x04, 0x00 }; 503 | bResult = NativeMethods.WriteFile(pHandle, abyWriteData, (uint)abyWriteData.Length, ref unBytesReturned, IntPtr.Zero); 504 | bResult = NativeMethods.ReadFile(pHandle, abyReadData, 1, ref unBytesReturned, IntPtr.Zero); 505 | ushVIDLSB = abyReadData[0]; 506 | abyWriteData = new byte[4] { 0x40, 0xA1, 0x05, 0x00 }; 507 | bResult = NativeMethods.WriteFile(pHandle, abyWriteData, (uint)abyWriteData.Length, ref unBytesReturned, IntPtr.Zero); 508 | bResult = NativeMethods.ReadFile(pHandle, abyReadData, 1, ref unBytesReturned, IntPtr.Zero); 509 | ushVIDMSB = abyReadData[0]; 510 | ushVID = (ushort)((ushVIDMSB << 8) | ushVIDLSB); 511 | oCH340BConfigurationData.ushVID = ushVID; 512 | 513 | // Read USB Product ID 514 | // Read the E2PROM location 0x06 and 0x07 515 | ushort ushPID = 0x0000; 516 | ushort ushPIDLSB = 0x0000; 517 | ushort ushPIDMSB = 0x0000; 518 | abyWriteData = new byte[4] { 0x40, 0xA1, 0x06, 0x00 }; 519 | bResult = NativeMethods.WriteFile(pHandle, abyWriteData, (uint)abyWriteData.Length, ref unBytesReturned, IntPtr.Zero); 520 | bResult = NativeMethods.ReadFile(pHandle, abyReadData, 1, ref unBytesReturned, IntPtr.Zero); 521 | ushPIDLSB = abyReadData[0]; 522 | abyWriteData = new byte[4] { 0x40, 0xA1, 0x07, 0x00 }; 523 | bResult = NativeMethods.WriteFile(pHandle, abyWriteData, (uint)abyWriteData.Length, ref unBytesReturned, IntPtr.Zero); 524 | bResult = NativeMethods.ReadFile(pHandle, abyReadData, 1, ref unBytesReturned, IntPtr.Zero); 525 | ushPIDMSB = abyReadData[0]; 526 | ushPID = (ushort)((ushPIDMSB << 8) | ushPIDLSB); 527 | oCH340BConfigurationData.ushPID = ushPID; 528 | 529 | // Read USB Product String 530 | // Read the E2PROM location 0x1A 531 | abyWriteData = new byte[4] { 0x40, 0xA1, 0x1A, 0x00 }; 532 | bResult = NativeMethods.WriteFile(pHandle, abyWriteData, (uint)abyWriteData.Length, ref unBytesReturned, IntPtr.Zero); 533 | bResult = NativeMethods.ReadFile(pHandle, abyReadData, 1, ref unBytesReturned, IntPtr.Zero); 534 | byte byUnicodeStringLength = abyReadData[0]; 535 | 536 | // Read the E2PROM location 0x1B 537 | abyWriteData = new byte[4] { 0x40, 0xA1, 0x1B, 0x00 }; 538 | bResult = NativeMethods.WriteFile(pHandle, abyWriteData, (uint)abyWriteData.Length, ref unBytesReturned, IntPtr.Zero); 539 | bResult = NativeMethods.ReadFile(pHandle, abyReadData, 1, ref unBytesReturned, IntPtr.Zero); 540 | int nUsbProductStringIndentifier = abyReadData[0]; 541 | 542 | // Read the E2PROM location 0x1C to 0x3F 543 | byte i = 0x1C; 544 | byte[] abyUnicodeProductString = new byte[36]; 545 | int nIndex = 0; 546 | for (; i <= 0x3F; i++) 547 | { 548 | abyWriteData = new byte[4] { 0x40, 0xA1, i, 0x00 }; 549 | bResult = NativeMethods.WriteFile(pHandle, abyWriteData, (uint)abyWriteData.Length, ref unBytesReturned, IntPtr.Zero); 550 | bResult = NativeMethods.ReadFile(pHandle, abyReadData, 1, ref unBytesReturned, IntPtr.Zero); 551 | abyUnicodeProductString[nIndex++] = abyReadData[0]; 552 | } 553 | 554 | // Perform the conversion from one encoding to the other. 555 | byte[] abyAsciiProductString = Encoding.Convert(Encoding.Unicode, Encoding.UTF8, abyUnicodeProductString, 0, byUnicodeStringLength - 2); 556 | // Convert the new byte[] into a char[] and then into a string. 557 | // This is a slightly different approach to converting to illustrate 558 | // the use of GetCharCount/GetChars. 559 | char[] asciiChars = new char[Encoding.UTF8.GetCharCount(abyAsciiProductString, 0, abyAsciiProductString.Length)]; 560 | Encoding.UTF8.GetChars(abyAsciiProductString, 0, abyAsciiProductString.Length, asciiChars, 0); 561 | string asciiProductString = new string(asciiChars); 562 | oCH340BConfigurationData.szProductString = asciiProductString; 563 | 564 | // Read USB Serial Number 565 | // Read EEPROM location 0x10 to 0x17 566 | string szSerialNumber = ""; 567 | i = 0x10; 568 | byte[] abyAsciiSerialNumberString = new byte[8]; 569 | nIndex = 0; 570 | for (; i <= 0x17; i++) // 0x17 is the last EEPROM location to access 571 | { 572 | abyWriteData = new byte[4] { 0x40, 0xA1, i, 0x00 }; 573 | bResult = NativeMethods.WriteFile(pHandle, abyWriteData, (uint)abyWriteData.Length, ref unBytesReturned, IntPtr.Zero); 574 | bResult = NativeMethods.ReadFile(pHandle, abyReadData, 1, ref unBytesReturned, IntPtr.Zero); 575 | abyAsciiSerialNumberString[nIndex++] = abyReadData[0]; 576 | } 577 | if (abyAsciiSerialNumberString[0] > 0x21 && abyAsciiSerialNumberString[0] < 0x7F) 578 | { 579 | asciiChars = new char[Encoding.ASCII.GetCharCount(abyAsciiSerialNumberString, 0, abyAsciiSerialNumberString.Length)]; 580 | Encoding.ASCII.GetChars(abyAsciiSerialNumberString, 0, abyAsciiSerialNumberString.Length, asciiChars, 0); 581 | szSerialNumber = new string(asciiChars); 582 | } 583 | oCH340BConfigurationData.szSerialNumber = szSerialNumber; 584 | bResult = true; 585 | } 586 | catch (Exception ex) 587 | { 588 | MessageBox.Show("Exception occurred: " + ex.Message, "CH340B Configuration Utlity", MessageBoxButtons.OK, 589 | MessageBoxIcon.Exclamation, MessageBoxDefaultButton.Button1); 590 | } 591 | try 592 | { 593 | if (pHandle != IntPtr.Zero && pHandle != Constants.INVALID_HANDLE_VALUE) 594 | { 595 | NativeMethods.CloseHandle(pHandle); 596 | } 597 | } 598 | catch (Exception ex) 599 | { 600 | MessageBox.Show("Exception occurred: " + ex.Message, "CH340B Configuration Utlity", MessageBoxButtons.OK, 601 | MessageBoxIcon.Exclamation, MessageBoxDefaultButton.Button1); 602 | } 603 | return bResult; 604 | } 605 | 606 | /* 607 | * Function Name: WriteConfigurationData 608 | * Description: This function writes the configuration data to CH340B's EEPROM 609 | * Arguments: 610 | * int nSelectedDeviceIndex - index of the selected device - this denotes the index in the device list if 611 | * there are multiple devices found. If there is only one device, then its value would be 0 612 | * CH340BConfigurationData oCH340BConfigurationData - reference of the object of type CH340BConfigurationData 613 | * this oCH340BConfigurationData will have the actual configuration data that is filled by the caller. 614 | * Return: boolean value - true if the write function finishes successfully, else false 615 | */ 616 | internal bool WriteConfigurationData(int nSelectedDeviceIndex, CH340BConfigurationData oCH340BConfigurationData) 617 | { 618 | bool bResult = false; 619 | 620 | do 621 | { 622 | try 623 | { 624 | ushort ushVID = oCH340BConfigurationData.ushVID; 625 | ushort ushPID = oCH340BConfigurationData.ushPID; 626 | string szSerialNumber = oCH340BConfigurationData.szSerialNumber; 627 | string szProductString = oCH340BConfigurationData.szProductString; 628 | 629 | // Open device handle 630 | pHandle = NativeMethods.CreateFile(aoDevInfo[nSelectedDeviceIndex].szComportNameForHandle, Constants.GENERIC_READ | Constants.GENERIC_WRITE, 631 | Constants.FILE_SHARE_READ | Constants.FILE_SHARE_WRITE, IntPtr.Zero, Constants.OPEN_EXISTING, 0, IntPtr.Zero); 632 | if (pHandle == IntPtr.Zero || pHandle == Constants.INVALID_HANDLE_VALUE) 633 | { 634 | MessageBox.Show("Can't open device for writing configuration data.", "CH340B Configuration Utlity", MessageBoxButtons.OK, 635 | MessageBoxIcon.Exclamation, MessageBoxDefaultButton.Button1); 636 | break; 637 | } 638 | InitializeCh340BVendorInterface(pHandle); 639 | abyWriteData = new byte[4] { 0x40, 0xA0, 0x00, 0x5B }; 640 | bResult = NativeMethods.WriteFile(pHandle, abyWriteData, (uint)abyWriteData.Length, ref unBytesReturned, IntPtr.Zero); 641 | // all the values are now validated 642 | 643 | // Write VID to EEPROM 0x04 (LSB) and 0x05 (MSB) 644 | Byte byVIDLSB = (Byte)(ushVID & 0xFF); 645 | Byte byVIDMSB = (Byte)(ushVID >> 8 & 0xFF); 646 | 647 | abyWriteData = new byte[4] { 0x40, 0xA0, 0x04, byVIDLSB }; 648 | bResult = NativeMethods.WriteFile(pHandle, abyWriteData, (uint)abyWriteData.Length, ref unBytesReturned, IntPtr.Zero); 649 | 650 | abyWriteData = new byte[4] { 0x40, 0xA0, 0x05, byVIDMSB }; 651 | bResult = NativeMethods.WriteFile(pHandle, abyWriteData, (uint)abyWriteData.Length, ref unBytesReturned, IntPtr.Zero); 652 | 653 | // Write PID to EEPROM 0x06 (LSB) and 0x07 (MSB) 654 | Byte byPIDLSB = (Byte)(ushPID & 0xFF); 655 | Byte byPIDMSB = (Byte)(ushPID >> 8 & 0xFF); 656 | 657 | abyWriteData = new byte[4] { 0x40, 0xA0, 0x06, byPIDLSB }; 658 | bResult = NativeMethods.WriteFile(pHandle, abyWriteData, (uint)abyWriteData.Length, ref unBytesReturned, IntPtr.Zero); 659 | 660 | abyWriteData = new byte[4] { 0x40, 0xA0, 0x07, byPIDMSB }; 661 | bResult = NativeMethods.WriteFile(pHandle, abyWriteData, (uint)abyWriteData.Length, ref unBytesReturned, IntPtr.Zero); 662 | 663 | // Write Serial number to EEPROM 664 | if (string.IsNullOrEmpty(szSerialNumber) == false) 665 | { 666 | // Valid Serail number, write it to EEPROM location 0x10 to 0x17 667 | byte[] abyAsciiSerialNumber = Encoding.ASCII.GetBytes(szSerialNumber); 668 | 669 | // form a 8 byte array 670 | int nSerialNumberLength = abyAsciiSerialNumber.Length; 671 | 672 | if (nSerialNumberLength > 8) 673 | { 674 | nSerialNumberLength = 8; 675 | } 676 | 677 | byte[] abySerialNumber = new byte[8]; 678 | Array.Copy(abyAsciiSerialNumber, abySerialNumber, nSerialNumberLength); 679 | int nIndex = 0; 680 | for (byte i = 0x10; i <= 0x17; i++) 681 | { 682 | abyWriteData = new byte[4] { 0x40, 0xA0, i, abySerialNumber[nIndex++] }; 683 | bResult = NativeMethods.WriteFile(pHandle, abyWriteData, (uint)abyWriteData.Length, ref unBytesReturned, IntPtr.Zero); 684 | } 685 | } 686 | else 687 | { 688 | // Serial number is empty 689 | // Clear the Serial number 690 | byte[] abySerialNumber = new byte[8]; 691 | Array.Clear(abySerialNumber, 0, abySerialNumber.Length); 692 | int nIndex = 0; 693 | for (byte i = 0x10; i <= 0x17; i++) 694 | { 695 | abyWriteData = new byte[4] { 0x40, 0xA0, i, abySerialNumber[nIndex++] }; 696 | bResult = NativeMethods.WriteFile(pHandle, abyWriteData, (uint)abyWriteData.Length, ref unBytesReturned, IntPtr.Zero); 697 | } 698 | } 699 | 700 | // Write Product String to device 701 | // Prepare the array of bytes with Unicode byte values of the string and write the array to EEPROM location 0x1A to 0x3F 702 | if (string.IsNullOrEmpty(szProductString) == false) 703 | { 704 | byte[] abyUnicodeProdString = Encoding.Unicode.GetBytes(szProductString); 705 | 706 | // form a 38 byte array 707 | byte[] abyProdStringBuffer = new byte[38]; 708 | abyProdStringBuffer[0] = (byte)(abyUnicodeProdString.Length + 2); 709 | abyProdStringBuffer[1] = 0x03; 710 | 711 | Array.Copy(abyUnicodeProdString, 0, abyProdStringBuffer, 2, abyUnicodeProdString.Length); 712 | 713 | int nIndex = 0; 714 | for (byte i = 0x1A; i <= 0x3F; i++) 715 | { 716 | abyWriteData = new byte[4] { 0x40, 0xA0, i, abyProdStringBuffer[nIndex++] }; 717 | bResult = NativeMethods.WriteFile(pHandle, abyWriteData, (uint)abyWriteData.Length, ref unBytesReturned, IntPtr.Zero); 718 | } 719 | } 720 | } 721 | catch (Exception ex) 722 | { 723 | MessageBox.Show("Exception occurred: " + ex.Message, "CH340B Configuration Utlity", MessageBoxButtons.OK, 724 | MessageBoxIcon.Exclamation, MessageBoxDefaultButton.Button1); 725 | } 726 | 727 | } while (false); 728 | try 729 | { 730 | // Close the device handle 731 | if (pHandle != IntPtr.Zero && pHandle != Constants.INVALID_HANDLE_VALUE) 732 | { 733 | NativeMethods.CloseHandle(pHandle); 734 | } 735 | } 736 | catch (Exception ex) 737 | { 738 | MessageBox.Show("Exception occurred: " + ex.Message, "CH340B Configuration Utlity", MessageBoxButtons.OK, 739 | MessageBoxIcon.Exclamation, MessageBoxDefaultButton.Button1); 740 | } 741 | return bResult; 742 | } 743 | } 744 | } 745 | --------------------------------------------------------------------------------