├── .gitignore
├── README.md
├── VisualStudioHelpDownloader2012
├── Docs
│ └── screenshot.JPG
├── VisualStudioHelpDownloader.sln
├── VisualStudioHelpDownloader.vssscc
└── VisualStudioHelpDownloader2012
│ ├── AuthenticodeTools.cs
│ ├── Book.cs
│ ├── BookGroup.cs
│ ├── Downloader.cs
│ ├── Extensions.cs
│ ├── HelpIndexManager.cs
│ ├── ItemBase.cs
│ ├── Locale.cs
│ ├── MainForm.Designer.cs
│ ├── MainForm.cs
│ ├── MainForm.resx
│ ├── Package.cs
│ ├── Program.cs
│ ├── Properties
│ ├── App.ico
│ ├── App.manifest
│ ├── AssemblyInfo.cs
│ └── Default.snk
│ ├── VisualStudioHelpDownloader.csproj
│ ├── VisualStudioHelpDownloader.csproj.vspscc
│ └── app.config
└── docs
├── Home.md
└── Home_screenshot.JPG
/.gitignore:
--------------------------------------------------------------------------------
1 |
2 | # Created by https://www.gitignore.io/api/visualstudio
3 |
4 | ### VisualStudio ###
5 | ## Ignore Visual Studio temporary files, build results, and
6 | ## files generated by popular Visual Studio add-ons.
7 | ##
8 | ## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore
9 |
10 | # User-specific files
11 | *.suo
12 | *.user
13 | *.userosscache
14 | *.sln.docstates
15 |
16 | # User-specific files (MonoDevelop/Xamarin Studio)
17 | *.userprefs
18 |
19 | # Build results
20 | [Dd]ebug/
21 | [Dd]ebugPublic/
22 | [Rr]elease/
23 | [Rr]eleases/
24 | x64/
25 | x86/
26 | bld/
27 | [Bb]in/
28 | [Oo]bj/
29 | [Ll]og/
30 |
31 | # Visual Studio 2015 cache/options directory
32 | .vs/
33 | # Uncomment if you have tasks that create the project's static files in wwwroot
34 | #wwwroot/
35 |
36 | # MSTest test Results
37 | [Tt]est[Rr]esult*/
38 | [Bb]uild[Ll]og.*
39 |
40 | # NUNIT
41 | *.VisualState.xml
42 | TestResult.xml
43 |
44 | # Build Results of an ATL Project
45 | [Dd]ebugPS/
46 | [Rr]eleasePS/
47 | dlldata.c
48 |
49 | # .NET Core
50 | project.lock.json
51 | project.fragment.lock.json
52 | artifacts/
53 | **/Properties/launchSettings.json
54 |
55 | *_i.c
56 | *_p.c
57 | *_i.h
58 | *.ilk
59 | *.meta
60 | *.obj
61 | *.pch
62 | *.pdb
63 | *.pgc
64 | *.pgd
65 | *.rsp
66 | *.sbr
67 | *.tlb
68 | *.tli
69 | *.tlh
70 | *.tmp
71 | *.tmp_proj
72 | *.log
73 | *.vspscc
74 | *.vssscc
75 | .builds
76 | *.pidb
77 | *.svclog
78 | *.scc
79 |
80 | # Chutzpah Test files
81 | _Chutzpah*
82 |
83 | # Visual C++ cache files
84 | ipch/
85 | *.aps
86 | *.ncb
87 | *.opendb
88 | *.opensdf
89 | *.sdf
90 | *.cachefile
91 | *.VC.db
92 | *.VC.VC.opendb
93 |
94 | # Visual Studio profiler
95 | *.psess
96 | *.vsp
97 | *.vspx
98 | *.sap
99 |
100 | # TFS 2012 Local Workspace
101 | $tf/
102 |
103 | # Guidance Automation Toolkit
104 | *.gpState
105 |
106 | # ReSharper is a .NET coding add-in
107 | _ReSharper*/
108 | *.[Rr]e[Ss]harper
109 | *.DotSettings.user
110 |
111 | # JustCode is a .NET coding add-in
112 | .JustCode
113 |
114 | # TeamCity is a build add-in
115 | _TeamCity*
116 |
117 | # DotCover is a Code Coverage Tool
118 | *.dotCover
119 |
120 | # Visual Studio code coverage results
121 | *.coverage
122 | *.coveragexml
123 |
124 | # NCrunch
125 | _NCrunch_*
126 | .*crunch*.local.xml
127 | nCrunchTemp_*
128 |
129 | # MightyMoose
130 | *.mm.*
131 | AutoTest.Net/
132 |
133 | # Web workbench (sass)
134 | .sass-cache/
135 |
136 | # Installshield output folder
137 | [Ee]xpress/
138 |
139 | # DocProject is a documentation generator add-in
140 | DocProject/buildhelp/
141 | DocProject/Help/*.HxT
142 | DocProject/Help/*.HxC
143 | DocProject/Help/*.hhc
144 | DocProject/Help/*.hhk
145 | DocProject/Help/*.hhp
146 | DocProject/Help/Html2
147 | DocProject/Help/html
148 |
149 | # Click-Once directory
150 | publish/
151 |
152 | # Publish Web Output
153 | *.[Pp]ublish.xml
154 | *.azurePubxml
155 | # TODO: Comment the next line if you want to checkin your web deploy settings
156 | # but database connection strings (with potential passwords) will be unencrypted
157 | *.pubxml
158 | *.publishproj
159 |
160 | # Microsoft Azure Web App publish settings. Comment the next line if you want to
161 | # checkin your Azure Web App publish settings, but sensitive information contained
162 | # in these scripts will be unencrypted
163 | PublishScripts/
164 |
165 | # NuGet Packages
166 | *.nupkg
167 | # The packages folder can be ignored because of Package Restore
168 | **/packages/*
169 | # except build/, which is used as an MSBuild target.
170 | !**/packages/build/
171 | # Uncomment if necessary however generally it will be regenerated when needed
172 | #!**/packages/repositories.config
173 | # NuGet v3's project.json files produces more ignorable files
174 | *.nuget.props
175 | *.nuget.targets
176 |
177 | # Microsoft Azure Build Output
178 | csx/
179 | *.build.csdef
180 |
181 | # Microsoft Azure Emulator
182 | ecf/
183 | rcf/
184 |
185 | # Windows Store app package directories and files
186 | AppPackages/
187 | BundleArtifacts/
188 | Package.StoreAssociation.xml
189 | _pkginfo.txt
190 |
191 | # Visual Studio cache files
192 | # files ending in .cache can be ignored
193 | *.[Cc]ache
194 | # but keep track of directories ending in .cache
195 | !*.[Cc]ache/
196 |
197 | # Others
198 | ClientBin/
199 | ~$*
200 | *~
201 | *.dbmdl
202 | *.dbproj.schemaview
203 | *.jfm
204 | *.pfx
205 | *.publishsettings
206 | orleans.codegen.cs
207 |
208 | # Since there are multiple workflows, uncomment next line to ignore bower_components
209 | # (https://github.com/github/gitignore/pull/1529#issuecomment-104372622)
210 | #bower_components/
211 |
212 | # RIA/Silverlight projects
213 | Generated_Code/
214 |
215 | # Backup & report files from converting an old project file
216 | # to a newer Visual Studio version. Backup files are not needed,
217 | # because we have git ;-)
218 | _UpgradeReport_Files/
219 | Backup*/
220 | UpgradeLog*.XML
221 | UpgradeLog*.htm
222 |
223 | # SQL Server files
224 | *.mdf
225 | *.ldf
226 | *.ndf
227 |
228 | # Business Intelligence projects
229 | *.rdl.data
230 | *.bim.layout
231 | *.bim_*.settings
232 |
233 | # Microsoft Fakes
234 | FakesAssemblies/
235 |
236 | # GhostDoc plugin setting file
237 | *.GhostDoc.xml
238 |
239 | # Node.js Tools for Visual Studio
240 | .ntvs_analysis.dat
241 | node_modules/
242 |
243 | # Typescript v1 declaration files
244 | typings/
245 |
246 | # Visual Studio 6 build log
247 | *.plg
248 |
249 | # Visual Studio 6 workspace options file
250 | *.opt
251 |
252 | # Visual Studio 6 auto-generated workspace file (contains which files were open etc.)
253 | *.vbw
254 |
255 | # Visual Studio LightSwitch build output
256 | **/*.HTMLClient/GeneratedArtifacts
257 | **/*.DesktopClient/GeneratedArtifacts
258 | **/*.DesktopClient/ModelManifest.xml
259 | **/*.Server/GeneratedArtifacts
260 | **/*.Server/ModelManifest.xml
261 | _Pvt_Extensions
262 |
263 | # Paket dependency manager
264 | .paket/paket.exe
265 | paket-files/
266 |
267 | # FAKE - F# Make
268 | .fake/
269 |
270 | # JetBrains Rider
271 | .idea/
272 | *.sln.iml
273 |
274 | # CodeRush
275 | .cr/
276 |
277 | # Python Tools for Visual Studio (PTVS)
278 | __pycache__/
279 | *.pyc
280 |
281 | # Cake - Uncomment if you are using it
282 | # tools/**
283 | # !tools/packages.config
284 |
285 | # Telerik's JustMock configuration file
286 | *.jmconfig
287 |
288 | # BizTalk build output
289 | *.btp.cs
290 | *.btm.cs
291 | *.odx.cs
292 | *.xsd.cs
293 |
294 | # End of https://www.gitignore.io/api/visualstudio
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Visual Studio Help Downloader
2 |
3 | Moved from Codeplex https://vshd.codeplex.com/
4 |
5 | ## Project Description
6 | Tool for downloading the Visual Studio 2012/2013/2015/2017 help packages for offline use
7 |
8 | ## Overview
9 |
10 | Allows Visual Studio 2012/2013/2015/2017 packages to be downloaded to an offline cache location before importing them into Microsoft Help Viewer 2.0/2.1/2.2/2.3.
11 |
12 | If the cache is kept following the import, then only changes will be downloaded on subsequent occasions.
13 |
14 | 
15 |
16 | ## Quick Guide
17 |
18 | * Select the version of Visual Studio to download the help for
19 | * Select your language from the drop down list
20 | * Press "Load Books" to retrieve the list of available books. Books that are already in the cache (partially or fully) will automatically be checked. Note that because packages are shared between different books, you may get extra items checked automatically.
21 | * Check (or uncheck) book that you want to download. The "Download Size" and "Num Downloads" columns indicate an approximate amount of data that needs to be downloaded for the book based on what is already in the cache.
22 | * Press "Download" to start downloading the requested books. Packages for books no longer selected will be deleted at this point.
23 | * When the download is complete, import the new books into "Microsoft Help Viewer" using the "Manage Content" tab.
24 |
25 | ## Credits
26 |
27 | This project is based on (and shares some code with) the earlier project [url:Visual Studio Help Downloader|http://vshd.codeplex.com/] by [url:nop|http://www.codeplex.com/site/users/view/nop].
28 |
--------------------------------------------------------------------------------
/VisualStudioHelpDownloader2012/Docs/screenshot.JPG:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/nickdalt/VSHD/5119cb6945cbecb8c6ae269399d900d5039cb79b/VisualStudioHelpDownloader2012/Docs/screenshot.JPG
--------------------------------------------------------------------------------
/VisualStudioHelpDownloader2012/VisualStudioHelpDownloader.sln:
--------------------------------------------------------------------------------
1 |
2 | Microsoft Visual Studio Solution File, Format Version 12.00
3 | # Visual Studio 15
4 | VisualStudioVersion = 15.0.27428.2002
5 | MinimumVisualStudioVersion = 10.0.40219.1
6 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "VisualStudioHelpDownloader", "VisualStudioHelpDownloader2012\VisualStudioHelpDownloader.csproj", "{2AE1E505-92AB-40DD-86D9-E47B307CEC94}"
7 | EndProject
8 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{9431BA4B-D228-4CCD-88B7-7621C0DB4AA5}"
9 | ProjectSection(SolutionItems) = preProject
10 | ..\README.md = ..\README.md
11 | EndProjectSection
12 | EndProject
13 | Global
14 | GlobalSection(SolutionConfigurationPlatforms) = preSolution
15 | Debug|Any CPU = Debug|Any CPU
16 | Release|Any CPU = Release|Any CPU
17 | EndGlobalSection
18 | GlobalSection(ProjectConfigurationPlatforms) = postSolution
19 | {2AE1E505-92AB-40DD-86D9-E47B307CEC94}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
20 | {2AE1E505-92AB-40DD-86D9-E47B307CEC94}.Debug|Any CPU.Build.0 = Debug|Any CPU
21 | {2AE1E505-92AB-40DD-86D9-E47B307CEC94}.Release|Any CPU.ActiveCfg = Release|Any CPU
22 | {2AE1E505-92AB-40DD-86D9-E47B307CEC94}.Release|Any CPU.Build.0 = Release|Any CPU
23 | EndGlobalSection
24 | GlobalSection(SolutionProperties) = preSolution
25 | HideSolutionNode = FALSE
26 | EndGlobalSection
27 | GlobalSection(ExtensibilityGlobals) = postSolution
28 | SolutionGuid = {032C2CE1-6CC2-4DC7-BC35-CCE49349DDD3}
29 | EndGlobalSection
30 | EndGlobal
31 |
--------------------------------------------------------------------------------
/VisualStudioHelpDownloader2012/VisualStudioHelpDownloader.vssscc:
--------------------------------------------------------------------------------
1 | ""
2 | {
3 | "FILE_VERSION" = "9237"
4 | "ENLISTMENT_CHOICE" = "NEVER"
5 | "PROJECT_FILE_RELATIVE_PATH" = ""
6 | "NUMBER_OF_EXCLUDED_FILES" = "0"
7 | "ORIGINAL_PROJECT_FILE_PATH" = ""
8 | "NUMBER_OF_NESTED_PROJECTS" = "0"
9 | "SOURCE_CONTROL_SETTINGS_PROVIDER" = "PROJECT"
10 | }
11 |
--------------------------------------------------------------------------------
/VisualStudioHelpDownloader2012/VisualStudioHelpDownloader2012/AuthenticodeTools.cs:
--------------------------------------------------------------------------------
1 | // Taken from https://stackoverflow.com/questions/6596327/how-to-check-if-a-file-is-signed-in-c
2 |
3 | namespace VisualStudioHelpDownloader2012
4 | {
5 | using System;
6 | using System.Runtime.InteropServices;
7 | internal static class AuthenticodeTools
8 | {
9 | [DllImport("Wintrust.dll", PreserveSig = true, SetLastError = false)]
10 | private static extern uint WinVerifyTrust(IntPtr hWnd, IntPtr pgActionID, IntPtr pWinTrustData);
11 | private static uint WinVerifyTrust(string fileName)
12 | {
13 | Guid wintrust_action_generic_verify_v2 = new Guid("{00AAC56B-CD44-11d0-8CC2-00C04FC295EE}");
14 | uint result = 0;
15 | using (WINTRUST_FILE_INFO fileInfo = new WINTRUST_FILE_INFO(fileName, Guid.Empty))
16 | using (UnmanagedPointer guidPtr = new UnmanagedPointer(Marshal.AllocHGlobal(Marshal.SizeOf(typeof(Guid))), AllocMethod.HGlobal))
17 | using (UnmanagedPointer wvtDataPtr = new UnmanagedPointer(Marshal.AllocHGlobal(Marshal.SizeOf(typeof(WINTRUST_DATA))), AllocMethod.HGlobal))
18 | {
19 | WINTRUST_DATA data = new WINTRUST_DATA(fileInfo);
20 | IntPtr pGuid = guidPtr;
21 | IntPtr pData = wvtDataPtr;
22 | Marshal.StructureToPtr(wintrust_action_generic_verify_v2, pGuid, true);
23 | Marshal.StructureToPtr(data, pData, true);
24 | result = WinVerifyTrust(IntPtr.Zero, pGuid, pData);
25 | }
26 |
27 | return result;
28 | }
29 |
30 | public static bool IsTrusted(string fileName)
31 | {
32 | return WinVerifyTrust(fileName) == 0;
33 | }
34 | }
35 |
36 | internal struct WINTRUST_FILE_INFO : IDisposable
37 | {
38 | public WINTRUST_FILE_INFO(string fileName, Guid subject)
39 | {
40 | cbStruct = (uint)Marshal.SizeOf(typeof(WINTRUST_FILE_INFO));
41 | pcwszFilePath = fileName;
42 | if (subject != Guid.Empty)
43 | {
44 | pgKnownSubject = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(Guid)));
45 | Marshal.StructureToPtr(subject, pgKnownSubject, true);
46 | }
47 | else
48 | {
49 | pgKnownSubject = IntPtr.Zero;
50 | }
51 |
52 | hFile = IntPtr.Zero;
53 | }
54 |
55 | public uint cbStruct;
56 | [MarshalAs(UnmanagedType.LPTStr)]
57 | public string pcwszFilePath;
58 | public IntPtr hFile;
59 | public IntPtr pgKnownSubject;
60 |
61 | public void Dispose()
62 | {
63 | Dispose(true);
64 | }
65 |
66 | private void Dispose(bool disposing)
67 | {
68 | if (pgKnownSubject != IntPtr.Zero)
69 | {
70 | Marshal.DestroyStructure(pgKnownSubject, typeof(Guid));
71 | Marshal.FreeHGlobal(pgKnownSubject);
72 | }
73 | }
74 | }
75 |
76 | enum AllocMethod
77 | {
78 | HGlobal,
79 | CoTaskMem
80 | };
81 | enum UnionChoice
82 | {
83 | File = 1,
84 | Catalog,
85 | Blob,
86 | Signer,
87 | Cert
88 | };
89 | enum UiChoice
90 | {
91 | All = 1,
92 | NoUI,
93 | NoBad,
94 | NoGood
95 | };
96 | enum RevocationCheckFlags
97 | {
98 | None = 0,
99 | WholeChain
100 | };
101 | enum StateAction
102 | {
103 | Ignore = 0,
104 | Verify,
105 | Close,
106 | AutoCache,
107 | AutoCacheFlush
108 | };
109 | enum TrustProviderFlags
110 | {
111 | UseIE4Trust = 1,
112 | NoIE4Chain = 2,
113 | NoPolicyUsage = 4,
114 | RevocationCheckNone = 16,
115 | RevocationCheckEndCert = 32,
116 | RevocationCheckChain = 64,
117 | RecovationCheckChainExcludeRoot = 128,
118 | Safer = 256,
119 | HashOnly = 512,
120 | UseDefaultOSVerCheck = 1024,
121 | LifetimeSigning = 2048
122 | };
123 | enum UIContext
124 | {
125 | Execute = 0,
126 | Install
127 | };
128 |
129 | [StructLayout(LayoutKind.Sequential)]
130 | internal struct WINTRUST_DATA : IDisposable
131 | {
132 | public WINTRUST_DATA(WINTRUST_FILE_INFO fileInfo)
133 | {
134 | cbStruct = (uint)Marshal.SizeOf(typeof(WINTRUST_DATA));
135 | pInfoStruct = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(WINTRUST_FILE_INFO)));
136 | Marshal.StructureToPtr(fileInfo, pInfoStruct, false);
137 | dwUnionChoice = UnionChoice.File;
138 | pPolicyCallbackData = IntPtr.Zero;
139 | pSIPCallbackData = IntPtr.Zero;
140 | dwUIChoice = UiChoice.NoUI;
141 | fdwRevocationChecks = RevocationCheckFlags.None;
142 | dwStateAction = StateAction.Ignore;
143 | hWVTStateData = IntPtr.Zero;
144 | pwszURLReference = IntPtr.Zero;
145 | dwProvFlags = TrustProviderFlags.Safer;
146 | dwUIContext = UIContext.Execute;
147 | }
148 |
149 | public uint cbStruct;
150 | public IntPtr pPolicyCallbackData;
151 | public IntPtr pSIPCallbackData;
152 | public UiChoice dwUIChoice;
153 | public RevocationCheckFlags fdwRevocationChecks;
154 | public UnionChoice dwUnionChoice;
155 | public IntPtr pInfoStruct;
156 | public StateAction dwStateAction;
157 | public IntPtr hWVTStateData;
158 | private IntPtr pwszURLReference;
159 | public TrustProviderFlags dwProvFlags;
160 | public UIContext dwUIContext;
161 |
162 | public void Dispose()
163 | {
164 | Dispose(true);
165 | }
166 |
167 | private void Dispose(bool disposing)
168 | {
169 | if (dwUnionChoice == UnionChoice.File)
170 | {
171 | using (WINTRUST_FILE_INFO info = new WINTRUST_FILE_INFO())
172 | {
173 | Marshal.PtrToStructure(pInfoStruct, info);
174 | }
175 |
176 | Marshal.DestroyStructure(pInfoStruct, typeof(WINTRUST_FILE_INFO));
177 | }
178 |
179 | Marshal.FreeHGlobal(pInfoStruct);
180 | }
181 | }
182 |
183 | internal sealed class UnmanagedPointer : IDisposable
184 | {
185 | private IntPtr m_ptr;
186 | private AllocMethod m_meth;
187 |
188 | internal UnmanagedPointer(IntPtr ptr, AllocMethod method)
189 | {
190 | m_meth = method;
191 | m_ptr = ptr;
192 | }
193 |
194 | ~UnmanagedPointer()
195 | {
196 | Dispose(false);
197 | }
198 |
199 | private void Dispose(bool disposing)
200 | {
201 | if (m_ptr != IntPtr.Zero)
202 | {
203 | if (m_meth == AllocMethod.HGlobal)
204 | {
205 | Marshal.FreeHGlobal(m_ptr);
206 | }
207 | else if (m_meth == AllocMethod.CoTaskMem)
208 | {
209 | Marshal.FreeCoTaskMem(m_ptr);
210 | }
211 |
212 | m_ptr = IntPtr.Zero;
213 | }
214 |
215 | if (disposing)
216 | {
217 | GC.SuppressFinalize(this);
218 | }
219 | }
220 |
221 | public void Dispose()
222 | {
223 | Dispose(true);
224 | }
225 |
226 | public static implicit operator IntPtr(UnmanagedPointer ptr)
227 | {
228 | return ptr.m_ptr;
229 | }
230 | }
231 | }
--------------------------------------------------------------------------------
/VisualStudioHelpDownloader2012/VisualStudioHelpDownloader2012/Book.cs:
--------------------------------------------------------------------------------
1 | namespace VisualStudioHelpDownloader2012
2 | {
3 | using System.Collections.Generic;
4 | using System.Globalization;
5 |
6 | ///
7 | /// Represents an MSDN book
8 | ///
9 | internal sealed class Book : ItemBase
10 | {
11 | ///
12 | /// Gets or sets the display category for the book
13 | ///
14 | public string Category
15 | {
16 | get;
17 | set;
18 | }
19 |
20 | ///
21 | /// Gets or sets a value indicating whether the a download of the book has been requested.
22 | ///
23 | public bool Wanted
24 | {
25 | get;
26 | set;
27 | }
28 |
29 | ///
30 | /// Gets or sets the collection of packages associated with the book
31 | ///
32 | public ICollection Packages
33 | {
34 | get;
35 | set;
36 | }
37 |
38 | ///
39 | /// Create a file name for the book index file
40 | ///
41 | ///
42 | /// A string containing the file name
43 | ///
44 | public string CreateFileName()
45 | {
46 | return string.Format( CultureInfo.InvariantCulture, "Book-{0}-{1}.xml", Code, Locale.Name );
47 | }
48 | }
49 | }
50 |
--------------------------------------------------------------------------------
/VisualStudioHelpDownloader2012/VisualStudioHelpDownloader2012/BookGroup.cs:
--------------------------------------------------------------------------------
1 | namespace VisualStudioHelpDownloader2012
2 | {
3 | using System.Collections.Generic;
4 | using System.Globalization;
5 |
6 | ///
7 | /// Represents an MSDN book group
8 | ///
9 | internal sealed class BookGroup : ItemBase
10 | {
11 | ///
12 | /// Gets or sets the books associated with the book group
13 | ///
14 | public ICollection Books
15 | {
16 | get;
17 | set;
18 | }
19 |
20 | ///
21 | /// Create a file name for the book group index file
22 | ///
23 | ///
24 | /// A string containing the file name
25 | ///
26 | public string CreateFileName()
27 | {
28 | return string.Format( CultureInfo.InvariantCulture, "product-{0}.xml", Code );
29 | }
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/VisualStudioHelpDownloader2012/VisualStudioHelpDownloader2012/Downloader.cs:
--------------------------------------------------------------------------------
1 | namespace VisualStudioHelpDownloader2012
2 | {
3 | using System;
4 | using System.Collections.Generic;
5 | using System.Diagnostics;
6 | using System.Globalization;
7 | using System.IO;
8 | using System.Linq;
9 | using System.Net;
10 | using System.Reflection;
11 | using System.Text;
12 | using System.Threading.Tasks;
13 | using System.Windows.Forms;
14 | using System.Xml;
15 | using System.Xml.Linq;
16 |
17 | ///
18 | /// Class to perfom the downloading of the MSDN book information and the books themselves
19 | ///
20 | internal sealed class Downloader : IDisposable
21 | {
22 | ///
23 | /// The http client used for downloading
24 | ///
25 | private WebClient client = new WebClient();
26 |
27 | ///
28 | /// Initializes a new instance of the class.
29 | ///
30 | ///
31 | /// If the settings cannot be loaded
32 | ///
33 | ///
34 | /// If the data cannot be processed
35 | ///
36 | public Downloader()
37 | {
38 | client.BaseAddress = "https://services.mtps.microsoft.com/serviceapi/";
39 |
40 | string directory = Path.GetDirectoryName( Application.ExecutablePath );
41 | if ( directory != null )
42 | {
43 | string settingsFile = Path.Combine(
44 | directory,
45 | string.Format( CultureInfo.InvariantCulture, "{0}.xml", Assembly.GetEntryAssembly().GetName().Name ) );
46 |
47 | if ( File.Exists( settingsFile ) )
48 | {
49 | XElement element = XDocument.Load( settingsFile ).Root;
50 | if ( element != null )
51 | {
52 | element = element.Elements().Single( x => x.Name.LocalName?.Equals( "proxy", StringComparison.OrdinalIgnoreCase ) ?? false );
53 | WebProxy proxy = new WebProxy( element.Attributes().Single( x => x.Name.LocalName?.Equals( "address", StringComparison.OrdinalIgnoreCase ) ?? false ).Value )
54 | {
55 | Credentials =
56 | new NetworkCredential(
57 | element.Attributes().Single( x => x.Name.LocalName?.Equals( "login", StringComparison.OrdinalIgnoreCase ) ?? false ).Value,
58 | element.Attributes().Single( x => x.Name.LocalName?.Equals( "password", StringComparison.OrdinalIgnoreCase ) ?? false ).Value,
59 | element.Attributes().Single( x => x.Name.LocalName?.Equals( "domain", StringComparison.OrdinalIgnoreCase ) ?? false ).Value )
60 | };
61 |
62 | client.Proxy = proxy;
63 | }
64 | else
65 | {
66 | throw new XmlException( "Missing root element" );
67 | }
68 | }
69 | }
70 | }
71 |
72 | ///
73 | /// Finalizes an instance of the class.
74 | ///
75 | ~Downloader()
76 | {
77 | Dispose( false );
78 | }
79 |
80 | ///
81 | /// Check the current caching status of the packages so that the required downloads can be
82 | /// determined
83 | ///
84 | ///
85 | /// The collection of bookGroups to check the packages for
86 | ///
87 | ///
88 | /// The directory where the packages are locally cached
89 | ///
90 | ///
91 | /// If bookGroups or cachePath are null
92 | ///
93 | public static void CheckPackagesStates( ICollection bookGroups, string cachePath )
94 | {
95 | if ( bookGroups == null )
96 | {
97 | throw new ArgumentNullException( "bookGroups" );
98 | }
99 |
100 | if ( cachePath == null )
101 | {
102 | throw new ArgumentNullException( "cachePath" );
103 | }
104 |
105 | foreach ( BookGroup bookGroup in bookGroups )
106 | {
107 | foreach ( Book book in bookGroup.Books )
108 | {
109 | foreach ( Package package in book.Packages )
110 | {
111 | string packagePath = Path.Combine( cachePath, "Packages", package.Name + ".cab" );
112 | FileInfo packageFile = new FileInfo( packagePath );
113 | if ( packageFile.Exists )
114 | {
115 | if ( packageFile.LastWriteTime == package.LastModified && packageFile.Length == package.Size )
116 | {
117 | package.State = PackageState.OutOfDate;
118 | }
119 | else
120 | {
121 | package.State = PackageState.Ready;
122 | }
123 | }
124 | else
125 | {
126 | package.State = PackageState.NotDownloaded;
127 | }
128 | }
129 | }
130 | }
131 | }
132 |
133 | ///
134 | /// The dispose.
135 | ///
136 | public void Dispose()
137 | {
138 | Dispose( true );
139 | GC.SuppressFinalize( this );
140 | }
141 |
142 | ///
143 | /// Retrieves a collection of locales available to download the help for
144 | ///
145 | ///
146 | /// Collection of Locales available
147 | ///
148 | ///
149 | /// If the data cannot be downloaded
150 | ///
151 | ///
152 | /// If the data cannot be processed
153 | ///
154 | ///
155 | /// If the data cannot be processed
156 | ///
157 | public async Task> LoadAvailableLocalesAsync( string vsVersion )
158 | {
159 | string catalogPath = string.Format("catalogs/{0}", vsVersion);
160 | Debug.Print("Downloading locales list from {0}{1}", client.BaseAddress, catalogPath);
161 | ICollection locales = HelpIndexManager.LoadLocales( await client.DownloadDataTaskAsync( catalogPath ) );
162 | return locales;
163 | }
164 |
165 | ///
166 | /// Download information about the available books for the selected locale
167 | ///
168 | ///
169 | /// The relative path to the book catalog download location
170 | ///
171 | ///
172 | /// Collection of available bookGroups
173 | ///
174 | ///
175 | /// If path is null or empty
176 | ///
177 | ///
178 | /// If the data cannot be downloaded
179 | ///
180 | ///
181 | /// If the data cannot be processed
182 | ///
183 | ///
184 | /// If the data cannot be processed
185 | ///
186 | public async Task> LoadBooksInformationAsync( string path )
187 | {
188 | if ( path == null )
189 | {
190 | throw new ArgumentNullException( "path" );
191 | }
192 |
193 | Debug.Print("Downloading books list from {0}{1}", client.BaseAddress, path);
194 | return HelpIndexManager.LoadBooks( await client.DownloadDataTaskAsync( path ) );
195 | }
196 |
197 | ///
198 | /// Download the requested books and create the appropriate index files for MSDN HelpViewer
199 | ///
200 | ///
201 | /// The collection of bookGroups to with the books to download indicated by the Book.Wanted
202 | /// property
203 | ///
204 | ///
205 | /// The path where the downloaded books are cached
206 | ///
207 | ///
208 | /// Interface used to report the percentage progress back to the GUI
209 | ///
210 | ///
211 | /// If any of the parameters are null
212 | ///
213 | ///
214 | /// If the data cannot be downloaded
215 | ///
216 | ///
217 | /// If the data cannot be processed
218 | ///
219 | ///
220 | /// If there was a problem reading or writing to the cache directory
221 | ///
222 | ///
223 | /// If the user does not have permission to write to the cache directory
224 | ///
225 | ///
226 | /// If the data cannot be processed
227 | ///
228 | public async Task DownloadBooksAsync( ICollection bookGroups, string cachePath, IProgress progress )
229 | {
230 | if ( bookGroups == null )
231 | {
232 | throw new ArgumentNullException( "bookGroups" );
233 | }
234 |
235 | if ( cachePath == null )
236 | {
237 | throw new ArgumentNullException( "cachePath" );
238 | }
239 |
240 | if ( cachePath == null )
241 | {
242 | throw new ArgumentNullException( "progress" );
243 | }
244 |
245 | // Create cachePath
246 | string targetDirectory = Path.Combine( cachePath, "Packages" );
247 |
248 | if ( !Directory.Exists( targetDirectory ) )
249 | {
250 | Directory.CreateDirectory( targetDirectory );
251 | }
252 |
253 | // Cleanup index files
254 | Directory.GetFiles( cachePath, "*.msha" ).ForEach( File.Delete );
255 | Directory.GetFiles( cachePath, "*.xml" ).ForEach( File.Delete );
256 |
257 | // Creating setup indexes
258 | File.WriteAllText(
259 | Path.Combine( cachePath, "HelpContentSetup.msha" ), HelpIndexManager.CreateSetupIndex( bookGroups ), Encoding.UTF8 );
260 |
261 | // Create list of unique packages for possible download and write the book group and
262 | // book index files
263 | Dictionary packages = new Dictionary();
264 | foreach ( BookGroup bookGroup in bookGroups )
265 | {
266 | File.WriteAllText(
267 | Path.Combine( cachePath, bookGroup.CreateFileName() ),
268 | HelpIndexManager.CreateBookGroupBooksIndex( bookGroup ),
269 | Encoding.UTF8 );
270 | Debug.Print( "BookGroup: {0}", bookGroup.Name );
271 | foreach ( Book book in bookGroup.Books )
272 | {
273 | if ( book.Wanted )
274 | {
275 | Debug.Print( " Book: {0}", book.Name );
276 | File.WriteAllText(
277 | Path.Combine( cachePath, book.CreateFileName() ),
278 | HelpIndexManager.CreateBookPackagesIndex( bookGroup, book ),
279 | Encoding.UTF8 );
280 | foreach ( Package package in book.Packages )
281 | {
282 | string name = package.Name.ToUpperInvariant();
283 | Debug.Print( " Package: {0}", name );
284 | if ( !packages.ContainsKey( name ) )
285 | {
286 | packages.Add( name, package );
287 | }
288 | }
289 | }
290 | }
291 | }
292 |
293 | // Cleanup old files
294 | foreach ( string file in Directory.GetFiles( targetDirectory, "*.cab" ) )
295 | {
296 | string fileName = Path.GetFileNameWithoutExtension( file );
297 | if ( !string.IsNullOrEmpty( fileName ) )
298 | {
299 | fileName = fileName.ToUpperInvariant();
300 | if ( !packages.ContainsKey( fileName ) )
301 | {
302 | File.Delete( file );
303 | }
304 | }
305 | }
306 |
307 | // Download the packages
308 | int packagesCountCurrent = 0;
309 | client.BaseAddress = "https://packages.mtps.microsoft.com/";
310 | foreach ( Package package in packages.Values )
311 | {
312 | string targetFileName = Path.Combine( targetDirectory, package.CreateFileName() );
313 | if ( package.State == PackageState.NotDownloaded || package.State == PackageState.OutOfDate )
314 | {
315 | Debug.Print( " Downloading : '{0}' to '{1}'", package.Link, targetFileName );
316 | await client.DownloadFileTaskAsync( package.Link, targetFileName );
317 |
318 | if (AuthenticodeTools.IsTrusted(targetFileName))
319 | {
320 | File.SetCreationTime(targetFileName, package.LastModified);
321 | File.SetLastAccessTime(targetFileName, package.LastModified);
322 | File.SetLastWriteTime(targetFileName, package.LastModified);
323 | }
324 | else
325 | {
326 | Debug.Print("The signature on '{0}' is not valid - deleting");
327 | File.Delete(targetFileName);
328 |
329 | throw new InvalidDataException($"The signature on '{targetFileName}' is not valid - deleting");
330 | }
331 | }
332 |
333 | progress.Report( 100 * ++packagesCountCurrent / packages.Count );
334 | }
335 | }
336 |
337 | ///
338 | /// Standard IDispose pattern
339 | ///
340 | ///
341 | /// true if called by Dispose, false if called from destructor
342 | ///
343 | private void Dispose( bool disposing )
344 | {
345 | if ( disposing )
346 | {
347 | if ( client != null )
348 | {
349 | client.Dispose();
350 | client = null;
351 | }
352 | }
353 | }
354 | }
355 | }
356 |
--------------------------------------------------------------------------------
/VisualStudioHelpDownloader2012/VisualStudioHelpDownloader2012/Extensions.cs:
--------------------------------------------------------------------------------
1 | namespace VisualStudioHelpDownloader2012
2 | {
3 | using System;
4 | using System.Collections.Generic;
5 |
6 | ///
7 | /// Help class with extension methods.
8 | ///
9 | internal static class Extensions
10 | {
11 | ///
12 | /// Perform action on each element from source.
13 | ///
14 | ///
15 | /// Element type.
16 | ///
17 | ///
18 | /// Elements source.
19 | ///
20 | ///
21 | /// Action to perform.
22 | ///
23 | public static void ForEach( this IEnumerable source, Action action )
24 | {
25 | if ( null != action )
26 | {
27 | foreach ( T x in source )
28 | {
29 | action( x );
30 | }
31 | }
32 | }
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/VisualStudioHelpDownloader2012/VisualStudioHelpDownloader2012/HelpIndexManager.cs:
--------------------------------------------------------------------------------
1 | namespace VisualStudioHelpDownloader2012
2 | {
3 | using System;
4 | using System.Collections.Generic;
5 | using System.Globalization;
6 | using System.IO;
7 | using System.Linq;
8 | using System.Xml;
9 | using System.Xml.Linq;
10 |
11 | ///
12 | /// Helper class for parsing and creating documents with help indexes.
13 | ///
14 | internal static class HelpIndexManager
15 | {
16 | ///
17 | /// Find the available locales for the help collections
18 | ///
19 | ///
20 | /// The page data downloaded containing the locale catalog data
21 | ///
22 | ///
23 | /// Collection of locales in which the help collection may be downloaded
24 | ///
25 | ///
26 | /// If data is null
27 | ///
28 | ///
29 | /// If there was a error processing the xml data
30 | ///
31 | ///
32 | /// If there was a error processing the xml data
33 | ///
34 | public static ICollection LoadLocales( byte[] data )
35 | {
36 | XDocument document;
37 | List result = new List();
38 |
39 | if ( data == null )
40 | {
41 | throw new ArgumentNullException( "data" );
42 | }
43 |
44 | // This would normally be loaded directly from the bytes but the MS server
45 | // seems to be returning junk whitespace at the start that cant be loaded
46 | // directly as XML
47 | document = XDocument.Parse( System.Text.Encoding.UTF8.GetString(data).TrimStart() );
48 |
49 | if ( document.Root != null )
50 | {
51 | IEnumerable query =
52 | document.Root.Elements()
53 | .Where( x => x.GetClassName()?.Equals( "catalogLocales", StringComparison.OrdinalIgnoreCase ) ?? false )
54 | .Take( 1 )
55 | .Single()
56 | .Elements()
57 | .Where( x => x.GetClassName()?.Equals( "catalog-locale-list", StringComparison.OrdinalIgnoreCase ) ?? false )
58 | .Take( 1 )
59 | .Single()
60 | .Elements()
61 | .Where( x => x.GetClassName()?.Equals( "catalog-locale", StringComparison.OrdinalIgnoreCase ) ?? false );
62 |
63 | result.AddRange(
64 | query.Select(
65 | x =>
66 | new Locale
67 | {
68 | Code = x.GetChildClassValue( "locale" ),
69 | CatalogLink = x.GetChildClassAttributeValue( "locale-link", "href" )
70 | } ) );
71 | }
72 | else
73 | {
74 | throw new XmlException( "Missing document root" );
75 | }
76 |
77 | return result;
78 | }
79 |
80 | ///
81 | /// Find the available book groups, books, and packages for the selected language
82 | ///
83 | ///
84 | /// The page data downloaded containing the book data
85 | ///
86 | ///
87 | /// Collection of book groups for the help collection
88 | ///
89 | ///
90 | /// If data is null
91 | ///
92 | ///
93 | /// If there was a error processing the xml data
94 | ///
95 | ///
96 | /// If there was a error processing the xml data
97 | ///
98 | public static ICollection LoadBooks( byte[] data )
99 | {
100 | XDocument document;
101 | using ( MemoryStream stream = new MemoryStream( data ) )
102 | {
103 | document = XDocument.Load( stream );
104 | }
105 |
106 | if ( data == null )
107 | {
108 | throw new ArgumentNullException( "data" );
109 | }
110 |
111 | List result = new List();
112 |
113 | if ( document.Root != null )
114 | {
115 | IEnumerable groups =
116 | document.Root.Elements()
117 | .Where( x => x.GetClassName()?.Equals( "book-list", StringComparison.OrdinalIgnoreCase ) ?? false )
118 | .Take( 1 )
119 | .Single()
120 | .Elements()
121 | .Where( x => x.GetClassName()?.Equals( "book-groups", StringComparison.OrdinalIgnoreCase ) ?? false )
122 | .Take( 1 )
123 | .Single()
124 | .Elements()
125 | .Where( x => x.GetClassName()?.Equals( "book-group", StringComparison.OrdinalIgnoreCase ) ?? false );
126 | foreach ( XElement group in groups )
127 | {
128 | BookGroup bookGroup = new BookGroup
129 | {
130 | Name = group.GetChildClassValue( "name" ),
131 | Code = group.GetChildClassValue( "id" ),
132 | Books = new List(),
133 | Locale = new Locale { Code = "en-us" },
134 | Description = group.GetChildClassValue( "name" )
135 | };
136 |
137 | result.Add( bookGroup );
138 |
139 | IEnumerable books = group.Elements().Where( x => x.GetClassName()?.Equals( "book", StringComparison.OrdinalIgnoreCase ) ?? false );
140 | foreach ( XElement book in books )
141 | {
142 | XElement path =
143 | book.Elements()
144 | .Where( x => x.GetClassName()?.Equals( "properties", StringComparison.OrdinalIgnoreCase ) ?? false )
145 | .Take( 1 )
146 | .Single()
147 | .Elements()
148 | .Where( x => x.GetClassName()?.Equals( "paths", StringComparison.OrdinalIgnoreCase ) ?? false )
149 | .Take( 1 )
150 | .Single()
151 | .Elements()
152 | .Where( x => x.GetClassName()?.Equals( "path", StringComparison.OrdinalIgnoreCase ) ?? false )
153 | .Take( 1 )
154 | .Single();
155 | string bookPath = path.GetChildClassValue( "name" ).TrimStart( new[] { '\\' } );
156 |
157 | Book b = new Book
158 | {
159 | Name = book.GetChildClassValue( "name" ),
160 | Description = book.GetChildClassValue( "description" ),
161 | Code = book.GetChildClassValue( "id" ),
162 | Packages = new List(),
163 | Locale = new Locale { Code = "en-us" },
164 | Category = bookPath
165 | };
166 |
167 | bookGroup.Name = bookPath;
168 | bookGroup.Books.Add( b );
169 | IEnumerable packages =
170 | book.Elements()
171 | .Where( x => x.GetClassName()?.Equals( "packages", StringComparison.OrdinalIgnoreCase ) ?? false )
172 | .Take( 1 )
173 | .Single()
174 | .Elements()
175 | .Where( x => x.GetClassName()?.Equals( "package" , StringComparison.OrdinalIgnoreCase ) ?? false );
176 | foreach ( XElement package in packages )
177 | {
178 | Package p = new Package
179 | {
180 | LastModified = DateTime.Parse( package.GetChildClassValue( "last-modified" ), CultureInfo.InvariantCulture ),
181 | Link = package.GetChildClassAttributeValue( "current-link", "href" ),
182 | Tag = package.GetChildClassValue( "package-etag" ),
183 | Name = package.GetChildClassValue( "name" ),
184 | Size = long.Parse( package.GetChildClassValue( "package-size-bytes" ), CultureInfo.InvariantCulture )
185 | };
186 |
187 | b.Packages.Add( p );
188 | }
189 | }
190 | }
191 | }
192 | else
193 | {
194 | throw new XmlException( "Missing document root" );
195 | }
196 |
197 | return result;
198 | }
199 |
200 | ///
201 | /// Creates main help setup index.
202 | ///
203 | ///
204 | /// A collection of book groups to add to the index
205 | ///
206 | ///
207 | /// The xml document text
208 | ///
209 | public static string CreateSetupIndex( IEnumerable bookGroups )
210 | {
211 | XDocument document = new XDocument( new XDeclaration( "1.0", "utf-8", null ), CreateElement( "html", null, null ) );
212 |
213 | XElement bodyElement = CreateElement( "body", "product-list", null );
214 |
215 | foreach ( BookGroup bookGroup in bookGroups )
216 | {
217 | XElement productElement = CreateElement( "div", "product", null );
218 |
219 | XElement linkElement = CreateElement( "a", "product-link", null );
220 | linkElement.SetAttributeValue( XName.Get( "href", string.Empty ), bookGroup.CreateFileName() );
221 |
222 | productElement.Add(
223 | CreateElement( "span", "name", bookGroup.Name ),
224 | CreateElement( "span", "locale", bookGroup.Locale.Code ),
225 | CreateElement( "span", "description", bookGroup.Description ),
226 | linkElement );
227 |
228 | bodyElement.Add( productElement );
229 | }
230 |
231 | if ( document.Root != null )
232 | {
233 | document.Root.Add( bodyElement );
234 | }
235 |
236 | return document.ToStringWithDeclaration();
237 | }
238 |
239 | ///
240 | /// Create book group books index.
241 | ///
242 | ///
243 | /// The book group to create the index for.
244 | ///
245 | ///
246 | /// The xml document text
247 | ///
248 | public static string CreateBookGroupBooksIndex( BookGroup bookGroup )
249 | {
250 | XDocument document = new XDocument( new XDeclaration( "1.0", "utf-8", null ), CreateElement( "html", null, null ) );
251 |
252 | XElement headElement = CreateElement( "head", null, null );
253 | XElement metaDateElemet = CreateElement( "meta", null, null );
254 | metaDateElemet.SetAttributeValue( XName.Get( "http-equiv", string.Empty ), "Date" );
255 | metaDateElemet.SetAttributeValue( XName.Get( "content", string.Empty ), DateTime.Now.ToString( "R", CultureInfo.InvariantCulture ) );
256 | headElement.Add( metaDateElemet );
257 |
258 | XElement bodyElement = CreateElement( "body", "product", null );
259 | XElement detailsElement = CreateElement( "div", "details", null );
260 | detailsElement.Add(
261 | CreateElement( "span", "name", bookGroup.Name ),
262 | CreateElement( "span", "locale", bookGroup.Locale.Code ),
263 | CreateElement( "span", "description", bookGroup.Description ) );
264 | XElement bookListElement = CreateElement( "div", "book-list", null );
265 |
266 | foreach ( Book book in bookGroup.Books )
267 | {
268 | if ( book.Wanted )
269 | {
270 | XElement bookElement = CreateElement( "div", "book", null );
271 |
272 | XElement linkElement = CreateElement( "a", "book-link", null );
273 | linkElement.SetAttributeValue( XName.Get( "href", string.Empty ), book.CreateFileName() );
274 |
275 | bookElement.Add(
276 | CreateElement( "span", "name", book.Name ),
277 | CreateElement( "span", "locale", book.Locale.Code ),
278 | CreateElement( "span", "description", book.Description ),
279 | linkElement );
280 |
281 | bookListElement.Add( bookElement );
282 | }
283 | }
284 |
285 | bodyElement.Add( detailsElement, bookListElement );
286 | if ( document.Root != null )
287 | {
288 | document.Root.Add( headElement, bodyElement );
289 | }
290 |
291 | return document.ToStringWithDeclaration();
292 | }
293 |
294 | ///
295 | /// Create book packages index.
296 | ///
297 | ///
298 | /// The book Group associated with the book.
299 | ///
300 | ///
301 | /// The book associated with the packages
302 | ///
303 | ///
304 | /// The xml document text
305 | ///
306 | public static string CreateBookPackagesIndex( BookGroup bookGroup, Book book )
307 | {
308 | XDocument document = new XDocument( new XDeclaration( "1.0", "utf-8", null ), CreateElement( "html", null, null ) );
309 |
310 | XElement headElement = CreateElement( "head", null, null );
311 | XElement metaDateElemet = CreateElement( "meta", null, null );
312 | metaDateElemet.SetAttributeValue( XName.Get( "http-equiv", string.Empty ), "Date" );
313 | metaDateElemet.SetAttributeValue( XName.Get( "content", string.Empty ), DateTime.Now.ToString( "R", CultureInfo.InvariantCulture ) );
314 | headElement.Add( metaDateElemet );
315 |
316 | XElement bodyElement = CreateElement( "body", "book", null );
317 | XElement detailsElement = CreateElement( "div", "details", null );
318 |
319 | XElement brandingPackageElement1 = CreateElement( "a", "branding-package-link", null );
320 | XElement brandingPackageElement2 = CreateElement( "a", "branding-package-link", null );
321 | XElement productLinkElement = CreateElement( "a", "product-link", null );
322 |
323 | productLinkElement.SetAttributeValue( XName.Get( "href", string.Empty ), Uri.EscapeDataString(bookGroup.CreateFileName()) );
324 |
325 | detailsElement.Add(
326 | CreateElement( "span", "name", book.Name ),
327 | CreateElement( "span", "description", book.Description ),
328 | CreateElement( "span", "vendor", "Microsoft" ),
329 | CreateElement( "span", "locale", book.Locale.Code ),
330 | brandingPackageElement1,
331 | brandingPackageElement2 );
332 |
333 | XElement packageListElement = CreateElement( "div", "package-list", null );
334 |
335 | foreach ( Package package in book.Packages )
336 | {
337 | XElement packageElement = CreateElement( "div", "package", null );
338 | XElement linkElement = CreateElement( "a", "current-link", null );
339 |
340 | linkElement.SetAttributeValue(
341 | XName.Get( "href", string.Empty ),
342 | string.Format( CultureInfo.InvariantCulture, @"Packages\{0}", Uri.EscapeDataString(package.CreateFileName()) ) );
343 |
344 | packageElement.Add(
345 | CreateElement( "span", "name", package.Name ),
346 | CreateElement( "span", "deployed", "true" ),
347 | CreateElement( "span", "package-etag", package.Tag ),
348 | CreateElement( "span", "last-modified", package.LastModified.ToUniversalTime().ToString( "O", CultureInfo.InvariantCulture ) ),
349 | linkElement );
350 |
351 | packageListElement.Add( packageElement );
352 | }
353 |
354 | bodyElement.Add( detailsElement, packageListElement );
355 | if ( document.Root != null )
356 | {
357 | document.Root.Add( headElement, bodyElement );
358 | }
359 |
360 | return document.ToStringWithDeclaration();
361 | }
362 |
363 | ///
364 | /// Create a new xml element
365 | ///
366 | ///
367 | /// The name of the element
368 | ///
369 | ///
370 | /// The class attribute value (may be null)
371 | ///
372 | ///
373 | /// The element content (may be null)
374 | ///
375 | ///
376 | /// The created element
377 | ///
378 | private static XElement CreateElement( string name, string className, string value )
379 | {
380 | XElement element = new XElement( XName.Get( name, "http://www.w3.org/1999/xhtml" ) );
381 |
382 | if ( className != null )
383 | {
384 | element.SetAttributeValue( XName.Get( "class", string.Empty ), className );
385 | }
386 |
387 | if ( value != null )
388 | {
389 | element.Value = value;
390 | }
391 |
392 | return element;
393 | }
394 |
395 | ///
396 | /// Get the name of the class of an xml element
397 | ///
398 | ///
399 | /// The element to get the class name of
400 | ///
401 | ///
402 | /// The class name or null if there is no class name
403 | ///
404 | private static string GetClassName( this XElement element )
405 | {
406 | return GetAttributeValue( element, "class" );
407 | }
408 |
409 | ///
410 | /// The the value of an attribute of an xml element
411 | ///
412 | ///
413 | /// The element to get the attribute value from
414 | ///
415 | ///
416 | /// The name of the attrbute to query
417 | ///
418 | ///
419 | /// The attribute value or null if the attribute was not found
420 | ///
421 | private static string GetAttributeValue( this XElement element, string name )
422 | {
423 | XAttribute attribute = element.Attribute( XName.Get( name, string.Empty ) );
424 |
425 | return attribute == null ? null : attribute.Value;
426 | }
427 |
428 | ///
429 | /// Get the value of the first child element of the specified element with the class attribute that matched
430 | /// the specified name
431 | ///
432 | ///
433 | /// The element to get the child class value from
434 | ///
435 | ///
436 | /// The class name to find
437 | ///
438 | ///
439 | /// The value of the child class element
440 | ///
441 | ///
442 | /// If there was no child element with the class attribute
443 | ///
444 | private static string GetChildClassValue( this XElement element, string name )
445 | {
446 | XElement result = element.Elements().Where( x => x.GetClassName()?.Equals( name, StringComparison.OrdinalIgnoreCase ) ?? false ).Take( 1 ).Single();
447 |
448 | return null != result ? result.Value : null;
449 | }
450 |
451 | ///
452 | /// Get the value of the specified attribute of the first child element of the specified element with the
453 | /// class attribute that matched the specified name
454 | ///
455 | ///
456 | /// The element to get the child attribute value from
457 | ///
458 | ///
459 | /// The class name to find
460 | ///
461 | ///
462 | /// The attribute name to find
463 | ///
464 | ///
465 | /// The value of the attribute
466 | ///
467 | ///
468 | /// If there was no child element with the class attribute
469 | ///
470 | private static string GetChildClassAttributeValue( this XElement element, string name, string attribute )
471 | {
472 | XElement result = element.Elements().Where( x => x.GetClassName()?.Equals( name, StringComparison.OrdinalIgnoreCase ) ?? false ).Take( 1 ).Single();
473 |
474 | return null != result ? result.GetAttributeValue( attribute ) : null;
475 | }
476 |
477 | ///
478 | /// XDocument extension method to get the XML text including the declaration from an XDocument
479 | ///
480 | ///
481 | /// The document to get the xml text from
482 | ///
483 | ///
484 | /// The xml text for the document
485 | ///
486 | private static string ToStringWithDeclaration( this XDocument document )
487 | {
488 | return document.Declaration == null ?
489 | document.ToString() :
490 | string.Format( CultureInfo.InvariantCulture, "{0}{1}{2}", document.Declaration, Environment.NewLine, document );
491 | }
492 | }
493 | }
494 |
--------------------------------------------------------------------------------
/VisualStudioHelpDownloader2012/VisualStudioHelpDownloader2012/ItemBase.cs:
--------------------------------------------------------------------------------
1 | namespace VisualStudioHelpDownloader2012
2 | {
3 | using System.Globalization;
4 |
5 | ///
6 | /// Base class for container items.
7 | ///
8 | internal abstract class ItemBase
9 | {
10 | ///
11 | /// Gets or sets the Item code (for Uri combination).
12 | ///
13 | public string Code
14 | {
15 | get;
16 | set;
17 | }
18 |
19 | ///
20 | /// Gets or sets the item name.
21 | ///
22 | public string Name
23 | {
24 | get;
25 | set;
26 | }
27 |
28 | ///
29 | /// Gets or sets the item locale.
30 | ///
31 | public Locale Locale
32 | {
33 | get;
34 | set;
35 | }
36 |
37 | ///
38 | /// Gets or sets the item description.
39 | ///
40 | public string Description
41 | {
42 | get;
43 | set;
44 | }
45 |
46 | ///
47 | /// Returns a string representing the object
48 | ///
49 | ///
50 | /// String representing the object
51 | ///
52 | public override string ToString()
53 | {
54 | return string.Format( CultureInfo.InvariantCulture, "{0} [{1}]", Name ?? "NULL", Locale.Name ?? "NULL" );
55 | }
56 | }
57 | }
58 |
--------------------------------------------------------------------------------
/VisualStudioHelpDownloader2012/VisualStudioHelpDownloader2012/Locale.cs:
--------------------------------------------------------------------------------
1 | namespace VisualStudioHelpDownloader2012
2 | {
3 | ///
4 | /// The locale.
5 | ///
6 | public sealed class Locale
7 | {
8 | ///
9 | /// Gets the normalized locale name display.
10 | ///
11 | public string Name
12 | {
13 | get
14 | {
15 | return NormalizeLocale( Code );
16 | }
17 | }
18 |
19 | ///
20 | /// Gets or sets the locale code.
21 | ///
22 | public string Code
23 | {
24 | get;
25 | set;
26 | }
27 |
28 | ///
29 | /// Gets or sets the relative location of the catalog page associated with the locale
30 | ///
31 | public string CatalogLink
32 | {
33 | get;
34 | set;
35 | }
36 |
37 | ///
38 | /// Returns a string representing the object
39 | ///
40 | ///
41 | /// The Name of the locale
42 | ///
43 | public override string ToString()
44 | {
45 | return Name;
46 | }
47 |
48 | ///
49 | /// Normalizes the locale code
50 | ///
51 | ///
52 | /// The locale code to normalize
53 | ///
54 | ///
55 | /// The normalized locale code
56 | ///
57 | private static string NormalizeLocale( string value )
58 | {
59 | if ( null == value )
60 | {
61 | return string.Empty;
62 | }
63 |
64 | string[] parts = value.Split( '-' );
65 |
66 | if ( parts.Length != 2 )
67 | {
68 | return value;
69 | }
70 |
71 | return string.Join( "-", parts[0], parts[1].ToUpperInvariant() );
72 | }
73 | }
74 | }
75 |
--------------------------------------------------------------------------------
/VisualStudioHelpDownloader2012/VisualStudioHelpDownloader2012/MainForm.Designer.cs:
--------------------------------------------------------------------------------
1 | namespace VisualStudioHelpDownloader2012
2 | {
3 | partial class MainForm
4 | {
5 | ///
6 | /// Clean up any resources being used.
7 | ///
8 | /// true if managed resources should be disposed; otherwise, false.
9 | protected override void Dispose(bool disposing)
10 | {
11 | base.Dispose(disposing);
12 | }
13 |
14 | #region Windows Form Designer generated code
15 |
16 | ///
17 | /// Required method for Designer support - do not modify
18 | /// the contents of this method with the code editor.
19 | ///
20 | private void InitializeComponent()
21 | {
22 | System.Windows.Forms.Label _labelDirectory;
23 | System.Windows.Forms.Label _labelFilter;
24 | System.Windows.Forms.ColumnHeader bookName;
25 | System.Windows.Forms.ColumnHeader totalSize;
26 | System.Windows.Forms.ColumnHeader totalPackages;
27 | System.Windows.Forms.ColumnHeader downloadSize;
28 | System.Windows.Forms.ColumnHeader packagesToDownload;
29 | System.Windows.Forms.Label label1;
30 | System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(MainForm));
31 | this.loadBooks = new System.Windows.Forms.Button();
32 | this.cacheDirectory = new System.Windows.Forms.TextBox();
33 | this.browseDirectory = new System.Windows.Forms.Button();
34 | this.downloadProgress = new System.Windows.Forms.ProgressBar();
35 | this.startupTip = new System.Windows.Forms.Label();
36 | this.downloadBooks = new System.Windows.Forms.Button();
37 | this.loadingBooksTip = new System.Windows.Forms.Label();
38 | this.booksList = new System.Windows.Forms.ListView();
39 | this.languageSelection = new System.Windows.Forms.ComboBox();
40 | this.vsVersion = new System.Windows.Forms.ComboBox();
41 | _labelDirectory = new System.Windows.Forms.Label();
42 | _labelFilter = new System.Windows.Forms.Label();
43 | bookName = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader()));
44 | totalSize = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader()));
45 | totalPackages = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader()));
46 | downloadSize = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader()));
47 | packagesToDownload = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader()));
48 | label1 = new System.Windows.Forms.Label();
49 | this.SuspendLayout();
50 | //
51 | // _labelDirectory
52 | //
53 | _labelDirectory.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left)));
54 | _labelDirectory.AutoSize = true;
55 | _labelDirectory.Location = new System.Drawing.Point(12, 684);
56 | _labelDirectory.Name = "_labelDirectory";
57 | _labelDirectory.Size = new System.Drawing.Size(108, 25);
58 | _labelDirectory.TabIndex = 10;
59 | _labelDirectory.Text = "Store files in";
60 | //
61 | // _labelFilter
62 | //
63 | _labelFilter.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left)));
64 | _labelFilter.AutoSize = true;
65 | _labelFilter.Location = new System.Drawing.Point(364, 573);
66 | _labelFilter.Name = "_labelFilter";
67 | _labelFilter.Size = new System.Drawing.Size(159, 25);
68 | _labelFilter.TabIndex = 8;
69 | _labelFilter.Text = "2. Select Language";
70 | //
71 | // bookName
72 | //
73 | bookName.Text = "Book";
74 | bookName.Width = 550;
75 | //
76 | // totalSize
77 | //
78 | totalSize.Text = "Total Size (MB)";
79 | totalSize.TextAlign = System.Windows.Forms.HorizontalAlignment.Right;
80 | totalSize.Width = 131;
81 | //
82 | // totalPackages
83 | //
84 | totalPackages.Text = "# Packages";
85 | totalPackages.TextAlign = System.Windows.Forms.HorizontalAlignment.Right;
86 | totalPackages.Width = 129;
87 | //
88 | // downloadSize
89 | //
90 | downloadSize.Text = "Download Size (MB)";
91 | downloadSize.TextAlign = System.Windows.Forms.HorizontalAlignment.Right;
92 | downloadSize.Width = 174;
93 | //
94 | // packagesToDownload
95 | //
96 | packagesToDownload.Text = "Num Downloads";
97 | packagesToDownload.TextAlign = System.Windows.Forms.HorizontalAlignment.Right;
98 | packagesToDownload.Width = 159;
99 | //
100 | // label1
101 | //
102 | label1.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left)));
103 | label1.AutoSize = true;
104 | label1.Location = new System.Drawing.Point(12, 573);
105 | label1.Name = "label1";
106 | label1.Size = new System.Drawing.Size(196, 25);
107 | label1.TabIndex = 12;
108 | label1.Text = "1. Visual Studio Version";
109 | //
110 | // loadBooks
111 | //
112 | this.loadBooks.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right)));
113 | this.loadBooks.Enabled = false;
114 | this.loadBooks.Location = new System.Drawing.Point(914, 563);
115 | this.loadBooks.Name = "loadBooks";
116 | this.loadBooks.Size = new System.Drawing.Size(170, 44);
117 | this.loadBooks.TabIndex = 3;
118 | this.loadBooks.Text = "3. Load Books";
119 | this.loadBooks.UseVisualStyleBackColor = true;
120 | this.loadBooks.Click += new System.EventHandler(this.LoadBooksClick);
121 | //
122 | // cacheDirectory
123 | //
124 | this.cacheDirectory.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left)
125 | | System.Windows.Forms.AnchorStyles.Right)));
126 | this.cacheDirectory.Location = new System.Drawing.Point(126, 681);
127 | this.cacheDirectory.Name = "cacheDirectory";
128 | this.cacheDirectory.ReadOnly = true;
129 | this.cacheDirectory.Size = new System.Drawing.Size(1075, 31);
130 | this.cacheDirectory.TabIndex = 5;
131 | //
132 | // browseDirectory
133 | //
134 | this.browseDirectory.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right)));
135 | this.browseDirectory.Enabled = false;
136 | this.browseDirectory.Image = ((System.Drawing.Image)(resources.GetObject("browseDirectory.Image")));
137 | this.browseDirectory.Location = new System.Drawing.Point(1207, 678);
138 | this.browseDirectory.Name = "browseDirectory";
139 | this.browseDirectory.Size = new System.Drawing.Size(31, 35);
140 | this.browseDirectory.TabIndex = 2;
141 | this.browseDirectory.UseVisualStyleBackColor = true;
142 | this.browseDirectory.Click += new System.EventHandler(this.BrowseDirectoryClick);
143 | //
144 | // downloadProgress
145 | //
146 | this.downloadProgress.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left)
147 | | System.Windows.Forms.AnchorStyles.Right)));
148 | this.downloadProgress.Location = new System.Drawing.Point(12, 622);
149 | this.downloadProgress.MarqueeAnimationSpeed = 25;
150 | this.downloadProgress.Name = "downloadProgress";
151 | this.downloadProgress.Size = new System.Drawing.Size(1226, 36);
152 | this.downloadProgress.Style = System.Windows.Forms.ProgressBarStyle.Continuous;
153 | this.downloadProgress.TabIndex = 9;
154 | //
155 | // startupTip
156 | //
157 | this.startupTip.Anchor = System.Windows.Forms.AnchorStyles.None;
158 | this.startupTip.AutoSize = true;
159 | this.startupTip.BackColor = System.Drawing.SystemColors.Window;
160 | this.startupTip.Location = new System.Drawing.Point(235, 299);
161 | this.startupTip.Name = "startupTip";
162 | this.startupTip.Size = new System.Drawing.Size(778, 25);
163 | this.startupTip.TabIndex = 6;
164 | this.startupTip.Text = "Select your Visual Studio version and language, then press \"Load\" to retrieve th" +
165 | "e available books";
166 | this.startupTip.Visible = false;
167 | //
168 | // downloadBooks
169 | //
170 | this.downloadBooks.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right)));
171 | this.downloadBooks.Enabled = false;
172 | this.downloadBooks.Location = new System.Drawing.Point(1090, 563);
173 | this.downloadBooks.Name = "downloadBooks";
174 | this.downloadBooks.Size = new System.Drawing.Size(148, 44);
175 | this.downloadBooks.TabIndex = 5;
176 | this.downloadBooks.Text = "4. Download";
177 | this.downloadBooks.UseVisualStyleBackColor = true;
178 | this.downloadBooks.Click += new System.EventHandler(this.DownloadBooksClick);
179 | //
180 | // loadingBooksTip
181 | //
182 | this.loadingBooksTip.Anchor = System.Windows.Forms.AnchorStyles.None;
183 | this.loadingBooksTip.AutoSize = true;
184 | this.loadingBooksTip.BackColor = System.Drawing.SystemColors.Window;
185 | this.loadingBooksTip.Location = new System.Drawing.Point(545, 299);
186 | this.loadingBooksTip.Name = "loadingBooksTip";
187 | this.loadingBooksTip.Size = new System.Drawing.Size(223, 25);
188 | this.loadingBooksTip.TabIndex = 7;
189 | this.loadingBooksTip.Text = "Downloading please wait...";
190 | //
191 | // booksList
192 | //
193 | this.booksList.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom)
194 | | System.Windows.Forms.AnchorStyles.Left)
195 | | System.Windows.Forms.AnchorStyles.Right)));
196 | this.booksList.CheckBoxes = true;
197 | this.booksList.Columns.AddRange(new System.Windows.Forms.ColumnHeader[] {
198 | bookName,
199 | totalSize,
200 | totalPackages,
201 | downloadSize,
202 | packagesToDownload});
203 | this.booksList.FullRowSelect = true;
204 | this.booksList.HeaderStyle = System.Windows.Forms.ColumnHeaderStyle.Nonclickable;
205 | this.booksList.HoverSelection = true;
206 | this.booksList.Location = new System.Drawing.Point(17, 12);
207 | this.booksList.Name = "booksList";
208 | this.booksList.ShowItemToolTips = true;
209 | this.booksList.Size = new System.Drawing.Size(1226, 537);
210 | this.booksList.TabIndex = 4;
211 | this.booksList.UseCompatibleStateImageBehavior = false;
212 | this.booksList.View = System.Windows.Forms.View.Details;
213 | this.booksList.ItemChecked += new System.Windows.Forms.ItemCheckedEventHandler(this.BooksListItemChecked);
214 | //
215 | // languageSelection
216 | //
217 | this.languageSelection.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left)));
218 | this.languageSelection.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList;
219 | this.languageSelection.Enabled = false;
220 | this.languageSelection.FormattingEnabled = true;
221 | this.languageSelection.Location = new System.Drawing.Point(538, 570);
222 | this.languageSelection.Name = "languageSelection";
223 | this.languageSelection.Size = new System.Drawing.Size(121, 33);
224 | this.languageSelection.Sorted = true;
225 | this.languageSelection.TabIndex = 1;
226 | this.languageSelection.SelectedIndexChanged += new System.EventHandler(this.BookOptionsChanged);
227 | //
228 | // vsVersion
229 | //
230 | this.vsVersion.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left)));
231 | this.vsVersion.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList;
232 | this.vsVersion.FormattingEnabled = true;
233 | this.vsVersion.Items.AddRange(new object[] {
234 | "2012",
235 | "2013",
236 | "2015",
237 | "2017"});
238 | this.vsVersion.Location = new System.Drawing.Point(214, 570);
239 | this.vsVersion.Name = "vsVersion";
240 | this.vsVersion.Size = new System.Drawing.Size(111, 33);
241 | this.vsVersion.TabIndex = 0;
242 | this.vsVersion.SelectedIndexChanged += new System.EventHandler(this.VsVersionChanged);
243 | //
244 | // MainForm
245 | //
246 | this.AutoScaleDimensions = new System.Drawing.SizeF(10F, 25F);
247 | this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
248 | this.ClientSize = new System.Drawing.Size(1258, 725);
249 | this.Controls.Add(label1);
250 | this.Controls.Add(this.vsVersion);
251 | this.Controls.Add(this.languageSelection);
252 | this.Controls.Add(_labelFilter);
253 | this.Controls.Add(_labelDirectory);
254 | this.Controls.Add(this.loadingBooksTip);
255 | this.Controls.Add(this.startupTip);
256 | this.Controls.Add(this.downloadProgress);
257 | this.Controls.Add(this.browseDirectory);
258 | this.Controls.Add(this.cacheDirectory);
259 | this.Controls.Add(this.downloadBooks);
260 | this.Controls.Add(this.loadBooks);
261 | this.Controls.Add(this.booksList);
262 | this.Font = new System.Drawing.Font("Segoe UI", 9F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(204)));
263 | this.Icon = ((System.Drawing.Icon)(resources.GetObject("$this.Icon")));
264 | this.MinimumSize = new System.Drawing.Size(861, 490);
265 | this.Name = "MainForm";
266 | this.StartPosition = System.Windows.Forms.FormStartPosition.CenterScreen;
267 | this.Text = "%TITLE%";
268 | this.ResumeLayout(false);
269 | this.PerformLayout();
270 |
271 | }
272 |
273 | #endregion
274 |
275 | private System.Windows.Forms.Button loadBooks;
276 | private System.Windows.Forms.TextBox cacheDirectory;
277 | private System.Windows.Forms.Button browseDirectory;
278 | private System.Windows.Forms.ProgressBar downloadProgress;
279 | private System.Windows.Forms.Label startupTip;
280 | private System.Windows.Forms.Button downloadBooks;
281 | private System.Windows.Forms.Label loadingBooksTip;
282 | private System.Windows.Forms.ListView booksList;
283 | private System.Windows.Forms.ComboBox languageSelection;
284 | private System.Windows.Forms.ComboBox vsVersion;
285 | }
286 | }
287 |
288 |
--------------------------------------------------------------------------------
/VisualStudioHelpDownloader2012/VisualStudioHelpDownloader2012/MainForm.cs:
--------------------------------------------------------------------------------
1 | namespace VisualStudioHelpDownloader2012
2 | {
3 | using System;
4 | using System.Collections.Generic;
5 | using System.Globalization;
6 | using System.IO;
7 | using System.Threading.Tasks;
8 | using System.Windows.Forms;
9 | using System.Diagnostics;
10 | ///
11 | /// Main application form.
12 | ///
13 | internal sealed partial class MainForm : Form, IProgress
14 | {
15 | ///
16 | /// The products.
17 | ///
18 | private ICollection products;
19 |
20 | ///
21 | /// Initializes a new instance of the class.
22 | ///
23 | public MainForm()
24 | {
25 | InitializeComponent();
26 |
27 | Text = Application.ProductName;
28 | products = new List();
29 | startupTip.Visible = false;
30 | cacheDirectory.Text = Path.Combine( Environment.GetFolderPath( Environment.SpecialFolder.UserProfile ), "Downloads", "MSDN Library" );
31 | }
32 |
33 | ///
34 | /// Reports a progress update.
35 | ///
36 | ///
37 | /// The value of the updated progress. (percentage complete)
38 | ///
39 | public void Report( int value )
40 | {
41 | Invoke(
42 | new MethodInvoker(
43 | delegate
44 | {
45 | downloadProgress.Value = value;
46 | } ) );
47 | }
48 |
49 | ///
50 | /// Called when the form is loaded. Start retrieving the list of available
51 | /// languages in the background.
52 | ///
53 | ///
54 | /// The parameter is not used.
55 | ///
56 | protected override void OnLoad( EventArgs e )
57 | {
58 | base.OnLoad( e );
59 | loadingBooksTip.Visible = false;
60 | startupTip.Visible = true;
61 | }
62 |
63 | ///
64 | /// Called to update the available locales for the selected version of visual studio
65 | ///
66 | private async Task UpdateLocalesAsync()
67 | {
68 | if ( vsVersion.SelectedIndex == -1 )
69 | {
70 | return;
71 | }
72 |
73 | string[] vsVersions = { "visualstudio11", "visualstudio12", "dev14", "dev15" };
74 | string version = vsVersions[vsVersion.SelectedIndex];
75 | startupTip.Visible = false;
76 | SetBusyState();
77 | languageSelection.Items.Clear();
78 | downloadProgress.Style = ProgressBarStyle.Marquee;
79 |
80 | try
81 | {
82 | using (Downloader downloader = new Downloader())
83 | {
84 | (await downloader.LoadAvailableLocalesAsync(version)).ForEach(x => languageSelection.Items.Add(x));
85 | }
86 | }
87 | catch ( Exception ex )
88 | {
89 | MessageBox.Show(
90 | $"Locales update failed - {ex.Message}",
91 | Application.ProductName,
92 | MessageBoxButtons.OK,
93 | MessageBoxIcon.Error,
94 | MessageBoxDefaultButton.Button1,
95 | 0);
96 | }
97 | finally
98 | {
99 | ClearBusyState();
100 | startupTip.Visible = true;
101 | }
102 | }
103 |
104 | ///
105 | /// Called when the download books button is clicked. Start downloading in a background thread
106 | ///
107 | ///
108 | /// The parameter is not used.
109 | ///
110 | ///
111 | /// The parameter is not used.
112 | ///
113 | private async void DownloadBooksClick( object sender, EventArgs e )
114 | {
115 | SetBusyState();
116 | downloadProgress.Style = ProgressBarStyle.Continuous;
117 | downloadProgress.Value = 0;
118 |
119 | try
120 | {
121 | using (Downloader downloader = new Downloader())
122 | {
123 | await downloader.DownloadBooksAsync(products, cacheDirectory.Text, this);
124 | MessageBox.Show(
125 | "Download completed successfully",
126 | Application.ProductName,
127 | MessageBoxButtons.OK,
128 | MessageBoxIcon.Information,
129 | MessageBoxDefaultButton.Button1,
130 | 0);
131 | }
132 | }
133 | catch ( Exception ex )
134 | {
135 | MessageBox.Show(
136 | $"Download failed - {ex.Message}",
137 | Application.ProductName,
138 | MessageBoxButtons.OK,
139 | MessageBoxIcon.Error,
140 | MessageBoxDefaultButton.Button1,
141 | 0);
142 | }
143 | finally
144 | {
145 | ClearBusyState();
146 | DisplayBooks();
147 | downloadProgress.Value = 0;
148 | }
149 |
150 | }
151 |
152 | ///
153 | /// Called when the load books button is clicked. Load the list of available books for the selected
154 | /// language
155 | ///
156 | ///
157 | /// The parameter is not used.
158 | ///
159 | ///
160 | /// The parameter is not used.
161 | ///
162 | private async void LoadBooksClick( object sender, EventArgs e )
163 | {
164 | string path = ((Locale)languageSelection.SelectedItem).CatalogLink;
165 |
166 | SetBusyState();
167 | downloadProgress.Style = ProgressBarStyle.Marquee;
168 | startupTip.Visible = false;
169 |
170 | try
171 | {
172 | using (Downloader downloader = new Downloader())
173 | {
174 | products = await downloader.LoadBooksInformationAsync(path);
175 | DisplayBooks();
176 | }
177 | }
178 | catch ( Exception ex )
179 | {
180 | MessageBox.Show(
181 | $"Failed to retrieve book information - {ex.Message}",
182 | Application.ProductName,
183 | MessageBoxButtons.OK,
184 | MessageBoxIcon.Error,
185 | MessageBoxDefaultButton.Button1,
186 | 0);
187 | }
188 | finally
189 | {
190 | ClearBusyState();
191 | }
192 | }
193 |
194 | ///
195 | /// Enable/disable, hide/show controls for when the program is not busy
196 | ///
197 | private void ClearBusyState()
198 | {
199 | vsVersion.Enabled = true;
200 | languageSelection.Enabled = languageSelection.Items.Count > 0;
201 | loadBooks.Enabled = languageSelection.Items.Count > 0;
202 | downloadBooks.Enabled = (booksList.Items.Count > 0) && !string.IsNullOrEmpty( cacheDirectory.Text );
203 | browseDirectory.Enabled = true;
204 | downloadProgress.Style = ProgressBarStyle.Continuous;
205 | startupTip.Visible = false;
206 | loadingBooksTip.Visible = false;
207 | booksList.Enabled = true;
208 | }
209 |
210 | ///
211 | /// Enable/disable, hide/show controls for when the program is busy
212 | ///
213 | private void SetBusyState()
214 | {
215 | vsVersion.Enabled = false;
216 | languageSelection.Enabled = false;
217 | loadBooks.Enabled = false;
218 | downloadBooks.Enabled = false;
219 | browseDirectory.Enabled = false;
220 | booksList.Enabled = false;
221 | loadingBooksTip.Visible = true;
222 | }
223 |
224 | ///
225 | /// Populate the list view control with the books available for download
226 | ///
227 | private void DisplayBooks()
228 | {
229 | booksList.Items.Clear();
230 | if ( !string.IsNullOrEmpty( cacheDirectory.Text ) )
231 | {
232 | Downloader.CheckPackagesStates( products, cacheDirectory.Text );
233 | }
234 |
235 | Dictionary groups = new Dictionary();
236 | foreach ( BookGroup product in products )
237 | {
238 | foreach ( Book book in product.Books )
239 | {
240 | // Calculate some details about any prospective download
241 | long totalSize = 0;
242 | long downloadSize = 0;
243 | int packagesOutOfDate = 0;
244 | int packagesCached = 0;
245 | foreach ( Package package in book.Packages )
246 | {
247 | totalSize += package.Size;
248 | if ( package.State != PackageState.Ready )
249 | {
250 | downloadSize += package.Size;
251 | packagesOutOfDate++;
252 | }
253 |
254 | if ( package.State != PackageState.NotDownloaded )
255 | {
256 | packagesCached++;
257 | }
258 | }
259 |
260 | // Make sure the groups aren't duplicated
261 | ListViewGroup itemGroup;
262 | if ( groups.ContainsKey( book.Category ) )
263 | {
264 | itemGroup = groups[book.Category];
265 | }
266 | else
267 | {
268 | itemGroup = booksList.Groups.Add( book.Category, book.Category );
269 | groups.Add( book.Category, itemGroup );
270 | }
271 |
272 | ListViewItem item = booksList.Items.Add( book.Name );
273 | item.SubItems.Add( (totalSize / 1000000).ToString( "F1", CultureInfo.CurrentCulture ) );
274 | item.SubItems.Add( book.Packages.Count.ToString( CultureInfo.CurrentCulture ) );
275 | item.SubItems.Add( (downloadSize / 1000000).ToString( "F1", CultureInfo.CurrentCulture ) );
276 | item.SubItems.Add( packagesOutOfDate.ToString( CultureInfo.CurrentCulture ) );
277 | item.ToolTipText = book.Description;
278 | item.Checked = packagesCached > 1;
279 | book.Wanted = item.Checked;
280 | item.Tag = book;
281 | item.Group = itemGroup;
282 | }
283 | }
284 | }
285 |
286 | ///
287 | /// Called when the browse for directory button is clicked. Show an folder browser to allow the
288 | /// user to select a directory to store the cached file in
289 | ///
290 | ///
291 | /// The parameter is not used.
292 | ///
293 | ///
294 | /// The parameter is not used.
295 | ///
296 | private void BrowseDirectoryClick( object sender, EventArgs e )
297 | {
298 | using ( FolderBrowserDialog dialog = new FolderBrowserDialog() )
299 | {
300 | dialog.RootFolder = Environment.SpecialFolder.MyComputer;
301 | dialog.SelectedPath = cacheDirectory.Text;
302 | dialog.ShowNewFolderButton = true;
303 | dialog.Description = "Select local cache folder to store selected MSDN Library books";
304 |
305 | if ( DialogResult.OK == dialog.ShowDialog( this ) )
306 | {
307 | cacheDirectory.Text = dialog.SelectedPath;
308 | downloadBooks.Enabled = (booksList.Items.Count > 0) && !string.IsNullOrEmpty( cacheDirectory.Text );
309 | DisplayBooks();
310 | }
311 | }
312 | }
313 |
314 | ///
315 | /// Called when the checkbox of one of the listview items is checked or unchecked. Mark the associated book state
316 | ///
317 | ///
318 | /// The parameter is not used.
319 | ///
320 | ///
321 | /// Details about the item checked/unchecked
322 | ///
323 | private void BooksListItemChecked( object sender, ItemCheckedEventArgs e )
324 | {
325 | Book book = e.Item.Tag as Book;
326 | if ( book != null )
327 | {
328 | book.Wanted = e.Item.Checked;
329 | }
330 | }
331 |
332 | ///
333 | /// Called when the language combobox selection is changed. Clear the
334 | /// currently list of available books and reshow the instruction.
335 | ///
336 | ///
337 | /// The parameter is not used.
338 | ///
339 | ///
340 | /// The parameter is not used.
341 | ///
342 | private void BookOptionsChanged( object sender, EventArgs e )
343 | {
344 | booksList.Items.Clear();
345 | downloadBooks.Enabled = false;
346 | startupTip.Visible = true;
347 | }
348 |
349 | ///
350 | /// Called when the visual studio language combobox selection is changed. Clear the
351 | /// currently list of available books and reshow the instruction.
352 | ///
353 | ///
354 | /// The parameter is not used.
355 | ///
356 | ///
357 | /// The parameter is not used.
358 | ///
359 | private async void VsVersionChanged(object sender, EventArgs e)
360 | {
361 | booksList.Items.Clear();
362 | languageSelection.Items.Clear();
363 | languageSelection.SelectedItem = -1;
364 | await UpdateLocalesAsync();
365 | }
366 | }
367 | }
368 |
--------------------------------------------------------------------------------
/VisualStudioHelpDownloader2012/VisualStudioHelpDownloader2012/MainForm.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 | False
122 |
123 |
124 | False
125 |
126 |
127 | False
128 |
129 |
130 | False
131 |
132 |
133 | False
134 |
135 |
136 | False
137 |
138 |
139 | False
140 |
141 |
142 | False
143 |
144 |
145 |
146 |
147 | iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABGdBTUEAALGPC/xhBQAAABl0RVh0U29m
148 | dHdhcmUAQWRvYmUgSW1hZ2VSZWFkeXHJZTwAAAIISURBVDhPY/jx4wdFGKsgFDMBsQMQpwFxAhBbAjGG
149 | OgwBKHb5+v3HtkW3X5+vPPv0fv35Z3dW3X1zFijeBMTmSOqwGuB0/dWn/aFbbr03W37lPzJO3Hnn1dMP
150 | X3YB1RjD1KNrZvr67fu2yKVX3llOOfs/etnVd4tPP70w58Tjy0ELL38CiaWtuf4CqK4OpgfdALvlp56c
151 | s+w5+T9y3sV3IMOAYk5A7P3649cd3tPOfgXJnbn/9hBQTAGkB92AlPp1N+5Zthz9P+/gg0tAvhuSXFzr
152 | ppu30eWQNYNwQvOaa3csaw78n7L99lUgPxxJLq1mxZX7ILnFB+9fAPJBLsMwQHf3uafHLUt3//eoP/D9
153 | 0cuPu4Fi+UBcfPHumwMOVXv/2JTv+Xv32fu9QDFhkB50A+JOXnt+2LZg2x/L3C3/HYu3/y6ZcfJRwdQT
154 | T2Bik9ZduQZUB0obYD2omq88PeyUs/6XRerq/8FV2z6CaBi2zVj7Z9Kq8yDNWUDMBtMH13z8wsPDtvHz
155 | fhmHz/yf1rjp+dev37fdf/xmz6b9105tP3zzxIvXH3YC1aUAMVwzCIMIpaNnbx82Der4pe3Z9D+hbCFQ
156 | 8zdQ9OkDsSAQgxINiM0NxHCNMAwiQhv7VtxQssr4H5ndi6wZQzE2DCJAJmdNmbnw3JcvX0nSDMLIHDsg
157 | BuVAZDEC+AcDADVk7WUUiqKZAAAAAElFTkSuQmCC
158 |
159 |
160 |
161 |
162 | AAABAAQAMDAAAAEAIACoJQAARgAAACAgAAABACAAqBAAAO4lAAAYGAAAAQAgAIgJAACWNgAAEBAAAAEA
163 | IABoBAAAHkAAACgAAAAwAAAAYAAAAAEAIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
164 | AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
165 | AAAAAAAAAAAAAAAAAAAAAAABAAAAAwAAAAYAAAAIAAAABgAAAAMAAAABAAAAAAAAAAAAAAAAAAAAAAAA
166 | AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
167 | AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
168 | AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADAAAACwAAABYAAAAbAAAAFwAAAA0AAAAEAAAAAQAA
169 | AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
170 | AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
171 | AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIAAAALAAAAHQAAADIAAAA9AAAANQAA
172 | ACEAAAANAAAAAwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
173 | AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
174 | AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgAAAAkfHx8fnJyc4piY
175 | mOCamprrFRUVXAAAADoAAAAeAAAACgAAAAIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
176 | AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
177 | AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAAAABwAA
178 | ABeUlJS/nZ2d8cbGxv+kpKT2kJCQ3AAAAFUAAAA1AAAAGQAAAAgAAAABAAAAAAAAAAAAAAAAAAAAAAAA
179 | AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
180 | AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
181 | AAEAAAAFAAAAE4aGho6enp70qKio/8PDw//R0dH/oKCg+Hx8fL4AAABPAAAALwAAABUAAAAGAAAAAQAA
182 | AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
183 | AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
184 | AAAAAAAAAAAAAAAAAAQAAAAPbW1tXJ2dnfiqqqr/rq6u/6urq//Ly8v/ycnJ/6CgoPtbW1uaAAAASQAA
185 | ACkAAAARAAAABQAAAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
186 | AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
187 | AAAAAAAAAAAAAAAAAAAAAAAAAAAAAgAAAAxCQkIynJyc9aenp/mzs7P/s7Oz/6+vr/+urq7/0tLS/729
188 | vfyfn5/5MzMzeAAAAEIAAAAkAAAADgAAAAMAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
189 | AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
190 | AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAAAACRwcHCGWlpbhn5+f87i4uP+5ubn/tra2/7Ky
191 | sv+wsLD/srKy/9fX1/+xsbH4mZmZ7hQUFGMAAAA8AAAAHgAAAAsAAAACAAAAAAAAAAAAAAAAAAAAAAAA
192 | AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
193 | AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEAAAAHAAAAGIyMjL2amprzvLy8/8DA
194 | wP+9vb3/urq6/7e3t/+0tLT/sLCw/7q6uv/X19f/qKio942NjdsAAABVAAAANQAAABkAAAAIAAAAAQAA
195 | AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
196 | AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQAAAAYAAAAUfX19jZeX
197 | l/a7u7v/xcXF/8TExP/AwMD/vr6+/7q6uv+3t7f/s7Oz/7CwsP/CwsL/1dXV/6Ojo/l6enq9AAAATwAA
198 | AC8AAAAVAAAABgAAAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
199 | AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAAA
200 | ABBlZWVblZWV+La2tv/Kysr/y8vL/8jIyP/ExMT/wsLC/76+vv+6urr/t7e3/7W1tf+xsbH/zMzM/87O
201 | zv+fn5/6W1tbmAAAAEkAAAAqAAAAEQAAAAUAAAABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
202 | AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
203 | AAAAAAADAAAADTw8PDShoaH1q6ur+83Nzf/R0dH/zs7O/8vLy//IyMj/xcXF/8HBwf++vr7/u7u7/7i4
204 | uP+0tLT/srKy/9LS0v/Dw8P9n5+f+DMzM3gAAABCAAAAJAAAAA4AAAADAAAAAAAAAAAAAAAAAAAAAAAA
205 | AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
206 | AAAAAAAAAAAAAAAAAAIAAAAKDg4OIIyMjN+enp72z8/P/9XV1f/U1NT/0dHR/8/Pz//Ly8v/ycnJ/8XF
207 | xf/CwsL/v7+//7y8vP+4uLj/tbW1/7W1tf/Y2Nj/tbW1+ZmZme4PDw9hAAAAPAAAAB4AAAALAAAAAgAA
208 | AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
209 | AAAAAAAAAAAAAAAAAAAAAAAAAAAAAQAAAAgAAAAZgoKCuZSUlPbNzc3/2dnZ/9nZ2f/X19f/1NTU/9HR
210 | 0f/Ozs7/zMzM/8jIyP/FxcX/wsLC/7+/v/+7u7v/ubm5/7W1tf+8vLz/2tra/6urq/iLi4vYAAAAVQAA
211 | ADYAAAAaAAAACAAAAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
212 | AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAAAABgAAABVycnKKnJyc+crKyv/c3Nz/3t7e/9zc
213 | 3P/Z2dn/19fX/9TU1P/S0tL/z8/P/8zMzP/Jycn/xsbG/8PDw//AwMD/vb29/7m5uf+2trb/w8PD/9nZ
214 | 2f+kpKT6dXV1uQAAAFAAAAAwAAAAFgAAAAYAAAABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
215 | AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEAAAAFAAAAEVlZWVqZmZn5vb29/+Hh
216 | 4f/i4uL/4ODg/97e3v/c3Nz/2tra/9fX1//V1dX/0tLS/8/Pz//MzMz/ycnJ/8bGxv/Dw8P/wMDA/7y8
217 | vP+5ubn/tra2/8zMzP/S0tL/oKCg+1ZWVpYAAABJAAAAKgAAABIAAAAFAAAAAQAAAAAAAAAAAAAAAAAA
218 | AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMAAAAOMDAwM6Sk
219 | pPWurq7+4ODg/+np6f/l5eX/4uLi/+Dg4P/e3t7/3Nzc/9ra2v/X19f/1dXV/9LS0v/Q0ND/zc3N/8rK
220 | yv/Hx8f/xMTE/8DAwP+9vb3/urq6/7e3t//T09P/yMjI/ZycnPcvLy93AAAAQwAAACQAAAAOAAAAAwAA
221 | AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgAA
222 | AAsMDAwioaGh5ZmZmfnd3d3/6+vr/+rq6v/n5+f/5OTk/+Li4v/h4eH/39/f/93d3f/a2tr/2NjY/9XV
223 | 1f/T09P/0NDQ/83Nzf/Kysr/x8fH/8PDw//BwcH/vb29/7q6uv+5ubn/2dnZ/7q6uvqWlpbsCgoKXwAA
224 | ADwAAAAfAAAACwAAAAIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
225 | AAAAAAACAAAACQAAABp3d3e4p6en+dfX1//p6en/6+vr/+vr6//p6en/5eXl/+Tk5P/i4uL/4eHh/9/f
226 | 3//d3d3/2tra/9jY2P/W1tb/09PT/9HR0f/Nzc3/y8vL/8fHx//FxcX/wcHB/76+vv+7u7v/vr6+/9zc
227 | 3P+urq75iYmJ1wAAAFUAAAA2AAAAGgAAAAgAAAACAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
228 | AAAAAAAAAAAAAAAAAAEAAAAHAAAAFmdnZ4ahoaH6ycnJ/+fn5//r6+v/6+vr/+vr6//q6ur/5ubm/+Xl
229 | 5f/k5OT/4+Pj/+Hh4f/f39//3d3d/9vb2//Y2Nj/1tbW/9PT0//Q0ND/zs7O/8rKyv/IyMj/xMTE/8HB
230 | wf++vr7/urq6/8TExP/b29v/paWl+3FxcbUAAABQAAAAMAAAABYAAAAGAAAAAQAAAAAAAAAAAAAAAAAA
231 | AAAAAAAAAAAAAAAAAAAAAAAAAAAAAQAAAAUAAAATT09PWp+fn/q4uLj/4+Pj/+rq6v/r6+v/6+vr/+vr
232 | 6//r6+v/6Ojo/+bm5v/l5eX/5OTk/+Pj4//h4eH/39/f/93d3f/b29v/2dnZ/9fX1//U1NT/0dHR/87O
233 | zv/Ly8v/yMjI/8XFxf/CwsL/vr6+/7u7u//MzMz/1tbW/6CgoPtSUlKTAAAASgAAACoAAAASAAAABQAA
234 | AAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAwAAAA4lJSUznJyc9aSkpP7d3d3/6Ojo/+np
235 | 6f/q6ur/6+vr/+vr6//r6+v/6urq/+fn5//m5ub/5eXl/+Tk5P/j4+P/4uLi/+Dg4P/e3t7/29vb/9nZ
236 | 2f/W1tb/1NTU/9HR0f/Ozs7/y8vL/8jIyP/FxcX/wcHB/7+/v/+7u7v/1NTU/8zMzP2bm5v3LCwsdQAA
237 | AEMAAAAkAAAADgAAAAMAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABg8PDxmNjY3fn5+f+9bW
238 | 1v/l5eX/5+fn/+jo6P/p6en/6urq/+vr6//r6+v/6urq/+fn5//n5+f/5ubm/+bm5v/k5OT/4+Pj/+Hh
239 | 4f/g4OD/3t7e/9zc3P/Z2dn/19fX/9TU1P/S0tL/z8/P/8zMzP/Jycn/xcXF/8PDw/+/v7//vr6+/9nZ
240 | 2f+/v7/6lZWV6AwMDFEAAAAwAAAAFQAAAAYAAAABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAAAAB3V1
241 | daeSkpL5y8vL/+Dg4P/k5OT/5eXl/+bm5v/n5+f/6enp/+rq6v/r6+v/6+vr/+fn5//n5+f/5+fn/+fn
242 | 5//m5ub/5eXl/+Pj4//i4uL/4ODg/97e3v/c3Nz/2tra/9fX1//U1NT/0tLS/8/Pz//MzMz/ycnJ/8bG
243 | xv/CwsL/v7+//8HBwf/d3d3/srKy+I6OjsYAAAAvAAAAFwAAAAgAAAABAAAAAAAAAAAAAAAAAAAAAAAA
244 | AAAAAAAAeHh4ao2Njfm8vLz/29vb/+Hh4f/i4uL/5OTk/+bm5v/n5+f/6enp/+rq6v/q6ur/6+vr/+jo
245 | 6P/n5+f/5+fn/+fn5//n5+f/5ubm/+Tk5P/j4+P/4uLi/+Hh4f/e3t7/3Nzc/9ra2v/X19f/1dXV/9PT
246 | 0//Q0ND/zc3N/8rKyv/Gxsb/w8PD/8DAwP/Hx8f/3d3d/6SkpPiPj4+KAAAADgAAAAUAAAABAAAAAAAA
247 | AAAAAAAAAAAAAAAAAAAAAAAAfHx80rS0tP/d3d3/39/f/+Hh4f/k5OT/5eXl/+fn5//p6en/6urq/+jo
248 | 6P/o6Oj/6urq/+jo6P/n5+f/5+fn/+fn5//n5+f/5+fn/+bm5v/l5eX/5OTk/+Li4v/h4eH/39/f/9zc
249 | 3P/q6ur/6enp/+zs7P/s7Oz/6+vr/+rq6v/o6Oj/5+fn/+bm5v/l5eX/5+fn/+Tk5P+enp7lAAAABgAA
250 | AAIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAenp6pIGBgf+CgoL/g4OD/4ODg/+EhIT/hYWF/4WF
251 | hf+Ghob/hoaG/4aGhv+Hh4f/6+vr/+jo6P/m5ub/5+fn/+fn5//n5+f/5+fn/+fn5//m5ub/5eXl/+Tk
252 | 5P/j4+P/4eHh/9/f3//t7e3/rKys/56env+enp7/n5+f/6Ghof+hoaH/oqKi/6Ojo/+jo6P/pKSk/6am
253 | pv+NjY2XAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
254 | AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACGhob/6urq/+jo6P/l5eX/5ubm/+fn5//n5+f/5+fn/+fn
255 | 5//n5+f/5ubm/+Xl5f/k5OT/4+Pj/+Hh4f/v7+//qqqq/wAAACsAAAAOAAAAAAAAAAAAAAAAAAAAAAAA
256 | AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
257 | AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACGhob/6Ojo/+fn5//l5eX/5eXl/+bm
258 | 5v/n5+f/5+fn/+fn5//n5+f/5+fn/+bm5v/l5eX/5OTk/+Pj4//w8PD/qamp/wAAACsAAAAOAAAAAAAA
259 | AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
260 | 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
344 | AAAAAAAAAAAAAQAAAAein5ust7Sv/+jo6P/g4OD/3d3d/9ra2v/W1tb/09PT/8/Pz//Ly8v/x8fH/8PD
345 | w/+/v7//0tLS/7a2tv+np6f7REREXAAAADAAAAAUAAAABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
346 | AAAAAAAAAAAAAAAAAAAAAAAEn5uYeKShm/7r6ur/5+fn/+Pj4//g4OD/3t7e/9vb2//X19f/1NTU/9DQ
347 | 0P/MzMz/yMjI/8PDw//CwsL/1NTU/6+vr/+mpqbuJiYmTwAAACsAAAAPAAAAAgAAAAAAAAAAAAAAAAAA
348 | AAAAAAAAAAAAAAAAAAAAAAAAAAAAApKPjEGemZT74+Lg/+zs7P/q6ur/5eXl/+Pj4//h4eH/3t7e/9vb
349 | 2//Y2Nj/1NTU/9DQ0P/MzMz/yMjI/8TExP/Gxsb/z8/P/6qqqv+enp7NAAAAPwAAACQAAAALAAAAAQAA
350 | AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAItKSUUnZiQ8dLQzf/s7Oz/6+vr/+rq6v/n5+f/5OTk/+Pj
351 | 4//h4eH/3t7e/9vb2//Y2Nj/1dXV/9HR0f/Nzc3/yMjI/8TExP/Ly8v/xcXF/6ampv+KioqcAAAAOgAA
352 | AB8AAAAIAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAABAAAAC6Kak9bAu7P/6+vr/+rq6v/r6+v/6+vr/+np
353 | 6f/m5ub/5eXl/+Pj4//h4eH/39/f/9zc3P/Z2dn/1dXV/9HR0f/MzMz/yMjI/8TExP/Q0ND/vb29/6am
354 | pv5ubm56AAAANgAAABoAAAAGAAAAAQAAAAAAAAAAAAAAAAAAAAafnJqtp6Og/+jo6P/o6Oj/6Ojo/+rq
355 | 6v/r6+v/6enp/+fn5//m5ub/5ubm/+Tk5P/i4uL/39/f/9zc3P/Z2dn/1tbW/9LS0v/Nzc3/ycnJ/8bG
356 | xv/X19f/tra2/6mpqftLS0tgAAAALgAAABMAAAADAAAAAAAAAAAAAAAAp6WjcJiUj//d3Nz/4+Pj/+Xl
357 | 5f/n5+f/6enp/+rq6v/q6ur/5+fn/+fn5//n5+f/5ubm/+Tk5P/i4uL/4ODg/9zc3P/Z2dn/1dXV/9LS
358 | 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
454 | rEHwH6xB8B+sQfAfrEHwH6xB8B+sQQ==
455 |
456 |
457 |
--------------------------------------------------------------------------------
/VisualStudioHelpDownloader2012/VisualStudioHelpDownloader2012/Package.cs:
--------------------------------------------------------------------------------
1 | namespace VisualStudioHelpDownloader2012
2 | {
3 | using System;
4 | using System.Globalization;
5 |
6 | ///
7 | /// The possible download states for a package
8 | ///
9 | public enum PackageState
10 | {
11 | ///
12 | /// The package has not been downloaded yet
13 | ///
14 | NotDownloaded,
15 |
16 | ///
17 | /// The package has been previously downloaded but is now out of date
18 | ///
19 | OutOfDate,
20 |
21 | ///
22 | /// The package has been downloaded and is up to date
23 | ///
24 | Ready
25 | }
26 |
27 | ///
28 | /// Represents an MSDN package
29 | ///
30 | internal sealed class Package
31 | {
32 | ///
33 | /// Gets or sets the last modified time.
34 | ///
35 | public DateTime LastModified
36 | {
37 | get;
38 | set;
39 | }
40 |
41 | ///
42 | /// Gets or sets the tag associated with the package
43 | ///
44 | public string Tag
45 | {
46 | get;
47 | set;
48 | }
49 |
50 | ///
51 | /// Gets or sets the package relative URL for downloading.
52 | ///
53 | public string Link
54 | {
55 | get;
56 | set;
57 | }
58 |
59 | ///
60 | /// Gets or sets the package name
61 | ///
62 | public string Name
63 | {
64 | get;
65 | set;
66 | }
67 |
68 | ///
69 | /// Gets or sets the size in bytes.
70 | ///
71 | public long Size
72 | {
73 | get;
74 | set;
75 | }
76 |
77 | ///
78 | /// Gets or sets the state.
79 | ///
80 | public PackageState State
81 | {
82 | get;
83 | set;
84 | }
85 |
86 | ///
87 | /// Create a file name for the package file
88 | ///
89 | ///
90 | /// A string containing the file name
91 | ///
92 | public string CreateFileName()
93 | {
94 | return string.Format( CultureInfo.InvariantCulture, "{0}.cab", Name.ToUpperInvariant() );
95 | }
96 |
97 | ///
98 | /// Returns a string representing the object
99 | ///
100 | ///
101 | /// String representing the object
102 | ///
103 | public override string ToString()
104 | {
105 | return Name ?? "NULL";
106 | }
107 | }
108 | }
109 |
--------------------------------------------------------------------------------
/VisualStudioHelpDownloader2012/VisualStudioHelpDownloader2012/Program.cs:
--------------------------------------------------------------------------------
1 | namespace VisualStudioHelpDownloader2012
2 | {
3 | using System;
4 | using System.Diagnostics;
5 | using System.Globalization;
6 | using System.Windows.Forms;
7 |
8 | ///
9 | /// The program.
10 | ///
11 | internal static class Program
12 | {
13 | ///
14 | /// Log exception to event log.
15 | ///
16 | ///
17 | /// The exeception to log
18 | ///
19 | public static void LogException( Exception ex )
20 | {
21 | if ( null != ex )
22 | {
23 | EventLog.WriteEntry(
24 | "Application",
25 | string.Format( CultureInfo.InvariantCulture, "{1}{0}{0}{2}", Environment.NewLine, ex.Message, ex.StackTrace ),
26 | EventLogEntryType.Error );
27 | }
28 | }
29 |
30 | ///
31 | /// The main.
32 | ///
33 | [STAThread]
34 | private static void Main()
35 | {
36 | AppDomain.CurrentDomain.UnhandledException += ( sender, e ) => LogException( e.ExceptionObject as Exception );
37 | Application.ThreadException += ( sender, e ) => LogException( e.Exception );
38 | Application.EnableVisualStyles();
39 | Application.SetCompatibleTextRenderingDefault( false );
40 | Application.Run( new MainForm() );
41 | }
42 | }
43 | }
44 |
--------------------------------------------------------------------------------
/VisualStudioHelpDownloader2012/VisualStudioHelpDownloader2012/Properties/App.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/nickdalt/VSHD/5119cb6945cbecb8c6ae269399d900d5039cb79b/VisualStudioHelpDownloader2012/VisualStudioHelpDownloader2012/Properties/App.ico
--------------------------------------------------------------------------------
/VisualStudioHelpDownloader2012/VisualStudioHelpDownloader2012/Properties/App.manifest:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Visual Studio 2010 Help Downloader
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 | true
20 |
21 |
22 |
--------------------------------------------------------------------------------
/VisualStudioHelpDownloader2012/VisualStudioHelpDownloader2012/Properties/AssemblyInfo.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Reflection;
3 | using System.Runtime.InteropServices;
4 |
5 | [assembly: AssemblyTitle("VisualStudioHelpDownloader")]
6 | [assembly: AssemblyDescription("MSDN Library packages downloader")]
7 | [assembly: AssemblyConfiguration("")]
8 | [assembly: AssemblyProduct("Visual Studio Help Downloader")]
9 | [assembly: AssemblyCopyright("© 2012-2020 NickDal, Based on Visual Studio 2010 Help Downloader Alexander Kozlenko")]
10 | [assembly: AssemblyCulture("")]
11 | [assembly: AssemblyVersion("1.5.0.0")]
12 | [assembly: AssemblyFileVersion("1.5.0.0")]
13 | [assembly: CLSCompliant(true)]
14 | [assembly: ComVisible(false)]
15 |
--------------------------------------------------------------------------------
/VisualStudioHelpDownloader2012/VisualStudioHelpDownloader2012/Properties/Default.snk:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/nickdalt/VSHD/5119cb6945cbecb8c6ae269399d900d5039cb79b/VisualStudioHelpDownloader2012/VisualStudioHelpDownloader2012/Properties/Default.snk
--------------------------------------------------------------------------------
/VisualStudioHelpDownloader2012/VisualStudioHelpDownloader2012/VisualStudioHelpDownloader.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Debug
5 | x86
6 | 8.0.30703
7 | 2.0
8 | {2AE1E505-92AB-40DD-86D9-E47B307CEC94}
9 | WinExe
10 | Properties
11 | VisualStudioHelpDownloader
12 | VisualStudioHelpDownloader
13 | v4.7.2
14 |
15 |
16 | 512
17 | VisualStudioHelpDownloader2012.Program
18 | Properties\App.manifest
19 | true
20 | Properties\Default.snk
21 | Properties\App.ico
22 | SAK
23 | SAK
24 | SAK
25 | SAK
26 |
27 |
28 | true
29 | bin\Debug\
30 | DEBUG;TRACE
31 | full
32 | AnyCPU
33 | prompt
34 | AllRules.ruleset
35 |
36 |
37 | bin\Release\
38 | TRACE
39 | true
40 | AnyCPU
41 | prompt
42 | MinimumRecommendedRules.ruleset
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 | Form
56 |
57 |
58 | MainForm.cs
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 | MainForm.cs
71 | Designer
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 | False
85 | Microsoft .NET Framework 4 Client Profile %28x86 and x64%29
86 | true
87 |
88 |
89 | False
90 | .NET Framework 3.5 SP1 Client Profile
91 | false
92 |
93 |
94 | False
95 | .NET Framework 3.5 SP1
96 | false
97 |
98 |
99 | False
100 | Windows Installer 3.1
101 | true
102 |
103 |
104 |
105 |
112 |
--------------------------------------------------------------------------------
/VisualStudioHelpDownloader2012/VisualStudioHelpDownloader2012/VisualStudioHelpDownloader.csproj.vspscc:
--------------------------------------------------------------------------------
1 | ""
2 | {
3 | "FILE_VERSION" = "9237"
4 | "ENLISTMENT_CHOICE" = "NEVER"
5 | "PROJECT_FILE_RELATIVE_PATH" = ""
6 | "NUMBER_OF_EXCLUDED_FILES" = "0"
7 | "ORIGINAL_PROJECT_FILE_PATH" = ""
8 | "NUMBER_OF_NESTED_PROJECTS" = "0"
9 | "SOURCE_CONTROL_SETTINGS_PROVIDER" = "PROVIDER"
10 | }
11 |
--------------------------------------------------------------------------------
/VisualStudioHelpDownloader2012/VisualStudioHelpDownloader2012/app.config:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
--------------------------------------------------------------------------------
/docs/Home.md:
--------------------------------------------------------------------------------
1 | **Project Description**
2 | Tool for downloading the Visual Studio 2012/2013/2015 help packages for offline use
3 |
4 | # Overview
5 |
6 | Allows Visual Studio 2012/2013/2015 packages to be downloaded to an offline cache location before importing them into Microsoft Help Viewer 2.0/2.1/2.2.
7 |
8 | If the cache is kept following the import, then only changes will be downloaded on subsequent occasions.
9 |
10 | 
11 |
12 | # Quick Guide
13 |
14 | * Select the version of Visual Studio to download the help for
15 | * Select your language from the drop down list
16 | * Press "Load Books" to retrieve the list of available books. Books that are already in the cache (partially or fully) will automatically be checked. Note that because packages are shared between different books, you may get extra items checked automatically.
17 | * Check (or uncheck) book that you want to download. The "Download Size" and "Num Downloads" columns indicate an approximate amount of data that needs to be downloaded for the book based on what is already in the cache.
18 | * Press "Download" to start downloading the requested books. Packages for books no longer selected will be deleted at this point.
19 | * When the download is complete, import the new books into "Microsoft Help Viewer" using the "Manage Content" tab.
20 |
21 | # Credits
22 |
23 | This project is based on (and shares some code with) the earlier project [Visual Studio Help Downloader](http://vshd.codeplex.com/) by [nop](http://www.codeplex.com/site/users/view/nop).
--------------------------------------------------------------------------------
/docs/Home_screenshot.JPG:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/nickdalt/VSHD/5119cb6945cbecb8c6ae269399d900d5039cb79b/docs/Home_screenshot.JPG
--------------------------------------------------------------------------------