diff --git a/.gitignore b/.gitignore
index 46028121..a380d480 100644
--- a/.gitignore
+++ b/.gitignore
@@ -6,9 +6,11 @@ typings
tmp
temp
projects/**
-win10/app/bin
-win10/app/bld
-win10/*.opendb
+clients/win10/app/bin
+clients/win10/app/bld
+clients/win10/*.opendb
+clients/**/bin/**
+clients/**/obj/**
*.user
*.sw?
diff --git a/win10/app.sln b/clients/win10/app.sln
similarity index 100%
rename from win10/app.sln
rename to clients/win10/app.sln
diff --git a/win10/app/AppPackages/latest/Add-AppDevPackage.ps1 b/clients/win10/app/AppPackages/latest/Add-AppDevPackage.ps1
similarity index 100%
rename from win10/app/AppPackages/latest/Add-AppDevPackage.ps1
rename to clients/win10/app/AppPackages/latest/Add-AppDevPackage.ps1
diff --git a/win10/app/AppPackages/latest/Add-AppDevPackage.resources/Add-AppDevPackage.psd1 b/clients/win10/app/AppPackages/latest/Add-AppDevPackage.resources/Add-AppDevPackage.psd1
similarity index 100%
rename from win10/app/AppPackages/latest/Add-AppDevPackage.resources/Add-AppDevPackage.psd1
rename to clients/win10/app/AppPackages/latest/Add-AppDevPackage.resources/Add-AppDevPackage.psd1
diff --git a/win10/app/AppPackages/latest/Add-AppDevPackage.resources/cs-CZ/Add-AppDevPackage.psd1 b/clients/win10/app/AppPackages/latest/Add-AppDevPackage.resources/cs-CZ/Add-AppDevPackage.psd1
similarity index 100%
rename from win10/app/AppPackages/latest/Add-AppDevPackage.resources/cs-CZ/Add-AppDevPackage.psd1
rename to clients/win10/app/AppPackages/latest/Add-AppDevPackage.resources/cs-CZ/Add-AppDevPackage.psd1
diff --git a/win10/app/AppPackages/latest/Add-AppDevPackage.resources/de-DE/Add-AppDevPackage.psd1 b/clients/win10/app/AppPackages/latest/Add-AppDevPackage.resources/de-DE/Add-AppDevPackage.psd1
similarity index 100%
rename from win10/app/AppPackages/latest/Add-AppDevPackage.resources/de-DE/Add-AppDevPackage.psd1
rename to clients/win10/app/AppPackages/latest/Add-AppDevPackage.resources/de-DE/Add-AppDevPackage.psd1
diff --git a/win10/app/AppPackages/latest/Add-AppDevPackage.resources/en-US/Add-AppDevPackage.psd1 b/clients/win10/app/AppPackages/latest/Add-AppDevPackage.resources/en-US/Add-AppDevPackage.psd1
similarity index 100%
rename from win10/app/AppPackages/latest/Add-AppDevPackage.resources/en-US/Add-AppDevPackage.psd1
rename to clients/win10/app/AppPackages/latest/Add-AppDevPackage.resources/en-US/Add-AppDevPackage.psd1
diff --git a/win10/app/AppPackages/latest/Add-AppDevPackage.resources/es-ES/Add-AppDevPackage.psd1 b/clients/win10/app/AppPackages/latest/Add-AppDevPackage.resources/es-ES/Add-AppDevPackage.psd1
similarity index 100%
rename from win10/app/AppPackages/latest/Add-AppDevPackage.resources/es-ES/Add-AppDevPackage.psd1
rename to clients/win10/app/AppPackages/latest/Add-AppDevPackage.resources/es-ES/Add-AppDevPackage.psd1
diff --git a/win10/app/AppPackages/latest/Add-AppDevPackage.resources/fr-FR/Add-AppDevPackage.psd1 b/clients/win10/app/AppPackages/latest/Add-AppDevPackage.resources/fr-FR/Add-AppDevPackage.psd1
similarity index 100%
rename from win10/app/AppPackages/latest/Add-AppDevPackage.resources/fr-FR/Add-AppDevPackage.psd1
rename to clients/win10/app/AppPackages/latest/Add-AppDevPackage.resources/fr-FR/Add-AppDevPackage.psd1
diff --git a/win10/app/AppPackages/latest/Add-AppDevPackage.resources/it-IT/Add-AppDevPackage.psd1 b/clients/win10/app/AppPackages/latest/Add-AppDevPackage.resources/it-IT/Add-AppDevPackage.psd1
similarity index 100%
rename from win10/app/AppPackages/latest/Add-AppDevPackage.resources/it-IT/Add-AppDevPackage.psd1
rename to clients/win10/app/AppPackages/latest/Add-AppDevPackage.resources/it-IT/Add-AppDevPackage.psd1
diff --git a/win10/app/AppPackages/latest/Add-AppDevPackage.resources/ja-JP/Add-AppDevPackage.psd1 b/clients/win10/app/AppPackages/latest/Add-AppDevPackage.resources/ja-JP/Add-AppDevPackage.psd1
similarity index 100%
rename from win10/app/AppPackages/latest/Add-AppDevPackage.resources/ja-JP/Add-AppDevPackage.psd1
rename to clients/win10/app/AppPackages/latest/Add-AppDevPackage.resources/ja-JP/Add-AppDevPackage.psd1
diff --git a/win10/app/AppPackages/latest/Add-AppDevPackage.resources/ko-KR/Add-AppDevPackage.psd1 b/clients/win10/app/AppPackages/latest/Add-AppDevPackage.resources/ko-KR/Add-AppDevPackage.psd1
similarity index 100%
rename from win10/app/AppPackages/latest/Add-AppDevPackage.resources/ko-KR/Add-AppDevPackage.psd1
rename to clients/win10/app/AppPackages/latest/Add-AppDevPackage.resources/ko-KR/Add-AppDevPackage.psd1
diff --git a/win10/app/AppPackages/latest/Add-AppDevPackage.resources/pl-PL/Add-AppDevPackage.psd1 b/clients/win10/app/AppPackages/latest/Add-AppDevPackage.resources/pl-PL/Add-AppDevPackage.psd1
similarity index 100%
rename from win10/app/AppPackages/latest/Add-AppDevPackage.resources/pl-PL/Add-AppDevPackage.psd1
rename to clients/win10/app/AppPackages/latest/Add-AppDevPackage.resources/pl-PL/Add-AppDevPackage.psd1
diff --git a/win10/app/AppPackages/latest/Add-AppDevPackage.resources/pt-BR/Add-AppDevPackage.psd1 b/clients/win10/app/AppPackages/latest/Add-AppDevPackage.resources/pt-BR/Add-AppDevPackage.psd1
similarity index 100%
rename from win10/app/AppPackages/latest/Add-AppDevPackage.resources/pt-BR/Add-AppDevPackage.psd1
rename to clients/win10/app/AppPackages/latest/Add-AppDevPackage.resources/pt-BR/Add-AppDevPackage.psd1
diff --git a/win10/app/AppPackages/latest/Add-AppDevPackage.resources/ru-RU/Add-AppDevPackage.psd1 b/clients/win10/app/AppPackages/latest/Add-AppDevPackage.resources/ru-RU/Add-AppDevPackage.psd1
similarity index 100%
rename from win10/app/AppPackages/latest/Add-AppDevPackage.resources/ru-RU/Add-AppDevPackage.psd1
rename to clients/win10/app/AppPackages/latest/Add-AppDevPackage.resources/ru-RU/Add-AppDevPackage.psd1
diff --git a/win10/app/AppPackages/latest/Add-AppDevPackage.resources/tr-TR/Add-AppDevPackage.psd1 b/clients/win10/app/AppPackages/latest/Add-AppDevPackage.resources/tr-TR/Add-AppDevPackage.psd1
similarity index 100%
rename from win10/app/AppPackages/latest/Add-AppDevPackage.resources/tr-TR/Add-AppDevPackage.psd1
rename to clients/win10/app/AppPackages/latest/Add-AppDevPackage.resources/tr-TR/Add-AppDevPackage.psd1
diff --git a/win10/app/AppPackages/latest/Add-AppDevPackage.resources/zh-CN/Add-AppDevPackage.psd1 b/clients/win10/app/AppPackages/latest/Add-AppDevPackage.resources/zh-CN/Add-AppDevPackage.psd1
similarity index 100%
rename from win10/app/AppPackages/latest/Add-AppDevPackage.resources/zh-CN/Add-AppDevPackage.psd1
rename to clients/win10/app/AppPackages/latest/Add-AppDevPackage.resources/zh-CN/Add-AppDevPackage.psd1
diff --git a/win10/app/AppPackages/latest/Add-AppDevPackage.resources/zh-TW/Add-AppDevPackage.psd1 b/clients/win10/app/AppPackages/latest/Add-AppDevPackage.resources/zh-TW/Add-AppDevPackage.psd1
similarity index 100%
rename from win10/app/AppPackages/latest/Add-AppDevPackage.resources/zh-TW/Add-AppDevPackage.psd1
rename to clients/win10/app/AppPackages/latest/Add-AppDevPackage.resources/zh-TW/Add-AppDevPackage.psd1
diff --git a/win10/app/AppPackages/latest/m.pxt.io_0.1.4.0_AnyCPU_Debug.appxbundle b/clients/win10/app/AppPackages/latest/m.pxt.io_0.1.4.0_AnyCPU_Debug.appxbundle
similarity index 100%
rename from win10/app/AppPackages/latest/m.pxt.io_0.1.4.0_AnyCPU_Debug.appxbundle
rename to clients/win10/app/AppPackages/latest/m.pxt.io_0.1.4.0_AnyCPU_Debug.appxbundle
diff --git a/win10/app/AppPackages/latest/m.pxt.io_0.1.4.0_AnyCPU_Debug.cer b/clients/win10/app/AppPackages/latest/m.pxt.io_0.1.4.0_AnyCPU_Debug.cer
similarity index 100%
rename from win10/app/AppPackages/latest/m.pxt.io_0.1.4.0_AnyCPU_Debug.cer
rename to clients/win10/app/AppPackages/latest/m.pxt.io_0.1.4.0_AnyCPU_Debug.cer
diff --git a/win10/app/BundleArtifacts/neutral.txt b/clients/win10/app/BundleArtifacts/neutral.txt
similarity index 100%
rename from win10/app/BundleArtifacts/neutral.txt
rename to clients/win10/app/BundleArtifacts/neutral.txt
diff --git a/win10/app/images/LockScreenLogo.scale-200.png b/clients/win10/app/images/LockScreenLogo.scale-200.png
similarity index 100%
rename from win10/app/images/LockScreenLogo.scale-200.png
rename to clients/win10/app/images/LockScreenLogo.scale-200.png
diff --git a/win10/app/images/SplashScreen.scale-200.png b/clients/win10/app/images/SplashScreen.scale-200.png
similarity index 100%
rename from win10/app/images/SplashScreen.scale-200.png
rename to clients/win10/app/images/SplashScreen.scale-200.png
diff --git a/win10/app/images/Square150x150Logo.scale-200.png b/clients/win10/app/images/Square150x150Logo.scale-200.png
similarity index 100%
rename from win10/app/images/Square150x150Logo.scale-200.png
rename to clients/win10/app/images/Square150x150Logo.scale-200.png
diff --git a/win10/app/images/Square44x44Logo.scale-200.png b/clients/win10/app/images/Square44x44Logo.scale-200.png
similarity index 100%
rename from win10/app/images/Square44x44Logo.scale-200.png
rename to clients/win10/app/images/Square44x44Logo.scale-200.png
diff --git a/win10/app/images/Square44x44Logo.targetsize-24_altform-unplated.png b/clients/win10/app/images/Square44x44Logo.targetsize-24_altform-unplated.png
similarity index 100%
rename from win10/app/images/Square44x44Logo.targetsize-24_altform-unplated.png
rename to clients/win10/app/images/Square44x44Logo.targetsize-24_altform-unplated.png
diff --git a/win10/app/images/StoreLogo.png b/clients/win10/app/images/StoreLogo.png
similarity index 100%
rename from win10/app/images/StoreLogo.png
rename to clients/win10/app/images/StoreLogo.png
diff --git a/win10/app/images/Wide310x150Logo.scale-200.png b/clients/win10/app/images/Wide310x150Logo.scale-200.png
similarity index 100%
rename from win10/app/images/Wide310x150Logo.scale-200.png
rename to clients/win10/app/images/Wide310x150Logo.scale-200.png
diff --git a/win10/app/m.pxt.io.jsproj b/clients/win10/app/m.pxt.io.jsproj
similarity index 100%
rename from win10/app/m.pxt.io.jsproj
rename to clients/win10/app/m.pxt.io.jsproj
diff --git a/win10/app/msapp-error.css b/clients/win10/app/msapp-error.css
similarity index 100%
rename from win10/app/msapp-error.css
rename to clients/win10/app/msapp-error.css
diff --git a/win10/app/msapp-error.html b/clients/win10/app/msapp-error.html
similarity index 100%
rename from win10/app/msapp-error.html
rename to clients/win10/app/msapp-error.html
diff --git a/win10/app/msapp-error.js b/clients/win10/app/msapp-error.js
similarity index 100%
rename from win10/app/msapp-error.js
rename to clients/win10/app/msapp-error.js
diff --git a/win10/app/package.appxmanifest b/clients/win10/app/package.appxmanifest
similarity index 100%
rename from win10/app/package.appxmanifest
rename to clients/win10/app/package.appxmanifest
diff --git a/win10/app/pxtwinapp_TemporaryKey.pfx b/clients/win10/app/pxtwinapp_TemporaryKey.pfx
similarity index 100%
rename from win10/app/pxtwinapp_TemporaryKey.pfx
rename to clients/win10/app/pxtwinapp_TemporaryKey.pfx
diff --git a/clients/winuploader/CodeTheMicroBit.Loader.sln b/clients/winuploader/CodeTheMicroBit.Loader.sln
new file mode 100644
index 00000000..9c82e656
--- /dev/null
+++ b/clients/winuploader/CodeTheMicroBit.Loader.sln
@@ -0,0 +1,22 @@
+
+Microsoft Visual Studio Solution File, Format Version 12.00
+# Visual Studio 14
+VisualStudioVersion = 14.0.25123.0
+MinimumVisualStudioVersion = 10.0.40219.1
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CodeTheMicrobit.Uploader", "Microbit.Uploader\CodeTheMicrobit.Uploader.csproj", "{7DC6CA45-FD75-44BC-805E-708C812CD4BF}"
+EndProject
+Global
+ GlobalSection(SolutionConfigurationPlatforms) = preSolution
+ Debug|Any CPU = Debug|Any CPU
+ Release|Any CPU = Release|Any CPU
+ EndGlobalSection
+ GlobalSection(ProjectConfigurationPlatforms) = postSolution
+ {7DC6CA45-FD75-44BC-805E-708C812CD4BF}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {7DC6CA45-FD75-44BC-805E-708C812CD4BF}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {7DC6CA45-FD75-44BC-805E-708C812CD4BF}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {7DC6CA45-FD75-44BC-805E-708C812CD4BF}.Release|Any CPU.Build.0 = Release|Any CPU
+ EndGlobalSection
+ GlobalSection(SolutionProperties) = preSolution
+ HideSolutionNode = FALSE
+ EndGlobalSection
+EndGlobal
diff --git a/clients/winuploader/Microbit.Uploader/App.config b/clients/winuploader/Microbit.Uploader/App.config
new file mode 100644
index 00000000..99844edd
--- /dev/null
+++ b/clients/winuploader/Microbit.Uploader/App.config
@@ -0,0 +1,7 @@
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/clients/winuploader/Microbit.Uploader/CodeTheMicrobit.Uploader.csproj b/clients/winuploader/Microbit.Uploader/CodeTheMicrobit.Uploader.csproj
new file mode 100644
index 00000000..077710b6
--- /dev/null
+++ b/clients/winuploader/Microbit.Uploader/CodeTheMicrobit.Uploader.csproj
@@ -0,0 +1,123 @@
+
+
+
+
+ Debug
+ AnyCPU
+ {7DC6CA45-FD75-44BC-805E-708C812CD4BF}
+ WinExe
+ Properties
+ Microsoft.MicroBit
+ Microbit.Uploader
+ v2.0
+ 512
+ true
+
+
+
+ AnyCPU
+ true
+ full
+ false
+ bin\Debug\
+ DEBUG;TRACE
+ prompt
+ 4
+ true
+ AllRules.ruleset
+
+
+ AnyCPU
+ pdbonly
+ true
+ bin\Release\
+ TRACE
+ prompt
+ 4
+
+
+
+
+
+
+ false
+
+
+ false
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Form
+
+
+ Settings.cs
+
+
+
+
+ Form
+
+
+ LicenseDialog.cs
+
+
+ Form
+
+
+ MainForm.cs
+
+
+
+
+
+
+ LicenseDialog.cs
+
+
+ MainForm.cs
+
+
+ ResXFileCodeGenerator
+ Resources.Designer.cs
+ Designer
+
+
+ True
+ Resources.resx
+ True
+
+
+ Settings.cs
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/clients/winuploader/Microbit.Uploader/GlobalSuppressions.cs b/clients/winuploader/Microbit.Uploader/GlobalSuppressions.cs
new file mode 100644
index 00000000..8122d89b
Binary files /dev/null and b/clients/winuploader/Microbit.Uploader/GlobalSuppressions.cs differ
diff --git a/clients/winuploader/Microbit.Uploader/KnownFolders.cs b/clients/winuploader/Microbit.Uploader/KnownFolders.cs
new file mode 100644
index 00000000..0c9f1584
--- /dev/null
+++ b/clients/winuploader/Microbit.Uploader/KnownFolders.cs
@@ -0,0 +1,33 @@
+using System;
+using System.Diagnostics.CodeAnalysis;
+using System.Management;
+using System.Runtime.InteropServices;
+using System.Security;
+
+namespace Microsoft.MicroBit
+{
+ ///
+ /// Class containing methods to retrieve specific file system paths.
+ ///
+ internal static class KnownFoldersNativeMethods
+ {
+ [SecurityCritical]
+ [SuppressMessage("Microsoft.Design", "CA1024:UsePropertiesWhereAppropriate")]
+ public static string GetDownloadPath()
+ {
+ IntPtr outPath;
+ int result = SHGetKnownFolderPath(new Guid("{374DE290-123F-4565-9164-39C4925E467B}"), 0x00004000, new IntPtr(0), out outPath);
+ if (result >= 0)
+ return Marshal.PtrToStringUni(outPath);
+ else return null;
+ }
+
+ [SuppressMessage("Microsoft.Security", "CA5122:PInvokesShouldNotBeSafeCriticalFxCopRule")]
+ [DllImport("Shell32.dll")]
+ [SecurityCritical]
+ private static extern int SHGetKnownFolderPath(
+ [MarshalAs(UnmanagedType.LPStruct)]Guid rfid, uint dwFlags, IntPtr hToken,
+ out IntPtr ppszPath);
+ }
+
+}
\ No newline at end of file
diff --git a/clients/winuploader/Microbit.Uploader/LicenseDialog.Designer.cs b/clients/winuploader/Microbit.Uploader/LicenseDialog.Designer.cs
new file mode 100644
index 00000000..bf8ed131
--- /dev/null
+++ b/clients/winuploader/Microbit.Uploader/LicenseDialog.Designer.cs
@@ -0,0 +1,93 @@
+namespace Microsoft.MicroBit
+{
+ partial class LicenseDialog
+ {
+ ///
+ /// Required designer variable.
+ ///
+ private System.ComponentModel.IContainer components = null;
+
+ ///
+ /// Clean up any resources being used.
+ ///
+ /// true if managed resources should be disposed; otherwise, false.
+ protected override void Dispose(bool disposing)
+ {
+ if (disposing && (components != null))
+ {
+ components.Dispose();
+ }
+ base.Dispose(disposing);
+ }
+
+ #region Windows Form Designer generated code
+
+ ///
+ /// Required method for Designer support - do not modify
+ /// the contents of this method with the code editor.
+ ///
+ private void InitializeComponent()
+ {
+ this.textBox = new System.Windows.Forms.RichTextBox();
+ this.acceptButton = new System.Windows.Forms.Button();
+ this.exitButton = new System.Windows.Forms.Button();
+ this.SuspendLayout();
+ //
+ // textBox
+ //
+ this.textBox.BorderStyle = System.Windows.Forms.BorderStyle.None;
+ this.textBox.Location = new System.Drawing.Point(13, 13);
+ this.textBox.Name = "textBox";
+ this.textBox.ReadOnly = true;
+ this.textBox.Size = new System.Drawing.Size(465, 438);
+ this.textBox.TabIndex = 0;
+ this.textBox.Text = "";
+ //
+ // acceptButton
+ //
+ this.acceptButton.Location = new System.Drawing.Point(322, 457);
+ this.acceptButton.Name = "acceptButton";
+ this.acceptButton.Size = new System.Drawing.Size(75, 23);
+ this.acceptButton.TabIndex = 1;
+ this.acceptButton.Text = "Accept";
+ this.acceptButton.UseVisualStyleBackColor = true;
+ this.acceptButton.Click += new System.EventHandler(this.acceptButton_Click);
+ //
+ // exitButton
+ //
+ this.exitButton.DialogResult = System.Windows.Forms.DialogResult.Cancel;
+ this.exitButton.Location = new System.Drawing.Point(403, 457);
+ this.exitButton.Name = "exitButton";
+ this.exitButton.Size = new System.Drawing.Size(75, 23);
+ this.exitButton.TabIndex = 2;
+ this.exitButton.Text = "Exit";
+ this.exitButton.UseVisualStyleBackColor = true;
+ this.exitButton.Click += new System.EventHandler(this.exitButton_Click);
+ //
+ // LicenseDialog
+ //
+ this.AcceptButton = this.acceptButton;
+ this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
+ this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
+ this.CancelButton = this.exitButton;
+ this.ClientSize = new System.Drawing.Size(490, 492);
+ this.ControlBox = false;
+ this.Controls.Add(this.exitButton);
+ this.Controls.Add(this.acceptButton);
+ this.Controls.Add(this.textBox);
+ this.MaximizeBox = false;
+ this.MinimizeBox = false;
+ this.Name = "LicenseDialog";
+ this.StartPosition = System.Windows.Forms.FormStartPosition.CenterScreen;
+ this.Text = "code the micro:bit uploader Terms Of Use";
+ this.ResumeLayout(false);
+
+ }
+
+ #endregion
+
+ private System.Windows.Forms.RichTextBox textBox;
+ private System.Windows.Forms.Button acceptButton;
+ private System.Windows.Forms.Button exitButton;
+ }
+}
\ No newline at end of file
diff --git a/clients/winuploader/Microbit.Uploader/LicenseDialog.cs b/clients/winuploader/Microbit.Uploader/LicenseDialog.cs
new file mode 100644
index 00000000..22c7a087
--- /dev/null
+++ b/clients/winuploader/Microbit.Uploader/LicenseDialog.cs
@@ -0,0 +1,32 @@
+using Microsoft.MicroBit.Properties;
+using System;
+using System.Collections.Generic;
+using System.ComponentModel;
+using System.Data;
+using System.Drawing;
+using System.Text;
+using System.Windows.Forms;
+
+namespace Microsoft.MicroBit
+{
+ public partial class LicenseDialog : Form
+ {
+ public LicenseDialog()
+ {
+ InitializeComponent();
+ this.textBox.Rtf = Resources.MSR_LA___2576;
+ }
+
+ private void acceptButton_Click(object sender, EventArgs e)
+ {
+ this.DialogResult = DialogResult.Yes;
+ this.Close();
+ }
+
+ private void exitButton_Click(object sender, EventArgs e)
+ {
+ this.DialogResult = DialogResult.No;
+ this.Close();
+ }
+ }
+}
diff --git a/clients/winuploader/Microbit.Uploader/LicenseDialog.resx b/clients/winuploader/Microbit.Uploader/LicenseDialog.resx
new file mode 100644
index 00000000..7080a7d1
--- /dev/null
+++ b/clients/winuploader/Microbit.Uploader/LicenseDialog.resx
@@ -0,0 +1,120 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ text/microsoft-resx
+
+
+ 2.0
+
+
+ System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+
+
+ System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+
+
\ No newline at end of file
diff --git a/clients/winuploader/Microbit.Uploader/MSFT_logo_png.png b/clients/winuploader/Microbit.Uploader/MSFT_logo_png.png
new file mode 100644
index 00000000..60c210e1
Binary files /dev/null and b/clients/winuploader/Microbit.Uploader/MSFT_logo_png.png differ
diff --git a/clients/winuploader/Microbit.Uploader/MainForm.Designer.cs b/clients/winuploader/Microbit.Uploader/MainForm.Designer.cs
new file mode 100644
index 00000000..cf9a6d0c
--- /dev/null
+++ b/clients/winuploader/Microbit.Uploader/MainForm.Designer.cs
@@ -0,0 +1,172 @@
+namespace Microsoft.MicroBit
+{
+ partial class MainForm
+ {
+ ///
+ /// Required designer variable.
+ ///
+ private System.ComponentModel.IContainer components = null;
+
+ ///
+ /// Clean up any resources being used.
+ ///
+ /// true if managed resources should be disposed; otherwise, false.
+ protected override void Dispose(bool disposing)
+ {
+ if (disposing && (components != null))
+ {
+ components.Dispose();
+ }
+ base.Dispose(disposing);
+ }
+
+ #region Windows Form Designer generated code
+
+ ///
+ /// Required method for Designer support - do not modify
+ /// the contents of this method with the code editor.
+ ///
+ private void InitializeComponent()
+ {
+ this.components = new System.ComponentModel.Container();
+ System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(MainForm));
+ this.statusLabel = new System.Windows.Forms.Label();
+ this.backgroundPictureBox = new System.Windows.Forms.PictureBox();
+ this.trayIcon = new System.Windows.Forms.NotifyIcon(this.components);
+ this.versionLabel = new System.Windows.Forms.LinkLabel();
+ this.label1 = new System.Windows.Forms.Label();
+ this.SettingsLabel = new System.Windows.Forms.LinkLabel();
+ this.pictureBox1 = new System.Windows.Forms.PictureBox();
+ this.linkLabel1 = new System.Windows.Forms.LinkLabel();
+ ((System.ComponentModel.ISupportInitialize)(this.backgroundPictureBox)).BeginInit();
+ ((System.ComponentModel.ISupportInitialize)(this.pictureBox1)).BeginInit();
+ this.SuspendLayout();
+ //
+ // statusLabel
+ //
+ this.statusLabel.BackColor = System.Drawing.SystemColors.Window;
+ this.statusLabel.Font = new System.Drawing.Font("Consolas", 12F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
+ this.statusLabel.Location = new System.Drawing.Point(11, 30);
+ this.statusLabel.Name = "statusLabel";
+ this.statusLabel.Size = new System.Drawing.Size(364, 23);
+ this.statusLabel.TabIndex = 1;
+ this.statusLabel.Text = "loading...";
+ //
+ // backgroundPictureBox
+ //
+ this.backgroundPictureBox.BackColor = System.Drawing.Color.White;
+ this.backgroundPictureBox.Cursor = System.Windows.Forms.Cursors.Hand;
+ this.backgroundPictureBox.Image = global::Microsoft.MicroBit.Properties.Resources.MSFT_logo_png;
+ this.backgroundPictureBox.InitialImage = null;
+ this.backgroundPictureBox.Location = new System.Drawing.Point(226, 91);
+ this.backgroundPictureBox.Name = "backgroundPictureBox";
+ this.backgroundPictureBox.Size = new System.Drawing.Size(149, 52);
+ this.backgroundPictureBox.SizeMode = System.Windows.Forms.PictureBoxSizeMode.Zoom;
+ this.backgroundPictureBox.TabIndex = 0;
+ this.backgroundPictureBox.TabStop = false;
+ this.backgroundPictureBox.Click += new System.EventHandler(this.backgroundPictureBox_Click);
+ //
+ // trayIcon
+ //
+ this.trayIcon.Icon = ((System.Drawing.Icon)(resources.GetObject("trayIcon.Icon")));
+ this.trayIcon.Visible = true;
+ this.trayIcon.Click += new System.EventHandler(this.trayIcon_Click);
+ //
+ // versionLabel
+ //
+ this.versionLabel.AutoSize = true;
+ this.versionLabel.Location = new System.Drawing.Point(12, 121);
+ this.versionLabel.Name = "versionLabel";
+ this.versionLabel.Size = new System.Drawing.Size(28, 13);
+ this.versionLabel.TabIndex = 2;
+ this.versionLabel.TabStop = true;
+ this.versionLabel.Text = "v0.9";
+ this.versionLabel.LinkClicked += new System.Windows.Forms.LinkLabelLinkClickedEventHandler(this.versionLabel_LinkClicked);
+ //
+ // label1
+ //
+ this.label1.AutoSize = true;
+ this.label1.Font = new System.Drawing.Font("Microsoft Sans Serif", 9F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
+ this.label1.Location = new System.Drawing.Point(12, 103);
+ this.label1.Name = "label1";
+ this.label1.Size = new System.Drawing.Size(169, 15);
+ this.label1.TabIndex = 3;
+ this.label1.Text = "Automatic upload of .hex files.";
+ //
+ // SettingsLabel
+ //
+ this.SettingsLabel.AutoSize = true;
+ this.SettingsLabel.Location = new System.Drawing.Point(151, 121);
+ this.SettingsLabel.Name = "SettingsLabel";
+ this.SettingsLabel.Size = new System.Drawing.Size(43, 13);
+ this.SettingsLabel.TabIndex = 4;
+ this.SettingsLabel.TabStop = true;
+ this.SettingsLabel.Text = "settings";
+ this.SettingsLabel.LinkClicked += new System.Windows.Forms.LinkLabelLinkClickedEventHandler(this.SettingsLabel_LinkClicked);
+ //
+ // pictureBox1
+ //
+ this.pictureBox1.BackColor = System.Drawing.Color.White;
+ this.pictureBox1.Cursor = System.Windows.Forms.Cursors.Hand;
+ this.pictureBox1.Image = global::Microsoft.MicroBit.Properties.Resources.microbit_red;
+ this.pictureBox1.InitialImage = null;
+ this.pictureBox1.Location = new System.Drawing.Point(226, 6);
+ this.pictureBox1.Name = "pictureBox1";
+ this.pictureBox1.Size = new System.Drawing.Size(149, 79);
+ this.pictureBox1.SizeMode = System.Windows.Forms.PictureBoxSizeMode.Zoom;
+ this.pictureBox1.TabIndex = 5;
+ this.pictureBox1.TabStop = false;
+ //
+ // linkLabel1
+ //
+ this.linkLabel1.AutoSize = true;
+ this.linkLabel1.Location = new System.Drawing.Point(62, 121);
+ this.linkLabel1.Name = "linkLabel1";
+ this.linkLabel1.Size = new System.Drawing.Size(60, 13);
+ this.linkLabel1.TabIndex = 6;
+ this.linkLabel1.TabStop = true;
+ this.linkLabel1.Text = "open editor";
+ this.linkLabel1.LinkClicked += new System.Windows.Forms.LinkLabelLinkClickedEventHandler(this.linkLabel1_LinkClicked);
+ //
+ // MainForm
+ //
+ this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
+ this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
+ this.BackColor = System.Drawing.Color.White;
+ this.ClientSize = new System.Drawing.Size(388, 143);
+ this.Controls.Add(this.linkLabel1);
+ this.Controls.Add(this.pictureBox1);
+ this.Controls.Add(this.SettingsLabel);
+ this.Controls.Add(this.label1);
+ this.Controls.Add(this.versionLabel);
+ this.Controls.Add(this.statusLabel);
+ this.Controls.Add(this.backgroundPictureBox);
+ this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedSingle;
+ this.Icon = ((System.Drawing.Icon)(resources.GetObject("$this.Icon")));
+ this.MaximizeBox = false;
+ this.Name = "MainForm";
+ this.ShowInTaskbar = false;
+ this.SizeGripStyle = System.Windows.Forms.SizeGripStyle.Hide;
+ this.StartPosition = System.Windows.Forms.FormStartPosition.CenterScreen;
+ this.Text = "code the micro:bit uploader";
+ this.Load += new System.EventHandler(this.MainForm_Load);
+ ((System.ComponentModel.ISupportInitialize)(this.backgroundPictureBox)).EndInit();
+ ((System.ComponentModel.ISupportInitialize)(this.pictureBox1)).EndInit();
+ this.ResumeLayout(false);
+ this.PerformLayout();
+
+ }
+
+ #endregion
+
+ private System.Windows.Forms.PictureBox backgroundPictureBox;
+ private System.Windows.Forms.Label statusLabel;
+ private System.Windows.Forms.NotifyIcon trayIcon;
+ private System.Windows.Forms.LinkLabel versionLabel;
+ private System.Windows.Forms.Label label1;
+ private System.Windows.Forms.LinkLabel SettingsLabel;
+ private System.Windows.Forms.PictureBox pictureBox1;
+ private System.Windows.Forms.LinkLabel linkLabel1;
+ }
+}
+
diff --git a/clients/winuploader/Microbit.Uploader/MainForm.cs b/clients/winuploader/Microbit.Uploader/MainForm.cs
new file mode 100644
index 00000000..2800bda3
--- /dev/null
+++ b/clients/winuploader/Microbit.Uploader/MainForm.cs
@@ -0,0 +1,266 @@
+using Microsoft.Win32;
+using System;
+using System.Collections.Generic;
+using System.Diagnostics;
+using System.Drawing;
+using System.IO;
+using System.Security;
+using System.Threading;
+using System.Windows.Forms;
+
+namespace Microsoft.MicroBit
+{
+ internal partial class MainForm : Form
+ {
+ FileSystemWatcher watcher;
+ private string customcopypath = "";
+
+ public MainForm()
+ {
+ InitializeComponent();
+ var v = typeof(MainForm).Assembly.GetName().Version;
+ this.versionLabel.Text = "v" + v.Major + "." + v.Minor;
+ }
+
+ private void MainForm_Load(object sender, EventArgs e)
+ {
+ this.initializeFileWatch();
+ customcopypath = (string)Application.UserAppDataRegistry.GetValue("CustomDirectory", "");
+ this.openEditor();
+ }
+
+ private void openEditor()
+ {
+ // lanch editor
+ try { Process.Start("https://codethemicrobit.com"); } catch (Exception) { }
+ }
+
+ private void initializeFileWatch()
+ {
+ if (!checkTOU()) return;
+
+ var downloads = KnownFoldersNativeMethods.GetDownloadPath();
+ if (downloads == null)
+ {
+ this.updateStatus("oops, can't find the `Downloads` folder");
+ return;
+ }
+
+ this.watcher = new FileSystemWatcher(downloads);
+ this.watcher.Renamed += (sender, e) => this.handleFileEvent(e);
+ this.watcher.Created += (sender, e) => this.handleFileEvent(e);
+ this.watcher.EnableRaisingEvents = true;
+
+ this.waitingForHexFileStatus();
+ }
+
+ private void waitingForHexFileStatus()
+ {
+ this.updateStatus("waiting for .hex file...");
+ this.trayIcon.ShowBalloonTip(3000, "ready...", "waiting for .hex file...", ToolTipIcon.None);
+ }
+
+ static bool checkTOU()
+ {
+ var v = (int)Application.UserAppDataRegistry.GetValue("TermOfUse", 0);
+ if (v != 1)
+ {
+ using (var f = new LicenseDialog())
+ {
+ var r = f.ShowDialog();
+ if (r != DialogResult.Yes)
+ {
+ Application.Exit();
+ return false;
+ }
+ }
+ Application.UserAppDataRegistry.SetValue("TermOfUse", 1, RegistryValueKind.DWord);
+ }
+
+ return true;
+ }
+
+ delegate void Callback();
+
+ private void updateStatus(string value)
+ {
+ Callback a = (Callback)(() =>
+ {
+ this.statusLabel.Text = value;
+ this.trayIcon.Text = value;
+ });
+ this.Invoke(a);
+ }
+
+ void handleFileEvent(FileSystemEventArgs e)
+ {
+ this.handleFile(e.FullPath);
+ }
+
+ volatile int copying;
+ void handleFile(string fullPath)
+ {
+ try
+ {
+ // In case this is data-url download, at least Chrome will not rename file, but instead write to it
+ // directly. This mean we may catch it in the act. Let's leave it some time to finish writing.
+ Thread.Sleep(500);
+
+ var info = new System.IO.FileInfo(fullPath);
+ Trace.WriteLine("download: " + info.FullName);
+
+ if (info.Extension != ".hex") return;
+
+ var infoName = info.Name;
+ Trace.WriteLine("download name: " + info.Name);
+ if (!infoName.StartsWith("microbit-", StringComparison.OrdinalIgnoreCase)) return;
+ if (info.Name.EndsWith(".uploaded.hex", StringComparison.OrdinalIgnoreCase)) return;
+ if (info.Length > 1000000) return; // make sure we don't try to copy large files
+
+
+ // already copying?
+ if (Interlocked.Exchange(ref this.copying, 1) == 1)
+ return;
+
+ try
+ {
+
+ var driveletters = getMicrobitDrives();
+ List drives = new List();
+ foreach (var d in driveletters)
+ {
+ drives.Add(d.RootDirectory.FullName);
+ }
+ if (!String.IsNullOrEmpty(customcopypath) && Directory.Exists(customcopypath))
+ {
+ drives.Add(customcopypath);
+ }
+ if (drives.Count == 0)
+ {
+ this.updateStatus("no board found");
+ this.trayIcon.ShowBalloonTip(3000, "cancelled uploading...", "no board found", ToolTipIcon.None);
+ return;
+ }
+
+ this.updateStatus("uploading .hex file");
+ this.trayIcon.ShowBalloonTip(3000, "uploading...", "uploading .hex file", ToolTipIcon.None);
+
+ // copy to all boards
+ copyFirmware(info.FullName, drives);
+
+ // move away hex file
+ var temp = System.IO.Path.ChangeExtension(info.FullName, ".uploaded.hex");
+ try
+ {
+ File.Copy(info.FullName, temp, true);
+ File.Delete(info.FullName);
+ }
+ catch (IOException) { }
+ catch (NotSupportedException) { }
+ catch (UnauthorizedAccessException) { }
+ catch (ArgumentException) { }
+
+ // update ui
+ this.updateStatus("uploading done");
+ this.waitingForHexFileStatus();
+ }
+ finally
+ {
+ Interlocked.Exchange(ref this.copying, 0);
+ }
+ }
+ catch (IOException) { }
+ catch (NotSupportedException) { }
+ catch (UnauthorizedAccessException) { }
+ catch (ArgumentException) { }
+ }
+
+ static void copyFirmware(string file, List drives)
+ {
+ var waitHandles = new List();
+ foreach (var drive in drives)
+ {
+ var ev = new AutoResetEvent(false);
+ waitHandles.Add(ev);
+ ThreadPool.QueueUserWorkItem((state) =>
+ {
+ try
+ {
+ var trg = System.IO.Path.Combine(drive, "firmware.hex");
+ File.Copy(file, trg, true);
+ }
+ catch (IOException) { }
+ catch (NotSupportedException) { }
+ catch (UnauthorizedAccessException) { }
+ catch (ArgumentException) { }
+ ev.Set();
+ }, ev);
+ }
+
+ //waits for all the threads (waitHandles) to call the .Set() method
+ //and inform that the execution has finished.
+ WaitHandle.WaitAll(waitHandles.ToArray());
+ }
+
+ static DriveInfo[] getMicrobitDrives()
+ {
+ var drives = System.IO.DriveInfo.GetDrives();
+ var r = new System.Collections.Generic.List();
+ foreach (var di in drives)
+ {
+ var label = getVolumeLabel(di);
+ if (label.StartsWith("MICROBIT", StringComparison.Ordinal))
+ r.Add(di);
+ }
+ return r.ToArray();
+ }
+
+ static string getVolumeLabel(DriveInfo di)
+ {
+ try { return di.VolumeLabel; }
+ catch (IOException) { }
+ catch (SecurityException) { }
+ catch (UnauthorizedAccessException) { }
+ return "";
+ }
+
+ private void trayIcon_Click(object sender, EventArgs e)
+ {
+ this.WindowState = FormWindowState.Minimized;
+ this.WindowState = FormWindowState.Normal;
+ this.Show();
+ this.Activate();
+ }
+
+ private void versionLabel_LinkClicked(object sender, LinkLabelLinkClickedEventArgs e)
+ {
+ try
+ {
+ Process.Start("https://codethemicrobit.com/uploader");
+ }
+ catch (IOException) { }
+ }
+
+ private void backgroundPictureBox_Click(object sender, EventArgs e)
+ {
+ try
+ {
+ Process.Start("https://codethemicrobit.com");
+ }
+ catch (IOException) { }
+ }
+
+ private void SettingsLabel_LinkClicked(object sender, LinkLabelLinkClickedEventArgs e)
+ {
+ var settings = new Settings(customcopypath);
+ settings.ShowDialog();
+ customcopypath = settings.CustomCopyPath;
+ Application.UserAppDataRegistry.SetValue("CustomDirectory", customcopypath, RegistryValueKind.String);
+ }
+
+ private void linkLabel1_LinkClicked(object sender, LinkLabelLinkClickedEventArgs e)
+ {
+ this.openEditor();
+ }
+ }
+}
diff --git a/clients/winuploader/Microbit.Uploader/MainForm.resx b/clients/winuploader/Microbit.Uploader/MainForm.resx
new file mode 100644
index 00000000..6a64aeb4
--- /dev/null
+++ b/clients/winuploader/Microbit.Uploader/MainForm.resx
@@ -0,0 +1,172 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ text/microsoft-resx
+
+
+ 2.0
+
+
+ System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+
+
+ System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+
+
+ 17, 17
+
+
+
+
+ AAABAAEAEBAAAAAAIABoBAAAFgAAACgAAAAQAAAAIAAAAAEAIAAAAAAAAAQAAMIOAADCDgAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAN6bIZTOkxoUtj62FL5W1hTWpzYUvlbWFLY+thTKgwoUxnb+FLY6shS6TsoUzpMaFL5a1hS2P
+ rYUxnb6FNZ2+ZTCTsvkriaf/KYKe/yuIpf8uk7L/K4il/ymBnP8tjqz/K4qn/yiBnP8qhaL/KoWh/yqG
+ o/8ogJv/JXeQ/yqDnvkRMjz/Di02/wofJv8MJS3/Di02/wskLP8HGB3/Di43/w0qM/8HFxz/CyMr/w4s
+ Nv8MJi7/CiAm/w4sNv8RMTv/BQsN/wUQE/8BAgL/AQQF/wYRFP8EBgf/AgIA/xAYJv8TGy3/AgIA/wMF
+ Bv8HEhX/AQUG/wECAv8FEBT/BQsN/wYFD/8LByT/AQAC/wAAAP8CAgL/AwMD/woKEv8LCxT/DAwY/woK
+ Ev8DAwT/AgIC/wAAAP8AAAD/AAAA/wICAv8JCA//IBs//wwMEP8AAAD/AgIC/wQEBv8bGzf/BgYK/wQE
+ Bf8bGzj/BgYJ/wMDA/8AAAD/CgoK/xEREf8HBwf/Li4u/1FRUf9ERET/AQEA/wwMGf8UFCj/BAQE/wMD
+ Av8DAwL/BAQE/xAQIP8RESL/AAAA/z8/P/9SUlH/NTU1/y4uLv9QUFD/QUFB/wEBAP8LCxf/EhIk/wIC
+ Af8JCRH/CwsV/wICAf8PDx3/Dw8f/wAAAP89PT3/UVFQ/zQ0M/8FBQX/DAwM/wgICP8AAAD/CwsW/xIS
+ JP8FBQb/Dg4b/xERIv8FBQb/Dw8d/w8PHv8AAAD/CAgK/xwXO/8KCRT/BAMI/wAAAP8AAAD/AAAA/wIC
+ Av8EBAX/HR06/wgIEP8GBgv/HR07/wYGCf8DAwL/AAAA/wAAAP8JBh3/BwUS/y0fhf8FBBD/AAAA/wAA
+ AP8AAAD/AAAA/xIOMv8fFVz/HhVa/xQPOP8AAQD/AAAA/wAAAP8AAAD/AAAA/wICAv9UO/v/MiKX/wUD
+ D/8FAw7/AwIK/wAAAP8RCzP/IBZi/yAWYP8TDTr/AAAA/wAAAP8AAAD/AAAA/wAAAP8CAgL/VTz/+FQ6
+ /P8yI5j/IBZg/ywehf8MCCX/BAMN/wUEEP8GBBH/AQED/wAAAP8AAAD/AAAA/wAAAP8AAAD/AgIC9Vc+
+ /2BVOv9+Ujj0fTwptH5ONul9OCapfRUOPn4AAAB+AAAAfQAAAH4AAAB+AAAAfQAAAH4AAAB+AAAAfgQE
+ BFkAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAA//8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAA//8AAA==
+
+
+
+
+ AAABAAEAEBAAAAAAIABoBAAAFgAAACgAAAAQAAAAIAAAAAEAIAAAAAAAAAQAAMIOAADCDgAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAN6bIZTOkxoUtj62FL5W1hTWpzYUvlbWFLY+thTKgwoUxnb+FLY6shS6TsoUzpMaFL5a1hS2P
+ rYUxnb6FNZ2+ZTCTsvkriaf/KYKe/yuIpf8uk7L/K4il/ymBnP8tjqz/K4qn/yiBnP8qhaL/KoWh/yqG
+ o/8ogJv/JXeQ/yqDnvkRMjz/Di02/wofJv8MJS3/Di02/wskLP8HGB3/Di43/w0qM/8HFxz/CyMr/w4s
+ Nv8MJi7/CiAm/w4sNv8RMTv/BQsN/wUQE/8BAgL/AQQF/wYRFP8EBgf/AgIA/xAYJv8TGy3/AgIA/wMF
+ Bv8HEhX/AQUG/wECAv8FEBT/BQsN/wYFD/8LByT/AQAC/wAAAP8CAgL/AwMD/woKEv8LCxT/DAwY/woK
+ Ev8DAwT/AgIC/wAAAP8AAAD/AAAA/wICAv8JCA//IBs//wwMEP8AAAD/AgIC/wQEBv8bGzf/BgYK/wQE
+ Bf8bGzj/BgYJ/wMDA/8AAAD/CgoK/xEREf8HBwf/Li4u/1FRUf9ERET/AQEA/wwMGf8UFCj/BAQE/wMD
+ Av8DAwL/BAQE/xAQIP8RESL/AAAA/z8/P/9SUlH/NTU1/y4uLv9QUFD/QUFB/wEBAP8LCxf/EhIk/wIC
+ Af8JCRH/CwsV/wICAf8PDx3/Dw8f/wAAAP89PT3/UVFQ/zQ0M/8FBQX/DAwM/wgICP8AAAD/CwsW/xIS
+ JP8FBQb/Dg4b/xERIv8FBQb/Dw8d/w8PHv8AAAD/CAgK/xwXO/8KCRT/BAMI/wAAAP8AAAD/AAAA/wIC
+ Av8EBAX/HR06/wgIEP8GBgv/HR07/wYGCf8DAwL/AAAA/wAAAP8JBh3/BwUS/y0fhf8FBBD/AAAA/wAA
+ AP8AAAD/AAAA/xIOMv8fFVz/HhVa/xQPOP8AAQD/AAAA/wAAAP8AAAD/AAAA/wICAv9UO/v/MiKX/wUD
+ D/8FAw7/AwIK/wAAAP8RCzP/IBZi/yAWYP8TDTr/AAAA/wAAAP8AAAD/AAAA/wAAAP8CAgL/VTz/+FQ6
+ /P8yI5j/IBZg/ywehf8MCCX/BAMN/wUEEP8GBBH/AQED/wAAAP8AAAD/AAAA/wAAAP8AAAD/AgIC9Vc+
+ /2BVOv9+Ujj0fTwptH5ONul9OCapfRUOPn4AAAB+AAAAfQAAAH4AAAB+AAAAfQAAAH4AAAB+AAAAfgQE
+ BFkAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAA//8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAA//8AAA==
+
+
+
\ No newline at end of file
diff --git a/clients/winuploader/Microbit.Uploader/Program.cs b/clients/winuploader/Microbit.Uploader/Program.cs
new file mode 100644
index 00000000..8c8cc288
--- /dev/null
+++ b/clients/winuploader/Microbit.Uploader/Program.cs
@@ -0,0 +1,30 @@
+using Microsoft.VisualBasic.ApplicationServices;
+using System;
+using System.Windows.Forms;
+
+namespace Microsoft.MicroBit
+{
+ static class Program
+ {
+ ///
+ /// The main entry point for the application.
+ ///
+ [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Reliability", "CA2000:Dispose objects before losing scope")]
+ [STAThread]
+ static void Main()
+ {
+ Application.EnableVisualStyles();
+ Application.SetCompatibleTextRenderingDefault(false);
+ SingleInstanceAppStarter.Start(new MainForm(), StartNewInstance);
+ }
+
+ // The handler when attempting to start another instance of this application
+ // We can customize the logic here for which form to activate in different
+ // conditions. Like in this sample, we will be selectively activate the LoginForm
+ // or MainForm based on the login state of the user.
+ static void StartNewInstance(object sender, StartupNextInstanceEventArgs e)
+ {
+ e.BringToForeground = true;
+ }
+ }
+}
diff --git a/clients/winuploader/Microbit.Uploader/Properties/AssemblyInfo.cs b/clients/winuploader/Microbit.Uploader/Properties/AssemblyInfo.cs
new file mode 100644
index 00000000..ef356c48
--- /dev/null
+++ b/clients/winuploader/Microbit.Uploader/Properties/AssemblyInfo.cs
@@ -0,0 +1,40 @@
+using System;
+using System.Reflection;
+using System.Resources;
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+
+// General Information about an assembly is controlled through the following
+// set of attributes. Change these attribute values to modify the information
+// associated with an assembly.
+[assembly: AssemblyTitle("Code The micro:bit Uploader")]
+[assembly: AssemblyDescription("")]
+[assembly: AssemblyConfiguration("")]
+[assembly: AssemblyCompany("Microsoft")]
+[assembly: AssemblyProduct("MicrosoftMicrobitUploader")]
+[assembly: AssemblyCopyright("Copyright © Microsoft 2016")]
+[assembly: AssemblyTrademark("")]
+[assembly: AssemblyCulture("")]
+
+// Setting ComVisible to false makes the types in this assembly not visible
+// to COM components. If you need to access a type in this assembly from
+// COM, set the ComVisible attribute to true on that type.
+[assembly: ComVisible(false)]
+
+// The following GUID is for the ID of the typelib if this project is exposed to COM
+[assembly: Guid("7dc6ca45-fd75-44bc-805e-708c812cd4bf")]
+
+// Version information for an assembly consists of the following four values:
+//
+// Major Version
+// Minor Version
+// Build Number
+// Revision
+//
+// You can specify all the values or you can default the Build and Revision Numbers
+// by using the '*' as shown below:
+// [assembly: AssemblyVersion("1.0.*")]
+[assembly: AssemblyVersion("0.9.0.0")]
+[assembly: AssemblyFileVersion("0.9.0.0")]
+[assembly: CLSCompliant(true)]
+[assembly: NeutralResourcesLanguage("en-US")]
\ No newline at end of file
diff --git a/clients/winuploader/Microbit.Uploader/Properties/Resources.Designer.cs b/clients/winuploader/Microbit.Uploader/Properties/Resources.Designer.cs
new file mode 100644
index 00000000..356a30a3
--- /dev/null
+++ b/clients/winuploader/Microbit.Uploader/Properties/Resources.Designer.cs
@@ -0,0 +1,93 @@
+//------------------------------------------------------------------------------
+//
+// This code was generated by a tool.
+// Runtime Version:4.0.30319.42000
+//
+// Changes to this file may cause incorrect behavior and will be lost if
+// the code is regenerated.
+//
+//------------------------------------------------------------------------------
+
+namespace Microsoft.MicroBit.Properties {
+ using System;
+
+
+ ///
+ /// A strongly-typed resource class, for looking up localized strings, etc.
+ ///
+ // This class was auto-generated by the StronglyTypedResourceBuilder
+ // class via a tool like ResGen or Visual Studio.
+ // To add or remove a member, edit your .ResX file then rerun ResGen
+ // with the /str option, or rebuild your VS project.
+ [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")]
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
+ [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
+ internal class Resources {
+
+ private static global::System.Resources.ResourceManager resourceMan;
+
+ private static global::System.Globalization.CultureInfo resourceCulture;
+
+ [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
+ internal Resources() {
+ }
+
+ ///
+ /// Returns the cached ResourceManager instance used by this class.
+ ///
+ [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
+ internal static global::System.Resources.ResourceManager ResourceManager {
+ get {
+ if (object.ReferenceEquals(resourceMan, null)) {
+ global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("Microsoft.MicroBit.Properties.Resources", typeof(Resources).Assembly);
+ resourceMan = temp;
+ }
+ return resourceMan;
+ }
+ }
+
+ ///
+ /// Overrides the current thread's CurrentUICulture property for all
+ /// resource lookups using this strongly typed resource class.
+ ///
+ [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
+ internal static global::System.Globalization.CultureInfo Culture {
+ get {
+ return resourceCulture;
+ }
+ set {
+ resourceCulture = value;
+ }
+ }
+
+ ///
+ /// Looks up a localized resource of type System.Drawing.Bitmap.
+ ///
+ internal static System.Drawing.Bitmap microbit_red {
+ get {
+ object obj = ResourceManager.GetObject("microbit_red", resourceCulture);
+ return ((System.Drawing.Bitmap)(obj));
+ }
+ }
+
+ ///
+ /// Looks up a localized resource of type System.Drawing.Bitmap.
+ ///
+ internal static System.Drawing.Bitmap MSFT_logo_png {
+ get {
+ object obj = ResourceManager.GetObject("MSFT_logo_png", resourceCulture);
+ return ((System.Drawing.Bitmap)(obj));
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to {\rtf1\adeflang1025\ansi\ansicpg1252\uc1\adeff0\deff0\stshfdbch0\stshfloch0\stshfhich0\stshfbi0\deflang1033\deflangfe1033\themelang1033\themelangfe0\themelangcs0{\fonttbl{\f0\fbidi \froman\fcharset0\fprq2{\*\panose 02020603050405020304}Times New Roman;}{\f1\fbidi \fswiss\fcharset0\fprq2{\*\panose 020b0604020202020204}Arial;}
+ ///{\f2\fbidi \fmodern\fcharset0\fprq1{\*\panose 02070309020205020404}Courier New;}{\f3\fbidi \froman\fcharset2\fprq2{\*\panose 05050102010706020507}Symbol;}{\f10\fbidi \fnil\fcharset2\fp [rest of string was truncated]";.
+ ///
+ internal static string MSR_LA___2576 {
+ get {
+ return ResourceManager.GetString("MSR_LA___2576", resourceCulture);
+ }
+ }
+ }
+}
diff --git a/clients/winuploader/Microbit.Uploader/Properties/Resources.resx b/clients/winuploader/Microbit.Uploader/Properties/Resources.resx
new file mode 100644
index 00000000..b9194340
--- /dev/null
+++ b/clients/winuploader/Microbit.Uploader/Properties/Resources.resx
@@ -0,0 +1,130 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ text/microsoft-resx
+
+
+ 2.0
+
+
+ System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+
+
+ System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+
+
+
+ ..\Resources\MSR-LA - 2576.rtf;System.String, mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+
+
+ ..\MSFT_logo_png.png;System.Drawing.Bitmap, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a
+
+
+ ..\microbit.red.png;System.Drawing.Bitmap, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a
+
+
\ No newline at end of file
diff --git a/clients/winuploader/Microbit.Uploader/Resources/MSR-LA - 2576.rtf b/clients/winuploader/Microbit.Uploader/Resources/MSR-LA - 2576.rtf
new file mode 100644
index 00000000..2fd9f957
--- /dev/null
+++ b/clients/winuploader/Microbit.Uploader/Resources/MSR-LA - 2576.rtf
@@ -0,0 +1 @@
+TBD
\ No newline at end of file
diff --git a/clients/winuploader/Microbit.Uploader/Settings.Designer.cs b/clients/winuploader/Microbit.Uploader/Settings.Designer.cs
new file mode 100644
index 00000000..04615446
--- /dev/null
+++ b/clients/winuploader/Microbit.Uploader/Settings.Designer.cs
@@ -0,0 +1,76 @@
+namespace Microsoft.MicroBit
+{
+ partial class Settings
+ {
+ ///
+ /// Required designer variable.
+ ///
+ private System.ComponentModel.IContainer components = null;
+
+ ///
+ /// Clean up any resources being used.
+ ///
+ /// true if managed resources should be disposed; otherwise, false.
+ protected override void Dispose(bool disposing)
+ {
+ if (disposing && (components != null))
+ {
+ components.Dispose();
+ }
+ base.Dispose(disposing);
+ }
+
+ #region Windows Form Designer generated code
+
+ ///
+ /// Required method for Designer support - do not modify
+ /// the contents of this method with the code editor.
+ ///
+ private void InitializeComponent()
+ {
+ this.textBox1 = new System.Windows.Forms.TextBox();
+ this.label1 = new System.Windows.Forms.Label();
+ this.SuspendLayout();
+ //
+ // textBox1
+ //
+ this.textBox1.Location = new System.Drawing.Point(107, 12);
+ this.textBox1.Name = "textBox1";
+ this.textBox1.Size = new System.Drawing.Size(100, 20);
+ this.textBox1.TabIndex = 0;
+ this.textBox1.TextChanged += new System.EventHandler(this.textBox1_TextChanged);
+ //
+ // label1
+ //
+ this.label1.AutoSize = true;
+ this.label1.Location = new System.Drawing.Point(34, 15);
+ this.label1.Name = "label1";
+ this.label1.Size = new System.Drawing.Size(67, 13);
+ this.label1.TabIndex = 1;
+ this.label1.Text = "Custom Path";
+ //
+ // Settings
+ //
+ this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
+ this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
+ this.ClientSize = new System.Drawing.Size(246, 48);
+ this.Controls.Add(this.label1);
+ this.Controls.Add(this.textBox1);
+ this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedDialog;
+ this.MaximizeBox = false;
+ this.MinimizeBox = false;
+ this.Name = "Settings";
+ this.ShowIcon = false;
+ this.Text = "Settings";
+ this.Load += new System.EventHandler(this.Settings_Load);
+ this.ResumeLayout(false);
+ this.PerformLayout();
+
+ }
+
+ #endregion
+
+ private System.Windows.Forms.TextBox textBox1;
+ private System.Windows.Forms.Label label1;
+ }
+}
\ No newline at end of file
diff --git a/clients/winuploader/Microbit.Uploader/Settings.cs b/clients/winuploader/Microbit.Uploader/Settings.cs
new file mode 100644
index 00000000..e2a4f3a4
--- /dev/null
+++ b/clients/winuploader/Microbit.Uploader/Settings.cs
@@ -0,0 +1,37 @@
+using System;
+using System.Collections.Generic;
+using System.ComponentModel;
+using System.Data;
+using System.Drawing;
+using System.Security.AccessControl;
+using System.Text;
+using System.Windows.Forms;
+
+namespace Microsoft.MicroBit
+{
+ public partial class Settings : Form
+ {
+ public string CustomCopyPath;
+ public Settings(string currentpath)
+ {
+ InitializeComponent();
+ CustomCopyPath = currentpath;
+
+ }
+
+ private void Settings_Load(object sender, EventArgs e)
+ {
+ textBox1.Text = CustomCopyPath;
+ }
+
+ private void label1_Click(object sender, EventArgs e)
+ {
+
+ }
+
+ private void textBox1_TextChanged(object sender, EventArgs e)
+ {
+ CustomCopyPath = textBox1.Text;
+ }
+ }
+}
diff --git a/clients/winuploader/Microbit.Uploader/Settings.resx b/clients/winuploader/Microbit.Uploader/Settings.resx
new file mode 100644
index 00000000..7080a7d1
--- /dev/null
+++ b/clients/winuploader/Microbit.Uploader/Settings.resx
@@ -0,0 +1,120 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ text/microsoft-resx
+
+
+ 2.0
+
+
+ System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+
+
+ System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+
+
\ No newline at end of file
diff --git a/clients/winuploader/Microbit.Uploader/SingleInstanceAppHelper.cs b/clients/winuploader/Microbit.Uploader/SingleInstanceAppHelper.cs
new file mode 100644
index 00000000..e57d20d2
--- /dev/null
+++ b/clients/winuploader/Microbit.Uploader/SingleInstanceAppHelper.cs
@@ -0,0 +1,39 @@
+/****************************** Module Header ******************************\
+* Module Name: SingleInstanceAppHelper.cs
+* Project: CSWinFormSingleInstanceApp
+* Copyright (c) Microsoft Corporation.
+*
+* The sample demonstrates how to achieve the goal that only
+* one instance of the application is allowed in Windows Forms application..
+*
+* This source is subject to the Microsoft Public License.
+* See http://www.microsoft.com/en-us/openness/resources/licenses.aspx#MPL.
+* All other rights reserved.
+*
+* THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND,
+* EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED
+* WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR PURPOSE.
+\***************************************************************************/
+
+using System;
+using Microsoft.VisualBasic.ApplicationServices;
+using System.Windows.Forms;
+
+namespace Microsoft.MicroBit
+{
+ // We need to add Microsoft.VisualBasic reference to use
+ // WindowsFormsApplicationBase type.
+ class SingleInstanceApp : WindowsFormsApplicationBase
+ {
+ public SingleInstanceApp()
+ {
+ }
+ public SingleInstanceApp(Form f)
+ {
+ // Set IsSingleInstance property to true to make the application
+ base.IsSingleInstance = true;
+ // Set MainForm of the application.
+ this.MainForm = f;
+ }
+ }
+}
diff --git a/clients/winuploader/Microbit.Uploader/SingleInstanceAppStarter.cs b/clients/winuploader/Microbit.Uploader/SingleInstanceAppStarter.cs
new file mode 100644
index 00000000..f3b9b6bb
--- /dev/null
+++ b/clients/winuploader/Microbit.Uploader/SingleInstanceAppStarter.cs
@@ -0,0 +1,39 @@
+/****************************** Module Header ******************************\
+* Module Name: SingleInstanceAppStarter.cs
+* Project: CSWinFormSingleInstanceApp
+* Copyright (c) Microsoft Corporation.
+*
+* The sample demonstrates how to achieve the goal that only
+* one instance of the application is allowed in Windows Forms application..
+*
+* This source is subject to the Microsoft Public License.
+* See http://www.microsoft.com/en-us/openness/resources/licenses.aspx#MPL.
+* All other rights reserved.
+*
+* THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND,
+* EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED
+* WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR PURPOSE.
+\***************************************************************************/
+
+using System;
+using System.Windows.Forms;
+using Microsoft.VisualBasic.ApplicationServices;
+
+namespace Microsoft.MicroBit
+{
+ internal static class SingleInstanceAppStarter
+ {
+ static SingleInstanceApp app = null;
+
+ // Construct SingleInstanceApp object, and invoke its run method.
+ public static void Start(Form f, StartupNextInstanceEventHandler handler)
+ {
+ if (app == null && f != null)
+ app = new SingleInstanceApp(f);
+
+ // Wire up StartupNextInstance event handler.
+ app.StartupNextInstance += handler;
+ app.Run(Environment.GetCommandLineArgs());
+ }
+ }
+}
diff --git a/clients/winuploader/Microbit.Uploader/favicon.ico b/clients/winuploader/Microbit.Uploader/favicon.ico
new file mode 100644
index 00000000..f4f666c8
Binary files /dev/null and b/clients/winuploader/Microbit.Uploader/favicon.ico differ
diff --git a/clients/winuploader/Microbit.Uploader/microbit.red.png b/clients/winuploader/Microbit.Uploader/microbit.red.png
new file mode 100644
index 00000000..9b2a5efa
Binary files /dev/null and b/clients/winuploader/Microbit.Uploader/microbit.red.png differ